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 <[email protected]>
@@ -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);