xref: /openbsd/sys/arch/armv7/omap/omdog.c (revision ee4ffdb6)
1 /*	$OpenBSD: omdog.c,v 1.8 2017/11/27 06:29:41 jsg Exp $	*/
2 /*
3  * Copyright (c) 2013 Federico G. Schwindt <fgsch@openbsd.org>
4  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/queue.h>
22 #include <sys/malloc.h>
23 #include <sys/device.h>
24 #include <sys/evcount.h>
25 #include <sys/socket.h>
26 #include <sys/timeout.h>
27 
28 #include <machine/intr.h>
29 #include <machine/bus.h>
30 #include <machine/fdt.h>
31 
32 #include <dev/ofw/openfirm.h>
33 #include <dev/ofw/fdt.h>
34 
35 #include <armv7/armv7/armv7var.h>
36 
37 #define WIDR		0x00			/* Identification Register */
38 #define WCLR		0x24			/* Control Register */
39 #define  WCLR_PRE		(1 << 5)
40 #define  WCLR_PTV		(0 << 2)
41 #define WCRR		0x28			/* Counter Register */
42 #define WLDR		0x2c			/* Load Register */
43 #define WTGR		0x30			/* Trigger Register */
44 #define WWPS		0x34			/* Write Posting Bits Reg. */
45 #define  WWPS_WSPR		(1 << 4)
46 #define  WWPS_WTGR		(1 << 3)
47 #define  WWPS_WLDR		(1 << 2)
48 #define  WWPS_WCRR		(1 << 1)
49 #define  WWPS_WCLR		(1 << 0)
50 #define WSPR		0x48			/* Start/Stop Register */
51 
52 #define OMDOG_VAL(secs)	(0xffffffff - ((secs) * (32768 / (1 << 0))) + 1)
53 
54 
55 struct omdog_softc {
56 	struct device		sc_dev;
57 	bus_space_tag_t		sc_iot;
58 	bus_space_handle_t	sc_ioh;
59 
60 	int			sc_period;
61 };
62 
63 struct omdog_softc *omdog_sc;
64 
65 int	omdog_match(struct device *, void *, void *);
66 void	omdog_attach(struct device *, struct device *, void *);
67 int	omdog_activate(struct device *, int);
68 void	omdog_start(struct omdog_softc *);
69 void	omdog_stop(struct omdog_softc *);
70 void	omdog_sync(struct omdog_softc *);
71 int	omdog_cb(void *, int);
72 void	omdog_reset(void);
73 
74 struct cfattach	omdog_ca = {
75 	sizeof (struct omdog_softc), omdog_match, omdog_attach, NULL,
76 	omdog_activate
77 };
78 
79 struct cfdriver omdog_cd = {
80 	NULL, "omdog", DV_DULL
81 };
82 
83 int
84 omdog_match(struct device *parent, void *match, void *aux)
85 {
86 	struct fdt_attach_args *faa = aux;
87 
88 	return OF_is_compatible(faa->fa_node, "ti,omap3-wdt");
89 }
90 
91 void
92 omdog_attach(struct device *parent, struct device *self, void *aux)
93 {
94 	struct fdt_attach_args *faa = aux;
95 	struct omdog_softc *sc = (struct omdog_softc *) self;
96 	u_int32_t rev;
97 
98 	if (faa->fa_nreg < 1)
99 		return;
100 
101 	sc->sc_iot = faa->fa_iot;
102 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
103 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
104 		panic("%s: bus_space_map failed!", __func__);
105 
106 	rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR);
107 
108 	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
109 
110 	omdog_stop(sc);
111 
112 	/* only register one watchdog, OMAP4 has two */
113 	if (omdog_sc != NULL)
114 		return;
115 
116 	omdog_sc = sc;
117 
118 #ifndef SMALL_KERNEL
119 	wdog_register(omdog_cb, sc);
120 #endif
121 }
122 
123 int
124 omdog_activate(struct device *self, int act)
125 {
126 	switch (act) {
127 	case DVACT_POWERDOWN:
128 #ifndef SMALL_KERNEL
129 		wdog_shutdown(self);
130 #endif
131 		break;
132 	}
133 
134 	return (0);
135 }
136 
137 void
138 omdog_start(struct omdog_softc *sc)
139 {
140 	/* Write the enable sequence data BBBBh followed by 4444h */
141 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb);
142 	omdog_sync(sc);
143 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444);
144 	omdog_sync(sc);
145 }
146 
147 void
148 omdog_stop(struct omdog_softc *sc)
149 {
150 	/* Write the disable sequence data AAAAh followed by 5555h */
151 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa);
152 	omdog_sync(sc);
153 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555);
154 	omdog_sync(sc);
155 }
156 
157 void
158 omdog_sync(struct omdog_softc *sc)
159 {
160 	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) &
161 	    (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR))
162 		delay(10);
163 }
164 
165 int
166 omdog_cb(void *self, int period)
167 {
168 	struct omdog_softc *sc = self;
169 
170 	if (sc->sc_period != 0 && sc->sc_period != period)
171 		omdog_stop(sc);
172 
173 	if (period != 0) {
174 		if (sc->sc_period != period) {
175 			/* Set the prescaler */
176 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR,
177 			    (WCLR_PRE|WCLR_PTV));
178 
179 			/* Set the reload counter */
180 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR,
181 			    OMDOG_VAL(period));
182 		}
183 
184 		omdog_sync(sc);
185 
186 		/* Trigger the reload */
187 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR,
188 		    ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR));
189 
190 		if (sc->sc_period != period)
191 			omdog_start(sc);
192 	}
193 
194 	sc->sc_period = period;
195 
196 	return (period);
197 }
198 
199 void
200 omdog_reset(void)
201 {
202 	if (omdog_sc == NULL)
203 		return;
204 
205 	if (omdog_sc->sc_period != 0)
206 		omdog_stop(omdog_sc);
207 
208 	bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR,
209 	    0xffffff80);
210 
211 	omdog_start(omdog_sc);
212 
213 	delay(100000);
214 }
215