All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.