xref: /openbsd/sys/arch/arm64/dev/aplpinctrl.c (revision 3bef86f7)
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
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
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
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
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
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
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
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 *
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
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
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
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
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