1 /* $NetBSD: octeon_gpio.c,v 1.1 2026/07/07 08:14:15 kbowling Exp $ */ 2 /* $OpenBSD: octgpio.c,v 1.2 2019/09/29 04:28:52 visa Exp $ */ 3 4 /* 5 * Copyright (c) 2019 Visa Hankala 6 * Copyright (c) 2026 Kevin Bowling <kevin.bowling (at) kev009.com> 7 * 8 * Permission to use, copy, modify, and/or distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 /* Driver for OCTEON GPIO controller. */ 22 23 #include <sys/cdefs.h> 24 __KERNEL_RCSID(0, "$NetBSD: octeon_gpio.c,v 1.1 2026/07/07 08:14:15 kbowling Exp $"); 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/bus.h> 29 #include <sys/device.h> 30 #include <sys/endian.h> 31 #include <sys/gpio.h> 32 #include <sys/kmem.h> 33 #include <sys/mutex.h> 34 35 #include <dev/fdt/fdtvar.h> 36 37 #include <mips/cpuregs.h> 38 #include <mips/locore.h> 39 40 #include <mips/cavium/dev/octeon_gpioreg.h> 41 42 struct octgpio_softc { 43 device_t sc_dev; 44 bus_space_tag_t sc_iot; 45 bus_space_handle_t sc_ioh; 46 kmutex_t sc_lock; 47 uint32_t sc_npins; 48 uint32_t sc_xbit; 49 bool sc_out_sel; /* BIT_CFG has OUTPUT_SEL */ 50 }; 51 52 struct octgpio_pin { 53 struct octgpio_softc *pin_sc; 54 uint32_t pin_no; 55 bool pin_actlo; 56 }; 57 58 #define GPIO_RD_8(sc, reg) \ 59 bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)) 60 #define GPIO_WR_8(sc, reg, val) \ 61 bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 62 63 static int octgpio_match(device_t, cfdata_t, void *); 64 static void octgpio_attach(device_t, device_t, void *); 65 66 static void *octgpio_acquire(device_t, const void *, size_t, int); 67 static void octgpio_release(device_t, void *); 68 static int octgpio_read(device_t, void *, bool); 69 static void octgpio_write(device_t, void *, int, bool); 70 71 static void octgpio_pin_ctl(struct octgpio_softc *, uint32_t, int); 72 73 CFATTACH_DECL_NEW(octgpio, sizeof(struct octgpio_softc), 74 octgpio_match, octgpio_attach, NULL, NULL); 75 76 static const struct device_compatible_entry compat_data[] = { 77 { .compat = "cavium,octeon-3860-gpio" }, 78 { .compat = "cavium,octeon-7890-gpio" }, 79 DEVICE_COMPAT_EOL 80 }; 81 82 static const struct fdtbus_gpio_controller_func octgpio_funcs = { 83 .acquire = octgpio_acquire, 84 .release = octgpio_release, 85 .read = octgpio_read, 86 .write = octgpio_write, 87 }; 88 89 static int 90 octgpio_match(device_t parent, cfdata_t cf, void *aux) 91 { 92 struct fdt_attach_args * const faa = aux; 93 94 return of_compatible_match(faa->faa_phandle, compat_data); 95 } 96 97 static void 98 octgpio_attach(device_t parent, device_t self, void *aux) 99 { 100 struct fdt_attach_args * const faa = aux; 101 struct octgpio_softc *sc = device_private(self); 102 const int phandle = faa->faa_phandle; 103 bus_addr_t addr; 104 bus_size_t size; 105 106 sc->sc_dev = self; 107 sc->sc_iot = faa->faa_bst; 108 109 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 110 aprint_error(": could not get registers\n"); 111 return; 112 } 113 /* 114 * Device trees give a 0x100 window but the extended pin 115 * configuration registers (GPIO_XBIT_CFG) live at +0x100. 116 */ 117 if (size < GPIO_SIZE) 118 size = GPIO_SIZE; 119 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { 120 aprint_error(": could not map registers\n"); 121 return; 122 } 123 124 /* 125 * Set the pin count and the register layout per the SDK CSR 126 * definitions (cvmx-gpio-defs.h). Pins below sc_xbit are 127 * configured through GPIO_BIT_CFG, the rest through 128 * GPIO_XBIT_CFG. On CN73XX and CN78XX all pins use the 129 * GPIO_XBIT_CFG range. The BIT_CFG OUTPUT_SEL output mux 130 * exists on CN70XX and newer only; on CN61XX-class chips the 131 * same bits belong to SYNCE_SEL and must not be touched. 132 */ 133 switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) { 134 case MIPS_CN30XX: 135 case MIPS_CN31XX: 136 case MIPS_CN50XX: 137 sc->sc_npins = 24; 138 sc->sc_xbit = 16; 139 break; 140 case MIPS_CN38XX: 141 case MIPS_CN52XX: 142 case MIPS_CN56XX: 143 case MIPS_CN58XX: 144 case MIPS_CN63XX: 145 case MIPS_CN68XX: 146 sc->sc_npins = 16; 147 sc->sc_xbit = 16; 148 break; 149 case MIPS_CN61XX: 150 case MIPS_CN66XX: 151 case MIPS_CNF71XX: 152 sc->sc_npins = 20; 153 sc->sc_xbit = 16; 154 break; 155 case MIPS_CN70XX: 156 sc->sc_npins = 20; 157 sc->sc_xbit = 16; 158 sc->sc_out_sel = true; 159 break; 160 case MIPS_CN73XX: 161 case MIPS_CNF75XX: 162 sc->sc_npins = 32; 163 sc->sc_xbit = 0; 164 sc->sc_out_sel = true; 165 break; 166 case MIPS_CN78XX: 167 sc->sc_npins = 20; 168 sc->sc_xbit = 0; 169 sc->sc_out_sel = true; 170 break; 171 default: 172 /* Be conservative about unknown models. */ 173 sc->sc_npins = 16; 174 sc->sc_xbit = 16; 175 break; 176 } 177 178 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 179 180 aprint_naive("\n"); 181 aprint_normal(": GPIO controller, %u pins\n", sc->sc_npins); 182 183 fdtbus_register_gpio_controller(self, phandle, &octgpio_funcs); 184 } 185 186 static bus_size_t 187 octgpio_cfg_reg(struct octgpio_softc *sc, uint32_t pin) 188 { 189 190 if (pin >= sc->sc_xbit) 191 return GPIO_XBIT_CFG16_OFFSET + (pin - sc->sc_xbit) * 8; 192 return GPIO_BIT_CFG0_OFFSET + pin * 8; 193 } 194 195 static void 196 octgpio_pin_ctl(struct octgpio_softc *sc, uint32_t pin, int flags) 197 { 198 uint64_t value; 199 bus_size_t reg; 200 201 KASSERT(pin < sc->sc_npins); 202 reg = octgpio_cfg_reg(sc, pin); 203 204 mutex_enter(&sc->sc_lock); 205 value = GPIO_RD_8(sc, reg); 206 if (ISSET(flags, GPIO_PIN_OUTPUT)) { 207 value |= GPIO_BIT_CFG_TX_OE; 208 /* Select normal GPIO output where the mux exists. */ 209 if (sc->sc_out_sel) 210 value &= ~GPIO_BIT_CFG_OUT_SEL; 211 } else { 212 value &= ~(GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_RX_XOR); 213 } 214 /* 215 * Interrupts are not supported; keep INT_EN clear (on models 216 * whose XBIT_CFG lacks INT_EN the bit reads as zero anyway). 217 */ 218 value &= ~GPIO_BIT_CFG_INT_EN; 219 GPIO_WR_8(sc, reg, value); 220 mutex_exit(&sc->sc_lock); 221 } 222 223 static void * 224 octgpio_acquire(device_t dev, const void *data, size_t len, int flags) 225 { 226 struct octgpio_softc *sc = device_private(dev); 227 const u_int *gpio = data; 228 struct octgpio_pin *pin; 229 u_int pinno; 230 bool actlo; 231 232 /* #gpio-cells = <2>: controller phandle, pin, flags. */ 233 if (len != 12) 234 return NULL; 235 236 pinno = be32toh(gpio[1]); 237 actlo = (be32toh(gpio[2]) & 1) != 0; 238 if (pinno >= sc->sc_npins) 239 return NULL; 240 241 octgpio_pin_ctl(sc, pinno, flags); 242 243 pin = kmem_zalloc(sizeof(*pin), KM_SLEEP); 244 pin->pin_sc = sc; 245 pin->pin_no = pinno; 246 pin->pin_actlo = actlo; 247 248 return pin; 249 } 250 251 static void 252 octgpio_release(device_t dev, void *priv) 253 { 254 struct octgpio_softc *sc = device_private(dev); 255 struct octgpio_pin *pin = priv; 256 257 octgpio_pin_ctl(sc, pin->pin_no, GPIO_PIN_INPUT); 258 kmem_free(pin, sizeof(*pin)); 259 } 260 261 static int 262 octgpio_read(device_t dev, void *priv, bool raw) 263 { 264 struct octgpio_pin *pin = priv; 265 struct octgpio_softc *sc = pin->pin_sc; 266 int val; 267 268 val = (GPIO_RD_8(sc, GPIO_RX_DAT_OFFSET) >> pin->pin_no) & 1; 269 if (!raw && pin->pin_actlo) 270 val = !val; 271 272 return val; 273 } 274 275 static void 276 octgpio_write(device_t dev, void *priv, int val, bool raw) 277 { 278 struct octgpio_pin *pin = priv; 279 struct octgpio_softc *sc = pin->pin_sc; 280 281 if (!raw && pin->pin_actlo) 282 val = !val; 283 284 if (val) 285 GPIO_WR_8(sc, GPIO_TX_SET_OFFSET, 1ull << pin->pin_no); 286 else 287 GPIO_WR_8(sc, GPIO_TX_CLR_OFFSET, 1ull << pin->pin_no); 288 } 289