1*9fdf0c62Smpi /* $OpenBSD: omdog.c,v 1.10 2021/10/24 17:52:27 mpi Exp $ */
28eda2d14Spatrick /*
3e062047fSfgsch * Copyright (c) 2013 Federico G. Schwindt <fgsch@openbsd.org>
48eda2d14Spatrick * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
58eda2d14Spatrick *
68eda2d14Spatrick * Permission to use, copy, modify, and distribute this software for any
78eda2d14Spatrick * purpose with or without fee is hereby granted, provided that the above
88eda2d14Spatrick * copyright notice and this permission notice appear in all copies.
98eda2d14Spatrick *
108eda2d14Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
118eda2d14Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
128eda2d14Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
138eda2d14Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
148eda2d14Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158eda2d14Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
168eda2d14Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
178eda2d14Spatrick */
188eda2d14Spatrick
198eda2d14Spatrick #include <sys/param.h>
208eda2d14Spatrick #include <sys/systm.h>
218eda2d14Spatrick #include <sys/device.h>
227f0748ebSjsg
238eda2d14Spatrick #include <machine/bus.h>
247f0748ebSjsg #include <machine/fdt.h>
257f0748ebSjsg
267f0748ebSjsg #include <dev/ofw/openfirm.h>
27ac7c670eSpatrick #include <dev/ofw/fdt.h>
287f0748ebSjsg
29e062047fSfgsch #define WIDR 0x00 /* Identification Register */
30e062047fSfgsch #define WCLR 0x24 /* Control Register */
31e062047fSfgsch #define WCLR_PRE (1 << 5)
32e062047fSfgsch #define WCLR_PTV (0 << 2)
33e062047fSfgsch #define WCRR 0x28 /* Counter Register */
34e062047fSfgsch #define WLDR 0x2c /* Load Register */
35e062047fSfgsch #define WTGR 0x30 /* Trigger Register */
36e062047fSfgsch #define WWPS 0x34 /* Write Posting Bits Reg. */
37e062047fSfgsch #define WWPS_WSPR (1 << 4)
38e062047fSfgsch #define WWPS_WTGR (1 << 3)
39e062047fSfgsch #define WWPS_WLDR (1 << 2)
40e062047fSfgsch #define WWPS_WCRR (1 << 1)
41e062047fSfgsch #define WWPS_WCLR (1 << 0)
42e062047fSfgsch #define WSPR 0x48 /* Start/Stop Register */
43e062047fSfgsch
44e062047fSfgsch #define OMDOG_VAL(secs) (0xffffffff - ((secs) * (32768 / (1 << 0))) + 1)
458eda2d14Spatrick
468eda2d14Spatrick
478eda2d14Spatrick struct omdog_softc {
488eda2d14Spatrick struct device sc_dev;
498eda2d14Spatrick bus_space_tag_t sc_iot;
508eda2d14Spatrick bus_space_handle_t sc_ioh;
51e062047fSfgsch
52e062047fSfgsch int sc_period;
538eda2d14Spatrick };
548eda2d14Spatrick
558eda2d14Spatrick struct omdog_softc *omdog_sc;
568eda2d14Spatrick
577f0748ebSjsg int omdog_match(struct device *, void *, void *);
58e062047fSfgsch void omdog_attach(struct device *, struct device *, void *);
593b06f262Smikeb int omdog_activate(struct device *, int);
60e062047fSfgsch void omdog_start(struct omdog_softc *);
61e062047fSfgsch void omdog_stop(struct omdog_softc *);
62e062047fSfgsch void omdog_sync(struct omdog_softc *);
63e062047fSfgsch int omdog_cb(void *, int);
64e062047fSfgsch void omdog_reset(void);
658eda2d14Spatrick
66*9fdf0c62Smpi const struct cfattach omdog_ca = {
677f0748ebSjsg sizeof (struct omdog_softc), omdog_match, omdog_attach, NULL,
687f0748ebSjsg omdog_activate
698eda2d14Spatrick };
708eda2d14Spatrick
718eda2d14Spatrick struct cfdriver omdog_cd = {
728eda2d14Spatrick NULL, "omdog", DV_DULL
738eda2d14Spatrick };
748eda2d14Spatrick
757f0748ebSjsg int
omdog_match(struct device * parent,void * match,void * aux)767f0748ebSjsg omdog_match(struct device *parent, void *match, void *aux)
778eda2d14Spatrick {
787f0748ebSjsg struct fdt_attach_args *faa = aux;
797f0748ebSjsg
807f0748ebSjsg return OF_is_compatible(faa->fa_node, "ti,omap3-wdt");
817f0748ebSjsg }
827f0748ebSjsg
837f0748ebSjsg void
omdog_attach(struct device * parent,struct device * self,void * aux)847f0748ebSjsg omdog_attach(struct device *parent, struct device *self, void *aux)
857f0748ebSjsg {
867f0748ebSjsg struct fdt_attach_args *faa = aux;
878eda2d14Spatrick struct omdog_softc *sc = (struct omdog_softc *) self;
888eda2d14Spatrick u_int32_t rev;
898eda2d14Spatrick
90ac7c670eSpatrick if (faa->fa_nreg < 1)
917f0748ebSjsg return;
927f0748ebSjsg
937f0748ebSjsg sc->sc_iot = faa->fa_iot;
94ac7c670eSpatrick if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
95ac7c670eSpatrick faa->fa_reg[0].size, 0, &sc->sc_ioh))
96e062047fSfgsch panic("%s: bus_space_map failed!", __func__);
978eda2d14Spatrick
988eda2d14Spatrick rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR);
998eda2d14Spatrick
1008eda2d14Spatrick printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
101e062047fSfgsch
102e062047fSfgsch omdog_stop(sc);
103e062047fSfgsch
104ac5fc12cSjsg /* only register one watchdog, OMAP4 has two */
105ac5fc12cSjsg if (omdog_sc != NULL)
106ac5fc12cSjsg return;
107ac5fc12cSjsg
108ac5fc12cSjsg omdog_sc = sc;
109ac5fc12cSjsg
11020598bedSjsg #ifndef SMALL_KERNEL
111e062047fSfgsch wdog_register(omdog_cb, sc);
11220598bedSjsg #endif
1138eda2d14Spatrick }
1148eda2d14Spatrick
1153b06f262Smikeb int
omdog_activate(struct device * self,int act)1163b06f262Smikeb omdog_activate(struct device *self, int act)
1173b06f262Smikeb {
1183b06f262Smikeb switch (act) {
1193b06f262Smikeb case DVACT_POWERDOWN:
1203b06f262Smikeb #ifndef SMALL_KERNEL
1213b06f262Smikeb wdog_shutdown(self);
1223b06f262Smikeb #endif
1233b06f262Smikeb break;
1243b06f262Smikeb }
1253b06f262Smikeb
1263b06f262Smikeb return (0);
1273b06f262Smikeb }
1283b06f262Smikeb
1298eda2d14Spatrick void
omdog_start(struct omdog_softc * sc)130e062047fSfgsch omdog_start(struct omdog_softc *sc)
1318eda2d14Spatrick {
132e062047fSfgsch /* Write the enable sequence data BBBBh followed by 4444h */
133e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb);
134e062047fSfgsch omdog_sync(sc);
135e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444);
136e062047fSfgsch omdog_sync(sc);
1378eda2d14Spatrick }
1388eda2d14Spatrick
139e062047fSfgsch void
omdog_stop(struct omdog_softc * sc)140e062047fSfgsch omdog_stop(struct omdog_softc *sc)
141e062047fSfgsch {
142e062047fSfgsch /* Write the disable sequence data AAAAh followed by 5555h */
143e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa);
144e062047fSfgsch omdog_sync(sc);
145e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555);
146e062047fSfgsch omdog_sync(sc);
147e062047fSfgsch }
1488eda2d14Spatrick
1498eda2d14Spatrick void
omdog_sync(struct omdog_softc * sc)150e062047fSfgsch omdog_sync(struct omdog_softc *sc)
151e062047fSfgsch {
152e062047fSfgsch while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) &
153e062047fSfgsch (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR))
154e062047fSfgsch delay(10);
155e062047fSfgsch }
156e062047fSfgsch
157e062047fSfgsch int
omdog_cb(void * self,int period)158e062047fSfgsch omdog_cb(void *self, int period)
159e062047fSfgsch {
160e062047fSfgsch struct omdog_softc *sc = self;
161e062047fSfgsch
162e062047fSfgsch if (sc->sc_period != 0 && sc->sc_period != period)
163e062047fSfgsch omdog_stop(sc);
164e062047fSfgsch
165e062047fSfgsch if (period != 0) {
166e062047fSfgsch if (sc->sc_period != period) {
167e062047fSfgsch /* Set the prescaler */
168e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR,
169e062047fSfgsch (WCLR_PRE|WCLR_PTV));
170e062047fSfgsch
171e062047fSfgsch /* Set the reload counter */
172e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR,
173e062047fSfgsch OMDOG_VAL(period));
174e062047fSfgsch }
175e062047fSfgsch
176e062047fSfgsch omdog_sync(sc);
177e062047fSfgsch
178e062047fSfgsch /* Trigger the reload */
179e062047fSfgsch bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR,
180e062047fSfgsch ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR));
181e062047fSfgsch
182e062047fSfgsch if (sc->sc_period != period)
183e062047fSfgsch omdog_start(sc);
184e062047fSfgsch }
185e062047fSfgsch
186e062047fSfgsch sc->sc_period = period;
187e062047fSfgsch
188e062047fSfgsch return (period);
189e062047fSfgsch }
190e062047fSfgsch
191e062047fSfgsch void
omdog_reset(void)192e062047fSfgsch omdog_reset(void)
1938eda2d14Spatrick {
1948eda2d14Spatrick if (omdog_sc == NULL)
1958eda2d14Spatrick return;
1968eda2d14Spatrick
197e062047fSfgsch if (omdog_sc->sc_period != 0)
198e062047fSfgsch omdog_stop(omdog_sc);
1998eda2d14Spatrick
200e062047fSfgsch bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR,
201e062047fSfgsch 0xffffff80);
202e062047fSfgsch
203e062047fSfgsch omdog_start(omdog_sc);
204e062047fSfgsch
2058eda2d14Spatrick delay(100000);
2068eda2d14Spatrick }
207