git: 3d20f8a02243 - main - jh7110_gpio: driver enhancements

Mitchell Horne <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a888307.1c431.5d77f663__7566.98026541329$1787331387$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=3d20f8a022435e8ed37e2c0ce8f66d4c1203ec1c

commit 3d20f8a022435e8ed37e2c0ce8f66d4c1203ec1c
Author:     Brian Scott <[email protected]>
AuthorDate: 2026-08-21 16:27:00 +0000
Commit:     Mitchell Horne <[email protected]>
CommitDate: 2026-08-21 16:55:24 +0000

    jh7110_gpio: driver enhancements
    
    Fix reporting of state and capabilities by the gpioctl command.
    
    Support selection of pull-up and pull-down resistors.
    
    Support second gpio device (AON - always on power domain) to allow
    attaching gpioled device to visionfive2 status LED or querying boot
    selection switches.
    
    Reviewed by:    mhorne
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D58693
---
 sys/riscv/starfive/jh7110_gpio.c | 149 +++++++++++++++++++++++++++++----------
 1 file changed, 112 insertions(+), 37 deletions(-)

diff --git a/sys/riscv/starfive/jh7110_gpio.c b/sys/riscv/starfive/jh7110_gpio.c
index 93de49e79ace..fdf40e5c147d 100644
--- a/sys/riscv/starfive/jh7110_gpio.c
+++ b/sys/riscv/starfive/jh7110_gpio.c
@@ -25,24 +25,39 @@
 
 #include "gpio_if.h"
 
+#define	PINCTRL_SYS		1
+#define	PINCTRL_AON		2
+
 #define	GPIO_PINS		64
+#define	AON_GPIO_PINS		4
 #define	GPIO_REGS		2
 
 #define	GP0_DOEN_CFG		0x0
+#define	AON_DOEN_CFG		0x0
 #define	GP0_DOUT_CFG		0x40
+#define	AON_DOUT_CFG		0x4
 #define	GPIOEN			0xdc
+#define	AON_GPIOEN		0xc
 #define	GPIOE_0			0x100
 #define	GPIOE_1			0x104
+#define	GPIOE_AON		0x20
 #define	GPIO_DIN_LOW		0x118
 #define	GPIO_DIN_HIGH		0x11c
+#define	GPIO_DIN_AON		0x2c
 #define	IOMUX_SYSCFG_288	0x120
+#define	IOMUX_AONCFG_52		0x34
 
 #define	PAD_INPUT_EN		(1 << 0)
+#define	SHIFT_DRIVESTRENGTH	1
+#define	PAD_DRIVESTRENGTH	(0x3 << SHIFT_DRIVESTRENGTH)
 #define	PAD_PULLUP		(1 << 3)
 #define	PAD_PULLDOWN		(1 << 4)
+#define	PAD_SLEW		(1 << 5)
 #define	PAD_HYST		(1 << 6)
+#define	PAD_POWERONSTART	(1 << 7)
 
 #define	ENABLE_MASK		0x3f
+#define	OUTPUT_MASK		0x01
 #define	DATA_OUT_MASK		0x7f
 #define	DIROUT_DISABLE		1
 
@@ -52,10 +67,17 @@ struct jh7110_gpio_softc {
 	struct mtx		mtx;
 	struct resource		*res;
 	clk_t			clk;
+	int			pinctrl; /* which pinctrl controller */
+	uint32_t		maxpin; /* pins on this controller */
+	/* location of variable position fields for the two controllers */
+	uint32_t		iomuxcfg;
+	uint32_t		doutcfg;
+	uint32_t		doencfg;
 };
 
 static struct ofw_compat_data compat_data[] = {
-	{"starfive,jh7110-sys-pinctrl", 1},
+	{"starfive,jh7110-sys-pinctrl",	PINCTRL_SYS},
+	{"starfive,jh7110-aon-pinctrl",	PINCTRL_AON},
 	{NULL,				0}
 };
 
