15685f66aSYouMin Chen // SPDX-License-Identifier: GPL-2.0
25685f66aSYouMin Chen /*
35685f66aSYouMin Chen * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
45685f66aSYouMin Chen */
55685f66aSYouMin Chen
65685f66aSYouMin Chen #include <common.h>
75685f66aSYouMin Chen #include <debug_uart.h>
85685f66aSYouMin Chen #include <ram.h>
95685f66aSYouMin Chen #include <asm/io.h>
105685f66aSYouMin Chen #include <asm/arch/sdram.h>
115685f66aSYouMin Chen #include <asm/arch/sdram_common.h>
125685f66aSYouMin Chen
pctl_dis_zqcs_aref(void __iomem * pctl_base)13*e1652d39SZhihuan He u32 __weak pctl_dis_zqcs_aref(void __iomem *pctl_base)
14*e1652d39SZhihuan He {
15*e1652d39SZhihuan He return 0;
16*e1652d39SZhihuan He }
pctl_rest_zqcs_aref(void __iomem * pctl_base,u32 dis_auto_zq)17*e1652d39SZhihuan He void __weak pctl_rest_zqcs_aref(void __iomem *pctl_base, u32 dis_auto_zq)
18*e1652d39SZhihuan He {
19*e1652d39SZhihuan He
20*e1652d39SZhihuan He }
send_a_refresh(void __iomem * pctl_base,u32 cs)21*e1652d39SZhihuan He void __weak send_a_refresh(void __iomem *pctl_base, u32 cs)
22*e1652d39SZhihuan He {
23*e1652d39SZhihuan He
24*e1652d39SZhihuan He }
25*e1652d39SZhihuan He
sdram_print_dram_type(unsigned char dramtype)265685f66aSYouMin Chen void sdram_print_dram_type(unsigned char dramtype)
275685f66aSYouMin Chen {
285685f66aSYouMin Chen switch (dramtype) {
295685f66aSYouMin Chen case DDR3:
305685f66aSYouMin Chen printascii("DDR3");
315685f66aSYouMin Chen break;
325685f66aSYouMin Chen case DDR4:
335685f66aSYouMin Chen printascii("DDR4");
345685f66aSYouMin Chen break;
355685f66aSYouMin Chen case LPDDR2:
365685f66aSYouMin Chen printascii("LPDDR2");
375685f66aSYouMin Chen break;
385685f66aSYouMin Chen case LPDDR3:
395685f66aSYouMin Chen printascii("LPDDR3");
405685f66aSYouMin Chen break;
415685f66aSYouMin Chen case LPDDR4:
425685f66aSYouMin Chen printascii("LPDDR4");
435685f66aSYouMin Chen break;
44de9242dcSTang Yun ping case LPDDR4X:
45de9242dcSTang Yun ping printascii("LPDDR4X");
46de9242dcSTang Yun ping break;
475685f66aSYouMin Chen default:
485685f66aSYouMin Chen printascii("Unknown Device");
495685f66aSYouMin Chen break;
505685f66aSYouMin Chen }
515685f66aSYouMin Chen }
525685f66aSYouMin Chen
sdram_print_ddr_info(struct sdram_cap_info * cap_info,struct sdram_base_params * base,u32 split)535685f66aSYouMin Chen void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
545685f66aSYouMin Chen struct sdram_base_params *base, u32 split)
555685f66aSYouMin Chen {
565685f66aSYouMin Chen u64 cap;
575685f66aSYouMin Chen u32 bg;
585685f66aSYouMin Chen
595685f66aSYouMin Chen bg = (cap_info->dbw == 0) ? 2 : 1;
605685f66aSYouMin Chen
615685f66aSYouMin Chen sdram_print_dram_type(base->dramtype);
625685f66aSYouMin Chen
635685f66aSYouMin Chen printascii(", ");
645685f66aSYouMin Chen printdec(base->ddr_freq);
655685f66aSYouMin Chen printascii("MHz\n");
665685f66aSYouMin Chen
675685f66aSYouMin Chen printascii("BW=");
685685f66aSYouMin Chen printdec(8 << cap_info->bw);
695685f66aSYouMin Chen printascii(" Col=");
705685f66aSYouMin Chen printdec(cap_info->col);
715685f66aSYouMin Chen printascii(" Bk=");
725685f66aSYouMin Chen printdec(0x1 << cap_info->bk);
735685f66aSYouMin Chen if (base->dramtype == DDR4) {
745685f66aSYouMin Chen printascii(" BG=");
755685f66aSYouMin Chen printdec(1 << bg);
765685f66aSYouMin Chen }
775685f66aSYouMin Chen printascii(" CS0 Row=");
785685f66aSYouMin Chen printdec(cap_info->cs0_row);
795685f66aSYouMin Chen if (cap_info->cs0_high16bit_row !=
805685f66aSYouMin Chen cap_info->cs0_row) {
815685f66aSYouMin Chen printascii("/");
825685f66aSYouMin Chen printdec(cap_info->cs0_high16bit_row);
835685f66aSYouMin Chen }
845685f66aSYouMin Chen if (cap_info->rank > 1) {
855685f66aSYouMin Chen printascii(" CS1 Row=");
865685f66aSYouMin Chen printdec(cap_info->cs1_row);
875685f66aSYouMin Chen if (cap_info->cs1_high16bit_row !=
885685f66aSYouMin Chen cap_info->cs1_row) {
895685f66aSYouMin Chen printascii("/");
905685f66aSYouMin Chen printdec(cap_info->cs1_high16bit_row);
915685f66aSYouMin Chen }
925685f66aSYouMin Chen }
93de9242dcSTang Yun ping if (cap_info->rank > 2) {
94de9242dcSTang Yun ping printascii(" CS2 Row=");
95de9242dcSTang Yun ping printdec(cap_info->cs2_row);
96f627cf25SZhihuan He if (cap_info->cs2_high16bit_row !=
97f627cf25SZhihuan He cap_info->cs2_row) {
98f627cf25SZhihuan He printascii("/");
99f627cf25SZhihuan He printdec(cap_info->cs2_high16bit_row);
100f627cf25SZhihuan He }
101de9242dcSTang Yun ping printascii(" CS3 Row=");
102de9242dcSTang Yun ping printdec(cap_info->cs3_row);
103f627cf25SZhihuan He if (cap_info->cs3_high16bit_row !=
104f627cf25SZhihuan He cap_info->cs3_row) {
105f627cf25SZhihuan He printascii("/");
106f627cf25SZhihuan He printdec(cap_info->cs3_high16bit_row);
107f627cf25SZhihuan He }
108de9242dcSTang Yun ping }
1095685f66aSYouMin Chen printascii(" CS=");
1105685f66aSYouMin Chen printdec(cap_info->rank);
1115685f66aSYouMin Chen printascii(" Die BW=");
1125685f66aSYouMin Chen printdec(8 << cap_info->dbw);
1135685f66aSYouMin Chen
1145685f66aSYouMin Chen cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
1155685f66aSYouMin Chen if (cap_info->row_3_4)
1165685f66aSYouMin Chen cap = cap * 3 / 4;
1175685f66aSYouMin Chen else if (split)
1185685f66aSYouMin Chen cap = cap / 2 + (split << 24) / 2;
1195685f66aSYouMin Chen
1205685f66aSYouMin Chen printascii(" Size=");
1215685f66aSYouMin Chen printdec(cap >> 20);
1225685f66aSYouMin Chen printascii("MB\n");
1235685f66aSYouMin Chen }
1245685f66aSYouMin Chen
1255685f66aSYouMin Chen /*
1265685f66aSYouMin Chen * cs: 0:cs0
1275685f66aSYouMin Chen * 1:cs1
1285685f66aSYouMin Chen * else cs0+cs1
1295685f66aSYouMin Chen * note: it didn't consider about row_3_4
1305685f66aSYouMin Chen */
sdram_get_cs_cap(struct sdram_cap_info * cap_info,u32 cs,u32 dram_type)1315685f66aSYouMin Chen u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
1325685f66aSYouMin Chen {
1335685f66aSYouMin Chen u32 bg;
134de9242dcSTang Yun ping u64 cap[4];
1355685f66aSYouMin Chen
1365685f66aSYouMin Chen if (dram_type == DDR4)
1375685f66aSYouMin Chen /* DDR4 8bit dram BG = 2(4bank groups),
1385685f66aSYouMin Chen * 16bit dram BG = 1 (2 bank groups)
1395685f66aSYouMin Chen */
1405685f66aSYouMin Chen bg = (cap_info->dbw == 0) ? 2 : 1;
1415685f66aSYouMin Chen else
1425685f66aSYouMin Chen bg = 0;
1435685f66aSYouMin Chen cap[0] = 1llu << (cap_info->bw + cap_info->col +
1445685f66aSYouMin Chen bg + cap_info->bk + cap_info->cs0_row);
1455685f66aSYouMin Chen
146de9242dcSTang Yun ping if (cap_info->rank >= 2)
1475685f66aSYouMin Chen cap[1] = 1llu << (cap_info->bw + cap_info->col +
1485685f66aSYouMin Chen bg + cap_info->bk + cap_info->cs1_row);
1495685f66aSYouMin Chen else
1505685f66aSYouMin Chen cap[1] = 0;
1511a6462e1STang Yun ping
152de9242dcSTang Yun ping if (cap_info->rank == 4) {
153de9242dcSTang Yun ping cap[2] = 1llu << (cap_info->bw + cap_info->col +
154de9242dcSTang Yun ping bg + cap_info->bk + cap_info->cs2_row);
155de9242dcSTang Yun ping cap[3] = 1llu << (cap_info->bw + cap_info->col +
156de9242dcSTang Yun ping bg + cap_info->bk + cap_info->cs3_row);
157de9242dcSTang Yun ping } else {
158de9242dcSTang Yun ping cap[2] = 0;
159de9242dcSTang Yun ping cap[3] = 0;
160de9242dcSTang Yun ping }
1615685f66aSYouMin Chen if (cs == 0)
1625685f66aSYouMin Chen return cap[0];
1635685f66aSYouMin Chen else if (cs == 1)
1645685f66aSYouMin Chen return cap[1];
1655685f66aSYouMin Chen else
166de9242dcSTang Yun ping return (cap[0] + cap[1] + cap[2] + cap[3]);
1675685f66aSYouMin Chen }
1685685f66aSYouMin Chen
1695685f66aSYouMin Chen /* n: Unit bytes */
sdram_copy_to_reg(u32 * dest,const u32 * src,u32 n)1705685f66aSYouMin Chen void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
1715685f66aSYouMin Chen {
1725685f66aSYouMin Chen int i;
1735685f66aSYouMin Chen
1745685f66aSYouMin Chen for (i = 0; i < n / sizeof(u32); i++) {
1755685f66aSYouMin Chen writel(*src, dest);
1765685f66aSYouMin Chen src++;
1775685f66aSYouMin Chen dest++;
1785685f66aSYouMin Chen }
1795685f66aSYouMin Chen }
1805685f66aSYouMin Chen
sdram_org_config(struct sdram_cap_info * cap_info,struct sdram_base_params * base,u32 * p_os_reg2,u32 * p_os_reg3,u32 channel)1815685f66aSYouMin Chen void sdram_org_config(struct sdram_cap_info *cap_info,
1825685f66aSYouMin Chen struct sdram_base_params *base,
1835685f66aSYouMin Chen u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
1845685f66aSYouMin Chen {
1855685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
1865685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
1875685f66aSYouMin Chen
1885685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
1895685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
1905685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
1915685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
1925685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
1935685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
1945685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
1955685f66aSYouMin Chen
1965685f66aSYouMin Chen SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
1975685f66aSYouMin Chen if (cap_info->cs1_row)
1985685f66aSYouMin Chen SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
1995685f66aSYouMin Chen *p_os_reg3, channel);
2005685f66aSYouMin Chen *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
2015685f66aSYouMin Chen *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
2025685f66aSYouMin Chen }
2035685f66aSYouMin Chen
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)204c69667e0STang Yun ping void sdram_org_config_v3(struct sdram_cap_info *cap_info,
205c69667e0STang Yun ping struct sdram_base_params *base,
206c69667e0STang Yun ping u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
207c69667e0STang Yun ping {
208c69667e0STang Yun ping SYS_REG_ENC_DDRTYPE_V3(base->dramtype, *p_os_reg2, *p_os_reg3);
209c69667e0STang Yun ping
210c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_NUM_CH_V3((base->num_channels > 2) ?
211c69667e0STang Yun ping 2 : base->num_channels);
212c69667e0STang Yun ping
213c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_ROW_3_4_V3(cap_info->row_3_4, channel);
214c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_CHINFO_V3((channel >= 2) ? channel - 2 : channel);
215c69667e0STang Yun ping if (channel == 0 || channel == 2)
216c69667e0STang Yun ping SYS_REG_ENC_CH0_2_RANK_V3(cap_info->rank,
217c69667e0STang Yun ping *p_os_reg2, *p_os_reg3);
218c69667e0STang Yun ping else
219c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_CH1_3_RANK(cap_info->rank);
220c69667e0STang Yun ping
221c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_COL_V3(cap_info->col, channel);
222c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_BK_V3(cap_info->bk, channel);
223c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_BW_V3(cap_info->bw, channel);
224c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_DBW_V3(cap_info->dbw, channel);
225c69667e0STang Yun ping
226c69667e0STang Yun ping SYS_REG_ENC_CS0_ROW_V3(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
227c69667e0STang Yun ping if (cap_info->cs1_row)
228c69667e0STang Yun ping SYS_REG_ENC_CS1_ROW_V3(cap_info->cs1_row, *p_os_reg2,
229c69667e0STang Yun ping *p_os_reg3, channel);
230c69667e0STang Yun ping if ((channel == 0 || channel == 2) && cap_info->rank > 2) {
231c69667e0STang Yun ping if (cap_info->cs2_row == cap_info->cs0_row)
232c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(0);
233c69667e0STang Yun ping else
234c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(1);
235c69667e0STang Yun ping
236c69667e0STang Yun ping if (cap_info->cs3_row == cap_info->cs0_row)
237c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(0);
238c69667e0STang Yun ping else
239c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(1);
240c69667e0STang Yun ping }
241c69667e0STang Yun ping
242c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS1_COL_V3(cap_info->col, channel);
243c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION_3);
244c69667e0STang Yun ping }
245c69667e0STang Yun ping
sdram_detect_bw(struct sdram_cap_info * cap_info)2465685f66aSYouMin Chen int sdram_detect_bw(struct sdram_cap_info *cap_info)
2475685f66aSYouMin Chen {
2485685f66aSYouMin Chen return 0;
2495685f66aSYouMin Chen }
2505685f66aSYouMin Chen
sdram_detect_cs(struct sdram_cap_info * cap_info)2515685f66aSYouMin Chen int sdram_detect_cs(struct sdram_cap_info *cap_info)
2525685f66aSYouMin Chen {
2535685f66aSYouMin Chen return 0;
2545685f66aSYouMin Chen }
2555685f66aSYouMin Chen
sdram_detect_col(struct sdram_cap_info * cap_info,u32 coltmp)2565685f66aSYouMin Chen int sdram_detect_col(struct sdram_cap_info *cap_info,
2575685f66aSYouMin Chen u32 coltmp)
2585685f66aSYouMin Chen {
2595685f66aSYouMin Chen void __iomem *test_addr;
2605685f66aSYouMin Chen u32 col;
2615685f66aSYouMin Chen u32 bw = cap_info->bw;
2625685f66aSYouMin Chen
2635685f66aSYouMin Chen for (col = coltmp; col >= 9; col -= 1) {
2645685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE);
2655685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2665685f66aSYouMin Chen (1ul << (col + bw - 1ul)));
2675685f66aSYouMin Chen writel(PATTERN, test_addr);
2685685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) &&
2695685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0))
2705685f66aSYouMin Chen break;
2715685f66aSYouMin Chen }
2725685f66aSYouMin Chen if (col == 8) {
2735685f66aSYouMin Chen printascii("col error\n");
2745685f66aSYouMin Chen return -1;
2755685f66aSYouMin Chen }
2765685f66aSYouMin Chen
2775685f66aSYouMin Chen cap_info->col = col;
2785685f66aSYouMin Chen
2795685f66aSYouMin Chen return 0;
2805685f66aSYouMin Chen }
2815685f66aSYouMin Chen
sdram_detect_bank(struct sdram_cap_info * cap_info,void __iomem * pctl_base,u32 coltmp,u32 bktmp)282*e1652d39SZhihuan He int sdram_detect_bank(struct sdram_cap_info *cap_info, void __iomem *pctl_base,
2835685f66aSYouMin Chen u32 coltmp, u32 bktmp)
2845685f66aSYouMin Chen {
2855685f66aSYouMin Chen void __iomem *test_addr;
2865685f66aSYouMin Chen u32 bk;
2875685f66aSYouMin Chen u32 bw = cap_info->bw;
288*e1652d39SZhihuan He u32 read;
289*e1652d39SZhihuan He u32 dis_auto_ref = 0;
2905685f66aSYouMin Chen
291*e1652d39SZhihuan He dis_auto_ref = pctl_dis_zqcs_aref(pctl_base);
2925685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2935685f66aSYouMin Chen (1ul << (coltmp + bktmp + bw - 1ul)));
2945685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE);
295*e1652d39SZhihuan He send_a_refresh(pctl_base, 0x1);
2965685f66aSYouMin Chen writel(PATTERN, test_addr);
297*e1652d39SZhihuan He read = readl(test_addr);
298*e1652d39SZhihuan He send_a_refresh(pctl_base, 0x1);
299*e1652d39SZhihuan He if ((read == PATTERN) &&
3005685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0))
3015685f66aSYouMin Chen bk = 3;
3025685f66aSYouMin Chen else
3035685f66aSYouMin Chen bk = 2;
3045685f66aSYouMin Chen
3055685f66aSYouMin Chen cap_info->bk = bk;
3065685f66aSYouMin Chen
307*e1652d39SZhihuan He send_a_refresh(pctl_base, 0x1);
308*e1652d39SZhihuan He pctl_rest_zqcs_aref(pctl_base, dis_auto_ref);
309*e1652d39SZhihuan He
3105685f66aSYouMin Chen return 0;
3115685f66aSYouMin Chen }
3125685f66aSYouMin Chen
3135685f66aSYouMin Chen /* detect bg for ddr4 */
sdram_detect_bg(struct sdram_cap_info * cap_info,void __iomem * pctl_base,u32 coltmp)314*e1652d39SZhihuan He int sdram_detect_bg(struct sdram_cap_info *cap_info, void __iomem *pctl_base,
3155685f66aSYouMin Chen u32 coltmp)
3165685f66aSYouMin Chen {
3175685f66aSYouMin Chen void __iomem *test_addr;
3185685f66aSYouMin Chen u32 dbw;
3195685f66aSYouMin Chen u32 bw = cap_info->bw;
320*e1652d39SZhihuan He u32 read;
321*e1652d39SZhihuan He u32 dis_auto_ref = 0;
3225685f66aSYouMin Chen
323*e1652d39SZhihuan He dis_auto_ref = pctl_dis_zqcs_aref(pctl_base);
3245685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
3255685f66aSYouMin Chen (1ul << (coltmp + bw + 1ul)));
3265685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE);
327*e1652d39SZhihuan He send_a_refresh(pctl_base, 0x1);
3285685f66aSYouMin Chen writel(PATTERN, test_addr);
329*e1652d39SZhihuan He read = readl(test_addr);
330*e1652d39SZhihuan He send_a_refresh(pctl_base, 0x1);
331*e1652d39SZhihuan He if ((read == PATTERN) &&
3325685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0))
3335685f66aSYouMin Chen dbw = 0;
3345685f66aSYouMin Chen else
3355685f66aSYouMin Chen dbw = 1;
3365685f66aSYouMin Chen
3375685f66aSYouMin Chen cap_info->dbw = dbw;
338*e1652d39SZhihuan He send_a_refresh(pctl_base, 0x1);
339*e1652d39SZhihuan He pctl_rest_zqcs_aref(pctl_base, dis_auto_ref);
3405685f66aSYouMin Chen
3415685f66aSYouMin Chen return 0;
3425685f66aSYouMin Chen }
3435685f66aSYouMin Chen
3445685f66aSYouMin Chen /* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
sdram_detect_dbw(struct sdram_cap_info * cap_info,u32 dram_type)3455685f66aSYouMin Chen int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
3465685f66aSYouMin Chen {
3475685f66aSYouMin Chen u32 row, col, bk, bw, cs_cap, cs;
3485685f66aSYouMin Chen u32 die_bw_0 = 0, die_bw_1 = 0;
3495685f66aSYouMin Chen
3509d5c314bSWesley Yao if (dram_type == DDR3) {
3519d5c314bSWesley Yao if (cap_info->bw == 0)
3529d5c314bSWesley Yao cap_info->dbw = 0;
3539d5c314bSWesley Yao else
3549d5c314bSWesley Yao cap_info->dbw = 1;
3559d5c314bSWesley Yao } else if (dram_type == LPDDR4) {
3565685f66aSYouMin Chen cap_info->dbw = 1;
3575685f66aSYouMin Chen } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
3585685f66aSYouMin Chen row = cap_info->cs0_row;
3595685f66aSYouMin Chen col = cap_info->col;
3605685f66aSYouMin Chen bk = cap_info->bk;
3615685f66aSYouMin Chen cs = cap_info->rank;
3625685f66aSYouMin Chen bw = cap_info->bw;
3635685f66aSYouMin Chen cs_cap = (1 << (row + col + bk + bw - 20));
3645685f66aSYouMin Chen if (bw == 2) {
365cd88e935STang Yun ping if (cs_cap <= 0x20) /* 256Mb */
3665685f66aSYouMin Chen die_bw_0 = (col < 9) ? 2 : 1;
367cd88e935STang Yun ping else if (cs_cap <= 0x100) /* 2Gb */
3685685f66aSYouMin Chen die_bw_0 = (col < 10) ? 2 : 1;
369cd88e935STang Yun ping else if (cs_cap <= 0x400) /* 8Gb */
3705685f66aSYouMin Chen die_bw_0 = (col < 11) ? 2 : 1;
3715685f66aSYouMin Chen else
3725685f66aSYouMin Chen die_bw_0 = (col < 12) ? 2 : 1;
3735685f66aSYouMin Chen if (cs > 1) {
3745685f66aSYouMin Chen row = cap_info->cs1_row;
3755685f66aSYouMin Chen cs_cap = (1 << (row + col + bk + bw - 20));
376cd88e935STang Yun ping if (cs_cap <= 0x20) /* 256Mb */
3775685f66aSYouMin Chen die_bw_0 = (col < 9) ? 2 : 1;
378cd88e935STang Yun ping else if (cs_cap <= 0x100) /* 2Gb */
3795685f66aSYouMin Chen die_bw_0 = (col < 10) ? 2 : 1;
380cd88e935STang Yun ping else if (cs_cap <= 0x400) /* 8Gb */
3815685f66aSYouMin Chen die_bw_0 = (col < 11) ? 2 : 1;
3825685f66aSYouMin Chen else
3835685f66aSYouMin Chen die_bw_0 = (col < 12) ? 2 : 1;
3845685f66aSYouMin Chen }
3855685f66aSYouMin Chen } else {
3865685f66aSYouMin Chen die_bw_1 = 1;
3875685f66aSYouMin Chen die_bw_0 = 1;
3885685f66aSYouMin Chen }
3895685f66aSYouMin Chen cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
3905685f66aSYouMin Chen }
3915685f66aSYouMin Chen
3925685f66aSYouMin Chen return 0;
3935685f66aSYouMin Chen }
3945685f66aSYouMin Chen
sdram_detect_row(struct sdram_cap_info * cap_info,u32 coltmp,u32 bktmp,u32 rowtmp)3955685f66aSYouMin Chen int sdram_detect_row(struct sdram_cap_info *cap_info,
3965685f66aSYouMin Chen u32 coltmp, u32 bktmp, u32 rowtmp)
3975685f66aSYouMin Chen {
3985685f66aSYouMin Chen u32 row;
3995685f66aSYouMin Chen u32 bw = cap_info->bw;
4005685f66aSYouMin Chen void __iomem *test_addr;
4015685f66aSYouMin Chen
4025685f66aSYouMin Chen for (row = rowtmp; row > 12; row--) {
4035685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE);
4045685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
4055685f66aSYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul)));
4065685f66aSYouMin Chen writel(PATTERN, test_addr);
4075685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) &&
4085685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0))
4095685f66aSYouMin Chen break;
4105685f66aSYouMin Chen }
4115685f66aSYouMin Chen if (row == 12) {
4125685f66aSYouMin Chen printascii("row error");
4135685f66aSYouMin Chen return -1;
4145685f66aSYouMin Chen }
4155685f66aSYouMin Chen
4165685f66aSYouMin Chen cap_info->cs0_row = row;
4175685f66aSYouMin Chen
4185685f66aSYouMin Chen return 0;
4195685f66aSYouMin Chen }
4205685f66aSYouMin Chen
sdram_detect_row_3_4(struct sdram_cap_info * cap_info,u32 coltmp,u32 bktmp)4215685f66aSYouMin Chen int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
4225685f66aSYouMin Chen u32 coltmp, u32 bktmp)
4235685f66aSYouMin Chen {
4245685f66aSYouMin Chen u32 row_3_4;
4255685f66aSYouMin Chen u32 bw = cap_info->bw;
4265685f66aSYouMin Chen u32 row = cap_info->cs0_row;
4275685f66aSYouMin Chen void __iomem *test_addr, *test_addr1;
4285685f66aSYouMin Chen
4295685f66aSYouMin Chen test_addr = CONFIG_SYS_SDRAM_BASE;
4305685f66aSYouMin Chen test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
4315685f66aSYouMin Chen (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
4325685f66aSYouMin Chen
4335685f66aSYouMin Chen writel(0, test_addr);
4345685f66aSYouMin Chen writel(PATTERN, test_addr1);
4355685f66aSYouMin Chen if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
4365685f66aSYouMin Chen row_3_4 = 0;
4375685f66aSYouMin Chen else
4385685f66aSYouMin Chen row_3_4 = 1;
4395685f66aSYouMin Chen
4405685f66aSYouMin Chen cap_info->row_3_4 = row_3_4;
4415685f66aSYouMin Chen
4425685f66aSYouMin Chen return 0;
4435685f66aSYouMin Chen }
4445685f66aSYouMin Chen
sdram_detect_high_row(struct sdram_cap_info * cap_info,u32 dramtype)445f627cf25SZhihuan He int sdram_detect_high_row(struct sdram_cap_info *cap_info, u32 dramtype)
4465685f66aSYouMin Chen {
447f627cf25SZhihuan He unsigned long base_addr;
448f627cf25SZhihuan He u32 cs0_high_row, cs1_high_row, cs;
449f627cf25SZhihuan He u64 cap = 0, cs0_cap = 0;
450f627cf25SZhihuan He u32 i;
451f627cf25SZhihuan He void __iomem *test_addr, *test_addr1;
452f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
453f627cf25SZhihuan He u32 cs2_high_row, cs3_high_row;
454f627cf25SZhihuan He #endif
455f627cf25SZhihuan He
456f627cf25SZhihuan He cs = cap_info->rank;
457f627cf25SZhihuan He /* 8bit bandwidth no enable axi split*/
458f627cf25SZhihuan He if (!cap_info->bw) {
459f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row;
460f627cf25SZhihuan He cs1_high_row = cap_info->cs1_row;
461f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
462f627cf25SZhihuan He if (cs > 2) {
463f627cf25SZhihuan He cs2_high_row = cap_info->cs2_row;
464f627cf25SZhihuan He cs3_high_row = cap_info->cs3_row;
465f627cf25SZhihuan He }
466f627cf25SZhihuan He #endif
467f627cf25SZhihuan He goto out;
468f627cf25SZhihuan He }
469f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
470f627cf25SZhihuan He if (cs > 2) {
471f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row;
472f627cf25SZhihuan He cs1_high_row = cap_info->cs1_row;
473f627cf25SZhihuan He cs2_high_row = cap_info->cs2_row;
474f627cf25SZhihuan He cs3_high_row = cap_info->cs3_row;
475f627cf25SZhihuan He
476f627cf25SZhihuan He goto out;
477f627cf25SZhihuan He }
478f627cf25SZhihuan He #endif
479f627cf25SZhihuan He
480f627cf25SZhihuan He cs0_cap = sdram_get_cs_cap(cap_info, 0, dramtype);
481f627cf25SZhihuan He if (cs == 2) {
482f627cf25SZhihuan He base_addr = CONFIG_SYS_SDRAM_BASE + cs0_cap;
483f627cf25SZhihuan He cap = sdram_get_cs_cap(cap_info, 1, dramtype);
484f627cf25SZhihuan He } else {
485f627cf25SZhihuan He base_addr = CONFIG_SYS_SDRAM_BASE;
486f627cf25SZhihuan He cap = cs0_cap;
487f627cf25SZhihuan He }
488f627cf25SZhihuan He /* detect full bandwidth size */
489f627cf25SZhihuan He for (i = 0; i < 4; i++) {
490f627cf25SZhihuan He test_addr = (void __iomem *)base_addr;
491f627cf25SZhihuan He test_addr1 = (void __iomem *)(base_addr +
492f627cf25SZhihuan He (unsigned long)(cap / (1ul << (i + 1))));
493f627cf25SZhihuan He writel(0x0, test_addr);
494f627cf25SZhihuan He writel(PATTERN, test_addr1);
495f627cf25SZhihuan He if ((readl(test_addr) == 0x0) &&
496f627cf25SZhihuan He (readl(test_addr1) == PATTERN))
497f627cf25SZhihuan He break;
498f627cf25SZhihuan He }
499f627cf25SZhihuan He if (i == 4 && cs == 1) {
500f627cf25SZhihuan He printascii("can't support this cap\n");
501f627cf25SZhihuan He return -1;
502f627cf25SZhihuan He }
503f627cf25SZhihuan He
504f627cf25SZhihuan He if (cs == 2) {
505f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row;
506f627cf25SZhihuan He if (i == 4)
507f627cf25SZhihuan He cs1_high_row = 0;
508f627cf25SZhihuan He else
509f627cf25SZhihuan He cs1_high_row = cap_info->cs1_row - i;
510f627cf25SZhihuan He } else {
511f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row - i;
512f627cf25SZhihuan He cs1_high_row = 0;
513f627cf25SZhihuan He }
514f627cf25SZhihuan He
515f627cf25SZhihuan He out:
516f627cf25SZhihuan He cap_info->cs0_high16bit_row = cs0_high_row;
517f627cf25SZhihuan He cap_info->cs1_high16bit_row = cs1_high_row;
518f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
519f627cf25SZhihuan He if (cs > 2) {
520f627cf25SZhihuan He cap_info->cs2_high16bit_row = cs2_high_row;
521f627cf25SZhihuan He cap_info->cs3_high16bit_row = cs3_high_row;
522f627cf25SZhihuan He }
523f627cf25SZhihuan He #endif
5245685f66aSYouMin Chen
5255685f66aSYouMin Chen return 0;
5265685f66aSYouMin Chen }
5275685f66aSYouMin Chen
sdram_detect_cs1_row(struct sdram_cap_info * cap_info,u32 dram_type)5285685f66aSYouMin Chen int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
5295685f66aSYouMin Chen {
5305685f66aSYouMin Chen void __iomem *test_addr;
5315685f66aSYouMin Chen u32 row = 0, bktmp, coltmp, bw;
5325685f66aSYouMin Chen ulong cs0_cap;
5335685f66aSYouMin Chen u32 byte_mask;
5345685f66aSYouMin Chen
5355685f66aSYouMin Chen if (cap_info->rank == 2) {
5365685f66aSYouMin Chen cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
5375685f66aSYouMin Chen
5385685f66aSYouMin Chen if (dram_type == DDR4) {
5395685f66aSYouMin Chen if (cap_info->dbw == 0)
5405685f66aSYouMin Chen bktmp = cap_info->bk + 2;
5415685f66aSYouMin Chen else
5425685f66aSYouMin Chen bktmp = cap_info->bk + 1;
5435685f66aSYouMin Chen } else {
5445685f66aSYouMin Chen bktmp = cap_info->bk;
5455685f66aSYouMin Chen }
5465685f66aSYouMin Chen bw = cap_info->bw;
5475685f66aSYouMin Chen coltmp = cap_info->col;
5485685f66aSYouMin Chen
5495685f66aSYouMin Chen /*
5505685f66aSYouMin Chen * because px30 support axi split,min bandwidth
5515685f66aSYouMin Chen * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
5525685f66aSYouMin Chen * so we check low 16bit data when detect cs1 row.
5535685f66aSYouMin Chen * if cs0 is 16bit/8bit, we check low 8bit data.
5545685f66aSYouMin Chen */
5555685f66aSYouMin Chen if (bw == 2)
5565685f66aSYouMin Chen byte_mask = 0xFFFF;
5575685f66aSYouMin Chen else
5585685f66aSYouMin Chen byte_mask = 0xFF;
5595685f66aSYouMin Chen
5605685f66aSYouMin Chen /* detect cs1 row */
5615685f66aSYouMin Chen for (row = cap_info->cs0_row; row > 12; row--) {
5625685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
5635685f66aSYouMin Chen cs0_cap +
5645685f66aSYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul)));
5655685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
5665685f66aSYouMin Chen writel(PATTERN, test_addr);
5675685f66aSYouMin Chen
5685685f66aSYouMin Chen if (((readl(test_addr) & byte_mask) ==
5695685f66aSYouMin Chen (PATTERN & byte_mask)) &&
5705685f66aSYouMin Chen ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
5715685f66aSYouMin Chen byte_mask) == 0)) {
5725685f66aSYouMin Chen break;
5735685f66aSYouMin Chen }
5745685f66aSYouMin Chen }
5755685f66aSYouMin Chen }
5765685f66aSYouMin Chen
5775685f66aSYouMin Chen cap_info->cs1_row = row;
5785685f66aSYouMin Chen
5795685f66aSYouMin Chen return 0;
5805685f66aSYouMin Chen }
5815685f66aSYouMin Chen
582