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