[PATCH 5/5] drivers: ddr: altera: Add ECC scrubbing with Dcache enabled
Naresh Kumar Ravulapalli
nareshkumar.ravulapalli at altera.com
Tue May 6 16:12:46 CEST 2025
Add ECC scrubbing with Dcache enabled to speed up the scrubbing time.
Change the SDRAM region to writethrough before scrubbing and restore back
to its original behavior after that. This is to avoid triggering of false
double-bit error.
Signed-off-by: Naresh Kumar Ravulapalli <nareshkumar.ravulapalli at altera.com>
Signed-off-by: Tien Fong Chee <tien.fong.chee at altera.com>
---
drivers/ddr/altera/sdram_arria10.c | 62 ++++++++++++------------
drivers/ddr/altera/sdram_soc32.c | 75 ++++++++++++++++++++++++++----
drivers/ddr/altera/sdram_soc32.h | 2 +-
3 files changed, 99 insertions(+), 40 deletions(-)
diff --git a/drivers/ddr/altera/sdram_arria10.c b/drivers/ddr/altera/sdram_arria10.c
index 133d4604738..8f281b82765 100644
--- a/drivers/ddr/altera/sdram_arria10.c
+++ b/drivers/ddr/altera/sdram_arria10.c
@@ -4,7 +4,6 @@
* Copyright (C) 2025 Altera Corporation <www.altera.com>
*/
-#include <cpu_func.h>
#include <errno.h>
#include <fdtdec.h>
#include <init.h>
@@ -23,11 +22,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);
@@ -129,10 +131,10 @@ static int emif_reset(void)
s2c = readl(DDR_REG_SEQ2CORE);
debug("c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n",
- c2s, s2c, readl(IO48_MMR_NIOS2_RESERVE0),
- readl(IO48_MMR_NIOS2_RESERVE1),
- readl(IO48_MMR_NIOS2_RESERVE2),
- readl(IO48_MMR_DRAMSTS));
+ c2s, s2c, readl(IO48_MMR_NIOS2_RESERVE0),
+ readl(IO48_MMR_NIOS2_RESERVE1),
+ readl(IO48_MMR_NIOS2_RESERVE2),
+ readl(IO48_MMR_DRAMSTS));
if (s2c & SEQ2CORE_MASK) {
ret = emif_clear();
@@ -162,9 +164,9 @@ static int emif_reset(void)
debug("emif_reset interrupt cleared\n");
debug("nr0=%08x nr1=%08x nr2=%08x\n",
- readl(IO48_MMR_NIOS2_RESERVE0),
- readl(IO48_MMR_NIOS2_RESERVE1),
- readl(IO48_MMR_NIOS2_RESERVE2));
+ readl(IO48_MMR_NIOS2_RESERVE0),
+ readl(IO48_MMR_NIOS2_RESERVE1),
+ readl(IO48_MMR_NIOS2_RESERVE2));
return 0;
}
@@ -225,7 +227,7 @@ static u64 sdram_size_calc(void)
(dramaddrw & IO48_MMR_DRAMADDRW_CFG_COL_ADDR_WIDTH_MASK));
size *= (2 << (readl(&socfpga_ecc_hmc_base->ddrioctrl) &
- ALT_ECC_HMC_OCP_DDRIOCTRL_IO_SIZE_MSK));
+ ALT_ECC_HMC_OCP_DDRIOCTRL_IO_SIZE_MSK));
debug("SDRAM size=%llu\n", size);
@@ -264,7 +266,7 @@ static void sdram_mmr_init(void)
if ((readl(&socfpga_io48_mmr_base->niosreserve1) >> 6) & 0x1FF) {
update_value = readl(&socfpga_io48_mmr_base->niosreserve0);
writel(((update_value & 0xFF) >> 5),
- &socfpga_ecc_hmc_base->ddrioctrl);
+ &socfpga_ecc_hmc_base->ddrioctrl);
}
ddrioctl = readl(&socfpga_ecc_hmc_base->ddrioctrl);
@@ -352,11 +354,11 @@ static void sdram_mmr_init(void)
(ctrlcfg0_cfg_ctrl_burst_len >> 2));
io48_value = ((((readl(&socfpga_io48_mmr_base->dramtiming0) &
- ALT_IO48_DRAMTIME_MEM_READ_LATENCY_MASK) + 2 + 15 +
- (ctrlcfg0_cfg_ctrl_burst_len >> 1)) >> 1) -
- /* Up to here was in memory cycles so divide by 2 */
- caltim1_cfg_rd_to_wr + caltim0_cfg_act_to_rdwr +
- caltim4_cfg_pch_to_valid);
+ ALT_IO48_DRAMTIME_MEM_READ_LATENCY_MASK) + 2 + 15 +
+ (ctrlcfg0_cfg_ctrl_burst_len >> 1)) >> 1) -
+ /* Up to here was in memory cycles so divide by 2 */
+ caltim1_cfg_rd_to_wr + caltim0_cfg_act_to_rdwr +
+ caltim4_cfg_pch_to_valid);
writel(((caltim0_cfg_act_to_act <<
ALT_NOC_MPU_DDR_T_SCHED_DDRTIMING_ACTTOACT_LSB) |
@@ -414,23 +416,23 @@ static void sdram_mmr_init(void)
/* Enable or disable the SDRAM ECC */
if (ctrlcfg1 & IO48_MMR_CTRLCFG1_CTRL_ENABLE_ECC) {
setbits_le32(&socfpga_ecc_hmc_base->eccctrl,
- (ALT_ECC_HMC_OCP_ECCCTL_AWB_CNT_RST_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL_CNT_RST_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL_ECC_EN_SET_MSK));
+ (ALT_ECC_HMC_OCP_ECCCTL_AWB_CNT_RST_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL_CNT_RST_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL_ECC_EN_SET_MSK));
clrbits_le32(&socfpga_ecc_hmc_base->eccctrl,
- (ALT_ECC_HMC_OCP_ECCCTL_AWB_CNT_RST_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL_CNT_RST_SET_MSK));
+ (ALT_ECC_HMC_OCP_ECCCTL_AWB_CNT_RST_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL_CNT_RST_SET_MSK));
setbits_le32(&socfpga_ecc_hmc_base->eccctrl2,
- (ALT_ECC_HMC_OCP_ECCCTL2_RMW_EN_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL2_AWB_EN_SET_MSK));
+ (ALT_ECC_HMC_OCP_ECCCTL2_RMW_EN_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL2_AWB_EN_SET_MSK));
} else {
clrbits_le32(&socfpga_ecc_hmc_base->eccctrl,
- (ALT_ECC_HMC_OCP_ECCCTL_AWB_CNT_RST_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL_CNT_RST_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL_ECC_EN_SET_MSK));
+ (ALT_ECC_HMC_OCP_ECCCTL_AWB_CNT_RST_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL_CNT_RST_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL_ECC_EN_SET_MSK));
clrbits_le32(&socfpga_ecc_hmc_base->eccctrl2,
- (ALT_ECC_HMC_OCP_ECCCTL2_RMW_EN_SET_MSK |
- ALT_ECC_HMC_OCP_ECCCTL2_AWB_EN_SET_MSK));
+ (ALT_ECC_HMC_OCP_ECCCTL2_RMW_EN_SET_MSK |
+ ALT_ECC_HMC_OCP_ECCCTL2_AWB_EN_SET_MSK));
}
}
@@ -643,8 +645,8 @@ static int of_sdram_firewall_setup(const void *blob)
}
writel((start_end[0] & ALT_NOC_FW_DDR_ADDR_MASK) |
- (start_end[1] << ALT_NOC_FW_DDR_END_ADDR_LSB),
- firewall_table[i].cfg_addr);
+ (start_end[1] << ALT_NOC_FW_DDR_END_ADDR_LSB),
+ firewall_table[i].cfg_addr);
setbits_le32(firewall_table[i].en_addr,
firewall_table[i].en_bit);
}
@@ -719,7 +721,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();
sdram_size_check();
diff --git a/drivers/ddr/altera/sdram_soc32.c b/drivers/ddr/altera/sdram_soc32.c
index ccb4266473c..b6693a03617 100644
--- a/drivers/ddr/altera/sdram_soc32.c
+++ b/drivers/ddr/altera/sdram_soc32.c
@@ -7,25 +7,82 @@
#include <cpu_func.h>
#include <linux/sizes.h>
#include "sdram_soc32.h"
+#include <watchdog.h>
+#include <wait_bit.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(u32 size)
+void sdram_init_ecc_bits(void)
{
- icache_enable();
+ u32 start;
+ phys_addr_t start_addr, saved_start;
+ phys_size_t size, size_init, saved_size;
+ enum dcache_option option = DCACHE_WRITEBACK;
- memset(0, 0, 0x8000);
- gd->arch.tlb_addr = 0x4000;
- gd->arch.tlb_size = PGTABLE_SIZE;
+ if (IS_ENABLED(CONFIG_SYS_ARM_CACHE_WRITETHROUGH))
+ option = DCACHE_WRITETHROUGH;
+ else if (IS_ENABLED(CONFIG_SYS_ARM_CACHE_WRITEALLOC))
+ option = DCACHE_WRITEALLOC;
+
+ 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();
- 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");
+ saved_start = start_addr;
+ saved_size = size;
+ /* Set SDRAM region to writethrough to avoid false double-bit error. */
+ mmu_set_region_dcache_behaviour(saved_start, saved_size,
+ DCACHE_WRITETHROUGH);
+
+ 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;
+
+ if (IS_ENABLED(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);
+ }
+ }
+
dcache_disable();
+
+ /* Restore back to original dcache behaviour. */
+ mmu_set_region_dcache_behaviour(saved_start, saved_size,
+ option);
+
+ 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
index 4c6137e728d..85a951a5a74 100644
--- a/drivers/ddr/altera/sdram_soc32.h
+++ b/drivers/ddr/altera/sdram_soc32.h
@@ -6,6 +6,6 @@
#ifndef _SDRAM_SOC32_H_
#define _SDRAM_SOC32_H_
-void sdram_init_ecc_bits(u32 size);
+void sdram_init_ecc_bits(void);
#endif /* _SDRAM_SOC32_H_ */
--
2.35.3
More information about the U-Boot
mailing list