blob: 99a67edfb0a8fc0aa89058bd476007af9395cab2 [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
14void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
15{
16 int i = 0;
17
18 for (i = 0; i < num; i++) {
19 reg32_write(ddrc_cfg->reg, ddrc_cfg->val);
20 ddrc_cfg++;
21 }
22}
23
Sherry Sun7957bd62020-01-20 11:13:14 +080024#ifdef CONFIG_IMX8M_DRAM_INLINE_ECC
25void ddrc_inline_ecc_scrub(unsigned int start_address,
26 unsigned int range_address)
27{
28 unsigned int tmp;
29
30 /* Step1: Enable quasi-dynamic programming */
31 reg32_write(DDRC_SWCTL(0), 0x00000000);
32 /* Step2: Set ECCCFG1.ecc_parity_region_lock to 1 */
33 reg32setbit(DDRC_ECCCFG1(0), 0x4);
34 /* Step3: Block the AXI ports from taking the transaction */
35 reg32_write(DDRC_PCTRL_0(0), 0x0);
36 /* Step4: Set scrub start address */
37 reg32_write(DDRC_SBRSTART0(0), start_address);
38 /* Step5: Set scrub range address */
39 reg32_write(DDRC_SBRRANGE0(0), range_address);
40 /* Step6: Set scrub_mode to write */
41 reg32_write(DDRC_SBRCTL(0), 0x00000014);
42 /* Step7: Set the desired pattern through SBRWDATA0 registers */
43 reg32_write(DDRC_SBRWDATA0(0), 0x55aa55aa);
44 /* Step8: Enable the SBR by programming SBRCTL.scrub_en=1 */
45 reg32setbit(DDRC_SBRCTL(0), 0x0);
46 /* Step9: Poll SBRSTAT.scrub_done=1 */
47 tmp = reg32_read(DDRC_SBRSTAT(0));
48 while (tmp != 0x00000002)
49 tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x2;
50 /* Step10: Poll SBRSTAT.scrub_busy=0 */
51 tmp = reg32_read(DDRC_SBRSTAT(0));
52 while (tmp != 0x0)
53 tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x1;
54 /* Step11: Disable SBR by programming SBRCTL.scrub_en=0 */
55 clrbits_le32(DDRC_SBRCTL(0), 0x1);
56 /* Step12: Prepare for normal scrub operation(Read) and set scrub_interval*/
57 reg32_write(DDRC_SBRCTL(0), 0x100);
58 /* Step13: Enable the SBR by programming SBRCTL.scrub_en=1 */
59 reg32_write(DDRC_SBRCTL(0), 0x101);
60 /* Step14: Enable AXI ports by programming */
61 reg32_write(DDRC_PCTRL_0(0), 0x1);
62 /* Step15: Disable quasi-dynamic programming */
63 reg32_write(DDRC_SWCTL(0), 0x00000001);
64}
65
66void ddrc_inline_ecc_scrub_end(unsigned int start_address,
67 unsigned int range_address)
68{
69 /* Step1: Enable quasi-dynamic programming */
70 reg32_write(DDRC_SWCTL(0), 0x00000000);
71 /* Step2: Block the AXI ports from taking the transaction */
72 reg32_write(DDRC_PCTRL_0(0), 0x0);
73 /* Step3: Set scrub start address */
74 reg32_write(DDRC_SBRSTART0(0), start_address);
75 /* Step4: Set scrub range address */
76 reg32_write(DDRC_SBRRANGE0(0), range_address);
77 /* Step5: Disable SBR by programming SBRCTL.scrub_en=0 */
78 clrbits_le32(DDRC_SBRCTL(0), 0x1);
79 /* Step6: Prepare for normal scrub operation(Read) and set scrub_interval */
80 reg32_write(DDRC_SBRCTL(0), 0x100);
81 /* Step7: Enable the SBR by programming SBRCTL.scrub_en=1 */
82 reg32_write(DDRC_SBRCTL(0), 0x101);
83 /* Step8: Enable AXI ports by programming */
84 reg32_write(DDRC_PCTRL_0(0), 0x1);
85 /* Step9: Disable quasi-dynamic programming */
86 reg32_write(DDRC_SWCTL(0), 0x00000001);
87}
88#endif
89
90void __weak board_dram_ecc_scrub(void)
91{
92}
93
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +000094int ddr_init(struct dram_timing_info *dram_timing)
Jacky Baid62ddc12019-08-08 09:59:08 +000095{
96 unsigned int tmp, initial_drate, target_freq;
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +000097 int ret;
Jacky Baid62ddc12019-08-08 09:59:08 +000098
Fabio Estevam9f7ee332019-12-11 17:37:09 -030099 debug("DDRINFO: start DRAM init\n");
Jacky Baid62ddc12019-08-08 09:59:08 +0000100
101 /* Step1: Follow the power up procedure */
102 if (is_imx8mq()) {
103 reg32_write(SRC_DDRC_RCR_ADDR + 0x04, 0x8F00000F);
104 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F00000F);
105 reg32_write(SRC_DDRC_RCR_ADDR + 0x04, 0x8F000000);
106 } else {
107 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F00001F);
108 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F00000F);
109 }
110
111 debug("DDRINFO: cfg clk\n");
112 /* change the clock source of dram_apb_clk_root: source 4 800MHz /4 = 200MHz */
113 clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(4) |
114 CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV4));
115
Jacky Baid62ddc12019-08-08 09:59:08 +0000116 /* disable iso */
117 reg32_write(0x303A00EC, 0x0000ffff); /* PGC_CPU_MAPPING */
118 reg32setbit(0x303A00F8, 5); /* PU_PGC_SW_PUP_REQ */
119
Jacky Bai828d41b2019-08-08 09:59:11 +0000120 initial_drate = dram_timing->fsp_msg[0].drate;
121 /* default to the frequency point 0 clock */
122 ddrphy_init_set_dfi_clk(initial_drate);
123
Jacky Baid62ddc12019-08-08 09:59:08 +0000124 /* D-aasert the presetn */
125 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000006);
126
127 /* Step2: Program the dwc_ddr_umctl2 registers */
128 debug("DDRINFO: ddrc config start\n");
129 ddr_cfg_umctl2(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num);
130 debug("DDRINFO: ddrc config done\n");
131
132 /* Step3: De-assert reset signal(core_ddrc_rstn & aresetn_n) */
133 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000004);
134 reg32_write(SRC_DDRC_RCR_ADDR, 0x8F000000);
135
136 /*
137 * Step4: Disable auto-refreshes, self-refresh, powerdown, and
138 * assertion of dfi_dram_clk_disable by setting RFSHCTL3.dis_auto_refresh = 1,
139 * PWRCTL.powerdown_en = 0, and PWRCTL.selfref_en = 0, PWRCTL.en_dfi_dram_clk_disable = 0
140 */
141 reg32_write(DDRC_DBG1(0), 0x00000000);
142 reg32_write(DDRC_RFSHCTL3(0), 0x0000001);
143 reg32_write(DDRC_PWRCTL(0), 0xa0);
144
145 /* if ddr type is LPDDR4, do it */
146 tmp = reg32_read(DDRC_MSTR(0));
Jacky Baiedae3662019-06-05 11:26:12 +0800147 if (tmp & (0x1 << 5) && !is_imx8mn())
Jacky Baid62ddc12019-08-08 09:59:08 +0000148 reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
149
150 /* determine the initial boot frequency */
151 target_freq = reg32_read(DDRC_MSTR2(0)) & 0x3;
152 target_freq = (tmp & (0x1 << 29)) ? target_freq : 0x0;
153
154 /* Step5: Set SWCT.sw_done to 0 */
155 reg32_write(DDRC_SWCTL(0), 0x00000000);
156
157 /* Set the default boot frequency point */
158 clrsetbits_le32(DDRC_DFIMISC(0), (0x1f << 8), target_freq << 8);
159 /* Step6: Set DFIMISC.dfi_init_complete_en to 0 */
160 clrbits_le32(DDRC_DFIMISC(0), 0x1);
161
162 /* Step7: Set SWCTL.sw_done to 1; need to polling SWSTAT.sw_done_ack */
163 reg32_write(DDRC_SWCTL(0), 0x00000001);
164 do {
165 tmp = reg32_read(DDRC_SWSTAT(0));
166 } while ((tmp & 0x1) == 0x0);
167
168 /*
169 * Step8 ~ Step13: Start PHY initialization and training by
170 * accessing relevant PUB registers
171 */
172 debug("DDRINFO:ddrphy config start\n");
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +0000173
174 ret = ddr_cfg_phy(dram_timing);
175 if (ret)
176 return ret;
177
Jacky Baid62ddc12019-08-08 09:59:08 +0000178 debug("DDRINFO: ddrphy config done\n");
179
180 /*
181 * step14 CalBusy.0 =1, indicates the calibrator is actively
182 * calibrating. Wait Calibrating done.
183 */
184 do {
185 tmp = reg32_read(DDRPHY_CalBusy(0));
186 } while ((tmp & 0x1));
187
Fabio Estevam9f7ee332019-12-11 17:37:09 -0300188 debug("DDRINFO:ddrphy calibration done\n");
Jacky Baid62ddc12019-08-08 09:59:08 +0000189
190 /* Step15: Set SWCTL.sw_done to 0 */
191 reg32_write(DDRC_SWCTL(0), 0x00000000);
192
Oliver Chen42eda3a2020-04-21 14:48:09 +0800193 /* Apply rank-to-rank workaround */
194 update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1);
195
Jacky Baid62ddc12019-08-08 09:59:08 +0000196 /* Step16: Set DFIMISC.dfi_init_start to 1 */
197 setbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
198
199 /* Step17: Set SWCTL.sw_done to 1; need to polling SWSTAT.sw_done_ack */
200 reg32_write(DDRC_SWCTL(0), 0x00000001);
201 do {
202 tmp = reg32_read(DDRC_SWSTAT(0));
203 } while ((tmp & 0x1) == 0x0);
204
205 /* Step18: Polling DFISTAT.dfi_init_complete = 1 */
206 do {
207 tmp = reg32_read(DDRC_DFISTAT(0));
208 } while ((tmp & 0x1) == 0x0);
209
210 /* Step19: Set SWCTL.sw_done to 0 */
211 reg32_write(DDRC_SWCTL(0), 0x00000000);
212
213 /* Step20: Set DFIMISC.dfi_init_start to 0 */
214 clrbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
215
216 /* Step21: optional */
217
218 /* Step22: Set DFIMISC.dfi_init_complete_en to 1 */
219 setbits_le32(DDRC_DFIMISC(0), 0x1);
220
221 /* Step23: Set PWRCTL.selfref_sw to 0 */
222 clrbits_le32(DDRC_PWRCTL(0), (0x1 << 5));
223
224 /* Step24: Set SWCTL.sw_done to 1; need polling SWSTAT.sw_done_ack */
225 reg32_write(DDRC_SWCTL(0), 0x00000001);
226 do {
227 tmp = reg32_read(DDRC_SWSTAT(0));
228 } while ((tmp & 0x1) == 0x0);
229
230 /* Step25: Wait for dwc_ddr_umctl2 to move to normal operating mode by monitoring
231 * STAT.operating_mode signal */
232 do {
233 tmp = reg32_read(DDRC_STAT(0));
234 } while ((tmp & 0x3) != 0x1);
235
236 /* Step26: Set back register in Step4 to the original values if desired */
237 reg32_write(DDRC_RFSHCTL3(0), 0x0000000);
238 /* enable selfref_en by default */
Jacky Bai9f981ca2020-02-10 18:02:00 +0800239 setbits_le32(DDRC_PWRCTL(0), 0x1);
Jacky Baid62ddc12019-08-08 09:59:08 +0000240
241 /* enable port 0 */
242 reg32_write(DDRC_PCTRL_0(0), 0x00000001);
Fabio Estevam9f7ee332019-12-11 17:37:09 -0300243 debug("DDRINFO: ddrmix config done\n");
Jacky Baid62ddc12019-08-08 09:59:08 +0000244
Sherry Sun7957bd62020-01-20 11:13:14 +0800245 board_dram_ecc_scrub();
246
Jacky Baid62ddc12019-08-08 09:59:08 +0000247 /* save the dram timing config into memory */
248 dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE);
Frieder Schrempf2a9b1f52019-12-11 10:01:19 +0000249
250 return 0;
Jacky Baid62ddc12019-08-08 09:59:08 +0000251}