diff mbox series

[v2,06/22] pinctrl: sunxi: remove struct sunxi_gpio

Message ID 20230928215455.28094-7-andre.przywara@arm.com
State Accepted
Delegated to: Andre Przywara
Headers show
Series sunxi: Allwinner T113s support | expand

Commit Message

Andre Przywara Sept. 28, 2023, 9:54 p.m. UTC
So far every Allwinner SoC used the same basic pincontroller/GPIO
register frame, and just differed by the number of implemented banks and
pins, plus some special functionality from time to time. However the D1
and successors use a slightly different pinctrl register layout.
Use that opportunity to drop "struct sunxi_gpio", that described that
MMIO frame in a C struct. That approach is somewhat frowned upon in the
Linux world and rarely used there, though still popular with U-Boot.

Switching from a C struct to a "base address plus offset" approach allows
to switch between the two models more dynamically, without reverting to
preprocessor macros and #ifdef's.

Model the pinctrl MMIO register frame in the usual "base address +
offset" way, and replace a hard-to-parse CPP macro with a more readable
static function.
All the users get converted over. There are no functional changes at
this point, it just prepares the stages for the D1 and friends.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/include/asm/arch-sunxi/gpio.h | 40 ++----------
 drivers/gpio/sunxi_gpio.c              | 88 ++++++++++++++++----------
 drivers/pinctrl/sunxi/pinctrl-sunxi.c  | 14 ++--
 3 files changed, 66 insertions(+), 76 deletions(-)

Comments

Samuel Holland Oct. 21, 2023, 8:37 a.m. UTC | #1
Hi Andre,

