1 /* $OpenBSD: bcm2835_dog.c,v 1.3 2021/10/24 17:52:26 mpi Exp $ */ 2 /* 3 * Copyright (c) 2015 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/queue.h> 21 #include <sys/malloc.h> 22 #include <sys/device.h> 23 #include <sys/evcount.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/fdt.h> 29 30 extern void (*cpuresetfn)(void); 31 32 /* registers */ 33 #define PM_RSTC 0x1c 34 #define PM_RSTS 0x20 35 #define PM_WDOG 0x24 36 37 /* bits and bytes */ 38 #define PM_PASSWORD 0x5a000000 39 #define PM_RSTC_CONFIGMASK 0x00000030 40 #define PM_RSTC_FULL_RESET 0x00000020 41 #define PM_RSTC_RESET 0x00000102 42 #define PM_WDOG_TIMEMASK 0x000fffff 43 44 #define HREAD4(sc, reg) \ 45 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 46 #define HWRITE4(sc, reg, val) \ 47 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 48 #define HSET4(sc, reg, bits) \ 49 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 50 #define HCLR4(sc, reg, bits) \ 51 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 52 53 struct bcmdog_softc { 54 struct device sc_dev; 55 bus_space_tag_t sc_iot; 56 bus_space_handle_t sc_ioh; 57 }; 58 59 struct bcmdog_softc *bcmdog_sc; 60 61 int bcmdog_match(struct device *, void *, void *); 62 void bcmdog_attach(struct device *, struct device *, void *); 63 int bcmdog_activate(struct device *, int); 64 int bcmdog_wdog_cb(void *, int); 65 void bcmdog_wdog_reset(void); 66 67 const struct cfattach bcmdog_ca = { 68 sizeof (struct bcmdog_softc), bcmdog_match, bcmdog_attach, NULL, 69 bcmdog_activate 70 }; 71 72 struct cfdriver bcmdog_cd = { 73 NULL, "bcmdog", DV_DULL 74 }; 75 76 int 77 bcmdog_match(struct device *parent, void *cfdata, void *aux) 78 { 79 struct fdt_attach_args *fa = aux; 80 81 return OF_is_compatible(fa->fa_node, "brcm,bcm2835-pm-wdt"); 82 } 83 84 void 85 bcmdog_attach(struct device *parent, struct device *self, void *aux) 86 { 87 struct bcmdog_softc *sc = (struct bcmdog_softc *)self; 88 struct fdt_attach_args *fa = aux; 89 90 sc->sc_iot = fa->fa_iot; 91 92 if (bus_space_map(sc->sc_iot, fa->fa_reg[0].addr, 93 fa->fa_reg[0].size, 0, &sc->sc_ioh)) 94 panic("%s: bus_space_map failed!", __func__); 95 96 printf("\n"); 97 98 bcmdog_sc = sc; 99 cpuresetfn = bcmdog_wdog_reset; 100 101 #ifndef SMALL_KERNEL 102 wdog_register(bcmdog_wdog_cb, sc); 103 #endif 104 } 105 106 int 107 bcmdog_activate(struct device *self, int act) 108 { 109 switch (act) { 110 case DVACT_POWERDOWN: 111 #ifndef SMALL_KERNEL 112 wdog_shutdown(self); 113 #endif 114 break; 115 } 116 117 return 0; 118 } 119 120 void 121 bcmdog_wdog_set(struct bcmdog_softc *sc, uint32_t period) 122 { 123 uint32_t rstc, wdog; 124 125 if (period == 0) { 126 HWRITE4(sc, PM_RSTC, PM_RSTC_RESET | PM_PASSWORD); 127 return; 128 } 129 130 rstc = HREAD4(sc, PM_RSTC) & PM_RSTC_CONFIGMASK; 131 rstc |= PM_RSTC_FULL_RESET; 132 rstc |= PM_PASSWORD; 133 134 wdog = period & PM_WDOG_TIMEMASK; 135 wdog |= PM_PASSWORD; 136 137 HWRITE4(sc, PM_WDOG, wdog); 138 HWRITE4(sc, PM_RSTC, rstc); 139 } 140 141 int 142 bcmdog_wdog_cb(void *self, int period) 143 { 144 struct bcmdog_softc *sc = self; 145 146 bcmdog_wdog_set(sc, period << 16); 147 return period; 148 } 149 150 void 151 bcmdog_wdog_reset(void) 152 { 153 struct bcmdog_softc *sc = bcmdog_sc; 154 155 bcmdog_wdog_set(sc, 10); 156 delay(100000); 157 } 158