xref: /rk3399_rockchip-uboot/arch/arm/mach-mvebu/dram.c (revision 76b00aca4f1c13bc8f91a539e612abc70d0c692f)
1d0787656SStefan Roese /*
2d0787656SStefan Roese  * (C) Copyright 2009
3d0787656SStefan Roese  * Marvell Semiconductor <www.marvell.com>
4d0787656SStefan Roese  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
5d0787656SStefan Roese  *
6d0787656SStefan Roese  * SPDX-License-Identifier:	GPL-2.0+
7d0787656SStefan Roese  */
8d0787656SStefan Roese 
9d0787656SStefan Roese #include <config.h>
10d0787656SStefan Roese #include <common.h>
11d0787656SStefan Roese #include <asm/io.h>
12d0787656SStefan Roese #include <asm/arch/cpu.h>
13d0787656SStefan Roese #include <asm/arch/soc.h>
14d0787656SStefan Roese 
1581e33f4bSStefan Roese #if defined(CONFIG_ARCH_MVEBU)
1681e33f4bSStefan Roese /* Use common XOR definitions for A3x and AXP */
170ceb2daeSStefan Roese #include "../../../drivers/ddr/marvell/axp/xor.h"
180ceb2daeSStefan Roese #include "../../../drivers/ddr/marvell/axp/xor_regs.h"
198a83c65fSStefan Roese #endif
208a83c65fSStefan Roese 
21d0787656SStefan Roese DECLARE_GLOBAL_DATA_PTR;
22d0787656SStefan Roese 
23d0787656SStefan Roese struct sdram_bank {
24d0787656SStefan Roese 	u32	win_bar;
25d0787656SStefan Roese 	u32	win_sz;
26d0787656SStefan Roese };
27d0787656SStefan Roese 
28d0787656SStefan Roese struct sdram_addr_dec {
29d0787656SStefan Roese 	struct sdram_bank sdram_bank[4];
30d0787656SStefan Roese };
31d0787656SStefan Roese 
32d0787656SStefan Roese #define REG_CPUCS_WIN_ENABLE		(1 << 0)
33d0787656SStefan Roese #define REG_CPUCS_WIN_WR_PROTECT	(1 << 1)
34d0787656SStefan Roese #define REG_CPUCS_WIN_WIN0_CS(x)	(((x) & 0x3) << 2)
35d0787656SStefan Roese #define REG_CPUCS_WIN_SIZE(x)		(((x) & 0xff) << 24)
36d0787656SStefan Roese 
37a8b57a90SStefan Roese #define SDRAM_SIZE_MAX			0xc0000000
38a8b57a90SStefan Roese 
390ceb2daeSStefan Roese #define SCRUB_MAGIC		0xbeefdead
400ceb2daeSStefan Roese 
410ceb2daeSStefan Roese #define SCRB_XOR_UNIT		0
420ceb2daeSStefan Roese #define SCRB_XOR_CHAN		1
430ceb2daeSStefan Roese #define SCRB_XOR_WIN		0
440ceb2daeSStefan Roese 
450ceb2daeSStefan Roese #define XEBARX_BASE_OFFS	16
460ceb2daeSStefan Roese 
47d0787656SStefan Roese /*
48d0787656SStefan Roese  * mvebu_sdram_bar - reads SDRAM Base Address Register
49d0787656SStefan Roese  */
mvebu_sdram_bar(enum memory_bank bank)50d0787656SStefan Roese u32 mvebu_sdram_bar(enum memory_bank bank)
51d0787656SStefan Roese {
52d0787656SStefan Roese 	struct sdram_addr_dec *base =
53d0787656SStefan Roese 		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
54d0787656SStefan Roese 	u32 result = 0;
55d0787656SStefan Roese 	u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
56d0787656SStefan Roese 
57d0787656SStefan Roese 	if ((!enable) || (bank > BANK3))
58d0787656SStefan Roese 		return 0;
59d0787656SStefan Roese 
60d0787656SStefan Roese 	result = readl(&base->sdram_bank[bank].win_bar);
61d0787656SStefan Roese 	return result;
62d0787656SStefan Roese }
63d0787656SStefan Roese 
64d0787656SStefan Roese /*
65d0787656SStefan Roese  * mvebu_sdram_bs_set - writes SDRAM Bank size
66d0787656SStefan Roese  */
mvebu_sdram_bs_set(enum memory_bank bank,u32 size)67d0787656SStefan Roese static void mvebu_sdram_bs_set(enum memory_bank bank, u32 size)
68d0787656SStefan Roese {
69d0787656SStefan Roese 	struct sdram_addr_dec *base =
70d0787656SStefan Roese 		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
71d0787656SStefan Roese 	/* Read current register value */
72d0787656SStefan Roese 	u32 reg = readl(&base->sdram_bank[bank].win_sz);
73d0787656SStefan Roese 
74d0787656SStefan Roese 	/* Clear window size */
75d0787656SStefan Roese 	reg &= ~REG_CPUCS_WIN_SIZE(0xFF);
76d0787656SStefan Roese 
77d0787656SStefan Roese 	/* Set new window size */
78d0787656SStefan Roese 	reg |= REG_CPUCS_WIN_SIZE((size - 1) >> 24);
79d0787656SStefan Roese 
80d0787656SStefan Roese 	writel(reg, &base->sdram_bank[bank].win_sz);
81d0787656SStefan Roese }
82d0787656SStefan Roese 
83d0787656SStefan Roese /*
84d0787656SStefan Roese  * mvebu_sdram_bs - reads SDRAM Bank size
85d0787656SStefan Roese  */
mvebu_sdram_bs(enum memory_bank bank)86d0787656SStefan Roese u32 mvebu_sdram_bs(enum memory_bank bank)
87d0787656SStefan Roese {
88d0787656SStefan Roese 	struct sdram_addr_dec *base =
89d0787656SStefan Roese 		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
90d0787656SStefan Roese 	u32 result = 0;
91d0787656SStefan Roese 	u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
92d0787656SStefan Roese 
93d0787656SStefan Roese 	if ((!enable) || (bank > BANK3))
94d0787656SStefan Roese 		return 0;
95d0787656SStefan Roese 	result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz);
96d0787656SStefan Roese 	result += 0x01000000;
97d0787656SStefan Roese 	return result;
98d0787656SStefan Roese }
99d0787656SStefan Roese 
mvebu_sdram_size_adjust(enum memory_bank bank)100d0787656SStefan Roese void mvebu_sdram_size_adjust(enum memory_bank bank)
101d0787656SStefan Roese {
102d0787656SStefan Roese 	u32 size;
103d0787656SStefan Roese 
104d0787656SStefan Roese 	/* probe currently equipped RAM size */
105d0787656SStefan Roese 	size = get_ram_size((void *)mvebu_sdram_bar(bank),
106d0787656SStefan Roese 			    mvebu_sdram_bs(bank));
107d0787656SStefan Roese 
108d0787656SStefan Roese 	/* adjust SDRAM window size accordingly */
109d0787656SStefan Roese 	mvebu_sdram_bs_set(bank, size);
110d0787656SStefan Roese }
111d0787656SStefan Roese 
11281e33f4bSStefan Roese #if defined(CONFIG_ARCH_MVEBU)
1130ceb2daeSStefan Roese static u32 xor_ctrl_save;
1140ceb2daeSStefan Roese static u32 xor_base_save;
1150ceb2daeSStefan Roese static u32 xor_mask_save;
1160ceb2daeSStefan Roese 
mv_xor_init2(u32 cs)1170ceb2daeSStefan Roese static void mv_xor_init2(u32 cs)
1180ceb2daeSStefan Roese {
1190ceb2daeSStefan Roese 	u32 reg, base, size, base2;
1200ceb2daeSStefan Roese 	u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 };
1210ceb2daeSStefan Roese 
1220ceb2daeSStefan Roese 	xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT,
1230ceb2daeSStefan Roese 						     SCRB_XOR_CHAN));
1240ceb2daeSStefan Roese 	xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT,
1250ceb2daeSStefan Roese 						   SCRB_XOR_WIN));
1260ceb2daeSStefan Roese 	xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT,
1270ceb2daeSStefan Roese 						   SCRB_XOR_WIN));
1280ceb2daeSStefan Roese 
1290ceb2daeSStefan Roese 	/* Enable Window x for each CS */
1300ceb2daeSStefan Roese 	reg = 0x1;
1310ceb2daeSStefan Roese 	reg |= (0x3 << 16);
1320ceb2daeSStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg);
1330ceb2daeSStefan Roese 
1340ceb2daeSStefan Roese 	base = 0;
1350ceb2daeSStefan Roese 	size = mvebu_sdram_bs(cs) - 1;
1360ceb2daeSStefan Roese 	if (size) {
1370ceb2daeSStefan Roese 		base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) |
1380ceb2daeSStefan Roese 			bank_attr[cs];
1390ceb2daeSStefan Roese 		reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
1400ceb2daeSStefan Roese 			  base2);
1410ceb2daeSStefan Roese 
1420ceb2daeSStefan Roese 		base += size + 1;
1430ceb2daeSStefan Roese 		size = (size / (64 << 10)) << 16;
1440ceb2daeSStefan Roese 		/* Window x - size - 256 MB */
1450ceb2daeSStefan Roese 		reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size);
1460ceb2daeSStefan Roese 	}
1470ceb2daeSStefan Roese 
1480ceb2daeSStefan Roese 	mv_xor_hal_init(0);
1490ceb2daeSStefan Roese 
1500ceb2daeSStefan Roese 	return;
1510ceb2daeSStefan Roese }
1520ceb2daeSStefan Roese 
mv_xor_finish2(void)1530ceb2daeSStefan Roese static void mv_xor_finish2(void)
1540ceb2daeSStefan Roese {
1550ceb2daeSStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN),
1560ceb2daeSStefan Roese 		  xor_ctrl_save);
1570ceb2daeSStefan Roese 	reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
1580ceb2daeSStefan Roese 		  xor_base_save);
1590ceb2daeSStefan Roese 	reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
1600ceb2daeSStefan Roese 		  xor_mask_save);
1610ceb2daeSStefan Roese }
1620ceb2daeSStefan Roese 
dram_ecc_scrubbing(void)1630ceb2daeSStefan Roese static void dram_ecc_scrubbing(void)
1640ceb2daeSStefan Roese {
1650ceb2daeSStefan Roese 	int cs;
1660ceb2daeSStefan Roese 	u32 size, temp;
1670ceb2daeSStefan Roese 	u32 total_mem = 0;
1680ceb2daeSStefan Roese 	u64 total;
1690ceb2daeSStefan Roese 	u32 start_addr;
1700ceb2daeSStefan Roese 
1710ceb2daeSStefan Roese 	/*
1720ceb2daeSStefan Roese 	 * The DDR training code from the bin_hdr / SPL already
1730ceb2daeSStefan Roese 	 * scrubbed the DDR till 0x1000000. And the main U-Boot
1740ceb2daeSStefan Roese 	 * is loaded to an address < 0x1000000. So we need to
1750ceb2daeSStefan Roese 	 * skip this range to not re-scrub this area again.
1760ceb2daeSStefan Roese 	 */
1770ceb2daeSStefan Roese 	temp = reg_read(REG_SDRAM_CONFIG_ADDR);
1780ceb2daeSStefan Roese 	temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
1790ceb2daeSStefan Roese 	reg_write(REG_SDRAM_CONFIG_ADDR, temp);
1800ceb2daeSStefan Roese 
1810ceb2daeSStefan Roese 	for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) {
1820ceb2daeSStefan Roese 		size = mvebu_sdram_bs(cs) - 1;
1830ceb2daeSStefan Roese 		if (size == 0)
1840ceb2daeSStefan Roese 			continue;
1850ceb2daeSStefan Roese 
1860ceb2daeSStefan Roese 		total = (u64)size + 1;
1870ceb2daeSStefan Roese 		total_mem += (u32)(total / (1 << 30));
1880ceb2daeSStefan Roese 		start_addr = 0;
1890ceb2daeSStefan Roese 		mv_xor_init2(cs);
1900ceb2daeSStefan Roese 
1910ceb2daeSStefan Roese 		/* Skip first 16 MiB */
1920ceb2daeSStefan Roese 		if (0 == cs) {
1930ceb2daeSStefan Roese 			start_addr = 0x1000000;
1940ceb2daeSStefan Roese 			size -= start_addr;
1950ceb2daeSStefan Roese 		}
1960ceb2daeSStefan Roese 
1970ceb2daeSStefan Roese 		mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size,
1980ceb2daeSStefan Roese 				SCRUB_MAGIC, SCRUB_MAGIC);
1990ceb2daeSStefan Roese 
2000ceb2daeSStefan Roese 		/* Wait for previous transfer completion */
2010ceb2daeSStefan Roese 		while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE)
2020ceb2daeSStefan Roese 			;
2030ceb2daeSStefan Roese 
2040ceb2daeSStefan Roese 		mv_xor_finish2();
2050ceb2daeSStefan Roese 	}
2060ceb2daeSStefan Roese 
2070ceb2daeSStefan Roese 	temp = reg_read(REG_SDRAM_CONFIG_ADDR);
2080ceb2daeSStefan Roese 	temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
2090ceb2daeSStefan Roese 	reg_write(REG_SDRAM_CONFIG_ADDR, temp);
2100ceb2daeSStefan Roese }
2110ceb2daeSStefan Roese 
ecc_enabled(void)2120ceb2daeSStefan Roese static int ecc_enabled(void)
2130ceb2daeSStefan Roese {
2140ceb2daeSStefan Roese 	if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS))
2150ceb2daeSStefan Roese 		return 1;
2160ceb2daeSStefan Roese 
2170ceb2daeSStefan Roese 	return 0;
2180ceb2daeSStefan Roese }
2190ceb2daeSStefan Roese #else
dram_ecc_scrubbing(void)2200ceb2daeSStefan Roese static void dram_ecc_scrubbing(void)
2210ceb2daeSStefan Roese {
2220ceb2daeSStefan Roese }
2230ceb2daeSStefan Roese 
ecc_enabled(void)2240ceb2daeSStefan Roese static int ecc_enabled(void)
2250ceb2daeSStefan Roese {
2260ceb2daeSStefan Roese 	return 0;
2270ceb2daeSStefan Roese }
2280ceb2daeSStefan Roese #endif
2290ceb2daeSStefan Roese 
dram_init(void)230d0787656SStefan Roese int dram_init(void)
231d0787656SStefan Roese {
232a8b57a90SStefan Roese 	u64 size = 0;
233d0787656SStefan Roese 	int i;
234d0787656SStefan Roese 
235d0787656SStefan Roese 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
236d0787656SStefan Roese 		/*
237d0787656SStefan Roese 		 * It is assumed that all memory banks are consecutive
238d0787656SStefan Roese 		 * and without gaps.
239d0787656SStefan Roese 		 * If the gap is found, ram_size will be reported for
240d0787656SStefan Roese 		 * consecutive memory only
241d0787656SStefan Roese 		 */
242a8b57a90SStefan Roese 		if (mvebu_sdram_bar(i) != size)
243d0787656SStefan Roese 			break;
244d0787656SStefan Roese 
245d0787656SStefan Roese 		/*
246d0787656SStefan Roese 		 * Don't report more than 3GiB of SDRAM, otherwise there is no
247d0787656SStefan Roese 		 * address space left for the internal registers etc.
248d0787656SStefan Roese 		 */
249a8b57a90SStefan Roese 		size += mvebu_sdram_bs(i);
250a8b57a90SStefan Roese 		if (size > SDRAM_SIZE_MAX)
251a8b57a90SStefan Roese 			size = SDRAM_SIZE_MAX;
252d0787656SStefan Roese 	}
253d0787656SStefan Roese 
254d0787656SStefan Roese 	for (; i < CONFIG_NR_DRAM_BANKS; i++) {
255d0787656SStefan Roese 		/* If above loop terminated prematurely, we need to set
256d0787656SStefan Roese 		 * remaining banks' start address & size as 0. Otherwise other
257d0787656SStefan Roese 		 * u-boot functions and Linux kernel gets wrong values which
258d0787656SStefan Roese 		 * could result in crash */
259d0787656SStefan Roese 		gd->bd->bi_dram[i].start = 0;
260d0787656SStefan Roese 		gd->bd->bi_dram[i].size = 0;
261d0787656SStefan Roese 	}
262d0787656SStefan Roese 
2630ceb2daeSStefan Roese 
2640ceb2daeSStefan Roese 	if (ecc_enabled())
2650ceb2daeSStefan Roese 		dram_ecc_scrubbing();
2660ceb2daeSStefan Roese 
267a8b57a90SStefan Roese 	gd->ram_size = size;
268a8b57a90SStefan Roese 
269d0787656SStefan Roese 	return 0;
270d0787656SStefan Roese }
271d0787656SStefan Roese 
272d0787656SStefan Roese /*
273d0787656SStefan Roese  * If this function is not defined here,
274d0787656SStefan Roese  * board.c alters dram bank zero configuration defined above.
275d0787656SStefan Roese  */
dram_init_banksize(void)276*76b00acaSSimon Glass int dram_init_banksize(void)
277d0787656SStefan Roese {
278a8b57a90SStefan Roese 	u64 size = 0;
279a8b57a90SStefan Roese 	int i;
280a8b57a90SStefan Roese 
281a8b57a90SStefan Roese 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
282a8b57a90SStefan Roese 		gd->bd->bi_dram[i].start = mvebu_sdram_bar(i);
283a8b57a90SStefan Roese 		gd->bd->bi_dram[i].size = mvebu_sdram_bs(i);
284a8b57a90SStefan Roese 
285a8b57a90SStefan Roese 		/* Clip the banksize to 1GiB if it exceeds the max size */
286a8b57a90SStefan Roese 		size += gd->bd->bi_dram[i].size;
287a8b57a90SStefan Roese 		if (size > SDRAM_SIZE_MAX)
288a8b57a90SStefan Roese 			mvebu_sdram_bs_set(i, 0x40000000);
289a8b57a90SStefan Roese 	}
290*76b00acaSSimon Glass 
291*76b00acaSSimon Glass 	return 0;
292d0787656SStefan Roese }
2938a83c65fSStefan Roese 
29481e33f4bSStefan Roese #if defined(CONFIG_ARCH_MVEBU)
board_add_ram_info(int use_default)2958a83c65fSStefan Roese void board_add_ram_info(int use_default)
2968a83c65fSStefan Roese {
297d718bf2cSStefan Roese 	struct sar_freq_modes sar_freq;
298d718bf2cSStefan Roese 
299d718bf2cSStefan Roese 	get_sar_freq(&sar_freq);
300d718bf2cSStefan Roese 	printf(" (%d MHz, ", sar_freq.d_clk);
301d718bf2cSStefan Roese 
3020ceb2daeSStefan Roese 	if (ecc_enabled())
303d718bf2cSStefan Roese 		printf("ECC");
3048a83c65fSStefan Roese 	else
305d718bf2cSStefan Roese 		printf("ECC not");
3068a83c65fSStefan Roese 	printf(" enabled)");
3078a83c65fSStefan Roese }
308d718bf2cSStefan Roese #endif
309