[PATCH 3/3] pinctrl: pinctrl_stm32: support IO synchronization parameters

Patrick DELAUNAY patrick.delaunay at foss.st.com
Tue Feb 24 10:44:05 CET 2026


Hi,

On 2/5/26 09:07, Patrice Chotard wrote:
> From: Fabien Dessenne <fabien.dessenne at foss.st.com>
>
> Support the following IO synchronization parameters:
> - Delay (in ns)
> - Delay path (input / output)
> - Clock edge (single / double edge)
> - Clock inversion
> - Retiming
> These settings allow a fine tuning of the high speed interface signals.
>
> Enable this feature for the stm32mp257 SOC.
>
> Signed-off-by: Fabien Dessenne <fabien.dessenne at foss.st.com>
> Signed-off-by: Valentin Caron <valentin.caron at foss.st.com>
> Signed-off-by: Patrice Chotard <patrice.chotard at foss.st.com>
> ---
>   drivers/gpio/stm32_gpio_priv.h  | 58 +++++++++++++++++++++++++++---
>   drivers/pinctrl/pinctrl_stm32.c | 80 +++++++++++++++++++++++++++++++++--------
>   2 files changed, 119 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/gpio/stm32_gpio_priv.h b/drivers/gpio/stm32_gpio_priv.h
> index d89e9b8ed60..69868787af0 100644
> --- a/drivers/gpio/stm32_gpio_priv.h
> +++ b/drivers/gpio/stm32_gpio_priv.h
> @@ -51,7 +51,45 @@ enum stm32_gpio_af {
>   	STM32_GPIO_AF15
>   };
>   
> +enum stm32_gpio_delay_path {
> +	STM32_GPIO_DELAY_PATH_OUT = 0,
> +	STM32_GPIO_DELAY_PATH_IN
> +};
> +
> +enum stm32_gpio_clk_edge {
> +	STM32_GPIO_CLK_EDGE_SINGLE = 0,
> +	STM32_GPIO_CLK_EDGE_DOUBLE
> +};
> +
> +enum stm32_gpio_clk_type {
> +	STM32_GPIO_CLK_TYPE_NOT_INVERT = 0,
> +	STM32_GPIO_CLK_TYPE_INVERT
> +};
> +
> +enum stm32_gpio_retime {
> +	STM32_GPIO_RETIME_DISABLED = 0,
> +	STM32_GPIO_RETIME_ENABLED
> +};
> +
> +enum stm32_gpio_delay {
> +	STM32_GPIO_DELAY_NONE = 0,
> +	STM32_GPIO_DELAY_0_3,
> +	STM32_GPIO_DELAY_0_5,
> +	STM32_GPIO_DELAY_0_75,
> +	STM32_GPIO_DELAY_1_0,
> +	STM32_GPIO_DELAY_1_25,
> +	STM32_GPIO_DELAY_1_5,
> +	STM32_GPIO_DELAY_1_75,
> +	STM32_GPIO_DELAY_2_0,
> +	STM32_GPIO_DELAY_2_25,
> +	STM32_GPIO_DELAY_2_5,
> +	STM32_GPIO_DELAY_2_75,
> +	STM32_GPIO_DELAY_3_0,
> +	STM32_GPIO_DELAY_3_25
> +};
> +
>   #define STM32_GPIO_FLAG_SEC_CTRL	BIT(0)
> +#define STM32_GPIO_FLAG_IO_SYNC_CTRL	BIT(1)
>   
>   struct stm32_gpio_dsc {
>   	u8	port;
> @@ -59,11 +97,16 @@ struct stm32_gpio_dsc {
>   };
>   
>   struct stm32_gpio_ctl {
> -	enum stm32_gpio_mode	mode;
> -	enum stm32_gpio_otype	otype;
> -	enum stm32_gpio_speed	speed;
> -	enum stm32_gpio_pupd	pupd;
> -	enum stm32_gpio_af	af;
> +	enum stm32_gpio_mode		mode;
> +	enum stm32_gpio_otype		otype;
> +	enum stm32_gpio_speed		speed;
> +	enum stm32_gpio_pupd		pupd;
> +	enum stm32_gpio_af		af;
> +	enum stm32_gpio_delay_path	delay_path;
> +	enum stm32_gpio_clk_edge	clk_edge;
> +	enum stm32_gpio_clk_type	clk_type;
> +	enum stm32_gpio_retime		retime;
> +	enum stm32_gpio_delay		delay;
>   };
>   
>   struct stm32_gpio_regs {
> @@ -79,6 +122,11 @@ struct stm32_gpio_regs {
>   	u32 brr;	/* GPIO port bit reset */
>   	u32 rfu;	/* Reserved */
>   	u32 seccfgr;	/* GPIO secure configuration */
> +	u32 rfu2;	/* Reserved (privcfgr) */
> +	u32 rfu3;	/* Reserved (rcfglock) */
> +	u32 rfu4;	/* Reserved */
> +	u32 delayr[2];	/* GPIO port delay */
> +	u32 advcfgr[2];	/* GPIO port PIO control */
>   };
>   
>   struct stm32_gpio_priv {
> diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
> index 1758f9a909c..7d5a0471a65 100644
> --- a/drivers/pinctrl/pinctrl_stm32.c
> +++ b/drivers/pinctrl/pinctrl_stm32.c
> @@ -29,6 +29,12 @@
>   #define OTYPE_MSK			1
>   #define AFR_MASK			0xF
>   #define SECCFG_MSK			1
> +#define ADVCFGR_MASK			0xF
> +#define DELAYR_MASK			0xF
> +#define ADVCFGR_DLYPATH_POS		0
> +#define ADVCFGR_DE_POS			1
> +#define ADVCFGR_INVCLK_POS		2
> +#define ADVCFGR_RET_POS			3
>   
>   struct stm32_pinctrl_priv {
>   	struct hwspinlock hws;
> @@ -43,6 +49,7 @@ struct stm32_gpio_bank {
>   
>   struct stm32_pinctrl_data {
>   	bool secure_control;
> +	bool io_sync_control;
>   };
>   
>   #ifndef CONFIG_XPL_BUILD
> @@ -304,7 +311,7 @@ static int stm32_gpio_config(ofnode node,
>   	struct stm32_gpio_regs *regs = priv->regs;
>   	struct stm32_pinctrl_priv *ctrl_priv;
>   	int ret;
> -	u32 index;
> +	u32 index, io_sync, advcfg;
>   
>   	/* Check access protection */
>   	ret = stm32_pinctrl_get_access(desc->dev, desc->offset);
> @@ -318,6 +325,14 @@ static int stm32_gpio_config(ofnode node,
>   	    ctl->pupd > 2 || ctl->speed > 3)
>   		return -EINVAL;
>   
> +	io_sync = dev_get_driver_data(desc->dev) & STM32_GPIO_FLAG_IO_SYNC_CTRL;
> +	if (io_sync && (ctl->delay_path > STM32_GPIO_DELAY_PATH_IN ||
> +			ctl->clk_edge > STM32_GPIO_CLK_EDGE_DOUBLE ||
> +			ctl->clk_type > STM32_GPIO_CLK_TYPE_INVERT ||
> +			ctl->retime > STM32_GPIO_RETIME_ENABLED ||
> +			ctl->delay > STM32_GPIO_DELAY_3_25))
> +		return -EINVAL;
> +
>   	ctrl_priv = dev_get_priv(dev_get_parent(desc->dev));
>   	ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10);
>   	if (ret == -ETIME) {
> @@ -339,6 +354,20 @@ static int stm32_gpio_config(ofnode node,
>   	index = desc->offset;
>   	clrsetbits_le32(&regs->otyper, OTYPE_MSK << index, ctl->otype << index);
>   
> +	if (io_sync) {
> +		index = (desc->offset & 0x07) * 4;
> +		advcfg = (ctl->delay_path << ADVCFGR_DLYPATH_POS) |
> +			 (ctl->clk_edge << ADVCFGR_DE_POS) |
> +			 (ctl->clk_type << ADVCFGR_INVCLK_POS) |
> +			 (ctl->retime << ADVCFGR_RET_POS);
> +
> +		clrsetbits_le32(&regs->advcfgr[desc->offset >> 3],
> +				ADVCFGR_MASK << index, advcfg << index);
> +
> +		clrsetbits_le32(&regs->delayr[desc->offset >> 3],
> +				DELAYR_MASK << index, ctl->delay << index);
> +	}
> +
>   	uc_priv->name[desc->offset] = strdup(ofnode_get_name(node));
>   
>   	hwspinlock_unlock(&ctrl_priv->hws);
> @@ -391,10 +420,24 @@ static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn,
>   	else
>   		gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
>   
> +	gpio_ctl->delay_path = ofnode_read_u32_default(node, "st,io-delay-path", 0);
> +	gpio_ctl->clk_edge = ofnode_read_u32_default(node, "st,io-clk-edge", 0);
> +	gpio_ctl->clk_type = ofnode_read_u32_default(node, "st,io-clk-type", 0);
> +	gpio_ctl->retime = ofnode_read_u32_default(node, "st,io-retime", 0);
> +	gpio_ctl->delay = ofnode_read_u32_default(node, "st,io-delay", 0);
> +


The binding seens not aligned with latest proposal done for kernel

https://patchwork.ozlabs.org/project/devicetree-bindings/list/?series=479156


'skew-delay-{in,out}put-ps'


https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251023132700.1199871-12-antonio.borneo@foss.st.com/


I think, it is the old OpenSTLinux downstream binding


>   	log_debug("gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n",
>   		  gpio_fn, gpio_ctl->speed, gpio_ctl->otype,
>   		  gpio_ctl->pupd);
>   
> +	if (gpio_ctl->retime || gpio_ctl->clk_type || gpio_ctl->clk_edge || gpio_ctl->delay_path ||
> +	    gpio_ctl->delay)
> +		log_debug("	Retime:%d InvClk:%d DblEdge:%d DelayIn:%d\n",
> +			  gpio_ctl->retime, gpio_ctl->clk_type, gpio_ctl->clk_edge,
> +			  gpio_ctl->delay_path);
> +	if (gpio_ctl->delay)
> +		log_debug("	Delay: %d (%d ps)\n", gpio_ctl->delay, gpio_ctl->delay * 250);
> +
>   	return 0;
>   }
>   
> @@ -466,7 +509,9 @@ static int stm32_pinctrl_bind(struct udevice *dev)
>   		return -EINVAL;
>   	}
>   	if (drv_data->secure_control)
> -		gpio_data = STM32_GPIO_FLAG_SEC_CTRL;
> +		gpio_data |= STM32_GPIO_FLAG_SEC_CTRL;
> +	if (drv_data->io_sync_control)
> +		gpio_data |= STM32_GPIO_FLAG_IO_SYNC_CTRL;
>   
>   	dev_for_each_subnode(node, dev) {
>   		dev_dbg(dev, "bind %s\n", ofnode_get_name(node));
> @@ -546,25 +591,32 @@ static struct pinctrl_ops stm32_pinctrl_ops = {
>   #endif
>   };
>   
> -static const struct stm32_pinctrl_data stm32_pinctrl_no_sec = {
> +static const struct stm32_pinctrl_data stm32_pinctrl_base = {
>   	.secure_control = false,
> +	.io_sync_control = false,
> +};
> +
> +static const struct stm32_pinctrl_data stm32_pinctrl_sec = {
> +	.secure_control = true,
> +	.io_sync_control = false,
>   };
>   
> -static const struct stm32_pinctrl_data stm32_pinctrl_with_sec = {
> +static const struct stm32_pinctrl_data stm32_pinctrl_sec_iosync = {
>   	.secure_control = true,
> +	.io_sync_control = true,
>   };
>   
>   static const struct udevice_id stm32_pinctrl_ids[] = {
> -	{ .compatible = "st,stm32f429-pinctrl",    .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32f469-pinctrl",    .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32f746-pinctrl",    .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32f769-pinctrl",    .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32h743-pinctrl",    .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32mp157-pinctrl",   .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32mp157-z-pinctrl", .data = (ulong)&stm32_pinctrl_no_sec },
> -	{ .compatible = "st,stm32mp135-pinctrl",   .data = (ulong)&stm32_pinctrl_with_sec },
> -	{ .compatible = "st,stm32mp257-pinctrl",   .data = (ulong)&stm32_pinctrl_with_sec },
> -	{ .compatible = "st,stm32mp257-z-pinctrl", .data = (ulong)&stm32_pinctrl_with_sec },
> +	{ .compatible = "st,stm32f429-pinctrl",    .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32f469-pinctrl",    .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32f746-pinctrl",    .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32f769-pinctrl",    .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32h743-pinctrl",    .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32mp157-pinctrl",   .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32mp157-z-pinctrl", .data = (ulong)&stm32_pinctrl_base },
> +	{ .compatible = "st,stm32mp135-pinctrl",   .data = (ulong)&stm32_pinctrl_sec },
> +	{ .compatible = "st,stm32mp257-pinctrl",   .data = (ulong)&stm32_pinctrl_sec_iosync },
> +	{ .compatible = "st,stm32mp257-z-pinctrl", .data = (ulong)&stm32_pinctrl_sec_iosync },
>   	{ }
>   };
>   
>
Thanks

Patrick



More information about the U-Boot mailing list