All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] riscv: spacemit: add pinctrl support for K3 SoC
@ 2026-08-20 13:01 Yixun Lan
  2026-08-20 13:01 ` [PATCH 1/2] pinctrl: spacemit: configure drive strength based on power source Yixun Lan
  2026-08-20 13:01 ` [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support Yixun Lan
  0 siblings, 2 replies; 6+ messages in thread
From: Yixun Lan @ 2026-08-20 13:01 UTC (permalink / raw)
  To: u-boot-spacemit, u-boot
  Cc: Eric Chung, Raymond Mao, Junhui Liu, Tom Rini, Yixun Lan

The pinctrl controller of SpacemiT K3 SoC changed its register BIT
layout definition comparing to old K1 SoC, has different IO
power-domain tables, and extend drive strength bits to 4.

First patch fix drive strength configuration for external-voltage
IO pins.

Please note, this series is composed on top of K1 pinctrl patch-2,3,4
which sent to mailing list here [1]

Link: https://patch.msgid.link/20260802-m4-v8-2-e916643205f3@riscstar.com [1]
Signed-off-by: Yixun Lan <dlan@kernel.org>
---
Yixun Lan (2):
      pinctrl: spacemit: configure drive strength based on power source
      pinctrl: spacemit: k3: add K3 pin support

 drivers/pinctrl/spacemit/Kconfig      |   4 +-
 drivers/pinctrl/spacemit/pinctrl-k1.c | 457 +++++++++++++++++++++++++++++-----
 2 files changed, 390 insertions(+), 71 deletions(-)
---
base-commit: 289cb83053b5939debd96508fb8a839025fab9ee
change-id: 20260820-01-k3-pinctrl-support-77eefc901e47

Best regards,
--  
Yixun Lan <dlan@kernel.org>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] pinctrl: spacemit: configure drive strength based on power source
  2026-08-20 13:01 [PATCH 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
@ 2026-08-20 13:01 ` Yixun Lan
  2026-08-20 13:01 ` [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support Yixun Lan
  1 sibling, 0 replies; 6+ messages in thread
From: Yixun Lan @ 2026-08-20 13:01 UTC (permalink / raw)
  To: u-boot-spacemit, u-boot
  Cc: Eric Chung, Raymond Mao, Junhui Liu, Tom Rini, Yixun Lan

SpacemiT external-voltage pins use different drive strength tables for
1.8V and 3.3V. The selected power source therefore needs to be known
before programming the drive strength. But pinctrl_generic_set_state()
applies pin configuration properties according device tree order, which
lead to configure drive-strength before power-source.

Add a vendor specific set_state() callback that applies the supported
properties in a fixed order, ensuring that power-source is configured
before setting drive strength.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 drivers/pinctrl/spacemit/pinctrl-k1.c | 166 +++++++++++++++++++++++++++-------
 1 file changed, 131 insertions(+), 35 deletions(-)

diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c
index 9c0fa4badc2..469c41c40c8 100644
--- a/drivers/pinctrl/spacemit/pinctrl-k1.c
+++ b/drivers/pinctrl/spacemit/pinctrl-k1.c
@@ -439,8 +439,8 @@ static const struct pinconf_param spacemit_pinconf_params[] = {
 	{ "bias-disable",	PIN_CONFIG_BIAS_DISABLE,	0 },
 	{ "bias-pull-down",	PIN_CONFIG_BIAS_PULL_DOWN,	1 },
 	{ "bias-pull-up",	PIN_CONFIG_BIAS_PULL_UP,	1 },
-	{ "drive-strength",	PIN_CONFIG_DRIVE_STRENGTH,	U32_MAX },
 	{ "power-source",	PIN_CONFIG_POWER_SOURCE,	U32_MAX },
+	{ "drive-strength",	PIN_CONFIG_DRIVE_STRENGTH,	U32_MAX },
 };
 
 static void spacemit_set_io_power_domain(struct udevice *dev,
@@ -472,16 +472,59 @@ static void spacemit_set_io_power_domain(struct udevice *dev,
 	writel(val, priv->regs + IO_PWR_DOMAIN_OFFSET + offset);
 }
 
+static enum spacemit_pin_io_type spacemit_get_pin_io_type(struct spacemit_pinctrl_priv *priv,
+							  unsigned int pin)
+{
+	int i;
+
+	for (i = 0; i < priv->nr_io_pins; i++)
+		if (priv->io_pins[i].pin == pin &&
+		    priv->io_pins[i].io_type != IO_TYPE_EXTERNAL)
+			return priv->io_pins[i].io_type;
+
+	return IO_TYPE_1V8;
+}
+
+static int spacemit_set_pin_power_source(struct udevice *dev, unsigned int pin,
+					 unsigned int power_source)
+{
+	struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+	enum spacemit_pin_io_type io_type;
+	int i;
+
+	switch (power_source) {
+	case PIN_POWER_STATE_1V8:
+		io_type = IO_TYPE_1V8;
+		break;
+	case PIN_POWER_STATE_3V3:
+		io_type = IO_TYPE_3V3;
+		break;
+	default:
+		dev_err(dev, "Invalid power source (%d)\n", power_source);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < priv->nr_io_pins; i++) {
+		if (priv->io_pins[i].pin != pin)
+			continue;
+
+		priv->io_pins[i].io_type = io_type;
+		spacemit_set_io_power_domain(dev, pin, io_type);
+
+		return 0;
+	}
+
+	return 0;
+}
+
 static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 				unsigned int param, unsigned int argument)
 {
-	struct spacemit_pinctrl_data *data;
 	struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+	struct spacemit_pinctrl_data *data;
+	enum spacemit_pin_io_type io_type;
 	void __iomem *addr;
-	unsigned int io_type;
 	u8 ds;
-	bool found;
-	int i;
 
 	data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev);
 	if (!data || !data->pin_to_reg)
@@ -501,14 +544,7 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 				argument ? PAD_PULLUP | PAD_PULL_EN : 0);
 		break;
 	case PIN_CONFIG_DRIVE_STRENGTH:
-		io_type = IO_TYPE_1V8;
-		for (i = 0; i < priv->nr_io_pins; i++) {
-			if (priv->io_pins[i].pin != pin_selector)
-				continue;
-			if (priv->io_pins[i].io_type != IO_TYPE_EXTERNAL)
-				io_type = priv->io_pins[i].io_type;
-			break;
-		}
+		io_type = spacemit_get_pin_io_type(priv, pin_selector);
 		if (io_type != IO_TYPE_3V3 && io_type != IO_TYPE_1V8) {
 			dev_err(dev, "Invalid IO type (%d)\n", io_type);
 			return -EINVAL;
@@ -517,30 +553,90 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 		clrsetbits_le32(addr, PAD_DRIVE, FIELD_PREP(PAD_DRIVE, ds));
 		break;
 	case PIN_CONFIG_POWER_SOURCE:
-		for (i = 0, found = false; i < priv->nr_io_pins; i++) {
-			if (priv->io_pins[i].pin != pin_selector)
-				continue;
-			if (argument == PIN_POWER_STATE_3V3) {
-				priv->io_pins[i].io_type = IO_TYPE_3V3;
-				found = true;
-			} else if (argument == PIN_POWER_STATE_1V8) {
-				priv->io_pins[i].io_type = IO_TYPE_1V8;
-				found = true;
-			}
-			break;
-		}
-		if (!found && argument != PIN_POWER_STATE_1V8 &&
-		    argument != PIN_POWER_STATE_3V3) {
-			dev_err(dev, "Invalid power source (%d)\n", argument);
-			return -EINVAL;
-		}
-		if (found)
-			spacemit_set_io_power_domain(dev, pin_selector,
-						     priv->io_pins[i].io_type);
-		break;
+		return spacemit_set_pin_power_source(dev, pin_selector, argument);
 	default:
 		return -EOPNOTSUPP;
 	}
+
+	return 0;
+}
+
+static int spacemit_pinctrl_apply_group(struct udevice *dev,
+					struct udevice *config)
+{
+	const struct pinconf_param *param;
+	const void *value;
+	u32 argument;
+	u32 pinmux;
+	int npins;
+	int len;
+	int ret;
+	int i, j;
+
+	ret = dev_read_size(config, "pinmux");
+	if (ret == -EINVAL)
+		return 0;
+	if (ret < 0 || ret % sizeof(pinmux))
+		return -EINVAL;
+	npins = ret / sizeof(pinmux);
+
+	for (i = 0; i < npins; i++) {
+		ret = dev_read_u32_index(config, "pinmux", i, &pinmux);
+		if (ret)
+			return ret;
+
+		ret = spacemit_pinmux_set(dev, spacemit_dt_get_pin(pinmux),
+					  spacemit_dt_get_pin_mux(pinmux));
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(spacemit_pinconf_params); i++) {
+		param = &spacemit_pinconf_params[i];
+		value = dev_read_prop(config, param->property, &len);
+		if (!value)
+			continue;
+
+		if (len >= sizeof(fdt32_t))
+			argument = fdt32_to_cpu(*(const fdt32_t *)value);
+		else
+			argument = param->default_value;
+
+		for (j = 0; j < npins; j++) {
+			ret = dev_read_u32_index(config, "pinmux", j,
+						 &pinmux);
+			if (ret)
+				return ret;
+
+			ret = spacemit_pinconf_set(dev,
+						   spacemit_dt_get_pin(pinmux),
+						   param->param, argument);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int spacemit_pinctrl_set_state(struct udevice *dev,
+				      struct udevice *config)
+{
+	struct udevice *child;
+	int ret;
+
+	ret = spacemit_pinctrl_apply_group(dev, config);
+	if (ret)
+		return ret;
+
+	for (device_find_first_child(config, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		ret = spacemit_pinctrl_apply_group(dev, child);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -622,7 +718,7 @@ static const struct pinctrl_ops spacemit_pinctrl_ops = {
 	.get_pin_name		= spacemit_get_pin_name,
 	.get_functions_count	= spacemit_get_functions_count,
 	.get_pin_muxing		= spacemit_get_pin_muxing,
-	.set_state		= pinctrl_generic_set_state,
+	.set_state		= spacemit_pinctrl_set_state,
 	.gpio_request_enable	= spacemit_pinctrl_request_gpio,
 	.gpio_disable_free	= spacemit_pinctrl_free_gpio,
 	.pinmux_set		= spacemit_pinmux_set,

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support
  2026-08-20 13:01 [PATCH 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
  2026-08-20 13:01 ` [PATCH 1/2] pinctrl: spacemit: configure drive strength based on power source Yixun Lan
@ 2026-08-20 13:01 ` Yixun Lan
  2026-08-27 21:55   ` Bo Gan
  1 sibling, 1 reply; 6+ messages in thread
From: Yixun Lan @ 2026-08-20 13:01 UTC (permalink / raw)
  To: u-boot-spacemit, u-boot
  Cc: Eric Chung, Raymond Mao, Junhui Liu, Tom Rini, Yixun Lan

Based on upstream Linux:
  7412311c4655 ("pinctrl: spacemit: k3: add initial pin support")
  3f20bdf71518 ("pinctrl: spacemit: k3: adjust drive strength and schmitter trigger")

K3 uses a different pin-to-register mapping than K1, so add a
K3-specific pin_to_reg path and pin/IO power-domain tables. Drive
strength expands to 4 bits with larger mA tables, and the shared
pinctrl data gains per-SoC drive_mask and drive-strength tables so
K1 and K3 can live in the same driver.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 drivers/pinctrl/spacemit/Kconfig      |   4 +-
 drivers/pinctrl/spacemit/pinctrl-k1.c | 291 ++++++++++++++++++++++++++++++----
 2 files changed, 259 insertions(+), 36 deletions(-)

diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig
index 6aab89e160c..87cba336923 100644
--- a/drivers/pinctrl/spacemit/Kconfig
+++ b/drivers/pinctrl/spacemit/Kconfig
@@ -1,8 +1,8 @@
 config PINCTRL_SPACEMIT_K1
-	bool "Spacemit K1 SoC pinctrl driver"
+	bool "Spacemit K1/K3 SoC pinctrl driver"
 	depends on PINCTRL_GENERIC && DM
 	help
-	  Supports pin multiplexing control on Spacemit K1 SoCs.
+	  Supports pin multiplexing control on Spacemit K1 and K3 SoCs.
 
 	  The driver is controlled by a device tree node which contains both
 	  the GPIO definitions and pin control functions for each available
diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c
index 469c41c40c8..1eb20fd2956 100644
--- a/drivers/pinctrl/spacemit/pinctrl-k1.c
+++ b/drivers/pinctrl/spacemit/pinctrl-k1.c
@@ -30,8 +30,10 @@
 #define PAD_EDGE_CLEAR		BIT(6)
 #define PAD_SLEW_RATE		GENMASK(12, 11)
 #define PAD_SLEW_RATE_EN	BIT(7)
-#define PAD_SCHMITT		GENMASK(9, 8)
-#define PAD_DRIVE		GENMASK(12, 10)
+#define PAD_SCHMITT_K1		GENMASK(9, 8)
+#define PAD_DRIVE_K1		GENMASK(12, 10)
+#define PAD_SCHMITT_K3		BIT(8)
+#define PAD_DRIVE_K3		GENMASK(12, 9)
 #define PAD_PULLDOWN		BIT(13)
 #define PAD_PULLUP		BIT(14)
 #define PAD_PULL_EN		BIT(15)
@@ -43,6 +45,11 @@
 #define IO_PWR_DOMAIN_MMC_Kx	0x1c
 #define IO_PWR_DOMAIN_QSPI_K1	0x20
 
+#define IO_PWR_DOMAIN_GPIO1_K3  0x04
+#define IO_PWR_DOMAIN_GPIO5_K3  0x10
+#define IO_PWR_DOMAIN_GPIO4_K3  0x20
+#define IO_PWR_DOMAIN_QSPI_K3   0x2c
+
 #define IO_PWR_DOMAIN_V18EN	BIT(2)
 
 #define APBC_ASFAR		0x50
@@ -68,6 +75,12 @@ struct spacemit_pin_io {
 	unsigned int	reserved : 8;
 };
 
+struct spacemit_pin_drv_strength {
+	unsigned int	val : 8;
+	unsigned int	ma : 16;
+	unsigned int	reserved : 8;
+};
+
 struct spacemit_pinctrl_data {
 	struct spacemit_pin_io *io_pins;
 	int nr_io_pins;
@@ -78,6 +91,12 @@ struct spacemit_pinctrl_data {
 	int (*get_functions)(struct udevice *dev);
 	int (*get_io_type)(struct udevice *dev, unsigned int pin);
 	unsigned int (*pin_to_io_pd_offset)(unsigned int pin);
+
+	u32 drive_mask;
+	struct spacemit_pin_drv_strength *ds_1v8_tbl;
+	int ds_1v8_tbl_num;
+	struct spacemit_pin_drv_strength *ds_3v3_tbl;
+	int ds_3v3_tbl_num;
 };
 
 struct spacemit_pinctrl_priv {
@@ -92,12 +111,6 @@ struct spacemit_pin_mux_config {
 	u32				config;
 };
 
-struct spacemit_pin_drv_strength {
-	unsigned int	val : 8;
-	unsigned int	ma : 16;
-	unsigned int	reserved : 8;
-};
-
 static char pin_name[PINNAME_SIZE];
 
 /* External: IO voltage via external source, can be 1.8V or 3.3V */
@@ -280,35 +293,17 @@ static inline u32 spacemit_get_ds_ma(struct spacemit_pin_drv_strength *tbl,
 	return 0;
 }
 
-static inline u8 spacemit_get_drive_strength(enum spacemit_pin_io_type type,
+static inline u8 spacemit_get_drive_strength(struct spacemit_pinctrl_data *data,
+					     enum spacemit_pin_io_type type,
 					     u32 ma)
 {
 	switch (type) {
 	case IO_TYPE_1V8:
-		return spacemit_get_ds_value(spacemit_ds_1v8_tbl,
-					     ARRAY_SIZE(spacemit_ds_1v8_tbl),
-					     ma);
-	case IO_TYPE_3V3:
-		return spacemit_get_ds_value(spacemit_ds_3v3_tbl,
-					     ARRAY_SIZE(spacemit_ds_3v3_tbl),
-					     ma);
-	default:
-		return 0;
-	}
-}
-
-static inline u32 spacemit_get_drive_strength_ma(enum spacemit_pin_io_type type,
-						 u32 value)
-{
-	switch (type) {
-	case IO_TYPE_1V8:
-		return spacemit_get_ds_ma(spacemit_ds_1v8_tbl,
-					  ARRAY_SIZE(spacemit_ds_1v8_tbl),
-					  value & 0x6);
+		return spacemit_get_ds_value(data->ds_1v8_tbl,
+					     data->ds_1v8_tbl_num, ma);
 	case IO_TYPE_3V3:
-		return spacemit_get_ds_ma(spacemit_ds_3v3_tbl,
-					  ARRAY_SIZE(spacemit_ds_3v3_tbl),
-					  value);
+		return spacemit_get_ds_value(data->ds_3v3_tbl,
+					     data->ds_3v3_tbl_num, ma);
 	default:
 		return 0;
 	}
@@ -549,8 +544,9 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 			dev_err(dev, "Invalid IO type (%d)\n", io_type);
 			return -EINVAL;
 		}
-		ds = spacemit_get_drive_strength(io_type, argument);
-		clrsetbits_le32(addr, PAD_DRIVE, FIELD_PREP(PAD_DRIVE, ds));
+		ds = spacemit_get_drive_strength(data, io_type, argument);
+		clrsetbits_le32(addr, data->drive_mask,
+				field_prep(data->drive_mask, ds));
 		break;
 	case PIN_CONFIG_POWER_SOURCE:
 		return spacemit_set_pin_power_source(dev, pin_selector, argument);
@@ -704,12 +700,239 @@ static const struct spacemit_pinctrl_data k1_pinctrl_data = {
 	.get_functions	= k1_get_functions,
 	.get_io_type	= k1_get_io_type,
 	.pin_to_io_pd_offset = spacemit_k1_pin_to_io_pd_offset,
+	.drive_mask	= PAD_DRIVE_K1,
+	.ds_1v8_tbl	= spacemit_ds_1v8_tbl,
+	.ds_1v8_tbl_num	= ARRAY_SIZE(spacemit_ds_1v8_tbl),
+	.ds_3v3_tbl	= spacemit_ds_3v3_tbl,
+	.ds_3v3_tbl_num	= ARRAY_SIZE(spacemit_ds_3v3_tbl),
+};
+
+static struct spacemit_pin_io k3_io_pins[] = {
+	{ 0, IO_TYPE_EXTERNAL, 0, },
+	{ 1, IO_TYPE_EXTERNAL, 0, },
+	{ 2, IO_TYPE_EXTERNAL, 0, },
+	{ 3, IO_TYPE_EXTERNAL, 0, },
+	{ 4, IO_TYPE_EXTERNAL, 0, },
+	{ 5, IO_TYPE_EXTERNAL, 0, },
+	{ 6, IO_TYPE_EXTERNAL, 0, },
+	{ 7, IO_TYPE_EXTERNAL, 0, },
+	{ 8, IO_TYPE_EXTERNAL, 0, },
+	{ 9, IO_TYPE_EXTERNAL, 0, },
+	{ 10, IO_TYPE_EXTERNAL, 0, },
+	{ 11, IO_TYPE_EXTERNAL, 0, },
+	{ 12, IO_TYPE_EXTERNAL, 0, },
+	{ 13, IO_TYPE_EXTERNAL, 0, },
+	{ 14, IO_TYPE_EXTERNAL, 0, },
+	{ 15, IO_TYPE_EXTERNAL, 0, },
+	{ 16, IO_TYPE_EXTERNAL, 0, },
+	{ 17, IO_TYPE_EXTERNAL, 0, },
+	{ 18, IO_TYPE_EXTERNAL, 0, },
+	{ 19, IO_TYPE_EXTERNAL, 0, },
+	{ 20, IO_TYPE_EXTERNAL, 0, },
+	{ 21, IO_TYPE_EXTERNAL, 0, },
+	{ 22, IO_TYPE_EXTERNAL, 0, },
+	{ 23, IO_TYPE_EXTERNAL, 0, },
+	{ 24, IO_TYPE_EXTERNAL, 0, },
+	{ 25, IO_TYPE_EXTERNAL, 0, },
+	{ 26, IO_TYPE_EXTERNAL, 0, },
+	{ 27, IO_TYPE_EXTERNAL, 0, },
+	{ 28, IO_TYPE_EXTERNAL, 0, },
+	{ 29, IO_TYPE_EXTERNAL, 0, },
+	{ 30, IO_TYPE_EXTERNAL, 0, },
+	{ 31, IO_TYPE_EXTERNAL, 0, },
+	{ 32, IO_TYPE_EXTERNAL, 0, },
+	{ 33, IO_TYPE_EXTERNAL, 0, },
+	{ 34, IO_TYPE_EXTERNAL, 0, },
+	{ 35, IO_TYPE_EXTERNAL, 0, },
+	{ 36, IO_TYPE_EXTERNAL, 0, },
+	{ 37, IO_TYPE_EXTERNAL, 0, },
+	{ 38, IO_TYPE_EXTERNAL, 0, },
+	{ 39, IO_TYPE_EXTERNAL, 0, },
+	{ 40, IO_TYPE_EXTERNAL, 0, },
+	{ 41, IO_TYPE_EXTERNAL, 0, },
+	{ 76, IO_TYPE_EXTERNAL, 0, },
+	{ 77, IO_TYPE_EXTERNAL, 0, },
+	{ 78, IO_TYPE_EXTERNAL, 0, },
+	{ 79, IO_TYPE_EXTERNAL, 0, },
+	{ 80, IO_TYPE_EXTERNAL, 0, },
+	{ 81, IO_TYPE_EXTERNAL, 0, },
+	{ 82, IO_TYPE_EXTERNAL, 0, },
+	{ 83, IO_TYPE_EXTERNAL, 0, },
+	{ 84, IO_TYPE_EXTERNAL, 0, },
+	{ 85, IO_TYPE_EXTERNAL, 0, },
+	{ 86, IO_TYPE_EXTERNAL, 0, },
+	{ 87, IO_TYPE_EXTERNAL, 0, },
+	{ 88, IO_TYPE_EXTERNAL, 0, },
+	{ 89, IO_TYPE_EXTERNAL, 0, },
+	{ 90, IO_TYPE_EXTERNAL, 0, },
+	{ 91, IO_TYPE_EXTERNAL, 0, },
+	{ 92, IO_TYPE_EXTERNAL, 0, },
+	{ 93, IO_TYPE_EXTERNAL, 0, },
+	{ 94, IO_TYPE_EXTERNAL, 0, },
+	{ 95, IO_TYPE_EXTERNAL, 0, },
+	{ 96, IO_TYPE_EXTERNAL, 0, },
+	{ 97, IO_TYPE_EXTERNAL, 0, },
+	{ 98, IO_TYPE_EXTERNAL, 0, },
+	{ 99, IO_TYPE_EXTERNAL, 0, },
+	{ 100, IO_TYPE_EXTERNAL, 0, },
+	{ 101, IO_TYPE_EXTERNAL, 0, },
+	{ 102, IO_TYPE_EXTERNAL, 0, },
+	{ 103, IO_TYPE_EXTERNAL, 0, },
+	{ 104, IO_TYPE_EXTERNAL, 0, },
+	{ 105, IO_TYPE_EXTERNAL, 0, },
+	{ 106, IO_TYPE_EXTERNAL, 0, },
+	{ 107, IO_TYPE_EXTERNAL, 0, },
+	{ 108, IO_TYPE_EXTERNAL, 0, },
+	{ 109, IO_TYPE_EXTERNAL, 0, },
+	{ 110, IO_TYPE_EXTERNAL, 0, },
+	{ 111, IO_TYPE_EXTERNAL, 0, },
+	{ 112, IO_TYPE_EXTERNAL, 0, },
+	{ 113, IO_TYPE_EXTERNAL, 0, },
+	{ 114, IO_TYPE_EXTERNAL, 0, },
+	{ 115, IO_TYPE_EXTERNAL, 0, },
+	{ 116, IO_TYPE_EXTERNAL, 0, },
+	{ 117, IO_TYPE_EXTERNAL, 0, },
+	{ 118, IO_TYPE_EXTERNAL, 0, },
+	{ 119, IO_TYPE_EXTERNAL, 0, },
+	{ 120, IO_TYPE_EXTERNAL, 0, },
+	{ 121, IO_TYPE_EXTERNAL, 0, },
+	{ 122, IO_TYPE_EXTERNAL, 0, },
+	{ 123, IO_TYPE_EXTERNAL, 0, },
+	{ 124, IO_TYPE_EXTERNAL, 0, },
+	{ 125, IO_TYPE_EXTERNAL, 0, },
+	{ 126, IO_TYPE_EXTERNAL, 0, },
+	{ 127, IO_TYPE_EXTERNAL, 0, },
+	{ 132, IO_TYPE_EXTERNAL, 0, },
+	{ 133, IO_TYPE_EXTERNAL, 0, },
+	{ 134, IO_TYPE_EXTERNAL, 0, },
+	{ 135, IO_TYPE_EXTERNAL, 0, },
+	{ 136, IO_TYPE_EXTERNAL, 0, },
+	{ 137, IO_TYPE_EXTERNAL, 0, },
+	{ 138, IO_TYPE_EXTERNAL, 0, },
+	{ 139, IO_TYPE_EXTERNAL, 0, },
+	{ 140, IO_TYPE_EXTERNAL, 0, },
+	{ 141, IO_TYPE_EXTERNAL, 0, },
+	{ 142, IO_TYPE_EXTERNAL, 0, },
+	{ 143, IO_TYPE_EXTERNAL, 0, },
+	{ 144, IO_TYPE_EXTERNAL, 0, },
+};
+
+static inline int k3_get_pins(struct udevice *dev)
+{
+	return 153;
+}
+
+static inline int k3_get_functions(struct udevice *dev)
+{
+	return 7;
+}
+
+static void __iomem *k3_pin_to_reg(struct udevice *dev, unsigned int pin)
+{
+	struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+	unsigned int offset = pin > 130 ? (pin + 2) : pin;
+
+	if (pin > 152) {
+		dev_err(dev, "Invalid pin (%u)\n", pin);
+		return NULL;
+	}
+	return priv->regs + (offset << 2);
+}
+
+static int k3_get_gpio_mux(struct udevice *dev, unsigned int selector)
+{
+	if (selector > 152) {
+		dev_err(dev, "Invalid pin (%u)\n", selector);
+		return -EINVAL;
+	}
+	/* SD/MMC1, QSPI, PMIC/JTAG use gpiofunc 1 per Linux pin data */
+	if (selector >= 132)
+		return 1;
+	return 0;
+}
+
+static int k3_get_io_type(struct udevice *dev, unsigned int selector)
+{
+	if (selector <= 41)
+		return IO_TYPE_EXTERNAL;
+	if (selector <= 75)
+		return IO_TYPE_1V8;
+	if (selector <= 127)
+		return IO_TYPE_EXTERNAL;
+	if (selector <= 131)
+		return IO_TYPE_1V8;
+	if (selector <= 144)
+		return IO_TYPE_EXTERNAL;
+	if (selector <= 152)
+		return IO_TYPE_1V8;
+	return -EINVAL;
+}
+
+static unsigned int spacemit_k3_pin_to_io_pd_offset(unsigned int pin)
+{
+	unsigned int offset = 0;
+
+	switch (pin) {
+	case 0 ... 20:
+		offset = IO_PWR_DOMAIN_GPIO1_K3;
+		break;
+	case 21 ... 41:
+		offset = IO_PWR_DOMAIN_GPIO2_Kx;
+		break;
+	case 76 ... 98:
+		offset = IO_PWR_DOMAIN_GPIO4_K3;
+		break;
+	case 99 ... 127:
+		offset = IO_PWR_DOMAIN_GPIO5_K3;
+		break;
+	case 132 ... 137:
+		offset = IO_PWR_DOMAIN_MMC_Kx;
+		break;
+	case 138 ... 144:
+		offset = IO_PWR_DOMAIN_QSPI_K3;
+		break;
+	}
+
+	return offset;
+}
+
+static struct spacemit_pin_drv_strength spacemit_k3_ds_1v8_tbl[16] = {
+	{ 0,  2 }, { 1,  4 }, { 2,  6 }, { 3,  7 },
+	{ 4,  9 }, { 5, 11 }, { 6, 13 }, { 7, 14 },
+	{ 8, 21 }, { 9, 23 }, { 10, 25 }, { 11, 26 },
+	{ 12, 28 }, { 13, 30 }, { 14, 31 }, { 15, 33 },
+};
+
+static struct spacemit_pin_drv_strength spacemit_k3_ds_3v3_tbl[16] = {
+	{ 0,  3 }, { 1,  5 }, { 2,  7 }, { 3,  9 },
+	{ 4, 11 }, { 5, 13 }, { 6, 15 }, { 7, 17 },
+	{ 8, 25 }, { 9, 27 }, { 10, 29 }, { 11, 31 },
+	{ 12, 33 }, { 13, 35 }, { 14, 37 }, { 15, 38 },
+};
+
+static const struct spacemit_pinctrl_data k3_pinctrl_data = {
+	.io_pins	= k3_io_pins,
+	.nr_io_pins	= ARRAY_SIZE(k3_io_pins),
+	.pin_to_reg	= k3_pin_to_reg,
+	.get_gpio_mux	= k3_get_gpio_mux,
+	.get_pins	= k3_get_pins,
+	.get_functions	= k3_get_functions,
+	.get_io_type	= k3_get_io_type,
+	.pin_to_io_pd_offset = spacemit_k3_pin_to_io_pd_offset,
+	.drive_mask	= PAD_DRIVE_K3,
+	.ds_1v8_tbl	= spacemit_k3_ds_1v8_tbl,
+	.ds_1v8_tbl_num	= ARRAY_SIZE(spacemit_k3_ds_1v8_tbl),
+	.ds_3v3_tbl	= spacemit_k3_ds_3v3_tbl,
+	.ds_3v3_tbl_num	= ARRAY_SIZE(spacemit_k3_ds_3v3_tbl),
 };
 
 static const struct udevice_id spacemit_pinctrl_ids[] = {
 	{
 		.compatible = "spacemit,k1-pinctrl",
 		.data = (uintptr_t)&k1_pinctrl_data,
+	}, {
+		.compatible = "spacemit,k3-pinctrl",
+		.data = (uintptr_t)&k3_pinctrl_data,
 	}, { /* sentinel */ }
 };
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support
  2026-08-20 13:01 ` [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support Yixun Lan
@ 2026-08-27 21:55   ` Bo Gan
  2026-08-27 22:05     ` Yixun Lan
  2026-09-23  8:46     ` Yixun Lan
  0 siblings, 2 replies; 6+ messages in thread
From: Bo Gan @ 2026-08-27 21:55 UTC (permalink / raw)
  To: Yixun Lan, u-boot-spacemit, u-boot
  Cc: Eric Chung, Raymond Mao, Junhui Liu, Tom Rini

Hi Yixun,

On 8/20/26 06:01, Yixun Lan wrote:
> Based on upstream Linux:
>    7412311c4655 ("pinctrl: spacemit: k3: add initial pin support")
>    3f20bdf71518 ("pinctrl: spacemit: k3: adjust drive strength and schmitter trigger")
> 
> K3 uses a different pin-to-register mapping than K1, so add a
> K3-specific pin_to_reg path and pin/IO power-domain tables. Drive
> strength expands to 4 bits with larger mA tables, and the shared
> pinctrl data gains per-SoC drive_mask and drive-strength tables so
> K1 and K3 can live in the same driver.
> 
> Signed-off-by: Yixun Lan <dlan@kernel.org>
> ---
>   drivers/pinctrl/spacemit/Kconfig      |   4 +-
>   drivers/pinctrl/spacemit/pinctrl-k1.c | 291 ++++++++++++++++++++++++++++++----
>   2 files changed, 259 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig
> index 6aab89e160c..87cba336923 100644
> --- a/drivers/pinctrl/spacemit/Kconfig
> +++ b/drivers/pinctrl/spacemit/Kconfig
> @@ -1,8 +1,8 @@
>   config PINCTRL_SPACEMIT_K1
> -	bool "Spacemit K1 SoC pinctrl driver"
> +	bool "Spacemit K1/K3 SoC pinctrl driver"
>   	depends on PINCTRL_GENERIC && DM
>   	help
> -	  Supports pin multiplexing control on Spacemit K1 SoCs.
> +	  Supports pin multiplexing control on Spacemit K1 and K3 SoCs.
>   
>   	  The driver is controlled by a device tree node which contains both
>   	  the GPIO definitions and pin control functions for each available
> diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c
> index 469c41c40c8..1eb20fd2956 100644
> --- a/drivers/pinctrl/spacemit/pinctrl-k1.c
> +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c
> @@ -30,8 +30,10 @@
>   #define PAD_EDGE_CLEAR		BIT(6)
>   #define PAD_SLEW_RATE		GENMASK(12, 11)
>   #define PAD_SLEW_RATE_EN	BIT(7)
> -#define PAD_SCHMITT		GENMASK(9, 8)
> -#define PAD_DRIVE		GENMASK(12, 10)
> +#define PAD_SCHMITT_K1		GENMASK(9, 8)
> +#define PAD_DRIVE_K1		GENMASK(12, 10)
> +#define PAD_SCHMITT_K3		BIT(8)
> +#define PAD_DRIVE_K3		GENMASK(12, 9)
>   #define PAD_PULLDOWN		BIT(13)
>   #define PAD_PULLUP		BIT(14)
>   #define PAD_PULL_EN		BIT(15)
> @@ -43,6 +45,11 @@
>   #define IO_PWR_DOMAIN_MMC_Kx	0x1c
>   #define IO_PWR_DOMAIN_QSPI_K1	0x20
>   
> +#define IO_PWR_DOMAIN_GPIO1_K3  0x04
> +#define IO_PWR_DOMAIN_GPIO5_K3  0x10
> +#define IO_PWR_DOMAIN_GPIO4_K3  0x20
> +#define IO_PWR_DOMAIN_QSPI_K3   0x2c
> +
>   #define IO_PWR_DOMAIN_V18EN	BIT(2)
>   
>   #define APBC_ASFAR		0x50
> @@ -68,6 +75,12 @@ struct spacemit_pin_io {
>   	unsigned int	reserved : 8;
>   };
>   
> +struct spacemit_pin_drv_strength {
> +	unsigned int	val : 8;
> +	unsigned int	ma : 16;
> +	unsigned int	reserved : 8;
> +};
> +
>   struct spacemit_pinctrl_data {
>   	struct spacemit_pin_io *io_pins;
>   	int nr_io_pins;
> @@ -78,6 +91,12 @@ struct spacemit_pinctrl_data {
>   	int (*get_functions)(struct udevice *dev);
>   	int (*get_io_type)(struct udevice *dev, unsigned int pin);
>   	unsigned int (*pin_to_io_pd_offset)(unsigned int pin);
> +
> +	u32 drive_mask;
> +	struct spacemit_pin_drv_strength *ds_1v8_tbl;
> +	int ds_1v8_tbl_num;
> +	struct spacemit_pin_drv_strength *ds_3v3_tbl;
> +	int ds_3v3_tbl_num;
>   };
>   
>   struct spacemit_pinctrl_priv {
> @@ -92,12 +111,6 @@ struct spacemit_pin_mux_config {
>   	u32				config;
>   };
>   
> -struct spacemit_pin_drv_strength {
> -	unsigned int	val : 8;
> -	unsigned int	ma : 16;
> -	unsigned int	reserved : 8;
> -};
> -
>   static char pin_name[PINNAME_SIZE];
>   
>   /* External: IO voltage via external source, can be 1.8V or 3.3V */
> @@ -280,35 +293,17 @@ static inline u32 spacemit_get_ds_ma(struct spacemit_pin_drv_strength *tbl,
>   	return 0;
>   }
>   
> -static inline u8 spacemit_get_drive_strength(enum spacemit_pin_io_type type,
> +static inline u8 spacemit_get_drive_strength(struct spacemit_pinctrl_data *data,
> +					     enum spacemit_pin_io_type type,
>   					     u32 ma)
>   {
>   	switch (type) {
>   	case IO_TYPE_1V8:
> -		return spacemit_get_ds_value(spacemit_ds_1v8_tbl,
> -					     ARRAY_SIZE(spacemit_ds_1v8_tbl),
> -					     ma);
> -	case IO_TYPE_3V3:
> -		return spacemit_get_ds_value(spacemit_ds_3v3_tbl,
> -					     ARRAY_SIZE(spacemit_ds_3v3_tbl),
> -					     ma);
> -	default:
> -		return 0;
> -	}
> -}
> -
> -static inline u32 spacemit_get_drive_strength_ma(enum spacemit_pin_io_type type,
> -						 u32 value)
> -{
> -	switch (type) {
> -	case IO_TYPE_1V8:
> -		return spacemit_get_ds_ma(spacemit_ds_1v8_tbl,
> -					  ARRAY_SIZE(spacemit_ds_1v8_tbl),
> -					  value & 0x6);
> +		return spacemit_get_ds_value(data->ds_1v8_tbl,
> +					     data->ds_1v8_tbl_num, ma);
>   	case IO_TYPE_3V3:
> -		return spacemit_get_ds_ma(spacemit_ds_3v3_tbl,
> -					  ARRAY_SIZE(spacemit_ds_3v3_tbl),
> -					  value);
> +		return spacemit_get_ds_value(data->ds_3v3_tbl,
> +					     data->ds_3v3_tbl_num, ma);
>   	default:
>   		return 0;
>   	}
> @@ -549,8 +544,9 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
>   			dev_err(dev, "Invalid IO type (%d)\n", io_type);
>   			return -EINVAL;
>   		}
> -		ds = spacemit_get_drive_strength(io_type, argument);
> -		clrsetbits_le32(addr, PAD_DRIVE, FIELD_PREP(PAD_DRIVE, ds));
> +		ds = spacemit_get_drive_strength(data, io_type, argument);
> +		clrsetbits_le32(addr, data->drive_mask,
> +				field_prep(data->drive_mask, ds));
>   		break;
>   	case PIN_CONFIG_POWER_SOURCE:
>   		return spacemit_set_pin_power_source(dev, pin_selector, argument);
> @@ -704,12 +700,239 @@ static const struct spacemit_pinctrl_data k1_pinctrl_data = {
>   	.get_functions	= k1_get_functions,
>   	.get_io_type	= k1_get_io_type,
>   	.pin_to_io_pd_offset = spacemit_k1_pin_to_io_pd_offset,
> +	.drive_mask	= PAD_DRIVE_K1,
> +	.ds_1v8_tbl	= spacemit_ds_1v8_tbl,
> +	.ds_1v8_tbl_num	= ARRAY_SIZE(spacemit_ds_1v8_tbl),
> +	.ds_3v3_tbl	= spacemit_ds_3v3_tbl,
> +	.ds_3v3_tbl_num	= ARRAY_SIZE(spacemit_ds_3v3_tbl),
> +};
> +

Can the following table be simplified using static function and switch
cases? As your other series mentioned, the SPL has very strict size limit,
so we'd better not define this huge data array.

> +static struct spacemit_pin_io k3_io_pins[] = {
> +	{ 0, IO_TYPE_EXTERNAL, 0, },
> +	{ 1, IO_TYPE_EXTERNAL, 0, },
> +	{ 2, IO_TYPE_EXTERNAL, 0, },
> +	{ 3, IO_TYPE_EXTERNAL, 0, },
> +	{ 4, IO_TYPE_EXTERNAL, 0, },
> +	{ 5, IO_TYPE_EXTERNAL, 0, },
> +	{ 6, IO_TYPE_EXTERNAL, 0, },
> +	{ 7, IO_TYPE_EXTERNAL, 0, },
> +	{ 8, IO_TYPE_EXTERNAL, 0, },
> +	{ 9, IO_TYPE_EXTERNAL, 0, },
> +	{ 10, IO_TYPE_EXTERNAL, 0, },
> +	{ 11, IO_TYPE_EXTERNAL, 0, },
> +	{ 12, IO_TYPE_EXTERNAL, 0, },
> +	{ 13, IO_TYPE_EXTERNAL, 0, },
> +	{ 14, IO_TYPE_EXTERNAL, 0, },
> +	{ 15, IO_TYPE_EXTERNAL, 0, },
> +	{ 16, IO_TYPE_EXTERNAL, 0, },
> +	{ 17, IO_TYPE_EXTERNAL, 0, },
> +	{ 18, IO_TYPE_EXTERNAL, 0, },
> +	{ 19, IO_TYPE_EXTERNAL, 0, },
> +	{ 20, IO_TYPE_EXTERNAL, 0, },
> +	{ 21, IO_TYPE_EXTERNAL, 0, },
> +	{ 22, IO_TYPE_EXTERNAL, 0, },
> +	{ 23, IO_TYPE_EXTERNAL, 0, },
> +	{ 24, IO_TYPE_EXTERNAL, 0, },
> +	{ 25, IO_TYPE_EXTERNAL, 0, },
> +	{ 26, IO_TYPE_EXTERNAL, 0, },
> +	{ 27, IO_TYPE_EXTERNAL, 0, },
> +	{ 28, IO_TYPE_EXTERNAL, 0, },
> +	{ 29, IO_TYPE_EXTERNAL, 0, },
> +	{ 30, IO_TYPE_EXTERNAL, 0, },
> +	{ 31, IO_TYPE_EXTERNAL, 0, },
> +	{ 32, IO_TYPE_EXTERNAL, 0, },
> +	{ 33, IO_TYPE_EXTERNAL, 0, },
> +	{ 34, IO_TYPE_EXTERNAL, 0, },
> +	{ 35, IO_TYPE_EXTERNAL, 0, },
> +	{ 36, IO_TYPE_EXTERNAL, 0, },
> +	{ 37, IO_TYPE_EXTERNAL, 0, },
> +	{ 38, IO_TYPE_EXTERNAL, 0, },
> +	{ 39, IO_TYPE_EXTERNAL, 0, },
> +	{ 40, IO_TYPE_EXTERNAL, 0, },
> +	{ 41, IO_TYPE_EXTERNAL, 0, },
> +	{ 76, IO_TYPE_EXTERNAL, 0, },
> +	{ 77, IO_TYPE_EXTERNAL, 0, },
> +	{ 78, IO_TYPE_EXTERNAL, 0, },
> +	{ 79, IO_TYPE_EXTERNAL, 0, },
> +	{ 80, IO_TYPE_EXTERNAL, 0, },
> +	{ 81, IO_TYPE_EXTERNAL, 0, },
> +	{ 82, IO_TYPE_EXTERNAL, 0, },
> +	{ 83, IO_TYPE_EXTERNAL, 0, },
> +	{ 84, IO_TYPE_EXTERNAL, 0, },
> +	{ 85, IO_TYPE_EXTERNAL, 0, },
> +	{ 86, IO_TYPE_EXTERNAL, 0, },
> +	{ 87, IO_TYPE_EXTERNAL, 0, },
> +	{ 88, IO_TYPE_EXTERNAL, 0, },
> +	{ 89, IO_TYPE_EXTERNAL, 0, },
> +	{ 90, IO_TYPE_EXTERNAL, 0, },
> +	{ 91, IO_TYPE_EXTERNAL, 0, },
> +	{ 92, IO_TYPE_EXTERNAL, 0, },
> +	{ 93, IO_TYPE_EXTERNAL, 0, },
> +	{ 94, IO_TYPE_EXTERNAL, 0, },
> +	{ 95, IO_TYPE_EXTERNAL, 0, },
> +	{ 96, IO_TYPE_EXTERNAL, 0, },
> +	{ 97, IO_TYPE_EXTERNAL, 0, },
> +	{ 98, IO_TYPE_EXTERNAL, 0, },
> +	{ 99, IO_TYPE_EXTERNAL, 0, },
> +	{ 100, IO_TYPE_EXTERNAL, 0, },
> +	{ 101, IO_TYPE_EXTERNAL, 0, },
> +	{ 102, IO_TYPE_EXTERNAL, 0, },
> +	{ 103, IO_TYPE_EXTERNAL, 0, },
> +	{ 104, IO_TYPE_EXTERNAL, 0, },
> +	{ 105, IO_TYPE_EXTERNAL, 0, },
> +	{ 106, IO_TYPE_EXTERNAL, 0, },
> +	{ 107, IO_TYPE_EXTERNAL, 0, },
> +	{ 108, IO_TYPE_EXTERNAL, 0, },
> +	{ 109, IO_TYPE_EXTERNAL, 0, },
> +	{ 110, IO_TYPE_EXTERNAL, 0, },
> +	{ 111, IO_TYPE_EXTERNAL, 0, },
> +	{ 112, IO_TYPE_EXTERNAL, 0, },
> +	{ 113, IO_TYPE_EXTERNAL, 0, },
> +	{ 114, IO_TYPE_EXTERNAL, 0, },
> +	{ 115, IO_TYPE_EXTERNAL, 0, },
> +	{ 116, IO_TYPE_EXTERNAL, 0, },
> +	{ 117, IO_TYPE_EXTERNAL, 0, },
> +	{ 118, IO_TYPE_EXTERNAL, 0, },
> +	{ 119, IO_TYPE_EXTERNAL, 0, },
> +	{ 120, IO_TYPE_EXTERNAL, 0, },
> +	{ 121, IO_TYPE_EXTERNAL, 0, },
> +	{ 122, IO_TYPE_EXTERNAL, 0, },
> +	{ 123, IO_TYPE_EXTERNAL, 0, },
> +	{ 124, IO_TYPE_EXTERNAL, 0, },
> +	{ 125, IO_TYPE_EXTERNAL, 0, },
> +	{ 126, IO_TYPE_EXTERNAL, 0, },
> +	{ 127, IO_TYPE_EXTERNAL, 0, },
> +	{ 132, IO_TYPE_EXTERNAL, 0, },
> +	{ 133, IO_TYPE_EXTERNAL, 0, },
> +	{ 134, IO_TYPE_EXTERNAL, 0, },
> +	{ 135, IO_TYPE_EXTERNAL, 0, },
> +	{ 136, IO_TYPE_EXTERNAL, 0, },
> +	{ 137, IO_TYPE_EXTERNAL, 0, },
> +	{ 138, IO_TYPE_EXTERNAL, 0, },
> +	{ 139, IO_TYPE_EXTERNAL, 0, },
> +	{ 140, IO_TYPE_EXTERNAL, 0, },
> +	{ 141, IO_TYPE_EXTERNAL, 0, },
> +	{ 142, IO_TYPE_EXTERNAL, 0, },
> +	{ 143, IO_TYPE_EXTERNAL, 0, },
> +	{ 144, IO_TYPE_EXTERNAL, 0, },
> +};
> +
> +static inline int k3_get_pins(struct udevice *dev)
> +{
> +	return 153;
> +}
> +
> +static inline int k3_get_functions(struct udevice *dev)
> +{
> +	return 7;
> +}
> +
> +static void __iomem *k3_pin_to_reg(struct udevice *dev, unsigned int pin)
> +{
> +	struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
> +	unsigned int offset = pin > 130 ? (pin + 2) : pin;
> +
> +	if (pin > 152) {
> +		dev_err(dev, "Invalid pin (%u)\n", pin);
> +		return NULL;
> +	}
> +	return priv->regs + (offset << 2);
> +}
> +
> +static int k3_get_gpio_mux(struct udevice *dev, unsigned int selector)
> +{
> +	if (selector > 152) {
> +		dev_err(dev, "Invalid pin (%u)\n", selector);
> +		return -EINVAL;
> +	}
> +	/* SD/MMC1, QSPI, PMIC/JTAG use gpiofunc 1 per Linux pin data */
> +	if (selector >= 132)
> +		return 1;
> +	return 0;
> +}
> +
> +static int k3_get_io_type(struct udevice *dev, unsigned int selector)
> +{
> +	if (selector <= 41)
> +		return IO_TYPE_EXTERNAL;
> +	if (selector <= 75)
> +		return IO_TYPE_1V8;
> +	if (selector <= 127)
> +		return IO_TYPE_EXTERNAL;
> +	if (selector <= 131)
> +		return IO_TYPE_1V8;
> +	if (selector <= 144)
> +		return IO_TYPE_EXTERNAL;
> +	if (selector <= 152)
> +		return IO_TYPE_1V8;
> +	return -EINVAL;
> +}
> +
> +static unsigned int spacemit_k3_pin_to_io_pd_offset(unsigned int pin)
> +{
> +	unsigned int offset = 0;
> +
> +	switch (pin) {
> +	case 0 ... 20:
> +		offset = IO_PWR_DOMAIN_GPIO1_K3;
> +		break;
> +	case 21 ... 41:
> +		offset = IO_PWR_DOMAIN_GPIO2_Kx;
> +		break;
> +	case 76 ... 98:
> +		offset = IO_PWR_DOMAIN_GPIO4_K3;
> +		break;
> +	case 99 ... 127:
> +		offset = IO_PWR_DOMAIN_GPIO5_K3;
> +		break;
> +	case 132 ... 137:
> +		offset = IO_PWR_DOMAIN_MMC_Kx;
> +		break;
> +	case 138 ... 144:
> +		offset = IO_PWR_DOMAIN_QSPI_K3;
> +		break;
> +	}
> +
> +	return offset;
> +}
> +
> +static struct spacemit_pin_drv_strength spacemit_k3_ds_1v8_tbl[16] = {
> +	{ 0,  2 }, { 1,  4 }, { 2,  6 }, { 3,  7 },
> +	{ 4,  9 }, { 5, 11 }, { 6, 13 }, { 7, 14 },
> +	{ 8, 21 }, { 9, 23 }, { 10, 25 }, { 11, 26 },
> +	{ 12, 28 }, { 13, 30 }, { 14, 31 }, { 15, 33 },
> +};
> +
> +static struct spacemit_pin_drv_strength spacemit_k3_ds_3v3_tbl[16] = {
> +	{ 0,  3 }, { 1,  5 }, { 2,  7 }, { 3,  9 },
> +	{ 4, 11 }, { 5, 13 }, { 6, 15 }, { 7, 17 },
> +	{ 8, 25 }, { 9, 27 }, { 10, 29 }, { 11, 31 },
> +	{ 12, 33 }, { 13, 35 }, { 14, 37 }, { 15, 38 },
> +};
> +
> +static const struct spacemit_pinctrl_data k3_pinctrl_data = {
> +	.io_pins	= k3_io_pins,
> +	.nr_io_pins	= ARRAY_SIZE(k3_io_pins),
> +	.pin_to_reg	= k3_pin_to_reg,
> +	.get_gpio_mux	= k3_get_gpio_mux,
> +	.get_pins	= k3_get_pins,
> +	.get_functions	= k3_get_functions,
> +	.get_io_type	= k3_get_io_type,
> +	.pin_to_io_pd_offset = spacemit_k3_pin_to_io_pd_offset,
> +	.drive_mask	= PAD_DRIVE_K3,
> +	.ds_1v8_tbl	= spacemit_k3_ds_1v8_tbl,
> +	.ds_1v8_tbl_num	= ARRAY_SIZE(spacemit_k3_ds_1v8_tbl),
> +	.ds_3v3_tbl	= spacemit_k3_ds_3v3_tbl,
> +	.ds_3v3_tbl_num	= ARRAY_SIZE(spacemit_k3_ds_3v3_tbl),
>   };
>   
>   static const struct udevice_id spacemit_pinctrl_ids[] = {
>   	{
>   		.compatible = "spacemit,k1-pinctrl",
>   		.data = (uintptr_t)&k1_pinctrl_data,
> +	}, {
> +		.compatible = "spacemit,k3-pinctrl",
> +		.data = (uintptr_t)&k3_pinctrl_data,
>   	}, { /* sentinel */ }
>   };
>   

Bo


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support
  2026-08-27 21:55   ` Bo Gan
@ 2026-08-27 22:05     ` Yixun Lan
  2026-09-23  8:46     ` Yixun Lan
  1 sibling, 0 replies; 6+ messages in thread
From: Yixun Lan @ 2026-08-27 22:05 UTC (permalink / raw)
  To: Bo Gan
  Cc: u-boot-spacemit, u-boot, Eric Chung, Raymond Mao, Junhui Liu,
	Tom Rini

Hi Bo,

On 14:55 Thu 27 Aug     , Bo Gan wrote:
> Hi Yixun,
> 
> On 8/20/26 06:01, Yixun Lan wrote:
> > Based on upstream Linux:
> >    7412311c4655 ("pinctrl: spacemit: k3: add initial pin support")
> >    3f20bdf71518 ("pinctrl: spacemit: k3: adjust drive strength and schmitter trigger")
> > 
> > K3 uses a different pin-to-register mapping than K1, so add a
> > K3-specific pin_to_reg path and pin/IO power-domain tables. Drive
> > strength expands to 4 bits with larger mA tables, and the shared
> > pinctrl data gains per-SoC drive_mask and drive-strength tables so
> > K1 and K3 can live in the same driver.
> > 
> > Signed-off-by: Yixun Lan <dlan@kernel.org>
> > ---
> >   drivers/pinctrl/spacemit/Kconfig      |   4 +-
> >   drivers/pinctrl/spacemit/pinctrl-k1.c | 291 ++++++++++++++++++++++++++++++----
> >   2 files changed, 259 insertions(+), 36 deletions(-)
> > 
> > diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig
> > index 6aab89e160c..87cba336923 100644
> > --- a/drivers/pinctrl/spacemit/Kconfig
> > +++ b/drivers/pinctrl/spacemit/Kconfig
> > @@ -1,8 +1,8 @@
> >   config PINCTRL_SPACEMIT_K1
> > -	bool "Spacemit K1 SoC pinctrl driver"
> > +	bool "Spacemit K1/K3 SoC pinctrl driver"
> >   	depends on PINCTRL_GENERIC && DM
> >   	help
> > -	  Supports pin multiplexing control on Spacemit K1 SoCs.
> > +	  Supports pin multiplexing control on Spacemit K1 and K3 SoCs.
> >   
> >   	  The driver is controlled by a device tree node which contains both
> >   	  the GPIO definitions and pin control functions for each available
> > diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c
> > index 469c41c40c8..1eb20fd2956 100644
> > --- a/drivers/pinctrl/spacemit/pinctrl-k1.c
> > +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c
> > @@ -30,8 +30,10 @@
> >   #define PAD_EDGE_CLEAR		BIT(6)
> >   #define PAD_SLEW_RATE		GENMASK(12, 11)
> >   #define PAD_SLEW_RATE_EN	BIT(7)
> > -#define PAD_SCHMITT		GENMASK(9, 8)
> > -#define PAD_DRIVE		GENMASK(12, 10)
> > +#define PAD_SCHMITT_K1		GENMASK(9, 8)
> > +#define PAD_DRIVE_K1		GENMASK(12, 10)
> > +#define PAD_SCHMITT_K3		BIT(8)
> > +#define PAD_DRIVE_K3		GENMASK(12, 9)
> >   #define PAD_PULLDOWN		BIT(13)
> >   #define PAD_PULLUP		BIT(14)
> >   #define PAD_PULL_EN		BIT(15)
> > @@ -43,6 +45,11 @@
> >   #define IO_PWR_DOMAIN_MMC_Kx	0x1c
> >   #define IO_PWR_DOMAIN_QSPI_K1	0x20
> >   
> > +#define IO_PWR_DOMAIN_GPIO1_K3  0x04
> > +#define IO_PWR_DOMAIN_GPIO5_K3  0x10
> > +#define IO_PWR_DOMAIN_GPIO4_K3  0x20
> > +#define IO_PWR_DOMAIN_QSPI_K3   0x2c
> > +
> >   #define IO_PWR_DOMAIN_V18EN	BIT(2)
> >   
> >   #define APBC_ASFAR		0x50
> > @@ -68,6 +75,12 @@ struct spacemit_pin_io {
> >   	unsigned int	reserved : 8;
> >   };
> >   
> > +struct spacemit_pin_drv_strength {
> > +	unsigned int	val : 8;
> > +	unsigned int	ma : 16;
> > +	unsigned int	reserved : 8;
> > +};
> > +
> >   struct spacemit_pinctrl_data {
> >   	struct spacemit_pin_io *io_pins;
> >   	int nr_io_pins;
> > @@ -78,6 +91,12 @@ struct spacemit_pinctrl_data {
> >   	int (*get_functions)(struct udevice *dev);
> >   	int (*get_io_type)(struct udevice *dev, unsigned int pin);
> >   	unsigned int (*pin_to_io_pd_offset)(unsigned int pin);
> > +
> > +	u32 drive_mask;
> > +	struct spacemit_pin_drv_strength *ds_1v8_tbl;
> > +	int ds_1v8_tbl_num;
> > +	struct spacemit_pin_drv_strength *ds_3v3_tbl;
> > +	int ds_3v3_tbl_num;
> >   };
> >   
> >   struct spacemit_pinctrl_priv {
> > @@ -92,12 +111,6 @@ struct spacemit_pin_mux_config {
> >   	u32				config;
> >   };
> >   
> > -struct spacemit_pin_drv_strength {
> > -	unsigned int	val : 8;
> > -	unsigned int	ma : 16;
> > -	unsigned int	reserved : 8;
> > -};
> > -
> >   static char pin_name[PINNAME_SIZE];
> >   
> >   /* External: IO voltage via external source, can be 1.8V or 3.3V */
> > @@ -280,35 +293,17 @@ static inline u32 spacemit_get_ds_ma(struct spacemit_pin_drv_strength *tbl,
> >   	return 0;
> >   }
> >   
> > -static inline u8 spacemit_get_drive_strength(enum spacemit_pin_io_type type,
> > +static inline u8 spacemit_get_drive_strength(struct spacemit_pinctrl_data *data,
> > +					     enum spacemit_pin_io_type type,
> >   					     u32 ma)
> >   {
> >   	switch (type) {
> >   	case IO_TYPE_1V8:
> > -		return spacemit_get_ds_value(spacemit_ds_1v8_tbl,
> > -					     ARRAY_SIZE(spacemit_ds_1v8_tbl),
> > -					     ma);
> > -	case IO_TYPE_3V3:
> > -		return spacemit_get_ds_value(spacemit_ds_3v3_tbl,
> > -					     ARRAY_SIZE(spacemit_ds_3v3_tbl),
> > -					     ma);
> > -	default:
> > -		return 0;
> > -	}
> > -}
> > -
> > -static inline u32 spacemit_get_drive_strength_ma(enum spacemit_pin_io_type type,
> > -						 u32 value)
> > -{
> > -	switch (type) {
> > -	case IO_TYPE_1V8:
> > -		return spacemit_get_ds_ma(spacemit_ds_1v8_tbl,
> > -					  ARRAY_SIZE(spacemit_ds_1v8_tbl),
> > -					  value & 0x6);
> > +		return spacemit_get_ds_value(data->ds_1v8_tbl,
> > +					     data->ds_1v8_tbl_num, ma);
> >   	case IO_TYPE_3V3:
> > -		return spacemit_get_ds_ma(spacemit_ds_3v3_tbl,
> > -					  ARRAY_SIZE(spacemit_ds_3v3_tbl),
> > -					  value);
> > +		return spacemit_get_ds_value(data->ds_3v3_tbl,
> > +					     data->ds_3v3_tbl_num, ma);
> >   	default:
> >   		return 0;
> >   	}
> > @@ -549,8 +544,9 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
> >   			dev_err(dev, "Invalid IO type (%d)\n", io_type);
> >   			return -EINVAL;
> >   		}
> > -		ds = spacemit_get_drive_strength(io_type, argument);
> > -		clrsetbits_le32(addr, PAD_DRIVE, FIELD_PREP(PAD_DRIVE, ds));
> > +		ds = spacemit_get_drive_strength(data, io_type, argument);
> > +		clrsetbits_le32(addr, data->drive_mask,
> > +				field_prep(data->drive_mask, ds));
> >   		break;
> >   	case PIN_CONFIG_POWER_SOURCE:
> >   		return spacemit_set_pin_power_source(dev, pin_selector, argument);
> > @@ -704,12 +700,239 @@ static const struct spacemit_pinctrl_data k1_pinctrl_data = {
> >   	.get_functions	= k1_get_functions,
> >   	.get_io_type	= k1_get_io_type,
> >   	.pin_to_io_pd_offset = spacemit_k1_pin_to_io_pd_offset,
> > +	.drive_mask	= PAD_DRIVE_K1,
> > +	.ds_1v8_tbl	= spacemit_ds_1v8_tbl,
> > +	.ds_1v8_tbl_num	= ARRAY_SIZE(spacemit_ds_1v8_tbl),
> > +	.ds_3v3_tbl	= spacemit_ds_3v3_tbl,
> > +	.ds_3v3_tbl_num	= ARRAY_SIZE(spacemit_ds_3v3_tbl),
> > +};
> > +
> 
> Can the following table be simplified using static function and switch
> cases? As your other series mentioned, the SPL has very strict size limit,
> so we'd better not define this huge data array.
> 
I think it's possible, will try to implement, and see how much space it
can save.. thanks for the suggestion

> > +static struct spacemit_pin_io k3_io_pins[] = {
> > +	{ 0, IO_TYPE_EXTERNAL, 0, },
> > +	{ 1, IO_TYPE_EXTERNAL, 0, },
..
> 

-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support
  2026-08-27 21:55   ` Bo Gan
  2026-08-27 22:05     ` Yixun Lan
@ 2026-09-23  8:46     ` Yixun Lan
  1 sibling, 0 replies; 6+ messages in thread
From: Yixun Lan @ 2026-09-23  8:46 UTC (permalink / raw)
  To: Bo Gan
  Cc: u-boot-spacemit, u-boot, Eric Chung, Raymond Mao, Junhui Liu,
	Tom Rini

Hi Bo Gan,

On 14:55 Thu 27 Aug     , Bo Gan wrote:
> Hi Yixun,
> 
> On 8/20/26 06:01, Yixun Lan wrote:
> > Based on upstream Linux:
> >    7412311c4655 ("pinctrl: spacemit: k3: add initial pin support")
> >    3f20bdf71518 ("pinctrl: spacemit: k3: adjust drive strength and schmitter trigger")
> > 
> > K3 uses a different pin-to-register mapping than K1, so add a
> > K3-specific pin_to_reg path and pin/IO power-domain tables. Drive
> > strength expands to 4 bits with larger mA tables, and the shared
> > pinctrl data gains per-SoC drive_mask and drive-strength tables so
> > K1 and K3 can live in the same driver.
> > 
> > Signed-off-by: Yixun Lan <dlan@kernel.org>
> > ---
> >   drivers/pinctrl/spacemit/Kconfig      |   4 +-
> >   drivers/pinctrl/spacemit/pinctrl-k1.c | 291 ++++++++++++++++++++++++++++++----
> >   2 files changed, 259 insertions(+), 36 deletions(-)
> > 
...
> > @@ -704,12 +700,239 @@ static const struct spacemit_pinctrl_data k1_pinctrl_data = {
> >   	.get_functions	= k1_get_functions,
> >   	.get_io_type	= k1_get_io_type,
> >   	.pin_to_io_pd_offset = spacemit_k1_pin_to_io_pd_offset,
> > +	.drive_mask	= PAD_DRIVE_K1,
> > +	.ds_1v8_tbl	= spacemit_ds_1v8_tbl,
> > +	.ds_1v8_tbl_num	= ARRAY_SIZE(spacemit_ds_1v8_tbl),
> > +	.ds_3v3_tbl	= spacemit_ds_3v3_tbl,
> > +	.ds_3v3_tbl_num	= ARRAY_SIZE(spacemit_ds_3v3_tbl),
> > +};
> > +
> 
> Can the following table be simplified using static function and switch
> cases? As your other series mentioned, the SPL has very strict size limit,
> so we'd better not define this huge data array.
> 
While actually looking into the implemenation, I end at giving up to
optimize it by using static function, it's much hard than I expected..
the io pin's information is per pin bias, and io voltage is dynamically
parsed from the DT property, which mean we actually need to allocate
each instance for all pins..

The optimization implenmation isn't critical, so I will leave it
unchanged for next version..

> > +static struct spacemit_pin_io k3_io_pins[] = {
> > +	{ 0, IO_TYPE_EXTERNAL, 0, },
> > +	{ 1, IO_TYPE_EXTERNAL, 0, },
> > +	{ 2, IO_TYPE_EXTERNAL, 0, },
> > +	{ 3, IO_TYPE_EXTERNAL, 0, },
> > +	{ 4, IO_TYPE_EXTERNAL, 0, },
> > +	{ 5, IO_TYPE_EXTERNAL, 0, },
....

-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-23  8:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20 13:01 [PATCH 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
2026-08-20 13:01 ` [PATCH 1/2] pinctrl: spacemit: configure drive strength based on power source Yixun Lan
2026-08-20 13:01 ` [PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support Yixun Lan
2026-08-27 21:55   ` Bo Gan
2026-08-27 22:05     ` Yixun Lan
2026-09-23  8:46     ` Yixun Lan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.