1 /* $NetBSD: cycv_rstmgr.c,v 1.3 2019/10/18 06:50:08 skrll Exp $ */ 2 3 /* This file is in the public domain. */ 4 5 #include <sys/cdefs.h> 6 __KERNEL_RCSID(0, "$NetBSD: cycv_rstmgr.c,v 1.3 2019/10/18 06:50:08 skrll Exp $"); 7 8 #include <sys/param.h> 9 #include <sys/bus.h> 10 #include <sys/device.h> 11 #include <sys/intr.h> 12 #include <sys/systm.h> 13 #include <sys/kernel.h> 14 #include <sys/atomic.h> 15 #include <sys/kmem.h> 16 17 #include <arm/altera/cycv_reg.h> 18 #include <arm/altera/cycv_var.h> 19 20 #include <dev/fdt/fdtvar.h> 21 22 static int cycv_rstmgr_match(device_t, cfdata_t, void *); 23 static void cycv_rstmgr_attach(device_t, device_t, void *); 24 25 static void *cycv_rst_acquire(device_t, const void *, size_t); 26 static void cycv_rst_release(device_t, void *); 27 static int cycv_rst_reset_assert(device_t, void *); 28 static int cycv_rst_reset_deassert(device_t, void *); 29 30 static const struct fdtbus_reset_controller_func cycv_rstmgr_funcs = { 31 cycv_rst_acquire, cycv_rst_release, 32 cycv_rst_reset_assert, cycv_rst_reset_deassert 33 }; 34 35 struct cycv_rstmgr_softc { 36 device_t sc_dev; 37 38 bus_space_tag_t sc_bst; 39 bus_space_handle_t sc_bsh; 40 }; 41 42 struct cycv_reset { 43 bus_addr_t address; 44 uint32_t mask; 45 }; 46 47 CFATTACH_DECL_NEW(cycvrstmgr, sizeof (struct cycv_rstmgr_softc), 48 cycv_rstmgr_match, cycv_rstmgr_attach, NULL, NULL); 49 50 static struct cycv_rstmgr_softc *cycv_rstmgr_sc; 51 52 static int 53 cycv_rstmgr_match(device_t parent, cfdata_t cf, void *aux) 54 { 55 const char *compatible[] = { "altr,rst-mgr", NULL }; 56 struct fdt_attach_args *faa = aux; 57 58 return of_match_compatible(faa->faa_phandle, compatible); 59 } 60 61 static void 62 cycv_rstmgr_attach(device_t parent, device_t self, void *aux) 63 { 64 struct cycv_rstmgr_softc *sc = device_private(self); 65 struct fdt_attach_args *faa = aux; 66 int phandle = faa->faa_phandle; 67 bus_addr_t addr; 68 bus_size_t size; 69 int error; 70 71 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 72 aprint_error(": couldn't get registers\n"); 73 return; 74 } 75 76 sc->sc_dev = self; 77 sc->sc_bst = faa->faa_bst; 78 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 79 if (error) { 80 aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", 81 addr, error); 82 return; 83 } 84 85 aprint_normal(": reset manager\n"); 86 87 fdtbus_register_reset_controller(self, phandle, &cycv_rstmgr_funcs); 88 cycv_rstmgr_sc = sc; 89 } 90 91 static void * 92 cycv_rst_acquire(device_t dev, const void *data, size_t len) { 93 struct cycv_reset *reset = NULL; 94 uint32_t value; 95 96 if (len != sizeof value) 97 goto err_decode; 98 99 value = of_decode_int(data); 100 if (value < 0 || value > 101 (CYCV_RSTMGR_MISCMODRST - CYCV_RSTMGR_MPUMODRST + 4) / 4 * 32) 102 goto err_decode; 103 104 reset = kmem_alloc(sizeof *reset, KM_SLEEP); 105 reset->address = CYCV_RSTMGR_MPUMODRST + value / 32 * 4; 106 reset->mask = 1 << (value % 32); 107 108 if (0) { 109 err_decode: 110 aprint_debug_dev(dev, "couln't decode reset\n"); 111 } 112 return reset; 113 } 114 115 static void 116 cycv_rst_release(device_t dev, void *r) { 117 kmem_free(r, sizeof (struct cycv_reset)); 118 } 119 120 static void 121 cycv_rst_reset_set(device_t dev, struct cycv_reset *reset, int set) { 122 struct cycv_rstmgr_softc *sc = device_private(dev); 123 uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reset->address); 124 125 if (set) 126 val |= reset->mask; 127 else 128 val &= ~reset->mask; 129 130 bus_space_write_4(sc->sc_bst, sc->sc_bsh, reset->address, val); 131 } 132 133 static int 134 cycv_rst_reset_assert(device_t dev, void *r) { 135 136 cycv_rst_reset_set(dev, r, 1); 137 138 return 0; 139 } 140 141 static int 142 cycv_rst_reset_deassert(device_t dev, void *r) { 143 144 cycv_rst_reset_set(dev, r, 0); 145 146 return 0; 147 } 148