From 29873c74f367474faafd16376e2a9f404172fbdd Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 16 Apr 2019 22:04:39 +0200 Subject: arm: socfpga: move gen5 SDR driver to DM To clean up reset handling for socfpga gen5, port the DDR driver to DM using UCLASS_RAM and implement proper reset handling. This gets us rid of one ad-hoc call to socfpga_per_reset(). The gen5 driver is implemented in 2 distinct files. One of it (containing the calibration training) is not touched much and is kept at using hard coded addresses since the code grows even more otherwise. SPL is changed from calling hard into the DDR driver code to just probing UCLASS_RESET and UCLASS_RAM. It is happy after finding a RAM driver after that. Signed-off-by: Simon Goldschmidt --- arch/arm/mach-socfpga/include/mach/sdram_gen5.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/arm/mach-socfpga/include') diff --git a/arch/arm/mach-socfpga/include/mach/sdram_gen5.h b/arch/arm/mach-socfpga/include/mach/sdram_gen5.h index a238d5d17f..c41208591a 100644 --- a/arch/arm/mach-socfpga/include/mach/sdram_gen5.h +++ b/arch/arm/mach-socfpga/include/mach/sdram_gen5.h @@ -7,10 +7,6 @@ #ifndef __ASSEMBLY__ -unsigned long sdram_calculate_size(void); -int sdram_mmr_init_full(unsigned int sdr_phy_reg); -int sdram_calibration_full(void); - const struct socfpga_sdram_config *socfpga_get_sdram_config(void); void socfpga_get_seq_ac_init(const u32 **init, unsigned int *nelem); -- cgit v1.2.3 From 8ab9daabe5e88a401c891d02d4a765de2c6abaa2 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Fri, 22 Mar 2019 01:24:04 +0800 Subject: arm: socfpga: stratix10: Add cpu_has_been_warmreset() Add helper function cpu_has_been_warmreset() to check if CPU is from warm reset boot. Signed-off-by: Ley Foon Tan --- arch/arm/mach-socfpga/include/mach/reset_manager_s10.h | 3 +++ arch/arm/mach-socfpga/reset_manager_s10.c | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'arch/arm/mach-socfpga/include') diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager_s10.h b/arch/arm/mach-socfpga/include/mach/reset_manager_s10.h index 31b73edabe..e186296791 100644 --- a/arch/arm/mach-socfpga/include/mach/reset_manager_s10.h +++ b/arch/arm/mach-socfpga/include/mach/reset_manager_s10.h @@ -9,6 +9,7 @@ void reset_cpu(ulong addr); void reset_deassert_peripherals_handoff(void); +int cpu_has_been_warmreset(void); void socfpga_bridges_reset(int enable); @@ -47,6 +48,8 @@ struct socfpga_reset_manager { #define RSTMGR_MPUMODRST_CORE0 0 #define RSTMGR_PER0MODRST_OCP_MASK 0x0020bf00 #define RSTMGR_BRGMODRST_DDRSCH_MASK 0X00000040 +/* Watchdogs and MPU warm reset mask */ +#define RSTMGR_L4WD_MPU_WARMRESET_MASK 0x000F0F00 /* * Define a reset identifier, from which a permodrst bank ID diff --git a/arch/arm/mach-socfpga/reset_manager_s10.c b/arch/arm/mach-socfpga/reset_manager_s10.c index f176c38495..f8dd787cc6 100644 --- a/arch/arm/mach-socfpga/reset_manager_s10.c +++ b/arch/arm/mach-socfpga/reset_manager_s10.c @@ -103,3 +103,12 @@ void reset_deassert_peripherals_handoff(void) writel(~RSTMGR_PER0MODRST_OCP_MASK, &reset_manager_base->per0modrst); writel(0, &reset_manager_base->per0modrst); } + +/* + * Return non-zero if the CPU has been warm reset + */ +int cpu_has_been_warmreset(void) +{ + return readl(&reset_manager_base->status) & + RSTMGR_L4WD_MPU_WARMRESET_MASK; +} -- cgit v1.2.3 From 456d45261bc6abee1ffedd0f9cbd35aada5c0ff3 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Fri, 22 Mar 2019 01:24:05 +0800 Subject: ddr: altera: Stratix10: Add ECC memory scrubbing Scrub memory content if ECC is enabled and it is not from warm reset boot. Enable icache and dcache before scrub memory and use "DC ZVA" instruction to clear memory to zeros. This instruction writes a cache line at a time and it can prevent false ECC error trigger if write cache line partially. Signed-off-by: Ley Foon Tan --- arch/arm/mach-socfpga/include/mach/sdram_s10.h | 9 +++ drivers/ddr/altera/sdram_s10.c | 81 ++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) (limited to 'arch/arm/mach-socfpga/include') diff --git a/arch/arm/mach-socfpga/include/mach/sdram_s10.h b/arch/arm/mach-socfpga/include/mach/sdram_s10.h index ca68594445..f39206ca1e 100644 --- a/arch/arm/mach-socfpga/include/mach/sdram_s10.h +++ b/arch/arm/mach-socfpga/include/mach/sdram_s10.h @@ -22,6 +22,7 @@ int sdram_calibration_full(void); #define ECCCTRL1 0x100 #define ECCCTRL2 0x104 #define ERRINTEN 0x110 +#define ERRINTENS 0x114 #define INTMODE 0x11c #define INTSTAT 0x120 #define AUTOWB_CORRADDR 0x138 @@ -52,6 +53,10 @@ int sdram_calibration_full(void); #define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3) #define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f +#define DDR_HMC_ERRINTEN_INTMASK \ + (DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK | \ + DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK) + /* NOC DDR scheduler */ #define DDR_SCH_ID_COREID 0 #define DDR_SCH_ID_REVID 0x4 @@ -180,4 +185,8 @@ int sdram_calibration_full(void); #define CALTIMING9_CFG_4_ACT_TO_ACT(x) \ (((x) >> 0) & 0xFF) +/* Firewall DDR scheduler MPFE */ +#define FW_HMC_ADAPTOR_REG_ADDR 0xf8020004 +#define FW_HMC_ADAPTOR_MPU_MASK BIT(0) + #endif /* _SDRAM_S10_H_ */ diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c index 462c8feaef..e4d4a02ca2 100644 --- a/drivers/ddr/altera/sdram_s10.c +++ b/drivers/ddr/altera/sdram_s10.c @@ -23,6 +23,8 @@ static const struct socfpga_system_manager *sysmgr_regs = #define DDR_CONFIG(A, B, C, R) (((A) << 24) | ((B) << 16) | ((C) << 8) | (R)) +#define PGTABLE_OFF 0x4000 + /* The followring are the supported configurations */ u32 ddr_config[] = { /* DDR_CONFIG(Address order,Bank,Column,Row) */ @@ -136,6 +138,76 @@ static int poll_hmc_clock_status(void) SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false); } +static void sdram_clear_mem(phys_addr_t addr, phys_size_t size) +{ + phys_size_t i; + + if (addr % CONFIG_SYS_CACHELINE_SIZE) { + printf("DDR: address 0x%llx is not cacheline size aligned.\n", + addr); + hang(); + } + + if (size % CONFIG_SYS_CACHELINE_SIZE) { + printf("DDR: size 0x%llx is not multiple of cacheline size\n", + size); + hang(); + } + + /* Use DC ZVA instruction to clear memory to zeros by a cache line */ + for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) { + asm volatile("dc zva, %0" + : + : "r"(addr) + : "memory"); + addr += CONFIG_SYS_CACHELINE_SIZE; + } +} + +static void sdram_init_ecc_bits(bd_t *bd) +{ + phys_size_t size, size_init; + phys_addr_t start_addr; + int bank = 0; + unsigned int start = get_timer(0); + + icache_enable(); + + start_addr = bd->bi_dram[0].start; + size = bd->bi_dram[0].size; + + /* Initialize small block for page table */ + 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 (1) { + while (size) { + size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size); + sdram_clear_mem(start_addr, size_init); + size -= size_init; + start_addr += size_init; + WATCHDOG_RESET(); + } + + bank++; + if (bank >= CONFIG_NR_DRAM_BANKS) + break; + + start_addr = bd->bi_dram[bank].start; + size = bd->bi_dram[bank].size; + } + + dcache_disable(); + icache_disable(); + + printf("SDRAM-ECC: Initialized success with %d ms\n", + (unsigned int)get_timer(start)); +} + static void sdram_size_check(bd_t *bd) { phys_size_t total_ram_check = 0; @@ -400,6 +472,15 @@ int sdram_mmr_init_full(unsigned int unused) setbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL2, (DDR_HMC_ECCCTL2_RMW_EN_SET_MSK | DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); + writel(DDR_HMC_ERRINTEN_INTMASK, + SOCFPGA_SDR_ADDRESS + ERRINTENS); + + /* Enable non-secure writes to HMC Adapter for SDRAM ECC */ + writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR); + + /* Initialize memory content if not from warm reset */ + if (!cpu_has_been_warmreset()) + sdram_init_ecc_bits(&bd); } else { clrbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL1, (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | -- cgit v1.2.3