1 /* $OpenBSD: aplpinctrl.c,v 1.8 2023/07/23 11:17:50 kettenis Exp $ */
2 /*
3 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/evcount.h>
22 #include <sys/malloc.h>
23
24 #include <machine/bus.h>
25 #include <machine/fdt.h>
26 #include <machine/intr.h>
27
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_gpio.h>
30 #include <dev/ofw/ofw_pinctrl.h>
31 #include <dev/ofw/ofw_power.h>
32 #include <dev/ofw/fdt.h>
33
34 #define APPLE_PIN(pinmux) ((pinmux) & 0xffff)
35 #define APPLE_FUNC(pinmux) ((pinmux) >> 16)
36
37 #define GPIO_PIN(pin) ((pin) * 4)
38 #define GPIO_PIN_GROUP_MASK (7 << 16)
39 #define GPIO_PIN_INPUT_ENABLE (1 << 9)
40 #define GPIO_PIN_FUNC_MASK (3 << 5)
41 #define GPIO_PIN_FUNC_SHIFT 5
42 #define GPIO_PIN_MODE_MASK (7 << 1)
43 #define GPIO_PIN_MODE_INPUT (0 << 1)
44 #define GPIO_PIN_MODE_OUTPUT (1 << 1)
45 #define GPIO_PIN_MODE_IRQ_HI (2 << 1)
46 #define GPIO_PIN_MODE_IRQ_LO (3 << 1)
47 #define GPIO_PIN_MODE_IRQ_UP (4 << 1)
48 #define GPIO_PIN_MODE_IRQ_DN (5 << 1)
49 #define GPIO_PIN_MODE_IRQ_ANY (6 << 1)
50 #define GPIO_PIN_MODE_IRQ_OFF (7 << 1)
51 #define GPIO_PIN_DATA (1 << 0)
52 #define GPIO_IRQ(grp, pin) (0x800 + (grp) * 64 + ((pin) >> 5) * 4)
53
54 #define HREAD4(sc, reg) \
55 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
56 #define HWRITE4(sc, reg, val) \
57 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
58 #define HSET4(sc, reg, bits) \
59 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
60 #define HCLR4(sc, reg, bits) \
61 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
62
63 struct intrhand {
64 TAILQ_ENTRY(intrhand) ih_list;
65 int (*ih_func)(void *);
66 void *ih_arg;
67 int ih_irq;
68 int ih_type;
69 int ih_ipl;
70 struct evcount ih_count;
71 char *ih_name;
72 void *ih_sc;
73 };
74
75 struct aplpinctrl_softc {
76 struct device sc_dev;
77 bus_space_tag_t sc_iot;
78 bus_space_handle_t sc_ioh;
79
80 int sc_ngpios;
81 struct gpio_controller sc_gc;
82
83 void *sc_ih;
84 TAILQ_HEAD(, intrhand) *sc_handler;
85 struct interrupt_controller sc_ic;
86 };
87
88 int aplpinctrl_match(struct device *, void *, void *);
89 void aplpinctrl_attach(struct device *, struct device *, void *);
90
91 const struct cfattach aplpinctrl_ca = {
92 sizeof (struct aplpinctrl_softc), aplpinctrl_match, aplpinctrl_attach
93 };
94
95 struct cfdriver aplpinctrl_cd = {
96 NULL, "aplpinctrl", DV_DULL
97 };
98
99 int aplpinctrl_pinctrl(uint32_t, void *);
100 void aplpinctrl_config_pin(void *, uint32_t *, int);
101 int aplpinctrl_get_pin(void *, uint32_t *);
102 void aplpinctrl_set_pin(void *, uint32_t *, int);
103
104 int aplpinctrl_intr(void *);
105 void *aplpinctrl_intr_establish(void *, int *, int, struct cpu_info *,
106 int (*)(void *), void *, char *);
107 void aplpinctrl_intr_disestablish(void *);
108 void aplpinctrl_intr_enable(void *);
109 void aplpinctrl_intr_disable(void *);
110 void aplpinctrl_intr_barrier(void *);
111
112 int
aplpinctrl_match(struct device * parent,void * match,void * aux)113 aplpinctrl_match(struct device *parent, void *match, void *aux)
114 {
115 struct fdt_attach_args *faa = aux;
116
117 return OF_is_compatible(faa->fa_node, "apple,pinctrl");
118 }
119
120 void
aplpinctrl_attach(struct device * parent,struct device * self,void * aux)121 aplpinctrl_attach(struct device *parent, struct device *self, void *aux)
122 {
123 struct aplpinctrl_softc *sc = (struct aplpinctrl_softc *)self;
124 struct fdt_attach_args *faa = aux;
125 uint32_t gpio_ranges[4] = {};
126 int i;
127
128 if (faa->fa_nreg < 1) {
129 printf(": no registers\n");
130 return;
131 }
132
133 sc->sc_iot = faa->fa_iot;
134 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
135 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
136 printf(": can't map registers\n");
137 return;
138 }
139
140 power_domain_enable(faa->fa_node);
141
142 pinctrl_register(faa->fa_node, aplpinctrl_pinctrl, sc);
143
144 OF_getpropintarray(faa->fa_node, "gpio-ranges",
145 gpio_ranges, sizeof(gpio_ranges));
146 sc->sc_ngpios = gpio_ranges[3];
147 if (sc->sc_ngpios == 0) {
148 printf("\n");
149 return;
150 }
151
152 sc->sc_gc.gc_node = faa->fa_node;
153 sc->sc_gc.gc_cookie = sc;
154 sc->sc_gc.gc_config_pin = aplpinctrl_config_pin;
155 sc->sc_gc.gc_get_pin = aplpinctrl_get_pin;
156 sc->sc_gc.gc_set_pin = aplpinctrl_set_pin;
157 gpio_controller_register(&sc->sc_gc);
158
159 sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_BIO,
160 aplpinctrl_intr, sc, sc->sc_dev.dv_xname);
161 if (sc->sc_ih == NULL) {
162 printf(": can't establish interrupt\n");
163 return;
164 }
165
166 sc->sc_handler = mallocarray(sc->sc_ngpios,
167 sizeof(*sc->sc_handler), M_DEVBUF, M_ZERO | M_WAITOK);
168 for (i = 0; i < sc->sc_ngpios; i++)
169 TAILQ_INIT(&sc->sc_handler[i]);
170
171 sc->sc_ic.ic_node = faa->fa_node;
172 sc->sc_ic.ic_cookie = sc;
173 sc->sc_ic.ic_establish = aplpinctrl_intr_establish;
174 sc->sc_ic.ic_disestablish = aplpinctrl_intr_disestablish;
175 sc->sc_ic.ic_enable = aplpinctrl_intr_enable;
176 sc->sc_ic.ic_disable = aplpinctrl_intr_disable;
177 sc->sc_ic.ic_barrier = aplpinctrl_intr_barrier;
178 fdt_intr_register(&sc->sc_ic);
179
180 printf("\n");
181 }
182
183 int
aplpinctrl_pinctrl(uint32_t phandle,void * cookie)184 aplpinctrl_pinctrl(uint32_t phandle, void *cookie)
185 {
186 struct aplpinctrl_softc *sc = cookie;
187 uint32_t *pinmux;
188 int node, len, i;
189 uint16_t pin, func;
190 uint32_t reg;
191
192 node = OF_getnodebyphandle(phandle);
193 if (node == 0)
194 return -1;
195
196 len = OF_getproplen(node, "pinmux");
197 if (len <= 0)
198 return -1;
199
200 pinmux = malloc(len, M_TEMP, M_WAITOK);
201 OF_getpropintarray(node, "pinmux", pinmux, len);
202
203 for (i = 0; i < len / sizeof(uint32_t); i++) {
204 pin = APPLE_PIN(pinmux[i]);
205 func = APPLE_FUNC(pinmux[i]);
206 reg = HREAD4(sc, GPIO_PIN(pin));
207 reg &= ~GPIO_PIN_FUNC_MASK;
208 reg |= (func << GPIO_PIN_FUNC_SHIFT) & GPIO_PIN_FUNC_MASK;
209 HWRITE4(sc, GPIO_PIN(pin), reg);
210 }
211
212 free(pinmux, M_TEMP, len);
213 return 0;
214 }
215
216 void
aplpinctrl_config_pin(void * cookie,uint32_t * cells,int config)217 aplpinctrl_config_pin(void *cookie, uint32_t *cells, int config)
218 {
219 struct aplpinctrl_softc *sc = cookie;
220 uint32_t pin = cells[0];
221 uint32_t reg;
222
223 KASSERT(pin < sc->sc_ngpios);
224
225 reg = HREAD4(sc, GPIO_PIN(pin));
226 reg &= ~GPIO_PIN_FUNC_MASK;
227 reg &= ~GPIO_PIN_MODE_MASK;
228 if (config & GPIO_CONFIG_OUTPUT)
229 reg |= GPIO_PIN_MODE_OUTPUT;
230 else
231 reg |= GPIO_PIN_MODE_INPUT;
232 HWRITE4(sc, GPIO_PIN(pin), reg);
233 }
234
235 int
aplpinctrl_get_pin(void * cookie,uint32_t * cells)236 aplpinctrl_get_pin(void *cookie, uint32_t *cells)
237 {
238 struct aplpinctrl_softc *sc = cookie;
239 uint32_t pin = cells[0];
240 uint32_t flags = cells[1];
241 uint32_t reg;
242 int val;
243
244 KASSERT(pin < sc->sc_ngpios);
245
246 reg = HREAD4(sc, GPIO_PIN(pin));
247 val = !!(reg & GPIO_PIN_DATA);
248 if (flags & GPIO_ACTIVE_LOW)
249 val = !val;
250 return val;
251 }
252
253 void
aplpinctrl_set_pin(void * cookie,uint32_t * cells,int val)254 aplpinctrl_set_pin(void *cookie, uint32_t *cells, int val)
255 {
256 struct aplpinctrl_softc *sc = cookie;
257 uint32_t pin = cells[0];
258 uint32_t flags = cells[1];
259
260 KASSERT(pin < sc->sc_ngpios);
261
262 if (flags & GPIO_ACTIVE_LOW)
263 val = !val;
264 if (val)
265 HSET4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
266 else
267 HCLR4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
268 }
269
270 int
aplpinctrl_intr(void * arg)271 aplpinctrl_intr(void *arg)
272 {
273 struct aplpinctrl_softc *sc = arg;
274 struct intrhand *ih;
275 uint32_t status, pending;
276 int base, bit, pin, s;
277
278 for (base = 0; base < sc->sc_ngpios; base += 32) {
279 status = HREAD4(sc, GPIO_IRQ(0, base));
280 pending = status;
281
282 while (pending) {
283 bit = ffs(pending) - 1;
284 pin = base + bit;
285 TAILQ_FOREACH(ih, &sc->sc_handler[pin], ih_list) {
286 s = splraise(ih->ih_ipl);
287 if (ih->ih_func(ih->ih_arg))
288 ih->ih_count.ec_count++;
289 splx(s);
290 }
291
292 pending &= ~(1 << bit);
293 }
294
295 HWRITE4(sc, GPIO_IRQ(0, base), status);
296 }
297
298 return 1;
299 }
300
301 void *
aplpinctrl_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)302 aplpinctrl_intr_establish(void *cookie, int *cells, int ipl,
303 struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
304 {
305 struct aplpinctrl_softc *sc = cookie;
306 struct intrhand *ih;
307 uint32_t pin = cells[0];
308 uint32_t type = IST_NONE;
309 uint32_t reg;
310
311 KASSERT(pin < sc->sc_ngpios);
312
313 if (ci != NULL && !CPU_IS_PRIMARY(ci))
314 return NULL;
315
316 switch (cells[1]) {
317 case 1:
318 type = IST_EDGE_RISING;
319 break;
320 case 2:
321 type = IST_EDGE_FALLING;
322 break;
323 case 3:
324 type = IST_EDGE_BOTH;
325 break;
326 case 4:
327 type = IST_LEVEL_HIGH;
328 break;
329 case 8:
330 type = IST_LEVEL_LOW;
331 break;
332 }
333
334 ih = TAILQ_FIRST(&sc->sc_handler[pin]);
335 if (ih && ih->ih_type != type)
336 return NULL;
337
338 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
339 ih->ih_func = func;
340 ih->ih_arg = arg;
341 ih->ih_irq = pin;
342 ih->ih_type = type;
343 ih->ih_ipl = ipl & IPL_IRQMASK;
344 ih->ih_name = name;
345 ih->ih_sc = sc;
346 if (name != NULL)
347 evcount_attach(&ih->ih_count, name, &ih->ih_irq);
348 TAILQ_INSERT_TAIL(&sc->sc_handler[pin], ih, ih_list);
349
350 reg = HREAD4(sc, GPIO_PIN(pin));
351 reg &= ~GPIO_PIN_DATA;
352 reg &= ~GPIO_PIN_FUNC_MASK;
353 reg &= ~GPIO_PIN_MODE_MASK;
354 switch (type) {
355 case IST_NONE:
356 reg |= GPIO_PIN_MODE_IRQ_OFF;
357 break;
358 case IST_EDGE_RISING:
359 reg |= GPIO_PIN_MODE_IRQ_UP;
360 break;
361 case IST_EDGE_FALLING:
362 reg |= GPIO_PIN_MODE_IRQ_DN;
363 break;
364 case IST_EDGE_BOTH:
365 reg |= GPIO_PIN_MODE_IRQ_ANY;
366 break;
367 case IST_LEVEL_HIGH:
368 reg |= GPIO_PIN_MODE_IRQ_HI;
369 break;
370 case IST_LEVEL_LOW:
371 reg |= GPIO_PIN_MODE_IRQ_LO;
372 break;
373 }
374 reg |= GPIO_PIN_INPUT_ENABLE;
375 reg &= ~GPIO_PIN_GROUP_MASK;
376 HWRITE4(sc, GPIO_PIN(pin), reg);
377
378 return ih;
379 }
380
381 void
aplpinctrl_intr_disestablish(void * cookie)382 aplpinctrl_intr_disestablish(void *cookie)
383 {
384 struct intrhand *ih = cookie;
385 struct aplpinctrl_softc *sc = ih->ih_sc;
386 uint32_t reg;
387 int s;
388
389 s = splhigh();
390
391 TAILQ_REMOVE(&sc->sc_handler[ih->ih_irq], ih, ih_list);
392 if (ih->ih_name)
393 evcount_detach(&ih->ih_count);
394
395 if (TAILQ_EMPTY(&sc->sc_handler[ih->ih_irq])) {
396 reg = HREAD4(sc, GPIO_PIN(ih->ih_irq));
397 reg &= ~GPIO_PIN_MODE_MASK;
398 reg |= GPIO_PIN_MODE_IRQ_OFF;
399 HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg);
400 }
401
402 free(ih, M_DEVBUF, sizeof(*ih));
403
404 splx(s);
405 }
406
407 void
aplpinctrl_intr_enable(void * cookie)408 aplpinctrl_intr_enable(void *cookie)
409 {
410 struct intrhand *ih = cookie;
411 struct aplpinctrl_softc *sc = ih->ih_sc;
412 uint32_t reg;
413 int s;
414
415 s = splhigh();
416 reg = HREAD4(sc, GPIO_PIN(ih->ih_irq));
417 reg &= ~GPIO_PIN_MODE_MASK;
418 switch (ih->ih_type) {
419 case IST_NONE:
420 reg |= GPIO_PIN_MODE_IRQ_OFF;
421 break;
422 case IST_EDGE_RISING:
423 reg |= GPIO_PIN_MODE_IRQ_UP;
424 break;
425 case IST_EDGE_FALLING:
426 reg |= GPIO_PIN_MODE_IRQ_DN;
427 break;
428 case IST_EDGE_BOTH:
429 reg |= GPIO_PIN_MODE_IRQ_ANY;
430 break;
431 case IST_LEVEL_HIGH:
432 reg |= GPIO_PIN_MODE_IRQ_HI;
433 break;
434 case IST_LEVEL_LOW:
435 reg |= GPIO_PIN_MODE_IRQ_LO;
436 break;
437 }
438 HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg);
439 splx(s);
440 }
441
442 void
aplpinctrl_intr_disable(void * cookie)443 aplpinctrl_intr_disable(void *cookie)
444 {
445 struct intrhand *ih = cookie;
446 struct aplpinctrl_softc *sc = ih->ih_sc;
447 uint32_t reg;
448 int s;
449
450 s = splhigh();
451 reg = HREAD4(sc, GPIO_PIN(ih->ih_irq));
452 reg &= ~GPIO_PIN_MODE_MASK;
453 reg |= GPIO_PIN_MODE_IRQ_OFF;
454 HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg);
455 splx(s);
456 }
457
458 void
aplpinctrl_intr_barrier(void * cookie)459 aplpinctrl_intr_barrier(void *cookie)
460 {
461 struct intrhand *ih = cookie;
462 struct aplpinctrl_softc *sc = ih->ih_sc;
463
464 intr_barrier(sc->sc_ih);
465 }
466