[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