[PATCH v5 03/13] ram: k3-ddrss: Add support for DDR in self-refresh
Dhruva Gole
d-gole at ti.com
Tue Nov 11 11:04:38 CET 2025
On Nov 10, 2025 at 21:10:27 +0100, Markus Schneider-Pargmann (TI.com) 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.
>
> Tested-by: Anshul Dalal <anshuld at ti.com>
> Signed-off-by: Markus Schneider-Pargmann (TI.com) <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 5144470b931384534e78fbfcea5e66b7083c9f07..5aca55129326ab4f369ae6e4f2c048df6e971eff 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)
>
> +#define K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL 0x430080d0
> +#define K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD BIT(31)
> +#define K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RETENTION_MASK GENMASK(3, 0)
> +
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1 0x4301830c
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1_CANUART_IO_MODE BIT(0)
> +
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT 0x43018318
> +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT_MW 0x555555
> +
> #define SINGLE_DDR_SUBSYSTEM 0x1
> #define MULTI_DDR_SUBSYSTEM 0x2
> #define MAX_MULTI_DDR 4
> @@ -211,6 +221,32 @@ struct reginitdata {
> #define DENALI_CTL_0_DRAM_CLASS_DDR4 0xA
> #define DENALI_CTL_0_DRAM_CLASS_LPDDR4 0xB
>
> +#define K3_DDRSS_CFG_DENALI_CTL_20 0x0050
> +#define K3_DDRSS_CFG_DENALI_CTL_20_PHY_INDEP_TRAIN_MODE BIT(24)
> +#define K3_DDRSS_CFG_DENALI_CTL_21 0x0054
> +#define K3_DDRSS_CFG_DENALI_CTL_21_PHY_INDEP_INIT_MODE BIT(8)
> +#define K3_DDRSS_CFG_DENALI_CTL_106 0x01a8
> +#define K3_DDRSS_CFG_DENALI_CTL_106_PWRUP_SREFRESH_EXIT BIT(16)
> +#define K3_DDRSS_CFG_DENALI_CTL_160 0x0280
> +#define K3_DDRSS_CFG_DENALI_CTL_160_LP_CMD_MASK GENMASK(14, 8)
> +#define K3_DDRSS_CFG_DENALI_CTL_160_LP_CMD_ENTRY BIT(9)
> +#define K3_DDRSS_CFG_DENALI_CTL_169 0x02a4
> +#define K3_DDRSS_CFG_DENALI_CTL_169_LP_AUTO_EXIT_EN_MASK GENMASK(27, 24)
> +#define K3_DDRSS_CFG_DENALI_CTL_169_LP_AUTO_ENTRY_EN_MASK GENMASK(19, 16)
> +#define K3_DDRSS_CFG_DENALI_CTL_169_LP_STATE_MASK GENMASK(14, 8)
> +#define K3_DDRSS_CFG_DENALI_CTL_169_LP_STATE_SHIFT 8
> +#define K3_DDRSS_CFG_DENALI_CTL_345 0x0564
> +#define K3_DDRSS_CFG_DENALI_CTL_345_INT_STATUS_LOWPOWER_SHIFT 16
> +#define K3_DDRSS_CFG_DENALI_CTL_353 0x0584
> +#define K3_DDRSS_CFG_DENALI_CTL_353_INT_ACK_LOWPOWER_SHIFT 16
> +#define K3_DDRSS_CFG_DENALI_PI_6 0x2018
> +#define K3_DDRSS_CFG_DENALI_PI_6_PI_DFI_PHYMSTR_STATE_SEL_R BIT(8)
> +#define K3_DDRSS_CFG_DENALI_PI_146 0x2248
> +#define K3_DDRSS_CFG_DENALI_PI_150 0x2258
> +#define K3_DDRSS_CFG_DENALI_PI_150_PI_DRAM_INIT_EN BIT(8)
> +#define K3_DDRSS_CFG_DENALI_PHY_1820 0x5C70
> +#define K3_DDRSS_CFG_DENALI_PHY_1820_SET_DFI_INPUT_2_SHIFT 16
> +
> #define TH_OFFSET_FROM_REG(REG, SHIFT, offset) do {\
> char *i, *pstr = xstr(REG); offset = 0;\
> for (i = &pstr[SHIFT]; *i != '\0'; ++i) {\
> @@ -864,6 +900,132 @@ static void k3_ddrss_lpddr4_ecc_init(struct k3_ddrss_desc *ddrss)
> writel(val, base + DDRSS_ECC_CTRL_REG);
> }
>
> +static void k3_ddrss_reg_update_bits(void __iomem *addr, u32 offset, u32 mask, u32 set)
> +{
> + u32 val = readl(addr + offset);
> +
> + val &= ~mask;
> + val |= set;
> + writel(val, addr + offset);
> +}
> +
> +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);
> + 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);
Magic number 5000... It can be #defined out as a TIMEOUT
> + 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;
> + }
> +}
> +
> +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);
Magic num, same comment as above
Reviewed-by: Dhruva Gole <d-gole at ti.com>
--
Best regards,
Dhruva Gole
Texas Instruments Incorporated
More information about the U-Boot
mailing list