xref: /openbmc/u-boot/arch/arm/mach-mvebu/dram.c (revision acf52fb26fe527e8ba2643017e3d747686a4c40e)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2d0787656SStefan Roese /*
3d0787656SStefan Roese  * (C) Copyright 2009
4d0787656SStefan Roese  * Marvell Semiconductor <www.marvell.com>
5d0787656SStefan Roese  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
6d0787656SStefan Roese  */
7d0787656SStefan Roese 
8d0787656SStefan Roese #include <config.h>
9d0787656SStefan Roese #include <common.h>
10d0787656SStefan Roese #include <asm/io.h>
11d0787656SStefan Roese #include <asm/arch/cpu.h>
12d0787656SStefan Roese #include <asm/arch/soc.h>
13d0787656SStefan Roese 
1481e33f4bSStefan Roese #if defined(CONFIG_ARCH_MVEBU)
1581e33f4bSStefan Roese /* Use common XOR definitions for A3x and AXP */
160ceb2daeSStefan Roese #include "../../../drivers/ddr/marvell/axp/xor.h"
170ceb2daeSStefan Roese #include "../../../drivers/ddr/marvell/axp/xor_regs.h"
188a83c65fSStefan Roese #endif
198a83c65fSStefan Roese 
20d0787656SStefan Roese DECLARE_GLOBAL_DATA_PTR;
21d0787656SStefan Roese 
22d0787656SStefan Roese struct sdram_bank {
23d0787656SStefan Roese 	u32	win_bar;
24d0787656SStefan Roese 	u32	win_sz;
25d0787656SStefan Roese };
26d0787656SStefan Roese 
27d0787656SStefan Roese struct sdram_addr_dec {
28d0787656SStefan Roese 	struct sdram_bank sdram_bank[4];
29d0787656SStefan Roese };
30d0787656SStefan Roese 
31d0787656SStefan Roese #define REG_CPUCS_WIN_ENABLE		(1 << 0)
32d0787656SStefan Roese #define REG_CPUCS_WIN_WR_PROTECT	(1 << 1)
33d0787656SStefan Roese #define REG_CPUCS_WIN_WIN0_CS(x)	(((x) & 0x3) << 2)
34d0787656SStefan Roese #define REG_CPUCS_WIN_SIZE(x)		(((x) & 0xff) << 24)
35d0787656SStefan Roese 
36*a8483505SStefan Roese #ifndef MVEBU_SDRAM_SIZE_MAX
37*a8483505SStefan Roese #define MVEBU_SDRAM_SIZE_MAX		0xc0000000
38*a8483505SStefan Roese #endif
39a8b57a90SStefan Roese 
400ceb2daeSStefan Roese #define SCRUB_MAGIC		0xbeefdead
410ceb2daeSStefan Roese 
420ceb2daeSStefan Roese #define SCRB_XOR_UNIT		0
430ceb2daeSStefan Roese #define SCRB_XOR_CHAN		1
440ceb2daeSStefan Roese #define SCRB_XOR_WIN		0
450ceb2daeSStefan Roese 
460ceb2daeSStefan Roese #define XEBARX_BASE_OFFS	16
470ceb2daeSStefan Roese 
48d0787656SStefan Roese /*
49d0787656SStefan Roese  * mvebu_sdram_bar - reads SDRAM Base Address Register
50d0787656SStefan Roese  */
mvebu_sdram_bar(enum memory_bank bank)51d0787656SStefan Roese u32 mvebu_sdram_bar(enum memory_bank bank)
52d0787656SStefan Roese {
53d0787656SStefan Roese 	struct sdram_addr_dec *base =
54d0787656SStefan Roese 		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
55d0787656SStefan Roese 	u32 result = 0;
56d0787656SStefan Roese 	u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
57d0787656SStefan Roese 
58d0787656SStefan Roese 	if ((!enable) || (bank > BANK3))
59d0787656SStefan Roese 		return 0;
60d0787656SStefan Roese 
61d0787656SStefan Roese 	result = readl(&base->sdram_bank[bank].win_bar);
62d0787656SStefan Roese 	return result;
63d0787656SStefan Roese }
64d0787656SStefan Roese 
65d0787656SStefan Roese /*
66d0787656SStefan Roese  * mvebu_sdram_bs_set - writes SDRAM Bank size
67d0787656SStefan Roese  */
mvebu_sdram_bs_set(enum memory_bank bank,u32 size)68d0787656SStefan Roese static void mvebu_sdram_bs_set(enum memory_bank bank, u32 size)
69d0787656SStefan Roese {
70d0787656SStefan Roese 	struct sdram_addr_dec *base =
71d0787656SStefan Roese 		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
72d0787656SStefan Roese 	/* Read current register value */
73d0787656SStefan Roese 	u32 reg = readl(&base->sdram_bank[bank].win_sz);
74d0787656SStefan Roese 
75d0787656SStefan Roese 	/* Clear window size */
76d0787656SStefan Roese 	reg &= ~REG_CPUCS_WIN_SIZE(0xFF);
77d0787656SStefan Roese 
78d0787656SStefan Roese 	/* Set new window size */
79d0787656SStefan Roese 	reg |= REG_CPUCS_WIN_SIZE((size - 1) >> 24);
80d0787656SStefan Roese 
81d0787656SStefan Roese 	writel(reg, &base->sdram_bank[bank].win_sz);
82d0787656SStefan Roese }
83d0787656SStefan Roese 
84d0787656SStefan Roese /*
85d0787656SStefan Roese  * mvebu_sdram_bs - reads SDRAM Bank size
86d0787656SStefan Roese  */
mvebu_sdram_bs(enum memory_bank bank)87d0787656SStefan Roese u32 mvebu_sdram_bs(enum memory_bank bank)
88d0787656SStefan Roese {
89d0787656SStefan Roese 	struct sdram_addr_dec *base =
90d0787656SStefan Roese 		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
91d0787656SStefan Roese 	u32 result = 0;
92d0787656SStefan Roese 	u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
93d0787656SStefan Roese 
94d0787656SStefan Roese 	if ((!enable) || (bank > BANK3))
95d0787656SStefan Roese 		return 0;
96d0787656SStefan Roese 	result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz);
97d0787656SStefan Roese 	result += 0x01000000;
98d0787656SStefan Roese 	return result;
99d0787656SStefan Roese }
100d0787656SStefan Roese 
mvebu_sdram_size_adjust(enum memory_bank bank)101d0787656SStefan Roese void mvebu_sdram_size_adjust(enum memory_bank bank)
102d0787656SStefan Roese {
103d0787656SStefan Roese 	u32 size;
104d0787656SStefan Roese 
105d0787656SStefan Roese 	/* probe currently equipped RAM size */
106d0787656SStefan Roese 	size = get_ram_size((void *)mvebu_sdram_bar(bank),
107d0787656SStefan Roese 			    mvebu_sdram_bs(bank));
108d0787656SStefan Roese 
109d0787656SStefan Roese 	/* adjust SDRAM window size accordingly */
110d0787656SStefan Roese 	mvebu_sdram_bs_set(bank, size);
111d0787656SStefan Roese }
112d0787656SStefan Roese 
11381e33f4bSStefan Roese #if defined(CONFIG_ARCH_MVEBU)
1140ceb2daeSStefan Roese static u32 xor_ctrl_save;
1150ceb2daeSStefan Roese static u32 xor_base_save;
1160ceb2daeSStefan Roese static u32 xor_mask_save;
1170ceb2daeSStefan Roese 
mv_xor_init2(u32 cs)1180ceb2daeSStefan Roese static void mv_xor_init2(u32 cs)
1190ceb2daeSStefan Roese {
1200ceb2daeSStefan Roese 	u32 reg, base, size, base2;
1210ceb2daeSStefan Roese 	u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 };
1220ceb2daeSStefan Roese 
1230ceb2daeSStefan Roese 	xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT,
1240ceb2daeSStefan Roese 						     SCRB_XOR_CHAN));
1250ceb2daeSStefan Roese 	xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT,
1260ceb2daeSStefan Roese 						   SCRB_XOR_WIN));
1270ceb2daeSStefan Roese 	xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT,
1280ceb2daeSStefan Roese 						   SCRB_XOR_WIN));
1290ceb2daeSStefan Roese 
1300ceb2daeSStefan Roese 	/* Enable Window x for each CS */
1310ceb2daeSStefan Roese 	reg = 0x1;
1320ceb2daeSStefan Roese 	reg |= (0x3 << 16);
1330ceb2daeSStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg);
1340ceb2daeSStefan Roese 
1350ceb2daeSStefan Roese 	base = 0;
1360ceb2daeSStefan Roese 	size = mvebu_sdram_bs(cs) - 1;
1370ceb2daeSStefan Roese 	if (size) {
1380ceb2daeSStefan Roese 		base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) |
1390ceb2daeSStefan Roese 			bank_attr[cs];
1400ceb2daeSStefan Roese 		reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
1410ceb2daeSStefan Roese 			  base2);
1420ceb2daeSStefan Roese 
1430ceb2daeSStefan Roese 		base += size + 1;
1440ceb2daeSStefan Roese 		size = (size / (64 << 10)) << 16;
1450ceb2daeSStefan Roese 		/* Window x - size - 256 MB */
1460ceb2daeSStefan Roese 		reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size);
1470ceb2daeSStefan Roese 	}
1480ceb2daeSStefan Roese 
1490ceb2daeSStefan Roese 	mv_xor_hal_init(0);
1500ceb2daeSStefan Roese 
1510ceb2daeSStefan Roese 	return;
1520ceb2daeSStefan Roese }
1530ceb2daeSStefan Roese 
mv_xor_finish2(void)1540ceb2daeSStefan Roese static void mv_xor_finish2(void)
1550ceb2daeSStefan Roese {
1560ceb2daeSStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN),
1570ceb2daeSStefan Roese 		  xor_ctrl_save);
1580ceb2daeSStefan Roese 	reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
1590ceb2daeSStefan Roese 		  xor_base_save);
1600ceb2daeSStefan Roese 	reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
1610ceb2daeSStefan Roese 		  xor_mask_save);
1620ceb2daeSStefan Roese }
1630ceb2daeSStefan Roese 
dram_ecc_scrubbing(void)1640ceb2daeSStefan Roese static void dram_ecc_scrubbing(void)
1650ceb2daeSStefan Roese {
1660ceb2daeSStefan Roese 	int cs;
1670ceb2daeSStefan Roese 	u32 size, temp;
1680ceb2daeSStefan Roese 	u32 total_mem = 0;
1690ceb2daeSStefan Roese 	u64 total;
1700ceb2daeSStefan Roese 	u32 start_addr;
1710ceb2daeSStefan Roese 
1720ceb2daeSStefan Roese 	/*
1730ceb2daeSStefan Roese 	 * The DDR training code from the bin_hdr / SPL already
1740ceb2daeSStefan Roese 	 * scrubbed the DDR till 0x1000000. And the main U-Boot
1750ceb2daeSStefan Roese 	 * is loaded to an address < 0x1000000. So we need to
1760ceb2daeSStefan Roese 	 * skip this range to not re-scrub this area again.
1770ceb2daeSStefan Roese 	 */
1780ceb2daeSStefan Roese 	temp = reg_read(REG_SDRAM_CONFIG_ADDR);
1790ceb2daeSStefan Roese 	temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
1800ceb2daeSStefan Roese 	reg_write(REG_SDRAM_CONFIG_ADDR, temp);
1810ceb2daeSStefan Roese 
1820ceb2daeSStefan Roese 	for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) {
183c3ab2744SChris Packham 		size = mvebu_sdram_bs(cs);
1840ceb2daeSStefan Roese 		if (size == 0)
1850ceb2daeSStefan Roese 			continue;
1860ceb2daeSStefan Roese 
187c3ab2744SChris Packham 		total = (u64)size;
1880ceb2daeSStefan Roese 		total_mem += (u32)(total / (1 << 30));
1890ceb2daeSStefan Roese 		start_addr = 0;
1900ceb2daeSStefan Roese 		mv_xor_init2(cs);
1910ceb2daeSStefan Roese 
1920ceb2daeSStefan Roese 		/* Skip first 16 MiB */
1930ceb2daeSStefan Roese 		if (0 == cs) {
1940ceb2daeSStefan Roese 			start_addr = 0x1000000;
1950ceb2daeSStefan Roese 			size -= start_addr;
1960ceb2daeSStefan Roese 		}
1970ceb2daeSStefan Roese 
198c3ab2744SChris Packham 		mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size - 1,
1990ceb2daeSStefan Roese 				SCRUB_MAGIC, SCRUB_MAGIC);
2000ceb2daeSStefan Roese 
2010ceb2daeSStefan Roese 		/* Wait for previous transfer completion */
2020ceb2daeSStefan Roese 		while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE)
2030ceb2daeSStefan Roese 			;
2040ceb2daeSStefan Roese 
2050ceb2daeSStefan Roese 		mv_xor_finish2();
2060ceb2daeSStefan Roese 	}
2070ceb2daeSStefan Roese 
2080ceb2daeSStefan Roese 	temp = reg_read(REG_SDRAM_CONFIG_ADDR);
2090ceb2daeSStefan Roese 	temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
2100ceb2daeSStefan Roese 	reg_write(REG_SDRAM_CONFIG_ADDR, temp);
2110ceb2daeSStefan Roese }
2120ceb2daeSStefan Roese 
ecc_enabled(void)2130ceb2daeSStefan Roese static int ecc_enabled(void)
2140ceb2daeSStefan Roese {
2150ceb2daeSStefan Roese 	if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS))
2160ceb2daeSStefan Roese 		return 1;
2170ceb2daeSStefan Roese 
2180ceb2daeSStefan Roese 	return 0;
2190ceb2daeSStefan Roese }
220631407c5SJoshua Scott 
221631407c5SJoshua Scott /* Return the width of the DRAM bus, or 0 for unknown. */
bus_width(void)222631407c5SJoshua Scott static int bus_width(void)
223631407c5SJoshua Scott {
224631407c5SJoshua Scott 	int full_width = 0;
225631407c5SJoshua Scott 
226631407c5SJoshua Scott 	if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_WIDTH_OFFS))
227631407c5SJoshua Scott 		full_width = 1;
228631407c5SJoshua Scott 
229631407c5SJoshua Scott 	switch (mvebu_soc_family()) {
230631407c5SJoshua Scott 	case MVEBU_SOC_AXP:
231631407c5SJoshua Scott 	    return full_width ? 64 : 32;
232631407c5SJoshua Scott 	    break;
233631407c5SJoshua Scott 	case MVEBU_SOC_A375:
234631407c5SJoshua Scott 	case MVEBU_SOC_A38X:
235631407c5SJoshua Scott 	case MVEBU_SOC_MSYS:
236631407c5SJoshua Scott 	    return full_width ? 32 : 16;
237631407c5SJoshua Scott 	default:
238631407c5SJoshua Scott 	    return 0;
239631407c5SJoshua Scott 	}
240631407c5SJoshua Scott }
241631407c5SJoshua Scott 
cycle_mode(void)242631407c5SJoshua Scott static int cycle_mode(void)
243631407c5SJoshua Scott {
244631407c5SJoshua Scott 	int val = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
245631407c5SJoshua Scott 
246631407c5SJoshua Scott 	return (val >> REG_DUNIT_CTRL_LOW_2T_OFFS) & REG_DUNIT_CTRL_LOW_2T_MASK;
247631407c5SJoshua Scott }
248631407c5SJoshua Scott 
2490ceb2daeSStefan Roese #else
dram_ecc_scrubbing(void)2500ceb2daeSStefan Roese static void dram_ecc_scrubbing(void)
2510ceb2daeSStefan Roese {
2520ceb2daeSStefan Roese }
2530ceb2daeSStefan Roese 
ecc_enabled(void)2540ceb2daeSStefan Roese static int ecc_enabled(void)
2550ceb2daeSStefan Roese {
2560ceb2daeSStefan Roese 	return 0;
2570ceb2daeSStefan Roese }
2580ceb2daeSStefan Roese #endif
2590ceb2daeSStefan Roese 
dram_init(void)260d0787656SStefan Roese int dram_init(void)
261d0787656SStefan Roese {
262a8b57a90SStefan Roese 	u64 size = 0;
263d0787656SStefan Roese 	int i;
264d0787656SStefan Roese 
265d0787656SStefan Roese 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
266d0787656SStefan Roese 		/*
267d0787656SStefan Roese 		 * It is assumed that all memory banks are consecutive
268d0787656SStefan Roese 		 * and without gaps.
269d0787656SStefan Roese 		 * If the gap is found, ram_size will be reported for
270d0787656SStefan Roese 		 * consecutive memory only
271d0787656SStefan Roese 		 */
272a8b57a90SStefan Roese 		if (mvebu_sdram_bar(i) != size)
273d0787656SStefan Roese 			break;
274d0787656SStefan Roese 
275d0787656SStefan Roese 		/*
276d0787656SStefan Roese 		 * Don't report more than 3GiB of SDRAM, otherwise there is no
277d0787656SStefan Roese 		 * address space left for the internal registers etc.
278d0787656SStefan Roese 		 */
279a8b57a90SStefan Roese 		size += mvebu_sdram_bs(i);
280*a8483505SStefan Roese 		if (size > MVEBU_SDRAM_SIZE_MAX)
281*a8483505SStefan Roese 			size = MVEBU_SDRAM_SIZE_MAX;
282d0787656SStefan Roese 	}
283d0787656SStefan Roese 
284d0787656SStefan Roese 	for (; i < CONFIG_NR_DRAM_BANKS; i++) {
285d0787656SStefan Roese 		/* If above loop terminated prematurely, we need to set
286d0787656SStefan Roese 		 * remaining banks' start address & size as 0. Otherwise other
287d0787656SStefan Roese 		 * u-boot functions and Linux kernel gets wrong values which
288d0787656SStefan Roese 		 * could result in crash */
289d0787656SStefan Roese 		gd->bd->bi_dram[i].start = 0;
290d0787656SStefan Roese 		gd->bd->bi_dram[i].size = 0;
291d0787656SStefan Roese 	}
292d0787656SStefan Roese 
2930ceb2daeSStefan Roese 
2940ceb2daeSStefan Roese 	if (ecc_enabled())
2950ceb2daeSStefan Roese 		dram_ecc_scrubbing();
2960ceb2daeSStefan Roese 
297a8b57a90SStefan Roese 	gd->ram_size = size;
298a8b57a90SStefan Roese 
299d0787656SStefan Roese 	return 0;
300d0787656SStefan Roese }
301d0787656SStefan Roese 
302d0787656SStefan Roese /*
303d0787656SStefan Roese  * If this function is not defined here,
304d0787656SStefan Roese  * board.c alters dram bank zero configuration defined above.
305d0787656SStefan Roese  */
dram_init_banksize(void)30676b00acaSSimon Glass int dram_init_banksize(void)
307d0787656SStefan Roese {
308a8b57a90SStefan Roese 	u64 size = 0;
309a8b57a90SStefan Roese 	int i;
310a8b57a90SStefan Roese 
311a8b57a90SStefan Roese 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
312a8b57a90SStefan Roese 		gd->bd->bi_dram[i].start = mvebu_sdram_bar(i);
313a8b57a90SStefan Roese 		gd->bd->bi_dram[i].size = mvebu_sdram_bs(i);
314a8b57a90SStefan Roese 
315a8b57a90SStefan Roese 		/* Clip the banksize to 1GiB if it exceeds the max size */
316a8b57a90SStefan Roese 		size += gd->bd->bi_dram[i].size;
317*a8483505SStefan Roese 		if (size > MVEBU_SDRAM_SIZE_MAX)
318a8b57a90SStefan Roese 			mvebu_sdram_bs_set(i, 0x40000000);
319a8b57a90SStefan Roese 	}
32076b00acaSSimon Glass 
32176b00acaSSimon Glass 	return 0;
322d0787656SStefan Roese }
3238a83c65fSStefan Roese 
32481e33f4bSStefan Roese #if defined(CONFIG_ARCH_MVEBU)
board_add_ram_info(int use_default)3258a83c65fSStefan Roese void board_add_ram_info(int use_default)
3268a83c65fSStefan Roese {
327d718bf2cSStefan Roese 	struct sar_freq_modes sar_freq;
328631407c5SJoshua Scott 	int mode;
329631407c5SJoshua Scott 	int width;
330d718bf2cSStefan Roese 
331d718bf2cSStefan Roese 	get_sar_freq(&sar_freq);
332d718bf2cSStefan Roese 	printf(" (%d MHz, ", sar_freq.d_clk);
333d718bf2cSStefan Roese 
334631407c5SJoshua Scott 	width = bus_width();
335631407c5SJoshua Scott 	if (width)
336631407c5SJoshua Scott 		printf("%d-bit, ", width);
337631407c5SJoshua Scott 
338631407c5SJoshua Scott 	mode = cycle_mode();
339631407c5SJoshua Scott 	/* Mode 0 = Single cycle
340631407c5SJoshua Scott 	 * Mode 1 = Two cycles   (2T)
341631407c5SJoshua Scott 	 * Mode 2 = Three cycles (3T)
342631407c5SJoshua Scott 	 */
343631407c5SJoshua Scott 	if (mode == 1)
344631407c5SJoshua Scott 		printf("2T, ");
345631407c5SJoshua Scott 	if (mode == 2)
346631407c5SJoshua Scott 		printf("3T, ");
347631407c5SJoshua Scott 
3480ceb2daeSStefan Roese 	if (ecc_enabled())
349d718bf2cSStefan Roese 		printf("ECC");
3508a83c65fSStefan Roese 	else
351d718bf2cSStefan Roese 		printf("ECC not");
3528a83c65fSStefan Roese 	printf(" enabled)");
3538a83c65fSStefan Roese }
354d718bf2cSStefan Roese #endif
355