From: Siew Chin Lim <elly.siew.chin....@intel.com>

Add SDRAM driver for Diamond Mesa.

Signed-off-by: Siew Chin Lim <elly.siew.chin....@intel.com>
Signed-off-by: Tien Fong Chee <tien.fong.c...@intel.com>
---
 arch/arm/mach-socfpga/include/mach/misc.h |    4 +
 arch/arm/mach-socfpga/misc_soc64.c        |   70 +-
 drivers/ddr/altera/sdram_dm.c             | 1227 +++++++++++++++++++++
 3 files changed, 1300 insertions(+), 1 deletion(-)
 create mode 100644 drivers/ddr/altera/sdram_dm.c

diff --git a/arch/arm/mach-socfpga/include/mach/misc.h 
b/arch/arm/mach-socfpga/include/mach/misc.h
index 8460acb00d..f366f51001 100644
--- a/arch/arm/mach-socfpga/include/mach/misc.h
+++ b/arch/arm/mach-socfpga/include/mach/misc.h
@@ -44,6 +44,10 @@ void socfpga_sdram_remap_zero(void);
 int is_fpga_config_ready(void);
 #endif
 
+#if defined(CONFIG_TARGET_SOCFPGA_DM)
+bool is_ddr_init_skipped(void);
+#endif
+
 void do_bridge_reset(int enable, unsigned int mask);
 void force_periph_program(unsigned int status);
 bool is_regular_boot_valid(void);
diff --git a/arch/arm/mach-socfpga/misc_soc64.c 
b/arch/arm/mach-socfpga/misc_soc64.c
index 2acdfad07b..e61276d8ed 100644
--- a/arch/arm/mach-socfpga/misc_soc64.c
+++ b/arch/arm/mach-socfpga/misc_soc64.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
+ * Copyright (C) 2016-2020 Intel Corporation <www.intel.com>
  *
  */
 
@@ -20,6 +20,14 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/* Reset type */
+enum reset_type {
+       por_reset,
+       warm_reset,
+       cold_reset,
+       rsu_reset
+};
+
 /*
  * FPGA programming support for SoC FPGA Stratix 10
  */
@@ -89,3 +97,63 @@ void do_bridge_reset(int enable, unsigned int mask)
 
        socfpga_bridges_reset(enable);
 }
