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