1 /* $NetBSD: cycv_rstmgr.c,v 1.5 2022/01/01 13:47:19 andvar 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.5 2022/01/01 13:47:19 andvar 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 const struct device_compatible_entry compat_data[] = { 53 { .compat = "altr,rst-mgr" }, 54 DEVICE_COMPAT_EOL 55 }; 56 57 static int 58 cycv_rstmgr_match(device_t parent, cfdata_t cf, void *aux) 59 { 60 struct fdt_attach_args *faa = aux; 61 62 return of_compatible_match(faa->faa_phandle, compat_data); 63 } 64 65 static void 66 cycv_rstmgr_attach(device_t parent, device_t self, void *aux) 67 { 68 struct cycv_rstmgr_softc *sc = device_private(self); 69 struct fdt_attach_args *faa = aux; 70 int phandle = faa->faa_phandle; 71 bus_addr_t addr; 72 bus_size_t size; 73 int error; 74 75 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 76 aprint_error(": couldn't get registers\n"); 77 return; 78 } 79 80 sc->sc_dev = self; 81 sc->sc_bst = faa->faa_bst; 82 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); 83 if (error) { 84 aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", 85 addr, error); 86 return; 87 } 88 89 aprint_normal(": reset manager\n"); 90 91 fdtbus_register_reset_controller(self, phandle, &cycv_rstmgr_funcs); 92 cycv_rstmgr_sc = sc; 93 } 94 95 static void * 96 cycv_rst_acquire(device_t dev, const void *data, size_t len) { 97 struct cycv_reset *reset = NULL; 98 uint32_t value; 99 100 if (len != sizeof value) 101 goto err_decode; 102 103 value = of_decode_int(data); 104 if (value < 0 || value > 105 (CYCV_RSTMGR_MISCMODRST - CYCV_RSTMGR_MPUMODRST + 4) / 4 * 32) 106 goto err_decode; 107 108 reset = kmem_alloc(sizeof *reset, KM_SLEEP); 109 reset->address = CYCV_RSTMGR_MPUMODRST + value / 32 * 4; 110 reset->mask = 1 << (value % 32); 111 112 if (0) { 113 err_decode: 114 aprint_debug_dev(dev, "couldn't decode reset\n"); 115 } 116 return reset; 117 } 118 119 static void 120 cycv_rst_release(device_t dev, void *r) { 121 kmem_free(r, sizeof (struct cycv_reset)); 122 } 123 124 static void 125 cycv_rst_reset_set(device_t dev, struct cycv_reset *reset, int set) { 126 struct cycv_rstmgr_softc *sc = device_private(dev); 127 uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reset->address); 128 129 if (set) 130 val |= reset->mask; 131 else 132 val &= ~reset->mask; 133 134 bus_space_write_4(sc->sc_bst, sc->sc_bsh, reset->address, val); 135 } 136 137 static int 138 cycv_rst_reset_assert(device_t dev, void *r) { 139 140 cycv_rst_reset_set(dev, r, 1); 141 142 return 0; 143 } 144 145 static int 146 cycv_rst_reset_deassert(device_t dev, void *r) { 147 148 cycv_rst_reset_set(dev, r, 0); 149 150 return 0; 151 } 152