1 1.11 thorpej /* $NetBSD: imxgpio.c,v 1.11 2021/08/07 16:18:44 thorpej Exp $ */ 2 1.1 bsh 3 1.1 bsh /*- 4 1.9 ad * Copyright (c) 2007, 2020 The NetBSD Foundation, Inc. 5 1.1 bsh * All rights reserved. 6 1.1 bsh * 7 1.1 bsh * This code is derived from software contributed to The NetBSD Foundation 8 1.1 bsh * by Matt Thomas 9 1.1 bsh * 10 1.1 bsh * Redistribution and use in source and binary forms, with or without 11 1.1 bsh * modification, are permitted provided that the following conditions 12 1.1 bsh * are met: 13 1.1 bsh * 1. Redistributions of source code must retain the above copyright 14 1.1 bsh * notice, this list of conditions and the following disclaimer. 15 1.1 bsh * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 bsh * notice, this list of conditions and the following disclaimer in the 17 1.1 bsh * documentation and/or other materials provided with the distribution. 18 1.1 bsh * 19 1.1 bsh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 bsh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 bsh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 bsh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 bsh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 bsh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 bsh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 bsh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 bsh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 bsh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 bsh * POSSIBILITY OF SUCH DAMAGE. 30 1.1 bsh */ 31 1.1 bsh #include <sys/cdefs.h> 32 1.11 thorpej __KERNEL_RCSID(0, "$NetBSD: imxgpio.c,v 1.11 2021/08/07 16:18:44 thorpej Exp $"); 33 1.1 bsh 34 1.1 bsh #define _INTR_PRIVATE 35 1.1 bsh 36 1.1 bsh #include "locators.h" 37 1.1 bsh #include "gpio.h" 38 1.1 bsh 39 1.1 bsh #include <sys/param.h> 40 1.1 bsh #include <sys/evcnt.h> 41 1.1 bsh #include <sys/atomic.h> 42 1.6 hkenken #include <sys/bus.h> 43 1.9 ad #include <sys/cpu.h> 44 1.9 ad #include <sys/intr.h> 45 1.1 bsh 46 1.1 bsh #include <arm/cpu.h> 47 1.1 bsh #include <arm/armreg.h> 48 1.1 bsh #include <arm/cpufunc.h> 49 1.1 bsh 50 1.1 bsh #include <arm/imx/imxgpioreg.h> 51 1.1 bsh #include <arm/imx/imxgpiovar.h> 52 1.1 bsh 53 1.1 bsh #if NGPIO > 0 54 1.1 bsh /* GPIO access from userland */ 55 1.1 bsh #include <sys/gpio.h> 56 1.1 bsh #include <dev/gpio/gpiovar.h> 57 1.1 bsh #endif 58 1.1 bsh 59 1.5 ryo #define MAX_NGROUP 8 60 1.1 bsh 61 1.6 hkenken static void imxgpio_pic_block_irqs(struct pic_softc *, size_t, uint32_t); 62 1.6 hkenken static void imxgpio_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t); 63 1.6 hkenken static int imxgpio_pic_find_pending_irqs(struct pic_softc *); 64 1.6 hkenken static void imxgpio_pic_establish_irq(struct pic_softc *, struct intrsource *); 65 1.6 hkenken 66 1.6 hkenken const struct pic_ops imxgpio_pic_ops = { 67 1.6 hkenken .pic_unblock_irqs = imxgpio_pic_unblock_irqs, 68 1.6 hkenken .pic_block_irqs = imxgpio_pic_block_irqs, 69 1.6 hkenken .pic_find_pending_irqs = imxgpio_pic_find_pending_irqs, 70 1.6 hkenken .pic_establish_irq = imxgpio_pic_establish_irq, 71 1.1 bsh .pic_source_name = NULL 72 1.1 bsh }; 73 1.1 bsh 74 1.6 hkenken static struct imxgpio_softc *imxgpio_handles[MAX_NGROUP]; 75 1.6 hkenken 76 1.6 hkenken CFATTACH_DECL_NEW(imxgpio, sizeof(struct imxgpio_softc), 77 1.6 hkenken imxgpio_match, imxgpio_attach, NULL, NULL); 78 1.1 bsh 79 1.6 hkenken #define PIC_TO_SOFTC(pic) \ 80 1.6 hkenken ((struct imxgpio_softc *)((char *)(pic) - \ 81 1.6 hkenken offsetof(struct imxgpio_softc, gpio_pic))) 82 1.1 bsh 83 1.6 hkenken #define GPIO_READ(gpio, reg) \ 84 1.1 bsh bus_space_read_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg)) 85 1.6 hkenken #define GPIO_WRITE(gpio, reg, val) \ 86 1.1 bsh bus_space_write_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg), (val)) 87 1.1 bsh 88 1.1 bsh void 89 1.6 hkenken imxgpio_pic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) 90 1.1 bsh { 91 1.6 hkenken struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic); 92 1.1 bsh KASSERT(irq_base == 0); 93 1.1 bsh 94 1.1 bsh gpio->gpio_enable_mask |= irq_mask; 95 1.1 bsh 96 1.1 bsh GPIO_WRITE(gpio, GPIO_ISR, irq_mask); 97 1.1 bsh GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask); 98 1.1 bsh } 99 1.1 bsh 100 1.1 bsh void 101 1.6 hkenken imxgpio_pic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) 102 1.1 bsh { 103 1.6 hkenken struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic); 104 1.1 bsh KASSERT(irq_base == 0); 105 1.1 bsh 106 1.1 bsh gpio->gpio_enable_mask &= ~irq_mask; 107 1.1 bsh GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask); 108 1.1 bsh } 109 1.1 bsh 110 1.1 bsh int 111 1.6 hkenken imxgpio_pic_find_pending_irqs(struct pic_softc *pic) 112 1.1 bsh { 113 1.6 hkenken struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic); 114 1.1 bsh uint32_t v; 115 1.1 bsh uint32_t pending; 116 1.1 bsh 117 1.1 bsh v = GPIO_READ(gpio, GPIO_ISR); 118 1.1 bsh pending = (v & gpio->gpio_enable_mask); 119 1.1 bsh if (pending == 0) 120 1.1 bsh return 0; 121 1.1 bsh 122 1.1 bsh /* 123 1.1 bsh * Disable the pending interrupts. 124 1.1 bsh */ 125 1.1 bsh gpio->gpio_enable_mask &= ~pending; 126 1.1 bsh GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask); 127 1.1 bsh 128 1.1 bsh /* 129 1.1 bsh * If any of the sources are edge triggered, ack them now so 130 1.1 bsh * we won't lose them. 131 1.1 bsh */ 132 1.1 bsh if (v & gpio->gpio_edge_mask) 133 1.1 bsh GPIO_WRITE(gpio, GPIO_ISR, v & gpio->gpio_edge_mask); 134 1.1 bsh 135 1.1 bsh /* 136 1.1 bsh * Now find all the pending bits and mark them as pending. 137 1.1 bsh */ 138 1.1 bsh do { 139 1.1 bsh int irq; 140 1.1 bsh KASSERT(pending != 0); 141 1.1 bsh irq = 31 - __builtin_clz(pending); 142 1.1 bsh pending &= ~__BIT(irq); 143 1.4 hkenken 144 1.4 hkenken const struct intrsource *is = pic->pic_sources[irq]; 145 1.4 hkenken if (is->is_type == IST_EDGE_BOTH) { 146 1.4 hkenken /* 147 1.4 hkenken * for both edge 148 1.4 hkenken */ 149 1.4 hkenken uint32_t icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2); 150 1.4 hkenken v = GPIO_READ(gpio, icr_reg); 151 1.4 hkenken uint32_t icr_shift = (is->is_irq & 0x0f) << 1; 152 1.4 hkenken uint32_t mask = (3 << icr_shift); 153 1.4 hkenken int gtype = __SHIFTOUT(v, mask); 154 1.4 hkenken if (gtype == GPIO_ICR_EDGE_RISING) 155 1.4 hkenken gtype = GPIO_ICR_EDGE_FALLING; 156 1.4 hkenken else if (gtype == GPIO_ICR_EDGE_FALLING) 157 1.4 hkenken gtype = GPIO_ICR_EDGE_RISING; 158 1.4 hkenken v &= ~mask; 159 1.4 hkenken v |= __SHIFTIN(gtype, mask); 160 1.4 hkenken GPIO_WRITE(gpio, icr_reg, v); 161 1.4 hkenken } 162 1.1 bsh pic_mark_pending(&gpio->gpio_pic, irq); 163 1.1 bsh } while (pending != 0); 164 1.1 bsh 165 1.1 bsh return 1; 166 1.1 bsh } 167 1.1 bsh 168 1.1 bsh #define GPIO_TYPEMAP \ 169 1.1 bsh ((GPIO_ICR_LEVEL_LOW << (2*IST_LEVEL_LOW)) | \ 170 1.1 bsh (GPIO_ICR_LEVEL_HIGH << (2*IST_LEVEL_HIGH)) | \ 171 1.1 bsh (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_RISING)) | \ 172 1.4 hkenken (GPIO_ICR_EDGE_FALLING << (2*IST_EDGE_FALLING)) | \ 173 1.4 hkenken (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_BOTH))) 174 1.1 bsh 175 1.1 bsh void 176 1.6 hkenken imxgpio_pic_establish_irq(struct pic_softc *pic, struct intrsource *is) 177 1.1 bsh { 178 1.6 hkenken struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic); 179 1.1 bsh KASSERT(is->is_irq < 32); 180 1.1 bsh uint32_t irq_mask = __BIT(is->is_irq); 181 1.1 bsh uint32_t v; 182 1.1 bsh unsigned int icr_shift, icr_reg; 183 1.1 bsh unsigned int gtype; 184 1.1 bsh 185 1.1 bsh /* 186 1.1 bsh * Make sure the irq isn't enabled and not asserting. 187 1.1 bsh */ 188 1.1 bsh gpio->gpio_enable_mask &= ~irq_mask; 189 1.1 bsh GPIO_WRITE(gpio, GPIO_ISR, irq_mask); 190 1.1 bsh GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask); 191 1.1 bsh /* 192 1.1 bsh * Convert the type to a gpio type and figure out which bits in what 193 1.1 bsh * register we have to tweak. 194 1.1 bsh */ 195 1.1 bsh gtype = (GPIO_TYPEMAP >> (2 * is->is_type)) & 3; 196 1.1 bsh icr_shift = (is->is_irq & 0x0f) << 1; 197 1.1 bsh icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2); 198 1.1 bsh 199 1.1 bsh /* 200 1.1 bsh * Set the interrupt type. 201 1.1 bsh */ 202 1.1 bsh v = GPIO_READ(gpio, icr_reg); 203 1.1 bsh v &= ~(3 << icr_shift); 204 1.1 bsh v |= gtype << icr_shift; 205 1.1 bsh GPIO_WRITE(gpio, icr_reg, v); 206 1.1 bsh 207 1.1 bsh /* 208 1.1 bsh * Mark it as input. 209 1.1 bsh */ 210 1.1 bsh v = GPIO_READ(gpio, GPIO_DIR); 211 1.1 bsh v &= ~irq_mask; 212 1.1 bsh GPIO_WRITE(gpio, GPIO_DIR, v); 213 1.1 bsh 214 1.1 bsh /* 215 1.1 bsh * Now record the type of interrupt. 216 1.1 bsh */ 217 1.1 bsh if (gtype == GPIO_ICR_EDGE_RISING || gtype == GPIO_ICR_EDGE_FALLING) { 218 1.1 bsh gpio->gpio_edge_mask |= irq_mask; 219 1.1 bsh gpio->gpio_level_mask &= ~irq_mask; 220 1.1 bsh } else { 221 1.1 bsh gpio->gpio_edge_mask &= ~irq_mask; 222 1.1 bsh gpio->gpio_level_mask |= irq_mask; 223 1.1 bsh } 224 1.1 bsh } 225 1.1 bsh 226 1.1 bsh #if NGPIO > 0 227 1.1 bsh 228 1.6 hkenken int 229 1.1 bsh imxgpio_pin_read(void *arg, int pin) 230 1.1 bsh { 231 1.6 hkenken struct imxgpio_softc * const gpio = arg; 232 1.6 hkenken int val; 233 1.6 hkenken 234 1.6 hkenken val = __SHIFTOUT(GPIO_READ(gpio, GPIO_DR), __BIT(pin)); 235 1.1 bsh 236 1.6 hkenken return val; 237 1.1 bsh } 238 1.1 bsh 239 1.6 hkenken void 240 1.1 bsh imxgpio_pin_write(void *arg, int pin, int value) 241 1.1 bsh { 242 1.6 hkenken struct imxgpio_softc * const gpio = arg; 243 1.6 hkenken uint32_t mask = __BIT(pin); 244 1.6 hkenken uint32_t old; 245 1.6 hkenken uint32_t new; 246 1.6 hkenken 247 1.6 hkenken mutex_enter(&gpio->gpio_lock); 248 1.1 bsh 249 1.1 bsh old = GPIO_READ(gpio, GPIO_DR); 250 1.1 bsh if (value) 251 1.1 bsh new = old | mask; 252 1.1 bsh else 253 1.1 bsh new = old & ~mask; 254 1.1 bsh 255 1.1 bsh if (old != new) 256 1.1 bsh GPIO_WRITE(gpio, GPIO_DR, new); 257 1.6 hkenken 258 1.6 hkenken mutex_exit(&gpio->gpio_lock); 259 1.1 bsh } 260 1.1 bsh 261 1.6 hkenken void 262 1.1 bsh imxgpio_pin_ctl(void *arg, int pin, int flags) 263 1.1 bsh { 264 1.6 hkenken struct imxgpio_softc * const gpio = arg; 265 1.6 hkenken uint32_t mask = __BIT(pin); 266 1.6 hkenken uint32_t old; 267 1.6 hkenken uint32_t new; 268 1.6 hkenken 269 1.6 hkenken mutex_enter(&gpio->gpio_lock); 270 1.1 bsh 271 1.1 bsh old = GPIO_READ(gpio, GPIO_DIR); 272 1.1 bsh new = old; 273 1.6 hkenken switch (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 274 1.6 hkenken case GPIO_PIN_INPUT: 275 1.6 hkenken new &= ~mask; 276 1.6 hkenken break; 277 1.6 hkenken case GPIO_PIN_OUTPUT: 278 1.6 hkenken new |= mask; 279 1.6 hkenken break; 280 1.6 hkenken default: 281 1.6 hkenken break; 282 1.1 bsh } 283 1.6 hkenken 284 1.1 bsh if (old != new) 285 1.1 bsh GPIO_WRITE(gpio, GPIO_DIR, new); 286 1.6 hkenken 287 1.6 hkenken mutex_exit(&gpio->gpio_lock); 288 1.1 bsh } 289 1.1 bsh 290 1.1 bsh static void 291 1.7 hkenken imxgpio_attach_ports(struct imxgpio_softc *gpio) 292 1.1 bsh { 293 1.1 bsh struct gpio_chipset_tag * const gp = &gpio->gpio_chipset; 294 1.1 bsh struct gpiobus_attach_args gba; 295 1.7 hkenken uint32_t dir; 296 1.7 hkenken u_int pin; 297 1.1 bsh 298 1.1 bsh gp->gp_cookie = gpio; 299 1.1 bsh gp->gp_pin_read = imxgpio_pin_read; 300 1.1 bsh gp->gp_pin_write = imxgpio_pin_write; 301 1.1 bsh gp->gp_pin_ctl = imxgpio_pin_ctl; 302 1.1 bsh 303 1.1 bsh dir = GPIO_READ(gpio, GPIO_DIR); 304 1.7 hkenken for (pin = 0; pin < __arraycount(gpio->gpio_pins); pin++) { 305 1.7 hkenken uint32_t mask = __BIT(pin); 306 1.7 hkenken gpio_pin_t *pins = &gpio->gpio_pins[pin]; 307 1.1 bsh pins->pin_num = pin; 308 1.6 hkenken if ((gpio->gpio_edge_mask | gpio->gpio_level_mask) & mask) 309 1.1 bsh pins->pin_caps = GPIO_PIN_INPUT; 310 1.1 bsh else 311 1.7 hkenken pins->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 312 1.1 bsh pins->pin_flags = 313 1.1 bsh (dir & mask) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; 314 1.7 hkenken pins->pin_state = imxgpio_pin_read(gpio, pin); 315 1.1 bsh } 316 1.1 bsh 317 1.7 hkenken memset(&gba, 0, sizeof(gba)); 318 1.7 hkenken gba.gba_gc = gp; 319 1.7 hkenken gba.gba_pins = gpio->gpio_pins; 320 1.7 hkenken gba.gba_npins = __arraycount(gpio->gpio_pins); 321 1.11 thorpej config_found(gpio->gpio_dev, &gba, gpiobus_print, CFARGS_NONE); 322 1.1 bsh } 323 1.1 bsh #endif /* NGPIO > 0 */ 324 1.1 bsh 325 1.1 bsh void 326 1.6 hkenken imxgpio_attach_common(device_t self) 327 1.1 bsh { 328 1.6 hkenken struct imxgpio_softc * const gpio = device_private(self); 329 1.1 bsh 330 1.1 bsh gpio->gpio_dev = self; 331 1.1 bsh 332 1.8 jmcneill if (gpio->gpio_irqbase == PIC_IRQBASE_ALLOC || gpio->gpio_irqbase > 0) { 333 1.6 hkenken gpio->gpio_pic.pic_ops = &imxgpio_pic_ops; 334 1.3 chs strlcpy(gpio->gpio_pic.pic_name, device_xname(self), 335 1.1 bsh sizeof(gpio->gpio_pic.pic_name)); 336 1.8 jmcneill gpio->gpio_pic.pic_maxsources = GPIO_NPINS; 337 1.1 bsh 338 1.8 jmcneill gpio->gpio_irqbase = pic_add(&gpio->gpio_pic, gpio->gpio_irqbase); 339 1.8 jmcneill 340 1.8 jmcneill aprint_normal_dev(gpio->gpio_dev, "interrupts %d..%d\n", 341 1.8 jmcneill gpio->gpio_irqbase, gpio->gpio_irqbase + GPIO_NPINS - 1); 342 1.6 hkenken } 343 1.1 bsh 344 1.6 hkenken mutex_init(&gpio->gpio_lock, MUTEX_DEFAULT, IPL_VM); 345 1.1 bsh 346 1.8 jmcneill if (gpio->gpio_unit != -1) { 347 1.8 jmcneill KASSERT(gpio->gpio_unit < MAX_NGROUP); 348 1.8 jmcneill imxgpio_handles[gpio->gpio_unit] = gpio; 349 1.8 jmcneill } 350 1.1 bsh 351 1.1 bsh #if NGPIO > 0 352 1.7 hkenken imxgpio_attach_ports(gpio); 353 1.1 bsh #endif 354 1.1 bsh } 355 1.1 bsh 356 1.6 hkenken /* in-kernel GPIO access utility functions */ 357 1.1 bsh void 358 1.8 jmcneill imxgpio_set_direction(u_int gpio, int dir) 359 1.1 bsh { 360 1.1 bsh int index = gpio / GPIO_NPINS; 361 1.6 hkenken int pin = gpio % GPIO_NPINS; 362 1.1 bsh 363 1.1 bsh KDASSERT(index < imxgpio_ngroups); 364 1.6 hkenken KASSERT(imxgpio_handles[index] != NULL); 365 1.1 bsh 366 1.6 hkenken imxgpio_pin_ctl(imxgpio_handles[index], pin, dir); 367 1.1 bsh } 368 1.1 bsh 369 1.1 bsh void 370 1.8 jmcneill imxgpio_data_write(u_int gpio, u_int value) 371 1.1 bsh { 372 1.1 bsh int index = gpio / GPIO_NPINS; 373 1.6 hkenken int pin = gpio % GPIO_NPINS; 374 1.1 bsh 375 1.1 bsh KDASSERT(index < imxgpio_ngroups); 376 1.6 hkenken KASSERT(imxgpio_handles[index] != NULL); 377 1.1 bsh 378 1.6 hkenken imxgpio_pin_write(imxgpio_handles[index], pin, value); 379 1.1 bsh } 380 1.1 bsh 381 1.1 bsh bool 382 1.8 jmcneill imxgpio_data_read(u_int gpio) 383 1.1 bsh { 384 1.1 bsh int index = gpio / GPIO_NPINS; 385 1.6 hkenken int pin = gpio % GPIO_NPINS; 386 1.1 bsh 387 1.1 bsh KDASSERT(index < imxgpio_ngroups); 388 1.6 hkenken KASSERT(imxgpio_handles[index] != NULL); 389 1.1 bsh 390 1.6 hkenken return imxgpio_pin_read(imxgpio_handles[index], pin) ? true : false; 391 1.6 hkenken } 392 1.1 bsh 393