From 0ceb2dae788848ad6df9fb1cc0e20e632f380887 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 6 Aug 2015 14:43:13 +0200 Subject: arm: mvebu: Add complete SDRAM ECC scrubbing This patch introduces the SDRAM scrubbing for ECC enabled board to fill/initialize the ECC bytes. This is done via the XOR engine to speed up the process. The scrubbing is a 2-stage process: 1) SPL scrubs the area 0 - 0x100.0000 (16MiB) for the main U-Boot 2) U-Boot scrubs the remaining SDRAM area(s) Signed-off-by: Stefan Roese Cc: Luka Perkov --- arch/arm/mach-mvebu/Makefile | 4 ++ arch/arm/mach-mvebu/dram.c | 141 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 446ce041097..21c56a4d969 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -14,6 +14,10 @@ else obj-y = cpu.o obj-y += dram.o +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_SYS_MVEBU_DDR_A38X) += ../../../drivers/ddr/marvell/a38x/xor.o +obj-$(CONFIG_SYS_MVEBU_DDR_AXP) += ../../../drivers/ddr/marvell/axp/xor.o +endif obj-y += gpio.o obj-y += mbus.o obj-y += timer.o diff --git a/arch/arm/mach-mvebu/dram.c b/arch/arm/mach-mvebu/dram.c index a75ada30467..ddc5b7ee3ea 100644 --- a/arch/arm/mach-mvebu/dram.c +++ b/arch/arm/mach-mvebu/dram.c @@ -13,10 +13,12 @@ #include #ifdef CONFIG_SYS_MVEBU_DDR_A38X -#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h" +#include "../../../drivers/ddr/marvell/axp/xor.h" +#include "../../../drivers/ddr/marvell/axp/xor_regs.h" #endif #ifdef CONFIG_SYS_MVEBU_DDR_AXP -#include "../../../drivers/ddr/marvell/axp/ddr3_init.h" +#include "../../../drivers/ddr/marvell/axp/xor.h" +#include "../../../drivers/ddr/marvell/axp/xor_regs.h" #endif DECLARE_GLOBAL_DATA_PTR; @@ -37,6 +39,14 @@ struct sdram_addr_dec { #define SDRAM_SIZE_MAX 0xc0000000 +#define SCRUB_MAGIC 0xbeefdead + +#define SCRB_XOR_UNIT 0 +#define SCRB_XOR_CHAN 1 +#define SCRB_XOR_WIN 0 + +#define XEBARX_BASE_OFFS 16 + /* * mvebu_sdram_bar - reads SDRAM Base Address Register */ @@ -102,6 +112,124 @@ void mvebu_sdram_size_adjust(enum memory_bank bank) mvebu_sdram_bs_set(bank, size); } +#if defined(CONFIG_SYS_MVEBU_DDR_A38X) || defined(CONFIG_SYS_MVEBU_DDR_AXP) +static u32 xor_ctrl_save; +static u32 xor_base_save; +static u32 xor_mask_save; + +static void mv_xor_init2(u32 cs) +{ + u32 reg, base, size, base2; + u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 }; + + xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, + SCRB_XOR_CHAN)); + xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, + SCRB_XOR_WIN)); + xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, + SCRB_XOR_WIN)); + + /* Enable Window x for each CS */ + reg = 0x1; + reg |= (0x3 << 16); + reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg); + + base = 0; + size = mvebu_sdram_bs(cs) - 1; + if (size) { + base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) | + bank_attr[cs]; + reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), + base2); + + base += size + 1; + size = (size / (64 << 10)) << 16; + /* Window x - size - 256 MB */ + reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size); + } + + mv_xor_hal_init(0); + + return; +} + +static void mv_xor_finish2(void) +{ + reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), + xor_ctrl_save); + reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), + xor_base_save); + reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), + xor_mask_save); +} + +static void dram_ecc_scrubbing(void) +{ + int cs; + u32 size, temp; + u32 total_mem = 0; + u64 total; + u32 start_addr; + + /* + * The DDR training code from the bin_hdr / SPL already + * scrubbed the DDR till 0x1000000. And the main U-Boot + * is loaded to an address < 0x1000000. So we need to + * skip this range to not re-scrub this area again. + */ + temp = reg_read(REG_SDRAM_CONFIG_ADDR); + temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS); + reg_write(REG_SDRAM_CONFIG_ADDR, temp); + + for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) { + size = mvebu_sdram_bs(cs) - 1; + if (size == 0) + continue; + + total = (u64)size + 1; + total_mem += (u32)(total / (1 << 30)); + start_addr = 0; + mv_xor_init2(cs); + + /* Skip first 16 MiB */ + if (0 == cs) { + start_addr = 0x1000000; + size -= start_addr; + } + + mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size, + SCRUB_MAGIC, SCRUB_MAGIC); + + /* Wait for previous transfer completion */ + while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE) + ; + + mv_xor_finish2(); + } + + temp = reg_read(REG_SDRAM_CONFIG_ADDR); + temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS); + reg_write(REG_SDRAM_CONFIG_ADDR, temp); +} + +static int ecc_enabled(void) +{ + if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS)) + return 1; + + return 0; +} +#else +static void dram_ecc_scrubbing(void) +{ +} + +static int ecc_enabled(void) +{ + return 0; +} +#endif + int dram_init(void) { u64 size = 0; @@ -135,6 +263,10 @@ int dram_init(void) gd->bd->bi_dram[i].size = 0; } + + if (ecc_enabled()) + dram_ecc_scrubbing(); + gd->ram_size = size; return 0; @@ -162,10 +294,7 @@ void dram_init_banksize(void) void board_add_ram_info(int use_default) { - u32 reg; - - reg = reg_read(REG_SDRAM_CONFIG_ADDR); - if (reg & (1 << REG_SDRAM_CONFIG_ECC_OFFS)) + if (ecc_enabled()) printf(" (ECC"); else printf(" (ECC not"); -- cgit v1.2.3