1478af8d3SJacky Bai /* 2478af8d3SJacky Bai * Copyright 2021-2024 NXP 3478af8d3SJacky Bai * 4478af8d3SJacky Bai * SPDX-License-Identifier: BSD-3-Clause 5478af8d3SJacky Bai */ 6478af8d3SJacky Bai 7478af8d3SJacky Bai #include <assert.h> 8478af8d3SJacky Bai #include <stdbool.h> 9478af8d3SJacky Bai 10caee2733SJacky Bai #include <arch_helpers.h> 11caee2733SJacky Bai #include <bl31/interrupt_mgmt.h> 12caee2733SJacky Bai #include <common/runtime_svc.h> 13478af8d3SJacky Bai #include <lib/mmio.h> 14caee2733SJacky Bai #include <lib/spinlock.h> 15caee2733SJacky Bai #include <plat/common/platform.h> 16caee2733SJacky Bai 17478af8d3SJacky Bai #include <platform_def.h> 18478af8d3SJacky Bai 19caee2733SJacky Bai #include <dram.h> 20478af8d3SJacky Bai #include <upower_api.h> 21478af8d3SJacky Bai 22478af8d3SJacky Bai #define PHY_FREQ_SEL_INDEX(x) ((x) << 16) 23478af8d3SJacky Bai #define PHY_FREQ_MULTICAST_EN(x) ((x) << 8) 24478af8d3SJacky Bai #define DENALI_PHY_1537 U(0x5804) 25478af8d3SJacky Bai 26478af8d3SJacky Bai #define IMX_DDRC_BASE U(0x2E060000) 27478af8d3SJacky Bai #define SAVED_DRAM_DATA_BASE U(0x20055000) 28*ee25e6a5SAdrian Alonso #define IMX_DRAM_BASE U(0x80000000) 29*ee25e6a5SAdrian Alonso #define DENALI_CTL_143 U(0x23C) 30*ee25e6a5SAdrian Alonso #define DENALI_CTL_144 U(0x240) 31*ee25e6a5SAdrian Alonso #define DENALI_CTL_146 U(0x248) 32*ee25e6a5SAdrian Alonso #define LP_STATE_CS_IDLE U(0x404000) 33*ee25e6a5SAdrian Alonso #define LP_STATE_CS_PD_CG U(0x4F4F00) 34478af8d3SJacky Bai #define LPI_WAKEUP_EN_SHIFT U(8) 35478af8d3SJacky Bai #define IMX_LPAV_SIM_BASE 0x2DA50000 36478af8d3SJacky Bai #define LPDDR_CTRL 0x14 37478af8d3SJacky Bai #define LPDDR_AUTO_LP_MODE_DISABLE BIT(24) 38478af8d3SJacky Bai #define SOC_LP_CMD_SHIFT U(15) 39478af8d3SJacky Bai #define LPDDR_CTRL2 0x18 40*ee25e6a5SAdrian Alonso #define LPDDR_EN_CLKGATE (0x1<<17) 41*ee25e6a5SAdrian Alonso #define LPDDR_MAX_CLKDIV_EN (0x1 << 16) 42*ee25e6a5SAdrian Alonso #define LP_AUTO_ENTRY_EN 0x4 43*ee25e6a5SAdrian Alonso #define LP_AUTO_EXIT_EN 0xF 44478af8d3SJacky Bai 45478af8d3SJacky Bai #define DENALI_CTL_00 U(0x0) 46478af8d3SJacky Bai #define DENALI_CTL_23 U(0x5c) 47478af8d3SJacky Bai #define DFIBUS_FREQ_INIT_SHIFT U(24) 48478af8d3SJacky Bai #define TSREF2PHYMSTR_SHIFT U(8) 49478af8d3SJacky Bai #define TSREF2PHYMSTR_MASK GENMASK(13, 8) 50478af8d3SJacky Bai 51478af8d3SJacky Bai #define DENALI_CTL_24 U(0x60) 52478af8d3SJacky Bai #define DENALI_CTL_25 U(0x64) 53478af8d3SJacky Bai 54478af8d3SJacky Bai #define DENALI_CTL_93 U(0x174) 55478af8d3SJacky Bai #define PWRUP_SREFRESH_EXIT BIT(0) 56478af8d3SJacky Bai 57478af8d3SJacky Bai #define DENALI_CTL_127 U(0x1fc) 58478af8d3SJacky Bai #define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE BIT(16) 59478af8d3SJacky Bai 60478af8d3SJacky Bai #define DENALI_CTL_147 U(0x24c) 61478af8d3SJacky Bai #define DENALI_CTL_153 U(0x264) 62478af8d3SJacky Bai #define PCPCS_PD_EN BIT(8) 63478af8d3SJacky Bai 64478af8d3SJacky Bai #define DENALI_CTL_249 U(0x3E4) 65478af8d3SJacky Bai #define DENALI_CTL_266 U(0x428) 66478af8d3SJacky Bai 67478af8d3SJacky Bai #define DENALI_PHY_1547 U(0x582c) 68478af8d3SJacky Bai #define PHY_LP4_BOOT_DISABLE BIT(8) 69478af8d3SJacky Bai 70478af8d3SJacky Bai #define DENALI_PHY_1559 U(0x585c) 71478af8d3SJacky Bai #define DENALI_PHY_1590 U(0x58D8) 72478af8d3SJacky Bai 73478af8d3SJacky Bai #define DENALI_PI_00 U(0x2000) 74478af8d3SJacky Bai #define DENALI_PI_04 U(0x2010) 75478af8d3SJacky Bai #define DENALI_PI_52 U(0x20D0) 76478af8d3SJacky Bai #define DENALI_PI_26 U(0x2068) 77478af8d3SJacky Bai #define DENALI_PI_33 U(0x2084) 78478af8d3SJacky Bai #define DENALI_PI_65 U(0x2104) 79478af8d3SJacky Bai #define DENALI_PI_77 U(0x2134) 80478af8d3SJacky Bai #define DENALI_PI_134 U(0x2218) 81478af8d3SJacky Bai #define DENALI_PI_131 U(0x220C) 82478af8d3SJacky Bai #define DENALI_PI_132 U(0x2210) 83478af8d3SJacky Bai #define DENALI_PI_134 U(0x2218) 84478af8d3SJacky Bai #define DENALI_PI_137 U(0x2224) 85478af8d3SJacky Bai #define DENALI_PI_174 U(0x22B8) 86478af8d3SJacky Bai #define DENALI_PI_175 U(0x22BC) 87478af8d3SJacky Bai #define DENALI_PI_181 U(0x22D4) 88478af8d3SJacky Bai #define DENALI_PI_182 U(0x22D8) 89478af8d3SJacky Bai #define DENALI_PI_191 U(0x22FC) 90478af8d3SJacky Bai #define DENALI_PI_192 U(0x2300) 91478af8d3SJacky Bai #define DENALI_PI_212 U(0x2350) 92478af8d3SJacky Bai #define DENALI_PI_214 U(0x2358) 93478af8d3SJacky Bai #define DENALI_PI_217 U(0x2364) 94478af8d3SJacky Bai 95478af8d3SJacky Bai #define LPDDR3_TYPE U(0x7) 96478af8d3SJacky Bai #define LPDDR4_TYPE U(0xB) 97478af8d3SJacky Bai 98478af8d3SJacky Bai extern void upower_wait_resp(void); 99478af8d3SJacky Bai 100478af8d3SJacky Bai struct dram_cfg_param { 101478af8d3SJacky Bai uint32_t reg; 102478af8d3SJacky Bai uint32_t val; 103478af8d3SJacky Bai }; 104478af8d3SJacky Bai 105478af8d3SJacky Bai struct dram_timing_info { 106478af8d3SJacky Bai /* ddr controller config */ 107478af8d3SJacky Bai struct dram_cfg_param *ctl_cfg; 108478af8d3SJacky Bai unsigned int ctl_cfg_num; 109478af8d3SJacky Bai /* pi config */ 110478af8d3SJacky Bai struct dram_cfg_param *pi_cfg; 111478af8d3SJacky Bai unsigned int pi_cfg_num; 112478af8d3SJacky Bai /* phy freq1 config */ 113478af8d3SJacky Bai struct dram_cfg_param *phy_f1_cfg; 114478af8d3SJacky Bai unsigned int phy_f1_cfg_num; 115478af8d3SJacky Bai /* phy freq2 config */ 116478af8d3SJacky Bai struct dram_cfg_param *phy_f2_cfg; 117478af8d3SJacky Bai unsigned int phy_f2_cfg_num; 118*ee25e6a5SAdrian Alonso /* automatic low power config */ 119*ee25e6a5SAdrian Alonso struct dram_cfg_param *auto_lp_cfg; 120*ee25e6a5SAdrian Alonso unsigned int auto_lp_cfg_num; 121478af8d3SJacky Bai /* initialized drate table */ 122478af8d3SJacky Bai unsigned int fsp_table[3]; 123478af8d3SJacky Bai }; 124478af8d3SJacky Bai 125478af8d3SJacky Bai #define CTL_NUM U(680) 126478af8d3SJacky Bai #define PI_NUM U(298) 127478af8d3SJacky Bai #define PHY_NUM U(1654) 128478af8d3SJacky Bai #define PHY_DIFF_NUM U(49) 129*ee25e6a5SAdrian Alonso #define AUTO_LP_NUM U(3) 130478af8d3SJacky Bai struct dram_cfg { 131478af8d3SJacky Bai uint32_t ctl_cfg[CTL_NUM]; 132478af8d3SJacky Bai uint32_t pi_cfg[PI_NUM]; 133478af8d3SJacky Bai uint32_t phy_full[PHY_NUM]; 134478af8d3SJacky Bai uint32_t phy_diff[PHY_DIFF_NUM]; 135*ee25e6a5SAdrian Alonso uint32_t auto_lp_cfg[AUTO_LP_NUM]; 136478af8d3SJacky Bai }; 137478af8d3SJacky Bai 138478af8d3SJacky Bai struct dram_timing_info *info; 139478af8d3SJacky Bai struct dram_cfg *dram_timing_cfg; 140478af8d3SJacky Bai 141478af8d3SJacky Bai /* mark if dram cfg is already saved */ 142478af8d3SJacky Bai static bool dram_cfg_saved; 143*ee25e6a5SAdrian Alonso static bool dram_auto_lp_true; 144*ee25e6a5SAdrian Alonso static uint32_t dram_class, dram_ctl_143; 145478af8d3SJacky Bai 146478af8d3SJacky Bai /* PHY register index for frequency diff */ 147478af8d3SJacky Bai uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = { 148478af8d3SJacky Bai 90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114, 149478af8d3SJacky Bai 346, 348, 349, 352, 353, 356, 357, 358, 359, 360, 150478af8d3SJacky Bai 370, 602, 604, 605, 608, 609, 612, 613, 614, 615, 151478af8d3SJacky Bai 616, 626, 858, 860, 861, 864, 865, 868, 869, 870, 152478af8d3SJacky Bai 871, 872, 882, 1063, 1319, 1566, 1624, 1625 153478af8d3SJacky Bai }; 154478af8d3SJacky Bai 155caee2733SJacky Bai /* lock used for DDR DVFS */ 156caee2733SJacky Bai spinlock_t dfs_lock; 157caee2733SJacky Bai static volatile uint32_t core_count; 158caee2733SJacky Bai static volatile bool in_progress; 159416c4433SJacky Bai static volatile bool sys_dvfs; 160caee2733SJacky Bai static int num_fsp; 161caee2733SJacky Bai 162478af8d3SJacky Bai static void ddr_init(void) 163478af8d3SJacky Bai { 164478af8d3SJacky Bai unsigned int i; 165478af8d3SJacky Bai 166478af8d3SJacky Bai /* restore the ddr ctl config */ 167478af8d3SJacky Bai for (i = 0U; i < CTL_NUM; i++) { 168478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]); 169478af8d3SJacky Bai } 170478af8d3SJacky Bai 171478af8d3SJacky Bai /* load the PI registers */ 172478af8d3SJacky Bai for (i = 0U; i < PI_NUM; i++) { 173478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]); 174478af8d3SJacky Bai } 175478af8d3SJacky Bai 176478af8d3SJacky Bai 177478af8d3SJacky Bai /* restore all PHY registers for all the fsp. */ 178478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100); 179478af8d3SJacky Bai /* restore all the phy configs */ 180478af8d3SJacky Bai for (i = 0U; i < PHY_NUM; i++) { 181478af8d3SJacky Bai /* skip the reserved registers space */ 182478af8d3SJacky Bai if (i >= 121U && i <= 255U) { 183478af8d3SJacky Bai continue; 184478af8d3SJacky Bai } 185478af8d3SJacky Bai if (i >= 377U && i <= 511U) { 186478af8d3SJacky Bai continue; 187478af8d3SJacky Bai } 188478af8d3SJacky Bai if (i >= 633U && i <= 767U) { 189478af8d3SJacky Bai continue; 190478af8d3SJacky Bai } 191478af8d3SJacky Bai if (i >= 889U && i <= 1023U) { 192478af8d3SJacky Bai continue; 193478af8d3SJacky Bai } 194478af8d3SJacky Bai if (i >= 1065U && i <= 1279U) { 195478af8d3SJacky Bai continue; 196478af8d3SJacky Bai } 197478af8d3SJacky Bai if (i >= 1321U && i <= 1535U) { 198478af8d3SJacky Bai continue; 199478af8d3SJacky Bai } 200478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]); 201478af8d3SJacky Bai } 202478af8d3SJacky Bai 203478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 204478af8d3SJacky Bai /* restore only the diff. */ 205478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0); 206478af8d3SJacky Bai for (i = 0U; i < PHY_DIFF_NUM; i++) { 207478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4, 208478af8d3SJacky Bai dram_timing_cfg->phy_diff[i]); 209478af8d3SJacky Bai } 210478af8d3SJacky Bai } 211478af8d3SJacky Bai 212478af8d3SJacky Bai /* Re-enable MULTICAST mode */ 213478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1)); 214478af8d3SJacky Bai } 215478af8d3SJacky Bai 216*ee25e6a5SAdrian Alonso void dram_lp_auto_disable(void) 217*ee25e6a5SAdrian Alonso { 218*ee25e6a5SAdrian Alonso uint32_t lp_auto_en; 219*ee25e6a5SAdrian Alonso 220*ee25e6a5SAdrian Alonso dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE + 221*ee25e6a5SAdrian Alonso sizeof(struct dram_timing_info)); 222*ee25e6a5SAdrian Alonso lp_auto_en = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & (LP_AUTO_ENTRY_EN << 24)); 223*ee25e6a5SAdrian Alonso /* Save initial config */ 224*ee25e6a5SAdrian Alonso dram_ctl_143 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_143); 225*ee25e6a5SAdrian Alonso 226*ee25e6a5SAdrian Alonso if (lp_auto_en && !dram_auto_lp_true) { 227*ee25e6a5SAdrian Alonso /* 0.a Save DDRC auto low-power mode parameter */ 228*ee25e6a5SAdrian Alonso dram_timing_cfg->auto_lp_cfg[0] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144); 229*ee25e6a5SAdrian Alonso dram_timing_cfg->auto_lp_cfg[1] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_147); 230*ee25e6a5SAdrian Alonso dram_timing_cfg->auto_lp_cfg[2] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146); 231*ee25e6a5SAdrian Alonso /* Set LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 to Maximum */ 232*ee25e6a5SAdrian Alonso mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_143, 0xF << 24); 233*ee25e6a5SAdrian Alonso /* 0.b Disable DDRC auto low-power mode interface */ 234*ee25e6a5SAdrian Alonso mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_146, LP_AUTO_ENTRY_EN << 24); 235*ee25e6a5SAdrian Alonso /* 0.c Read any location to get DRAM out of Self-refresh */ 236*ee25e6a5SAdrian Alonso mmio_read_32(IMX_DRAM_BASE); 237*ee25e6a5SAdrian Alonso /* 0.d Confirm DRAM is out of Self-refresh */ 238*ee25e6a5SAdrian Alonso while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & 239*ee25e6a5SAdrian Alonso LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) { 240*ee25e6a5SAdrian Alonso ; 241*ee25e6a5SAdrian Alonso } 242*ee25e6a5SAdrian Alonso /* 0.e Disable DDRC auto low-power exit */ 243*ee25e6a5SAdrian Alonso mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_147, LP_AUTO_EXIT_EN); 244*ee25e6a5SAdrian Alonso /* dram low power mode flag */ 245*ee25e6a5SAdrian Alonso dram_auto_lp_true = true; 246*ee25e6a5SAdrian Alonso } 247*ee25e6a5SAdrian Alonso } 248*ee25e6a5SAdrian Alonso 249*ee25e6a5SAdrian Alonso void dram_lp_auto_enable(void) 250*ee25e6a5SAdrian Alonso { 251*ee25e6a5SAdrian Alonso /* Switch back to Auto Low-power mode */ 252*ee25e6a5SAdrian Alonso if (dram_auto_lp_true) { 253*ee25e6a5SAdrian Alonso /* 12.a Confirm DRAM is out of Self-refresh */ 254*ee25e6a5SAdrian Alonso while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & 255*ee25e6a5SAdrian Alonso LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) { 256*ee25e6a5SAdrian Alonso ; 257*ee25e6a5SAdrian Alonso } 258*ee25e6a5SAdrian Alonso /* 12.b Enable DDRC auto low-power exit */ 259*ee25e6a5SAdrian Alonso /* 260*ee25e6a5SAdrian Alonso * 12.c TBC! : Set DENALI_CTL_144 [LPI_CTRL_REQ_EN[24]] and 261*ee25e6a5SAdrian Alonso * [DFI_LP_VERSION[16]] back to default settings = 1b'1. 262*ee25e6a5SAdrian Alonso */ 263*ee25e6a5SAdrian Alonso /* 264*ee25e6a5SAdrian Alonso * 12.d Reconfigure DENALI_CTL_144 [LPI_WAKEUP_EN[5:0]] bit 265*ee25e6a5SAdrian Alonso * LPI_WAKEUP_EN[3] = 1b'1. 266*ee25e6a5SAdrian Alonso */ 267*ee25e6a5SAdrian Alonso mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, dram_timing_cfg->auto_lp_cfg[0]); 268*ee25e6a5SAdrian Alonso mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_147, dram_timing_cfg->auto_lp_cfg[1]); 269*ee25e6a5SAdrian Alonso /* 12.e Re-enable DDRC auto low-power mode interface */ 270*ee25e6a5SAdrian Alonso mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_146, dram_timing_cfg->auto_lp_cfg[2]); 271*ee25e6a5SAdrian Alonso /* restore ctl config */ 272*ee25e6a5SAdrian Alonso mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_143, dram_ctl_143); 273*ee25e6a5SAdrian Alonso /* dram low power mode flag */ 274*ee25e6a5SAdrian Alonso dram_auto_lp_true = false; 275*ee25e6a5SAdrian Alonso } 276*ee25e6a5SAdrian Alonso } 277*ee25e6a5SAdrian Alonso 278*ee25e6a5SAdrian Alonso void dram_enter_self_refresh(void) 279*ee25e6a5SAdrian Alonso { 280*ee25e6a5SAdrian Alonso /* disable auto low power interface */ 281*ee25e6a5SAdrian Alonso dram_lp_auto_disable(); 282*ee25e6a5SAdrian Alonso /* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */ 283*ee25e6a5SAdrian Alonso mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22); 284*ee25e6a5SAdrian Alonso /* 1.a Clock gate PCC_LPDDR4[CGC] and no software reset PCC_LPDDR4[SWRST] */ 285*ee25e6a5SAdrian Alonso mmio_setbits_32(IMX_PCC5_BASE + 0x108, (BIT(30) | BIT(28))); 286*ee25e6a5SAdrian Alonso 287*ee25e6a5SAdrian Alonso /* 288*ee25e6a5SAdrian Alonso * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit 289*ee25e6a5SAdrian Alonso * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh 290*ee25e6a5SAdrian Alonso * long with mem and ctlr clk gating or self-refresh power-down long 291*ee25e6a5SAdrian Alonso * with mem and ctlr clk gating' 292*ee25e6a5SAdrian Alonso */ 293*ee25e6a5SAdrian Alonso mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT); 294*ee25e6a5SAdrian Alonso /* TODO: Needed ? 2.a DENALI_CTL_144[LPI_TIMER_WAKEUP_F2] */ 295*ee25e6a5SAdrian Alonso //mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(0)); 296*ee25e6a5SAdrian Alonso 297*ee25e6a5SAdrian Alonso /* 298*ee25e6a5SAdrian Alonso * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable 299*ee25e6a5SAdrian Alonso * the logic to automatic handles low power entry/exit. This is the recommended 300*ee25e6a5SAdrian Alonso * option over handling through software. 301*ee25e6a5SAdrian Alonso * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for 302*ee25e6a5SAdrian Alonso * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory 303*ee25e6a5SAdrian Alonso * since LPPDR logic will be power gated). 304*ee25e6a5SAdrian Alonso */ 305*ee25e6a5SAdrian Alonso mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE); 306*ee25e6a5SAdrian Alonso mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, 307*ee25e6a5SAdrian Alonso 0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT); 308*ee25e6a5SAdrian Alonso /* 3.c clock gate ddr controller */ 309*ee25e6a5SAdrian Alonso mmio_setbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_EN_CLKGATE); 310*ee25e6a5SAdrian Alonso /* 3.d lpddr max clk div en */ 311*ee25e6a5SAdrian Alonso mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_MAX_CLKDIV_EN); 312*ee25e6a5SAdrian Alonso } 313*ee25e6a5SAdrian Alonso 314*ee25e6a5SAdrian Alonso void dram_exit_self_refresh(void) 315*ee25e6a5SAdrian Alonso { 316*ee25e6a5SAdrian Alonso dram_lp_auto_enable(); 317*ee25e6a5SAdrian Alonso } 318*ee25e6a5SAdrian Alonso 319478af8d3SJacky Bai void dram_enter_retention(void) 320478af8d3SJacky Bai { 321478af8d3SJacky Bai unsigned int i; 322478af8d3SJacky Bai 323*ee25e6a5SAdrian Alonso dram_lp_auto_disable(); 324*ee25e6a5SAdrian Alonso 325478af8d3SJacky Bai /* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */ 326478af8d3SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22); 327478af8d3SJacky Bai 328478af8d3SJacky Bai /* 329478af8d3SJacky Bai * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit 330478af8d3SJacky Bai * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh 331478af8d3SJacky Bai * long with mem and ctlr clk gating or self-refresh power-down 332478af8d3SJacky Bai * long with mem and ctlr clk gating' 333478af8d3SJacky Bai */ 334478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT); 335478af8d3SJacky Bai 336478af8d3SJacky Bai /* 337478af8d3SJacky Bai * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable 338478af8d3SJacky Bai * the logic to automatic handles low power entry/exit. This is the recommended 339478af8d3SJacky Bai * option over handling through software. 340478af8d3SJacky Bai * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for 341478af8d3SJacky Bai * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory 342478af8d3SJacky Bai * since LPPDR logic will be power gated). 343478af8d3SJacky Bai */ 344478af8d3SJacky Bai mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE); 345478af8d3SJacky Bai mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, 346478af8d3SJacky Bai 0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT); 347478af8d3SJacky Bai 348478af8d3SJacky Bai /* Save DDR Controller & PHY config. 349478af8d3SJacky Bai * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all 350478af8d3SJacky Bai * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between 351478af8d3SJacky Bai * F1 & F2 into phy_f2_cfg. 352478af8d3SJacky Bai */ 353478af8d3SJacky Bai if (!dram_cfg_saved) { 354478af8d3SJacky Bai info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE; 355478af8d3SJacky Bai dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE + 356478af8d3SJacky Bai sizeof(struct dram_timing_info)); 357478af8d3SJacky Bai 358478af8d3SJacky Bai /* get the dram type */ 359478af8d3SJacky Bai dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00); 360478af8d3SJacky Bai dram_class = (dram_class >> 8) & 0xf; 361478af8d3SJacky Bai 362478af8d3SJacky Bai /* save the ctl registers */ 363478af8d3SJacky Bai for (i = 0U; i < CTL_NUM; i++) { 364478af8d3SJacky Bai dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4); 365478af8d3SJacky Bai } 366478af8d3SJacky Bai dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE; 367478af8d3SJacky Bai 368478af8d3SJacky Bai /* save the PI registers */ 369478af8d3SJacky Bai for (i = 0U; i < PI_NUM; i++) { 370478af8d3SJacky Bai dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4); 371478af8d3SJacky Bai } 372478af8d3SJacky Bai dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE; 373478af8d3SJacky Bai 374478af8d3SJacky Bai /* 375478af8d3SJacky Bai * Read and store all PHY registers. full array is a full 376478af8d3SJacky Bai * copy for all the setpoint 377478af8d3SJacky Bai */ 378478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 379478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000); 380478af8d3SJacky Bai for (i = 0U; i < PHY_NUM; i++) { 381478af8d3SJacky Bai /* Make sure MULTICASE is enabled */ 382478af8d3SJacky Bai if (i == 1537U) { 383478af8d3SJacky Bai dram_timing_cfg->phy_full[i] = 0x100; 384478af8d3SJacky Bai } else { 385478af8d3SJacky Bai dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4); 386478af8d3SJacky Bai } 387478af8d3SJacky Bai } 388478af8d3SJacky Bai 389478af8d3SJacky Bai /* 390478af8d3SJacky Bai * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0. 391478af8d3SJacky Bai * Read and store only the diff. 392478af8d3SJacky Bai */ 393478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0); 394478af8d3SJacky Bai /* save only the frequency based diff config to save memory */ 395478af8d3SJacky Bai for (i = 0U; i < PHY_DIFF_NUM; i++) { 396478af8d3SJacky Bai dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + 397478af8d3SJacky Bai freq_specific_reg_array[i] * 4); 398478af8d3SJacky Bai } 399478af8d3SJacky Bai } else { 400478af8d3SJacky Bai /* LPDDR3, only f1 need to save */ 401478af8d3SJacky Bai for (i = 0U; i < info->phy_f1_cfg_num; i++) { 402478af8d3SJacky Bai info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg); 403478af8d3SJacky Bai } 404478af8d3SJacky Bai } 405478af8d3SJacky Bai 406478af8d3SJacky Bai dram_cfg_saved = true; 407478af8d3SJacky Bai } 408478af8d3SJacky Bai } 409478af8d3SJacky Bai 410478af8d3SJacky Bai void dram_exit_retention(void) 411478af8d3SJacky Bai { 412478af8d3SJacky Bai uint32_t val; 413478af8d3SJacky Bai 414478af8d3SJacky Bai /* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */ 415478af8d3SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30)); 416478af8d3SJacky Bai 417478af8d3SJacky Bai /* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */ 418478af8d3SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28)); 419478af8d3SJacky Bai 420478af8d3SJacky Bai /* 3. Reload the LPDDR CTL/PI/PHY register */ 421478af8d3SJacky Bai ddr_init(); 422478af8d3SJacky Bai 423478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 424478af8d3SJacky Bai /* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */ 425478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101); 426478af8d3SJacky Bai 427478af8d3SJacky Bai /* 428478af8d3SJacky Bai * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit 429478af8d3SJacky Bai * from controller. 430478af8d3SJacky Bai */ 431478af8d3SJacky Bai /* 432478af8d3SJacky Bai * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling 433478af8d3SJacky Bai * self refresh exit from PI 434478af8d3SJacky Bai */ 435478af8d3SJacky Bai /* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */ 436478af8d3SJacky Bai /* 437478af8d3SJacky Bai * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2= 438478af8d3SJacky Bai * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2. 439478af8d3SJacky Bai * Enable non initialization trainings. 440478af8d3SJacky Bai */ 441478af8d3SJacky Bai /* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */ 442478af8d3SJacky Bai /* 4f. PI_DLL_RESET=0x1 */ 443478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1); 444478af8d3SJacky Bai /* PI_PWRUP_SELF_REF_EXIT = 1 */ 445478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000); 446478af8d3SJacky Bai /* PI_MC_PWRUP_SELF_REF_EXIT = 0 */ 447478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16)); 448478af8d3SJacky Bai /* PI_INT_LVL_EN = 0 */ 449478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0)); 450478af8d3SJacky Bai /* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */ 451478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000); 452478af8d3SJacky Bai /* PI_WRLVL_EN_F2 = 3 */ 453478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03); 454478af8d3SJacky Bai /* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */ 455478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000); 456478af8d3SJacky Bai /* PI_CALVL_EN_F2 = 3 */ 457478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03); 458478af8d3SJacky Bai /* PI_WDQLVL_EN_F0 = 3 */ 459478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300); 460478af8d3SJacky Bai /* PI_WDQLVL_EN_F1 = 3 */ 461478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000); 462478af8d3SJacky Bai /* PI_WDQLVL_EN_F2 = 3 */ 463478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300); 464478af8d3SJacky Bai /* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */ 465478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000); 466478af8d3SJacky Bai /* 467478af8d3SJacky Bai * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3, 468478af8d3SJacky Bai * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3 469478af8d3SJacky Bai */ 470478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303); 471478af8d3SJacky Bai /* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */ 472478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000); 473478af8d3SJacky Bai } else { 474478af8d3SJacky Bai /* PI_DLL_RESET=1 */ 475478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1); 476478af8d3SJacky Bai /* PI_PWRUP_SELF_REF_EXIT=1 */ 477478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000); 478478af8d3SJacky Bai /* PI_MC_PWRUP_SELF_REF_EXIT=0 */ 479478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16)); 480478af8d3SJacky Bai /* PI_INT_LVL_EN=0 */ 481478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0)); 482478af8d3SJacky Bai /* PI_WRLVL_EN_F0=3 */ 483478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000); 484478af8d3SJacky Bai /* PI_CALVL_EN_F0=3 */ 485478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000); 486478af8d3SJacky Bai /* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */ 487478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000); 488478af8d3SJacky Bai /* PI_PWRUP_SREFRESH_EXIT_CS=0xF */ 489478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000); 490478af8d3SJacky Bai } 491478af8d3SJacky Bai 492478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00); 493478af8d3SJacky Bai 494478af8d3SJacky Bai /* Force in-order AXI read data */ 495478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1); 496478af8d3SJacky Bai 497478af8d3SJacky Bai /* 498478af8d3SJacky Bai * Disable special R/W group switches so that R/W group placement 499478af8d3SJacky Bai * is always at END of R/W group. 500478af8d3SJacky Bai */ 501478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0); 502478af8d3SJacky Bai 503478af8d3SJacky Bai /* Reduce time for IO pad calibration */ 504478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000); 505478af8d3SJacky Bai 506478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100); 507478af8d3SJacky Bai 508478af8d3SJacky Bai /* PD disable */ 509478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000); 510478af8d3SJacky Bai /* 511478af8d3SJacky Bai * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN 512478af8d3SJacky Bai * to 1b'0, PCPCS_PD_EN to 1b'0 513478af8d3SJacky Bai */ 514478af8d3SJacky Bai 515478af8d3SJacky Bai upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL); 516478af8d3SJacky Bai upower_wait_resp(); 517478af8d3SJacky Bai 518478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 519478af8d3SJacky Bai /* 7. Write PI START parameter to 1'b1 */ 520478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01); 521478af8d3SJacky Bai 522478af8d3SJacky Bai /* 8. Write CTL START parameter to 1'b1 */ 523478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01); 524478af8d3SJacky Bai } else { 525478af8d3SJacky Bai /* 7. Write PI START parameter to 1'b1 */ 526478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701); 527478af8d3SJacky Bai 528478af8d3SJacky Bai /* 8. Write CTL START parameter to 1'b1 */ 529478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701); 530478af8d3SJacky Bai } 531478af8d3SJacky Bai 532478af8d3SJacky Bai /* 9. DENALI_CTL_266: Wait for INT_STATUS_INIT=0x2 */ 533478af8d3SJacky Bai do { 534478af8d3SJacky Bai val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF; 535478af8d3SJacky Bai } while (val != 0x2); 536478af8d3SJacky Bai 537478af8d3SJacky Bai /* 538478af8d3SJacky Bai * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ, 539478af8d3SJacky Bai * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order. 540478af8d3SJacky Bai */ 541478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 542478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */ 543478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */ 544478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */ 545478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */ 546478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */ 547478af8d3SJacky Bai 548478af8d3SJacky Bai /* 11. Wait for trainings to get complete by polling PI_INT_STATUS */ 549478af8d3SJacky Bai while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) { 550478af8d3SJacky Bai ; 551478af8d3SJacky Bai } 552478af8d3SJacky Bai } else { 553478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */ 554478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */ 555478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */ 556478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */ 557478af8d3SJacky Bai while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) { 558478af8d3SJacky Bai ; 559478af8d3SJacky Bai } 560478af8d3SJacky Bai } 561*ee25e6a5SAdrian Alonso 562*ee25e6a5SAdrian Alonso dram_lp_auto_enable(); 563478af8d3SJacky Bai } 564caee2733SJacky Bai 565caee2733SJacky Bai #define LPDDR_DONE (0x1<<4) 566caee2733SJacky Bai #define SOC_FREQ_CHG_ACK (0x1<<6) 567caee2733SJacky Bai #define SOC_FREQ_CHG_REQ (0x1<<7) 568caee2733SJacky Bai #define LPI_WAKEUP_EN (0x4<<8) 569caee2733SJacky Bai #define SOC_FREQ_REQ (0x1<<11) 570caee2733SJacky Bai 571caee2733SJacky Bai static void set_cgc2_ddrclk(uint8_t src, uint8_t div) 572caee2733SJacky Bai { 573caee2733SJacky Bai 574caee2733SJacky Bai /* Wait until the reg is unlocked for writing */ 575caee2733SJacky Bai while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) 576caee2733SJacky Bai ; 577caee2733SJacky Bai 578caee2733SJacky Bai mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21)); 579caee2733SJacky Bai /* Wait for the clock switching done */ 580caee2733SJacky Bai while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27))) 581caee2733SJacky Bai ; 582caee2733SJacky Bai } 583caee2733SJacky Bai static void set_ddr_clk(uint32_t ddr_freq) 584caee2733SJacky Bai { 585caee2733SJacky Bai /* Disable DDR clock */ 586caee2733SJacky Bai mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30)); 587caee2733SJacky Bai switch (ddr_freq) { 588caee2733SJacky Bai /* boot frequency ? */ 589caee2733SJacky Bai case 48: 590caee2733SJacky Bai set_cgc2_ddrclk(2, 0); 591caee2733SJacky Bai break; 592caee2733SJacky Bai /* default bypass frequency for fsp 1 */ 593caee2733SJacky Bai case 192: 594caee2733SJacky Bai set_cgc2_ddrclk(0, 1); 595caee2733SJacky Bai break; 596caee2733SJacky Bai case 384: 597caee2733SJacky Bai set_cgc2_ddrclk(0, 0); 598caee2733SJacky Bai break; 599caee2733SJacky Bai case 264: 600caee2733SJacky Bai set_cgc2_ddrclk(4, 3); 601caee2733SJacky Bai break; 602caee2733SJacky Bai case 528: 603caee2733SJacky Bai set_cgc2_ddrclk(4, 1); 604caee2733SJacky Bai break; 605caee2733SJacky Bai default: 606caee2733SJacky Bai break; 607caee2733SJacky Bai } 608caee2733SJacky Bai /* Enable DDR clock */ 609caee2733SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30)); 610caee2733SJacky Bai 611caee2733SJacky Bai /* Wait until the reg is unlocked for writing */ 612caee2733SJacky Bai while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) { 613caee2733SJacky Bai ; 614caee2733SJacky Bai } 615caee2733SJacky Bai } 616caee2733SJacky Bai 617caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL (IMX_LPAV_SIM_BASE + 0x14) 618caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL2 (IMX_LPAV_SIM_BASE + 0x18) 619caee2733SJacky Bai #define MAX_FSP_NUM U(3) 620caee2733SJacky Bai #define DDR_DFS_GET_FSP_COUNT 0x10 621caee2733SJacky Bai #define DDR_BYPASS_DRATE U(400) 622caee2733SJacky Bai 623416c4433SJacky Bai extern int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val); 624416c4433SJacky Bai 625caee2733SJacky Bai /* Normally, we only switch frequency between 1(bypass) and 2(highest) */ 626caee2733SJacky Bai int lpddr4_dfs(uint32_t freq_index) 627caee2733SJacky Bai { 628caee2733SJacky Bai uint32_t lpddr_ctrl, lpddr_ctrl2; 629caee2733SJacky Bai uint32_t ddr_ctl_144; 630caee2733SJacky Bai 631caee2733SJacky Bai /* 632caee2733SJacky Bai * Valid index: 0 to 2 633caee2733SJacky Bai * index 0: boot frequency 634caee2733SJacky Bai * index 1: bypass frequency 635caee2733SJacky Bai * index 2: highest frequency 636caee2733SJacky Bai */ 637caee2733SJacky Bai if (freq_index > 2U) { 638caee2733SJacky Bai return -1; 639caee2733SJacky Bai } 640caee2733SJacky Bai 641416c4433SJacky Bai /* 642416c4433SJacky Bai * increase the voltage to 1.1V firstly before increase frequency 643416c4433SJacky Bai * and APD enter OD mode 644416c4433SJacky Bai */ 645416c4433SJacky Bai if (freq_index == 2U && sys_dvfs) { 646416c4433SJacky Bai upower_pmic_i2c_write(0x22, 0x28); 647416c4433SJacky Bai } 648416c4433SJacky Bai 649caee2733SJacky Bai /* Enable LPI_WAKEUP_EN */ 650caee2733SJacky Bai ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144); 651caee2733SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN); 652caee2733SJacky Bai 653caee2733SJacky Bai /* put DRAM into long self-refresh & clock gating */ 654caee2733SJacky Bai lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL); 655caee2733SJacky Bai lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9); 656caee2733SJacky Bai mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl); 657caee2733SJacky Bai 658caee2733SJacky Bai /* Gating the clock */ 659caee2733SJacky Bai lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2); 660caee2733SJacky Bai mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE); 661caee2733SJacky Bai 662caee2733SJacky Bai /* Request frequency change */ 663caee2733SJacky Bai mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ); 664caee2733SJacky Bai 665caee2733SJacky Bai do { 666caee2733SJacky Bai lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL); 667caee2733SJacky Bai if (lpddr_ctrl & SOC_FREQ_CHG_REQ) { 668caee2733SJacky Bai /* Bypass mode */ 669caee2733SJacky Bai if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) { 670caee2733SJacky Bai /* Change to PLL bypass mode */ 671caee2733SJacky Bai mmio_write_32(IMX_LPAV_SIM_BASE, 0x1); 672caee2733SJacky Bai /* change the ddr clock source & frequency */ 673caee2733SJacky Bai set_ddr_clk(info->fsp_table[freq_index]); 674caee2733SJacky Bai } else { 675caee2733SJacky Bai /* Change to PLL unbypass mode */ 676caee2733SJacky Bai mmio_write_32(IMX_LPAV_SIM_BASE, 0x0); 677caee2733SJacky Bai /* change the ddr clock source & frequency */ 678caee2733SJacky Bai set_ddr_clk(info->fsp_table[freq_index] >> 1); 679caee2733SJacky Bai } 680caee2733SJacky Bai 681caee2733SJacky Bai mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK); 682caee2733SJacky Bai continue; 683caee2733SJacky Bai } 684caee2733SJacky Bai } while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */ 685caee2733SJacky Bai 686caee2733SJacky Bai /* restore the original setting */ 687caee2733SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144); 688caee2733SJacky Bai mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2); 689caee2733SJacky Bai 690caee2733SJacky Bai /* Check the DFS result */ 691caee2733SJacky Bai lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF; 692caee2733SJacky Bai if (lpddr_ctrl != 0U) { 693caee2733SJacky Bai /* Must be something wrong, return failure */ 694caee2733SJacky Bai return -1; 695caee2733SJacky Bai } 696caee2733SJacky Bai 697416c4433SJacky Bai /* decrease the BUCK3 voltage after frequency changed to lower 698416c4433SJacky Bai * and APD in ND_MODE 699416c4433SJacky Bai */ 700416c4433SJacky Bai if (freq_index == 1U && sys_dvfs) { 701416c4433SJacky Bai upower_pmic_i2c_write(0x22, 0x20); 702416c4433SJacky Bai } 703416c4433SJacky Bai 704caee2733SJacky Bai /* DFS done successfully */ 705caee2733SJacky Bai return 0; 706caee2733SJacky Bai } 707caee2733SJacky Bai 708caee2733SJacky Bai /* for the non-primary core, waiting for DFS done */ 709caee2733SJacky Bai static uint64_t waiting_dvfs(uint32_t id, uint32_t flags, 710caee2733SJacky Bai void *handle, void *cookie) 711caee2733SJacky Bai { 712caee2733SJacky Bai uint32_t irq; 713caee2733SJacky Bai 714caee2733SJacky Bai irq = plat_ic_acknowledge_interrupt(); 715caee2733SJacky Bai if (irq < 1022U) { 716caee2733SJacky Bai plat_ic_end_of_interrupt(irq); 717caee2733SJacky Bai } 718caee2733SJacky Bai 719caee2733SJacky Bai /* set the WFE done status */ 720caee2733SJacky Bai spin_lock(&dfs_lock); 721caee2733SJacky Bai core_count++; 722caee2733SJacky Bai dsb(); 723caee2733SJacky Bai spin_unlock(&dfs_lock); 724caee2733SJacky Bai 725caee2733SJacky Bai while (in_progress) { 726caee2733SJacky Bai wfe(); 727caee2733SJacky Bai } 728caee2733SJacky Bai 729caee2733SJacky Bai return 0; 730caee2733SJacky Bai } 731caee2733SJacky Bai 732caee2733SJacky Bai int dram_dvfs_handler(uint32_t smc_fid, void *handle, 733caee2733SJacky Bai u_register_t x1, u_register_t x2, u_register_t x3) 734caee2733SJacky Bai { 735caee2733SJacky Bai unsigned int fsp_index = x1; 736caee2733SJacky Bai uint32_t online_cpus = x2 - 1; 737caee2733SJacky Bai uint64_t mpidr = read_mpidr_el1(); 738caee2733SJacky Bai unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 739caee2733SJacky Bai 740caee2733SJacky Bai /* Get the number of FSPs */ 741caee2733SJacky Bai if (x1 == DDR_DFS_GET_FSP_COUNT) { 742caee2733SJacky Bai SMC_RET2(handle, num_fsp, info->fsp_table[1]); 743caee2733SJacky Bai } 744caee2733SJacky Bai 745caee2733SJacky Bai /* start lpddr frequency scaling */ 746caee2733SJacky Bai in_progress = true; 747416c4433SJacky Bai sys_dvfs = x3 ? true : false; 748caee2733SJacky Bai dsb(); 749caee2733SJacky Bai 750caee2733SJacky Bai /* notify other core wait for scaling done */ 751caee2733SJacky Bai for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) 752caee2733SJacky Bai /* Skip raise SGI for current CPU */ 753caee2733SJacky Bai if (i != cpu_id) { 754caee2733SJacky Bai plat_ic_raise_el3_sgi(0x8, i); 755caee2733SJacky Bai } 756caee2733SJacky Bai 757caee2733SJacky Bai /* Make sure all the cpu in WFE */ 758caee2733SJacky Bai while (online_cpus != core_count) { 759caee2733SJacky Bai ; 760caee2733SJacky Bai } 761caee2733SJacky Bai 762caee2733SJacky Bai /* Flush the L1/L2 cache */ 763caee2733SJacky Bai dcsw_op_all(DCCSW); 764caee2733SJacky Bai 765caee2733SJacky Bai lpddr4_dfs(fsp_index); 766caee2733SJacky Bai 767caee2733SJacky Bai in_progress = false; 768caee2733SJacky Bai core_count = 0; 769caee2733SJacky Bai dsb(); 770caee2733SJacky Bai sev(); 771caee2733SJacky Bai isb(); 772caee2733SJacky Bai 773caee2733SJacky Bai SMC_RET1(handle, 0); 774caee2733SJacky Bai } 775caee2733SJacky Bai 776caee2733SJacky Bai void dram_init(void) 777caee2733SJacky Bai { 778caee2733SJacky Bai uint32_t flags = 0; 779caee2733SJacky Bai uint32_t rc; 780caee2733SJacky Bai unsigned int i; 781caee2733SJacky Bai 782caee2733SJacky Bai /* Register the EL3 handler for DDR DVFS */ 783caee2733SJacky Bai set_interrupt_rm_flag(flags, NON_SECURE); 784caee2733SJacky Bai rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags); 785caee2733SJacky Bai if (rc) { 786caee2733SJacky Bai panic(); 787caee2733SJacky Bai } 788caee2733SJacky Bai 789caee2733SJacky Bai info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE; 790caee2733SJacky Bai 791caee2733SJacky Bai /* Get the num of the supported Fsp */ 792caee2733SJacky Bai for (i = 0; i < MAX_FSP_NUM; i++) { 793caee2733SJacky Bai if (!info->fsp_table[i]) { 794caee2733SJacky Bai break; 795caee2733SJacky Bai } 796caee2733SJacky Bai } 797caee2733SJacky Bai 798caee2733SJacky Bai num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i; 799caee2733SJacky Bai } 800