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