+
+/* Only applicable to DM */
+#ifdef CONFIG_TARGET_SOCFPGA_DM
+static bool is_ddr_retention_enabled(u32 boot_scratch_cold0_reg)
+{
+       return boot_scratch_cold0_reg &
+              ALT_SYSMGR_SCRATCH_REG_0_DDR_RETENTION_MASK;
+}
+
+static bool is_ddr_bitstream_sha_matching(u32 boot_scratch_cold0_reg)
+{
+       return boot_scratch_cold0_reg & ALT_SYSMGR_SCRATCH_REG_0_DDR_SHA_MASK;
+}
+
+static enum reset_type get_reset_type(u32 boot_scratch_cold0_reg)
+{
+       return (boot_scratch_cold0_reg &
+               ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK) >>
+               ALT_SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT;
+}
+
+bool is_ddr_init_skipped(void)
+{
+       u32 reg = readl(socfpga_get_sysmgr_addr() +
+                       SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
+
+       if (get_reset_type(reg) == por_reset) {
+               debug("%s: POR reset is triggered\n", __func__);
+               debug("%s: DDR init is required\n", __func__);
+               return false;
+       }
+
+       if (get_reset_type(reg) == warm_reset) {
+               debug("%s: Warm reset is triggered\n", __func__);
+               debug("%s: DDR init is skipped\n", __func__);
+               return true;
+       }
+
+       if ((get_reset_type(reg) == cold_reset) ||
+           (get_reset_type(reg) == rsu_reset)) {
+               debug("%s: Cold/RSU reset is triggered\n", __func__);
+
+               if (is_ddr_retention_enabled(reg)) {
+                       debug("%s: DDR retention bit is set\n", __func__);
+
+                       if (is_ddr_bitstream_sha_matching(reg)) {
+                               debug("%s: Matching in DDR bistream\n",
+                                     __func__);
+                               debug("%s: DDR init is skipped\n", __func__);
+                               return true;
+                       }
+
+                       debug("%s: Mismatch in DDR bistream\n", __func__);
+               }
+       }
+
+       debug("%s: DDR init is required\n", __func__);
+       return false;
+}
+#endif
diff --git a/drivers/ddr/altera/sdram_dm.c b/drivers/ddr/altera/sdram_dm.c
new file mode 100644
index 0000000000..2254961f79
--- /dev/null
+++ b/drivers/ddr/altera/sdram_dm.c
@@ -0,0 +1,1227 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <hang.h>
+#include <ram.h>
+#include <reset.h>
+#include "sdram_soc64.h"
+#include <wait_bit.h>
+#include <asm/arch/firewall.h>
+#include <asm/arch/handoff_soc64.h>
+#include <asm/arch/misc.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/system_manager.h>
+#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Memory reset manager */
+#define MEM_RST_MGR_STATUS     0x8
+
+/* Register and bit in memory reset manager */
+#define MEM_RST_MGR_STATUS_RESET_COMPLETE      BIT(0)
+#define MEM_RST_MGR_STATUS_PWROKIN_STATUS      BIT(1)
+#define MEM_RST_MGR_STATUS_CONTROLLER_RST      BIT(2)
+#define MEM_RST_MGR_STATUS_AXI_RST             BIT(3)
+
+#define TIMEOUT_200MS     200
+#define TIMEOUT_5000MS    5000
+
+/* DDR4 umctl2 */
+#define DDR4_STAT_OFFSET               0x4
+#define DDR4_STAT_SELFREF_TYPE         (BIT(5) | BIT(4))
+#define DDR4_STAT_SELFREF_TYPE_SHIFT   4
+#define DDR4_STAT_OPERATING_MODE       (BIT(2) | BIT(1) | BIT(0))
+
+#define DDR4_MRCTRL0_OFFSET            0x10
+#define DDR4_MRCTRL0_MR_TYPE           BIT(0)
+#define DDR4_MRCTRL0_MPR_EN            BIT(1)
+#define DDR4_MRCTRL0_MR_RANK           (BIT(5) | BIT(4))
+#define DDR4_MRCTRL0_MR_RANK_SHIFT     4
+#define DDR4_MRCTRL0_MR_ADDR           (BIT(15) | BIT(14) | BIT(13) | BIT(12))
+#define DDR4_MRCTRL0_MR_ADDR_SHIFT     12
+#define DDR4_MRCTRL0_MR_WR             BIT(31)
+
+#define DDR4_MRCTRL1_OFFSET            0x14
+#define DDR4_MRCTRL1_MR_DATA           0x3FFFF
+
+#define DDR4_MRSTAT_OFFSET             0x18
+#define DDR4_MRSTAT_MR_WR_BUSY         BIT(0)
+
+#define DDR4_MRCTRL2_OFFSET            0x1C
+
+#define DDR4_PWRCTL_OFFSET                     0x30
+#define DDR4_PWRCTL_SELFREF_EN                 BIT(0)
+#define DDR4_PWRCTL_POWERDOWN_EN               BIT(1)
+#define DDR4_PWRCTL_EN_DFI_DRAM_CLK_DISABLE    BIT(3)
+#define DDR4_PWRCTL_SELFREF_SW                 BIT(5)
+
+#define DDR4_PWRTMG_OFFSET             0x34
+#define DDR4_HWLPCTL_OFFSET            0x38
+#define DDR4_RFSHCTL0_OFFSET           0x50
+#define DDR4_RFSHCTL1_OFFSET           0x54
+
+#define DDR4_RFSHCTL3_OFFSET                   0x60
+#define DDR4_RFSHCTL3_DIS_AUTO_REFRESH         BIT(0)
+#define DDR4_RFSHCTL3_REFRESH_MODE             (BIT(6) | BIT(5) | BIT(4))
+#define DDR4_RFSHCTL3_REFRESH_MODE_SHIFT       4
+
+#define DDR4_ECCCFG0_OFFSET            0x70
+#define DDR4_ECC_MODE                  (BIT(2) | BIT(1) | BIT(0))
+#define DDR4_DIS_SCRUB                 BIT(4)
+
+#define DDR4_CRCPARCTL1_OFFSET                 0x04
+#define DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE        BIT(8)
+#define DDR4_CRCPARCTL1_ALERT_WAIT_FOR_SW      BIT(9)
+
+#define DDR4_CRCPARCTL0_OFFSET                 0xC0
+#define DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR BIT(1)
+
+#define DDR4_CRCPARSTAT_OFFSET                 0xCC
+#define DDR4_CRCPARSTAT_DFI_ALERT_ERR_INT      BIT(16)
+#define DDR4_CRCPARSTAT_DFI_ALERT_ERR_FATL_INT BIT(17)
+#define DDR4_CRCPARSTAT_DFI_ALERT_ERR_NO_SW    BIT(19)
+#define DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW      BIT(29)
+
+#define DDR4_DFIMISC_OFFSET                    0x1B0
+#define DDR4_DFIMISC_DFI_INIT_COMPLETE_EN      BIT(0)
+#define DDR4_DFIMISC_DFI_INIT_START            BIT(5)
+
+#define DDR4_DFISTAT_OFFSET            0x1BC
+#define DDR4_DFI_INIT_COMPLETE         BIT(0)
+
+#define DDR4_DBG0_OFFSET               0x300
+
+#define DDR4_DBG1_OFFSET               0x304
+#define DDR4_DBG1_DISDQ                        BIT(0)
+#define DDR4_DBG1_DIS_HIF              BIT(1)
+
+#define DDR4_DBGCAM_OFFSET                     0x308
+#define DDR4_DBGCAM_DBG_RD_Q_EMPTY             BIT(25)
+#define DDR4_DBGCAM_DBG_WR_Q_EMPTY             BIT(26)
+#define DDR4_DBGCAM_RD_DATA_PIPELINE_EMPTY     BIT(28)
+#define DDR4_DBGCAM_WR_DATA_PIPELINE_EMPTY     BIT(29)
+
+#define DDR4_SWCTL_OFFSET              0x320
+#define DDR4_SWCTL_SW_DONE             BIT(0)
+
+#define DDR4_SWSTAT_OFFSET             0x324
+#define DDR4_SWSTAT_SW_DONE_ACK                BIT(0)
+
+#define DDR4_PSTAT_OFFSET              0x3FC
+#define DDR4_PSTAT_RD_PORT_BUSY_0      BIT(0)
+#define DDR4_PSTAT_WR_PORT_BUSY_0      BIT(16)
+
+#define DDR4_PCTRL0_OFFSET             0x490
+#define DDR4_PCTRL0_PORT_EN            BIT(0)
+
+#define DDR4_SBRCTL_OFFSET             0xF24
+#define DDR4_SBRCTL_SCRUB_INTERVAL     0x1FFF00
+#define DDR4_SBRCTL_SCRUB_EN           BIT(0)
+#define DDR4_SBRCTL_SCRUB_WRITE                BIT(2)
+#define DDR_SBRCTL_SCRUB_BURST_1       BIT(4)
+
+#define DDR4_SBRSTAT_OFFSET            0xF28
+#define DDR4_SBRSTAT_SCRUB_BUSY BIT(0)
+#define DDR4_SBRSTAT_SCRUB_DONE BIT(1)
+
+#define DDR4_SBRWDATA0_OFFSET          0xF2C
+#define DDR4_SBRWDATA1_OFFSET          0xF30
+#define DDR4_SBRSTART0_OFFSET          0xF38
+#define DDR4_SBRSTART1_OFFSET          0xF3C
+#define DDR4_SBRRANGE0_OFFSET          0xF40
+#define DDR4_SBRRANGE1_OFFSET          0xF44
+
+/* DDR PHY */
+#define DDR_PHY_TXODTDRVSTREN_B0_P0            0x2009A
+#define DDR_PHY_RXPBDLYTG0_R0                  0x200D0
+#define DDR_PHY_CALRATE_OFFSET                 0x40110
+#define DDR_PHY_CALZAP_OFFSET                  0x40112
+#define DDR_PHY_SEQ0BDLY0_P0_OFFSET            0x40016
+#define DDR_PHY_SEQ0BDLY1_P0_OFFSET            0x40018
+#define DDR_PHY_SEQ0BDLY2_P0_OFFSET            0x4001A
+#define DDR_PHY_SEQ0BDLY3_P0_OFFSET            0x4001C
+#define DDR_PHY_SEQ0DISABLEFLAG0_OFFSET                0x120018
+#define DDR_PHY_SEQ0DISABLEFLAG1_OFFSET                0x12001A
+#define DDR_PHY_SEQ0DISABLEFLAG2_OFFSET                0x12001C
+#define DDR_PHY_SEQ0DISABLEFLAG3_OFFSET                0x12001E
+#define DDR_PHY_SEQ0DISABLEFLAG4_OFFSET                0x120020
+#define DDR_PHY_SEQ0DISABLEFLAG5_OFFSET                0x120022
+#define DDR_PHY_SEQ0DISABLEFLAG6_OFFSET                0x120024
+#define DDR_PHY_SEQ0DISABLEFLAG7_OFFSET                0x120026
+#define DDR_PHY_UCCLKHCLKENABLES_OFFSET                0x180100
+
+#define DDR_PHY_APBONLY0_OFFSET                        0x1A0000
+#define DDR_PHY_MICROCONTMUXSEL                        BIT(0)
+
+#define DDR_PHY_MICRORESET_OFFSET              0x1A0132
+#define DDR_PHY_MICRORESET_STALL               BIT(0)
+#define DDR_PHY_MICRORESET_RESET               BIT(3)
+
+#define DDR_PHY_TXODTDRVSTREN_B0_P1            0x22009A
+
+/* Operating mode */
+#define INIT_OPM                       0x000
+#define NORMAL_OPM                     0x001
+#define PWR_D0WN_OPM                   0x010
+#define SELF_SELFREF_OPM               0x011
+#define DDR4_DEEP_PWR_DOWN_OPM         0x100
+
+/* Refresh mode */
+#define FIXED_1X               0
+#define FIXED_2X               BIT(0)
+#define FIXED_4X               BIT(4)
+
+/* Address of mode register */
+#define MR0    0x0000
+#define MR1    0x0001
+#define MR2    0x0010
+#define MR3    0x0011
+#define MR4    0x0100
+#define MR5    0x0101
+#define MR6    0x0110
+#define MR7    0x0111
+
+/* MR rank */
+#define RANK0          0x1
+#define RANK1          0x2
+#define ALL_RANK       0x3
+
+#define MR5_BIT4       BIT(4)
+
+#ifdef CONFIG_TARGET_SOCFPGA_DM
+#define PSI_LL_SLAVE_APS_PER_OFST      0x00000000
+#define alt_write_hword(addr, val)     (writew(val, addr))
+#define SDM_HPS_PERI_ADDR_TRANSLATION(_HPS_OFFSET_) \
+       (PSI_LL_SLAVE_APS_PER_OFST + (_HPS_OFFSET_))
+#define DDR_PHY_BASE   0xF8800000
+#define SNPS_PHY_TRANSLATION(_PHY_OFFSET_) \
+       (PSI_LL_SLAVE_APS_PER_OFST + ((DDR_PHY_BASE + ((_PHY_OFFSET_) << 1))))
+#define dwc_ddrphy_apb_wr(dest, data) \
+       alt_write_hword(SNPS_PHY_TRANSLATION(dest), data)
+#define b_max 1
+#define timing_group_max 4
+#endif
+
+/* DDR handoff structure */
+struct ddr_handoff {
+       phys_addr_t mem_reset_base;
+       phys_addr_t umctl2_handoff_base;
+       phys_addr_t umctl2_base;
+       size_t umctl2_total_length;
+       size_t umctl2_handoff_length;
+       phys_addr_t phy_handoff_base;
+       phys_addr_t phy_base;
+       size_t phy_total_length;
+       size_t phy_handoff_length;
+       phys_addr_t phy_engine_handoff_base;
+       size_t phy_engine_total_length;
+       size_t phy_engine_handoff_length;
+};
+
+static int clr_ca_parity_error_status(struct ddr_handoff *ddr_handoff_info)
+{
+       int ret;
+
+       debug("%s: Clear C/A parity error status in MR5[4]\n", __func__);
+
+       /* Set mode register MRS */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_MRCTRL0_OFFSET,
+                    DDR4_MRCTRL0_MPR_EN);
+
+       /* Set mode register to write operation */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_MRCTRL0_OFFSET,
+                    DDR4_MRCTRL0_MR_TYPE);
+
+       /* Set the address of mode rgister to 0x101(MR5) */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_MRCTRL0_OFFSET,
+                    (MR5 << DDR4_MRCTRL0_MR_ADDR_SHIFT) &
+                    DDR4_MRCTRL0_MR_ADDR);
+
+       /* Set MR rank to rank 1 */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_MRCTRL0_OFFSET,
+                    (RANK1 << DDR4_MRCTRL0_MR_RANK_SHIFT) &
+                    DDR4_MRCTRL0_MR_RANK);
+
+       /* Clear C/A parity error status in MR5[4] */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_MRCTRL1_OFFSET,
+                    MR5_BIT4);
+
+       /* Trigger mode register read or write operation */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_MRCTRL0_OFFSET,
+                    DDR4_MRCTRL0_MR_WR);
+
+       /* Wait for retry done */
+       ret = wait_for_bit_le32((const void *)(ddr_handoff_info->umctl2_base +
+                               DDR4_MRSTAT_OFFSET), DDR4_MRSTAT_MR_WR_BUSY,
+                               false, TIMEOUT_200MS, false);
+       if (ret) {
+               debug("%s: Timeout while waiting for", __func__);
+               debug(" no outstanding MR transaction\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ddr4_retry_software_sequence(struct ddr_handoff *ddr_handoff_info)
+{
+       u32 value;
+       int ret;
+
+       /* Check software can perform MRS/MPR/PDA? */
+       value = readl(ddr_handoff_info->umctl2_base + DDR4_CRCPARSTAT_OFFSET) &
+                     DDR4_CRCPARSTAT_DFI_ALERT_ERR_NO_SW;
+
+       if (value) {
+               debug("%s: Software can't perform MRS/MPR/PDA\n", __func__);
+
+               /* Clear interrupt bit for DFI alert error */
+               setbits_le32(ddr_handoff_info->umctl2_base +
+                            DDR4_CRCPARCTL0_OFFSET,
+                            DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR);
+
+               /* Wait for retry done */
+               ret = wait_for_bit_le32((const void *)
+                                       (ddr_handoff_info->umctl2_base +
+                                       DDR4_MRSTAT_OFFSET),
+                                       DDR4_MRSTAT_MR_WR_BUSY,
+                                       false, TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" no outstanding MR transaction\n");
+                       return ret;
+               }
+
+               if (clr_ca_parity_error_status(ddr_handoff_info))
+                       return ret;
+       } else {
+               debug("%s: Software can perform MRS/MPR/PDA\n", __func__);
+
+               ret = wait_for_bit_le32((const void *)
+                                       (ddr_handoff_info->umctl2_base +
+                                       DDR4_MRSTAT_OFFSET),
+                                       DDR4_MRSTAT_MR_WR_BUSY,
+                                       false, TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" no outstanding MR transaction\n");
+                       return ret;
+               }
+
+               if (clr_ca_parity_error_status(ddr_handoff_info))
+                       return ret;
+
+               /* Clear interrupt bit for DFI alert error */
+               setbits_le32(ddr_handoff_info->umctl2_base +
+                            DDR4_CRCPARCTL0_OFFSET,
+                            DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR);
+       }
+
+       return 0;
+}
+
+static int ensure_retry_procedure_complete(struct ddr_handoff 
*ddr_handoff_info)
+{
+       u32 value;
+       u32 start = get_timer(0);
+       int ret;
+
+       /* Check parity/crc/error window is emptied ? */
+       value = readl(ddr_handoff_info->umctl2_base + DDR4_CRCPARSTAT_OFFSET) &
+                     DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW;
+
+       /* Polling until parity/crc/error window is emptied */
+       while (value) {
+               if (get_timer(start) > TIMEOUT_200MS) {
+                       debug("%s: Timeout while waiting for",
+                             __func__);
+                       debug(" parity/crc/error window empty\n");
+                       return -ETIMEDOUT;
+               }
+
+               /* Check software intervention is enabled? */
+               value = readl(ddr_handoff_info->umctl2_base +
+                             DDR4_CRCPARCTL1_OFFSET) &
+                             DDR4_CRCPARCTL1_ALERT_WAIT_FOR_SW;
+               if (value) {
+                       debug("%s: Software intervention is enabled\n",
+                             __func__);
+
+                       /* Check dfi alert error interrupt is set? */
+                       value = readl(ddr_handoff_info->umctl2_base +
+                                     DDR4_CRCPARSTAT_OFFSET) &
+                                     DDR4_CRCPARSTAT_DFI_ALERT_ERR_INT;
+
+                       if (value) {
+                               ret =
+                               ddr4_retry_software_sequence(ddr_handoff_info);
+                               debug("%s: DFI alert error interrupt ",
+                                     __func__);
+                               debug("is set\n");
+
+                               if (ret)
+                                       return ret;
+                       }
+
+                       /*
+                        * Check fatal parity error interrupt is set?
+                        */
+                       value = readl(ddr_handoff_info->umctl2_base +
+                                     DDR4_CRCPARSTAT_OFFSET) &
+                                     DDR4_CRCPARSTAT_DFI_ALERT_ERR_FATL_INT;
+                       if (value) {
+                               printf("%s: Fatal parity error  ",
+                                      __func__);
+                               printf("interrupt is set, Hang it!!\n");
+                               hang();
+                       }
+               }
+
+               value = readl(ddr_handoff_info->umctl2_base +
+                             DDR4_CRCPARSTAT_OFFSET) &
+                             DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW;
+
+               udelay(1);
+               WATCHDOG_RESET();
+       }
+
+       return 0;
+}
+
+static int enable_quasi_dynamic_reg_grp3(struct ddr_handoff *ddr_handoff_info)
+{
+       u32 i, value, backup;
+       int ret;
+
+       /* Disable input traffic per port */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_PCTRL0_OFFSET,
+                    DDR4_PCTRL0_PORT_EN);
+
+       /* Polling AXI port until idle */
+       ret = wait_for_bit_le32((const void *)(ddr_handoff_info->umctl2_base +
+                               DDR4_PSTAT_OFFSET), DDR4_PSTAT_WR_PORT_BUSY_0 |
+                               DDR4_PSTAT_RD_PORT_BUSY_0, false,
+                               TIMEOUT_200MS, false);
+       if (ret) {
+               debug("%s: Timeout while waiting for", __func__);
+               debug(" controller idle\n");
+               return ret;
+       }
+
+       /* Backup user setting */
+       backup = readl(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET);
+
+       /* Disable input traffic to the controller */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET,
+                    DDR4_DBG1_DIS_HIF);
+
+       /*
+        * Ensure CAM/data pipelines are empty.
+        * Poll until CAM/data pipelines are set at least twice,
+        * timeout at 200ms
+        */
+       for (i = 0; i < 2; i++) {
+               ret = wait_for_bit_le32((const void *)
+                                       (ddr_handoff_info->umctl2_base +
+                                       DDR4_DBGCAM_OFFSET),
+                                       DDR4_DBGCAM_WR_DATA_PIPELINE_EMPTY |
+                                       DDR4_DBGCAM_RD_DATA_PIPELINE_EMPTY |
+                                       DDR4_DBGCAM_DBG_WR_Q_EMPTY |
+                                       DDR4_DBGCAM_DBG_RD_Q_EMPTY, true,
+                                       TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: loop(%u): Timeout while waiting for",
+                             __func__, i + 1);
+                       debug(" CAM/data pipelines are empty\n");
+
+                       /* Restore user setting */
+                       writel(backup, ddr_handoff_info->umctl2_base +
+                              DDR4_DBG1_OFFSET);
+
+                       return ret;
+               }
+       }
+
+       /* Check DDR4 retry is enabled ? */
+       value = readl(ddr_handoff_info->umctl2_base + DDR4_CRCPARCTL1_OFFSET) &
+                     DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE;
+
+       if (value) {
+               debug("%s: DDR4 retry is enabled\n", __func__);
+
+               ret = ensure_retry_procedure_complete(ddr_handoff_info);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" retry procedure complete\n");
+
+                       /* Restore user setting */
+                       writel(backup, ddr_handoff_info->umctl2_base +
+                              DDR4_DBG1_OFFSET);
+
+                       return ret;
+               }
+       }
+
+       /* Restore user setting */
+       writel(backup, ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET);
+
+       debug("%s: Quasi-dynamic group 3 registers are enabled\n", __func__);
+
+       return 0;
+}
+
+static int scrubbing_ddr_config(struct ddr_handoff *ddr_handoff_info)
+{
+       u32 backup[7];
+       int ret;
+
+       /* Reset to default value, prevent scrubber stop due to lower power */
+       writel(0, ddr_handoff_info->umctl2_base + DDR4_PWRCTL_OFFSET);
+
+       /* Disable input traffic per port */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_PCTRL0_OFFSET,
+                    DDR4_PCTRL0_PORT_EN);
+
+       /* Backup user settings */
+       backup[0] = readl(ddr_handoff_info->umctl2_base + DDR4_SBRCTL_OFFSET);
+       backup[1] = readl(ddr_handoff_info->umctl2_base +
+                         DDR4_SBRWDATA0_OFFSET);
+       backup[2] = readl(ddr_handoff_info->umctl2_base +
+                         DDR4_SBRWDATA1_OFFSET);
+       backup[3] = readl(ddr_handoff_info->umctl2_base +
+                         DDR4_SBRSTART0_OFFSET);
+       backup[4] = readl(ddr_handoff_info->umctl2_base +
+                         DDR4_SBRSTART1_OFFSET);
+       backup[5] = readl(ddr_handoff_info->umctl2_base +
+                         DDR4_SBRRANGE0_OFFSET);
+       backup[6] = readl(ddr_handoff_info->umctl2_base +
+                         DDR4_SBRRANGE1_OFFSET);
+
+       /* Scrub_burst = 1, scrub_mode = 1(performs writes) */
+       writel(DDR_SBRCTL_SCRUB_BURST_1 | DDR4_SBRCTL_SCRUB_WRITE,
+              ddr_handoff_info->umctl2_base + DDR4_SBRCTL_OFFSET);
+
+       /* Zeroing whole DDR */
+       writel(0, ddr_handoff_info->umctl2_base +
+              DDR4_SBRWDATA0_OFFSET);
+       writel(0, ddr_handoff_info->umctl2_base +
+              DDR4_SBRWDATA1_OFFSET);
+       writel(0, ddr_handoff_info->umctl2_base + DDR4_SBRSTART0_OFFSET);
+       writel(0, ddr_handoff_info->umctl2_base + DDR4_SBRSTART1_OFFSET);
+       writel(0, ddr_handoff_info->umctl2_base + DDR4_SBRRANGE0_OFFSET);
+       writel(0, ddr_handoff_info->umctl2_base + DDR4_SBRRANGE1_OFFSET);
+
+#ifdef CONFIG_TARGET_SOCFPGA_DM
+       writel(0x0FFFFFFF, ddr_handoff_info->umctl2_base +
+              DDR4_SBRRANGE0_OFFSET);
+#endif
+
+       /* Enables scrubber */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_SBRCTL_OFFSET,
+                    DDR4_SBRCTL_SCRUB_EN);
+
+       /* Polling all scrub writes commands have been sent */
+       ret = wait_for_bit_le32((const void *)(ddr_handoff_info->umctl2_base +
+                               DDR4_SBRSTAT_OFFSET), DDR4_SBRSTAT_SCRUB_DONE,
+                               true, TIMEOUT_5000MS, false);
+       if (ret) {
+               debug("%s: Timeout while waiting for", __func__);
+               debug(" sending all scrub commands\n");
+               return ret;
+       }
+
+       /* Polling all scrub writes data have been sent */
+       ret = wait_for_bit_le32((const void *)(ddr_handoff_info->umctl2_base +
+                               DDR4_SBRSTAT_OFFSET), DDR4_SBRSTAT_SCRUB_BUSY,
+                               false, TIMEOUT_5000MS, false);
+       if (ret) {
+               debug("%s: Timeout while waiting for", __func__);
+               debug(" sending all scrub data\n");
+               return ret;
+       }
+
+       /* Disables scrubber */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_SBRCTL_OFFSET,
+                    DDR4_SBRCTL_SCRUB_EN);
+
+       /* Restore user settings */
+       writel(backup[0], ddr_handoff_info->umctl2_base + DDR4_SBRCTL_OFFSET);
+       writel(backup[1], ddr_handoff_info->umctl2_base +
+              DDR4_SBRWDATA0_OFFSET);
+       writel(backup[2], ddr_handoff_info->umctl2_base +
+              DDR4_SBRWDATA1_OFFSET);
+       writel(backup[3], ddr_handoff_info->umctl2_base +
+              DDR4_SBRSTART0_OFFSET);
+       writel(backup[4], ddr_handoff_info->umctl2_base +
+              DDR4_SBRSTART1_OFFSET);
+       writel(backup[5], ddr_handoff_info->umctl2_base +
+              DDR4_SBRRANGE0_OFFSET);
+       writel(backup[6], ddr_handoff_info->umctl2_base +
+              DDR4_SBRRANGE1_OFFSET);
+
+       return 0;
+}
+
+static int init_umctl2(struct ddr_handoff *ddr_handoff_info, u32 *user_backup)
+{
+       u32 handoff_table[ddr_handoff_info->umctl2_handoff_length];
+       u32 i, value, expected_value;
+       u32 start = get_timer(0);
+       int ret;
+
+       printf("Initializing DDR controller ...\n");
+
+       /* Prevent controller from issuing read/write to SDRAM */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET,
+                    DDR4_DBG1_DISDQ);
+
+       /* Put SDRAM into self-refresh */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_PWRCTL_OFFSET,
+                    DDR4_PWRCTL_SELFREF_EN);
+
+       /* Enable quasi-dynamic programing of the controller registers */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_SWCTL_OFFSET,
+                    DDR4_SWCTL_SW_DONE);
+
+       /* Ensure the controller is in initialization mode */
+       ret = wait_for_bit_le32((const void *)(ddr_handoff_info->umctl2_base +
+                               DDR4_STAT_OFFSET), DDR4_STAT_OPERATING_MODE,
+                               false, TIMEOUT_200MS, false);
+       if (ret) {
+               debug("%s: Timeout while waiting for", __func__);
+               debug(" init operating mode\n");
+               return ret;
+       }
+
+       debug("%s: Handoff table address = 0x%p table length = 0x%08x\n",
+             __func__, (u32 *)handoff_table,
+             (u32)ddr_handoff_info->umctl2_handoff_length);
+
+       handoff_read((void *)ddr_handoff_info->umctl2_handoff_base,
+                    handoff_table, ddr_handoff_info->umctl2_handoff_length,
+                    little_endian);
+
+       for (i = 0; i < ddr_handoff_info->umctl2_handoff_length; i = i + 2) {
+               debug("%s: Absolute addr: 0x%08llx APB offset: 0x%08x",
+                     __func__, handoff_table[i] +
+                     ddr_handoff_info->umctl2_base, handoff_table[i]);
+               debug(" wr = 0x%08x ", handoff_table[i + 1]);
+
+               writel(handoff_table[i + 1], (uintptr_t)(handoff_table[i] +
+                      ddr_handoff_info->umctl2_base));
+
+               debug("rd = 0x%08x\n", readl((uintptr_t)(handoff_table[i] +
+                     ddr_handoff_info->umctl2_base)));
+       }
+
+       /* Backup user settings, restore after DDR up running */
+       *user_backup = readl(ddr_handoff_info->umctl2_base +
+                            DDR4_PWRCTL_OFFSET);
+
+       /* Polling granularity of refresh mode change to fixed 2x (DDR4) */
+       value = readl(ddr_handoff_info->umctl2_base + DDR4_RFSHCTL3_OFFSET) &
+                     DDR4_RFSHCTL3_REFRESH_MODE;
+
+       expected_value = FIXED_2X << DDR4_RFSHCTL3_REFRESH_MODE_SHIFT;
+
+       while (value != expected_value) {
+               if (get_timer(start) > TIMEOUT_200MS) {
+                       debug("%s: loop(%u): Timeout while waiting for",
+                             __func__, i + 1);
+                       debug(" fine granularity refresh mode change to ");
+                       debug("fixed 2x\n");
+                       debug("%s: expected_value = 0x%x value= 0x%x\n",
+                             __func__, expected_value, value);
+                       return -ETIMEDOUT;
+               }
+
+               value = readl(ddr_handoff_info->umctl2_base +
+                             DDR4_RFSHCTL3_OFFSET) &
+                             DDR4_RFSHCTL3_REFRESH_MODE;
+       }
+
+       /* Disable self resfresh */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_PWRCTL_OFFSET,
+                    DDR4_PWRCTL_SELFREF_EN);
+
+       /* Complete quasi-dynamic register programming */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_SWCTL_OFFSET,
+                    DDR4_SWCTL_SW_DONE);
+
+       /* Enable controller from issuing read/write to SDRAM */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET,
+                    DDR4_DBG1_DISDQ);
+
+       /* Release the controller from reset */
+       setbits_le32((uintptr_t)(readl(ddr_handoff_info->mem_reset_base) +
+                    MEM_RST_MGR_STATUS), MEM_RST_MGR_STATUS_AXI_RST |
+                    MEM_RST_MGR_STATUS_CONTROLLER_RST |
+                    MEM_RST_MGR_STATUS_RESET_COMPLETE);
+
+       printf("DDR controller configuration is completed\n");
+
+       return 0;
+}
+
+static int init_phy(struct ddr_handoff *ddr_handoff_info)
+{
+       u32 handoff_table[ddr_handoff_info->phy_handoff_length];
+       u32 i, value;
+       int ret;
+
+       printf("Initializing DDR PHY ...\n");
+
+       /* Check DDR4 retry is enabled ? */
+       value = readl(ddr_handoff_info->umctl2_base + DDR4_CRCPARCTL1_OFFSET) &
+                     DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE;
+
+       if (value) {
+               debug("%s: DDR4 retry is enabled\n", __func__);
+               debug("%s: Disable auto refresh is not supported\n", __func__);
+       } else {
+               /* Disable auto refresh */
+               setbits_le32(ddr_handoff_info->umctl2_base +
+                            DDR4_RFSHCTL3_OFFSET,
+                            DDR4_RFSHCTL3_DIS_AUTO_REFRESH);
+       }
+
+       /* Disable selfref_en & powerdown_en, nvr disable dfi dram clk */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_PWRCTL_OFFSET,
+                    DDR4_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
+                    DDR4_PWRCTL_POWERDOWN_EN | DDR4_PWRCTL_SELFREF_EN);
+
+       /* Enable quasi-dynamic programing of the controller registers */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_SWCTL_OFFSET,
+                    DDR4_SWCTL_SW_DONE);
+
+       ret = enable_quasi_dynamic_reg_grp3(ddr_handoff_info);
+       if (ret)
+               return ret;
+
+       /* Masking dfi init complete */
+       clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_DFIMISC_OFFSET,
+                    DDR4_DFIMISC_DFI_INIT_COMPLETE_EN);
+
+       /* Complete quasi-dynamic register programming */
+       setbits_le32(ddr_handoff_info->umctl2_base + DDR4_SWCTL_OFFSET,
+                    DDR4_SWCTL_SW_DONE);
+
+       /* Polling programming done */
+       ret = wait_for_bit_le32((const void *)(ddr_handoff_info->umctl2_base +
+                               DDR4_SWSTAT_OFFSET), DDR4_SWSTAT_SW_DONE_ACK,
+                               true, TIMEOUT_200MS, false);
+       if (ret) {
+               debug("%s: Timeout while waiting for", __func__);
+               debug(" programming done\n");
+               return ret;
+       }
+
+       debug("%s: Handoff table address = 0x%p table length = 0x%08x\n",
+             __func__, (u32 *)handoff_table,
+             (u32)ddr_handoff_info->umctl2_handoff_length);
+
+       /* Execute PHY configuration handoff */
+       handoff_read((void *)ddr_handoff_info->phy_handoff_base, handoff_table,
+                    (u32)ddr_handoff_info->phy_handoff_length, little_endian);
+
+       for (i = 0; i < ddr_handoff_info->phy_handoff_length; i = i + 2) {
+               /*
+                * Convert PHY odd offset to even offset that supported by
+                * ARM processor.
+                */
+               value = handoff_table[i] << 1;
+               debug("%s: Absolute addr: 0x%08llx, APB offset: 0x%08x ",
+                     __func__, value + ddr_handoff_info->phy_base, value);
+               debug("PHY offset: 0x%08x", handoff_table[i]);
+               debug(" wr = 0x%08x ", handoff_table[i + 1]);
+               writew(handoff_table[i + 1], (uintptr_t)(value +
+                      ddr_handoff_info->phy_base));
+               debug("rd = 0x%08x\n", readw((uintptr_t)(value +
+                     ddr_handoff_info->phy_base)));
+       }
+
+#ifdef CONFIG_TARGET_SOCFPGA_DM
+       u8 numdbyte = 0x0009;
+       u8 byte, lane;
+       u32 b_addr, c_addr;
+
+       /* Program TxOdtDrvStren bx_p0 */
+       for (byte = 0; byte < numdbyte; byte++) {
+               c_addr = byte << 13;
+
+               for (lane = 0; lane <= b_max ; lane++) {
+                       b_addr = lane << 9;
+                       writew(0x00, (uintptr_t)
+                              (ddr_handoff_info->phy_base +
+                              DDR_PHY_TXODTDRVSTREN_B0_P0 + c_addr +
+                              b_addr));
+               }
+       }
+
+       /* Program TxOdtDrvStren bx_p1 */
+       for (byte = 0; byte < numdbyte; byte++) {
+               c_addr = byte << 13;
+
+               for (lane = 0; lane <= b_max ; lane++) {
+                       b_addr = lane << 9;
+                       writew(0x00, (uintptr_t)
+                              (ddr_handoff_info->phy_base +
+                              DDR_PHY_TXODTDRVSTREN_B0_P1 + c_addr +
+                              b_addr));
+               }
+       }
+
+       /*
+        * [phyinit_C_initPhyConfig] Pstate=0, Memclk=1600MHz,
+        * Programming ARdPtrInitVal to 0x2
+        * DWC_DDRPHYA_MASTER0_ARdPtrInitVal_p0
+        */
+       dwc_ddrphy_apb_wr(0x2002e, 0x3);
+
+       /* [phyinit_C_initPhyConfig] Pstate=1,
+        * Memclk=1067MHz, Programming ARdPtrInitVal to 0x2
+        * DWC_DDRPHYA_MASTER0_ARdPtrInitVal_p1
+        */
+       dwc_ddrphy_apb_wr(0x12002e, 0x3);
+
+       /* DWC_DDRPHYA_MASTER0_DfiFreqXlat0 */
+       dwc_ddrphy_apb_wr(0x200f0, 0x6666);
+
+       /* DWC_DDRPHYA_DBYTE0_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x10020, 0x4);
+       /* DWC_DDRPHYA_DBYTE1_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x11020, 0x4);
+       /* DWC_DDRPHYA_DBYTE2_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x12020, 0x4);
+       /* DWC_DDRPHYA_DBYTE3_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x13020, 0x4); //
+       /*  DWC_DDRPHYA_DBYTE4_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x14020, 0x4);
+       /* DWC_DDRPHYA_DBYTE5_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x15020, 0x4);
+       /* DWC_DDRPHYA_DBYTE6_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x16020, 0x4);
+       /* DWC_DDRPHYA_DBYTE7_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x17020, 0x4);
+       /* DWC_DDRPHYA_DBYTE8_DFIMRL_p0 */
+       dwc_ddrphy_apb_wr(0x18020, 0x4);
+       /* DWC_DDRPHYA_MASTER0_HwtMRL_p0 */
+       dwc_ddrphy_apb_wr(0x20020, 0x4);
+#endif
+
+       printf("DDR PHY configuration is completed\n");
+
+       return 0;
+}
+
+static void phy_init_engine(struct ddr_handoff *ddr_handoff_info)
+{
+       u32 i, value;
+       u32 handoff_table[ddr_handoff_info->phy_engine_handoff_length];
+
+       printf("Load PHY Init Engine ...\n");
+
+       /* Execute PIE production code handoff */
+       handoff_read((void *)ddr_handoff_info->phy_engine_handoff_base,
+                    handoff_table,
+                    (u32)ddr_handoff_info->phy_engine_handoff_length,
+                    little_endian);
+
+       for (i = 0; i < ddr_handoff_info->phy_engine_handoff_length;
+           i = i + 2) {
+               debug("Handoff addr: 0x%8llx ", handoff_table[i] +
+                     ddr_handoff_info->phy_base);
+
+               /*
+                * Convert PHY odd offset to even offset that supported by
+                * ARM processor.
+                */
+               value = handoff_table[i] << 1;
+               debug("%s: Absolute addr: 0x%08llx, APB offset: 0x%08x ",
+                     __func__, value + ddr_handoff_info->phy_base, value);
+               debug("PHY offset: 0x%08x", handoff_table[i]);
+               debug(" wr = 0x%08x ", handoff_table[i + 1]);
+
+               writew(handoff_table[i + 1], (uintptr_t)(value +
+                      ddr_handoff_info->phy_base));
+
+               debug("rd = 0x%08x\n", readw((uintptr_t)(value +
+                     ddr_handoff_info->phy_base)));
+       }
+
+#ifdef CONFIG_TARGET_SOCFPGA_DM
+       u8 numdbyte = 0x0009;
+       u8 byte, timing_group;
+       u32 b_addr, c_addr;
+
+       /* Enable access to the PHY configuration registers */
+       clrbits_le16(ddr_handoff_info->phy_base + DDR_PHY_APBONLY0_OFFSET,
+                    DDR_PHY_MICROCONTMUXSEL);
+
+       /* Program RXPBDLYTG0 bx_p0 */
+       for (byte = 0; byte < numdbyte; byte++) {
+               c_addr = byte << 9;
+
+               for (timing_group = 0; timing_group <= timing_group_max;
+                       timing_group++) {
+                       b_addr = timing_group << 1;
+                       writew(0x00, (uintptr_t)
+                              (ddr_handoff_info->phy_base +
+                              DDR_PHY_RXPBDLYTG0_R0 + c_addr +
+                              b_addr));
+               }
+       }
+
+       /* Isolate the APB access from internal CSRs */
+       setbits_le16(ddr_handoff_info->phy_base + DDR_PHY_APBONLY0_OFFSET,
+                    DDR_PHY_MICROCONTMUXSEL);
+#endif
+
+       printf("End of loading PHY Init Engine\n");
+}
+
+int populate_ddr_handoff(struct ddr_handoff *ddr_handoff_info)
+{
+       /* DDR handoff */
+       ddr_handoff_info->mem_reset_base = SOC64_HANDOFF_DDR_MEMRESET_BASE;
+       debug("%s: DDR memory reset base = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->mem_reset_base);
+       debug("%s: DDR memory reset address = 0x%x\n", __func__,
+             readl(ddr_handoff_info->mem_reset_base));
+
+       /* DDR controller handoff */
+       ddr_handoff_info->umctl2_handoff_base =
+               SOC64_HANDOFF_DDR_UMCTL2_SECTION;
+       debug("%s: umctl2 handoff base = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->umctl2_handoff_base);
+
+       ddr_handoff_info->umctl2_base = readl(SOC64_HANDOFF_DDR_UMCTL2_BASE);
+       debug("%s: umctl2 base = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->umctl2_base);
+
+       ddr_handoff_info->umctl2_total_length =
+                       readl(ddr_handoff_info->umctl2_handoff_base +
+                             SOC64_HANDOFF_OFFSET_LENGTH);
+       debug("%s: Umctl2 total length in byte = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->umctl2_total_length);
+
+       ddr_handoff_info->umctl2_handoff_length =
+               get_handoff_size((void *)ddr_handoff_info->umctl2_handoff_base,
+                                little_endian);
+       debug("%s: Umctl2 handoff length in word(32-bit) = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->umctl2_handoff_length);
+
+       if (ddr_handoff_info->umctl2_handoff_length < 0)
+               return ddr_handoff_info->umctl2_handoff_length;
+
+       /* DDR PHY handoff */
+       ddr_handoff_info->phy_handoff_base =
+               ddr_handoff_info->umctl2_handoff_base +
+                       ddr_handoff_info->umctl2_total_length;
+       debug("%s: PHY handoff base = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->phy_handoff_base);
+
+       ddr_handoff_info->phy_base =
+               readl(ddr_handoff_info->phy_handoff_base +
+                     SOC64_HANDOFF_DDR_PHY_BASE_OFFSET);
+       debug("%s: PHY base = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->phy_base);
+
+       ddr_handoff_info->phy_total_length =
+                       readl(ddr_handoff_info->phy_handoff_base +
+                             SOC64_HANDOFF_OFFSET_LENGTH);
+       debug("%s: PHY total length in byte = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->phy_total_length);
+
+       ddr_handoff_info->phy_handoff_length =
+               get_handoff_size((void *)ddr_handoff_info->phy_handoff_base,
+                                little_endian);
+       debug("%s: PHY handoff length in word(32-bit) = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->phy_handoff_length);
+
+       if (ddr_handoff_info->phy_handoff_length < 0)
+               return ddr_handoff_info->phy_handoff_length;
+
+       /* DDR PHY Engine handoff */
+       ddr_handoff_info->phy_engine_handoff_base =
+                               ddr_handoff_info->phy_handoff_base +
+                                       ddr_handoff_info->phy_total_length;
+       debug("%s: PHY base = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->phy_engine_handoff_base);
+
+       ddr_handoff_info->phy_engine_total_length =
+                       readl(ddr_handoff_info->phy_engine_handoff_base +
+                             SOC64_HANDOFF_OFFSET_LENGTH);
+       debug("%s: PHY engine total length in byte = 0x%x\n", __func__,
+             (u32)ddr_handoff_info->phy_engine_total_length);
+
+       ddr_handoff_info->phy_engine_handoff_length =
+       get_handoff_size((void *)ddr_handoff_info->phy_engine_handoff_base,
+                        little_endian);
+       debug("%s: PHY engine handoff length in word(32-bit) = 0x%x\n",
+             __func__, (u32)ddr_handoff_info->phy_engine_handoff_length);
+
+       if (ddr_handoff_info->phy_engine_handoff_length < 0)
+               return ddr_handoff_info->phy_engine_handoff_length;
+
+       return 0;
+}
+
+int enable_ddr_clock(struct udevice *dev)
+{
+       struct clk *ddr_clk;
+       int ret;
+
+       /* Enable clock before init DDR */
+       ddr_clk = devm_clk_get(dev, "mem_clk");
+       if (!IS_ERR(ddr_clk)) {
+               ret = clk_enable(ddr_clk);
+               if (ret) {
+                       printf("%s: Failed to enable DDR clock\n", __func__);
+                       return ret;
+               }
+       } else {
+               ret = PTR_ERR(ddr_clk);
+               debug("%s: Failed to get DDR clock from dts\n", __func__);
+               return ret;
+       }
+
+       printf("%s: DDR clock is enabled\n", __func__);
+
+       return 0;
+}
+
+int sdram_mmr_init_full(struct udevice *dev)
+{
+       u32 value, user_backup;
+       u32 start = get_timer(0);
+       int ret;
+       struct bd_info bd;
+       struct ddr_handoff ddr_handoff_info;
+       struct altera_sdram_priv *priv = dev_get_priv(dev);
+
+       if (!is_ddr_init_skipped()) {
+               printf("%s: SDRAM init in progress ...\n", __func__);
+
+               ret = populate_ddr_handoff(&ddr_handoff_info);
+               if (ret) {
+                       debug("%s: Failed to populate DDR handoff\n", __func__);
+                       return ret;
+               }
+
+               /*
+                * Polling reset complete, must be high to ensure DDR subsystem
+                * in complete reset state before init DDR clock and DDR
+                * controller
+                */
+               ret = wait_for_bit_le32((const void *)((uintptr_t)(readl
+                                       (ddr_handoff_info.mem_reset_base) +
+                                       MEM_RST_MGR_STATUS)),
+                                       MEM_RST_MGR_STATUS_RESET_COMPLETE, true,
+                                       TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" reset complete done\n");
+                       return ret;
+               }
+
+               ret = enable_ddr_clock(dev);
+               if (ret)
+                       return ret;
+
+               /* Initialize DDR controller */
+               ret = init_umctl2(&ddr_handoff_info, &user_backup);
+               if (ret) {
+                       debug("%s: Failed to inilialize DDR controller\n",
+                             __func__);
+                       return ret;
+               }
+
+               /* Initialize DDR PHY */
+               ret = init_phy(&ddr_handoff_info);
+               if (ret) {
+                       debug("%s: Failed to inilialize DDR PHY\n", __func__);
+                       return ret;
+               }
+
+               /* Reset ARC processor when no using for security purpose */
+               setbits_le16(ddr_handoff_info.phy_base +
+                            DDR_PHY_MICRORESET_OFFSET,
+                            DDR_PHY_MICRORESET_RESET);
+
+               /* DDR freq set to support DDR4-3200 */
+               phy_init_engine(&ddr_handoff_info);
+
+               /* Trigger memory controller to init SDRAM */
+               /* Enable quasi-dynamic programing of controller registers */
+               clrbits_le32(ddr_handoff_info.umctl2_base + DDR4_SWCTL_OFFSET,
+                            DDR4_SWCTL_SW_DONE);
+
+               ret = enable_quasi_dynamic_reg_grp3(&ddr_handoff_info);
+               if (ret)
+                       return ret;
+
+               /* Start DFI init sequence */
+               setbits_le32(ddr_handoff_info.umctl2_base + DDR4_DFIMISC_OFFSET,
+                            DDR4_DFIMISC_DFI_INIT_START);
+
+               /* Complete quasi-dynamic register programming */
+               setbits_le32(ddr_handoff_info.umctl2_base + DDR4_SWCTL_OFFSET,
+                            DDR4_SWCTL_SW_DONE);
+
+               /* Polling programming done */
+               ret = wait_for_bit_le32((const void *)
+                                       (ddr_handoff_info.umctl2_base +
+                                       DDR4_SWSTAT_OFFSET),
+                                       DDR4_SWSTAT_SW_DONE_ACK, true,
+                                       TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" programming done\n");
+                       return ret;
+               }
+
+               /* Polling DFI init complete */
+               ret = wait_for_bit_le32((const void *)
+                                       (ddr_handoff_info.umctl2_base +
+                                       DDR4_DFISTAT_OFFSET),
+                                       DDR4_DFI_INIT_COMPLETE, true,
+                                       TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" DFI init done\n");
+                       return ret;
+               }
+
+               debug("DFI init completed.\n");
+
+               /* Enable quasi-dynamic programing of controller registers */
+               clrbits_le32(ddr_handoff_info.umctl2_base + DDR4_SWCTL_OFFSET,
+                            DDR4_SWCTL_SW_DONE);
+
+               ret = enable_quasi_dynamic_reg_grp3(&ddr_handoff_info);
+               if (ret)
+                       return ret;
+
+               /* Stop DFI init sequence */
+               clrbits_le32(ddr_handoff_info.umctl2_base + DDR4_DFIMISC_OFFSET,
+                            DDR4_DFIMISC_DFI_INIT_START);
+
+               /* Unmasking dfi init complete */
+               setbits_le32(ddr_handoff_info.umctl2_base + DDR4_DFIMISC_OFFSET,
+                            DDR4_DFIMISC_DFI_INIT_COMPLETE_EN);
+
+               /* Software exit from self-refresh */
+               clrbits_le32(ddr_handoff_info.umctl2_base + DDR4_PWRCTL_OFFSET,
+                            DDR4_PWRCTL_SELFREF_SW);
+
+               /* Complete quasi-dynamic register programming */
+               setbits_le32(ddr_handoff_info.umctl2_base + DDR4_SWCTL_OFFSET,
+                            DDR4_SWCTL_SW_DONE);
+
+               /* Polling programming done */
+               ret = wait_for_bit_le32((const void *)
+                                       (ddr_handoff_info.umctl2_base +
+                                       DDR4_SWSTAT_OFFSET),
+                                       DDR4_SWSTAT_SW_DONE_ACK, true,
+                                       TIMEOUT_200MS, false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for", __func__);
+                       debug(" programming done\n");
+                       return ret;
+               }
+
+               debug("DDR programming done\n");
+
+               /* Polling until SDRAM entered normal operating mode */
+               value = readl(ddr_handoff_info.umctl2_base + DDR4_STAT_OFFSET) &
+                             DDR4_STAT_OPERATING_MODE;
+               while (value != NORMAL_OPM) {
+                       if (get_timer(start) > TIMEOUT_200MS) {
+                               debug("%s: Timeout while waiting for",
+                                     __func__);
+                               debug(" DDR enters normal operating mode\n");
+                               return -ETIMEDOUT;
+                       }
+
+                       value = readl(ddr_handoff_info.umctl2_base +
+                                     DDR4_STAT_OFFSET) &
+                                     DDR4_STAT_OPERATING_MODE;
+
+                       udelay(1);
+                       WATCHDOG_RESET();
+               }
+
+               debug("DDR entered normal operating mode\n");
+
+               /* Enabling auto refresh */
+               clrbits_le32(ddr_handoff_info.umctl2_base +
+                            DDR4_RFSHCTL3_OFFSET,
+                            DDR4_RFSHCTL3_DIS_AUTO_REFRESH);
+
+               /* Checking ECC is enabled? */
+               value = readl(ddr_handoff_info.umctl2_base +
+                             DDR4_ECCCFG0_OFFSET) & DDR4_ECC_MODE;
+               if (value) {
+                       printf("%s: ECC is enabled\n", __func__);
+                       ret = scrubbing_ddr_config(&ddr_handoff_info);
+                       if (ret) {
+                               debug("%s: Failed to enable ECC\n", __func__);
+                               return ret;
+                       }
+               }
+
+               /* Restore user settings */
+               writel(user_backup, ddr_handoff_info.umctl2_base +
+                      DDR4_PWRCTL_OFFSET);
+
+               /* Enable input traffic per port */
+               setbits_le32(ddr_handoff_info.umctl2_base + DDR4_PCTRL0_OFFSET,
+                            DDR4_PCTRL0_PORT_EN);
+
+               printf("%s: DDR init success\n", __func__);
+       }
+
+       /* 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) {
+               debug("%s: Failed to decode memory node\n",  __func__);
+               return -1;
+       }
+
+       printf("DDR: %lld MiB\n", gd->ram_size >> 20);
+
+       priv->info.base = bd.bi_dram[0].start;
+       priv->info.size = gd->ram_size;
+
+       /* This enables nonsecure access to DDR */
+       /* mpuregion0addr_limit */
+       FW_MPU_DDR_SCR_WRITEL(gd->ram_size - 1,
+                             FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT);
+       FW_MPU_DDR_SCR_WRITEL(((gd->ram_size - 1) >> SZ_32) &
+                             FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT_FIELD,
+                             FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT);
+
+       /* nonmpuregion0addr_limit */
+       FW_MPU_DDR_SCR_WRITEL(gd->ram_size - 1,
+                             FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT);
+
+       /* Enable mpuregion0enable and nonmpuregion0enable */
+       FW_MPU_DDR_SCR_WRITEL(MPUREGION0_ENABLE | NONMPUREGION0_ENABLE,
+                             FW_MPU_DDR_SCR_EN_SET);
+
+       return 0;
+}
\ No newline at end of file
-- 
2.26.2


Reply via email to