summaryrefslogtreecommitdiff
path: root/drivers/ddr
diff options
context:
space:
mode:
authorLey Foon Tan <ley.foon.tan@intel.com>2019-03-22 01:24:05 +0800
committerMarek Vasut <marex@denx.de>2019-04-17 22:20:17 +0200
commit456d45261bc6abee1ffedd0f9cbd35aada5c0ff3 (patch)
tree6eddb5f9e9e4108c13fea3685be662e2081e130f /drivers/ddr
parent8ab9daabe5e88a401c891d02d4a765de2c6abaa2 (diff)
downloadu-boot-456d45261bc6abee1ffedd0f9cbd35aada5c0ff3.tar.gz
ddr: altera: Stratix10: Add ECC memory scrubbing
Scrub memory content if ECC is enabled and it is not from warm reset boot. Enable icache and dcache before scrub memory and use "DC ZVA" instruction to clear memory to zeros. This instruction writes a cache line at a time and it can prevent false ECC error trigger if write cache line partially. Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
Diffstat (limited to 'drivers/ddr')
-rw-r--r--drivers/ddr/altera/sdram_s10.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c
index 462c8feaef..e4d4a02ca2 100644
--- a/drivers/ddr/altera/sdram_s10.c
+++ b/drivers/ddr/altera/sdram_s10.c
@@ -23,6 +23,8 @@ static const struct socfpga_system_manager *sysmgr_regs =
#define DDR_CONFIG(A, B, C, R) (((A) << 24) | ((B) << 16) | ((C) << 8) | (R))
+#define PGTABLE_OFF 0x4000
+
/* The followring are the supported configurations */
u32 ddr_config[] = {
/* DDR_CONFIG(Address order,Bank,Column,Row) */
@@ -136,6 +138,76 @@ static int poll_hmc_clock_status(void)
SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false);
}
+static void sdram_clear_mem(phys_addr_t addr, phys_size_t size)
+{
+ phys_size_t i;
+
+ if (addr % CONFIG_SYS_CACHELINE_SIZE) {
+ printf("DDR: address 0x%llx is not cacheline size aligned.\n",
+ addr);
+ hang();
+ }
+
+ if (size % CONFIG_SYS_CACHELINE_SIZE) {
+ printf("DDR: size 0x%llx is not multiple of cacheline size\n",
+ size);
+ hang();
+ }
+
+ /* Use DC ZVA instruction to clear memory to zeros by a cache line */
+ for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) {
+ asm volatile("dc zva, %0"
+ :
+ : "r"(addr)
+ : "memory");
+ addr += CONFIG_SYS_CACHELINE_SIZE;
+ }
+}
+
+static void sdram_init_ecc_bits(bd_t *bd)
+{
+ phys_size_t size, size_init;
+ phys_addr_t start_addr;
+ int bank = 0;
+ unsigned int start = get_timer(0);
+
+ icache_enable();
+
+ start_addr = bd->bi_dram[0].start;
+ size = bd->bi_dram[0].size;
+
+ /* Initialize small block for page table */
+ memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF);
+ gd->arch.tlb_addr = start_addr + PGTABLE_OFF;
+ gd->arch.tlb_size = PGTABLE_SIZE;
+ start_addr += PGTABLE_SIZE + PGTABLE_OFF;
+ size -= (PGTABLE_OFF + PGTABLE_SIZE);
+ dcache_enable();
+
+ while (1) {
+ while (size) {
+ size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size);
+ sdram_clear_mem(start_addr, size_init);
+ size -= size_init;
+ start_addr += size_init;
+ WATCHDOG_RESET();
+ }
+
+ bank++;
+ if (bank >= CONFIG_NR_DRAM_BANKS)
+ break;
+
+ start_addr = bd->bi_dram[bank].start;
+ size = bd->bi_dram[bank].size;
+ }
+
+ dcache_disable();
+ icache_disable();
+
+ printf("SDRAM-ECC: Initialized success with %d ms\n",
+ (unsigned int)get_timer(start));
+}
+
static void sdram_size_check(bd_t *bd)
{
phys_size_t total_ram_check = 0;
@@ -400,6 +472,15 @@ int sdram_mmr_init_full(unsigned int unused)
setbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL2,
(DDR_HMC_ECCCTL2_RMW_EN_SET_MSK |
DDR_HMC_ECCCTL2_AWB_EN_SET_MSK));
+ writel(DDR_HMC_ERRINTEN_INTMASK,
+ SOCFPGA_SDR_ADDRESS + ERRINTENS);
+
+ /* Enable non-secure writes to HMC Adapter for SDRAM ECC */
+ writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR);
+
+ /* Initialize memory content if not from warm reset */
+ if (!cpu_has_been_warmreset())
+ sdram_init_ecc_bits(&bd);
} else {
clrbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL1,
(DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK |