From 4dff02e997e7f25cd047bbe668ed46797555a0d1 Mon Sep 17 00:00:00 2001 From: manu Date: Thu, 16 Jan 2020 20:02:41 +0000 Subject: [PATCH] arm: allwinner: Add support for bank supply Each GPIO bank is powered by a different pin and so can be powered at different voltage from different regulators. Add a new config that now hold the pinmux data and the banks available on each SoCs. Since the aw_gpio driver being also the pinmux one it's attached before the PMIC so add a config_intrhook_oneshot function that will enable the needed regulators when the system is fully functional. MFC after: 2 weeks --- sys/arm/allwinner/aw_gpio.c | 247 +++++++++++++++++++++++++----------- 1 file changed, 171 insertions(+), 76 deletions(-) diff --git a/sys/arm/allwinner/aw_gpio.c b/sys/arm/allwinner/aw_gpio.c index 8fc6ecd339de..2e00a707ec5e 100644 --- a/sys/arm/allwinner/aw_gpio.c +++ b/sys/arm/allwinner/aw_gpio.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #if defined(__aarch64__) #include "opt_soc.h" @@ -78,102 +79,167 @@ __FBSDID("$FreeBSD$"); #define AW_PINCTRL 1 #define AW_R_PINCTRL 2 +struct aw_gpio_conf { + struct allwinner_padconf *padconf; + const char *banks; +}; + /* Defined in aw_padconf.c */ #ifdef SOC_ALLWINNER_A10 -extern const struct allwinner_padconf a10_padconf; +extern struct allwinner_padconf a10_padconf; +struct aw_gpio_conf a10_gpio_conf = { + .padconf = &a10_padconf, + .banks = "abcdefghi", +}; #endif /* Defined in a13_padconf.c */ #ifdef SOC_ALLWINNER_A13 -extern const struct allwinner_padconf a13_padconf; +extern struct allwinner_padconf a13_padconf; +struct aw_gpio_conf a13_gpio_conf = { + .padconf = &a13_padconf, + .banks = "bcdefg", +}; #endif /* Defined in a20_padconf.c */ #ifdef SOC_ALLWINNER_A20 -extern const struct allwinner_padconf a20_padconf; +extern struct allwinner_padconf a20_padconf; +struct aw_gpio_conf a20_gpio_conf = { + .padconf = &a20_padconf, + .banks = "abcdefghi", +}; #endif /* Defined in a31_padconf.c */ #ifdef SOC_ALLWINNER_A31 -extern const struct allwinner_padconf a31_padconf; +extern struct allwinner_padconf a31_padconf; +struct aw_gpio_conf a31_gpio_conf = { + .padconf = &a31_padconf, + .banks = "abcdefgh", +}; #endif /* Defined in a31s_padconf.c */ #ifdef SOC_ALLWINNER_A31S -extern const struct allwinner_padconf a31s_padconf; +extern struct allwinner_padconf a31s_padconf; +struct aw_gpio_conf a31s_gpio_conf = { + .padconf = &a31s_padconf, + .banks = "abcdefgh", +}; #endif #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) -extern const struct allwinner_padconf a31_r_padconf; +extern struct allwinner_padconf a31_r_padconf; +struct aw_gpio_conf a31_r_gpio_conf = { + .padconf = &a31_r_padconf, + .banks = "lm", +}; #endif /* Defined in a33_padconf.c */ #ifdef SOC_ALLWINNER_A33 -extern const struct allwinner_padconf a33_padconf; +extern struct allwinner_padconf a33_padconf; +struct aw_gpio_conf a33_gpio_conf = { + .padconf = &a33_padconf, + .banks = "bcdefgh", +}; #endif /* Defined in h3_padconf.c */ #if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) -extern const struct allwinner_padconf h3_padconf; -extern const struct allwinner_padconf h3_r_padconf; +extern struct allwinner_padconf h3_padconf; +extern struct allwinner_padconf h3_r_padconf; +struct aw_gpio_conf h3_gpio_conf = { + .padconf = &h3_padconf, + .banks = "acdefg", +}; +struct aw_gpio_conf h3_r_gpio_conf = { + .padconf = &h3_r_padconf, + .banks = "l", +}; #endif /* Defined in a83t_padconf.c */ #ifdef SOC_ALLWINNER_A83T -extern const struct allwinner_padconf a83t_padconf; -extern const struct allwinner_padconf a83t_r_padconf; +extern struct allwinner_padconf a83t_padconf; +extern struct allwinner_padconf a83t_r_padconf; +struct aw_gpio_conf a83t_gpio_conf = { + .padconf = &a83t_padconf, + .banks = "bcdefgh" +}; +struct aw_gpio_conf a83t_r_gpio_conf = { + .padconf = &a83t_r_padconf, + .banks = "l", +}; #endif /* Defined in a64_padconf.c */ #ifdef SOC_ALLWINNER_A64 -extern const struct allwinner_padconf a64_padconf; -extern const struct allwinner_padconf a64_r_padconf; +extern struct allwinner_padconf a64_padconf; +extern struct allwinner_padconf a64_r_padconf; +struct aw_gpio_conf a64_gpio_conf = { + .padconf = &a64_padconf, + .banks = "bcdefgh", +}; +struct aw_gpio_conf a64_r_gpio_conf = { + .padconf = &a64_r_padconf, + .banks = "l", +}; #endif /* Defined in h6_padconf.c */ #ifdef SOC_ALLWINNER_H6 -extern const struct allwinner_padconf h6_padconf; -extern const struct allwinner_padconf h6_r_padconf; +extern struct allwinner_padconf h6_padconf; +extern struct allwinner_padconf h6_r_padconf; +struct aw_gpio_conf h6_gpio_conf = { + .padconf = &h6_padconf, + .banks = "cdfgh", +}; +struct aw_gpio_conf h6_r_gpio_conf = { + .padconf = &h6_r_padconf, + .banks = "lm", +}; #endif static struct ofw_compat_data compat_data[] = { #ifdef SOC_ALLWINNER_A10 - {"allwinner,sun4i-a10-pinctrl", (uintptr_t)&a10_padconf}, + {"allwinner,sun4i-a10-pinctrl", (uintptr_t)&a10_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A13 - {"allwinner,sun5i-a13-pinctrl", (uintptr_t)&a13_padconf}, + {"allwinner,sun5i-a13-pinctrl", (uintptr_t)&a13_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A20 - {"allwinner,sun7i-a20-pinctrl", (uintptr_t)&a20_padconf}, + {"allwinner,sun7i-a20-pinctrl", (uintptr_t)&a20_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A31 - {"allwinner,sun6i-a31-pinctrl", (uintptr_t)&a31_padconf}, + {"allwinner,sun6i-a31-pinctrl", (uintptr_t)&a31_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A31S - {"allwinner,sun6i-a31s-pinctrl", (uintptr_t)&a31s_padconf}, + {"allwinner,sun6i-a31s-pinctrl", (uintptr_t)&a31s_gpio_conf}, #endif #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) - {"allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&a31_r_padconf}, + {"allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&a31_r_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A33 - {"allwinner,sun6i-a33-pinctrl", (uintptr_t)&a33_padconf}, + {"allwinner,sun6i-a33-pinctrl", (uintptr_t)&a33_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A83T - {"allwinner,sun8i-a83t-pinctrl", (uintptr_t)&a83t_padconf}, - {"allwinner,sun8i-a83t-r-pinctrl", (uintptr_t)&a83t_r_padconf}, + {"allwinner,sun8i-a83t-pinctrl", (uintptr_t)&a83t_gpio_conf}, + {"allwinner,sun8i-a83t-r-pinctrl", (uintptr_t)&a83t_r_gpio_conf}, #endif #if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) - {"allwinner,sun8i-h3-pinctrl", (uintptr_t)&h3_padconf}, - {"allwinner,sun50i-h5-pinctrl", (uintptr_t)&h3_padconf}, - {"allwinner,sun8i-h3-r-pinctrl", (uintptr_t)&h3_r_padconf}, + {"allwinner,sun8i-h3-pinctrl", (uintptr_t)&h3_gpio_conf}, + {"allwinner,sun50i-h5-pinctrl", (uintptr_t)&h3_gpio_conf}, + {"allwinner,sun8i-h3-r-pinctrl", (uintptr_t)&h3_r_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A64 - {"allwinner,sun50i-a64-pinctrl", (uintptr_t)&a64_padconf}, - {"allwinner,sun50i-a64-r-pinctrl", (uintptr_t)&a64_r_padconf}, + {"allwinner,sun50i-a64-pinctrl", (uintptr_t)&a64_gpio_conf}, + {"allwinner,sun50i-a64-r-pinctrl", (uintptr_t)&a64_r_gpio_conf}, #endif #ifdef SOC_ALLWINNER_H6 - {"allwinner,sun50i-h6-pinctrl", (uintptr_t)&h6_padconf}, - {"allwinner,sun50i-h6-r-pinctrl", (uintptr_t)&h6_r_padconf}, + {"allwinner,sun50i-h6-pinctrl", (uintptr_t)&h6_gpio_conf}, + {"allwinner,sun50i-h6-r-pinctrl", (uintptr_t)&h6_r_gpio_conf}, #endif {NULL, 0} }; @@ -192,7 +258,7 @@ struct aw_gpio_softc { bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; void * sc_intrhand; - const struct allwinner_padconf * padconf; + struct aw_gpio_conf *conf; TAILQ_HEAD(, clk_list) clk_list; }; @@ -237,10 +303,10 @@ aw_gpio_get_function(struct aw_gpio_softc *sc, uint32_t pin) /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - if (pin > sc->padconf->npins) + if (pin > sc->conf->padconf->npins) return (0); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x07) << 2); func = AW_GPIO_READ(sc, AW_GPIO_GP_CFG(bank, pin >> 3)); @@ -254,14 +320,14 @@ aw_gpio_set_function(struct aw_gpio_softc *sc, uint32_t pin, uint32_t f) uint32_t bank, data, offset; /* Check if the function exists in the padconf data */ - if (sc->padconf->pins[pin].functions[f] == NULL) + if (sc->conf->padconf->pins[pin].functions[f] == NULL) return (EINVAL); /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x07) << 2); data = AW_GPIO_READ(sc, AW_GPIO_GP_CFG(bank, pin >> 3)); @@ -280,8 +346,8 @@ aw_gpio_get_pud(struct aw_gpio_softc *sc, uint32_t pin) /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_PUL(bank, pin >> 4)); @@ -300,8 +366,8 @@ aw_gpio_set_pud(struct aw_gpio_softc *sc, uint32_t pin, uint32_t state) /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_PUL(bank, pin >> 4)); @@ -318,8 +384,8 @@ aw_gpio_get_drv(struct aw_gpio_softc *sc, uint32_t pin) /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_DRV(bank, pin >> 4)); @@ -338,8 +404,8 @@ aw_gpio_set_drv(struct aw_gpio_softc *sc, uint32_t pin, uint32_t drive) /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_DRV(bank, pin >> 4)); @@ -357,7 +423,7 @@ aw_gpio_pin_configure(struct aw_gpio_softc *sc, uint32_t pin, uint32_t flags) /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); - if (pin > sc->padconf->npins) + if (pin > sc->conf->padconf->npins) return (EINVAL); /* Manage input/output. */ @@ -412,7 +478,7 @@ aw_gpio_pin_max(device_t dev, int *maxpin) sc = device_get_softc(dev); - *maxpin = sc->padconf->npins - 1; + *maxpin = sc->conf->padconf->npins - 1; return (0); } @@ -422,7 +488,7 @@ aw_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) struct aw_gpio_softc *sc; sc = device_get_softc(dev); - if (pin >= sc->padconf->npins) + if (pin >= sc->conf->padconf->npins) return (EINVAL); *caps = AW_GPIO_DEFAULT_CAPS; @@ -438,7 +504,7 @@ aw_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) uint32_t pud; sc = device_get_softc(dev); - if (pin >= sc->padconf->npins) + if (pin >= sc->conf->padconf->npins) return (EINVAL); AW_GPIO_LOCK(sc); @@ -478,11 +544,11 @@ aw_gpio_pin_getname(device_t dev, uint32_t pin, char *name) struct aw_gpio_softc *sc; sc = device_get_softc(dev); - if (pin >= sc->padconf->npins) + if (pin >= sc->conf->padconf->npins) return (EINVAL); snprintf(name, GPIOMAXNAME - 1, "%s", - sc->padconf->pins[pin].name); + sc->conf->padconf->pins[pin].name); name[GPIOMAXNAME - 1] = '\0'; return (0); @@ -495,7 +561,7 @@ aw_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) int err; sc = device_get_softc(dev); - if (pin > sc->padconf->npins) + if (pin > sc->conf->padconf->npins) return (EINVAL); AW_GPIO_LOCK(sc); @@ -513,11 +579,11 @@ aw_gpio_pin_set_locked(struct aw_gpio_softc *sc, uint32_t pin, AW_GPIO_LOCK_ASSERT(sc); - if (pin > sc->padconf->npins) + if (pin > sc->conf->padconf->npins) return (EINVAL); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); if (value) @@ -552,11 +618,11 @@ aw_gpio_pin_get_locked(struct aw_gpio_softc *sc,uint32_t pin, AW_GPIO_LOCK_ASSERT(sc); - if (pin > sc->padconf->npins) + if (pin > sc->conf->padconf->npins) return (EINVAL); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; reg_data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); *val = (reg_data & (1 << pin)) ? 1 : 0; @@ -655,11 +721,11 @@ aw_gpio_pin_toggle(device_t dev, uint32_t pin) uint32_t bank, data; sc = device_get_softc(dev); - if (pin > sc->padconf->npins) + if (pin > sc->conf->padconf->npins) return (EINVAL); - bank = sc->padconf->pins[pin].port; - pin = sc->padconf->pins[pin].pin; + bank = sc->conf->padconf->pins[pin].port; + pin = sc->conf->padconf->pins[pin].pin; AW_GPIO_LOCK(sc); data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); @@ -681,7 +747,7 @@ aw_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, uint32_t bank, data, pin; sc = device_get_softc(dev); - if (first_pin > sc->padconf->npins) + if (first_pin > sc->conf->padconf->npins) return (EINVAL); /* @@ -690,8 +756,8 @@ aw_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, * change simultaneously (required) with reasonably high performance * (desired); we need to do a read-modify-write on a single register. */ - bank = sc->padconf->pins[first_pin].port; - pin = sc->padconf->pins[first_pin].pin; + bank = sc->conf->padconf->pins[first_pin].port; + pin = sc->conf->padconf->pins[first_pin].pin; if (pin != 0) return (EINVAL); @@ -717,11 +783,11 @@ aw_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, int err; sc = device_get_softc(dev); - if (first_pin > sc->padconf->npins) + if (first_pin > sc->conf->padconf->npins) return (EINVAL); - bank = sc->padconf->pins[first_pin].port; - if (sc->padconf->pins[first_pin].pin != 0) + bank = sc->conf->padconf->pins[first_pin].port; + if (sc->conf->padconf->pins[first_pin].pin != 0) return (EINVAL); /* @@ -745,8 +811,8 @@ aw_find_pinnum_by_name(struct aw_gpio_softc *sc, const char *pinname) { int i; - for (i = 0; i < sc->padconf->npins; i++) - if (!strcmp(pinname, sc->padconf->pins[i].name)) + for (i = 0; i < sc->conf->padconf->npins; i++) + if (!strcmp(pinname, sc->conf->padconf->pins[i].name)) return i; return (-1); @@ -758,8 +824,8 @@ aw_find_pin_func(struct aw_gpio_softc *sc, int pin, const char *func) int i; for (i = 0; i < AW_MAX_FUNC_BY_PIN; i++) - if (sc->padconf->pins[pin].functions[i] && - !strcmp(func, sc->padconf->pins[pin].functions[i])) + if (sc->conf->padconf->pins[pin].functions[i] && + !strcmp(func, sc->conf->padconf->pins[pin].functions[i])) return (i); return (-1); @@ -828,6 +894,33 @@ aw_fdt_configure_pins(device_t dev, phandle_t cfgxref) return (ret); } +static void +aw_gpio_enable_bank_supply(void *arg) +{ + struct aw_gpio_softc *sc = arg; + regulator_t vcc_supply; + char bank_reg_name[16]; + int i, nbanks; + + nbanks = strlen(sc->conf->banks); + for (i = 0; i < nbanks; i++) { + snprintf(bank_reg_name, sizeof(bank_reg_name), "vcc-p%c-supply", + sc->conf->banks[i]); + + if (regulator_get_by_ofw_property(sc->sc_dev, 0, bank_reg_name, &vcc_supply) == 0) { + if (bootverbose) + device_printf(sc->sc_dev, + "Enabling regulator for gpio bank %c\n", + sc->conf->banks[i]); + if (regulator_enable(vcc_supply) != 0) { + device_printf(sc->sc_dev, + "Cannot enable regulator for bank %c\n", + sc->conf->banks[i]); + } + } + } +} + static int aw_gpio_probe(device_t dev) { @@ -884,7 +977,7 @@ aw_gpio_attach(device_t dev) goto fail; /* Use the right pin data for the current SoC */ - sc->padconf = (struct allwinner_padconf *)ofw_bus_search_compatible(dev, + sc->conf = (struct aw_gpio_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (hwreset_get_by_ofw_idx(dev, 0, 0, &rst) == 0) { @@ -928,6 +1021,8 @@ aw_gpio_attach(device_t dev) fdt_pinctrl_register(dev, "allwinner,pins"); fdt_pinctrl_configure_tree(dev); + config_intrhook_oneshot(aw_gpio_enable_bank_supply, sc); + return (0); fail: @@ -985,9 +1080,9 @@ aw_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, sc = device_get_softc(bus); /* The GPIO pins are mapped as: . */ - for (i = 0; i < sc->padconf->npins; i++) - if (sc->padconf->pins[i].port == gpios[0] && - sc->padconf->pins[i].pin == gpios[1]) { + for (i = 0; i < sc->conf->padconf->npins; i++) + if (sc->conf->padconf->pins[i].port == gpios[0] && + sc->conf->padconf->pins[i].pin == gpios[1]) { *pin = i; break; }