blob: 3aa3ce76272ce977ed2b1b177ba5f54337e9d654 [file] [log] [blame]
Icenowy Zheng645ee3c2022-01-29 10:23:04 -05001// SPDX-License-Identifier: (GPL-2.0+)
2/*
3 * suniv DRAM initialization
4 *
5 * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
6 *
7 * Based on xboot's arch/arm32/mach-f1c100s/sys-dram.c, which is:
8 *
9 * Copyright(c) 2007-2018 Jianjun Jiang <8192542@qq.com>
10 */
11
12#include <common.h>
13#include <asm/io.h>
14#include <asm/arch/clock.h>
15#include <asm/arch/dram.h>
16#include <asm/arch/gpio.h>
17#include <linux/bitops.h>
18#include <linux/delay.h>
19#include <hang.h>
20
21#define SDR_T_CAS (0x2)
22#define SDR_T_RAS (0x8)
23#define SDR_T_RCD (0x3)
24#define SDR_T_RP (0x3)
25#define SDR_T_WR (0x3)
26#define SDR_T_RFC (0xd)
27#define SDR_T_XSR (0xf9)
28#define SDR_T_RC (0xb)
29#define SDR_T_INIT (0x8)
30#define SDR_T_INIT_REF (0x7)
31#define SDR_T_WTR (0x2)
32#define SDR_T_RRD (0x2)
33#define SDR_T_XP (0x0)
34
35enum dram_type {
36 DRAM_TYPE_SDR = 0,
37 DRAM_TYPE_DDR = 1,
38 /* Not supported yet. */
39 DRAM_TYPE_MDDR = 2,
40};
41
42struct dram_para {
43 u32 size; /* dram size (unit: MByte) */
44 u32 clk; /* dram work clock (unit: MHz) */
45 u32 access_mode; /* 0: interleave mode 1: sequence mode */
46 u32 cs_num; /* dram chip count 1: one chip 2: two chip */
47 u32 ddr8_remap; /* for 8bits data width DDR 0: normal 1: 8bits */
48 enum dram_type sdr_ddr;
49 u32 bwidth; /* dram bus width */
50 u32 col_width; /* column address width */
51 u32 row_width; /* row address width */
52 u32 bank_size; /* dram bank count */
53 u32 cas; /* dram cas */
54};
55
56struct dram_para suniv_dram_para = {
57 .size = 32,
58 .clk = 156,
59 .access_mode = 1,
60 .cs_num = 1,
61 .ddr8_remap = 0,
62 .sdr_ddr = DRAM_TYPE_DDR,
63 .bwidth = 16,
64 .col_width = 10,
65 .row_width = 13,
66 .bank_size = 4,
67 .cas = 0x3,
68};
69
70static int dram_initial(void)
71{
72 unsigned int time = 0xffffff;
73
74 setbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR, 0x1);
75 while ((readl(SUNXI_DRAMC_BASE + DRAM_SCTLR) & 0x1) && time--) {
76 if (time == 0)
77 return 0;
78 }
79 return 1;
80}
81
82static int dram_delay_scan(void)
83{
84 unsigned int time = 0xffffff;
85
86 setbits_le32(SUNXI_DRAMC_BASE + DRAM_DDLYR, 0x1);
87 while ((readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) & 0x1) && time--) {
88 if (time == 0)
89 return 0;
90 }
91 return 1;
92}
93
94static void dram_set_autofresh_cycle(u32 clk)
95{
96 u32 val = 0;
97 u32 row = 0;
98 u32 temp = 0;
99
100 row = readl(SUNXI_DRAMC_BASE + DRAM_SCONR);
101 row &= 0x1e0;
102 row >>= 0x5;
103
104 if (row == 0xc) {
105 if (clk >= 1000000) {
106 temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
107 while (temp >= (10000000 >> 6)) {
108 temp -= (10000000 >> 6);
109 val++;
110 }
111 } else {
112 val = (clk * 499) >> 6;
113 }
114 } else if (row == 0xb) {
115 if (clk >= 1000000) {
116 temp = clk + (clk >> 3) + (clk >> 4) + (clk >> 5);
117 while (temp >= (10000000 >> 7)) {
118 temp -= (10000000 >> 7);
119 val++;
120 }
121 } else {
122 val = (clk * 499) >> 5;
123 }
124 }
125 writel(val, SUNXI_DRAMC_BASE + DRAM_SREFR);
126}
127
128static int dram_para_setup(struct dram_para *para)
129{
130 u32 val = 0;
131
132 val = (para->ddr8_remap) | (0x1 << 1) |
133 ((para->bank_size >> 2) << 3) |
134 ((para->cs_num >> 1) << 4) |
135 ((para->row_width - 1) << 5) |
136 ((para->col_width - 1) << 9) |
137 ((para->sdr_ddr ? (para->bwidth >> 4) : (para->bwidth >> 5)) << 13) |
138 (para->access_mode << 15) |
139 (para->sdr_ddr << 16);
140
141 writel(val, SUNXI_DRAMC_BASE + DRAM_SCONR);
142 setbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR, 0x1 << 19);
143 return dram_initial();
144}
145
146static u32 dram_check_delay(u32 bwidth)
147{
148 u32 dsize;
149 int i, j;
150 u32 num = 0;
151 u32 dflag = 0;
152
153 dsize = ((bwidth == 16) ? 4 : 2);
154 for (i = 0; i < dsize; i++) {
155 if (i == 0)
156 dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR0);
157 else if (i == 1)
158 dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR1);
159 else if (i == 2)
160 dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR2);
161 else if (i == 3)
162 dflag = readl(SUNXI_DRAMC_BASE + DRAM_DRPTR3);
163
164 for (j = 0; j < 32; j++) {
165 if (dflag & 0x1)
166 num++;
167 dflag >>= 1;
168 }
169 }
170 return num;
171}
172
173static int sdr_readpipe_scan(void)
174{
175 u32 k = 0;
176
177 for (k = 0; k < 32; k++)
Tom Riniaa6e94d2022-11-16 13:10:37 -0500178 writel(k, CFG_SYS_SDRAM_BASE + 4 * k);
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500179 for (k = 0; k < 32; k++) {
Tom Riniaa6e94d2022-11-16 13:10:37 -0500180 if (readl(CFG_SYS_SDRAM_BASE + 4 * k) != k)
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500181 return 0;
182 }
183 return 1;
184}
185
186static u32 sdr_readpipe_select(void)
187{
188 u32 value = 0;
189 u32 i = 0;
190
191 for (i = 0; i < 8; i++) {
192 clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
193 0x7 << 6, i << 6);
194 if (sdr_readpipe_scan()) {
195 value = i;
196 return value;
197 }
198 }
199 return value;
200}
201
202static u32 dram_check_type(struct dram_para *para)
203{
204 u32 times = 0;
205 int i;
206
207 for (i = 0; i < 8; i++) {
208 clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
209 0x7 << 6, i << 6);
210 dram_delay_scan();
211 if (readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) & 0x30)
212 times++;
213 }
214
215 if (times == 8) {
216 para->sdr_ddr = DRAM_TYPE_SDR;
217 return 0;
218 }
219 para->sdr_ddr = DRAM_TYPE_DDR;
220 return 1;
221}
222
223static u32 dram_scan_readpipe(struct dram_para *para)
224{
225 u32 rp_best = 0, rp_val = 0;
226 u32 readpipe[8];
227 int i;
228
229 if (para->sdr_ddr == DRAM_TYPE_DDR) {
230 for (i = 0; i < 8; i++) {
231 clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
232 0x7 << 6, i << 6);
233 dram_delay_scan();
234 readpipe[i] = 0;
235 if ((((readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) >> 4) & 0x3) == 0x0) &&
236 (((readl(SUNXI_DRAMC_BASE + DRAM_DDLYR) >> 4) & 0x1) == 0x0))
237 readpipe[i] = dram_check_delay(para->bwidth);
238 if (rp_val < readpipe[i]) {
239 rp_val = readpipe[i];
240 rp_best = i;
241 }
242 }
243 clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
244 0x7 << 6, rp_best << 6);
245 dram_delay_scan();
246 } else {
247 clrbits_le32(SUNXI_DRAMC_BASE + DRAM_SCONR,
248 (0x1 << 16) | (0x3 << 13));
249 rp_best = sdr_readpipe_select();
250 clrsetbits_le32(SUNXI_DRAMC_BASE + DRAM_SCTLR,
251 0x7 << 6, rp_best << 6);
252 }
253 return 0;
254}
255
256static u32 dram_get_dram_size(struct dram_para *para)
257{
258 u32 colflag = 10, rowflag = 13;
259 u32 val1 = 0;
260 u32 count = 0;
261 u32 addr1, addr2;
262 int i;
263
264 para->col_width = colflag;
265 para->row_width = rowflag;
266 dram_para_setup(para);
267 dram_scan_readpipe(para);
268 for (i = 0; i < 32; i++) {
Tom Riniaa6e94d2022-11-16 13:10:37 -0500269 *((u8 *)(CFG_SYS_SDRAM_BASE + 0x200 + i)) = 0x11;
270 *((u8 *)(CFG_SYS_SDRAM_BASE + 0x600 + i)) = 0x22;
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500271 }
272 for (i = 0; i < 32; i++) {
Tom Riniaa6e94d2022-11-16 13:10:37 -0500273 val1 = *((u8 *)(CFG_SYS_SDRAM_BASE + 0x200 + i));
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500274 if (val1 == 0x22)
275 count++;
276 }
277 if (count == 32)
278 colflag = 9;
279 else
280 colflag = 10;
281 count = 0;
282 para->col_width = colflag;
283 para->row_width = rowflag;
284 dram_para_setup(para);
285 if (colflag == 10) {
Tom Riniaa6e94d2022-11-16 13:10:37 -0500286 addr1 = CFG_SYS_SDRAM_BASE + 0x400000;
287 addr2 = CFG_SYS_SDRAM_BASE + 0xc00000;
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500288 } else {
Tom Riniaa6e94d2022-11-16 13:10:37 -0500289 addr1 = CFG_SYS_SDRAM_BASE + 0x200000;
290 addr2 = CFG_SYS_SDRAM_BASE + 0x600000;
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500291 }
292 for (i = 0; i < 32; i++) {
293 *((u8 *)(addr1 + i)) = 0x33;
294 *((u8 *)(addr2 + i)) = 0x44;
295 }
296 for (i = 0; i < 32; i++) {
297 val1 = *((u8 *)(addr1 + i));
298 if (val1 == 0x44)
299 count++;
300 }
301 if (count == 32)
302 rowflag = 12;
303 else
304 rowflag = 13;
305 para->col_width = colflag;
306 para->row_width = rowflag;
307 if (para->row_width != 13)
308 para->size = 16;
309 else if (para->col_width == 10)
310 para->size = 64;
311 else
312 para->size = 32;
313 dram_set_autofresh_cycle(para->clk);
314 para->access_mode = 0;
315 dram_para_setup(para);
316
317 return 0;
318}
319
320static void simple_dram_check(void)
321{
Tom Riniaa6e94d2022-11-16 13:10:37 -0500322 volatile u32 *dram = (u32 *)CFG_SYS_SDRAM_BASE;
Icenowy Zheng645ee3c2022-01-29 10:23:04 -0500323 int i;
324
325 for (i = 0; i < 0x40; i++)
326 dram[i] = i;
327
328 for (i = 0; i < 0x40; i++) {
329 if (dram[i] != i) {
330 printf("DRAM initialization failed: dram[0x%x] != 0x%x.", i, dram[i]);
331 hang();
332 }
333 }
334
335 for (i = 0; i < 0x10000; i += 0x40)
336 dram[i] = i;
337
338 for (i = 0; i < 0x10000; i += 0x40) {
339 if (dram[i] != i) {
340 printf("DRAM initialization failed: dram[0x%x] != 0x%x.", i, dram[i]);
341 hang();
342 }
343 }
344}
345
346static void do_dram_init(struct dram_para *para)
347{
348 struct sunxi_ccm_reg * const ccm =
349 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
350 u32 val;
351 u8 m; /* PLL_DDR clock factor */
352
353 sunxi_gpio_set_cfgpin(SUNXI_GPB(3), 0x7);
354 mdelay(5);
355 /* TODO: dig out what's them... some analog register? */
356 if ((para->cas >> 3) & 0x1)
357 setbits_le32(SUNXI_PIO_BASE + 0x2c4, (0x1 << 23) | (0x20 << 17));
358
359 if (para->clk >= 144 && para->clk <= 180)
360 writel(0xaaa, SUNXI_PIO_BASE + 0x2c0);
361 if (para->clk >= 180)
362 writel(0xfff, SUNXI_PIO_BASE + 0x2c0);
363
364 if (para->cas & BIT(4))
365 writel(0xd1303333, &ccm->pll5_pattern_cfg);
366 else if (para->cas & BIT(5))
367 writel(0xcce06666, &ccm->pll5_pattern_cfg);
368 else if (para->cas & BIT(6))
369 writel(0xc8909999, &ccm->pll5_pattern_cfg);
370 else if (para->cas & BIT(7))
371 writel(0xc440cccc, &ccm->pll5_pattern_cfg);
372
373 if (para->clk <= 96)
374 m = 2;
375 else
376 m = 1;
377
378 val = CCM_PLL5_CTRL_EN | CCM_PLL5_CTRL_UPD |
379 CCM_PLL5_CTRL_N((para->clk * 2) / (24 / m)) |
380 CCM_PLL5_CTRL_K(1) | CCM_PLL5_CTRL_M(m);
381 if (para->cas & GENMASK(7, 4))
382 val |= CCM_PLL5_CTRL_SIGMA_DELTA_EN;
383 writel(val, &ccm->pll5_cfg);
384 setbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_UPD);
385 mctl_await_completion(&ccm->pll5_cfg, BIT(28), BIT(28));
386 mdelay(5);
387
388 setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_MCTL));
389 clrbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_RESET_OFFSET_MCTL));
390 udelay(50);
391 setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_RESET_OFFSET_MCTL));
392
393 clrsetbits_le32(SUNXI_PIO_BASE + 0x2c4, (1 << 16),
394 ((para->sdr_ddr == DRAM_TYPE_DDR) << 16));
395
396 val = (SDR_T_CAS << 0) | (SDR_T_RAS << 3) | (SDR_T_RCD << 7) |
397 (SDR_T_RP << 10) | (SDR_T_WR << 13) | (SDR_T_RFC << 15) |
398 (SDR_T_XSR << 19) | (SDR_T_RC << 28);
399 writel(val, SUNXI_DRAMC_BASE + DRAM_STMG0R);
400 val = (SDR_T_INIT << 0) | (SDR_T_INIT_REF << 16) | (SDR_T_WTR << 20) |
401 (SDR_T_RRD << 22) | (SDR_T_XP << 25);
402 writel(val, SUNXI_DRAMC_BASE + DRAM_STMG1R);
403 dram_para_setup(para);
404 dram_check_type(para);
405
406 clrsetbits_le32(SUNXI_PIO_BASE + 0x2c4, (1 << 16),
407 ((para->sdr_ddr == DRAM_TYPE_DDR) << 16));
408
409 dram_set_autofresh_cycle(para->clk);
410 dram_scan_readpipe(para);
411 dram_get_dram_size(para);
412 simple_dram_check();
413}
414
415unsigned long sunxi_dram_init(void)
416{
417 do_dram_init(&suniv_dram_para);
418
419 return suniv_dram_para.size * 1024 * 1024;
420}