[v2 12/17] ddr: altera: Add SDRAM driver for Intel N5X device

Chee, Tien Fong tien.fong.chee at intel.com
Fri Jun 4 06:03:01 CEST 2021


Hi Ley Foon,

> -----Original Message-----
> From: Ley Foon Tan <lftan.linux at gmail.com>
> Sent: Friday, 28 May, 2021 5:41 PM
> To: Lim, Elly Siew Chin <elly.siew.chin.lim at intel.com>
> Cc: ZY - u-boot <u-boot at lists.denx.de>; Marek Vasut <marex at denx.de>; Tan,
> Ley Foon <ley.foon.tan at intel.com>; See, Chin Liang
> <chin.liang.see at intel.com>; Simon Goldschmidt
> <simon.k.r.goldschmidt at gmail.com>; Chee, Tien Fong
> <tien.fong.chee at intel.com>; Westergreen, Dalon
> <dalon.westergreen at intel.com>; Simon Glass <sjg at chromium.org>; Gan, Yau
> Wai <yau.wai.gan at intel.com>
> Subject: Re: [v2 12/17] ddr: altera: Add SDRAM driver for Intel N5X device
> 
> On Fri, Apr 30, 2021 at 3:41 PM Siew Chin Lim
> <elly.siew.chin.lim at intel.com> wrote:
> >
> > The DDR subsystem in Diamond Mesa is consisted of controller, PHY,
> > memory reset manager and memory clock manager.
> >
> > Configuration settings of controller, PHY and  memory reset manager
> > is come from DDR handoff data in bitstream, which contain the register
> > base addresses and user settings from tool.
> >
> > Configuration settings of memory clock manager is come from the HPS
> > handoff data in bitstream, however the register base address is defined
> > in device tree.
> >
> > The calibration is fully done in HPS, which requires IMEM and DMEM
> > binaries loading to PHY SRAM for running this calibration, both
> > IMEM and DMEM binaries are also part of bitstream, this bitstream
> > would be loaded to OCRAM by SDM, and configured by DDR driver.
> >
> > Signed-off-by: Siew Chin Lim <elly.siew.chin.lim at intel.com>
> > Signed-off-by: Tien Fong Chee <tien.fong.chee at intel.com>
> >
> > ---
> > v2:
> > - Move is_ddr_init_skipped and its helper functions to DDR driver and
> >   converted function to positive checking
> > - Using GENMASK() macro
> > - Fixed typo
> > - Return status of subfunction
> > - Changed dm to n5x
> > ---
> >  arch/arm/mach-socfpga/include/mach/firewall.h |    6 +
> >  .../include/mach/system_manager_soc64.h       |   10 +-
> >  drivers/ddr/altera/Makefile                   |    3 +-
> >  drivers/ddr/altera/sdram_n5x.c                | 2299 +++++++++++++++++
> >  drivers/ddr/altera/sdram_soc64.c              |   70 +
> >  drivers/ddr/altera/sdram_soc64.h              |    1 +
> >  6 files changed, 2387 insertions(+), 2 deletions(-)
> >  create mode 100644 drivers/ddr/altera/sdram_n5x.c
> >
> 
> [..]
> 
> > diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
> > index 39dfee5d5a..9fa5d85a27 100644
> > --- a/drivers/ddr/altera/Makefile
> > +++ b/drivers/ddr/altera/Makefile
> > @@ -4,11 +4,12 @@
> >  # Wolfgang Denk, DENX Software Engineering, wd at denx.de.
> >  #
> >  # (C) Copyright 2010, Thomas Chou <thomas at wytron.com.tw>
> > -# Copyright (C) 2014 Altera Corporation <www.altera.com>
> > +# Copyright (C) 2014-2021 Altera Corporation <www.altera.com>
> Intel copyright
> 
> 
> [...]
> 
> > +#include <common.h>
> Sort include header.

Okay.

