mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	The empty function define should not be in the header file, or else the build will error with function multi definition after CONFIG_RAM_ROCKCHIP_DEBUG is disabled. Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
		
			
				
	
	
		
			443 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			443 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
 | 
						|
 */
 | 
						|
 | 
						|
#include <common.h>
 | 
						|
#include <debug_uart.h>
 | 
						|
#include <ram.h>
 | 
						|
#include <asm/io.h>
 | 
						|
#include <asm/arch-rockchip/sdram.h>
 | 
						|
#include <asm/arch-rockchip/sdram_common.h>
 | 
						|
 | 
						|
#ifdef CONFIG_RAM_ROCKCHIP_DEBUG
 | 
						|
void sdram_print_dram_type(unsigned char dramtype)
 | 
						|
{
 | 
						|
	switch (dramtype) {
 | 
						|
	case DDR3:
 | 
						|
		printascii("DDR3");
 | 
						|
		break;
 | 
						|
	case DDR4:
 | 
						|
		printascii("DDR4");
 | 
						|
		break;
 | 
						|
	case LPDDR2:
 | 
						|
		printascii("LPDDR2");
 | 
						|
		break;
 | 
						|
	case LPDDR3:
 | 
						|
		printascii("LPDDR3");
 | 
						|
		break;
 | 
						|
	case LPDDR4:
 | 
						|
		printascii("LPDDR4");
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		printascii("Unknown Device");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
 | 
						|
			  struct sdram_base_params *base)
 | 
						|
{
 | 
						|
	u64 cap;
 | 
						|
	u32 bg;
 | 
						|
 | 
						|
	bg = (cap_info->dbw == 0) ? 2 : 1;
 | 
						|
 | 
						|
	sdram_print_dram_type(base->dramtype);
 | 
						|
 | 
						|
	printascii(", ");
 | 
						|
	printdec(base->ddr_freq);
 | 
						|
	printascii("MHz\n");
 | 
						|
 | 
						|
	printascii("BW=");
 | 
						|
	printdec(8 << cap_info->bw);
 | 
						|
	printascii(" Col=");
 | 
						|
	printdec(cap_info->col);
 | 
						|
	printascii(" Bk=");
 | 
						|
	printdec(0x1 << cap_info->bk);
 | 
						|
	if (base->dramtype == DDR4) {
 | 
						|
		printascii(" BG=");
 | 
						|
		printdec(1 << bg);
 | 
						|
	}
 | 
						|
	printascii(" CS0 Row=");
 | 
						|
	printdec(cap_info->cs0_row);
 | 
						|
	if (cap_info->cs0_high16bit_row !=
 | 
						|
		cap_info->cs0_row) {
 | 
						|
		printascii("/");
 | 
						|
		printdec(cap_info->cs0_high16bit_row);
 | 
						|
	}
 | 
						|
	if (cap_info->rank > 1) {
 | 
						|
		printascii(" CS1 Row=");
 | 
						|
		printdec(cap_info->cs1_row);
 | 
						|
		if (cap_info->cs1_high16bit_row !=
 | 
						|
			cap_info->cs1_row) {
 | 
						|
			printascii("/");
 | 
						|
			printdec(cap_info->cs1_high16bit_row);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printascii(" CS=");
 | 
						|
	printdec(cap_info->rank);
 | 
						|
	printascii(" Die BW=");
 | 
						|
	printdec(8 << cap_info->dbw);
 | 
						|
 | 
						|
	cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
 | 
						|
	if (cap_info->row_3_4)
 | 
						|
		cap = cap * 3 / 4;
 | 
						|
 | 
						|
	printascii(" Size=");
 | 
						|
	printdec(cap >> 20);
 | 
						|
	printascii("MB\n");
 | 
						|
}
 | 
						|
 | 
						|
void sdram_print_stride(unsigned int stride)
 | 
						|
{
 | 
						|
	switch (stride) {
 | 
						|
	case 0xc:
 | 
						|
		printf("128B stride\n");
 | 
						|
		break;
 | 
						|
	case 5:
 | 
						|
	case 9:
 | 
						|
	case 0xd:
 | 
						|
	case 0x11:
 | 
						|
	case 0x19:
 | 
						|
		printf("256B stride\n");
 | 
						|
		break;
 | 
						|
	case 0xa:
 | 
						|
	case 0xe:
 | 
						|
	case 0x12:
 | 
						|
		printf("512B stride\n");
 | 
						|
		break;
 | 
						|
	case 0xf:
 | 
						|
		printf("4K stride\n");
 | 
						|
		break;
 | 
						|
	case 0x1f:
 | 
						|
		printf("32MB + 256B stride\n");
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		printf("no stride\n");
 | 
						|
	}
 | 
						|
}
 | 
						|
#else
 | 
						|
inline void sdram_print_dram_type(unsigned char dramtype)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
 | 
						|
				 struct sdram_base_params *base)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
inline void sdram_print_stride(unsigned int stride)
 | 
						|
{
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * cs: 0:cs0
 | 
						|
 *	   1:cs1
 | 
						|
 *     else cs0+cs1
 | 
						|
 * note: it didn't consider about row_3_4
 | 
						|
 */
 | 
						|
u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
 | 
						|
{
 | 
						|
	u32 bg;
 | 
						|
	u64 cap[2];
 | 
						|
 | 
						|
	if (dram_type == DDR4)
 | 
						|
		/* DDR4 8bit dram BG = 2(4bank groups),
 | 
						|
		 * 16bit dram BG = 1 (2 bank groups)
 | 
						|
		 */
 | 
						|
		bg = (cap_info->dbw == 0) ? 2 : 1;
 | 
						|
	else
 | 
						|
		bg = 0;
 | 
						|
	cap[0] = 1llu << (cap_info->bw + cap_info->col +
 | 
						|
		bg + cap_info->bk + cap_info->cs0_row);
 | 
						|
 | 
						|
	if (cap_info->rank == 2)
 | 
						|
		cap[1] = 1llu << (cap_info->bw + cap_info->col +
 | 
						|
			bg + cap_info->bk + cap_info->cs1_row);
 | 
						|
	else
 | 
						|
		cap[1] = 0;
 | 
						|
 | 
						|
	if (cs == 0)
 | 
						|
		return cap[0];
 | 
						|
	else if (cs == 1)
 | 
						|
		return cap[1];
 | 
						|
	else
 | 
						|
		return (cap[0] + cap[1]);
 | 
						|
}
 | 
						|
 | 
						|
/* n: Unit bytes */
 | 
						|
void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < n / sizeof(u32); i++) {
 | 
						|
		writel(*src, dest);
 | 
						|
		src++;
 | 
						|
		dest++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void sdram_org_config(struct sdram_cap_info *cap_info,
 | 
						|
		      struct sdram_base_params *base,
 | 
						|
		      u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
 | 
						|
{
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
 | 
						|
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
 | 
						|
	*p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
 | 
						|
 | 
						|
	SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
 | 
						|
	if (cap_info->cs1_row)
 | 
						|
		SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
 | 
						|
				    *p_os_reg3, channel);
 | 
						|
	*p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
 | 
						|
	*p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_bw(struct sdram_cap_info *cap_info)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_cs(struct sdram_cap_info *cap_info)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_col(struct sdram_cap_info *cap_info,
 | 
						|
		     u32 coltmp)
 | 
						|
{
 | 
						|
	void __iomem *test_addr;
 | 
						|
	u32 col;
 | 
						|
	u32 bw = cap_info->bw;
 | 
						|
 | 
						|
	for (col = coltmp; col >= 9; col -= 1) {
 | 
						|
		writel(0, CONFIG_SYS_SDRAM_BASE);
 | 
						|
		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 | 
						|
				(1ul << (col + bw - 1ul)));
 | 
						|
		writel(PATTERN, test_addr);
 | 
						|
		if ((readl(test_addr) == PATTERN) &&
 | 
						|
		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (col == 8) {
 | 
						|
		printascii("col error\n");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	cap_info->col = col;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_bank(struct sdram_cap_info *cap_info,
 | 
						|
		      u32 coltmp, u32 bktmp)
 | 
						|
{
 | 
						|
	void __iomem *test_addr;
 | 
						|
	u32 bk;
 | 
						|
	u32 bw = cap_info->bw;
 | 
						|
 | 
						|
	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 | 
						|
			(1ul << (coltmp + bktmp + bw - 1ul)));
 | 
						|
	writel(0, CONFIG_SYS_SDRAM_BASE);
 | 
						|
	writel(PATTERN, test_addr);
 | 
						|
	if ((readl(test_addr) == PATTERN) &&
 | 
						|
	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 | 
						|
		bk = 3;
 | 
						|
	else
 | 
						|
		bk = 2;
 | 
						|
 | 
						|
	cap_info->bk = bk;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* detect bg for ddr4 */
 | 
						|
int sdram_detect_bg(struct sdram_cap_info *cap_info,
 | 
						|
		    u32 coltmp)
 | 
						|
{
 | 
						|
	void __iomem *test_addr;
 | 
						|
	u32 dbw;
 | 
						|
	u32 bw = cap_info->bw;
 | 
						|
 | 
						|
	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 | 
						|
			(1ul << (coltmp + bw + 1ul)));
 | 
						|
	writel(0, CONFIG_SYS_SDRAM_BASE);
 | 
						|
	writel(PATTERN, test_addr);
 | 
						|
	if ((readl(test_addr) == PATTERN) &&
 | 
						|
	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 | 
						|
		dbw = 0;
 | 
						|
	else
 | 
						|
		dbw = 1;
 | 
						|
 | 
						|
	cap_info->dbw = dbw;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
 | 
						|
int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
 | 
						|
{
 | 
						|
	u32 row, col, bk, bw, cs_cap, cs;
 | 
						|
	u32 die_bw_0 = 0, die_bw_1 = 0;
 | 
						|
 | 
						|
	if (dram_type == DDR3 || dram_type == LPDDR4) {
 | 
						|
		cap_info->dbw = 1;
 | 
						|
	} else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
 | 
						|
		row = cap_info->cs0_row;
 | 
						|
		col = cap_info->col;
 | 
						|
		bk = cap_info->bk;
 | 
						|
		cs = cap_info->rank;
 | 
						|
		bw = cap_info->bw;
 | 
						|
		cs_cap = (1 << (row + col + bk + bw - 20));
 | 
						|
		if (bw == 2) {
 | 
						|
			if (cs_cap <= 0x2000000) /* 256Mb */
 | 
						|
				die_bw_0 = (col < 9) ? 2 : 1;
 | 
						|
			else if (cs_cap <= 0x10000000) /* 2Gb */
 | 
						|
				die_bw_0 = (col < 10) ? 2 : 1;
 | 
						|
			else if (cs_cap <= 0x40000000) /* 8Gb */
 | 
						|
				die_bw_0 = (col < 11) ? 2 : 1;
 | 
						|
			else
 | 
						|
				die_bw_0 = (col < 12) ? 2 : 1;
 | 
						|
			if (cs > 1) {
 | 
						|
				row = cap_info->cs1_row;
 | 
						|
				cs_cap = (1 << (row + col + bk + bw - 20));
 | 
						|
				if (cs_cap <= 0x2000000) /* 256Mb */
 | 
						|
					die_bw_0 = (col < 9) ? 2 : 1;
 | 
						|
				else if (cs_cap <= 0x10000000) /* 2Gb */
 | 
						|
					die_bw_0 = (col < 10) ? 2 : 1;
 | 
						|
				else if (cs_cap <= 0x40000000) /* 8Gb */
 | 
						|
					die_bw_0 = (col < 11) ? 2 : 1;
 | 
						|
				else
 | 
						|
					die_bw_0 = (col < 12) ? 2 : 1;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			die_bw_1 = 1;
 | 
						|
			die_bw_0 = 1;
 | 
						|
		}
 | 
						|
		cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_row(struct sdram_cap_info *cap_info,
 | 
						|
		     u32 coltmp, u32 bktmp, u32 rowtmp)
 | 
						|
{
 | 
						|
	u32 row;
 | 
						|
	u32 bw = cap_info->bw;
 | 
						|
	void __iomem *test_addr;
 | 
						|
 | 
						|
	for (row = rowtmp; row > 12; row--) {
 | 
						|
		writel(0, CONFIG_SYS_SDRAM_BASE);
 | 
						|
		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 | 
						|
				(1ul << (row + bktmp + coltmp + bw - 1ul)));
 | 
						|
		writel(PATTERN, test_addr);
 | 
						|
		if ((readl(test_addr) == PATTERN) &&
 | 
						|
		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (row == 12) {
 | 
						|
		printascii("row error");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	cap_info->cs0_row = row;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
 | 
						|
			 u32 coltmp, u32 bktmp)
 | 
						|
{
 | 
						|
	u32 row_3_4;
 | 
						|
	u32 bw = cap_info->bw;
 | 
						|
	u32 row = cap_info->cs0_row;
 | 
						|
	void __iomem *test_addr, *test_addr1;
 | 
						|
 | 
						|
	test_addr = CONFIG_SYS_SDRAM_BASE;
 | 
						|
	test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 | 
						|
			(0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
 | 
						|
 | 
						|
	writel(0, test_addr);
 | 
						|
	writel(PATTERN, test_addr1);
 | 
						|
	if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
 | 
						|
		row_3_4 = 0;
 | 
						|
	else
 | 
						|
		row_3_4 = 1;
 | 
						|
 | 
						|
	cap_info->row_3_4 = row_3_4;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_high_row(struct sdram_cap_info *cap_info)
 | 
						|
{
 | 
						|
	cap_info->cs0_high16bit_row = cap_info->cs0_row;
 | 
						|
	cap_info->cs1_high16bit_row = cap_info->cs1_row;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
 | 
						|
{
 | 
						|
	void __iomem *test_addr;
 | 
						|
	u32 row = 0, bktmp, coltmp, bw;
 | 
						|
	ulong cs0_cap;
 | 
						|
	u32 byte_mask;
 | 
						|
 | 
						|
	if (cap_info->rank == 2) {
 | 
						|
		cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
 | 
						|
 | 
						|
		if (dram_type == DDR4) {
 | 
						|
			if (cap_info->dbw == 0)
 | 
						|
				bktmp = cap_info->bk + 2;
 | 
						|
			else
 | 
						|
				bktmp = cap_info->bk + 1;
 | 
						|
		} else {
 | 
						|
			bktmp = cap_info->bk;
 | 
						|
		}
 | 
						|
		bw = cap_info->bw;
 | 
						|
		coltmp = cap_info->col;
 | 
						|
 | 
						|
		/*
 | 
						|
		 * because px30 support axi split,min bandwidth
 | 
						|
		 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
 | 
						|
		 * so we check low 16bit data when detect cs1 row.
 | 
						|
		 * if cs0 is 16bit/8bit, we check low 8bit data.
 | 
						|
		 */
 | 
						|
		if (bw == 2)
 | 
						|
			byte_mask = 0xFFFF;
 | 
						|
		else
 | 
						|
			byte_mask = 0xFF;
 | 
						|
 | 
						|
		/* detect cs1 row */
 | 
						|
		for (row = cap_info->cs0_row; row > 12; row--) {
 | 
						|
			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 | 
						|
				    cs0_cap +
 | 
						|
				    (1ul << (row + bktmp + coltmp + bw - 1ul)));
 | 
						|
			writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
 | 
						|
			writel(PATTERN, test_addr);
 | 
						|
 | 
						|
			if (((readl(test_addr) & byte_mask) ==
 | 
						|
			     (PATTERN & byte_mask)) &&
 | 
						|
			    ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
 | 
						|
			      byte_mask) == 0)) {
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	cap_info->cs1_row = row;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |