1 /* $OpenBSD: imxgpio.c,v 1.7 2023/03/05 14:45:07 patrick Exp $ */
2 /*
3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/queue.h>
22 #include <sys/device.h>
23 #include <sys/malloc.h>
24 #include <sys/evcount.h>
25
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 #include <machine/intr.h>
29
30 #include <dev/ofw/openfirm.h>
31 #include <dev/ofw/ofw_gpio.h>
32 #include <dev/ofw/fdt.h>
33
34 /* iMX6 registers */
35 #define GPIO_DR 0x00
36 #define GPIO_GDIR 0x04
37 #define GPIO_PSR 0x08
38 #define GPIO_ICR1 0x0C
39 #define GPIO_ICR2 0x10
40 #define GPIO_IMR 0x14
41 #define GPIO_ISR 0x18
42 #define GPIO_EDGE_SEL 0x1C
43
44 #define GPIO_NUM_PINS 32
45
46 struct intrhand {
47 int (*ih_func)(void *); /* handler */
48 void *ih_arg; /* arg for handler */
49 int ih_ipl; /* IPL_* */
50 int ih_irq; /* IRQ number */
51 int ih_level; /* GPIO level */
52 struct evcount ih_count;
53 char *ih_name;
54 void *ih_sc;
55 };
56
57 struct imxgpio_softc {
58 struct device sc_dev;
59 bus_space_tag_t sc_iot;
60 bus_space_handle_t sc_ioh;
61 int sc_node;
62
63 void *sc_ih_h;
64 void *sc_ih_l;
65 int sc_ipl;
66 int sc_irq;
67 struct intrhand *sc_handlers[GPIO_NUM_PINS];
68 struct interrupt_controller sc_ic;
69
70 struct gpio_controller sc_gc;
71 };
72
73 int imxgpio_match(struct device *, void *, void *);
74 void imxgpio_attach(struct device *, struct device *, void *);
75
76 void imxgpio_config_pin(void *, uint32_t *, int);
77 int imxgpio_get_pin(void *, uint32_t *);
78 void imxgpio_set_pin(void *, uint32_t *, int);
79
80 int imxgpio_intr(void *);
81 void *imxgpio_intr_establish(void *, int *, int, struct cpu_info *,
82 int (*)(void *), void *, char *);
83 void imxgpio_intr_disestablish(void *);
84 void imxgpio_recalc_ipl(struct imxgpio_softc *);
85 void imxgpio_intr_enable(void *);
86 void imxgpio_intr_disable(void *);
87 void imxgpio_intr_barrier(void *);
88
89
90 const struct cfattach imxgpio_ca = {
91 sizeof (struct imxgpio_softc), imxgpio_match, imxgpio_attach
92 };
93
94 struct cfdriver imxgpio_cd = {
95 NULL, "imxgpio", DV_DULL
96 };
97
98 int
imxgpio_match(struct device * parent,void * match,void * aux)99 imxgpio_match(struct device *parent, void *match, void *aux)
100 {
101 struct fdt_attach_args *faa = aux;
102
103 return OF_is_compatible(faa->fa_node, "fsl,imx35-gpio");
104 }
105
106 void
imxgpio_attach(struct device * parent,struct device * self,void * aux)107 imxgpio_attach(struct device *parent, struct device *self, void *aux)
108 {
109 struct imxgpio_softc *sc = (struct imxgpio_softc *)self;
110 struct fdt_attach_args *faa = aux;
111
112 if (faa->fa_nreg < 1)
113 return;
114
115 sc->sc_node = faa->fa_node;
116 sc->sc_iot = faa->fa_iot;
117 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
118 faa->fa_reg[0].size, 0, &sc->sc_ioh))
119 panic("imxgpio_attach: bus_space_map failed!");
120
121 sc->sc_gc.gc_node = faa->fa_node;
122 sc->sc_gc.gc_cookie = sc;
123 sc->sc_gc.gc_config_pin = imxgpio_config_pin;
124 sc->sc_gc.gc_get_pin = imxgpio_get_pin;
125 sc->sc_gc.gc_set_pin = imxgpio_set_pin;
126 gpio_controller_register(&sc->sc_gc);
127
128 sc->sc_ipl = IPL_NONE;
129 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, 0);
130 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, ~0);
131 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_EDGE_SEL, 0);
132
133 sc->sc_ic.ic_node = faa->fa_node;
134 sc->sc_ic.ic_cookie = sc;
135 sc->sc_ic.ic_establish = imxgpio_intr_establish;
136 sc->sc_ic.ic_disestablish = imxgpio_intr_disestablish;
137 sc->sc_ic.ic_enable = imxgpio_intr_enable;
138 sc->sc_ic.ic_disable = imxgpio_intr_disable;
139 sc->sc_ic.ic_barrier = imxgpio_intr_barrier;
140 fdt_intr_register(&sc->sc_ic);
141
142 printf("\n");
143
144 /* XXX - SYSCONFIG */
145 /* XXX - CTRL */
146 /* XXX - DEBOUNCE */
147 }
148
149 void
imxgpio_config_pin(void * cookie,uint32_t * cells,int config)150 imxgpio_config_pin(void *cookie, uint32_t *cells, int config)
151 {
152 struct imxgpio_softc *sc = cookie;
153 uint32_t pin = cells[0];
154 uint32_t val;
155
156 if (pin >= GPIO_NUM_PINS)
157 return;
158
159 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
160 if (config & GPIO_CONFIG_OUTPUT)
161 val |= 1 << pin;
162 else
163 val &= ~(1 << pin);
164 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val);
165 }
166
167 int
imxgpio_get_pin(void * cookie,uint32_t * cells)168 imxgpio_get_pin(void *cookie, uint32_t *cells)
169 {
170 struct imxgpio_softc *sc = cookie;
171 uint32_t pin = cells[0];
172 uint32_t flags = cells[1];
173 uint32_t reg;
174 int val;
175
176 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
177 reg &= (1 << pin);
178 val = (reg >> pin) & 1;
179 if (flags & GPIO_ACTIVE_LOW)
180 val = !val;
181 return val;
182 }
183
184 void
imxgpio_set_pin(void * cookie,uint32_t * cells,int val)185 imxgpio_set_pin(void *cookie, uint32_t *cells, int val)
186 {
187 struct imxgpio_softc *sc = cookie;
188 uint32_t pin = cells[0];
189 uint32_t flags = cells[1];
190 uint32_t reg;
191
192 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
193 if (flags & GPIO_ACTIVE_LOW)
194 val = !val;
195 if (val)
196 reg |= (1 << pin);
197 else
198 reg &= ~(1 << pin);
199 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR, reg);
200 }
201
202 int
imxgpio_intr(void * cookie)203 imxgpio_intr(void *cookie)
204 {
205 struct imxgpio_softc *sc = (struct imxgpio_softc *)cookie;
206 struct intrhand *ih;
207 uint32_t status, pending, mask;
208 int pin, s;
209
210 status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR);
211 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
212
213 status &= mask;
214 pending = status;
215
216 while (pending) {
217 pin = ffs(pending) - 1;
218
219 if ((ih = sc->sc_handlers[pin]) != NULL) {
220 s = splraise(ih->ih_ipl);
221 if (ih->ih_func(ih->ih_arg))
222 ih->ih_count.ec_count++;
223 splx(s);
224 }
225
226 pending &= ~(1 << pin);
227 }
228
229 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, status);
230
231 return 1;
232 }
233
234 void *
imxgpio_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)235 imxgpio_intr_establish(void *cookie, int *cells, int ipl,
236 struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
237 {
238 struct imxgpio_softc *sc = (struct imxgpio_softc *)cookie;
239 struct intrhand *ih;
240 int s, val, reg, shift;
241 int irqno = cells[0];
242 int level = cells[1];
243
244 if (irqno < 0 || irqno >= GPIO_NUM_PINS)
245 panic("%s: bogus irqnumber %d: %s", __func__,
246 irqno, name);
247
248 if (sc->sc_handlers[irqno] != NULL)
249 panic("%s: irqnumber %d reused: %s", __func__,
250 irqno, name);
251
252 if (ci != NULL && !CPU_IS_PRIMARY(ci))
253 return NULL;
254
255 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
256 ih->ih_func = func;
257 ih->ih_arg = arg;
258 ih->ih_ipl = ipl & IPL_IRQMASK;
259 ih->ih_irq = irqno;
260 ih->ih_name = name;
261 ih->ih_level = level;
262 ih->ih_sc = sc;
263
264 s = splhigh();
265
266 sc->sc_handlers[irqno] = ih;
267
268 if (name != NULL)
269 evcount_attach(&ih->ih_count, name, &ih->ih_irq);
270
271 #ifdef DEBUG_INTC
272 printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
273 ih->ih_name);
274 #endif
275
276 imxgpio_recalc_ipl(sc);
277
278 switch (level) {
279 case 1: /* rising */
280 val = 2;
281 break;
282 case 2: /* falling */
283 val = 3;
284 break;
285 case 4: /* high */
286 val = 1;
287 break;
288 case 8: /* low */
289 val = 0;
290 break;
291 default:
292 panic("%s: unsupported trigger type", __func__);
293 }
294
295 if (irqno < 16) {
296 reg = GPIO_ICR1;
297 shift = irqno << 1;
298 } else {
299 reg = GPIO_ICR2;
300 shift = (irqno - 16) << 1;
301 }
302
303 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg,
304 bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) & ~(0x3 << shift));
305 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg,
306 bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) | val << shift);
307
308 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR,
309 bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR) | 1 << irqno);
310
311 splx(s);
312 return (ih);
313 }
314
315 void
imxgpio_intr_disestablish(void * cookie)316 imxgpio_intr_disestablish(void *cookie)
317 {
318 struct intrhand *ih = cookie;
319 struct imxgpio_softc *sc = ih->ih_sc;
320 uint32_t mask;
321 int s;
322
323 s = splhigh();
324
325 #ifdef DEBUG_INTC
326 printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
327 ih->ih_name);
328 #endif
329
330 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
331 mask &= ~(1 << ih->ih_irq);
332 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask);
333
334 sc->sc_handlers[ih->ih_irq] = NULL;
335 if (ih->ih_name != NULL)
336 evcount_detach(&ih->ih_count);
337 free(ih, M_DEVBUF, sizeof(*ih));
338
339 imxgpio_recalc_ipl(sc);
340
341 splx(s);
342 }
343
344 void
imxgpio_recalc_ipl(struct imxgpio_softc * sc)345 imxgpio_recalc_ipl(struct imxgpio_softc *sc)
346 {
347 struct intrhand *ih;
348 int pin;
349 int max = IPL_NONE;
350 int min = IPL_HIGH;
351
352 for (pin = 0; pin < GPIO_NUM_PINS; pin++) {
353 ih = sc->sc_handlers[pin];
354 if (ih == NULL)
355 continue;
356
357 if (ih->ih_ipl > max)
358 max = ih->ih_ipl;
359
360 if (ih->ih_ipl < min)
361 min = ih->ih_ipl;
362 }
363
364 if (max == IPL_NONE)
365 min = IPL_NONE;
366
367 if (sc->sc_ipl != max) {
368 sc->sc_ipl = max;
369
370 if (sc->sc_ih_l != NULL)
371 fdt_intr_disestablish(sc->sc_ih_l);
372
373 if (sc->sc_ih_h != NULL)
374 fdt_intr_disestablish(sc->sc_ih_h);
375
376 if (sc->sc_ipl != IPL_NONE) {
377 sc->sc_ih_l = fdt_intr_establish_idx(sc->sc_node, 0,
378 sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname);
379 sc->sc_ih_h = fdt_intr_establish_idx(sc->sc_node, 1,
380 sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname);
381 }
382 }
383 }
384
385 void
imxgpio_intr_enable(void * cookie)386 imxgpio_intr_enable(void *cookie)
387 {
388 struct intrhand *ih = cookie;
389 struct imxgpio_softc *sc = ih->ih_sc;
390 uint32_t mask;
391 int s;
392
393 s = splhigh();
394 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
395 mask |= (1 << ih->ih_irq);
396 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask);
397 splx(s);
398 }
399
400 void
imxgpio_intr_disable(void * cookie)401 imxgpio_intr_disable(void *cookie)
402 {
403 struct intrhand *ih = cookie;
404 struct imxgpio_softc *sc = ih->ih_sc;
405 uint32_t mask;
406 int s;
407
408 s = splhigh();
409 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
410 mask &= ~(1 << ih->ih_irq);
411 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask);
412 splx(s);
413 }
414
415 void
imxgpio_intr_barrier(void * cookie)416 imxgpio_intr_barrier(void *cookie)
417 {
418 struct intrhand *ih = cookie;
419 struct imxgpio_softc *sc = ih->ih_sc;
420
421 if (sc->sc_ih_h && ih->ih_irq >= 16)
422 intr_barrier(sc->sc_ih_h);
423 else if (sc->sc_ih_l)
424 intr_barrier(sc->sc_ih_l);
425 }
426