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
imxgpio_pic_unblock_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)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
imxgpio_pic_block_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)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
imxgpio_pic_find_pending_irqs(struct pic_softc * pic)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
imxgpio_pic_establish_irq(struct pic_softc * pic,struct intrsource * is)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
imxgpio_pin_read(void * arg,int pin)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
imxgpio_pin_write(void * arg,int pin,int value)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
imxgpio_pin_ctl(void * arg,int pin,int flags)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
imxgpio_attach_ports(struct imxgpio_softc * gpio)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
imxgpio_attach_common(device_t self)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
imxgpio_set_direction(u_int gpio,int dir)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
imxgpio_data_write(u_int gpio,u_int value)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
imxgpio_data_read(u_int gpio)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