imxgpio.c revision 1.11 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