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

Jonas Karlman jonas at kwiboo.se
Sun Mar 19 00:56:59 CET 2023


Some GPIO regs used on RK35xx have changed offset and now use upper 16
bits as a write mask. Refactor and add support for this to add support
for RK3568 and RK3588 to the driver.

Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
---
 drivers/gpio/rk_gpio.c | 111 ++++++++++++++++++++++++++++-------------
 1 file changed, 75 insertions(+), 36 deletions(-)

diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
index bc77b28307c0..1f71038e0366 100644
--- a/drivers/gpio/rk_gpio.c
+++ b/drivers/gpio/rk_gpio.c
@@ -13,84 +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 <dm/read.h>
-#include <dt-bindings/clock/rk3288-cru.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 +181,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;
+	}
 
 	ret = dev_read_alias_seq(dev, &priv->bank);
 	if (ret) {
@@ -161,6 +198,8 @@ static int rockchip_gpio_probe(struct udevice *dev)
 	uc_priv->bank_name = priv->name;
 	uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
 
+	priv->version = readl(priv->regs + VER_ID_V2);
+
 	return 0;
 }
 
-- 
2.40.0



More information about the U-Boot mailing list