From: Sin Hui Kho <sin.hui....@intel.com>

Add SDRAM driver for AGILEX7 SoC.

Signed-off-by: Sin Hui Kho <sin.hui....@intel.com>
---
 drivers/ddr/altera/Makefile        |   1 +
 drivers/ddr/altera/sdram_agilex7.c | 331 +++++++++++++++++++++++++++++
 drivers/ddr/altera/sdram_soc64.c   |  15 +-
 drivers/ddr/altera/sdram_soc64.h   |   9 +-
 4 files changed, 351 insertions(+), 5 deletions(-)
 create mode 100644 drivers/ddr/altera/sdram_agilex7.c

diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
index 9fa5d85a27..555357d669 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -12,4 +12,5 @@ obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o
 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_AGILEX7) += sdram_soc64.o sdram_agilex7.o
 endif
diff --git a/drivers/ddr/altera/sdram_agilex7.c 
b/drivers/ddr/altera/sdram_agilex7.c
new file mode 100644
index 0000000000..d50e0899cc
--- /dev/null
+++ b/drivers/ddr/altera/sdram_agilex7.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <dm.h>
+#include <hang.h>
+#include <log.h>
+#include <ram.h>
+#include <reset.h>
+#include "iossm_mailbox.h"
+#include "sdram_soc64.h"
+#include <wait_bit.h>
+#include <asm/arch/system_manager.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
+
+/* Reset type */
+enum reset_type {
+       POR_RESET,
+       WARM_RESET,
+       COLD_RESET,
+       NCONFIG,
+       JTAG_CONFIG,
+       RSU_RECONFIG
+};
+
+static enum reset_type get_reset_type(u32 reg)
+{
+       return (reg & ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK) >>
+               ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT;
+}
+
+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);
+}
+
+void update_io96b_assigned_to_hps(u8 num_io96b_instance)
+{
+       u32 reg = readl(socfpga_get_sysmgr_addr() +
+                       SYSMGR_SOC64_BOOT_SCRATCH_COLD8);
+
+       writel(reg | ((num_io96b_instance << 
ALT_SYSMGR_SCRATCH_REG_8_IO96B_HPS_SHIFT)
+               & ALT_SYSMGR_SCRATCH_REG_8_IO96B_HPS_MASK), 
socfpga_get_sysmgr_addr() +
+               SYSMGR_SOC64_BOOT_SCRATCH_COLD8);
+}
+
+int populate_ddr_handoff(struct udevice *dev, struct io96b_info *io96b_ctrl)
+{
+       struct altera_sdram_plat *plat = dev_get_plat(dev);
+       fdt_addr_t addr;
+       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-IO96B is in %s mode\n", __func__
+                       , plat->multichannel_interleaving ? "interleaving" : 
"multichannel");
+
+       /* Assign IO96B CSR base address if it is valid */
+       for (i = 0; i < MAX_IO96B_SUPPORTED; i++) {
+               addr = dev_read_addr_index(dev, i + 1);
+
+               if (addr == FDT_ADDR_T_NONE)
+                       return -EINVAL;
+
+               switch (i) {
+               case 0:
+                       if (handoff_table[1] & BIT(i)) {
+                               io96b_ctrl->io96b_0.io96b_csr_addr = addr;
+                               debug("%s: IO96B 0x%llx CSR enabled\n", __func__
+                                               , 
io96b_ctrl->io96b_0.io96b_csr_addr);
+                               count++;
+                       }
+                       break;
+               case 1:
+                       if (handoff_table[1] & BIT(i)) {
+                               io96b_ctrl->io96b_1.io96b_csr_addr = addr;
+                               debug("%s: IO96B 0x%llx CSR enabled\n", __func__
+                                               , 
io96b_ctrl->io96b_1.io96b_csr_addr);
+                               count++;
+                       }
+                       break;
+               default:
+                       printf("%s: Invalid IO96B CSR\n", __func__);
+               }
+       }
+
+       io96b_ctrl->num_instance = count;
+       update_io96b_assigned_to_hps(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;
+
+       if (plat->multichannel_interleaving) {
+               debug("%s: Set interleaving bit\n", __func__);
+               setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(5));
+       } else {
+               debug("%s: Set multichannel bit\n", __func__);
+               setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(4));
+       }
+
+       reg = readl(SIDEBANDMGR_FLAGOUTSTATUS0_REG);
+       debug("%s: F2SDRAM_SIDEBAND_FLAGOUTSTATUS0: 0x%x\n", __func__, reg);
+
+       if ((reg & BIT(1)) == plat->multichannel_interleaving)
+               return 0;
+
+       return -1;
+}
+
+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)
+{
+       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 bd_info bd = {0};
+       bool full_mem_init = false;
+       phys_size_t hw_size;
+       int ret;
+       u32 reg = readl(socfpga_get_sysmgr_addr() + 
SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
+       enum reset_type reset_t = get_reset_type(reg);
+
+       debug("DDR: Address MPFE 0x%llx\n", plat->mpfe_base_addr);
+
+       /* DDR initialization progress status tracking */
+       bool is_ddr_hang_be4_rst = is_ddr_init_hang();
+
+       printf("DDR: IO96B SDRAM init in progress ...\n");
+       ddr_init_inprogress(true);
+
+       /* Populating DDR handoff data */
+       debug("DDR: MPFE configuration in progress ...\n");
+       ret = populate_ddr_handoff(dev, io96b_ctrl);
+       if (ret) {
+               printf("DDR: Failed to populate DDR handoff\n");
+               return ret;
+       }
+
+       /* Configuring MPFE sideband manager registers - multichannel or 
interleaving*/
+       ret = config_mpfe_sideband_mgr(dev);
+       if (ret) {
+               printf("DDR: Failed to configure multichannel/interleaving 
mode\n");
+               return ret;
+       }
+
+       debug("DDR: MPFE configuration completed\n");
+
+       printf("DDR: Waiting for NOCPLL locked ...\n");
+       /* Ensure NOCPLL locked */
+       ret = wait_for_bit_le32((const void *)socfpga_get_sysmgr_addr() + 
SYSMGR_HMC_CLK
+                               , SYSMGR_HMC_CLK_NOCPLL, true, TIMEOUT_10000MS, 
false);
+       if (ret) {
+               printf("DDR: NOCPLL is not locked\n");
+               return ret;
+       }
+
+       printf("DDR: NOCPLL locked\n");
+
+       printf("DDR: Checking calibration...\n");
+
+       /* Ensure calibration status passing */
+       init_mem_cal(io96b_ctrl);
+
+       /* Initiate IOSSM mailbox */
+       io96b_mb_init(io96b_ctrl);
+
+       /* Need to trigger re-calibration for DDR DBE */
+       if (ddr_ecc_dbe_status()) {
+               io96b_ctrl->io96b_0.cal_status = false;
+               io96b_ctrl->io96b_1.cal_status = false;
+               io96b_ctrl->overall_cal_status = io96b_ctrl->io96b_0.cal_status 
||
+                                                io96b_ctrl->io96b_1.cal_status;
+       }
+
+       /* Trigger re-calibration if calibration failed */
+       if (!(io96b_ctrl->overall_cal_status)) {
+               printf("DDR: Re-calibration in progress...\n");
+               init_mem_cal(io96b_ctrl);
+       }
+
+       if (!(io96b_ctrl->overall_cal_status)) {
+               printf("DDR: Retry calibration failed & not able to 
re-calibrate\n");
+               return -1;
+       }
+
+       printf("DDR: Calibration success\n");
+
+       /* DDR type, DDR size and ECC status) */
+       ret = get_mem_technology(io96b_ctrl);
+       if (ret) {
+               printf("DDR: Failed to get DDR type\n");
+               return ret;
+       }
+
+       ret = get_mem_width_info(io96b_ctrl);
+       if (ret) {
+               printf("DDR: Failed to get DDR size\n");
+               return ret;
+       }
+
+       /* 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("DDR: Failed to decode memory node\n");
+               return -ENXIO;
+       }
+
+       hw_size = (phys_size_t)io96b_ctrl->overall_size * SZ_1G / SZ_8;
+
+       if (gd->ram_size != hw_size) {
+               printf("DDR: Warning: DRAM size from device tree (%lld MiB)\n",
+                      gd->ram_size >> 20);
+               printf(" mismatch with hardware (%lld MiB).\n",
+                      hw_size >> 20);
+       }
+
+       if (gd->ram_size > hw_size) {
+               printf("DDR: Error: DRAM size from device tree is greater\n");
+               printf(" than hardware size.\n");
+               hang();
+       }
+
+       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 DDR ECC status\n");
+               return ret;
+       }
+
+       /* Is HPS cold or warm reset? If yes, Skip full memory initialization 
if ECC
+        *  enabled to preserve memory content
+        */
+       if (io96b_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("%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);
+                               return ret;
+                       }
+               }
+       }
+
+       sdram_size_check(&bd);
+       printf("%s: size check success\n", io96b_ctrl->ddr_type);
+
+       sdram_set_firewall(&bd);
+       printf("%s: firewall init success\n", io96b_ctrl->ddr_type);
+
+       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: IO96B SDRAM init success\n", io96b_ctrl->ddr_type);
+
+       return 0;
+}
diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c
index 4716abfc9a..86561bcbd4 100644
--- a/drivers/ddr/altera/sdram_soc64.c
+++ b/drivers/ddr/altera/sdram_soc64.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2016-2022 Intel Corporation <www.intel.com>
+ * Copyright (C) 2016-2023 Intel Corporation <www.intel.com>
  *
  */
 
@@ -28,6 +28,7 @@
 
 #define PGTABLE_OFF    0x4000
 
+#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7)
 u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg)
 {
        return readl(plat->iomhc + reg);
@@ -99,6 +100,7 @@ int emif_reset(struct altera_sdram_plat *plat)
        debug("DDR: %s triggered successly\n", __func__);
        return 0;
 }
+#endif
 
 #if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
 int poll_hmc_clock_status(void)
@@ -322,8 +324,12 @@ 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;
-#endif
-
+#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7)
+       addr = dev_read_addr_index(dev, 0);
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+       plat->mpfe_base_addr = addr;
+#else
        addr = dev_read_addr_index(dev, 0);
        if (addr == FDT_ADDR_T_NONE)
                return -EINVAL;
@@ -338,7 +344,7 @@ static int altera_sdram_of_to_plat(struct udevice *dev)
        if (addr == FDT_ADDR_T_NONE)
                return -EINVAL;
        plat->hmc = (void __iomem *)addr;
-
+#endif
        return 0;
 }
 
