1 /* $OpenBSD: imxgpio.c,v 1.5 2020/07/17 08:07:34 patrick Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/queue.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 #include <sys/evcount.h> 25 26 #include <machine/bus.h> 27 #include <machine/fdt.h> 28 #include <machine/intr.h> 29 30 #include <dev/ofw/openfirm.h> 31 #include <dev/ofw/ofw_gpio.h> 32 #include <dev/ofw/fdt.h> 33 34 /* iMX6 registers */ 35 #define GPIO_DR 0x00 36 #define GPIO_GDIR 0x04 37 #define GPIO_PSR 0x08 38 #define GPIO_ICR1 0x0C 39 #define GPIO_ICR2 0x10 40 #define GPIO_IMR 0x14 41 #define GPIO_ISR 0x18 42 #define GPIO_EDGE_SEL 0x1C 43 44 #define GPIO_NUM_PINS 32 45 46 struct intrhand { 47 int (*ih_func)(void *); /* handler */ 48 void *ih_arg; /* arg for handler */ 49 int ih_ipl; /* IPL_* */ 50 int ih_irq; /* IRQ number */ 51 int ih_level; /* GPIO level */ 52 struct evcount ih_count; 53 char *ih_name; 54 void *ih_sc; 55 }; 56 57 struct imxgpio_softc { 58 struct device sc_dev; 59 bus_space_tag_t sc_iot; 60 bus_space_handle_t sc_ioh; 61 int sc_node; 62 63 void *sc_ih_h; 64 void *sc_ih_l; 65 int sc_ipl; 66 int sc_irq; 67 struct intrhand *sc_handlers[GPIO_NUM_PINS]; 68 struct interrupt_controller sc_ic; 69 70 struct gpio_controller sc_gc; 71 }; 72 73 int imxgpio_match(struct device *, void *, void *); 74 void imxgpio_attach(struct device *, struct device *, void *); 75 76 void imxgpio_config_pin(void *, uint32_t *, int); 77 int imxgpio_get_pin(void *, uint32_t *); 78 void imxgpio_set_pin(void *, uint32_t *, int); 79 80 int imxgpio_intr(void *); 81 void *imxgpio_intr_establish(void *, int *, int, struct cpu_info *, 82 int (*)(void *), void *, char *); 83 void imxgpio_intr_disestablish(void *); 84 void imxgpio_recalc_ipl(struct imxgpio_softc *); 85 void imxgpio_intr_enable(void *); 86 void imxgpio_intr_disable(void *); 87 void imxgpio_intr_barrier(void *); 88 89 90 struct cfattach imxgpio_ca = { 91 sizeof (struct imxgpio_softc), imxgpio_match, imxgpio_attach 92 }; 93 94 struct cfdriver imxgpio_cd = { 95 NULL, "imxgpio", DV_DULL 96 }; 97 98 int 99 imxgpio_match(struct device *parent, void *match, void *aux) 100 { 101 struct fdt_attach_args *faa = aux; 102 103 return OF_is_compatible(faa->fa_node, "fsl,imx35-gpio"); 104 } 105 106 void 107 imxgpio_attach(struct device *parent, struct device *self, void *aux) 108 { 109 struct imxgpio_softc *sc = (struct imxgpio_softc *)self; 110 struct fdt_attach_args *faa = aux; 111 112 if (faa->fa_nreg < 1) 113 return; 114 115 sc->sc_node = faa->fa_node; 116 sc->sc_iot = faa->fa_iot; 117 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 118 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 119 panic("imxgpio_attach: bus_space_map failed!"); 120 121 sc->sc_gc.gc_node = faa->fa_node; 122 sc->sc_gc.gc_cookie = sc; 123 sc->sc_gc.gc_config_pin = imxgpio_config_pin; 124 sc->sc_gc.gc_get_pin = imxgpio_get_pin; 125 sc->sc_gc.gc_set_pin = imxgpio_set_pin; 126 gpio_controller_register(&sc->sc_gc); 127 128 sc->sc_ipl = IPL_NONE; 129 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, 0); 130 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, ~0); 131 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_EDGE_SEL, 0); 132 133 sc->sc_ic.ic_node = faa->fa_node; 134 sc->sc_ic.ic_cookie = sc; 135 sc->sc_ic.ic_establish = imxgpio_intr_establish; 136 sc->sc_ic.ic_disestablish = imxgpio_intr_disestablish; 137 sc->sc_ic.ic_enable = imxgpio_intr_enable; 138 sc->sc_ic.ic_disable = imxgpio_intr_disable; 139 sc->sc_ic.ic_barrier = imxgpio_intr_barrier; 140 fdt_intr_register(&sc->sc_ic); 141 142 printf("\n"); 143 144 /* XXX - SYSCONFIG */ 145 /* XXX - CTRL */ 146 /* XXX - DEBOUNCE */ 147 } 148 149 void 150 imxgpio_config_pin(void *cookie, uint32_t *cells, int config) 151 { 152 struct imxgpio_softc *sc = cookie; 153 uint32_t pin = cells[0]; 154 uint32_t val; 155 156 if (pin >= GPIO_NUM_PINS) 157 return; 158 159 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR); 160 if (config & GPIO_CONFIG_OUTPUT) 161 val |= 1 << pin; 162 else 163 val &= ~(1 << pin); 164 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val); 165 } 166 167 int 168 imxgpio_get_pin(void *cookie, uint32_t *cells) 169 { 170 struct imxgpio_softc *sc = cookie; 171 uint32_t pin = cells[0]; 172 uint32_t flags = cells[1]; 173 uint32_t reg; 174 int val; 175 176 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR); 177 reg &= (1 << pin); 178 val = (reg >> pin) & 1; 179 if (flags & GPIO_ACTIVE_LOW) 180 val = !val; 181 return val; 182 } 183 184 void 185 imxgpio_set_pin(void *cookie, uint32_t *cells, int val) 186 { 187 struct imxgpio_softc *sc = cookie; 188 uint32_t pin = cells[0]; 189 uint32_t flags = cells[1]; 190 uint32_t reg; 191 192 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR); 193 if (flags & GPIO_ACTIVE_LOW) 194 val = !val; 195 if (val) 196 reg |= (1 << pin); 197 else 198 reg &= ~(1 << pin); 199 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR, reg); 200 } 201 202 int 203 imxgpio_intr(void *cookie) 204 { 205 struct imxgpio_softc *sc = (struct imxgpio_softc *)cookie; 206 struct intrhand *ih; 207 uint32_t status, pending, mask; 208 int pin, s; 209 210 status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR); 211 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 212 213 status &= mask; 214 pending = status; 215 216 while (pending) { 217 pin = ffs(pending) - 1; 218 219 if ((ih = sc->sc_handlers[pin]) != NULL) { 220 s = splraise(ih->ih_ipl); 221 if (ih->ih_func(ih->ih_arg)) 222 ih->ih_count.ec_count++; 223 splx(s); 224 } 225 226 pending &= ~(1 << pin); 227 } 228 229 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, status); 230 231 return 1; 232 } 233 234 void * 235 imxgpio_intr_establish(void *cookie, int *cells, int ipl, 236 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 237 { 238 struct imxgpio_softc *sc = (struct imxgpio_softc *)cookie; 239 struct intrhand *ih; 240 int s, val, reg, shift; 241 int irqno = cells[0]; 242 int level = cells[1]; 243 244 if (irqno < 0 || irqno >= GPIO_NUM_PINS) 245 panic("%s: bogus irqnumber %d: %s", __func__, 246 irqno, name); 247 248 if (sc->sc_handlers[irqno] != NULL) 249 panic("%s: irqnumber %d reused: %s", __func__, 250 irqno, name); 251 252 if (ci != NULL && !CPU_IS_PRIMARY(ci)) 253 return NULL; 254 255 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 256 ih->ih_func = func; 257 ih->ih_arg = arg; 258 ih->ih_ipl = ipl; 259 ih->ih_irq = irqno; 260 ih->ih_name = name; 261 ih->ih_level = level; 262 ih->ih_sc = sc; 263 264 s = splhigh(); 265 266 sc->sc_handlers[irqno] = ih; 267 268 if (name != NULL) 269 evcount_attach(&ih->ih_count, name, &ih->ih_irq); 270 271 #ifdef DEBUG_INTC 272 printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl, 273 ih->ih_name); 274 #endif 275 276 imxgpio_recalc_ipl(sc); 277 278 switch (level) { 279 case 1: /* rising */ 280 val = 2; 281 break; 282 case 2: /* falling */ 283 val = 3; 284 break; 285 case 4: /* high */ 286 val = 1; 287 break; 288 case 8: /* low */ 289 val = 0; 290 break; 291 default: 292 panic("%s: unsupported trigger type", __func__); 293 } 294 295 if (irqno < 16) { 296 reg = GPIO_ICR1; 297 shift = irqno << 1; 298 } else { 299 reg = GPIO_ICR2; 300 shift = (irqno - 16) << 1; 301 } 302 303 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, 304 bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) & ~(0x3 << shift)); 305 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, 306 bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) | val << shift); 307 308 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, 309 bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR) | 1 << irqno); 310 311 splx(s); 312 return (ih); 313 } 314 315 void 316 imxgpio_intr_disestablish(void *cookie) 317 { 318 struct intrhand *ih = cookie; 319 struct imxgpio_softc *sc = ih->ih_sc; 320 uint32_t mask; 321 int s; 322 323 s = splhigh(); 324 325 #ifdef DEBUG_INTC 326 printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl, 327 ih->ih_name); 328 #endif 329 330 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 331 mask &= ~(1 << ih->ih_irq); 332 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask); 333 334 sc->sc_handlers[ih->ih_irq] = NULL; 335 if (ih->ih_name != NULL) 336 evcount_detach(&ih->ih_count); 337 free(ih, M_DEVBUF, sizeof(*ih)); 338 339 imxgpio_recalc_ipl(sc); 340 341 splx(s); 342 } 343 344 void 345 imxgpio_recalc_ipl(struct imxgpio_softc *sc) 346 { 347 struct intrhand *ih; 348 int pin; 349 int max = IPL_NONE; 350 int min = IPL_HIGH; 351 352 for (pin = 0; pin < GPIO_NUM_PINS; pin++) { 353 ih = sc->sc_handlers[pin]; 354 if (ih == NULL) 355 continue; 356 357 if (ih->ih_ipl > max) 358 max = ih->ih_ipl; 359 360 if (ih->ih_ipl < min) 361 min = ih->ih_ipl; 362 } 363 364 if (max == IPL_NONE) 365 min = IPL_NONE; 366 367 if (sc->sc_ipl != max) { 368 sc->sc_ipl = max; 369 370 if (sc->sc_ih_l != NULL) 371 fdt_intr_disestablish(sc->sc_ih_l); 372 373 if (sc->sc_ih_h != NULL) 374 fdt_intr_disestablish(sc->sc_ih_h); 375 376 if (sc->sc_ipl != IPL_NONE) { 377 sc->sc_ih_l = fdt_intr_establish_idx(sc->sc_node, 0, 378 sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname); 379 sc->sc_ih_h = fdt_intr_establish_idx(sc->sc_node, 1, 380 sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname); 381 } 382 } 383 } 384 385 void 386 imxgpio_intr_enable(void *cookie) 387 { 388 struct intrhand *ih = cookie; 389 struct imxgpio_softc *sc = ih->ih_sc; 390 uint32_t mask; 391 int s; 392 393 s = splhigh(); 394 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 395 mask |= (1 << ih->ih_irq); 396 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask); 397 splx(s); 398 } 399 400 void 401 imxgpio_intr_disable(void *cookie) 402 { 403 struct intrhand *ih = cookie; 404 struct imxgpio_softc *sc = ih->ih_sc; 405 uint32_t mask; 406 int s; 407 408 s = splhigh(); 409 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 410 mask &= ~(1 << ih->ih_irq); 411 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask); 412 splx(s); 413 } 414 415 void 416 imxgpio_intr_barrier(void *cookie) 417 { 418 struct intrhand *ih = cookie; 419 struct imxgpio_softc *sc = ih->ih_sc; 420 421 if (sc->sc_ih_h && ih->ih_irq >= 16) 422 intr_barrier(sc->sc_ih_h); 423 else if (sc->sc_ih_l) 424 intr_barrier(sc->sc_ih_l); 425 } 426