The branch stable/15 has been updated by mhorne:

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

commit a722716674ba883bfa4d5eac4b29363706023d33
Author:     Brian Scott <[email protected]>
AuthorDate: 2026-08-21 16:27:00 +0000
Commit:     Mitchell Horne <[email protected]>
CommitDate: 2026-09-03 16:29:08 +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
    
    (cherry picked from commit 3d20f8a022435e8ed37e2c0ce8f66d4c1203ec1c)
---
 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 96b2cef43a4c..67e64bb29045 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");
@@ -300,23 +360,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) {

Reply via email to