On 9/28/23 16:54, Andre Przywara wrote:
> So far every Allwinner SoC used the same basic pincontroller/GPIO
> register frame, and just differed by the number of implemented banks and
> pins, plus some special functionality from time to time. However the D1
> and successors use a slightly different pinctrl register layout.
> Use that opportunity to drop "struct sunxi_gpio", that described that
> MMIO frame in a C struct. That approach is somewhat frowned upon in the
> Linux world and rarely used there, though still popular with U-Boot.
> 
> Switching from a C struct to a "base address plus offset" approach allows
> to switch between the two models more dynamically, without reverting to
> preprocessor macros and #ifdef's.
> 
> Model the pinctrl MMIO register frame in the usual "base address +
> offset" way, and replace a hard-to-parse CPP macro with a more readable
> static function.
> All the users get converted over. There are no functional changes at
> this point, it just prepares the stages for the D1 and friends.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arch/arm/include/asm/arch-sunxi/gpio.h | 40 ++----------
>  drivers/gpio/sunxi_gpio.c              | 88 ++++++++++++++++----------
>  drivers/pinctrl/sunxi/pinctrl-sunxi.c  | 14 ++--
>  3 files changed, 66 insertions(+), 76 deletions(-)
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
> index 4bc9e8ffcc9..e0fb5b5da63 100644
> --- a/arch/arm/include/asm/arch-sunxi/gpio.h
> +++ b/arch/arm/include/asm/arch-sunxi/gpio.h
> @@ -31,13 +31,6 @@
>  #define SUNXI_GPIO_H	7
>  #define SUNXI_GPIO_I	8
>  
> -/*
> - * This defines the number of GPIO banks for the _main_ GPIO controller.
> - * You should fix up the padding in struct sunxi_gpio_reg below if you
> - * change this.
> - */
> -#define SUNXI_GPIO_BANKS 9
> -
>  /*
>   * sun6i/sun8i and later SoCs have an additional GPIO controller (R_PIO)
>   * at a different register offset.
> @@ -55,32 +48,11 @@
>  #define SUNXI_GPIO_M	12
>  #define SUNXI_GPIO_N	13
>  
> -struct sunxi_gpio {
> -	u32 cfg[4];
> -	u32 dat;
> -	u32 drv[2];
> -	u32 pull[2];
> -};
> -
> -/* gpio interrupt control */
> -struct sunxi_gpio_int {
> -	u32 cfg[3];
> -	u32 ctl;
> -	u32 sta;
> -	u32 deb;		/* interrupt debounce */
> -};
> -
> -struct sunxi_gpio_reg {
> -	struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS];
> -	u8 res[0xbc];
> -	struct sunxi_gpio_int gpio_int;
> -};
> -
>  #define SUN50I_H6_GPIO_POW_MOD_SEL	0x340
>  #define SUN50I_H6_GPIO_POW_MOD_VAL	0x348
>  
> -/* GPIO bank sizes */
>  #define SUNXI_GPIOS_PER_BANK	32
> +#define SUNXI_PINCTRL_BANK_SIZE 0x24
>  
>  #define SUNXI_GPIO_NEXT(__gpio) \
>  	((__gpio##_START) + SUNXI_GPIOS_PER_BANK)
> @@ -200,19 +172,19 @@ enum sunxi_gpio_number {
>  #define SUNXI_GPIO_AXP0_GPIO_COUNT	6
>  
>  struct sunxi_gpio_plat {
> -	struct sunxi_gpio	*regs;
> +	void			*regs;
>  	char			bank_name[3];
>  };
>  
>  /* prototypes for the non-DM GPIO/pinctrl functions, used in the SPL */
> -void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val);
> +void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val);
>  void sunxi_gpio_set_cfgpin(u32 pin, u32 val);
> -int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset);
> +int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset);
>  int sunxi_gpio_get_cfgpin(u32 pin);
>  void sunxi_gpio_set_drv(u32 pin, u32 val);
> -void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val);
> +void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val);
>  void sunxi_gpio_set_pull(u32 pin, u32 val);
> -void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val);
> +void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val);
>  int sunxi_name_to_gpio(const char *name);
>  
>  #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
> diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
> index a4b336943b6..fe3f6ed0938 100644
> --- a/drivers/gpio/sunxi_gpio.c
> +++ b/drivers/gpio/sunxi_gpio.c
> @@ -29,45 +29,61 @@
>   * =======================================================================
>   */
>  
> -#define BANK_TO_GPIO(bank)	(((bank) < SUNXI_GPIO_L) ? \
> -	&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank] : \
> -	&((struct sunxi_gpio_reg *)SUNXI_R_PIO_BASE)->gpio_bank[(bank) - SUNXI_GPIO_L])
> -
>  #define GPIO_BANK(pin)		((pin) >> 5)
>  #define GPIO_NUM(pin)		((pin) & 0x1f)
>  
> +#define GPIO_CFG_REG_OFFSET	0x00
>  #define GPIO_CFG_INDEX(pin)	(((pin) & 0x1f) >> 3)
>  #define GPIO_CFG_OFFSET(pin)	((((pin) & 0x1f) & 0x7) << 2)
>  
> +#define GPIO_DAT_REG_OFFSET	0x10
> +
> +#define GPIO_DRV_REG_OFFSET	0x14
>  #define GPIO_DRV_INDEX(pin)	(((pin) & 0x1f) >> 4)
>  #define GPIO_DRV_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)
>  
> +#define GPIO_PULL_REG_OFFSET	0x1c
>  #define GPIO_PULL_INDEX(pin)	(((pin) & 0x1f) >> 4)
>  #define GPIO_PULL_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)

Now that we've ensured the *_bank functions only get called with pin
numbers in the range 0-31, we don't need the masking anymore. But this
can be a later cleanup.

Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Samuel Holland <samuel@sholland.org>

