git: 3d20f8a02243 - main - jh7110_gpio: driver enhancements
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 21 Aug 2026 16:55:35 UTC
The branch main has been updated by mhorne:
URL: https://cgit.FreeBSD.org/src/commit/?id=3d20f8a022435e8ed37e2c0ce8f66d4c1203ec1c
commit 3d20f8a022435e8ed37e2c0ce8f66d4c1203ec1c
Author: Brian Scott <bscott@bunyatech.com.au>
AuthorDate: 2026-08-21 16:27:00 +0000
Commit: Mitchell Horne <mhorne@FreeBSD.org>
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) {