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 10*caee2733SJacky Bai #include <arch_helpers.h> 11*caee2733SJacky Bai #include <bl31/interrupt_mgmt.h> 12*caee2733SJacky Bai #include <common/runtime_svc.h> 13478af8d3SJacky Bai #include <lib/mmio.h> 14*caee2733SJacky Bai #include <lib/spinlock.h> 15*caee2733SJacky Bai #include <plat/common/platform.h> 16*caee2733SJacky Bai 17478af8d3SJacky Bai #include <platform_def.h> 18478af8d3SJacky Bai 19*caee2733SJacky 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) 28478af8d3SJacky Bai #define DENALI_CTL_144 0x240 29478af8d3SJacky Bai #define LPI_WAKEUP_EN_SHIFT U(8) 30478af8d3SJacky Bai #define IMX_LPAV_SIM_BASE 0x2DA50000 31478af8d3SJacky Bai #define LPDDR_CTRL 0x14 32478af8d3SJacky Bai #define LPDDR_AUTO_LP_MODE_DISABLE BIT(24) 33478af8d3SJacky Bai #define SOC_LP_CMD_SHIFT U(15) 34478af8d3SJacky Bai #define LPDDR_CTRL2 0x18 35478af8d3SJacky Bai 36478af8d3SJacky Bai #define DENALI_CTL_00 U(0x0) 37478af8d3SJacky Bai #define DENALI_CTL_23 U(0x5c) 38478af8d3SJacky Bai #define DFIBUS_FREQ_INIT_SHIFT U(24) 39478af8d3SJacky Bai #define TSREF2PHYMSTR_SHIFT U(8) 40478af8d3SJacky Bai #define TSREF2PHYMSTR_MASK GENMASK(13, 8) 41478af8d3SJacky Bai 42478af8d3SJacky Bai #define DENALI_CTL_24 U(0x60) 43478af8d3SJacky Bai #define DENALI_CTL_25 U(0x64) 44478af8d3SJacky Bai 45478af8d3SJacky Bai #define DENALI_CTL_93 U(0x174) 46478af8d3SJacky Bai #define PWRUP_SREFRESH_EXIT BIT(0) 47478af8d3SJacky Bai 48478af8d3SJacky Bai #define DENALI_CTL_127 U(0x1fc) 49478af8d3SJacky Bai #define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE BIT(16) 50478af8d3SJacky Bai 51478af8d3SJacky Bai #define DENALI_CTL_147 U(0x24c) 52478af8d3SJacky Bai #define DENALI_CTL_153 U(0x264) 53478af8d3SJacky Bai #define PCPCS_PD_EN BIT(8) 54478af8d3SJacky Bai 55478af8d3SJacky Bai #define DENALI_CTL_249 U(0x3E4) 56478af8d3SJacky Bai #define DENALI_CTL_266 U(0x428) 57478af8d3SJacky Bai 58478af8d3SJacky Bai #define DENALI_PHY_1547 U(0x582c) 59478af8d3SJacky Bai #define PHY_LP4_BOOT_DISABLE BIT(8) 60478af8d3SJacky Bai 61478af8d3SJacky Bai #define DENALI_PHY_1559 U(0x585c) 62478af8d3SJacky Bai #define DENALI_PHY_1590 U(0x58D8) 63478af8d3SJacky Bai 64478af8d3SJacky Bai #define DENALI_PI_00 U(0x2000) 65478af8d3SJacky Bai #define DENALI_PI_04 U(0x2010) 66478af8d3SJacky Bai #define DENALI_PI_52 U(0x20D0) 67478af8d3SJacky Bai #define DENALI_PI_26 U(0x2068) 68478af8d3SJacky Bai #define DENALI_PI_33 U(0x2084) 69478af8d3SJacky Bai #define DENALI_PI_65 U(0x2104) 70478af8d3SJacky Bai #define DENALI_PI_77 U(0x2134) 71478af8d3SJacky Bai #define DENALI_PI_134 U(0x2218) 72478af8d3SJacky Bai #define DENALI_PI_131 U(0x220C) 73478af8d3SJacky Bai #define DENALI_PI_132 U(0x2210) 74478af8d3SJacky Bai #define DENALI_PI_134 U(0x2218) 75478af8d3SJacky Bai #define DENALI_PI_137 U(0x2224) 76478af8d3SJacky Bai #define DENALI_PI_174 U(0x22B8) 77478af8d3SJacky Bai #define DENALI_PI_175 U(0x22BC) 78478af8d3SJacky Bai #define DENALI_PI_181 U(0x22D4) 79478af8d3SJacky Bai #define DENALI_PI_182 U(0x22D8) 80478af8d3SJacky Bai #define DENALI_PI_191 U(0x22FC) 81478af8d3SJacky Bai #define DENALI_PI_192 U(0x2300) 82478af8d3SJacky Bai #define DENALI_PI_212 U(0x2350) 83478af8d3SJacky Bai #define DENALI_PI_214 U(0x2358) 84478af8d3SJacky Bai #define DENALI_PI_217 U(0x2364) 85478af8d3SJacky Bai 86478af8d3SJacky Bai #define LPDDR3_TYPE U(0x7) 87478af8d3SJacky Bai #define LPDDR4_TYPE U(0xB) 88478af8d3SJacky Bai 89478af8d3SJacky Bai extern void upower_wait_resp(void); 90478af8d3SJacky Bai 91478af8d3SJacky Bai struct dram_cfg_param { 92478af8d3SJacky Bai uint32_t reg; 93478af8d3SJacky Bai uint32_t val; 94478af8d3SJacky Bai }; 95478af8d3SJacky Bai 96478af8d3SJacky Bai struct dram_timing_info { 97478af8d3SJacky Bai /* ddr controller config */ 98478af8d3SJacky Bai struct dram_cfg_param *ctl_cfg; 99478af8d3SJacky Bai unsigned int ctl_cfg_num; 100478af8d3SJacky Bai /* pi config */ 101478af8d3SJacky Bai struct dram_cfg_param *pi_cfg; 102478af8d3SJacky Bai unsigned int pi_cfg_num; 103478af8d3SJacky Bai /* phy freq1 config */ 104478af8d3SJacky Bai struct dram_cfg_param *phy_f1_cfg; 105478af8d3SJacky Bai unsigned int phy_f1_cfg_num; 106478af8d3SJacky Bai /* phy freq2 config */ 107478af8d3SJacky Bai struct dram_cfg_param *phy_f2_cfg; 108478af8d3SJacky Bai unsigned int phy_f2_cfg_num; 109478af8d3SJacky Bai /* initialized drate table */ 110478af8d3SJacky Bai unsigned int fsp_table[3]; 111478af8d3SJacky Bai }; 112478af8d3SJacky Bai 113478af8d3SJacky Bai #define CTL_NUM U(680) 114478af8d3SJacky Bai #define PI_NUM U(298) 115478af8d3SJacky Bai #define PHY_NUM U(1654) 116478af8d3SJacky Bai #define PHY_DIFF_NUM U(49) 117478af8d3SJacky Bai struct dram_cfg { 118478af8d3SJacky Bai uint32_t ctl_cfg[CTL_NUM]; 119478af8d3SJacky Bai uint32_t pi_cfg[PI_NUM]; 120478af8d3SJacky Bai uint32_t phy_full[PHY_NUM]; 121478af8d3SJacky Bai uint32_t phy_diff[PHY_DIFF_NUM]; 122478af8d3SJacky Bai }; 123478af8d3SJacky Bai 124478af8d3SJacky Bai struct dram_timing_info *info; 125478af8d3SJacky Bai struct dram_cfg *dram_timing_cfg; 126478af8d3SJacky Bai 127478af8d3SJacky Bai /* mark if dram cfg is already saved */ 128478af8d3SJacky Bai static bool dram_cfg_saved; 129478af8d3SJacky Bai static uint32_t dram_class; 130478af8d3SJacky Bai 131478af8d3SJacky Bai /* PHY register index for frequency diff */ 132478af8d3SJacky Bai uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = { 133478af8d3SJacky Bai 90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114, 134478af8d3SJacky Bai 346, 348, 349, 352, 353, 356, 357, 358, 359, 360, 135478af8d3SJacky Bai 370, 602, 604, 605, 608, 609, 612, 613, 614, 615, 136478af8d3SJacky Bai 616, 626, 858, 860, 861, 864, 865, 868, 869, 870, 137478af8d3SJacky Bai 871, 872, 882, 1063, 1319, 1566, 1624, 1625 138478af8d3SJacky Bai }; 139478af8d3SJacky Bai 140*caee2733SJacky Bai /* lock used for DDR DVFS */ 141*caee2733SJacky Bai spinlock_t dfs_lock; 142*caee2733SJacky Bai static volatile uint32_t core_count; 143*caee2733SJacky Bai static volatile bool in_progress; 144*caee2733SJacky Bai static int num_fsp; 145*caee2733SJacky Bai 146478af8d3SJacky Bai static void ddr_init(void) 147478af8d3SJacky Bai { 148478af8d3SJacky Bai unsigned int i; 149478af8d3SJacky Bai 150478af8d3SJacky Bai /* restore the ddr ctl config */ 151478af8d3SJacky Bai for (i = 0U; i < CTL_NUM; i++) { 152478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]); 153478af8d3SJacky Bai } 154478af8d3SJacky Bai 155478af8d3SJacky Bai /* load the PI registers */ 156478af8d3SJacky Bai for (i = 0U; i < PI_NUM; i++) { 157478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]); 158478af8d3SJacky Bai } 159478af8d3SJacky Bai 160478af8d3SJacky Bai 161478af8d3SJacky Bai /* restore all PHY registers for all the fsp. */ 162478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100); 163478af8d3SJacky Bai /* restore all the phy configs */ 164478af8d3SJacky Bai for (i = 0U; i < PHY_NUM; i++) { 165478af8d3SJacky Bai /* skip the reserved registers space */ 166478af8d3SJacky Bai if (i >= 121U && i <= 255U) { 167478af8d3SJacky Bai continue; 168478af8d3SJacky Bai } 169478af8d3SJacky Bai if (i >= 377U && i <= 511U) { 170478af8d3SJacky Bai continue; 171478af8d3SJacky Bai } 172478af8d3SJacky Bai if (i >= 633U && i <= 767U) { 173478af8d3SJacky Bai continue; 174478af8d3SJacky Bai } 175478af8d3SJacky Bai if (i >= 889U && i <= 1023U) { 176478af8d3SJacky Bai continue; 177478af8d3SJacky Bai } 178478af8d3SJacky Bai if (i >= 1065U && i <= 1279U) { 179478af8d3SJacky Bai continue; 180478af8d3SJacky Bai } 181478af8d3SJacky Bai if (i >= 1321U && i <= 1535U) { 182478af8d3SJacky Bai continue; 183478af8d3SJacky Bai } 184478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]); 185478af8d3SJacky Bai } 186478af8d3SJacky Bai 187478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 188478af8d3SJacky Bai /* restore only the diff. */ 189478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0); 190478af8d3SJacky Bai for (i = 0U; i < PHY_DIFF_NUM; i++) { 191478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4, 192478af8d3SJacky Bai dram_timing_cfg->phy_diff[i]); 193478af8d3SJacky Bai } 194478af8d3SJacky Bai } 195478af8d3SJacky Bai 196478af8d3SJacky Bai /* Re-enable MULTICAST mode */ 197478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1)); 198478af8d3SJacky Bai } 199478af8d3SJacky Bai 200478af8d3SJacky Bai void dram_enter_retention(void) 201478af8d3SJacky Bai { 202478af8d3SJacky Bai unsigned int i; 203478af8d3SJacky Bai 204478af8d3SJacky Bai /* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */ 205478af8d3SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22); 206478af8d3SJacky Bai 207478af8d3SJacky Bai /* 208478af8d3SJacky Bai * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit 209478af8d3SJacky Bai * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh 210478af8d3SJacky Bai * long with mem and ctlr clk gating or self-refresh power-down 211478af8d3SJacky Bai * long with mem and ctlr clk gating' 212478af8d3SJacky Bai */ 213478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT); 214478af8d3SJacky Bai 215478af8d3SJacky Bai /* 216478af8d3SJacky Bai * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable 217478af8d3SJacky Bai * the logic to automatic handles low power entry/exit. This is the recommended 218478af8d3SJacky Bai * option over handling through software. 219478af8d3SJacky Bai * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for 220478af8d3SJacky Bai * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory 221478af8d3SJacky Bai * since LPPDR logic will be power gated). 222478af8d3SJacky Bai */ 223478af8d3SJacky Bai mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE); 224478af8d3SJacky Bai mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, 225478af8d3SJacky Bai 0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT); 226478af8d3SJacky Bai 227478af8d3SJacky Bai /* Save DDR Controller & PHY config. 228478af8d3SJacky Bai * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all 229478af8d3SJacky Bai * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between 230478af8d3SJacky Bai * F1 & F2 into phy_f2_cfg. 231478af8d3SJacky Bai */ 232478af8d3SJacky Bai if (!dram_cfg_saved) { 233478af8d3SJacky Bai info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE; 234478af8d3SJacky Bai dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE + 235478af8d3SJacky Bai sizeof(struct dram_timing_info)); 236478af8d3SJacky Bai 237478af8d3SJacky Bai /* get the dram type */ 238478af8d3SJacky Bai dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00); 239478af8d3SJacky Bai dram_class = (dram_class >> 8) & 0xf; 240478af8d3SJacky Bai 241478af8d3SJacky Bai /* save the ctl registers */ 242478af8d3SJacky Bai for (i = 0U; i < CTL_NUM; i++) { 243478af8d3SJacky Bai dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4); 244478af8d3SJacky Bai } 245478af8d3SJacky Bai dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE; 246478af8d3SJacky Bai 247478af8d3SJacky Bai /* save the PI registers */ 248478af8d3SJacky Bai for (i = 0U; i < PI_NUM; i++) { 249478af8d3SJacky Bai dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4); 250478af8d3SJacky Bai } 251478af8d3SJacky Bai dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE; 252478af8d3SJacky Bai 253478af8d3SJacky Bai /* 254478af8d3SJacky Bai * Read and store all PHY registers. full array is a full 255478af8d3SJacky Bai * copy for all the setpoint 256478af8d3SJacky Bai */ 257478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 258478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000); 259478af8d3SJacky Bai for (i = 0U; i < PHY_NUM; i++) { 260478af8d3SJacky Bai /* Make sure MULTICASE is enabled */ 261478af8d3SJacky Bai if (i == 1537U) { 262478af8d3SJacky Bai dram_timing_cfg->phy_full[i] = 0x100; 263478af8d3SJacky Bai } else { 264478af8d3SJacky Bai dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4); 265478af8d3SJacky Bai } 266478af8d3SJacky Bai } 267478af8d3SJacky Bai 268478af8d3SJacky Bai /* 269478af8d3SJacky Bai * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0. 270478af8d3SJacky Bai * Read and store only the diff. 271478af8d3SJacky Bai */ 272478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0); 273478af8d3SJacky Bai /* save only the frequency based diff config to save memory */ 274478af8d3SJacky Bai for (i = 0U; i < PHY_DIFF_NUM; i++) { 275478af8d3SJacky Bai dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + 276478af8d3SJacky Bai freq_specific_reg_array[i] * 4); 277478af8d3SJacky Bai } 278478af8d3SJacky Bai } else { 279478af8d3SJacky Bai /* LPDDR3, only f1 need to save */ 280478af8d3SJacky Bai for (i = 0U; i < info->phy_f1_cfg_num; i++) { 281478af8d3SJacky Bai info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg); 282478af8d3SJacky Bai } 283478af8d3SJacky Bai } 284478af8d3SJacky Bai 285478af8d3SJacky Bai dram_cfg_saved = true; 286478af8d3SJacky Bai } 287478af8d3SJacky Bai } 288478af8d3SJacky Bai 289478af8d3SJacky Bai void dram_exit_retention(void) 290478af8d3SJacky Bai { 291478af8d3SJacky Bai uint32_t val; 292478af8d3SJacky Bai 293478af8d3SJacky Bai /* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */ 294478af8d3SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30)); 295478af8d3SJacky Bai 296478af8d3SJacky Bai /* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */ 297478af8d3SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28)); 298478af8d3SJacky Bai 299478af8d3SJacky Bai /* 3. Reload the LPDDR CTL/PI/PHY register */ 300478af8d3SJacky Bai ddr_init(); 301478af8d3SJacky Bai 302478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 303478af8d3SJacky Bai /* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */ 304478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101); 305478af8d3SJacky Bai 306478af8d3SJacky Bai /* 307478af8d3SJacky Bai * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit 308478af8d3SJacky Bai * from controller. 309478af8d3SJacky Bai */ 310478af8d3SJacky Bai /* 311478af8d3SJacky Bai * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling 312478af8d3SJacky Bai * self refresh exit from PI 313478af8d3SJacky Bai */ 314478af8d3SJacky Bai /* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */ 315478af8d3SJacky Bai /* 316478af8d3SJacky Bai * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2= 317478af8d3SJacky Bai * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2. 318478af8d3SJacky Bai * Enable non initialization trainings. 319478af8d3SJacky Bai */ 320478af8d3SJacky Bai /* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */ 321478af8d3SJacky Bai /* 4f. PI_DLL_RESET=0x1 */ 322478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1); 323478af8d3SJacky Bai /* PI_PWRUP_SELF_REF_EXIT = 1 */ 324478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000); 325478af8d3SJacky Bai /* PI_MC_PWRUP_SELF_REF_EXIT = 0 */ 326478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16)); 327478af8d3SJacky Bai /* PI_INT_LVL_EN = 0 */ 328478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0)); 329478af8d3SJacky Bai /* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */ 330478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000); 331478af8d3SJacky Bai /* PI_WRLVL_EN_F2 = 3 */ 332478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03); 333478af8d3SJacky Bai /* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */ 334478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000); 335478af8d3SJacky Bai /* PI_CALVL_EN_F2 = 3 */ 336478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03); 337478af8d3SJacky Bai /* PI_WDQLVL_EN_F0 = 3 */ 338478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300); 339478af8d3SJacky Bai /* PI_WDQLVL_EN_F1 = 3 */ 340478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000); 341478af8d3SJacky Bai /* PI_WDQLVL_EN_F2 = 3 */ 342478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300); 343478af8d3SJacky Bai /* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */ 344478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000); 345478af8d3SJacky Bai /* 346478af8d3SJacky Bai * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3, 347478af8d3SJacky Bai * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3 348478af8d3SJacky Bai */ 349478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303); 350478af8d3SJacky Bai /* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */ 351478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000); 352478af8d3SJacky Bai } else { 353478af8d3SJacky Bai /* PI_DLL_RESET=1 */ 354478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1); 355478af8d3SJacky Bai /* PI_PWRUP_SELF_REF_EXIT=1 */ 356478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000); 357478af8d3SJacky Bai /* PI_MC_PWRUP_SELF_REF_EXIT=0 */ 358478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16)); 359478af8d3SJacky Bai /* PI_INT_LVL_EN=0 */ 360478af8d3SJacky Bai mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0)); 361478af8d3SJacky Bai /* PI_WRLVL_EN_F0=3 */ 362478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000); 363478af8d3SJacky Bai /* PI_CALVL_EN_F0=3 */ 364478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000); 365478af8d3SJacky Bai /* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */ 366478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000); 367478af8d3SJacky Bai /* PI_PWRUP_SREFRESH_EXIT_CS=0xF */ 368478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000); 369478af8d3SJacky Bai } 370478af8d3SJacky Bai 371478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00); 372478af8d3SJacky Bai 373478af8d3SJacky Bai /* Force in-order AXI read data */ 374478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1); 375478af8d3SJacky Bai 376478af8d3SJacky Bai /* 377478af8d3SJacky Bai * Disable special R/W group switches so that R/W group placement 378478af8d3SJacky Bai * is always at END of R/W group. 379478af8d3SJacky Bai */ 380478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0); 381478af8d3SJacky Bai 382478af8d3SJacky Bai /* Reduce time for IO pad calibration */ 383478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000); 384478af8d3SJacky Bai 385478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100); 386478af8d3SJacky Bai 387478af8d3SJacky Bai /* PD disable */ 388478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000); 389478af8d3SJacky Bai /* 390478af8d3SJacky Bai * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN 391478af8d3SJacky Bai * to 1b'0, PCPCS_PD_EN to 1b'0 392478af8d3SJacky Bai */ 393478af8d3SJacky Bai 394478af8d3SJacky Bai upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL); 395478af8d3SJacky Bai upower_wait_resp(); 396478af8d3SJacky Bai 397478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 398478af8d3SJacky Bai /* 7. Write PI START parameter to 1'b1 */ 399478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01); 400478af8d3SJacky Bai 401478af8d3SJacky Bai /* 8. Write CTL START parameter to 1'b1 */ 402478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01); 403478af8d3SJacky Bai } else { 404478af8d3SJacky Bai /* 7. Write PI START parameter to 1'b1 */ 405478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701); 406478af8d3SJacky Bai 407478af8d3SJacky Bai /* 8. Write CTL START parameter to 1'b1 */ 408478af8d3SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701); 409478af8d3SJacky Bai } 410478af8d3SJacky Bai 411478af8d3SJacky Bai /* 9. DENALI_CTL_266: Wait for INT_STATUS_INIT=0x2 */ 412478af8d3SJacky Bai do { 413478af8d3SJacky Bai val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF; 414478af8d3SJacky Bai } while (val != 0x2); 415478af8d3SJacky Bai 416478af8d3SJacky Bai /* 417478af8d3SJacky Bai * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ, 418478af8d3SJacky Bai * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order. 419478af8d3SJacky Bai */ 420478af8d3SJacky Bai if (dram_class == LPDDR4_TYPE) { 421478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */ 422478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */ 423478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */ 424478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */ 425478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */ 426478af8d3SJacky Bai 427478af8d3SJacky Bai /* 11. Wait for trainings to get complete by polling PI_INT_STATUS */ 428478af8d3SJacky Bai while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) { 429478af8d3SJacky Bai ; 430478af8d3SJacky Bai } 431478af8d3SJacky Bai } else { 432478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */ 433478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */ 434478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */ 435478af8d3SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */ 436478af8d3SJacky Bai while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) { 437478af8d3SJacky Bai ; 438478af8d3SJacky Bai } 439478af8d3SJacky Bai } 440478af8d3SJacky Bai } 441*caee2733SJacky Bai 442*caee2733SJacky Bai #define LPDDR_DONE (0x1<<4) 443*caee2733SJacky Bai #define SOC_FREQ_CHG_ACK (0x1<<6) 444*caee2733SJacky Bai #define SOC_FREQ_CHG_REQ (0x1<<7) 445*caee2733SJacky Bai #define LPI_WAKEUP_EN (0x4<<8) 446*caee2733SJacky Bai #define SOC_FREQ_REQ (0x1<<11) 447*caee2733SJacky Bai 448*caee2733SJacky Bai #define LPDDR_EN_CLKGATE (0x1<<17) 449*caee2733SJacky Bai 450*caee2733SJacky Bai static void set_cgc2_ddrclk(uint8_t src, uint8_t div) 451*caee2733SJacky Bai { 452*caee2733SJacky Bai 453*caee2733SJacky Bai /* Wait until the reg is unlocked for writing */ 454*caee2733SJacky Bai while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) 455*caee2733SJacky Bai ; 456*caee2733SJacky Bai 457*caee2733SJacky Bai mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21)); 458*caee2733SJacky Bai /* Wait for the clock switching done */ 459*caee2733SJacky Bai while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27))) 460*caee2733SJacky Bai ; 461*caee2733SJacky Bai } 462*caee2733SJacky Bai static void set_ddr_clk(uint32_t ddr_freq) 463*caee2733SJacky Bai { 464*caee2733SJacky Bai /* Disable DDR clock */ 465*caee2733SJacky Bai mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30)); 466*caee2733SJacky Bai switch (ddr_freq) { 467*caee2733SJacky Bai /* boot frequency ? */ 468*caee2733SJacky Bai case 48: 469*caee2733SJacky Bai set_cgc2_ddrclk(2, 0); 470*caee2733SJacky Bai break; 471*caee2733SJacky Bai /* default bypass frequency for fsp 1 */ 472*caee2733SJacky Bai case 192: 473*caee2733SJacky Bai set_cgc2_ddrclk(0, 1); 474*caee2733SJacky Bai break; 475*caee2733SJacky Bai case 384: 476*caee2733SJacky Bai set_cgc2_ddrclk(0, 0); 477*caee2733SJacky Bai break; 478*caee2733SJacky Bai case 264: 479*caee2733SJacky Bai set_cgc2_ddrclk(4, 3); 480*caee2733SJacky Bai break; 481*caee2733SJacky Bai case 528: 482*caee2733SJacky Bai set_cgc2_ddrclk(4, 1); 483*caee2733SJacky Bai break; 484*caee2733SJacky Bai default: 485*caee2733SJacky Bai break; 486*caee2733SJacky Bai } 487*caee2733SJacky Bai /* Enable DDR clock */ 488*caee2733SJacky Bai mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30)); 489*caee2733SJacky Bai 490*caee2733SJacky Bai /* Wait until the reg is unlocked for writing */ 491*caee2733SJacky Bai while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) { 492*caee2733SJacky Bai ; 493*caee2733SJacky Bai } 494*caee2733SJacky Bai } 495*caee2733SJacky Bai 496*caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL (IMX_LPAV_SIM_BASE + 0x14) 497*caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL2 (IMX_LPAV_SIM_BASE + 0x18) 498*caee2733SJacky Bai #define MAX_FSP_NUM U(3) 499*caee2733SJacky Bai #define DDR_DFS_GET_FSP_COUNT 0x10 500*caee2733SJacky Bai #define DDR_BYPASS_DRATE U(400) 501*caee2733SJacky Bai 502*caee2733SJacky Bai /* Normally, we only switch frequency between 1(bypass) and 2(highest) */ 503*caee2733SJacky Bai int lpddr4_dfs(uint32_t freq_index) 504*caee2733SJacky Bai { 505*caee2733SJacky Bai uint32_t lpddr_ctrl, lpddr_ctrl2; 506*caee2733SJacky Bai uint32_t ddr_ctl_144; 507*caee2733SJacky Bai 508*caee2733SJacky Bai /* 509*caee2733SJacky Bai * Valid index: 0 to 2 510*caee2733SJacky Bai * index 0: boot frequency 511*caee2733SJacky Bai * index 1: bypass frequency 512*caee2733SJacky Bai * index 2: highest frequency 513*caee2733SJacky Bai */ 514*caee2733SJacky Bai if (freq_index > 2U) { 515*caee2733SJacky Bai return -1; 516*caee2733SJacky Bai } 517*caee2733SJacky Bai 518*caee2733SJacky Bai /* Enable LPI_WAKEUP_EN */ 519*caee2733SJacky Bai ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144); 520*caee2733SJacky Bai mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN); 521*caee2733SJacky Bai 522*caee2733SJacky Bai /* put DRAM into long self-refresh & clock gating */ 523*caee2733SJacky Bai lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL); 524*caee2733SJacky Bai lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9); 525*caee2733SJacky Bai mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl); 526*caee2733SJacky Bai 527*caee2733SJacky Bai /* Gating the clock */ 528*caee2733SJacky Bai lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2); 529*caee2733SJacky Bai mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE); 530*caee2733SJacky Bai 531*caee2733SJacky Bai /* Request frequency change */ 532*caee2733SJacky Bai mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ); 533*caee2733SJacky Bai 534*caee2733SJacky Bai do { 535*caee2733SJacky Bai lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL); 536*caee2733SJacky Bai if (lpddr_ctrl & SOC_FREQ_CHG_REQ) { 537*caee2733SJacky Bai /* Bypass mode */ 538*caee2733SJacky Bai if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) { 539*caee2733SJacky Bai /* Change to PLL bypass mode */ 540*caee2733SJacky Bai mmio_write_32(IMX_LPAV_SIM_BASE, 0x1); 541*caee2733SJacky Bai /* change the ddr clock source & frequency */ 542*caee2733SJacky Bai set_ddr_clk(info->fsp_table[freq_index]); 543*caee2733SJacky Bai } else { 544*caee2733SJacky Bai /* Change to PLL unbypass mode */ 545*caee2733SJacky Bai mmio_write_32(IMX_LPAV_SIM_BASE, 0x0); 546*caee2733SJacky Bai /* change the ddr clock source & frequency */ 547*caee2733SJacky Bai set_ddr_clk(info->fsp_table[freq_index] >> 1); 548*caee2733SJacky Bai } 549*caee2733SJacky Bai 550*caee2733SJacky Bai mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK); 551*caee2733SJacky Bai continue; 552*caee2733SJacky Bai } 553*caee2733SJacky Bai } while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */ 554*caee2733SJacky Bai 555*caee2733SJacky Bai /* restore the original setting */ 556*caee2733SJacky Bai mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144); 557*caee2733SJacky Bai mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2); 558*caee2733SJacky Bai 559*caee2733SJacky Bai /* Check the DFS result */ 560*caee2733SJacky Bai lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF; 561*caee2733SJacky Bai if (lpddr_ctrl != 0U) { 562*caee2733SJacky Bai /* Must be something wrong, return failure */ 563*caee2733SJacky Bai return -1; 564*caee2733SJacky Bai } 565*caee2733SJacky Bai 566*caee2733SJacky Bai /* DFS done successfully */ 567*caee2733SJacky Bai return 0; 568*caee2733SJacky Bai } 569*caee2733SJacky Bai 570*caee2733SJacky Bai /* for the non-primary core, waiting for DFS done */ 571*caee2733SJacky Bai static uint64_t waiting_dvfs(uint32_t id, uint32_t flags, 572*caee2733SJacky Bai void *handle, void *cookie) 573*caee2733SJacky Bai { 574*caee2733SJacky Bai uint32_t irq; 575*caee2733SJacky Bai 576*caee2733SJacky Bai irq = plat_ic_acknowledge_interrupt(); 577*caee2733SJacky Bai if (irq < 1022U) { 578*caee2733SJacky Bai plat_ic_end_of_interrupt(irq); 579*caee2733SJacky Bai } 580*caee2733SJacky Bai 581*caee2733SJacky Bai /* set the WFE done status */ 582*caee2733SJacky Bai spin_lock(&dfs_lock); 583*caee2733SJacky Bai core_count++; 584*caee2733SJacky Bai dsb(); 585*caee2733SJacky Bai spin_unlock(&dfs_lock); 586*caee2733SJacky Bai 587*caee2733SJacky Bai while (in_progress) { 588*caee2733SJacky Bai wfe(); 589*caee2733SJacky Bai } 590*caee2733SJacky Bai 591*caee2733SJacky Bai return 0; 592*caee2733SJacky Bai } 593*caee2733SJacky Bai 594*caee2733SJacky Bai int dram_dvfs_handler(uint32_t smc_fid, void *handle, 595*caee2733SJacky Bai u_register_t x1, u_register_t x2, u_register_t x3) 596*caee2733SJacky Bai { 597*caee2733SJacky Bai unsigned int fsp_index = x1; 598*caee2733SJacky Bai uint32_t online_cpus = x2 - 1; 599*caee2733SJacky Bai uint64_t mpidr = read_mpidr_el1(); 600*caee2733SJacky Bai unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 601*caee2733SJacky Bai 602*caee2733SJacky Bai /* Get the number of FSPs */ 603*caee2733SJacky Bai if (x1 == DDR_DFS_GET_FSP_COUNT) { 604*caee2733SJacky Bai SMC_RET2(handle, num_fsp, info->fsp_table[1]); 605*caee2733SJacky Bai } 606*caee2733SJacky Bai 607*caee2733SJacky Bai /* start lpddr frequency scaling */ 608*caee2733SJacky Bai in_progress = true; 609*caee2733SJacky Bai dsb(); 610*caee2733SJacky Bai 611*caee2733SJacky Bai /* notify other core wait for scaling done */ 612*caee2733SJacky Bai for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) 613*caee2733SJacky Bai /* Skip raise SGI for current CPU */ 614*caee2733SJacky Bai if (i != cpu_id) { 615*caee2733SJacky Bai plat_ic_raise_el3_sgi(0x8, i); 616*caee2733SJacky Bai } 617*caee2733SJacky Bai 618*caee2733SJacky Bai /* Make sure all the cpu in WFE */ 619*caee2733SJacky Bai while (online_cpus != core_count) { 620*caee2733SJacky Bai ; 621*caee2733SJacky Bai } 622*caee2733SJacky Bai 623*caee2733SJacky Bai /* Flush the L1/L2 cache */ 624*caee2733SJacky Bai dcsw_op_all(DCCSW); 625*caee2733SJacky Bai 626*caee2733SJacky Bai lpddr4_dfs(fsp_index); 627*caee2733SJacky Bai 628*caee2733SJacky Bai in_progress = false; 629*caee2733SJacky Bai core_count = 0; 630*caee2733SJacky Bai dsb(); 631*caee2733SJacky Bai sev(); 632*caee2733SJacky Bai isb(); 633*caee2733SJacky Bai 634*caee2733SJacky Bai SMC_RET1(handle, 0); 635*caee2733SJacky Bai } 636*caee2733SJacky Bai 637*caee2733SJacky Bai void dram_init(void) 638*caee2733SJacky Bai { 639*caee2733SJacky Bai uint32_t flags = 0; 640*caee2733SJacky Bai uint32_t rc; 641*caee2733SJacky Bai unsigned int i; 642*caee2733SJacky Bai 643*caee2733SJacky Bai /* Register the EL3 handler for DDR DVFS */ 644*caee2733SJacky Bai set_interrupt_rm_flag(flags, NON_SECURE); 645*caee2733SJacky Bai rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags); 646*caee2733SJacky Bai if (rc) { 647*caee2733SJacky Bai panic(); 648*caee2733SJacky Bai } 649*caee2733SJacky Bai 650*caee2733SJacky Bai info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE; 651*caee2733SJacky Bai 652*caee2733SJacky Bai /* Get the num of the supported Fsp */ 653*caee2733SJacky Bai for (i = 0; i < MAX_FSP_NUM; i++) { 654*caee2733SJacky Bai if (!info->fsp_table[i]) { 655*caee2733SJacky Bai break; 656*caee2733SJacky Bai } 657*caee2733SJacky Bai } 658*caee2733SJacky Bai 659*caee2733SJacky Bai num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i; 660*caee2733SJacky Bai } 661