xref: /rk3399_rockchip-uboot/drivers/ram/rockchip/sdram_common.c (revision f627cf25e97b0bb49b3faf2118965c992c4dee8f)
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 
135685f66aSYouMin Chen void sdram_print_dram_type(unsigned char dramtype)
145685f66aSYouMin Chen {
155685f66aSYouMin Chen 	switch (dramtype) {
165685f66aSYouMin Chen 	case DDR3:
175685f66aSYouMin Chen 		printascii("DDR3");
185685f66aSYouMin Chen 		break;
195685f66aSYouMin Chen 	case DDR4:
205685f66aSYouMin Chen 		printascii("DDR4");
215685f66aSYouMin Chen 		break;
225685f66aSYouMin Chen 	case LPDDR2:
235685f66aSYouMin Chen 		printascii("LPDDR2");
245685f66aSYouMin Chen 		break;
255685f66aSYouMin Chen 	case LPDDR3:
265685f66aSYouMin Chen 		printascii("LPDDR3");
275685f66aSYouMin Chen 		break;
285685f66aSYouMin Chen 	case LPDDR4:
295685f66aSYouMin Chen 		printascii("LPDDR4");
305685f66aSYouMin Chen 		break;
31de9242dcSTang Yun ping 	case LPDDR4X:
32de9242dcSTang Yun ping 		printascii("LPDDR4X");
33de9242dcSTang Yun ping 		break;
345685f66aSYouMin Chen 	default:
355685f66aSYouMin Chen 		printascii("Unknown Device");
365685f66aSYouMin Chen 		break;
375685f66aSYouMin Chen 	}
385685f66aSYouMin Chen }
395685f66aSYouMin Chen 
405685f66aSYouMin Chen void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
415685f66aSYouMin Chen 			  struct sdram_base_params *base, u32 split)
425685f66aSYouMin Chen {
435685f66aSYouMin Chen 	u64 cap;
445685f66aSYouMin Chen 	u32 bg;
455685f66aSYouMin Chen 
465685f66aSYouMin Chen 	bg = (cap_info->dbw == 0) ? 2 : 1;
475685f66aSYouMin Chen 
485685f66aSYouMin Chen 	sdram_print_dram_type(base->dramtype);
495685f66aSYouMin Chen 
505685f66aSYouMin Chen 	printascii(", ");
515685f66aSYouMin Chen 	printdec(base->ddr_freq);
525685f66aSYouMin Chen 	printascii("MHz\n");
535685f66aSYouMin Chen 
545685f66aSYouMin Chen 	printascii("BW=");
555685f66aSYouMin Chen 	printdec(8 << cap_info->bw);
565685f66aSYouMin Chen 	printascii(" Col=");
575685f66aSYouMin Chen 	printdec(cap_info->col);
585685f66aSYouMin Chen 	printascii(" Bk=");
595685f66aSYouMin Chen 	printdec(0x1 << cap_info->bk);
605685f66aSYouMin Chen 	if (base->dramtype == DDR4) {
615685f66aSYouMin Chen 		printascii(" BG=");
625685f66aSYouMin Chen 		printdec(1 << bg);
635685f66aSYouMin Chen 	}
645685f66aSYouMin Chen 	printascii(" CS0 Row=");
655685f66aSYouMin Chen 	printdec(cap_info->cs0_row);
665685f66aSYouMin Chen 	if (cap_info->cs0_high16bit_row !=
675685f66aSYouMin Chen 		cap_info->cs0_row) {
685685f66aSYouMin Chen 		printascii("/");
695685f66aSYouMin Chen 		printdec(cap_info->cs0_high16bit_row);
705685f66aSYouMin Chen 	}
715685f66aSYouMin Chen 	if (cap_info->rank > 1) {
725685f66aSYouMin Chen 		printascii(" CS1 Row=");
735685f66aSYouMin Chen 		printdec(cap_info->cs1_row);
745685f66aSYouMin Chen 		if (cap_info->cs1_high16bit_row !=
755685f66aSYouMin Chen 			cap_info->cs1_row) {
765685f66aSYouMin Chen 			printascii("/");
775685f66aSYouMin Chen 			printdec(cap_info->cs1_high16bit_row);
785685f66aSYouMin Chen 		}
795685f66aSYouMin Chen 	}
80de9242dcSTang Yun ping 	if (cap_info->rank > 2) {
81de9242dcSTang Yun ping 		printascii(" CS2 Row=");
82de9242dcSTang Yun ping 		printdec(cap_info->cs2_row);
83*f627cf25SZhihuan He 		if (cap_info->cs2_high16bit_row !=
84*f627cf25SZhihuan He 			cap_info->cs2_row) {
85*f627cf25SZhihuan He 			printascii("/");
86*f627cf25SZhihuan He 			printdec(cap_info->cs2_high16bit_row);
87*f627cf25SZhihuan He 		}
88de9242dcSTang Yun ping 		printascii(" CS3 Row=");
89de9242dcSTang Yun ping 		printdec(cap_info->cs3_row);
90*f627cf25SZhihuan He 		if (cap_info->cs3_high16bit_row !=
91*f627cf25SZhihuan He 			cap_info->cs3_row) {
92*f627cf25SZhihuan He 			printascii("/");
93*f627cf25SZhihuan He 			printdec(cap_info->cs3_high16bit_row);
94*f627cf25SZhihuan He 		}
95de9242dcSTang Yun ping 	}
965685f66aSYouMin Chen 	printascii(" CS=");
975685f66aSYouMin Chen 	printdec(cap_info->rank);
985685f66aSYouMin Chen 	printascii(" Die BW=");
995685f66aSYouMin Chen 	printdec(8 << cap_info->dbw);
1005685f66aSYouMin Chen 
1015685f66aSYouMin Chen 	cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
1025685f66aSYouMin Chen 	if (cap_info->row_3_4)
1035685f66aSYouMin Chen 		cap = cap * 3 / 4;
1045685f66aSYouMin Chen 	else if (split)
1055685f66aSYouMin Chen 		cap = cap / 2 + (split << 24) / 2;
1065685f66aSYouMin Chen 
1075685f66aSYouMin Chen 	printascii(" Size=");
1085685f66aSYouMin Chen 	printdec(cap >> 20);
1095685f66aSYouMin Chen 	printascii("MB\n");
1105685f66aSYouMin Chen }
1115685f66aSYouMin Chen 
1125685f66aSYouMin Chen /*
1135685f66aSYouMin Chen  * cs: 0:cs0
1145685f66aSYouMin Chen  *	   1:cs1
1155685f66aSYouMin Chen  *     else cs0+cs1
1165685f66aSYouMin Chen  * note: it didn't consider about row_3_4
1175685f66aSYouMin Chen  */
1185685f66aSYouMin Chen u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
1195685f66aSYouMin Chen {
1205685f66aSYouMin Chen 	u32 bg;
121de9242dcSTang Yun ping 	u64 cap[4];
1225685f66aSYouMin Chen 
1235685f66aSYouMin Chen 	if (dram_type == DDR4)
1245685f66aSYouMin Chen 		/* DDR4 8bit dram BG = 2(4bank groups),
1255685f66aSYouMin Chen 		 * 16bit dram BG = 1 (2 bank groups)
1265685f66aSYouMin Chen 		 */
1275685f66aSYouMin Chen 		bg = (cap_info->dbw == 0) ? 2 : 1;
1285685f66aSYouMin Chen 	else
1295685f66aSYouMin Chen 		bg = 0;
1305685f66aSYouMin Chen 	cap[0] = 1llu << (cap_info->bw + cap_info->col +
1315685f66aSYouMin Chen 		bg + cap_info->bk + cap_info->cs0_row);
1325685f66aSYouMin Chen 
133de9242dcSTang Yun ping 	if (cap_info->rank >= 2)
1345685f66aSYouMin Chen 		cap[1] = 1llu << (cap_info->bw + cap_info->col +
1355685f66aSYouMin Chen 			bg + cap_info->bk + cap_info->cs1_row);
1365685f66aSYouMin Chen 	else
1375685f66aSYouMin Chen 		cap[1] = 0;
1381a6462e1STang Yun ping 
139de9242dcSTang Yun ping 	if (cap_info->rank == 4) {
140de9242dcSTang Yun ping 		cap[2] = 1llu << (cap_info->bw + cap_info->col +
141de9242dcSTang Yun ping 			bg + cap_info->bk + cap_info->cs2_row);
142de9242dcSTang Yun ping 		cap[3] = 1llu << (cap_info->bw + cap_info->col +
143de9242dcSTang Yun ping 			bg + cap_info->bk + cap_info->cs3_row);
144de9242dcSTang Yun ping 	} else {
145de9242dcSTang Yun ping 		cap[2] = 0;
146de9242dcSTang Yun ping 		cap[3] = 0;
147de9242dcSTang Yun ping 	}
1485685f66aSYouMin Chen 	if (cs == 0)
1495685f66aSYouMin Chen 		return cap[0];
1505685f66aSYouMin Chen 	else if (cs == 1)
1515685f66aSYouMin Chen 		return cap[1];
1525685f66aSYouMin Chen 	else
153de9242dcSTang Yun ping 		return (cap[0] + cap[1] + cap[2] + cap[3]);
1545685f66aSYouMin Chen }
1555685f66aSYouMin Chen 
1565685f66aSYouMin Chen /* n: Unit bytes */
1575685f66aSYouMin Chen void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
1585685f66aSYouMin Chen {
1595685f66aSYouMin Chen 	int i;
1605685f66aSYouMin Chen 
1615685f66aSYouMin Chen 	for (i = 0; i < n / sizeof(u32); i++) {
1625685f66aSYouMin Chen 		writel(*src, dest);
1635685f66aSYouMin Chen 		src++;
1645685f66aSYouMin Chen 		dest++;
1655685f66aSYouMin Chen 	}
1665685f66aSYouMin Chen }
1675685f66aSYouMin Chen 
1685685f66aSYouMin Chen void sdram_org_config(struct sdram_cap_info *cap_info,
1695685f66aSYouMin Chen 		      struct sdram_base_params *base,
1705685f66aSYouMin Chen 		      u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
1715685f66aSYouMin Chen {
1725685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
1735685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
1745685f66aSYouMin Chen 
1755685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
1765685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
1775685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
1785685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
1795685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
1805685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
1815685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
1825685f66aSYouMin Chen 
1835685f66aSYouMin Chen 	SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
1845685f66aSYouMin Chen 	if (cap_info->cs1_row)
1855685f66aSYouMin Chen 		SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
1865685f66aSYouMin Chen 				    *p_os_reg3, channel);
1875685f66aSYouMin Chen 	*p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
1885685f66aSYouMin Chen 	*p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
1895685f66aSYouMin Chen }
1905685f66aSYouMin Chen 
191c69667e0STang Yun ping void sdram_org_config_v3(struct sdram_cap_info *cap_info,
192c69667e0STang Yun ping 			 struct sdram_base_params *base,
193c69667e0STang Yun ping 			 u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
194c69667e0STang Yun ping {
195c69667e0STang Yun ping 	SYS_REG_ENC_DDRTYPE_V3(base->dramtype, *p_os_reg2, *p_os_reg3);
196c69667e0STang Yun ping 
197c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_NUM_CH_V3((base->num_channels > 2) ?
198c69667e0STang Yun ping 					    2 : base->num_channels);
199c69667e0STang Yun ping 
200c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_ROW_3_4_V3(cap_info->row_3_4, channel);
201c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_CHINFO_V3((channel >= 2) ? channel - 2 : channel);
202c69667e0STang Yun ping 	if (channel == 0 || channel == 2)
203c69667e0STang Yun ping 		SYS_REG_ENC_CH0_2_RANK_V3(cap_info->rank,
204c69667e0STang Yun ping 					  *p_os_reg2, *p_os_reg3);
205c69667e0STang Yun ping 	else
206c69667e0STang Yun ping 		*p_os_reg2 |= SYS_REG_ENC_CH1_3_RANK(cap_info->rank);
207c69667e0STang Yun ping 
208c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_COL_V3(cap_info->col, channel);
209c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_BK_V3(cap_info->bk, channel);
210c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_BW_V3(cap_info->bw, channel);
211c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_DBW_V3(cap_info->dbw, channel);
212c69667e0STang Yun ping 
213c69667e0STang Yun ping 	SYS_REG_ENC_CS0_ROW_V3(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
214c69667e0STang Yun ping 	if (cap_info->cs1_row)
215c69667e0STang Yun ping 		SYS_REG_ENC_CS1_ROW_V3(cap_info->cs1_row, *p_os_reg2,
216c69667e0STang Yun ping 				       *p_os_reg3, channel);
217c69667e0STang Yun ping 	if ((channel == 0 || channel == 2) && cap_info->rank > 2) {
218c69667e0STang Yun ping 		if (cap_info->cs2_row == cap_info->cs0_row)
219c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(0);
220c69667e0STang Yun ping 		else
221c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(1);
222c69667e0STang Yun ping 
223c69667e0STang Yun ping 		if (cap_info->cs3_row == cap_info->cs0_row)
224c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(0);
225c69667e0STang Yun ping 		else
226c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(1);
227c69667e0STang Yun ping 	}
228c69667e0STang Yun ping 
229c69667e0STang Yun ping 	*p_os_reg3 |= SYS_REG_ENC_CS1_COL_V3(cap_info->col, channel);
230c69667e0STang Yun ping 	*p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION_3);
231c69667e0STang Yun ping }
232c69667e0STang Yun ping 
2335685f66aSYouMin Chen int sdram_detect_bw(struct sdram_cap_info *cap_info)
2345685f66aSYouMin Chen {
2355685f66aSYouMin Chen 	return 0;
2365685f66aSYouMin Chen }
2375685f66aSYouMin Chen 
2385685f66aSYouMin Chen int sdram_detect_cs(struct sdram_cap_info *cap_info)
2395685f66aSYouMin Chen {
2405685f66aSYouMin Chen 	return 0;
2415685f66aSYouMin Chen }
2425685f66aSYouMin Chen 
2435685f66aSYouMin Chen int sdram_detect_col(struct sdram_cap_info *cap_info,
2445685f66aSYouMin Chen 		     u32 coltmp)
2455685f66aSYouMin Chen {
2465685f66aSYouMin Chen 	void __iomem *test_addr;
2475685f66aSYouMin Chen 	u32 col;
2485685f66aSYouMin Chen 	u32 bw = cap_info->bw;
2495685f66aSYouMin Chen 
2505685f66aSYouMin Chen 	for (col = coltmp; col >= 9; col -= 1) {
2515685f66aSYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
2525685f66aSYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2535685f66aSYouMin Chen 				(1ul << (col + bw - 1ul)));
2545685f66aSYouMin Chen 		writel(PATTERN, test_addr);
2555685f66aSYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
2565685f66aSYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
2575685f66aSYouMin Chen 			break;
2585685f66aSYouMin Chen 	}
2595685f66aSYouMin Chen 	if (col == 8) {
2605685f66aSYouMin Chen 		printascii("col error\n");
2615685f66aSYouMin Chen 		return -1;
2625685f66aSYouMin Chen 	}
2635685f66aSYouMin Chen 
2645685f66aSYouMin Chen 	cap_info->col = col;
2655685f66aSYouMin Chen 
2665685f66aSYouMin Chen 	return 0;
2675685f66aSYouMin Chen }
2685685f66aSYouMin Chen 
2695685f66aSYouMin Chen int sdram_detect_bank(struct sdram_cap_info *cap_info,
2705685f66aSYouMin Chen 		      u32 coltmp, u32 bktmp)
2715685f66aSYouMin Chen {
2725685f66aSYouMin Chen 	void __iomem *test_addr;
2735685f66aSYouMin Chen 	u32 bk;
2745685f66aSYouMin Chen 	u32 bw = cap_info->bw;
2755685f66aSYouMin Chen 
2765685f66aSYouMin Chen 	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2775685f66aSYouMin Chen 			(1ul << (coltmp + bktmp + bw - 1ul)));
2785685f66aSYouMin Chen 	writel(0, CONFIG_SYS_SDRAM_BASE);
2795685f66aSYouMin Chen 	writel(PATTERN, test_addr);
2805685f66aSYouMin Chen 	if ((readl(test_addr) == PATTERN) &&
2815685f66aSYouMin Chen 	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
2825685f66aSYouMin Chen 		bk = 3;
2835685f66aSYouMin Chen 	else
2845685f66aSYouMin Chen 		bk = 2;
2855685f66aSYouMin Chen 
2865685f66aSYouMin Chen 	cap_info->bk = bk;
2875685f66aSYouMin Chen 
2885685f66aSYouMin Chen 	return 0;
2895685f66aSYouMin Chen }
2905685f66aSYouMin Chen 
2915685f66aSYouMin Chen /* detect bg for ddr4 */
2925685f66aSYouMin Chen int sdram_detect_bg(struct sdram_cap_info *cap_info,
2935685f66aSYouMin Chen 		    u32 coltmp)
2945685f66aSYouMin Chen {
2955685f66aSYouMin Chen 	void __iomem *test_addr;
2965685f66aSYouMin Chen 	u32 dbw;
2975685f66aSYouMin Chen 	u32 bw = cap_info->bw;
2985685f66aSYouMin Chen 
2995685f66aSYouMin Chen 	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
3005685f66aSYouMin Chen 			(1ul << (coltmp + bw + 1ul)));
3015685f66aSYouMin Chen 	writel(0, CONFIG_SYS_SDRAM_BASE);
3025685f66aSYouMin Chen 	writel(PATTERN, test_addr);
3035685f66aSYouMin Chen 	if ((readl(test_addr) == PATTERN) &&
3045685f66aSYouMin Chen 	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
3055685f66aSYouMin Chen 		dbw = 0;
3065685f66aSYouMin Chen 	else
3075685f66aSYouMin Chen 		dbw = 1;
3085685f66aSYouMin Chen 
3095685f66aSYouMin Chen 	cap_info->dbw = dbw;
3105685f66aSYouMin Chen 
3115685f66aSYouMin Chen 	return 0;
3125685f66aSYouMin Chen }
3135685f66aSYouMin Chen 
3145685f66aSYouMin Chen /* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
3155685f66aSYouMin Chen int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
3165685f66aSYouMin Chen {
3175685f66aSYouMin Chen 	u32 row, col, bk, bw, cs_cap, cs;
3185685f66aSYouMin Chen 	u32 die_bw_0 = 0, die_bw_1 = 0;
3195685f66aSYouMin Chen 
3209d5c314bSWesley Yao 	if (dram_type == DDR3) {
3219d5c314bSWesley Yao 		if (cap_info->bw == 0)
3229d5c314bSWesley Yao 			cap_info->dbw = 0;
3239d5c314bSWesley Yao 		else
3249d5c314bSWesley Yao 			cap_info->dbw = 1;
3259d5c314bSWesley Yao 	} else if (dram_type == LPDDR4) {
3265685f66aSYouMin Chen 		cap_info->dbw = 1;
3275685f66aSYouMin Chen 	} else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
3285685f66aSYouMin Chen 		row = cap_info->cs0_row;
3295685f66aSYouMin Chen 		col = cap_info->col;
3305685f66aSYouMin Chen 		bk = cap_info->bk;
3315685f66aSYouMin Chen 		cs = cap_info->rank;
3325685f66aSYouMin Chen 		bw = cap_info->bw;
3335685f66aSYouMin Chen 		cs_cap = (1 << (row + col + bk + bw - 20));
3345685f66aSYouMin Chen 		if (bw == 2) {
3355685f66aSYouMin Chen 			if (cs_cap <= 0x2000000) /* 256Mb */
3365685f66aSYouMin Chen 				die_bw_0 = (col < 9) ? 2 : 1;
3375685f66aSYouMin Chen 			else if (cs_cap <= 0x10000000) /* 2Gb */
3385685f66aSYouMin Chen 				die_bw_0 = (col < 10) ? 2 : 1;
3395685f66aSYouMin Chen 			else if (cs_cap <= 0x40000000) /* 8Gb */
3405685f66aSYouMin Chen 				die_bw_0 = (col < 11) ? 2 : 1;
3415685f66aSYouMin Chen 			else
3425685f66aSYouMin Chen 				die_bw_0 = (col < 12) ? 2 : 1;
3435685f66aSYouMin Chen 			if (cs > 1) {
3445685f66aSYouMin Chen 				row = cap_info->cs1_row;
3455685f66aSYouMin Chen 				cs_cap = (1 << (row + col + bk + bw - 20));
3465685f66aSYouMin Chen 				if (cs_cap <= 0x2000000) /* 256Mb */
3475685f66aSYouMin Chen 					die_bw_0 = (col < 9) ? 2 : 1;
3485685f66aSYouMin Chen 				else if (cs_cap <= 0x10000000) /* 2Gb */
3495685f66aSYouMin Chen 					die_bw_0 = (col < 10) ? 2 : 1;
3505685f66aSYouMin Chen 				else if (cs_cap <= 0x40000000) /* 8Gb */
3515685f66aSYouMin Chen 					die_bw_0 = (col < 11) ? 2 : 1;
3525685f66aSYouMin Chen 				else
3535685f66aSYouMin Chen 					die_bw_0 = (col < 12) ? 2 : 1;
3545685f66aSYouMin Chen 			}
3555685f66aSYouMin Chen 		} else {
3565685f66aSYouMin Chen 			die_bw_1 = 1;
3575685f66aSYouMin Chen 			die_bw_0 = 1;
3585685f66aSYouMin Chen 		}
3595685f66aSYouMin Chen 		cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
3605685f66aSYouMin Chen 	}
3615685f66aSYouMin Chen 
3625685f66aSYouMin Chen 	return 0;
3635685f66aSYouMin Chen }
3645685f66aSYouMin Chen 
3655685f66aSYouMin Chen int sdram_detect_row(struct sdram_cap_info *cap_info,
3665685f66aSYouMin Chen 		     u32 coltmp, u32 bktmp, u32 rowtmp)
3675685f66aSYouMin Chen {
3685685f66aSYouMin Chen 	u32 row;
3695685f66aSYouMin Chen 	u32 bw = cap_info->bw;
3705685f66aSYouMin Chen 	void __iomem *test_addr;
3715685f66aSYouMin Chen 
3725685f66aSYouMin Chen 	for (row = rowtmp; row > 12; row--) {
3735685f66aSYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
3745685f66aSYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
3755685f66aSYouMin Chen 				(1ul << (row + bktmp + coltmp + bw - 1ul)));
3765685f66aSYouMin Chen 		writel(PATTERN, test_addr);
3775685f66aSYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
3785685f66aSYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
3795685f66aSYouMin Chen 			break;
3805685f66aSYouMin Chen 	}
3815685f66aSYouMin Chen 	if (row == 12) {
3825685f66aSYouMin Chen 		printascii("row error");
3835685f66aSYouMin Chen 		return -1;
3845685f66aSYouMin Chen 	}
3855685f66aSYouMin Chen 
3865685f66aSYouMin Chen 	cap_info->cs0_row = row;
3875685f66aSYouMin Chen 
3885685f66aSYouMin Chen 	return 0;
3895685f66aSYouMin Chen }
3905685f66aSYouMin Chen 
3915685f66aSYouMin Chen int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
3925685f66aSYouMin Chen 			 u32 coltmp, u32 bktmp)
3935685f66aSYouMin Chen {
3945685f66aSYouMin Chen 	u32 row_3_4;
3955685f66aSYouMin Chen 	u32 bw = cap_info->bw;
3965685f66aSYouMin Chen 	u32 row = cap_info->cs0_row;
3975685f66aSYouMin Chen 	void __iomem *test_addr, *test_addr1;
3985685f66aSYouMin Chen 
3995685f66aSYouMin Chen 	test_addr = CONFIG_SYS_SDRAM_BASE;
4005685f66aSYouMin Chen 	test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
4015685f66aSYouMin Chen 			(0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
4025685f66aSYouMin Chen 
4035685f66aSYouMin Chen 	writel(0, test_addr);
4045685f66aSYouMin Chen 	writel(PATTERN, test_addr1);
4055685f66aSYouMin Chen 	if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
4065685f66aSYouMin Chen 		row_3_4 = 0;
4075685f66aSYouMin Chen 	else
4085685f66aSYouMin Chen 		row_3_4 = 1;
4095685f66aSYouMin Chen 
4105685f66aSYouMin Chen 	cap_info->row_3_4 = row_3_4;
4115685f66aSYouMin Chen 
4125685f66aSYouMin Chen 	return 0;
4135685f66aSYouMin Chen }
4145685f66aSYouMin Chen 
415*f627cf25SZhihuan He int sdram_detect_high_row(struct sdram_cap_info *cap_info, u32 dramtype)
4165685f66aSYouMin Chen {
417*f627cf25SZhihuan He 	unsigned long base_addr;
418*f627cf25SZhihuan He 	u32 cs0_high_row, cs1_high_row, cs;
419*f627cf25SZhihuan He 	u64 cap = 0, cs0_cap = 0;
420*f627cf25SZhihuan He 	u32 i;
421*f627cf25SZhihuan He 	void __iomem *test_addr, *test_addr1;
422*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
423*f627cf25SZhihuan He 	u32 cs2_high_row, cs3_high_row;
424*f627cf25SZhihuan He #endif
425*f627cf25SZhihuan He 
426*f627cf25SZhihuan He 	cs = cap_info->rank;
427*f627cf25SZhihuan He 	/* 8bit bandwidth no enable axi split*/
428*f627cf25SZhihuan He 	if (!cap_info->bw) {
429*f627cf25SZhihuan He 		cs0_high_row = cap_info->cs0_row;
430*f627cf25SZhihuan He 		cs1_high_row = cap_info->cs1_row;
431*f627cf25SZhihuan He 	#ifdef CONFIG_ROCKCHIP_RK3568
432*f627cf25SZhihuan He 		if (cs > 2) {
433*f627cf25SZhihuan He 			cs2_high_row = cap_info->cs2_row;
434*f627cf25SZhihuan He 			cs3_high_row = cap_info->cs3_row;
435*f627cf25SZhihuan He 		}
436*f627cf25SZhihuan He 	#endif
437*f627cf25SZhihuan He 		goto out;
438*f627cf25SZhihuan He 	}
439*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
440*f627cf25SZhihuan He 	if (cs > 2) {
441*f627cf25SZhihuan He 		cs0_high_row = cap_info->cs0_row;
442*f627cf25SZhihuan He 		cs1_high_row = cap_info->cs1_row;
443*f627cf25SZhihuan He 		cs2_high_row = cap_info->cs2_row;
444*f627cf25SZhihuan He 		cs3_high_row = cap_info->cs3_row;
445*f627cf25SZhihuan He 
446*f627cf25SZhihuan He 		goto out;
447*f627cf25SZhihuan He 	}
448*f627cf25SZhihuan He #endif
449*f627cf25SZhihuan He 
450*f627cf25SZhihuan He 	cs0_cap = sdram_get_cs_cap(cap_info, 0, dramtype);
451*f627cf25SZhihuan He 	if (cs == 2) {
452*f627cf25SZhihuan He 		base_addr = CONFIG_SYS_SDRAM_BASE + cs0_cap;
453*f627cf25SZhihuan He 		cap = sdram_get_cs_cap(cap_info, 1, dramtype);
454*f627cf25SZhihuan He 	} else {
455*f627cf25SZhihuan He 		base_addr = CONFIG_SYS_SDRAM_BASE;
456*f627cf25SZhihuan He 		cap = cs0_cap;
457*f627cf25SZhihuan He 	}
458*f627cf25SZhihuan He 	/* detect full bandwidth size */
459*f627cf25SZhihuan He 	for (i = 0; i < 4; i++) {
460*f627cf25SZhihuan He 		test_addr = (void __iomem *)base_addr;
461*f627cf25SZhihuan He 		test_addr1 = (void __iomem *)(base_addr +
462*f627cf25SZhihuan He 			     (unsigned long)(cap / (1ul << (i + 1))));
463*f627cf25SZhihuan He 		writel(0x0, test_addr);
464*f627cf25SZhihuan He 		writel(PATTERN, test_addr1);
465*f627cf25SZhihuan He 		if ((readl(test_addr) == 0x0) &&
466*f627cf25SZhihuan He 		    (readl(test_addr1) == PATTERN))
467*f627cf25SZhihuan He 			break;
468*f627cf25SZhihuan He 	}
469*f627cf25SZhihuan He 	if (i == 4 && cs == 1) {
470*f627cf25SZhihuan He 		printascii("can't support this cap\n");
471*f627cf25SZhihuan He 		return -1;
472*f627cf25SZhihuan He 	}
473*f627cf25SZhihuan He 
474*f627cf25SZhihuan He 	if (cs == 2) {
475*f627cf25SZhihuan He 		cs0_high_row = cap_info->cs0_row;
476*f627cf25SZhihuan He 		if (i == 4)
477*f627cf25SZhihuan He 			cs1_high_row = 0;
478*f627cf25SZhihuan He 		else
479*f627cf25SZhihuan He 			cs1_high_row = cap_info->cs1_row - i;
480*f627cf25SZhihuan He 	} else {
481*f627cf25SZhihuan He 		cs0_high_row = cap_info->cs0_row - i;
482*f627cf25SZhihuan He 		cs1_high_row = 0;
483*f627cf25SZhihuan He 	}
484*f627cf25SZhihuan He 
485*f627cf25SZhihuan He out:
486*f627cf25SZhihuan He 	cap_info->cs0_high16bit_row = cs0_high_row;
487*f627cf25SZhihuan He 	cap_info->cs1_high16bit_row = cs1_high_row;
488*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568
489*f627cf25SZhihuan He 	if (cs > 2) {
490*f627cf25SZhihuan He 		cap_info->cs2_high16bit_row = cs2_high_row;
491*f627cf25SZhihuan He 		cap_info->cs3_high16bit_row = cs3_high_row;
492*f627cf25SZhihuan He 	}
493*f627cf25SZhihuan He #endif
4945685f66aSYouMin Chen 
4955685f66aSYouMin Chen 	return 0;
4965685f66aSYouMin Chen }
4975685f66aSYouMin Chen 
4985685f66aSYouMin Chen int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
4995685f66aSYouMin Chen {
5005685f66aSYouMin Chen 	void __iomem *test_addr;
5015685f66aSYouMin Chen 	u32 row = 0, bktmp, coltmp, bw;
5025685f66aSYouMin Chen 	ulong cs0_cap;
5035685f66aSYouMin Chen 	u32 byte_mask;
5045685f66aSYouMin Chen 
5055685f66aSYouMin Chen 	if (cap_info->rank == 2) {
5065685f66aSYouMin Chen 		cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
5075685f66aSYouMin Chen 
5085685f66aSYouMin Chen 		if (dram_type == DDR4) {
5095685f66aSYouMin Chen 			if (cap_info->dbw == 0)
5105685f66aSYouMin Chen 				bktmp = cap_info->bk + 2;
5115685f66aSYouMin Chen 			else
5125685f66aSYouMin Chen 				bktmp = cap_info->bk + 1;
5135685f66aSYouMin Chen 		} else {
5145685f66aSYouMin Chen 			bktmp = cap_info->bk;
5155685f66aSYouMin Chen 		}
5165685f66aSYouMin Chen 		bw = cap_info->bw;
5175685f66aSYouMin Chen 		coltmp = cap_info->col;
5185685f66aSYouMin Chen 
5195685f66aSYouMin Chen 		/*
5205685f66aSYouMin Chen 		 * because px30 support axi split,min bandwidth
5215685f66aSYouMin Chen 		 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
5225685f66aSYouMin Chen 		 * so we check low 16bit data when detect cs1 row.
5235685f66aSYouMin Chen 		 * if cs0 is 16bit/8bit, we check low 8bit data.
5245685f66aSYouMin Chen 		 */
5255685f66aSYouMin Chen 		if (bw == 2)
5265685f66aSYouMin Chen 			byte_mask = 0xFFFF;
5275685f66aSYouMin Chen 		else
5285685f66aSYouMin Chen 			byte_mask = 0xFF;
5295685f66aSYouMin Chen 
5305685f66aSYouMin Chen 		/* detect cs1 row */
5315685f66aSYouMin Chen 		for (row = cap_info->cs0_row; row > 12; row--) {
5325685f66aSYouMin Chen 			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
5335685f66aSYouMin Chen 				    cs0_cap +
5345685f66aSYouMin Chen 				    (1ul << (row + bktmp + coltmp + bw - 1ul)));
5355685f66aSYouMin Chen 			writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
5365685f66aSYouMin Chen 			writel(PATTERN, test_addr);
5375685f66aSYouMin Chen 
5385685f66aSYouMin Chen 			if (((readl(test_addr) & byte_mask) ==
5395685f66aSYouMin Chen 			     (PATTERN & byte_mask)) &&
5405685f66aSYouMin Chen 			    ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
5415685f66aSYouMin Chen 			      byte_mask) == 0)) {
5425685f66aSYouMin Chen 				break;
5435685f66aSYouMin Chen 			}
5445685f66aSYouMin Chen 		}
5455685f66aSYouMin Chen 	}
5465685f66aSYouMin Chen 
5475685f66aSYouMin Chen 	cap_info->cs1_row = row;
5485685f66aSYouMin Chen 
5495685f66aSYouMin Chen 	return 0;
5505685f66aSYouMin Chen }
5515685f66aSYouMin Chen 
552