[PATCH v3 03/22] ram: k3-ddrss: Add support for DDR in self-refresh
Markus Schneider-Pargmann
msp at baylibre.com
Tue Aug 12 15:25:52 CEST 2025
Hi Akashdeep,
On Wed Jul 2, 2025 at 8:49 AM CEST, Akashdeep Kaur wrote:
> Hi Markus,
>
> On 23/06/25 17:38, Markus Schneider-Pargmann wrote:
>> In IO+DDR the DDR is kept in self-refresh while the SoC cores are
>> powered off completely. During boot the normal initialization routine of
>> DDR is slightly different to exit self-refresh and keep the DDR contents.
>>
>> Signed-off-by: Markus Schneider-Pargmann <msp at baylibre.com>
>> ---
>> drivers/ram/k3-ddrss/k3-ddrss.c | 177 ++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 177 insertions(+)
>>
>> diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
>> index 6590d57ad84f3c4dc5c72c6c5889038c463b0469..874614140c6d4a785fcca6eda4a8736e1183e193 100644
>> --- a/drivers/ram/k3-ddrss/k3-ddrss.c
>> +++ b/drivers/ram/k3-ddrss/k3-ddrss.c
>> @@ -57,6 +57,16 @@
>> #define DDRSS_V2A_INT_SET_REG_ECC2BERR_EN BIT(4)
>> #define DDRSS_V2A_INT_SET_REG_ECCM1BERR_EN BIT(5
>> +static void k3_ddrss_self_refresh_exit(struct k3_ddrss_desc *ddrss)
>> +{
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_CTL_169,
>> + K3_DDRSS_CFG_DENALI_CTL_169_LP_AUTO_EXIT_EN_MASK |
>> + K3_DDRSS_CFG_DENALI_CTL_169_LP_AUTO_ENTRY_EN_MASK,
>> + 0x0);
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_PHY_1820,
>> + 0,
>> + BIT(2) << K3_DDRSS_CFG_DENALI_PHY_1820_SET_DFI_INPUT_2_SHIFT);
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_CTL_106,
>> + 0,
>> + K3_DDRSS_CFG_DENALI_CTL_106_PWRUP_SREFRESH_EXIT);
>> + writel(0, ddrss->ddrss_ctl_cfg + K3_DDRSS_CFG_DENALI_PI_146);
>
> Can we change this writel also to reg update function based call?
Yes, that would be possible, but it would transform a single write into
a read/update/write.
>
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_PI_150,
>> + K3_DDRSS_CFG_DENALI_PI_150_PI_DRAM_INIT_EN,
>> + 0x0);
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_PI_6,
>> + 0,
>> + K3_DDRSS_CFG_DENALI_PI_6_PI_DFI_PHYMSTR_STATE_SEL_R);
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_CTL_21,
>> + K3_DDRSS_CFG_DENALI_CTL_21_PHY_INDEP_INIT_MODE,
>> + 0);
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_CTL_20,
>> + 0,
>> + K3_DDRSS_CFG_DENALI_CTL_20_PHY_INDEP_TRAIN_MODE);
>> +}
>> +
>> +static void k3_ddrss_lpm_resume(struct k3_ddrss_desc *ddrss)
>> +{
>> + int ret;
>> + unsigned long timeout_start;
>> +
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_CTL_160,
>> + K3_DDRSS_CFG_DENALI_CTL_160_LP_CMD_MASK,
>> + K3_DDRSS_CFG_DENALI_CTL_160_LP_CMD_ENTRY);
>> + ret = wait_for_bit_32(ddrss->ddrss_ctl_cfg + K3_DDRSS_CFG_DENALI_CTL_345,
>> + (1 << K3_DDRSS_CFG_DENALI_CTL_345_INT_STATUS_LOWPOWER_SHIFT),
>> + true, 5000, false);
>> + if (ret)
>> + panic("Failed waiting for low power command %d\n", ret);
>> +
>> + k3_ddrss_reg_update_bits(ddrss->ddrss_ctl_cfg,
>> + K3_DDRSS_CFG_DENALI_CTL_353,
>> + 0,
>> + 1 << K3_DDRSS_CFG_DENALI_CTL_353_INT_ACK_LOWPOWER_SHIFT);
>> +
>> + timeout_start = get_timer(0);
>> + while (1) {
>> + if (get_timer(timeout_start) > 5000)
>> + panic("Failed waiting for low power state\n");
>> +
>> + if ((readl(ddrss->ddrss_ctl_cfg + K3_DDRSS_CFG_DENALI_CTL_169) &
>> + K3_DDRSS_CFG_DENALI_CTL_169_LP_STATE_MASK) ==
>> + 0x40 << K3_DDRSS_CFG_DENALI_CTL_169_LP_STATE_SHIFT)
>> + break;
>
> As i see, wait for bit function can wait on mask also, can we use wait
> on the bit transition with timeout in this case?
If I see it correctly wait_for_bit_32 accepts a mask but can only check
if the full mask is set or not. In the example above we would need
separate arguments for mask and expected value, e.g.
K3_DDRSS_CFG_DENALI_CTL_169_LP_STATE_MASK as mask and 0x40 shifted as
the expected value.
>> + }
>> +}
>> +
>> +static void k3_ddrss_deassert_retention(struct k3_ddrss_desc *ddrss)
>> +{
>> + int ret;
>> +
>> + k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL,
>> + 0x0,
>> + K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD |
>> + K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RETENTION_MASK,
>> + 0);
>> + k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL,
>> + 0x0,
>> + K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD,
>> + K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD);
>> +
>> + ret = wait_for_bit_32((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL,
>> + K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD,
>> + true, 5000, false);
>> + if (ret)
>> + panic("Failed waiting for latching of retention %d\n", ret);
>> +
>> + k3_ddrss_reg_update_bits((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL,
>> + 0x0,
>> + K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD,
>> + 0);
>> +}
>> +
>> +static bool k3_ddrss_wkup_conf_canuart_wakeup_active(struct k3_ddrss_desc *ddrss)
>> +{
>> + u32 active;
>> +
>> + active = readl(ddrss->ddrss_ctrl_mmr + K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1);
>
> As seen in
> https://elixir.bootlin.com/u-boot/v2025.07-rc5/source/arch/arm/dts/k3-am62a-ddr.dtsi#L10
> - the address range for CTRL MMR is starting from 0x43014000 and has a
> size of 0x100 but the address we want to access is outside that range.
> (0x43018318)
> We need to increase the address range in this node in dt file as well.
Thanks for pointing this out. I am trying to push for a syscon node
upstream without success yet. The CTRL_MMR register definition is
overlapping with the wkup_conf device node in the upstream dts
k3-am62a-wakeup.dtsi, so I chose to didn't increase the size.
Best
Markus
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 289 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20250812/ad430a95/attachment.sig>
More information about the U-Boot
mailing list