@@ -66,7 +88,7 @@ static struct resource_spec jh7110_gpio_spec[] = {
 
 #define	GPIO_RW_OFFSET(_val)		(_val & ~3)
 #define	GPIO_SHIFT(_val)		((_val & 3) * 8)
-#define	PAD_OFFSET(_val)		(_val * 4)
+#define	PAD_OFFSET(_val)		(_val * 4) /* 32 bits per pin (even though only 8 used) */
 
 #define	JH7110_GPIO_LOCK(_sc)		mtx_lock(&(_sc)->mtx)
 #define	JH7110_GPIO_UNLOCK(_sc)		mtx_unlock(&(_sc)->mtx)
@@ -87,7 +109,11 @@ jh7110_gpio_get_bus(device_t dev)
 static int
 jh7110_gpio_pin_max(device_t dev, int *maxpin)
 {
-	*maxpin = GPIO_PINS - 1;
+	struct jh7110_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	*maxpin = sc->maxpin;
 
 	return (0);
 }
@@ -100,11 +126,14 @@ jh7110_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)
 
 	sc = device_get_softc(dev);
 
-	if (pin >= GPIO_PINS)
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
 	JH7110_GPIO_LOCK(sc);
-	if (pin < GPIO_PINS / GPIO_REGS) {
+	if (sc->pinctrl == PINCTRL_AON) {
+		reg = RD4(sc, GPIO_DIN_AON);
+		*val = (reg >> pin) & 0x1;
+	} else if (pin < GPIO_PINS / GPIO_REGS) {
 		reg = RD4(sc, GPIO_DIN_LOW);
 		*val = (reg >> pin) & 0x1;
 	} else {
@@ -124,15 +153,15 @@ jh7110_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val)
 
 	sc = device_get_softc(dev);
 
-	if (pin >= GPIO_PINS)
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
 	JH7110_GPIO_LOCK(sc);
-	reg = RD4(sc, GP0_DOUT_CFG + GPIO_RW_OFFSET(pin));
+	reg = RD4(sc, sc->doutcfg + GPIO_RW_OFFSET(pin));
 	reg &= ~(DATA_OUT_MASK << GPIO_SHIFT(pin));
 	if (val != 0)
 		reg |= 0x1 << GPIO_SHIFT(pin);
-	WR4(sc, GP0_DOUT_CFG + GPIO_RW_OFFSET(pin), reg);
+	WR4(sc, sc->doutcfg + GPIO_RW_OFFSET(pin), reg);
 	JH7110_GPIO_UNLOCK(sc);
 
 	return (0);
@@ -146,18 +175,18 @@ jh7110_gpio_pin_toggle(device_t dev, uint32_t pin)
 
 	sc = device_get_softc(dev);
 
-	if (pin >= GPIO_PINS)
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
 	JH7110_GPIO_LOCK(sc);
-	reg = RD4(sc, GP0_DOUT_CFG + GPIO_RW_OFFSET(pin));
+	reg = RD4(sc, sc->doutcfg + GPIO_RW_OFFSET(pin));
 	if ((reg & 0x1 << GPIO_SHIFT(pin)) != 0) {
 		reg &= ~(DATA_OUT_MASK << GPIO_SHIFT(pin));
 	} else {
 		reg &= ~(DATA_OUT_MASK << GPIO_SHIFT(pin));
 		reg |= 0x1 << GPIO_SHIFT(pin);
 	}
-	WR4(sc, GP0_DOUT_CFG + GPIO_RW_OFFSET(pin), reg);
+	WR4(sc, sc->doutcfg + GPIO_RW_OFFSET(pin), reg);
 	JH7110_GPIO_UNLOCK(sc);
 
 	return (0);
@@ -166,10 +195,14 @@ jh7110_gpio_pin_toggle(device_t dev, uint32_t pin)
 static int
 jh7110_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
 {
-	if (pin >= GPIO_PINS)
+	struct jh7110_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
-	*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
+	*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
 
 	return (0);
 }
@@ -177,10 +210,15 @@ jh7110_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
 static int
 jh7110_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
 {
-	if (pin >= GPIO_PINS)
+	struct jh7110_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
-	snprintf(name, GPIOMAXNAME, "GPIO%d", pin);
+	snprintf(name, GPIOMAXNAME, "%sGPIO%d", sc->pinctrl == PINCTRL_SYS ?
+	  "" : "R", pin);
 
 	return (0);
 }
@@ -193,16 +231,22 @@ jh7110_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
 
 	sc = device_get_softc(dev);
 
-	if (pin >= GPIO_PINS)
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
 	/* Reading the direction */
+	*flags = 0;
 	JH7110_GPIO_LOCK(sc);
-	reg = RD4(sc, GP0_DOEN_CFG + GPIO_RW_OFFSET(pin));
+	reg = RD4(sc, sc->doencfg + GPIO_RW_OFFSET(pin));
 	if ((reg & ENABLE_MASK << GPIO_SHIFT(pin)) == 0)
 		*flags |= GPIO_PIN_OUTPUT;
 	else
 		*flags |= GPIO_PIN_INPUT;
+	reg = RD4(sc, sc->iomuxcfg + PAD_OFFSET(pin));
+	if (reg & PAD_PULLUP)
+		*flags |= GPIO_PIN_PULLUP;
+	if (reg & PAD_PULLDOWN)
+		*flags |= GPIO_PIN_PULLDOWN;
 	JH7110_GPIO_UNLOCK(sc);
 
 	return (0);
@@ -216,7 +260,7 @@ jh7110_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
 
 	sc = device_get_softc(dev);
 
-	if (pin >= GPIO_PINS)
+	if (pin > sc->maxpin)
 		return (EINVAL);
 
 	/* Setting the direction, enable or disable output, configuring pads */
@@ -224,27 +268,39 @@ jh7110_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
 	JH7110_GPIO_LOCK(sc);
 
 	if ((flags & GPIO_PIN_INPUT) != 0) {
-		reg = RD4(sc, IOMUX_SYSCFG_288 + PAD_OFFSET(pin));
+		reg = RD4(sc, sc->iomuxcfg + PAD_OFFSET(pin));
 		reg |= (PAD_INPUT_EN | PAD_HYST);
-		WR4(sc, IOMUX_SYSCFG_288 + PAD_OFFSET(pin), reg);
+		reg &= ~(PAD_DRIVESTRENGTH | PAD_SLEW);
+		if ((flags & GPIO_PIN_PULLUP) != 0)
+			reg |= PAD_PULLUP;
+		else
+			reg &= ~PAD_PULLUP;
+		if ((flags & GPIO_PIN_PULLDOWN) != 0)
+			reg |= PAD_PULLDOWN;
+		else
+			reg &= ~PAD_PULLDOWN;
+		WR4(sc, sc->iomuxcfg + PAD_OFFSET(pin), reg);
 	}
 
-	reg = RD4(sc, GP0_DOEN_CFG + GPIO_RW_OFFSET(pin));
+	reg = RD4(sc, sc->doencfg + GPIO_RW_OFFSET(pin));
 	reg &= ~(ENABLE_MASK << GPIO_SHIFT(pin));
 	if ((flags & GPIO_PIN_INPUT) != 0) {
 		reg |= DIROUT_DISABLE << GPIO_SHIFT(pin);
 	}
-	WR4(sc, GP0_DOEN_CFG + GPIO_RW_OFFSET(pin), reg);
+	WR4(sc, sc->doencfg + GPIO_RW_OFFSET(pin), reg);
 
 	if ((flags & GPIO_PIN_OUTPUT) != 0) {
-		reg = RD4(sc, GP0_DOUT_CFG + GPIO_RW_OFFSET(pin));
-		reg &= ~(ENABLE_MASK << GPIO_SHIFT(pin));
-		reg |= 0x1 << GPIO_SHIFT(pin);
-		WR4(sc, GP0_DOUT_CFG + GPIO_RW_OFFSET(pin), reg);
-
-		reg = RD4(sc, IOMUX_SYSCFG_288 + PAD_OFFSET(pin));
-		reg &= ~(PAD_INPUT_EN | PAD_PULLUP | PAD_PULLDOWN | PAD_HYST);
-		WR4(sc, IOMUX_SYSCFG_288 + PAD_OFFSET(pin), reg);
+		reg = RD4(sc, sc->doutcfg + GPIO_RW_OFFSET(pin));
+		/*
+		 * Clear the output selection but maintain the current (from
+		 * last time as output) state.
+		 */
+		reg &= ~((ENABLE_MASK - OUTPUT_MASK) << GPIO_SHIFT(pin));
+		WR4(sc, sc->doutcfg + GPIO_RW_OFFSET(pin), reg);
+
+		reg = RD4(sc, sc->iomuxcfg + PAD_OFFSET(pin));
+		reg &= ~(PAD_PULLUP | PAD_PULLDOWN | PAD_HYST);
+		WR4(sc, sc->iomuxcfg + PAD_OFFSET(pin), reg);
 	}
 
 	JH7110_GPIO_UNLOCK(sc);
@@ -255,10 +311,14 @@ jh7110_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
 static int
 jh7110_gpio_probe(device_t dev)
 {
+	struct jh7110_gpio_softc *sc;
+
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
-	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+	sc = device_get_softc(dev);
+
+	if ((sc->pinctrl = ofw_bus_search_compatible(dev, compat_data)->ocd_data) == 0)
 		return (ENXIO);
 
 	device_set_desc(dev, "StarFive JH7110 GPIO controller");
@@ -299,23 +359,38 @@ jh7110_gpio_attach(device_t dev)
 		return (ENXIO);
 	}
 
-	if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0) {
+	sc->clk = NULL;
+	if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0 &&
+	    sc->pinctrl != PINCTRL_AON) {
 		device_printf(dev, "Cannot get clock\n");
 		jh7110_gpio_detach(dev);
 		return (ENXIO);
 	}
 
