[RESEND v2 16/22] ddr: altera: dm: Add SDRAM driver for Diamond Mesa
Tan, Ley Foon
ley.foon.tan at intel.com
Mon Nov 23 11:37:16 CET 2020
> -----Original Message-----
> From: Lim, Elly Siew Chin <elly.siew.chin.lim at intel.com>
> Sent: Tuesday, November 10, 2020 2:45 PM
> To: u-boot at lists.denx.de
> Cc: 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>; Lim, Elly Siew Chin
> <elly.siew.chin.lim at intel.com>
> Subject: [RESEND v2 16/22] ddr: altera: dm: Add SDRAM driver for Diamond
> Mesa
>
> 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 Quartus.
>
> 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>
> ---
> arch/arm/mach-socfpga/include/mach/firewall.h | 1 +
> .../include/mach/system_manager_soc64.h | 4 +
> drivers/ddr/altera/Makefile | 1 +
> drivers/ddr/altera/sdram_dm.c | 1294 ++++++++++++++++++++
> drivers/ddr/altera/sdram_soc64.c | 6 +
> 5 files changed, 1306 insertions(+)
> create mode 100644 drivers/ddr/altera/sdram_dm.c
>
[...]
>
> /* Firewall MPFE SCR Registers */
> #define FW_MPFE_SCR_HMC 0x00
> diff --git a/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
> b/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
> index 1e2289e5f8..4fc1a158b7 100644
> --- a/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
> +++ b/arch/arm/mach-socfpga/include/mach/system_manager_soc64.h
> @@ -94,6 +94,10 @@ void populate_sysmgr_pinmux(void);
> * storing qspi ref clock(kHz)
> */
> #define SYSMGR_SCRATCH_REG_0_QSPI_REFCLK_MASK
> GENMASK(27, 0)
> +#define SYSMGR_SCRATCH_REG_0_DDR_RETENTION_MASK
> BIT(31)
> +#define SYSMGR_SCRATCH_REG_0_DDR_SHA_MASK BIT(30)
> +#define SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK (BIT(29) |
> BIT(28))
Change the order, from bit-28 to 31.
> +#define SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT 28
>
> #define SYSMGR_SDMMC
> SYSMGR_SOC64_SDMMC
>
[...]
> +#define TIMEOUT_200MS 200
> +#define TIMEOUT_5000MS 5000
> +
> +/* DDR4 umctl2 */
> +#define DDR4_STAT_OFFSET 0x4
Change to 0x04.
> +#define DDR4_STAT_SELFREF_TYPE (BIT(5) | BIT(4))
> +#define DDR4_STAT_SELFREF_TYPE_SHIFT 4
> +#define DDR4_STAT_OPERATING_MODE (BIT(2) | BIT(1) | BIT(0))
> +
> +#define DDR4_MRCTRL0_OFFSET 0x10
> +#define DDR4_MRCTRL0_MR_TYPE BIT(0)
> +#define DDR4_MRCTRL0_MPR_EN BIT(1)
> +#define DDR4_MRCTRL0_MR_RANK (BIT(5) | BIT(4))
> +#define DDR4_MRCTRL0_MR_RANK_SHIFT 4
> +#define DDR4_MRCTRL0_MR_ADDR (BIT(15) | BIT(14) | BIT(13) |
> BIT(12))
> +#define DDR4_MRCTRL0_MR_ADDR_SHIFT 12
> +#define DDR4_MRCTRL0_MR_WR BIT(31)
> +
> +#define DDR4_MRCTRL1_OFFSET 0x14
> +#define DDR4_MRCTRL1_MR_DATA 0x3FFFF
Follow other drivers use small letter for hex value.
Check all in this file.
> +
> +#define DDR4_MRSTAT_OFFSET 0x18
> +#define DDR4_MRSTAT_MR_WR_BUSY BIT(0)
> +
> +#define DDR4_MRCTRL2_OFFSET 0x1C
> +
> +#define DDR4_PWRCTL_OFFSET 0x30
> +#define DDR4_PWRCTL_SELFREF_EN BIT(0)
> +#define DDR4_PWRCTL_POWERDOWN_EN BIT(1)
> +#define DDR4_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3)
> +#define DDR4_PWRCTL_SELFREF_SW BIT(5)
> +
> +#define DDR4_PWRTMG_OFFSET 0x34
> +#define DDR4_HWLPCTL_OFFSET 0x38
> +#define DDR4_RFSHCTL0_OFFSET 0x50
> +#define DDR4_RFSHCTL1_OFFSET 0x54
> +
> +#define DDR4_RFSHCTL3_OFFSET 0x60
> +#define DDR4_RFSHCTL3_DIS_AUTO_REFRESH BIT(0)
> +#define DDR4_RFSHCTL3_REFRESH_MODE (BIT(6) | BIT(5) |
> BIT(4))
> +#define DDR4_RFSHCTL3_REFRESH_MODE_SHIFT 4
> +
> +#define DDR4_ECCCFG0_OFFSET 0x70
> +#define DDR4_ECC_MODE (BIT(2) | BIT(1) | BIT(0))
> +#define DDR4_DIS_SCRUB BIT(4)
> +
> +#define DDR4_CRCPARCTL1_OFFSET 0x04
> +#define DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE BIT(8)
> +#define DDR4_CRCPARCTL1_ALERT_WAIT_FOR_SW BIT(9)
> +
> +#define DDR4_CRCPARCTL0_OFFSET 0xC0
> +#define DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR BIT(1)
> +
> +#define DDR4_CRCPARSTAT_OFFSET 0xCC
> +#define DDR4_CRCPARSTAT_DFI_ALERT_ERR_INT BIT(16)
> +#define DDR4_CRCPARSTAT_DFI_ALERT_ERR_FATL_INT BIT(17)
> +#define DDR4_CRCPARSTAT_DFI_ALERT_ERR_NO_SW BIT(19)
> +#define DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW BIT(29)
> +
> +#define DDR4_DFIMISC_OFFSET 0x1B0
> +#define DDR4_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
> +#define DDR4_DFIMISC_DFI_INIT_START BIT(5)
> +
> +#define DDR4_DFISTAT_OFFSET 0x1BC
> +#define DDR4_DFI_INIT_COMPLETE BIT(0)
> +
> +#define DDR4_DBG0_OFFSET 0x300
> +
> +#define DDR4_DBG1_OFFSET 0x304
> +#define DDR4_DBG1_DISDQ BIT(0)
> +#define DDR4_DBG1_DIS_HIF BIT(1)
> +
> +#define DDR4_DBGCAM_OFFSET 0x308
> +#define DDR4_DBGCAM_DBG_RD_Q_EMPTY BIT(25)
> +#define DDR4_DBGCAM_DBG_WR_Q_EMPTY BIT(26)
> +#define DDR4_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28)
> +#define DDR4_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29)
> +
> +#define DDR4_SWCTL_OFFSET 0x320
> +#define DDR4_SWCTL_SW_DONE BIT(0)
> +
> +#define DDR4_SWSTAT_OFFSET 0x324
> +#define DDR4_SWSTAT_SW_DONE_ACK BIT(0)
> +
> +#define DDR4_PSTAT_OFFSET 0x3FC
> +#define DDR4_PSTAT_RD_PORT_BUSY_0 BIT(0)
> +#define DDR4_PSTAT_WR_PORT_BUSY_0 BIT(16)
> +
> +#define DDR4_PCTRL0_OFFSET 0x490
> +#define DDR4_PCTRL0_PORT_EN BIT(0)
> +
> +#define DDR4_SBRCTL_OFFSET 0xF24
> +#define DDR4_SBRCTL_SCRUB_INTERVAL 0x1FFF00
> +#define DDR4_SBRCTL_SCRUB_EN BIT(0)
> +#define DDR4_SBRCTL_SCRUB_WRITE BIT(2)
> +#define DDR_SBRCTL_SCRUB_BURST_1 BIT(4)
> +
> +#define DDR4_SBRSTAT_OFFSET 0xF28
> +#define DDR4_SBRSTAT_SCRUB_BUSY BIT(0)
> +#define DDR4_SBRSTAT_SCRUB_DONE BIT(1)
> +
> +#define DDR4_SBRWDATA0_OFFSET 0xF2C
> +#define DDR4_SBRWDATA1_OFFSET 0xF30
> +#define DDR4_SBRSTART0_OFFSET 0xF38
> +#define DDR4_SBRSTART1_OFFSET 0xF3C
> +#define DDR4_SBRRANGE0_OFFSET 0xF40
> +#define DDR4_SBRRANGE1_OFFSET 0xF44
> +
> +/* DDR PHY */
> +#define DDR_PHY_TXODTDRVSTREN_B0_P0 0x2009A
> +#define DDR_PHY_RXPBDLYTG0_R0 0x200D0
> +#define DDR_PHY_CALRATE_OFFSET 0x40110
> +#define DDR_PHY_CALZAP_OFFSET 0x40112
> +#define DDR_PHY_SEQ0BDLY0_P0_OFFSET 0x40016
> +#define DDR_PHY_SEQ0BDLY1_P0_OFFSET 0x40018
> +#define DDR_PHY_SEQ0BDLY2_P0_OFFSET 0x4001A
> +#define DDR_PHY_SEQ0BDLY3_P0_OFFSET 0x4001C
> +#define DDR_PHY_SEQ0DISABLEFLAG0_OFFSET 0x120018
> +#define DDR_PHY_SEQ0DISABLEFLAG1_OFFSET 0x12001A
> +#define DDR_PHY_SEQ0DISABLEFLAG2_OFFSET 0x12001C
> +#define DDR_PHY_SEQ0DISABLEFLAG3_OFFSET 0x12001E
> +#define DDR_PHY_SEQ0DISABLEFLAG4_OFFSET 0x120020
> +#define DDR_PHY_SEQ0DISABLEFLAG5_OFFSET 0x120022
> +#define DDR_PHY_SEQ0DISABLEFLAG6_OFFSET 0x120024
> +#define DDR_PHY_SEQ0DISABLEFLAG7_OFFSET 0x120026
> +#define DDR_PHY_UCCLKHCLKENABLES_OFFSET 0x180100
> +
> +#define DDR_PHY_APBONLY0_OFFSET 0x1A0000
> +#define DDR_PHY_MICROCONTMUXSEL BIT(0)
> +
> +#define DDR_PHY_MICRORESET_OFFSET 0x1A0132
> +#define DDR_PHY_MICRORESET_STALL BIT(0)
> +#define DDR_PHY_MICRORESET_RESET BIT(3)
> +
> +#define DDR_PHY_TXODTDRVSTREN_B0_P1 0x22009A
These use prefix "DDR" instead of "DDR4". Is it intended?
> +
> +/* 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
Change to prefix OPM_.
> +
> +/* 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)
Try change all the display of macro value aligned to each other's.
> +
> +#ifdef CONFIG_TARGET_SOCFPGA_DM
This file only get compiled when CONFIG_TARGET_SOCFPGA_DM is enabled. No need add this.
> +#define PSI_LL_SLAVE_APS_PER_OFST 0x00000000
> +#define alt_write_hword(addr, val) (writew(val, addr))
> +#define SDM_HPS_PERI_ADDR_TRANSLATION(_HPS_OFFSET_) \
Don't use capital letter for _HPS_OFFSET_, and remove __.
> + (PSI_LL_SLAVE_APS_PER_OFST + (_HPS_OFFSET_))
> +#define DDR_PHY_BASE 0xF8800000
> +#define SNPS_PHY_TRANSLATION(_PHY_OFFSET_) \
> + (PSI_LL_SLAVE_APS_PER_OFST + ((DDR_PHY_BASE + ((_PHY_OFFSET_)
> << 1))))
> +#define dwc_ddrphy_apb_wr(dest, data) \
> + alt_write_hword(SNPS_PHY_TRANSLATION(dest), data) #define
> b_max 1
> +#define timing_group_max 4 #endif
Use capital letter for macros.
> +
> +/* Reset type */
> +enum reset_type {
> + por_reset,
> + warm_reset,
> + cold_reset,
> + rsu_reset
Use capital letter for enum.
> +};
> +
> +/* DDR handoff structure */
> +struct ddr_handoff {
> + phys_addr_t mem_reset_base;
> + phys_addr_t umctl2_handoff_base;
> + phys_addr_t umctl2_base;
> + size_t umctl2_total_length;
> + size_t umctl2_handoff_length;
> + phys_addr_t phy_handoff_base;
> + phys_addr_t phy_base;
> + size_t phy_total_length;
> + size_t phy_handoff_length;
> + phys_addr_t phy_engine_handoff_base;
> + size_t phy_engine_total_length;
> + size_t phy_engine_handoff_length;
> +};
> +
> +static bool is_ddr_retention_enabled(u32 boot_scratch_cold0_reg) {
> + return boot_scratch_cold0_reg &
> + SYSMGR_SCRATCH_REG_0_DDR_RETENTION_MASK;
> +}
> +
> +static bool is_ddr_bitstream_sha_matching(u32 boot_scratch_cold0_reg) {
> + return boot_scratch_cold0_reg &
> SYSMGR_SCRATCH_REG_0_DDR_SHA_MASK;
> +}
> +
> +static enum reset_type get_reset_type(u32 boot_scratch_cold0_reg) {
> + return (boot_scratch_cold0_reg &
> + SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_MASK) >>
> + SYSMGR_SCRATCH_REG_0_DDR_RESET_TYPE_SHIFT;
> +}
> +
> +static bool is_ddr_init_skipped(void)
Can invert the logic? Return true if need do the DDR init?
Easier to read the code.
> +{
> + u32 reg = readl(socfpga_get_sysmgr_addr() +
> + SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
> +
> + if (get_reset_type(reg) == por_reset) {
> + debug("%s: POR reset is triggered\n", __func__);
> + debug("%s: DDR init is required\n", __func__);
> + return false;
> + }
> +
> + if (get_reset_type(reg) == warm_reset) {
> + debug("%s: Warm reset is triggered\n", __func__);
> + debug("%s: DDR init is skipped\n", __func__);
> + return true;
> + }
> +
> + if ((get_reset_type(reg) == cold_reset) ||
> + (get_reset_type(reg) == rsu_reset)) {
> + debug("%s: Cold/RSU reset is triggered\n", __func__);
> +
> + if (is_ddr_retention_enabled(reg)) {
> + debug("%s: DDR retention bit is set\n", __func__);
> +
> + if (is_ddr_bitstream_sha_matching(reg)) {
> + debug("%s: Matching in DDR bistream\n",
> + __func__);
> + debug("%s: DDR init is skipped\n", __func__);
> + return true;
> + }
> +
> + debug("%s: Mismatch in DDR bistream\n", __func__);
SHA mismatch.
> + }
> + }
> +
> + debug("%s: DDR init is required\n", __func__);
> + return false;
> +}
> +
> +static int clr_ca_parity_error_status(struct ddr_handoff
> +*ddr_handoff_info) {
> + int ret;
> +
> + debug("%s: Clear C/A parity error status in MR5[4]\n", __func__);
> +
> + /* Set mode register MRS */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_MRCTRL0_OFFSET,
> + DDR4_MRCTRL0_MPR_EN);
> +
> + /* Set mode register to write operation */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_MRCTRL0_OFFSET,
> + DDR4_MRCTRL0_MR_TYPE);
> +
> + /* Set the address of mode rgister to 0x101(MR5) */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_MRCTRL0_OFFSET,
> + (MR5 << DDR4_MRCTRL0_MR_ADDR_SHIFT) &
> + DDR4_MRCTRL0_MR_ADDR);
> +
> + /* Set MR rank to rank 1 */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_MRCTRL0_OFFSET,
> + (RANK1 << DDR4_MRCTRL0_MR_RANK_SHIFT) &
> + DDR4_MRCTRL0_MR_RANK);
> +
> + /* Clear C/A parity error status in MR5[4] */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_MRCTRL1_OFFSET,
> + MR5_BIT4);
> +
> + /* Trigger mode register read or write operation */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_MRCTRL0_OFFSET,
> + DDR4_MRCTRL0_MR_WR);
> +
> + /* Wait for retry done */
> + ret = wait_for_bit_le32((const void *)(ddr_handoff_info-
> >umctl2_base +
> + DDR4_MRSTAT_OFFSET),
> DDR4_MRSTAT_MR_WR_BUSY,
> + false, TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" no outstanding MR transaction\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int ddr4_retry_software_sequence(struct ddr_handoff
> +*ddr_handoff_info) {
> + u32 value;
> + int ret;
> +
> + /* Check software can perform MRS/MPR/PDA? */
> + value = readl(ddr_handoff_info->umctl2_base +
> DDR4_CRCPARSTAT_OFFSET) &
> + DDR4_CRCPARSTAT_DFI_ALERT_ERR_NO_SW;
> +
> + if (value) {
> + debug("%s: Software can't perform MRS/MPR/PDA\n",
> __func__);
> +
> + /* Clear interrupt bit for DFI alert error */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> + DDR4_CRCPARCTL0_OFFSET,
> + DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR);
> +
> + /* Wait for retry done */
> + ret = wait_for_bit_le32((const void *)
> + (ddr_handoff_info->umctl2_base +
> + DDR4_MRSTAT_OFFSET),
> + DDR4_MRSTAT_MR_WR_BUSY,
> + false, TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" no outstanding MR transaction\n");
> + return ret;
> + }
> +
> + if (clr_ca_parity_error_status(ddr_handoff_info))
> + return ret;
> + } else {
> + debug("%s: Software can perform MRS/MPR/PDA\n",
> __func__);
> +
> + ret = wait_for_bit_le32((const void *)
> + (ddr_handoff_info->umctl2_base +
> + DDR4_MRSTAT_OFFSET),
> + DDR4_MRSTAT_MR_WR_BUSY,
> + false, TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" no outstanding MR transaction\n");
> + return ret;
> + }
> +
> + if (clr_ca_parity_error_status(ddr_handoff_info))
> + return ret;
> +
> + /* Clear interrupt bit for DFI alert error */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> + DDR4_CRCPARCTL0_OFFSET,
> + DDR4_CRCPARCTL0_DFI_ALERT_ERR_INIT_CLR);
> + }
This if .. else doing almost same thing, can combine.
> +
> + return 0;
> +}
> +
> +static int ensure_retry_procedure_complete(struct ddr_handoff
> +*ddr_handoff_info) {
> + u32 value;
> + u32 start = get_timer(0);
> + int ret;
> +
> + /* Check parity/crc/error window is emptied ? */
> + value = readl(ddr_handoff_info->umctl2_base +
> DDR4_CRCPARSTAT_OFFSET) &
> + DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW;
While loop below can change to do..while() then can remove this readl here.
> +
> + /* Polling until parity/crc/error window is emptied */
> + while (value) {
> + if (get_timer(start) > TIMEOUT_200MS) {
> + debug("%s: Timeout while waiting for",
> + __func__);
> + debug(" parity/crc/error window empty\n");
> + return -ETIMEDOUT;
> + }
> +
> + /* Check software intervention is enabled? */
> + value = readl(ddr_handoff_info->umctl2_base +
> + DDR4_CRCPARCTL1_OFFSET) &
> + DDR4_CRCPARCTL1_ALERT_WAIT_FOR_SW;
> + if (value) {
> + debug("%s: Software intervention is enabled\n",
> + __func__);
> +
> + /* Check dfi alert error interrupt is set? */
> + value = readl(ddr_handoff_info->umctl2_base +
> + DDR4_CRCPARSTAT_OFFSET) &
> + DDR4_CRCPARSTAT_DFI_ALERT_ERR_INT;
> +
> + if (value) {
> + ret =
> +
> ddr4_retry_software_sequence(ddr_handoff_info);
> + debug("%s: DFI alert error interrupt ",
> + __func__);
> + debug("is set\n");
> +
> + if (ret)
> + return ret;
> + }
> +
> + /*
> + * Check fatal parity error interrupt is set?
> + */
> + value = readl(ddr_handoff_info->umctl2_base +
> + DDR4_CRCPARSTAT_OFFSET) &
> +
> DDR4_CRCPARSTAT_DFI_ALERT_ERR_FATL_INT;
> + if (value) {
> + printf("%s: Fatal parity error ",
> + __func__);
> + printf("interrupt is set, Hang it!!\n");
> + hang();
> + }
> + }
> +
> + value = readl(ddr_handoff_info->umctl2_base +
> + DDR4_CRCPARSTAT_OFFSET) &
> + DDR4_CRCPARSTAT_CMD_IN_ERR_WINDOW;
> +
> + udelay(1);
> + WATCHDOG_RESET();
> + }
> +
> + return 0;
> +}
> +
> +static int enable_quasi_dynamic_reg_grp3(struct ddr_handoff
> +*ddr_handoff_info) {
> + u32 i, value, backup;
> + int ret;
> +
> + /* Disable input traffic per port */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_PCTRL0_OFFSET,
> + DDR4_PCTRL0_PORT_EN);
> +
> + /* Polling AXI port until idle */
> + ret = wait_for_bit_le32((const void *)(ddr_handoff_info-
> >umctl2_base +
> + DDR4_PSTAT_OFFSET),
> DDR4_PSTAT_WR_PORT_BUSY_0 |
> + DDR4_PSTAT_RD_PORT_BUSY_0, false,
> + TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" controller idle\n");
> + return ret;
> + }
> +
> + /* Backup user setting */
> + backup = readl(ddr_handoff_info->umctl2_base +
> DDR4_DBG1_OFFSET);
> +
> + /* Disable input traffic to the controller */
> + setbits_le32(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET,
> + DDR4_DBG1_DIS_HIF);
> +
> + /*
> + * Ensure CAM/data pipelines are empty.
> + * Poll until CAM/data pipelines are set at least twice,
> + * timeout at 200ms
> + */
> + for (i = 0; i < 2; i++) {
> + ret = wait_for_bit_le32((const void *)
> + (ddr_handoff_info->umctl2_base +
> + DDR4_DBGCAM_OFFSET),
> +
> DDR4_DBGCAM_WR_DATA_PIPELINE_EMPTY |
> +
> DDR4_DBGCAM_RD_DATA_PIPELINE_EMPTY |
> +
> DDR4_DBGCAM_DBG_WR_Q_EMPTY |
> + DDR4_DBGCAM_DBG_RD_Q_EMPTY,
> true,
> + TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: loop(%u): Timeout while waiting for",
> + __func__, i + 1);
> + debug(" CAM/data pipelines are empty\n");
> +
> + /* Restore user setting */
> + writel(backup, ddr_handoff_info->umctl2_base +
> + DDR4_DBG1_OFFSET);
Always need to restore backup. Can use "goto" at the exit function below.
> +
> + return ret;
> + }
> + }
> +
> + /* Check DDR4 retry is enabled ? */
> + value = readl(ddr_handoff_info->umctl2_base +
> DDR4_CRCPARCTL1_OFFSET) &
> + DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE;
> +
> + if (value) {
> + debug("%s: DDR4 retry is enabled\n", __func__);
> +
> + ret = ensure_retry_procedure_complete(ddr_handoff_info);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" retry procedure complete\n");
> +
> + /* Restore user setting */
> + writel(backup, ddr_handoff_info->umctl2_base +
> + DDR4_DBG1_OFFSET);
Same here.
> +
> + return ret;
> + }
> + }
> +
> + /* Restore user setting */
> + writel(backup, ddr_handoff_info->umctl2_base +
> DDR4_DBG1_OFFSET);
> +
> + debug("%s: Quasi-dynamic group 3 registers are enabled\n",
> __func__);
> +
> + return 0;
> +}
> +
> +static int scrubbing_ddr_config(struct ddr_handoff *ddr_handoff_info) {
> + u32 backup[7];
> + int ret;
> +
> + /* Reset to default value, prevent scrubber stop due to lower power
> */
> + writel(0, ddr_handoff_info->umctl2_base + DDR4_PWRCTL_OFFSET);
> +
> + /* Disable input traffic per port */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_PCTRL0_OFFSET,
> + DDR4_PCTRL0_PORT_EN);
> +
> + /* Backup user settings */
> + backup[0] = readl(ddr_handoff_info->umctl2_base +
> DDR4_SBRCTL_OFFSET);
> + backup[1] = readl(ddr_handoff_info->umctl2_base +
> + DDR4_SBRWDATA0_OFFSET);
> + backup[2] = readl(ddr_handoff_info->umctl2_base +
> + DDR4_SBRWDATA1_OFFSET);
> + backup[3] = readl(ddr_handoff_info->umctl2_base +
> + DDR4_SBRSTART0_OFFSET);
> + backup[4] = readl(ddr_handoff_info->umctl2_base +
> + DDR4_SBRSTART1_OFFSET);
> + backup[5] = readl(ddr_handoff_info->umctl2_base +
> + DDR4_SBRRANGE0_OFFSET);
> + backup[6] = readl(ddr_handoff_info->umctl2_base +
> + DDR4_SBRRANGE1_OFFSET);
> +
> + /* Scrub_burst = 1, scrub_mode = 1(performs writes) */
> + writel(DDR_SBRCTL_SCRUB_BURST_1 |
> DDR4_SBRCTL_SCRUB_WRITE,
> + ddr_handoff_info->umctl2_base + DDR4_SBRCTL_OFFSET);
> +
> + /* Zeroing whole DDR */
> + writel(0, ddr_handoff_info->umctl2_base +
> + DDR4_SBRWDATA0_OFFSET);
> + writel(0, ddr_handoff_info->umctl2_base +
> + DDR4_SBRWDATA1_OFFSET);
> + writel(0, ddr_handoff_info->umctl2_base +
> DDR4_SBRSTART0_OFFSET);
> + writel(0, ddr_handoff_info->umctl2_base +
> DDR4_SBRSTART1_OFFSET);
> + writel(0, ddr_handoff_info->umctl2_base +
> DDR4_SBRRANGE0_OFFSET);
> + writel(0, ddr_handoff_info->umctl2_base +
> DDR4_SBRRANGE1_OFFSET);
> +
> +#ifdef CONFIG_TARGET_SOCFPGA_DM
No need ifdef.
> + writel(0x0FFFFFFF, ddr_handoff_info->umctl2_base +
> + DDR4_SBRRANGE0_OFFSET);
> +#endif
> +
> + /* Enables scrubber */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_SBRCTL_OFFSET,
> + DDR4_SBRCTL_SCRUB_EN);
> +
> + /* Polling all scrub writes commands have been sent */
> + ret = wait_for_bit_le32((const void *)(ddr_handoff_info-
> >umctl2_base +
> + DDR4_SBRSTAT_OFFSET),
> DDR4_SBRSTAT_SCRUB_DONE,
> + true, TIMEOUT_5000MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" sending all scrub commands\n");
> + return ret;
> + }
> +
> + /* Polling all scrub writes data have been sent */
> + ret = wait_for_bit_le32((const void *)(ddr_handoff_info-
> >umctl2_base +
> + DDR4_SBRSTAT_OFFSET),
> DDR4_SBRSTAT_SCRUB_BUSY,
> + false, TIMEOUT_5000MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" sending all scrub data\n");
> + return ret;
> + }
> +
> + /* Disables scrubber */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_SBRCTL_OFFSET,
> + DDR4_SBRCTL_SCRUB_EN);
> +
> + /* Restore user settings */
> + writel(backup[0], ddr_handoff_info->umctl2_base +
> DDR4_SBRCTL_OFFSET);
> + writel(backup[1], ddr_handoff_info->umctl2_base +
> + DDR4_SBRWDATA0_OFFSET);
> + writel(backup[2], ddr_handoff_info->umctl2_base +
> + DDR4_SBRWDATA1_OFFSET);
> + writel(backup[3], ddr_handoff_info->umctl2_base +
> + DDR4_SBRSTART0_OFFSET);
> + writel(backup[4], ddr_handoff_info->umctl2_base +
> + DDR4_SBRSTART1_OFFSET);
> + writel(backup[5], ddr_handoff_info->umctl2_base +
> + DDR4_SBRRANGE0_OFFSET);
> + writel(backup[6], ddr_handoff_info->umctl2_base +
> + DDR4_SBRRANGE1_OFFSET);
Can have helper function to read and write these.
> +
> + return 0;
> +}
> +
> +static int init_umctl2(struct ddr_handoff *ddr_handoff_info, u32
> +*user_backup) {
> + u32 handoff_table[ddr_handoff_info->umctl2_handoff_length];
> + u32 i, value, expected_value;
> + u32 start = get_timer(0);
> + int ret;
> +
> + printf("Initializing DDR controller ...\n");
> +
> + /* Prevent controller from issuing read/write to SDRAM */
> + setbits_le32(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET,
> + DDR4_DBG1_DISDQ);
> +
> + /* Put SDRAM into self-refresh */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_PWRCTL_OFFSET,
> + DDR4_PWRCTL_SELFREF_EN);
> +
> + /* Enable quasi-dynamic programing of the controller registers */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + /* Ensure the controller is in initialization mode */
> + ret = wait_for_bit_le32((const void *)(ddr_handoff_info-
> >umctl2_base +
> + DDR4_STAT_OFFSET),
> DDR4_STAT_OPERATING_MODE,
> + false, TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" init operating mode\n");
> + return ret;
> + }
> +
> + debug("%s: Handoff table address = 0x%p table length = 0x%08x\n",
> + __func__, (u32 *)handoff_table,
> + (u32)ddr_handoff_info->umctl2_handoff_length);
> +
> + socfpga_handoff_read((void *)ddr_handoff_info-
> >umctl2_handoff_base,
> + handoff_table,
> + ddr_handoff_info->umctl2_handoff_length,
> + little_endian);
> +
> + for (i = 0; i < ddr_handoff_info->umctl2_handoff_length; i = i + 2) {
> + debug("%s: Absolute addr: 0x%08llx APB offset: 0x%08x",
> + __func__, handoff_table[i] +
> + ddr_handoff_info->umctl2_base, handoff_table[i]);
> + debug(" wr = 0x%08x ", handoff_table[i + 1]);
> +
> + writel(handoff_table[i + 1], (uintptr_t)(handoff_table[i] +
> + ddr_handoff_info->umctl2_base));
> +
> + debug("rd = 0x%08x\n", readl((uintptr_t)(handoff_table[i] +
> + ddr_handoff_info->umctl2_base)));
> + }
> +
> + /* Backup user settings, restore after DDR up running */
> + *user_backup = readl(ddr_handoff_info->umctl2_base +
> + DDR4_PWRCTL_OFFSET);
> +
> + /* Polling granularity of refresh mode change to fixed 2x (DDR4) */
> + value = readl(ddr_handoff_info->umctl2_base +
> DDR4_RFSHCTL3_OFFSET) &
> + DDR4_RFSHCTL3_REFRESH_MODE;
Use do...while() loop below, then can remove this.
> +
> + expected_value = FIXED_2X <<
> DDR4_RFSHCTL3_REFRESH_MODE_SHIFT;
> +
> + while (value != expected_value) {
> + if (get_timer(start) > TIMEOUT_200MS) {
> + debug("%s: loop(%u): Timeout while waiting for",
> + __func__, i + 1);
> + debug(" fine granularity refresh mode change to ");
> + debug("fixed 2x\n");
> + debug("%s: expected_value = 0x%x value= 0x%x\n",
> + __func__, expected_value, value);
> + return -ETIMEDOUT;
> + }
> +
> + value = readl(ddr_handoff_info->umctl2_base +
> + DDR4_RFSHCTL3_OFFSET) &
> + DDR4_RFSHCTL3_REFRESH_MODE;
> + }
> +
> + /* Disable self resfresh */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_PWRCTL_OFFSET,
> + DDR4_PWRCTL_SELFREF_EN);
> +
> + /* Complete quasi-dynamic register programming */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + /* Enable controller from issuing read/write to SDRAM */
> + clrbits_le32(ddr_handoff_info->umctl2_base + DDR4_DBG1_OFFSET,
> + DDR4_DBG1_DISDQ);
> +
> + /* Release the controller from reset */
> + setbits_le32((uintptr_t)(readl(ddr_handoff_info->mem_reset_base) +
> + MEM_RST_MGR_STATUS),
> MEM_RST_MGR_STATUS_AXI_RST |
> + MEM_RST_MGR_STATUS_CONTROLLER_RST |
> + MEM_RST_MGR_STATUS_RESET_COMPLETE);
> +
> + printf("DDR controller configuration is completed\n");
> +
> + return 0;
> +}
> +
> +static int init_phy(struct ddr_handoff *ddr_handoff_info) {
> + u32 handoff_table[ddr_handoff_info->phy_handoff_length];
> + u32 i, value;
> + int ret;
> +
> + printf("Initializing DDR PHY ...\n");
> +
> + /* Check DDR4 retry is enabled ? */
> + value = readl(ddr_handoff_info->umctl2_base +
> DDR4_CRCPARCTL1_OFFSET) &
> + DDR4_CRCPARCTL1_CRC_PARITY_RETRY_ENABLE;
> +
> + if (value) {
> + debug("%s: DDR4 retry is enabled\n", __func__);
> + debug("%s: Disable auto refresh is not supported\n",
> __func__);
> + } else {
> + /* Disable auto refresh */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> + DDR4_RFSHCTL3_OFFSET,
> + DDR4_RFSHCTL3_DIS_AUTO_REFRESH);
> + }
> +
> + /* Disable selfref_en & powerdown_en, nvr disable dfi dram clk */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_PWRCTL_OFFSET,
> + DDR4_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
> + DDR4_PWRCTL_POWERDOWN_EN |
> DDR4_PWRCTL_SELFREF_EN);
> +
> + /* Enable quasi-dynamic programing of the controller registers */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + ret = enable_quasi_dynamic_reg_grp3(ddr_handoff_info);
> + if (ret)
> + return ret;
> +
> + /* Masking dfi init complete */
> + clrbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_DFIMISC_OFFSET,
> + DDR4_DFIMISC_DFI_INIT_COMPLETE_EN);
> +
> + /* Complete quasi-dynamic register programming */
> + setbits_le32(ddr_handoff_info->umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + /* Polling programming done */
> + ret = wait_for_bit_le32((const void *)(ddr_handoff_info-
> >umctl2_base +
> + DDR4_SWSTAT_OFFSET),
> DDR4_SWSTAT_SW_DONE_ACK,
> + true, TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" programming done\n");
> + return ret;
> + }
> +
> + debug("%s: Handoff table address = 0x%p table length = 0x%08x\n",
> + __func__, (u32 *)handoff_table,
> + (u32)ddr_handoff_info->umctl2_handoff_length);
> +
> + /* Execute PHY configuration handoff */
> + socfpga_handoff_read((void *)ddr_handoff_info-
> >phy_handoff_base,
> + handoff_table,
> + (u32)ddr_handoff_info->phy_handoff_length,
> + little_endian);
> +
> + for (i = 0; i < ddr_handoff_info->phy_handoff_length; i = i + 2) {
> + /*
> + * Convert PHY odd offset to even offset that supported by
> + * ARM processor.
> + */
> + value = handoff_table[i] << 1;
> + debug("%s: Absolute addr: 0x%08llx, APB offset: 0x%08x ",
> + __func__, value + ddr_handoff_info->phy_base, value);
> + debug("PHY offset: 0x%08x", handoff_table[i]);
> + debug(" wr = 0x%08x ", handoff_table[i + 1]);
> + writew(handoff_table[i + 1], (uintptr_t)(value +
> + ddr_handoff_info->phy_base));
> + debug("rd = 0x%08x\n", readw((uintptr_t)(value +
> + ddr_handoff_info->phy_base)));
> + }
> +
> +#ifdef CONFIG_TARGET_SOCFPGA_DM
Same here, no need ifdef.
> + u8 numdbyte = 0x0009;
> + u8 byte, lane;
> + u32 b_addr, c_addr;
> +
> + /* Program TxOdtDrvStren bx_p0 */
> + for (byte = 0; byte < numdbyte; byte++) {
> + c_addr = byte << 13;
> +
> + for (lane = 0; lane <= b_max ; lane++) {
> + b_addr = lane << 9;
> + writew(0x00, (uintptr_t)
> + (ddr_handoff_info->phy_base +
> + DDR_PHY_TXODTDRVSTREN_B0_P0 + c_addr +
> + b_addr));
> + }
> + }
> +
> + /* Program TxOdtDrvStren bx_p1 */
> + for (byte = 0; byte < numdbyte; byte++) {
> + c_addr = byte << 13;
> +
> + for (lane = 0; lane <= b_max ; lane++) {
> + b_addr = lane << 9;
> + writew(0x00, (uintptr_t)
> + (ddr_handoff_info->phy_base +
> + DDR_PHY_TXODTDRVSTREN_B0_P1 + c_addr +
> + b_addr));
> + }
> + }
These 2 for loops can be combined or move to a function.
> +
> + /*
> + * [phyinit_C_initPhyConfig] Pstate=0, Memclk=1600MHz,
> + * Programming ARdPtrInitVal to 0x2
> + * DWC_DDRPHYA_MASTER0_ARdPtrInitVal_p0
> + */
> + dwc_ddrphy_apb_wr(0x2002e, 0x3);
> +
> + /* [phyinit_C_initPhyConfig] Pstate=1,
> + * Memclk=1067MHz, Programming ARdPtrInitVal to 0x2
> + * DWC_DDRPHYA_MASTER0_ARdPtrInitVal_p1
> + */
> + dwc_ddrphy_apb_wr(0x12002e, 0x3);
> +
> + /* DWC_DDRPHYA_MASTER0_DfiFreqXlat0 */
> + dwc_ddrphy_apb_wr(0x200f0, 0x6666);
> +
> + /* DWC_DDRPHYA_DBYTE0_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x10020, 0x4);
> + /* DWC_DDRPHYA_DBYTE1_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x11020, 0x4);
> + /* DWC_DDRPHYA_DBYTE2_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x12020, 0x4);
> + /* DWC_DDRPHYA_DBYTE3_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x13020, 0x4); //
> + /* DWC_DDRPHYA_DBYTE4_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x14020, 0x4);
> + /* DWC_DDRPHYA_DBYTE5_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x15020, 0x4);
> + /* DWC_DDRPHYA_DBYTE6_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x16020, 0x4);
> + /* DWC_DDRPHYA_DBYTE7_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x17020, 0x4);
> + /* DWC_DDRPHYA_DBYTE8_DFIMRL_p0 */
> + dwc_ddrphy_apb_wr(0x18020, 0x4);
> + /* DWC_DDRPHYA_MASTER0_HwtMRL_p0 */
> + dwc_ddrphy_apb_wr(0x20020, 0x4);
> +#endif
> +
> + printf("DDR PHY configuration is completed\n");
> +
> + return 0;
> +}
> +
> +static void phy_init_engine(struct ddr_handoff *ddr_handoff_info) {
> + u32 i, value;
> + u32 handoff_table[ddr_handoff_info->phy_engine_handoff_length];
> +
> + printf("Load PHY Init Engine ...\n");
> +
> + /* Execute PIE production code handoff */
> + socfpga_handoff_read((void *)ddr_handoff_info-
> >phy_engine_handoff_base,
> + handoff_table,
> + (u32)ddr_handoff_info-
> >phy_engine_handoff_length,
> + little_endian);
> +
> + for (i = 0; i < ddr_handoff_info->phy_engine_handoff_length;
> + i = i + 2) {
> + debug("Handoff addr: 0x%8llx ", handoff_table[i] +
> + ddr_handoff_info->phy_base);
> +
> + /*
> + * Convert PHY odd offset to even offset that supported by
> + * ARM processor.
> + */
> + value = handoff_table[i] << 1;
> + debug("%s: Absolute addr: 0x%08llx, APB offset: 0x%08x ",
> + __func__, value + ddr_handoff_info->phy_base, value);
> + debug("PHY offset: 0x%08x", handoff_table[i]);
> + debug(" wr = 0x%08x ", handoff_table[i + 1]);
> +
> + writew(handoff_table[i + 1], (uintptr_t)(value +
> + ddr_handoff_info->phy_base));
> +
> + debug("rd = 0x%08x\n", readw((uintptr_t)(value +
> + ddr_handoff_info->phy_base)));
Same code as in init_phy(), can have a helper function for this.
> + }
> +
> +#ifdef CONFIG_TARGET_SOCFPGA_DM
> + u8 numdbyte = 0x0009;
> + u8 byte, timing_group;
> + u32 b_addr, c_addr;
> +
> + /* Enable access to the PHY configuration registers */
> + clrbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_APBONLY0_OFFSET,
> + DDR_PHY_MICROCONTMUXSEL);
> +
> + /* Program RXPBDLYTG0 bx_p0 */
> + for (byte = 0; byte < numdbyte; byte++) {
> + c_addr = byte << 9;
> +
> + for (timing_group = 0; timing_group <= timing_group_max;
> + timing_group++) {
> + b_addr = timing_group << 1;
> + writew(0x00, (uintptr_t)
> + (ddr_handoff_info->phy_base +
> + DDR_PHY_RXPBDLYTG0_R0 + c_addr +
> + b_addr));
> + }
> + }
> +
> + /* Isolate the APB access from internal CSRs */
> + setbits_le16(ddr_handoff_info->phy_base +
> DDR_PHY_APBONLY0_OFFSET,
> + DDR_PHY_MICROCONTMUXSEL);
> +#endif
> +
> + printf("End of loading PHY Init Engine\n"); }
> +
> +int populate_ddr_handoff(struct ddr_handoff *ddr_handoff_info) {
> + /* DDR handoff */
> + ddr_handoff_info->mem_reset_base =
> SOC64_HANDOFF_DDR_MEMRESET_BASE;
> + debug("%s: DDR memory reset base = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->mem_reset_base);
> + debug("%s: DDR memory reset address = 0x%x\n", __func__,
> + readl(ddr_handoff_info->mem_reset_base));
> +
> + /* DDR controller handoff */
> + ddr_handoff_info->umctl2_handoff_base =
> SOC64_HANDOFF_DDR_UMCTL2_SECTION;
> + debug("%s: umctl2 handoff base = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->umctl2_handoff_base);
> +
> + ddr_handoff_info->umctl2_base =
> readl(SOC64_HANDOFF_DDR_UMCTL2_BASE);
> + debug("%s: umctl2 base = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->umctl2_base);
> +
> + ddr_handoff_info->umctl2_total_length =
> + readl(ddr_handoff_info->umctl2_handoff_base +
> + SOC64_HANDOFF_OFFSET_LENGTH);
> + debug("%s: Umctl2 total length in byte = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->umctl2_total_length);
> +
> + ddr_handoff_info->umctl2_handoff_length =
> + socfpga_get_handoff_size((void *)ddr_handoff_info-
> >umctl2_handoff_base,
> + little_endian);
> + debug("%s: Umctl2 handoff length in word(32-bit) = 0x%x\n",
> __func__,
> + (u32)ddr_handoff_info->umctl2_handoff_length);
> +
> + if (ddr_handoff_info->umctl2_handoff_length < 0)
> + return ddr_handoff_info->umctl2_handoff_length;
> +
> + /* DDR PHY handoff */
> + ddr_handoff_info->phy_handoff_base =
> + ddr_handoff_info->umctl2_handoff_base +
> + ddr_handoff_info->umctl2_total_length;
> + debug("%s: PHY handoff base = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->phy_handoff_base);
> +
> + ddr_handoff_info->phy_base =
> + readl(ddr_handoff_info->phy_handoff_base +
> + SOC64_HANDOFF_DDR_PHY_BASE_OFFSET);
> + debug("%s: PHY base = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->phy_base);
> +
> + ddr_handoff_info->phy_total_length =
> + readl(ddr_handoff_info->phy_handoff_base +
> + SOC64_HANDOFF_OFFSET_LENGTH);
> + debug("%s: PHY total length in byte = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->phy_total_length);
> +
> + ddr_handoff_info->phy_handoff_length =
> + socfpga_get_handoff_size((void *)ddr_handoff_info-
> >phy_handoff_base,
> + little_endian);
> + debug("%s: PHY handoff length in word(32-bit) = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->phy_handoff_length);
> +
> + if (ddr_handoff_info->phy_handoff_length < 0)
> + return ddr_handoff_info->phy_handoff_length;
> +
> + /* DDR PHY Engine handoff */
> + ddr_handoff_info->phy_engine_handoff_base =
> + ddr_handoff_info->phy_handoff_base +
> + ddr_handoff_info->phy_total_length;
> + debug("%s: PHY base = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->phy_engine_handoff_base);
> +
> + ddr_handoff_info->phy_engine_total_length =
> + readl(ddr_handoff_info->phy_engine_handoff_base
> +
> + SOC64_HANDOFF_OFFSET_LENGTH);
> + debug("%s: PHY engine total length in byte = 0x%x\n", __func__,
> + (u32)ddr_handoff_info->phy_engine_total_length);
> +
> + ddr_handoff_info->phy_engine_handoff_length =
> + socfpga_get_handoff_size((void *)ddr_handoff_info-
> >phy_engine_handoff_base,
> + little_endian);
> + debug("%s: PHY engine handoff length in word(32-bit) = 0x%x\n",
> + __func__, (u32)ddr_handoff_info->phy_engine_handoff_length);
> +
> + if (ddr_handoff_info->phy_engine_handoff_length < 0)
> + return ddr_handoff_info->phy_engine_handoff_length;
> +
> + return 0;
> +}
> +
> +int enable_ddr_clock(struct udevice *dev) {
> + struct clk *ddr_clk;
> + int ret;
> +
> + /* Enable clock before init DDR */
> + ddr_clk = devm_clk_get(dev, "mem_clk");
> + if (!IS_ERR(ddr_clk)) {
> + ret = clk_enable(ddr_clk);
> + if (ret) {
> + printf("%s: Failed to enable DDR clock\n", __func__);
> + return ret;
> + }
> + } else {
> + ret = PTR_ERR(ddr_clk);
> + debug("%s: Failed to get DDR clock from dts\n", __func__);
Fix the error message, it is not getting from dts.
> + return ret;
> + }
> +
> + printf("%s: DDR clock is enabled\n", __func__);
> +
> + return 0;
> +}
> +
> +int sdram_mmr_init_full(struct udevice *dev) {
> + u32 value, user_backup;
> + u32 start = get_timer(0);
> + int ret;
> + struct bd_info bd;
> + struct ddr_handoff ddr_handoff_info;
> + struct altera_sdram_priv *priv = dev_get_priv(dev);
> +
> + if (!is_ddr_init_skipped()) {
> + printf("%s: SDRAM init in progress ...\n", __func__);
> +
> + ret = populate_ddr_handoff(&ddr_handoff_info);
> + if (ret) {
> + debug("%s: Failed to populate DDR handoff\n",
> __func__);
> + return ret;
> + }
> +
> + /*
> + * Polling reset complete, must be high to ensure DDR
> subsystem
> + * in complete reset state before init DDR clock and DDR
> + * controller
> + */
> + ret = wait_for_bit_le32((const void *)((uintptr_t)(readl
> + (ddr_handoff_info.mem_reset_base)
> +
> + MEM_RST_MGR_STATUS)),
> +
> MEM_RST_MGR_STATUS_RESET_COMPLETE, true,
> + TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" reset complete done\n");
> + return ret;
> + }
> +
> + ret = enable_ddr_clock(dev);
> + if (ret)
> + return ret;
> +
> + /* Initialize DDR controller */
> + ret = init_umctl2(&ddr_handoff_info, &user_backup);
> + if (ret) {
> + debug("%s: Failed to inilialize DDR controller\n",
> + __func__);
> + return ret;
> + }
> +
> + /* Initialize DDR PHY */
> + ret = init_phy(&ddr_handoff_info);
> + if (ret) {
> + debug("%s: Failed to inilialize DDR PHY\n", __func__);
> + return ret;
> + }
> +
> + /* Reset ARC processor when no using for security purpose
> */
> + setbits_le16(ddr_handoff_info.phy_base +
> + DDR_PHY_MICRORESET_OFFSET,
> + DDR_PHY_MICRORESET_RESET);
> +
> + /* DDR freq set to support DDR4-3200 */
This comment is correct?
> + phy_init_engine(&ddr_handoff_info);
> +
> + /* Trigger memory controller to init SDRAM */
> + /* Enable quasi-dynamic programing of controller registers
> */
> + clrbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + ret = enable_quasi_dynamic_reg_grp3(&ddr_handoff_info);
> + if (ret)
> + return ret;
> +
> + /* Start DFI init sequence */
> + setbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_DFIMISC_OFFSET,
> + DDR4_DFIMISC_DFI_INIT_START);
> +
> + /* Complete quasi-dynamic register programming */
> + setbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + /* Polling programming done */
> + ret = wait_for_bit_le32((const void *)
> + (ddr_handoff_info.umctl2_base +
> + DDR4_SWSTAT_OFFSET),
> + DDR4_SWSTAT_SW_DONE_ACK, true,
> + TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" programming done\n");
> + return ret;
> + }
> +
> + /* Polling DFI init complete */
> + ret = wait_for_bit_le32((const void *)
> + (ddr_handoff_info.umctl2_base +
> + DDR4_DFISTAT_OFFSET),
> + DDR4_DFI_INIT_COMPLETE, true,
> + TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" DFI init done\n");
> + return ret;
> + }
> +
> + debug("DFI init completed.\n");
> +
> + /* Enable quasi-dynamic programing of controller registers
> */
> + clrbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + ret = enable_quasi_dynamic_reg_grp3(&ddr_handoff_info);
> + if (ret)
> + return ret;
> +
> + /* Stop DFI init sequence */
> + clrbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_DFIMISC_OFFSET,
> + DDR4_DFIMISC_DFI_INIT_START);
> +
> + /* Unmasking dfi init complete */
> + setbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_DFIMISC_OFFSET,
> + DDR4_DFIMISC_DFI_INIT_COMPLETE_EN);
> +
> + /* Software exit from self-refresh */
> + clrbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_PWRCTL_OFFSET,
> + DDR4_PWRCTL_SELFREF_SW);
> +
> + /* Complete quasi-dynamic register programming */
> + setbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_SWCTL_OFFSET,
> + DDR4_SWCTL_SW_DONE);
> +
> + /* Polling programming done */
> + ret = wait_for_bit_le32((const void *)
> + (ddr_handoff_info.umctl2_base +
> + DDR4_SWSTAT_OFFSET),
> + DDR4_SWSTAT_SW_DONE_ACK, true,
> + TIMEOUT_200MS, false);
> + if (ret) {
> + debug("%s: Timeout while waiting for", __func__);
> + debug(" programming done\n");
> + return ret;
> + }
> +
> + debug("DDR programming done\n");
> +
> + /* Polling until SDRAM entered normal operating mode */
> + value = readl(ddr_handoff_info.umctl2_base +
> DDR4_STAT_OFFSET) &
> + DDR4_STAT_OPERATING_MODE;
Change to do...while() and can remove this readl.
> + while (value != NORMAL_OPM) {
> + if (get_timer(start) > TIMEOUT_200MS) {
> + debug("%s: Timeout while waiting for",
> + __func__);
> + debug(" DDR enters normal operating
> mode\n");
> + return -ETIMEDOUT;
> + }
> +
> + value = readl(ddr_handoff_info.umctl2_base +
> + DDR4_STAT_OFFSET) &
> + DDR4_STAT_OPERATING_MODE;
> +
> + udelay(1);
> + WATCHDOG_RESET();
> + }
> +
> + debug("DDR entered normal operating mode\n");
> +
> + /* Enabling auto refresh */
> + clrbits_le32(ddr_handoff_info.umctl2_base +
> + DDR4_RFSHCTL3_OFFSET,
> + DDR4_RFSHCTL3_DIS_AUTO_REFRESH);
> +
> + /* Checking ECC is enabled? */
> + value = readl(ddr_handoff_info.umctl2_base +
> + DDR4_ECCCFG0_OFFSET) & DDR4_ECC_MODE;
> + if (value) {
> + printf("%s: ECC is enabled\n", __func__);
> + ret = scrubbing_ddr_config(&ddr_handoff_info);
> + if (ret) {
> + debug("%s: Failed to enable ECC\n",
> __func__);
> + return ret;
> + }
> + }
> +
> + /* Restore user settings */
> + writel(user_backup, ddr_handoff_info.umctl2_base +
> + DDR4_PWRCTL_OFFSET);
> +
> + /* Enable input traffic per port */
> + setbits_le32(ddr_handoff_info.umctl2_base +
> DDR4_PCTRL0_OFFSET,
> + DDR4_PCTRL0_PORT_EN);
> +
> + printf("%s: DDR init success\n", __func__);
> + }
> +
> + /* Get bank configuration from devicetree */
> + ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL,
> + (phys_size_t *)&gd->ram_size, &bd);
> + if (ret) {
> + debug("%s: Failed to decode memory node\n", __func__);
> + return -1;
Use errorno.
Regards
Ley Foon
More information about the U-Boot
mailing list