blob: b7a8fce607c8d9afb2ddbbbdfc9bfc7c0f3d0e8a [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
Tom Rinidec7ea02024-05-20 13:35:03 -06006#include <config.h>
Kever Yangb5497b52019-11-15 11:04:37 +08007#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,
Jagan Teki95bf5872022-12-14 23:20:49 +053039 struct sdram_base_params *base, u32 split)
Kever Yang8e005542019-11-15 11:04:38 +080040{
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;
Jagan Teki95bf5872022-12-14 23:20:49 +053086 else if (split)
87 cap = cap / 2 + (split << 24) / 2;
Kever Yang8e005542019-11-15 11:04:38 +080088
89 printascii(" Size=");
90 printdec(cap >> 20);
91 printascii("MB\n");
92}
93
94void sdram_print_stride(unsigned int stride)
95{
96 switch (stride) {
97 case 0xc:
98 printf("128B stride\n");
99 break;
100 case 5:
101 case 9:
102 case 0xd:
103 case 0x11:
104 case 0x19:
105 printf("256B stride\n");
106 break;
107 case 0xa:
108 case 0xe:
109 case 0x12:
110 printf("512B stride\n");
111 break;
112 case 0xf:
113 printf("4K stride\n");
114 break;
115 case 0x1f:
116 printf("32MB + 256B stride\n");
117 break;
118 default:
119 printf("no stride\n");
120 }
121}
Kever Yang924f1042020-07-20 18:34:12 +0800122#else
123inline void sdram_print_dram_type(unsigned char dramtype)
124{
125}
126
127inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
Jagan Teki95bf5872022-12-14 23:20:49 +0530128 struct sdram_base_params *base, u32 split)
Kever Yang924f1042020-07-20 18:34:12 +0800129{
130}
131
132inline void sdram_print_stride(unsigned int stride)
133{
134}
Kever Yang8e005542019-11-15 11:04:38 +0800135#endif
136
137/*
138 * cs: 0:cs0
139 * 1:cs1
140 * else cs0+cs1
141 * note: it didn't consider about row_3_4
142 */
143u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
144{
145 u32 bg;
146 u64 cap[2];
147
148 if (dram_type == DDR4)
149 /* DDR4 8bit dram BG = 2(4bank groups),
150 * 16bit dram BG = 1 (2 bank groups)
151 */
152 bg = (cap_info->dbw == 0) ? 2 : 1;
153 else
154 bg = 0;
155 cap[0] = 1llu << (cap_info->bw + cap_info->col +
156 bg + cap_info->bk + cap_info->cs0_row);
157
158 if (cap_info->rank == 2)
159 cap[1] = 1llu << (cap_info->bw + cap_info->col +
160 bg + cap_info->bk + cap_info->cs1_row);
161 else
162 cap[1] = 0;
163
164 if (cs == 0)
165 return cap[0];
166 else if (cs == 1)
167 return cap[1];
168 else
169 return (cap[0] + cap[1]);
170}
171
Kever Yangb5497b52019-11-15 11:04:37 +0800172/* n: Unit bytes */
173void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
174{
175 int i;
176
177 for (i = 0; i < n / sizeof(u32); i++) {
178 writel(*src, dest);
179 src++;
180 dest++;
181 }
182}
183
184void sdram_org_config(struct sdram_cap_info *cap_info,
185 struct sdram_base_params *base,
186 u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
187{
188 *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
189 *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
190
191 *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
192 *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
193 *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
194 *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
195 *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
196 *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
197 *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
198
199 SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
200 if (cap_info->cs1_row)
201 SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
202 *p_os_reg3, channel);
203 *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
204 *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
205}
206
207int sdram_detect_bw(struct sdram_cap_info *cap_info)
208{
209 return 0;
210}
211
212int sdram_detect_cs(struct sdram_cap_info *cap_info)
213{
214 return 0;
215}
216
217int sdram_detect_col(struct sdram_cap_info *cap_info,
218 u32 coltmp)
219{
220 void __iomem *test_addr;
221 u32 col;
222 u32 bw = cap_info->bw;
223
224 for (col = coltmp; col >= 9; col -= 1) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500225 writel(0, CFG_SYS_SDRAM_BASE);
226 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800227 (1ul << (col + bw - 1ul)));
228 writel(PATTERN, test_addr);
229 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500230 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800231 break;
232 }
233 if (col == 8) {
234 printascii("col error\n");
235 return -1;
236 }
237
238 cap_info->col = col;
239
240 return 0;
241}
242
243int sdram_detect_bank(struct sdram_cap_info *cap_info,
244 u32 coltmp, u32 bktmp)
245{
246 void __iomem *test_addr;
247 u32 bk;
248 u32 bw = cap_info->bw;
249
Tom Rinibb4dd962022-11-16 13:10:37 -0500250 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800251 (1ul << (coltmp + bktmp + bw - 1ul)));
Tom Rinibb4dd962022-11-16 13:10:37 -0500252 writel(0, CFG_SYS_SDRAM_BASE);
Kever Yangb5497b52019-11-15 11:04:37 +0800253 writel(PATTERN, test_addr);
254 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500255 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800256 bk = 3;
257 else
258 bk = 2;
259
260 cap_info->bk = bk;
261
262 return 0;
263}
264
265/* detect bg for ddr4 */
266int sdram_detect_bg(struct sdram_cap_info *cap_info,
267 u32 coltmp)
268{
269 void __iomem *test_addr;
270 u32 dbw;
271 u32 bw = cap_info->bw;
272
Tom Rinibb4dd962022-11-16 13:10:37 -0500273 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800274 (1ul << (coltmp + bw + 1ul)));
Tom Rinibb4dd962022-11-16 13:10:37 -0500275 writel(0, CFG_SYS_SDRAM_BASE);
Kever Yangb5497b52019-11-15 11:04:37 +0800276 writel(PATTERN, test_addr);
277 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500278 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800279 dbw = 0;
280 else
281 dbw = 1;
282
283 cap_info->dbw = dbw;
284
285 return 0;
286}
287
288/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
289int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
290{
291 u32 row, col, bk, bw, cs_cap, cs;
292 u32 die_bw_0 = 0, die_bw_1 = 0;
293
294 if (dram_type == DDR3 || dram_type == LPDDR4) {
295 cap_info->dbw = 1;
296 } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
297 row = cap_info->cs0_row;
298 col = cap_info->col;
299 bk = cap_info->bk;
300 cs = cap_info->rank;
301 bw = cap_info->bw;
302 cs_cap = (1 << (row + col + bk + bw - 20));
303 if (bw == 2) {
304 if (cs_cap <= 0x2000000) /* 256Mb */
305 die_bw_0 = (col < 9) ? 2 : 1;
306 else if (cs_cap <= 0x10000000) /* 2Gb */
307 die_bw_0 = (col < 10) ? 2 : 1;
308 else if (cs_cap <= 0x40000000) /* 8Gb */
309 die_bw_0 = (col < 11) ? 2 : 1;
310 else
311 die_bw_0 = (col < 12) ? 2 : 1;
312 if (cs > 1) {
313 row = cap_info->cs1_row;
314 cs_cap = (1 << (row + col + bk + bw - 20));
315 if (cs_cap <= 0x2000000) /* 256Mb */
316 die_bw_0 = (col < 9) ? 2 : 1;
317 else if (cs_cap <= 0x10000000) /* 2Gb */
318 die_bw_0 = (col < 10) ? 2 : 1;
319 else if (cs_cap <= 0x40000000) /* 8Gb */
320 die_bw_0 = (col < 11) ? 2 : 1;
321 else
322 die_bw_0 = (col < 12) ? 2 : 1;
323 }
324 } else {
325 die_bw_1 = 1;
326 die_bw_0 = 1;
327 }
328 cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
329 }
330
331 return 0;
332}
333
334int sdram_detect_row(struct sdram_cap_info *cap_info,
335 u32 coltmp, u32 bktmp, u32 rowtmp)
336{
337 u32 row;
338 u32 bw = cap_info->bw;
339 void __iomem *test_addr;
340
341 for (row = rowtmp; row > 12; row--) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500342 writel(0, CFG_SYS_SDRAM_BASE);
343 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800344 (1ul << (row + bktmp + coltmp + bw - 1ul)));
345 writel(PATTERN, test_addr);
346 if ((readl(test_addr) == PATTERN) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500347 (readl(CFG_SYS_SDRAM_BASE) == 0))
Kever Yangb5497b52019-11-15 11:04:37 +0800348 break;
349 }
350 if (row == 12) {
351 printascii("row error");
352 return -1;
353 }
354
355 cap_info->cs0_row = row;
356
357 return 0;
358}
359
360int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
361 u32 coltmp, u32 bktmp)
362{
363 u32 row_3_4;
364 u32 bw = cap_info->bw;
365 u32 row = cap_info->cs0_row;
366 void __iomem *test_addr, *test_addr1;
367
Tom Rinibb4dd962022-11-16 13:10:37 -0500368 test_addr = CFG_SYS_SDRAM_BASE;
369 test_addr1 = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800370 (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
371
372 writel(0, test_addr);
373 writel(PATTERN, test_addr1);
374 if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
375 row_3_4 = 0;
376 else
377 row_3_4 = 1;
378
379 cap_info->row_3_4 = row_3_4;
380
381 return 0;
382}
383
384int sdram_detect_high_row(struct sdram_cap_info *cap_info)
385{
386 cap_info->cs0_high16bit_row = cap_info->cs0_row;
387 cap_info->cs1_high16bit_row = cap_info->cs1_row;
388
389 return 0;
390}
391
392int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
393{
394 void __iomem *test_addr;
395 u32 row = 0, bktmp, coltmp, bw;
396 ulong cs0_cap;
397 u32 byte_mask;
398
399 if (cap_info->rank == 2) {
400 cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
401
402 if (dram_type == DDR4) {
403 if (cap_info->dbw == 0)
404 bktmp = cap_info->bk + 2;
405 else
406 bktmp = cap_info->bk + 1;
407 } else {
408 bktmp = cap_info->bk;
409 }
410 bw = cap_info->bw;
411 coltmp = cap_info->col;
412
413 /*
414 * because px30 support axi split,min bandwidth
415 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
416 * so we check low 16bit data when detect cs1 row.
417 * if cs0 is 16bit/8bit, we check low 8bit data.
418 */
419 if (bw == 2)
420 byte_mask = 0xFFFF;
421 else
422 byte_mask = 0xFF;
423
424 /* detect cs1 row */
425 for (row = cap_info->cs0_row; row > 12; row--) {
Tom Rinibb4dd962022-11-16 13:10:37 -0500426 test_addr = (void __iomem *)(CFG_SYS_SDRAM_BASE +
Kever Yangb5497b52019-11-15 11:04:37 +0800427 cs0_cap +
428 (1ul << (row + bktmp + coltmp + bw - 1ul)));
Tom Rinibb4dd962022-11-16 13:10:37 -0500429 writel(0, CFG_SYS_SDRAM_BASE + cs0_cap);
Kever Yangb5497b52019-11-15 11:04:37 +0800430 writel(PATTERN, test_addr);
431
432 if (((readl(test_addr) & byte_mask) ==
433 (PATTERN & byte_mask)) &&
Tom Rinibb4dd962022-11-16 13:10:37 -0500434 ((readl(CFG_SYS_SDRAM_BASE + cs0_cap) &
Kever Yangb5497b52019-11-15 11:04:37 +0800435 byte_mask) == 0)) {
436 break;
437 }
438 }
439 }
440
441 cap_info->cs1_row = row;
442
443 return 0;
444}