[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(®s->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(®s->swport_dr, mask, value ? mask : 0);
> - setbits_le32(®s->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(®s->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(®s->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(®s->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