On 8/22/26 04:30, Yixun Lan wrote:
> Based on upstream Linux:
> da64eb51595b ("gpio: spacemit: Add GPIO support for K3 SoC")
>
> SpacemiT K3 SoC uses different GPIO register and bank layout compared
> to old K1 generation. Refactor the driver by moving hard-coded register
> offsets into per-SoC tables and locating them via driver data.
>
> Signed-off-by: Yixun Lan <[email protected]>
> ---
> drivers/gpio/Kconfig | 11 ++---
> drivers/gpio/spacemit_gpio.c | 97
> ++++++++++++++++++++++++++++++--------------
> 2 files changed, 72 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index a11f3043670..78b4b45be87 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -450,12 +450,13 @@ config SANDBOX_GPIO_COUNT
> Select a suitable value depending on your needs.
>
> config SPACEMIT_GPIO
> - bool "Spacemit K1 GPIO driver"
> - depends on DM_GPIO && TARGET_SPACEMIT_K1
> + bool "Spacemit K1/K3 GPIO driver"
> + depends on DM_GPIO && (TARGET_SPACEMIT_K1 || TARGET_SPACEMIT_K3)
> help
> - Support the GPIO device in Spacemit SoCs. The GPIOs are arranged
> - into a number of banks (different for each SoC type) each with 32
> - GPIOs.
> + Support the GPIO device in Spacemit K1 and K3 SoCs. The GPIOs are
> + arranged into a number of banks (different for each SoC type) each
> + with 32 GPIOs.
> +
>
> config SUNXI_GPIO
> bool "Allwinner GPIO driver"
> diff --git a/drivers/gpio/spacemit_gpio.c b/drivers/gpio/spacemit_gpio.c
> index de71880df15..e0716a84dfc 100644
> --- a/drivers/gpio/spacemit_gpio.c
> +++ b/drivers/gpio/spacemit_gpio.c
> @@ -19,37 +19,28 @@
> #define GPIO_TO_BANK(pin) ((pin) / GPIO_BANK_SIZE)
> #define GPIO_TO_BIT(pin) ((pin) % GPIO_BANK_SIZE)
>
> -static inline int gpio_to_reg_offset(unsigned int pin)
> -{
> - unsigned int bank = GPIO_TO_BANK(pin);
> -
> - if (bank == 0)
> - return 0;
> - else if (bank == 1)
> - return 4;
> - else if (bank == 2)
> - return 8;
> - else if (bank == 3)
> - return 0x100;
> - log_warning("Use default GPIO bank for an invalid GPIO[%d].\n", pin);
> - return 0;
> -}
> -
> -#define REG_PLR(pin) (0x00 + gpio_to_reg_offset(pin))
> -#define REG_PDR(pin) (0x0c + gpio_to_reg_offset(pin))
> -#define REG_PSR(pin) (0x18 + gpio_to_reg_offset(pin))
> -#define REG_PCR(pin) (0x24 + gpio_to_reg_offset(pin))
> -#define REG_SDR(pin) (0x54 + gpio_to_reg_offset(pin))
> -#define REG_CDR(pin) (0x60 + gpio_to_reg_offset(pin))
> +#define to_spacemit_gpio_regs(priv, reg) ((priv)->data->offsets[reg])
> +
> +enum spacemit_gpio_registers {
> + SPACEMIT_GPLR,
> + SPACEMIT_GPDR,
> + SPACEMIT_GPSR,
> + SPACEMIT_GPCR,
> + SPACEMIT_GSDR,
> + SPACEMIT_GCDR,
> +};
>
> struct spacemit_gpio_data {
> u16 gpio_base;
> u16 gpio_count;
> u8 num_banks;
> + const u16 *bank_offsets;
> + const u16 *offsets;
> };
>
> struct spacemit_gpio_priv {
> void __iomem *regs;
> + const struct spacemit_gpio_data *data;
> };
>
> static int spacemit_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
> @@ -85,10 +76,12 @@ static int spacemit_gpio_xlate(struct udevice *dev,
> struct gpio_desc *desc,
> static int spacemit_gpio_get_value(struct udevice *dev, unsigned int offset)
> {
> struct spacemit_gpio_priv *priv = dev_get_priv(dev);
> - void __iomem *addr;
> + void __iomem *base, *addr;
> u32 value, mask;
>
> - addr = priv->regs + REG_PLR(offset);
> + base = priv->regs + priv->data->bank_offsets[GPIO_TO_BANK(offset)];
> +
> + addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GPLR);
> value = readl(addr);
> mask = 1 << GPIO_TO_BIT(offset);
> return !!(value & mask);
> @@ -97,10 +90,12 @@ static int spacemit_gpio_get_value(struct udevice *dev,
> unsigned int offset)
> static int spacemit_gpio_get_function(struct udevice *dev, unsigned int
> offset)
> {
> struct spacemit_gpio_priv *priv = dev_get_priv(dev);
> - void __iomem *addr;
> + void __iomem *base, *addr;
> u32 value, mask;
>
> - addr = priv->regs + REG_PDR(offset);
> + base = priv->regs + priv->data->bank_offsets[GPIO_TO_BANK(offset)];
> +
> + addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GPDR);
> value = readl(addr);
> mask = 1 << GPIO_TO_BIT(offset);
> if (value & mask)
> @@ -130,23 +125,25 @@ static int spacemit_gpio_set_flags(struct udevice *dev,
> unsigned int offset,
> ulong flags)
> {
> struct spacemit_gpio_priv *priv = dev_get_priv(dev);
> - void __iomem *addr;
> + void __iomem *base, *addr;
> int value;
>
> + base = priv->regs + priv->data->bank_offsets[GPIO_TO_BANK(offset)];
> +
> value = (flags & GPIOD_IS_OUT_ACTIVE) ? 1 : 0;
> if (flags & GPIOD_IS_IN) {
> - addr = priv->regs + REG_CDR(offset);
> + addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GCDR);
> writel(1 << GPIO_TO_BIT(offset), addr);
> }
> if (flags & GPIOD_IS_OUT) {
> if (value) {
> - addr = priv->regs + REG_PSR(offset);
> + addr = base + to_spacemit_gpio_regs(priv,
> SPACEMIT_GPSR);
> writel(1 << GPIO_TO_BIT(offset), addr);
> } else {
> - addr = priv->regs + REG_PCR(offset);
> + addr = base + to_spacemit_gpio_regs(priv,
> SPACEMIT_GPCR);
> writel(1 << GPIO_TO_BIT(offset), addr);
> }
> - addr = priv->regs + REG_SDR(offset);
> + addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GSDR);
> writel(1 << GPIO_TO_BIT(offset), addr);
> }
> return 0;
> @@ -207,6 +204,7 @@ static int spacemit_gpio_probe(struct udevice *dev)
>
> data = (struct spacemit_gpio_data *)dev_get_driver_data(dev);
> priv = dev_get_priv(dev);
> + priv->data = data;
> priv->regs = dev_read_addr_ptr(dev);
> if (!priv->regs) {
> dev_err(dev, "Fail to get base address\n");
> @@ -232,14 +230,51 @@ out:
> return ret;
> }
>
> +static const u16 spacemit_gpio_k1_offsets[] = {
> + [SPACEMIT_GPLR] = 0x00,
> + [SPACEMIT_GPDR] = 0x0c,
> + [SPACEMIT_GPSR] = 0x18,
> + [SPACEMIT_GPCR] = 0x24,
> + [SPACEMIT_GSDR] = 0x54,
> + [SPACEMIT_GCDR] = 0x60,
> +};
> +
> +static const u16 spacemit_gpio_k1_bank_offsets[] = {
> + 0x0, 0x4, 0x8, 0x100,
> +};
> +
> +static const u16 spacemit_gpio_k3_offsets[] = {
> + [SPACEMIT_GPLR] = 0x00,
> + [SPACEMIT_GPDR] = 0x04,
> + [SPACEMIT_GPSR] = 0x08,
> + [SPACEMIT_GPCR] = 0x0c,
> + [SPACEMIT_GSDR] = 0x1c,
> + [SPACEMIT_GCDR] = 0x20,
> +};
> +
> +static const u16 spacemit_gpio_k3_bank_offsets[] = {
> + 0x0, 0x40, 0x80, 0x100,
> +};
> +
> static const struct spacemit_gpio_data k1_gpio_data = {
> .num_banks = 4,
> .gpio_count = 128,
> .gpio_base = 0,
> + .bank_offsets = spacemit_gpio_k1_bank_offsets,
> + .offsets = spacemit_gpio_k1_offsets,
> +};
> +
> +static const struct spacemit_gpio_data k3_gpio_data = {
> + .num_banks = 4,
> + .gpio_count = 128,
> + .gpio_base = 0,
> + .bank_offsets = spacemit_gpio_k3_bank_offsets,
> + .offsets = spacemit_gpio_k3_offsets,
> };
>
> static const struct udevice_id spacemit_gpio_ids[] = {
> { .compatible = "spacemit,k1-gpio", .data = (uintptr_t)&k1_gpio_data, },
> + { .compatible = "spacemit,k3-gpio", .data = (uintptr_t)&k3_gpio_data, },
> { /* sentinel */ }
> };
>
>
> ---
> base-commit: 36c377b9859ffb53eb1e39ea31e8d96d1e0fe1e5
> change-id: 20260722-01-gpio-pinctrl-support-87d7b153599b
>
> Best regards,
> --
> Yixun Lan <[email protected]>
>
Acked-by: E Shattow <[email protected]>