xref: /freebsd/sys/arm64/apple/apple_pinctrl.c (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
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 	fdt_pinctrl_register(dev, "pinmux");
165 	fdt_pinctrl_configure_tree(dev);
166 
167 	if (OF_hasprop(node, "interrupt-controller")) {
168 		sc->sc_irqs = mallocarray(sc->sc_ngpios,
169 		    sizeof(*sc->sc_irqs), M_DEVBUF, M_ZERO | M_WAITOK);
170 		intr_pic_register(dev,
171 		    OF_xref_from_node(ofw_bus_get_node(dev)));
172 	}
173 
174 	sc->sc_busdev = gpiobus_add_bus(dev);
175 	if (sc->sc_busdev == NULL) {
176 		device_printf(dev, "failed to attach gpiobus\n");
177 		goto error;
178 	}
179 
180 	bus_attach_children(dev);
181 	return (0);
182 error:
183 	mtx_destroy(&sc->sc_mtx);
184 	bus_release_resources(dev, apple_pinctrl_res_spec, sc->sc_res);
185 	return (ENXIO);
186 }
187 
188 static int
189 apple_pinctrl_detach(device_t dev)
190 {
191 
192 	return (EBUSY);
193 }
194 
195 static void
196 apple_pinctrl_pin_configure(struct apple_pinctrl_softc *sc, uint32_t pin,
197     uint32_t flags)
198 {
199 	uint32_t reg;
200 
201 	APPLE_PINCTRL_LOCK_ASSERT(sc);
202 
203 	MPASS(pin < sc->sc_ngpios);
204 
205 	reg = HREAD4(sc, GPIO_PIN(pin));
206 	reg &= ~GPIO_PIN_FUNC_MASK;
207 	reg &= ~GPIO_PIN_MODE_MASK;
208 
209 	if ((flags & GPIO_PIN_PRESET_LOW) != 0)
210 		reg &= ~GPIO_PIN_DATA;
211 	else if ((flags & GPIO_PIN_PRESET_HIGH) != 0)
212 		reg |= GPIO_PIN_DATA;
213 
214 	if ((flags & GPIO_PIN_INPUT) != 0)
215 		reg |= GPIO_PIN_MODE_INPUT;
216 	else if ((flags & GPIO_PIN_OUTPUT) != 0)
217 		reg |= GPIO_PIN_MODE_OUTPUT;
218 
219 	HWRITE4(sc, GPIO_PIN(pin), reg);
220 }
221 
222 static device_t
223 apple_pinctrl_get_bus(device_t dev)
224 {
225 	struct apple_pinctrl_softc *sc;
226 
227 	sc = device_get_softc(dev);
228 	return (sc->sc_busdev);
229 }
230 
231 static int
232 apple_pinctrl_pin_max(device_t dev, int *maxpin)
233 {
234 	struct apple_pinctrl_softc *sc;
235 
236 	sc = device_get_softc(dev);
237 	*maxpin = sc->sc_ngpios - 1;
238 	return (0);
239 }
240 
241 static int
242 apple_pinctrl_pin_getname(device_t dev, uint32_t pin, char *name)
243 {
244 	struct apple_pinctrl_softc *sc;
245 
246 	sc = device_get_softc(dev);
247 	if (pin >= sc->sc_ngpios)
248 		return (EINVAL);
249 
250 	snprintf(name, GPIOMAXNAME - 1, "gpio%c%d",
251 	    device_get_unit(dev) + 'a', pin);
252 
253 	return (0);
254 }
255 
256 static int
257 apple_pinctrl_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
258 {
259 	struct apple_pinctrl_softc *sc;
260 	uint32_t reg;
261 
262 	sc = device_get_softc(dev);
263 	if (pin >= sc->sc_ngpios)
264 		return (EINVAL);
265 
266 	*flags = 0;
267 
268 	APPLE_PINCTRL_LOCK(sc);
269 
270 	reg = HREAD4(sc, GPIO_PIN(pin));
271 	if ((reg & GPIO_PIN_MODE_INPUT) != 0)
272 		*flags |= GPIO_PIN_INPUT;
273 	else if ((reg & GPIO_PIN_MODE_OUTPUT) != 0)
274 		*flags |= GPIO_PIN_OUTPUT;
275 
276 	APPLE_PINCTRL_UNLOCK(sc);
277 
278 	return (0);
279 }
280 
281 static int
282 apple_pinctrl_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
283 {
284 
285 	*caps = APPLE_PINCTRL_DEFAULT_CAPS;
286 	return (0);
287 }
288 
289 static int
290 apple_pinctrl_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
291 {
292 	struct apple_pinctrl_softc *sc;
293 
294 	sc = device_get_softc(dev);
295 	if (pin >= sc->sc_ngpios)
296 		return (EINVAL);
297 
298 	APPLE_PINCTRL_LOCK(sc);
299 	apple_pinctrl_pin_configure(sc, pin, flags);
300 	APPLE_PINCTRL_UNLOCK(sc);
301 
302 	return (0);
303 }
304 
305 static int
306 apple_pinctrl_pin_get(device_t dev, uint32_t pin, unsigned int *val)
307 {
308 	struct apple_pinctrl_softc *sc;
309 	uint32_t reg;
310 
311 	sc = device_get_softc(dev);
312 	if (pin >= sc->sc_ngpios)
313 		return (EINVAL);
314 
315 	APPLE_PINCTRL_LOCK(sc);
316 	reg = HREAD4(sc, GPIO_PIN(pin));
317 	*val = !!(reg & GPIO_PIN_DATA);
318 	APPLE_PINCTRL_UNLOCK(sc);
319 
320 	return (0);
321 }
322 
323 static int
324 apple_pinctrl_pin_set(device_t dev, uint32_t pin, unsigned int value)
325 {
326 	struct apple_pinctrl_softc *sc;
327 
328 	sc = device_get_softc(dev);
329 	if (pin >= sc->sc_ngpios)
330 		return (EINVAL);
331 
332 	APPLE_PINCTRL_LOCK(sc);
333 	if (value)
334 		HSET4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
335 	else
336 		HCLR4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
337 	device_printf(sc->sc_dev, "set pin %d to %x\n",
338 	    pin, HREAD4(sc, GPIO_PIN(pin)));
339 	APPLE_PINCTRL_UNLOCK(sc);
340 	return (0);
341 }
342 
343 
344 static int
345 apple_pinctrl_pin_toggle(device_t dev, uint32_t pin)
346 {
347 	struct apple_pinctrl_softc *sc;
348 	uint32_t reg;
349 
350 	sc = device_get_softc(dev);
351 	if (pin >= sc->sc_ngpios)
352 		return (EINVAL);
353 
354 	APPLE_PINCTRL_LOCK(sc);
355 	reg = HREAD4(sc, GPIO_PIN(pin));
356 	if ((reg & GPIO_PIN_DATA) == 0)
357 		reg |= GPIO_PIN_DATA;
358 	else
359 		reg &= ~GPIO_PIN_DATA;
360 	HWRITE4(sc, GPIO_PIN(pin), reg);
361 	APPLE_PINCTRL_UNLOCK(sc);
362 	return (0);
363 }
364 
365 
366 static int
367 apple_pinctrl_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
368     uint32_t *pin_flags)
369 {
370 	struct apple_pinctrl_softc *sc;
371 	uint32_t pin;
372 
373 	sc = device_get_softc(dev);
374 	if (first_pin >= sc->sc_ngpios)
375 		return (EINVAL);
376 
377 	/*
378 	 * The configuration for a bank of pins is scattered among several
379 	 * registers; we cannot g'tee to simultaneously change the state of all
380 	 * the pins in the flags array.  So just loop through the array
381 	 * configuring each pin for now.  If there was a strong need, it might
382 	 * be possible to support some limited simultaneous config, such as
383 	 * adjacent groups of 8 pins that line up the same as the config regs.
384 	 */
385 	APPLE_PINCTRL_LOCK(sc);
386 	for (pin = first_pin; pin < num_pins; ++pin) {
387 		if (pin_flags[pin] & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
388 			apple_pinctrl_pin_configure(sc, pin, pin_flags[pin]);
389 	}
390 	APPLE_PINCTRL_UNLOCK(sc);
391 
392 	return (0);
393 }
394 
395 static phandle_t
396 apple_pinctrl_get_node(device_t dev, device_t bus)
397 {
398 
399 	/* GPIO bus */
400 	return (ofw_bus_get_node(dev));
401 }
402 
403 static int
404 apple_pinctrl_configure(device_t dev, phandle_t cfgxref)
405 {
406 	struct apple_pinctrl_softc *sc;
407 	pcell_t *pinmux;
408 	phandle_t node;
409 	ssize_t len;
410 	uint32_t reg;
411 	uint16_t pin, func;
412 	int i;
413 
414 	sc = device_get_softc(dev);
415 	node = OF_node_from_xref(cfgxref);
416 
417 	len = OF_getencprop_alloc(node, "pinmux", (void **)&pinmux);
418 	if (len <= 0)
419 		return (-1);
420 
421 	APPLE_PINCTRL_LOCK(sc);
422 	for (i = 0; i < len / sizeof(pcell_t); i++) {
423 		pin = APPLE_PIN(pinmux[i]);
424 		func = APPLE_FUNC(pinmux[i]);
425 		reg = HREAD4(sc, GPIO_PIN(pin));
426 		reg &= ~GPIO_PIN_FUNC_MASK;
427 		reg |= (func << GPIO_PIN_FUNC_SHIFT) & GPIO_PIN_FUNC_MASK;
428 		HWRITE4(sc, GPIO_PIN(pin), reg);
429 	}
430 	APPLE_PINCTRL_UNLOCK(sc);
431 
432 	OF_prop_free(pinmux);
433 	return 0;
434 }
435 
436 static device_method_t apple_pinctrl_methods[] = {
437 	/* Device interface */
438 	DEVMETHOD(device_probe,		apple_pinctrl_probe),
439 	DEVMETHOD(device_attach,	apple_pinctrl_attach),
440 	DEVMETHOD(device_detach,	apple_pinctrl_detach),
441 
442 	/* GPIO protocol */
443 	DEVMETHOD(gpio_get_bus,		apple_pinctrl_get_bus),
444 	DEVMETHOD(gpio_pin_max,		apple_pinctrl_pin_max),
445 	DEVMETHOD(gpio_pin_getname,	apple_pinctrl_pin_getname),
446 	DEVMETHOD(gpio_pin_getflags,	apple_pinctrl_pin_getflags),
447 	DEVMETHOD(gpio_pin_getcaps,	apple_pinctrl_pin_getcaps),
448 	DEVMETHOD(gpio_pin_setflags,	apple_pinctrl_pin_setflags),
449 	DEVMETHOD(gpio_pin_get,		apple_pinctrl_pin_get),
450 	DEVMETHOD(gpio_pin_set,		apple_pinctrl_pin_set),
451 	DEVMETHOD(gpio_pin_toggle,	apple_pinctrl_pin_toggle),
452 	DEVMETHOD(gpio_pin_config_32,	apple_pinctrl_pin_config_32),
453 
454 	/* ofw_bus interface */
455 	DEVMETHOD(ofw_bus_get_node,		apple_pinctrl_get_node),
456 
457         /* fdt_pinctrl interface */
458 	DEVMETHOD(fdt_pinctrl_configure,	apple_pinctrl_configure),
459 
460 	DEVMETHOD_END
461 };
462 
463 static driver_t apple_pinctrl_driver = {
464 	"gpio",
465 	apple_pinctrl_methods,
466 	sizeof(struct apple_pinctrl_softc),
467 };
468 
469 EARLY_DRIVER_MODULE(apple_pinctrl, simplebus, apple_pinctrl_driver,
470     0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
471