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 <m...@baylibre.com> --- drivers/ram/k3-ddrss/k3-ddrss.c | 165 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c index ff87faf6a22419e54d3639817ad2b884a97a3911..d7ae6e9ef24d5aebdb61656e6ca797b1799ca0f6 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 0x430c +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1_CANUART_IO_MODE BIT(0) + +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT 0x4318 +#define K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT_MW 0x555555 + #define SINGLE_DDR_SUBSYSTEM 0x1 #define MULTI_DDR_SUBSYSTEM 0x2 @@ -189,6 +199,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) {\ @@ -775,10 +811,125 @@ 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) +{ + 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); + while (!(readl(ddrss->ddrss_ctl_cfg + K3_DDRSS_CFG_DENALI_CTL_345) & + (1 << K3_DDRSS_CFG_DENALI_CTL_345_INT_STATUS_LOWPOWER_SHIFT))) + ; + + 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); + while ((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) + ; +} + +static void k3_ddrss_deassert_retention(struct k3_ddrss_desc *ddrss) +{ + 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); + + while (true) { + u32 val; + + val = readl((void *)K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL); + if (val & K3_WKUP_CTRL_MMR0_DDR16SS_PMCTRL_DATA_RET_LD) + break; + } + + 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); + + return !!(active & K3_WKUP_CTRL_MMR_CANUART_WAKE_STAT1_CANUART_IO_MODE); +} + +static bool k3_ddrss_wkup_conf_canuart_magic_word_set(struct k3_ddrss_desc *ddrss) +{ + u32 magic_word; + + magic_word = readl(ddrss->ddrss_ctrl_mmr + K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT); + + return magic_word == K3_WKUP_CTRL_MMR_CANUART_WAKE_OFF_MODE_STAT_MW; +} + +static bool k3_ddrss_wkup_conf_boot_is_resume(struct k3_ddrss_desc *ddrss) +{ + return IS_ENABLED(CONFIG_K3_IODDR) && + k3_ddrss_wkup_conf_canuart_wakeup_active(ddrss) && + k3_ddrss_wkup_conf_canuart_magic_word_set(ddrss); +} + static int k3_ddrss_probe(struct udevice *dev) { int ret; struct k3_ddrss_desc *ddrss = dev_get_priv(dev); + bool is_lpm_resume; debug("%s(dev=%p)\n", __func__, dev); @@ -786,6 +937,11 @@ static int k3_ddrss_probe(struct udevice *dev) if (ret) return ret; + is_lpm_resume = k3_ddrss_wkup_conf_boot_is_resume(ddrss); + + if (is_lpm_resume) + dev_info(dev, "Detected IO+DDR resume\n"); + ddrss->dev = dev; ret = k3_ddrss_power_on(ddrss); if (ret) @@ -801,12 +957,21 @@ static int k3_ddrss_probe(struct udevice *dev) k3_lpddr4_init(ddrss); k3_lpddr4_hardware_reg_init(ddrss); + if (is_lpm_resume) + k3_ddrss_self_refresh_exit(ddrss); + ret = k3_ddrss_init_freq(ddrss); if (ret) return ret; + if (is_lpm_resume) + k3_ddrss_deassert_retention(ddrss); + k3_lpddr4_start(ddrss); + if (is_lpm_resume) + k3_ddrss_lpm_resume(ddrss); + if (IS_ENABLED(CONFIG_K3_INLINE_ECC)) { if (!ddrss->ddrss_ss_cfg) { printf("%s: ss_cfg is required if ecc is enabled but not provided.", -- 2.47.2