>  
> -void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val)
> +static void* BANK_TO_GPIO(int bank)
> +{
> +	void *pio_base;
> +
> +	if (bank < SUNXI_GPIO_L) {
> +		pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
> +	} else {
> +		pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
> +		bank -= SUNXI_GPIO_L;
> +	}
> +
> +	return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
> +}
> +
> +void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
>  {
> -	u32 index = GPIO_CFG_INDEX(bank_offset);
> -	u32 offset = GPIO_CFG_OFFSET(bank_offset);
> +	u32 index = GPIO_CFG_INDEX(pin_offset);
> +	u32 offset = GPIO_CFG_OFFSET(pin_offset);
>  
> -	clrsetbits_le32(&pio->cfg[index], 0xf << offset, val << offset);
> +	clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
> +			0xfU << offset, val << offset);
>  }
>  
>  void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
>  {
>  	u32 bank = GPIO_BANK(pin);
> -	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
> +	void *pio = BANK_TO_GPIO(bank);
>  
> -	sunxi_gpio_set_cfgbank(pio, pin, val);
> +	sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
>  }
>  
> -int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
> +int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
>  {
> -	u32 index = GPIO_CFG_INDEX(bank_offset);
> -	u32 offset = GPIO_CFG_OFFSET(bank_offset);
> +	u32 index = GPIO_CFG_INDEX(pin_offset);
> +	u32 offset = GPIO_CFG_OFFSET(pin_offset);
>  	u32 cfg;
>  
> -	cfg = readl(&pio->cfg[index]);
> +	cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
>  	cfg >>= offset;
>  
>  	return cfg & 0xf;
> @@ -76,54 +92,56 @@ int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
>  int sunxi_gpio_get_cfgpin(u32 pin)
>  {
>  	u32 bank = GPIO_BANK(pin);
> -	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
> +	void *bank_base = BANK_TO_GPIO(bank);
>  
> -	return sunxi_gpio_get_cfgbank(pio, pin);
> +	return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
>  }
>  
> -static void sunxi_gpio_set_output_bank(struct sunxi_gpio *pio,
> -				       int pin, bool set)
> +static void sunxi_gpio_set_output_bank(void *bank_base, int pin, bool set)
>  {
>  	u32 mask = 1U << pin;
>  
> -	clrsetbits_le32(&pio->dat, set ? 0 : mask, set ? mask : 0);
> +	clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
> +			set ? 0 : mask, set ? mask : 0);
>  }
>  
> -static int sunxi_gpio_get_output_bank(struct sunxi_gpio *pio, int pin)
> +static int sunxi_gpio_get_output_bank(void *bank_base, int pin)
>  {
> -	return !!(readl(&pio->dat) & (1U << pin));
> +	return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
>  }
>  
>  void sunxi_gpio_set_drv(u32 pin, u32 val)
>  {
>  	u32 bank = GPIO_BANK(pin);
> -	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
> +	void *bank_base = BANK_TO_GPIO(bank);
>  
> -	sunxi_gpio_set_drv_bank(pio, pin, val);
> +	sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
>  }
>  
> -void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val)
> +void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
>  {
> -	u32 index = GPIO_DRV_INDEX(bank_offset);
> -	u32 offset = GPIO_DRV_OFFSET(bank_offset);
> +	u32 index = GPIO_DRV_INDEX(pin_offset);
> +	u32 offset = GPIO_DRV_OFFSET(pin_offset);
>  
> -	clrsetbits_le32(&pio->drv[index], 0x3 << offset, val << offset);
> +	clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
> +			0x3U << offset, val << offset);
>  }
>  
>  void sunxi_gpio_set_pull(u32 pin, u32 val)
>  {
>  	u32 bank = GPIO_BANK(pin);
> -	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
> +	void *bank_base = BANK_TO_GPIO(bank);
>  
> -	sunxi_gpio_set_pull_bank(pio, pin, val);
> +	sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
>  }
>  
> -void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
> +void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
>  {
> -	u32 index = GPIO_PULL_INDEX(bank_offset);
> -	u32 offset = GPIO_PULL_OFFSET(bank_offset);
> +	u32 index = GPIO_PULL_INDEX(pin_offset);
> +	u32 offset = GPIO_PULL_OFFSET(pin_offset);
>  
> -	clrsetbits_le32(&pio->pull[index], 0x3 << offset, val << offset);
> +	clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
> +			0x3U << offset, val << offset);
>  }
>  
>  
> @@ -133,7 +151,7 @@ void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
>  static void sunxi_gpio_set_output(u32 pin, bool set)
>  {
>  	u32 bank = GPIO_BANK(pin);
> -	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
> +	void *pio = BANK_TO_GPIO(bank);
>  
>  	sunxi_gpio_set_output_bank(pio, GPIO_NUM(pin), set);
>  }
> @@ -141,7 +159,7 @@ static void sunxi_gpio_set_output(u32 pin, bool set)
>  static int sunxi_gpio_get_output(u32 pin)
>  {
>  	u32 bank = GPIO_BANK(pin);
> -	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
> +	void *pio = BANK_TO_GPIO(bank);
>  
>  	return sunxi_gpio_get_output_bank(pio, GPIO_NUM(pin));
>  }
> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> index e5102180902..946447e9136 100644
> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> @@ -35,7 +35,7 @@ struct sunxi_pinctrl_desc {
>  };
>  
>  struct sunxi_pinctrl_plat {
> -	struct sunxi_gpio __iomem *base;
> +	void __iomem *base;
>  };
>  
>  static int sunxi_pinctrl_get_pins_count(struct udevice *dev)
> @@ -86,8 +86,8 @@ static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector,
>  	      sunxi_pinctrl_get_function_name(dev, func_selector),
>  	      desc->functions[func_selector].mux);
>  
> -	sunxi_gpio_set_cfgbank(plat->base + bank, pin,
> -			       desc->functions[func_selector].mux);
> +	sunxi_gpio_set_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE,
> +			       pin, desc->functions[func_selector].mux);
>  
>  	return 0;
>  }
> @@ -102,7 +102,7 @@ static const struct pinconf_param sunxi_pinctrl_pinconf_params[] = {
>  static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
>  					  uint bank, uint pin, uint bias)
>  {
> -	struct sunxi_gpio *regs = &plat->base[bank];
> +	void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
>  
>  	sunxi_gpio_set_pull_bank(regs, pin, bias);
>  
> @@ -112,7 +112,7 @@ static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
>  static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat,
>  					   uint bank, uint pin, uint drive)
>  {
> -	struct sunxi_gpio *regs = &plat->base[bank];
> +	void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
>  
>  	if (drive < 10 || drive > 40)
>  		return -EINVAL;
> @@ -148,7 +148,7 @@ static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector,
>  	struct sunxi_pinctrl_plat *plat = dev_get_plat(dev);
>  	int bank = pin_selector / SUNXI_GPIOS_PER_BANK;
>  	int pin	 = pin_selector % SUNXI_GPIOS_PER_BANK;
> -	int mux  = sunxi_gpio_get_cfgbank(plat->base + bank, pin);
> +	int mux  = sunxi_gpio_get_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE, pin);
>  
>  	switch (mux) {
>  	case SUNXI_GPIO_INPUT:
> @@ -206,7 +206,7 @@ static int sunxi_pinctrl_bind(struct udevice *dev)
>  		if (!gpio_plat)
>  			return -ENOMEM;
>  
> -		gpio_plat->regs = plat->base + i;
> +		gpio_plat->regs = plat->base + i * SUNXI_PINCTRL_BANK_SIZE;
>  		gpio_plat->bank_name[0] = 'P';
>  		gpio_plat->bank_name[1] = 'A' + desc->first_bank + i;
>  		gpio_plat->bank_name[2] = '\0';
diff mbox series

Patch

diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 4bc9e8ffcc9..e0fb5b5da63 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -31,13 +31,6 @@ 
 #define SUNXI_GPIO_H	7
 #define SUNXI_GPIO_I	8
 
-/*
- * This defines the number of GPIO banks for the _main_ GPIO controller.
- * You should fix up the padding in struct sunxi_gpio_reg below if you
- * change this.
- */
-#define SUNXI_GPIO_BANKS 9
-
 /*
  * sun6i/sun8i and later SoCs have an additional GPIO controller (R_PIO)
  * at a different register offset.
@@ -55,32 +48,11 @@ 
 #define SUNXI_GPIO_M	12
 #define SUNXI_GPIO_N	13
 
-struct sunxi_gpio {
-	u32 cfg[4];
-	u32 dat;
-	u32 drv[2];
-	u32 pull[2];
-};
-
-/* gpio interrupt control */
-struct sunxi_gpio_int {
-	u32 cfg[3];
-	u32 ctl;
-	u32 sta;
-	u32 deb;		/* interrupt debounce */
-};
-
-struct sunxi_gpio_reg {
-	struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS];
-	u8 res[0xbc];
-	struct sunxi_gpio_int gpio_int;
-};
-
 #define SUN50I_H6_GPIO_POW_MOD_SEL	0x340
 #define SUN50I_H6_GPIO_POW_MOD_VAL	0x348
 
