From: Alif Zakuan Yuslaimi <[email protected]> Enable ECC scrubbing support for Gen5 by moving sdram_init_ecc_bits() from sdram_arria10.c to a new common file, sdram_soc32.c which is shared by both Arria10 and Gen5 devices. This makes ECC scrubbing support no longer exclusive only to Arria10.
New Kconfig is introduced to enable this implementation only on the default Arria10 and CycloneV boards as this will increase the SPL size which will exceed some Gen5 devices' SPL size limit. Signed-off-by: Tien Fong Chee <[email protected]> Signed-off-by: Alif Zakuan Yuslaimi <[email protected]> --- Changes in v3: - Updated commit message - Removed legacy HW watchdog check in favor of current WDT DM for Gen5/Arria10 - Dead code cleanups, indentation fixes Changes in v2: - ECC scrubbing is set as optional via Kconfig and defaulted on only for the reference Arria10/CycloneV boards to avoid SPL overflows on size-limited Gen5 defconfigs. arch/arm/mach-socfpga/Kconfig | 12 +++++ arch/arm/mach-socfpga/spl_a10.c | 11 ++-- arch/arm/mach-socfpga/spl_gen5.c | 10 +++- drivers/ddr/altera/Makefile | 4 +- drivers/ddr/altera/sdram_arria10.c | 31 ++++------- drivers/ddr/altera/sdram_gen5.c | 39 ++++++++++++-- drivers/ddr/altera/sdram_soc32.c | 85 ++++++++++++++++++++++++++++++ drivers/ddr/altera/sdram_soc32.h | 15 ++++++ 8 files changed, 172 insertions(+), 35 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/Kconfig b/arch/arm/mach-socfpga/Kconfig index b814e034ecd..dd71691b724 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -6,6 +6,13 @@ config ERR_PTR_OFFSET config NR_DRAM_BANKS default 1 +config SOCFPGA_ECC_SUPPORT + bool "Enable ECC support for DRAM" + help + Adds CPU-based ECC support for DRAM at boot. This will initialize + all DRAM ECC metadata to zero, preventing false ECC errors and + improving reliability. + config SOCFPGA_DRAM_SIZE_CHECK bool "Enable DRAM size checking for safety" help @@ -105,6 +112,7 @@ config ARCH_SOCFPGA_ARRIA10 select ETH_DESIGNWARE_SOCFPGA imply FPGA_SOCFPGA imply SPL_USE_TINY_PRINTF + select SOCFPGA_ECC_SUPPORT config SOCFPGA_ARRIA10_ALWAYS_REPROGRAM bool "Always reprogram Arria 10 FPGA" @@ -117,6 +125,9 @@ config SOCFPGA_ARRIA10_ALWAYS_REPROGRAM config ARCH_SOCFPGA_CYCLONE5 bool select ARCH_SOCFPGA_GEN5 + select SOCFPGA_ECC_SUPPORT if \ + !TARGET_SOCFPGA_TERASIC_SOCKIT && !TARGET_SOCFPGA_EBV_SOCRATES \ + && !TARGET_SOCFPGA_SOFTING_VINING_FPGA select SOCFPGA_DRAM_SIZE_CHECK if !TARGET_SOCFPGA_TERASIC_SOCKIT \ && !TARGET_SOCFPGA_EBV_SOCRATES && \ !TARGET_SOCFPGA_SOFTING_VINING_FPGA @@ -124,6 +135,7 @@ config ARCH_SOCFPGA_CYCLONE5 config ARCH_SOCFPGA_GEN5 bool select SPL_ALTERA_SDRAM + select SPL_CACHE if SPL && SOCFPGA_ECC_SUPPORT imply FPGA_SOCFPGA imply SPL_SIZE_LIMIT_SUBTRACT_GD imply SPL_SIZE_LIMIT_SUBTRACT_MALLOC diff --git a/arch/arm/mach-socfpga/spl_a10.c b/arch/arm/mach-socfpga/spl_a10.c index c20376f7f8e..0d0412d3507 100644 --- a/arch/arm/mach-socfpga/spl_a10.c +++ b/arch/arm/mach-socfpga/spl_a10.c @@ -25,6 +25,7 @@ #include <asm/sections.h> #include <fdtdec.h> #include <watchdog.h> +#include <wdt.h> #include <asm/arch/pinmux.h> #include <asm/arch/fpga_manager.h> #include <mmc.h> @@ -265,14 +266,8 @@ void board_init_f(ulong dummy) /* Configure the clock based on handoff */ cm_basic_init(gd->fdt_blob); -#ifdef CONFIG_HW_WATCHDOG - /* release osc1 watchdog timer 0 from reset */ - socfpga_reset_deassert_osc1wd0(); - - /* reconfigure and enable the watchdog */ - hw_watchdog_init(); - schedule(); -#endif /* CONFIG_HW_WATCHDOG */ + if (CONFIG_IS_ENABLED(WDT)) + initr_watchdog(); config_dedicated_pins(gd->fdt_blob); schedule(); diff --git a/arch/arm/mach-socfpga/spl_gen5.c b/arch/arm/mach-socfpga/spl_gen5.c index a9825173189..530863b1564 100644 --- a/arch/arm/mach-socfpga/spl_gen5.c +++ b/arch/arm/mach-socfpga/spl_gen5.c @@ -22,12 +22,14 @@ #include <debug_uart.h> #include <fdtdec.h> #include <watchdog.h> +#include <wdt.h> #include <dm/uclass.h> #include <linux/bitops.h> DECLARE_GLOBAL_DATA_PTR; -#if IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) || \ + IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) static struct bd_info bdata __attribute__ ((section(".data"))); #endif @@ -113,6 +115,9 @@ void board_init_f(ulong dummy) if (cm_basic_init(cm_default_cfg)) hang(); + if (CONFIG_IS_ENABLED(WDT)) + initr_watchdog(); + /* Enable bootrom to configure IOs. */ sysmgr_config_warmrstcfgio(1); @@ -150,7 +155,8 @@ void board_init_f(ulong dummy) /* enable console uart printing */ preloader_console_init(); -#if IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) || \ + IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) gd->bd = &bdata; #endif diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile index 8259ab04a7e..ece6a131897 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_ARCH_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o -obj-$(CONFIG_ARCH_SOCFPGA_ARRIA10) += sdram_arria10.o +obj-$(CONFIG_ARCH_SOCFPGA_GEN5) += sdram_soc32.o sdram_gen5.o sequencer.o +obj-$(CONFIG_ARCH_SOCFPGA_ARRIA10) += sdram_soc32.o sdram_arria10.o obj-$(CONFIG_ARCH_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o obj-$(CONFIG_ARCH_SOCFPGA_AGILEX) += sdram_soc64.o sdram_agilex.o obj-$(CONFIG_ARCH_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 c281f711fdf..ac5d3f03f05 100644 --- a/drivers/ddr/altera/sdram_arria10.c +++ b/drivers/ddr/altera/sdram_arria10.c @@ -22,6 +22,8 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/kernel.h> +#include <linux/sizes.h> +#include "sdram_soc32.h" DECLARE_GLOBAL_DATA_PTR; @@ -193,24 +195,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) { @@ -735,8 +719,15 @@ int ddr_calibration_sequence(void) if (of_sdram_firewall_setup(gd->fdt_blob)) puts("FW: Error Configuring Firewall\n"); - if (sdram_is_ecc_enabled()) - sdram_init_ecc_bits(gd->ram_size); + if (sdram_is_ecc_enabled()) { +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) + sdram_init_ecc_bits(); +#else + puts("DDR: Enable CONFIG_SOCFPGA_ECC_SUPPORT when SDRAM "); + puts("ECC is enabled.\n"); + hang(); +#endif + } sdram_size_check(); diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c index 1c3c70ea8ae..9c58e4355ae 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> @@ -19,8 +20,9 @@ #include <asm/global_data.h> #include <asm/io.h> #include <dm/device_compat.h> - +#include <linux/sizes.h> #include "sequencer.h" +#include "sdram_soc32.h" #ifdef CONFIG_XPL_BUILD @@ -566,6 +568,19 @@ static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl) return temp; } +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) +static int sdram_is_ecc_enabled(struct socfpga_sdr_ctrl *sdr_ctrl) +{ + return !!(readl(&sdr_ctrl->ctrl_cfg) & + SDR_CTRLGRP_CTRLCFG_ECCEN_MASK); +} +#else +static int sdram_is_ecc_enabled(struct socfpga_sdr_ctrl *sdr_ctrl) +{ + return 0; +} +#endif + static int altera_gen5_sdram_of_to_plat(struct udevice *dev) { struct altera_gen5_sdram_plat *plat = dev_get_plat(dev); @@ -608,10 +623,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 IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) +#if IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) || \ + IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) /* setup the dram info within bd */ dram_init_banksize(); +#endif +#if IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) if (sdram_size != gd->bd->bi_dram[0].size) { printf("DDR: Warning: DRAM size from device tree (%lu MiB)\n", (ulong)(gd->bd->bi_dram[0].size >> 20)); @@ -626,8 +644,23 @@ static int altera_gen5_sdram_probe(struct udevice *dev) } #endif + if (sdram_is_ecc_enabled(sdr_ctrl)) { +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) + /* Must set USEECCASDATA to 0 if ECC is enabled */ + clrbits_le32(&sdr_ctrl->static_cfg, + SDR_CTRLGRP_STATICCFG_USEECCASDATA_MASK); + sdram_init_ecc_bits(); +#else + puts("DDR: Enable CONFIG_SOCFPGA_ECC_SUPPORT when SDRAM "); + puts("ECC is enabled.\n"); + puts("DDR: Without scrub, false ECC errors may occur.\n"); + hang(); +#endif + } + /* Sanity check ensure correct SDRAM size specified */ -#if IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) +#if IS_ENABLED(CONFIG_SOCFPGA_DRAM_SIZE_CHECK) || \ + IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) if (get_ram_size(0, gd->bd->bi_dram[0].size) != gd->bd->bi_dram[0].size) { #else diff --git a/drivers/ddr/altera/sdram_soc32.c b/drivers/ddr/altera/sdram_soc32.c new file mode 100644 index 00000000000..2fc06fddd4c --- /dev/null +++ b/drivers/ddr/altera/sdram_soc32.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Altera Corporation <www.altera.com> + */ + +#include "sdram_soc32.h" +#include <string.h> +#include <hang.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 !IS_ENABLED(CONFIG_WATCHDOG) && !CONFIG_IS_ENABLED(WDT) +#include <asm/arch/reset_manager.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#define PGTABLE_OFF 0x4000 +#define PGTABLE_RESERVE (PGTABLE_OFF + PGTABLE_SIZE) + +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) +static void socfpga_prepare_watchdog_for_long_op(void) +{ +#if !IS_ENABLED(CONFIG_WATCHDOG) && !CONFIG_IS_ENABLED(WDT) + /* + * No watchdog driver is active in U-Boot. The bootrom or a + * previous boot stage may have left L4WD0 running. Assert and + * deassert its reset to stop it before the long ECC scrub, + * preventing a spurious watchdog reset during DDR init. + */ + socfpga_per_reset(SOCFPGA_RESET(L4WD0), 1); + socfpga_per_reset(SOCFPGA_RESET(L4WD0), 0); +#endif +} + +/* 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 (%lu MiB).\n", + (ulong)(size >> 20)); + + if (size <= PGTABLE_RESERVE) { + printf("DDRCAL: Error: DRAM size %#llx smaller than scrub reserve %#x\n", + (unsigned long long)size, PGTABLE_RESERVE); + hang(); + } + + memset((void *)start_addr, 0, PGTABLE_RESERVE); + gd->arch.tlb_addr = start_addr + PGTABLE_OFF; + gd->arch.tlb_size = PGTABLE_SIZE; + start_addr += PGTABLE_RESERVE; + size -= PGTABLE_RESERVE; + + dcache_enable(); + + socfpga_prepare_watchdog_for_long_op(); + + while (size > 0) { + size_init = min_t(phys_size_t, (phys_size_t)SZ_1G, size); + memset((void *)start_addr, 0, size_init); + size -= size_init; + start_addr += size_init; + + /* Service DM watchdog cyclic callbacks */ + schedule(); + } + + dcache_disable(); + + printf("DDRCAL: SDRAM-ECC initialized success with %u ms\n", + (u32)get_timer(start)); +} +#endif diff --git a/drivers/ddr/altera/sdram_soc32.h b/drivers/ddr/altera/sdram_soc32.h new file mode 100644 index 00000000000..efd4ac54a98 --- /dev/null +++ b/drivers/ddr/altera/sdram_soc32.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Altera Corporation <www.altera.com> + */ + +#ifndef _SDRAM_SOC32_H_ +#define _SDRAM_SOC32_H_ + +#if IS_ENABLED(CONFIG_SOCFPGA_ECC_SUPPORT) +void sdram_init_ecc_bits(void); +#else +static inline void sdram_init_ecc_bits(void) { } +#endif + +#endif /* _SDRAM_SOC32_H_ */ -- 2.43.7

