U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Yixun Lan <dlan@kernel.org>
To: u-boot-spacemit@groups.io, u-boot@lists.u-boot-project.org
Cc: Eric Chung <eric.chung@riscstar.com>,
	 Raymond Mao <raymond.mao@riscstar.com>,
	 Junhui Liu <junhui.liu@pigmoral.tech>,
	Tom Rini <trini@konsulko.com>,  Yixun Lan <dlan@kernel.org>
Subject: [PATCH v2 2/2] pinctrl: spacemit: k3: add K3 pin support
Date: Wed, 23 Sep 2026 13:06:53 +0000	[thread overview]
Message-ID: <20260923-01-k3-pinctrl-support-v2-2-e76a917ee252@kernel.org> (raw)
In-Reply-To: <20260923-01-k3-pinctrl-support-v2-0-e76a917ee252@kernel.org>

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 ff0fa3a4b18..002878862dc 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;
 	}
@@ -552,8 +547,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);
@@ -707,12 +703,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


  parent reply	other threads:[~2026-09-23 13:07 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-23 13:06 [PATCH v2 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
2026-09-23 13:06 ` [PATCH v2 1/2] pinctrl: spacemit: configure drive strength based on power source Yixun Lan
2026-09-23 13:06 ` Yixun Lan [this message]
2026-10-07  9:12   ` [PATCH v2 2/2] pinctrl: spacemit: k3: add K3 pin support E Shattow
2026-09-29 10:12 ` (subset) [PATCH v2 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
2026-10-09  7:24 ` Yixun Lan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260923-01-k3-pinctrl-support-v2-2-e76a917ee252@kernel.org \
    --to=dlan@kernel.org \
    --cc=eric.chung@riscstar.com \
    --cc=junhui.liu@pigmoral.tech \
    --cc=raymond.mao@riscstar.com \
    --cc=trini@konsulko.com \
    --cc=u-boot-spacemit@groups.io \
    --cc=u-boot@lists.u-boot-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox