1 /* $NetBSD: gemini_wdt.c,v 1.4 2019/01/08 19:41:10 jdolecek 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 <sys/bus.h>
45 #include <dev/sysmon/sysmonvar.h>
46
47 #include <arm/gemini/gemini_wdtvar.h>
48 #include <arm/gemini/gemini_reg.h>
49
50 geminiwdt_softc_t *geminiwdt_sc;
51
52 #define WATCHDOG_COUNT(nsec) \
53 (GEMINI_WDT_CLOCK_FREQ * (nsec))
54
55
56 static void
geminiwdt_start(void)57 geminiwdt_start(void)
58 {
59 geminiwdt_softc_t *sc = geminiwdt_sc;
60 uint32_t r;
61
62 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR);
63 r |= (WDT_WDCR_RESET_ENB
64 |WDT_WDCR_ENB);
65 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r);
66 }
67
68 static void
geminiwdt_stop(void)69 geminiwdt_stop(void)
70 {
71 geminiwdt_softc_t *sc = geminiwdt_sc;
72 uint32_t r;
73
74 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR);
75 r &= ~(WDT_WDCR_EXTSIG_ENB
76 |WDT_WDCR_RESET_ENB
77 |WDT_WDCR_INTR_ENB
78 |WDT_WDCR_ENB);
79 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r);
80 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
81 GEMINI_WDT_WDCLEAR, WDT_WDCLEAR_CLEAR);
82 }
83
84 static void
geminiwdt_do_set_timeout(void)85 geminiwdt_do_set_timeout(void)
86 {
87 geminiwdt_softc_t *sc = geminiwdt_sc;
88 uint32_t r;
89
90 /*
91 * Disable the watchdog timer
92 */
93 if (sc->sc_armed)
94 geminiwdt_stop();
95
96 /*
97 * Set WdLoad register
98 */
99 r = (sc->sc_smw.smw_period != 0) ?
100 WATCHDOG_COUNT(sc->sc_smw.smw_period) : WDT_WDLOAD_DFLT;
101 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDLOAD, r);
102
103 /*
104 * feed MAGIC treat to dog
105 */
106 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
107 GEMINI_WDT_WDRESTART, WDT_WDRESTART_MAGIC);
108
109 /*
110 * Select PCLK clock source
111 */
112 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR);
113 r &= ~WDCR_CLKSRC_5MHZ;
114 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GEMINI_WDT_WDCR, r);
115
116 /*
117 * Enable the timer
118 */
119 if (sc->sc_armed)
120 geminiwdt_start();
121 }
122
123 void
geminiwdt_set_timeout(unsigned int period)124 geminiwdt_set_timeout(unsigned int period)
125 {
126 geminiwdt_softc_t *sc = geminiwdt_sc;
127 int s = splhigh();
128
129 if (period != sc->sc_smw.smw_period) {
130 sc->sc_smw.smw_period = period;
131 geminiwdt_do_set_timeout();
132 }
133
134 splx(s);
135 }
136
137 int
geminiwdt_enable(int enable)138 geminiwdt_enable(int enable)
139 {
140 geminiwdt_softc_t *sc = geminiwdt_sc;
141 int s;
142 int prev_state = geminiwdt_sc->sc_armed;
143
144 /* Normalize the int to a boolean so we can compare values directly.
145 */
146 enable = !!enable;
147
148 s = splhigh();
149
150 if (enable != sc->sc_armed) {
151 if (enable) {
152 /* Make sure that the watchdog timeout is up to date.
153 */
154 geminiwdt_do_set_timeout();
155 geminiwdt_start();
156 } else {
157 geminiwdt_stop();
158 }
159 sc->sc_armed = enable;
160 }
161
162 splx(s);
163 return prev_state;
164 }
165
166 int
geminiwdt_setmode(struct sysmon_wdog * smw)167 geminiwdt_setmode(struct sysmon_wdog *smw)
168 {
169 geminiwdt_softc_t *sc = smw->smw_cookie;
170 int error = 0;
171
172 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
173 geminiwdt_enable(0);
174 } else {
175 if (smw->smw_period == WDOG_PERIOD_DEFAULT)
176 sc->sc_smw.smw_period = WDT_WDLOAD_DFLT;
177 else
178 sc->sc_smw.smw_period = smw->smw_period;
179 geminiwdt_set_timeout(sc->sc_smw.smw_period);
180 geminiwdt_enable(1);
181 }
182 return error;
183 }
184
185 int
geminiwdt_tickle(struct sysmon_wdog * smw)186 geminiwdt_tickle(struct sysmon_wdog *smw)
187 {
188 geminiwdt_softc_t *sc = geminiwdt_sc;
189 int s = splhigh();
190
191 /*
192 * feed the dog a MAGIC treat
193 */
194 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
195 GEMINI_WDT_WDRESTART, WDT_WDRESTART_MAGIC);
196
197 splx(s);
198 return 0;
199 }
200