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