[PATCH] ddr: socfpga: Add ECC DRAM scrubbing support for gen5

From: Tien Fong Chee tien.fong.chee@intel.com
The SDRAM must first be rewritten by zeroes if ECC is used to initialize the ECC metadata. Make the CPU overwrite the DRAM with zeroes in such a case. This scrubbing implementation turns the caches on temporarily, then overwrites the whole RAM with zeroes, flushes the caches and turns them off again. This provides satisfactory performance.
Signed-off-by: Tien Fong Chee tien.fong.chee@intel.com Signed-off-by: Teik Heng Chong teik.heng.chong@intel.com --- arch/arm/mach-socfpga/spl_gen5.c | 4 +++ drivers/ddr/altera/sdram_gen5.c | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+)
diff --git a/arch/arm/mach-socfpga/spl_gen5.c b/arch/arm/mach-socfpga/spl_gen5.c index 287fbd1713..b79d8cbd5d 100644 --- a/arch/arm/mach-socfpga/spl_gen5.c +++ b/arch/arm/mach-socfpga/spl_gen5.c @@ -29,6 +29,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static struct bd_info bdata __section(".data"); + u32 spl_boot_device(void) { const u32 bsel = readl(socfpga_get_sysmgr_addr() + @@ -148,6 +150,8 @@ void board_init_f(ulong dummy) /* enable console uart printing */ preloader_console_init();
+ gd->bd = &bdata; + ret = uclass_get_device(UCLASS_RAM, 0, &dev); if (ret) { debug("DRAM init failed: %d\n", ret); diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c index 8d3ce495de..9d69f009e9 100644 --- a/drivers/ddr/altera/sdram_gen5.c +++ b/drivers/ddr/altera/sdram_gen5.c @@ -3,6 +3,7 @@ * Copyright Altera Corporation (C) 2014-2015 */ #include <common.h> +#include <cpu_func.h> #include <dm.h> #include <errno.h> #include <div64.h> @@ -17,10 +18,14 @@ #include <asm/arch/system_manager.h> #include <asm/bitops.h> #include <asm/io.h> +#include <asm/system.h> #include <dm/device_compat.h> +#include <linux/sizes.h>
#include "sequencer.h"
+#define PGTABLE_OFF 0x4000 + #ifdef CONFIG_SPL_BUILD
struct altera_gen5_sdram_priv { @@ -563,6 +568,54 @@ static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl) return temp; }
+static int sdram_is_ecc_enabled(struct socfpga_sdr_ctrl *sdr_ctrl) +{ + return !!(readl(&sdr_ctrl->ctrl_cfg) & + SDR_CTRLGRP_CTRLCFG_ECCEN_MASK); +} + +/* Initialize SDRAM ECC bits to avoid false DBE */ +static void sdram_init_ecc_bits(phys_size_t size) +{ + phys_size_t start, size_init, start_addr; + + start = get_timer(0); + + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = size; + + gd->arch.tlb_addr = gd->bd->bi_dram[0].start + PGTABLE_OFF; + gd->arch.tlb_size = PGTABLE_SIZE; + + memset((void *)gd->bd->bi_dram[0].start, 0, gd->arch.tlb_addr + + gd->arch.tlb_size); + + icache_enable(); + dcache_enable(); + + printf("DDRCAL: Scrubbing ECC RAM (%lu MiB).\n", size >> 20); + + start_addr = gd->arch.tlb_addr + gd->arch.tlb_size; + size -= (gd->arch.tlb_addr + gd->arch.tlb_size); + + while (size > 0) { + size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size); + memset((void *)start_addr, 0, size_init); + size -= size_init; + start_addr += size_init; + WATCHDOG_RESET(); + } + + flush_dcache_all(); + + printf("DDRCAL: Scrubbing ECC RAM done.\n"); + + dcache_disable(); + + printf("DDRCAL: SDRAM-ECC initialized success with %d ms\n", + (u32)get_timer(start)); +} + static int altera_gen5_sdram_of_to_plat(struct udevice *dev) { struct altera_gen5_sdram_plat *plat = dev_get_plat(dev); @@ -605,6 +658,10 @@ static int altera_gen5_sdram_probe(struct udevice *dev) sdram_size = sdram_calculate_size(sdr_ctrl); debug("SDRAM: %ld MiB\n", sdram_size >> 20);
+ if (sdram_is_ecc_enabled(sdr_ctrl)) { + sdram_init_ecc_bits(sdram_size); + } + /* Sanity check ensure correct SDRAM size specified */ if (get_ram_size(0, sdram_size) != sdram_size) { puts("SDRAM size check failed!\n");
participants (1)
-
teik.heng.chong@intel.com