public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v1 0/5] Add new DDR driver support for Agilex7
@ 2023-04-23 18:11 sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 1/5] ddr: altera: agilex7: Add SDRAM driver for AGILEX7 sin.hui.kho
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: sin.hui.kho @ 2023-04-23 18:11 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Simon Goldschmidt, Tien Fong Chee, Sin Hui Kho,
	Simon Glass, Stefan Roese, Dinesh Maniyam, Jit Loon Lim,
	Teik Heng, Kok Kiang

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

*** BLURB HERE ***

Sin Hui Kho (5):
  ddr: altera: agilex7: Add SDRAM driver for AGILEX7
  arm: socfpga: agilex7: Add boot scratch register used for DDR driver
  arm: socfpga: soc64: Add F2SDRAM sideband manager base address for
    SOC64
  arm: socfpga: agilex7: Add DDR handoff data support for AGILEX7
  ddr: altera: Add IOSSM mailbox support for DDR driver

 .../include/mach/base_addr_soc64.h            |   1 +
 .../mach-socfpga/include/mach/handoff_soc64.h |  11 +-
 .../include/mach/system_manager_soc64.h       |  19 +-
 arch/arm/mach-socfpga/wrap_handoff_soc64.c    |   4 +
 drivers/ddr/altera/Makefile                   |   1 +
 drivers/ddr/altera/iossm_mailbox.c            | 847 ++++++++++++++++++
 drivers/ddr/altera/iossm_mailbox.h            | 142 +++
 drivers/ddr/altera/sdram_agilex7.c            | 331 +++++++
 drivers/ddr/altera/sdram_soc64.c              |  15 +-
 drivers/ddr/altera/sdram_soc64.h              |   9 +-
 10 files changed, 1373 insertions(+), 7 deletions(-)
 create mode 100644 drivers/ddr/altera/iossm_mailbox.c
 create mode 100644 drivers/ddr/altera/iossm_mailbox.h
 create mode 100644 drivers/ddr/altera/sdram_agilex7.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 1/5] ddr: altera: agilex7: Add SDRAM driver for AGILEX7
  2023-04-23 18:11 [PATCH v1 0/5] Add new DDR driver support for Agilex7 sin.hui.kho
@ 2023-04-23 18:11 ` sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 2/5] arm: socfpga: agilex7: Add boot scratch register used for DDR driver sin.hui.kho
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: sin.hui.kho @ 2023-04-23 18:11 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Simon Goldschmidt, Tien Fong Chee, Sin Hui Kho,
	Simon Glass, Stefan Roese, Dinesh Maniyam, Jit Loon Lim,
	Teik Heng, Kok Kiang

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

Add SDRAM driver for AGILEX7 SoC.

Signed-off-by: Sin Hui Kho <sin.hui.kho@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


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 2/5] arm: socfpga: agilex7: Add boot scratch register used for DDR driver
  2023-04-23 18:11 [PATCH v1 0/5] Add new DDR driver support for Agilex7 sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 1/5] ddr: altera: agilex7: Add SDRAM driver for AGILEX7 sin.hui.kho
@ 2023-04-23 18:11 ` sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 3/5] arm: socfpga: soc64: Add F2SDRAM sideband manager base address for SOC64 sin.hui.kho
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: sin.hui.kho @ 2023-04-23 18:11 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Simon Goldschmidt, Tien Fong Chee, Sin Hui Kho,
	Simon Glass, Stefan Roese, Dinesh Maniyam, Jit Loon Lim,
	Teik Heng, Kok Kiang

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

Add boot scratch register 8 in system manager used for AGILEX7 DDR
driver.

Signed-off-by: Sin Hui Kho <sin.hui.kho@intel.com>
---
 .../include/mach/system_manager_soc64.h       | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h b/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
index a8009664fe..fe85c0742d 100644
--- a/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
+++ b/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (C) 2019-2021 Intel Corporation <www.intel.com>
+ * Copyright (C) 2019-2023 Intel Corporation <www.intel.com>
  */
 
 #ifndef _SYSTEM_MANAGER_SOC64_H_
@@ -102,6 +102,23 @@ void populate_sysmgr_pinmux(void);
 #define ALT_SYSMGR_SCRATCH_REG_0_DDR_SHA_MASK		BIT(30)
 #define ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK	(BIT(29) | BIT(28))
 #define ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT	28
+/*
+ * Bits for SYSMGR_SOC64_BOOT_SCRATCH_COLD8
+ * Bit[31] reserved for FSBL to check DDR DBE is triggered (set by SDM to "1") ?
+ *
+ * Bit[30] reserved for FSBL to update the DDR init progress
+ * 1 - means in progress, 0 - haven't started / DDR is up running.
+ *
+ * Bit[29] reserved for FSBL to check OCRAM DBE is triggered (set by SDM to "1")
+ *
+ * Bit[17:1] - Setting by Linux EDAC.
+ * Bit[1](ECC_OCRAM), Bit[16](ECC_DDR0), Bit[17](ECC_DDR1)
+ */
+#define ALT_SYSMGR_SCRATCH_REG_8_DDR_DBE_MASK		BIT(31)
+#define ALT_SYSMGR_SCRATCH_REG_8_DDR_PROGRESS_MASK	BIT(30)
+#define ALT_SYSMGR_SCRATCH_REG_8_OCRAM_DBE_MASK		BIT(29)
+#define ALT_SYSMGR_SCRATCH_REG_8_IO96B_HPS_MASK		GENMASK(28, 27)
+#define ALT_SYSMGR_SCRATCH_REG_8_IO96B_HPS_SHIFT	27
 
 #define SYSMGR_SDMMC				SYSMGR_SOC64_SDMMC
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 3/5] arm: socfpga: soc64: Add F2SDRAM sideband manager base address for SOC64
  2023-04-23 18:11 [PATCH v1 0/5] Add new DDR driver support for Agilex7 sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 1/5] ddr: altera: agilex7: Add SDRAM driver for AGILEX7 sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 2/5] arm: socfpga: agilex7: Add boot scratch register used for DDR driver sin.hui.kho