-/* GPIO bank sizes */
 #define SUNXI_GPIOS_PER_BANK	32
+#define SUNXI_PINCTRL_BANK_SIZE 0x24
 
 #define SUNXI_GPIO_NEXT(__gpio) \
 	((__gpio##_START) + SUNXI_GPIOS_PER_BANK)
@@ -200,19 +172,19 @@  enum sunxi_gpio_number {
 #define SUNXI_GPIO_AXP0_GPIO_COUNT	6
 
 struct sunxi_gpio_plat {
-	struct sunxi_gpio	*regs;
+	void			*regs;
 	char			bank_name[3];
 };
 
 /* prototypes for the non-DM GPIO/pinctrl functions, used in the SPL */
-void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val);
+void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val);
 void sunxi_gpio_set_cfgpin(u32 pin, u32 val);
-int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset);
+int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset);
 int sunxi_gpio_get_cfgpin(u32 pin);
 void sunxi_gpio_set_drv(u32 pin, u32 val);
-void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val);
+void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val);
 void sunxi_gpio_set_pull(u32 pin, u32 val);
-void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val);
+void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val);
 int sunxi_name_to_gpio(const char *name);
 
 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index a4b336943b6..fe3f6ed0938 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -29,45 +29,61 @@ 
  * =======================================================================
  */
 
