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
apple_pinctrl_probe(device_t dev)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
apple_pinctrl_attach(device_t dev)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
apple_pinctrl_detach(device_t dev)189 apple_pinctrl_detach(device_t dev)
190 {
191
192 return (EBUSY);
193 }
194
195 static void
apple_pinctrl_pin_configure(struct apple_pinctrl_softc * sc,uint32_t pin,uint32_t flags)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
apple_pinctrl_get_bus(device_t dev)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
apple_pinctrl_pin_max(device_t dev,int * maxpin)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
apple_pinctrl_pin_getname(device_t dev,uint32_t pin,char * name)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
apple_pinctrl_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)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
apple_pinctrl_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)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
apple_pinctrl_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)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
apple_pinctrl_pin_get(device_t dev,uint32_t pin,unsigned int * val)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
apple_pinctrl_pin_set(device_t dev,uint32_t pin,unsigned int value)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
apple_pinctrl_pin_toggle(device_t dev,uint32_t pin)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
apple_pinctrl_pin_config_32(device_t dev,uint32_t first_pin,uint32_t num_pins,uint32_t * pin_flags)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
apple_pinctrl_get_node(device_t dev,device_t bus)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
apple_pinctrl_configure(device_t dev,phandle_t cfgxref)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