gemini_wdt.c revision 1.1 1 /* $NetBSD: gemini_wdt.c,v 1.1 2008/10/24 04:23:18 matt Exp $ */
2
3 /*
4 * OMAP watchdog timers, common code
5 *
6 * Copyright (c) 2007 Microsoft
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Microsoft
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTERS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35
36 #include <sys/param.h>
37 #include <sys/callout.h>
38 #include <sys/cdefs.h>
39 #include <sys/device.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
42 #include <sys/wdog.h>
43
44 #include <machine/param.h>
45 #include <machine/bus.h>
46 #include <dev/sysmon/sysmonvar.h>
47
48 #include <arm/gemini/gemini_wdtvar.h>
49 #include <arm/gemini/gemini_reg.h>
50
51 geminiwdt_softc_t *geminiwdt_sc;
52
53 #define WATCHDOG_COUNT(nsec) \
54 (GEMINI_WDT_CLOCK_FREQ * (nsec))
55
56
57 static void
58 geminiwdt_start(void)
59 {
60 geminiwdt_softc_t *sc = geminiwdt_sc;
61 uint32_t r;
62
63 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR);
64 r |= (WDT_WDCR_RESET_ENB
65 |WDT_WDCR_ENB);
66 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r);
67 }
68
69 static void
70 geminiwdt_stop(void)
71 {
72 geminiwdt_softc_t *sc = geminiwdt_sc;
73 uint32_t r;
74
75 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR);
76 r &= ~(WDT_WDCR_EXTSIG_ENB
77 |WDT_WDCR_RESET_ENB
78 |WDT_WDCR_INTR_ENB
79 |WDT_WDCR_ENB);
80 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r);
81 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
82 GEMINI_WDT_WDCLEAR, WDT_WDCLEAR_CLEAR);
83 }
84
85 static void
86 geminiwdt_do_set_timeout(void)
87 {
88 geminiwdt_softc_t *sc = geminiwdt_sc;
89 uint32_t r;
90
91 /*
92 * Disable the watchdog timer
93 */
94 if (sc->sc_armed)
95 geminiwdt_stop();
96
97 /*
98 * Set WdLoad register
99 */
100 r = (sc->sc_smw.smw_period != 0) ?
101 WATCHDOG_COUNT(sc->sc_smw.smw_period) : WDT_WDLOAD_DFLT;
102 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDLOAD, r);
103
104 /*
105 * feed MAGIC treat to dog
106 */
107 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
108 GEMINI_WDT_WDRESTART, WDT_WDRESTART_MAGIC);
109
110 /*
111 * Select PCLK clock source
112 */
113 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR);
114 r &= ~WDCR_CLKSRC_5MHZ;
115 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r);
116
117 /*
118 * Enable the timer
119 */
120 if (sc->sc_armed)
121 geminiwdt_start();
122 }
123
124 void
125 geminiwdt_set_timeout(unsigned int period)
126 {
127 geminiwdt_softc_t *sc = geminiwdt_sc;
128 int s = splhigh();
129
130 if (period != sc->sc_smw.smw_period) {
131 sc->sc_smw.smw_period = period;
132 geminiwdt_do_set_timeout();
133 }
134
135 splx(s);
136 }
137
138 int
139 geminiwdt_enable(int enable)
140 {
141 geminiwdt_softc_t *sc = geminiwdt_sc;
142 int s;
143 int prev_state = geminiwdt_sc->sc_armed;
144
145 /* Normalize the int to a boolean so we can compare values directly.
146 */
147 enable = !!enable;
148
149 s = splhigh();
150
151 if (enable != sc->sc_armed) {
152 if (enable) {
153 /* Make sure that the watchdog timeout is up to date.
154 */
155 geminiwdt_do_set_timeout();
156 geminiwdt_start();
157 } else {
158 geminiwdt_stop();
159 }
160 sc->sc_armed = enable;
161 }
162
163 splx(s);
164 return prev_state;
165 }
166
167 int
168 geminiwdt_setmode(struct sysmon_wdog *smw)
169 {
170 geminiwdt_softc_t *sc = smw->smw_cookie;
171 int error = 0;
172
173 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
174 geminiwdt_enable(0);
175 } else {
176 if (smw->smw_period == WDOG_PERIOD_DEFAULT)
177 sc->sc_smw.smw_period = WDT_WDLOAD_DFLT;
178 else
179 sc->sc_smw.smw_period = smw->smw_period;
180 geminiwdt_set_timeout(sc->sc_smw.smw_period);
181 geminiwdt_enable(1);
182 }
183 return error;
184 }
185
186 int
187 geminiwdt_tickle(struct sysmon_wdog *smw)
188 {
189 geminiwdt_softc_t *sc = geminiwdt_sc;
190 int s = splhigh();
191
192 /*
193 * feed the dog a MAGIC treat
194 */
195 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
196 GEMINI_WDT_WDRESTART, WDT_WDRESTART_MAGIC);
197
198 splx(s);
199 return 0;
200 }
201
202 void
203 geminiwdt_reboot(void)
204 {
205 int s = splhigh();
206
207 geminiwdt_set_timeout(30);
208 geminiwdt_start();
209 delay(100);
210 splx(s);
211 }
212