xref: /openbsd/sys/arch/octeon/dev/octgpio.c (revision cc838d97)
1*cc838d97Svisa /*	$OpenBSD: octgpio.c,v 1.2 2019/09/29 04:28:52 visa Exp $	*/
24c76d6caSvisa 
34c76d6caSvisa /*
44c76d6caSvisa  * Copyright (c) 2019 Visa Hankala
54c76d6caSvisa  *
64c76d6caSvisa  * Permission to use, copy, modify, and distribute this software for any
74c76d6caSvisa  * purpose with or without fee is hereby granted, provided that the above
84c76d6caSvisa  * copyright notice and this permission notice appear in all copies.
94c76d6caSvisa  *
104c76d6caSvisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114c76d6caSvisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124c76d6caSvisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134c76d6caSvisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144c76d6caSvisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154c76d6caSvisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164c76d6caSvisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174c76d6caSvisa  */
184c76d6caSvisa 
194c76d6caSvisa /*
204c76d6caSvisa  * Driver for OCTEON GPIO controller.
214c76d6caSvisa  */
224c76d6caSvisa 
234c76d6caSvisa #include <sys/param.h>
244c76d6caSvisa #include <sys/systm.h>
254c76d6caSvisa #include <sys/device.h>
264c76d6caSvisa #include <sys/malloc.h>
274c76d6caSvisa 
284c76d6caSvisa #include <dev/ofw/fdt.h>
294c76d6caSvisa #include <dev/ofw/ofw_gpio.h>
304c76d6caSvisa #include <dev/ofw/openfirm.h>
314c76d6caSvisa 
324c76d6caSvisa #include <machine/fdt.h>
33*cc838d97Svisa #include <machine/octeonvar.h>
344c76d6caSvisa #include <machine/octeon_model.h>
354c76d6caSvisa 
364c76d6caSvisa #define GPIO_BIT_CFG(x)		(0x0000u + (x) * 8)
37*cc838d97Svisa #define   GPIO_BIT_CFG_OUTPUT_SEL_M	0x00000000001f0000ull
38*cc838d97Svisa #define   GPIO_BIT_CFG_OUTPUT_SEL_S	16
394c76d6caSvisa #define   GPIO_BIT_CFG_INT_EN		0x0000000000000004ull
404c76d6caSvisa #define   GPIO_BIT_CFG_RX_XOR		0x0000000000000002ull
414c76d6caSvisa #define   GPIO_BIT_CFG_TX_OE		0x0000000000000001ull
424c76d6caSvisa #define GPIO_XBIT_CFG(x)	(0x0100u + (x) * 8)
434c76d6caSvisa #define GPIO_RX_DAT		0x0080u
444c76d6caSvisa #define GPIO_TX_SET		0x0088u
454c76d6caSvisa #define GPIO_TX_CLR		0x0090u
464c76d6caSvisa 
474c76d6caSvisa #define GPIO_RD_8(sc, reg) \
484c76d6caSvisa 	bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg))
494c76d6caSvisa #define GPIO_WR_8(sc, reg, val) \
504c76d6caSvisa 	bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
514c76d6caSvisa 
524c76d6caSvisa struct octgpio_softc {
534c76d6caSvisa 	struct device		 sc_dev;
544c76d6caSvisa 	bus_space_tag_t		 sc_iot;
554c76d6caSvisa 	bus_space_handle_t	 sc_ioh;
564c76d6caSvisa 	struct gpio_controller	 sc_gc;
574c76d6caSvisa 	uint32_t		 sc_npins;
584c76d6caSvisa 	uint32_t		 sc_xbit;
594c76d6caSvisa };
604c76d6caSvisa 
614c76d6caSvisa int	octgpio_match(struct device *, void *, void *);
624c76d6caSvisa void	octgpio_attach(struct device *, struct device *, void *);
634c76d6caSvisa 
644c76d6caSvisa void	octgpio_config_pin(void *, uint32_t *, int);
654c76d6caSvisa int	octgpio_get_pin(void *, uint32_t *);
664c76d6caSvisa void	octgpio_set_pin(void *, uint32_t *, int);
674c76d6caSvisa 
684c76d6caSvisa const struct cfattach octgpio_ca = {
694c76d6caSvisa 	sizeof(struct octgpio_softc), octgpio_match, octgpio_attach
704c76d6caSvisa };
714c76d6caSvisa 
724c76d6caSvisa struct cfdriver octgpio_cd = {
734c76d6caSvisa 	NULL, "octgpio", DV_DULL
744c76d6caSvisa };
754c76d6caSvisa 
764c76d6caSvisa int
octgpio_match(struct device * parent,void * match,void * aux)774c76d6caSvisa octgpio_match(struct device *parent, void *match, void *aux)
784c76d6caSvisa {
794c76d6caSvisa 	struct fdt_attach_args *faa = aux;
804c76d6caSvisa 
814c76d6caSvisa 	return OF_is_compatible(faa->fa_node, "cavium,octeon-3860-gpio") ||
824c76d6caSvisa 	    OF_is_compatible(faa->fa_node, "cavium,octeon-7890-gpio");
834c76d6caSvisa }
844c76d6caSvisa 
854c76d6caSvisa void
octgpio_attach(struct device * parent,struct device * self,void * aux)864c76d6caSvisa octgpio_attach(struct device *parent, struct device *self, void *aux)
874c76d6caSvisa {
884c76d6caSvisa 	struct fdt_attach_args *faa = aux;
894c76d6caSvisa 	struct octgpio_softc *sc = (struct octgpio_softc *)self;
904c76d6caSvisa 	uint32_t chipid;
914c76d6caSvisa 
924c76d6caSvisa 	if (faa->fa_nreg != 1) {
934c76d6caSvisa 		printf(": no registers\n");
944c76d6caSvisa 		return;
954c76d6caSvisa 	}
964c76d6caSvisa 
974c76d6caSvisa 	sc->sc_iot = faa->fa_iot;
984c76d6caSvisa 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
994c76d6caSvisa 	    0, &sc->sc_ioh)) {
1004c76d6caSvisa 		printf(": can't map registers\n");
1014c76d6caSvisa 		return;
1024c76d6caSvisa 	}
1034c76d6caSvisa 
1044c76d6caSvisa 	chipid = octeon_get_chipid();
1054c76d6caSvisa 	switch (octeon_model_family(chipid)) {
1064c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN61XX:
1074c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN63XX:
1084c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN66XX:
1094c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN68XX:
1104c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN71XX:
1114c76d6caSvisa 		sc->sc_npins = 20;
1124c76d6caSvisa 		sc->sc_xbit = 16;
1134c76d6caSvisa 		break;
1144c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN73XX:
1154c76d6caSvisa 		sc->sc_npins = 32;
1164c76d6caSvisa 		sc->sc_xbit = 0;
1174c76d6caSvisa 		break;
1184c76d6caSvisa 	case OCTEON_MODEL_FAMILY_CN78XX:
1194c76d6caSvisa 		sc->sc_npins = 20;
1204c76d6caSvisa 		sc->sc_xbit = 0;
1214c76d6caSvisa 		break;
1224c76d6caSvisa 	default:
1234c76d6caSvisa 		sc->sc_npins = 24;
1244c76d6caSvisa 		sc->sc_xbit = 16;
1254c76d6caSvisa 		break;
1264c76d6caSvisa 	}
1274c76d6caSvisa 
1284c76d6caSvisa 	sc->sc_gc.gc_node = faa->fa_node;
1294c76d6caSvisa 	sc->sc_gc.gc_cookie = sc;
1304c76d6caSvisa 	sc->sc_gc.gc_config_pin = octgpio_config_pin;
1314c76d6caSvisa 	sc->sc_gc.gc_get_pin = octgpio_get_pin;
1324c76d6caSvisa 	sc->sc_gc.gc_set_pin = octgpio_set_pin;
1334c76d6caSvisa 	gpio_controller_register(&sc->sc_gc);
1344c76d6caSvisa 
1354c76d6caSvisa 	printf(": %u pins, xbit %u\n", sc->sc_npins, sc->sc_xbit);
1364c76d6caSvisa }
1374c76d6caSvisa 
1384c76d6caSvisa void
octgpio_config_pin(void * cookie,uint32_t * cells,int config)1394c76d6caSvisa octgpio_config_pin(void *cookie, uint32_t *cells, int config)
1404c76d6caSvisa {
1414c76d6caSvisa 	struct octgpio_softc *sc = cookie;
142*cc838d97Svisa 	uint64_t output_sel, reg, value;
1434c76d6caSvisa 	uint32_t pin = cells[0];
1444c76d6caSvisa 
1454c76d6caSvisa 	if (pin >= sc->sc_npins)
1464c76d6caSvisa 		return;
1474c76d6caSvisa 	if (pin >= sc->sc_xbit)
1484c76d6caSvisa 		reg = GPIO_XBIT_CFG(pin - sc->sc_xbit);
1494c76d6caSvisa 	else
1504c76d6caSvisa 		reg = GPIO_BIT_CFG(pin);
1514c76d6caSvisa 
1524c76d6caSvisa 	value = GPIO_RD_8(sc, reg);
153*cc838d97Svisa 	if (config & GPIO_CONFIG_OUTPUT) {
1544c76d6caSvisa 		value |= GPIO_BIT_CFG_TX_OE;
155*cc838d97Svisa 
156*cc838d97Svisa 		switch (config & GPIO_CONFIG_MD_OUTPUT_SEL_MASK) {
157*cc838d97Svisa 		case GPIO_CONFIG_MD_USB0_VBUS_CTRL:
158*cc838d97Svisa 			output_sel = 0x14;
159*cc838d97Svisa 			break;
160*cc838d97Svisa 		case GPIO_CONFIG_MD_USB1_VBUS_CTRL:
161*cc838d97Svisa 			output_sel = 0x19;
162*cc838d97Svisa 			break;
163*cc838d97Svisa 		default:
164*cc838d97Svisa 			output_sel = 0;
165*cc838d97Svisa 			break;
166*cc838d97Svisa 		}
167*cc838d97Svisa 		value &= ~GPIO_BIT_CFG_OUTPUT_SEL_M;
168*cc838d97Svisa 		value |= output_sel << GPIO_BIT_CFG_OUTPUT_SEL_S;
169*cc838d97Svisa 	} else
1704c76d6caSvisa 		value &= ~(GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_RX_XOR);
1714c76d6caSvisa 	/* There is no INT_EN bit on true XBIT pins. */
1724c76d6caSvisa 	value &= ~GPIO_BIT_CFG_INT_EN;
1734c76d6caSvisa 	GPIO_WR_8(sc, reg, value);
1744c76d6caSvisa }
1754c76d6caSvisa 
1764c76d6caSvisa int
octgpio_get_pin(void * cookie,uint32_t * cells)1774c76d6caSvisa octgpio_get_pin(void *cookie, uint32_t *cells)
1784c76d6caSvisa {
1794c76d6caSvisa 	struct octgpio_softc *sc = cookie;
1804c76d6caSvisa 	uint32_t pin = cells[0];
1814c76d6caSvisa 	uint32_t flags = cells[1];
1824c76d6caSvisa 	int value;
1834c76d6caSvisa 
1844c76d6caSvisa 	if (pin >= sc->sc_npins)
1854c76d6caSvisa 		return 0;
1864c76d6caSvisa 
1874c76d6caSvisa 	value = (GPIO_RD_8(sc, GPIO_RX_DAT) >> pin) & 1;
1884c76d6caSvisa 	if (flags & GPIO_ACTIVE_LOW)
1894c76d6caSvisa 		value = !value;
1904c76d6caSvisa 	return value;
1914c76d6caSvisa }
1924c76d6caSvisa 
1934c76d6caSvisa void
octgpio_set_pin(void * cookie,uint32_t * cells,int value)1944c76d6caSvisa octgpio_set_pin(void *cookie, uint32_t *cells, int value)
1954c76d6caSvisa {
1964c76d6caSvisa 	struct octgpio_softc *sc = cookie;
1974c76d6caSvisa 	uint32_t pin = cells[0];
1984c76d6caSvisa 	uint32_t flags = cells[1];
1994c76d6caSvisa 
2004c76d6caSvisa 	if (pin >= sc->sc_npins)
2014c76d6caSvisa 		return;
2024c76d6caSvisa 
2034c76d6caSvisa 	if (flags & GPIO_ACTIVE_LOW)
2044c76d6caSvisa 		value = !value;
2054c76d6caSvisa 	if (value)
2064c76d6caSvisa 		GPIO_WR_8(sc, GPIO_TX_SET, 1ul << pin);
2074c76d6caSvisa 	else
2084c76d6caSvisa 		GPIO_WR_8(sc, GPIO_TX_CLR, 1ul << pin);
2094c76d6caSvisa }
210