1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018-2019, Rubicon Communications, LLC (Netgate) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 36 #include <sys/gpio.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/rman.h> 40 41 #include <machine/bus.h> 42 #include <machine/resource.h> 43 44 #include <dev/gpio/gpiobusvar.h> 45 #include <dev/ofw/ofw_bus.h> 46 #include <dev/ofw/ofw_bus_subr.h> 47 48 #include "gpio_if.h" 49 50 static struct resource_spec a37x0_gpio_res_spec[] = { 51 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Pinctl / GPIO */ 52 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* Interrupts control */ 53 { -1, 0, 0 } 54 }; 55 56 struct a37x0_gpio_softc { 57 bus_space_tag_t sc_bst; 58 bus_space_handle_t sc_bsh; 59 device_t sc_busdev; 60 int sc_type; 61 uint32_t sc_max_pins; 62 uint32_t sc_npins; 63 struct resource *sc_mem_res[nitems(a37x0_gpio_res_spec) - 1]; 64 }; 65 66 /* Memory regions. */ 67 #define A37X0_GPIO 0 68 #define A37X0_INTR 1 69 70 /* North Bridge / South Bridge. */ 71 #define A37X0_NB_GPIO 1 72 #define A37X0_SB_GPIO 2 73 74 #define A37X0_GPIO_WRITE(_sc, _off, _val) \ 75 bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off), (_val)) 76 #define A37X0_GPIO_READ(_sc, _off) \ 77 bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off)) 78 79 #define A37X0_GPIO_BIT(_p) (1U << ((_p) % 32)) 80 #define A37X0_GPIO_OUT_EN(_p) (0x0 + ((_p) / 32) * 4) 81 #define A37X0_GPIO_LATCH(_p) (0x8 + ((_p) / 32) * 4) 82 #define A37X0_GPIO_INPUT(_p) (0x10 + ((_p) / 32) * 4) 83 #define A37X0_GPIO_OUTPUT(_p) (0x18 + ((_p) / 32) * 4) 84 #define A37X0_GPIO_SEL 0x30 85 86 87 static struct ofw_compat_data compat_data[] = { 88 { "marvell,armada3710-nb-pinctrl", A37X0_NB_GPIO }, 89 { "marvell,armada3710-sb-pinctrl", A37X0_SB_GPIO }, 90 { NULL, 0 } 91 }; 92 93 static phandle_t 94 a37x0_gpio_get_node(device_t bus, device_t dev) 95 { 96 97 return (ofw_bus_get_node(bus)); 98 } 99 100 static device_t 101 a37x0_gpio_get_bus(device_t dev) 102 { 103 struct a37x0_gpio_softc *sc; 104 105 sc = device_get_softc(dev); 106 107 return (sc->sc_busdev); 108 } 109 110 static int 111 a37x0_gpio_pin_max(device_t dev, int *maxpin) 112 { 113 struct a37x0_gpio_softc *sc; 114 115 sc = device_get_softc(dev); 116 *maxpin = sc->sc_npins - 1; 117 118 return (0); 119 } 120 121 static int 122 a37x0_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 123 { 124 struct a37x0_gpio_softc *sc; 125 126 sc = device_get_softc(dev); 127 if (pin >= sc->sc_npins) 128 return (EINVAL); 129 snprintf(name, GPIOMAXNAME, "pin %d", pin); 130 131 return (0); 132 } 133 134 static int 135 a37x0_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 136 { 137 struct a37x0_gpio_softc *sc; 138 139 sc = device_get_softc(dev); 140 if (pin >= sc->sc_npins) 141 return (EINVAL); 142 *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 143 144 return (0); 145 } 146 147 static int 148 a37x0_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 149 { 150 struct a37x0_gpio_softc *sc; 151 uint32_t reg; 152 153 sc = device_get_softc(dev); 154 if (pin >= sc->sc_npins) 155 return (EINVAL); 156 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin)); 157 if ((reg & A37X0_GPIO_BIT(pin)) != 0) 158 *flags = GPIO_PIN_OUTPUT; 159 else 160 *flags = GPIO_PIN_INPUT; 161 162 return (0); 163 } 164 165 static int 166 a37x0_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 167 { 168 struct a37x0_gpio_softc *sc; 169 uint32_t reg; 170 171 sc = device_get_softc(dev); 172 if (pin >= sc->sc_npins) 173 return (EINVAL); 174 175 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin)); 176 if (flags & GPIO_PIN_OUTPUT) 177 reg |= A37X0_GPIO_BIT(pin); 178 else 179 reg &= ~A37X0_GPIO_BIT(pin); 180 A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUT_EN(pin), reg); 181 182 return (0); 183 } 184 185 static int 186 a37x0_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 187 { 188 struct a37x0_gpio_softc *sc; 189 uint32_t reg; 190 191 sc = device_get_softc(dev); 192 if (pin >= sc->sc_npins) 193 return (EINVAL); 194 195 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin)); 196 if ((reg & A37X0_GPIO_BIT(pin)) != 0) 197 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin)); 198 else 199 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_INPUT(pin)); 200 *val = ((reg & A37X0_GPIO_BIT(pin)) != 0) ? 1 : 0; 201 202 return (0); 203 } 204 205 static int 206 a37x0_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val) 207 { 208 struct a37x0_gpio_softc *sc; 209 uint32_t reg; 210 211 sc = device_get_softc(dev); 212 if (pin >= sc->sc_npins) 213 return (EINVAL); 214 215 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin)); 216 if (val != 0) 217 reg |= A37X0_GPIO_BIT(pin); 218 else 219 reg &= ~A37X0_GPIO_BIT(pin); 220 A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUTPUT(pin), reg); 221 222 return (0); 223 } 224 225 static int 226 a37x0_gpio_pin_toggle(device_t dev, uint32_t pin) 227 { 228 struct a37x0_gpio_softc *sc; 229 uint32_t reg; 230 231 sc = device_get_softc(dev); 232 if (pin >= sc->sc_npins) 233 return (EINVAL); 234 235 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin)); 236 if ((reg & A37X0_GPIO_BIT(pin)) == 0) 237 return (EINVAL); 238 reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin)); 239 reg ^= A37X0_GPIO_BIT(pin); 240 A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUTPUT(pin), reg); 241 242 return (0); 243 } 244 245 static int 246 a37x0_gpio_probe(device_t dev) 247 { 248 const char *desc; 249 struct a37x0_gpio_softc *sc; 250 251 if (!OF_hasprop(ofw_bus_get_node(dev), "gpio-controller")) 252 return (ENXIO); 253 254 sc = device_get_softc(dev); 255 sc->sc_type = ofw_bus_search_compatible( 256 device_get_parent(dev), compat_data)->ocd_data; 257 switch (sc->sc_type) { 258 case A37X0_NB_GPIO: 259 sc->sc_max_pins = 36; 260 desc = "Armada 37x0 North Bridge GPIO Controller"; 261 break; 262 case A37X0_SB_GPIO: 263 sc->sc_max_pins = 30; 264 desc = "Armada 37x0 South Bridge GPIO Controller"; 265 break; 266 default: 267 return (ENXIO); 268 } 269 device_set_desc(dev, desc); 270 271 return (BUS_PROBE_DEFAULT); 272 } 273 274 static int 275 a37x0_gpio_attach(device_t dev) 276 { 277 int err, ncells; 278 pcell_t *ranges; 279 struct a37x0_gpio_softc *sc; 280 281 sc = device_get_softc(dev); 282 283 /* Read and verify the "gpio-ranges" property. */ 284 ncells = OF_getencprop_alloc(ofw_bus_get_node(dev), "gpio-ranges", 285 (void **)&ranges); 286 if (ncells == -1) 287 return (ENXIO); 288 if (ncells != sizeof(*ranges) * 4 || ranges[1] != 0 || ranges[2] != 0) { 289 OF_prop_free(ranges); 290 return (ENXIO); 291 } 292 sc->sc_npins = ranges[3]; 293 OF_prop_free(ranges); 294 295 /* Check the number of pins in the DTS vs HW capabilities. */ 296 if (sc->sc_npins > sc->sc_max_pins) 297 return (ENXIO); 298 299 err = bus_alloc_resources(dev, a37x0_gpio_res_spec, sc->sc_mem_res); 300 if (err != 0) { 301 device_printf(dev, "cannot allocate memory window\n"); 302 return (ENXIO); 303 } 304 sc->sc_bst = rman_get_bustag(sc->sc_mem_res[A37X0_GPIO]); 305 sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res[A37X0_GPIO]); 306 307 sc->sc_busdev = gpiobus_attach_bus(dev); 308 if (sc->sc_busdev == NULL) 309 return (ENXIO); 310 311 return (0); 312 } 313 314 static int 315 a37x0_gpio_detach(device_t dev) 316 { 317 318 return (EBUSY); 319 } 320 321 static device_method_t a37x0_gpio_methods[] = { 322 /* Device interface */ 323 DEVMETHOD(device_probe, a37x0_gpio_probe), 324 DEVMETHOD(device_attach, a37x0_gpio_attach), 325 DEVMETHOD(device_detach, a37x0_gpio_detach), 326 327 /* GPIO interface */ 328 DEVMETHOD(gpio_get_bus, a37x0_gpio_get_bus), 329 DEVMETHOD(gpio_pin_max, a37x0_gpio_pin_max), 330 DEVMETHOD(gpio_pin_getname, a37x0_gpio_pin_getname), 331 DEVMETHOD(gpio_pin_getcaps, a37x0_gpio_pin_getcaps), 332 DEVMETHOD(gpio_pin_getflags, a37x0_gpio_pin_getflags), 333 DEVMETHOD(gpio_pin_setflags, a37x0_gpio_pin_setflags), 334 DEVMETHOD(gpio_pin_get, a37x0_gpio_pin_get), 335 DEVMETHOD(gpio_pin_set, a37x0_gpio_pin_set), 336 DEVMETHOD(gpio_pin_toggle, a37x0_gpio_pin_toggle), 337 338 /* ofw_bus interface */ 339 DEVMETHOD(ofw_bus_get_node, a37x0_gpio_get_node), 340 341 DEVMETHOD_END 342 }; 343 344 static devclass_t a37x0_gpio_devclass; 345 static driver_t a37x0_gpio_driver = { 346 "gpio", 347 a37x0_gpio_methods, 348 sizeof(struct a37x0_gpio_softc), 349 }; 350 351 EARLY_DRIVER_MODULE(a37x0_gpio, simple_mfd, a37x0_gpio_driver, 352 a37x0_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); 353