Module Name:    src
Committed By:   tnn
Date:           Tue Oct 17 17:31:12 UTC 2023

Modified Files:
        src/sys/arch/arm/rockchip: rk_gpio.c

Log Message:
rk_gpio: add support for version 2 controller

Based on PR 57597 from Johann Rudloff.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/rockchip/rk_gpio.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/rockchip/rk_gpio.c
diff -u src/sys/arch/arm/rockchip/rk_gpio.c:1.6 src/sys/arch/arm/rockchip/rk_gpio.c:1.7
--- src/sys/arch/arm/rockchip/rk_gpio.c:1.6	Tue Oct 17 15:09:18 2023
+++ src/sys/arch/arm/rockchip/rk_gpio.c	Tue Oct 17 17:31:12 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_gpio.c,v 1.6 2023/10/17 15:09:18 tnn Exp $ */
+/* $NetBSD: rk_gpio.c,v 1.7 2023/10/17 17:31:12 tnn Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_gpio.c,v 1.6 2023/10/17 15:09:18 tnn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_gpio.c,v 1.7 2023/10/17 17:31:12 tnn Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -55,6 +55,26 @@ __KERNEL_RCSID(0, "$NetBSD: rk_gpio.c,v 
 #define	GPIO_PORTA_EOI_REG		0x004c
 #define	GPIO_EXT_PORTA_REG		0x0050
 #define	GPIO_LS_SYNC_REG		0x0060
+#define	GPIO_VER_ID_REG			0x0078
+#define	GPIO_VER_ID_GPIOV2		0x0101157c
+
+/*
+ * In "version 2" GPIO controllers, half of each register is used by the
+ * write_enable mask, so the 32 pins are spread over two registers.
+ *
+ * pins  0 - 15 go into the GPIO_SWPORT_*_L register
+ * pins 16 - 31 go into the GPIO_SWPORT_*_H register
+ */
+#define GPIOV2_SWPORT_DR_BASE		0x0000
+#define GPIOV2_SWPORT_DR_REG(pin)	\
+	(GPIOV2_SWPORT_DR_BASE + GPIOV2_REG_OFFSET(pin))
+#define	GPIOV2_SWPORT_DDR_BASE		0x0008
+#define	GPIOV2_SWPORT_DDR_REG(pin)	\
+	(GPIOV2_SWPORT_DDR_BASE + GPIOV2_REG_OFFSET(pin))
+#define	GPIOV2_EXT_PORT_REG		0x0070
+#define	GPIOV2_REG_OFFSET(pin)		(((pin) >> 4) << 2)
+#define	GPIOV2_DATA_MASK(pin)		(__BIT((pin) & 0xF))
+#define	GPIOV2_WRITE_MASK(pin)		(__BIT(((pin) & 0xF) | 0x10))
 
 static const struct device_compatible_entry compat_data[] = {
 	{ .compat = "rockchip,gpio-bank" },
@@ -223,18 +243,58 @@ rk_gpio_pin_ctl(void *priv, int pin, int
 	mutex_exit(&sc->sc_lock);
 }
 
+static int
+rk_gpio_v2_pin_read(void *priv, int pin)
+{
+	struct rk_gpio_softc * const sc = priv;
+	uint32_t data;
+	int val;
+
+	KASSERT(pin < __arraycount(sc->sc_pins));
+
+	const uint32_t data_mask = __BIT(pin);
+
+	/* No lock required for reads */
+	data = RD4(sc, GPIOV2_EXT_PORT_REG);
+	val = __SHIFTOUT(data, data_mask);
+
+	return val;
+}
+
+static void
+rk_gpio_v2_pin_write(void *priv, int pin, int val)
+{
+	struct rk_gpio_softc * const sc = priv;
+	uint32_t data;
+
+	KASSERT(pin < __arraycount(sc->sc_pins));
+
+	const uint32_t write_mask = GPIOV2_WRITE_MASK(pin);
+
+	/* No lock required for writes on v2 controllers  */
+	data = val ? GPIOV2_DATA_MASK(pin) : 0;
+	WR4(sc, GPIOV2_SWPORT_DR_REG(pin), write_mask | data);
+}
+
+static void
+rk_gpio_v2_pin_ctl(void *priv, int pin, int flags)
+{
+	struct rk_gpio_softc * const sc = priv;
+	uint32_t ddr;
+
+	KASSERT(pin < __arraycount(sc->sc_pins));
+
+	/* No lock required for writes on v2 controllers  */
+	ddr = (flags & GPIO_PIN_OUTPUT) ? GPIOV2_DATA_MASK(pin) : 0;
+	WR4(sc, GPIOV2_SWPORT_DDR_REG(pin), GPIOV2_WRITE_MASK(pin) | ddr);
+}
+
 static void
 rk_gpio_attach_ports(struct rk_gpio_softc *sc)
 {
-	struct gpio_chipset_tag *gp = &sc->sc_gp;
 	struct gpiobus_attach_args gba;
 	u_int pin;
 
-	gp->gp_cookie = sc;
-	gp->gp_pin_read = rk_gpio_pin_read;
-	gp->gp_pin_write = rk_gpio_pin_write;
-	gp->gp_pin_ctl = rk_gpio_pin_ctl;
-
 	for (pin = 0; pin < __arraycount(sc->sc_pins); pin++) {
 		sc->sc_pins[pin].pin_num = pin;
 		sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
@@ -242,7 +302,7 @@ rk_gpio_attach_ports(struct rk_gpio_soft
 	}
 
 	memset(&gba, 0, sizeof(gba));
-	gba.gba_gc = gp;
+	gba.gba_gc = &sc->sc_gp;
 	gba.gba_pins = sc->sc_pins;
 	gba.gba_npins = __arraycount(sc->sc_pins);
 	sc->sc_gpiodev = config_found(sc->sc_dev, &gba, NULL, CFARGS_NONE);
@@ -260,11 +320,14 @@ static void
 rk_gpio_attach(device_t parent, device_t self, void *aux)
 {
 	struct rk_gpio_softc * const sc = device_private(self);
+	struct gpio_chipset_tag * const gp = &sc->sc_gp;
 	struct fdt_attach_args * const faa = aux;
 	const int phandle = faa->faa_phandle;
 	struct clk *clk;
 	bus_addr_t addr;
 	bus_size_t size;
+	uint32_t ver_id;
+	int ver;
 
 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
 		aprint_error(": couldn't get registers\n");
@@ -282,10 +345,31 @@ rk_gpio_attach(device_t parent, device_t
 		aprint_error(": couldn't map registers\n");
 		return;
 	}
+
+	gp->gp_cookie = sc;
+	ver_id = RD4(sc, GPIO_VER_ID_REG);
+	switch (ver_id) {
+	case 0: /* VER_ID not implemented in v1 but reads back as 0 */
+		ver = 1;
+		gp->gp_pin_read = rk_gpio_pin_read;
+		gp->gp_pin_write = rk_gpio_pin_write;
+		gp->gp_pin_ctl = rk_gpio_pin_ctl;
+		break;
+	case GPIO_VER_ID_GPIOV2:
+		ver = 2;
+		gp->gp_pin_read = rk_gpio_v2_pin_read;
+		gp->gp_pin_write = rk_gpio_v2_pin_write;
+		gp->gp_pin_ctl = rk_gpio_v2_pin_ctl;
+		break;
+	default:
+		aprint_error(": unknown version 0x%08" PRIx32 "\n", ver_id);
+		return;
+	}
+
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
 
 	aprint_naive("\n");
-	aprint_normal(": GPIO (%s)\n", fdtbus_get_string(phandle, "name"));
+	aprint_normal(": GPIO v%d (%s)\n", ver, fdtbus_get_string(phandle, "name"));
 
 	fdtbus_register_gpio_controller(self, phandle, &rk_gpio_funcs);
 

Reply via email to