Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ OR MIT |
| 2 | /* |
| 3 | * Copyright 2021 NXP |
| 4 | */ |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 5 | #include <asm/io.h> |
| 6 | #include <asm/arch/clock.h> |
| 7 | #include <asm/arch/ddr.h> |
| 8 | #include <asm/arch/imx-regs.h> |
| 9 | |
| 10 | #define DENALI_CTL_00 (DDR_CTL_BASE_ADDR + 4 * 0) |
| 11 | #define CTL_START 0x1 |
| 12 | |
| 13 | #define DENALI_CTL_03 (DDR_CTL_BASE_ADDR + 4 * 3) |
| 14 | #define DENALI_CTL_197 (DDR_CTL_BASE_ADDR + 4 * 197) |
| 15 | #define DENALI_CTL_250 (DDR_CTL_BASE_ADDR + 4 * 250) |
| 16 | #define DENALI_CTL_251 (DDR_CTL_BASE_ADDR + 4 * 251) |
| 17 | #define DENALI_CTL_266 (DDR_CTL_BASE_ADDR + 4 * 266) |
| 18 | #define DFI_INIT_COMPLETE 0x2 |
| 19 | |
| 20 | #define DENALI_CTL_614 (DDR_CTL_BASE_ADDR + 4 * 614) |
| 21 | #define DENALI_CTL_615 (DDR_CTL_BASE_ADDR + 4 * 615) |
| 22 | |
| 23 | #define DENALI_PI_00 (DDR_PI_BASE_ADDR + 4 * 0) |
| 24 | #define PI_START 0x1 |
| 25 | |
| 26 | #define DENALI_PI_04 (DDR_PI_BASE_ADDR + 4 * 4) |
| 27 | #define DENALI_PI_11 (DDR_PI_BASE_ADDR + 4 * 11) |
| 28 | #define DENALI_PI_12 (DDR_PI_BASE_ADDR + 4 * 12) |
| 29 | #define DENALI_CTL_23 (DDR_CTL_BASE_ADDR + 4 * 23) |
| 30 | #define DENALI_CTL_25 (DDR_CTL_BASE_ADDR + 4 * 25) |
| 31 | |
| 32 | #define DENALI_PHY_1624 (DDR_PHY_BASE_ADDR + 4 * 1624) |
Jacky Bai | 09e3e13 | 2023-01-31 16:42:29 +0800 | [diff] [blame] | 33 | #define DENALI_PHY_1625 (DDR_PHY_BASE_ADDR + 4 * 1625) |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 34 | #define DENALI_PHY_1537 (DDR_PHY_BASE_ADDR + 4 * 1537) |
| 35 | #define PHY_FREQ_SEL_MULTICAST_EN(X) ((X) << 8) |
| 36 | #define PHY_FREQ_SEL_INDEX(X) ((X) << 16) |
| 37 | |
| 38 | #define DENALI_PHY_1547 (DDR_PHY_BASE_ADDR + 4 * 1547) |
| 39 | #define DENALI_PHY_1555 (DDR_PHY_BASE_ADDR + 4 * 1555) |
| 40 | #define DENALI_PHY_1564 (DDR_PHY_BASE_ADDR + 4 * 1564) |
| 41 | #define DENALI_PHY_1565 (DDR_PHY_BASE_ADDR + 4 * 1565) |
| 42 | |
| 43 | static void ddr_enable_pll_bypass(void) |
| 44 | { |
| 45 | u32 reg_val; |
| 46 | |
| 47 | /* PI_INIT_LVL_EN=0x0 (DENALI_PI_04) */ |
| 48 | reg_val = readl(DENALI_PI_04) & ~0x1; |
| 49 | writel(reg_val, DENALI_PI_04); |
| 50 | |
| 51 | /* PI_FREQ_MAP=0x1 (DENALI_PI_12) */ |
| 52 | writel(0x1, DENALI_PI_12); |
| 53 | |
| 54 | /* PI_INIT_WORK_FREQ=0x0 (DENALI_PI_11) */ |
| 55 | reg_val = readl(DENALI_PI_11) & ~(0x1f << 8); |
| 56 | writel(reg_val, DENALI_PI_11); |
| 57 | |
| 58 | /* DFIBUS_FREQ_INIT=0x0 (DENALI_CTL_23) */ |
| 59 | reg_val = readl(DENALI_CTL_23) & ~(0x3 << 24); |
| 60 | writel(reg_val, DENALI_CTL_23); |
| 61 | |
| 62 | /* PHY_LP4_BOOT_DISABLE=0x0 (DENALI_PHY_1547) */ |
| 63 | reg_val = readl(DENALI_PHY_1547) & ~(0x1 << 8); |
| 64 | writel(reg_val, DENALI_PHY_1547); |
| 65 | |
| 66 | /* PHY_PLL_BYPASS=0x1 (DENALI_PHY_1624) */ |
| 67 | reg_val = readl(DENALI_PHY_1624) | 0x1; |
| 68 | writel(reg_val, DENALI_PHY_1624); |
| 69 | |
| 70 | /* PHY_LP4_BOOT_PLL_BYPASS to 0x1 (DENALI_PHY_1555) */ |
| 71 | reg_val = readl(DENALI_PHY_1555) | 0x1; |
| 72 | writel(reg_val, DENALI_PHY_1555); |
| 73 | |
| 74 | /* FREQ_CHANGE_TYPE_F0 = 0x0/FREQ_CHANGE_TYPE_F1 = 0x1/FREQ_CHANGE_TYPE_F2 = 0x2 */ |
| 75 | reg_val = 0x020100; |
| 76 | writel(reg_val, DENALI_CTL_25); |
| 77 | } |
| 78 | |
| 79 | int ddr_calibration(unsigned int fsp_table[3]) |
| 80 | { |
| 81 | u32 reg_val; |
| 82 | u32 int_status_init, phy_freq_req, phy_freq_type; |
| 83 | u32 lock_0, lock_1, lock_2; |
| 84 | u32 freq_chg_pt, freq_chg_cnt; |
Jacky Bai | 09e3e13 | 2023-01-31 16:42:29 +0800 | [diff] [blame] | 85 | u32 is_lpddr4 = 0; |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 86 | |
| 87 | if (IS_ENABLED(CONFIG_IMX8ULP_DRAM_PHY_PLL_BYPASS)) { |
| 88 | ddr_enable_pll_bypass(); |
| 89 | freq_chg_cnt = 0; |
| 90 | freq_chg_pt = 0; |
| 91 | } else { |
Jacky Bai | 09e3e13 | 2023-01-31 16:42:29 +0800 | [diff] [blame] | 92 | reg_val = (readl(DENALI_CTL_00)>>8)&0xf; |
| 93 | if(reg_val == 0x7) { |
| 94 | /* LPDDR3 type */ |
| 95 | set_ddr_clk(fsp_table[1] >> 1); |
| 96 | freq_chg_cnt = 0; |
| 97 | freq_chg_pt = 0; |
| 98 | } else if(reg_val == 0xb) { |
| 99 | /* LPDDR4/4x type */ |
| 100 | is_lpddr4 = 1; |
| 101 | reg_val = readl(DENALI_CTL_250); |
| 102 | if (((reg_val >> 16) & 0x3) == 1) |
| 103 | freq_chg_cnt = 2; |
| 104 | else |
| 105 | freq_chg_cnt = 3; |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 106 | |
Jacky Bai | 09e3e13 | 2023-01-31 16:42:29 +0800 | [diff] [blame] | 107 | reg_val = readl(DENALI_PI_12); |
| 108 | if(reg_val == 0x3) |
| 109 | freq_chg_pt = 1; |
| 110 | else if(reg_val == 0x7) |
| 111 | freq_chg_pt = 2; |
| 112 | else { |
| 113 | printf("frequency map(0x%x) is wrong, please check!\r\n", reg_val); |
| 114 | return -1; |
| 115 | } |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 116 | } else { |
Jacky Bai | 09e3e13 | 2023-01-31 16:42:29 +0800 | [diff] [blame] | 117 | printf("Incorrect DDR type configured!\r\n"); |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 118 | return -1; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | /* Assert PI_START parameter and then assert START parameter in Controller. */ |
| 123 | reg_val = readl(DENALI_PI_00) | PI_START; |
| 124 | writel(reg_val, DENALI_PI_00); |
| 125 | |
| 126 | reg_val = readl(DENALI_CTL_00) | CTL_START; |
| 127 | writel(reg_val, DENALI_CTL_00); |
| 128 | |
| 129 | /* Poll for init_done_bit in Controller interrupt status register (INT_STATUS_INIT) */ |
| 130 | do { |
| 131 | if (!freq_chg_cnt) { |
| 132 | int_status_init = (readl(DENALI_CTL_266) >> 8) & 0xff; |
| 133 | /* DDR subsystem is ready for traffic. */ |
| 134 | if (int_status_init & DFI_INIT_COMPLETE) { |
| 135 | debug("complete\n"); |
| 136 | break; |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | /* |
| 141 | * During leveling, PHY will request for freq change and SoC clock logic |
| 142 | * should provide requested frequency |
| 143 | * Polling SIM LPDDR_CTRL2 Bit phy_freq_chg_req until be 1'b1 |
| 144 | */ |
| 145 | reg_val = readl(AVD_SIM_LPDDR_CTRL2); |
Ye Li | 7f5dd94 | 2021-10-29 09:46:34 +0800 | [diff] [blame] | 146 | /* DFS interrupt is set */ |
| 147 | phy_freq_req = ((reg_val >> 7) & 0x1) && ((reg_val >> 15) & 0x1); |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 148 | if (phy_freq_req) { |
| 149 | phy_freq_type = reg_val & 0x1F; |
| 150 | if (phy_freq_type == 0x00) { |
| 151 | debug("Poll for freq_chg_req on SIM register and change to F0 frequency.\n"); |
| 152 | set_ddr_clk(fsp_table[phy_freq_type] >> 1); |
| 153 | |
| 154 | /* Write 1'b1 at LPDDR_CTRL2 bit phy_freq_cfg_ack */ |
| 155 | reg_val = readl(AVD_SIM_LPDDR_CTRL2); |
| 156 | writel(reg_val | (0x1 << 6), AVD_SIM_LPDDR_CTRL2); |
| 157 | } else if (phy_freq_type == 0x01) { |
| 158 | debug("Poll for freq_chg_req on SIM register and change to F1 frequency.\n"); |
| 159 | set_ddr_clk(fsp_table[phy_freq_type] >> 1); |
| 160 | |
| 161 | /* Write 1'b1 at LPDDR_CTRL2 bit phy_freq_cfg_ack */ |
| 162 | reg_val = readl(AVD_SIM_LPDDR_CTRL2); |
| 163 | writel(reg_val | (0x1 << 6), AVD_SIM_LPDDR_CTRL2); |
| 164 | if (freq_chg_pt == 1) |
| 165 | freq_chg_cnt--; |
| 166 | } else if (phy_freq_type == 0x02) { |
| 167 | debug("Poll for freq_chg_req on SIM register and change to F2 frequency.\n"); |
| 168 | set_ddr_clk(fsp_table[phy_freq_type] >> 1); |
| 169 | |
| 170 | /* Write 1'b1 at LPDDR_CTRL2 bit phy_freq_cfg_ack */ |
| 171 | reg_val = readl(AVD_SIM_LPDDR_CTRL2); |
| 172 | writel(reg_val | (0x1 << 6), AVD_SIM_LPDDR_CTRL2); |
| 173 | if (freq_chg_pt == 2) |
| 174 | freq_chg_cnt--; |
| 175 | } |
Ye Li | 7f5dd94 | 2021-10-29 09:46:34 +0800 | [diff] [blame] | 176 | |
| 177 | /* Hardware clear the ack on falling edge of LPDDR_CTRL2:phy_freq_chg_reg */ |
| 178 | /* Ensure the ack is clear before starting to poll request again */ |
| 179 | while ((readl(AVD_SIM_LPDDR_CTRL2) & BIT(6))) |
| 180 | ; |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 181 | } |
| 182 | } while (1); |
| 183 | |
| 184 | /* Check PLL lock status */ |
| 185 | lock_0 = readl(DENALI_PHY_1564) & 0xffff; |
| 186 | lock_1 = (readl(DENALI_PHY_1564) >> 16) & 0xffff; |
| 187 | lock_2 = readl(DENALI_PHY_1565) & 0xffff; |
| 188 | |
| 189 | if ((lock_0 & 0x3) != 0x3 || (lock_1 & 0x3) != 0x3 || (lock_2 & 0x3) != 0x3) { |
| 190 | debug("De-Skew PLL failed to lock\n"); |
| 191 | debug("lock_0=0x%x, lock_1=0x%x, lock_2=0x%x\n", lock_0, lock_1, lock_2); |
| 192 | return -1; |
| 193 | } |
| 194 | |
| 195 | debug("De-Skew PLL is locked and ready\n"); |
Jacky Bai | 09e3e13 | 2023-01-31 16:42:29 +0800 | [diff] [blame] | 196 | |
| 197 | /* Change LPDDR4 FREQ1 to bypass mode if it is lower than 200MHz */ |
| 198 | if(is_lpddr4 && fsp_table[1] < 400) { |
| 199 | /* Set FREQ1 to bypass mode */ |
| 200 | reg_val = PHY_FREQ_SEL_MULTICAST_EN(0) | PHY_FREQ_SEL_INDEX(0); |
| 201 | writel(reg_val, DENALI_PHY_1537); |
| 202 | |
| 203 | /* PHY_PLL_BYPASS=0x1 (DENALI_PHY_1624) */ |
| 204 | reg_val =readl(DENALI_PHY_1624) | 0x1; |
| 205 | writel(reg_val, DENALI_PHY_1624); |
| 206 | |
| 207 | /* DENALI_PHY_1625: bypass mode in PHY PLL */ |
| 208 | reg_val =readl(DENALI_PHY_1625) & ~0xf; |
| 209 | writel(reg_val, DENALI_PHY_1625); |
| 210 | } |
| 211 | |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 212 | return 0; |
| 213 | } |
| 214 | |
Jacky Bai | 9cac6e2 | 2021-10-29 09:46:33 +0800 | [diff] [blame] | 215 | static void save_dram_config(struct dram_timing_info2 *timing_info, unsigned long saved_timing_base) |
| 216 | { |
| 217 | int i = 0; |
| 218 | struct dram_timing_info2 *saved_timing = (struct dram_timing_info2 *)saved_timing_base; |
| 219 | struct dram_cfg_param *cfg; |
| 220 | |
| 221 | saved_timing->ctl_cfg_num = timing_info->ctl_cfg_num; |
| 222 | saved_timing->phy_f1_cfg_num = timing_info->phy_f1_cfg_num; |
| 223 | saved_timing->phy_f2_cfg_num = timing_info->phy_f2_cfg_num; |
| 224 | |
| 225 | /* save the fsp table */ |
| 226 | for (i = 0; i < 3; i++) |
| 227 | saved_timing->fsp_table[i] = timing_info->fsp_table[i]; |
| 228 | |
| 229 | cfg = (struct dram_cfg_param *)(saved_timing_base + |
| 230 | sizeof(*timing_info)); |
| 231 | |
| 232 | /* save ctl config */ |
| 233 | saved_timing->ctl_cfg = cfg; |
| 234 | for (i = 0; i < timing_info->ctl_cfg_num; i++) { |
| 235 | cfg->reg = timing_info->ctl_cfg[i].reg; |
| 236 | cfg->val = timing_info->ctl_cfg[i].val; |
| 237 | cfg++; |
| 238 | } |
| 239 | |
| 240 | /* save phy f1 config */ |
| 241 | saved_timing->phy_f1_cfg = cfg; |
| 242 | for (i = 0; i < timing_info->phy_f1_cfg_num; i++) { |
| 243 | cfg->reg = timing_info->phy_f1_cfg[i].reg; |
| 244 | cfg->val = timing_info->phy_f1_cfg[i].val; |
| 245 | cfg++; |
| 246 | } |
| 247 | |
| 248 | /* save phy f2 config */ |
| 249 | saved_timing->phy_f2_cfg = cfg; |
| 250 | for (i = 0; i < timing_info->phy_f2_cfg_num; i++) { |
| 251 | cfg->reg = timing_info->phy_f2_cfg[i].reg; |
| 252 | cfg->val = timing_info->phy_f2_cfg[i].val; |
| 253 | cfg++; |
| 254 | } |
| 255 | } |
| 256 | |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 257 | int ddr_init(struct dram_timing_info2 *dram_timing) |
| 258 | { |
| 259 | int i; |
| 260 | |
| 261 | if (IS_ENABLED(CONFIG_IMX8ULP_DRAM_PHY_PLL_BYPASS)) { |
| 262 | /* Use PLL bypass for boot freq */ |
| 263 | /* Since PLL can't generate the double freq, Need ddr clock to generate it. */ |
| 264 | set_ddr_clk(dram_timing->fsp_table[0]); /* Set to boot freq */ |
| 265 | setbits_le32(AVD_SIM_BASE_ADDR, 0x1); /* SIM_DDR_CTRL_DIV2_EN */ |
| 266 | } else { |
| 267 | set_ddr_clk(dram_timing->fsp_table[0] >> 1); /* Set to boot freq */ |
| 268 | clrbits_le32(AVD_SIM_BASE_ADDR, 0x1); /* SIM_DDR_CTRL_DIV2_EN */ |
| 269 | } |
| 270 | |
Jacky Bai | 9cac6e2 | 2021-10-29 09:46:33 +0800 | [diff] [blame] | 271 | /* save the dram config into sram for low power mode */ |
| 272 | save_dram_config(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE); |
| 273 | |
Ye Li | 56499f6 | 2021-08-07 16:01:11 +0800 | [diff] [blame] | 274 | /* Initialize CTL registers */ |
| 275 | for (i = 0; i < dram_timing->ctl_cfg_num; i++) |
| 276 | writel(dram_timing->ctl_cfg[i].val, (ulong)dram_timing->ctl_cfg[i].reg); |
| 277 | |
| 278 | /* Initialize PI registers */ |
| 279 | for (i = 0; i < dram_timing->pi_cfg_num; i++) |
| 280 | writel(dram_timing->pi_cfg[i].val, (ulong)dram_timing->pi_cfg[i].reg); |
| 281 | |
| 282 | /* Write PHY regiters for all 3 frequency points (48Mhz/384Mhz/528Mhz): f1_index=0 */ |
| 283 | writel(PHY_FREQ_SEL_MULTICAST_EN(1) | PHY_FREQ_SEL_INDEX(0), DENALI_PHY_1537); |
| 284 | for (i = 0; i < dram_timing->phy_f1_cfg_num; i++) |
| 285 | writel(dram_timing->phy_f1_cfg[i].val, (ulong)dram_timing->phy_f1_cfg[i].reg); |
| 286 | |
| 287 | /* Write PHY regiters for freqency point 2 (528Mhz): f2_index=1 */ |
| 288 | writel(PHY_FREQ_SEL_MULTICAST_EN(0) | PHY_FREQ_SEL_INDEX(1), DENALI_PHY_1537); |
| 289 | for (i = 0; i < dram_timing->phy_f2_cfg_num; i++) |
| 290 | writel(dram_timing->phy_f2_cfg[i].val, (ulong)dram_timing->phy_f2_cfg[i].reg); |
| 291 | |
| 292 | /* Re-enable MULTICAST mode */ |
| 293 | writel(PHY_FREQ_SEL_MULTICAST_EN(1) | PHY_FREQ_SEL_INDEX(0), DENALI_PHY_1537); |
| 294 | |
| 295 | return ddr_calibration(dram_timing->fsp_table); |
| 296 | } |