-	if (clk_enable(sc->clk) != 0) {
+	if (sc->clk != NULL && clk_enable(sc->clk) != 0) {
 		device_printf(dev, "Could not enable clock %s\n",
 		    clk_get_name(sc->clk));
 		jh7110_gpio_detach(dev);
 		return (ENXIO);
 	}
 
-	/* Reseting GPIO interrupts */
-	WR4(sc, GPIOE_0, 0);
-	WR4(sc, GPIOE_1, 0);
-	WR4(sc, GPIOEN, 1);
+	/* Reset GPIO interrupts and set register offsets. */
+	if (sc->pinctrl == PINCTRL_SYS) {
+		WR4(sc, GPIOE_0, 0);
+		WR4(sc, GPIOE_1, 0);
+		WR4(sc, GPIOEN, 1);
+		sc->maxpin = GPIO_PINS - 1;
+		sc->iomuxcfg = IOMUX_SYSCFG_288;
+		sc->doutcfg = GP0_DOUT_CFG;
+		sc->doencfg = GP0_DOEN_CFG;
+	} else {
+		WR4(sc, GPIOE_AON, 0);
+		WR4(sc, AON_GPIOEN, 1);
+		sc->maxpin = AON_GPIO_PINS - 1;
+		sc->iomuxcfg = IOMUX_AONCFG_52;
+		sc->doutcfg = AON_DOUT_CFG;
+		sc->doencfg = AON_DOEN_CFG;
+	}
 
 	sc->busdev = gpiobus_add_bus(dev);
 	if (sc->busdev == NULL) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.