[U-Boot] [PATCH v2 6/6] ddr: altera: Stratix10: Add ECC memory scrubbing

Ley Foon Tan ley.foon.tan at intel.com
Thu Mar 21 17:24:05 UTC 2019


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 at intel.com>
---
 .../arm/mach-socfpga/include/mach/sdram_s10.h |  9 +++
 drivers/ddr/altera/sdram_s10.c                | 81 +++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/arch/arm/mach-socfpga/include/mach/sdram_s10.h b/arch/arm/mach-socfpga/include/mach/sdram_s10.h
index ca68594445..f39206ca1e 100644
--- a/arch/arm/mach-socfpga/include/mach/sdram_s10.h
+++ b/arch/arm/mach-socfpga/include/mach/sdram_s10.h
@@ -22,6 +22,7 @@ int sdram_calibration_full(void);
 #define ECCCTRL1			0x100
 #define ECCCTRL2			0x104
 #define ERRINTEN			0x110
+#define ERRINTENS			0x114
 #define INTMODE				0x11c
 #define INTSTAT				0x120
 #define AUTOWB_CORRADDR			0x138
@@ -52,6 +53,10 @@ int sdram_calibration_full(void);
 #define DDR_HMC_SEQ2CORE_INT_RESP_MASK		BIT(3)
 #define DDR_HMC_HPSINTFCSEL_ENABLE_MASK		0x001f1f1f
 
+#define	DDR_HMC_ERRINTEN_INTMASK				\
+		(DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK |	\
+		 DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK)
+
 /* NOC DDR scheduler */
 #define DDR_SCH_ID_COREID		0
 #define DDR_SCH_ID_REVID		0x4
@@ -180,4 +185,8 @@ int sdram_calibration_full(void);
 #define CALTIMING9_CFG_4_ACT_TO_ACT(x)			\
 	(((x) >> 0) & 0xFF)
 
+/* Firewall DDR scheduler MPFE */
+#define FW_HMC_ADAPTOR_REG_ADDR			0xf8020004
+#define FW_HMC_ADAPTOR_MPU_MASK			BIT(0)
+
 #endif /* _SDRAM_S10_H_ */
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 |
-- 
2.19.0



More information about the U-Boot mailing list