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