xref: /openbsd/sys/arch/armv7/omap/omdog.c (revision 9fdf0c62)
1 /*	$OpenBSD: omdog.c,v 1.10 2021/10/24 17:52:27 mpi 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/device.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/fdt.h>
28 
29 #define WIDR		0x00			/* Identification Register */
30 #define WCLR		0x24			/* Control Register */
31 #define  WCLR_PRE		(1 << 5)
32 #define  WCLR_PTV		(0 << 2)
33 #define WCRR		0x28			/* Counter Register */
34 #define WLDR		0x2c			/* Load Register */
35 #define WTGR		0x30			/* Trigger Register */
36 #define WWPS		0x34			/* Write Posting Bits Reg. */
37 #define  WWPS_WSPR		(1 << 4)
38 #define  WWPS_WTGR		(1 << 3)
39 #define  WWPS_WLDR		(1 << 2)
40 #define  WWPS_WCRR		(1 << 1)
41 #define  WWPS_WCLR		(1 << 0)
42 #define WSPR		0x48			/* Start/Stop Register */
43 
44 #define OMDOG_VAL(secs)	(0xffffffff - ((secs) * (32768 / (1 << 0))) + 1)
45 
46 
47 struct omdog_softc {
48 	struct device		sc_dev;
49 	bus_space_tag_t		sc_iot;
50 	bus_space_handle_t	sc_ioh;
51 
52 	int			sc_period;
53 };
54 
55 struct omdog_softc *omdog_sc;
56 
57 int	omdog_match(struct device *, void *, void *);
58 void	omdog_attach(struct device *, struct device *, void *);
59 int	omdog_activate(struct device *, int);
60 void	omdog_start(struct omdog_softc *);
61 void	omdog_stop(struct omdog_softc *);
62 void	omdog_sync(struct omdog_softc *);
63 int	omdog_cb(void *, int);
64 void	omdog_reset(void);
65 
66 const struct cfattach	omdog_ca = {
67 	sizeof (struct omdog_softc), omdog_match, omdog_attach, NULL,
68 	omdog_activate
69 };
70 
71 struct cfdriver omdog_cd = {
72 	NULL, "omdog", DV_DULL
73 };
74 
75 int
omdog_match(struct device * parent,void * match,void * aux)76 omdog_match(struct device *parent, void *match, void *aux)
77 {
78 	struct fdt_attach_args *faa = aux;
79 
80 	return OF_is_compatible(faa->fa_node, "ti,omap3-wdt");
81 }
82 
83 void
omdog_attach(struct device * parent,struct device * self,void * aux)84 omdog_attach(struct device *parent, struct device *self, void *aux)
85 {
86 	struct fdt_attach_args *faa = aux;
87 	struct omdog_softc *sc = (struct omdog_softc *) self;
88 	u_int32_t rev;
89 
90 	if (faa->fa_nreg < 1)
91 		return;
92 
93 	sc->sc_iot = faa->fa_iot;
94 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
95 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
96 		panic("%s: bus_space_map failed!", __func__);
97 
98 	rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR);
99 
100 	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
101 
102 	omdog_stop(sc);
103 
104 	/* only register one watchdog, OMAP4 has two */
105 	if (omdog_sc != NULL)
106 		return;
107 
108 	omdog_sc = sc;
109 
110 #ifndef SMALL_KERNEL
111 	wdog_register(omdog_cb, sc);
112 #endif
113 }
114 
115 int
omdog_activate(struct device * self,int act)116 omdog_activate(struct device *self, int act)
117 {
118 	switch (act) {
119 	case DVACT_POWERDOWN:
120 #ifndef SMALL_KERNEL
121 		wdog_shutdown(self);
122 #endif
123 		break;
124 	}
125 
126 	return (0);
127 }
128 
129 void
omdog_start(struct omdog_softc * sc)130 omdog_start(struct omdog_softc *sc)
131 {
132 	/* Write the enable sequence data BBBBh followed by 4444h */
133 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb);
134 	omdog_sync(sc);
135 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444);
136 	omdog_sync(sc);
137 }
138 
139 void
omdog_stop(struct omdog_softc * sc)140 omdog_stop(struct omdog_softc *sc)
141 {
142 	/* Write the disable sequence data AAAAh followed by 5555h */
143 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa);
144 	omdog_sync(sc);
145 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555);
146 	omdog_sync(sc);
147 }
148 
149 void
omdog_sync(struct omdog_softc * sc)150 omdog_sync(struct omdog_softc *sc)
151 {
152 	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) &
153 	    (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR))
154 		delay(10);
155 }
156 
157 int
omdog_cb(void * self,int period)158 omdog_cb(void *self, int period)
159 {
160 	struct omdog_softc *sc = self;
161 
162 	if (sc->sc_period != 0 && sc->sc_period != period)
163 		omdog_stop(sc);
164 
165 	if (period != 0) {
166 		if (sc->sc_period != period) {
167 			/* Set the prescaler */
168 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR,
169 			    (WCLR_PRE|WCLR_PTV));
170 
171 			/* Set the reload counter */
172 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR,
173 			    OMDOG_VAL(period));
174 		}
175 
176 		omdog_sync(sc);
177 
178 		/* Trigger the reload */
179 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR,
180 		    ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR));
181 
182 		if (sc->sc_period != period)
183 			omdog_start(sc);
184 	}
185 
186 	sc->sc_period = period;
187 
188 	return (period);
189 }
190 
191 void
omdog_reset(void)192 omdog_reset(void)
193 {
194 	if (omdog_sc == NULL)
195 		return;
196 
197 	if (omdog_sc->sc_period != 0)
198 		omdog_stop(omdog_sc);
199 
200 	bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR,
201 	    0xffffff80);
202 
203 	omdog_start(omdog_sc);
204 
205 	delay(100000);
206 }
207