blob: 52a4aa632304559fce99682842e48b91020e980e [file] [log] [blame]
Jacky Baid62ddc12019-08-08 09:59:08 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018-2019 NXP
4 */
5
6#include <common.h>
7#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Jacky Baid62ddc12019-08-08 09:59:08 +00009#include <asm/io.h>
10#include <asm/arch/ddr.h>
11#include <asm/arch/clock.h>
12#include <asm/arch/sys_proto.h>
13
Ye Lib2cfc422022-07-26 16:41:07 +080014static unsigned int g_cdd_rr_max[4];
15static unsigned int g_cdd_rw_max[4];
16static unsigned int g_cdd_wr_max[4];
17static unsigned int g_cdd_ww_max[4];
18
Jacky Baid62ddc12019-08-08 09:59:08 +000019void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
20{
21 int i = 0;
22
23 for (i = 0; i < num; i++) {
24 reg32_write(ddrc_cfg->reg, ddrc_cfg->val);
25 ddrc_cfg++;
26 }
27}
28
Sherry Sun7957bd62020-01-20 11:13:14 +080029#ifdef CONFIG_IMX8M_DRAM_INLINE_ECC
30void ddrc_inline_ecc_scrub(unsigned int start_address,
31 unsigned int range_address)
32{
33 unsigned int tmp;
34
35 /* Step1: Enable quasi-dynamic programming */
36 reg32_write(DDRC_SWCTL(0), 0x00000000);
37 /* Step2: Set ECCCFG1.ecc_parity_region_lock to 1 */
38 reg32setbit(DDRC_ECCCFG1(0), 0x4);
39 /* Step3: Block the AXI ports from taking the transaction */
40 reg32_write(DDRC_PCTRL_0(0), 0x0);
41 /* Step4: Set scrub start address */
42 reg32_write(DDRC_SBRSTART0(0), start_address);
43 /* Step5: Set scrub range address */
44 reg32_write(DDRC_SBRRANGE0(0), range_address);
45 /* Step6: Set scrub_mode to write */
46 reg32_write(DDRC_SBRCTL(0), 0x00000014);
47 /* Step7: Set the desired pattern through SBRWDATA0 registers */
48 reg32_write(DDRC_SBRWDATA0(0), 0x55aa55aa);
49 /* Step8: Enable the SBR by programming SBRCTL.scrub_en=1 */
50 reg32setbit(DDRC_SBRCTL(0), 0x0);
51 /* Step9: Poll SBRSTAT.scrub_done=1 */
52 tmp = reg32_read(DDRC_SBRSTAT(0));
53 while (tmp != 0x00000002)
54 tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x2;
55 /* Step10: Poll SBRSTAT.scrub_busy=0 */
56 tmp = reg32_read(DDRC_SBRSTAT(0));
57 while (tmp != 0x0)
58 tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x1;
59 /* Step11: Disable SBR by programming SBRCTL.scrub_en=0 */
60 clrbits_le32(DDRC_SBRCTL(0), 0x1);
61 /* Step12: Prepare for normal scrub operation(Read) and set scrub_interval*/
62 reg32_write(DDRC_SBRCTL(0), 0x100);
63 /* Step13: Enable the SBR by programming SBRCTL.scrub_en=1 */
64 reg32_write(DDRC_SBRCTL(0), 0x101);
65 /* Step14: Enable AXI ports by programming */
66 reg32_write(DDRC_PCTRL_0(0), 0x1);
67 /* Step15: Disable quasi-dynamic programming */
68 reg32_write(DDRC_SWCTL(0), 0x00000001);
69}
70
71void ddrc_inline_ecc_scrub_end(unsigned int start_address,
72 unsigned int range_address)
73{
74 /* Step1: Enable quasi-dynamic programming */
75 reg32_write(DDRC_SWCTL(0), 0x00000000);
76 /* Step2: Block the AXI ports from taking the transaction */
77 reg32_write(DDRC_PCTRL_0(0), 0x0);
78 /* Step3: Set scrub start address */
79 reg32_write(DDRC_SBRSTART0(0), start_address);
80 /* Step4: Set scrub range address */
81 reg32_write(DDRC_SBRRANGE0(0), range_address);
82 /* Step5: Disable SBR by programming SBRCTL.scrub_en=0 */
83 clrbits_le32(DDRC_SBRCTL(0), 0x1);
84 /* Step6: Prepare for normal scrub operation(Read) and set scrub_interval */
85 reg32_write(DDRC_SBRCTL(0), 0x100);
86 /* Step7: Enable the SBR by programming SBRCTL.scrub_en=1 */
87 reg32_write(DDRC_SBRCTL(0), 0x101);
88 /* Step8: Enable AXI ports by programming */
89 reg32_write(DDRC_PCTRL_0(0), 0x1);
90 /* Step9: Disable quasi-dynamic programming */
91 reg32_write(DDRC_SWCTL(0), 0x00000001);
92}
93#endif
94
95void __weak board_dram_ecc_scrub(void)
96{
Ye Lib2cfc422022-07-26 16:41:07 +080097}
98
99void lpddr4_mr_write(unsigned int mr_rank, unsigned int mr_addr,
100 unsigned int mr_data)
101{
102 unsigned int tmp;
103 /*
104 * 1. Poll MRSTAT.mr_wr_busy until it is 0.
105 * This checks that there is no outstanding MR transaction.
106 * No writes should be performed to MRCTRL0 and MRCTRL1 if
107 * MRSTAT.mr_wr_busy = 1.
108 */
109 do {
110 tmp = reg32_read(DDRC_MRSTAT(0));
111 } while (tmp & 0x1);
112 /*
113 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank and
114 * (for MRWs) MRCTRL1.mr_data to define the MR transaction.
115 */
116 reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4));
117 reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data);
118 reg32setbit(DDRC_MRCTRL0(0), 31);
119}
120
121unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr)
122{
123 unsigned int tmp;
124
125 reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1);
126 do {
127 tmp = reg32_read(DDRC_MRSTAT(0));
128 } while (tmp & 0x1);
129
130 reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1);
131 reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8));
132 reg32setbit(DDRC_MRCTRL0(0), 31);
133 do {
134 tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0));
135 } while ((tmp & 0x8) == 0);
136 tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0));
Ye Lib2cfc422022-07-26 16:41:07 +0800137 reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4);
Rasmus Villemoes666bf362022-10-06 14:56:50 +0200138 while (tmp) { //try to find a significant byte in the word
139 if (tmp & 0xff) {
140 tmp &= 0xff;
141 break;
142 }
143 tmp >>= 8;
144 }
Ye Lib2cfc422022-07-26 16:41:07 +0800145
146 return tmp;
147}
148
149static unsigned int look_for_max(unsigned int data[], unsigned int addr_start,
150 unsigned int addr_end)
151{
152 unsigned int i, imax = 0;
153
154 for (i = addr_start; i <= addr_end; i++) {
155 if (((data[i] >> 7) == 0) && data[i] > imax)
156 imax = data[i];
157 }
158
159 return imax;
Sherry Sun7957bd62020-01-20 11:13:14 +0800160}
161
Ye Lib2cfc422022-07-26 16:41:07 +0800162void get_trained_CDD(u32 fsp)
163{
164 unsigned int i, ddr_type, tmp;
165 unsigned int cdd_cha[12], cdd_chb[12];
166 unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max;
167 unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max;
168
169 ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
170 if (ddr_type == 0x20) {
171 for (i = 0; i < 6; i++) {
172 tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54013 + i) * 4);
173 cdd_cha[i * 2] = tmp & 0xff;
174 cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
175 }
176
177 for (i = 0; i < 7; i++) {
178 tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x5402c + i) * 4);
179 if (i == 0) {
180 cdd_cha[0] = (tmp >> 8) & 0xff;
181 } else if (i == 6) {
182 cdd_cha[11] = tmp & 0xff;
183 } else {
184 cdd_chb[i * 2 - 1] = tmp & 0xff;
185 cdd_chb[i * 2] = (tmp >> 8) & 0xff;
186 }
187 }
188
189 cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1);
190 cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5);
191 cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9);
192 cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11);
193 cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1);
194 cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5);
195 cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9);
196 cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11);
197 g_cdd_rr_max[fsp] =
198 cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max;
199 g_cdd_rw_max[fsp] =
200 cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max;
201 g_cdd_wr_max[fsp] =
202 cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max;
203 g_cdd_ww_max[fsp] =
204 cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max;
205 } else {
206 unsigned int ddr4_cdd[64];
207
208 for (i = 0; i < 29; i++) {
209 tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54012 + i) * 4);
210 ddr4_cdd[i * 2] = tmp & 0xff;
211 ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff;
212 }
213
214 g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12);
215 g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24);
216 g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40);
217 g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56);
218 }
219}
220
221void update_umctl2_rank_space_setting(unsigned int pstat_num)
222{
223 unsigned int i, ddr_type;
224 unsigned int addr_slot, rdata, tmp, tmp_t;
225 unsigned int ddrc_w2r, ddrc_r2w, ddrc_wr_gap, ddrc_rd_gap;
226
227 ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
228 for (i = 0; i < pstat_num; i++) {
229 addr_slot = i ? (i + 1) * 0x1000 : 0;
230 if (ddr_type == 0x20) {
231 /* update r2w:[13:8], w2r:[5:0] */
232 rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
233 ddrc_w2r = rdata & 0x3f;
234 if (is_imx8mp())
235 tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
236 else
237 tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
238 ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
239
240 ddrc_r2w = (rdata >> 8) & 0x3f;
241 if (is_imx8mp())
242 tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
243 else
244 tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
245 ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
246
247 tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r;
248 reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
249 } else {
250 /* update w2r:[5:0] */
251 rdata = reg32_read(DDRC_DRAMTMG9(0) + addr_slot);
252 ddrc_w2r = rdata & 0x3f;
253 if (is_imx8mp())
254 tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
255 else
256 tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
257 ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
258 tmp_t = (rdata & 0xffffffc0) | ddrc_w2r;
259 reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t);
260
261 /* update r2w:[13:8] */
262 rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
263 ddrc_r2w = (rdata >> 8) & 0x3f;
264 if (is_imx8mp())
265 tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
266 else
267 tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
268 ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
269
270 tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8);
271 reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
272 }
273
274 if (!is_imx8mq()) {
275 /*
276 * update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static)
277 */
278 rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot);
279 ddrc_wr_gap = (rdata >> 8) & 0xf;
280 if (is_imx8mp())
281 tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1);
282 else
283 tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1;
284 ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
285
286 ddrc_rd_gap = (rdata >> 4) & 0xf;
287 if (is_imx8mp())
288 tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1);
289 else
290 tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1;
291 ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
292
293 tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
294 reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t);
295 }
296 }
297
298 if (is_imx8mq()) {
299 /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
300 rdata = reg32_read(DDRC_RANKCTL(0));
301 ddrc_wr_gap = (rdata >> 8) & 0xf;
302 tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1;
303 ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
304
305 ddrc_rd_gap = (rdata >> 4) & 0xf;
306 tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1;
307 ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
308
309 tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
310 reg32_write(DDRC_RANKCTL(0), tmp_t);
311 }
312}
313
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +0000314int ddr_init(struct dram_timing_info *dram_timing)
Jacky Baid62ddc12019-08-08 09:59:08 +0000315{
316 unsigned int tmp, initial_drate, target_freq;
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +0000317 int ret;
Jacky Baid62ddc12019-08-08 09:59:08 +0000318
Fabio Estevam9f7ee332019-12-11 17:37:09 -0300319 debug("DDRINFO: start DRAM init\n");
Jacky Baid62ddc12019-08-08 09:59:08 +0000320
321 /* Step1: Follow the power up procedure */
322 if (is_imx8mq()) {
323 reg32_write(SRC_DDRC_RCR_ADDR + 0x04, 0x8F00000F);
324 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F00000F);
325 reg32_write(SRC_DDRC_RCR_ADDR + 0x04, 0x8F000000);
326 } else {
327 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F00001F);
328 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F00000F);
329 }
330
331 debug("DDRINFO: cfg clk\n");
332 /* change the clock source of dram_apb_clk_root: source 4 800MHz /4 = 200MHz */
333 clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(4) |
334 CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV4));
335
Jacky Baid62ddc12019-08-08 09:59:08 +0000336 /* disable iso */
337 reg32_write(0x303A00EC, 0x0000ffff); /* PGC_CPU_MAPPING */
338 reg32setbit(0x303A00F8, 5); /* PU_PGC_SW_PUP_REQ */
339
Jacky Bai828d41b2019-08-08 09:59:11 +0000340 initial_drate = dram_timing->fsp_msg[0].drate;
341 /* default to the frequency point 0 clock */
342 ddrphy_init_set_dfi_clk(initial_drate);
343
Jacky Baid62ddc12019-08-08 09:59:08 +0000344 /* D-aasert the presetn */
345 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000006);
346
347 /* Step2: Program the dwc_ddr_umctl2 registers */
348 debug("DDRINFO: ddrc config start\n");
349 ddr_cfg_umctl2(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num);
350 debug("DDRINFO: ddrc config done\n");
351
352 /* Step3: De-assert reset signal(core_ddrc_rstn & aresetn_n) */
353 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000004);
354 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000000);
355
356 /*
357 * Step4: Disable auto-refreshes, self-refresh, powerdown, and
358 * assertion of dfi_dram_clk_disable by setting RFSHCTL3.dis_auto_refresh = 1,
359 * PWRCTL.powerdown_en = 0, and PWRCTL.selfref_en = 0, PWRCTL.en_dfi_dram_clk_disable = 0
360 */
361 reg32_write(DDRC_DBG1(0), 0x00000000);
362 reg32_write(DDRC_RFSHCTL3(0), 0x0000001);
363 reg32_write(DDRC_PWRCTL(0), 0xa0);
364
365 /* if ddr type is LPDDR4, do it */
366 tmp = reg32_read(DDRC_MSTR(0));
Jacky Baiedae3662019-06-05 11:26:12 +0800367 if (tmp & (0x1 << 5) && !is_imx8mn())
Jacky Baid62ddc12019-08-08 09:59:08 +0000368 reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
369
370 /* determine the initial boot frequency */
371 target_freq = reg32_read(DDRC_MSTR2(0)) & 0x3;
372 target_freq = (tmp & (0x1 << 29)) ? target_freq : 0x0;
373
374 /* Step5: Set SWCT.sw_done to 0 */
375 reg32_write(DDRC_SWCTL(0), 0x00000000);
376
377 /* Set the default boot frequency point */
378 clrsetbits_le32(DDRC_DFIMISC(0), (0x1f << 8), target_freq << 8);
379 /* Step6: Set DFIMISC.dfi_init_complete_en to 0 */
380 clrbits_le32(DDRC_DFIMISC(0), 0x1);
381
382 /* Step7: Set SWCTL.sw_done to 1; need to polling SWSTAT.sw_done_ack */
383 reg32_write(DDRC_SWCTL(0), 0x00000001);
384 do {
385 tmp = reg32_read(DDRC_SWSTAT(0));
386 } while ((tmp & 0x1) == 0x0);
387
388 /*
389 * Step8 ~ Step13: Start PHY initialization and training by
390 * accessing relevant PUB registers
391 */
392 debug("DDRINFO:ddrphy config start\n");
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +0000393
394 ret = ddr_cfg_phy(dram_timing);
395 if (ret)
396 return ret;
397
Jacky Baid62ddc12019-08-08 09:59:08 +0000398 debug("DDRINFO: ddrphy config done\n");
399
400 /*
401 * step14 CalBusy.0 =1, indicates the calibrator is actively
402 * calibrating. Wait Calibrating done.
403 */
404 do {
405 tmp = reg32_read(DDRPHY_CalBusy(0));
406 } while ((tmp & 0x1));
407
Fabio Estevam9f7ee332019-12-11 17:37:09 -0300408 debug("DDRINFO:ddrphy calibration done\n");
Jacky Baid62ddc12019-08-08 09:59:08 +0000409
410 /* Step15: Set SWCTL.sw_done to 0 */
411 reg32_write(DDRC_SWCTL(0), 0x00000000);
412
Oliver Chen42eda3a2020-04-21 14:48:09 +0800413 /* Apply rank-to-rank workaround */
414 update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1);
415
Jacky Baid62ddc12019-08-08 09:59:08 +0000416 /* Step16: Set DFIMISC.dfi_init_start to 1 */
417 setbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
418
419 /* Step17: Set SWCTL.sw_done to 1; need to polling SWSTAT.sw_done_ack */
420 reg32_write(DDRC_SWCTL(0), 0x00000001);
421 do {
422 tmp = reg32_read(DDRC_SWSTAT(0));
423 } while ((tmp & 0x1) == 0x0);
424
425 /* Step18: Polling DFISTAT.dfi_init_complete = 1 */
426 do {
427 tmp = reg32_read(DDRC_DFISTAT(0));
428 } while ((tmp & 0x1) == 0x0);
429
430 /* Step19: Set SWCTL.sw_done to 0 */
431 reg32_write(DDRC_SWCTL(0), 0x00000000);
432
433 /* Step20: Set DFIMISC.dfi_init_start to 0 */
434 clrbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
435
436 /* Step21: optional */
437
438 /* Step22: Set DFIMISC.dfi_init_complete_en to 1 */
439 setbits_le32(DDRC_DFIMISC(0), 0x1);
440
441 /* Step23: Set PWRCTL.selfref_sw to 0 */
442 clrbits_le32(DDRC_PWRCTL(0), (0x1 << 5));
443
444 /* Step24: Set SWCTL.sw_done to 1; need polling SWSTAT.sw_done_ack */
445 reg32_write(DDRC_SWCTL(0), 0x00000001);
446 do {
447 tmp = reg32_read(DDRC_SWSTAT(0));
448 } while ((tmp & 0x1) == 0x0);
449
450 /* Step25: Wait for dwc_ddr_umctl2 to move to normal operating mode by monitoring
451 * STAT.operating_mode signal */
452 do {
453 tmp = reg32_read(DDRC_STAT(0));
454 } while ((tmp & 0x3) != 0x1);
455
456 /* Step26: Set back register in Step4 to the original values if desired */
457 reg32_write(DDRC_RFSHCTL3(0), 0x0000000);
Jacky Baid62ddc12019-08-08 09:59:08 +0000458
459 /* enable port 0 */
460 reg32_write(DDRC_PCTRL_0(0), 0x00000001);
Fabio Estevam9f7ee332019-12-11 17:37:09 -0300461 debug("DDRINFO: ddrmix config done\n");
Jacky Baid62ddc12019-08-08 09:59:08 +0000462
Sherry Sun7957bd62020-01-20 11:13:14 +0800463 board_dram_ecc_scrub();
464
Ye Li36fcf112020-09-29 21:55:32 -0700465 /* enable selfref_en by default */
466 setbits_le32(DDRC_PWRCTL(0), 0x1);
467
Jacky Baid62ddc12019-08-08 09:59:08 +0000468 /* save the dram timing config into memory */
469 dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE);
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +0000470
471 return 0;
Jacky Baid62ddc12019-08-08 09:59:08 +0000472}
Ye Lib2cfc422022-07-26 16:41:07 +0800473
474ulong ddrphy_addr_remap(uint32_t paddr_apb_from_ctlr)
475{
476 return 4 * paddr_apb_from_ctlr;
477}