On Fri, Apr 30, 2021 at 3:41 PM Siew Chin Lim <[email protected]> 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 <[email protected]> > Signed-off-by: Tien Fong Chee <[email protected]> > > --- > 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, [email protected]. > # > # (C) Copyright 2010, Thomas Chou <[email protected]> > -# 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. > +#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 > + > +/* 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. > + > + /* 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? > + } > + > + /* 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. > + } > + > + /* 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(). > + 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. > + 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"? > + 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 >

