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 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 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 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 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 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 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 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 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