On 9/23/26 06:06, 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 <[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 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 */ }
> };
>
>
Acked-by: E Shattow <[email protected]>