xref: /openbsd-src/sys/arch/armv7/omap/omdog.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: omdog.c,v 1.7 2016/07/27 11:45:02 patrick 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 	omdog_sc = sc;
110 
111 	omdog_stop(sc);
112 
113 #ifndef SMALL_KERNEL
114 	wdog_register(omdog_cb, sc);
115 #endif
116 }
117 
118 int
119 omdog_activate(struct device *self, int act)
120 {
121 	switch (act) {
122 	case DVACT_POWERDOWN:
123 #ifndef SMALL_KERNEL
124 		wdog_shutdown(self);
125 #endif
126 		break;
127 	}
128 
129 	return (0);
130 }
131 
132 void
133 omdog_start(struct omdog_softc *sc)
134 {
135 	/* Write the enable sequence data BBBBh followed by 4444h */
136 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb);
137 	omdog_sync(sc);
138 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444);
139 	omdog_sync(sc);
140 }
141 
142 void
143 omdog_stop(struct omdog_softc *sc)
144 {
145 	/* Write the disable sequence data AAAAh followed by 5555h */
146 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa);
147 	omdog_sync(sc);
148 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555);
149 	omdog_sync(sc);
150 }
151 
152 void
153 omdog_sync(struct omdog_softc *sc)
154 {
155 	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) &
156 	    (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR))
157 		delay(10);
158 }
159 
160 int
161 omdog_cb(void *self, int period)
162 {
163 	struct omdog_softc *sc = self;
164 
165 	if (sc->sc_period != 0 && sc->sc_period != period)
166 		omdog_stop(sc);
167 
168 	if (period != 0) {
169 		if (sc->sc_period != period) {
170 			/* Set the prescaler */
171 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR,
172 			    (WCLR_PRE|WCLR_PTV));
173 
174 			/* Set the reload counter */
175 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR,
176 			    OMDOG_VAL(period));
177 		}
178 
179 		omdog_sync(sc);
180 
181 		/* Trigger the reload */
182 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR,
183 		    ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR));
184 
185 		if (sc->sc_period != period)
186 			omdog_start(sc);
187 	}
188 
189 	sc->sc_period = period;
190 
191 	return (period);
192 }
193 
194 void
195 omdog_reset(void)
196 {
197 	if (omdog_sc == NULL)
198 		return;
199 
200 	if (omdog_sc->sc_period != 0)
201 		omdog_stop(omdog_sc);
202 
203 	bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR,
204 	    0xffffff80);
205 
206 	omdog_start(omdog_sc);
207 
208 	delay(100000);
209 }
210