1 /* $OpenBSD: bcm2835_gpio.c,v 1.5 2022/04/06 18:59:28 naddy Exp $ */ 2 /* 3 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> 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/device.h> 20 #include <sys/gpio.h> 21 #include <sys/malloc.h> 22 #include <sys/systm.h> 23 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/gpio/gpiovar.h> 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/ofw_pinctrl.h> 31 #include <dev/ofw/fdt.h> 32 33 #include "gpio.h" 34 35 /* Registers */ 36 #define GPFSEL(n) (0x00 + ((n) * 4)) 37 #define GPFSEL_MASK 0x7 38 #define GPFSEL_GPIO_IN 0x0 39 #define GPFSEL_GPIO_OUT 0x1 40 #define GPFSEL_ALT0 0x4 41 #define GPFSEL_ALT1 0x5 42 #define GPFSEL_ALT2 0x6 43 #define GPFSEL_ALT3 0x7 44 #define GPFSEL_ALT4 0x3 45 #define GPFSEL_ALT5 0x2 46 #define GPSET(n) (0x1c + ((n) * 4)) 47 #define GPCLR(n) (0x28 + ((n) * 4)) 48 #define GPLEV(n) (0x34 + ((n) * 4)) 49 #define GPPUD 0x94 50 #define GPPUD_PUD 0x3 51 #define GPPUD_PUD_OFF 0x0 52 #define GPPUD_PUD_DOWN 0x1 53 #define GPPUD_PUD_UP 0x2 54 #define GPPUDCLK(n) (0x98 + ((n) * 4)) 55 #define GPPULL(n) (0xe4 + ((n) * 4)) 56 #define GPPULL_MASK 0x3 57 58 #define BCMGPIO_MAX_PINS 58 59 60 #define HREAD4(sc, reg) \ 61 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 62 #define HWRITE4(sc, reg, val) \ 63 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 64 65 struct bcmgpio_softc { 66 struct device sc_dev; 67 bus_space_tag_t sc_iot; 68 bus_space_handle_t sc_ioh; 69 70 void (*sc_config_pull)(struct bcmgpio_softc *, int, int); 71 int sc_num_pins; 72 73 struct gpio_controller sc_gc; 74 75 struct gpio_chipset_tag sc_gpio_tag; 76 gpio_pin_t sc_gpio_pins[BCMGPIO_MAX_PINS]; 77 int sc_gpio_claimed[BCMGPIO_MAX_PINS]; 78 }; 79 80 int bcmgpio_match(struct device *, void *, void *); 81 void bcmgpio_attach(struct device *, struct device *, void *); 82 83 const struct cfattach bcmgpio_ca = { 84 sizeof (struct bcmgpio_softc), bcmgpio_match, bcmgpio_attach 85 }; 86 87 struct cfdriver bcmgpio_cd = { 88 NULL, "bcmgpio", DV_DULL 89 }; 90 91 void bcm2711_config_pull(struct bcmgpio_softc *, int, int); 92 void bcm2835_config_pull(struct bcmgpio_softc *, int, int); 93 int bcmgpio_pinctrl(uint32_t, void *); 94 void bcmgpio_config_pin(void *, uint32_t *, int); 95 int bcmgpio_get_pin(void *, uint32_t *); 96 void bcmgpio_set_pin(void *, uint32_t *, int); 97 void bcmgpio_attach_gpio(struct device *); 98 99 int 100 bcmgpio_match(struct device *parent, void *match, void *aux) 101 { 102 struct fdt_attach_args *faa = aux; 103 104 return (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio") || 105 OF_is_compatible(faa->fa_node, "brcm,bcm2835-gpio")); 106 } 107 108 void 109 bcmgpio_attach(struct device *parent, struct device *self, void *aux) 110 { 111 struct bcmgpio_softc *sc = (struct bcmgpio_softc *)self; 112 struct fdt_attach_args *faa = aux; 113 114 if (faa->fa_nreg < 1) { 115 printf(": no registers\n"); 116 return; 117 } 118 119 sc->sc_iot = faa->fa_iot; 120 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 121 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 122 printf(": can't map registers\n"); 123 return; 124 } 125 126 printf("\n"); 127 128 if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-gpio")) { 129 sc->sc_config_pull = bcm2711_config_pull; 130 sc->sc_num_pins = 58; 131 } else { 132 sc->sc_config_pull = bcm2835_config_pull; 133 sc->sc_num_pins = 54; 134 } 135 136 pinctrl_register(faa->fa_node, bcmgpio_pinctrl, sc); 137 138 sc->sc_gc.gc_node = faa->fa_node; 139 sc->sc_gc.gc_cookie = sc; 140 sc->sc_gc.gc_config_pin = bcmgpio_config_pin; 141 sc->sc_gc.gc_get_pin = bcmgpio_get_pin; 142 sc->sc_gc.gc_set_pin = bcmgpio_set_pin; 143 gpio_controller_register(&sc->sc_gc); 144 145 config_mountroot(self, bcmgpio_attach_gpio); 146 } 147 148 void 149 bcmgpio_config_func(struct bcmgpio_softc *sc, int pin, int func) 150 { 151 int reg = (pin / 10); 152 int shift = (pin % 10) * 3; 153 uint32_t val; 154 155 val = HREAD4(sc, GPFSEL(reg)); 156 val &= ~(GPFSEL_MASK << shift); 157 HWRITE4(sc, GPFSEL(reg), val); 158 val |= ((func & GPFSEL_MASK) << shift); 159 HWRITE4(sc, GPFSEL(reg), val); 160 } 161 162 void 163 bcm2711_config_pull(struct bcmgpio_softc *sc, int pin, int pull) 164 { 165 int reg = (pin / 16); 166 int shift = (pin % 16) * 2; 167 uint32_t val; 168 169 val = HREAD4(sc, GPPULL(reg)); 170 val &= ~(GPPULL_MASK << shift); 171 pull = ((pull & 1) << 1) | ((pull & 2) >> 1); 172 val |= (pull << shift); 173 HWRITE4(sc, GPPULL(reg), val); 174 } 175 176 void 177 bcm2835_config_pull(struct bcmgpio_softc *sc, int pin, int pull) 178 { 179 int reg = (pin / 32); 180 int shift = (pin % 32); 181 182 HWRITE4(sc, GPPUD, pull & GPPUD_PUD); 183 delay(1); 184 HWRITE4(sc, GPPUDCLK(reg), 1 << shift); 185 delay(1); 186 HWRITE4(sc, GPPUDCLK(reg), 0); 187 } 188 189 int 190 bcmgpio_pinctrl(uint32_t phandle, void *cookie) 191 { 192 struct bcmgpio_softc *sc = cookie; 193 uint32_t *pins, *pull = NULL; 194 int len, plen = 0; 195 int node, i; 196 int func; 197 198 node = OF_getnodebyphandle(phandle); 199 if (node == 0) 200 return -1; 201 202 len = OF_getproplen(node, "brcm,pins"); 203 if (len <= 0) 204 return -1; 205 206 pins = malloc(len, M_TEMP, M_WAITOK); 207 if (OF_getpropintarray(node, "brcm,pins", pins, len) != len) 208 goto fail; 209 func = OF_getpropint(node, "brcm,function", -1); 210 211 plen = OF_getproplen(node, "brcm,pull"); 212 if (plen > 0) { 213 pull = malloc(len, M_TEMP, M_WAITOK); 214 if (OF_getpropintarray(node, "brcm,pull", pull, plen) != plen) 215 goto fail; 216 } 217 218 for (i = 0; i < len / sizeof(uint32_t); i++) { 219 bcmgpio_config_func(sc, pins[i], func); 220 if (plen > 0 && i < plen / sizeof(uint32_t)) 221 sc->sc_config_pull(sc, pins[i], pull[i]); 222 sc->sc_gpio_claimed[pins[i]] = 1; 223 } 224 225 free(pull, M_TEMP, plen); 226 free(pins, M_TEMP, len); 227 return 0; 228 229 fail: 230 free(pull, M_TEMP, plen); 231 free(pins, M_TEMP, len); 232 return -1; 233 } 234 235 void 236 bcmgpio_config_pin(void *cookie, uint32_t *cells, int config) 237 { 238 struct bcmgpio_softc *sc = cookie; 239 uint32_t pin = cells[0]; 240 241 if (pin >= sc->sc_num_pins) 242 return; 243 244 if (config & GPIO_CONFIG_OUTPUT) 245 bcmgpio_config_func(sc, pin, GPFSEL_GPIO_OUT); 246 else 247 bcmgpio_config_func(sc, pin, GPFSEL_GPIO_IN); 248 if (config & GPIO_CONFIG_PULL_UP) 249 sc->sc_config_pull(sc, pin, GPPUD_PUD_UP); 250 else if (config & GPIO_CONFIG_PULL_DOWN) 251 sc->sc_config_pull(sc, pin, GPPUD_PUD_DOWN); 252 else 253 sc->sc_config_pull(sc, pin, GPPUD_PUD_OFF); 254 } 255 256 int 257 bcmgpio_get_pin(void *cookie, uint32_t *cells) 258 { 259 struct bcmgpio_softc *sc = cookie; 260 uint32_t pin = cells[0]; 261 uint32_t flags = cells[1]; 262 uint32_t reg; 263 int val; 264 265 if (pin >= sc->sc_num_pins) 266 return 0; 267 268 reg = HREAD4(sc, GPLEV(pin / 32)); 269 val = (reg >> (pin % 32)) & 1; 270 if (flags & GPIO_ACTIVE_LOW) 271 val = !val; 272 return val; 273 } 274 275 void 276 bcmgpio_set_pin(void *cookie, uint32_t *cells, int val) 277 { 278 struct bcmgpio_softc *sc = cookie; 279 uint32_t pin = cells[0]; 280 uint32_t flags = cells[1]; 281 282 if (pin >= sc->sc_num_pins) 283 return; 284 285 if (flags & GPIO_ACTIVE_LOW) 286 val = !val; 287 if (val) 288 HWRITE4(sc, GPSET(pin / 32), (1 << (pin % 32))); 289 else 290 HWRITE4(sc, GPCLR(pin / 32), (1 << (pin % 32))); 291 } 292 293 /* 294 * GPIO support code 295 */ 296 297 int bcmgpio_pin_read(void *, int); 298 void bcmgpio_pin_write(void *, int, int); 299 void bcmgpio_pin_ctl(void *, int, int); 300 301 static const struct gpio_chipset_tag bcmgpio_gpio_tag = { 302 .gp_pin_read = bcmgpio_pin_read, 303 .gp_pin_write = bcmgpio_pin_write, 304 .gp_pin_ctl = bcmgpio_pin_ctl 305 }; 306 307 int 308 bcmgpio_pin_read(void *cookie, int pin) 309 { 310 struct bcmgpio_softc *sc = cookie; 311 uint32_t cells[2]; 312 313 cells[0] = pin; 314 cells[1] = 0; 315 316 return bcmgpio_get_pin(sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 317 } 318 319 void 320 bcmgpio_pin_write(void *cookie, int pin, int val) 321 { 322 struct bcmgpio_softc *sc = cookie; 323 uint32_t cells[2]; 324 325 cells[0] = pin; 326 cells[1] = 0; 327 328 bcmgpio_set_pin(sc, cells, val); 329 } 330 331 void 332 bcmgpio_pin_ctl(void *cookie, int pin, int flags) 333 { 334 struct bcmgpio_softc *sc = cookie; 335 uint32_t cells[2]; 336 uint32_t config; 337 338 cells[0] = pin; 339 cells[1] = 0; 340 341 config = 0; 342 if (ISSET(flags, GPIO_PIN_OUTPUT)) 343 config |= GPIO_CONFIG_OUTPUT; 344 if (ISSET(flags, GPIO_PIN_PULLUP)) 345 config |= GPIO_CONFIG_PULL_UP; 346 if (ISSET(flags, GPIO_PIN_PULLDOWN)) 347 config |= GPIO_CONFIG_PULL_DOWN; 348 349 bcmgpio_config_pin(sc, cells, config); 350 } 351 352 void 353 bcmgpio_attach_gpio(struct device *parent) 354 { 355 struct bcmgpio_softc *sc = (struct bcmgpio_softc *)parent; 356 struct gpiobus_attach_args gba; 357 uint32_t reg; 358 int func, state, flags; 359 int pin; 360 361 for (pin = 0; pin < sc->sc_num_pins; pin++) { 362 /* Skip pins claimed by other devices. */ 363 if (sc->sc_gpio_claimed[pin]) 364 continue; 365 366 /* Get pin configuration. */ 367 reg = HREAD4(sc, GPFSEL(pin / 10)); 368 func = (reg >> ((pin % 10) * 3)) & GPFSEL_MASK; 369 370 switch (func) { 371 case GPFSEL_GPIO_IN: 372 flags = GPIO_PIN_SET | GPIO_PIN_INPUT; 373 break; 374 case GPFSEL_GPIO_OUT: 375 flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT; 376 break; 377 default: 378 /* Ignore pins with an assigned function. */ 379 continue; 380 } 381 382 /* Get pin state. */ 383 reg = HREAD4(sc, GPLEV(pin / 32)); 384 state = (reg >> (pin % 32)) & 1; 385 386 sc->sc_gpio_pins[pin].pin_caps = 387 GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | 388 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN; 389 sc->sc_gpio_pins[pin].pin_flags = flags; 390 sc->sc_gpio_pins[pin].pin_state = state; 391 sc->sc_gpio_pins[pin].pin_num = pin; 392 } 393 394 memcpy(&sc->sc_gpio_tag, &bcmgpio_gpio_tag, sizeof(bcmgpio_gpio_tag)); 395 sc->sc_gpio_tag.gp_cookie = sc; 396 397 gba.gba_name = "gpio"; 398 gba.gba_gc = &sc->sc_gpio_tag; 399 gba.gba_pins = &sc->sc_gpio_pins[0]; 400 gba.gba_npins = sc->sc_num_pins; 401 402 #if NGPIO > 0 403 config_found(&sc->sc_dev, &gba, gpiobus_print); 404 #endif 405 } 406