xref: /rk3399_rockchip-uboot/drivers/ram/rockchip/sdram_common.c (revision 9d5c314b35defd1c678227deba13c3b4dfd4a0f3)
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);
83de9242dcSTang Yun ping 		printascii(" CS3 Row=");
84de9242dcSTang Yun ping 		printdec(cap_info->cs3_row);
85de9242dcSTang Yun ping 	}
865685f66aSYouMin Chen 	printascii(" CS=");
875685f66aSYouMin Chen 	printdec(cap_info->rank);
885685f66aSYouMin Chen 	printascii(" Die BW=");
895685f66aSYouMin Chen 	printdec(8 << cap_info->dbw);
905685f66aSYouMin Chen 
915685f66aSYouMin Chen 	cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
925685f66aSYouMin Chen 	if (cap_info->row_3_4)
935685f66aSYouMin Chen 		cap = cap * 3 / 4;
945685f66aSYouMin Chen 	else if (split)
955685f66aSYouMin Chen 		cap = cap / 2 + (split << 24) / 2;
965685f66aSYouMin Chen 
975685f66aSYouMin Chen 	printascii(" Size=");
985685f66aSYouMin Chen 	printdec(cap >> 20);
995685f66aSYouMin Chen 	printascii("MB\n");
1005685f66aSYouMin Chen }
1015685f66aSYouMin Chen 
1025685f66aSYouMin Chen /*
1035685f66aSYouMin Chen  * cs: 0:cs0
1045685f66aSYouMin Chen  *	   1:cs1
1055685f66aSYouMin Chen  *     else cs0+cs1
1065685f66aSYouMin Chen  * note: it didn't consider about row_3_4
1075685f66aSYouMin Chen  */
1085685f66aSYouMin Chen u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
1095685f66aSYouMin Chen {
1105685f66aSYouMin Chen 	u32 bg;
111de9242dcSTang Yun ping 	u64 cap[4];
1125685f66aSYouMin Chen 
1135685f66aSYouMin Chen 	if (dram_type == DDR4)
1145685f66aSYouMin Chen 		/* DDR4 8bit dram BG = 2(4bank groups),
1155685f66aSYouMin Chen 		 * 16bit dram BG = 1 (2 bank groups)
1165685f66aSYouMin Chen 		 */
1175685f66aSYouMin Chen 		bg = (cap_info->dbw == 0) ? 2 : 1;
1185685f66aSYouMin Chen 	else
1195685f66aSYouMin Chen 		bg = 0;
1205685f66aSYouMin Chen 	cap[0] = 1llu << (cap_info->bw + cap_info->col +
1215685f66aSYouMin Chen 		bg + cap_info->bk + cap_info->cs0_row);
1225685f66aSYouMin Chen 
123de9242dcSTang Yun ping 	if (cap_info->rank >= 2)
1245685f66aSYouMin Chen 		cap[1] = 1llu << (cap_info->bw + cap_info->col +
1255685f66aSYouMin Chen 			bg + cap_info->bk + cap_info->cs1_row);
1265685f66aSYouMin Chen 	else
1275685f66aSYouMin Chen 		cap[1] = 0;
1281a6462e1STang Yun ping 
129de9242dcSTang Yun ping 	if (cap_info->rank == 4) {
130de9242dcSTang Yun ping 		cap[2] = 1llu << (cap_info->bw + cap_info->col +
131de9242dcSTang Yun ping 			bg + cap_info->bk + cap_info->cs2_row);
132de9242dcSTang Yun ping 		cap[3] = 1llu << (cap_info->bw + cap_info->col +
133de9242dcSTang Yun ping 			bg + cap_info->bk + cap_info->cs3_row);
134de9242dcSTang Yun ping 	} else {
135de9242dcSTang Yun ping 		cap[2] = 0;
136de9242dcSTang Yun ping 		cap[3] = 0;
137de9242dcSTang Yun ping 	}
1385685f66aSYouMin Chen 	if (cs == 0)
1395685f66aSYouMin Chen 		return cap[0];
1405685f66aSYouMin Chen 	else if (cs == 1)
1415685f66aSYouMin Chen 		return cap[1];
1425685f66aSYouMin Chen 	else
143de9242dcSTang Yun ping 		return (cap[0] + cap[1] + cap[2] + cap[3]);
1445685f66aSYouMin Chen }
1455685f66aSYouMin Chen 
1465685f66aSYouMin Chen /* n: Unit bytes */
1475685f66aSYouMin Chen void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
1485685f66aSYouMin Chen {
1495685f66aSYouMin Chen 	int i;
1505685f66aSYouMin Chen 
1515685f66aSYouMin Chen 	for (i = 0; i < n / sizeof(u32); i++) {
1525685f66aSYouMin Chen 		writel(*src, dest);
1535685f66aSYouMin Chen 		src++;
1545685f66aSYouMin Chen 		dest++;
1555685f66aSYouMin Chen 	}
1565685f66aSYouMin Chen }
1575685f66aSYouMin Chen 
1585685f66aSYouMin Chen void sdram_org_config(struct sdram_cap_info *cap_info,
1595685f66aSYouMin Chen 		      struct sdram_base_params *base,
1605685f66aSYouMin Chen 		      u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
1615685f66aSYouMin Chen {
1625685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
1635685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
1645685f66aSYouMin Chen 
1655685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
1665685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
1675685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
1685685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
1695685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
1705685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
1715685f66aSYouMin Chen 	*p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
1725685f66aSYouMin Chen 
1735685f66aSYouMin Chen 	SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
1745685f66aSYouMin Chen 	if (cap_info->cs1_row)
1755685f66aSYouMin Chen 		SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
1765685f66aSYouMin Chen 				    *p_os_reg3, channel);
1775685f66aSYouMin Chen 	*p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
1785685f66aSYouMin Chen 	*p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
1795685f66aSYouMin Chen }
1805685f66aSYouMin Chen 
181c69667e0STang Yun ping void sdram_org_config_v3(struct sdram_cap_info *cap_info,
182c69667e0STang Yun ping 			 struct sdram_base_params *base,
183c69667e0STang Yun ping 			 u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
184c69667e0STang Yun ping {
185c69667e0STang Yun ping 	SYS_REG_ENC_DDRTYPE_V3(base->dramtype, *p_os_reg2, *p_os_reg3);
186c69667e0STang Yun ping 
187c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_NUM_CH_V3((base->num_channels > 2) ?
188c69667e0STang Yun ping 					    2 : base->num_channels);
189c69667e0STang Yun ping 
190c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_ROW_3_4_V3(cap_info->row_3_4, channel);
191c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_CHINFO_V3((channel >= 2) ? channel - 2 : channel);
192c69667e0STang Yun ping 	if (channel == 0 || channel == 2)
193c69667e0STang Yun ping 		SYS_REG_ENC_CH0_2_RANK_V3(cap_info->rank,
194c69667e0STang Yun ping 					  *p_os_reg2, *p_os_reg3);
195c69667e0STang Yun ping 	else
196c69667e0STang Yun ping 		*p_os_reg2 |= SYS_REG_ENC_CH1_3_RANK(cap_info->rank);
197c69667e0STang Yun ping 
198c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_COL_V3(cap_info->col, channel);
199c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_BK_V3(cap_info->bk, channel);
200c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_BW_V3(cap_info->bw, channel);
201c69667e0STang Yun ping 	*p_os_reg2 |= SYS_REG_ENC_DBW_V3(cap_info->dbw, channel);
202c69667e0STang Yun ping 
203c69667e0STang Yun ping 	SYS_REG_ENC_CS0_ROW_V3(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
204c69667e0STang Yun ping 	if (cap_info->cs1_row)
205c69667e0STang Yun ping 		SYS_REG_ENC_CS1_ROW_V3(cap_info->cs1_row, *p_os_reg2,
206c69667e0STang Yun ping 				       *p_os_reg3, channel);
207c69667e0STang Yun ping 	if ((channel == 0 || channel == 2) && cap_info->rank > 2) {
208c69667e0STang Yun ping 		if (cap_info->cs2_row == cap_info->cs0_row)
209c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(0);
210c69667e0STang Yun ping 		else
211c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(1);
212c69667e0STang Yun ping 
213c69667e0STang Yun ping 		if (cap_info->cs3_row == cap_info->cs0_row)
214c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(0);
215c69667e0STang Yun ping 		else
216c69667e0STang Yun ping 			*p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(1);
217c69667e0STang Yun ping 	}
218c69667e0STang Yun ping 
219c69667e0STang Yun ping 	*p_os_reg3 |= SYS_REG_ENC_CS1_COL_V3(cap_info->col, channel);
220c69667e0STang Yun ping 	*p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION_3);
221c69667e0STang Yun ping }
222c69667e0STang Yun ping 
2235685f66aSYouMin Chen int sdram_detect_bw(struct sdram_cap_info *cap_info)
2245685f66aSYouMin Chen {
2255685f66aSYouMin Chen 	return 0;
2265685f66aSYouMin Chen }
2275685f66aSYouMin Chen 
2285685f66aSYouMin Chen int sdram_detect_cs(struct sdram_cap_info *cap_info)
2295685f66aSYouMin Chen {
2305685f66aSYouMin Chen 	return 0;
2315685f66aSYouMin Chen }
2325685f66aSYouMin Chen 
2335685f66aSYouMin Chen int sdram_detect_col(struct sdram_cap_info *cap_info,
2345685f66aSYouMin Chen 		     u32 coltmp)
2355685f66aSYouMin Chen {
2365685f66aSYouMin Chen 	void __iomem *test_addr;
2375685f66aSYouMin Chen 	u32 col;
2385685f66aSYouMin Chen 	u32 bw = cap_info->bw;
2395685f66aSYouMin Chen 
2405685f66aSYouMin Chen 	for (col = coltmp; col >= 9; col -= 1) {
2415685f66aSYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
2425685f66aSYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2435685f66aSYouMin Chen 				(1ul << (col + bw - 1ul)));
2445685f66aSYouMin Chen 		writel(PATTERN, test_addr);
2455685f66aSYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
2465685f66aSYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
2475685f66aSYouMin Chen 			break;
2485685f66aSYouMin Chen 	}
2495685f66aSYouMin Chen 	if (col == 8) {
2505685f66aSYouMin Chen 		printascii("col error\n");
2515685f66aSYouMin Chen 		return -1;
2525685f66aSYouMin Chen 	}
2535685f66aSYouMin Chen 
2545685f66aSYouMin Chen 	cap_info->col = col;
2555685f66aSYouMin Chen 
2565685f66aSYouMin Chen 	return 0;
2575685f66aSYouMin Chen }
2585685f66aSYouMin Chen 
2595685f66aSYouMin Chen int sdram_detect_bank(struct sdram_cap_info *cap_info,
2605685f66aSYouMin Chen 		      u32 coltmp, u32 bktmp)
2615685f66aSYouMin Chen {
2625685f66aSYouMin Chen 	void __iomem *test_addr;
2635685f66aSYouMin Chen 	u32 bk;
2645685f66aSYouMin Chen 	u32 bw = cap_info->bw;
2655685f66aSYouMin Chen 
2665685f66aSYouMin Chen 	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2675685f66aSYouMin Chen 			(1ul << (coltmp + bktmp + bw - 1ul)));
2685685f66aSYouMin Chen 	writel(0, CONFIG_SYS_SDRAM_BASE);
2695685f66aSYouMin Chen 	writel(PATTERN, test_addr);
2705685f66aSYouMin Chen 	if ((readl(test_addr) == PATTERN) &&
2715685f66aSYouMin Chen 	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
2725685f66aSYouMin Chen 		bk = 3;
2735685f66aSYouMin Chen 	else
2745685f66aSYouMin Chen 		bk = 2;
2755685f66aSYouMin Chen 
2765685f66aSYouMin Chen 	cap_info->bk = bk;
2775685f66aSYouMin Chen 
2785685f66aSYouMin Chen 	return 0;
2795685f66aSYouMin Chen }
2805685f66aSYouMin Chen 
2815685f66aSYouMin Chen /* detect bg for ddr4 */
2825685f66aSYouMin Chen int sdram_detect_bg(struct sdram_cap_info *cap_info,
2835685f66aSYouMin Chen 		    u32 coltmp)
2845685f66aSYouMin Chen {
2855685f66aSYouMin Chen 	void __iomem *test_addr;
2865685f66aSYouMin Chen 	u32 dbw;
2875685f66aSYouMin Chen 	u32 bw = cap_info->bw;
2885685f66aSYouMin Chen 
2895685f66aSYouMin Chen 	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
2905685f66aSYouMin Chen 			(1ul << (coltmp + bw + 1ul)));
2915685f66aSYouMin Chen 	writel(0, CONFIG_SYS_SDRAM_BASE);
2925685f66aSYouMin Chen 	writel(PATTERN, test_addr);
2935685f66aSYouMin Chen 	if ((readl(test_addr) == PATTERN) &&
2945685f66aSYouMin Chen 	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
2955685f66aSYouMin Chen 		dbw = 0;
2965685f66aSYouMin Chen 	else
2975685f66aSYouMin Chen 		dbw = 1;
2985685f66aSYouMin Chen 
2995685f66aSYouMin Chen 	cap_info->dbw = dbw;
3005685f66aSYouMin Chen 
3015685f66aSYouMin Chen 	return 0;
3025685f66aSYouMin Chen }
3035685f66aSYouMin Chen 
3045685f66aSYouMin Chen /* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
3055685f66aSYouMin Chen int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
3065685f66aSYouMin Chen {
3075685f66aSYouMin Chen 	u32 row, col, bk, bw, cs_cap, cs;
3085685f66aSYouMin Chen 	u32 die_bw_0 = 0, die_bw_1 = 0;
3095685f66aSYouMin Chen 
310*9d5c314bSWesley Yao 	if (dram_type == DDR3) {
311*9d5c314bSWesley Yao 		if (cap_info->bw == 0)
312*9d5c314bSWesley Yao 			cap_info->dbw = 0;
313*9d5c314bSWesley Yao 		else
314*9d5c314bSWesley Yao 			cap_info->dbw = 1;
315*9d5c314bSWesley Yao 	} else if (dram_type == LPDDR4) {
3165685f66aSYouMin Chen 		cap_info->dbw = 1;
3175685f66aSYouMin Chen 	} else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
3185685f66aSYouMin Chen 		row = cap_info->cs0_row;
3195685f66aSYouMin Chen 		col = cap_info->col;
3205685f66aSYouMin Chen 		bk = cap_info->bk;
3215685f66aSYouMin Chen 		cs = cap_info->rank;
3225685f66aSYouMin Chen 		bw = cap_info->bw;
3235685f66aSYouMin Chen 		cs_cap = (1 << (row + col + bk + bw - 20));
3245685f66aSYouMin Chen 		if (bw == 2) {
3255685f66aSYouMin Chen 			if (cs_cap <= 0x2000000) /* 256Mb */
3265685f66aSYouMin Chen 				die_bw_0 = (col < 9) ? 2 : 1;
3275685f66aSYouMin Chen 			else if (cs_cap <= 0x10000000) /* 2Gb */
3285685f66aSYouMin Chen 				die_bw_0 = (col < 10) ? 2 : 1;
3295685f66aSYouMin Chen 			else if (cs_cap <= 0x40000000) /* 8Gb */
3305685f66aSYouMin Chen 				die_bw_0 = (col < 11) ? 2 : 1;
3315685f66aSYouMin Chen 			else
3325685f66aSYouMin Chen 				die_bw_0 = (col < 12) ? 2 : 1;
3335685f66aSYouMin Chen 			if (cs > 1) {
3345685f66aSYouMin Chen 				row = cap_info->cs1_row;
3355685f66aSYouMin Chen 				cs_cap = (1 << (row + col + bk + bw - 20));
3365685f66aSYouMin Chen 				if (cs_cap <= 0x2000000) /* 256Mb */
3375685f66aSYouMin Chen 					die_bw_0 = (col < 9) ? 2 : 1;
3385685f66aSYouMin Chen 				else if (cs_cap <= 0x10000000) /* 2Gb */
3395685f66aSYouMin Chen 					die_bw_0 = (col < 10) ? 2 : 1;
3405685f66aSYouMin Chen 				else if (cs_cap <= 0x40000000) /* 8Gb */
3415685f66aSYouMin Chen 					die_bw_0 = (col < 11) ? 2 : 1;
3425685f66aSYouMin Chen 				else
3435685f66aSYouMin Chen 					die_bw_0 = (col < 12) ? 2 : 1;
3445685f66aSYouMin Chen 			}
3455685f66aSYouMin Chen 		} else {
3465685f66aSYouMin Chen 			die_bw_1 = 1;
3475685f66aSYouMin Chen 			die_bw_0 = 1;
3485685f66aSYouMin Chen 		}
3495685f66aSYouMin Chen 		cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
3505685f66aSYouMin Chen 	}
3515685f66aSYouMin Chen 
3525685f66aSYouMin Chen 	return 0;
3535685f66aSYouMin Chen }
3545685f66aSYouMin Chen 
3555685f66aSYouMin Chen int sdram_detect_row(struct sdram_cap_info *cap_info,
3565685f66aSYouMin Chen 		     u32 coltmp, u32 bktmp, u32 rowtmp)
3575685f66aSYouMin Chen {
3585685f66aSYouMin Chen 	u32 row;
3595685f66aSYouMin Chen 	u32 bw = cap_info->bw;
3605685f66aSYouMin Chen 	void __iomem *test_addr;
3615685f66aSYouMin Chen 
3625685f66aSYouMin Chen 	for (row = rowtmp; row > 12; row--) {
3635685f66aSYouMin Chen 		writel(0, CONFIG_SYS_SDRAM_BASE);
3645685f66aSYouMin Chen 		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
3655685f66aSYouMin Chen 				(1ul << (row + bktmp + coltmp + bw - 1ul)));
3665685f66aSYouMin Chen 		writel(PATTERN, test_addr);
3675685f66aSYouMin Chen 		if ((readl(test_addr) == PATTERN) &&
3685685f66aSYouMin Chen 		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
3695685f66aSYouMin Chen 			break;
3705685f66aSYouMin Chen 	}
3715685f66aSYouMin Chen 	if (row == 12) {
3725685f66aSYouMin Chen 		printascii("row error");
3735685f66aSYouMin Chen 		return -1;
3745685f66aSYouMin Chen 	}
3755685f66aSYouMin Chen 
3765685f66aSYouMin Chen 	cap_info->cs0_row = row;
3775685f66aSYouMin Chen 
3785685f66aSYouMin Chen 	return 0;
3795685f66aSYouMin Chen }
3805685f66aSYouMin Chen 
3815685f66aSYouMin Chen int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
3825685f66aSYouMin Chen 			 u32 coltmp, u32 bktmp)
3835685f66aSYouMin Chen {
3845685f66aSYouMin Chen 	u32 row_3_4;
3855685f66aSYouMin Chen 	u32 bw = cap_info->bw;
3865685f66aSYouMin Chen 	u32 row = cap_info->cs0_row;
3875685f66aSYouMin Chen 	void __iomem *test_addr, *test_addr1;
3885685f66aSYouMin Chen 
3895685f66aSYouMin Chen 	test_addr = CONFIG_SYS_SDRAM_BASE;
3905685f66aSYouMin Chen 	test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
3915685f66aSYouMin Chen 			(0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
3925685f66aSYouMin Chen 
3935685f66aSYouMin Chen 	writel(0, test_addr);
3945685f66aSYouMin Chen 	writel(PATTERN, test_addr1);
3955685f66aSYouMin Chen 	if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
3965685f66aSYouMin Chen 		row_3_4 = 0;
3975685f66aSYouMin Chen 	else
3985685f66aSYouMin Chen 		row_3_4 = 1;
3995685f66aSYouMin Chen 
4005685f66aSYouMin Chen 	cap_info->row_3_4 = row_3_4;
4015685f66aSYouMin Chen 
4025685f66aSYouMin Chen 	return 0;
4035685f66aSYouMin Chen }
4045685f66aSYouMin Chen 
4055685f66aSYouMin Chen int sdram_detect_high_row(struct sdram_cap_info *cap_info)
4065685f66aSYouMin Chen {
4075685f66aSYouMin Chen 	cap_info->cs0_high16bit_row = cap_info->cs0_row;
4085685f66aSYouMin Chen 	cap_info->cs1_high16bit_row = cap_info->cs1_row;
4095685f66aSYouMin Chen 
4105685f66aSYouMin Chen 	return 0;
4115685f66aSYouMin Chen }
4125685f66aSYouMin Chen 
4135685f66aSYouMin Chen int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
4145685f66aSYouMin Chen {
4155685f66aSYouMin Chen 	void __iomem *test_addr;
4165685f66aSYouMin Chen 	u32 row = 0, bktmp, coltmp, bw;
4175685f66aSYouMin Chen 	ulong cs0_cap;
4185685f66aSYouMin Chen 	u32 byte_mask;
4195685f66aSYouMin Chen 
4205685f66aSYouMin Chen 	if (cap_info->rank == 2) {
4215685f66aSYouMin Chen 		cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
4225685f66aSYouMin Chen 
4235685f66aSYouMin Chen 		if (dram_type == DDR4) {
4245685f66aSYouMin Chen 			if (cap_info->dbw == 0)
4255685f66aSYouMin Chen 				bktmp = cap_info->bk + 2;
4265685f66aSYouMin Chen 			else
4275685f66aSYouMin Chen 				bktmp = cap_info->bk + 1;
4285685f66aSYouMin Chen 		} else {
4295685f66aSYouMin Chen 			bktmp = cap_info->bk;
4305685f66aSYouMin Chen 		}
4315685f66aSYouMin Chen 		bw = cap_info->bw;
4325685f66aSYouMin Chen 		coltmp = cap_info->col;
4335685f66aSYouMin Chen 
4345685f66aSYouMin Chen 		/*
4355685f66aSYouMin Chen 		 * because px30 support axi split,min bandwidth
4365685f66aSYouMin Chen 		 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
4375685f66aSYouMin Chen 		 * so we check low 16bit data when detect cs1 row.
4385685f66aSYouMin Chen 		 * if cs0 is 16bit/8bit, we check low 8bit data.
4395685f66aSYouMin Chen 		 */
4405685f66aSYouMin Chen 		if (bw == 2)
4415685f66aSYouMin Chen 			byte_mask = 0xFFFF;
4425685f66aSYouMin Chen 		else
4435685f66aSYouMin Chen 			byte_mask = 0xFF;
4445685f66aSYouMin Chen 
4455685f66aSYouMin Chen 		/* detect cs1 row */
4465685f66aSYouMin Chen 		for (row = cap_info->cs0_row; row > 12; row--) {
4475685f66aSYouMin Chen 			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
4485685f66aSYouMin Chen 				    cs0_cap +
4495685f66aSYouMin Chen 				    (1ul << (row + bktmp + coltmp + bw - 1ul)));
4505685f66aSYouMin Chen 			writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
4515685f66aSYouMin Chen 			writel(PATTERN, test_addr);
4525685f66aSYouMin Chen 
4535685f66aSYouMin Chen 			if (((readl(test_addr) & byte_mask) ==
4545685f66aSYouMin Chen 			     (PATTERN & byte_mask)) &&
4555685f66aSYouMin Chen 			    ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
4565685f66aSYouMin Chen 			      byte_mask) == 0)) {
4575685f66aSYouMin Chen 				break;
4585685f66aSYouMin Chen 			}
4595685f66aSYouMin Chen 		}
4605685f66aSYouMin Chen 	}
4615685f66aSYouMin Chen 
4625685f66aSYouMin Chen 	cap_info->cs1_row = row;
4635685f66aSYouMin Chen 
4645685f66aSYouMin Chen 	return 0;
4655685f66aSYouMin Chen }
4665685f66aSYouMin Chen 
467