1 /* $OpenBSD: aplpinctrl.c,v 1.8 2023/07/23 11:17:50 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2021 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/systm.h> 20 #include <sys/device.h> 21 #include <sys/evcount.h> 22 #include <sys/malloc.h> 23 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 #include <machine/intr.h> 27 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/ofw_pinctrl.h> 31 #include <dev/ofw/ofw_power.h> 32 #include <dev/ofw/fdt.h> 33 34 #define APPLE_PIN(pinmux) ((pinmux) & 0xffff) 35 #define APPLE_FUNC(pinmux) ((pinmux) >> 16) 36 37 #define GPIO_PIN(pin) ((pin) * 4) 38 #define GPIO_PIN_GROUP_MASK (7 << 16) 39 #define GPIO_PIN_INPUT_ENABLE (1 << 9) 40 #define GPIO_PIN_FUNC_MASK (3 << 5) 41 #define GPIO_PIN_FUNC_SHIFT 5 42 #define GPIO_PIN_MODE_MASK (7 << 1) 43 #define GPIO_PIN_MODE_INPUT (0 << 1) 44 #define GPIO_PIN_MODE_OUTPUT (1 << 1) 45 #define GPIO_PIN_MODE_IRQ_HI (2 << 1) 46 #define GPIO_PIN_MODE_IRQ_LO (3 << 1) 47 #define GPIO_PIN_MODE_IRQ_UP (4 << 1) 48 #define GPIO_PIN_MODE_IRQ_DN (5 << 1) 49 #define GPIO_PIN_MODE_IRQ_ANY (6 << 1) 50 #define GPIO_PIN_MODE_IRQ_OFF (7 << 1) 51 #define GPIO_PIN_DATA (1 << 0) 52 #define GPIO_IRQ(grp, pin) (0x800 + (grp) * 64 + ((pin) >> 5) * 4) 53 54 #define HREAD4(sc, reg) \ 55 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 56 #define HWRITE4(sc, reg, val) \ 57 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 58 #define HSET4(sc, reg, bits) \ 59 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 60 #define HCLR4(sc, reg, bits) \ 61 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 62 63 struct intrhand { 64 TAILQ_ENTRY(intrhand) ih_list; 65 int (*ih_func)(void *); 66 void *ih_arg; 67 int ih_irq; 68 int ih_type; 69 int ih_ipl; 70 struct evcount ih_count; 71 char *ih_name; 72 void *ih_sc; 73 }; 74 75 struct aplpinctrl_softc { 76 struct device sc_dev; 77 bus_space_tag_t sc_iot; 78 bus_space_handle_t sc_ioh; 79 80 int sc_ngpios; 81 struct gpio_controller sc_gc; 82 83 void *sc_ih; 84 TAILQ_HEAD(, intrhand) *sc_handler; 85 struct interrupt_controller sc_ic; 86 }; 87 88 int aplpinctrl_match(struct device *, void *, void *); 89 void aplpinctrl_attach(struct device *, struct device *, void *); 90 91 const struct cfattach aplpinctrl_ca = { 92 sizeof (struct aplpinctrl_softc), aplpinctrl_match, aplpinctrl_attach 93 }; 94 95 struct cfdriver aplpinctrl_cd = { 96 NULL, "aplpinctrl", DV_DULL 97 }; 98 99 int aplpinctrl_pinctrl(uint32_t, void *); 100 void aplpinctrl_config_pin(void *, uint32_t *, int); 101 int aplpinctrl_get_pin(void *, uint32_t *); 102 void aplpinctrl_set_pin(void *, uint32_t *, int); 103 104 int aplpinctrl_intr(void *); 105 void *aplpinctrl_intr_establish(void *, int *, int, struct cpu_info *, 106 int (*)(void *), void *, char *); 107 void aplpinctrl_intr_disestablish(void *); 108 void aplpinctrl_intr_enable(void *); 109 void aplpinctrl_intr_disable(void *); 110 void aplpinctrl_intr_barrier(void *); 111 112 int 113 aplpinctrl_match(struct device *parent, void *match, void *aux) 114 { 115 struct fdt_attach_args *faa = aux; 116 117 return OF_is_compatible(faa->fa_node, "apple,pinctrl"); 118 } 119 120 void 121 aplpinctrl_attach(struct device *parent, struct device *self, void *aux) 122 { 123 struct aplpinctrl_softc *sc = (struct aplpinctrl_softc *)self; 124 struct fdt_attach_args *faa = aux; 125 uint32_t gpio_ranges[4] = {}; 126 int i; 127 128 if (faa->fa_nreg < 1) { 129 printf(": no registers\n"); 130 return; 131 } 132 133 sc->sc_iot = faa->fa_iot; 134 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 135 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 136 printf(": can't map registers\n"); 137 return; 138 } 139 140 power_domain_enable(faa->fa_node); 141 142 pinctrl_register(faa->fa_node, aplpinctrl_pinctrl, sc); 143 144 OF_getpropintarray(faa->fa_node, "gpio-ranges", 145 gpio_ranges, sizeof(gpio_ranges)); 146 sc->sc_ngpios = gpio_ranges[3]; 147 if (sc->sc_ngpios == 0) { 148 printf("\n"); 149 return; 150 } 151 152 sc->sc_gc.gc_node = faa->fa_node; 153 sc->sc_gc.gc_cookie = sc; 154 sc->sc_gc.gc_config_pin = aplpinctrl_config_pin; 155 sc->sc_gc.gc_get_pin = aplpinctrl_get_pin; 156 sc->sc_gc.gc_set_pin = aplpinctrl_set_pin; 157 gpio_controller_register(&sc->sc_gc); 158 159 sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_BIO, 160 aplpinctrl_intr, sc, sc->sc_dev.dv_xname); 161 if (sc->sc_ih == NULL) { 162 printf(": can't establish interrupt\n"); 163 return; 164 } 165 166 sc->sc_handler = mallocarray(sc->sc_ngpios, 167 sizeof(*sc->sc_handler), M_DEVBUF, M_ZERO | M_WAITOK); 168 for (i = 0; i < sc->sc_ngpios; i++) 169 TAILQ_INIT(&sc->sc_handler[i]); 170 171 sc->sc_ic.ic_node = faa->fa_node; 172 sc->sc_ic.ic_cookie = sc; 173 sc->sc_ic.ic_establish = aplpinctrl_intr_establish; 174 sc->sc_ic.ic_disestablish = aplpinctrl_intr_disestablish; 175 sc->sc_ic.ic_enable = aplpinctrl_intr_enable; 176 sc->sc_ic.ic_disable = aplpinctrl_intr_disable; 177 sc->sc_ic.ic_barrier = aplpinctrl_intr_barrier; 178 fdt_intr_register(&sc->sc_ic); 179 180 printf("\n"); 181 } 182 183 int 184 aplpinctrl_pinctrl(uint32_t phandle, void *cookie) 185 { 186 struct aplpinctrl_softc *sc = cookie; 187 uint32_t *pinmux; 188 int node, len, i; 189 uint16_t pin, func; 190 uint32_t reg; 191 192 node = OF_getnodebyphandle(phandle); 193 if (node == 0) 194 return -1; 195 196 len = OF_getproplen(node, "pinmux"); 197 if (len <= 0) 198 return -1; 199 200 pinmux = malloc(len, M_TEMP, M_WAITOK); 201 OF_getpropintarray(node, "pinmux", pinmux, len); 202 203 for (i = 0; i < len / sizeof(uint32_t); i++) { 204 pin = APPLE_PIN(pinmux[i]); 205 func = APPLE_FUNC(pinmux[i]); 206 reg = HREAD4(sc, GPIO_PIN(pin)); 207 reg &= ~GPIO_PIN_FUNC_MASK; 208 reg |= (func << GPIO_PIN_FUNC_SHIFT) & GPIO_PIN_FUNC_MASK; 209 HWRITE4(sc, GPIO_PIN(pin), reg); 210 } 211 212 free(pinmux, M_TEMP, len); 213 return 0; 214 } 215 216 void 217 aplpinctrl_config_pin(void *cookie, uint32_t *cells, int config) 218 { 219 struct aplpinctrl_softc *sc = cookie; 220 uint32_t pin = cells[0]; 221 uint32_t reg; 222 223 KASSERT(pin < sc->sc_ngpios); 224 225 reg = HREAD4(sc, GPIO_PIN(pin)); 226 reg &= ~GPIO_PIN_FUNC_MASK; 227 reg &= ~GPIO_PIN_MODE_MASK; 228 if (config & GPIO_CONFIG_OUTPUT) 229 reg |= GPIO_PIN_MODE_OUTPUT; 230 else 231 reg |= GPIO_PIN_MODE_INPUT; 232 HWRITE4(sc, GPIO_PIN(pin), reg); 233 } 234 235 int 236 aplpinctrl_get_pin(void *cookie, uint32_t *cells) 237 { 238 struct aplpinctrl_softc *sc = cookie; 239 uint32_t pin = cells[0]; 240 uint32_t flags = cells[1]; 241 uint32_t reg; 242 int val; 243 244 KASSERT(pin < sc->sc_ngpios); 245 246 reg = HREAD4(sc, GPIO_PIN(pin)); 247 val = !!(reg & GPIO_PIN_DATA); 248 if (flags & GPIO_ACTIVE_LOW) 249 val = !val; 250 return val; 251 } 252 253 void 254 aplpinctrl_set_pin(void *cookie, uint32_t *cells, int val) 255 { 256 struct aplpinctrl_softc *sc = cookie; 257 uint32_t pin = cells[0]; 258 uint32_t flags = cells[1]; 259 260 KASSERT(pin < sc->sc_ngpios); 261 262 if (flags & GPIO_ACTIVE_LOW) 263 val = !val; 264 if (val) 265 HSET4(sc, GPIO_PIN(pin), GPIO_PIN_DATA); 266 else 267 HCLR4(sc, GPIO_PIN(pin), GPIO_PIN_DATA); 268 } 269 270 int 271 aplpinctrl_intr(void *arg) 272 { 273 struct aplpinctrl_softc *sc = arg; 274 struct intrhand *ih; 275 uint32_t status, pending; 276 int base, bit, pin, s; 277 278 for (base = 0; base < sc->sc_ngpios; base += 32) { 279 status = HREAD4(sc, GPIO_IRQ(0, base)); 280 pending = status; 281 282 while (pending) { 283 bit = ffs(pending) - 1; 284 pin = base + bit; 285 TAILQ_FOREACH(ih, &sc->sc_handler[pin], ih_list) { 286 s = splraise(ih->ih_ipl); 287 if (ih->ih_func(ih->ih_arg)) 288 ih->ih_count.ec_count++; 289 splx(s); 290 } 291 292 pending &= ~(1 << bit); 293 } 294 295 HWRITE4(sc, GPIO_IRQ(0, base), status); 296 } 297 298 return 1; 299 } 300 301 void * 302 aplpinctrl_intr_establish(void *cookie, int *cells, int ipl, 303 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 304 { 305 struct aplpinctrl_softc *sc = cookie; 306 struct intrhand *ih; 307 uint32_t pin = cells[0]; 308 uint32_t type = IST_NONE; 309 uint32_t reg; 310 311 KASSERT(pin < sc->sc_ngpios); 312 313 if (ci != NULL && !CPU_IS_PRIMARY(ci)) 314 return NULL; 315 316 switch (cells[1]) { 317 case 1: 318 type = IST_EDGE_RISING; 319 break; 320 case 2: 321 type = IST_EDGE_FALLING; 322 break; 323 case 3: 324 type = IST_EDGE_BOTH; 325 break; 326 case 4: 327 type = IST_LEVEL_HIGH; 328 break; 329 case 8: 330 type = IST_LEVEL_LOW; 331 break; 332 } 333 334 ih = TAILQ_FIRST(&sc->sc_handler[pin]); 335 if (ih && ih->ih_type != type) 336 return NULL; 337 338 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 339 ih->ih_func = func; 340 ih->ih_arg = arg; 341 ih->ih_irq = pin; 342 ih->ih_type = type; 343 ih->ih_ipl = ipl & IPL_IRQMASK; 344 ih->ih_name = name; 345 ih->ih_sc = sc; 346 if (name != NULL) 347 evcount_attach(&ih->ih_count, name, &ih->ih_irq); 348 TAILQ_INSERT_TAIL(&sc->sc_handler[pin], ih, ih_list); 349 350 reg = HREAD4(sc, GPIO_PIN(pin)); 351 reg &= ~GPIO_PIN_DATA; 352 reg &= ~GPIO_PIN_FUNC_MASK; 353 reg &= ~GPIO_PIN_MODE_MASK; 354 switch (type) { 355 case IST_NONE: 356 reg |= GPIO_PIN_MODE_IRQ_OFF; 357 break; 358 case IST_EDGE_RISING: 359 reg |= GPIO_PIN_MODE_IRQ_UP; 360 break; 361 case IST_EDGE_FALLING: 362 reg |= GPIO_PIN_MODE_IRQ_DN; 363 break; 364 case IST_EDGE_BOTH: 365 reg |= GPIO_PIN_MODE_IRQ_ANY; 366 break; 367 case IST_LEVEL_HIGH: 368 reg |= GPIO_PIN_MODE_IRQ_HI; 369 break; 370 case IST_LEVEL_LOW: 371 reg |= GPIO_PIN_MODE_IRQ_LO; 372 break; 373 } 374 reg |= GPIO_PIN_INPUT_ENABLE; 375 reg &= ~GPIO_PIN_GROUP_MASK; 376 HWRITE4(sc, GPIO_PIN(pin), reg); 377 378 return ih; 379 } 380 381 void 382 aplpinctrl_intr_disestablish(void *cookie) 383 { 384 struct intrhand *ih = cookie; 385 struct aplpinctrl_softc *sc = ih->ih_sc; 386 uint32_t reg; 387 int s; 388 389 s = splhigh(); 390 391 TAILQ_REMOVE(&sc->sc_handler[ih->ih_irq], ih, ih_list); 392 if (ih->ih_name) 393 evcount_detach(&ih->ih_count); 394 395 if (TAILQ_EMPTY(&sc->sc_handler[ih->ih_irq])) { 396 reg = HREAD4(sc, GPIO_PIN(ih->ih_irq)); 397 reg &= ~GPIO_PIN_MODE_MASK; 398 reg |= GPIO_PIN_MODE_IRQ_OFF; 399 HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg); 400 } 401 402 free(ih, M_DEVBUF, sizeof(*ih)); 403 404 splx(s); 405 } 406 407 void 408 aplpinctrl_intr_enable(void *cookie) 409 { 410 struct intrhand *ih = cookie; 411 struct aplpinctrl_softc *sc = ih->ih_sc; 412 uint32_t reg; 413 int s; 414 415 s = splhigh(); 416 reg = HREAD4(sc, GPIO_PIN(ih->ih_irq)); 417 reg &= ~GPIO_PIN_MODE_MASK; 418 switch (ih->ih_type) { 419 case IST_NONE: 420 reg |= GPIO_PIN_MODE_IRQ_OFF; 421 break; 422 case IST_EDGE_RISING: 423 reg |= GPIO_PIN_MODE_IRQ_UP; 424 break; 425 case IST_EDGE_FALLING: 426 reg |= GPIO_PIN_MODE_IRQ_DN; 427 break; 428 case IST_EDGE_BOTH: 429 reg |= GPIO_PIN_MODE_IRQ_ANY; 430 break; 431 case IST_LEVEL_HIGH: 432 reg |= GPIO_PIN_MODE_IRQ_HI; 433 break; 434 case IST_LEVEL_LOW: 435 reg |= GPIO_PIN_MODE_IRQ_LO; 436 break; 437 } 438 HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg); 439 splx(s); 440 } 441 442 void 443 aplpinctrl_intr_disable(void *cookie) 444 { 445 struct intrhand *ih = cookie; 446 struct aplpinctrl_softc *sc = ih->ih_sc; 447 uint32_t reg; 448 int s; 449 450 s = splhigh(); 451 reg = HREAD4(sc, GPIO_PIN(ih->ih_irq)); 452 reg &= ~GPIO_PIN_MODE_MASK; 453 reg |= GPIO_PIN_MODE_IRQ_OFF; 454 HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg); 455 splx(s); 456 } 457 458 void 459 aplpinctrl_intr_barrier(void *cookie) 460 { 461 struct intrhand *ih = cookie; 462 struct aplpinctrl_softc *sc = ih->ih_sc; 463 464 intr_barrier(sc->sc_ih); 465 } 466