blob: 4cb810f45fc6b2f2a94c901d2246e9aa4986375a [file] [log] [blame]
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*
* Refer doc/README.imximage for more details about how-to configure
* and create imximage boot image
*
* The syntax is taken as close as possible with the kwbimage
*/
/* image version */
#define __ASSEMBLY__
/* C header files modified with the expand_c_define.sh script from
source files in
../../imx-sc-firmware/firmware/platform/board/mx8qm_val/ddrc/
or verification BOM:
testbench/blocks/soc_tb/tool_data/compiler/include/drc.h
*/
#include <ddrc_mem_map.h>
#include <ddr_phy_mem_map.h>
/*
* Device Configuration Data (DCD)
*
* Each entry must have the format:
* Addr-type Address Value
*
* where:
* Addr-type register length (1,2 or 4 bytes)
* Address absolute address of the register
* value value to be stored in the register
*/
/* from file: imx-sc-firmware/firmware/platform/board/mx8qm_val/ddrc/ss_drc_lpddr4_init_zebu.c mx8qm_val/ddrc/ss_drc_lpddr4_init_zebu.c */
/* copy/paste from ddrc_init() */
/* Mike comment #1: added DRC bringup */
/* From BootROM team: */
/* BootROM reserved 0xFF000000 ~ 0xFFFFFFFF as DRC bringup command purpose.
BootROM will not actually write values to that address range, but call
ROM API to bring up DRC.
If DCD address’s highest 8bit is 0xFF, BootROM will not actually access
that address but takes them as a ROM API call.
The lower 24bit are mapped as:
Bit23-20: API type.
1-ROM_API_BRINGUP_SS (Support DRC_0/1 only);
8- ROM_API_AI_WR;
9- ROM_API_AI_RD;
0xF- ROM_API_UDELAY;
Bit19-14: DSC_ID.
Relative to ROM_API_BRINGUP_SS/ ROM_API_AI_WR/ ROM_API_AI_RD
Bit13-9: AI SRC SEL.
Relative to ROM_API_AI_WR/ ROM_API_AI_RD
Bit8-0: AI Register offset.
Relative to ROM_API_AI_WR/ ROM_API_AI_RD
The date in DCD pair will be parsed as follow;
Bit7-0: delay value, in ms, if API is ROM_API_UDELAY
Bit7-0: PLL Integer which will be programed into PLL register.
For ROM_API_BRINGUP_SS.
Bit13-10: CSLICE_SRC_SEL. To specify the clock source of DRC CSLICE.
For ROM_API_BRINGUP_SS only.
[JF] DRC cslice source coded in bit10-bit13
#define BRINGUP_SS_CSLICE_SRC_SEL(x) (((x)>>10)&0xF)
And definition as follow:
Bits[13:10]:
0000 = xtal24M
0001 = PLL DIV1
0010 = PLL DIV2
0011 = PLL DIV4
[MJ] lower bits (bits[7:0]) encoding scheme.
Bits[7:0]: PLL multiplier. PLL_Freq = 24 MHz * multiplier / 2.
0xC8 => 200, PLL_FREQ = 2400MHz.
0x85 => 133, PLL_FREQ = 1596MHz.
So this confirms a settings of 0x00000C85 gives a PLL speed of 1600MHz
with DIV4 to yield 800MHz.
[MK] Previous setting of 0x00000cc8: PLL to 2400MHz with a DIV2 to yield 1200MHz.
Nitin had noticed this which started the discussion on setting this
to be 1600MHz (0x00000885) which aligned to the eventual target of
MX8QM LPDDR4.
So basically they are asking if we can go back to the previous
PLL:2400MHz/DDR:1200MHz setting (0x00000cc8).
[MK] I was actually able to get confirmation from our local software team.
So it is ok to go ahead and modify the DCD.
However, as Stephane pointed out, it is unlikely that 1600MHz will
work out of the gate for initial silicon so we can put in the two
options as follows:
// For 1600MHz DDR operation, uncomment the following
DATA 4 0xff148000 0x00000885 // DRC0 bringup
DATA 4 0xff1a0000 0x00000885 // DRC1 bringup
// For 800MHz DDR operation, uncomment the following
//DATA 4 0xff148000 0x00000C85 // DRC0 bringup
//DATA 4 0xff1a0000 0x00000C85 // DRC1 bringup
And by default, we’ll have the 1600Mhz operation for zebu purposes
(I think some folks may do some performance analysis on zebu so having
the higher speed may be more beneficial).
*/
/* For 1600MHz DDR operation (Zebu) */
DATA 4 0xff148000 0x00000885 /* DRC0 bringup */
DATA 4 0xff1a0000 0x00000885 /* DRC1 bringup */
/* DRAM 0 controller configuration begin */
/* Program the umctl2 registers */
/* ddrc_lpddr4_init(0) */
/* begin unroll ddrc_lpddr4_init(0) */
/* ddrc_lpddr4_init - DRAM controller initialization */
// This is for lpddr4 controller 800MHz and ddr 1600MHz
DATA 4 DDRC_MSTR_0 0xC3080020 // Set LPDDR4, BL = 16 and active ranks
#ifdef DDRC_POSTED_REFRESH_EN
DATA 4 DDRC_RFSHCTL0_0 0x00210070 // posted refresh
#endif
#ifdef DDRC_REFRESH_PER_BANK_EN
SET_BIT 4 DDRC_RFSHCTL0_0 (1<<2)
DATA 4 DDRC_RFSHTMG_0 0x000C006F // treflpb=488ns*2/1.26264/2/32,
#else
DATA 4 DDRC_RFSHTMG_0 0x006100E0 // tREFI, tRFC
#endif
// CAST32(DDRC_INIT0_0 0x4002061A // skip_dram_init, post_cke, pre_cke
DATA 4 DDRC_INIT0_0 0x40020010 // pre_cke = 2ms is too long - LPDDR4 model hacked for 20us
// CAST32(DDRC_INIT1_0 0x009d0000 // dram_rstn = 200us;
DATA 4 DDRC_INIT1_0 0x00100000 // dram_rstn - LPDDR4 model hacked for 20us;
DATA 4 DDRC_INIT3_0 0x0054002d // MR1=0x54: nWR=30 BL=16; MR2=0x2d: RL=28 WL=14
DATA 4 DDRC_INIT4_0 0x00310000 // MR3, MR13
DATA 4 DDRC_RANKCTL_0 0x000006cf // diff_rank_wr_gap, diff_rank_rd_gap, max_rank_rd
DATA 4 DDRC_DRAMTMG0_0 0x1a201b22 // wr2pr, tFAW, tRASmax, tRASmin
DATA 4 DDRC_DRAMTMG1_0 0x00060633 // tXP, rd2pre, tRC
/* Mike comment #2 */
/* RD2WR and WR2RD calculation:
RD2WR: RL + BL/2 + RU(tDQSCKmax/tCK) + WR_PREAMBLE + RD_POSTAMBLE - WL
RU[(28+16/2+RU(3.5/0.625)+2+0.5-14)/2] =
RU[(28+8+6+2+0.5-14)/2] = RU[15.25] = 16 (0x10)
WR2RD: CWL + BL/2 + tWTR + 1(spec says to add one extra clock cycle)
RU[(14+8+16+1)/2)] = 20 (0x14)
*/
DATA 4 DDRC_DRAMTMG2_0 0x070E1014 // WL, RL, rd2wr, wr2rd
DATA 4 DDRC_DRAMTMG3_0 0x0170c00c // tmrw, tmrd, tmod
/* Mike and Stephane comment #3 */
/* T_RP calculation:
T_RP: all bank precharge time of 21ns opposed to pre-bank 18ns
21ns @ 1.6GHz = 33.6 -> RU[33.6/2] = 17 (0x11)
18ns @ 1.6GHz = 28.8 -> RU[28.8/2] = 15 (0x0F)
-> we use per-bank
[SC] t_rp description is
“Minimum time from precharge to activate of same bank”.
So for me they refer to a single bank and not all bank.
*/
DATA 4 DDRC_DRAMTMG4_0 0x0f04080F // trcd, tccd, trrd, trp
/* Mike and Stephane comment #4 */
/* T_CKSRX and T_CKSRE calculatin:
T_CKSRX: LPDDR4 tCKCKEH=3cks; RU(3/2)= 2
T_CKSRE: LPDDR4 tCKCKEL, per JEDEC, max(5ns,3tCK)
5ns@1.6GHz=8clks, RU(8/2) = 4
-> use max(5ns, 5tCK).
[SC] tCKCKEL is different for power down entry.
As per JEDEC it is Max(5ns, 5nCK) there is another table in JEDEC spec for
power-down entry timings. Note that it seems there is a typo in JEDEC
because they call it tCKELCK.
Thus it gives RU(8/2) = 4
[MK] I noticed the Synopsys spec describes this as
“This is the time after Self Refresh Down Entry that CK is maintained as a valid clock. Specifies the clock disable delay after SRE.”
The Self Refresh AC timing table seems to have a closely matched description:
“Valid Clock Requirement after CKE Input low: tCKCKEL” which is
max(7.5ns, 3tck). For “tCKELCK”, I can see this is described in
the Power Down AC timing but the Synopsys spec did not mention power
down, just self refresh. Is it possible that the spec is incorrect
and should really be referring to the power down AC timing or maybe
I am misinterpreting the Synopsys spec?
[SC] Basically when CKE goes low we enter in power down mode. Depending
on the state of the memory before CKE low we enter different power
down modes. You can refer to chapter 4.41.1 (FYI I have this version:
JESD209-4A from November 2015):
“If power-down occurs when all banks are idle, this mode is referred to as idle power-down. if power-down occurs when there is a row active in any bank, this mode is referred to as active power-down. And If power-down occurs when Self Refresh is in progress, this mode is referred to as Self Refresh power-down in which the internal refresh is continuing in the same way as Self Refresh mode.”
The tCKELCK appears in 2 tables: one linked to command bus training
(max(7.5ns, 3tck)) and one for Power-Down (Max(5ns, 5nCK)). So I
guess the timing in “Power-down AC Timing” table should apply.
Moreover the command bus training is fully done by software and thus
there is no need to have this timing is a register.
*/
DATA 4 DDRC_DRAMTMG5_0 0x02040C0C // tCKCKEH, tCKCKEL, tckesr, tcke
DATA 4 DDRC_DRAMTMG6_0 0x02020007 // tckdpde, tckdpdx, tckcsx
/* Mike and Stephane comment #5 */
/* T_CKPDE calculation:
T_CKPDE: the spec says to use tCKCKEL.
[SC] tCKCKEL is different for power down entry.
As per JEDEC it is Max(5ns, 5nCK)
*/
DATA 4 DDRC_DRAMTMG7_0 0x00000401 // tckpde, tckpdx
DATA 4 DDRC_DRAMTMG12_0 0x00020610 // tCMDCKE, tCKEHCMD (=tXP?)
DATA 4 DDRC_DRAMTMG13_0 0x0c100002 // tODTLoff, tCCDMW, tPPD
DATA 4 DDRC_DRAMTMG14_0 0x000000E6 // txsr
DATA 4 DDRC_ZQCTL0_0 0x03200018 // tZQCAL, tZQLAT
DATA 4 DDRC_ZQCTL1_0 0x02800100 // tZQReset, tzq_short_interval
DATA 4 DDRC_DFITMG0_0 0x049C820C // dfi_t_ctrl_delay, dfi_t_rddata_en, dfi_tphy_wrdata, dfi_tphy_wrlat
DATA 4 DDRC_DFITMG1_0 0x00060303 // dfi_t_wrdata_delay, dfi_t_dram_clk_disable, dfi_t_dram_clk_enable
DATA 4 DDRC_DFITMG2_0 0x00001A0A // dfi_tphy_rdcslat, dfi_tphy_wrcslat
DATA 4 DDRC_DFIMISC_0 0x00000005 // dfi_data_cs_polarity
DATA 4 DDRC_DFIUPD0_0 0x80400003 // Disable the automatic dfi_ctrlupd_req generation
DATA 4 DDRC_DFIUPD1_0 0x00010002 // dfi_ctrlupd_req generation interval generation (min and max)
DATA 4 DDRC_DFIUPD2_0 0x80000000 // dfi_phyupd_en
DATA 4 DDRC_ADDRMAP0_0 0x00000017 // addrmap_cs_bit0
/* Mike and Stephane comment #6 */
/* Added DDRC_ADDRMAP4_0.
[MK] recommends the following line to make sure un-used columns are not activated:
This will help us with the DDR stress test. Eventually, we’ll add in the
capability to calculate a device’s density from the ADDRMAP registers.
But in order to correctly calculate, we need to set unused column bits to
0xF.
This was something we actually discovered when developing the stress test
for MX7D (which uses a Synopsys controller for LPDDR3).
*/
DATA 4 DDRC_ADDRMAP4_0 0x00000F0F // addrmap_col_b10 and addrmap_col_b11 set to de-activated
#ifdef DISABLE_DDRC_BANK_INTERLEAVE
DATA 4 DDRC_ADDRMAP1_0 0x00181818 // addrmap_bank_b2, addrmap_bank_b1, addrmap_bank_b0
DATA 4 DDRC_ADDRMAP5_0 0x04040404 // addrmap_row_b11, addrmap_row_b10_b2, addrmap_row_b1, addrmap_row_b0
DATA 4 DDRC_ADDRMAP6_0 0x04040404 // addrmap_row_b15, addrmap_row_b14, addrmap_row_b13, addrmap_row_b12
#else
DATA 4 DDRC_ADDRMAP1_0 0x00080808 // addrmap_bank_b2, addrmap_bank_b1, addrmap_bank_b0
DATA 4 DDRC_ADDRMAP5_0 0x07070707 // addrmap_row_b11, addrmap_row_b10_b2, addrmap_row_b1, addrmap_row_b0
DATA 4 DDRC_ADDRMAP6_0 0x07070707 // addrmap_row_b15, addrmap_row_b14, addrmap_row_b13, addrmap_row_b12
#endif
//CAST32(DDRC_ODTCFG_0 0x0a020b28 // wr_odt_hold, wr_odt_delay, rd_odt_hold, rd_odt_delay
DATA 4 DDRC_ODTMAP_0 0x00002211 // rank[3:0]_wr_odt, rank[3:0]_wr_odt
DATA 4 DDRC_PCTRL_0_0 0x00000001 // Enable port 0
// In prevision of low frequency switch. DFITMG0.xxx_use_sdr fields can only
// be written when controller is under reset.
DATA 4 DDRC_DFITMG0_SHADOW_0 0x00808000
DATA 4 DDRC_PWRCTL_0 0x10D
DATA 4 DDRC_PWRCTL_1 0x10D
/* end unroll ddrc_lpddr4_init(0) */
/* ddrc_lpddr4_init(1) */
/* begin unroll ddrc_lpddr4_init(1) */
/* ddrc_lpddr4_init - DRAM controller initialization */
// This is for lpddr4 controller 800MHz and ddr 1600MHz
DATA 4 DDRC_MSTR_1 0xC3080020 // Set LPDDR4, BL = 16 and active ranks
#ifdef DDRC_POSTED_REFRESH_EN
DATA 4 DDRC_RFSHCTL0_1 0x00210070 // posted refresh
#endif
#ifdef DDRC_REFRESH_PER_BANK_EN
SET_BIT 4 DDRC_RFSHCTL0_0 (1<<2)
DATA 4 DDRC_RFSHTMG_1 0x000C006F // treflpb=488ns*2/1.26264/2/32,
#else
DATA 4 DDRC_RFSHTMG_1 0x006100E0 // tREFI, tRFC
#endif
// CAST32(DDRC_INIT0_1 0x4002061A // skip_dram_init, post_cke, pre_cke
DATA 4 DDRC_INIT0_1 0x40020010 // pre_cke = 2ms is too long - LPDDR4 model hacked for 20us
// CAST32(DDRC_INIT1_1 0x009d0000 // dram_rstn = 200us;
DATA 4 DDRC_INIT1_1 0x00100000 // dram_rstn - LPDDR4 model hacked for 20us;
DATA 4 DDRC_INIT3_1 0x0054002d // MR1=0x54: nWR=30 BL=16; MR2=0x2d: RL=28 WL=14
DATA 4 DDRC_INIT4_1 0x00310000 // MR3, MR13
DATA 4 DDRC_RANKCTL_1 0x000006cf // diff_rank_wr_gap, diff_rank_rd_gap, max_rank_rd
DATA 4 DDRC_DRAMTMG0_1 0x1a201b22 // wr2pr, tFAW, tRASmax, tRASmin
DATA 4 DDRC_DRAMTMG1_1 0x00060633 // tXP, rd2pre, tRC
DATA 4 DDRC_DRAMTMG2_1 0x070E1014 // WL, RL, rd2wr, wr2rd
DATA 4 DDRC_DRAMTMG3_1 0x0170c00c // tmrw, tmrd, tmod
DATA 4 DDRC_DRAMTMG4_1 0x0f04080F // trcd, tccd, trrd, trp
DATA 4 DDRC_DRAMTMG5_1 0x02040C0C // tCKCKEH, tCKCKEL, tckesr, tcke
DATA 4 DDRC_DRAMTMG6_1 0x02020007 // tckdpde, tckdpdx, tckcsx
DATA 4 DDRC_DRAMTMG7_1 0x00000401 // tckpde, tckpdx
DATA 4 DDRC_DRAMTMG12_1 0x00020610 // tCMDCKE, tCKEHCMD (=tXP?)
DATA 4 DDRC_DRAMTMG13_1 0x0c100002 // tODTLoff, tCCDMW, tPPD
DATA 4 DDRC_DRAMTMG14_1 0x000000E6 // txsr
DATA 4 DDRC_ZQCTL0_1 0x03200018 // tZQCAL, tZQLAT
DATA 4 DDRC_ZQCTL1_1 0x02800100 // tZQReset, tzq_short_interval
DATA 4 DDRC_DFITMG0_1 0x049C820C // dfi_t_ctrl_delay, dfi_t_rddata_en, dfi_tphy_wrdata, dfi_tphy_wrlat
DATA 4 DDRC_DFITMG1_1 0x00060303 // dfi_t_wrdata_delay, dfi_t_dram_clk_disable, dfi_t_dram_clk_enable
DATA 4 DDRC_DFITMG2_1 0x00001A0A // dfi_tphy_rdcslat, dfi_tphy_wrcslat
DATA 4 DDRC_DFIMISC_1 0x00000005 // dfi_data_cs_polarity
DATA 4 DDRC_DFIUPD0_1 0x80400003 // Disable the automatic dfi_ctrlupd_req generation
DATA 4 DDRC_DFIUPD1_1 0x00010002 // dfi_ctrlupd_req generation interval generation (min and max)
DATA 4 DDRC_DFIUPD2_1 0x80000000 // dfi_phyupd_en
DATA 4 DDRC_ADDRMAP0_1 0x00000017 // addrmap_cs_bit0
DATA 4 DDRC_ADDRMAP4_1 0x00000F0F // addrmap_col_b10 and addrmap_col_b11 set to de-activated
#ifdef DISABLE_DDRC_BANK_INTERLEAVE
DATA 4 DDRC_ADDRMAP1_1 0x00181818 // addrmap_bank_b2, addrmap_bank_b1, addrmap_bank_b0
DATA 4 DDRC_ADDRMAP5_1 0x04040404 // addrmap_row_b11, addrmap_row_b10_b2, addrmap_row_b1, addrmap_row_b0
DATA 4 DDRC_ADDRMAP6_1 0x04040404 // addrmap_row_b15, addrmap_row_b14, addrmap_row_b13, addrmap_row_b12
#else
DATA 4 DDRC_ADDRMAP1_1 0x00080808 // addrmap_bank_b2, addrmap_bank_b1, addrmap_bank_b0
DATA 4 DDRC_ADDRMAP5_1 0x07070707 // addrmap_row_b11, addrmap_row_b10_b2, addrmap_row_b1, addrmap_row_b0
DATA 4 DDRC_ADDRMAP6_1 0x07070707 // addrmap_row_b15, addrmap_row_b14, addrmap_row_b13, addrmap_row_b12
#endif
DATA 4 DDRC_ODTMAP_1 0x00002211 // rank[3:0]_wr_odt, rank[3:0]_wr_odt
DATA 4 DDRC_PCTRL_0_1 0x00000001 // Enable port 0
DATA 4 DDRC_DFITMG0_SHADOW_1 0x00808000
/* end unroll ddrc_lpddr4_init(1) */
// Overwrite some settings
/* for (ddr_num=0;ddr_num<=1;ddr_num++) { } */
/* DDR #0 */
/* Set DFIMISC.dfi_init_complete_en to 0 to avoid controller init
sequence to start after reset release */
CLR_BIT 4 DDRC_DFIMISC_0 0x00000001
// As DRAM init sequence will be run by controller set 0x0 to skip_dram_init field
CLR_BIT 4 DDRC_INIT0_0 0xC0000000
/* DDR #1 */
CLR_BIT 4 DDRC_DFIMISC_1 0x00000001
CLR_BIT 4 DDRC_INIT0_1 0xC0000000
// ZeBu DDR PHY initialization begin...
// Launch DDR PHY PLLINIT, DCAL and ZCAL
/* ddr_phy_lpddr4_phy_init(0); */
/* begin unroll ddr_phy_lpddr4_phy_init(0); */
/* ddr_phy_lpddr4_phy_init - PHY initialization */
//-------------------------------------------
// Configure registers for PHY initialization
// Timings are computed for a PHY at 800MHz (DRAM at 1600MHz)
//-------------------------------=------------
// Set-up DRAM Configuration Register
DATA 4 DDR_PHY_DCR_0 0x0000040D // LPDDR4 selection with 8 bank
// Set-up PHY General Configuration Register
// PGCR1,4,5,6,7 are untouched
DATA 4 DDR_PHY_PGCR0_0 0x87001E00 // Set ADCP=1 (Address Copy)
/* Mike and Stephane comment #7 */
/* tREFPRD calculation:
[MK] the revision of the PUB book I have is ” PUB Version 1.50c”
[SC] We have to follow latest specification. Hence
“(9*3900/Dram_clk_period)-600” => 0xD941.
*/
DATA 4 DDR_PHY_PGCR2_0 0x00F0D941 // Set tREFPRD (9*3.904us - 600)
DATA 4 DDR_PHY_PGCR3_0 0x050A1080 // CKEN/CKNEN toggling and polarity
// Set-up PHY Timing Register
// PTR2 is untouched
DATA 4 DDR_PHY_PTR0_0 0x64032010 // tPLLPD, tPLLGS, tPHYRST
// CAST32(DDR_PHY_PTR1(ddr_num)) = 0x4E201C20; // tPLLLOCK=25us, tPLLRST=9us
DATA 4 DDR_PHY_PTR1_0 0x0D701C20 // tPLLLOCK reduced to 4.3us, tPLLRST=9us
// Set-up PLL Control Register
DATA 4 DDR_PHY_PLLCR0_0 0x08000000 // FREQSEL=8
DATA 4 DDR_PHY_DX8SLbPLLCR0_0 0x08000000
// Set-up Impedance Control Register
DATA 4 DDR_PHY_ZQCR_0 0x001FEC58 // Set ODT_MODE=0b10(LPDDR4 stype pullup)
// Set-up Impedance Controller Program Register
// ZQnPR0, ZQnPR1 are untouched, lpddr4 PD_REFSEL should not be default value, FIXME
/* end unroll ddr_phy_lpddr4_phy_init(0); */
/* ddr_phy_launch_init(0, 0x40); */
/* begin unroll ddr_phy_launch_init(0, 0x40); */
// Set-up PHY Initialization Register
DATA 4 DDR_PHY_PIR_0 0x40
// Launch initialization (set bit 0)
DATA 4 DDR_PHY_PIR_0 0x41
/* end unroll ddr_phy_launch_init(0, 0x40); */
/* ddr_phy_lpddr4_phy_init(1); */
/* begin unroll ddr_phy_lpddr4_phy_init(1); */
/* ddr_phy_lpddr4_phy_init - PHY initialization */
//-------------------------------------------
// Configure registers for PHY initialization
// Timings are computed for a PHY at 800MHz (DRAM at 1600MHz)
//-------------------------------=------------
// Set-up DRAM Configuration Register
DATA 4 DDR_PHY_DCR_1 0x0000040D // LPDDR4 selection with 8 bank
// Set-up PHY General Configuration Register
// PGCR1,4,5,6,7 are untouched
DATA 4 DDR_PHY_PGCR0_1 0x87001E00 // Set ADCP=1 (Address Copy)
/* Mike and Stephane comment #7 */
/* tREFPRD calculation:
[MK] the revision of the PUB book I have is ” PUB Version 1.50c”
[SC] We have to follow latest specification. Hence
“(9*3900/Dram_clk_period)-600” => 0xD941.
*/
DATA 4 DDR_PHY_PGCR2_1 0x00F0D941 // Set tREFPRD (9*3.904us - 600)
DATA 4 DDR_PHY_PGCR3_1 0x050A1080 // CKEN/CKNEN toggling and polarity
// Set-up PHY Timing Register
// PTR2 is untouched
DATA 4 DDR_PHY_PTR0_1 0x64032010 // tPLLPD, tPLLGS, tPHYRST
// CAST32(DDR_PHY_PTR1(ddr_num)) = 0x4E201C20; // tPLLLOCK=25us, tPLLRST=9us
DATA 4 DDR_PHY_PTR1_1 0x0D701C20 // tPLLLOCK reduced to 4.3us, tPLLRST=9us
// Set-up PLL Control Register
DATA 4 DDR_PHY_PLLCR0_1 0x08000000 // FREQSEL=8
DATA 4 DDR_PHY_DX8SLbPLLCR0_1 0x08000000
// Set-up Impedance Control Register
DATA 4 DDR_PHY_ZQCR_1 0x001FEC58 // Set ODT_MODE=0b10(LPDDR4 stype pullup)
// Set-up Impedance Controller Program Register
// ZQnPR0, ZQnPR1 are untouched, lpddr4 PD_REFSEL should not be default value, FIXME
/* end unroll ddr_phy_lpddr4_phy_init(1); */
/* ddr_phy_launch_init(1, 0x40); */
/* begin unroll ddr_phy_launch_init(1, 0x40); */
// Set-up PHY Initialization Register
DATA 4 DDR_PHY_PIR_1 0x40
// Launch initialization (set bit 0)
DATA 4 DDR_PHY_PIR_1 0x41
/* end unroll ddr_phy_launch_init(1, 0x40); */
// While PHY initialization is running, registers for DRAM initialization can be configured
/* ddr_phy_lpddr4_dram_init(0); */
/* begin unroll ddr_phy_lpddr4_dram_init(0); */
/* ddr_phy_lpddr4_dram_init(0) DRAM initialization */
//-------------------------------------------
// Configure registers for DRAM initialization
//-------------------------------------------
// Set-up Mode Register
// MR0, MR3, MR4, MR5 MR6 are untouched
DATA 4 DDR_PHY_MR1_0 0x54 // Set BL, WR-PRE, nWR, RPST
DATA 4 DDR_PHY_MR2_0 0x2D // Set RL=28/WL=14
DATA 4 DDR_PHY_MR3_0 0x31 // Set drive strength (40 Ohms by default)
DATA 4 DDR_PHY_MR11_0 0x60 // Set CA ODT=RZQ/6
DATA 4 DDR_PHY_MR22_0 0x10 // Set ODTE-CS=1 (overrides ODT_CA for CS1 as CS not shared between ranks)
// Set-up DRAM Timing Parameters Register
// DTPR6 is untouched
DATA 4 DDR_PHY_DTPR0_0 0x1044220C // tRRD, tRAS, tRP, tRTP
/* Mike and Stephane comment #8 */
/* [SC] As we have RTL 1.51a (and not 1.40a as I mentioned before),
tODTUP does not exist anymore in DTPR1 (I also looked at the RTL)
Note that tODTUP exists in DTPR5 register. So I get following value
for DTPR1 (tMOD reset value is 4):
DDR_PHY_DTPR1 = 0x28400417; // tWLMRD, tFAW, tMRD
*/
DATA 4 DDR_PHY_DTPR1_0 0x28400417 // tWLMRD, tFAW, tODTUP, tMRD
/* Mike and Stephane comment #9 */
/* [MK] I am adding the following note in the DDR Register Programming aid for tVRCG:
For LPDDR4, we take the greater of (tVRCG_ENABLE,VRCG_DISABLE), which per JEDEC is (200ns, 100ns). So, 200ns converted to clock cycles (1.6GHz freq) yields 320 clocks, which yields a tVRCG bit setting of '100' or 4.
However, tVRCG-3 = 4 - 3 = 1, which is less than tVRCG_ENABLE/tVRCG_DISABLE or 200ns/100ns = 2.
So, recommend to set tVRCG to the next higher value of 5 (bit setting '101') or 384 clocks.
So I set DTPR2=0x006CA1CC
*/
DATA 4 DDR_PHY_DTPR2_0 0x006CA1CC // tRTW, tRTODT, tCMDCKE, tCKE, tVRCG, tXS
DATA 4 DDR_PHY_DTPR3_0 0x01800604 // tODX, tCCD, tDLLK, tDQSCKmax, tDQSCK (FIXME double check tDLLK)
/* Mike and Stephane comment #10 */
/* [MK] The PHY spec states for tXP:
"Note: For LPDDR4, additional offset of +3 tCK must be added to the value calculated for the corresponding speed grade."
[SC] What about the tWLO field ? You set it to 0. What follows the
tWLOmin requirement but description says:
“This must include the SDRAM tWLO timing parameter plus the round trip delay from control block to SDRAM back to control block.”
And I have ni idea how to calculate this round trip delay. So I kept
the default value. I will ask Synopsys.
[MK] For tXP, I will make the update to +3 clocks (I confirm I get 0xF).
[SC] Here is Synopsys’s Answer for DTPR4.tWLO:
"There is no need to change the default value, it has a significant margin, enough to cover the maximum round trip delay supported scenario.”
So I get DDR_PHY_DTPR4 = 0x01C02B0F; // tRFC, tWLO, tXP.
*/
DATA 4 DDR_PHY_DTPR4_0 0x01C02B0F // tRFC, tWLO, tXP
DATA 4 DDR_PHY_DTPR5_0 0x00651D10 // tRC, tRCD, tWTR
// Set-up PHY Timing Register
// CAST32(DDR_PHY_PTR3(ddr_num)) = 0x0030D400; // tDINIT0 - 2ms
DATA 4 DDR_PHY_PTR3_0 0x00007D00 // tDINIT0 - memory model hacked to 20us
/* Mike and Stephane comment #11 */
/* [MK] When we calculated this we came up with DATA 4 DDR_PHY_PTR4_0 0x00000C80:
2000ns*1.6GHz=3200 -> convert to hex -> 0xC80
[SC] I guess I did not get the 2000ns with 0xC80. That’s why I
increased it a little bit. But I may have wrong. I will make a trial
with 0xC80.
[MK] Ok, let me know what you find out.
[SC] 0xC80 works fine in my simulation. So I will keep it.
*/
DATA 4 DDR_PHY_PTR4_0 0x00000C80 // tDINIT1 (2000ns)
DATA 4 DDR_PHY_PTR5_0 0x00007D00 // tDINIT2 - normally 200us but memory model hacked to 20us
/* Mike and Stephane comment #12 */
/* [MK] For tDINIT4, the PHY spec says:
"Note: For LPDDR4 tZQLAT, additional offset of +3 tCK must be added i.e. value programmed in this register field must be MAX(30ns, 8 tCK) + 3 tCK"
But we did not add 3 clocks, should we?
[SC] I have 0x03300641 in this register. Yes you need the +3 tCK. This was not stated in the 1.40a databook but I get issues and Synopsys confirmed me the +3 tCK are mandatory.
[MK] Ok, I’ve added the “+3” in the register programming aid and I confirm I get “0x33”
For tDINIT3, we calculated 0x640 as follows:
1us*1.6Ghz= 1600 ->converted to hex -> 0x640
[SC] You’re correct but I guess I did not get the 1us with 0x640.
That’s why I increased it to 0x641. I will make a trial with 0x640.
[MK] Thanks, let me know if 0x640 works.
[SC] 0x640 works fine in my simulation. So I will keep it.
[MK] Thanks, I will also keep 0x640 in the register programming aid.
*/
DATA 4 DDR_PHY_PTR6_0 0x03300640 // tDINIT4 (MAX(30ns, 8 tCK)+3 tCK), tDINIT3 (1us)
// RDIMMGCR0-2 RDIMMGCR0-4??
// Set-up DATX8 Common Configuration Register
// DXCCR is untouched
// Set-up DDR System General Configuration Register
// DSGCR is untouched
// Set-up ODT Configuration Register
// DDR ODT_CA signal is tied at boundary of DDR. Thus no need to drive it dynamically.
DATA 4 DDR_PHY_RANKIDR_0 1 // Select rank 1 to write
DATA 4 DDR_PHY_ODTCR_0 0x00000000 // ODT of rank1 disabled
DATA 4 DDR_PHY_RANKIDR_0 0 // Select rank 0 to write
DATA 4 DDR_PHY_ODTCR_0 0x00000000 // ODT of rank0 disabled
// Set-up Anti-Aging Control Register
// AACR is untouched
// Set-up Data Training Address Register
// DTAR0-3 are untouched
// !! DTAR3 is not described in spec !!
// Set-up AC I/O Configuration Register
// ACIOCR1-4 are untouched
DATA 4 DDR_PHY_ACIOCR0_0 0x30070800 // PNUM2 (i.e.LPDDR4) selection [10:11] = 0x2
DATA 4 DDR_PHY_ACIOCR5_0 0x09000000 // I/O mode = LPDDR4
// Due to address copy set A[13] (=cke_B[0]) and A[15] (=cke_B[1]) outputs as always ON.
DATA 4 DDR_PHY_ACIOCR1_0 0x44000000
// IOVCR0-1, DXnGCR0-4??, CALBYP
// Set-up VREF Training Control Registers
DATA 4 DDR_PHY_VTCR0_0 0xF0032019 // CK1, CK0
DATA 4 DDR_PHY_VTCR1_0 0x07F00173 // HVIO=1, SHREN=1, SHRNK=0
// Set-up DATX8 General Configuration Registers
// DXnGCR0-4 are untouched
// Set-up DATX8 DX Control Register 2
// PREOEX=2.5tCK (0.5 more than MR1), POSOEX=1tCK (0.5 more than in MR3), LPWAKEUP_THRSH=0xA
/* Mike comment #14 */
/* [MK] Regarding chap 2.2.1. As I was reading through it some new
information was made aware to me and I wanted to pass it by you to get
your thoughts and opinions and maybe get Synopsys to weigh in:
1. Preamble and Postamble extensions in DDR_PHY_DX8SLbDXCTL2, PREOES
and POSOEX. The spec says to program a value 0.5*tCK more than the value
required by the DRAM. It is re-iterated in chap 4.9.13. We currently
have these set to PREOEX=2 dram clock preamble, POSOEX=0.5 dram clock
postamble. These values are also the same values programmed into the
LPDDR4 MR1 register. So the question is, should be add 0.5 to the values
in PREOEX and POSOEX?
[SC] I have DDR_PHY_DX8SLbDXCTL2 = 0x001C1400. So it matches
the +0.5tCK. Laurent told me that it did not take my library for the
registers settings. Hence the few discrepancies you noticed. I think he
is now aligned.
[MK] Thanks, I confirm I get the same value for PREOEX and POSOEX
when I add the additional 0.5*tCK, however for the setting of
“LPWAKEUP_THRSH”, the previous value was “4b1100” but it appears
to now be changed to “4b1010”. Honestly, after reading the bit
description I became more confused as to what this configures (actually,
many of the bit descriptions in the PHY are barely understandable). But
I was curious if you knew why this value was changed?
[SC] The LPWAKEUP_THRSH indicates the time needed by PHY to come back
from low power mode.
When controller uMCTL2 requests for low power through the dfi_lp_ctrl_req
or dfi_lp_data_req pins, it also sends a signal named dfi_lp_wakeup. Then
there is a comparison between dfi_lp_wakeup and LPWAKEUP_THRSH.
If dfi_lp_wakeup > LPWAKEUP_THRSH then PHY goes in low power.
Note that the dfi_lp_wakeup value is set through a controller register. So
basically I understand that the software should make an estimation on how
many times the low power mode will length. If this estimation is lower
than the LPWAKEUP_THRSH then the PHY will not go into low power mode as
it would take more time to wake-up than the estimated low power length.
Regarding LPWAKEUP_THRSH value:
In RTL verification we can see that PLL lock time is 4.3us. So it
gives a LPWAKEUP_THRSH=0xA (4.3us/800MHz + 8*800).
In real world PLL lock time is given for 25us. So you should get
25us/800MHz + 8*800 => 26400. Thus LPWAKEUP_THRSH=0xB.
[MK] Thank you for the explanation.
For DDR_PHY_DX8SLbDXCTL2 I have 0x001C1400. We can probably close this one.
2. There is mention of drift detection feature being on. In chap 4.5.2.1,
there’s a statement “Drift detection is enabled by DQSDR0.DFTDTEN”
but we currently do not have this set does Synopsys feel that we should
set this?
[SC] I think we should have it but for RTL verification it was not
mandatory. I have to work on this for Silicon.
3. There’s mention of setting ODT in the DRAM for DQODT and CAODT
in MR11 along with setting MR22.CODT, however, the Synopsys controller
does not have registers for this. I am wondering if the defaults for
these are ok or if the controller automatically updates these in some
training algorithm?
[SC] I need to work on this as well. If some registers are not written
during DRAM init or through a training then we will need to write
them manually.
4. There’s talk of programming ZQnPR0, DQnPR0, and ZQnPR1 however,
our DCD do not touch these registers. Does Synopsys have any thoughts
as to how we should treat this?
[SC] I need to work on this as well
[MK] Stephane and I agreed that we needed to add “0.5tck” for both
POSOEX and PREOEX. Also, LPWAKEUP_THRSH was updated.
It should be 0x001C1600.
It is different than in RTL verification due to the reduced time observed
for PLL lock in RTL (4.3us instead of 25us).
*/
DATA 4 DDR_PHY_DX8SLbDXCTL2_0 0x001C1600
// Set-up DATX8 IO Control Register
DATA 4 DDR_PHY_DX8SLbIOCR_0 0x09000000 // I/O mode = LPDDR4
// Set-up DATX8 DQS Control Register
/* Mike and Stephane comment #13 */
/* [MK] The upper value of this register is written as 0x013, however,
per the PHY spec these bits are reserved. Is it a mistake in the spec?
Is the reserved value of these upper bits 0x013?
[SC] In databook 1.40a bit 21 is WRRMODE and bit 24 is RRRMODE. Both
need to be set at ‘1’. I will check with Synopsys whether or not
they are reserved for RTL 1.40a as well.
Bits [20:19] are DQSGX. It is set to 0x2. If I well remember I needed this
because almost all our verification testcases are run without training.
[MK] Ok, let me know what you find out from Synopsys. BTW, for DQSGX,
in order to get “0x013E…”, should bits [20:19] be set to 11b (0x3)?
If set to “0x2” then the “E” becomes “6”?
[SC] Synopsys did not really answer for WRRMODE and RRRMODE. So I ask
them again.
Anyway I looked into the RTL and the bitfields are there. Moreover they
are connected; so I would say they have an effect in our RTL. Hence I
would strongly recommend to write them to ‘1’.
Regarding DQSGX my mistake I set it to 0x3.
However I am not able to remember why I configure this register. As per
register description DQSRES and DQSNRES usage is for LPDDR3 or DDR3,
and DQSGX=0x3 seems to be required for LPDDR3 only.
Do you have more clues ?
[MK] Regarding WRRMODE and RRRMODE, I will include these are reserved
bit field in the register programming aid and till set each to ‘1’
to yield 0x013E4091.
Regarding DQSRES, DQSNRES, and DQSGX, you ask a very good question.
Admittedly I barely noticed that these applied to different memory
types other than LPDDR4. When I first created the register programming
aid, I simply applied to values found in the SCU firmware and assumed
whoever came up with these values knew more about the PHY than I did so
I left these as is. Would you mind also asking Synopsys about this?
Perhaps our documentation needs to be updated to include LPDDR4 for
these or we don’t program these bit fields and see what happens?
[SC] I ran 2 simulations without configuring this DDR_PHY_DX8SLbDQSCTL_0
register and they passed. So it looks like we should not touch it.
Anyway I am still waiting feedback for the WRRMODE and RRRMODE.
Regarding DQSRES, DQSNRES, and DQSGX I found this in the databook
(chapter 2.2.1 LPDDR4 Usage, version 1.50c):
- DQS pulldown and DQSN pullup should be disabled. To do this, set
DX8SL*DQSCTL.DQSRES=0000 and set DX8SL*DQSCTL.DQSNRES=0000. Disabling
the pullup and pulldown provides optimal DQS/DQSN duty cycle on reads.
- Gate extension must be disabled (set DX8SL*DQSCTL.DQSGX=00)
[MK] Regarding WRRMODE and RRRMODE : we’ll wait and see what Synopsys says
Regarding DQSRES, DQSNRES, and DQSGX: thanks for highlighting chap 2.2.1,
some very good info was conveyed there. I agree we should zero thee
parameters out.
So for now, should the register be programmed as: 0x01264000?
[SC] I think so. I basically removed the configuration of this register
and I get no issues. From PHY RTL I can see the reset value as 0x01264000.
I am still in discussion with Synopsys to clarify the WRRMODE and
RRRMODE bitfields.
[SC] Synopsys opened a ticket on their side to update databook. So these
fields exist and value should be ‘1’.
*/
DATA 4 DDR_PHY_DX8SLbDQSCTL_0 0x01264000 // DQS resistor
/* end unroll ddr_phy_lpddr4_dram_init(0); */
/* ddr_phy_lpddr4_dram_init(1); */
/* begin unroll ddr_phy_lpddr4_dram_init(1); */
/* ddr_phy_lpddr4_dram_init(1) DRAM initialization */
//-------------------------------------------
// Configure registers for DRAM initialization
//-------------------------------------------
// Set-up Mode Register
// MR0, MR3, MR4, MR5 MR6 are untouched
DATA 4 DDR_PHY_MR1_1 0x54 // Set BL, WR-PRE, nWR, RPST
DATA 4 DDR_PHY_MR2_1 0x2D // Set RL=28/WL=14
DATA 4 DDR_PHY_MR3_1 0x31 // Set drive strength (40 Ohms by default)
DATA 4 DDR_PHY_MR11_1 0x60 // Set CA ODT=RZQ/6
DATA 4 DDR_PHY_MR22_1 0x10 // Set ODTE-CS=1 (overrides ODT_CA for CS1 as CS not shared between ranks)
// Set-up DRAM Timing Parameters Register
// DTPR6 is untouched
DATA 4 DDR_PHY_DTPR0_1 0x1044220C // tRRD, tRAS, tRP, tRTP
DATA 4 DDR_PHY_DTPR1_1 0x28400417 // tWLMRD, tFAW, tODTUP, tMRD
DATA 4 DDR_PHY_DTPR2_1 0x006CA1CC // tRTW, tRTODT, tCMDCKE, tCKE, tVRCG, tXS
DATA 4 DDR_PHY_DTPR3_1 0x01800604 // tODX, tCCD, tDLLK, tDQSCKmax, tDQSCK (FIXME double check tDLLK)
DATA 4 DDR_PHY_DTPR4_1 0x01C02B0F // tRFC, tWLO, tXP
DATA 4 DDR_PHY_DTPR5_1 0x00651D10 // tRC, tRCD, tWTR
// Set-up PHY Timing Register
// CAST32(DDR_PHY_PTR3(ddr_num)) = 0x0030D400; // tDINIT0 - 2ms
DATA 4 DDR_PHY_PTR3_1 0x00007D00 // tDINIT0 - memory model hacked to 20us
DATA 4 DDR_PHY_PTR4_1 0x00000C80 // tDINIT1 (2000ns)
DATA 4 DDR_PHY_PTR5_1 0x00007D00 // tDINIT2 - normally 200us but memory model hacked to 20us
DATA 4 DDR_PHY_PTR6_1 0x03300640 // tDINIT4 (MAX(30ns, 8 tCK)+3 tCK), tDINIT3 (1us)
// RDIMMGCR0-2 RDIMMGCR0-4??
// Set-up DATX8 Common Configuration Register
// DXCCR is untouched
// Set-up DDR System General Configuration Register
// DSGCR is untouched
// Set-up ODT Configuration Register
// DDR ODT_CA signal is tied at boundary of DDR. Thus no need to drive it dynamically.
DATA 4 DDR_PHY_RANKIDR_1 1 // Select rank 1 to write
DATA 4 DDR_PHY_ODTCR_1 0x00000000 // ODT of rank1 disabled
DATA 4 DDR_PHY_RANKIDR_1 0 // Select rank 0 to write
DATA 4 DDR_PHY_ODTCR_1 0x00000000 // ODT of rank0 disabled
// Set-up Anti-Aging Control Register
// AACR is untouched
// Set-up Data Training Address Register
// DTAR0-3 are untouched
// !! DTAR3 is not described in spec !!
// Set-up AC I/O Configuration Register
// ACIOCR2-4 are untouched
DATA 4 DDR_PHY_ACIOCR0_1 0x30070800 // PNUM2 (i.e.LPDDR4) selection [10:11] = 0x2
DATA 4 DDR_PHY_ACIOCR5_1 0x09000000 // I/O mode = LPDDR4
// Due to address copy set A[13] (=cke_B[0]) and A[15] (=cke_B[1]) outputs as always ON.
DATA 4 DDR_PHY_ACIOCR1_1 0x44000000
// IOVCR0-1, DXnGCR0-4??, CALBYP
// Set-up VREF Training Control Registers
DATA 4 DDR_PHY_VTCR0_1 0xF0032019 // CK1, CK0
DATA 4 DDR_PHY_VTCR1_1 0x07F00173 // HVIO=1, SHREN=1, SHRNK=0
// Set-up DATX8 General Configuration Registers
// DXnGCR0-4 are untouched
// Set-up DATX8 DX Control Register 2
// PREOEX=2.5tCK (0.5 more than MR1), POSOEX=1tCK (0.5 more than in MR3), LPWAKEUP_THRSH=0xA
DATA 4 DDR_PHY_DX8SLbDXCTL2_1 0x001C1600
// Set-up DATX8 IO Control Register
DATA 4 DDR_PHY_DX8SLbIOCR_1 0x09000000 // I/O mode = LPDDR4
// Set-up DATX8 DQS Control Register
DATA 4 DDR_PHY_DX8SLbDQSCTL_1 0x01264000 // DQS resistor
/* end unroll ddr_phy_lpddr4_dram_init(1); */
// Wait PHY initialization end then advise DDR PHY that DRAM init will be done by uMCTL2
/* ddr_phy_wait_init_done(0); */
/* begin unroll ddr_phy_wait_init_done(0); */
// Wait for bit 0 of PGSR0 to be '1'
CHECK_BITS_SET 4 DDR_PHY_PGSR0_0 0x1 0x1
// Check that no error occured
/* [LC] TODO: not sure if this check should be implemented
if ((CAST32(DDR_PHY_PGSR0(ddr_num)) & 0x7FFC0000) != 0x0) {
board_print(0, "DDR PHY - Initialization failed !\n");
}
*/
/* end unroll ddr_phy_wait_init_done(0); */
/* ddr_phy_launch_init(0, 0x40000); */
/* begin unroll ddr_phy_launch_init(0, 0x40000); */
// Set-up PHY Initialization Register
DATA 4 DDR_PHY_PIR_0 0x40000
// Launch initialization (set bit 0)
DATA 4 DDR_PHY_PIR_0 0x40001
/* end unroll ddr_phy_launch_init(0, 0x40000); */
/* ddr_phy_wait_init_done(1); */
/* begin unroll ddr_phy_wait_init_done(1); */
// Wait for bit 0 of PGSR0 to be '1'
CHECK_BITS_SET 4 DDR_PHY_PGSR0_1 0x1 0x1
// Check that no error occured
/* [LC] TODO: not sure if this check should be implemented
if ((CAST32(DDR_PHY_PGSR0(ddr_num)) & 0x7FFC0000) != 0x0) {
board_print(0, "DDR PHY - Initialization failed !\n");
}
*/
/* end unroll ddr_phy_wait_init_done(1); */
/* ddr_phy_launch_init(1, 0x40000); */
/* begin unroll ddr_phy_launch_init(1, 0x40000); */
// Set-up PHY Initialization Register
DATA 4 DDR_PHY_PIR_1 0x40000
// Launch initialization (set bit 0)
DATA 4 DDR_PHY_PIR_1 0x40001
/* end unroll ddr_phy_launch_init(1, 0x40000); */
// Wait assertion of DDR PHY PGSR0.IDONE field acknowledging that DRAM init will be done by controller
/* ddr_phy_wait_init_done(0); */
/* begin unroll ddr_phy_wait_init_done(0); */
// Wait for bit 0 of PGSR0 to be '1'
CHECK_BITS_SET 4 DDR_PHY_PGSR0_0 0x1 0x1
// Check that no error occured
/* [LC] TODO: not sure if this check should be implemented
if ((CAST32(DDR_PHY_PGSR0(ddr_num)) & 0x7FFC0000) != 0x0) {
board_print(0, "DDR PHY - Initialization failed !\n");
}
*/
/* end unroll ddr_phy_wait_init_done(0); */
/* ddr_phy_wait_init_done(1); */
/* begin unroll ddr_phy_wait_init_done(1); */
// Wait for bit 0 of PGSR0 to be '1'
CHECK_BITS_SET 4 DDR_PHY_PGSR0_1 0x1 0x1
// Check that no error occured
/* [LC] TODO: not sure if this check should be implemented
if ((CAST32(DDR_PHY_PGSR0(ddr_num)) & 0x7FFC0000) != 0x0) {
board_print(0, "DDR PHY - Initialization failed !\n");
}
*/
/* end unroll ddr_phy_wait_init_done(1); */