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);