[PATCH 2/2] pinctrl: spacemit: k3: add K3 pin support

Yixun Lan <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.