xref: /netbsd-src/sys/arch/arm/gemini/gemini_wdt.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: gemini_wdt.c,v 1.3 2011/07/01 19:32:28 dyoung 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 <sys/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