@ 2023-04-23 18:11 ` sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 4/5] arm: socfpga: agilex7: Add DDR handoff data support for AGILEX7 sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 5/5] ddr: altera: Add IOSSM mailbox support for DDR driver sin.hui.kho
  4 siblings, 0 replies; 6+ messages in thread
From: sin.hui.kho @ 2023-04-23 18:11 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Simon Goldschmidt, Tien Fong Chee, Sin Hui Kho,
	Simon Glass, Stefan Roese, Dinesh Maniyam, Jit Loon Lim,
	Teik Heng, Kok Kiang

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

F2SDRAM sideband manager in MPFE is used in DDR driver to configure the
data traffic path.

Signed-off-by: Sin Hui Kho <sin.hui.kho@intel.com>
---
 arch/arm/mach-socfpga/include/mach/base_addr_soc64.h | 1 +
 1 file changed, 1 insertion(+)

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 eecbb037f5..cee7d482c8 100644
--- a/arch/arm/mach-socfpga/include/mach/base_addr_soc64.h
+++ b/arch/arm/mach-socfpga/include/mach/base_addr_soc64.h
@@ -17,6 +17,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
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 4/5] arm: socfpga: agilex7: Add DDR handoff data support for AGILEX7
  2023-04-23 18:11 [PATCH v1 0/5] Add new DDR driver support for Agilex7 sin.hui.kho
                   ` (2 preceding siblings ...)
  2023-04-23 18:11 ` [PATCH v1 3/5] arm: socfpga: soc64: Add F2SDRAM sideband manager base address for SOC64 sin.hui.kho
@ 2023-04-23 18:11 ` sin.hui.kho
  2023-04-23 18:11 ` [PATCH v1 5/5] ddr: altera: Add IOSSM mailbox support for DDR driver sin.hui.kho
  4 siblings, 0 replies; 6+ messages in thread
From: sin.hui.kho @ 2023-04-23 18:11 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Simon Goldschmidt, Tien Fong Chee, Sin Hui Kho,
	Simon Glass, Stefan Roese, Dinesh Maniyam, Jit Loon Lim,
	Teik Heng, Kok Kiang

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

Add AGILEX7 supported DDR handoff data

Signed-off-by: Sin Hui Kho <sin.hui.kho@intel.com>
---
 arch/arm/mach-socfpga/include/mach/handoff_soc64.h | 11 ++++++++++-
 arch/arm/mach-socfpga/wrap_handoff_soc64.c         |  4 ++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-socfpga/include/mach/handoff_soc64.h b/arch/arm/mach-socfpga/include/mach/handoff_soc64.h
index b0134dd9bd..bfda3c42bb 100644
--- a/arch/arm/mach-socfpga/include/mach/handoff_soc64.h
+++ b/arch/arm/mach-socfpga/include/mach/handoff_soc64.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0
  *
- * Copyright (C) 2016-2021 Intel Corporation <www.intel.com>
+ * Copyright (C) 2016-2023 Intel Corporation <www.intel.com>
  *
  */
 
@@ -27,7 +27,16 @@
 	IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \
 	IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7)
 #define SOC64_HANDOFF_BASE		0xFFE3F000
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7)
+#define SOC64_HANDOFF_MISC		(SOC64_HANDOFF_BASE + 0x628)
+/* DDR handoff */
+#define SOC64_HANDOFF_MAGIC_DDR	0x5344524D
+#define SOC64_HANDOFF_DDR_BASE	(SOC64_HANDOFF_BASE + 0x610)
+#define SOC64_HANDOFF_DDR_LEN	2
+#define SOC64_HANDOFF_DDR_INTERLEAVING_MODE_MASK	BIT(0)
+#else
 #define SOC64_HANDOFF_MISC		(SOC64_HANDOFF_BASE + 0x610)
+#endif
 #elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
 #define SOC64_HANDOFF_BASE		0xFFE5F000
 #define SOC64_HANDOFF_MISC		(SOC64_HANDOFF_BASE + 0x630)
diff --git a/arch/arm/mach-socfpga/wrap_handoff_soc64.c b/arch/arm/mach-socfpga/wrap_handoff_soc64.c
index e7cb5ea89c..1abbe5a0d0 100644
--- a/arch/arm/mach-socfpga/wrap_handoff_soc64.c
+++ b/arch/arm/mach-socfpga/wrap_handoff_soc64.c
@@ -31,6 +31,10 @@ static enum endianness check_endianness(u32 handoff)
 	case SOC64_HANDOFF_DDR_PHY_INIT_ENGINE_MAGIC:
 		debug("%s: PHY engine handoff data\n", __func__);
 		return LITTLE_ENDIAN;
+#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX7)
+	case SOC64_HANDOFF_MAGIC_DDR:
+		debug("%s: SOC64_HANDOFF_MAGIC_DDR\n", __func__);
+		return BIG_ENDIAN;
 #endif
 	default:
 		debug("%s: Unknown endianness!!\n", __func__);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 5/5] ddr: altera: Add IOSSM mailbox support for DDR driver
  2023-04-23 18:11 [PATCH v1 0/5] Add new DDR driver support for Agilex7 sin.hui.kho
                   ` (3 preceding siblings ...)
  2023-04-23 18:11 ` [PATCH v1 4/5] arm: socfpga: agilex7: Add DDR handoff data support for AGILEX7 sin.hui.kho
@ 2023-04-23 18:11 ` sin.hui.kho
  4 siblings, 0 replies; 6+ messages in thread
