1 /* $OpenBSD: omdog.c,v 1.3 2013/11/06 19:03:07 syl 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 #include <machine/intr.h> 28 #include <machine/bus.h> 29 #include <armv7/armv7/armv7var.h> 30 31 #define WIDR 0x00 /* Identification Register */ 32 #define WCLR 0x24 /* Control Register */ 33 #define WCLR_PRE (1 << 5) 34 #define WCLR_PTV (0 << 2) 35 #define WCRR 0x28 /* Counter Register */ 36 #define WLDR 0x2c /* Load Register */ 37 #define WTGR 0x30 /* Trigger Register */ 38 #define WWPS 0x34 /* Write Posting Bits Reg. */ 39 #define WWPS_WSPR (1 << 4) 40 #define WWPS_WTGR (1 << 3) 41 #define WWPS_WLDR (1 << 2) 42 #define WWPS_WCRR (1 << 1) 43 #define WWPS_WCLR (1 << 0) 44 #define WSPR 0x48 /* Start/Stop Register */ 45 46 #define OMDOG_VAL(secs) (0xffffffff - ((secs) * (32768 / (1 << 0))) + 1) 47 48 49 struct omdog_softc { 50 struct device sc_dev; 51 bus_space_tag_t sc_iot; 52 bus_space_handle_t sc_ioh; 53 54 int sc_period; 55 }; 56 57 struct omdog_softc *omdog_sc; 58 59 void omdog_attach(struct device *, struct device *, void *); 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 struct cfattach omdog_ca = { 67 sizeof (struct omdog_softc), NULL, omdog_attach 68 }; 69 70 struct cfdriver omdog_cd = { 71 NULL, "omdog", DV_DULL 72 }; 73 74 void 75 omdog_attach(struct device *parent, struct device *self, void *args) 76 { 77 struct armv7_attach_args *aa = args; 78 struct omdog_softc *sc = (struct omdog_softc *) self; 79 u_int32_t rev; 80 81 sc->sc_iot = aa->aa_iot; 82 if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, 83 aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) 84 panic("%s: bus_space_map failed!", __func__); 85 86 rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR); 87 88 printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); 89 omdog_sc = sc; 90 91 omdog_stop(sc); 92 93 wdog_register(omdog_cb, sc); 94 } 95 96 void 97 omdog_start(struct omdog_softc *sc) 98 { 99 /* Write the enable sequence data BBBBh followed by 4444h */ 100 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb); 101 omdog_sync(sc); 102 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444); 103 omdog_sync(sc); 104 } 105 106 void 107 omdog_stop(struct omdog_softc *sc) 108 { 109 /* Write the disable sequence data AAAAh followed by 5555h */ 110 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa); 111 omdog_sync(sc); 112 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555); 113 omdog_sync(sc); 114 } 115 116 void 117 omdog_sync(struct omdog_softc *sc) 118 { 119 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) & 120 (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR)) 121 delay(10); 122 } 123 124 int 125 omdog_cb(void *self, int period) 126 { 127 struct omdog_softc *sc = self; 128 129 if (sc->sc_period != 0 && sc->sc_period != period) 130 omdog_stop(sc); 131 132 if (period != 0) { 133 if (sc->sc_period != period) { 134 /* Set the prescaler */ 135 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR, 136 (WCLR_PRE|WCLR_PTV)); 137 138 /* Set the reload counter */ 139 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR, 140 OMDOG_VAL(period)); 141 } 142 143 omdog_sync(sc); 144 145 /* Trigger the reload */ 146 bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR, 147 ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR)); 148 149 if (sc->sc_period != period) 150 omdog_start(sc); 151 } 152 153 sc->sc_period = period; 154 155 return (period); 156 } 157 158 void 159 omdog_reset(void) 160 { 161 if (omdog_sc == NULL) 162 return; 163 164 if (omdog_sc->sc_period != 0) 165 omdog_stop(omdog_sc); 166 167 bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR, 168 0xffffff80); 169 170 omdog_start(omdog_sc); 171 172 delay(100000); 173 } 174