[PATCH v1 2/5] ddr: socfpga: Add ECC DRAM scrubbing support for Gen5/Arria10
alif.zakuan.yuslaimi at altera.com
alif.zakuan.yuslaimi at altera.com
Tue Dec 16 09:46:20 CET 2025
From: Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi at altera.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.
Move common code sdram_init_ecc_bits() to new common file sdram_soc32.c.
Preparation for Gen5 uses the same memory initialization function as
Arria10.
Signed-off-by: Tien Fong Chee <tien.fong.chee at altera.com>
Signed-off-by: Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi at altera.com>
---
arch/arm/mach-socfpga/spl_gen5.c | 4 ++
drivers/ddr/altera/Makefile | 4 +-
drivers/ddr/altera/sdram_arria10.c | 25 +++-------
drivers/ddr/altera/sdram_gen5.c | 18 ++++++++
drivers/ddr/altera/sdram_soc32.c | 74 ++++++++++++++++++++++++++++++
drivers/ddr/altera/sdram_soc32.h | 11 +++++
6 files changed, 115 insertions(+), 21 deletions(-)
create mode 100644 drivers/ddr/altera/sdram_soc32.c
create mode 100644 drivers/ddr/altera/sdram_soc32.h
diff --git a/arch/arm/mach-socfpga/spl_gen5.c b/arch/arm/mach-socfpga/spl_gen5.c
index df79cfe0f7f..5c78a4c1fea 100644
--- a/arch/arm/mach-socfpga/spl_gen5.c
+++ b/arch/arm/mach-socfpga/spl_gen5.c
@@ -27,6 +27,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static struct bd_info bdata __attribute__ ((section(".data")));
+
u32 spl_boot_device(void)
{
const u32 bsel = readl(socfpga_get_sysmgr_addr() +
@@ -146,6 +148,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/Makefile b/drivers/ddr/altera/Makefile
index 7ed43965be5..b9e3302d714 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -7,8 +7,8 @@
# Copyright (C) 2014-2025 Altera Corporation <www.altera.com>
ifdef CONFIG_$(PHASE_)ALTERA_SDRAM
-obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o
-obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o
+obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_soc32.o sdram_gen5.o sequencer.o
+obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_soc32.o sdram_arria10.o
obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o
obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += sdram_soc64.o sdram_agilex.o
obj-$(CONFIG_TARGET_SOCFPGA_N5X) += sdram_soc64.o sdram_n5x.o
diff --git a/drivers/ddr/altera/sdram_arria10.c b/drivers/ddr/altera/sdram_arria10.c
index d3305a6c82d..0e3a1d42f34 100644
--- a/drivers/ddr/altera/sdram_arria10.c
+++ b/drivers/ddr/altera/sdram_arria10.c
@@ -21,9 +21,14 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/kernel.h>
+#include <linux/sizes.h>
+
+#include "sdram_soc32.h"
DECLARE_GLOBAL_DATA_PTR;
+#define PGTABLE_OFF 0x4000
+
static void sdram_mmr_init(void);
static u64 sdram_size_calc(void);
@@ -192,24 +197,6 @@ static int sdram_is_ecc_enabled(void)
ALT_ECC_HMC_OCP_ECCCTL_ECC_EN_SET_MSK);
}
-/* Initialize SDRAM ECC bits to avoid false DBE */
-static void sdram_init_ecc_bits(u32 size)
-{
- icache_enable();
-
- memset(0, 0, 0x8000);
- gd->arch.tlb_addr = 0x4000;
- gd->arch.tlb_size = PGTABLE_SIZE;
-
- dcache_enable();
-
- printf("DDRCAL: Scrubbing ECC RAM (%i MiB).\n", size >> 20);
- memset((void *)0x8000, 0, size - 0x8000);
- flush_dcache_all();
- printf("DDRCAL: Scrubbing ECC RAM done.\n");
- dcache_disable();
-}
-
/* Function to startup the SDRAM*/
static int sdram_startup(void)
{
@@ -706,7 +693,7 @@ int ddr_calibration_sequence(void)
puts("FW: Error Configuring Firewall\n");
if (sdram_is_ecc_enabled())
- sdram_init_ecc_bits(gd->ram_size);
+ sdram_init_ecc_bits();
return 0;
}
diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c
index 3c79bb11802..7a0a043557b 100644
--- a/drivers/ddr/altera/sdram_gen5.c
+++ b/drivers/ddr/altera/sdram_gen5.c
@@ -2,6 +2,7 @@
/*
* Copyright Altera Corporation (C) 2014-2015
*/
+#include <cpu_func.h>
#include <dm.h>
#include <errno.h>
#include <div64.h>
@@ -17,8 +18,12 @@
#include <asm/bitops.h>
#include <asm/io.h>
#include <dm/device_compat.h>
+#include <linux/sizes.h>
#include "sequencer.h"
+#include "sdram_soc32.h"
+
+#define PGTABLE_OFF 0x4000
#ifdef CONFIG_XPL_BUILD
@@ -562,6 +567,12 @@ 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);
+}
+
static int altera_gen5_sdram_of_to_plat(struct udevice *dev)
{
struct altera_gen5_sdram_plat *plat = dev_get_plat(dev);
@@ -604,6 +615,13 @@ 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)) {
+ /* Must set USEECCASDATA to 0 if ECC is enabled */
+ clrbits_le32(&sdr_ctrl->static_cfg,
+ SDR_CTRLGRP_STATICCFG_USEECCASDATA_MASK);
+ sdram_init_ecc_bits();
+ }
+
/* Sanity check ensure correct SDRAM size specified */
if (get_ram_size(0, sdram_size) != sdram_size) {
puts("SDRAM size check failed!\n");
diff --git a/drivers/ddr/altera/sdram_soc32.c b/drivers/ddr/altera/sdram_soc32.c
new file mode 100644
index 00000000000..b8b42ef8e03
--- /dev/null
+++ b/drivers/ddr/altera/sdram_soc32.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#include "sdram_soc32.h"
+#include <string.h>
+#include <linux/sizes.h>
+#include <cpu_func.h>
+#include <watchdog.h>
+#include <wait_bit.h>
+#include <asm/global_data.h>
+#include <asm/system.h>
+#if !defined(CONFIG_HW_WATCHDOG)
+#include <asm/arch/reset_manager.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PGTABLE_OFF 0x4000
+
+/* Initialize SDRAM ECC bits to avoid false DBE */
+void sdram_init_ecc_bits(void)
+{
+ u32 start;
+ phys_addr_t start_addr;
+ phys_size_t size, size_init;
+
+ start = get_timer(0);
+
+ start_addr = gd->bd->bi_dram[0].start;
+ size = gd->bd->bi_dram[0].size;
+
+ printf("DDRCAL: Scrubbing ECC RAM (%ld MiB).\n", size >> 20);
+
+ 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 (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;
+
+#ifdef CONFIG_HW_WATCHDOG
+ /*
+ * In case the watchdog is enabled, make sure to
+ * (re-)configure watchdog so that the defined timeout is
+ * valid.
+ */
+ debug("%s: %d\n", __func__, __LINE__);
+ hw_watchdog_init();
+#else
+ /*
+ * If the HW watchdog is NOT enabled, make sure it is not
+ * running, because it is enabled in the preloader and
+ * causing boot loop if is not handled.
+ */
+ debug("%s: %d\n", __func__, __LINE__);
+ socfpga_per_reset(SOCFPGA_RESET(L4WD0), 1);
+ socfpga_per_reset(SOCFPGA_RESET(L4WD0), 0);
+#endif
+ }
+
+ dcache_disable();
+
+ printf("DDRCAL: SDRAM-ECC initialized success with %d ms\n",
+ (u32)get_timer(start));
+}
diff --git a/drivers/ddr/altera/sdram_soc32.h b/drivers/ddr/altera/sdram_soc32.h
new file mode 100644
index 00000000000..85a951a5a74
--- /dev/null
+++ b/drivers/ddr/altera/sdram_soc32.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#ifndef _SDRAM_SOC32_H_
+#define _SDRAM_SOC32_H_
+
+void sdram_init_ecc_bits(void);
+
+#endif /* _SDRAM_SOC32_H_ */
--
2.43.7
More information about the U-Boot
mailing list