-#define BANK_TO_GPIO(bank)	(((bank) < SUNXI_GPIO_L) ? \
-	&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank] : \
-	&((struct sunxi_gpio_reg *)SUNXI_R_PIO_BASE)->gpio_bank[(bank) - SUNXI_GPIO_L])
-
 #define GPIO_BANK(pin)		((pin) >> 5)
 #define GPIO_NUM(pin)		((pin) & 0x1f)
 
+#define GPIO_CFG_REG_OFFSET	0x00
 #define GPIO_CFG_INDEX(pin)	(((pin) & 0x1f) >> 3)
 #define GPIO_CFG_OFFSET(pin)	((((pin) & 0x1f) & 0x7) << 2)
 
+#define GPIO_DAT_REG_OFFSET	0x10
+
+#define GPIO_DRV_REG_OFFSET	0x14
 #define GPIO_DRV_INDEX(pin)	(((pin) & 0x1f) >> 4)
 #define GPIO_DRV_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)
 
+#define GPIO_PULL_REG_OFFSET	0x1c
 #define GPIO_PULL_INDEX(pin)	(((pin) & 0x1f) >> 4)
 #define GPIO_PULL_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)
 
-void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val)
+static void* BANK_TO_GPIO(int bank)
+{
+	void *pio_base;
+
+	if (bank < SUNXI_GPIO_L) {
+		pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
+	} else {
+		pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
+		bank -= SUNXI_GPIO_L;
+	}
+
+	return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
+}
+
+void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
 {
-	u32 index = GPIO_CFG_INDEX(bank_offset);
-	u32 offset = GPIO_CFG_OFFSET(bank_offset);
+	u32 index = GPIO_CFG_INDEX(pin_offset);
+	u32 offset = GPIO_CFG_OFFSET(pin_offset);
 
-	clrsetbits_le32(&pio->cfg[index], 0xf << offset, val << offset);
+	clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
+			0xfU << offset, val << offset);
 }
 
 void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
 {
 	u32 bank = GPIO_BANK(pin);
-	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+	void *pio = BANK_TO_GPIO(bank);
 
-	sunxi_gpio_set_cfgbank(pio, pin, val);
+	sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
 }
 
-int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
+int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
 {
-	u32 index = GPIO_CFG_INDEX(bank_offset);
-	u32 offset = GPIO_CFG_OFFSET(bank_offset);
+	u32 index = GPIO_CFG_INDEX(pin_offset);
+	u32 offset = GPIO_CFG_OFFSET(pin_offset);
 	u32 cfg;
 
-	cfg = readl(&pio->cfg[index]);
+	cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
 	cfg >>= offset;
 
 	return cfg & 0xf;
@@ -76,54 +92,56 @@  int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
 int sunxi_gpio_get_cfgpin(u32 pin)
 {
 	u32 bank = GPIO_BANK(pin);
-	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+	void *bank_base = BANK_TO_GPIO(bank);
 
-	return sunxi_gpio_get_cfgbank(pio, pin);
+	return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
 }
 
-static void sunxi_gpio_set_output_bank(struct sunxi_gpio *pio,
-				       int pin, bool set)
+static void sunxi_gpio_set_output_bank(void *bank_base, int pin, bool set)
 {
 	u32 mask = 1U << pin;
 
-	clrsetbits_le32(&pio->dat, set ? 0 : mask, set ? mask : 0);
+	clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
+			set ? 0 : mask, set ? mask : 0);
 }
 
-static int sunxi_gpio_get_output_bank(struct sunxi_gpio *pio, int pin)
+static int sunxi_gpio_get_output_bank(void *bank_base, int pin)
 {
-	return !!(readl(&pio->dat) & (1U << pin));
+	return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
 }
 
 void sunxi_gpio_set_drv(u32 pin, u32 val)
 {
 	u32 bank = GPIO_BANK(pin);
-	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+	void *bank_base = BANK_TO_GPIO(bank);
 
-	sunxi_gpio_set_drv_bank(pio, pin, val);
+	sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
 }
 