@@ -385,6 +391,7 @@ static const struct udevice_id altera_sdram_ids[] = {
        { .compatible = "altr,sdr-ctl-s10" },
        { .compatible = "intel,sdr-ctl-agilex" },
        { .compatible = "intel,sdr-ctl-n5x" },
+       { .compatible = "intel,sdr-ctl-agilex7" },
        { /* sentinel */ }
 };
 
diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h
index 07a0f9f2ae..1e802f1bdb 100644
--- a/drivers/ddr/altera/sdram_soc64.h
+++ b/drivers/ddr/altera/sdram_soc64.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (C) 2017-2019 Intel Corporation <www.intel.com>
+ * Copyright (C) 2017-2023 Intel Corporation <www.intel.com>
  */
 
 #ifndef        _SDRAM_SOC64_H_
@@ -14,11 +14,18 @@ struct altera_sdram_priv {
        struct reset_ctl_bulk resets;
 };
 
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7)
+struct altera_sdram_plat {
+       fdt_addr_t mpfe_base_addr;
+       bool multichannel_interleaving;
+};
+#else
 struct altera_sdram_plat {
        void __iomem *hmc;
        void __iomem *ddr_sch;
        void __iomem *iomhc;
 };
+#endif
 
 /* ECC HMC registers */
 #define DDRIOCTRL                      0x8
-- 
2.25.1

Reply via email to