[PATCH] ram: ti: k3-ddrss: Add workaround sequence for errata i2487

Sebin Francis sebin.francis at ti.com
Thu Dec 11 11:09:13 CET 2025


Hi

On 11/12/25 15:02, Akashdeep Kaur wrote:
> As per errata
> i2487: "the low power modes may inadvertently corrupt DDR contents"
> for AM62AX[0] and AM62PX[1].
> 
> Based on the recommendation, add SW workaround sequence to
> clear data retention latch on every boot and/or abort scenarios to
> make sure that latch is initialized to zero rather than unknown value.
> 
> Executing this sequence during boot helps to successfully resume the SoCs
> from IO+DDR low power mode.
> This sequence is executed in partial I/O resume as well as all the
> other conditions when reset is issued during low power mode entry/exit
> or when the SoC is in idle mode.
> 
> The sequence should be executed for SoCs that support IO+DDR mode, that
> is AM62AX and AM62PX.
> 
> [0]: https://www.ti.com/lit/er/sprz544c/sprz544c.pdf
> [1]: https://www.ti.com/lit/er/sprz574b/sprz574b.pdf
> 
> Signed-off-by: Akashdeep Kaur <a-kaur at ti.com>

Tested all low power modes in AM62A including IO only plus DDR with the 
patch. Everything look good.

Tested-by Sebin Francis <sebin.francis at ti.com>

> ---
> 
> Depends-On: https://lore.kernel.org/all/20251210-topic-am62-ioddr-v2025-04-rc1-v7-0-f113b156f83f@baylibre.com/
> 
> ---
>   drivers/ram/k3-ddrss/k3-ddrss-lpm.c | 78 +++++++++++++++++++++++++++++
>   drivers/ram/k3-ddrss/k3-ddrss-lpm.h |  1 +
>   drivers/ram/k3-ddrss/k3-ddrss.c     |  3 ++
>   3 files changed, 82 insertions(+)
> 
> diff --git a/drivers/ram/k3-ddrss/k3-ddrss-lpm.c b/drivers/ram/k3-ddrss/k3-ddrss-lpm.c
> index 2556632df88..523f0cb6219 100644
> --- a/drivers/ram/k3-ddrss/k3-ddrss-lpm.c
> +++ b/drivers/ram/k3-ddrss/k3-ddrss-lpm.c
> @@ -19,8 +19,18 @@
>   #define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT		0x43018318
>   #define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT_MW		0x555555
>   
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL			0x43018300
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_LD	BIT(0)
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW		0x55555554
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_MASK	GENMASK(31, 1)
> +
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE			0x43018310
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_MW		0xDD555555
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_MW_MASK	GENMASK(31, 0)
> +
>   #define K3_DDRSS_LPM_TIMEOUT_MS 5000
>   #define K3_DDRSS_RETENTION_TIMEOUT_MS 5000
> +#define K3_DDRSS_RETENTION_LATCH_CLR_TIMEOUT_MS 500
>   
>   #define K3_DDRSS_CFG_DENALI_CTL_20				0x0050
>   #define K3_DDRSS_CFG_DENALI_CTL_20_PHY_INDEP_TRAIN_MODE		BIT(24)
> @@ -149,6 +159,61 @@ void k3_ddrss_deassert_retention(void)
>   				 0);
>   }
>   
> +static void k3_ddrss_clear_retention_latch_and_magic_words(void)
> +{
> +	int ret;
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE,
> +				 0,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_MW_MASK,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_MW);
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL,
> +				 0,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_MASK |
> +				   K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_LD,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW |
> +				   K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_LD);
> +
> +	ret = wait_for_bit_32((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1,
> +			      K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1_CANUART_IO_MODE,
> +			      true, K3_DDRSS_RETENTION_LATCH_CLR_TIMEOUT_MS, false);
> +	if (ret)
> +		panic("Timeout during latch clearing sequence %d\n", ret);
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL,
> +				 0,
> +			   K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD |
> +			   K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RETENTION_MASK,
> +			   K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD);
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL,
> +				 0,
> +			   K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD,
> +			   0);
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL,
> +				 0,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_LD,
> +			   0);
> +
> +	ret = wait_for_bit_32((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1,
> +			      K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1_CANUART_IO_MODE,
> +			      false, K3_DDRSS_RETENTION_LATCH_CLR_TIMEOUT_MS, false);
> +	if (ret)
> +		panic("Timeout during latch clearing sequence %d\n", ret);
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE,
> +				 0,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_MW_MASK,
> +			   0);
> +
> +	k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL,
> +				 0,
> +			   K3_WKUP_CTRL_MMR_CANUART_WAKE_CTRL_MW_MASK,
> +			   0);
> +}
> +
>   static bool k3_ddrss_wkup_conf_canuart_wakeup_active(void)
>   {
>   	u32 active;
> @@ -173,3 +238,16 @@ bool k3_ddrss_wkup_conf_boot_is_resume(void)
>   		k3_ddrss_wkup_conf_canuart_wakeup_active() &&
>   		k3_ddrss_wkup_conf_canuart_magic_word_set();
>   }
> +
> +void k3_ddrss_run_retention_latch_clear_sequence(void)
> +{
> +	/*
> +	 * Workaround of errata i12487
> +	 * Errata states that During entry to the Deep Sleep or RTC+IO+DDR
> +	 * low-power modes, SoC may not properly transition the attached
> +	 * DDR into retention mode, which will lead to corruption of the DDR
> +	 * data.
> +	 */
> +	if (IS_ENABLED(CONFIG_K3_IODDR))
> +		k3_ddrss_clear_retention_latch_and_magic_words();
> +}
> diff --git a/drivers/ram/k3-ddrss/k3-ddrss-lpm.h b/drivers/ram/k3-ddrss/k3-ddrss-lpm.h
> index cb2c270b7b2..1c2343924fb 100644
> --- a/drivers/ram/k3-ddrss/k3-ddrss-lpm.h
> +++ b/drivers/ram/k3-ddrss/k3-ddrss-lpm.h
> @@ -7,3 +7,4 @@ void k3_ddrss_self_refresh_exit(void __iomem *ddrss_ctl_cfg);
>   void k3_ddrss_lpm_resume(void __iomem *ddrss_ctl_cfg);
>   void k3_ddrss_deassert_retention(void);
>   bool k3_ddrss_wkup_conf_boot_is_resume(void);
> +void k3_ddrss_run_retention_latch_clear_sequence(void);
> diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
> index cedec616e23..ebe56da72cf 100644
> --- a/drivers/ram/k3-ddrss/k3-ddrss.c
> +++ b/drivers/ram/k3-ddrss/k3-ddrss.c
> @@ -886,6 +886,9 @@ static int k3_ddrss_probe(struct udevice *dev)
>   
>   	if (is_lpm_resume)
>   		dev_info(dev, "Detected IO+DDR resume\n");
> +	else
> +		/* Clear the latch after any reset or partial I/O exit */
> +		k3_ddrss_run_retention_latch_clear_sequence();
>   
>   	ddrss->dev = dev;
>   	ret = k3_ddrss_power_on(ddrss);


More information about the U-Boot mailing list