-void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val)
+void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
 {
-	u32 index = GPIO_DRV_INDEX(bank_offset);
-	u32 offset = GPIO_DRV_OFFSET(bank_offset);
+	u32 index = GPIO_DRV_INDEX(pin_offset);
+	u32 offset = GPIO_DRV_OFFSET(pin_offset);
 
-	clrsetbits_le32(&pio->drv[index], 0x3 << offset, val << offset);
+	clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
+			0x3U << offset, val << offset);
 }
 
 void sunxi_gpio_set_pull(u32 pin, u32 val)
 {
 	u32 bank = GPIO_BANK(pin);
-	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+	void *bank_base = BANK_TO_GPIO(bank);
 
-	sunxi_gpio_set_pull_bank(pio, pin, val);
+	sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
 }
 
-void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
+void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
 {
-	u32 index = GPIO_PULL_INDEX(bank_offset);
-	u32 offset = GPIO_PULL_OFFSET(bank_offset);
+	u32 index = GPIO_PULL_INDEX(pin_offset);
+	u32 offset = GPIO_PULL_OFFSET(pin_offset);
 
-	clrsetbits_le32(&pio->pull[index], 0x3 << offset, val << offset);
+	clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
+			0x3U << offset, val << offset);
 }
 
 
@@ -133,7 +151,7 @@  void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
 static void sunxi_gpio_set_output(u32 pin, bool set)
 {
 	u32 bank = GPIO_BANK(pin);
-	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+	void *pio = BANK_TO_GPIO(bank);
 
 	sunxi_gpio_set_output_bank(pio, GPIO_NUM(pin), set);
 }
@@ -141,7 +159,7 @@  static void sunxi_gpio_set_output(u32 pin, bool set)
 static int sunxi_gpio_get_output(u32 pin)
 {
 	u32 bank = GPIO_BANK(pin);
-	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+	void *pio = BANK_TO_GPIO(bank);
 
 	return sunxi_gpio_get_output_bank(pio, GPIO_NUM(pin));
 }
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index e5102180902..946447e9136 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -35,7 +35,7 @@  struct sunxi_pinctrl_desc {
 };
 
 struct sunxi_pinctrl_plat {
-	struct sunxi_gpio __iomem *base;
+	void __iomem *base;
 };
 
 static int sunxi_pinctrl_get_pins_count(struct udevice *dev)
@@ -86,8 +86,8 @@  static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector,
 	      sunxi_pinctrl_get_function_name(dev, func_selector),
 	      desc->functions[func_selector].mux);
 
-	sunxi_gpio_set_cfgbank(plat->base + bank, pin,
-			       desc->functions[func_selector].mux);
+	sunxi_gpio_set_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE,
+			       pin, desc->functions[func_selector].mux);
 
 	return 0;
 }
@@ -102,7 +102,7 @@  static const struct pinconf_param sunxi_pinctrl_pinconf_params[] = {
 static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
 					  uint bank, uint pin, uint bias)
 {
-	struct sunxi_gpio *regs = &plat->base[bank];
+	void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
 
 	sunxi_gpio_set_pull_bank(regs, pin, bias);
 
@@ -112,7 +112,7 @@  static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
 static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat,
 					   uint bank, uint pin, uint drive)
 {
-	struct sunxi_gpio *regs = &plat->base[bank];
+	void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
 
 	if (drive < 10 || drive > 40)
 		return -EINVAL;
@@ -148,7 +148,7 @@  static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector,
 	struct sunxi_pinctrl_plat *plat = dev_get_plat(dev);
 	int bank = pin_selector / SUNXI_GPIOS_PER_BANK;
 	int pin	 = pin_selector % SUNXI_GPIOS_PER_BANK;
-	int mux  = sunxi_gpio_get_cfgbank(plat->base + bank, pin);
+	int mux  = sunxi_gpio_get_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE, pin);
 
 	switch (mux) {
 	case SUNXI_GPIO_INPUT:
@@ -206,7 +206,7 @@  static int sunxi_pinctrl_bind(struct udevice *dev)
 		if (!gpio_plat)
 			return -ENOMEM;
 
-		gpio_plat->regs = plat->base + i;
+		gpio_plat->regs = plat->base + i * SUNXI_PINCTRL_BANK_SIZE;
 		gpio_plat->bank_name[0] = 'P';
 		gpio_plat->bank_name[1] = 'A' + desc->first_bank + i;
 		gpio_plat->bank_name[2] = '\0';