From c889ca7ccf9ea960d164ee8568eb44e5c2f9a46d Mon Sep 17 00:00:00 2001 From: Naresh Kumar Ravulapalli Date: Fri, 7 Mar 2025 02:28:51 -0800 Subject: drivers: ddr: altera: Fix integer overflow during size calculation Data structure, dramaddrw, is defined as u32. Compiler performs 32-bit arithmetic and logic operations on this data structure. Fix is provided to avoid integer overflow while performing shifting operations greater than 32-bit. Signed-off-by: Naresh Kumar Ravulapalli Reviewed-by: Tien Fong Chee --- drivers/ddr/altera/sdram_soc64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index c8c9211adce..75c6de1e4ec 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -249,7 +249,7 @@ phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat) DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) + DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw)); - size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) & + size *= ((phys_size_t)2 << (hmc_ecc_readl(plat, DDRIOCTRL) & DDR_HMC_DDRIOCTRL_IOSIZE_MSK)); return size; -- cgit v1.2.3 From 9aa85e01a4ac55c233c238ecc66d146aa12581d8 Mon Sep 17 00:00:00 2001 From: Naresh Kumar Ravulapalli Date: Fri, 14 Mar 2025 10:42:25 -0700 Subject: reset: socfpga: release more A10 peripherals out of reset Current implementation releases most peripherals out of reset for gen5, but A10 has more peripherals than gen5, hence this patch is required to release the rest of peripherals to support old kernels. Signed-off-by: Tien Fong Chee Signed-off-by: Naresh Kumar Ravulapalli Reviewed-by: Tien Fong Chee --- drivers/reset/reset-socfpga.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index 76d108080d9..e57729f0ef9 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -23,6 +23,7 @@ #include #include #include +#include #define BANK_INCREMENT 4 #define NR_BANKS 8 @@ -114,6 +115,8 @@ static int socfpga_reset_remove(struct udevice *dev) if (socfpga_reset_keep_enabled()) { puts("Deasserting all peripheral resets\n"); writel(0, data->modrst_base + 4); + if (IS_ENABLED(CONFIG_TARGET_SOCFPGA_ARRIA10)) + writel(0, data->modrst_base + 8); } return 0; -- cgit v1.2.3 From ef16992e3eab0eaa3c194fffd65bd8cc89050388 Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Mon, 10 Mar 2025 23:38:51 -0700 Subject: arm: socfpga: mailbox: Notify SDM on HPS code execution stages Introducing a new mailbox command "HPS_STAGE_NOTIFY" to notify Secure Device Manager (SDM) on the stage of HPS code execution. Generally, there are three main code execution stages: First Stage Boot Loader (FSBL) which is U-Boot SPL, Second Stage Boot Loader (SSBL) which is U-Boot, and the Operating System (OS) which is Linux. This enables the user to query the SDM for HPS error details. Signed-off-by: Alif Zakuan Yuslaimi Reviewed-by: Tien Fong Chee --- arch/arm/mach-socfpga/include/mach/mailbox_s10.h | 4 ++++ arch/arm/mach-socfpga/mailbox_s10.c | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h index 45cc9912f94..2099c51b682 100644 --- a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h +++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h @@ -128,6 +128,7 @@ enum ALT_SDM_MBOX_RESP_CODE { #define MBOX_QSPI_CLOSE 51 #define MBOX_QSPI_DIRECT 59 #define MBOX_REBOOT_HPS 71 +#define MBOX_HPS_STAGE_NOTIFY 93 /* Mailbox registers */ #define MBOX_CIN 0 /* command valid offset */ @@ -385,6 +386,8 @@ enum MBOX_CFGSTAT_MINOR_ERR_CODE { #define RCF_SOFTFUNC_STATUS_SEU_ERROR BIT(3) #define RCF_PIN_STATUS_NSTATUS BIT(31) +#define HPS_EXECUTION_STATE_FSBL 0 + int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, u8 urgent, u32 *resp_buf_len, u32 *resp_buf); int mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, @@ -401,6 +404,7 @@ int mbox_qspi_open(void); #endif int mbox_reset_cold(void); +int mbox_hps_stage_notify(u32 execution_stage); int mbox_get_fpga_config_status(u32 cmd); int mbox_get_fpga_config_status_psci(u32 cmd); #endif /* _MAILBOX_S10_H_ */ diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c index b69bd3e47ec..f9c34e85711 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -474,6 +475,17 @@ int __secure mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, urgent, resp_buf_len, resp_buf); } +int mbox_hps_stage_notify(u32 execution_stage) +{ +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF) + return smc_send_mailbox(MBOX_HPS_STAGE_NOTIFY, 1, &execution_stage, + 0, 0, NULL); +#else + return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_HPS_STAGE_NOTIFY, + MBOX_CMD_DIRECT, 1, &execution_stage, 0, 0, NULL); +#endif +} + int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg) { return mbox_send_cmd_only_common(id, cmd, is_indirect, len, arg); -- cgit v1.2.3 From 9acad2b4c7214bb423a6221b67b0d7ea37edbdf7 Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Thu, 3 Apr 2025 19:07:02 -0700 Subject: arm: socfpga: soc64: Update reset manager registers for F2S bridge Add reset manager registers in preparation for F2S bridge reset support as well as the mask support to enable/disable the bridges. Mask value: BIT0: soc2fpga BIT1: lwhps2fpga BIT2: fpga2soc These bridges are available only in Stratix10: BIT3: f2sdram0 BIT4: f2sdram1 BIT5: f2sdram2 Signed-off-by: Alif Zakuan Yuslaimi Reviewed-by: Tien Fong Chee --- .../mach-socfpga/include/mach/reset_manager_soc64.h | 18 +++++++++++++++--- arch/arm/mach-socfpga/misc_soc64.c | 2 +- include/linux/intel-smc.h | 15 +++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager_soc64.h b/arch/arm/mach-socfpga/include/mach/reset_manager_soc64.h index 058fdd6e548..4b010be9ee8 100644 --- a/arch/arm/mach-socfpga/include/mach/reset_manager_soc64.h +++ b/arch/arm/mach-socfpga/include/mach/reset_manager_soc64.h @@ -10,9 +10,12 @@ void reset_deassert_peripherals_handoff(void); int cpu_has_been_warmreset(void); void print_reset_info(void); -void socfpga_bridges_reset(int enable); +void socfpga_bridges_reset(int enable, unsigned int mask); #define RSTMGR_SOC64_STATUS 0x00 +#define RSTMGR_SOC64_HDSKEN 0x10 +#define RSTMGR_SOC64_HDSKREQ 0x14 +#define RSTMGR_SOC64_HDSKACK 0x18 #define RSTMGR_SOC64_MPUMODRST 0x20 #define RSTMGR_SOC64_PER0MODRST 0x24 #define RSTMGR_SOC64_PER1MODRST 0x28 @@ -20,8 +23,17 @@ void socfpga_bridges_reset(int enable); #define RSTMGR_MPUMODRST_CORE0 0 #define RSTMGR_PER0MODRST_OCP_MASK 0x0020bf00 -#define RSTMGR_BRGMODRST_DDRSCH_MASK 0X00000040 -#define RSTMGR_BRGMODRST_FPGA2SOC_MASK 0x00000004 + +#define RSTMGR_BRGMODRST_SOC2FPGA_MASK BIT(0) +#define RSTMGR_BRGMODRST_LWSOC2FPGA_MASK BIT(1) +#define RSTMGR_BRGMODRST_FPGA2SOC_MASK BIT(2) +#define RSTMGR_BRGMODRST_F2SDRAM0_MASK BIT(3) +#define RSTMGR_BRGMODRST_F2SDRAM1_MASK BIT(4) +#define RSTMGR_BRGMODRST_F2SDRAM2_MASK BIT(5) +#define RSTMGR_BRGMODRST_DDRSCH_MASK BIT(6) + +#define RSTMGR_HDSKEN_FPGAHSEN BIT(2) +#define RSTMGR_HDSKREQ_FPGAHSREQ BIT(2) /* SDM, Watchdogs and MPU warm reset mask */ #define RSTMGR_STAT_SDMWARMRST 0x2 diff --git a/arch/arm/mach-socfpga/misc_soc64.c b/arch/arm/mach-socfpga/misc_soc64.c index e0b2b4237e1..104b24241e4 100644 --- a/arch/arm/mach-socfpga/misc_soc64.c +++ b/arch/arm/mach-socfpga/misc_soc64.c @@ -107,5 +107,5 @@ void do_bridge_reset(int enable, unsigned int mask) return; } - socfpga_bridges_reset(enable); + socfpga_bridges_reset(enable, mask); } diff --git a/include/linux/intel-smc.h b/include/linux/intel-smc.h index a54eff43add..6455335bae4 100644 --- a/include/linux/intel-smc.h +++ b/include/linux/intel-smc.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2017-2018, Intel Corporation + * Copyright (C) 2025 Altera Corporation */ #ifndef __INTEL_SMC_H @@ -482,10 +483,16 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE) * Call register usage: * a0 INTEL_SIP_SMC_HPS_SET_BRIDGES * a1 Set bridges status: - * 0 - Disable - * 1 - Enable - * a2-7 not used - * + * Bit 0: 0 - Disable, 1 - Enable + * Bit 1: 1 - Has mask value in a2 + * a2 Mask value + * Bit 0: soc2fpga + * Bit 1: lwhps2fpga + * Bit 2: fpga2soc + * Bit 3: f2sdram0 (For Stratix 10 only) + * Bit 4: f2sdram1 (For Stratix 10 only) + * Bit 5: f2sdram2 (For Stratix 10 only) + * a3-7 not used * Return status * a0 INTEL_SIP_SMC_STATUS_OK */ -- cgit v1.2.3 From cf5b58ef6ed577f07ad76ec5024060c84acef481 Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Thu, 3 Apr 2025 19:07:03 -0700 Subject: arm: socfpga: soc64: Enable F2S bridge reset support Enable reset support for FPGA2SDRAM bridge for Stratix10, as well as FPGA2SoC and SoC2FPGA bridges for all SoC64 families. Signed-off-by: Alif Zakuan Yuslaimi Reviewed-by: Tien Fong Chee --- .../mach-socfpga/include/mach/base_addr_soc64.h | 1 + arch/arm/mach-socfpga/reset_manager_s10.c | 236 +++++++++++++++++---- 2 files changed, 199 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-socfpga/include/mach/base_addr_soc64.h b/arch/arm/mach-socfpga/include/mach/base_addr_soc64.h index 65721098b2b..5ac868a281b 100644 --- a/arch/arm/mach-socfpga/include/mach/base_addr_soc64.h +++ b/arch/arm/mach-socfpga/include/mach/base_addr_soc64.h @@ -51,6 +51,7 @@ #else #define SOCFPGA_FW_MPU_DDR_SCR_ADDRESS 0xf8020100 #endif +#define SOCFPGA_F2SDRAM_MGR_ADDRESS 0xf8024000 #define SOCFPGA_SMMU_ADDRESS 0xfa000000 #define SOCFPGA_MAILBOX_ADDRESS 0xffa30000 #define SOCFPGA_UART0_ADDRESS 0xffc02000 diff --git a/arch/arm/mach-socfpga/reset_manager_s10.c b/arch/arm/mach-socfpga/reset_manager_s10.c index a634c11a028..abb62a9b49f 100644 --- a/arch/arm/mach-socfpga/reset_manager_s10.c +++ b/arch/arm/mach-socfpga/reset_manager_s10.c @@ -1,21 +1,34 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016-2018 Intel Corporation + * Copyright (C) 2025 Altera Corporation * */ +#include #include #include #include +#include #include #include #include +#include #include +#include #include #include +#include DECLARE_GLOBAL_DATA_PTR; +#define TIMEOUT_300MS 300 + +/* F2S manager registers */ +#define F2SDRAM_SIDEBAND_FLAGINSTATUS0 0x14 +#define F2SDRAM_SIDEBAND_FLAGOUTSET0 0x50 +#define F2SDRAM_SIDEBAND_FLAGOUTCLR0 0x54 + /* Assert or de-assert SoCFPGA reset manager reset. */ void socfpga_per_reset(u32 reset, int set) { @@ -56,66 +69,213 @@ void socfpga_per_reset_all(void) writel(0xffffffff, socfpga_get_rstmgr_addr() + RSTMGR_SOC64_PER1MODRST); } -void socfpga_bridges_reset(int enable) +static void socfpga_f2s_bridges_reset(int enable, unsigned int mask) { -#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF) - u64 arg = enable; + int ret; + u32 brg_mask; + u32 flagout_idlereq = 0; + u32 flagoutset_fdrain = 0; + u32 flagoutset_en = 0; + u32 flaginstatus_idleack = 0; + u32 flaginstatus_respempty = 0; + + if (CONFIG_IS_ENABLED(TARGET_SOCFPGA_STRATIX10)) { + /* Support fpga2soc and f2sdram */ + brg_mask = mask & (RSTMGR_BRGMODRST_FPGA2SOC_MASK | + RSTMGR_BRGMODRST_F2SDRAM0_MASK | + RSTMGR_BRGMODRST_F2SDRAM1_MASK | + RSTMGR_BRGMODRST_F2SDRAM2_MASK); - int ret = invoke_smc(INTEL_SIP_SMC_HPS_SET_BRIDGES, &arg, 1, NULL, 0); - if (ret) { - printf("SMC call failed with error %d in %s.\n", ret, __func__); + if (brg_mask & RSTMGR_BRGMODRST_F2SDRAM0_MASK) { + flagout_idlereq |= BIT(0); + flaginstatus_idleack |= BIT(1); + flagoutset_fdrain |= BIT(2); + flagoutset_en |= BIT(1); + flaginstatus_respempty |= BIT(3); + } + + if (brg_mask & RSTMGR_BRGMODRST_F2SDRAM1_MASK) { + flagout_idlereq |= BIT(3); + flaginstatus_idleack |= BIT(5); + flagoutset_fdrain |= BIT(5); + flagoutset_en |= BIT(4); + flaginstatus_respempty |= BIT(7); + } + + if (brg_mask & RSTMGR_BRGMODRST_F2SDRAM2_MASK) { + flagout_idlereq |= BIT(6); + flaginstatus_idleack |= BIT(9); + flagoutset_fdrain |= BIT(8); + flagoutset_en |= BIT(7); + flaginstatus_respempty |= BIT(11); + } + } else { + /* Support fpga2soc only */ + brg_mask = mask & RSTMGR_BRGMODRST_FPGA2SOC_MASK; + if (brg_mask & RSTMGR_BRGMODRST_FPGA2SOC_MASK) { + flagout_idlereq |= BIT(0); + flaginstatus_idleack |= BIT(1); + flagoutset_fdrain |= BIT(2); + flagoutset_en |= BIT(1); + flaginstatus_respempty |= BIT(3); + } + } + + /* mask is not set, return here */ + if (!brg_mask) return; + + if (enable) { + clrbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_BRGMODRST, + brg_mask); + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTCLR0, + flagout_idlereq); + + /* Wait for mpfe noc idleack to 0 */ + wait_for_bit_le32((u32 *)(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGINSTATUS0), + flaginstatus_idleack, false, TIMEOUT_300MS, false); + + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTCLR0, + flagoutset_fdrain); + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTSET0, flagoutset_en); + + udelay(1); /* wait 1us */ + } else { + if (readl((socfpga_get_rstmgr_addr() + + RSTMGR_SOC64_BRGMODRST) & brg_mask)) { + /* Bridge cannot be reset twice */ + return; + } + + setbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_HDSKEN, + RSTMGR_HDSKEN_FPGAHSEN); + setbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_HDSKREQ, + RSTMGR_HDSKREQ_FPGAHSREQ); + + /* Wait for FPGA ack the handshake request to 1 */ + wait_for_bit_le32((u32 *)(socfpga_get_rstmgr_addr() + + RSTMGR_SOC64_HDSKACK), RSTMGR_HDSKREQ_FPGAHSREQ, + true, TIMEOUT_300MS, false); + + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTCLR0, flagoutset_en); + + udelay(1); + + /* Requests MPFE NoC to idle */ + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTSET0, flagout_idlereq); + + /* Force F2S bridge to drain */ + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTSET0, flagoutset_fdrain); + + /* Wait for respond queue empty status to 1 (resp idle) */ + ret = wait_for_bit_le32((u32 *)(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGINSTATUS0), + flaginstatus_respempty, true, + TIMEOUT_300MS, false); + + /* Confirm again */ + if (!ret) + ret = wait_for_bit_le32((u32 *) + (SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGINSTATUS0), + flaginstatus_respempty, true, + TIMEOUT_300MS, false); + + setbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_BRGMODRST, + brg_mask & ~RSTMGR_BRGMODRST_FPGA2SOC_MASK); + clrbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_HDSKREQ, + RSTMGR_HDSKREQ_FPGAHSREQ); + setbits_le32(SOCFPGA_F2SDRAM_MGR_ADDRESS + + F2SDRAM_SIDEBAND_FLAGOUTCLR0, + flagout_idlereq); } -#else - u32 reg; +} + +static void socfpga_s2f_bridges_reset(int enable, unsigned int mask) +{ + unsigned int noc_mask = 0; + unsigned int brg_mask = 0; + + if (mask & RSTMGR_BRGMODRST_SOC2FPGA_MASK) { + noc_mask = SYSMGR_NOC_H2F_MSK; + brg_mask = RSTMGR_BRGMODRST_SOC2FPGA_MASK; + } + + if (mask & RSTMGR_BRGMODRST_LWSOC2FPGA_MASK) { + noc_mask |= SYSMGR_NOC_LWH2F_MSK; + brg_mask |= RSTMGR_BRGMODRST_LWSOC2FPGA_MASK; + } + + /* s2f mask is not set, return here */ + if (!brg_mask) + return; if (enable) { /* clear idle request to all bridges */ setbits_le32(socfpga_get_sysmgr_addr() + - SYSMGR_SOC64_NOC_IDLEREQ_CLR, ~0); + SYSMGR_SOC64_NOC_IDLEREQ_CLR, noc_mask); - /* Release all bridges from reset state */ + /* Release SOC2FPGA bridges from reset state */ clrbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_BRGMODRST, - ~0); + brg_mask); - /* Poll until all idleack to 0 */ - read_poll_timeout(readl, reg, !reg, 1000, 300000, - socfpga_get_sysmgr_addr() + - SYSMGR_SOC64_NOC_IDLEACK); + /* Wait for all NOC master ack to 0 */ + wait_for_bit_le32((u32 *)(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_NOC_IDLEACK), noc_mask, false, + TIMEOUT_300MS, false); } else { /* set idle request to all bridges */ - writel(~0, - socfpga_get_sysmgr_addr() + - SYSMGR_SOC64_NOC_IDLEREQ_SET); + setbits_le32(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_NOC_IDLEREQ_SET, noc_mask); /* Enable the NOC timeout */ writel(1, socfpga_get_sysmgr_addr() + SYSMGR_SOC64_NOC_TIMEOUT); - /* Poll until all idleack to 1 */ - read_poll_timeout(readl, reg, - reg == (SYSMGR_NOC_H2F_MSK | - SYSMGR_NOC_LWH2F_MSK), - 1000, 300000, - socfpga_get_sysmgr_addr() + - SYSMGR_SOC64_NOC_IDLEACK); - - /* Poll until all idlestatus to 1 */ - read_poll_timeout(readl, reg, - reg == (SYSMGR_NOC_H2F_MSK | - SYSMGR_NOC_LWH2F_MSK), - 1000, 300000, - socfpga_get_sysmgr_addr() + - SYSMGR_SOC64_NOC_IDLESTATUS); - - /* Reset all bridges (except NOR DDR scheduler & F2S) */ + /* Wait for all NOC master ack to 1 */ + wait_for_bit_le32((u32 *)(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_NOC_IDLEACK), noc_mask, true, + TIMEOUT_300MS, false); + + /* Wait for all NOC master idlestatus to 1 */ + wait_for_bit_le32((u32 *)(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_NOC_IDLESTATUS), noc_mask, true, + TIMEOUT_300MS, false); + + /* Reset all SOC2FPGA bridges */ setbits_le32(socfpga_get_rstmgr_addr() + RSTMGR_SOC64_BRGMODRST, - ~(RSTMGR_BRGMODRST_DDRSCH_MASK | - RSTMGR_BRGMODRST_FPGA2SOC_MASK)); + brg_mask); /* Disable NOC timeout */ writel(0, socfpga_get_sysmgr_addr() + SYSMGR_SOC64_NOC_TIMEOUT); } -#endif +} + +void socfpga_bridges_reset(int enable, unsigned int mask) +{ + if (!IS_ENABLED(CONFIG_XPL_BUILD) && IS_ENABLED(CONFIG_SPL_ATF)) { + u64 arg[2]; + int ret; + + /* Set bit-1 to indicate has mask value in arg[1]. */ + arg[0] = (enable & BIT(0)) | BIT(1); + arg[1] = mask; + + ret = invoke_smc(INTEL_SIP_SMC_HPS_SET_BRIDGES, arg, + ARRAY_SIZE(arg), NULL, 0); + if (ret) + printf("Failed to %s the HPS bridges, check bridges availability. Status %d.\n", + enable ? "enable" : "disable", ret); + } else { + socfpga_s2f_bridges_reset(enable, mask); + socfpga_f2s_bridges_reset(enable, mask); + } } /* -- cgit v1.2.3 From 2ab78d1dbd65c39dc92bf10344064402e0c345c4 Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Mon, 10 Mar 2025 23:38:52 -0700 Subject: arm: socfpga: spl: Notify SDM on FSBL execution Send out "HPS_STAGE_NOTIFY" mailbox command to the Secure Device Manager (SDM) in SPL to inform SDM on FSBL execution. This is necessary for the SDM to recognize that the FSBL stage has begun its execution and should be made as early as possible in the FSBL process. Therefore, the mailbox will initialize and send out the notification right after the completion of timer initialization. Signed-off-by: Mahesh Rao Signed-off-by: Alif Zakuan Yuslaimi Reviewed-by: Tien Fong Chee --- arch/arm/mach-socfpga/spl_agilex.c | 6 ++++-- arch/arm/mach-socfpga/spl_agilex5.c | 6 ++++-- arch/arm/mach-socfpga/spl_n5x.c | 6 ++++-- arch/arm/mach-socfpga/spl_s10.c | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-socfpga/spl_agilex.c b/arch/arm/mach-socfpga/spl_agilex.c index 52617a39cca..91c27a5543d 100644 --- a/arch/arm/mach-socfpga/spl_agilex.c +++ b/arch/arm/mach-socfpga/spl_agilex.c @@ -50,6 +50,10 @@ void board_init_f(ulong dummy) timer_init(); + mbox_init(); + + mbox_hps_stage_notify(HPS_EXECUTION_STATE_FSBL); + sysmgr_pinmux_init(); ret = uclass_get_device(UCLASS_CLK, 0, &dev); @@ -77,8 +81,6 @@ void board_init_f(ulong dummy) } #endif - mbox_init(); - #ifdef CONFIG_CADENCE_QSPI mbox_qspi_open(); #endif diff --git a/arch/arm/mach-socfpga/spl_agilex5.c b/arch/arm/mach-socfpga/spl_agilex5.c index 3451611082d..a9aad5350d2 100644 --- a/arch/arm/mach-socfpga/spl_agilex5.c +++ b/arch/arm/mach-socfpga/spl_agilex5.c @@ -62,6 +62,10 @@ void board_init_f(ulong dummy) timer_init(); + mbox_init(); + + mbox_hps_stage_notify(HPS_EXECUTION_STATE_FSBL); + ret = uclass_get_device(UCLASS_CLK, 0, &dev); if (ret) { debug("Clock init failed: %d\n", ret); @@ -100,8 +104,6 @@ void board_init_f(ulong dummy) } } - mbox_init(); - if (IS_ENABLED(CONFIG_CADENCE_QSPI)) mbox_qspi_open(); diff --git a/arch/arm/mach-socfpga/spl_n5x.c b/arch/arm/mach-socfpga/spl_n5x.c index 5ff137e5c6f..81283ef7162 100644 --- a/arch/arm/mach-socfpga/spl_n5x.c +++ b/arch/arm/mach-socfpga/spl_n5x.c @@ -49,6 +49,10 @@ void board_init_f(ulong dummy) timer_init(); + mbox_init(); + + mbox_hps_stage_notify(HPS_EXECUTION_STATE_FSBL); + sysmgr_pinmux_init(); preloader_console_init(); @@ -84,8 +88,6 @@ void board_init_f(ulong dummy) } #endif - mbox_init(); - #ifdef CONFIG_CADENCE_QSPI mbox_qspi_open(); #endif diff --git a/arch/arm/mach-socfpga/spl_s10.c b/arch/arm/mach-socfpga/spl_s10.c index 53852cb7443..fa83ff96adc 100644 --- a/arch/arm/mach-socfpga/spl_s10.c +++ b/arch/arm/mach-socfpga/spl_s10.c @@ -52,6 +52,10 @@ void board_init_f(ulong dummy) socfpga_per_reset(SOCFPGA_RESET(OSC1TIMER0), 0); timer_init(); + mbox_init(); + + mbox_hps_stage_notify(HPS_EXECUTION_STATE_FSBL); + sysmgr_pinmux_init(); /* configuring the HPS clocks */ @@ -84,8 +88,6 @@ void board_init_f(ulong dummy) } #endif - mbox_init(); - #ifdef CONFIG_CADENCE_QSPI mbox_qspi_open(); #endif -- cgit v1.2.3 From d13b1bbbde8f286fade80b50fd6645b869550de6 Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Mon, 17 Mar 2025 19:57:46 -0700 Subject: configs: agilex5: Enable Marvell PHY driver Enable Marvell Ethernet PHYs support for Agilex5 defconfig Signed-off-by: Alif Zakuan Yuslaimi Reviewed-by: Tien Fong Chee --- configs/socfpga_agilex5_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/socfpga_agilex5_defconfig b/configs/socfpga_agilex5_defconfig index 8f327e5f2ab..a57c866fd38 100644 --- a/configs/socfpga_agilex5_defconfig +++ b/configs/socfpga_agilex5_defconfig @@ -82,6 +82,7 @@ CONFIG_SPI_FLASH_SPANSION=y CONFIG_SPI_FLASH_STMICRO=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_SPI_FLASH_MTD=y +CONFIG_PHY_MARVELL=y CONFIG_DWC_ETH_XGMAC=y CONFIG_RGMII=y CONFIG_SYS_NS16550_MEM32=y -- cgit v1.2.3 From 1aa1022780c42e9835069b3005df60d578658b34 Mon Sep 17 00:00:00 2001 From: Naresh Kumar Ravulapalli Date: Mon, 3 Mar 2025 21:06:43 -0800 Subject: arch: arm: dts: Enable kernel itb file generation for Agilex5 SoCFPGA Load and entry addresses are corrected for Agilex5 SoCFPGA board which would enable to generate the kernel itb file with the right addresses. Signed-off-by: Naresh Kumar Ravulapalli Reviewed-by: Tien Fong Chee --- arch/arm/dts/socfpga_soc64_fit-u-boot.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/dts/socfpga_soc64_fit-u-boot.dtsi b/arch/arm/dts/socfpga_soc64_fit-u-boot.dtsi index 15306db6002..93a8e0697d6 100644 --- a/arch/arm/dts/socfpga_soc64_fit-u-boot.dtsi +++ b/arch/arm/dts/socfpga_soc64_fit-u-boot.dtsi @@ -106,8 +106,13 @@ arch = "arm64"; os = "linux"; compression = "none"; + #if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) + load = <0x86000000>; + entry = <0x86000000>; + #else load = <0x6000000>; entry = <0x6000000>; + #endif kernel_blob: blob-ext { filename = "Image"; }; -- cgit v1.2.3 From b396583c5825ed2ebcded85f585bf4f641042892 Mon Sep 17 00:00:00 2001 From: Naresh Kumar Ravulapalli Date: Mon, 3 Mar 2025 21:06:44 -0800 Subject: configs: Enable VAB flow for Agilex5 SoCFPGA boards Vendor Authorized Boot flow configurations are enabled for boards based on Agilex5 SoCFPGA. Also, required changes are made to the SoCFPGA make file for building and linking relevant secure source code files. Signed-off-by: Naresh Kumar Ravulapalli Reviewed-by: Tien Fong Chee --- MAINTAINERS | 1 + arch/arm/mach-socfpga/Makefile | 2 ++ configs/socfpga_agilex5_vab_defconfig | 3 +++ 3 files changed, 6 insertions(+) create mode 100644 configs/socfpga_agilex5_vab_defconfig diff --git a/MAINTAINERS b/MAINTAINERS index a0b06e9ee24..9d5af7ebca4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -157,6 +157,7 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-socfpga.git F: drivers/ddr/altera/ F: arch/arm/mach-socfpga/ +F: configs/socfpga_agilex5_vab_defconfig F: drivers/sysreset/sysreset_socfpga* ARM AMLOGIC SOC SUPPORT diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 22d48dfae1c..c43fdee4a48 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -68,6 +68,8 @@ obj-y += altera-sysmgr.o obj-y += ccu_ncore3.o obj-y += system_manager_soc64.o obj-y += timer_s10.o +obj-$(CONFIG_SOCFPGA_SECURE_VAB_AUTH) += secure_vab.o +obj-$(CONFIG_SOCFPGA_SECURE_VAB_AUTH) += vab.o endif ifdef CONFIG_TARGET_SOCFPGA_N5X diff --git a/configs/socfpga_agilex5_vab_defconfig b/configs/socfpga_agilex5_vab_defconfig new file mode 100644 index 00000000000..a5f4b335760 --- /dev/null +++ b/configs/socfpga_agilex5_vab_defconfig @@ -0,0 +1,3 @@ +#include + +CONFIG_SOCFPGA_SECURE_VAB_AUTH=y -- cgit v1.2.3 From 0bec32b8bd89260b87ed9e0d60298616bf64a532 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Fri, 14 Mar 2025 19:29:00 -0600 Subject: ARM: socfpga: Drop incorrect imply SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION* The use of both "imply SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION" and "imply SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE" here is wrong as those are both part of the same choice statement. Furthermore you cannot select/imply something from a choice statement, it must be a "default ... if ..." construct within the choice statement in question. Signed-off-by: Tom Rini --- arch/arm/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d8c99d3ab19..83f6cb6edcc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1171,8 +1171,6 @@ config ARCH_SOCFPGA imply SPL_DM_SPI_FLASH imply SPL_LIBDISK_SUPPORT imply SPL_MMC - imply SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION - imply SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE imply SPL_SPI_FLASH_SUPPORT imply SPL_SPI imply L2X0_CACHE -- cgit v1.2.3 From 577a60760e1e63a0976b4583c4aa060d81ccfd9e Mon Sep 17 00:00:00 2001 From: Tingting Meng Date: Tue, 15 Apr 2025 23:12:05 -0700 Subject: configs: agilex5: Restore fixed bloblist CONFIG_BLOBLIST_FIXED and CONFIG_BLOBLIST_ADDR options were unintentionally removed during recent external updates to the defconfig. This patch restores the missing entries to ensure proper board functionality. No new features are introduced. Fixes: d6a53f523afe ("spl: Add an SPL_HAVE_INIT_STACK option") Signed-off-by: Tingting Meng Reviewed-by: Tien Fong Chee --- configs/socfpga_agilex5_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/socfpga_agilex5_defconfig b/configs/socfpga_agilex5_defconfig index a57c866fd38..79c3f039030 100644 --- a/configs/socfpga_agilex5_defconfig +++ b/configs/socfpga_agilex5_defconfig @@ -31,6 +31,8 @@ CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200 initrd=0x90000000 root=/dev/ram0 rw init=/sbin/init ramdisk_size=10000000 earlycon panic=-1 nosmp kvm-arm.mode=nvhe" CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_FIXED=y +CONFIG_BLOBLIST_ADDR=0x7e000 CONFIG_BLOBLIST_SIZE=0x1000 CONFIG_SPL_MAX_SIZE=0x40000 CONFIG_HANDOFF=y -- cgit v1.2.3 From b0dbc9fcb7dfb7522be25ee205997be2fb5e1bdc Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Wed, 16 Apr 2025 01:42:12 -0700 Subject: arch: arm: dts: agilex5: Set SDIO_SEL GPIO pin as output Use GPIO hogging method in device tree to set SDIO_SEL pin (portb3) direction as output with value 0 after power-on reset. This is to ensure stable 0V voltage reading from SDIO_SEL GPIO pin after board init. Signed-off-by: Alif Zakuan Yuslaimi Reviewed-by: Tien Fong Chee --- arch/arm/dts/socfpga_agilex5-u-boot.dtsi | 11 +++++++++++ configs/socfpga_agilex5_defconfig | 3 +++ 2 files changed, 14 insertions(+) diff --git a/arch/arm/dts/socfpga_agilex5-u-boot.dtsi b/arch/arm/dts/socfpga_agilex5-u-boot.dtsi index 8d6503dd091..b34af85c58d 100644 --- a/arch/arm/dts/socfpga_agilex5-u-boot.dtsi +++ b/arch/arm/dts/socfpga_agilex5-u-boot.dtsi @@ -673,6 +673,17 @@ bootph-all; }; +&gpio1 { + /* Configure GPIO 1 pin 3 as output pin with value 0 during GPIO probe */ + portb: gpio-controller@0{ + sdio_sel { + gpio-hog; + gpios = <3 GPIO_ACTIVE_HIGH>; + output-low; + }; + }; +}; + &i2c0 { reset-names = "i2c"; }; diff --git a/configs/socfpga_agilex5_defconfig b/configs/socfpga_agilex5_defconfig index 79c3f039030..4ac0a5d9b99 100644 --- a/configs/socfpga_agilex5_defconfig +++ b/configs/socfpga_agilex5_defconfig @@ -1,6 +1,7 @@ CONFIG_ARM=y CONFIG_ARCH_SOCFPGA=y CONFIG_TEXT_BASE=0x80200000 +CONFIG_SPL_GPIO=y CONFIG_NR_DRAM_BANKS=3 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x80300000 @@ -75,6 +76,8 @@ CONFIG_BOOTFILE="kernel.itb" CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM_SEQ_ALIAS=y CONFIG_SPL_ALTERA_SDRAM=y +CONFIG_GPIO_HOG=y +CONFIG_SPL_GPIO_HOG=y CONFIG_DWAPB_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_DW=y -- cgit v1.2.3 From 3d54b52addc0c8c58a7f9aa97c6c145d773a1e0e Mon Sep 17 00:00:00 2001 From: Alif Zakuan Yuslaimi Date: Fri, 18 Apr 2025 16:21:17 +0800 Subject: arm: socfpga: soc64: Update SoC64 CPU info As of 2025, Altera is now a standalone company prior to being a subsidiary of Intel Corporation. Update CPU info printout naming from Intel to Altera. Signed-off-by: Alif Zakuan Yuslaimi --- arch/arm/mach-socfpga/misc_soc64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-socfpga/misc_soc64.c b/arch/arm/mach-socfpga/misc_soc64.c index 104b24241e4..4f080f4f0b3 100644 --- a/arch/arm/mach-socfpga/misc_soc64.c +++ b/arch/arm/mach-socfpga/misc_soc64.c @@ -61,7 +61,7 @@ void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2, #if defined(CONFIG_DISPLAY_CPUINFO) int print_cpuinfo(void) { - printf("CPU: Intel FPGA SoCFPGA Platform (ARMv8 64bit Cortex-%s)\n", + printf("CPU: Altera FPGA SoCFPGA Platform (ARMv8 64bit Cortex-%s)\n", IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) ? "A55/A76" : "A53"); return 0; -- cgit v1.2.3 From 1f8d5085e985884ae1c82254d6e1af231f9d9e8b Mon Sep 17 00:00:00 2001 From: Tingting Meng Date: Mon, 10 Mar 2025 15:29:41 +0800 Subject: arm: socfpga: agilex5: Add MMU mapping region MMU mapping regions were added for the second and third DDR memory banks. Signed-off-by: Tingting Meng --- arch/arm/mach-socfpga/mmu-arm64_s10.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/mach-socfpga/mmu-arm64_s10.c b/arch/arm/mach-socfpga/mmu-arm64_s10.c index b8e40d9a788..1dc44ab4797 100644 --- a/arch/arm/mach-socfpga/mmu-arm64_s10.c +++ b/arch/arm/mach-socfpga/mmu-arm64_s10.c @@ -57,6 +57,20 @@ static struct mm_region socfpga_agilex5_mem_map[] = { .size = 0x80000000UL, .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE, + }, { + /* MEM 30GB */ + .virt = 0x880000000UL, + .phys = 0x880000000UL, + .size = 0x780000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE, + }, { + /* MEM 480GB */ + .virt = 0x8800000000UL, + .phys = 0x8800000000UL, + .size = 0x7800000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE, }, { /* List terminator */ }, -- cgit v1.2.3 From d0bf7bebfd5c045b96686e314177b2e01d0695e3 Mon Sep 17 00:00:00 2001 From: Tingting Meng Date: Mon, 10 Mar 2025 15:31:24 +0800 Subject: arm: socfpga: socfpga_soc64: Enable LMB_ARCH_MEM_MAP LMB_ARCH_MEM_MAP is enabled, and lmb_arch_add_memory() is introduced to correctly handle memory reservations for the second and third DDR memory banks. Signed-off-by: Tingting Meng --- arch/arm/Kconfig | 1 + arch/arm/mach-socfpga/board.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 83f6cb6edcc..df373d38a55 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1138,6 +1138,7 @@ config ARCH_SOCFPGA select DM_SERIAL select GPIO_EXTRA_HEADER select ENABLE_ARM_SOC_BOOT0_HOOK if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10 + select LMB_ARCH_MEM_MAP if TARGET_SOCFPGA_SOC64 select OF_CONTROL select SPL_DM_RESET if DM_RESET select SPL_DM_SERIAL diff --git a/arch/arm/mach-socfpga/board.c b/arch/arm/mach-socfpga/board.c index 27072e53135..8506d510413 100644 --- a/arch/arm/mach-socfpga/board.c +++ b/arch/arm/mach-socfpga/board.c @@ -195,3 +195,16 @@ void board_prep_linux(struct bootm_headers *images) } } #endif + +#if CONFIG_IS_ENABLED(LMB_ARCH_MEM_MAP) +void lmb_arch_add_memory(void) +{ + int i; + struct bd_info *bd = gd->bd; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + if (bd->bi_dram[i].size) + lmb_add(bd->bi_dram[i].start, bd->bi_dram[i].size); + } +} +#endif -- cgit v1.2.3 From 52891fda68977e321043c2c4e04f6f3d55352726 Mon Sep 17 00:00:00 2001 From: Tingting Meng Date: Tue, 15 Apr 2025 09:55:35 +0800 Subject: arm: dts: agilex5: Update CCU configuration Cache allocation for dirty writes in the CCU system cache was disabled for performance optimization. Signed-off-by: Tingting Meng --- arch/arm/dts/socfpga_agilex5-u-boot.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/socfpga_agilex5-u-boot.dtsi b/arch/arm/dts/socfpga_agilex5-u-boot.dtsi index b34af85c58d..874e71b5ca4 100644 --- a/arch/arm/dts/socfpga_agilex5-u-boot.dtsi +++ b/arch/arm/dts/socfpga_agilex5-u-boot.dtsi @@ -208,7 +208,8 @@ intel,offset-settings = /* DMIUSMCTCR */ <0x00000300 0x00000001 0x00000003>, - <0x00000300 0x00000003 0x00000003>; + <0x00000300 0x00000003 0x00000003>, + <0x00000308 0x00000004 0x0000001F>; bootph-all; }; @@ -218,7 +219,8 @@ intel,offset-settings = /* DMIUSMCTCR */ <0x00000300 0x00000001 0x00000003>, - <0x00000300 0x00000003 0x00000003>; + <0x00000300 0x00000003 0x00000003>, + <0x00000308 0x00000004 0x0000001F>; bootph-all; }; }; -- cgit v1.2.3 From c42ce8d8bd2ed0d20ae12517caccda6a04d7276d Mon Sep 17 00:00:00 2001 From: Tingting Meng Date: Tue, 15 Apr 2025 14:50:51 +0800 Subject: ddr: altera: agilex5: LPDDRs in-line ECC support In-line ECC support was added for LPDDR by reserving the last one-eighth of the memory space for ECC data. Full memory initialization using the BIST MEM INIT mailbox command, based on address and size, is required to correctly generate ECC data and enable proper ECC logic verification. Signed-off-by: Tingting Meng --- arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi | 26 ++-- drivers/ddr/altera/iossm_mailbox.c | 161 +++++++++++++++++++++++-- drivers/ddr/altera/iossm_mailbox.h | 11 +- drivers/ddr/altera/sdram_agilex5.c | 19 +-- drivers/ddr/altera/sdram_soc64.c | 52 +++++--- 5 files changed, 220 insertions(+), 49 deletions(-) diff --git a/arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi b/arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi index d7ab58267eb..8d7dc0945ab 100644 --- a/arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi +++ b/arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi @@ -25,34 +25,44 @@ /* * Both Memory base address and size default info is retrieved from HW setting. * Reconfiguration / Overwrite these info can be done with examples below. - */ - /* + * + * When LPDDR ECC is enabled, the last 1/8 of the memory region must + * be reserved for the Inline ECC buffer. + * * Example for memory size with 2GB: * memory { * reg = <0x0 0x80000000 0x0 0x80000000>; * }; - */ - /* + * * Example for memory size with 8GB: * memory { * reg = <0x0 0x80000000 0x0 0x80000000>, * <0x8 0x80000000 0x1 0x80000000>; * }; - */ - /* + * * Example for memory size with 32GB: * memory { * reg = <0x0 0x80000000 0x0 0x80000000>, * <0x8 0x80000000 0x7 0x80000000>; * }; - */ - /* + * * Example for memory size with 512GB: * memory { * reg = <0x0 0x80000000 0x0 0x80000000>, * <0x8 0x80000000 0x7 0x80000000>, * <0x88 0x00000000 0x78 0x00000000>; * }; + * + * Example for memory size with 2GB with LPDDR Inline ECC ON: + * memory { + * reg = <0x0 0x80000000 0x0 0x70000000>; + * }; + * + * Example for memory size with 8GB with LPDDR Inline ECC ON: + * memory { + * reg = <0x0 0x80000000 0x0 0x80000000>, + * <0x8 0x80000000 0x1 0x40000000>; + * }; */ chosen { diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c index db9435db657..26602858777 100644 --- a/drivers/ddr/altera/iossm_mailbox.c +++ b/drivers/ddr/altera/iossm_mailbox.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "iossm_mailbox.h" #define TIMEOUT_120000MS 120000 @@ -87,6 +88,7 @@ /* offset info of ECC_ENABLE_INTF */ #define INTF_ECC_ENABLE_TYPE_MASK GENMASK(1, 0) +#define INTF_ECC_TYPE_MASK BIT(8) /* cmd opcode BIST_MEM_INIT_START, BIST performed on full memory address range */ #define BIST_FULL_MEM BIT(6) @@ -107,6 +109,10 @@ #define MAX_ECC_ERR_INFO_COUNT 16 +#define BIST_START_ADDR_SPACE_MASK GENMASK(5, 0) +#define BIST_START_ADDR_LOW_MASK GENMASK(31, 0) +#define BIST_START_ADDR_HIGH_MASK GENMASK(37, 32) + #define IO96B_MB_REQ_SETUP(v, w, x, y, z) \ usr_req.ip_type = v; \ usr_req.ip_id = w; \ @@ -512,7 +518,7 @@ int get_mem_width_info(struct io96b_info *io96b_ctrl) { int i, j, ret = 0; u32 mem_width_info; - u16 memory_size, total_memory_size = 0; + phys_size_t memory_size, total_memory_size = 0; u32 mem_total_capacity_intf_offset[MAX_MEM_INTERFACE_SUPPORTED] = { IOSSM_MEM_TOTAL_CAPACITY_INTF0_OFFSET, @@ -526,8 +532,11 @@ int get_mem_width_info(struct io96b_info *io96b_ctrl) mem_width_info = readl(io96b_ctrl->io96b[i].io96b_csr_addr + mem_total_capacity_intf_offset[j]); - memory_size = memory_size + - FIELD_GET(INTF_CAPACITY_GBITS_MASK, mem_width_info); + io96b_ctrl->io96b[i].mb_ctrl.memory_size[j] = + FIELD_GET(INTF_CAPACITY_GBITS_MASK, mem_width_info) * SZ_1G / SZ_8; + + if (io96b_ctrl->io96b[i].mb_ctrl.memory_size[j] != 0) + memory_size += io96b_ctrl->io96b[i].mb_ctrl.memory_size[j]; } if (!memory_size) { @@ -536,8 +545,6 @@ int get_mem_width_info(struct io96b_info *io96b_ctrl) goto err; } - io96b_ctrl->io96b[i].size = memory_size; - total_memory_size = total_memory_size + memory_size; } @@ -556,7 +563,7 @@ int ecc_enable_status(struct io96b_info *io96b_ctrl) { int i, j, ret = 0; u32 ecc_enable_intf; - bool ecc_stat, ecc_stat_set = false; + bool ecc_status, ecc_status_set = false, inline_ecc = false; u32 ecc_enable_intf_offset[MAX_MEM_INTERFACE_SUPPORTED] = { IOSSM_ECC_ENABLE_INTF0_OFFSET, @@ -565,6 +572,7 @@ int ecc_enable_status(struct io96b_info *io96b_ctrl) /* Initialize ECC status */ io96b_ctrl->ecc_status = false; + io96b_ctrl->inline_ecc = false; /* Get and ensure all memory interface(s) same ECC status */ for (i = 0; i < io96b_ctrl->num_instance; i++) { @@ -572,15 +580,21 @@ int ecc_enable_status(struct io96b_info *io96b_ctrl) ecc_enable_intf = readl(io96b_ctrl->io96b[i].io96b_csr_addr + ecc_enable_intf_offset[j]); - ecc_stat = (FIELD_GET(INTF_ECC_ENABLE_TYPE_MASK, ecc_enable_intf) + ecc_status = (FIELD_GET(INTF_ECC_ENABLE_TYPE_MASK, ecc_enable_intf) == 0) ? false : true; + inline_ecc = FIELD_GET(INTF_ECC_TYPE_MASK, ecc_enable_intf); + + if (!ecc_status_set) { + io96b_ctrl->ecc_status = ecc_status; - if (!ecc_stat_set) { - io96b_ctrl->ecc_status = ecc_stat; - ecc_stat_set = true; + if (io96b_ctrl->ecc_status) + io96b_ctrl->inline_ecc = inline_ecc; + + ecc_status_set = true; } - if (ecc_stat != io96b_ctrl->ecc_status) { + if (ecc_status != io96b_ctrl->ecc_status || + (io96b_ctrl->ecc_status && inline_ecc != io96b_ctrl->inline_ecc)) { printf("%s: Mismatch DDR ECC status on IO96B_%d\n", __func__, i); ret = -EINVAL; @@ -673,7 +687,7 @@ bool ecc_interrupt_status(struct io96b_info *io96b_ctrl) return ecc_error_flag; } -int bist_mem_init_start(struct io96b_info *io96b_ctrl) +int out_of_band_bist_mem_init_start(struct io96b_info *io96b_ctrl) { struct io96b_mb_req usr_req; struct io96b_mb_resp usr_resp; @@ -746,3 +760,126 @@ int bist_mem_init_start(struct io96b_info *io96b_ctrl) err: return ret; } + +int bist_mem_init_by_addr(struct io96b_info *io96b_ctrl, int inst_id, int intf_id, + phys_addr_t base_addr, phys_size_t size) +{ + struct io96b_mb_req usr_req; + struct io96b_mb_resp usr_resp; + int n, ret = 0; + bool bist_start, bist_success; + u32 mem_exp, mem_init_status_intf, start; + phys_size_t chunk_size; + + u32 mem_init_status_offset[MAX_MEM_INTERFACE_SUPPORTED] = { + IOSSM_MEM_INIT_STATUS_INTF0_OFFSET, + IOSSM_MEM_INIT_STATUS_INTF1_OFFSET + }; + + /* Check if size is a power of 2 */ + if (size == 0 || (size & (size - 1)) != 0) { + ret = -EINVAL; + goto err; + } + + mem_exp = 0; + chunk_size = size; + + while (chunk_size >>= 1) + mem_exp++; + + /* Start memory initialization BIST on the specified address range */ + IO96B_MB_REQ_SETUP(io96b_ctrl->io96b[inst_id].mb_ctrl.ip_type[intf_id], + io96b_ctrl->io96b[inst_id].mb_ctrl.ip_id[intf_id], + CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0); + + /* CMD_PARAM_0 bit[5:0] = mem_exp */ + /* CMD_PARAM_0 bit[6]: 0 - on the specified address range */ + usr_req.cmd_param[0] = FIELD_PREP(BIST_START_ADDR_SPACE_MASK, mem_exp); + /* Extract address fields START_ADDR[31:0] */ + usr_req.cmd_param[1] = FIELD_GET(BIST_START_ADDR_LOW_MASK, base_addr); + /* Extract address fields START_ADDR[37:32] */ + usr_req.cmd_param[2] = FIELD_GET(BIST_START_ADDR_HIGH_MASK, base_addr); + /* Initialize memory to all zeros */ + usr_req.cmd_param[3] = 0; + + bist_start = false; + bist_success = false; + + /* Send request to DDR controller */ + debug("%s:Initializing memory: Addr=0x%llx, Size=2^%u\n", __func__, + base_addr, mem_exp); + ret = io96b_mb_req(io96b_ctrl->io96b[inst_id].io96b_csr_addr, + usr_req, 0, &usr_resp); + if (ret) + goto err; + + bist_start = IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) + & BIT(0); + + if (!bist_start) { + printf("%s: Failed to initialize memory on IO96B_%d\n", __func__, + inst_id); + printf("%s: BIST_MEM_INIT_START Error code 0x%lx\n", __func__, + IOSSM_STATUS_CMD_RESPONSE_ERROR(usr_resp.cmd_resp_status)); + + ret = -EINVAL; + goto err; + } + + /* Polling for the initiated memory initialization BIST status */ + start = get_timer(0); + while (!bist_success) { + udelay(1); + + mem_init_status_intf = readl(io96b_ctrl->io96b[inst_id].io96b_csr_addr + + mem_init_status_offset[intf_id]); + + bist_success = FIELD_GET(INTF_BIST_STATUS_MASK, mem_init_status_intf); + + if (!bist_success && (get_timer(start) > TIMEOUT)) { + printf("%s: Timeout initialize memory on IO96B_%d\n", + __func__, inst_id); + printf("%s: BIST_MEM_INIT_STATUS Error code 0x%lx\n", + __func__, + IOSSM_STATUS_CMD_RESPONSE_ERROR(usr_resp.cmd_resp_status)); + + ret = -ETIMEDOUT; + goto err; + } + } + + debug("%s:DDR memory initializationat 0x%llx completed.\n", __func__, base_addr); + +err: + return ret; +} + +int inline_ecc_bist_mem_init(struct io96b_info *io96b_ctrl) +{ + int i, j, ret = 0; + + /* Memory initialization BIST performed on all memory interfaces */ + for (i = 0; i < io96b_ctrl->num_instance; i++) { + for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) { + ret = bist_mem_init_by_addr(io96b_ctrl, i, j, 0, + io96b_ctrl->io96b[i].mb_ctrl.memory_size[j]); + if (ret) { + printf("Error: Memory init failed at Instance %d, Interface %d\n", + i, j); + goto err; + } + } + } + +err: + return ret; +} + +int bist_mem_init_start(struct io96b_info *io96b_ctrl) +{ + if (io96b_ctrl->inline_ecc) + return inline_ecc_bist_mem_init(io96b_ctrl); + else + return out_of_band_bist_mem_init_start(io96b_ctrl); +} diff --git a/drivers/ddr/altera/iossm_mailbox.h b/drivers/ddr/altera/iossm_mailbox.h index 6f794781d30..02d1db28e20 100644 --- a/drivers/ddr/altera/iossm_mailbox.h +++ b/drivers/ddr/altera/iossm_mailbox.h @@ -40,11 +40,13 @@ enum iossm_mailbox_cmd_opcode { * @num_mem_interface: Number of memory interfaces instantiated * @ip_type: IP type implemented on the IO96B * @ip_instance_id: IP identifier for every IP instance implemented on the IO96B + * @memory_size[2]: Memory size for every IP instance implemented on the IO96B */ struct io96b_mb_ctrl { u32 num_mem_interface; u32 ip_type[2]; u32 ip_id[2]; + phys_size_t memory_size[2]; }; /* CMD_REQ Register Definition */ @@ -53,6 +55,9 @@ struct io96b_mb_ctrl { #define CMD_TYPE_MASK GENMASK(23, 16) #define CMD_OPCODE_MASK GENMASK(15, 0) +/* Computes the Inline ECC data region size */ +#define CALC_INLINE_ECC_HW_SIZE(size) (((size) * 7) / 8) + /* * IOSSM mailbox request * @ip_type: IP type for the specified memory interface @@ -83,13 +88,11 @@ struct io96b_mb_resp { /* * IO96B instance specific information * - * @size: Memory size * @io96b_csr_addr: IO96B instance CSR address * @cal_status: IO96B instance calibration status * @mb_ctrl: IOSSM mailbox required information */ struct io96b_instance { - u16 size; phys_addr_t io96b_csr_addr; bool cal_status; struct io96b_mb_ctrl mb_ctrl; @@ -102,6 +105,7 @@ struct io96b_instance { * @overall_cal_status: Overall calibration status for all IO96B instance(s) * @ddr_type: DDR memory type * @ecc_status: ECC enable status (false = disabled, true = enabled) + * @inline_ecc: Inline ECC or Out of Band ECC (false = Out of Band ECC, true = Inline ECC) * @overall_size: Total DDR memory size * @io96b[]: IO96B instance specific information * @ckgen_lock: IO96B GEN PLL lock (false = not locked, true = locked) @@ -115,7 +119,8 @@ struct io96b_info { bool overall_cal_status; const char *ddr_type; bool ecc_status; - u16 overall_size; + bool inline_ecc; + phys_size_t overall_size; struct io96b_instance io96b[MAX_IO96B_SUPPORTED]; bool ckgen_lock; u8 num_port; diff --git a/drivers/ddr/altera/sdram_agilex5.c b/drivers/ddr/altera/sdram_agilex5.c index 801a6bbab46..ee66c72157a 100644 --- a/drivers/ddr/altera/sdram_agilex5.c +++ b/drivers/ddr/altera/sdram_agilex5.c @@ -291,7 +291,14 @@ int sdram_mmr_init_full(struct udevice *dev) goto err; } - hw_size = (phys_size_t)io96b_ctrl->overall_size * SZ_1G / SZ_8; + ret = ecc_enable_status(io96b_ctrl); + if (ret) { + printf("DDR: Failed to get ECC enabled status\n"); + + goto err; + } + + hw_size = io96b_ctrl->overall_size; /* Get bank configuration from devicetree */ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, @@ -303,6 +310,9 @@ int sdram_mmr_init_full(struct udevice *dev) goto err; } + if (io96b_ctrl->inline_ecc) + hw_size = CALC_INLINE_ECC_HW_SIZE(hw_size); + if (gd->ram_size > hw_size) { printf("DDR: Warning: DRAM size from device tree (%lld MiB) exceeds\n", gd->ram_size >> 20); @@ -355,13 +365,6 @@ int sdram_mmr_init_full(struct udevice *dev) printf("%s: %lld MiB\n", io96b_ctrl->ddr_type, gd->ram_size >> 20); - ret = ecc_enable_status(io96b_ctrl); - if (ret) { - printf("DDR: Failed to get ECC enabled status\n"); - - goto err; - } - /* Is HPS cold or warm reset? If yes, Skip full memory initialization if ECC * enabled to preserve memory content */ diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index 75c6de1e4ec..27fbe80ed41 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -185,35 +185,51 @@ void sdram_init_ecc_bits(struct bd_info *bd) void sdram_size_check(struct bd_info *bd) { phys_size_t total_ram_check = 0; - phys_size_t ram_check = 0; - phys_addr_t start = 0; - phys_size_t size, remaining_size; int bank; /* Sanity check ensure correct SDRAM size specified */ debug("DDR: Running SDRAM size sanity check\n"); for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + phys_size_t ram_check = 0; + phys_addr_t start = 0; + phys_size_t remaining_size; + start = bd->bi_dram[bank].start; remaining_size = bd->bi_dram[bank].size; + debug("Checking bank %d: start=0x%llx, size=0x%llx\n", + bank, start, remaining_size); + while (ram_check < bd->bi_dram[bank].size) { - size = min((phys_addr_t)SZ_1G, - (phys_addr_t)remaining_size); - - /* - * Ensure the size is power of two, this is requirement - * to run get_ram_size() / memory test - */ - if (size != 0 && ((size & (size - 1)) == 0)) { - ram_check += get_ram_size((void *) - (start + ram_check), size); - remaining_size = bd->bi_dram[bank].size - - ram_check; - } else { - puts("DDR: Memory test requires SDRAM size "); - puts("in power of two!\n"); + phys_size_t size, test_size, detected_size; + + size = min((phys_addr_t)SZ_1G, (phys_addr_t)remaining_size); + + if (size < SZ_8) { + puts("Invalid size: Memory size required to be multiple\n"); + puts("of 64-Bit word!\n"); hang(); } + + /* Adjust size to the nearest power of two to support get_ram_size() */ + test_size = SZ_8; + + while (test_size * 2 <= size) + test_size *= 2; + + debug("Testing memory at 0x%llx with size 0x%llx\n", + start + ram_check, test_size); + detected_size = get_ram_size((void *)(start + ram_check), test_size); + + if (detected_size != test_size) { + debug("Detected size 0x%llx doesn’t match the test size 0x%llx!\n", + detected_size, test_size); + puts("Memory testing failed!\n"); + hang(); + } + + ram_check += detected_size; + remaining_size = bd->bi_dram[bank].size - ram_check; } total_ram_check += ram_check; -- cgit v1.2.3 From 0415429935d7e19595d2997ee08415d0d8052d4d Mon Sep 17 00:00:00 2001 From: Tingting Meng Date: Mon, 7 Apr 2025 10:47:24 +0800 Subject: ddr: altera: iossm: Enhance debug information for ECC errors ECC debug information was enhanced to improve the readability of error messages. Signed-off-by: Tingting Meng --- drivers/ddr/altera/iossm_mailbox.c | 64 ++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c index 26602858777..fc09dde3f9e 100644 --- a/drivers/ddr/altera/iossm_mailbox.c +++ b/drivers/ddr/altera/iossm_mailbox.c @@ -98,6 +98,7 @@ /* offset info of ECC_ERR_STATUS */ #define ECC_ERR_COUNTER_MASK GENMASK(15, 0) +#define ECC_ERR_OVERFLOW_MASK GENMASK(31, 16) /* offset info of ECC_ERR_DATA */ #define ECC_ERR_IP_TYPE_MASK GENMASK(24, 22) @@ -106,6 +107,8 @@ #define ECC_ERR_TYPE_MASK GENMASK(9, 6) #define ECC_ERR_ADDR_UPPER_MASK GENMASK(5, 0) #define ECC_ERR_ADDR_LOWER_MASK GENMASK(31, 0) +#define ECC_FULL_ADDR_UPPER_MASK GENMASK(63, 32) +#define ECC_FULL_ADDR_LOWER_MASK GENMASK(31, 0) #define MAX_ECC_ERR_INFO_COUNT 16 @@ -167,6 +170,24 @@ struct ecc_err_info { u32 addr_lower; }; +struct ecc_overflow_error_desc { + int bit; + const char *msg; +}; + +static const struct ecc_overflow_error_desc ecc_overflow_errors[] = { + { 0, " - Single-bit error\n" }, + { 1, " - Multiple single-bit errors\n" }, + { 2, " - Double-bit error\n" }, + { 3, " - Multiple double-bit errors\n" }, + { 8, " - Single-bit error during ECC scrubbing\n" }, + { 9, " - Write link ECC single-bit error (LPDDR5 only)\n" }, + { 10, " - Write link ECC double-bit error (LPDDR5 only)\n" }, + { 11, " - Read link ECC single-bit error (LPDDR5 only)\n" }, + { 12, " - Read link ECC double-bit error (LPDDR5 only)\n" }, + { 13, " - RMW read link ECC double-bit error (LPDDR5 only)\n" }, +}; + static int is_ddr_csr_clkgen_locked(u8 io96b_pll) { int ret = 0; @@ -628,16 +649,28 @@ bool ecc_interrupt_status(struct io96b_info *io96b_ctrl) { int i, j; u32 ecc_err_status; - u16 ecc_err_counter; + u16 ecc_err_counter, ecc_overflow_status; bool ecc_error_flag = false; /* Get ECC double-bit error status */ for (i = 0; i < io96b_ctrl->num_instance; i++) { ecc_err_status = readl(io96b_ctrl->io96b[i].io96b_csr_addr + IOSSM_ECC_ERR_STATUS_OFFSET); + ecc_err_counter = FIELD_GET(ECC_ERR_COUNTER_MASK, ecc_err_status); - debug("%s: ECC error number detected on IO96B_%d: %d\n", - __func__, i, ecc_err_counter); + log_err("%s: ECC error number detected on IO96B_%d: %d\n", + __func__, i, ecc_err_counter); + + ecc_overflow_status = FIELD_GET(ECC_ERR_OVERFLOW_MASK, ecc_err_status); + if (ecc_overflow_status != 0) { + log_err("ECC Error Overflow Flags:\n"); + + for (int i = 0; i < ARRAY_SIZE(ecc_overflow_errors); i++) { + if (ecc_overflow_status & BIT(ecc_overflow_errors[i].bit)) { + log_err("%s", ecc_overflow_errors[i].msg); + } + } + } if (ecc_err_counter != 0) { phys_addr_t address; @@ -661,15 +694,20 @@ bool ecc_interrupt_status(struct io96b_info *io96b_ctrl) ecc_err_data); err_info.addr_lower = readl(address + sizeof(u32)); - debug("%s: ECC double-bit error detected on IO96B_%d:\n", - __func__, i); - debug("- error info address :0x%llx\n", address); - debug("- error ip type: %d\n", err_info.ip_type); - debug("- error instance id: %d\n", err_info.instance_id); - debug("- error source id: %d\n", err_info.source_id); - debug("- error type: %d\n", err_info.err_type); - debug("- error address upper: 0x%x\n", err_info.addr_upper); - debug("- error address lower: 0x%x\n", err_info.addr_lower); + log_err(" %s: DDR ECC Error Detected on IO96B_%d number:%d\n", + __func__, i, j); + log_err(" - error info address :0x%llx\n", address); + log_err(" - error ip type: %d\n", err_info.ip_type); + log_err(" - error instance id: %d\n", err_info.instance_id); + log_err(" - error source id: %d\n", err_info.source_id); + log_err(" - error type: %s\n", + is_double_bit_error(err_info.err_type) ? + "Double-bit error" : "Single-bit error"); + log_err(" - error address: 0x%016llx\n", + (u64)FIELD_PREP(ECC_FULL_ADDR_UPPER_MASK, + err_info.addr_upper) | + FIELD_PREP(ECC_FULL_ADDR_LOWER_MASK, + err_info.addr_lower)); if (is_double_bit_error(err_info.err_type)) { if (!ecc_error_flag) @@ -682,7 +720,7 @@ bool ecc_interrupt_status(struct io96b_info *io96b_ctrl) } if (ecc_error_flag) - printf("\n%s: ECC double-bit error detected!\n", __func__); + log_err("\n%s: ECC double-bit error detected!\n", __func__); return ecc_error_flag; } -- cgit v1.2.3