blob: c20494701840216887350db14299cce9b6c3b44f [file] [log] [blame]
Jacky Baiba997cc2021-06-25 09:47:46 +08001/*
2 * Copyright 2021-2024 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <stdbool.h>
9
10#include <lib/mmio.h>
11#include <platform_def.h>
12
13#include <upower_api.h>
14
15#define PHY_FREQ_SEL_INDEX(x) ((x) << 16)
16#define PHY_FREQ_MULTICAST_EN(x) ((x) << 8)
17#define DENALI_PHY_1537 U(0x5804)
18
19#define IMX_DDRC_BASE U(0x2E060000)
20#define SAVED_DRAM_DATA_BASE U(0x20055000)
21#define DENALI_CTL_144 0x240
22#define LPI_WAKEUP_EN_SHIFT U(8)
23#define IMX_LPAV_SIM_BASE 0x2DA50000
24#define LPDDR_CTRL 0x14
25#define LPDDR_AUTO_LP_MODE_DISABLE BIT(24)
26#define SOC_LP_CMD_SHIFT U(15)
27#define LPDDR_CTRL2 0x18
28
29#define DENALI_CTL_00 U(0x0)
30#define DENALI_CTL_23 U(0x5c)
31#define DFIBUS_FREQ_INIT_SHIFT U(24)
32#define TSREF2PHYMSTR_SHIFT U(8)
33#define TSREF2PHYMSTR_MASK GENMASK(13, 8)
34
35#define DENALI_CTL_24 U(0x60)
36#define DENALI_CTL_25 U(0x64)
37
38#define DENALI_CTL_93 U(0x174)
39#define PWRUP_SREFRESH_EXIT BIT(0)
40
41#define DENALI_CTL_127 U(0x1fc)
42#define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE BIT(16)
43
44#define DENALI_CTL_147 U(0x24c)
45#define DENALI_CTL_153 U(0x264)
46#define PCPCS_PD_EN BIT(8)
47
48#define DENALI_CTL_249 U(0x3E4)
49#define DENALI_CTL_266 U(0x428)
50
51#define DENALI_PHY_1547 U(0x582c)
52#define PHY_LP4_BOOT_DISABLE BIT(8)
53
54#define DENALI_PHY_1559 U(0x585c)
55#define DENALI_PHY_1590 U(0x58D8)
56
57#define DENALI_PI_00 U(0x2000)
58#define DENALI_PI_04 U(0x2010)
59#define DENALI_PI_52 U(0x20D0)
60#define DENALI_PI_26 U(0x2068)
61#define DENALI_PI_33 U(0x2084)
62#define DENALI_PI_65 U(0x2104)
63#define DENALI_PI_77 U(0x2134)
64#define DENALI_PI_134 U(0x2218)
65#define DENALI_PI_131 U(0x220C)
66#define DENALI_PI_132 U(0x2210)
67#define DENALI_PI_134 U(0x2218)
68#define DENALI_PI_137 U(0x2224)
69#define DENALI_PI_174 U(0x22B8)
70#define DENALI_PI_175 U(0x22BC)
71#define DENALI_PI_181 U(0x22D4)
72#define DENALI_PI_182 U(0x22D8)
73#define DENALI_PI_191 U(0x22FC)
74#define DENALI_PI_192 U(0x2300)
75#define DENALI_PI_212 U(0x2350)
76#define DENALI_PI_214 U(0x2358)
77#define DENALI_PI_217 U(0x2364)
78
79#define LPDDR3_TYPE U(0x7)
80#define LPDDR4_TYPE U(0xB)
81
82extern void upower_wait_resp(void);
83
84struct dram_cfg_param {
85 uint32_t reg;
86 uint32_t val;
87};
88
89struct dram_timing_info {
90 /* ddr controller config */
91 struct dram_cfg_param *ctl_cfg;
92 unsigned int ctl_cfg_num;
93 /* pi config */
94 struct dram_cfg_param *pi_cfg;
95 unsigned int pi_cfg_num;
96 /* phy freq1 config */
97 struct dram_cfg_param *phy_f1_cfg;
98 unsigned int phy_f1_cfg_num;
99 /* phy freq2 config */
100 struct dram_cfg_param *phy_f2_cfg;
101 unsigned int phy_f2_cfg_num;
102 /* initialized drate table */
103 unsigned int fsp_table[3];
104};
105
106#define CTL_NUM U(680)
107#define PI_NUM U(298)
108#define PHY_NUM U(1654)
109#define PHY_DIFF_NUM U(49)
110struct dram_cfg {
111 uint32_t ctl_cfg[CTL_NUM];
112 uint32_t pi_cfg[PI_NUM];
113 uint32_t phy_full[PHY_NUM];
114 uint32_t phy_diff[PHY_DIFF_NUM];
115};
116
117struct dram_timing_info *info;
118struct dram_cfg *dram_timing_cfg;
119
120/* mark if dram cfg is already saved */
121static bool dram_cfg_saved;
122static uint32_t dram_class;
123
124/* PHY register index for frequency diff */
125uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
12690, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
127346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
128370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
129616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
130871, 872, 882, 1063, 1319, 1566, 1624, 1625
131};
132
133static void ddr_init(void)
134{
135 unsigned int i;
136
137 /* restore the ddr ctl config */
138 for (i = 0U; i < CTL_NUM; i++) {
139 mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
140 }
141
142 /* load the PI registers */
143 for (i = 0U; i < PI_NUM; i++) {
144 mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
145 }
146
147
148 /* restore all PHY registers for all the fsp. */
149 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
150 /* restore all the phy configs */
151 for (i = 0U; i < PHY_NUM; i++) {
152 /* skip the reserved registers space */
153 if (i >= 121U && i <= 255U) {
154 continue;
155 }
156 if (i >= 377U && i <= 511U) {
157 continue;
158 }
159 if (i >= 633U && i <= 767U) {
160 continue;
161 }
162 if (i >= 889U && i <= 1023U) {
163 continue;
164 }
165 if (i >= 1065U && i <= 1279U) {
166 continue;
167 }
168 if (i >= 1321U && i <= 1535U) {
169 continue;
170 }
171 mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
172 }
173
174 if (dram_class == LPDDR4_TYPE) {
175 /* restore only the diff. */
176 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
177 for (i = 0U; i < PHY_DIFF_NUM; i++) {
178 mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
179 dram_timing_cfg->phy_diff[i]);
180 }
181 }
182
183 /* Re-enable MULTICAST mode */
184 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
185}
186
187void dram_enter_retention(void)
188{
189 unsigned int i;
190
191 /* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
192 mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
193
194 /*
195 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
196 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
197 * long with mem and ctlr clk gating or self-refresh power-down
198 * long with mem and ctlr clk gating'
199 */
200 mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
201
202 /*
203 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
204 * the logic to automatic handles low power entry/exit. This is the recommended
205 * option over handling through software.
206 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
207 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
208 * since LPPDR logic will be power gated).
209 */
210 mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
211 mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
212 0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
213
214 /* Save DDR Controller & PHY config.
215 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
216 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
217 * F1 & F2 into phy_f2_cfg.
218 */
219 if (!dram_cfg_saved) {
220 info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
221 dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
222 sizeof(struct dram_timing_info));
223
224 /* get the dram type */
225 dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
226 dram_class = (dram_class >> 8) & 0xf;
227
228 /* save the ctl registers */
229 for (i = 0U; i < CTL_NUM; i++) {
230 dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
231 }
232 dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
233
234 /* save the PI registers */
235 for (i = 0U; i < PI_NUM; i++) {
236 dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
237 }
238 dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
239
240 /*
241 * Read and store all PHY registers. full array is a full
242 * copy for all the setpoint
243 */
244 if (dram_class == LPDDR4_TYPE) {
245 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
246 for (i = 0U; i < PHY_NUM; i++) {
247 /* Make sure MULTICASE is enabled */
248 if (i == 1537U) {
249 dram_timing_cfg->phy_full[i] = 0x100;
250 } else {
251 dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
252 }
253 }
254
255 /*
256 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
257 * Read and store only the diff.
258 */
259 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
260 /* save only the frequency based diff config to save memory */
261 for (i = 0U; i < PHY_DIFF_NUM; i++) {
262 dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
263 freq_specific_reg_array[i] * 4);
264 }
265 } else {
266 /* LPDDR3, only f1 need to save */
267 for (i = 0U; i < info->phy_f1_cfg_num; i++) {
268 info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
269 }
270 }
271
272 dram_cfg_saved = true;
273 }
274}
275
276void dram_exit_retention(void)
277{
278 uint32_t val;
279
280 /* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
281 mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
282
283 /* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
284 mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
285
286 /* 3. Reload the LPDDR CTL/PI/PHY register */
287 ddr_init();
288
289 if (dram_class == LPDDR4_TYPE) {
290 /* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
291 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
292
293 /*
294 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
295 * from controller.
296 */
297 /*
298 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
299 * self refresh exit from PI
300 */
301 /* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
302 /*
303 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
304 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
305 * Enable non initialization trainings.
306 */
307 /* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
308 /* 4f. PI_DLL_RESET=0x1 */
309 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
310 /* PI_PWRUP_SELF_REF_EXIT = 1 */
311 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
312 /* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
313 mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
314 /* PI_INT_LVL_EN = 0 */
315 mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
316 /* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
317 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
318 /* PI_WRLVL_EN_F2 = 3 */
319 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
320 /* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
321 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
322 /* PI_CALVL_EN_F2 = 3 */
323 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
324 /* PI_WDQLVL_EN_F0 = 3 */
325 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
326 /* PI_WDQLVL_EN_F1 = 3 */
327 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
328 /* PI_WDQLVL_EN_F2 = 3 */
329 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
330 /* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
331 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
332 /*
333 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
334 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
335 */
336 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
337 /* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
338 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
339 } else {
340 /* PI_DLL_RESET=1 */
341 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
342 /* PI_PWRUP_SELF_REF_EXIT=1 */
343 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
344 /* PI_MC_PWRUP_SELF_REF_EXIT=0 */
345 mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
346 /* PI_INT_LVL_EN=0 */
347 mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
348 /* PI_WRLVL_EN_F0=3 */
349 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
350 /* PI_CALVL_EN_F0=3 */
351 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
352 /* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
353 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
354 /* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
355 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
356 }
357
358 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
359
360 /* Force in-order AXI read data */
361 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
362
363 /*
364 * Disable special R/W group switches so that R/W group placement
365 * is always at END of R/W group.
366 */
367 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
368
369 /* Reduce time for IO pad calibration */
370 mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
371
372 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
373
374 /* PD disable */
375 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
376 /*
377 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
378 * to 1b'0, PCPCS_PD_EN to 1b'0
379 */
380
381 upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
382 upower_wait_resp();
383
384 if (dram_class == LPDDR4_TYPE) {
385 /* 7. Write PI START parameter to 1'b1 */
386 mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
387
388 /* 8. Write CTL START parameter to 1'b1 */
389 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
390 } else {
391 /* 7. Write PI START parameter to 1'b1 */
392 mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
393
394 /* 8. Write CTL START parameter to 1'b1 */
395 mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
396 }
397
398 /* 9. DENALI_CTL_266: Wait for INT_STATUS_INIT=0x2 */
399 do {
400 val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
401 } while (val != 0x2);
402
403 /*
404 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
405 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
406 */
407 if (dram_class == LPDDR4_TYPE) {
408 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
409 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
410 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
411 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
412 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
413
414 /* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
415 while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
416 ;
417 }
418 } else {
419 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
420 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
421 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
422 mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
423 while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
424 ;
425 }
426 }
427}