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

teik.heng.chong at intel.com teik.heng.chong at intel.com
Mon Sep 12 03:47:36 CEST 2022


From: Tien Fong Chee <tien.fong.chee at 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 at intel.com>
Signed-off-by: Teik Heng Chong <teik.heng.chong at 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");
-- 
2.26.2



More information about the U-Boot mailing list