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