1 /* $OpenBSD: sxipio.c,v 1.19 2024/02/08 00:00:16 jsg Exp $ */
2 /*
3 * Copyright (c) 2010 Miodrag Vallat.
4 * Copyright (c) 2013 Artturi Alm
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/device.h>
22 #include <sys/gpio.h>
23 #include <sys/evcount.h>
24 #include <sys/malloc.h>
25
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 #include <machine/intr.h>
29
30 #include <dev/gpio/gpiovar.h>
31 #include <dev/ofw/openfirm.h>
32 #include <dev/ofw/ofw_clock.h>
33 #include <dev/ofw/ofw_gpio.h>
34 #include <dev/ofw/ofw_pinctrl.h>
35 #include <dev/ofw/ofw_regulator.h>
36 #include <dev/ofw/fdt.h>
37
38 #include <dev/fdt/sunxireg.h>
39 #include <dev/fdt/sxipiovar.h>
40
41 #include "gpio.h"
42
43 #define SXIPIO_NPORT 9
44
45 struct sxipio_softc;
46
47 struct sxipio_gpio {
48 struct sxipio_softc *sc;
49 int port;
50 };
51
52 struct intrhand {
53 int (*ih_func)(void *); /* handler */
54 void *ih_arg; /* arg for handler */
55 int ih_ipl; /* IPL_* */
56 int ih_irq; /* IRQ number */
57 int ih_gpio; /* gpio pin */
58 struct evcount ih_count;
59 char *ih_name;
60 };
61
62 struct sxipio_softc {
63 struct device sc_dev;
64 bus_space_tag_t sc_iot;
65 bus_space_handle_t sc_ioh;
66 int sc_node;
67 void *sc_ih_h;
68 void *sc_ih_l;
69 int sc_max_il;
70 int sc_min_il;
71
72 const struct sxipio_pin *sc_pins;
73 int sc_npins;
74 struct gpio_controller sc_gc;
75
76 struct sxipio_gpio sc_gpio[SXIPIO_NPORT];
77 struct gpio_chipset_tag sc_gpio_tag[SXIPIO_NPORT];
78 gpio_pin_t sc_gpio_pins[SXIPIO_NPORT][32];
79
80 struct intrhand *sc_handlers[32];
81
82 void (*sc_bias_cfg)(struct sxipio_softc *,
83 int, uint32_t);
84 };
85
86 #define SXIPIO_CFG(port, pin) 0x00 + ((port) * 0x24) + (((pin) >> 3) * 0x04)
87 #define SXIPIO_DAT(port) 0x10 + ((port) * 0x24)
88 #define SXIPIO_DRV(port, pin) 0x14 + ((port) * 0x24) + (((pin) >> 4) * 0x04)
89 #define SXIPIO_PUL(port, pin) 0x1c + ((port) * 0x24) + (((pin) >> 4) * 0x04)
90 #define SXIPIO_INT_CFG0(port) 0x0200 + ((port) * 0x04)
91 #define SXIPIO_INT_CTL 0x0210
92 #define SXIPIO_INT_STA 0x0214
93 #define SXIPIO_INT_DEB 0x0218 /* debounce register */
94 #define SXIPIO_GRP_CFG(port) 0x0300 + ((port) * 0x04)
95 #define SXIPIO_IO_BIAS_MASK (0xf << 0)
96 #define SXIPIO_IO_BIAS_1_8V 0x0
97 #define SXIPIO_IO_BIAS_2_5V 0x6
98 #define SXIPIO_IO_BIAS_2_8V 0x9
99 #define SXIPIO_IO_BIAS_3_0V 0xa
100 #define SXIPIO_IO_BIAS_3_3V 0xd
101
102 #define SXIPIO_GPIO_IN 0
103 #define SXIPIO_GPIO_OUT 1
104 #define SXIPIO_DISABLED 7
105
106 int sxipio_match(struct device *, void *, void *);
107 void sxipio_attach(struct device *, struct device *, void *);
108
109 const struct cfattach sxipio_ca = {
110 sizeof (struct sxipio_softc), sxipio_match, sxipio_attach
111 };
112
113 struct cfdriver sxipio_cd = {
114 NULL, "sxipio", DV_DULL
115 };
116
117 void sxipio_attach_gpio(struct device *);
118 int sxipio_pinctrl(uint32_t, void *);
119 void sxipio_config_pin(void *, uint32_t *, int);
120 int sxipio_get_pin(void *, uint32_t *);
121 void sxipio_set_pin(void *, uint32_t *, int);
122 void sxipio_a80_bias_cfg(struct sxipio_softc *, int, uint32_t);
123
124 #include "sxipio_pins.h"
125
126 struct sxipio_pins {
127 const char *compat;
128 const struct sxipio_pin *pins;
129 int npins;
130 };
131
132 const struct sxipio_pins sxipio_pins[] = {
133 {
134 "allwinner,sun4i-a10-pinctrl",
135 sun4i_a10_pins, nitems(sun4i_a10_pins)
136 },
137 {
138 "allwinner,sun5i-a10s-pinctrl",
139 sun5i_a10s_pins, nitems(sun5i_a10s_pins)
140 },
141 {
142 "allwinner,sun5i-a13-pinctrl",
143 sun5i_a13_pins, nitems(sun5i_a13_pins)
144 },
145 {
146 "allwinner,sun5i-gr8-pinctrl",
147 sun5i_gr8_pins, nitems(sun5i_gr8_pins)
148 },
149 {
150 "allwinner,sun7i-a20-pinctrl",
151 sun7i_a20_pins, nitems(sun7i_a20_pins)
152 },
153 {
154 "allwinner,sun8i-r40-pinctrl",
155 sun8i_r40_pins, nitems(sun8i_r40_pins)
156 },
157 {
158 "allwinner,sun8i-a33-pinctrl",
159 sun8i_a33_pins, nitems(sun8i_a33_pins)
160 },
161 {
162 "allwinner,sun8i-h3-pinctrl",
163 sun8i_h3_pins, nitems(sun8i_h3_pins)
164 },
165 {
166 "allwinner,sun8i-h3-r-pinctrl",
167 sun8i_h3_r_pins, nitems(sun8i_h3_r_pins)
168 },
169 {
170 "allwinner,sun8i-v3-pinctrl",
171 sun8i_v3_pins, nitems(sun8i_v3_pins)
172 },
173 {
174 "allwinner,sun8i-v3s-pinctrl",
175 sun8i_v3s_pins, nitems(sun8i_v3s_pins)
176 },
177 {
178 "allwinner,sun9i-a80-pinctrl",
179 sun9i_a80_pins, nitems(sun9i_a80_pins)
180 },
181 {
182 "allwinner,sun9i-a80-r-pinctrl",
183 sun9i_a80_r_pins, nitems(sun9i_a80_r_pins)
184 },
185 {
186 "allwinner,sun20i-d1-pinctrl",
187 sun20i_d1_pins, nitems(sun20i_d1_pins)
188 },
189 {
190 "allwinner,sun50i-a64-pinctrl",
191 sun50i_a64_pins, nitems(sun50i_a64_pins)
192 },
193 {
194 "allwinner,sun50i-a64-r-pinctrl",
195 sun50i_a64_r_pins, nitems(sun50i_a64_r_pins)
196 },
197 {
198 "allwinner,sun50i-h5-pinctrl",
199 sun50i_h5_pins, nitems(sun50i_h5_pins)
200 },
201 {
202 "allwinner,sun50i-h6-pinctrl",
203 sun50i_h6_pins, nitems(sun50i_h6_pins)
204 },
205 {
206 "allwinner,sun50i-h6-r-pinctrl",
207 sun50i_h6_r_pins, nitems(sun50i_h6_r_pins)
208 },
209 {
210 "allwinner,sun50i-h616-pinctrl",
211 sun50i_h616_pins, nitems(sun50i_h616_pins)
212 },
213 {
214 "allwinner,sun50i-h616-r-pinctrl",
215 sun50i_h616_r_pins, nitems(sun50i_h616_r_pins)
216 },
217 };
218
219 int
sxipio_match(struct device * parent,void * match,void * aux)220 sxipio_match(struct device *parent, void *match, void *aux)
221 {
222 struct fdt_attach_args *faa = aux;
223 int i;
224
225 for (i = 0; i < nitems(sxipio_pins); i++) {
226 if (OF_is_compatible(faa->fa_node, sxipio_pins[i].compat))
227 return 1;
228 }
229
230 return 0;
231 }
232
233 void
sxipio_attach(struct device * parent,struct device * self,void * aux)234 sxipio_attach(struct device *parent, struct device *self, void *aux)
235 {
236 struct sxipio_softc *sc = (struct sxipio_softc *)self;
237 struct fdt_attach_args *faa = aux;
238 int i;
239
240 sc->sc_iot = faa->fa_iot;
241 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
242 faa->fa_reg[0].size, 0, &sc->sc_ioh))
243 panic("%s: bus_space_map failed!", __func__);
244 sc->sc_node = faa->fa_node;
245
246 clock_enable_all(faa->fa_node);
247 reset_deassert_all(faa->fa_node);
248
249 for (i = 0; i < nitems(sxipio_pins); i++) {
250 if (OF_is_compatible(faa->fa_node, sxipio_pins[i].compat)) {
251 sc->sc_pins = sxipio_pins[i].pins;
252 sc->sc_npins = sxipio_pins[i].npins;
253 break;
254 }
255 }
256
257 /* Allwinner A80 needs IO pad bias configuration. */
258 if (OF_is_compatible(faa->fa_node, "allwinner,sun9i-a80-pinctrl") ||
259 OF_is_compatible(faa->fa_node, "allwinner,sun9i-a80-r-pinctrl"))
260 sc->sc_bias_cfg = sxipio_a80_bias_cfg;
261
262 KASSERT(sc->sc_pins);
263 pinctrl_register(faa->fa_node, sxipio_pinctrl, sc);
264
265 sc->sc_gc.gc_node = faa->fa_node;
266 sc->sc_gc.gc_cookie = sc;
267 sc->sc_gc.gc_config_pin = sxipio_config_pin;
268 sc->sc_gc.gc_get_pin = sxipio_get_pin;
269 sc->sc_gc.gc_set_pin = sxipio_set_pin;
270 gpio_controller_register(&sc->sc_gc);
271
272 config_defer(self, sxipio_attach_gpio);
273
274 printf(": %d pins\n", sc->sc_npins);
275 }
276
277 int
sxipio_drive(int node)278 sxipio_drive(int node)
279 {
280 int drive;
281
282 drive = OF_getpropint(node, "allwinner,drive", -1);
283 if (drive >= 0)
284 return drive;
285 drive = OF_getpropint(node, "drive-strength", 0) - 10;
286 if (drive >= 0)
287 return (drive / 10);
288 return -1;
289 }
290
291 int
sxipio_pull(int node)292 sxipio_pull(int node)
293 {
294 int pull;
295
296 pull = OF_getpropint(node, "allwinner,pull", -1);
297 if (pull >= 0)
298 return pull;
299 if (OF_getproplen(node, "bias-disable") == 0)
300 return 0;
301 if (OF_getproplen(node, "bias-pull-up") == 0)
302 return 1;
303 if (OF_getproplen(node, "bias-pull-down") == 0)
304 return 2;
305 return -1;
306 }
307
308 int
sxipio_pinctrl(uint32_t phandle,void * cookie)309 sxipio_pinctrl(uint32_t phandle, void *cookie)
310 {
311 struct sxipio_softc *sc = cookie;
312 char func[32];
313 char vcc[16];
314 char *names, *name;
315 uint32_t supply;
316 int group, port, pin, off, mask;
317 int mux, drive, pull;
318 int node;
319 int len;
320 int i, j;
321 int s;
322
323 node = OF_getnodebyphandle(phandle);
324 if (node == 0)
325 return -1;
326
327 len = OF_getprop(node, "allwinner,function", func, sizeof(func));
328 if (len <= 0 || len >= sizeof(func)) {
329 len = OF_getprop(node, "function", func, sizeof(func));
330 if (len <= 0 || len >= sizeof(func))
331 return -1;
332 }
333
334 len = OF_getproplen(node, "allwinner,pins");
335 if (len <= 0) {
336 len = OF_getproplen(node, "pins");
337 if (len <= 0)
338 return -1;
339 }
340
341 names = malloc(len, M_TEMP, M_WAITOK);
342 if (OF_getprop(node, "allwinner,pins", names, len) <= 0)
343 OF_getprop(node, "pins", names, len);
344
345 drive = sxipio_drive(node);
346 pull = sxipio_pull(node);
347
348 name = names;
349 while (len > 0) {
350 /* Lookup the pin. */
351 for (i = 0; i < sc->sc_npins; i++) {
352 if (strcmp(name, sc->sc_pins[i].name) == 0)
353 break;
354 }
355 if (i >= sc->sc_npins)
356 goto err;
357
358 /* Lookup the function of the pin. */
359 for (j = 0; j < nitems(sc->sc_pins[i].funcs); j++) {
360 if (sc->sc_pins[i].funcs[j].name == NULL)
361 continue;
362 if (strcmp(func, sc->sc_pins[i].funcs[j].name) == 0)
363 break;
364 }
365 if (j >= nitems(sc->sc_pins[i].funcs))
366 goto err;
367
368 group = sc->sc_pins[i].name[1] - 'A';
369 port = sc->sc_pins[i].port;
370 pin = sc->sc_pins[i].pin;
371 mux = sc->sc_pins[i].funcs[j].mux;
372
373 snprintf(vcc, sizeof(vcc), "vcc-p%c-supply", 'a' + group);
374 supply = OF_getpropint(sc->sc_node, vcc, 0);
375 if (supply) {
376 regulator_enable(supply);
377 if (sc->sc_bias_cfg)
378 sc->sc_bias_cfg(sc, port, supply);
379 }
380
381 s = splhigh();
382 off = (pin & 0x7) << 2, mask = (0x7 << off);
383 SXICMS4(sc, SXIPIO_CFG(port, pin), mask, mux << off);
384 off = (pin & 0xf) << 1, mask = (0x3 << off);
385 if (drive >= 0 && drive < 4)
386 SXICMS4(sc, SXIPIO_DRV(port, pin), mask, drive << off);
387 if (pull >= 0 && pull < 3)
388 SXICMS4(sc, SXIPIO_PUL(port, pin), mask, pull << off);
389 splx(s);
390
391 len -= strlen(name) + 1;
392 name += strlen(name) + 1;
393 }
394
395 free(names, M_TEMP, len);
396 return 0;
397
398 err:
399 free(names, M_TEMP, len);
400 return -1;
401 }
402
403 void
sxipio_config_pin(void * cookie,uint32_t * cells,int config)404 sxipio_config_pin(void *cookie, uint32_t *cells, int config)
405 {
406 struct sxipio_softc *sc = cookie;
407 uint32_t port = cells[0];
408 uint32_t pin = cells[1];
409 int mux, off;
410
411 if (port > SXIPIO_NPORT || pin >= 32)
412 return;
413
414 mux = (config & GPIO_CONFIG_OUTPUT) ? 1 : 0;
415 off = (pin & 0x7) << 2;
416 SXICMS4(sc, SXIPIO_CFG(port, pin), 0x7 << off, mux << off);
417 }
418
419 int
sxipio_get_pin(void * cookie,uint32_t * cells)420 sxipio_get_pin(void *cookie, uint32_t *cells)
421 {
422 struct sxipio_softc *sc = cookie;
423 uint32_t port = cells[0];
424 uint32_t pin = cells[1];
425 uint32_t flags = cells[2];
426 uint32_t reg;
427 int val;
428
429 if (port > SXIPIO_NPORT || pin >= 32)
430 return 0;
431
432 reg = SXIREAD4(sc, SXIPIO_DAT(port));
433 reg &= (1 << pin);
434 val = (reg >> pin) & 1;
435 if (flags & GPIO_ACTIVE_LOW)
436 val = !val;
437 return val;
438 }
439
440 void
sxipio_set_pin(void * cookie,uint32_t * cells,int val)441 sxipio_set_pin(void *cookie, uint32_t *cells, int val)
442 {
443 struct sxipio_softc *sc = cookie;
444 uint32_t port = cells[0];
445 uint32_t pin = cells[1];
446 uint32_t flags = cells[2];
447 uint32_t reg;
448
449 if (port > SXIPIO_NPORT || pin >= 32)
450 return;
451
452 reg = SXIREAD4(sc, SXIPIO_DAT(port));
453 if (flags & GPIO_ACTIVE_LOW)
454 val = !val;
455 if (val)
456 reg |= (1 << pin);
457 else
458 reg &= ~(1 << pin);
459 SXIWRITE4(sc, SXIPIO_DAT(port), reg);
460 }
461
462 void
sxipio_a80_bias_cfg(struct sxipio_softc * sc,int port,uint32_t supply)463 sxipio_a80_bias_cfg(struct sxipio_softc *sc, int port, uint32_t supply)
464 {
465 uint32_t voltage;
466 uint32_t bias;
467
468 voltage = regulator_get_voltage(supply);
469 if (voltage <= 1800000)
470 bias = SXIPIO_IO_BIAS_1_8V;
471 else if (voltage <= 2500000)
472 bias = SXIPIO_IO_BIAS_2_5V;
473 else if (voltage <= 2800000)
474 bias = SXIPIO_IO_BIAS_2_8V;
475 else if (voltage <= 3000000)
476 bias = SXIPIO_IO_BIAS_3_0V;
477 else
478 bias = SXIPIO_IO_BIAS_3_3V;
479
480 SXICMS4(sc, SXIPIO_GRP_CFG(port), SXIPIO_IO_BIAS_MASK, bias);
481 }
482
483 /*
484 * GPIO support code
485 */
486
487 int sxipio_pin_read(void *, int);
488 void sxipio_pin_write(void *, int, int);
489 void sxipio_pin_ctl(void *, int, int);
490
491 static const struct gpio_chipset_tag sxipio_gpio_tag = {
492 .gp_pin_read = sxipio_pin_read,
493 .gp_pin_write = sxipio_pin_write,
494 .gp_pin_ctl = sxipio_pin_ctl
495 };
496
497 int
sxipio_pin_read(void * cookie,int pin)498 sxipio_pin_read(void *cookie, int pin)
499 {
500 struct sxipio_gpio *gpio = cookie;
501 uint32_t cells[3];
502
503 cells[0] = gpio->port;
504 cells[1] = pin;
505 cells[2] = 0;
506
507 return sxipio_get_pin(gpio->sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
508 }
509
510 void
sxipio_pin_write(void * cookie,int pin,int val)511 sxipio_pin_write(void *cookie, int pin, int val)
512 {
513 struct sxipio_gpio *gpio = cookie;
514 uint32_t cells[3];
515
516 cells[0] = gpio->port;
517 cells[1] = pin;
518 cells[2] = 0;
519
520 sxipio_set_pin(gpio->sc, cells, val);
521 }
522
523 void
sxipio_pin_ctl(void * cookie,int pin,int flags)524 sxipio_pin_ctl(void *cookie, int pin, int flags)
525 {
526 struct sxipio_gpio *gpio = cookie;
527 uint32_t cells[3];
528
529 cells[0] = gpio->port;
530 cells[1] = pin;
531 cells[2] = 0;
532
533 if (ISSET(flags, GPIO_PIN_OUTPUT))
534 sxipio_config_pin(gpio->sc, cells, GPIO_CONFIG_OUTPUT);
535 else
536 sxipio_config_pin(gpio->sc, cells, 0);
537 }
538
539 void
sxipio_attach_gpio(struct device * parent)540 sxipio_attach_gpio(struct device *parent)
541 {
542 struct sxipio_softc *sc = (struct sxipio_softc *)parent;
543 struct gpiobus_attach_args gba;
544 uint32_t reg;
545 int port, pin;
546 int off, mux;
547 int state, flags;
548 int i;
549
550 for (i = 0; i < sc->sc_npins; i++) {
551 /* Skip pins that have no gpio function. */
552 if (strcmp(sc->sc_pins[i].funcs[0].name, "gpio_in") != 0 ||
553 strcmp(sc->sc_pins[i].funcs[1].name, "gpio_out") != 0)
554 continue;
555
556 port = sc->sc_pins[i].port;
557 pin = sc->sc_pins[i].pin;
558
559 /* Get pin configuration. */
560 reg = SXIREAD4(sc, SXIPIO_CFG(port, pin));
561 off = (pin & 0x7) << 2;
562 mux = (reg >> off) & 0x7;
563
564 /* Skip pins that have been assigned other functions. */
565 if (mux != SXIPIO_GPIO_IN && mux != SXIPIO_GPIO_OUT &&
566 mux != SXIPIO_DISABLED)
567 continue;
568
569 switch (mux) {
570 case SXIPIO_GPIO_IN:
571 flags = GPIO_PIN_SET | GPIO_PIN_INPUT;
572 break;
573 case SXIPIO_GPIO_OUT:
574 flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT;
575 break;
576 default:
577 flags = GPIO_PIN_SET;
578 }
579
580 /* Get pin state. */
581 reg = SXIREAD4(sc, SXIPIO_DAT(port));
582 state = (reg >> pin) & 1;
583
584 sc->sc_gpio_pins[port][pin].pin_caps =
585 GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
586 sc->sc_gpio_pins[port][pin].pin_flags = flags;
587 sc->sc_gpio_pins[port][pin].pin_state = state;
588 sc->sc_gpio_pins[port][pin].pin_num = pin;
589 }
590
591 for (i = 0; i <= port; i++) {
592 memcpy(&sc->sc_gpio_tag[i], &sxipio_gpio_tag, sizeof(sxipio_gpio_tag));
593 sc->sc_gpio_tag[i].gp_cookie = &sc->sc_gpio[i];
594 sc->sc_gpio[i].sc = sc;
595 sc->sc_gpio[i].port = i;
596
597 gba.gba_name = "gpio";
598 gba.gba_gc = &sc->sc_gpio_tag[i];
599 gba.gba_pins = &sc->sc_gpio_pins[i][0];
600 gba.gba_npins = 32;
601
602 #if NGPIO > 0
603 config_found(&sc->sc_dev, &gba, gpiobus_print);
604 #endif
605 }
606 }
607