blob: ec46ba54575e6315ea1ecd71a923fded56d248b6 [file] [log] [blame]
Kever Yangb5497b52019-11-15 11:04:37 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
4 */
5
6#include <common.h>
7#include <debug_uart.h>
8#include <ram.h>
9#include <asm/io.h>
10#include <asm/arch-rockchip/sdram.h>
11#include <asm/arch-rockchip/sdram_common.h>
12
Kever Yang8e005542019-11-15 11:04:38 +080013#ifdef CONFIG_RAM_ROCKCHIP_DEBUG
14void sdram_print_dram_type(unsigned char dramtype)
15{
16 switch (dramtype) {
17 case DDR3:
18 printascii("DDR3");
19 break;
20 case DDR4:
21 printascii("DDR4");
22 break;
23 case LPDDR2:
24 printascii("LPDDR2");
25 break;
26 case LPDDR3:
27 printascii("LPDDR3");
28 break;
29 case LPDDR4:
30 printascii("LPDDR4");
31 break;
32 default:
33 printascii("Unknown Device");
34 break;
35 }
36}
37
38void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
39 struct sdram_base_params *base)
40{
41 u64 cap;
42 u32 bg;
43
44 bg = (cap_info->dbw == 0) ? 2 : 1;
45
46 sdram_print_dram_type(base->dramtype);
47
48 printascii(", ");
49 printdec(base->ddr_freq);
50 printascii("MHz\n");
51
52 printascii("BW=");
53 printdec(8 << cap_info->bw);
54 printascii(" Col=");
55 printdec(cap_info->col);
56 printascii(" Bk=");
57 printdec(0x1 << cap_info->bk);
58 if (base->dramtype == DDR4) {
59 printascii(" BG=");
60 printdec(1 << bg);
61 }
62 printascii(" CS0 Row=");
63 printdec(cap_info->cs0_row);
64 if (cap_info->cs0_high16bit_row !=
65 cap_info->cs0_row) {
66 printascii("/");
67 printdec(cap_info->cs0_high16bit_row);
68 }
69 if (cap_info->rank > 1) {
70 printascii(" CS1 Row=");
71 printdec(cap_info->cs1_row);
72 if (cap_info->cs1_high16bit_row !=
73 cap_info->cs1_row) {
74 printascii("/");
75 printdec(cap_info->cs1_high16bit_row);
76 }
77 }
78 printascii(" CS=");
79 printdec(cap_info->rank);
80 printascii(" Die BW=");
81 printdec(8 << cap_info->dbw);
82
83 cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
84 if (cap_info->row_3_4)
85 cap = cap * 3 / 4;
86
87 printascii(" Size=");
88 printdec(cap >> 20);
89 printascii("MB\n");
90}
91
92void sdram_print_stride(unsigned int stride)
93{
94 switch (stride) {
95 case 0xc:
96 printf("128B stride\n");
97 break;
98 case 5:
99 case 9:
100 case 0xd:
101 case 0x11:
102 case 0x19:
103 printf("256B stride\n");
104 break;
105 case 0xa:
106 case 0xe:
107 case 0x12:
108 printf("512B stride\n");
109 break;
110 case 0xf:
111 printf("4K stride\n");
112 break;
113 case 0x1f:
114 printf("32MB + 256B stride\n");
115 break;
116 default:
117 printf("no stride\n");
118 }
119}
Kever Yang924f1042020-07-20 18:34:12 +0800120#else
121inline void sdram_print_dram_type(unsigned char dramtype)
122{
123}
124
125inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
126 struct sdram_base_params *base)
127{
128}
129
130inline void sdram_print_stride(unsigned int stride)
131{
132}
Kever Yang8e005542019-11-15 11:04:38 +0800133#endif
134
135/*
136 * cs: 0:cs0
137 * 1:cs1
138 * else cs0+cs1
139 * note: it didn't consider about row_3_4
140 */
141u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
142{
143 u32 bg;
144 u64 cap[2];
145
146 if (dram_type == DDR4)
147 /* DDR4 8bit dram BG = 2(4bank groups),
148 * 16bit dram BG = 1 (2 bank groups)
149 */
150 bg = (cap_info->dbw == 0) ? 2 : 1;
151 else
152 bg = 0;
153 cap[0] = 1llu << (cap_info->bw + cap_info->col +
154 bg + cap_info->bk + cap_info->cs0_row);
155
156 if (cap_info->rank == 2)
157 cap[1] = 1llu << (cap_info->bw + cap_info->col +
158 bg + cap_info->bk + cap_info->cs1_row);
159 else
160 cap[1] = 0;
161
162 if (cs == 0)
163 return cap[0];
164 else if (cs == 1)
165 return cap[1];
166 else
167 return (cap[0] + cap[1]);
168}
169
Kever Yangb5497b52019-11-15 11:04:37 +0800170/* n: Unit bytes */
171void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
172{
173 int i;
174
175 for (i = 0; i < n / sizeof(u32); i++) {
176 writel(*src, dest);
177 src++;
178 dest++;
179 }
180}
181
182void sdram_org_config(struct sdram_cap_info *cap_info,
183 struct sdram_base_params *base,
184 u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
185{
186 *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
187 *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
188
189 *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
190 *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
191 *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
192 *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
193 *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
194 *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
195 *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
196
197 SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
198 if (cap_info->cs1_row)
199 SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
200 *p_os_reg3, channel);
201 *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
202 *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
203}
204
205int sdram_detect_bw(struct sdram_cap_info *cap_info)
206{
207 return 0;
208}
209
210int sdram_detect_cs(struct sdram_cap_info *cap_info)
211{
212 return 0;
213}
214
215int sdram_detect_col(struct sdram_cap_info *cap_info,
216 u32 coltmp)
217{
218 void __iomem *test_addr;
219 u32 col;
220 u32 bw = cap_info->bw;
221
222 for (col = coltmp; col >= 9; col -= 1) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500223 writel(0, CFG_SYS_SDRAM_BASE);
224 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800225 (1ul << (col + bw - 1ul)));
226 writel(PATTERN, test_addr);
227 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500228 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800229 break;
230 }
231 if (col == 8) {
232 printascii("col error\n");
233 return -1;
234 }
235
236 cap_info->col = col;
237
238 return 0;
239}
240
241int sdram_detect_bank(struct sdram_cap_info *cap_info,
242 u32 coltmp, u32 bktmp)
243{
244 void __iomem *test_addr;
245 u32 bk;
246 u32 bw = cap_info->bw;
247
Tom Rinibb4dd962022-11-16 13:10:37 -0500248 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800249 (1ul << (coltmp + bktmp + bw - 1ul)));
Tom Rinibb4dd962022-11-16 13:10:37 -0500250 writel(0, CFG_SYS_SDRAM_BASE);
Kever Yangb5497b52019-11-15 11:04:37 +0800251 writel(PATTERN, test_addr);
252 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500253 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800254 bk = 3;
255 else
256 bk = 2;
257
258 cap_info->bk = bk;
259
260 return 0;
261}
262
263/* detect bg for ddr4 */
264int sdram_detect_bg(struct sdram_cap_info *cap_info,
265 u32 coltmp)
266{
267 void __iomem *test_addr;
268 u32 dbw;
269 u32 bw = cap_info->bw;
270
Tom Rinibb4dd962022-11-16 13:10:37 -0500271 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800272 (1ul << (coltmp + bw + 1ul)));
Tom Rinibb4dd962022-11-16 13:10:37 -0500273 writel(0, CFG_SYS_SDRAM_BASE);
Kever Yangb5497b52019-11-15 11:04:37 +0800274 writel(PATTERN, test_addr);
275 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500276 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800277 dbw = 0;
278 else
279 dbw = 1;
280
281 cap_info->dbw = dbw;
282
283 return 0;
284}
285
286/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
287int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
288{
289 u32 row, col, bk, bw, cs_cap, cs;
290 u32 die_bw_0 = 0, die_bw_1 = 0;
291
292 if (dram_type == DDR3 || dram_type == LPDDR4) {
293 cap_info->dbw = 1;
294 } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
295 row = cap_info->cs0_row;
296 col = cap_info->col;
297 bk = cap_info->bk;
298 cs = cap_info->rank;
299 bw = cap_info->bw;
300 cs_cap = (1 << (row + col + bk + bw - 20));
301 if (bw == 2) {
302 if (cs_cap <= 0x2000000) /* 256Mb */
303 die_bw_0 = (col < 9) ? 2 : 1;
304 else if (cs_cap <= 0x10000000) /* 2Gb */
305 die_bw_0 = (col < 10) ? 2 : 1;
306 else if (cs_cap <= 0x40000000) /* 8Gb */
307 die_bw_0 = (col < 11) ? 2 : 1;
308 else
309 die_bw_0 = (col < 12) ? 2 : 1;
310 if (cs > 1) {
311 row = cap_info->cs1_row;
312 cs_cap = (1 << (row + col + bk + bw - 20));
313 if (cs_cap <= 0x2000000) /* 256Mb */
314 die_bw_0 = (col < 9) ? 2 : 1;
315 else if (cs_cap <= 0x10000000) /* 2Gb */
316 die_bw_0 = (col < 10) ? 2 : 1;
317 else if (cs_cap <= 0x40000000) /* 8Gb */
318 die_bw_0 = (col < 11) ? 2 : 1;
319 else
320 die_bw_0 = (col < 12) ? 2 : 1;
321 }
322 } else {
323 die_bw_1 = 1;
324 die_bw_0 = 1;
325 }
326 cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
327 }
328
329 return 0;
330}
331
332int sdram_detect_row(struct sdram_cap_info *cap_info,
333 u32 coltmp, u32 bktmp, u32 rowtmp)
334{
335 u32 row;
336 u32 bw = cap_info->bw;
337 void __iomem *test_addr;
338
339 for (row = rowtmp; row > 12; row--) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500340 writel(0, CFG_SYS_SDRAM_BASE);
341 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800342 (1ul << (row + bktmp + coltmp + bw - 1ul)));
343 writel(PATTERN, test_addr);
344 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500345 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800346 break;
347 }
348 if (row == 12) {
349 printascii("row error");
350 return -1;
351 }
352
353 cap_info->cs0_row = row;
354
355 return 0;
356}
357
358int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
359 u32 coltmp, u32 bktmp)
360{
361 u32 row_3_4;
362 u32 bw = cap_info->bw;
363 u32 row = cap_info->cs0_row;
364 void __iomem *test_addr, *test_addr1;
365
Tom Rinibb4dd962022-11-16 13:10:37 -0500366 test_addr = CFG_SYS_SDRAM_BASE;
367 test_addr1 = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800368 (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
369
370 writel(0, test_addr);
371 writel(PATTERN, test_addr1);
372 if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
373 row_3_4 = 0;
374 else
375 row_3_4 = 1;
376
377 cap_info->row_3_4 = row_3_4;
378
379 return 0;
380}
381
382int sdram_detect_high_row(struct sdram_cap_info *cap_info)
383{
384 cap_info->cs0_high16bit_row = cap_info->cs0_row;
385 cap_info->cs1_high16bit_row = cap_info->cs1_row;
386
387 return 0;
388}
389
390int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
391{
392 void __iomem *test_addr;
393 u32 row = 0, bktmp, coltmp, bw;
394 ulong cs0_cap;
395 u32 byte_mask;
396
397 if (cap_info->rank == 2) {
398 cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
399
400 if (dram_type == DDR4) {
401 if (cap_info->dbw == 0)
402 bktmp = cap_info->bk + 2;
403 else
404 bktmp = cap_info->bk + 1;
405 } else {
406 bktmp = cap_info->bk;
407 }
408 bw = cap_info->bw;
409 coltmp = cap_info->col;
410
411 /*
412 * because px30 support axi split,min bandwidth
413 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
414 * so we check low 16bit data when detect cs1 row.
415 * if cs0 is 16bit/8bit, we check low 8bit data.
416 */
417 if (bw == 2)
418 byte_mask = 0xFFFF;
419 else
420 byte_mask = 0xFF;
421
422 /* detect cs1 row */
423 for (row = cap_info->cs0_row; row > 12; row--) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500424 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800425 cs0_cap +
426 (1ul << (row + bktmp + coltmp + bw - 1ul)));
Tom Rinibb4dd962022-11-16 13:10:37 -0500427 writel(0, CFG_SYS_SDRAM_BASE + cs0_cap);
Kever Yangb5497b52019-11-15 11:04:37 +0800428 writel(PATTERN, test_addr);
429
430 if (((readl(test_addr) & byte_mask) ==
431 (PATTERN & byte_mask)) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500432 ((readl(CFG_SYS_SDRAM_BASE + cs0_cap) &
Kever Yangb5497b52019-11-15 11:04:37 +0800433 byte_mask) == 0)) {
434 break;
435 }
436 }
437 }
438
439 cap_info->cs1_row = row;
440
441 return 0;
442}