1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <common.h>
7*4882a593Smuzhiyun #include <debug_uart.h>
8*4882a593Smuzhiyun #include <ram.h>
9*4882a593Smuzhiyun #include <asm/io.h>
10*4882a593Smuzhiyun #include <asm/arch/sdram.h>
11*4882a593Smuzhiyun #include <asm/arch/sdram_common.h>
12*4882a593Smuzhiyun
sdram_print_dram_type(unsigned char dramtype)13*4882a593Smuzhiyun void sdram_print_dram_type(unsigned char dramtype)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun switch (dramtype) {
16*4882a593Smuzhiyun case DDR3:
17*4882a593Smuzhiyun printascii("DDR3");
18*4882a593Smuzhiyun break;
19*4882a593Smuzhiyun case DDR4:
20*4882a593Smuzhiyun printascii("DDR4");
21*4882a593Smuzhiyun break;
22*4882a593Smuzhiyun case LPDDR2:
23*4882a593Smuzhiyun printascii("LPDDR2");
24*4882a593Smuzhiyun break;
25*4882a593Smuzhiyun case LPDDR3:
26*4882a593Smuzhiyun printascii("LPDDR3");
27*4882a593Smuzhiyun break;
28*4882a593Smuzhiyun case LPDDR4:
29*4882a593Smuzhiyun printascii("LPDDR4");
30*4882a593Smuzhiyun break;
31*4882a593Smuzhiyun case LPDDR4X:
32*4882a593Smuzhiyun printascii("LPDDR4X");
33*4882a593Smuzhiyun break;
34*4882a593Smuzhiyun default:
35*4882a593Smuzhiyun printascii("Unknown Device");
36*4882a593Smuzhiyun break;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
sdram_print_ddr_info(struct sdram_cap_info * cap_info,struct sdram_base_params * base,u32 split)40*4882a593Smuzhiyun void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
41*4882a593Smuzhiyun struct sdram_base_params *base, u32 split)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun u64 cap;
44*4882a593Smuzhiyun u32 bg;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun bg = (cap_info->dbw == 0) ? 2 : 1;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun sdram_print_dram_type(base->dramtype);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun printascii(", ");
51*4882a593Smuzhiyun printdec(base->ddr_freq);
52*4882a593Smuzhiyun printascii("MHz\n");
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun printascii("BW=");
55*4882a593Smuzhiyun printdec(8 << cap_info->bw);
56*4882a593Smuzhiyun printascii(" Col=");
57*4882a593Smuzhiyun printdec(cap_info->col);
58*4882a593Smuzhiyun printascii(" Bk=");
59*4882a593Smuzhiyun printdec(0x1 << cap_info->bk);
60*4882a593Smuzhiyun if (base->dramtype == DDR4) {
61*4882a593Smuzhiyun printascii(" BG=");
62*4882a593Smuzhiyun printdec(1 << bg);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun printascii(" CS0 Row=");
65*4882a593Smuzhiyun printdec(cap_info->cs0_row);
66*4882a593Smuzhiyun if (cap_info->cs0_high16bit_row !=
67*4882a593Smuzhiyun cap_info->cs0_row) {
68*4882a593Smuzhiyun printascii("/");
69*4882a593Smuzhiyun printdec(cap_info->cs0_high16bit_row);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun if (cap_info->rank > 1) {
72*4882a593Smuzhiyun printascii(" CS1 Row=");
73*4882a593Smuzhiyun printdec(cap_info->cs1_row);
74*4882a593Smuzhiyun if (cap_info->cs1_high16bit_row !=
75*4882a593Smuzhiyun cap_info->cs1_row) {
76*4882a593Smuzhiyun printascii("/");
77*4882a593Smuzhiyun printdec(cap_info->cs1_high16bit_row);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun if (cap_info->rank > 2) {
81*4882a593Smuzhiyun printascii(" CS2 Row=");
82*4882a593Smuzhiyun printdec(cap_info->cs2_row);
83*4882a593Smuzhiyun if (cap_info->cs2_high16bit_row !=
84*4882a593Smuzhiyun cap_info->cs2_row) {
85*4882a593Smuzhiyun printascii("/");
86*4882a593Smuzhiyun printdec(cap_info->cs2_high16bit_row);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun printascii(" CS3 Row=");
89*4882a593Smuzhiyun printdec(cap_info->cs3_row);
90*4882a593Smuzhiyun if (cap_info->cs3_high16bit_row !=
91*4882a593Smuzhiyun cap_info->cs3_row) {
92*4882a593Smuzhiyun printascii("/");
93*4882a593Smuzhiyun printdec(cap_info->cs3_high16bit_row);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun printascii(" CS=");
97*4882a593Smuzhiyun printdec(cap_info->rank);
98*4882a593Smuzhiyun printascii(" Die BW=");
99*4882a593Smuzhiyun printdec(8 << cap_info->dbw);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
102*4882a593Smuzhiyun if (cap_info->row_3_4)
103*4882a593Smuzhiyun cap = cap * 3 / 4;
104*4882a593Smuzhiyun else if (split)
105*4882a593Smuzhiyun cap = cap / 2 + (split << 24) / 2;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun printascii(" Size=");
108*4882a593Smuzhiyun printdec(cap >> 20);
109*4882a593Smuzhiyun printascii("MB\n");
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * cs: 0:cs0
114*4882a593Smuzhiyun * 1:cs1
115*4882a593Smuzhiyun * else cs0+cs1
116*4882a593Smuzhiyun * note: it didn't consider about row_3_4
117*4882a593Smuzhiyun */
sdram_get_cs_cap(struct sdram_cap_info * cap_info,u32 cs,u32 dram_type)118*4882a593Smuzhiyun u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun u32 bg;
121*4882a593Smuzhiyun u64 cap[4];
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (dram_type == DDR4)
124*4882a593Smuzhiyun /* DDR4 8bit dram BG = 2(4bank groups),
125*4882a593Smuzhiyun * 16bit dram BG = 1 (2 bank groups)
126*4882a593Smuzhiyun */
127*4882a593Smuzhiyun bg = (cap_info->dbw == 0) ? 2 : 1;
128*4882a593Smuzhiyun else
129*4882a593Smuzhiyun bg = 0;
130*4882a593Smuzhiyun cap[0] = 1llu << (cap_info->bw + cap_info->col +
131*4882a593Smuzhiyun bg + cap_info->bk + cap_info->cs0_row);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (cap_info->rank >= 2)
134*4882a593Smuzhiyun cap[1] = 1llu << (cap_info->bw + cap_info->col +
135*4882a593Smuzhiyun bg + cap_info->bk + cap_info->cs1_row);
136*4882a593Smuzhiyun else
137*4882a593Smuzhiyun cap[1] = 0;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (cap_info->rank == 4) {
140*4882a593Smuzhiyun cap[2] = 1llu << (cap_info->bw + cap_info->col +
141*4882a593Smuzhiyun bg + cap_info->bk + cap_info->cs2_row);
142*4882a593Smuzhiyun cap[3] = 1llu << (cap_info->bw + cap_info->col +
143*4882a593Smuzhiyun bg + cap_info->bk + cap_info->cs3_row);
144*4882a593Smuzhiyun } else {
145*4882a593Smuzhiyun cap[2] = 0;
146*4882a593Smuzhiyun cap[3] = 0;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun if (cs == 0)
149*4882a593Smuzhiyun return cap[0];
150*4882a593Smuzhiyun else if (cs == 1)
151*4882a593Smuzhiyun return cap[1];
152*4882a593Smuzhiyun else
153*4882a593Smuzhiyun return (cap[0] + cap[1] + cap[2] + cap[3]);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* n: Unit bytes */
sdram_copy_to_reg(u32 * dest,const u32 * src,u32 n)157*4882a593Smuzhiyun void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun int i;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun for (i = 0; i < n / sizeof(u32); i++) {
162*4882a593Smuzhiyun writel(*src, dest);
163*4882a593Smuzhiyun src++;
164*4882a593Smuzhiyun dest++;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
sdram_org_config(struct sdram_cap_info * cap_info,struct sdram_base_params * base,u32 * p_os_reg2,u32 * p_os_reg3,u32 channel)168*4882a593Smuzhiyun void sdram_org_config(struct sdram_cap_info *cap_info,
169*4882a593Smuzhiyun struct sdram_base_params *base,
170*4882a593Smuzhiyun u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
173*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
176*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
177*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
178*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
179*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
180*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
181*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
184*4882a593Smuzhiyun if (cap_info->cs1_row)
185*4882a593Smuzhiyun SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
186*4882a593Smuzhiyun *p_os_reg3, channel);
187*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
188*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
sdram_org_config_v3(struct sdram_cap_info * cap_info,struct sdram_base_params * base,u32 * p_os_reg2,u32 * p_os_reg3,u32 channel)191*4882a593Smuzhiyun void sdram_org_config_v3(struct sdram_cap_info *cap_info,
192*4882a593Smuzhiyun struct sdram_base_params *base,
193*4882a593Smuzhiyun u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun SYS_REG_ENC_DDRTYPE_V3(base->dramtype, *p_os_reg2, *p_os_reg3);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_NUM_CH_V3((base->num_channels > 2) ?
198*4882a593Smuzhiyun 2 : base->num_channels);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_ROW_3_4_V3(cap_info->row_3_4, channel);
201*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_CHINFO_V3((channel >= 2) ? channel - 2 : channel);
202*4882a593Smuzhiyun if (channel == 0 || channel == 2)
203*4882a593Smuzhiyun SYS_REG_ENC_CH0_2_RANK_V3(cap_info->rank,
204*4882a593Smuzhiyun *p_os_reg2, *p_os_reg3);
205*4882a593Smuzhiyun else
206*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_CH1_3_RANK(cap_info->rank);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_COL_V3(cap_info->col, channel);
209*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_BK_V3(cap_info->bk, channel);
210*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_BW_V3(cap_info->bw, channel);
211*4882a593Smuzhiyun *p_os_reg2 |= SYS_REG_ENC_DBW_V3(cap_info->dbw, channel);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun SYS_REG_ENC_CS0_ROW_V3(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
214*4882a593Smuzhiyun if (cap_info->cs1_row)
215*4882a593Smuzhiyun SYS_REG_ENC_CS1_ROW_V3(cap_info->cs1_row, *p_os_reg2,
216*4882a593Smuzhiyun *p_os_reg3, channel);
217*4882a593Smuzhiyun if ((channel == 0 || channel == 2) && cap_info->rank > 2) {
218*4882a593Smuzhiyun if (cap_info->cs2_row == cap_info->cs0_row)
219*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(0);
220*4882a593Smuzhiyun else
221*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(1);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (cap_info->cs3_row == cap_info->cs0_row)
224*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(0);
225*4882a593Smuzhiyun else
226*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(1);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_CS1_COL_V3(cap_info->col, channel);
230*4882a593Smuzhiyun *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION_3);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
sdram_detect_bw(struct sdram_cap_info * cap_info)233*4882a593Smuzhiyun int sdram_detect_bw(struct sdram_cap_info *cap_info)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
sdram_detect_cs(struct sdram_cap_info * cap_info)238*4882a593Smuzhiyun int sdram_detect_cs(struct sdram_cap_info *cap_info)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun return 0;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
sdram_detect_col(struct sdram_cap_info * cap_info,u32 coltmp)243*4882a593Smuzhiyun int sdram_detect_col(struct sdram_cap_info *cap_info,
244*4882a593Smuzhiyun u32 coltmp)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun void __iomem *test_addr;
247*4882a593Smuzhiyun u32 col;
248*4882a593Smuzhiyun u32 bw = cap_info->bw;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun for (col = coltmp; col >= 9; col -= 1) {
251*4882a593Smuzhiyun writel(0, CONFIG_SYS_SDRAM_BASE);
252*4882a593Smuzhiyun test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
253*4882a593Smuzhiyun (1ul << (col + bw - 1ul)));
254*4882a593Smuzhiyun writel(PATTERN, test_addr);
255*4882a593Smuzhiyun if ((readl(test_addr) == PATTERN) &&
256*4882a593Smuzhiyun (readl(CONFIG_SYS_SDRAM_BASE) == 0))
257*4882a593Smuzhiyun break;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun if (col == 8) {
260*4882a593Smuzhiyun printascii("col error\n");
261*4882a593Smuzhiyun return -1;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun cap_info->col = col;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
sdram_detect_bank(struct sdram_cap_info * cap_info,u32 coltmp,u32 bktmp)269*4882a593Smuzhiyun int sdram_detect_bank(struct sdram_cap_info *cap_info,
270*4882a593Smuzhiyun u32 coltmp, u32 bktmp)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun void __iomem *test_addr;
273*4882a593Smuzhiyun u32 bk;
274*4882a593Smuzhiyun u32 bw = cap_info->bw;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
277*4882a593Smuzhiyun (1ul << (coltmp + bktmp + bw - 1ul)));
278*4882a593Smuzhiyun writel(0, CONFIG_SYS_SDRAM_BASE);
279*4882a593Smuzhiyun writel(PATTERN, test_addr);
280*4882a593Smuzhiyun if ((readl(test_addr) == PATTERN) &&
281*4882a593Smuzhiyun (readl(CONFIG_SYS_SDRAM_BASE) == 0))
282*4882a593Smuzhiyun bk = 3;
283*4882a593Smuzhiyun else
284*4882a593Smuzhiyun bk = 2;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun cap_info->bk = bk;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return 0;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* detect bg for ddr4 */
sdram_detect_bg(struct sdram_cap_info * cap_info,u32 coltmp)292*4882a593Smuzhiyun int sdram_detect_bg(struct sdram_cap_info *cap_info,
293*4882a593Smuzhiyun u32 coltmp)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun void __iomem *test_addr;
296*4882a593Smuzhiyun u32 dbw;
297*4882a593Smuzhiyun u32 bw = cap_info->bw;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
300*4882a593Smuzhiyun (1ul << (coltmp + bw + 1ul)));
301*4882a593Smuzhiyun writel(0, CONFIG_SYS_SDRAM_BASE);
302*4882a593Smuzhiyun writel(PATTERN, test_addr);
303*4882a593Smuzhiyun if ((readl(test_addr) == PATTERN) &&
304*4882a593Smuzhiyun (readl(CONFIG_SYS_SDRAM_BASE) == 0))
305*4882a593Smuzhiyun dbw = 0;
306*4882a593Smuzhiyun else
307*4882a593Smuzhiyun dbw = 1;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun cap_info->dbw = dbw;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
sdram_detect_dbw(struct sdram_cap_info * cap_info,u32 dram_type)315*4882a593Smuzhiyun int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun u32 row, col, bk, bw, cs_cap, cs;
318*4882a593Smuzhiyun u32 die_bw_0 = 0, die_bw_1 = 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (dram_type == DDR3) {
321*4882a593Smuzhiyun if (cap_info->bw == 0)
322*4882a593Smuzhiyun cap_info->dbw = 0;
323*4882a593Smuzhiyun else
324*4882a593Smuzhiyun cap_info->dbw = 1;
325*4882a593Smuzhiyun } else if (dram_type == LPDDR4) {
326*4882a593Smuzhiyun cap_info->dbw = 1;
327*4882a593Smuzhiyun } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
328*4882a593Smuzhiyun row = cap_info->cs0_row;
329*4882a593Smuzhiyun col = cap_info->col;
330*4882a593Smuzhiyun bk = cap_info->bk;
331*4882a593Smuzhiyun cs = cap_info->rank;
332*4882a593Smuzhiyun bw = cap_info->bw;
333*4882a593Smuzhiyun cs_cap = (1 << (row + col + bk + bw - 20));
334*4882a593Smuzhiyun if (bw == 2) {
335*4882a593Smuzhiyun if (cs_cap <= 0x20) /* 256Mb */
336*4882a593Smuzhiyun die_bw_0 = (col < 9) ? 2 : 1;
337*4882a593Smuzhiyun else if (cs_cap <= 0x100) /* 2Gb */
338*4882a593Smuzhiyun die_bw_0 = (col < 10) ? 2 : 1;
339*4882a593Smuzhiyun else if (cs_cap <= 0x400) /* 8Gb */
340*4882a593Smuzhiyun die_bw_0 = (col < 11) ? 2 : 1;
341*4882a593Smuzhiyun else
342*4882a593Smuzhiyun die_bw_0 = (col < 12) ? 2 : 1;
343*4882a593Smuzhiyun if (cs > 1) {
344*4882a593Smuzhiyun row = cap_info->cs1_row;
345*4882a593Smuzhiyun cs_cap = (1 << (row + col + bk + bw - 20));
346*4882a593Smuzhiyun if (cs_cap <= 0x20) /* 256Mb */
347*4882a593Smuzhiyun die_bw_0 = (col < 9) ? 2 : 1;
348*4882a593Smuzhiyun else if (cs_cap <= 0x100) /* 2Gb */
349*4882a593Smuzhiyun die_bw_0 = (col < 10) ? 2 : 1;
350*4882a593Smuzhiyun else if (cs_cap <= 0x400) /* 8Gb */
351*4882a593Smuzhiyun die_bw_0 = (col < 11) ? 2 : 1;
352*4882a593Smuzhiyun else
353*4882a593Smuzhiyun die_bw_0 = (col < 12) ? 2 : 1;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun } else {
356*4882a593Smuzhiyun die_bw_1 = 1;
357*4882a593Smuzhiyun die_bw_0 = 1;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun return 0;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
sdram_detect_row(struct sdram_cap_info * cap_info,u32 coltmp,u32 bktmp,u32 rowtmp)365*4882a593Smuzhiyun int sdram_detect_row(struct sdram_cap_info *cap_info,
366*4882a593Smuzhiyun u32 coltmp, u32 bktmp, u32 rowtmp)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun u32 row;
369*4882a593Smuzhiyun u32 bw = cap_info->bw;
370*4882a593Smuzhiyun void __iomem *test_addr;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun for (row = rowtmp; row > 12; row--) {
373*4882a593Smuzhiyun writel(0, CONFIG_SYS_SDRAM_BASE);
374*4882a593Smuzhiyun test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
375*4882a593Smuzhiyun (1ul << (row + bktmp + coltmp + bw - 1ul)));
376*4882a593Smuzhiyun writel(PATTERN, test_addr);
377*4882a593Smuzhiyun if ((readl(test_addr) == PATTERN) &&
378*4882a593Smuzhiyun (readl(CONFIG_SYS_SDRAM_BASE) == 0))
379*4882a593Smuzhiyun break;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun if (row == 12) {
382*4882a593Smuzhiyun printascii("row error");
383*4882a593Smuzhiyun return -1;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun cap_info->cs0_row = row;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun return 0;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
sdram_detect_row_3_4(struct sdram_cap_info * cap_info,u32 coltmp,u32 bktmp)391*4882a593Smuzhiyun int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
392*4882a593Smuzhiyun u32 coltmp, u32 bktmp)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun u32 row_3_4;
395*4882a593Smuzhiyun u32 bw = cap_info->bw;
396*4882a593Smuzhiyun u32 row = cap_info->cs0_row;
397*4882a593Smuzhiyun void __iomem *test_addr, *test_addr1;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun test_addr = CONFIG_SYS_SDRAM_BASE;
400*4882a593Smuzhiyun test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
401*4882a593Smuzhiyun (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun writel(0, test_addr);
404*4882a593Smuzhiyun writel(PATTERN, test_addr1);
405*4882a593Smuzhiyun if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
406*4882a593Smuzhiyun row_3_4 = 0;
407*4882a593Smuzhiyun else
408*4882a593Smuzhiyun row_3_4 = 1;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun cap_info->row_3_4 = row_3_4;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun return 0;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
sdram_detect_high_row(struct sdram_cap_info * cap_info,u32 dramtype)415*4882a593Smuzhiyun int sdram_detect_high_row(struct sdram_cap_info *cap_info, u32 dramtype)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun unsigned long base_addr;
418*4882a593Smuzhiyun u32 cs0_high_row, cs1_high_row, cs;
419*4882a593Smuzhiyun u64 cap = 0, cs0_cap = 0;
420*4882a593Smuzhiyun u32 i;
421*4882a593Smuzhiyun void __iomem *test_addr, *test_addr1;
422*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_RK3568
423*4882a593Smuzhiyun u32 cs2_high_row, cs3_high_row;
424*4882a593Smuzhiyun #endif
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun cs = cap_info->rank;
427*4882a593Smuzhiyun /* 8bit bandwidth no enable axi split*/
428*4882a593Smuzhiyun if (!cap_info->bw) {
429*4882a593Smuzhiyun cs0_high_row = cap_info->cs0_row;
430*4882a593Smuzhiyun cs1_high_row = cap_info->cs1_row;
431*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_RK3568
432*4882a593Smuzhiyun if (cs > 2) {
433*4882a593Smuzhiyun cs2_high_row = cap_info->cs2_row;
434*4882a593Smuzhiyun cs3_high_row = cap_info->cs3_row;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun #endif
437*4882a593Smuzhiyun goto out;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_RK3568
440*4882a593Smuzhiyun if (cs > 2) {
441*4882a593Smuzhiyun cs0_high_row = cap_info->cs0_row;
442*4882a593Smuzhiyun cs1_high_row = cap_info->cs1_row;
443*4882a593Smuzhiyun cs2_high_row = cap_info->cs2_row;
444*4882a593Smuzhiyun cs3_high_row = cap_info->cs3_row;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun goto out;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun #endif
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun cs0_cap = sdram_get_cs_cap(cap_info, 0, dramtype);
451*4882a593Smuzhiyun if (cs == 2) {
452*4882a593Smuzhiyun base_addr = CONFIG_SYS_SDRAM_BASE + cs0_cap;
453*4882a593Smuzhiyun cap = sdram_get_cs_cap(cap_info, 1, dramtype);
454*4882a593Smuzhiyun } else {
455*4882a593Smuzhiyun base_addr = CONFIG_SYS_SDRAM_BASE;
456*4882a593Smuzhiyun cap = cs0_cap;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun /* detect full bandwidth size */
459*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
460*4882a593Smuzhiyun test_addr = (void __iomem *)base_addr;
461*4882a593Smuzhiyun test_addr1 = (void __iomem *)(base_addr +
462*4882a593Smuzhiyun (unsigned long)(cap / (1ul << (i + 1))));
463*4882a593Smuzhiyun writel(0x0, test_addr);
464*4882a593Smuzhiyun writel(PATTERN, test_addr1);
465*4882a593Smuzhiyun if ((readl(test_addr) == 0x0) &&
466*4882a593Smuzhiyun (readl(test_addr1) == PATTERN))
467*4882a593Smuzhiyun break;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun if (i == 4 && cs == 1) {
470*4882a593Smuzhiyun printascii("can't support this cap\n");
471*4882a593Smuzhiyun return -1;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun if (cs == 2) {
475*4882a593Smuzhiyun cs0_high_row = cap_info->cs0_row;
476*4882a593Smuzhiyun if (i == 4)
477*4882a593Smuzhiyun cs1_high_row = 0;
478*4882a593Smuzhiyun else
479*4882a593Smuzhiyun cs1_high_row = cap_info->cs1_row - i;
480*4882a593Smuzhiyun } else {
481*4882a593Smuzhiyun cs0_high_row = cap_info->cs0_row - i;
482*4882a593Smuzhiyun cs1_high_row = 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun out:
486*4882a593Smuzhiyun cap_info->cs0_high16bit_row = cs0_high_row;
487*4882a593Smuzhiyun cap_info->cs1_high16bit_row = cs1_high_row;
488*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_RK3568
489*4882a593Smuzhiyun if (cs > 2) {
490*4882a593Smuzhiyun cap_info->cs2_high16bit_row = cs2_high_row;
491*4882a593Smuzhiyun cap_info->cs3_high16bit_row = cs3_high_row;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun #endif
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun return 0;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
sdram_detect_cs1_row(struct sdram_cap_info * cap_info,u32 dram_type)498*4882a593Smuzhiyun int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun void __iomem *test_addr;
501*4882a593Smuzhiyun u32 row = 0, bktmp, coltmp, bw;
502*4882a593Smuzhiyun ulong cs0_cap;
503*4882a593Smuzhiyun u32 byte_mask;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun if (cap_info->rank == 2) {
506*4882a593Smuzhiyun cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun if (dram_type == DDR4) {
509*4882a593Smuzhiyun if (cap_info->dbw == 0)
510*4882a593Smuzhiyun bktmp = cap_info->bk + 2;
511*4882a593Smuzhiyun else
512*4882a593Smuzhiyun bktmp = cap_info->bk + 1;
513*4882a593Smuzhiyun } else {
514*4882a593Smuzhiyun bktmp = cap_info->bk;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun bw = cap_info->bw;
517*4882a593Smuzhiyun coltmp = cap_info->col;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /*
520*4882a593Smuzhiyun * because px30 support axi split,min bandwidth
521*4882a593Smuzhiyun * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
522*4882a593Smuzhiyun * so we check low 16bit data when detect cs1 row.
523*4882a593Smuzhiyun * if cs0 is 16bit/8bit, we check low 8bit data.
524*4882a593Smuzhiyun */
525*4882a593Smuzhiyun if (bw == 2)
526*4882a593Smuzhiyun byte_mask = 0xFFFF;
527*4882a593Smuzhiyun else
528*4882a593Smuzhiyun byte_mask = 0xFF;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* detect cs1 row */
531*4882a593Smuzhiyun for (row = cap_info->cs0_row; row > 12; row--) {
532*4882a593Smuzhiyun test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
533*4882a593Smuzhiyun cs0_cap +
534*4882a593Smuzhiyun (1ul << (row + bktmp + coltmp + bw - 1ul)));
535*4882a593Smuzhiyun writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
536*4882a593Smuzhiyun writel(PATTERN, test_addr);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (((readl(test_addr) & byte_mask) ==
539*4882a593Smuzhiyun (PATTERN & byte_mask)) &&
540*4882a593Smuzhiyun ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
541*4882a593Smuzhiyun byte_mask) == 0)) {
542*4882a593Smuzhiyun break;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun cap_info->cs1_row = row;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun return 0;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552