[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