[PATCH v2] gpio: rockchip: Add support for RK3568 and RK3588 banks

Kever Yang kever.yang at rock-chips.com
Tue Mar 21 04:11:32 CET 2023


On 2023/3/20 02:39, Jonas Karlman wrote:
> The GPIO V2 controller on RK3568 and RK3588 works very similar to
> prior generation, main difference is the use of a write mask in the
> upper 16 bits and register address offset have changed.
>
> GPIO_VER_ID is a new register at 0x0078 that is used to determine when
> the driver should use new or old register offsets and values. Earlier
> generation return 0x0 from this offset.
>
> Refactor code and add support for the GPIO V2 controller used in RK3568
> and RK3588.
>
> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
Reviewed-by: Kever Yang <kever.yang at rock-chips.com>

Thanks,
- Kever
> ---
> Changes in v2:
> - Drop two patches related to gpio alias id
>
>   drivers/gpio/rk_gpio.c | 112 ++++++++++++++++++++++++++++-------------
>   1 file changed, 76 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
> index f7ad4d68b452..d9bde8f4f034 100644
> --- a/drivers/gpio/rk_gpio.c
> +++ b/drivers/gpio/rk_gpio.c
> @@ -13,83 +13,118 @@
>   #include <asm/gpio.h>
>   #include <asm/io.h>
>   #include <asm/arch-rockchip/clock.h>
> +#include <asm/arch-rockchip/hardware.h>
>   #include <asm/arch-rockchip/gpio.h>
>   #include <dm/pinctrl.h>
> -#include <dt-bindings/clock/rk3288-cru.h>
> +#include <dm/read.h>
> +#include <dt-bindings/pinctrl/rockchip.h>
> +
> +#define SWPORT_DR		0x0000
> +#define SWPORT_DDR		0x0004
> +#define EXT_PORT		0x0050
> +#define SWPORT_DR_L		0x0000
> +#define SWPORT_DR_H		0x0004
> +#define SWPORT_DDR_L		0x0008
> +#define SWPORT_DDR_H		0x000C
> +#define EXT_PORT_V2		0x0070
> +#define VER_ID_V2		0x0078
>   
>   enum {
>   	ROCKCHIP_GPIOS_PER_BANK		= 32,
>   };
>   
> -#define OFFSET_TO_BIT(bit)	(1UL << (bit))
> -
>   struct rockchip_gpio_priv {
> -	struct rockchip_gpio_regs *regs;
> +	void __iomem *regs;
>   	struct udevice *pinctrl;
>   	int bank;
>   	char name[2];
> +	u32 version;
>   };
>   
> -static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
> +static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
>   {
>   	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
> -	struct rockchip_gpio_regs *regs = priv->regs;
> +	u32 mask = BIT(offset), data;
>   
> -	clrbits_le32(&regs->swport_ddr, OFFSET_TO_BIT(offset));
> +	if (priv->version)
> +		data = readl(priv->regs + EXT_PORT_V2);
> +	else
> +		data = readl(priv->regs + EXT_PORT);
>   
> -	return 0;
> +	return (data & mask) ? 1 : 0;
>   }
>   
> -static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
> -					  int value)
> +static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
> +				   int value)
>   {
>   	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
> -	struct rockchip_gpio_regs *regs = priv->regs;
> -	int mask = OFFSET_TO_BIT(offset);
> +	u32 mask = BIT(offset), data = value ? mask : 0;
>   
> -	clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
> -	setbits_le32(&regs->swport_ddr, mask);
> +	if (priv->version && offset >= 16)
> +		rk_clrsetreg(priv->regs + SWPORT_DR_H, mask >> 16, data >> 16);
> +	else if (priv->version)
> +		rk_clrsetreg(priv->regs + SWPORT_DR_L, mask, data);
> +	else
> +		clrsetbits_le32(priv->regs + SWPORT_DR, mask, data);
>   
>   	return 0;
>   }
>   
> -static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
> +static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
>   {
>   	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
> -	struct rockchip_gpio_regs *regs = priv->regs;
> +	u32 mask = BIT(offset);
> +
> +	if (priv->version && offset >= 16)
> +		rk_clrreg(priv->regs + SWPORT_DDR_H, mask >> 16);
> +	else if (priv->version)
> +		rk_clrreg(priv->regs + SWPORT_DDR_L, mask);
> +	else
> +		clrbits_le32(priv->regs + SWPORT_DDR, mask);
>   
> -	return readl(&regs->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
> +	return 0;
>   }
>   
> -static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
> -				   int value)
> +static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
> +					  int value)
>   {
>   	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
> -	struct rockchip_gpio_regs *regs = priv->regs;
> -	int mask = OFFSET_TO_BIT(offset);
> +	u32 mask = BIT(offset);
> +
> +	rockchip_gpio_set_value(dev, offset, value);
>   
> -	clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
> +	if (priv->version && offset >= 16)
> +		rk_setreg(priv->regs + SWPORT_DDR_H, mask >> 16);
> +	else if (priv->version)
> +		rk_setreg(priv->regs + SWPORT_DDR_L, mask);
> +	else
> +		setbits_le32(priv->regs + SWPORT_DDR, mask);
>   
>   	return 0;
>   }
>   
>   static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
>   {
> -#ifdef CONFIG_SPL_BUILD
> -	return -ENODATA;
> -#else
>   	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
> -	struct rockchip_gpio_regs *regs = priv->regs;
> -	bool is_output;
> +	u32 mask = BIT(offset), data;
>   	int ret;
>   
> -	ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
> -	if (ret)
> -		return ret;
> -	is_output = readl(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
> +	if (CONFIG_IS_ENABLED(PINCTRL)) {
> +		ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
> +		if (ret < 0)
> +			return ret;
> +		else if (ret != RK_FUNC_GPIO)
> +			return GPIOF_FUNC;
> +	}
> +
> +	if (priv->version && offset >= 16)
> +		data = readl(priv->regs + SWPORT_DDR_H) << 16;
> +	else if (priv->version)
> +		data = readl(priv->regs + SWPORT_DDR_L);
> +	else
> +		data = readl(priv->regs + SWPORT_DDR);
>   
> -	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
> -#endif
> +	return (data & mask) ? GPIOF_OUTPUT : GPIOF_INPUT;
>   }
>   
>   /* Simple SPL interface to GPIOs */
> @@ -147,9 +182,12 @@ static int rockchip_gpio_probe(struct udevice *dev)
>   	int ret;
>   
>   	priv->regs = dev_read_addr_ptr(dev);
> -	ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
> -	if (ret)
> -		return ret;
> +
> +	if (CONFIG_IS_ENABLED(PINCTRL)) {
> +		ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
> +		if (ret)
> +			return ret;
> +	}
>   
>   	/*
>   	 * If "gpio-ranges" is present in the devicetree use it to parse
> @@ -170,6 +208,8 @@ static int rockchip_gpio_probe(struct udevice *dev)
>   	priv->name[0] = 'A' + priv->bank;
>   	uc_priv->bank_name = priv->name;
>   
> +	priv->version = readl(priv->regs + VER_ID_V2);
> +
>   	return 0;
>   }
>   


More information about the U-Boot mailing list