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