xref: /freebsd/sys/arm64/apple/apple_pinctrl.c (revision ee3960cba1068e12fb032a68c46d74841d9edab3)
1 /*	$OpenBSD: aplpinctrl.c,v 1.4 2022/04/06 18:59:26 naddy Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  * Copyright (c) 2022 Kyle Evans <kevans@FreeBSD.org>
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/bus.h>
22 #include <sys/gpio.h>
23 #include <sys/kernel.h>
24 #include <sys/malloc.h>
25 #include <sys/module.h>
26 #include <sys/mutex.h>
27 
28 #include <machine/bus.h>
29 #include <machine/intr.h>
30 #include <machine/resource.h>
31 
32 #include <dev/gpio/gpiobusvar.h>
33 #include <dev/ofw/ofw_bus.h>
34 #include <dev/ofw/ofw_bus_subr.h>
35 #include <dev/fdt/fdt_pinctrl.h>
36 
37 #include "pic_if.h"
38 #include "gpio_if.h"
39 
40 #define APPLE_PIN(pinmux) ((pinmux) & 0xffff)
41 #define APPLE_FUNC(pinmux) ((pinmux) >> 16)
42 
43 #define GPIO_PIN(pin)		((pin) * 4)
44 #define  GPIO_PIN_GROUP_MASK	(7 << 16)
45 #define  GPIO_PIN_INPUT_ENABLE	(1 << 9)
46 #define  GPIO_PIN_FUNC_MASK	(3 << 5)
47 #define  GPIO_PIN_FUNC_SHIFT	5
48 #define  GPIO_PIN_MODE_MASK	(7 << 1)
49 #define  GPIO_PIN_MODE_INPUT	(0 << 1)
50 #define  GPIO_PIN_MODE_OUTPUT	(1 << 1)
51 #define  GPIO_PIN_MODE_IRQ_HI	(2 << 1)
52 #define  GPIO_PIN_MODE_IRQ_LO	(3 << 1)
53 #define  GPIO_PIN_MODE_IRQ_UP	(4 << 1)
54 #define  GPIO_PIN_MODE_IRQ_DN	(5 << 1)
55 #define  GPIO_PIN_MODE_IRQ_ANY	(6 << 1)
56 #define  GPIO_PIN_MODE_IRQ_OFF	(7 << 1)
57 #define  GPIO_PIN_DATA		(1 << 0)
58 #define GPIO_IRQ(grp, pin)	(0x800 + (grp) * 64 + ((pin) >> 5) * 4)
59 
60 #define	APPLE_PINCTRL_DEFAULT_CAPS	\
61 	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
62 
63 #define HREAD4(sc, reg)							\
64 	bus_read_4((sc)->sc_res[APPLE_PINCTRL_MEMRES], reg)
65 #define HWRITE4(sc, reg, val)						\
66 	bus_write_4((sc)->sc_res[APPLE_PINCTRL_MEMRES], reg, val)
67 #define HSET4(sc, reg, bits)						\
68 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
69 #define HCLR4(sc, reg, bits)						\
70 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
71 
72 struct apple_pinctrl_irqsrc {
73 	struct intr_irqsrc	isrc;
74 	int			irq;
75 	int			type;
76 };
77 
78 enum {
79 	APPLE_PINCTRL_MEMRES = 0,
80 	APPLE_PINCTRL_IRQRES,
81 	APPLE_PINCTRL_NRES,
82 };
83 
84 struct apple_pinctrl_softc {
85 	device_t		sc_dev;
86 	device_t		sc_busdev;
87 	struct mtx		sc_mtx;
88 	int			sc_ngpios;
89 
90 	void			*sc_intrhand;
91 	struct resource		*sc_res[APPLE_PINCTRL_NRES];
92 	struct apple_pinctrl_irqsrc	*sc_irqs;
93 };
94 
95 #define	APPLE_PINCTRL_LOCK(sc)		mtx_lock_spin(&(sc)->sc_mtx)
96 #define	APPLE_PINCTRL_UNLOCK(sc)	mtx_unlock_spin(&(sc)->sc_mtx)
97 #define	APPLE_PINCTRL_LOCK_ASSERT(sc)	mtx_assert(&(sc)->sc_mtx, MA_OWNED)
98 
99 static struct ofw_compat_data compat_data[] = {
100 	{"apple,pinctrl",	1},
101 	{NULL,			0},
102 };
103 
104 static struct resource_spec apple_pinctrl_res_spec[] = {
105 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
106 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
107 	{ -1,			0,	0 },
108 };
109 
110 static int	apple_pinctrl_probe(device_t dev);
111 static int	apple_pinctrl_attach(device_t dev);
112 static int	apple_pinctrl_detach(device_t dev);
113 
114 static int	apple_pinctrl_configure(device_t, phandle_t);
115 static phandle_t	apple_pinctrl_get_node(device_t, device_t);
116 
117 static int
118 apple_pinctrl_probe(device_t dev)
119 {
120 
121 	if (!ofw_bus_status_okay(dev))
122 		return (ENXIO);
123 
124 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
125 		return (ENXIO);
126 
127 	device_set_desc(dev, "Apple Pinmux Controller");
128 	return (BUS_PROBE_DEFAULT);
129 }
130 
131 static int
132 apple_pinctrl_attach(device_t dev)
133 {
134 	pcell_t gpio_ranges[4];
135 	phandle_t node;
136 	struct apple_pinctrl_softc *sc;
137 	int error;
138 
139 	sc = device_get_softc(dev);
140 	sc->sc_dev = dev;
141 
142 	node = ofw_bus_get_node(dev);
143 
144 	if (bus_alloc_resources(dev, apple_pinctrl_res_spec, sc->sc_res) != 0) {
145 		device_printf(dev, "cannot allocate device resources\n");
146 		return (ENXIO);
147 	}
148 
149 	mtx_init(&sc->sc_mtx, "aapl gpio", "gpio", MTX_SPIN);
150 
151 	error = OF_getencprop(node, "gpio-ranges", gpio_ranges,
152 	    sizeof(gpio_ranges));
153 	if (error == -1) {
154 		device_printf(dev, "failed to get gpio-ranges\n");
155 		goto error;
156 	}
157 
158 	sc->sc_ngpios = gpio_ranges[3];
159 	if (sc->sc_ngpios == 0) {
160 		device_printf(dev, "no GPIOs\n");
161 		goto error;
162 	}
163 
164 	sc->sc_busdev = gpiobus_attach_bus(dev);
165 	if (sc->sc_busdev == NULL) {
166 		device_printf(dev, "failed to attach gpiobus\n");
167 		goto error;
168 	}
169 
170 	fdt_pinctrl_register(dev, "pinmux");
171 	fdt_pinctrl_configure_tree(dev);
172 
173 	if (!OF_hasprop(node, "interrupt-controller"))
174 		return (0);
175 
176 	sc->sc_irqs = mallocarray(sc->sc_ngpios,
177 	    sizeof(*sc->sc_irqs), M_DEVBUF, M_ZERO | M_WAITOK);
178 	intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev)));
179 
180 	return (0);
181 error:
182 	mtx_destroy(&sc->sc_mtx);
183 	bus_release_resources(dev, apple_pinctrl_res_spec, sc->sc_res);
184 	return (ENXIO);
185 }
186 
187 static int
188 apple_pinctrl_detach(device_t dev)
189 {
190 
191 	return (EBUSY);
192 }
193 
194 static void
195 apple_pinctrl_pin_configure(struct apple_pinctrl_softc *sc, uint32_t pin,
196     uint32_t flags)
197 {
198 	uint32_t reg;
199 
200 	APPLE_PINCTRL_LOCK_ASSERT(sc);
201 
202 	MPASS(pin < sc->sc_ngpios);
203 
204 	reg = HREAD4(sc, GPIO_PIN(pin));
205 	reg &= ~GPIO_PIN_FUNC_MASK;
206 	reg &= ~GPIO_PIN_MODE_MASK;
207 
208 	if ((flags & GPIO_PIN_PRESET_LOW) != 0)
209 		reg &= ~GPIO_PIN_DATA;
210 	else if ((flags & GPIO_PIN_PRESET_HIGH) != 0)
211 		reg |= GPIO_PIN_DATA;
212 
213 	if ((flags & GPIO_PIN_INPUT) != 0)
214 		reg |= GPIO_PIN_MODE_INPUT;
215 	else if ((flags & GPIO_PIN_OUTPUT) != 0)
216 		reg |= GPIO_PIN_MODE_OUTPUT;
217 
218 	HWRITE4(sc, GPIO_PIN(pin), reg);
219 }
220 
221 static device_t
222 apple_pinctrl_get_bus(device_t dev)
223 {
224 	struct apple_pinctrl_softc *sc;
225 
226 	sc = device_get_softc(dev);
227 	return (sc->sc_busdev);
228 }
229 
230 static int
231 apple_pinctrl_pin_max(device_t dev, int *maxpin)
232 {
233 	struct apple_pinctrl_softc *sc;
234 
235 	sc = device_get_softc(dev);
236 	*maxpin = sc->sc_ngpios - 1;
237 	return (0);
238 }
239 
240 static int
241 apple_pinctrl_pin_getname(device_t dev, uint32_t pin, char *name)
242 {
243 	struct apple_pinctrl_softc *sc;
244 
245 	sc = device_get_softc(dev);
246 	if (pin >= sc->sc_ngpios)
247 		return (EINVAL);
248 
249 	snprintf(name, GPIOMAXNAME - 1, "gpio%c%d",
250 	    device_get_unit(dev) + 'a', pin);
251 
252 	return (0);
253 }
254 
255 static int
256 apple_pinctrl_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
257 {
258 	struct apple_pinctrl_softc *sc;
259 	uint32_t reg;
260 
261 	sc = device_get_softc(dev);
262 	if (pin >= sc->sc_ngpios)
263 		return (EINVAL);
264 
265 	*flags = 0;
266 
267 	APPLE_PINCTRL_LOCK(sc);
268 
269 	reg = HREAD4(sc, GPIO_PIN(pin));
270 	if ((reg & GPIO_PIN_MODE_INPUT) != 0)
271 		*flags |= GPIO_PIN_INPUT;
272 	else if ((reg & GPIO_PIN_MODE_OUTPUT) != 0)
273 		*flags |= GPIO_PIN_OUTPUT;
274 
275 	APPLE_PINCTRL_UNLOCK(sc);
276 
277 	return (0);
278 }
279 
280 static int
281 apple_pinctrl_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
282 {
283 
284 	*caps = APPLE_PINCTRL_DEFAULT_CAPS;
285 	return (0);
286 }
287 
288 static int
289 apple_pinctrl_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
290 {
291 	struct apple_pinctrl_softc *sc;
292 
293 	sc = device_get_softc(dev);
294 	if (pin >= sc->sc_ngpios)
295 		return (EINVAL);
296 
297 	APPLE_PINCTRL_LOCK(sc);
298 	apple_pinctrl_pin_configure(sc, pin, flags);
299 	APPLE_PINCTRL_UNLOCK(sc);
300 
301 	return (0);
302 }
303 
304 static int
305 apple_pinctrl_pin_get(device_t dev, uint32_t pin, unsigned int *val)
306 {
307 	struct apple_pinctrl_softc *sc;
308 	uint32_t reg;
309 
310 	sc = device_get_softc(dev);
311 	if (pin >= sc->sc_ngpios)
312 		return (EINVAL);
313 
314 	APPLE_PINCTRL_LOCK(sc);
315 	reg = HREAD4(sc, GPIO_PIN(pin));
316 	*val = !!(reg & GPIO_PIN_DATA);
317 	APPLE_PINCTRL_UNLOCK(sc);
318 
319 	return (0);
320 }
321 
322 static int
323 apple_pinctrl_pin_set(device_t dev, uint32_t pin, unsigned int value)
324 {
325 	struct apple_pinctrl_softc *sc;
326 
327 	sc = device_get_softc(dev);
328 	if (pin >= sc->sc_ngpios)
329 		return (EINVAL);
330 
331 	APPLE_PINCTRL_LOCK(sc);
332 	if (value)
333 		HSET4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
334 	else
335 		HCLR4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
336 	device_printf(sc->sc_dev, "set pin %d to %x\n",
337 	    pin, HREAD4(sc, GPIO_PIN(pin)));
338 	APPLE_PINCTRL_UNLOCK(sc);
339 	return (0);
340 }
341 
342 
343 static int
344 apple_pinctrl_pin_toggle(device_t dev, uint32_t pin)
345 {
346 	struct apple_pinctrl_softc *sc;
347 	uint32_t reg;
348 
349 	sc = device_get_softc(dev);
350 	if (pin >= sc->sc_ngpios)
351 		return (EINVAL);
352 
353 	APPLE_PINCTRL_LOCK(sc);
354 	reg = HREAD4(sc, GPIO_PIN(pin));
355 	if ((reg & GPIO_PIN_DATA) == 0)
356 		reg |= GPIO_PIN_DATA;
357 	else
358 		reg &= ~GPIO_PIN_DATA;
359 	HWRITE4(sc, GPIO_PIN(pin), reg);
360 	APPLE_PINCTRL_UNLOCK(sc);
361 	return (0);
362 }
363 
364 
365 static int
366 apple_pinctrl_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
367     uint32_t *pin_flags)
368 {
369 	struct apple_pinctrl_softc *sc;
370 	uint32_t pin;
371 
372 	sc = device_get_softc(dev);
373 	if (first_pin >= sc->sc_ngpios)
374 		return (EINVAL);
375 
376 	/*
377 	 * The configuration for a bank of pins is scattered among several
378 	 * registers; we cannot g'tee to simultaneously change the state of all
379 	 * the pins in the flags array.  So just loop through the array
380 	 * configuring each pin for now.  If there was a strong need, it might
381 	 * be possible to support some limited simultaneous config, such as
382 	 * adjacent groups of 8 pins that line up the same as the config regs.
383 	 */
384 	APPLE_PINCTRL_LOCK(sc);
385 	for (pin = first_pin; pin < num_pins; ++pin) {
386 		if (pin_flags[pin] & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
387 			apple_pinctrl_pin_configure(sc, pin, pin_flags[pin]);
388 	}
389 	APPLE_PINCTRL_UNLOCK(sc);
390 
391 	return (0);
392 }
393 
394 static phandle_t
395 apple_pinctrl_get_node(device_t dev, device_t bus)
396 {
397 
398 	/* GPIO bus */
399 	return (ofw_bus_get_node(dev));
400 }
401 
402 static int
403 apple_pinctrl_configure(device_t dev, phandle_t cfgxref)
404 {
405 	struct apple_pinctrl_softc *sc;
406 	pcell_t *pinmux;
407 	phandle_t node;
408 	ssize_t len;
409 	uint32_t reg;
410 	uint16_t pin, func;
411 	int i;
412 
413 	sc = device_get_softc(dev);
414 	node = OF_node_from_xref(cfgxref);
415 
416 	len = OF_getencprop_alloc(node, "pinmux", (void **)&pinmux);
417 	if (len <= 0)
418 		return (-1);
419 
420 	APPLE_PINCTRL_LOCK(sc);
421 	for (i = 0; i < len / sizeof(pcell_t); i++) {
422 		pin = APPLE_PIN(pinmux[i]);
423 		func = APPLE_FUNC(pinmux[i]);
424 		reg = HREAD4(sc, GPIO_PIN(pin));
425 		reg &= ~GPIO_PIN_FUNC_MASK;
426 		reg |= (func << GPIO_PIN_FUNC_SHIFT) & GPIO_PIN_FUNC_MASK;
427 		HWRITE4(sc, GPIO_PIN(pin), reg);
428 	}
429 	APPLE_PINCTRL_UNLOCK(sc);
430 
431 	OF_prop_free(pinmux);
432 	return 0;
433 }
434 
435 static device_method_t apple_pinctrl_methods[] = {
436 	/* Device interface */
437 	DEVMETHOD(device_probe,		apple_pinctrl_probe),
438 	DEVMETHOD(device_attach,	apple_pinctrl_attach),
439 	DEVMETHOD(device_detach,	apple_pinctrl_detach),
440 
441 	/* GPIO protocol */
442 	DEVMETHOD(gpio_get_bus,		apple_pinctrl_get_bus),
443 	DEVMETHOD(gpio_pin_max,		apple_pinctrl_pin_max),
444 	DEVMETHOD(gpio_pin_getname,	apple_pinctrl_pin_getname),
445 	DEVMETHOD(gpio_pin_getflags,	apple_pinctrl_pin_getflags),
446 	DEVMETHOD(gpio_pin_getcaps,	apple_pinctrl_pin_getcaps),
447 	DEVMETHOD(gpio_pin_setflags,	apple_pinctrl_pin_setflags),
448 	DEVMETHOD(gpio_pin_get,		apple_pinctrl_pin_get),
449 	DEVMETHOD(gpio_pin_set,		apple_pinctrl_pin_set),
450 	DEVMETHOD(gpio_pin_toggle,	apple_pinctrl_pin_toggle),
451 	DEVMETHOD(gpio_pin_config_32,	apple_pinctrl_pin_config_32),
452 
453 	/* ofw_bus interface */
454 	DEVMETHOD(ofw_bus_get_node,		apple_pinctrl_get_node),
455 
456         /* fdt_pinctrl interface */
457 	DEVMETHOD(fdt_pinctrl_configure,	apple_pinctrl_configure),
458 
459 	DEVMETHOD_END
460 };
461 
462 static driver_t apple_pinctrl_driver = {
463 	"gpio",
464 	apple_pinctrl_methods,
465 	sizeof(struct apple_pinctrl_softc),
466 };
467 
468 EARLY_DRIVER_MODULE(apple_pinctrl, simplebus, apple_pinctrl_driver,
469     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
470