From: sin.hui.kho @ 2023-04-23 18:11 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Simon Goldschmidt, Tien Fong Chee, Sin Hui Kho,
	Simon Glass, Stefan Roese, Dinesh Maniyam, Jit Loon Lim,
	Teik Heng, Kok Kiang

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

Add IOSSM mailbox support for DDR driver to access memory interface
implemented on an IO96B instance.

Signed-off-by: Sin Hui Kho <sin.hui.kho@intel.com>
---
 drivers/ddr/altera/Makefile        |   2 +-
 drivers/ddr/altera/iossm_mailbox.c | 847 +++++++++++++++++++++++++++++
 drivers/ddr/altera/iossm_mailbox.h | 142 +++++
 3 files changed, 990 insertions(+), 1 deletion(-)
 create mode 100644 drivers/ddr/altera/iossm_mailbox.c
 create mode 100644 drivers/ddr/altera/iossm_mailbox.h

diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
index 555357d669..59938168b5 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -12,5 +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
+obj-$(CONFIG_TARGET_SOCFPGA_AGILEX7) += sdram_soc64.o sdram_agilex7.o iossm_mailbox.o
 endif
diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c
new file mode 100644
index 0000000000..80aa2fa533
--- /dev/null
+++ b/drivers/ddr/altera/iossm_mailbox.c
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <hang.h>
+#include <asm/io.h>
+#include "iossm_mailbox.h"
+#include <wait_bit.h>
+
+/* supported DDR type list */
+static const char *ddr_type_list[7] = {
+	"DDR4", "DDR5", "DDR5_RDIMM", "LPDDR4", "LPDDR5", "QDRIV", "UNKNOWN"
+};
+
+/* Mailbox request function
+ * This function will send the request to IOSSM mailbox and wait for response return
+ *
+ * @io96b_csr_addr: CSR address for the target IO96B
+ * @ip_type:	    IP type for the specified memory interface
+ * @instance_id:    IP instance ID for the specified memory interface
+ * @usr_cmd_type:   User desire IOSSM mailbox command type
+ * @usr_cmd_opcode: User desire IOSSM mailbox command opcode
+ * @cmd_param_*:    Parameters (if applicable) for the requested IOSSM mailbox command
+ * @resp_data_len:  User desire extra response data fields other than
+ *					CMD_RESPONSE_DATA_SHORT field on CMD_RESPONSE_STATUS
+ * @resp:			Structure contain responses returned from the requested IOSSM
+ *					mailbox command
+ */
+int io96b_mb_req(phys_addr_t io96b_csr_addr, u32 ip_type, u32 instance_id
+					, u32 usr_cmd_type, u32 usr_cmd_opcode, u32 cmd_param_0
+					, u32 cmd_param_1, u32 cmd_param_2, u32 cmd_param_3
+					, u32 cmd_param_4, u32 cmd_param_5, u32 cmd_param_6
+					, u32 resp_data_len, struct io96b_mb_resp *resp)
+{
+	int i;
+	int ret;
+	u32 cmd_req, cmd_resp;
+
+	/* Initialized zeros for responses*/
+	resp->cmd_resp_status = 0;
+	resp->cmd_resp_data_0 = 0;
+	resp->cmd_resp_data_1 = 0;
+	resp->cmd_resp_data_2 = 0;
+
+	/* Ensure CMD_REQ is cleared before write any command request */
+	ret = wait_for_bit_le32((const void *)(io96b_csr_addr + IOSSM_CMD_REQ_OFFSET)
+				, GENMASK(31, 0), 0, TIMEOUT, false);
+
+	if (ret) {
+		printf("%s: CMD_REQ not ready\n", __func__);
+		return -1;
+	}
+
+	/* Write CMD_PARAM_* */
+	for (i = 0; i < 6 ; i++) {
+		switch (i) {
+		case 0:
+			if (cmd_param_0)
+				writel(cmd_param_0, io96b_csr_addr + IOSSM_CMD_PARAM_0_OFFSET);
+			break;
+		case 1:
+			if (cmd_param_1)
+				writel(cmd_param_1, io96b_csr_addr + IOSSM_CMD_PARAM_1_OFFSET);
+			break;
+		case 2:
+			if (cmd_param_2)
+				writel(cmd_param_2, io96b_csr_addr + IOSSM_CMD_PARAM_2_OFFSET);
+			break;
+		case 3:
+			if (cmd_param_3)
+				writel(cmd_param_3, io96b_csr_addr + IOSSM_CMD_PARAM_3_OFFSET);
+			break;
+		case 4:
+			if (cmd_param_4)
+				writel(cmd_param_4, io96b_csr_addr + IOSSM_CMD_PARAM_4_OFFSET);
+			break;
+		case 5:
+			if (cmd_param_5)
+				writel(cmd_param_5, io96b_csr_addr + IOSSM_CMD_PARAM_5_OFFSET);
+			break;
+		case 6:
+			if (cmd_param_6)
+				writel(cmd_param_6, io96b_csr_addr + IOSSM_CMD_PARAM_6_OFFSET);
+			break;
+		default:
+			printf("%s: Invalid command parameter\n", __func__);
+		}
+	}
+
+	/* Write CMD_REQ (IP_TYPE, IP_INSTANCE_ID, CMD_TYPE and CMD_OPCODE) */
+	cmd_req = (usr_cmd_opcode << 0) | (usr_cmd_type << 16) | (instance_id << 24) |
+				(ip_type << 29);
+	writel(cmd_req, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+	debug("%s: Write 0x%x to IOSSM_CMD_REQ_OFFSET 0x%llx\n", __func__, cmd_req
+		, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+
+	/* Read CMD_RESPONSE_READY in CMD_RESPONSE_STATUS*/
+	ret = wait_for_bit_le32((const void *)(io96b_csr_addr +
+			IOSSM_CMD_RESPONSE_STATUS_OFFSET), IOSSM_STATUS_COMMAND_RESPONSE_READY, 1,
+			TIMEOUT, false);
+
+	if (ret) {
+		printf("%s: CMD_RESPONSE ERROR:\n", __func__);
+		cmd_resp = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+		printf("%s: STATUS_GENERAL_ERROR: 0x%x\n", __func__, (cmd_resp >> 1) & 0xF);
+		printf("%s: STATUS_CMD_RESPONSE_ERROR: 0x%x\n", __func__, (cmd_resp >> 5) & 0x7);
+	}
+
+	/* read CMD_RESPONSE_STATUS*/
+	resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__, io96b_csr_addr +
+		IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	/* read CMD_RESPONSE_DATA_* */
+	for (i = 0; i < resp_data_len; i++) {
+		switch (i) {
+		case 0:
+			resp->cmd_resp_data_0 =
+					readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET);
+			debug("%s: IOSSM_CMD_RESPONSE_DATA_0_OFFSET 0x%llx: 0x%x\n", __func__
+				, io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET,
+				resp->cmd_resp_data_0);
+			break;
+		case 1:
+			resp->cmd_resp_data_1 =
+					readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET);
+			debug("%s: IOSSM_CMD_RESPONSE_DATA_1_OFFSET 0x%llx: 0x%x\n", __func__
+				, io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET,
+				resp->cmd_resp_data_1);
+			break;
+		case 2:
+			resp->cmd_resp_data_2 =
+					readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET);
+			debug("%s: IOSSM_CMD_RESPONSE_DATA_2_OFFSET 0x%llx: 0x%x\n", __func__
+				, io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET,
+				resp->cmd_resp_data_2);
+			break;
+		default:
+			printf("%s: Invalid response data\n", __func__);
+		}
+	}
+
+	/* write CMD_RESPONSE_READY = 0 */
+	clrbits_le32((u32 *)(uintptr_t)(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET)
+					, IOSSM_STATUS_COMMAND_RESPONSE_READY);
+
+	resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x (cleared)\n", __func__, io96b_csr_addr +
+		IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	return 0;
+}
+
+/*
+ * Initial function to be called to set memory interface IP type and instance ID
+ * IP type and instance ID need to be determined before sending mailbox command
+ */
+void io96b_mb_init(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	u8 ip_type_ret, instance_id_ret;
+	int i, j, k;
+
+	debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance);
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		debug("%s: get memory interface IO96B %d\n", __func__, i);
+		switch (i) {
+		case 0:
+			/* Get memory interface IP type & instance ID (IP identifier) */
+			io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0
+					, CMD_GET_SYS_INFO, GET_MEM_INTF_INFO
+					, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+			debug("%s: get response from memory interface IO96B %d\n", __func__, i);
+			/* Retrieve number of memory interface(s) */
+			io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface =
+				IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3;
+
+			/* Retrieve memory interface IP type and instance ID (IP identifier) */
+			j = 0;
+			for (k = 0; k < MAX_MEM_INTERFACES_SUPPORTED; k++) {
+				switch (k) {
+				case 0:
+					ip_type_ret = (usr_resp.cmd_resp_data_0 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_0 >> 24) & 0x1F;
+					break;
+				case 1:
+					ip_type_ret = (usr_resp.cmd_resp_data_1 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_1 >> 24) & 0x1F;
+					break;
+				}
+
+				if (ip_type_ret) {
+					io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] = ip_type_ret;
+					io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] =
+						instance_id_ret;
+					j++;
+				}
+
+				debug("%s: IO96B %d [%d]: ip_type: 0x%x\n", __func__, i, k
+					, ip_type_ret);
+				debug("%s: IO96B %d [%d]: instance_id: 0x%x\n", __func__, i, k
+					, instance_id_ret);
+			}
+;
+			break;
+		case 1:
+			/* Get memory interface IP type and instance ID (IP identifier) */
+			io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0, CMD_GET_SYS_INFO
+					, GET_MEM_INTF_INFO, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+			debug("%s: get response from memory interface IO96B %d\n", __func__, i);
+			/* Retrieve number of memory interface(s) */
+			io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface =
+				IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3;
+			debug("%s: IO96B %d: num_mem_interface: 0x%x\n", __func__, i
+				, io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface);
+
+			/* Retrieve memory interface IP type and instance ID (IP identifier) */
+			j = 0;
+			for (k = 0; k < MAX_MEM_INTERFACES_SUPPORTED; k++) {
+				switch (k) {
+				case 0:
+					ip_type_ret = (usr_resp.cmd_resp_data_0 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_0 >> 24) & 0x1F;
+					break;
+				case 1:
+					ip_type_ret = (usr_resp.cmd_resp_data_1 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_1 >> 24) & 0x1F;
+					break;
+				}
+
+				if (ip_type_ret) {
+					io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] = ip_type_ret;
+					io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] =
+						instance_id_ret;
+					j++;
+				}
+
+				debug("%s: IO96B %d [%d]: ip_type: 0x%x\n", __func__, i, k
+					, ip_type_ret);
+				debug("%s: IO96B %d [%d]: instance_id: 0x%x\n", __func__, i, k
+					, instance_id_ret);
+			}
+			break;
+		}
+	}
+}
+
+int io96b_cal_status(phys_addr_t addr)
+{
+	int ret;
+	phys_addr_t status_addr = addr + IOSSM_STATUS_OFFSET;
+	/* Ensure calibration completed */
+	ret = wait_for_bit_le32((const void *)status_addr, IOSSM_STATUS_CAL_BUSY, false
+							, 1000000000, false);
+
+	debug("%s: Cal_stat 0x%llx: 0x%x\n", __func__, status_addr, readl(status_addr));
+
+	if (ret) {
+		printf("%s: SDRAM calibration IO96b instance 0x%llx timeout\n", __func__
+			, status_addr);
+		hang();
+	}
+
+	/* Calibration status */
+	if (readl(status_addr) == 0x1)
+		return 0;
+	else
+		return -EPERM;
+}
+
+void init_mem_cal(struct io96b_info *io96b_ctrl)
+{
+	int count, i, ret;
+
+	/* Initialize overall calibration status */
+	io96b_ctrl->overall_cal_status = false;
+
+	/* Check initial calibration status for the assigned IO96B*/
+	count = 0;
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			ret = io96b_cal_status(io96b_ctrl->io96b_0.io96b_csr_addr);
+			if (ret) {
+				io96b_ctrl->io96b_0.cal_status = false;
+				printf("%s: Initial DDR calibration IO96B_0 failed %d\n", __func__
+						, ret);
+				break;
+			}
+			io96b_ctrl->io96b_0.cal_status = true;
+			debug("%s: Initial DDR calibration IO96B_0 succeed\n", __func__);
+			count++;
+			break;
+		case 1:
+			ret = io96b_cal_status(io96b_ctrl->io96b_1.io96b_csr_addr);
+			if (ret) {
+				io96b_ctrl->io96b_1.cal_status = false;
+				printf("%s: Initial DDR calibration IO96B_1 failed %d\n", __func__
+						, ret);
+				break;
+			}
+			io96b_ctrl->io96b_1.cal_status = true;
+			debug("%s: Initial DDR calibration IO96B_1 succeed\n", __func__);
+			count++;
+			break;
+		}
+	}
+
+	if (count == io96b_ctrl->num_instance)
+		io96b_ctrl->overall_cal_status = true;
+}
+
+/*
+ * Trying 3 times re-calibration if initial calibration failed
+ */
+int trig_mem_cal(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	bool recal_done;
+	int i, j;
+	u8 cal_stat;
+	u32 reg;
+
+	/* Initialize overall calibration status */
+	io96b_ctrl->overall_cal_status = false;
+
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			if (!(io96b_ctrl->io96b_0.cal_status)) {
+				recal_done = false;
+
+				/* Re-calibration first memory interface with failed calibration */
+				for (j = 0; j < 3; j++) {
+				/* Get the memory calibration status for first memory interface */
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[0], 0
+						, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0
+						, 0, 0, 0, 0, 2, &usr_resp);
+					reg = readl(io96b_ctrl->io96b_0.io96b_csr_addr +
+							usr_resp.cmd_resp_data_0);
+					cal_stat =  reg & GENMASK(2, 0);
+
+					/* Calibration was successful or INTF_0 unused*/
+					if (cal_stat < 0x2) {
+						recal_done = true;
+						break;
+					}
+
+					/* Calibration failed - recalibration */
+					if (cal_stat == 0x2) {
+						io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[0]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[0]
+						, CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0
+						, 0, 0, 2, &usr_resp);
+					}
+
+					/* Calibration ongoing */
+					while (cal_stat == 0x4) {
+						udelay(1000);
+
+						io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+							, io96b_ctrl->io96b_0.mb_ctrl.ip_type[0], 0
+							, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS
+							, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+						reg = readl(io96b_ctrl->io96b_0.io96b_csr_addr +
+								usr_resp.cmd_resp_data_0);
+						cal_stat =  reg & GENMASK(2, 0);
+					}
+				}
+
+				if (!recal_done) {
+					printf("%s: Error as SDRAM calibration failed\n", __func__);
+					hang();
+				}
+
+				recal_done = false;
+
+				/* Re-calibration second memory interface with failed calibration */
+				for (j = 0; j < 3; j++) {
+				/* Get the memory calibration status for second memory interface */
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[1], 0
+						, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0
+						, 0, 0, 0, 0, 2, &usr_resp);
+					reg = readl(io96b_ctrl->io96b_0.io96b_csr_addr +
+							usr_resp.cmd_resp_data_1);
+					cal_stat =  reg & GENMASK(2, 0);
+
+					/* Calibration was successful or INTF_0 unused*/
+					if (cal_stat < 0x2) {
+						recal_done = true;
+						break;
+					}
+
+					/* Calibration failed - recalibration */
+					if (cal_stat == 0x2) {
+						io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[1]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[0]
+						, CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0
+						, 0, 0, 2, &usr_resp);
+					}
+
+					/* Calibration ongoing */
+					while (cal_stat == 0x4) {
+						udelay(1000);
+
+						io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+							, io96b_ctrl->io96b_0.mb_ctrl.ip_type[1], 0
+							, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS
+							, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+						reg = readl(io96b_ctrl->io96b_0.io96b_csr_addr +
+								usr_resp.cmd_resp_data_1);
+						cal_stat =  reg & GENMASK(2, 0);
+					}
+				}
+
+				if (!recal_done) {
+					printf("%s: Error as SDRAM calibration failed\n", __func__);
+					hang();
+				}
+
+				io96b_ctrl->io96b_0.cal_status = true;
+			}
+			break;
+		case 1:
+			if (!(io96b_ctrl->io96b_1.cal_status)) {
+				recal_done = false;
+
+				/* Re-calibration first memory interface with failed calibration */
+				for (j = 0; j < 3; j++) {
+				/* Get the memory calibration status for first memory interface */
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[0], 0
+						, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0
+						, 0, 0, 0, 0, 2, &usr_resp);
+					reg = readl(io96b_ctrl->io96b_1.io96b_csr_addr +
+							usr_resp.cmd_resp_data_0);
+					cal_stat =  reg & GENMASK(2, 0);
+
+					/* Calibration was successful or INTF_0 unused*/
+					if (cal_stat < 0x2) {
+						recal_done = true;
+						break;
+					}
+
+					/* Calibration failed - recalibration */
+					if (cal_stat == 0x2) {
+						io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[0]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[0]
+						, CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0
+						, 0, 0, 2, &usr_resp);
+					}
+
+					/* Calibration ongoing */
+					while (cal_stat == 0x4) {
+						udelay(1000);
+
+						io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+							, io96b_ctrl->io96b_1.mb_ctrl.ip_type[0], 0
+							, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS
+							, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+						reg = readl(io96b_ctrl->io96b_1.io96b_csr_addr +
+								usr_resp.cmd_resp_data_0);
+						cal_stat =  reg & GENMASK(2, 0);
+					}
+				}
+
+				if (!recal_done) {
+					printf("%s: Error as SDRAM calibration failed\n", __func__);
+					hang();
+				}
+
+				recal_done = false;
+
+				/* Re-calibration second memory interface with failed calibration */
+				for (j = 0; j < 3; j++) {
+				/* Get the memory calibration status for second memory interface */
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[1], 0
+						, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0
+						, 0, 0, 0, 0, 2, &usr_resp);
+					reg = readl(io96b_ctrl->io96b_1.io96b_csr_addr +
+							usr_resp.cmd_resp_data_1);
+					cal_stat =  reg & GENMASK(2, 0);
+
+					/* Calibration was successful or INTF_0 unused*/
+					if (cal_stat < 0x2) {
+						recal_done = true;
+						break;
+					}
+
+					/* Calibration failed - recalibration */
+					if (cal_stat == 0x2) {
+						io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[1]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[0]
+						, CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0, 0
+						, 0, 0, 2, &usr_resp);
+					}
+
+					/* Calibration ongoing */
+					while (cal_stat == 0x4) {
+						udelay(1000);
+
+						io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+							, io96b_ctrl->io96b_1.mb_ctrl.ip_type[1], 0
+							, CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS
+							, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+						reg = readl(io96b_ctrl->io96b_1.io96b_csr_addr +
+								usr_resp.cmd_resp_data_1);
+						cal_stat =  reg & GENMASK(2, 0);
+					}
+				}
+
+				if (!recal_done) {
+					printf("%s: Error as SDRAM calibration failed\n", __func__);
+					hang();
+				}
+
+				io96b_ctrl->io96b_1.cal_status = true;
+			}
+			break;
+		}
+	}
+
+	if (io96b_ctrl->io96b_0.cal_status && io96b_ctrl->io96b_1.cal_status) {
+		debug("%s: Overall SDRAM calibration success\n", __func__);
+		io96b_ctrl->overall_cal_status = true;
+	}
+
+	return 0;
+}
+
+int get_mem_technology(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	u8 ddr_type_ret;
+
+	/* Initialize ddr type */
+	io96b_ctrl->ddr_type = ddr_type_list[6];
+
+	/* Get and ensure all memory interface(s) same DDR type */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j]
+						, CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, 0, 0, 0, 0
+						, 0, 0, 0, 0, &usr_resp);
+
+				ddr_type_ret =
+					IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 0);
+
+				if (!strcmp(io96b_ctrl->ddr_type, "UNKNOWN"))
+					io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret];
+
+				if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) {
+					printf("%s: Mismatch DDR type on IO96B_0\n", __func__);
+					return -ENOEXEC;
+				}
+			}
+			break;
+		case 1:
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j]
+						, CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, 0, 0, 0, 0
+						, 0, 0, 0, 0, &usr_resp);
+
+				ddr_type_ret =
+					IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 0);
+
+				if (!strcmp(io96b_ctrl->ddr_type, "UNKNOWN"))
+					io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret];
+
+				if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) {
+					printf("%s: Mismatch DDR type on IO96B_1\n", __func__);
+					return -ENOEXEC;
+				}
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int get_mem_width_info(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	u16 memory_size;
+	u16 total_memory_size = 0;
+
+	/* Get all memory interface(s) total memory size on all instance(s) */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			memory_size = 0;
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j]
+						, CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, 0, 0, 0, 0
+						, 0, 0, 0, 2, &usr_resp);
+
+				memory_size = memory_size +
+						(usr_resp.cmd_resp_data_1 & GENMASK(7, 0));
+			}
+
+			if (!memory_size) {
+				printf("%s: Failed to get valid memory size\n", __func__);
+				return -ENOEXEC;
+			}
+
+			io96b_ctrl->io96b_0.size = memory_size;
+
+			break;
+		case 1:
+			memory_size = 0;
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j]
+						, CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, 0, 0, 0, 0
+						, 0, 0, 0, 2, &usr_resp);
+
+				memory_size = memory_size +
+						(usr_resp.cmd_resp_data_1 & GENMASK(7, 0));
+			}
+
+			if (!memory_size) {
+				printf("%s: Failed to get valid memory size\n", __func__);
+				return -ENOEXEC;
+			}
+
+			io96b_ctrl->io96b_1.size = memory_size;
+
+			break;
+		}
+
+		total_memory_size = total_memory_size + memory_size;
+	}
+
+	if (!total_memory_size) {
+		printf("%s: Failed to get valid memory size\n", __func__);
+		return -ENOEXEC;
+	}
+
+	io96b_ctrl->overall_size = total_memory_size;
+
+	return 0;
+}
+
+int ecc_enable_status(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	bool ecc_stat_set = false;
+	bool ecc_stat;
+
+	/* Initialize ECC status */
+	io96b_ctrl->ecc_status = false;
+
+	/* Get and ensure all memory interface(s) same ECC status */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				debug("%s: ECC_ENABLE_STATUS\n", __func__);
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j]
+						, CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS, 0, 0, 0
+						, 0, 0, 0, 0, 0, &usr_resp);
+
+				ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+						& GENMASK(1, 0)) == 0 ? false : true);
+
+				if (!ecc_stat_set) {
+					io96b_ctrl->ecc_status = ecc_stat;
+					ecc_stat_set = true;
+				}
+
+				if (ecc_stat != io96b_ctrl->ecc_status) {
+					printf("%s: Mismatch DDR ECC status on IO96B_0\n"
+						, __func__);
+					return -ENOEXEC;
+				}
+			}
+			break;
+		case 1:
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				debug("%s: ECC_ENABLE_STATUS\n", __func__);
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j]
+						, CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS, 0, 0, 0
+						, 0, 0, 0, 0, 0, &usr_resp);
+
+				ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+						& GENMASK(1, 0)) == 0 ? false : true);
+
+				if (!ecc_stat_set) {
+					io96b_ctrl->ecc_status = ecc_stat;
+					ecc_stat_set = true;
+				}
+
+				if (ecc_stat != io96b_ctrl->ecc_status) {
+					printf("%s: Mismatch DDR ECC status on IO96B_1\n"
+						, __func__);
+					return -ENOEXEC;
+				}
+			}
+			break;
+		}
+	}
+
+	debug("%s: ECC: %s\n", __func__, io96b_ctrl->ecc_status ? "Enabled" : "Disabled");
+
+	return 0;
+}
+
+int bist_mem_init_start(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	bool bist_start, bist_success;
+	u32 start;
+	int count;
+
+	/* Full memory initialization BIST performed on all memory interface(s) */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				bist_start = false;
+				bist_success = false;
+
+				/* Start memory initialization BIST on full memory address */
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j]
+						, CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0x9
+						, 0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+				bist_start =
+					(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& BIT(0));
+
+				if (!bist_start) {
+					printf("%s: Failed to initialized memory on IO96B_0\n"
+						, __func__);
+					printf("%s: BIST_MEM_INIT_START Error code 0x%x\n", __func__
+					, (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 1)) > 0x1);
+					return -ENOEXEC;
+				}
+
+				/* Polling for the initiated memory initialization BIST status */
+				start = get_timer(0);
+				count = 1;
+				while (!bist_success) {
+					debug(" io96b_0: BIST delay count: %d\n", count);
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j]
+						, CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_STATUS, 0
+						, 0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+					bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT
+							(usr_resp.cmd_resp_status) & BIT(0));
+
+					mdelay(5000);
+					count++;
+				}
+			}
+
+			debug("%s: Memory initialized successfully on IO96B_0\n", __func__);
+			debug("%s: Initialized success with %d ms\n", __func__
+				, (unsigned int)get_timer(start));
+
+			break;
+		case 1:
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				bist_start = false;
+				bist_success = false;
+
+				/* Start memory initialization BIST on full memory address */
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j]
+						, CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0x40
+						, 0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+				bist_start =
+					(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& BIT(0));
+
+				if (!bist_start) {
+					printf("%s: Failed to initialized memory on IO96B_1\n"
+						, __func__);
+					printf("%s: BIST_MEM_INIT_START Error code 0x%x\n", __func__
+					, (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 1)) > 0x1);
+					return -ENOEXEC;
+				}
+
+				/* Polling for the initiated memory initialization BIST status */
+				start = get_timer(0);
+				count = 1;
+				while (!bist_success) {
+					debug(" io96b_1: BIST delay count: %d\n", count);
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_type[j]
+						, io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j]
+						, CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_STATUS, 0
+						, 0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+					bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT
+							(usr_resp.cmd_resp_status) & BIT(0));
+
+					mdelay(5000);
+					count++;
+				}
+			}
+			debug("%s: Memory initialized successfully on IO96B_1\n", __func__);
+			debug("%s: Initialized success with %d ms\n", __func__
+				, (unsigned int)get_timer(start));
+			break;
+		}
+	}
+	return 0;
+}
diff --git a/drivers/ddr/altera/iossm_mailbox.h b/drivers/ddr/altera/iossm_mailbox.h
new file mode 100644
index 0000000000..e66b240120
--- /dev/null
+++ b/drivers/ddr/altera/iossm_mailbox.h
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Intel Corporation <www.intel.com>
+ */
+
+#define TIMEOUT_10000MS				10000
+#define TIMEOUT					TIMEOUT_10000MS
+#define IOSSM_STATUS_CAL_SUCCESS		BIT(0)
+#define IOSSM_STATUS_CAL_FAIL			BIT(1)
+#define IOSSM_STATUS_CAL_BUSY			BIT(2)
+#define IOSSM_STATUS_COMMAND_RESPONSE_READY	BIT(0)
+#define IOSSM_CMD_RESPONSE_STATUS_OFFSET	0x45C
+#define IOSSM_CMD_RESPONSE_DATA_0_OFFSET	0x458
+#define IOSSM_CMD_RESPONSE_DATA_1_OFFSET	0x454
+#define IOSSM_CMD_RESPONSE_DATA_2_OFFSET	0x450
+#define IOSSM_CMD_REQ_OFFSET			0x43C
+#define IOSSM_CMD_PARAM_0_OFFSET		0x438
+#define IOSSM_CMD_PARAM_1_OFFSET		0x434
+#define IOSSM_CMD_PARAM_2_OFFSET		0x430
+#define IOSSM_CMD_PARAM_3_OFFSET		0x42C
+#define IOSSM_CMD_PARAM_4_OFFSET		0x428
+#define IOSSM_CMD_PARAM_5_OFFSET		0x424
+#define IOSSM_CMD_PARAM_6_OFFSET		0x420
+#define IOSSM_STATUS_OFFSET			0x400
+#define IOSSM_CMD_RESPONSE_DATA_SHORT_MASK	GENMASK(31, 16)
+#define IOSSM_CMD_RESPONSE_DATA_SHORT(data) (((data) & IOSSM_CMD_RESPONSE_DATA_SHORT_MASK) >> 16)
+#define MAX_IO96B_SUPPORTED			2
+#define MAX_MEM_INTERFACES_SUPPORTED		2
+
+/* supported mailbox command type */
+enum iossm_mailbox_cmd_type  {
+	CMD_NOP,
+	CMD_GET_SYS_INFO,
+	CMD_GET_MEM_INFO,
+	CMD_GET_MEM_CAL_INFO,
+	CMD_TRIG_CONTROLLER_OP,
+	CMD_TRIG_MEM_CAL_OP
+};
+
+/* supported mailbox command opcode */
+enum iossm_mailbox_cmd_opcode  {
+	GET_MEM_INTF_INFO = 0x0001,
+	GET_MEM_TECHNOLOGY,
+	GET_MEMCLK_FREQ_KHZ,
+	GET_MEM_WIDTH_INFO,
+	ECC_ENABLE_SET = 0x0101,
+	ECC_ENABLE_STATUS,
+	ECC_INTERRUPT_STATUS,
+	ECC_INTERRUPT_ACK,
+	ECC_INTERRUPT_MASK,
+	ECC_WRITEBACK_ENABLE,
+	ECC_SCRUB_IN_PROGRESS_STATUS = 0x0201,
+	ECC_SCRUB_MODE_0_START,
+	ECC_SCRUB_MODE_1_START,
+	BIST_STANDARD_MODE_START = 0x0301,
+	BIST_RESULTS_STATUS,
+	BIST_MEM_INIT_START,
+	BIST_MEM_INIT_STATUS,
+	BIST_SET_DATA_PATTERN_UPPER,
+	BIST_SET_DATA_PATTERN_LOWER,
+	TRIG_MEM_CAL = 0x000a,
+	GET_MEM_CAL_STATUS
+};
+
+/*
+ * IOSSM mailbox required information
+ *
+ * @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
+ */
+struct io96b_mb_ctrl {
+	u32 num_mem_interface;
+	u32 ip_type[2];
+	u32 ip_instance_id[2];
+};
+
+/*
+ * IOSSM mailbox response outputs
+ *
+ * @cmd_resp_status: Command Interface status
+ * @cmd_resp_data_*: More spaces for command response
+ */
+struct io96b_mb_resp {
+	u32 cmd_resp_status;
+	u32 cmd_resp_data_0;
+	u32 cmd_resp_data_1;
+	u32 cmd_resp_data_2;
+};
+
+/*
+ * 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;
+};
+
+/*
+ * Overall IO96B instance(s) information
+ *
+ * @num_instance:	Number of instance(s) assigned to HPS
+ * @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)
+ * @overall_size:	Total DDR memory size
+ * @io96b_0:		IO96B 0 instance specific information
+ * @io96b_1:		IO96B 1 instance specific information
+ */
+struct io96b_info {
+	u8 num_instance;
+	bool overall_cal_status;
+	const char *ddr_type;
+	bool ecc_status;
+	u16 overall_size;
+	struct io96b_instance io96b_0;
+	struct io96b_instance io96b_1;
+};
+
+int io96b_mb_req(phys_addr_t io96b_csr_addr, u32 ip_type, u32 instance_id
+			, u32 usr_cmd_type, u32 usr_cmd_opcode, u32 cmd_param_0
+			, u32 cmd_param_1, u32 cmd_param_2, u32 cmd_param_3, u32 cmd_param_4
+			, u32 cmd_param_5, u32 cmd_param_6, u32 resp_data_len
+			, struct io96b_mb_resp *resp);
+
+/* Supported IOSSM mailbox function */
+void io96b_mb_init(struct io96b_info *io96b_ctrl);
+int io96b_cal_status(phys_addr_t addr);
+void init_mem_cal(struct io96b_info *io96b_ctrl);
+int trig_mem_cal(struct io96b_info *io96b_ctrl);
+int get_mem_technology(struct io96b_info *io96b_ctrl);
+int get_mem_width_info(struct io96b_info *io96b_ctrl);
+int ecc_enable_status(struct io96b_info *io96b_ctrl);
+int bist_mem_init_start(struct io96b_info *io96b_ctrl);
+void trig_mem_cal_must(struct io96b_info *io96b_ctrl);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-04-23 18:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-23 18:11 [PATCH v1 0/5] Add new DDR driver support for Agilex7 sin.hui.kho
2023-04-23 18:11 ` [PATCH v1 1/5] ddr: altera: agilex7: Add SDRAM driver for AGILEX7 sin.hui.kho
2023-04-23 18:11 ` [PATCH v1 2/5] arm: socfpga: agilex7: Add boot scratch register used for DDR driver sin.hui.kho
2023-04-23 18:11 ` [PATCH v1 3/5] arm: socfpga: soc64: Add F2SDRAM sideband manager base address for SOC64 sin.hui.kho
2023-04-23 18:11 ` [PATCH v1 4/5] arm: socfpga: agilex7: Add DDR handoff data support for AGILEX7 sin.hui.kho
2023-04-23 18:11 ` [PATCH v1 5/5] ddr: altera: Add IOSSM mailbox support for DDR driver sin.hui.kho

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox