Home | History | Annotate | Line # | Download | only in imx
      1 /*	$NetBSD: imxgpio.c,v 1.11 2021/08/07 16:18:44 thorpej 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.11 2021/08/07 16:18:44 thorpej 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(gpio->gpio_dev, &gba, gpiobus_print, CFARGS_NONE);
    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