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