> 
> > +#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/global_data.h>
> > +#include <asm/io.h>
> > +#include <clk.h>
> > +#include <div64.h>
> > +#include <dm.h>
> > +#include <errno.h>
> > +#include <fdtdec.h>
> > +#include <hang.h>
> > +#include <linux/err.h>
> > +#include <linux/sizes.h>
> > +#include <ram.h>
> > +#include <reset.h>
> > +#include "sdram_soc64.h"
> > +#include <wait_bit.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
> > +
> > +/* MPFE NOC registers */
> > +#define FPGA2SDRAM_MGR_MAIN_SIDEBANDMGR_FLAGOUTSET0
> 0xF8024050
> > +
> > +/* 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_MSTR_OFFSET               0x0
> > +#define DDR4_FREQ_RATIO                        BIT(22)
> > +
> > +#define DDR4_STAT_OFFSET               0x4
> > +#define DDR4_STAT_SELFREF_TYPE         GENMASK(5, 4)
> > +#define DDR4_STAT_SELFREF_TYPE_SHIFT   4
> > +#define DDR4_STAT_OPERATING_MODE       GENMASK(2, 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           GENMASK(5, 4)
> > +#define DDR4_MRCTRL0_MR_RANK_SHIFT     4
> > +#define DDR4_MRCTRL0_MR_ADDR           GENMASK(15, 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             GENMASK(6, 4)
> > +#define DDR4_RFSHCTL3_REFRESH_MODE_SHIFT       4
> > +
> > +#define DDR4_ECCCFG0_OFFSET            0x70
> > +#define DDR4_ECC_MODE                  GENMASK(2, 0)
> > +#define DDR4_DIS_SCRUB                 BIT(4)
> > +#define LPDDR4_ECCCFG0_ECC_REGION_MAP_GRANU_SHIFT      30
> > +#define LPDDR4_ECCCFG0_ECC_REGION_MAP_SHIFT    8
> > +
> > +#define DDR4_ECCCFG1_OFFSET            0x74
> > +#define LPDDR4_ECCCFG1_ECC_REGIONS_PARITY_LOCK BIT(4)
> > +
> > +#define DDR4_CRCPARCTL0_OFFSET                 0xC0
> > +#define DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR BIT(1)
> > +
> > +#define DDR4_CRCPARCTL1_OFFSET                 0xC4
> > +#define DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE        BIT(8)
> > +#define DDR4_CRCPARCTL1_ALERT_WAIT_FOR_SW      BIT(9)
> > +
> > +#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_INIT0_OFFSET                      0xD0
> > +#define DDR4_INIT0_SKIP_RAM_INIT               GENMASK(31, 30)
> > +
> > +#define DDR4_RANKCTL_OFFSET                    0xF4
> > +#define DDR4_RANKCTL_DIFF_RANK_RD_GAP          GENMASK(7, 4)
> > +#define DDR4_RANKCTL_DIFF_RANK_WR_GAP          GENMASK(11, 8)
> > +#define DDR4_RANKCTL_DIFF_RANK_RD_GAP_MSB      BIT(24)
> > +#define DDR4_RANKCTL_DIFF_RANK_WR_GAP_MSB      BIT(26)
> > +#define DDR4_RANKCTL_DIFF_RANK_RD_GAP_SHIFT    4
> > +#define DDR4_RANKCTL_DIFF_RANK_WR_GAP_SHIFT    8
> > +#define DDR4_RANKCTL_DIFF_RANK_RD_GAP_MSB_SHIFT        24
> > +#define DDR4_RANKCTL_DIFF_RANK_WR_GAP_MSB_SHIFT        26
> > +
> > +#define DDR4_RANKCTL1_OFFSET   0xF8
> > +#define DDR4_RANKCTL1_WR2RD_DR GENMASK(5, 0)
> > +
> > +#define DDR4_DRAMTMG2_OFFSET   0x108
> > +#define DDR4_DRAMTMG2_WR2RD    GENMASK(5, 0)
> > +#define DDR4_DRAMTMG2_RD2WR    GENMASK(13, 8)
> > +#define DDR4_DRAMTMG2_RD2WR_SHIFT      8
> > +
> > +#define DDR4_DRAMTMG9_OFFSET   0x124
> > +#define DDR4_DRAMTMG9_W2RD_S   GENMASK(5, 0)
> > +
> > +#define DDR4_DFITMG1_OFFSET    0x194
> > +#define DDR4_DFITMG1_DFI_T_WRDATA_DELAY        GENMASK(20, 16)
> > +#define DDR4_DFITMG1_DFI_T_WRDATA_SHIFT        16
> > +
> > +#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 DDR4_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_DBYTE0_TXDQDLYTG0_U0_P0                0x201A0
> > +
> > +#define DDR_PHY_DBYTE0_TXDQDLYTG0_U1_P0                0x203A0
> > +#define DDR_PHY_DBYTE1_TXDQDLYTG0_U0_P0                0x221A0
> > +#define DDR_PHY_DBYTE1_TXDQDLYTG0_U1_P0                0x223A0
> > +#define DDR_PHY_TXDQDLYTG0_COARSE_DELAY                GENMASK(9, 6)
> > +#define DDR_PHY_TXDQDLYTG0_COARSE_DELAY_SHIFT  6
> > +
> > +#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_MEMRESETL_OFFSET               0x400C0
> > +#define DDR_PHY_MEMRESETL_VALUE                        BIT(0)
> > +#define DDR_PHY_PROTECT_MEMRESET               BIT(1)
> > +
> > +#define DDR_PHY_CALBUSY_OFFSET                 0x4012E
> > +#define DDR_PHY_CALBUSY                                BIT(0)
> > +
> > +#define DDR_PHY_TRAIN_IMEM_OFFSET              0xA0000
> > +#define DDR_PHY_TRAIN_DMEM_OFFSET              0xA8000
> > +
> > +#define DMEM_MB_CDD_RR_1_0_OFFSET              0xA802C
> > +#define DMEM_MB_CDD_RR_0_1_OFFSET              0xA8030
> > +#define DMEM_MB_CDD_WW_1_0_OFFSET              0xA8038
> > +#define DMEM_MB_CDD_WW_0_1_OFFSET              0xA803C
> > +#define DMEM_MB_CDD_RW_1_1_OFFSET              0xA8046
> > +#define DMEM_MB_CDD_RW_1_0_OFFSET              0xA8048
> > +#define DMEM_MB_CDD_RW_0_1_OFFSET              0xA804A
> > +#define DMEM_MB_CDD_RW_0_0_OFFSET              0xA804C
> > +
> > +#define DMEM_MB_CDD_CHA_RR_1_0_OFFSET          0xA8026
> > +#define DMEM_MB_CDD_CHA_RR_0_1_OFFSET          0xA8026
> > +#define DMEM_MB_CDD_CHB_RR_1_0_OFFSET          0xA8058
> > +#define DMEM_MB_CDD_CHB_RR_0_1_OFFSET          0xA805A
> > +#define DMEM_MB_CDD_CHA_WW_1_0_OFFSET          0xA8030
> > +#define DMEM_MB_CDD_CHA_WW_0_1_OFFSET          0xA8030
> > +#define DMEM_MB_CDD_CHB_WW_1_0_OFFSET          0xA8062
> > +#define DMEM_MB_CDD_CHB_WW_0_1_OFFSET          0xA8064
> > +
> > +#define DMEM_MB_CDD_CHA_RW_1_1_OFFSET          0xA8028
> > +#define DMEM_MB_CDD_CHA_RW_1_0_OFFSET          0xA8028
> > +#define DMEM_MB_CDD_CHA_RW_0_1_OFFSET          0xA802A
> > +#define DMEM_MB_CDD_CHA_RW_0_0_OFFSET          0xA802A
> > +
> > +#define DMEM_MB_CDD_CHB_RW_1_1_OFFSET          0xA805A
> > +#define DMEM_MB_CDD_CHB_RW_1_0_OFFSET          0xA805C
> > +#define DMEM_MB_CDD_CHB_RW_0_1_OFFSET          0xA805c
> > +#define DMEM_MB_CDD_CHB_RW_0_0_OFFSET          0xA805E
> > +
> > +#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_UCCLKHCLKENABLES_UCCLKEN       BIT(0)
> > +#define DDR_PHY_UCCLKHCLKENABLES_HCLKEN                BIT(1)
> > +
> > +#define DDR_PHY_UCTWRITEPROT_OFFSET            0x180066
> > +#define DDR_PHY_UCTWRITEPROT                   BIT(0)
> > +
> > +#define DDR_PHY_APBONLY0_OFFSET                        0x1A0000
> > +#define DDR_PHY_MICROCONTMUXSEL                        BIT(0)
> > +
> > +#define DDR_PHY_UCTSHADOWREGS_OFFSET                   0x1A0008
> > +#define DDR_PHY_UCTSHADOWREGS_UCTWRITEPROTESHADOW      BIT(0)
> > +
> > +#define DDR_PHY_DCTWRITEPROT_OFFSET            0x1A0062
> > +#define DDR_PHY_DCTWRITEPROT                   BIT(0)
> > +
> > +#define DDR_PHY_UCTWRITEONLYSHADOW_OFFSET      0x1A0064
> > +#define DDR_PHY_UCTDATWRITEONLYSHADOW_OFFSET   0x1A0068
> > +
> > +#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
> > +
> > +/* For firmware training */
> > +#define HW_DBG_TRACE_CONTROL_OFFSET    0x18
> > +#define FW_TRAINING_COMPLETED_STAT     0x07
> > +#define FW_TRAINING_FAILED_STAT                0xFF
> > +#define FW_COMPLETION_MSG_ONLY_MODE    0xFF
> > +#define FW_STREAMING_MSG_ID            0x08
> > +#define GET_LOWHW_DATA(x)              ((x) & 0xFFFF)
> > +#define GET_LOWB_DATA(x)               ((x) & 0xFF)
> > +#define GET_HIGHB_DATA(x)              (((x) & 0xFF00) >> 8)
> > +
> > +/* 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
> Use prefix OPM_xxx

Okay.

> 
> > +
> > +/* 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)
> > +
> > +/* Value for ecc_region_map */
> > +#define ALL_PROTECTED  0x7F
> > +
> > +/* Region size for ECCCFG0.ecc_region_map */
> > +enum region_size {
> > +       ONE_EIGHT,
> > +       ONE_SIXTEENTH,
> > +       ONE_THIRTY_SECOND,
> > +       ONE_SIXTY_FOURTH
> > +};
> > +
> > +enum ddr_type {
> > +       DDRTYPE_LPDDR4_0,
> > +       DDRTYPE_LPDDR4_1,
> > +       DDRTYPE_DDR4,
> > +       DDRTYPE_UNKNOWN
> > +};
> > +
> > +/* Reset type */
> > +enum reset_type {
> > +       POR_RESET,
> > +       WARM_RESET,
> > +       COLD_RESET
> > +};
> > +
> > +/* DDR handoff structure */
> > +struct ddr_handoff {
> > +       /* Memory reset manager base */
> > +       phys_addr_t mem_reset_base;
> > +
> > +       /* First controller attributes */
> > +       phys_addr_t cntlr_handoff_base;
> > +       phys_addr_t cntlr_base;
> > +       size_t cntlr_total_length;
> > +       enum ddr_type cntlr_t;
> > +       size_t cntlr_handoff_length;
> > +
> > +       /* Second controller attributes*/
> > +       phys_addr_t cntlr2_handoff_base;
> > +       phys_addr_t cntlr2_base;
> > +       size_t cntlr2_total_length;
> > +       enum ddr_type cntlr2_t;
> > +       size_t cntlr2_handoff_length;
> > +
> > +       /* PHY attributes */
> > +       phys_addr_t phy_handoff_base;
> > +       phys_addr_t phy_base;
> > +       size_t phy_total_length;
> > +       size_t phy_handoff_length;
> > +
> > +       /* PHY engine attributes */
> > +       phys_addr_t phy_engine_handoff_base;
> > +       size_t phy_engine_total_length;
> > +       size_t phy_engine_handoff_length;
> > +
> > +       /* Calibration attributes */
> > +       phys_addr_t train_imem_base;
> > +       phys_addr_t train_dmem_base;
> > +       size_t train_imem_length;
> > +       size_t train_dmem_length;
> > +};
> > +
> > +/* Message mode */
> > +enum message_mode {
> > +       MAJOR_MESSAGE,
> > +       STREAMING_MESSAGE
> > +};
> > +
> > +static int clr_ca_parity_error_status(phys_addr_t umctl2_base)
> > +{
> > +       int ret;
> > +
> > +       debug("%s: Clear C/A parity error status in MR5[4]\n", __func__);
> > +
> > +       /* Set mode register MRS */
> > +       clrbits_le32(umctl2_base + DDR4_MRCTRL0_OFFSET,
> DDR4_MRCTRL0_MPR_EN);
> > +
> > +       /* Set mode register to write operation */
> > +       setbits_le32(umctl2_base + DDR4_MRCTRL0_OFFSET,
> DDR4_MRCTRL0_MR_TYPE);
> > +
> > +       /* Set the address of mode rgister to 0x101(MR5) */
> > +       setbits_le32(umctl2_base + DDR4_MRCTRL0_OFFSET,
> > +                    (MR5 << DDR4_MRCTRL0_MR_ADDR_SHIFT) &
> > +                    DDR4_MRCTRL0_MR_ADDR);
> > +
> > +       /* Set MR rank to rank 1 */
> > +       setbits_le32(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(umctl2_base + DDR4_MRCTRL1_OFFSET, MR5_BIT4);
> > +
> > +       /* Trigger mode register read or write operation */
> > +       setbits_le32(umctl2_base + DDR4_MRCTRL0_OFFSET,
> DDR4_MRCTRL0_MR_WR);
> > +
> > +       /* Wait for retry done */
> > +       ret = wait_for_bit_le32((const void *)(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 ddr_retry_software_sequence(phys_addr_t umctl2_base)
> > +{
> > +       u32 value;
> > +       int ret;
> > +
> > +       /* Check software can perform MRS/MPR/PDA? */
> > +       value = readl(umctl2_base + DDR4_CRCPARSTAT_OFFSET) &
> > +                     DDR4_CRCPARSTAT_DFI_ALERT_ERR_NO_SW;
> > +
> > +       if (value) {
> > +               /* Clear interrupt bit for DFI alert error */
> > +               setbits_le32(umctl2_base + DDR4_CRCPARCTL0_OFFSET,
> > +                            DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR);
> > +       }
> > +
> > +       debug("%s: Software can perform MRS/MPR/PDA\n", __func__);
> > +
> > +       ret = wait_for_bit_le32((const void *)(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;
> > +       }
> > +
> > +       ret = clr_ca_parity_error_status(umctl2_base);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (!value) {
> > +               /* Clear interrupt bit for DFI alert error */
> > +               setbits_le32(umctl2_base + DDR4_CRCPARCTL0_OFFSET,
> > +                            DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR);
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int ensure_retry_procedure_complete(phys_addr_t umctl2_base)
> > +{
> > +       u32 value;
> > +       u32 start = get_timer(0);
> > +       int ret;
> > +
> > +       /* Check parity/crc/error window is emptied ? */
> > +       value = readl(umctl2_base + DDR4_CRCPARSTAT_OFFSET) &
> > +                     DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW;
> Can simplify the code with do...while loop.

Okay.

> 
> > +
> > +       /* 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(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(umctl2_base + DDR4_CRCPARSTAT_OFFSET) &
> > +                                     DDR4_CRCPARSTAT_DFI_ALERT_ERR_INT;
> > +
> > +                       if (value) {
> > +                               ret = ddr_retry_software_sequence(umctl2_base);
> > +                               debug("%s: DFI alert error interrupt ",
> > +                                     __func__);
> > +                               debug("is set\n");
> > +
> > +                               if (ret)
> > +                                       return ret;
> > +                       }
> > +
> > +                       /*
> > +                        * Check fatal parity error interrupt is set?
> > +                        */
> > +                       value = readl(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(umctl2_base + DDR4_CRCPARSTAT_OFFSET) &
> > +                             DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW;
> > +
> > +               udelay(1);
> > +               WATCHDOG_RESET();
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int enable_quasi_dynamic_reg_grp3(phys_addr_t umctl2_base,
> > +                                        enum ddr_type umctl2_type)
> > +{
> > +       u32 i, value, backup;
> > +       int ret = 0;
> > +
> > +       /* Disable input traffic per port */
> > +       clrbits_le32(umctl2_base + DDR4_PCTRL0_OFFSET,
> DDR4_PCTRL0_PORT_EN);
> > +
> > +       /* Polling AXI port until idle */
> > +       ret = wait_for_bit_le32((const void *)(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(umctl2_base + DDR4_DBG1_OFFSET);
> > +
> > +       /* Disable input traffic to the controller */
> > +       setbits_le32(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 *)(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");
> > +
> > +                       goto out;
> > +               }
> > +       }
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               /* Check DDR4 retry is enabled ? */
> > +               value = readl(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(umctl2_base);
> > +                       if (ret) {
> > +                               debug("%s: Timeout while waiting for",
> > +                                     __func__);
> > +                               debug(" retry procedure complete\n");
> > +
> > +                               goto out;
> > +                       }
> > +               }
> > +       }
> > +
> > +       debug("%s: Quasi-dynamic group 3 registers are enabled\n", __func__);
> > +
> > +out:
> > +       /* Restore user setting */
> > +       writel(backup, umctl2_base + DDR4_DBG1_OFFSET);
> > +
> > +       return ret;
> > +}
> > +
> > +static enum ddr_type get_ddr_type(phys_addr_t ddr_type_location)
> > +{
> > +       u32 ddr_type_magic = readl(ddr_type_location);
> > +
> > +       if (ddr_type_magic == SOC64_HANDOFF_DDR_UMCTL2_DDR4_TYPE)
> > +               return DDRTYPE_DDR4;
> > +
> > +       if (ddr_type_magic == SOC64_HANDOFF_DDR_UMCTL2_LPDDR4_0_TYPE)
> > +               return DDRTYPE_LPDDR4_0;
> > +
> > +       if (ddr_type_magic == SOC64_HANDOFF_DDR_UMCTL2_LPDDR4_1_TYPE)
> > +               return DDRTYPE_LPDDR4_1;
> > +
> > +       return DDRTYPE_UNKNOWN;
> > +}
> > +
> > +static void use_lpddr4_interleaving(bool set)
> > +{
> > +       if (set) {
> > +               printf("Starting LPDDR4 interleaving configuration ...\n");
> > +
> setbits_le32(FPGA2SDRAM_MGR_MAIN_SIDEBANDMGR_FLAGOUTSET0,
> > +                            BIT(5));
> > +       } else {
> > +               printf("Starting LPDDR4 non-interleaving configuration ...\n");
> > +
> clrbits_le32(FPGA2SDRAM_MGR_MAIN_SIDEBANDMGR_FLAGOUTSET0,
> > +                            BIT(5));
> > +       }
> > +}
> > +
> > +static void use_ddr4(enum ddr_type type)
> > +{
> > +       if (type == DDRTYPE_DDR4) {
> > +               printf("Starting DDR4 configuration ...\n");
> > +               setbits_le32(socfpga_get_sysmgr_addr() +
> SYSMGR_SOC64_DDR_MODE,
> > +                            SYSMGR_SOC64_DDR_MODE_MSK);
> > +       } else if (type == DDRTYPE_LPDDR4_0)  {
> > +               printf("Starting LPDDR4 configuration ...\n");
> > +               clrbits_le32(socfpga_get_sysmgr_addr() +
> SYSMGR_SOC64_DDR_MODE,
> > +                            SYSMGR_SOC64_DDR_MODE_MSK);
> > +
> > +               use_lpddr4_interleaving(false);
> > +       }
> > +}
> > +
> > +static int scrubber_ddr_config(phys_addr_t umctl2_base,
> > +                              enum ddr_type umctl2_type)
> > +{
> > +       u32 backup[9];
> > +       int ret;
> > +
> > +       /* Reset to default value, prevent scrubber stop due to lower power */
> > +       writel(0, umctl2_base + DDR4_PWRCTL_OFFSET);
> > +
> > +       /* Backup user settings */
> > +       backup[0] = readl(umctl2_base + DDR4_SBRCTL_OFFSET);
> > +       backup[1] = readl(umctl2_base + DDR4_SBRWDATA0_OFFSET);
> > +       backup[2] = readl(umctl2_base + DDR4_SBRSTART0_OFFSET);
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               backup[3] = readl(umctl2_base + DDR4_SBRWDATA1_OFFSET);
> > +               backup[4] = readl(umctl2_base + DDR4_SBRSTART1_OFFSET);
> > +       }
> > +       backup[5] = readl(umctl2_base + DDR4_SBRRANGE0_OFFSET);
> > +       backup[6] = readl(umctl2_base + DDR4_SBRRANGE1_OFFSET);
> > +       backup[7] = readl(umctl2_base + DDR4_ECCCFG0_OFFSET);
> > +       backup[8] = readl(umctl2_base + DDR4_ECCCFG1_OFFSET);
> > +
> > +       if (umctl2_type != DDRTYPE_DDR4) {
> > +               /* Lock ECC region, ensure this regions is not being accessed */
> > +               setbits_le32(umctl2_base + DDR4_ECCCFG1_OFFSET,
> > +                            LPDDR4_ECCCFG1_ECC_REGIONS_PARITY_LOCK);
> > +       }
> > +       /* Disable input traffic per port */
> > +       clrbits_le32(umctl2_base + DDR4_PCTRL0_OFFSET,
> DDR4_PCTRL0_PORT_EN);
> > +       /* Disables scrubber */
> > +       clrbits_le32(umctl2_base + DDR4_SBRCTL_OFFSET,
> DDR4_SBRCTL_SCRUB_EN);
> > +       /* Polling all scrub writes data have been sent */
> > +       ret = wait_for_bit_le32((const void *)(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;
> > +       }
> > +
> > +       /* LPDDR4 supports inline ECC only */
> > +       if (umctl2_type != DDRTYPE_DDR4) {
> > +               /*
> > +                * Setting all regions for protected, this is required for
> > +                * srubber to init whole LPDDR4 expect ECC region
> > +                */
> > +               writel(((ONE_EIGHT <<
> > +                      LPDDR4_ECCCFG0_ECC_REGION_MAP_GRANU_SHIFT) |
> > +                      (ALL_PROTECTED <<
> LPDDR4_ECCCFG0_ECC_REGION_MAP_SHIFT)),
> > +                      umctl2_base + DDR4_ECCCFG0_OFFSET);
> > +       }
> > +
> > +       /* Scrub_burst = 1, scrub_mode = 1(performs writes) */
> > +       writel(DDR4_SBRCTL_SCRUB_BURST_1 | DDR4_SBRCTL_SCRUB_WRITE,
> > +              umctl2_base + DDR4_SBRCTL_OFFSET);
> > +
> > +       /* Zeroing whole DDR */
> > +       writel(0, umctl2_base + DDR4_SBRWDATA0_OFFSET);
> > +       writel(0, umctl2_base + DDR4_SBRSTART0_OFFSET);
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               writel(0, umctl2_base + DDR4_SBRWDATA1_OFFSET);
> > +               writel(0, umctl2_base + DDR4_SBRSTART1_OFFSET);
> > +       }
> > +       writel(0, umctl2_base + DDR4_SBRRANGE0_OFFSET);
> > +       writel(0, umctl2_base + DDR4_SBRRANGE1_OFFSET);
> > +
> > +       /* Enables scrubber */
> > +       setbits_le32(umctl2_base + DDR4_SBRCTL_OFFSET,
> DDR4_SBRCTL_SCRUB_EN);
> > +       /* Polling all scrub writes commands have been sent */
> > +       ret = wait_for_bit_le32((const void *)(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;
> Need restore user settings before return?

No need because this is considered error, and system would hang for watchdog to kick in.

> 
> > +       }
> > +
> > +       /* Polling all scrub writes data have been sent */
> > +       ret = wait_for_bit_le32((const void *)(umctl2_base +
> > +                               DDR4_SBRSTAT_OFFSET), DDR4_SBRSTAT_SCRUB_BUSY,
> > +                               false, TIMEOUT_5000MS, false);
> > +       if (ret) {
> > +               printf("%s: Timeout while waiting for", __func__);
> > +               printf(" sending all scrub data\n");
> > +               return ret;
> Same here.

No need because this is considered error, and system would hang for watchdog to kick in.

> 
> > +       }
> > +
> > +       /* Disables scrubber */
> > +       clrbits_le32(umctl2_base + DDR4_SBRCTL_OFFSET,
> DDR4_SBRCTL_SCRUB_EN);
> > +
> > +       /* Restore user settings */
> > +       writel(backup[0], umctl2_base + DDR4_SBRCTL_OFFSET);
> > +       writel(backup[1], umctl2_base + DDR4_SBRWDATA0_OFFSET);
> > +       writel(backup[2], umctl2_base + DDR4_SBRSTART0_OFFSET);
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               writel(backup[3], umctl2_base + DDR4_SBRWDATA1_OFFSET);
> > +               writel(backup[4], umctl2_base + DDR4_SBRSTART1_OFFSET);
> > +       }
> > +       writel(backup[5], umctl2_base + DDR4_SBRRANGE0_OFFSET);
> > +       writel(backup[6], umctl2_base + DDR4_SBRRANGE1_OFFSET);
> > +       writel(backup[7], umctl2_base + DDR4_ECCCFG0_OFFSET);
> > +       writel(backup[8], umctl2_base + DDR4_ECCCFG1_OFFSET);
> > +
> > +       /* Enables ECC scrub on scrubber */
> > +       if (!(readl(umctl2_base + DDR4_SBRCTL_OFFSET) &
> > +           DDR4_SBRCTL_SCRUB_WRITE)) {
> > +               /* Enables scrubber */
> > +               setbits_le32(umctl2_base + DDR4_SBRCTL_OFFSET,
> > +                            DDR4_SBRCTL_SCRUB_EN);
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int init_umctl2(phys_addr_t umctl2_handoff_base,
> > +                      phys_addr_t umctl2_base, enum ddr_type umctl2_type,
> > +                      size_t umctl2_handoff_length,
> > +                      u32 *user_backup)
> > +{
> > +       u32 handoff_table[umctl2_handoff_length];
> > +       u32 i;
> > +       int ret;
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4)
> > +               printf("Initializing DDR4 controller ...\n");
> > +       else if (umctl2_type == DDRTYPE_LPDDR4_0)
> > +               printf("Initializing LPDDR4_0 controller ...\n");
> > +       else if (umctl2_type == DDRTYPE_LPDDR4_1)
> > +               printf("Initializing LPDDR4_1 controller ...\n");
> > +
> > +       /* Prevent controller from issuing read/write to SDRAM */
> > +       setbits_le32(umctl2_base + DDR4_DBG1_OFFSET, DDR4_DBG1_DISDQ);
> > +
> > +       /* Put SDRAM into self-refresh */
> > +       setbits_le32(umctl2_base + DDR4_PWRCTL_OFFSET,
> DDR4_PWRCTL_SELFREF_EN);
> > +
> > +       /* Enable quasi-dynamic programing of the controller registers */
> > +       clrbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Ensure the controller is in initialization mode */
> > +       ret = wait_for_bit_le32((const void *)(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: UMCTL2 handoff base address = 0x%p table length =
> 0x%08x\n",
> > +             __func__, (u32 *)umctl2_handoff_base,
> > +             (u32)umctl2_handoff_length);
> > +
> > +       socfpga_handoff_read((void *)umctl2_handoff_base, handoff_table,
> > +                            umctl2_handoff_length);
> > +
> > +       for (i = 0; i < umctl2_handoff_length; i = i + 2) {
> > +               debug("%s: Absolute addr: 0x%08llx APB offset: 0x%08x",
> > +                     __func__, handoff_table[i] + umctl2_base,
> > +                     handoff_table[i]);
> > +               debug(" wr = 0x%08x ", handoff_table[i + 1]);
> > +
> > +               writel(handoff_table[i + 1], (uintptr_t)(handoff_table[i] +
> > +                      umctl2_base));
> > +
> Can have a common function to write the handoff data. Check all code
> after call to socfpga_handoff_read().

I can create a common function for both PHY and PHY init engine, but not for this umctl because both for loop process are different, handoff_table for both PHY and PHY int engine need some preprocessing before writing into respective registers but this is not required in umctl.

> 
> > +               debug("rd = 0x%08x\n", readl((uintptr_t)(handoff_table[i] +
> > +                     umctl2_base)));
> > +       }
> > +
> > +       /* Backup user settings, restore after DDR up running */
> > +       *user_backup = readl(umctl2_base + DDR4_PWRCTL_OFFSET);
> > +
> > +       /* Disable self resfresh */
> > +       clrbits_le32(umctl2_base + DDR4_PWRCTL_OFFSET,
> DDR4_PWRCTL_SELFREF_EN);
> > +
> > +       if (umctl2_type == DDRTYPE_LPDDR4_0 ||
> > +           umctl2_type == DDRTYPE_LPDDR4_1) {
> > +               /* Setting selfref_sw to 1, based on lpddr4 requirement */
> > +               setbits_le32(umctl2_base + DDR4_PWRCTL_OFFSET,
> > +                            DDR4_PWRCTL_SELFREF_SW);
> > +
> > +               /* Backup user settings, restore after DDR up running */
> > +               user_backup++;
> > +               *user_backup = readl(umctl2_base + DDR4_INIT0_OFFSET) &
> > +                                    DDR4_INIT0_SKIP_RAM_INIT;
> > +
> > +               /*
> > +                * Setting INIT0.skip_dram_init to 0x3, based on lpddr4
> > +                * requirement
> > +                */
> > +               setbits_le32(umctl2_base + DDR4_INIT0_OFFSET,
> > +                            DDR4_INIT0_SKIP_RAM_INIT);
> > +       }
> > +
> > +       /* Complete quasi-dynamic register programming */
> > +       setbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Enable controller from issuing read/write to SDRAM */
> > +       clrbits_le32(umctl2_base + DDR4_DBG1_OFFSET, DDR4_DBG1_DISDQ);
> > +
> > +       return 0;
> > +}
> > +
> > +static int phy_pre_handoff_config(phys_addr_t umctl2_base,
> > +                                 enum ddr_type umctl2_type)
> > +{
> > +       int ret;
> > +       u32 value;
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               /* Check DDR4 retry is enabled ? */
> > +               value = readl(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(umctl2_base + DDR4_RFSHCTL3_OFFSET,
> > +                                    DDR4_RFSHCTL3_DIS_AUTO_REFRESH);
> > +               }
> > +       }
> > +
> > +       /* Disable selfref_en & powerdown_en, nvr disable dfi dram clk */
> > +       clrbits_le32(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(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       ret = enable_quasi_dynamic_reg_grp3(umctl2_base, umctl2_type);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /* Masking dfi init complete */
> > +       clrbits_le32(umctl2_base + DDR4_DFIMISC_OFFSET,
> > +                    DDR4_DFIMISC_DFI_INIT_COMPLETE_EN);
> > +
> > +       /* Complete quasi-dynamic register programming */
> > +       setbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Polling programming done */
> > +       ret = wait_for_bit_le32((const void *)(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;
> > +}
> > +
> > +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");
> > +
> > +       if (ddr_handoff_info->cntlr_t == DDRTYPE_DDR4 ||
> > +           ddr_handoff_info->cntlr_t == DDRTYPE_LPDDR4_0) {
> > +               ret = phy_pre_handoff_config(ddr_handoff_info->cntlr_base,
> > +                                            ddr_handoff_info->cntlr_t);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> > +       if (ddr_handoff_info->cntlr2_t == DDRTYPE_LPDDR4_1) {
> > +               ret = phy_pre_handoff_config
> > +                       (ddr_handoff_info->cntlr2_base,
> > +                        ddr_handoff_info->cntlr2_t);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> > +       /* Execute PHY configuration handoff */
> > +       socfpga_handoff_read((void *)ddr_handoff_info->phy_handoff_base,
> > +                            handoff_table,
> > +                            (u32)ddr_handoff_info->phy_handoff_length);
> > +
> > +       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)));
> > +       }
> > +
> > +       printf("DDR PHY configuration is completed\n");
> > +
> > +       return 0;
> > +}
> > +
> > +static void phy_init_engine(struct ddr_handoff *handoff)
> > +{
> > +       u32 i, value;
> > +       u32 handoff_table[handoff->phy_engine_handoff_length];
> > +
> > +       printf("Load PHY Init Engine ...\n");
> > +
> > +       /* Execute PIE production code handoff */
> > +       socfpga_handoff_read((void *)handoff->phy_engine_handoff_base,
> > +                            handoff_table,
> > +                            (u32)handoff->phy_engine_handoff_length);
> > +
> > +       for (i = 0; i < handoff->phy_engine_handoff_length; i = i + 2) {
> > +               debug("Handoff addr: 0x%8llx ", handoff_table[i] +
> > +                     handoff->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 + handoff->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 +
> > +                      handoff->phy_base));
> > +
> > +               debug("rd = 0x%08x\n", readw((uintptr_t)(value +
> > +                     handoff->phy_base)));
> > +       }
> > +
> > +       printf("End of loading PHY Init Engine\n");
> > +}
> > +
> > +int populate_ddr_handoff(struct ddr_handoff *handoff)
> > +{
> > +       phys_addr_t next_section_header;
> > +
> > +       /* DDR handoff */
> > +       handoff->mem_reset_base = SOC64_HANDOFF_DDR_MEMRESET_BASE;
> > +       debug("%s: DDR memory reset base = 0x%x\n", __func__,
> > +             (u32)handoff->mem_reset_base);
> > +       debug("%s: DDR memory reset address = 0x%x\n", __func__,
> > +             readl(handoff->mem_reset_base));
> > +
> > +       /* Beginning of DDR controller handoff */
> > +       handoff->cntlr_handoff_base =
> SOC64_HANDOFF_DDR_UMCTL2_SECTION;
> > +       debug("%s: cntlr handoff base = 0x%x\n", __func__,
> > +             (u32)handoff->cntlr_handoff_base);
> > +
> > +       /* Get 1st DDR type */
> > +       handoff->cntlr_t = get_ddr_type(handoff->cntlr_handoff_base +
> > +                                       SOC64_HANDOFF_DDR_UMCTL2_TYPE_OFFSET);
> > +       if (handoff->cntlr_t == DDRTYPE_LPDDR4_1 ||
> > +           handoff->cntlr_t == DDRTYPE_UNKNOWN) {
> > +               debug("%s: Wrong DDR handoff format, the 1st DDR ", __func__);
> > +               debug("type must be DDR4 or LPDDR4_0\n");
> > +               return -ENOEXEC;
> > +       }
> > +
> > +       /* 1st cntlr base physical address */
> > +       handoff->cntlr_base = readl(handoff->cntlr_handoff_base +
> > +                                   SOC64_HANDOFF_DDR_UMCTL2_BASE_ADDR_OFFSET);
> > +       debug("%s: cntlr base = 0x%x\n", __func__, (u32)handoff->cntlr_base);
> > +
> > +       /* Get the total length of DDR cntlr handoff section */
> > +       handoff->cntlr_total_length = readl(handoff->cntlr_handoff_base +
> > +                                           SOC64_HANDOFF_OFFSET_LENGTH);
> > +       debug("%s: Umctl2 total length in byte = 0x%x\n", __func__,
> > +             (u32)handoff->cntlr_total_length);
> > +
> > +       /* Get the length of user setting data in DDR cntlr handoff section */
> > +       handoff->cntlr_handoff_length = socfpga_get_handoff_size((void *)
> > +                                               handoff->cntlr_handoff_base);
> > +       debug("%s: Umctl2 handoff length in word(32-bit) = 0x%x\n", __func__,
> > +             (u32)handoff->cntlr_handoff_length);
> > +
> > +       /* Wrong format on user setting data */
> > +       if (handoff->cntlr_handoff_length < 0) {
> > +               debug("%s: Wrong format on user setting data\n", __func__);
> > +               return -ENOEXEC;
> > +       }
> > +
> > +       /* Get the next handoff section address */
> > +       next_section_header = handoff->cntlr_handoff_base +
> > +                               handoff->cntlr_total_length;
> > +       debug("%s: Next handoff section header location = 0x%llx\n", __func__,
> > +             next_section_header);
> > +
> > +       /*
> > +        * Checking next section handoff is cntlr or PHY, and changing
> > +        * subsequent implementation accordingly
> > +        */
> > +       if (readl(next_section_header) ==
> SOC64_HANDOFF_DDR_UMCTL2_MAGIC) {
> > +               /* Get the next cntlr handoff section address */
> > +               handoff->cntlr2_handoff_base = next_section_header;
> > +               debug("%s: umctl2 2nd handoff base = 0x%x\n", __func__,
> > +                     (u32)handoff->cntlr2_handoff_base);
> > +
> > +               /* Get 2nd DDR type */
> > +               handoff->cntlr2_t = get_ddr_type(handoff->cntlr2_handoff_base +
> > +                                       SOC64_HANDOFF_DDR_UMCTL2_TYPE_OFFSET);
> > +               if (handoff->cntlr2_t == DDRTYPE_LPDDR4_0 ||
> > +                   handoff->cntlr2_t == DDRTYPE_UNKNOWN) {
> > +                       debug("%s: Wrong DDR handoff format, the 2nd DDR ",
> > +                             __func__);
> > +                       debug("type must be LPDDR4_1\n");
> > +                       return -ENOEXEC;
> > +               }
> > +
> > +               /* 2nd umctl2 base physical address */
> > +               handoff->cntlr2_base =
> > +                       readl(handoff->cntlr2_handoff_base +
> > +                             SOC64_HANDOFF_DDR_UMCTL2_BASE_ADDR_OFFSET);
> > +               debug("%s: cntlr2 base = 0x%x\n", __func__,
> > +                     (u32)handoff->cntlr2_base);
> > +
> > +               /* Get the total length of 2nd DDR umctl2 handoff section */
> > +               handoff->cntlr2_total_length =
> > +                       readl(handoff->cntlr2_handoff_base +
> > +                             SOC64_HANDOFF_OFFSET_LENGTH);
> > +               debug("%s: Umctl2_2nd total length in byte = 0x%x\n", __func__,
> > +                     (u32)handoff->cntlr2_total_length);
> > +
> > +               /*
> > +                * Get the length of user setting data in DDR umctl2 handoff
> > +                * section
> > +                */
> > +               handoff->cntlr2_handoff_length =
> > +                       socfpga_get_handoff_size((void *)
> > +                                                handoff->cntlr2_handoff_base);
> > +               debug("%s: cntlr2 handoff length in word(32-bit) = 0x%x\n",
> > +                     __func__,
> > +                    (u32)handoff->cntlr2_handoff_length);
> > +
> > +               /* Wrong format on user setting data */
> > +               if (handoff->cntlr2_handoff_length < 0) {
> > +                       debug("%s: Wrong format on umctl2 user setting data\n",
> > +                             __func__);
> > +                       return -ENOEXEC;
> > +               }
> > +
> > +               /* Get the next handoff section address */
> > +               next_section_header = handoff->cntlr2_handoff_base +
> > +                                       handoff->cntlr2_total_length;
> > +               debug("%s: Next handoff section header location = 0x%llx\n",
> > +                     __func__, next_section_header);
> > +       }
> > +
> > +       /* Checking next section handoff is PHY ? */
> > +       if (readl(next_section_header) == SOC64_HANDOFF_DDR_PHY_MAGIC) {
> > +               /* DDR PHY handoff */
> > +               handoff->phy_handoff_base = next_section_header;
> > +               debug("%s: PHY handoff base = 0x%x\n", __func__,
> > +                     (u32)handoff->phy_handoff_base);
> > +
> > +               /* PHY base physical address */
> > +               handoff->phy_base = readl(handoff->phy_handoff_base +
> > +                                       SOC64_HANDOFF_DDR_PHY_BASE_OFFSET);
> > +               debug("%s: PHY base = 0x%x\n", __func__,
> > +                     (u32)handoff->phy_base);
> > +
> > +               /* Get the total length of PHY handoff section */
> > +               handoff->phy_total_length = readl(handoff->phy_handoff_base +
> > +                                               SOC64_HANDOFF_OFFSET_LENGTH);
> > +               debug("%s: PHY total length in byte = 0x%x\n", __func__,
> > +                     (u32)handoff->phy_total_length);
> > +
> > +               /*
> > +                * Get the length of user setting data in DDR PHY handoff
> > +                * section
> > +                */
> > +               handoff->phy_handoff_length = socfpga_get_handoff_size((void *)
> > +                                               handoff->phy_handoff_base);
> > +               debug("%s: PHY handoff length in word(32-bit) = 0x%x\n",
> > +                     __func__, (u32)handoff->phy_handoff_length);
> > +
> > +               /* Wrong format on PHY user setting data */
> > +               if (handoff->phy_handoff_length < 0) {
> > +                       debug("%s: Wrong format on PHY user setting data\n",
> > +                             __func__);
> > +                       return -ENOEXEC;
> > +               }
> > +
> > +               /* Get the next handoff section address */
> > +               next_section_header = handoff->phy_handoff_base +
> > +                                       handoff->phy_total_length;
> > +               debug("%s: Next handoff section header location = 0x%llx\n",
> > +                     __func__, next_section_header);
> > +       } else {
> > +               debug("%s: Wrong format for DDR handoff, expect PHY",
> > +                     __func__);
> > +               debug(" handoff section after umctl2 handoff section\n");
> > +               return -ENOEXEC;
> > +       }
> > +
> > +       /* Checking next section handoff is PHY init Engine ? */
> > +       if (readl(next_section_header) ==
> > +               SOC64_HANDOFF_DDR_PHY_INIT_ENGINE_MAGIC) {
> > +               /* DDR PHY Engine handoff */
> > +               handoff->phy_engine_handoff_base = next_section_header;
> > +               debug("%s: PHY init engine handoff base = 0x%x\n", __func__,
> > +                     (u32)handoff->phy_engine_handoff_base);
> > +
> > +               /* Get the total length of PHY init engine handoff section */
> > +               handoff->phy_engine_total_length =
> > +                               readl(handoff->phy_engine_handoff_base +
> > +                                     SOC64_HANDOFF_OFFSET_LENGTH);
> > +               debug("%s: PHY engine total length in byte = 0x%x\n", __func__,
> > +                     (u32)handoff->phy_engine_total_length);
> > +
> > +               /*
> > +                * Get the length of user setting data in DDR PHY init engine
> > +                * handoff section
> > +                */
> > +               handoff->phy_engine_handoff_length =
> > +                       socfpga_get_handoff_size((void *)
> > +                                       handoff->phy_engine_handoff_base);
> > +               debug("%s: PHY engine handoff length in word(32-bit) = 0x%x\n",
> > +                     __func__, (u32)handoff->phy_engine_handoff_length);
> > +
> > +               /* Wrong format on PHY init engine setting data */
> > +               if (handoff->phy_engine_handoff_length < 0) {
> > +                       debug("%s: Wrong format on PHY init engine ",
> > +                             __func__);
> > +                       debug("user setting data\n");
> > +                       return -ENOEXEC;
> > +               }
> > +       } else {
> > +               debug("%s: Wrong format for DDR handoff, expect PHY",
> > +                     __func__);
> > +               debug(" init engine handoff section after PHY handoff\n");
> > +               debug(" section\n");
> > +               return -ENOEXEC;
> > +       }
> > +
> > +       handoff->train_imem_base = handoff->phy_base +
> > +                                               DDR_PHY_TRAIN_IMEM_OFFSET;
> > +       debug("%s: PHY train IMEM base = 0x%x\n",
> > +             __func__, (u32)handoff->train_imem_base);
> > +
> > +       handoff->train_dmem_base = handoff->phy_base +
> > +                                               DDR_PHY_TRAIN_DMEM_OFFSET;
> > +       debug("%s: PHY train DMEM base = 0x%x\n",
> > +             __func__, (u32)handoff->train_dmem_base);
> > +
> > +       handoff->train_imem_length =
> SOC64_HANDOFF_DDR_TRAIN_IMEM_LENGTH;
> > +       debug("%s: PHY train IMEM length = 0x%x\n",
> > +             __func__, (u32)handoff->train_imem_length);
> > +
> > +       handoff->train_dmem_length =
> SOC64_HANDOFF_DDR_TRAIN_DMEM_LENGTH;
> > +       debug("%s: PHY train DMEM length = 0x%x\n",
> > +             __func__, (u32)handoff->train_dmem_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;
> > +}
> > +
> > +static int ddr_start_dfi_init(phys_addr_t umctl2_base,
> > +                             enum ddr_type umctl2_type)
> > +{
> > +       int ret;
> > +
> > +       debug("%s: Start DFI init\n", __func__);
> > +
> > +       /* Enable quasi-dynamic programing of controller registers */
> > +       clrbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       ret = enable_quasi_dynamic_reg_grp3(umctl2_base, umctl2_type);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /* Start DFI init sequence */
> > +       setbits_le32(umctl2_base + DDR4_DFIMISC_OFFSET,
> > +                    DDR4_DFIMISC_DFI_INIT_START);
> > +
> > +       /* Complete quasi-dynamic register programming */
> > +       setbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Polling programming done */
> > +       ret = wait_for_bit_le32((const void *)(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;
> > +}
> > +
> > +static int ddr_check_dfi_init_complete(phys_addr_t umctl2_base,
> > +                                      enum ddr_type umctl2_type)
> > +{
> > +       int ret;
> > +
> > +       /* Polling DFI init complete */
> > +       ret = wait_for_bit_le32((const void *)(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("%s: DFI init completed.\n", __func__);
> > +
> > +       /* Enable quasi-dynamic programing of controller registers */
> > +       clrbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       ret = enable_quasi_dynamic_reg_grp3(umctl2_base, umctl2_type);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /* Stop DFI init sequence */
> > +       clrbits_le32(umctl2_base + DDR4_DFIMISC_OFFSET,
> > +                    DDR4_DFIMISC_DFI_INIT_START);
> > +
> > +       /* Complete quasi-dynamic register programming */
> > +       setbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Polling programming done */
> > +       ret = wait_for_bit_le32((const void *)(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:DDR programming done\n", __func__);
> > +
> > +       return ret;
> > +}
> > +
> > +static int ddr_trigger_sdram_init(phys_addr_t umctl2_base,
> > +                                 enum ddr_type umctl2_type)
> > +{
> > +       int ret;
> > +
> > +       /* Enable quasi-dynamic programing of controller registers */
> > +       clrbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       ret = enable_quasi_dynamic_reg_grp3(umctl2_base, umctl2_type);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /* Unmasking dfi init complete */
> > +       setbits_le32(umctl2_base + DDR4_DFIMISC_OFFSET,
> > +                    DDR4_DFIMISC_DFI_INIT_COMPLETE_EN);
> > +
> > +       /* Software exit from self-refresh */
> > +       clrbits_le32(umctl2_base + DDR4_PWRCTL_OFFSET,
> DDR4_PWRCTL_SELFREF_SW);
> > +
> > +       /* Complete quasi-dynamic register programming */
> > +       setbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Polling programming done */
> > +       ret = wait_for_bit_le32((const void *)(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:DDR programming done\n", __func__);
> > +       return ret;
> > +}
> > +
> > +static int ddr_post_handoff_config(phys_addr_t umctl2_base,
> > +                                  enum ddr_type umctl2_type)
> > +{
> > +       int ret = 0;
> > +       u32 value;
> > +       u32 start = get_timer(0);
> > +
> > +       /* Polling until SDRAM entered normal operating mode */
> > +       value = readl(umctl2_base + DDR4_STAT_OFFSET) &
> > +                     DDR4_STAT_OPERATING_MODE;
> Can merge to "do..while" loop below.

Okay.

> 
> > +       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(umctl2_base + DDR4_STAT_OFFSET) &
> > +                             DDR4_STAT_OPERATING_MODE;
> > +
> > +               udelay(1);
> > +               WATCHDOG_RESET();
> > +       }
> > +
> > +       printf("DDR entered normal operating mode\n");
> > +
> > +       /* Enabling auto refresh */
> > +       clrbits_le32(umctl2_base + DDR4_RFSHCTL3_OFFSET,
> > +                    DDR4_RFSHCTL3_DIS_AUTO_REFRESH);
> > +
> > +       /* Checking ECC is enabled? */
> > +       value = readl(umctl2_base + DDR4_ECCCFG0_OFFSET) &
> DDR4_ECC_MODE;
> > +       if (value) {
> > +               printf("ECC is enabled\n");
> > +               ret = scrubber_ddr_config(umctl2_base, umctl2_type);
> > +               if (ret)
> > +                       printf("Failed to enable ECC\n");
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +static int configure_training_firmware(struct ddr_handoff *ddr_handoff_info,
> > +       const void *train_imem, const void *train_dmem)
> > +{
> > +       int ret = 0;
> > +
> > +       printf("Configuring training firmware ...\n");
> > +
> > +       /* Reset SDRAM */
> > +       writew(DDR_PHY_PROTECT_MEMRESET,
> > +              (uintptr_t)(ddr_handoff_info->phy_base +
> > +              DDR_PHY_MEMRESETL_OFFSET));
> > +
> > +       /* Enable access to the PHY configuration registers */
> > +       clrbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_APBONLY0_OFFSET,
> > +                    DDR_PHY_MICROCONTMUXSEL);
> > +
> > +       /* Copy train IMEM bin */
> > +       memcpy((void *)ddr_handoff_info->train_imem_base, train_imem,
> > +              ddr_handoff_info->train_imem_length);
> > +
> > +       ret = memcmp((void *)ddr_handoff_info->train_imem_base, train_imem,
> > +                    ddr_handoff_info->train_imem_length);
> > +       if (ret) {
> > +               debug("%s: Failed to copy train IMEM binary\n", __func__);
> > +               /* Isolate the APB access from internal CSRs */
> > +               setbits_le16(ddr_handoff_info->phy_base +
> > +                            DDR_PHY_APBONLY0_OFFSET,
> DDR_PHY_MICROCONTMUXSEL);
> > +               return ret;
> > +       }
> > +
> > +       memcpy((void *)ddr_handoff_info->train_dmem_base, train_dmem,
> > +              ddr_handoff_info->train_dmem_length);
> > +
> > +       ret = memcmp((void *)ddr_handoff_info->train_dmem_base,
> train_dmem,
> > +                    ddr_handoff_info->train_dmem_length);
> > +       if (ret)
> > +               debug("%s: Failed to copy train DMEM binary\n", __func__);
> > +
> > +       /* Isolate the APB access from internal CSRs */
> > +       setbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_APBONLY0_OFFSET,
> > +                    DDR_PHY_MICROCONTMUXSEL);
> > +
> > +       return ret;
> > +}
> > +
> > +static void calibrating_sdram(struct ddr_handoff *ddr_handoff_info)
> > +{
> > +       /* Init mailbox protocol - set 1 to DCTWRITEPROT[0] */
> > +       setbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_DCTWRITEPROT_OFFSET,
> > +                    DDR_PHY_DCTWRITEPROT);
> > +
> > +       /* Init mailbox protocol - set 1 to UCTWRITEPROT[0] */
> > +       setbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_UCTWRITEPROT_OFFSET,
> > +                    DDR_PHY_UCTWRITEPROT);
> > +
> > +       /* Reset and stalling ARC processor */
> > +       setbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_MICRORESET_OFFSET,
> > +                    DDR_PHY_MICRORESET_RESET | DDR_PHY_MICRORESET_STALL);
> > +
> > +       /* Release ARC processor */
> > +       clrbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_MICRORESET_OFFSET,
> > +                    DDR_PHY_MICRORESET_RESET);
> > +
> > +       /* Starting PHY firmware execution */
> > +       clrbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_MICRORESET_OFFSET,
> > +                    DDR_PHY_MICRORESET_STALL);
> > +}
> > +
> > +static int get_mail(struct ddr_handoff *handoff, enum message_mode mode,
> > +                   u32 *message_id)
> > +{
> > +       int ret;
> > +
> > +       /* Polling major messages from PMU */
> > +       ret = wait_for_bit_le16((const void *)(handoff->phy_base +
> > +                               DDR_PHY_UCTSHADOWREGS_OFFSET),
> > +                               DDR_PHY_UCTSHADOWREGS_UCTWRITEPROTESHADOW,
> > +                               false, TIMEOUT_200MS, false);
> > +       if (ret) {
> > +               debug("%s: Timeout while waiting for",
> > +                     __func__);
> > +               debug(" major messages from PMU\n");
> > +               return ret;
> > +       }
> > +
> > +       *message_id = readw((uintptr_t)(handoff->phy_base +
> > +                           DDR_PHY_UCTWRITEONLYSHADOW_OFFSET));
> > +
> > +       if (mode == STREAMING_MESSAGE)
> > +               *message_id |= readw((uintptr_t)((handoff->phy_base +
> > +                                    DDR_PHY_UCTDATWRITEONLYSHADOW_OFFSET))) <<
> > +                                    SZ_16;
> > +
> > +       /* Ack the receipt of the major message */
> > +       clrbits_le16(handoff->phy_base + DDR_PHY_DCTWRITEPROT_OFFSET,
> > +                    DDR_PHY_DCTWRITEPROT);
> > +
> > +       ret = wait_for_bit_le16((const void *)(handoff->phy_base +
> > +                               DDR_PHY_UCTSHADOWREGS_OFFSET),
> > +                               DDR_PHY_UCTSHADOWREGS_UCTWRITEPROTESHADOW,
> > +                               true, TIMEOUT_200MS, false);
> > +       if (ret) {
> > +               debug("%s: Timeout while waiting for",
> > +                     __func__);
> > +               debug(" ack the receipt of the major message completed\n");
> > +               return ret;
> > +       }
> > +
> > +       /* Complete protocol */
> > +       setbits_le16(handoff->phy_base + DDR_PHY_DCTWRITEPROT_OFFSET,
> > +                    DDR_PHY_DCTWRITEPROT);
> > +
> > +       return ret;
> > +}
> > +
> > +static int get_mail_streaming(struct ddr_handoff *handoff,
> > +                             enum message_mode mode, u32 *index)
> > +{
> > +       int ret;
> > +
> > +       *index = readw((uintptr_t)(handoff->phy_base +
> > +                      DDR_PHY_UCTWRITEONLYSHADOW_OFFSET));
> > +
> > +       if (mode == STREAMING_MESSAGE)
> > +               *index |= readw((uintptr_t)((handoff->phy_base +
> > +                               DDR_PHY_UCTDATWRITEONLYSHADOW_OFFSET))) <<
> > +                               SZ_16;
> > +
> > +       /* Ack the receipt of the major message */
> > +       clrbits_le16(handoff->phy_base + DDR_PHY_DCTWRITEPROT_OFFSET,
> > +                    DDR_PHY_DCTWRITEPROT);
> > +
> > +       ret = wait_for_bit_le16((const void *)(handoff->phy_base +
> > +                               DDR_PHY_UCTSHADOWREGS_OFFSET),
> > +                               DDR_PHY_UCTSHADOWREGS_UCTWRITEPROTESHADOW,
> > +                               true, TIMEOUT_200MS, false);
> > +       if (ret) {
> > +               debug("%s: Timeout while waiting for",
> > +                     __func__);
> > +               debug(" ack the receipt of the major message completed\n");
> > +               return ret;
> > +       }
> > +
> > +       /* Complete protocol */
> > +       setbits_le16(handoff->phy_base + DDR_PHY_DCTWRITEPROT_OFFSET,
> > +                    DDR_PHY_DCTWRITEPROT);
> > +
> > +       return 0;
> > +}
> > +
> > +static int decode_streaming_message(struct ddr_handoff *ddr_handoff_info,
> > +                                   u32 *streaming_index)
> > +{
> > +       int i = 0, ret;
> > +       u32 temp;
> > +
> > +       temp = *streaming_index;
> > +
> > +       while (i < GET_LOWHW_DATA(temp)) {
> > +               ret = get_mail(ddr_handoff_info, STREAMING_MESSAGE,
> > +                              streaming_index);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               printf("args[%d]: 0x%x ", i, *streaming_index);
> > +               i++;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int poll_for_training_complete(struct ddr_handoff *ddr_handoff_info)
> > +{
> > +       int ret;
> > +       u32 message_id = 0;
> > +       u32 streaming_index = 0;
> > +
> > +       do {
> > +               ret = get_mail(ddr_handoff_info, MAJOR_MESSAGE, &message_id);
> > +               if (ret)
> > +                       return ret;
> > +
> > +                printf("Major message id = 0%x\n", message_id);
> > +
> > +               if (message_id == FW_STREAMING_MSG_ID) {
> > +                       ret = get_mail_streaming(ddr_handoff_info,
> > +                                                STREAMING_MESSAGE,
> > +                                                &streaming_index);
> > +                       if (ret)
> > +                               return ret;
> > +
> > +                       printf("streaming index 0%x : ", streaming_index);
> > +
> > +                       decode_streaming_message(ddr_handoff_info,
> > +                                                &streaming_index);
> > +
> > +                       printf("\n");
> > +               }
> > +       } while ((message_id != FW_TRAINING_COMPLETED_STAT) &&
> > +              (message_id != FW_TRAINING_FAILED_STAT));
> > +
> > +       if (message_id == FW_TRAINING_COMPLETED_STAT) {
> > +               printf("DDR firmware training completed\n");
> > +       } else if (message_id == FW_TRAINING_FAILED_STAT) {
> > +               printf("DDR firmware training failed\n");
> > +               hang();
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static void enable_phy_clk_for_csr_access(struct ddr_handoff *handoff,
> > +                                         bool enable)
> > +{
> > +       if (enable) {
> > +               /* Enable PHY clk */
> > +               setbits_le16((uintptr_t)(handoff->phy_base +
> > +                            DDR_PHY_UCCLKHCLKENABLES_OFFSET),
> > +                            DDR_PHY_UCCLKHCLKENABLES_UCCLKEN |
> > +                            DDR_PHY_UCCLKHCLKENABLES_HCLKEN);
> > +       } else {
> > +               /* Disable PHY clk */
> > +               clrbits_le16((uintptr_t)(handoff->phy_base +
> > +                            DDR_PHY_UCCLKHCLKENABLES_OFFSET),
> > +                            DDR_PHY_UCCLKHCLKENABLES_UCCLKEN |
> > +                            DDR_PHY_UCCLKHCLKENABLES_HCLKEN);
> > +       }
> > +}
> > +
> > +/* helper function for updating train result to umctl2 RANKCTL register */
> > +static void set_cal_res_to_rankctrl(u32 reg_addr, u16 update_value,
> > +                                   u32 mask, u32 msb_mask, u32 shift)
> > +{
> > +       u32 reg, value;
> > +
> > +       reg = readl((uintptr_t)reg_addr);
> > +
> > +       debug("max value divided by 2 is 0x%x\n", update_value);
> > +       debug("umclt2 register 0x%x value is 0%x before ", reg_addr, reg);
> > +       debug("update with train result\n");
> > +
> > +       value = (reg & mask) >> shift;
> > +
> > +       value += update_value + 3;
> > +
> > +       /* reg value greater than 0xF, set one to diff_rank_wr_gap_msb */
> > +       if (value > 0xF)
> > +               setbits_le32((u32 *)(uintptr_t)reg_addr, msb_mask);
> > +       else
> > +               clrbits_le32((u32 *)(uintptr_t)reg_addr, msb_mask);
> > +
> > +       reg = readl((uintptr_t)reg_addr);
> > +
> > +       value = (value << shift) & mask;
> > +
> > +       /* update register */
> > +       writel((reg & (~mask)) | value, (uintptr_t)reg_addr);
> > +
> > +       reg = readl((uintptr_t)reg_addr);
> > +       debug("umclt2 register 0x%x value is 0%x before ", reg_addr, reg);
> > +       debug("update with train result\n");
> > +}
> > +
> > +/* helper function for updating train result to register */
> > +static void set_cal_res_to_reg(u32 reg_addr, u16 update_value, u32 mask,
> > +                              u32 shift)
> > +{
> > +       u32 reg, value;
> > +
> > +       reg = readl((uintptr_t)reg_addr);
> > +
> > +       debug("max value divided by 2 is 0x%x\n", update_value);
> > +       debug("umclt2 register 0x%x value is 0%x before ", reg_addr, reg);
> > +       debug("update with train result\n");
> > +
> > +       value = (reg & mask) >> shift;
> > +
> > +       value = ((value + update_value + 3) << shift) & mask;
> > +
> > +       /* update register */
> > +       writel((reg & (~mask)) | value, (uintptr_t)reg_addr);
> > +
> > +       reg = readl((uintptr_t)reg_addr);
> > +       debug("umclt2 register 0x%x value is 0%x before ", reg_addr, reg);
> > +       debug("update with train result\n");
> > +}
> > +
> > +static u16 get_max_txdqsdlytg0_ux_p0(struct ddr_handoff *handoff, u32 reg,
> > +                                    u8 numdbyte, u16 upd_val)
> > +{
> > +       u32 b_addr;
> > +       u16 val;
> > +       u8 byte;
> > +
> > +       /* Getting max value from DBYTEx TxDqsDlyTg0_ux_p0 */
> > +       for (byte = 0; byte < numdbyte; byte++) {
> > +               b_addr = byte << 13;
> > +
> > +               /* TxDqsDlyTg0[9:6] is the coarse delay */
> > +               val = (readw((uintptr_t)(handoff->phy_base +
> > +                            reg + b_addr)) &
> > +                            DDR_PHY_TXDQDLYTG0_COARSE_DELAY) >>
> > +                            DDR_PHY_TXDQDLYTG0_COARSE_DELAY_SHIFT;
> > +
> > +               upd_val = max(val, upd_val);
> > +       }
> > +
> > +       return upd_val;
> > +}
> > +
> > +static int set_cal_res_to_umctl2(struct ddr_handoff *handoff,
> > +                                phys_addr_t umctl2_base,
> > +                                enum ddr_type umctl2_type)
> > +{
> > +       int ret;
> > +       u8 numdbyte = 0x8;
> > +       u16 upd_val, val;
> > +       u32 dramtmg2_reg_addr, rankctl_reg_addr, reg_addr;
> > +
> > +       /* Enable quasi-dynamic programing of the controller registers */
> > +       clrbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       ret = enable_quasi_dynamic_reg_grp3(umctl2_base, umctl2_type);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /* Enable access to the PHY configuration registers */
> > +       clrbits_le16(handoff->phy_base + DDR_PHY_APBONLY0_OFFSET,
> > +                    DDR_PHY_MICROCONTMUXSEL);
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_WW_1_0_OFFSET)));
> > +
> > +               upd_val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                       DMEM_MB_CDD_WW_0_1_OFFSET)));
> > +       } else if (umctl2_type == DDRTYPE_LPDDR4_0) {
> > +               val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                   DMEM_MB_CDD_CHA_WW_1_0_OFFSET)));
> > +
> > +               upd_val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                        DMEM_MB_CDD_CHA_WW_0_1_OFFSET)));
> > +       } else if (umctl2_type == DDRTYPE_LPDDR4_1) {
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_CHB_WW_1_0_OFFSET)));
> > +
> > +               upd_val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                       DMEM_MB_CDD_CHB_WW_0_1_OFFSET)));
> > +       }
> > +
> > +       upd_val = max(val, upd_val);
> > +       debug("max value is 0x%x\n", upd_val);
> > +
> > +       /* Divided by two is required when running in freq ratio 1:2 */
> > +       if (!(readl(umctl2_base + DDR4_MSTR_OFFSET) & DDR4_FREQ_RATIO))
> > +               upd_val = DIV_ROUND_CLOSEST(upd_val, 2);
> > +
> > +       debug("Update train value to umctl2 RANKCTL.diff_rank_wr_gap\n");
> > +       rankctl_reg_addr = umctl2_base + DDR4_RANKCTL_OFFSET;
> > +       /* Update train value to umctl2 RANKCTL.diff_rank_wr_gap */
> > +       set_cal_res_to_rankctrl(rankctl_reg_addr, upd_val,
> > +                               DDR4_RANKCTL_DIFF_RANK_WR_GAP,
> > +                               DDR4_RANKCTL_DIFF_RANK_WR_GAP_MSB,
> > +                               DDR4_RANKCTL_DIFF_RANK_WR_GAP_SHIFT);
> > +
> > +       debug("Update train value to umctl2 DRAMTMG2.W2RD\n");
> > +       dramtmg2_reg_addr = umctl2_base + DDR4_DRAMTMG2_OFFSET;
> > +       /* Update train value to umctl2 dramtmg2.wr2rd */
> > +       set_cal_res_to_reg(dramtmg2_reg_addr, upd_val,
> DDR4_DRAMTMG2_WR2RD, 0);
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               debug("Update train value to umctl2 DRAMTMG9.W2RD_S\n");
> > +               reg_addr = umctl2_base + DDR4_DRAMTMG9_OFFSET;
> > +               /* Update train value to umctl2 dramtmg9.wr2rd_s */
> > +               set_cal_res_to_reg(reg_addr, upd_val, DDR4_DRAMTMG9_W2RD_S,
> 0);
> > +       }
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_RR_1_0_OFFSET)));
> > +
> > +               upd_val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                       DMEM_MB_CDD_RR_0_1_OFFSET)));
> > +       } else if (umctl2_type == DDRTYPE_LPDDR4_0) {
> > +               val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                   DMEM_MB_CDD_CHA_RR_1_0_OFFSET)));
> > +
> > +               upd_val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                        DMEM_MB_CDD_CHA_RR_0_1_OFFSET)));
> > +       } else if (umctl2_type == DDRTYPE_LPDDR4_1) {
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_CHB_RR_1_0_OFFSET)));
> > +
> > +               upd_val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                       DMEM_MB_CDD_CHB_RR_0_1_OFFSET)));
> > +       }
> > +
> > +       upd_val = max(val, upd_val);
> > +       debug("max value is 0x%x\n", upd_val);
> > +
> > +       /* Divided by two is required when running in freq ratio 1:2 */
> > +       if (!(readl(umctl2_base + DDR4_MSTR_OFFSET) & DDR4_FREQ_RATIO))
> > +               upd_val = DIV_ROUND_CLOSEST(upd_val, 2);
> > +
> > +       debug("Update train value to umctl2 RANKCTL.diff_rank_rd_gap\n");
> > +       /* Update train value to umctl2 RANKCTL.diff_rank_rd_gap */
> > +       set_cal_res_to_rankctrl(rankctl_reg_addr, upd_val,
> > +                               DDR4_RANKCTL_DIFF_RANK_RD_GAP,
> > +                               DDR4_RANKCTL_DIFF_RANK_RD_GAP_MSB,
> > +                               DDR4_RANKCTL_DIFF_RANK_RD_GAP_SHIFT);
> > +
> > +       if (umctl2_type == DDRTYPE_DDR4) {
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_RW_1_1_OFFSET)));
> > +
> > +               upd_val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                       DMEM_MB_CDD_RW_1_0_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_RW_0_1_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +
> > +               val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                   DMEM_MB_CDD_RW_0_0_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +       } else if (umctl2_type == DDRTYPE_LPDDR4_0) {
> > +               val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                   DMEM_MB_CDD_CHA_RW_1_1_OFFSET)));
> > +
> > +               upd_val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                        DMEM_MB_CDD_CHA_RW_1_0_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +
> > +               val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                   DMEM_MB_CDD_CHA_RW_0_1_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_CHA_RW_0_0_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +       } else if (umctl2_type == DDRTYPE_LPDDR4_1) {
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_CHB_RW_1_1_OFFSET)));
> > +
> > +               upd_val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                       DMEM_MB_CDD_CHB_RW_1_0_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +
> > +               val = GET_HIGHB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                    DMEM_MB_CDD_CHB_RW_0_1_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +
> > +               val = GET_LOWB_DATA(readw((uintptr_t)(handoff->phy_base +
> > +                                   DMEM_MB_CDD_CHB_RW_0_0_OFFSET)));
> > +
> > +               upd_val = max(val, upd_val);
> > +       }
> > +
> > +       debug("max value is 0x%x\n", upd_val);
> > +
> > +       /* Divided by two is required when running in freq ratio 1:2 */
> > +       if (!(readl(umctl2_base + DDR4_MSTR_OFFSET) & DDR4_FREQ_RATIO))
> > +               upd_val = DIV_ROUND_CLOSEST(upd_val, 2);
> > +
> > +       debug("Update train value to umctl2 dramtmg2.rd2wr\n");
> > +       /* Update train value to umctl2 dramtmg2.rd2wr */
> > +       set_cal_res_to_reg(dramtmg2_reg_addr, upd_val,
> DDR4_DRAMTMG2_RD2WR,
> > +                          DDR4_DRAMTMG2_RD2WR_SHIFT);
> > +
> > +       /* Checking ECC is enabled?, lpddr4 using inline ECC */
> > +       val = readl(umctl2_base + DDR4_ECCCFG0_OFFSET) & DDR4_ECC_MODE;
> > +       if (val && umctl2_type == DDRTYPE_DDR4)
> > +               numdbyte = 0x9;
> > +
> > +       upd_val = 0;
> > +
> > +       /* Getting max value from DBYTEx TxDqsDlyTg0_u0_p0 */
> > +       upd_val = get_max_txdqsdlytg0_ux_p0(handoff,
> > +                                           DDR_PHY_DBYTE0_TXDQDLYTG0_U0_P0,
> > +                                           numdbyte, upd_val);
> > +
> > +       /* Getting max value from DBYTEx TxDqsDlyTg0_u1_p0 */
> > +       upd_val = get_max_txdqsdlytg0_ux_p0(handoff,
> > +                                           DDR_PHY_DBYTE0_TXDQDLYTG0_U1_P0,
> > +                                           numdbyte, upd_val);
> > +
> > +       debug("TxDqsDlyTg0 max value is 0x%x\n", upd_val);
> > +
> > +       /* Divided by two is required when running in freq ratio 1:2 */
> > +       if (!(readl(umctl2_base + DDR4_MSTR_OFFSET) & DDR4_FREQ_RATIO))
> > +               upd_val = DIV_ROUND_CLOSEST(upd_val, 2);
> > +
> > +       reg_addr = umctl2_base + DDR4_DFITMG1_OFFSET;
> > +       /* Update train value to umctl2 dfitmg1.dfi_wrdata_delay */
> > +       set_cal_res_to_reg(reg_addr, upd_val,
> DDR4_DFITMG1_DFI_T_WRDATA_DELAY,
> > +                          DDR4_DFITMG1_DFI_T_WRDATA_SHIFT);
> > +
> > +       /* Complete quasi-dynamic register programming */
> > +       setbits_le32(umctl2_base + DDR4_SWCTL_OFFSET,
> DDR4_SWCTL_SW_DONE);
> > +
> > +       /* Polling programming done */
> > +       ret = wait_for_bit_le32((const void *)(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");
> > +       }
> > +
> > +       /* Isolate the APB access from internal CSRs */
> > +       setbits_le16(handoff->phy_base + DDR_PHY_APBONLY0_OFFSET,
> > +                    DDR_PHY_MICROCONTMUXSEL);
> > +
> > +       return ret;
> > +}
> > +
> > +static int start_ddr_calibration(struct ddr_handoff *ddr_handoff_info)
> > +{
> > +       int ret;
> > +
> > +       /* Implement 1D training firmware */
> > +       ret = configure_training_firmware(ddr_handoff_info,
> > +               (const void *)SOC64_HANDOFF_DDR_TRAIN_IMEM_1D_SECTION,
> > +               (const void *)SOC64_HANDOFF_DDR_TRAIN_DMEM_1D_SECTION);
> > +       if (ret) {
> > +               debug("%s: Failed to configure 1D training firmware\n",
> > +                     __func__);
> > +               return ret;
> > +       }
> > +
> > +       calibrating_sdram(ddr_handoff_info);
> > +
> > +       ret = poll_for_training_complete(ddr_handoff_info);
> > +       if (ret) {
> > +               debug("%s: Failed to get FW training completed\n",
> > +                     __func__);
> > +               return ret;
> > +       }
> > +
> > +       /* Updating training result to DDR controller */
> > +       if (ddr_handoff_info->cntlr_t == DDRTYPE_DDR4) {
> > +               ret = set_cal_res_to_umctl2(ddr_handoff_info,
> > +                                           ddr_handoff_info->cntlr_base,
> > +                                           ddr_handoff_info->cntlr_t);
> > +               if (ret) {
> > +                       debug("%s: Failed to update train result to ",
> > +                             __func__);
> > +                       debug("DDR controller\n");
> > +                       return ret;
> > +               }
> > +       }
> > +
> > +       /* Implement 2D training firmware */
> > +       ret = configure_training_firmware(ddr_handoff_info,
> > +               (const void *)SOC64_HANDOFF_DDR_TRAIN_IMEM_2D_SECTION,
> > +               (const void *)SOC64_HANDOFF_DDR_TRAIN_DMEM_2D_SECTION);
> > +       if (ret) {
> > +               if (ret) {
> Why need 2 checking for "ret"?

Good catch !! I think this was accidently duplicated

> 
> > +                       debug("%s: Failed to update train result to ",
> > +                             __func__);
> > +                       debug("DDR controller\n");
> > +                       return ret;
> > +               }
> > +       }
> > +
> > +       calibrating_sdram(ddr_handoff_info);
> > +
> > +       ret = poll_for_training_complete(ddr_handoff_info);
> > +       if (ret)
> > +               debug("%s: Failed to get FW training completed\n",
> > +                     __func__);
> > +
> > +       return ret;
> > +}
> > +
> > +static int init_controller(struct ddr_handoff *ddr_handoff_info,
> > +                          u32 *user_backup, u32 *user_backup_2nd)
> > +{
> > +       int ret = 0;
> > +
> > +       if (ddr_handoff_info->cntlr_t == DDRTYPE_DDR4  ||
> > +           ddr_handoff_info->cntlr_t == DDRTYPE_LPDDR4_0) {
> > +               /* Initialize 1st DDR controller */
> > +               ret = init_umctl2(ddr_handoff_info->cntlr_handoff_base,
> > +                                 ddr_handoff_info->cntlr_base,
> > +                                 ddr_handoff_info->cntlr_t,
> > +                                 ddr_handoff_info->cntlr_handoff_length,
> > +                                 user_backup);
> > +               if (ret) {
> > +                       debug("%s: Failed to inilialize first controller\n",
> > +                             __func__);
> > +                       return ret;
> > +               }
> > +       }
> > +
> > +       if (ddr_handoff_info->cntlr2_t == DDRTYPE_LPDDR4_1) {
> > +               /* Initialize 2nd DDR controller */
> > +               ret = init_umctl2(ddr_handoff_info->cntlr2_handoff_base,
> > +                                 ddr_handoff_info->cntlr2_base,
> > +                                 ddr_handoff_info->cntlr2_t,
> > +                                 ddr_handoff_info->cntlr2_handoff_length,
> > +                                 user_backup_2nd);
> > +               if (ret)
> > +                       debug("%s: Failed to inilialize 2nd controller\n",
> > +                             __func__);
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +static int dfi_init(struct ddr_handoff *ddr_handoff_info)
> > +{
> > +       int ret;
> > +
> > +       ret = ddr_start_dfi_init(ddr_handoff_info->cntlr_base,
> > +                                ddr_handoff_info->cntlr_t);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ddr_handoff_info->cntlr2_t == DDRTYPE_LPDDR4_1)
> > +               ret = ddr_start_dfi_init(ddr_handoff_info->cntlr2_base,
> > +                                        ddr_handoff_info->cntlr2_t);
> > +
> > +       return ret;
> > +}
> > +
> > +static int check_dfi_init(struct ddr_handoff *handoff)
> > +{
> > +       int ret;
> > +
> > +       ret = ddr_check_dfi_init_complete(handoff->cntlr_base,
> > +                                         handoff->cntlr_t);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (handoff->cntlr2_t == DDRTYPE_LPDDR4_1)
> > +               ret = ddr_check_dfi_init_complete(handoff->cntlr2_base,
> > +                                                 handoff->cntlr2_t);
> > +
> > +       return ret;
> > +}
> > +
> > +static int trigger_sdram_init(struct ddr_handoff *handoff)
> > +{
> > +       int ret;
> > +
> > +       ret = ddr_trigger_sdram_init(handoff->cntlr_base,
> > +                                    handoff->cntlr_t);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (handoff->cntlr2_t == DDRTYPE_LPDDR4_1)
> > +               ret = ddr_trigger_sdram_init(handoff->cntlr2_base,
> > +                                            handoff->cntlr2_t);
> > +
> > +       return ret;
> > +}
> > +
> > +static int ddr_post_config(struct ddr_handoff *handoff)
> > +{
> > +       int ret;
> > +
> > +       ret = ddr_post_handoff_config(handoff->cntlr_base,
> > +                                     handoff->cntlr_t);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (handoff->cntlr2_t == DDRTYPE_LPDDR4_1)
> > +               ret = ddr_post_handoff_config(handoff->cntlr2_base,
> > +                                             handoff->cntlr2_t);
> > +
> > +       return ret;
> > +}
> > +
> > +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;
> > +}
> > +
> > +void reset_type_debug_print(u32 boot_scratch_cold0_reg)
> > +{
> > +       switch (get_reset_type(boot_scratch_cold0_reg)) {
> > +       case POR_RESET:
> > +               debug("%s: POR is triggered\n", __func__);
> > +               break;
> > +       case WARM_RESET:
> > +               debug("%s: Warm reset is triggered\n", __func__);
> > +               break;
> > +       case COLD_RESET:
> > +               debug("%s: Cold reset is triggered\n", __func__);
> > +               break;
> > +       default:
> > +               debug("%s: Invalid reset type\n", __func__);
> > +       }
> > +}
> > +
> > +bool is_ddr_init(void)
> > +{
> > +       u32 reg = readl(socfpga_get_sysmgr_addr() +
> > +                       SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
> > +
> > +       reset_type_debug_print(reg);
> > +
> > +       if (get_reset_type(reg) == POR_RESET) {
> > +               debug("%s: DDR init is required\n", __func__);
> > +               return true;
> > +       }
> > +
> > +       if (get_reset_type(reg) == WARM_RESET) {
> > +               debug("%s: DDR init is skipped\n", __func__);
> > +               return false;
> > +       }
> > +
> > +       if (get_reset_type(reg) == COLD_RESET) {
> > +               if (is_ddr_retention_enabled(reg) &&
> > +                   is_ddr_bitstream_sha_matching(reg)) {
> > +                       debug("%s: DDR retention bit is set\n", __func__);
> > +                       debug("%s: Matching in DDR bistream\n", __func__);
> > +                       debug("%s: DDR init is skipped\n", __func__);
> > +                       return false;
> > +               }
> > +       }
> > +
> > +       debug("%s: DDR init is required\n", __func__);
> > +       return true;
> > +}
> > +
> > +int sdram_mmr_init_full(struct udevice *dev)
> > +{
> > +       u32 user_backup[2], user_backup_2nd[2];
> > +       int ret;
> > +       struct bd_info bd;
> > +       struct ddr_handoff ddr_handoff_info;
> > +       struct altera_sdram_priv *priv = dev_get_priv(dev);
> > +
> > +       printf("Checking SDRAM configuration in progress ...\n");
> > +       ret = populate_ddr_handoff(&ddr_handoff_info);
> > +               if (ret) {
> > +                       debug("%s: Failed to populate DDR handoff\n",
> > +                             __func__);
> > +                       return ret;
> > +               }
> > +
> > +       /* Set the MPFE NoC mux to correct DDR controller type */
> > +       use_ddr4(ddr_handoff_info.cntlr_t);
> > +
> > +       if (is_ddr_init()) {
> > +               printf("SDRAM init in progress ...\n");
> > +
> > +               /*
> > +                * 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;
> > +
> > +               ret = init_controller(&ddr_handoff_info, user_backup,
> > +                                     user_backup_2nd);
> > +               if (ret) {
> > +                       debug("%s: Failed to inilialize DDR controller\n",
> > +                             __func__);
> > +                       return ret;
> > +               }
> > +
> > +               /* 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");
> > +
> > +               /* Initialize DDR PHY */
> > +               ret = init_phy(&ddr_handoff_info);
> > +               if (ret) {
> > +                       debug("%s: Failed to inilialize DDR PHY\n", __func__);
> > +                       return ret;
> > +               }
> > +
> > +               enable_phy_clk_for_csr_access(&ddr_handoff_info, true);
> > +
> > +               ret = start_ddr_calibration(&ddr_handoff_info);
> > +               if (ret) {
> > +                       debug("%s: Failed to calibrate DDR\n", __func__);
> > +                       return ret;
> > +               }
> > +
> > +               enable_phy_clk_for_csr_access(&ddr_handoff_info, false);
> > +
> > +               /* 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);
> > +
> > +               ret = dfi_init(&ddr_handoff_info);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               ret = check_dfi_init(&ddr_handoff_info);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               ret = trigger_sdram_init(&ddr_handoff_info);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               ret = ddr_post_config(&ddr_handoff_info);
> > +               if (ret)
> > +                       return ret;
> > +
> > +               /* Restore user settings */
> > +               writel(user_backup[0], ddr_handoff_info.cntlr_base +
> > +                      DDR4_PWRCTL_OFFSET);
> > +
> > +               if (ddr_handoff_info.cntlr2_t == DDRTYPE_LPDDR4_0)
> > +                       setbits_le32(ddr_handoff_info.cntlr_base +
> > +                                    DDR4_INIT0_OFFSET, user_backup[1]);
> > +
> > +               if (ddr_handoff_info.cntlr2_t == DDRTYPE_LPDDR4_1) {
> > +                       /* Restore user settings */
> > +                       writel(user_backup_2nd[0],
> > +                              ddr_handoff_info.cntlr2_base +
> > +                              DDR4_PWRCTL_OFFSET);
> > +
> > +                       setbits_le32(ddr_handoff_info.cntlr2_base +
> > +                                    DDR4_INIT0_OFFSET, user_backup_2nd[1]);
> > +               }
> > +
> > +               /* Enable input traffic per port */
> > +               setbits_le32(ddr_handoff_info.cntlr_base + DDR4_PCTRL0_OFFSET,
> > +                            DDR4_PCTRL0_PORT_EN);
> > +
> > +               if (ddr_handoff_info.cntlr2_t == DDRTYPE_LPDDR4_1) {
> > +                       /* Enable input traffic per port */
> > +                       setbits_le32(ddr_handoff_info.cntlr2_base +
> > +                                    DDR4_PCTRL0_OFFSET, DDR4_PCTRL0_PORT_EN);
> > +               }
> > +
> > +               printf("DDR init success\n");
> > +       }
> > +
> > +       /* Get bank configuration from devicetree */
> > +       ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL,
> > +                                    (phys_size_t *)&gd->ram_size, &bd);
> > +       if (ret) {
> > +               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;
> > +
> > +       sdram_size_check(&bd);
> > +
> > +       sdram_set_firewall(&bd);
> > +
> > +       return 0;
> > +}
> > diff --git a/drivers/ddr/altera/sdram_soc64.c
> b/drivers/ddr/altera/sdram_soc64.c
> > index cc656db97c..d6baac2410 100644
> > --- a/drivers/ddr/altera/sdram_soc64.c
> > +++ b/drivers/ddr/altera/sdram_soc64.c
> > @@ -100,12 +100,14 @@ int emif_reset(struct altera_sdram_plat *plat)
> >         return 0;
> >  }
> >
> > +#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
> >  int poll_hmc_clock_status(void)
> >  {
> >         return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() +
> >                                  SYSMGR_SOC64_HMC_CLK),
> >                                  SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false);
> >  }
> > +#endif
> >
> >  void sdram_clear_mem(phys_addr_t addr, phys_size_t size)
> >  {
> > @@ -249,11 +251,78 @@ phys_size_t sdram_calculate_size(struct
> altera_sdram_plat *plat)
> >         return size;
> >  }
> >
> > +void sdram_set_firewall(struct bd_info *bd)
> > +{
> > +       u32 i;
> > +       phys_size_t value;
> > +       u32 lower, upper;
> > +
> > +       for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
> > +               if (!bd->bi_dram[i].size)
> > +                       continue;
> > +
> > +               value = bd->bi_dram[i].start;
> > +
> > +               /* Keep first 1MB of SDRAM memory region as secure region when
> > +                * using ATF flow, where the ATF code is located.
> > +                */
> > +               if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0)
> > +                       value += SZ_1M;
> > +
> > +               /* Setting non-secure MPU region base and base extended */
> > +               lower = lower_32_bits(value);
> > +               upper = upper_32_bits(value);
> > +               FW_MPU_DDR_SCR_WRITEL(lower,
> > +                                     FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE +
> > +                                     (i * 4 * sizeof(u32)));
> > +               FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
> > +                                     FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT +
> > +                                     (i * 4 * sizeof(u32)));
> > +
> > +               /* Setting non-secure Non-MPU region base and base extended */
> > +               FW_MPU_DDR_SCR_WRITEL(lower,
> > +                                     FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE +
> > +                                     (i * 4 * sizeof(u32)));
> > +               FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
> > +                                     FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT
> +
> > +                                     (i * 4 * sizeof(u32)));
> > +
> > +               /* Setting non-secure MPU limit and limit extexded */
> > +               value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
> > +
> > +               lower = lower_32_bits(value);
> > +               upper = upper_32_bits(value);
> > +
> > +               FW_MPU_DDR_SCR_WRITEL(lower,
> > +                                     FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT +
> > +                                     (i * 4 * sizeof(u32)));
> > +               FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
> > +                                     FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT +
> > +                                     (i * 4 * sizeof(u32)));
> > +
> > +               /* Setting non-secure Non-MPU limit and limit extexded */
> > +               FW_MPU_DDR_SCR_WRITEL(lower,
> > +                                     FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT +
> > +                                     (i * 4 * sizeof(u32)));
> > +               FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
> > +                                     FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT
> +
> > +                                     (i * 4 * sizeof(u32)));
> > +
> > +               FW_MPU_DDR_SCR_WRITEL(BIT(i) | BIT(i + 8),
> > +                                     FW_MPU_DDR_SCR_EN_SET);
> > +       }
> > +}
> > +
> >  static int altera_sdram_of_to_plat(struct udevice *dev)
> >  {
> >         struct altera_sdram_plat *plat = dev_get_plat(dev);
> >         fdt_addr_t addr;
> >
> > +       /* These regs info are part of DDR handoff in bitstream */
> > +#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
> > +       return 0;
> > +#endif
> > +
> >         addr = dev_read_addr_index(dev, 0);
> >         if (addr == FDT_ADDR_T_NONE)
> >                 return -EINVAL;
> > @@ -314,6 +383,7 @@ static struct ram_ops altera_sdram_ops = {
> >  static const struct udevice_id altera_sdram_ids[] = {
> >         { .compatible = "altr,sdr-ctl-s10" },
> >         { .compatible = "intel,sdr-ctl-agilex" },
> > +       { .compatible = "intel,sdr-ctl-n5x" },
> >         { /* sentinel */ }
> >  };
> >
> > diff --git a/drivers/ddr/altera/sdram_soc64.h
> b/drivers/ddr/altera/sdram_soc64.h
> > index 8af0afc410..7460f8c220 100644
> > --- a/drivers/ddr/altera/sdram_soc64.h
> > +++ b/drivers/ddr/altera/sdram_soc64.h
> > @@ -180,6 +180,7 @@ int emif_reset(struct altera_sdram_plat *plat);
> >  int poll_hmc_clock_status(void);
> >  void sdram_clear_mem(phys_addr_t addr, phys_size_t size);
> >  void sdram_init_ecc_bits(struct bd_info *bd);
> > +void sdram_set_firewall(struct bd_info *bd);
> >  void sdram_size_check(struct bd_info *bd);
> >  phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat);
> >  int sdram_mmr_init_full(struct udevice *dev);
> > --
> > 2.19.0
> >


More information about the U-Boot mailing list