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