summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/altera/Makefile1
-rw-r--r--drivers/clk/altera/clk-agilex.c37
-rw-r--r--drivers/clk/altera/clk-agilex.h2
-rw-r--r--drivers/ddr/altera/Makefile1
-rw-r--r--drivers/ddr/altera/sdram_agilex.c34
-rw-r--r--drivers/ddr/altera/sdram_agilex7m.c500
-rw-r--r--drivers/ddr/altera/sdram_soc64.c21
-rw-r--r--drivers/ddr/altera/sdram_soc64.h82
-rw-r--r--drivers/ddr/altera/uibssm_mailbox.c321
-rw-r--r--drivers/ddr/altera/uibssm_mailbox.h116
-rw-r--r--drivers/net/dwc_eth_xgmac.c2
-rw-r--r--drivers/net/dwc_eth_xgmac_socfpga.c8
-rw-r--r--drivers/sysreset/sysreset_socfpga_soc64.c63
-rw-r--r--drivers/watchdog/Kconfig2
14 files changed, 1123 insertions, 67 deletions
diff --git a/drivers/clk/altera/Makefile b/drivers/clk/altera/Makefile
index 61ffa4179a0..858f828e537 100644
--- a/drivers/clk/altera/Makefile
+++ b/drivers/clk/altera/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += clk-agilex.o
+obj-$(CONFIG_TARGET_SOCFPGA_AGILEX7M) += clk-agilex.o
obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += clk-arria10.o
obj-$(CONFIG_TARGET_SOCFPGA_N5X) += clk-n5x.o
obj-$(CONFIG_TARGET_SOCFPGA_N5X) += clk-mem-n5x.o
diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c
index e1ddd02f356..242740a4b00 100644
--- a/drivers/clk/altera/clk-agilex.c
+++ b/drivers/clk/altera/clk-agilex.c
@@ -1,11 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
*/
#include <log.h>
+#include <wait_bit.h>
#include <asm/global_data.h>
#include <asm/io.h>
+#include <asm/system.h>
#include <clk-uclass.h>
#include <dm.h>
#include <dm/lists.h>
@@ -27,21 +30,33 @@ struct socfpga_clk_plat {
*/
static void clk_write_bypass_mainpll(struct socfpga_clk_plat *plat, u32 val)
{
+ void __iomem *base = plat->regs;
+
CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_BYPASS);
- cm_wait_for_fsm();
+
+ wait_for_bit_le32(base + CLKMGR_STAT,
+ CLKMGR_STAT_BUSY, false, 20000, false);
}
static void clk_write_bypass_perpll(struct socfpga_clk_plat *plat, u32 val)
{
+ void __iomem *base = plat->regs;
+
CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_BYPASS);
- cm_wait_for_fsm();
+
+ wait_for_bit_le32(base + CLKMGR_STAT,
+ CLKMGR_STAT_BUSY, false, 20000, false);
}
/* function to write the ctrl register which requires a poll of the busy bit */
static void clk_write_ctrl(struct socfpga_clk_plat *plat, u32 val)
{
+ void __iomem *base = plat->regs;
+
CM_REG_WRITEL(plat, val, CLKMGR_CTRL);
- cm_wait_for_fsm();
+
+ wait_for_bit_le32(base + CLKMGR_STAT,
+ CLKMGR_STAT_BUSY, false, 20000, false);
}
#define MEMBUS_MAINPLL 0
@@ -238,6 +253,7 @@ static void clk_basic_init(struct udevice *dev,
{
struct socfpga_clk_plat *plat = dev_get_plat(dev);
u32 vcocalib;
+ uintptr_t base_addr = (uintptr_t)plat->regs;
if (!cfg)
return;
@@ -302,7 +318,8 @@ static void clk_basic_init(struct udevice *dev,
/* Membus programming for peripll */
membus_pll_configs(plat, MEMBUS_PERPLL);
- cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK);
+ wait_for_bit_le32((const void *)(base_addr + CLKMGR_STAT),
+ CLKMGR_STAT_ALLPLL_LOCKED_MASK, true, 20000, false);
/* Configure ping pong counters in altera group */
CM_REG_WRITEL(plat, cfg->alt_emacactr, CLKMGR_ALTR_EMACACTR);
@@ -337,6 +354,18 @@ static void clk_basic_init(struct udevice *dev,
CM_REG_CLRBITS(plat, CLKMGR_ALTR_EXTCNTRST,
CLKMGR_ALT_EXTCNTRST_ALLCNTRST);
+#ifdef COUNTER_FREQUENCY_REAL
+ u32 cntfrq = COUNTER_FREQUENCY_REAL;
+ u32 counter_freq = 0;
+
+ /* Update with accurate clock frequency */
+ if (current_el() == 3) {
+ asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (counter_freq));
+ debug("Counter freq = 0x%x\n", counter_freq);
+ }
+#endif
+
/* Out of boot mode */
clk_write_ctrl(plat,
CM_REG_READL(plat, CLKMGR_CTRL) & ~CLKMGR_CTRL_BOOTMODE);
diff --git a/drivers/clk/altera/clk-agilex.h b/drivers/clk/altera/clk-agilex.h
index cd68ebc4387..b3e8841a512 100644
--- a/drivers/clk/altera/clk-agilex.h
+++ b/drivers/clk/altera/clk-agilex.h
@@ -10,6 +10,8 @@
#include <linux/bitops.h>
#endif
+#define COUNTER_FREQUENCY_REAL 400000000
+
#define CM_REG_READL(plat, reg) \
readl((plat)->regs + (reg))
diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
index c627f16711e..7ed43965be5 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o
obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += sdram_soc64.o sdram_agilex.o
obj-$(CONFIG_TARGET_SOCFPGA_N5X) += sdram_soc64.o sdram_n5x.o
obj-$(CONFIG_TARGET_SOCFPGA_AGILEX5) += sdram_soc64.o sdram_agilex5.o iossm_mailbox.o
+obj-$(CONFIG_TARGET_SOCFPGA_AGILEX7M) += sdram_soc64.o sdram_agilex7m.o iossm_mailbox.o uibssm_mailbox.o
endif
diff --git a/drivers/ddr/altera/sdram_agilex.c b/drivers/ddr/altera/sdram_agilex.c
index 7f2cccb6af2..b36a765a5de 100644
--- a/drivers/ddr/altera/sdram_agilex.c
+++ b/drivers/ddr/altera/sdram_agilex.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
*
*/
@@ -72,12 +73,22 @@ int sdram_mmr_init_full(struct udevice *dev)
*/
/* Configure DDR IO size x16, x32 and x64 mode */
u32 update_value;
+ u32 reg;
update_value = hmc_readl(plat, NIOSRESERVED0);
update_value = (update_value & 0xFF) >> 5;
- /* Configure DDR data rate 0-HAlf-rate 1-Quarter-rate */
- update_value |= (hmc_readl(plat, CTRLCFG3) & 0x4);
+ /* Read ACF from boot_scratch_cold_8 register bit[18]*/
+ reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD8);
+ reg = ((reg & SYSMGR_SCRATCH_REG_8_ACF_DDR_RATE_MASK)
+ >> SYSMGR_SCRATCH_REG_8_ACF_DDR_RATE_SHIFT);
+
+ /* bit-2 of DDRIOCTRL: Configure DDR data rate 0-Half-rate 1-Quarter-rate */
+ clrsetbits_le32(&update_value,
+ DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_MSK,
+ reg << DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_SHIFT);
+
hmc_ecc_writel(plat, update_value, DDRIOCTRL);
/* Copy values MMR IOHMC dramaddrw to HMC adp DRAMADDRWIDTH */
@@ -114,20 +125,6 @@ int sdram_mmr_init_full(struct udevice *dev)
printf("DDR: %lld MiB\n", gd->ram_size >> 20);
- /* This enables nonsecure access to DDR */
- /* mpuregion0addr_limit */
- FW_MPU_DDR_SCR_WRITEL(gd->ram_size - 1,
- FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT);
- FW_MPU_DDR_SCR_WRITEL(0x1F, FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT);
-
- /* nonmpuregion0addr_limit */
- FW_MPU_DDR_SCR_WRITEL(gd->ram_size - 1,
- FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT);
-
- /* Enable mpuregion0enable and nonmpuregion0enable */
- FW_MPU_DDR_SCR_WRITEL(MPUREGION0_ENABLE | NONMPUREGION0_ENABLE,
- FW_MPU_DDR_SCR_EN_SET);
-
u32 ctrlcfg1 = hmc_readl(plat, CTRLCFG1);
/* Enable or disable the DDR ECC */
@@ -157,11 +154,10 @@ int sdram_mmr_init_full(struct udevice *dev)
DDR_HMC_ECCCTL2_AWB_EN_SET_MSK));
}
- /* Enable non-secure reads/writes to HMC Adapter for SDRAM ECC */
- writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR);
-
sdram_size_check(&bd);
+ sdram_set_firewall(&bd);
+
priv->info.base = bd.bi_dram[0].start;
priv->info.size = gd->ram_size;
diff --git a/drivers/ddr/altera/sdram_agilex7m.c b/drivers/ddr/altera/sdram_agilex7m.c
new file mode 100644
index 00000000000..9b3cc5c7b86
--- /dev/null
+++ b/drivers/ddr/altera/sdram_agilex7m.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#include <dm.h>
+#include <hang.h>
+#include <log.h>
+#include <ram.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <wdt.h>
+#include <asm/arch/system_manager.h>
+#include <linux/bitfield.h>
+#include "iossm_mailbox.h"
+#include "sdram_soc64.h"
+#include "uibssm_mailbox.h"
+
+/* NOCPLL register */
+#define SYSMGR_HMC_CLK 0xB4
+#define SYSMGR_HMC_CLK_NOCPLL BIT(8)
+
+/* MPFE NOC registers */
+#define F2SDRAM_SIDEBAND_FLAGOUTSET0 0x50
+#define F2SDRAM_SIDEBAND_FLAGOUTSTATUS0 0x58
+#define SIDEBANDMGR_FLAGOUTSET0_REG SOCFPGA_F2SDRAM_MGR_ADDRESS +\
+ F2SDRAM_SIDEBAND_FLAGOUTSET0
+#define SIDEBANDMGR_FLAGOUTSTATUS0_REG SOCFPGA_F2SDRAM_MGR_ADDRESS +\
+ F2SDRAM_SIDEBAND_FLAGOUTSTATUS0
+
+#define SIDEBANDMGR_FLAGOUTSET0_REG_MULTICHANNEL BIT(4)
+#define SIDEBANDMGR_FLAGOUTSET0_REG_INTERLEAVING BIT(5)
+
+/* Reset type */
+enum reset_type {
+ POR_RESET,
+ WARM_RESET,
+ COLD_RESET,
+ NCONFIG,
+ JTAG_CONFIG,
+ RSU_RECONFIG
+};
+
+phys_addr_t io96b_csr_reg_addr[] = {
+ 0xf8400000, /* IO96B_0 CSR registers address */
+ 0xf8800000 /* IO96B_1 CSR registers address */
+};
+
+phys_addr_t uib_csr_reg_addr[] = {
+ 0xf8400000, /* UIB_0 CSR registers address */
+ 0xf8410000, /* UIB_1 CSR registers address */
+ 0xf8420000, /* UIB_2 CSR registers address */
+ 0xf8430000, /* UIB_3 CSR registers address */
+ 0xf8440000, /* UIB_4 CSR registers address */
+ 0xf8450000, /* UIB_5 CSR registers address */
+ 0xf8460000, /* UIB_6 CSR registers address */
+ 0xf8470000 /* UIB_7 CSR registers address */
+};
+
+static enum reset_type get_reset_type(u32 reg)
+{
+ return FIELD_GET(ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK, reg);
+}
+
+bool is_ddr_init_hang(void)
+{
+ u32 reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD8);
+
+ debug("%s: 0x%x\n", __func__, reg);
+
+ if (reg & ALT_SYSMGR_SCRATCH_REG_8_DDR_PROGRESS_MASK)
+ return true;
+
+ return false;
+}
+
+void ddr_init_inprogress(bool start)
+{
+ if (start)
+ setbits_le32(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD8,
+ ALT_SYSMGR_SCRATCH_REG_8_DDR_PROGRESS_MASK);
+ else
+ clrbits_le32(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD8,
+ ALT_SYSMGR_SCRATCH_REG_8_DDR_PROGRESS_MASK);
+}
+
+static const char *memory_type_in_use(struct udevice *dev)
+{
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+
+ return (plat->mem_type == DDR_MEMORY ? "DDR" : "HBM");
+}
+
+static bool is_ddr_in_use(struct udevice *dev)
+{
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+
+ return (plat->mem_type == DDR_MEMORY ? true : false);
+}
+
+int populate_ddr_handoff(struct udevice *dev, struct io96b_info *io96b_ctrl,
+ struct uib_info *uib_ctrl)
+{
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+ int i;
+ u8 count = 0;
+ u32 len = SOC64_HANDOFF_DDR_LEN;
+ u32 handoff_table[len];
+
+ /* Read handoff for DDR configuration */
+ socfpga_handoff_read((void *)SOC64_HANDOFF_DDR_BASE, handoff_table, len);
+
+ /* Interleaving Mode */
+ if (handoff_table[0] & SOC64_HANDOFF_DDR_INTERLEAVING_MODE_MASK)
+ plat->multichannel_interleaving = true;
+ else
+ plat->multichannel_interleaving = false;
+
+ debug("%s: MPFE-EMIF is in %s mode\n", __func__,
+ plat->multichannel_interleaving ? "interleaving" : "multichannel");
+
+ /* Memory type */
+ if (handoff_table[2] & SOC64_HANDOFF_DDR_MEMORY_TYPE_MASK)
+ plat->mem_type = HBM_MEMORY;
+ else
+ plat->mem_type = DDR_MEMORY;
+
+ debug("%s: Memory type is %s\n", __func__
+ , plat->mem_type ? "HBM" : "DDR");
+
+ if (plat->mem_type == HBM_MEMORY) {
+ /* Assign UIB CSR base address if it is valid */
+ for (i = 0; i < MAX_UIB_SUPPORTED; i++) {
+ if (handoff_table[3] & BIT(i)) {
+ uib_ctrl->uib[count].uib_csr_addr = uib_csr_reg_addr[i];
+ debug("%s: UIB 0x%llx CSR enabled\n", __func__
+ , uib_ctrl->uib[count].uib_csr_addr);
+ count++;
+ }
+ }
+
+ uib_ctrl->num_instance = count;
+ debug("%s: returned num_instance 0x%x\n", __func__, uib_ctrl->num_instance);
+
+ /*
+ * HBM memory size
+ * 1 UIB channel has 2 pseudo channels
+ * 1 pseudo channel is 1GB, hence 1 UIB channel is 2GB
+ */
+ uib_ctrl->overall_size = (phys_size_t)uib_ctrl->num_instance * SZ_2G;
+
+ /* UIB ECC status */
+ uib_ctrl->ecc_status = handoff_table[4];
+
+ debug("%s: ECC status 0x%x\n", __func__, uib_ctrl->ecc_status);
+ } else {
+ /* Assign IO96B CSR base address if it is valid */
+ for (i = 0; i < MAX_IO96B_SUPPORTED; i++) {
+ if (handoff_table[1] & BIT(i)) {
+ io96b_ctrl->io96b[i].io96b_csr_addr = io96b_csr_reg_addr[i];
+
+ debug("%s: IO96B 0x%llx CSR enabled\n", __func__,
+ io96b_ctrl->io96b[i].io96b_csr_addr);
+
+ count++;
+ }
+ }
+
+ io96b_ctrl->num_instance = count;
+ debug("%s: returned num_instance 0x%x\n", __func__, io96b_ctrl->num_instance);
+ }
+
+ return 0;
+}
+
+int config_mpfe_sideband_mgr(struct udevice *dev)
+{
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+ u32 reg, mask;
+ int ret = 0;
+
+ if (plat->multichannel_interleaving) {
+ mask = SIDEBANDMGR_FLAGOUTSET0_REG_INTERLEAVING;
+ setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, mask);
+ } else {
+ mask = SIDEBANDMGR_FLAGOUTSET0_REG_MULTICHANNEL;
+ setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, mask);
+ }
+
+ reg = readl(SIDEBANDMGR_FLAGOUTSTATUS0_REG);
+
+ debug("%s: F2SDRAM_SIDEBAND_FLAGOUTSTATUS0: 0x%x\n", __func__, reg);
+
+ if ((reg & mask) == SIDEBANDMGR_FLAGOUTSET0_REG_INTERLEAVING)
+ debug("%s: Interleaving bit is set\n", __func__);
+ else if ((reg & mask) == SIDEBANDMGR_FLAGOUTSET0_REG_MULTICHANNEL)
+ debug("%s: Multichannel bit is set\n", __func__);
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+bool hps_ocram_dbe_status(void)
+{
+ u32 reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD8);
+
+ if (reg & ALT_SYSMGR_SCRATCH_REG_8_OCRAM_DBE_MASK)
+ return true;
+
+ return false;
+}
+
+bool ddr_ecc_dbe_status(void)
+{
+ u32 reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD8);
+
+ if (reg & ALT_SYSMGR_SCRATCH_REG_8_DDR_DBE_MASK)
+ return true;
+
+ return false;
+}
+
+int sdram_mmr_init_full(struct udevice *dev)
+{
+ int i, ret = 0;
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+ struct altera_sdram_priv *priv = dev_get_priv(dev);
+ struct io96b_info *io96b_ctrl = malloc(sizeof(*io96b_ctrl));
+ struct uib_info *uib_ctrl = malloc(sizeof(*uib_ctrl));
+ struct bd_info bd = {0};
+ bool full_mem_init = false, is_ddr_hang_be4_rst = false;
+ phys_size_t hw_size;
+ u32 reg = readl(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
+ enum reset_type reset_t = get_reset_type(reg);
+
+ /* Populating DDR handoff data */
+ debug("DDR: Populating DDR handoff\n");
+
+ ret = populate_ddr_handoff(dev, io96b_ctrl, uib_ctrl);
+ if (ret) {
+ printf("DDR: Failed to populate DDR handoff\n");
+
+ goto err;
+ }
+
+ debug("%s: Address MPFE 0x%llx\n", memory_type_in_use(dev), plat->mpfe_base_addr);
+
+ /* DDR initialization progress status tracking */
+ is_ddr_hang_be4_rst = is_ddr_init_hang();
+
+ printf("%s: SDRAM init in progress ...\n", memory_type_in_use(dev));
+
+ ddr_init_inprogress(true);
+
+ /* Configuring MPFE sideband manager registers - multichannel or interleaving*/
+ debug("%s: MPFE configuration in progress ...\n", memory_type_in_use(dev));
+
+ ret = config_mpfe_sideband_mgr(dev);
+ if (ret) {
+ printf("%s: Failed to configure multichannel/interleaving mode\n",
+ memory_type_in_use(dev));
+
+ goto err;
+ }
+
+ debug("%s: MPFE configuration completed\n", memory_type_in_use(dev));
+
+ debug("%s: Waiting for NOCPLL locked ...\n", memory_type_in_use(dev));
+
+ /* Ensure NOCPLL locked */
+ ret = wait_for_bit_le32((const void *)socfpga_get_sysmgr_addr() + SYSMGR_HMC_CLK
+ , SYSMGR_HMC_CLK_NOCPLL, true, TIMEOUT, false);
+ if (ret) {
+ printf("%s: NOCPLL is not locked\n", memory_type_in_use(dev));
+
+ goto err;
+ }
+
+ debug("%s: NOCPLL locked\n", memory_type_in_use(dev));
+
+ debug("%s: Checking calibration...\n", memory_type_in_use(dev));
+
+ if (is_ddr_in_use(dev)) {
+ /* Configure if polling is needed for IO96B GEN PLL locked */
+ io96b_ctrl->ckgen_lock = false;
+
+ /* Ensure calibration status passing */
+ init_mem_cal(io96b_ctrl);
+
+ printf("DDR: Calibration success\n");
+
+ /* Initiate IOSSM mailbox */
+ io96b_mb_init(io96b_ctrl);
+
+ /* DDR type */
+ ret = get_mem_technology(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to get DDR type\n");
+
+ goto err;
+ }
+
+ /* DDR size */
+ ret = get_mem_width_info(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to get DDR size\n");
+
+ goto err;
+ }
+ } else {
+ /* Ensure calibration status passing */
+ uib_init_mem_cal(uib_ctrl);
+
+ /* Need to trigger re-calibration for HBM DBE */
+ if (ddr_ecc_dbe_status()) {
+ for (i = 0; i < uib_ctrl->num_instance; i++)
+ uib_ctrl->uib[i].cal_status = false;
+
+ uib_ctrl->overall_cal_status = false;
+ }
+
+ /* Trigger re-calibration if calibration failed */
+ if (!(uib_ctrl->overall_cal_status)) {
+ printf("HBM: Re-calibration in progress...\n");
+
+ uib_trig_mem_cal(uib_ctrl);
+ }
+
+ if (!(uib_ctrl->overall_cal_status)) {
+ printf("HBM: Retry calibration failed & not able to re-calibrate\n");
+
+ ret = -EINVAL;
+ goto err;
+ }
+
+ debug("HBM: Setting Error Mask Register\n");
+
+ /* Responder Error Mask Register */
+ for (i = 0; i < uib_ctrl->num_instance; i++) {
+ clrsetbits_le32(uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_ERRMSK_PSEUDO_CH0_OFFSET,
+ UIB_DRAM_SBE_MSK | UIB_INTERNAL_CORR_ERR_MSK,
+ UIB_DRAM_SBE(0x1) | UIB_INTERNAL_CORR_ERR(0x1));
+
+ debug("HBM: Error Mask Pseudo CH0 addr: 0x%llx\n",
+ uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_ERRMSK_PSEUDO_CH0_OFFSET);
+
+ debug("HBM: Error Mask Pseudo CH0 value: 0x%x\n",
+ readl(uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_ERRMSK_PSEUDO_CH0_OFFSET));
+
+ clrsetbits_le32(uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_ERRMSK_PSEUDO_CH1_OFFSET,
+ UIB_DRAM_SBE_MSK | UIB_INTERNAL_CORR_ERR_MSK,
+ UIB_DRAM_SBE(0x1) | UIB_INTERNAL_CORR_ERR(0x1));
+
+ debug("HBM: Error Mask Pseudo CH1 addr: 0x%llx\n",
+ uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_ERRMSK_PSEUDO_CH1_OFFSET);
+
+ debug("HBM: Error Mask Pseudo CH1 value: 0x%x\n\n",
+ readl(uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_ERRMSK_PSEUDO_CH1_OFFSET));
+ }
+
+ printf("HBM: Calibration success\n");
+ }
+
+ /* Get bank configuration from devicetree */
+ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL,
+ (phys_size_t *)&gd->ram_size, &bd);
+ if (ret) {
+ printf("%s: Failed to decode memory node\n", memory_type_in_use(dev));
+
+ goto err;
+ }
+
+ if (!is_ddr_in_use(dev)) {
+ hw_size = uib_ctrl->overall_size;
+ } else {
+ /* ECC status */
+ ret = ecc_enable_status(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to get DDR ECC status\n");
+
+ goto err;
+ }
+
+ hw_size = io96b_ctrl->overall_size;
+
+ if (io96b_ctrl->inline_ecc)
+ hw_size = CALC_INLINE_ECC_HW_SIZE(hw_size);
+ }
+
+ if (gd->ram_size != hw_size) {
+ printf("%s: Warning: DRAM size from device tree (%lld MiB)\n",
+ memory_type_in_use(dev), gd->ram_size >> 20);
+ printf(" mismatch with hardware (%lld MiB).\n",
+ hw_size >> 20);
+ }
+
+ if (gd->ram_size > hw_size) {
+ printf("%s: Error: DRAM size from device tree is greater\n",
+ memory_type_in_use(dev));
+ printf(" than hardware size.\n");
+
+ hang();
+ }
+
+ printf("%s: %lld MiB\n", (is_ddr_in_use(dev) ? io96b_ctrl->ddr_type : "HBM"),
+ gd->ram_size >> 20);
+
+ if (is_ddr_in_use(dev)) {
+ /*
+ * Is HPS cold or warm reset? If yes, Skip full memory initialization if ECC
+ * enabled to preserve memory content
+ */
+ if (io96b_ctrl->ecc_status) {
+ if (ecc_interrupt_status(io96b_ctrl)) {
+ if (CONFIG_IS_ENABLED(WDT)) {
+ struct udevice *wdt;
+
+ printf("DDR: ECC error recover start now\n");
+ ret = uclass_first_device_err(UCLASS_WDT, &wdt);
+ if (ret) {
+ printf("DDR: Failed to trigger watchdog reset\n");
+ hang();
+ }
+
+ wdt_expire_now(wdt, 0);
+ }
+ hang();
+ }
+
+ full_mem_init = hps_ocram_dbe_status() | is_ddr_hang_be4_rst;
+ if (full_mem_init || !(reset_t == WARM_RESET || reset_t == COLD_RESET)) {
+ debug("%s: Needed to fully initialize DDR memory\n",
+ io96b_ctrl->ddr_type);
+
+ ret = bist_mem_init_start(io96b_ctrl);
+ if (ret) {
+ printf("%s: Failed to fully initialize DDR memory\n",
+ io96b_ctrl->ddr_type);
+
+ goto err;
+ }
+ }
+ }
+ } else {
+ debug("HBM: ECC enable status: %d\n", uib_ctrl->ecc_status);
+
+ /*
+ * Is HPS cold or warm reset? If yes, Skip full memory initialization if ECC
+ * enabled to preserve memory content
+ */
+ if (uib_ctrl->ecc_status) {
+ full_mem_init = hps_ocram_dbe_status() | ddr_ecc_dbe_status() |
+ is_ddr_hang_be4_rst;
+ if (full_mem_init || !(reset_t == WARM_RESET || reset_t == COLD_RESET)) {
+ debug("HBM: Needed to fully initialize HBM memory\n");
+
+ ret = uib_bist_mem_init_start(uib_ctrl);
+ if (ret) {
+ printf("HBM: Failed to fully initialize HBM memory\n");
+
+ goto err;
+ }
+ }
+ }
+ }
+
+ /* Ensure sanity memory test passing */
+ sdram_size_check(&bd);
+ printf("%s: size check success\n", (is_ddr_in_use(dev) ? io96b_ctrl->ddr_type : "HBM"));
+
+ sdram_set_firewall(&bd);
+
+ printf("%s: firewall init success\n", (is_ddr_in_use(dev) ? io96b_ctrl->ddr_type : "HBM"));
+
+ priv->info.base = bd.bi_dram[0].start;
+ priv->info.size = gd->ram_size;
+
+ /* Ending DDR driver initialization success tracking */
+ ddr_init_inprogress(false);
+
+ printf("%s init success\n", (is_ddr_in_use(dev) ? io96b_ctrl->ddr_type : "HBM"));
+
+err:
+ free(io96b_ctrl);
+ free(uib_ctrl);
+
+ return ret;
+}
diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c
index 27fbe80ed41..f8fc92060db 100644
--- a/drivers/ddr/altera/sdram_soc64.c
+++ b/drivers/ddr/altera/sdram_soc64.c
@@ -29,7 +29,10 @@
#define PGTABLE_OFF 0x4000
-#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
+#define SINGLE_RANK_CLAMSHELL 0xc3c3
+#define DUAL_RANK_CLAMSHELL 0xa5a5
+
+#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) && !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7M)
u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg)
{
return readl(plat->iomhc + reg);
@@ -258,8 +261,19 @@ phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat)
{
u32 dramaddrw = hmc_readl(plat, DRAMADDRW);
+ u32 reg_ctrlcfg6_value = hmc_readl(plat, CTRLCFG6);
+ u32 cs_rank = CTRLCFG6_CFG_CS_CHIP(reg_ctrlcfg6_value);
+ u32 cs_addr_width;
+
+ if (cs_rank == SINGLE_RANK_CLAMSHELL)
+ cs_addr_width = 0;
+ else if (cs_rank == DUAL_RANK_CLAMSHELL)
+ cs_addr_width = 1;
+ else
+ cs_addr_width = DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw);
+
phys_size_t size = (phys_size_t)1 <<
- (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) +
+ (cs_addr_width +
DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) +
DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) +
DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) +
@@ -398,7 +412,7 @@ static int altera_sdram_of_to_plat(struct udevice *dev)
/* These regs info are part of DDR handoff in bitstream */
#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
return 0;
-#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
+#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5) || IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7M)
addr = dev_read_addr_index(dev, 0);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
@@ -467,6 +481,7 @@ static const struct udevice_id altera_sdram_ids[] = {
{ .compatible = "intel,sdr-ctl-agilex" },
{ .compatible = "intel,sdr-ctl-n5x" },
{ .compatible = "intel,sdr-ctl-agilex5" },
+ { .compatible = "intel,sdr-ctl-agilex7m" },
{ /* sentinel */ }
};
diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h
index 183b1a33080..6031cef560e 100644
--- a/drivers/ddr/altera/sdram_soc64.h
+++ b/drivers/ddr/altera/sdram_soc64.h
@@ -21,6 +21,17 @@ struct altera_sdram_plat {
bool dualport;
bool dualemif;
};
+#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7M)
+enum memory_type {
+ DDR_MEMORY = 0,
+ HBM_MEMORY
+};
+
+struct altera_sdram_plat {
+ fdt_addr_t mpfe_base_addr;
+ bool multichannel_interleaving;
+ enum memory_type mem_type;
+};
#else
struct altera_sdram_plat {
void __iomem *hmc;
@@ -48,6 +59,8 @@ struct altera_sdram_plat {
#define RSTHANDSHAKESTAT 0x218
#define DDR_HMC_DDRIOCTRL_IOSIZE_MSK 0x00000003
+#define DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_MSK BIT(2)
+#define DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_SHIFT 2
#define DDR_HMC_DDRCALSTAT_CAL_MSK BIT(0)
#define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK BIT(16)
#define DDR_HMC_ECCCTL_CNT_RST_SET_MSK BIT(8)
@@ -63,7 +76,7 @@ struct altera_sdram_plat {
#define DDR_HMC_INTSTAT_ADDRMTCFLG_SET_MSK BIT(16)
#define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0)
#define DDR_HMC_RSTHANDSHAKE_MASK 0x0000000f
-#define DDR_HMC_CORE2SEQ_INT_REQ 0xF
+#define DDR_HMC_CORE2SEQ_INT_REQ 0x0000000f
#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3)
#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f
@@ -75,6 +88,8 @@ struct altera_sdram_plat {
#define CTRLCFG0 0x28
#define CTRLCFG1 0x2c
#define CTRLCFG3 0x34
+#define CTRLCFG5 0x3c
+#define CTRLCFG6 0x40
#define DRAMTIMING0 0x50
#define CALTIMING0 0x7c
#define CALTIMING1 0x80
@@ -89,90 +104,93 @@ struct altera_sdram_plat {
#define NIOSRESERVED2 0x118
#define DRAMADDRW_CFG_COL_ADDR_WIDTH(x) \
- (((x) >> 0) & 0x1F)
+ ((x) & 0x1f)
#define DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) \
- (((x) >> 5) & 0x1F)
+ (((x) >> 5) & 0x1f)
#define DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) \
- (((x) >> 10) & 0xF)
+ (((x) >> 10) & 0xf)
#define DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(x) \
(((x) >> 14) & 0x3)
#define DRAMADDRW_CFG_CS_ADDR_WIDTH(x) \
(((x) >> 16) & 0x7)
#define CTRLCFG0_CFG_MEMTYPE(x) \
- (((x) >> 0) & 0xF)
+ ((x) & 0xf)
#define CTRLCFG0_CFG_DIMM_TYPE(x) \
(((x) >> 4) & 0x7)
#define CTRLCFG0_CFG_AC_POS(x) \
(((x) >> 7) & 0x3)
#define CTRLCFG0_CFG_CTRL_BURST_LEN(x) \
- (((x) >> 9) & 0x1F)
+ (((x) >> 9) & 0x1f)
#define CTRLCFG1_CFG_DBC3_BURST_LEN(x) \
- (((x) >> 0) & 0x1F)
+ ((x) & 0x1f)
#define CTRLCFG1_CFG_ADDR_ORDER(x) \
(((x) >> 5) & 0x3)
#define CTRLCFG1_CFG_CTRL_EN_ECC(x) \
(((x) >> 7) & 0x1)
+#define CTRLCFG6_CFG_CS_CHIP(x) \
+ ((x) & 0xFFFF)
+
#define DRAMTIMING0_CFG_TCL(x) \
- (((x) >> 0) & 0x7F)
+ ((x) & 0x7f)
#define CALTIMING0_CFG_ACT_TO_RDWR(x) \
- (((x) >> 0) & 0x3F)
+ ((x) & 0x3f)
#define CALTIMING0_CFG_ACT_TO_PCH(x) \
- (((x) >> 6) & 0x3F)
+ (((x) >> 6) & 0x3f)
#define CALTIMING0_CFG_ACT_TO_ACT(x) \
- (((x) >> 12) & 0x3F)
+ (((x) >> 12) & 0x3f)
#define CALTIMING0_CFG_ACT_TO_ACT_DB(x) \
- (((x) >> 18) & 0x3F)
+ (((x) >> 18) & 0x3f)
#define CALTIMING1_CFG_RD_TO_RD(x) \
- (((x) >> 0) & 0x3F)
+ ((x) & 0x3f)
#define CALTIMING1_CFG_RD_TO_RD_DC(x) \
- (((x) >> 6) & 0x3F)
+ (((x) >> 6) & 0x3f)
#define CALTIMING1_CFG_RD_TO_RD_DB(x) \
- (((x) >> 12) & 0x3F)
+ (((x) >> 12) & 0x3f)
#define CALTIMING1_CFG_RD_TO_WR(x) \
(((x) >> 18) & 0x3F)
#define CALTIMING1_CFG_RD_TO_WR_DC(x) \
- (((x) >> 24) & 0x3F)
+ (((x) >> 24) & 0x3f)
#define CALTIMING2_CFG_RD_TO_WR_DB(x) \
- (((x) >> 0) & 0x3F)
+ ((x) & 0x3f)
#define CALTIMING2_CFG_RD_TO_WR_PCH(x) \
- (((x) >> 6) & 0x3F)
+ (((x) >> 6) & 0x3f)
#define CALTIMING2_CFG_RD_AP_TO_VALID(x) \
- (((x) >> 12) & 0x3F)
+ (((x) >> 12) & 0x3f)
#define CALTIMING2_CFG_WR_TO_WR(x) \
- (((x) >> 18) & 0x3F)
+ (((x) >> 18) & 0x3f)
#define CALTIMING2_CFG_WR_TO_WR_DC(x) \
- (((x) >> 24) & 0x3F)
+ (((x) >> 24) & 0x3f)
#define CALTIMING3_CFG_WR_TO_WR_DB(x) \
- (((x) >> 0) & 0x3F)
+ ((x) & 0x3F)
#define CALTIMING3_CFG_WR_TO_RD(x) \
- (((x) >> 6) & 0x3F)
+ (((x) >> 6) & 0x3f)
#define CALTIMING3_CFG_WR_TO_RD_DC(x) \
- (((x) >> 12) & 0x3F)
+ (((x) >> 12) & 0x3f)
#define CALTIMING3_CFG_WR_TO_RD_DB(x) \
- (((x) >> 18) & 0x3F)
+ (((x) >> 18) & 0x3f)
#define CALTIMING3_CFG_WR_TO_PCH(x) \
- (((x) >> 24) & 0x3F)
+ (((x) >> 24) & 0x3f)
#define CALTIMING4_CFG_WR_AP_TO_VALID(x) \
- (((x) >> 0) & 0x3F)
+ ((x) & 0x3f)
#define CALTIMING4_CFG_PCH_TO_VALID(x) \
- (((x) >> 6) & 0x3F)
+ (((x) >> 6) & 0x3f)
#define CALTIMING4_CFG_PCH_ALL_TO_VALID(x) \
- (((x) >> 12) & 0x3F)
+ (((x) >> 12) & 0x3f)
#define CALTIMING4_CFG_ARF_TO_VALID(x) \
- (((x) >> 18) & 0xFF)
+ (((x) >> 18) & 0xff)
#define CALTIMING4_CFG_PDN_TO_VALID(x) \
- (((x) >> 26) & 0x3F)
+ (((x) >> 26) & 0x3f)
#define CALTIMING9_CFG_4_ACT_TO_ACT(x) \
- (((x) >> 0) & 0xFF)
+ ((x) & 0xff)
/* Firewall DDR scheduler MPFE */
#define FW_HMC_ADAPTOR_REG_ADDR 0xf8020004
diff --git a/drivers/ddr/altera/uibssm_mailbox.c b/drivers/ddr/altera/uibssm_mailbox.c
new file mode 100644
index 00000000000..deef61f1178
--- /dev/null
+++ b/drivers/ddr/altera/uibssm_mailbox.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#include <hang.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include "uibssm_mailbox.h"
+
+#define MAX_RETRIES 3
+
+int uib_bist_mem_init_start(struct uib_info *uib_ctrl)
+{
+ struct uib_mb_resp usr_resp;
+ bool bist_start, bist_success;
+ u32 start;
+
+ for (int i = 0; i < uib_ctrl->num_instance; i++) {
+ bist_start = false;
+ bist_success = false;
+
+ /*
+ * Full memory initialization BIST performed on all UIB channels
+ * start memory initialization BIST on full memory address
+ */
+ uib_mb_req(uib_ctrl->uib[i].uib_csr_addr,
+ UIB_CMD_TRIG_CONTROLLER_OP,
+ UIB_BIST_MEM_INIT_START,
+ UIB_BIST_FULL_MEM, &usr_resp);
+
+ bist_start = UIBSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) &
+ UIB_BIST_INITIATE_PASS;
+
+ if (!bist_start) {
+ printf("%s: Failed to initialize memory on UIB instance %d\n",
+ __func__, i);
+
+ return -EINVAL;
+ }
+
+ /* Polling for the initiated memory initialization BIST status */
+ start = get_timer(0);
+ while (!bist_success) {
+ udelay(1);
+
+ /*
+ * cmd_param_0 is not used in BIST status request,
+ * hence set the value to 0
+ */
+ uib_mb_req(uib_ctrl->uib[i].uib_csr_addr,
+ UIB_CMD_TRIG_CONTROLLER_OP,
+ UIB_BIST_MEM_INIT_STATUS,
+ 0, &usr_resp);
+
+ bist_success = UIBSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) &
+ BIT(0);
+
+ if (!bist_success && (get_timer(start) > TIMEOUT)) {
+ printf("%s: Timeout initializing memory on UIB instance %d\n",
+ __func__, i);
+
+ return -ETIMEDOUT;
+ }
+ }
+
+ debug("%s: Memory initialized successfully on UIB instance %d\n", __func__, i);
+ }
+
+ return 0;
+}
+
+int uib_cal_status(phys_addr_t addr)
+{
+ int ret = 0;
+ phys_addr_t status_addr = addr + UIB_R_INITSTS_OFFSET;
+
+ /* Ensure calibration completed */
+ ret = wait_for_bit_le32((const void *)status_addr, UIB_R_INITSTS_INITSTS_PASS, true,
+ TIMEOUT, false);
+ if (ret)
+ printf("%s: HBM calibration UIB instance 0x%llx timeout\n", __func__, status_addr);
+
+ return ret;
+}
+
+void uib_init_mem_cal(struct uib_info *uib_ctrl)
+{
+ int i, ret;
+
+ if (!uib_ctrl->num_instance) {
+ uib_ctrl->overall_cal_status = false;
+ } else {
+ uib_ctrl->overall_cal_status = true;
+
+ /* Check initial calibration status for the assigned UIB */
+ for (i = 0; i < uib_ctrl->num_instance; i++) {
+ ret = uib_cal_status(uib_ctrl->uib[i].uib_csr_addr);
+ if (ret) {
+ uib_ctrl->uib[i].cal_status = false;
+ uib_ctrl->overall_cal_status = false;
+
+ printf("%s: Initial HBM calibration UIB_%d failed\n", __func__, i);
+ break;
+ }
+
+ uib_ctrl->uib[i].cal_status = true;
+
+ debug("%s: Initial HBM calibration UIB_%d succeed\n", __func__, i);
+ }
+ }
+}
+
+/* Trying 3 times re-calibration if initial calibration failed */
+void uib_trig_mem_cal(struct uib_info *uib_ctrl)
+{
+ int i, j, cal_stat;
+
+ if (!uib_ctrl->num_instance) {
+ uib_ctrl->overall_cal_status = false;
+ } else {
+ uib_ctrl->overall_cal_status = true;
+
+ for (i = 0; i < uib_ctrl->num_instance; i++) {
+ uib_ctrl->uib[i].cal_status = false;
+
+ /* Initiate Re-calibration */
+ for (j = 0; j < MAX_RETRIES; j++) {
+ clrsetbits_le32(uib_ctrl->uib[i].uib_csr_addr +
+ UIB_R_INITCTL_OFFSET,
+ UIB_R_INITCTL_INITTYPE_MASK |
+ UIB_R_INITCTL_INITREQ_MASK,
+ UIB_R_INITCTL_INITTYPE(UIB_RST_REQUEST_WITH_CAL) |
+ UIB_R_INITCTL_INITREQ(1));
+
+ cal_stat = uib_cal_status(uib_ctrl->uib[i].uib_csr_addr);
+ if (cal_stat)
+ continue;
+
+ debug("%s: HBM re-calibration UIB_%d succeed\n", __func__, i);
+
+ uib_ctrl->uib[i].cal_status = true;
+ break;
+ }
+
+ if (!uib_ctrl->uib[i].cal_status) {
+ uib_ctrl->overall_cal_status = false;
+
+ printf("%s: HBM re-calibration UIB_%d failed\n", __func__, i);
+ break;
+ }
+ }
+ }
+}
+
+static void uib_mailbox_write_request(u32 data, u32 target_write_addr, phys_addr_t csr_addr)
+{
+ int ret;
+
+ /*
+ * Read from chms0020 MBWRADDR_VALID and ensure its not set or
+ * wait till it get cleared by controller
+ */
+ debug("%s: #1 Read MBWRADDR_VALID from UIB_R_MBWRCTL\n", __func__);
+ ret = wait_for_bit_le32((const void *)csr_addr + UIB_R_MBWRCTL,
+ UIB_R_MBWRCTL_MBWRADDR_VALID, false, TIMEOUT, false);
+ if (ret) {
+ printf("%s: TIMEOUT!!! MBWRADDR_VALID is not zero\n", __func__);
+
+ hang();
+ }
+
+ /* Write <target write address> to chms0024 MBWRADDR */
+ debug("%s: #2 Write 0x%x to UIB_R_MBWRADDR\n", __func__, target_write_addr);
+ writel(target_write_addr, csr_addr + UIB_R_MBWRADDR);
+
+ /*
+ * Write 1 to chms0020 MBWRADDR_VALID to indicate the address is now valid
+ * for FW to read
+ */
+ debug("%s: #3 Write 1 to MBWRADDR_VALID for FW to read address\n", __func__);
+ setbits_le32(csr_addr + UIB_R_MBWRCTL, UIB_R_MBWRCTL_MBWRADDR_VALID);
+
+ /*
+ * Read from chms0020 MBWRDATA_VALID and ensure its not set or
+ * wait till it get cleared by controller
+ */
+ debug("%s: #4 Read MBWRDATA_VALID from UIB_R_MBWRCTL\n", __func__);
+ ret = wait_for_bit_le32((const void *)csr_addr + UIB_R_MBWRCTL,
+ UIB_R_MBWRCTL_MBWRDATA_VALID, false, TIMEOUT, false);
+ if (ret) {
+ printf("%s: TIMEOUT!!! MBWRADDR_VALID is not zero\n", __func__);
+
+ hang();
+ }
+
+ /*
+ * Read from chms0020 MBWRDATA_END and ensure its not set or
+ * wait till it get cleared by controller
+ */
+ debug("%s: #5 Read R_MBWRCTL_MBWRDATA_END from UIB_R_MBWRCTL\n", __func__);
+ ret = wait_for_bit_le32((const void *)csr_addr + UIB_R_MBWRCTL,
+ UIB_R_MBWRCTL_MBWRDATA_END, false, TIMEOUT, false);
+ if (ret) {
+ printf("%s: TIMEOUT!!! MBWRDATA_END is not zero\n", __func__);
+
+ hang();
+ }
+
+ /* Write <write data> to chms0028 MMR_MBWRDATA */
+ debug("%s: #6 Write 0x%x to UIB_R_MBWRDATA\n", __func__, data);
+ writel(data, csr_addr + UIB_R_MBWRDATA);
+
+ /*
+ * Write 1 to chms0020 MBWRDATA_END to indicate if the <write data> is the last burst
+ * for FW to read for the <target write address>
+ */
+ debug("%s: #7 Write 1 to MBWRDATA_END to inform FW this is last burst of data to read\n",
+ __func__);
+ setbits_le32(csr_addr + UIB_R_MBWRCTL, UIB_R_MBWRCTL_MBWRDATA_END);
+
+ /* Write 1 to chms0020 MBWRDATA_VALID to indicate the data is now valid for FW to read */
+ debug("%s: #8 Write 1 to MBWRDATA_VALID for FW to read data\n", __func__);
+ setbits_le32(csr_addr + UIB_R_MBWRCTL, UIB_R_MBWRCTL_MBWRDATA_VALID);
+}
+
+static u32 uib_mailbox_read_request(u32 target_read_addr, phys_addr_t csr_addr)
+{
+ int ret;
+ u32 reg, rd_data = 0;
+
+ /*
+ * Read from chms0030 MBRDADDR_VALID and ensure its not set or
+ * wait till it get cleared by controller
+ */
+ debug("%s: #1 Read MBRDADDR_VALID from UIB_R_MBRDCTL\n", __func__);
+ ret = wait_for_bit_le32((const void *)csr_addr + UIB_R_MBRDCTL,
+ UIB_R_MBRDCTL_MBRDADDR_VALID, false, TIMEOUT, false);
+ if (ret) {
+ printf("%s: TIMEOUT!!! MBRDADDR_VALID is not zero\n", __func__);
+
+ hang();
+ }
+
+ /* Write <target read address> to chms0034 MBRDADDR */
+ debug("%s: #2 Write 0x%x to UIB_R_MBRDADDR\n", __func__, target_read_addr);
+ writel(target_read_addr, csr_addr + UIB_R_MBRDADDR);
+
+ /*
+ * Write 1 to chms0030 MBRDADDR_VALID to indicate the address is now valid
+ * for FW to read
+ */
+ debug("%s: #3 Write 1 to MBRDADDR_VALID for FW to read address\n", __func__);
+ setbits_le32(csr_addr + UIB_R_MBRDCTL, UIB_R_MBRDCTL_MBRDADDR_VALID);
+
+ /*
+ * Continuously poll the chms0030 MBRDDATA_VALID. If MBRDDATA_VALID are set, read
+ * chms0038 MBRDDATA and chms0030 MBRDDATA_END to retrieve the <read data> and
+ * <end of read burst> status accordingly
+ */
+ debug("%s: #4 Read MBRDDATA_VALID from UIB_R_MBRDCTL\n", __func__);
+ ret = wait_for_bit_le32((const void *)csr_addr + UIB_R_MBRDCTL,
+ UIB_R_MBRDCTL_MBRDDATA_VALID, true, TIMEOUT, false);
+ if (ret) {
+ printf("%s: TIMEOUT!!! MBRDDATA_VALID is zero\n", __func__);
+
+ hang();
+ }
+
+ reg = readl(csr_addr + UIB_R_MBRRDATA);
+ debug("%s: #5 Read data from UIB_R_MBRRDATA = 0x%x\n", __func__, reg);
+ rd_data = reg;
+
+ reg = readl(csr_addr + UIB_R_MBRDCTL);
+ debug("%s: #6 Read end of read burst status from UIB_R_MBRDCTL = 0x%x\n", __func__, reg);
+
+ /*
+ * Once done retrieving the data, write 1 to chms0030 MBRDDATA_VALID,
+ * chms0030 MBRDDATA_END to clear the register
+ */
+ debug("%s: #7 Write 1 to MBRDDATA_VALID for FW to read address\n", __func__);
+ setbits_le32(csr_addr + UIB_R_MBRDCTL, UIB_R_MBRDCTL_MBRDDATA_VALID |
+ UIB_R_MBWRCTL_MBWRDATA_END);
+
+ return rd_data;
+}
+
+int uib_mb_req(phys_addr_t uib_csr_addr, u32 usr_cmd_type, u32 usr_cmd_opcode,
+ u32 cmd_param_0, struct uib_mb_resp *resp)
+{
+ u32 cmd_req;
+
+ /* Initialized zeros for responses */
+ resp->cmd_resp_status = 0;
+
+ /* Write CMD_REQ (CMD_TYPE and CMD_OPCODE) */
+ cmd_req = FIELD_PREP(CMD_TYPE_MASK, usr_cmd_type) |
+ FIELD_PREP(CMD_OPCODE_MASK, usr_cmd_opcode);
+ uib_mailbox_write_request(cmd_req, 0, uib_csr_addr);
+
+ debug("%s: Write 0x%x to UIBSSM_CMD_REQ_OFFSET 0x%llx\n", __func__, cmd_req, uib_csr_addr);
+
+ /* Write CMD_PARAM_* */
+ if (cmd_param_0)
+ uib_mailbox_write_request(cmd_param_0, 0, uib_csr_addr);
+ else
+ debug("%s: cmd_param_0 is NULL\n", __func__);
+
+ /* read CMD_RESPONSE_STATUS */
+ resp->cmd_resp_status = uib_mailbox_read_request(0, uib_csr_addr);
+
+ debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__,
+ uib_csr_addr, resp->cmd_resp_status);
+ debug("%s: STATUS_CMD_RESPONSE_ERROR: 0x%lx\n", __func__,
+ UIBSSM_CMD_RESPONSE_ERROR(resp->cmd_resp_status));
+ debug("%s: STATUS_GENERAL_ERROR: 0x%lx\n", __func__,
+ UIBSSM_GENERAL_ERROR(resp->cmd_resp_status));
+
+ return 0;
+}
diff --git a/drivers/ddr/altera/uibssm_mailbox.h b/drivers/ddr/altera/uibssm_mailbox.h
new file mode 100644
index 00000000000..771efab191e
--- /dev/null
+++ b/drivers/ddr/altera/uibssm_mailbox.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#define TIMEOUT_120000MS 120000
+#define TIMEOUT TIMEOUT_120000MS
+
+#define UIBSSM_CMD_RESPONSE_DATA_SHORT_MASK GENMASK(31, 16)
+#define UIBSSM_CMD_RESPONSE_DATA_SHORT(x) FIELD_GET(UIBSSM_CMD_RESPONSE_DATA_SHORT_MASK, x)
+#define UIBSSM_CMD_RESPONSE_ERROR_MASK GENMASK(7, 5)
+#define UIBSSM_CMD_RESPONSE_ERROR(x) FIELD_GET(UIBSSM_CMD_RESPONSE_ERROR_MASK, x)
+#define UIBSSM_GENERAL_ERROR_MASK GENMASK(4, 1)
+#define UIBSSM_GENERAL_ERROR(x) FIELD_GET(UIBSSM_GENERAL_ERROR_MASK, x)
+
+/* UIB Responder Initialization Control Register */
+#define UIB_R_INITCTL_OFFSET 0x10
+#define UIB_R_INITCTL_INITREQ_MASK BIT(0)
+#define UIB_R_INITCTL_INITTYPE_MASK GENMASK(11, 8)
+#define UIB_R_INITCTL_INITREQ(x) FIELD_PREP(UIB_R_INITCTL_INITREQ_MASK, x)
+#define UIB_R_INITCTL_INITTYPE(x) FIELD_PREP(UIB_R_INITCTL_INITTYPE_MASK, x)
+#define UIB_RST_REQUEST_WITH_CAL 5
+
+/* UIB Initialization control and status registers */
+#define UIB_R_INITSTS_OFFSET 0x14
+#define UIB_R_INITSTS_INITSTS_PASS BIT(1)
+#define MAX_UIB_SUPPORTED 8
+
+#define UIB_R_MBWRCTL 0x20
+#define UIB_R_MBWRADDR 0x24
+#define UIB_R_MBWRDATA 0x28
+#define UIB_R_MBWRCTL_MBWRADDR_VALID BIT(0)
+#define UIB_R_MBWRCTL_MBWRDATA_VALID BIT(4)
+#define UIB_R_MBWRCTL_MBWRDATA_END BIT(7)
+
+#define UIB_R_MBRDCTL 0x30
+#define UIB_R_MBRDADDR 0x34
+#define UIB_R_MBRRDATA 0x38
+#define UIB_R_MBRDCTL_MBRDADDR_VALID BIT(0)
+#define UIB_R_MBRDCTL_MBRDDATA_VALID BIT(4)
+#define UIB_R_MBRDCTL_MBRDDATA_END BIT(7)
+
+/* Responder Error Mask Register */
+#define UIB_R_ERRMSK_PSEUDO_CH0_OFFSET 0x520
+#define UIB_R_ERRMSK_PSEUDO_CH1_OFFSET 0X820
+#define UIB_DRAM_SBE_MSK BIT(25)
+#define UIB_INTERNAL_CORR_ERR_MSK BIT(30)
+#define UIB_DRAM_SBE(x) FIELD_PREP(UIB_DRAM_SBE_MSK, x)
+#define UIB_INTERNAL_CORR_ERR(x) FIELD_PREP(UIB_INTERNAL_CORR_ERR_MSK, x)
+
+/* CMD_REQ Register Definition */
+#define CMD_TYPE_MASK GENMASK(23, 16)
+#define CMD_OPCODE_MASK GENMASK(15, 0)
+
+/* supported mailbox command type */
+enum uibssm_mailbox_cmd_type {
+ UIB_CMD_TRIG_CONTROLLER_OP = 0x04
+};
+
+/* supported mailbox command opcode */
+enum uibssm_mailbox_cmd_opcode {
+ UIB_BIST_MEM_INIT_START = 0x0303,
+ UIB_BIST_MEM_INIT_STATUS
+};
+
+/* CMD_PARAM_0 for opcode UIB_BIST_MEM_INIT_START */
+#define UIB_BIST_FULL_MEM BIT(6)
+
+/* UIBSSM_CMD_RESPONSE_DATA_SHORT for opcode UIB_BIST_MEM_INIT_START */
+#define UIB_BIST_INITIATE_PASS BIT(0)
+
+/*
+ * UIBSSM mailbox response outputs
+ *
+ * @cmd_resp_status: Command Interface status
+ */
+struct uib_mb_resp {
+ u32 cmd_resp_status;
+};
+
+/*
+ * UIB instance specific information
+ *
+ * @uib_csr_addr: UIB instance CSR address
+ * @cal_status: UIB instance calibration status
+ */
+struct uib_instance {
+ phys_addr_t uib_csr_addr;
+ bool cal_status;
+};
+
+/*
+ * Overall UIB instance(s) information
+ *
+ * @num_instance: Number of instance(s) assigned to HPS
+ * @overall_cal_status: Overall calibration status for all UIB instance(s)
+ * @ecc_status: ECC enable status (false = disabled, true = enabled)
+ * @overall_size: Total HBM memory size
+ * @uib: UIB instance specific information
+ */
+struct uib_info {
+ u8 num_instance;
+ bool overall_cal_status;
+ bool ecc_status;
+ phys_size_t overall_size;
+ struct uib_instance uib[MAX_UIB_SUPPORTED];
+};
+
+/* Supported UIB function */
+int uib_mb_req(phys_addr_t uib_csr_addr,
+ u32 usr_cmd_type, u32 usr_cmd_opcode,
+ u32 cmd_param_0, struct uib_mb_resp *resp);
+int uib_cal_status(phys_addr_t addr);
+void uib_init_mem_cal(struct uib_info *uib_ctrl);
+void uib_trig_mem_cal(struct uib_info *uib_ctrl);
+int uib_bist_mem_init_start(struct uib_info *uib_ctrl);
diff --git a/drivers/net/dwc_eth_xgmac.c b/drivers/net/dwc_eth_xgmac.c
index 03959ea95a5..d29d871ea8c 100644
--- a/drivers/net/dwc_eth_xgmac.c
+++ b/drivers/net/dwc_eth_xgmac.c
@@ -1102,7 +1102,7 @@ static int xgmac_probe(struct udevice *dev)
ret = xgmac->config->ops->xgmac_start_clks(dev);
if (ret < 0) {
pr_err("%s xgmac_start_clks() failed: %d\n", dev->name, ret);
- return ret;
+ goto err_remove_resources_core;
}
if (IS_ENABLED(CONFIG_DM_ETH_PHY))
diff --git a/drivers/net/dwc_eth_xgmac_socfpga.c b/drivers/net/dwc_eth_xgmac_socfpga.c
index c89c8a188b7..f72f16b50ab 100644
--- a/drivers/net/dwc_eth_xgmac_socfpga.c
+++ b/drivers/net/dwc_eth_xgmac_socfpga.c
@@ -39,11 +39,9 @@ phy_interface_t dwxgmac_of_get_mac_mode(struct udevice *dev)
if (!mac_mode)
return PHY_INTERFACE_MODE_NA;
- if (mac_mode) {
- for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
- if (!strcmp(mac_mode, phy_interface_strings[i]))
- return i;
- }
+ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
+ if (!strcmp(mac_mode, phy_interface_strings[i]))
+ return i;
}
return PHY_INTERFACE_MODE_NA;
}
diff --git a/drivers/sysreset/sysreset_socfpga_soc64.c b/drivers/sysreset/sysreset_socfpga_soc64.c
index 6f44792abb0..6ce30d9eaf0 100644
--- a/drivers/sysreset/sysreset_socfpga_soc64.c
+++ b/drivers/sysreset/sysreset_socfpga_soc64.c
@@ -1,19 +1,78 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Pepperl+Fuchs
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
* Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
*/
+#include <command.h>
+#include <cpu_func.h>
#include <dm.h>
#include <errno.h>
#include <sysreset.h>
#include <asm/arch/mailbox_s10.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/secure.h>
+
+#define GICD_CTRL_ADDRESS 0xfffc1000
+
+static __always_inline void __l2_reset_cpu(void)
+{
+ asm volatile(/* Disable GIC distributor (IRQs). */
+ "str wzr, [%3]\n"
+ /* Set Magic Number */
+ "str %0, [%1]\n"
+ /* Increase timeout in rstmgr.hdsktimeout */
+ "ldr x2, =0xFFFFFF\n"
+ "str w2, [%2, #0x64]\n"
+ "ldr w2, [%2, #0x10]\n"
+ /*
+ * Set l2flushen = 1, etrstallen = 1,
+ * fpgahsen = 1 and sdrselfrefen = 1
+ * in rstmgr.hdsken to perform handshake
+ * in certain peripherals before trigger
+ * L2 reset.
+ */
+ "ldr x3, =0x10D\n"
+ "orr x2, x2, x3\n"
+ "str w2, [%2, #0x10]\n"
+ /* Trigger L2 reset in rstmgr.coldmodrst */
+ "ldr w2, [%2, #0x34]\n"
+ "orr x2, x2, #0x100\n"
+ "isb\n"
+ "dsb sy\n"
+ "str w2, [%2, #0x34]\n"
+ /* Put all cores into WFI mode */
+ "1:\n"
+ " wfi\n"
+ " b 1b\n"
+ : : "r" (L2_RESET_DONE_STATUS),
+ "r" (L2_RESET_DONE_REG),
+ "r" (SOCFPGA_RSTMGR_ADDRESS),
+ "r" (GICD_CTRL_ADDRESS)
+ : "x1", "x2", "x3");
+}
+
+static void l2_reset_cpu(void)
+{
+ __l2_reset_cpu();
+}
static int socfpga_sysreset_request(struct udevice *dev,
enum sysreset_t type)
{
- puts("Mailbox: Issuing mailbox cmd REBOOT_HPS\n");
- mbox_reset_cold();
+ if (type == SYSRESET_WARM) {
+ /* flush dcache */
+ flush_dcache_all();
+
+ /* request a warm reset */
+ puts("Do warm reset now...\n");
+ l2_reset_cpu();
+ } else {
+ puts("Mailbox: Issuing mailbox cmd REBOOT_HPS\n");
+ mbox_reset_cold();
+ }
+
return -EINPROGRESS;
}
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 56290b32bd9..9e149a75e81 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -31,7 +31,7 @@ config WATCHDOG_TIMEOUT_MSECS
default 128000 if ARCH_MX5 || ARCH_MX6
default 128000 if ARCH_MX7 || ARCH_VF610
default 30000 if ARCH_SNAPDRAGON
- default 30000 if ARCH_SOCFPGA
+ default 10000 if ARCH_SOCFPGA
default 16000 if ARCH_SUNXI
default 5376 if ULP_WATCHDOG
default 15000 if ARCH_BCM283X