
Hi Simon,
On Thu, Feb 5, 2015 at 12:24 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 3 February 2015 at 04:45, Bin Meng bmeng.cn@gmail.com wrote:
The codes are actually doing the memory initialization stuff.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
The most ugly codes I've ever seen ... There are 252 warnings and 127 checks in this patch, which are:
check: arch/x86/cpu/quark/smc.c,1609: Alignment should match open parenthesis warning: arch/x86/cpu/quark/smc.c,1610: line over 80 characters warning: arch/x86/cpu/quark/smc.c,1633: Too many leading tabs - consider code refactoring ...
Fixing 'Too many leading tabs ...' will be very dangerous, as I don't have all the details on how Intel's MRC codes are actually written to play with the hardware. Trying to refactor them may lead to a non-working MRC codes. For the 'line over 80 characters' issue, we have to leave them as is now due to the 'Too many leading tabs ...'. If I am trying to fix the 'Alignment should match open parenthesis' issue, I may end up adding more 'line over 80 characters' issues, so we have to bear with it. Sigh.
Understood. Will try to limit my comments.
arch/x86/cpu/quark/smc.c | 2764 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/cpu/quark/smc.h | 446 ++++++++ 2 files changed, 3210 insertions(+) create mode 100644 arch/x86/cpu/quark/smc.c create mode 100644 arch/x86/cpu/quark/smc.h
diff --git a/arch/x86/cpu/quark/smc.c b/arch/x86/cpu/quark/smc.c new file mode 100644 index 0000000..fb389cd --- /dev/null +++ b/arch/x86/cpu/quark/smc.c @@ -0,0 +1,2764 @@ +/*
- Copyright (C) 2013, Intel Corporation
- Copyright (C) 2015, Bin Meng bmeng.cn@gmail.com
- Ported from Intel released Quark UEFI BIOS
- QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/
Removed the ending / in v2.
- SPDX-License-Identifier: Intel
- */
+#include <common.h> +#include <pci.h> +#include <asm/arch/device.h> +#include <asm/arch/mrc.h> +#include <asm/arch/msg_port.h> +#include "mrc_util.h" +#include "hte.h" +#include "smc.h"
+/* t_rfc values (in picoseconds) per density */ +static const uint32_t t_rfc[5] = {
90000, /* 512Mb */
110000, /* 1Gb */
160000, /* 2Gb */
300000, /* 4Gb */
350000, /* 8Gb */
+};
+/* t_ck clock period in picoseconds per speed index 800, 1066, 1333 */ +static const uint32_t t_ck[3] = {
2500,
1875,
1500
+};
+/* Global variables */ +static const uint16_t ddr_wclk[] = {193, 158}; +static const uint16_t ddr_wctl[] = {1, 217}; +static const uint16_t ddr_wcmd[] = {1, 220};
+#ifdef BACKUP_RCVN +static const uint16_t ddr_rcvn[] = {129, 498}; +#endif
+#ifdef BACKUP_WDQS +static const uint16_t ddr_wdqs[] = {65, 289}; +#endif
+#ifdef BACKUP_RDQS +static const uint8_t ddr_rdqs[] = {32, 24}; +#endif
+#ifdef BACKUP_WDQ +static const uint16_t ddr_wdq[] = {32, 257}; +#endif
+/* Stop self refresh driven by MCU */ +void clear_self_refresh(struct mrc_params *mrc_params) +{
ENTERFN();
/* clear the PMSTS Channel Self Refresh bits */
mrc_write_mask(MEM_CTLR, PMSTS, BIT0, BIT0);
LEAVEFN();
+}
+/* It will initialise timing registers in the MCU (DTR0..DTR4) */ +void prog_ddr_timing_control(struct mrc_params *mrc_params) +{
uint8_t tcl, wl;
uint8_t trp, trcd, tras, twr, twtr, trrd, trtp, tfaw;
uint32_t tck;
u32 dtr0, dtr1, dtr2, dtr3, dtr4;
u32 tmp1, tmp2;
ENTERFN();
/* mcu_init starts */
mrc_post_code(0x02, 0x00);
dtr0 = msg_port_read(MEM_CTLR, DTR0);
dtr1 = msg_port_read(MEM_CTLR, DTR1);
dtr2 = msg_port_read(MEM_CTLR, DTR2);
dtr3 = msg_port_read(MEM_CTLR, DTR3);
dtr4 = msg_port_read(MEM_CTLR, DTR4);
tck = t_ck[mrc_params->ddr_speed]; /* Clock in picoseconds */
tcl = mrc_params->params.cl; /* CAS latency in clocks */
trp = tcl; /* Per CAT MRC */
trcd = tcl; /* Per CAT MRC */
tras = MCEIL(mrc_params->params.ras, tck);
/* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
twr = MCEIL(15000, tck);
twtr = MCEIL(mrc_params->params.wtr, tck);
trrd = MCEIL(mrc_params->params.rrd, tck);
trtp = 4; /* Valid for 800 and 1066, use 5 for 1333 */
tfaw = MCEIL(mrc_params->params.faw, tck);
wl = 5 + mrc_params->ddr_speed;
dtr0 &= ~(BIT0 | BIT1);
dtr0 |= mrc_params->ddr_speed;
dtr0 &= ~(BIT12 | BIT13 | BIT14);
tmp1 = tcl - 5;
dtr0 |= ((tcl - 5) << 12);
dtr0 &= ~(BIT4 | BIT5 | BIT6 | BIT7);
dtr0 |= ((trp - 5) << 4); /* 5 bit DRAM Clock */
dtr0 &= ~(BIT8 | BIT9 | BIT10 | BIT11);
dtr0 |= ((trcd - 5) << 8); /* 5 bit DRAM Clock */
dtr1 &= ~(BIT0 | BIT1 | BIT2);
tmp2 = wl - 3;
dtr1 |= (wl - 3);
dtr1 &= ~(BIT8 | BIT9 | BIT10 | BIT11);
dtr1 |= ((wl + 4 + twr - 14) << 8); /* Change to tWTP */
dtr1 &= ~(BIT28 | BIT29 | BIT30);
dtr1 |= ((MMAX(trtp, 4) - 3) << 28); /* 4 bit DRAM Clock */
dtr1 &= ~(BIT24 | BIT25);
dtr1 |= ((trrd - 4) << 24); /* 4 bit DRAM Clock */
dtr1 &= ~(BIT4 | BIT5);
dtr1 |= (1 << 4);
dtr1 &= ~(BIT20 | BIT21 | BIT22 | BIT23);
dtr1 |= ((tras - 14) << 20); /* 6 bit DRAM Clock */
dtr1 &= ~(BIT16 | BIT17 | BIT18 | BIT19);
dtr1 |= ((((tfaw + 1) >> 1) - 5) << 16);/* 4 bit DRAM Clock */
/* Set 4 Clock CAS to CAS delay (multi-burst) */
dtr1 &= ~(BIT12 | BIT13);
dtr2 &= ~(BIT0 | BIT1 | BIT2);
dtr2 |= 1;
dtr2 &= ~(BIT8 | BIT9 | BIT10);
dtr2 |= (2 << 8);
dtr2 &= ~(BIT16 | BIT17 | BIT18 | BIT19);
dtr2 |= (2 << 16);
dtr3 &= ~(BIT0 | BIT1 | BIT2);
dtr3 |= 2;
dtr3 &= ~(BIT4 | BIT5 | BIT6);
dtr3 |= (2 << 4);
dtr3 &= ~(BIT8 | BIT9 | BIT10 | BIT11);
if (mrc_params->ddr_speed == DDRFREQ_800) {
/* Extended RW delay (+1) */
dtr3 |= ((tcl - 5 + 1) << 8);
} else if (mrc_params->ddr_speed == DDRFREQ_1066) {
/* Extended RW delay (+1) */
dtr3 |= ((tcl - 5 + 1) << 8);
}
dtr3 &= ~(BIT13 | BIT14 | BIT15 | BIT16);
dtr3 |= ((4 + wl + twtr - 11) << 13);
dtr3 &= ~(BIT22 | BIT23);
if (mrc_params->ddr_speed == DDRFREQ_800)
dtr3 |= ((MMAX(0, 1 - 1)) << 22);
else
dtr3 |= ((MMAX(0, 2 - 1)) << 22);
dtr4 &= ~(BIT0 | BIT1);
dtr4 |= 1;
dtr4 &= ~(BIT4 | BIT5 | BIT6);
dtr4 |= (1 << 4);
dtr4 &= ~(BIT8 | BIT9 | BIT10);
dtr4 |= ((1 + tmp1 - tmp2 + 2) << 8);
dtr4 &= ~(BIT12 | BIT13 | BIT14);
dtr4 |= ((1 + tmp1 - tmp2 + 2) << 12);
dtr4 &= ~(BIT15 | BIT16);
msg_port_write(MEM_CTLR, DTR0, dtr0);
msg_port_write(MEM_CTLR, DTR1, dtr1);
msg_port_write(MEM_CTLR, DTR2, dtr2);
msg_port_write(MEM_CTLR, DTR3, dtr3);
msg_port_write(MEM_CTLR, DTR4, dtr4);
This bit stuff is a mess. It obscures the meaning IMO and we would be much better off with proper named #defines. What can we do here?
I agree it is a mess. To me DDR memory intialization itself is a black magic, with complicated hardware technology so we get ugly software codes in accompany with :( The MRC codes is a collection of analog electronics that are more similar to radio oscillators than to digital circuits appear to be a digital domain memory controller... These register fields are pure DDR timing numbers. I cannot find a better way of doing that, thus leave this unchanged in v2.
LEAVEFN();
+}
+/* Configure MCU before jedec init sequence */ +void prog_decode_before_jedec(struct mrc_params *mrc_params) +{
u32 drp;
u32 drfc;
u32 dcal;
u32 dsch;
u32 dpmc0;
ENTERFN();
/* Disable power saving features */
dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
dpmc0 |= (BIT24 | BIT25);
dpmc0 &= ~(BIT16 | BIT17 | BIT18);
dpmc0 &= ~BIT23;
msg_port_write(MEM_CTLR, DPMC0, dpmc0);
/* Disable out of order transactions */
dsch = msg_port_read(MEM_CTLR, DSCH);
dsch |= (BIT8 | BIT12);
msg_port_write(MEM_CTLR, DSCH, dsch);
/* Disable issuing the REF command */
drfc = msg_port_read(MEM_CTLR, DRFC);
drfc &= ~(BIT12 | BIT13 | BIT14);
msg_port_write(MEM_CTLR, DRFC, drfc);
/* Disable ZQ calibration short */
dcal = msg_port_read(MEM_CTLR, DCAL);
dcal &= ~(BIT8 | BIT9 | BIT10);
dcal &= ~(BIT12 | BIT13);
msg_port_write(MEM_CTLR, DCAL, dcal);
/*
* Training performed in address mode 0, rank population has limited
* impact, however simulator complains if enabled non-existing rank.
*/
drp = 0;
if (mrc_params->rank_enables & 1)
drp |= BIT0;
if (mrc_params->rank_enables & 2)
drp |= BIT1;
msg_port_write(MEM_CTLR, DRP, drp);
LEAVEFN();
+}
+/*
- After Cold Reset, BIOS should set COLDWAKE bit to 1 before
- sending the WAKE message to the Dunit.
- For Standby Exit, or any other mode in which the DRAM is in
- SR, this bit must be set to 0.
- */
+void perform_ddr_reset(struct mrc_params *mrc_params) +{
ENTERFN();
/* Set COLDWAKE bit before sending the WAKE message */
mrc_write_mask(MEM_CTLR, DRMC, BIT16, BIT16);
/* Send wake command to DUNIT (MUST be done before JEDEC) */
dram_wake_command();
/* Set default value */
msg_port_write(MEM_CTLR, DRMC,
(mrc_params->rd_odt_value == 0 ? BIT12 : 0));
LEAVEFN();
+}
+/*
- This function performs some initialization on the DDRIO unit.
- This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
- */
+void ddrphy_init(struct mrc_params *mrc_params) +{
uint32_t temp;
uint8_t ch; /* channel counter */
uint8_t rk; /* rank counter */
uint8_t bl_grp; /* byte lane group counter (2 BLs per module) */
uint8_t bl_divisor = 1; /* byte lane divisor */
/* For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 */
uint8_t speed = mrc_params->ddr_speed & (BIT1 | BIT0);
uint8_t cas;
uint8_t cwl;
ENTERFN();
cas = mrc_params->params.cl;
cwl = 5 + mrc_params->ddr_speed;
/* ddrphy_init starts */
mrc_post_code(0x03, 0x00);
/*
* HSD#231531
* Make sure IOBUFACT is deasserted before initializing the DDR PHY
*
* HSD#234845
* Make sure WRPTRENABLE is deasserted before initializing the DDR PHY
*/
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* Deassert DDRPHY Initialization Complete */
mrc_alt_write_mask(DDRPHY,
(CMDPMCONFIG0 + (ch * DDRIOCCC_CH_OFFSET)),
~BIT20, BIT20); /* SPID_INIT_COMPLETE=0 */
/* Deassert IOBUFACT */
mrc_alt_write_mask(DDRPHY,
(CMDCFGREG0 + (ch * DDRIOCCC_CH_OFFSET)),
~BIT2, BIT2); /* IOBUFACTRST_N=0 */
/* Disable WRPTR */
mrc_alt_write_mask(DDRPHY,
(CMDPTRREG + (ch * DDRIOCCC_CH_OFFSET)),
~BIT0, BIT0); /* WRPTRENABLE=0 */
}
}
/* Put PHY in reset */
mrc_alt_write_mask(DDRPHY, MASTERRSTN, 0, BIT0);
/* Initialize DQ01, DQ23, CMD, CLK-CTL, COMP modules */
/* STEP0 */
Can you put each step in its own static function?
for (ch = 0; ch < NUM_CHANNELS; ch++) step0(ch); for (ch = 0; ch < NUM_CHANNELS; ch++) step1(ch);
etc.
I am afraid it is not that simple. We need pass lots of variable to these static functions as parameters. I feel it does no good, instead creating possiblity of breaking the MRC, thus I left it unchanged.
mrc_post_code(0x03, 0x10);
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* DQ01-DQ23 */
for (bl_grp = 0;
bl_grp < ((NUM_BYTE_LANES / bl_divisor)/2);
bl_grp++) {
/* Analog MUX select - IO2xCLKSEL */
mrc_alt_write_mask(DDRPHY,
(DQOBSCKEBBCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
((bl_grp) ? (0x00) : (BIT22)), (BIT22));
/* ODT Strength */
switch (mrc_params->rd_odt_value) {
case 1:
temp = 0x3;
break; /* 60 ohm */
case 2:
temp = 0x3;
break; /* 120 ohm */
case 3:
temp = 0x3;
break; /* 180 ohm */
default:
temp = 0x3;
break; /* 120 ohm */
}
/* ODT strength */
mrc_alt_write_mask(DDRPHY,
(B0RXIOBUFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(temp << 5), (BIT6 | BIT5));
/* ODT strength */
mrc_alt_write_mask(DDRPHY,
(B1RXIOBUFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(temp << 5), (BIT6 | BIT5));
/* Dynamic ODT/DIFFAMP */
temp = (((cas) << 24) | ((cas) << 16) |
((cas) << 8) | ((cas) << 0));
switch (speed) {
case 0:
temp -= 0x01010101;
break; /* 800 */
case 1:
temp -= 0x02020202;
break; /* 1066 */
case 2:
temp -= 0x03030303;
break; /* 1333 */
case 3:
temp -= 0x04040404;
break; /* 1600 */
}
/* Launch Time: ODT, DIFFAMP, ODT, DIFFAMP */
mrc_alt_write_mask(DDRPHY,
(B01LATCTL1 +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
temp,
(BIT28 | BIT27 | BIT26 | BIT25 | BIT24 |
BIT20 | BIT19 | BIT18 | BIT17 | BIT16 |
BIT12 | BIT11 | BIT10 | BIT9 | BIT8 |
BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
switch (speed) {
/* HSD#234715 */
case 0:
temp = ((0x06 << 16) | (0x07 << 8));
break; /* 800 */
case 1:
temp = ((0x07 << 16) | (0x08 << 8));
break; /* 1066 */
case 2:
temp = ((0x09 << 16) | (0x0A << 8));
break; /* 1333 */
case 3:
temp = ((0x0A << 16) | (0x0B << 8));
break; /* 1600 */
}
/* On Duration: ODT, DIFFAMP */
mrc_alt_write_mask(DDRPHY,
(B0ONDURCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
temp,
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT13 | BIT12 | BIT11 | BIT10 |
BIT9 | BIT8));
/* On Duration: ODT, DIFFAMP */
mrc_alt_write_mask(DDRPHY,
(B1ONDURCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
temp,
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT13 | BIT12 | BIT11 | BIT10 |
BIT9 | BIT8));
switch (mrc_params->rd_odt_value) {
case 0:
/* override DIFFAMP=on, ODT=off */
temp = ((0x3F << 16) | (0x3f << 10));
break;
default:
/* override DIFFAMP=on, ODT=on */
temp = ((0x3F << 16) | (0x2A << 10));
break;
}
/* Override: DIFFAMP, ODT */
mrc_alt_write_mask(DDRPHY,
(B0OVRCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
temp,
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT15 | BIT14 | BIT13 | BIT12 |
BIT11 | BIT10));
/* Override: DIFFAMP, ODT */
mrc_alt_write_mask(DDRPHY,
(B1OVRCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
temp,
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT15 | BIT14 | BIT13 | BIT12 |
BIT11 | BIT10));
/* DLL Setup */
/* 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) */
mrc_alt_write_mask(DDRPHY,
(B0LATCTL0 +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(((cas + 7) << 16) | ((cas - 4) << 8) |
((cwl - 2) << 0)),
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT12 | BIT11 | BIT10 | BIT9 |
BIT8 | BIT4 | BIT3 | BIT2 | BIT1 |
BIT0));
mrc_alt_write_mask(DDRPHY,
(B1LATCTL0 +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(((cas + 7) << 16) | ((cas - 4) << 8) |
((cwl - 2) << 0)),
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT12 | BIT11 | BIT10 | BIT9 |
BIT8 | BIT4 | BIT3 | BIT2 | BIT1 |
BIT0));
/* RCVEN Bypass (PO) */
mrc_alt_write_mask(DDRPHY,
(B0RXIOBUFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
((0x0 << 7) | (0x0 << 0)),
(BIT7 | BIT0));
mrc_alt_write_mask(DDRPHY,
(B1RXIOBUFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
((0x0 << 7) | (0x0 << 0)),
(BIT7 | BIT0));
/* TX */
mrc_alt_write_mask(DDRPHY,
(DQCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(BIT16), (BIT16));
mrc_alt_write_mask(DDRPHY,
(B01PTRCTL1 +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(BIT8), (BIT8));
/* RX (PO) */
/* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
mrc_alt_write_mask(DDRPHY,
(B0VREFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
((0x03 << 2) | (0x0 << 1) | (0x0 << 0)),
(BIT7 | BIT6 | BIT5 | BIT4 | BIT3 |
BIT2 | BIT1 | BIT0));
/* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
mrc_alt_write_mask(DDRPHY,
(B1VREFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
((0x03 << 2) | (0x0 << 1) | (0x0 << 0)),
(BIT7 | BIT6 | BIT5 | BIT4 | BIT3 |
BIT2 | BIT1 | BIT0));
/* Per-Bit De-Skew Enable */
mrc_alt_write_mask(DDRPHY,
(B0RXIOBUFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(0), (BIT4));
/* Per-Bit De-Skew Enable */
mrc_alt_write_mask(DDRPHY,
(B1RXIOBUFCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(0), (BIT4));
}
/* CLKEBB */
mrc_alt_write_mask(DDRPHY,
(CMDOBSCKEBBCTL + (ch * DDRIOCCC_CH_OFFSET)),
0, (BIT23));
/* Enable tristate control of cmd/address bus */
mrc_alt_write_mask(DDRPHY,
(CMDCFGREG0 + (ch * DDRIOCCC_CH_OFFSET)),
0, (BIT1 | BIT0));
/* ODT RCOMP */
mrc_alt_write_mask(DDRPHY,
(CMDRCOMPODT + (ch * DDRIOCCC_CH_OFFSET)),
((0x03 << 5) | (0x03 << 0)),
(BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 |
BIT3 | BIT2 | BIT1 | BIT0));
/* CMDPM* registers must be programmed in this order */
/* Turn On Delays: SFR (regulator), MPLL */
mrc_alt_write_mask(DDRPHY,
(CMDPMDLYREG4 + (ch * DDRIOCCC_CH_OFFSET)),
((0xFFFFU << 16) | (0xFFFF << 0)),
0xFFFFFFFF);
/*
* Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3,
* VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT
* for_PM_MSG_gt0, MDLL Turn On
*/
mrc_alt_write_mask(DDRPHY,
(CMDPMDLYREG3 + (ch * DDRIOCCC_CH_OFFSET)),
((0xFU << 28) | (0xFFF << 16) | (0xF << 12) |
(0x616 << 0)), 0xFFFFFFFF);
/* MPLL Divider Reset Delays */
mrc_alt_write_mask(DDRPHY,
(CMDPMDLYREG2 + (ch * DDRIOCCC_CH_OFFSET)),
((0xFFU << 24) | (0xFF << 16) | (0xFF << 8) |
(0xFF << 0)), 0xFFFFFFFF);
/* Turn Off Delays: VREG, Staggered MDLL, MDLL, PI */
mrc_alt_write_mask(DDRPHY,
(CMDPMDLYREG1 + (ch * DDRIOCCC_CH_OFFSET)),
((0xFFU << 24) | (0xFF << 16) | (0xFF << 8) |
(0xFF << 0)), 0xFFFFFFFF);
/* Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT */
mrc_alt_write_mask(DDRPHY,
(CMDPMDLYREG0 + (ch * DDRIOCCC_CH_OFFSET)),
((0xFFU << 24) | (0xFF << 16) | (0xFF << 8) |
(0xFF << 0)), 0xFFFFFFFF);
/* Allow PUnit signals */
mrc_alt_write_mask(DDRPHY,
(CMDPMCONFIG0 + (ch * DDRIOCCC_CH_OFFSET)),
((0x6 << 8) | BIT6 | (0x4 << 0)),
(BIT31 | BIT30 | BIT29 | BIT28 | BIT27 | BIT26 |
BIT25 | BIT24 | BIT23 | BIT22 | BIT21 | BIT11 |
BIT10 | BIT9 | BIT8 | BIT6 | BIT3 | BIT2 |
BIT1 | BIT0));
/* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
mrc_alt_write_mask(DDRPHY,
(CMDMDLLCTL + (ch * DDRIOCCC_CH_OFFSET)),
((0x3 << 4) | (0x7 << 0)),
(BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 |
BIT0));
/* CLK-CTL */
mrc_alt_write_mask(DDRPHY,
(CCOBSCKEBBCTL + (ch * DDRIOCCC_CH_OFFSET)),
0, BIT24); /* CLKEBB */
/* Buffer Enable: CS,CKE,ODT,CLK */
mrc_alt_write_mask(DDRPHY,
(CCCFGREG0 + (ch * DDRIOCCC_CH_OFFSET)),
((0x0 << 16) | (0x0 << 12) | (0x0 << 8) |
(0xF << 4) | BIT0),
(BIT19 | BIT18 | BIT17 | BIT16 | BIT15 | BIT14 |
BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 |
BIT7 | BIT6 | BIT5 | BIT4 | BIT0));
/* ODT RCOMP */
mrc_alt_write_mask(DDRPHY,
(CCRCOMPODT + (ch * DDRIOCCC_CH_OFFSET)),
((0x03 << 8) | (0x03 << 0)),
(BIT12 | BIT11 | BIT10 | BIT9 | BIT8 | BIT4 |
BIT3 | BIT2 | BIT1 | BIT0));
/* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
mrc_alt_write_mask(DDRPHY,
(CCMDLLCTL + (ch * DDRIOCCC_CH_OFFSET)),
((0x3 << 4) | (0x7 << 0)),
(BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 |
BIT0));
/*
* COMP (RON channel specific)
* - DQ/DQS/DM RON: 32 Ohm
* - CTRL/CMD RON: 27 Ohm
* - CLK RON: 26 Ohm
*/
/* RCOMP Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(DQVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x08 << 24) | (0x03 << 16)),
(BIT29 | BIT28 | BIT27 | BIT26 | BIT25 |
BIT24 | BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16));
/* RCOMP Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(CMDVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x0C << 24) | (0x03 << 16)),
(BIT29 | BIT28 | BIT27 | BIT26 | BIT25 |
BIT24 | BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16));
/* RCOMP Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(CLKVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x0F << 24) | (0x03 << 16)),
(BIT29 | BIT28 | BIT27 | BIT26 | BIT25 |
BIT24 | BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16));
/* RCOMP Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(DQSVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x08 << 24) | (0x03 << 16)),
(BIT29 | BIT28 | BIT27 | BIT26 | BIT25 |
BIT24 | BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16));
/* RCOMP Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(CTLVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x0C << 24) | (0x03 << 16)),
(BIT29 | BIT28 | BIT27 | BIT26 | BIT25 |
BIT24 | BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16));
/* DQS Swapped Input Enable */
mrc_alt_write_mask(DDRPHY,
(COMPEN1CH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT19 | BIT17),
(BIT31 | BIT30 | BIT19 | BIT17 |
BIT15 | BIT14));
/* ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) */
/* ODT Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(DQVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x32 << 8) | (0x03 << 0)),
(BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 |
BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
/* ODT Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(DQSVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x32 << 8) | (0x03 << 0)),
(BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 |
BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
/* ODT Vref PU/PD */
mrc_alt_write_mask(DDRPHY,
(CLKVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x0E << 8) | (0x05 << 0)),
(BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 |
BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
/*
* Slew rate settings are frequency specific,
* numbers below are for 800Mhz (speed == 0)
* - DQ/DQS/DM/CLK SR: 4V/ns,
* - CTRL/CMD SR: 1.5V/ns
*/
temp = (0x0E << 16) | (0x0E << 12) | (0x08 << 8) |
(0x0B << 4) | (0x0B << 0);
/* DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ */
mrc_alt_write_mask(DDRPHY,
(DLYSELCH0 + (ch * DDRCOMP_CH_OFFSET)),
temp,
(BIT19 | BIT18 | BIT17 | BIT16 | BIT15 |
BIT14 | BIT13 | BIT12 | BIT11 | BIT10 |
BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 |
BIT3 | BIT2 | BIT1 | BIT0));
/* TCO Vref CLK,DQS,DQ */
mrc_alt_write_mask(DDRPHY,
(TCOVREFCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x05 << 16) | (0x05 << 8) | (0x05 << 0)),
(BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT13 | BIT12 | BIT11 | BIT10 |
BIT9 | BIT8 | BIT5 | BIT4 | BIT3 | BIT2 |
BIT1 | BIT0));
/* ODTCOMP CMD/CTL PU/PD */
mrc_alt_write_mask(DDRPHY,
(CCBUFODTCH0 + (ch * DDRCOMP_CH_OFFSET)),
((0x03 << 8) | (0x03 << 0)),
(BIT12 | BIT11 | BIT10 | BIT9 | BIT8 |
BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
/* COMP */
mrc_alt_write_mask(DDRPHY,
(COMPEN0CH0 + (ch * DDRCOMP_CH_OFFSET)),
0, (BIT31 | BIT30 | BIT8));
+#ifdef BACKUP_COMPS
/* DQ COMP Overrides */
/* RCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQDRVPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* RCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQDRVPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQDLYPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x10 << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQDLYPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x10 << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* ODTCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQODTPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* ODTCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQODTPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* TCOCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQTCOPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31), (BIT31));
/* TCOCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQTCOPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31), (BIT31));
/* DQS COMP Overrides */
/* RCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQSDRVPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* RCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQSDRVPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQSDLYPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x10 << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQSDLYPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x10 << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* ODTCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQSODTPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* ODTCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQSODTPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* TCOCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQSTCOPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31), (BIT31));
/* TCOCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQSTCOPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31), (BIT31));
/* CLK COMP Overrides */
/* RCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CLKDRVPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0C << 16)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* RCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CLKDRVPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0C << 16)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CLKDLYPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x07 << 16)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CLKDLYPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x07 << 16)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* ODTCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CLKODTPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0B << 16)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* ODTCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CLKODTPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0B << 16)),
(BIT31 | (0x0B << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* TCOCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CLKTCOPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31), (BIT31));
/* TCOCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CLKTCOPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31), (BIT31));
/* CMD COMP Overrides */
/* RCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CMDDRVPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0D << 16)),
(BIT31 | BIT21 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* RCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CMDDRVPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0D << 16)),
(BIT31 | BIT21 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CMDDLYPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CMDDLYPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* CTL COMP Overrides */
/* RCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CTLDRVPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0D << 16)),
(BIT31 | BIT21 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* RCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CTLDRVPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0D << 16)),
(BIT31 | BIT21 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CTLDLYPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CTLDLYPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x0A << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
+#else
/* DQ TCOCOMP Overrides */
/* TCOCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQTCOPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x1F << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* TCOCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQTCOPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x1F << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* DQS TCOCOMP Overrides */
/* TCOCOMP PU */
mrc_alt_write_mask(DDRPHY,
(DQSTCOPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x1F << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* TCOCOMP PD */
mrc_alt_write_mask(DDRPHY,
(DQSTCOPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x1F << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* CLK TCOCOMP Overrides */
/* TCOCOMP PU */
mrc_alt_write_mask(DDRPHY,
(CLKTCOPUCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x1F << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
/* TCOCOMP PD */
mrc_alt_write_mask(DDRPHY,
(CLKTCOPDCTLCH0 + (ch * DDRCOMP_CH_OFFSET)),
(BIT31 | (0x1F << 16)),
(BIT31 | BIT20 | BIT19 |
BIT18 | BIT17 | BIT16));
+#endif
/* program STATIC delays */
+#ifdef BACKUP_WCMD
set_wcmd(ch, ddr_wcmd[PLATFORM_ID]);
+#else
set_wcmd(ch, ddr_wclk[PLATFORM_ID] + HALF_CLK);
+#endif
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1<<rk)) {
set_wclk(ch, rk, ddr_wclk[PLATFORM_ID]);
+#ifdef BACKUP_WCTL
set_wctl(ch, rk, ddr_wctl[PLATFORM_ID]);
+#else
set_wctl(ch, rk, ddr_wclk[PLATFORM_ID] + HALF_CLK);
+#endif
}
}
}
}
/* COMP (non channel specific) */
/* RCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQANADRVPUCTL), (BIT30), (BIT30));
/* RCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQANADRVPDCTL), (BIT30), (BIT30));
/* RCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CMDANADRVPUCTL), (BIT30), (BIT30));
/* RCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CMDANADRVPDCTL), (BIT30), (BIT30));
/* RCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CLKANADRVPUCTL), (BIT30), (BIT30));
/* RCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CLKANADRVPDCTL), (BIT30), (BIT30));
/* RCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQSANADRVPUCTL), (BIT30), (BIT30));
/* RCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQSANADRVPDCTL), (BIT30), (BIT30));
/* RCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CTLANADRVPUCTL), (BIT30), (BIT30));
/* RCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CTLANADRVPDCTL), (BIT30), (BIT30));
/* ODT: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQANAODTPUCTL), (BIT30), (BIT30));
/* ODT: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQANAODTPDCTL), (BIT30), (BIT30));
/* ODT: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CLKANAODTPUCTL), (BIT30), (BIT30));
/* ODT: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CLKANAODTPDCTL), (BIT30), (BIT30));
/* ODT: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQSANAODTPUCTL), (BIT30), (BIT30));
/* ODT: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQSANAODTPDCTL), (BIT30), (BIT30));
/* DCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQANADLYPUCTL), (BIT30), (BIT30));
/* DCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQANADLYPDCTL), (BIT30), (BIT30));
/* DCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CMDANADLYPUCTL), (BIT30), (BIT30));
/* DCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CMDANADLYPDCTL), (BIT30), (BIT30));
/* DCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CLKANADLYPUCTL), (BIT30), (BIT30));
/* DCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CLKANADLYPDCTL), (BIT30), (BIT30));
/* DCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQSANADLYPUCTL), (BIT30), (BIT30));
/* DCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQSANADLYPDCTL), (BIT30), (BIT30));
/* DCOMP: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CTLANADLYPUCTL), (BIT30), (BIT30));
/* DCOMP: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CTLANADLYPDCTL), (BIT30), (BIT30));
/* TCO: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQANATCOPUCTL), (BIT30), (BIT30));
/* TCO: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQANATCOPDCTL), (BIT30), (BIT30));
/* TCO: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (CLKANATCOPUCTL), (BIT30), (BIT30));
/* TCO: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (CLKANATCOPDCTL), (BIT30), (BIT30));
/* TCO: Dither PU Enable */
mrc_alt_write_mask(DDRPHY, (DQSANATCOPUCTL), (BIT30), (BIT30));
/* TCO: Dither PD Enable */
mrc_alt_write_mask(DDRPHY, (DQSANATCOPDCTL), (BIT30), (BIT30));
/* TCOCOMP: Pulse Count */
mrc_alt_write_mask(DDRPHY, (TCOCNTCTRL), (0x1<<0), (BIT1|BIT0));
/* ODT: CMD/CTL PD/PU */
mrc_alt_write_mask(DDRPHY,
(CHNLBUFSTATIC), ((0x03<<24)|(0x03<<16)),
(BIT28 | BIT27 | BIT26 | BIT25 | BIT24 |
BIT20 | BIT19 | BIT18 | BIT17 | BIT16));
/* Set 1us counter */
mrc_alt_write_mask(DDRPHY,
(MSCNTR), (0x64 << 0),
(BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
mrc_alt_write_mask(DDRPHY,
(LATCH1CTL), (0x1 << 28),
(BIT30 | BIT29 | BIT28));
/* Release PHY from reset */
mrc_alt_write_mask(DDRPHY, MASTERRSTN, BIT0, BIT0);
/* STEP1 */
mrc_post_code(0x03, 0x11);
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* DQ01-DQ23 */
for (bl_grp = 0;
bl_grp < ((NUM_BYTE_LANES / bl_divisor) / 2);
bl_grp++) {
mrc_alt_write_mask(DDRPHY,
(DQMDLLCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(BIT13),
(BIT13)); /* Enable VREG */
delay_n(3);
}
/* ECC */
mrc_alt_write_mask(DDRPHY, (ECCMDLLCTL),
(BIT13), (BIT13)); /* Enable VREG */
delay_n(3);
/* CMD */
mrc_alt_write_mask(DDRPHY,
(CMDMDLLCTL + (ch * DDRIOCCC_CH_OFFSET)),
(BIT13), (BIT13)); /* Enable VREG */
delay_n(3);
/* CLK-CTL */
mrc_alt_write_mask(DDRPHY,
(CCMDLLCTL + (ch * DDRIOCCC_CH_OFFSET)),
(BIT13), (BIT13)); /* Enable VREG */
delay_n(3);
}
}
/* STEP2 */
mrc_post_code(0x03, 0x12);
delay_n(200);
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* DQ01-DQ23 */
for (bl_grp = 0;
bl_grp < ((NUM_BYTE_LANES / bl_divisor) / 2);
bl_grp++) {
mrc_alt_write_mask(DDRPHY,
(DQMDLLCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(BIT17),
(BIT17)); /* Enable MCDLL */
delay_n(50);
}
/* ECC */
mrc_alt_write_mask(DDRPHY, (ECCMDLLCTL),
(BIT17), (BIT17)); /* Enable MCDLL */
delay_n(50);
/* CMD */
mrc_alt_write_mask(DDRPHY,
(CMDMDLLCTL + (ch * DDRIOCCC_CH_OFFSET)),
(BIT18), (BIT18)); /* Enable MCDLL */
delay_n(50);
/* CLK-CTL */
mrc_alt_write_mask(DDRPHY,
(CCMDLLCTL + (ch * DDRIOCCC_CH_OFFSET)),
(BIT18), (BIT18)); /* Enable MCDLL */
delay_n(50);
}
}
/* STEP3: */
mrc_post_code(0x03, 0x13);
delay_n(100);
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* DQ01-DQ23 */
for (bl_grp = 0;
bl_grp < ((NUM_BYTE_LANES / bl_divisor) / 2);
bl_grp++) {
+#ifdef FORCE_16BIT_DDRIO
temp = ((bl_grp) &&
(mrc_params->channel_width == X16)) ?
((0x1 << 12) | (0x1 << 8) |
(0xF << 4) | (0xF << 0)) :
((0xF << 12) | (0xF << 8) |
(0xF << 4) | (0xF << 0));
+#else
temp = ((0xF << 12) | (0xF << 8) |
(0xF << 4) | (0xF << 0));
+#endif
/* Enable TXDLL */
mrc_alt_write_mask(DDRPHY,
(DQDLLTXCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
temp, 0xFFFF);
delay_n(3);
/* Enable RXDLL */
mrc_alt_write_mask(DDRPHY,
(DQDLLRXCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(BIT3 | BIT2 | BIT1 | BIT0),
(BIT3 | BIT2 | BIT1 | BIT0));
delay_n(3);
/* Enable RXDLL Overrides BL0 */
mrc_alt_write_mask(DDRPHY,
(B0OVRCTL +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(BIT3 | BIT2 | BIT1 | BIT0),
(BIT3 | BIT2 | BIT1 | BIT0));
}
/* ECC */
temp = ((0xF << 12) | (0xF << 8) |
(0xF << 4) | (0xF << 0));
mrc_alt_write_mask(DDRPHY, (ECCDLLTXCTL),
temp, 0xFFFF);
delay_n(3);
/* CMD (PO) */
mrc_alt_write_mask(DDRPHY,
(CMDDLLTXCTL + (ch * DDRIOCCC_CH_OFFSET)),
temp, 0xFFFF);
delay_n(3);
}
}
/* STEP4 */
mrc_post_code(0x03, 0x14);
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* Host To Memory Clock Alignment (HMC) for 800/1066 */
for (bl_grp = 0;
bl_grp < ((NUM_BYTE_LANES / bl_divisor) / 2);
bl_grp++) {
/* CLK_ALIGN_MOD_ID */
mrc_alt_write_mask(DDRPHY,
(DQCLKALIGNREG2 +
(bl_grp * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
(bl_grp) ? (0x3) : (0x1),
(BIT3 | BIT2 | BIT1 | BIT0));
}
mrc_alt_write_mask(DDRPHY,
(ECCCLKALIGNREG2 + (ch * DDRIODQ_CH_OFFSET)),
0x2,
(BIT3 | BIT2 | BIT1 | BIT0));
mrc_alt_write_mask(DDRPHY,
(CMDCLKALIGNREG2 + (ch * DDRIODQ_CH_OFFSET)),
0x0,
(BIT3 | BIT2 | BIT1 | BIT0));
mrc_alt_write_mask(DDRPHY,
(CCCLKALIGNREG2 + (ch * DDRIODQ_CH_OFFSET)),
0x2,
(BIT3 | BIT2 | BIT1 | BIT0));
mrc_alt_write_mask(DDRPHY,
(CMDCLKALIGNREG0 + (ch * DDRIOCCC_CH_OFFSET)),
(0x2 << 4), (BIT5 | BIT4));
/*
* NUM_SAMPLES, MAX_SAMPLES,
* MACRO_PI_STEP, MICRO_PI_STEP
*/
mrc_alt_write_mask(DDRPHY,
(CMDCLKALIGNREG1 + (ch * DDRIOCCC_CH_OFFSET)),
((0x18 << 16) | (0x10 << 8) |
(0x8 << 2) | (0x1 << 0)),
(BIT22 | BIT21 | BIT20 | BIT19 | BIT18 | BIT17 |
BIT16 | BIT14 | BIT13 | BIT12 | BIT11 | BIT10 |
BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 |
BIT2 | BIT1 | BIT0));
/* TOTAL_NUM_MODULES, FIRST_U_PARTITION */
mrc_alt_write_mask(DDRPHY,
(CMDCLKALIGNREG2 + (ch * DDRIOCCC_CH_OFFSET)),
((0x10 << 16) | (0x4 << 8) | (0x2 << 4)),
(BIT20 | BIT19 | BIT18 | BIT17 | BIT16 |
BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 |
BIT5 | BIT4));
+#ifdef HMC_TEST
/* START_CLK_ALIGN=1 */
mrc_alt_write_mask(DDRPHY,
(CMDCLKALIGNREG0 + (ch * DDRIOCCC_CH_OFFSET)),
BIT24, BIT24);
while (msg_port_alt_read(DDRPHY,
(CMDCLKALIGNREG0 + (ch * DDRIOCCC_CH_OFFSET))) &
BIT24)
; /* wait for START_CLK_ALIGN=0 */
+#endif
/* Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN */
mrc_alt_write_mask(DDRPHY,
(CMDPTRREG + (ch * DDRIOCCC_CH_OFFSET)),
BIT0, BIT0); /* WRPTRENABLE=1 */
/* COMP initial */
/* enable bypass for CLK buffer (PO) */
mrc_alt_write_mask(DDRPHY,
(COMPEN0CH0 + (ch * DDRCOMP_CH_OFFSET)),
BIT5, BIT5);
/* Initial COMP Enable */
mrc_alt_write_mask(DDRPHY, (CMPCTRL),
(BIT0), (BIT0));
/* wait for Initial COMP Enable = 0 */
while (msg_port_alt_read(DDRPHY, (CMPCTRL)) & BIT0)
;
/* disable bypass for CLK buffer (PO) */
mrc_alt_write_mask(DDRPHY,
(COMPEN0CH0 + (ch * DDRCOMP_CH_OFFSET)),
~BIT5, BIT5);
/* IOBUFACT */
/* STEP4a */
mrc_alt_write_mask(DDRPHY,
(CMDCFGREG0 + (ch * DDRIOCCC_CH_OFFSET)),
BIT2, BIT2); /* IOBUFACTRST_N=1 */
/* DDRPHY initialisation complete */
mrc_alt_write_mask(DDRPHY,
(CMDPMCONFIG0 + (ch * DDRIOCCC_CH_OFFSET)),
BIT20, BIT20); /* SPID_INIT_COMPLETE=1 */
}
}
LEAVEFN();
+}
+/* This function performs JEDEC initialisation on all enabled channels */ +void perform_jedec_init(struct mrc_params *mrc_params) +{
uint8_t twr, wl, rank;
uint32_t tck;
u32 dtr0;
u32 drp;
u32 drmc;
u32 mrs0_cmd = 0;
u32 emrs1_cmd = 0;
u32 emrs2_cmd = 0;
u32 emrs3_cmd = 0;
ENTERFN();
/* jedec_init starts */
mrc_post_code(0x04, 0x00);
/* DDR3_RESET_SET=0, DDR3_RESET_RESET=1 */
mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, BIT1, (BIT8 | BIT1));
/* Assert RESET# for 200us */
delay_u(200);
/* DDR3_RESET_SET=1, DDR3_RESET_RESET=0 */
mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, BIT8, (BIT8 | BIT1));
dtr0 = msg_port_read(MEM_CTLR, DTR0);
/*
* Set CKEVAL for populated ranks
* then send NOP to each rank (#4550197)
*/
drp = msg_port_read(MEM_CTLR, DRP);
drp &= 0x3;
drmc = msg_port_read(MEM_CTLR, DRMC);
drmc &= 0xFFFFFFFC;
drmc |= (BIT4 | drp);
msg_port_write(MEM_CTLR, DRMC, drmc);
for (rank = 0; rank < NUM_RANKS; rank++) {
/* Skip to next populated rank */
if ((mrc_params->rank_enables & (1 << rank)) == 0)
continue;
dram_init_command(DCMD_NOP(rank));
}
msg_port_write(MEM_CTLR, DRMC,
(mrc_params->rd_odt_value == 0 ? BIT12 : 0));
/*
* setup for emrs 2
* BIT[15:11] --> Always "0"
* BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
* BIT[08] --> Always "0"
* BIT[07] --> SRT: use sr_temp_range
* BIT[06] --> ASR: want "Manual SR Reference" (0)
* BIT[05:03] --> CWL: use oem_tCWL
* BIT[02:00] --> PASR: want "Full Array" (0)
*/
emrs2_cmd |= (2 << 3);
wl = 5 + mrc_params->ddr_speed;
emrs2_cmd |= ((wl - 5) << 9);
emrs2_cmd |= (mrc_params->sr_temp_range << 13);
/*
* setup for emrs 3
* BIT[15:03] --> Always "0"
* BIT[02] --> MPR: want "Normal Operation" (0)
* BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
*/
emrs3_cmd |= (3 << 3);
/*
* setup for emrs 1
* BIT[15:13] --> Always "0"
* BIT[12:12] --> Qoff: want "Output Buffer Enabled" (0)
* BIT[11:11] --> TDQS: want "Disabled" (0)
* BIT[10:10] --> Always "0"
* BIT[09,06,02] --> Rtt_nom: use rtt_nom_value
* BIT[08] --> Always "0"
* BIT[07] --> WR_LVL: want "Disabled" (0)
* BIT[05,01] --> DIC: use ron_value
* BIT[04:03] --> AL: additive latency want "0" (0)
* BIT[00] --> DLL: want "Enable" (0)
*
* (BIT5|BIT1) set Ron value
* 00 --> RZQ/6 (40ohm)
* 01 --> RZQ/7 (34ohm)
* 1* --> RESERVED
*
* (BIT9|BIT6|BIT2) set Rtt_nom value
* 000 --> Disabled
* 001 --> RZQ/4 ( 60ohm)
* 010 --> RZQ/2 (120ohm)
* 011 --> RZQ/6 ( 40ohm)
* 1** --> RESERVED
*/
Why oh why not just have #defines for these? It seems like the original author knew they should be created but never made the step of actually doing it.
Again, undocumented in the Intel datasheet. I suspect it is something in the JEDEC DDR spec though. Did not change this in v2.
emrs1_cmd |= (1 << 3);
emrs1_cmd &= ~BIT6;
if (mrc_params->ron_value == 0)
emrs1_cmd |= BIT7;
else
emrs1_cmd &= ~BIT7;
if (mrc_params->rtt_nom_value == 0)
emrs1_cmd |= (DDR3_EMRS1_RTTNOM_40 << 6);
else if (mrc_params->rtt_nom_value == 1)
emrs1_cmd |= (DDR3_EMRS1_RTTNOM_60 << 6);
else if (mrc_params->rtt_nom_value == 2)
emrs1_cmd |= (DDR3_EMRS1_RTTNOM_120 << 6);
/* save MRS1 value (excluding control fields) */
mrc_params->mrs1 = emrs1_cmd >> 6;
/*
* setup for mrs 0
* BIT[15:13] --> Always "0"
* BIT[12] --> PPD: for Quark (1)
* BIT[11:09] --> WR: use oem_tWR
* BIT[08] --> DLL: want "Reset" (1, self clearing)
* BIT[07] --> MODE: want "Normal" (0)
* BIT[06:04,02] --> CL: use oem_tCAS
* BIT[03] --> RD_BURST_TYPE: want "Interleave" (1)
* BIT[01:00] --> BL: want "8 Fixed" (0)
* WR:
* 0 --> 16
* 1 --> 5
* 2 --> 6
* 3 --> 7
* 4 --> 8
* 5 --> 10
* 6 --> 12
* 7 --> 14
* CL:
* BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
* BIT[06:04] use oem_tCAS-4
*/
mrs0_cmd |= BIT14;
mrs0_cmd |= BIT18;
mrs0_cmd |= ((((dtr0 >> 12) & 7) + 1) << 10);
tck = t_ck[mrc_params->ddr_speed];
/* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
twr = MCEIL(15000, tck);
mrs0_cmd |= ((twr - 4) << 15);
for (rank = 0; rank < NUM_RANKS; rank++) {
/* Skip to next populated rank */
if ((mrc_params->rank_enables & (1 << rank)) == 0)
continue;
emrs2_cmd |= (rank << 22);
dram_init_command(emrs2_cmd);
emrs3_cmd |= (rank << 22);
dram_init_command(emrs3_cmd);
emrs1_cmd |= (rank << 22);
dram_init_command(emrs1_cmd);
mrs0_cmd |= (rank << 22);
dram_init_command(mrs0_cmd);
dram_init_command(DCMD_ZQCL(rank));
}
LEAVEFN();
+}
+/*
- Dunit Initialisation Complete
- Indicates that initialisation of the Dunit has completed.
- Memory accesses are permitted and maintenance operation begins.
- Until this bit is set to a 1, the memory controller will not accept
- DRAM requests from the MEMORY_MANAGER or HTE.
- */
+void set_ddr_init_complete(struct mrc_params *mrc_params) +{
u32 dco;
ENTERFN();
dco = msg_port_read(MEM_CTLR, DCO);
dco &= ~BIT28;
dco |= BIT31;
msg_port_write(MEM_CTLR, DCO, dco);
LEAVEFN();
+}
+/*
- This function will retrieve relevant timing data
- This data will be used on subsequent boots to speed up boot times
- and is required for Suspend To RAM capabilities.
- */
+void restore_timings(struct mrc_params *mrc_params) +{
uint8_t ch, rk, bl;
const struct mrc_timings *mt = &mrc_params->timings;
for (ch = 0; ch < NUM_CHANNELS; ch++) {
for (rk = 0; rk < NUM_RANKS; rk++) {
for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]);
set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]);
set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]);
set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);
if (rk == 0) {
/* VREF (RANK0 only) */
set_vref(ch, bl, mt->vref[ch][bl]);
}
}
set_wctl(ch, rk, mt->wctl[ch][rk]);
}
set_wcmd(ch, mt->wcmd[ch]);
}
+}
+/*
- Configure default settings normally set as part of read training
- Some defaults have to be set earlier as they may affect earlier
- training steps.
- */
+void default_timings(struct mrc_params *mrc_params) +{
uint8_t ch, rk, bl;
for (ch = 0; ch < NUM_CHANNELS; ch++) {
for (rk = 0; rk < NUM_RANKS; rk++) {
for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
set_rdqs(ch, rk, bl, 24);
if (rk == 0) {
/* VREF (RANK0 only) */
set_vref(ch, bl, 32);
}
}
}
}
+}
+/*
- This function will perform our RCVEN Calibration Algorithm.
- We will only use the 2xCLK domain timings to perform RCVEN Calibration.
- All byte lanes will be calibrated "simultaneously" per channel per rank.
- */
+void rcvn_cal(struct mrc_params *mrc_params) +{
uint8_t ch; /* channel counter */
uint8_t rk; /* rank counter */
uint8_t bl; /* byte lane counter */
uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
+#ifdef R2R_SHARING
/* used to find placement for rank2rank sharing configs */
uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
+#ifndef BACKUP_RCVN
/* used to find placement for rank2rank sharing configs */
uint32_t num_ranks_enabled = 0;
+#endif +#endif
+#ifdef BACKUP_RCVN +#else
uint32_t temp;
/* absolute PI value to be programmed on the byte lane */
uint32_t delay[NUM_BYTE_LANES];
u32 dtr1, dtr1_save;
+#endif
ENTERFN();
/* rcvn_cal starts */
mrc_post_code(0x05, 0x00);
+#ifndef BACKUP_RCVN
/* need separate burst to sample DQS preamble */
dtr1 = msg_port_read(MEM_CTLR, DTR1);
dtr1_save = dtr1;
dtr1 |= BIT12;
msg_port_write(MEM_CTLR, DTR1, dtr1);
+#endif
+#ifdef R2R_SHARING
/* need to set "final_delay[][]" elements to "0" */
memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
+#endif
/* loop through each enabled channel */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* perform RCVEN Calibration on a per rank basis */
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
/*
* POST_CODE here indicates the current
* channel and rank being calibrated
*/
mrc_post_code(0x05, (0x10 + ((ch << 4) | rk)));
+#ifdef BACKUP_RCVN
/* et hard-coded timing values */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++)
set_rcvn(ch, rk, bl, ddr_rcvn[PLATFORM_ID]);
+#else
/* enable FIFORST */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
mrc_alt_write_mask(DDRPHY,
(B01PTRCTL1 +
((bl >> 1) * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
0, BIT8);
}
/* initialize the starting delay to 128 PI (cas +1 CLK) */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
/* 1x CLK domain timing is cas-4 */
delay[bl] = (4 + 1) * FULL_CLK;
set_rcvn(ch, rk, bl, delay[bl]);
}
/* now find the rising edge */
find_rising_edge(mrc_params, delay, ch, rk, true);
/* Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
delay[bl] += QRTR_CLK;
set_rcvn(ch, rk, bl, delay[bl]);
}
/* Now decrement delay by 128 PI (1 CLK) until we sample a "0" */
do {
temp = sample_dqs(mrc_params, ch, rk, true);
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
if (temp & (1 << bl)) {
if (delay[bl] >= FULL_CLK) {
delay[bl] -= FULL_CLK;
set_rcvn(ch, rk, bl, delay[bl]);
} else {
/* not enough delay */
training_message(ch, rk, bl);
mrc_post_code(0xEE, 0x50);
}
}
}
} while (temp & 0xFF);
+#ifdef R2R_SHARING
/* increment "num_ranks_enabled" */
num_ranks_enabled++;
/* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
delay[bl] += QRTR_CLK;
/* add "delay[]" values to "final_delay[][]" for rolling average */
final_delay[ch][bl] += delay[bl];
/* set timing based on rolling average values */
set_rcvn(ch, rk, bl, ((final_delay[ch][bl]) / num_ranks_enabled));
}
+#else
/* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
delay[bl] += QRTR_CLK;
set_rcvn(ch, rk, bl, delay[bl]);
}
+#endif
/* disable FIFORST */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
mrc_alt_write_mask(DDRPHY,
(B01PTRCTL1 +
((bl >> 1) * DDRIODQ_BL_OFFSET) +
(ch * DDRIODQ_CH_OFFSET)),
BIT8, BIT8);
}
+#endif
}
}
}
}
+#ifndef BACKUP_RCVN
/* restore original */
msg_port_write(MEM_CTLR, DTR1, dtr1_save);
+#endif
LEAVEFN();
+}
+/*
- This function will perform the Write Levelling algorithm
- (align WCLK and WDQS).
- This algorithm will act on each rank in each channel separately.
- */
+void wr_level(struct mrc_params *mrc_params) +{
uint8_t ch; /* channel counter */
uint8_t rk; /* rank counter */
uint8_t bl; /* byte lane counter */
uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
+#ifdef R2R_SHARING
/* used to find placement for rank2rank sharing configs */
uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
+#ifndef BACKUP_WDQS
/* used to find placement for rank2rank sharing configs */
uint32_t num_ranks_enabled = 0;
+#endif +#endif
+#ifdef BACKUP_WDQS +#else
/* determines stop condition for CRS_WR_LVL */
bool all_edges_found;
/* absolute PI value to be programmed on the byte lane */
uint32_t delay[NUM_BYTE_LANES];
/*
* static makes it so the data is loaded in the heap once by shadow(),
* where non-static copies the data onto the stack every time this
* function is called
*/
uint32_t address; /* address to be checked during COARSE_WR_LVL */
u32 dtr4, dtr4_save;
+#endif
ENTERFN();
/* wr_level starts */
mrc_post_code(0x06, 0x00);
+#ifdef R2R_SHARING
/* need to set "final_delay[][]" elements to "0" */
memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
+#endif
/* loop through each enabled channel */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
/* perform WRITE LEVELING algorithm on a per rank basis */
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
/*
* POST_CODE here indicates the current
* rank and channel being calibrated
*/
mrc_post_code(0x06, (0x10 + ((ch << 4) | rk)));
+#ifdef BACKUP_WDQS
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
set_wdqs(ch, rk, bl, ddr_wdqs[PLATFORM_ID]);
set_wdq(ch, rk, bl, (ddr_wdqs[PLATFORM_ID] - QRTR_CLK));
}
+#else
/*
* perform a single PRECHARGE_ALL command to
* make DRAM state machine go to IDLE state
*/
dram_init_command(DCMD_PREA(rk));
/*
* enable Write Levelling Mode
* (EMRS1 w/ Write Levelling Mode Enable)
*/
dram_init_command(DCMD_MRS1(rk, 0x0082));
/*
* set ODT DRAM Full Time Termination
* disable in MCU
*/
dtr4 = msg_port_read(MEM_CTLR, DTR4);
dtr4_save = dtr4;
dtr4 |= BIT15;
msg_port_write(MEM_CTLR, DTR4, dtr4);
for (bl = 0; bl < ((NUM_BYTE_LANES / bl_divisor) / 2); bl++) {
/*
* Enable Sandy Bridge Mode (WDQ Tri-State) &
* Ensure 5 WDQS pulses during Write Leveling
*/
mrc_alt_write_mask(DDRPHY,
DQCTL + (DDRIODQ_BL_OFFSET * bl) + (DDRIODQ_CH_OFFSET * ch),
(BIT28 | BIT8 | BIT6 | BIT4 | BIT2),
(BIT28 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2));
}
/* Write Leveling Mode enabled in IO */
mrc_alt_write_mask(DDRPHY,
CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * ch),
BIT16, BIT16);
/* Initialize the starting delay to WCLK */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
/*
* CLK0 --> RK0
* CLK1 --> RK1
*/
delay[bl] = get_wclk(ch, rk);
set_wdqs(ch, rk, bl, delay[bl]);
}
/* now find the rising edge */
find_rising_edge(mrc_params, delay, ch, rk, false);
/* disable Write Levelling Mode */
mrc_alt_write_mask(DDRPHY,
CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * ch),
0, BIT16);
for (bl = 0; bl < ((NUM_BYTE_LANES / bl_divisor) / 2); bl++) {
/* Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation */
mrc_alt_write_mask(DDRPHY,
DQCTL + (DDRIODQ_BL_OFFSET * bl) + (DDRIODQ_CH_OFFSET * ch),
(BIT8 | BIT6 | BIT4 | BIT2),
(BIT28 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2));
}
/* restore original DTR4 */
msg_port_write(MEM_CTLR, DTR4, dtr4_save);
/*
* restore original value
* (Write Levelling Mode Disable)
*/
dram_init_command(DCMD_MRS1(rk, mrc_params->mrs1));
/*
* perform a single PRECHARGE_ALL command to
* make DRAM state machine go to IDLE state
*/
dram_init_command(DCMD_PREA(rk));
mrc_post_code(0x06, (0x30 + ((ch << 4) | rk)));
/*
* COARSE WRITE LEVEL:
* check that we're on the correct clock edge
*/
/* hte reconfiguration request */
mrc_params->hte_setup = 1;
/* start CRS_WR_LVL with WDQS = WDQS + 128 PI */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
delay[bl] = get_wdqs(ch, rk, bl) + FULL_CLK;
set_wdqs(ch, rk, bl, delay[bl]);
/*
* program WDQ timings based on WDQS
* (WDQ = WDQS - 32 PI)
*/
set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
}
/* get an address in the targeted channel/rank */
address = get_addr(ch, rk);
do {
uint32_t coarse_result = 0x00;
uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
/* assume pass */
all_edges_found = true;
mrc_params->hte_setup = 1;
coarse_result = check_rw_coarse(mrc_params, address);
/* check for failures and margin the byte lane back 128 PI (1 CLK) */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
if (coarse_result & (coarse_result_mask << bl)) {
all_edges_found = false;
delay[bl] -= FULL_CLK;
set_wdqs(ch, rk, bl, delay[bl]);
/* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
}
}
} while (!all_edges_found);
+#ifdef R2R_SHARING
/* increment "num_ranks_enabled" */
num_ranks_enabled++;
/* accumulate "final_delay[][]" values from "delay[]" values for rolling average */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
final_delay[ch][bl] += delay[bl];
set_wdqs(ch, rk, bl, ((final_delay[ch][bl]) / num_ranks_enabled));
/* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
set_wdq(ch, rk, bl, ((final_delay[ch][bl]) / num_ranks_enabled) - QRTR_CLK);
}
+#endif +#endif
}
}
}
}
LEAVEFN();
+}
+void prog_page_ctrl(struct mrc_params *mrc_params) +{
u32 dpmc0;
ENTERFN();
dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
dpmc0 &= ~(BIT16 | BIT17 | BIT18);
dpmc0 |= (4 << 16);
dpmc0 |= BIT21;
msg_port_write(MEM_CTLR, DPMC0, dpmc0);
+}
+/*
- This function will perform the READ TRAINING Algorithm on all
- channels/ranks/byte_lanes simultaneously to minimize execution time.
- The idea here is to train the VREF and RDQS (and eventually RDQ) values
- to achieve maximum READ margins. The algorithm will first determine the
- X coordinate (RDQS setting). This is done by collapsing the VREF eye
- until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
- Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX,
- then average those; this will be the final X coordinate. The algorithm
- will then determine the Y coordinate (VREF setting). This is done by
- collapsing the RDQS eye until we find a minimum required VREF eye for
- RDQS_MIN and RDQS_MAX. Then we take the averages of the VREF eye at
- RDQS_MIN and RDQS_MAX, then average those; this will be the final Y
- coordinate.
- NOTE: this algorithm assumes the eye curves have a one-to-one relationship,
- meaning for each X the curve has only one Y and vice-a-versa.
- */
+void rd_train(struct mrc_params *mrc_params) +{
uint8_t ch; /* channel counter */
uint8_t rk; /* rank counter */
uint8_t bl; /* byte lane counter */
uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
+#ifdef BACKUP_RDQS +#else
uint8_t side_x; /* tracks LEFT/RIGHT approach vectors */
uint8_t side_y; /* tracks BOTTOM/TOP approach vectors */
/* X coordinate data (passing RDQS values) for approach vectors */
uint8_t x_coordinate[2][2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
/* Y coordinate data (passing VREF values) for approach vectors */
uint8_t y_coordinate[2][2][NUM_CHANNELS][NUM_BYTE_LANES];
/* centered X (RDQS) */
uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
/* centered Y (VREF) */
uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES];
uint32_t address; /* target address for check_bls_ex() */
uint32_t result; /* result of check_bls_ex() */
uint32_t bl_mask; /* byte lane mask for result checking */
+#ifdef R2R_SHARING
/* used to find placement for rank2rank sharing configs */
uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
/* used to find placement for rank2rank sharing configs */
uint32_t num_ranks_enabled = 0;
+#endif +#endif
/* rd_train starts */
mrc_post_code(0x07, 0x00);
ENTERFN();
+#ifdef BACKUP_RDQS
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
for (bl = 0;
bl < (NUM_BYTE_LANES / bl_divisor);
bl++) {
set_rdqs(ch, rk, bl, ddr_rdqs[PLATFORM_ID]);
}
}
}
}
}
+#else
/* initialise x/y_coordinate arrays */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
for (bl = 0;
bl < (NUM_BYTE_LANES / bl_divisor);
bl++) {
/* x_coordinate */
x_coordinate[L][B][ch][rk][bl] = RDQS_MIN;
x_coordinate[R][B][ch][rk][bl] = RDQS_MAX;
x_coordinate[L][T][ch][rk][bl] = RDQS_MIN;
x_coordinate[R][T][ch][rk][bl] = RDQS_MAX;
/* y_coordinate */
y_coordinate[L][B][ch][bl] = VREF_MIN;
y_coordinate[R][B][ch][bl] = VREF_MIN;
y_coordinate[L][T][ch][bl] = VREF_MAX;
y_coordinate[R][T][ch][bl] = VREF_MAX;
}
}
}
}
}
/* initialize other variables */
bl_mask = byte_lane_mask(mrc_params);
address = get_addr(0, 0);
+#ifdef R2R_SHARING
/* need to set "final_delay[][]" elements to "0" */
memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
+#endif
/* look for passing coordinates */
for (side_y = B; side_y <= T; side_y++) {
for (side_x = L; side_x <= R; side_x++) {
mrc_post_code(0x07, (0x10 + (side_y * 2) + (side_x)));
/* find passing values */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (0x1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables &
(0x1 << rk)) {
/* set x/y_coordinate search starting settings */
for (bl = 0;
bl < (NUM_BYTE_LANES / bl_divisor);
bl++) {
set_rdqs(ch, rk, bl,
x_coordinate[side_x][side_y][ch][rk][bl]);
set_vref(ch, bl,
y_coordinate[side_x][side_y][ch][bl]);
}
/* get an address in the target channel/rank */
address = get_addr(ch, rk);
/* request HTE reconfiguration */
mrc_params->hte_setup = 1;
/* test the settings */
do {
/* result[07:00] == failing byte lane (MAX 8) */
result = check_bls_ex(mrc_params, address);
/* check for failures */
if (result & 0xFF) {
/* at least 1 byte lane failed */
I'm pretty sure this block can go in a function
And I don't know how to name that function with a proper name. Sigh ... Did not change in v2.
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
if (result &
(bl_mask << bl)) {
/* adjust the RDQS values accordingly */
if (side_x == L)
x_coordinate[L][side_y][ch][rk][bl] += RDQS_STEP;
else
x_coordinate[R][side_y][ch][rk][bl] -= RDQS_STEP;
/* check that we haven't closed the RDQS_EYE too much */
if ((x_coordinate[L][side_y][ch][rk][bl] > (RDQS_MAX - MIN_RDQS_EYE)) ||
(x_coordinate[R][side_y][ch][rk][bl] < (RDQS_MIN + MIN_RDQS_EYE)) ||
(x_coordinate[L][side_y][ch][rk][bl] ==
x_coordinate[R][side_y][ch][rk][bl])) {
/*
* not enough RDQS margin available at this VREF
* update VREF values accordingly
*/
if (side_y == B)
y_coordinate[side_x][B][ch][bl] += VREF_STEP;
else
y_coordinate[side_x][T][ch][bl] -= VREF_STEP;
/* check that we haven't closed the VREF_EYE too much */
if ((y_coordinate[side_x][B][ch][bl] > (VREF_MAX - MIN_VREF_EYE)) ||
(y_coordinate[side_x][T][ch][bl] < (VREF_MIN + MIN_VREF_EYE)) ||
(y_coordinate[side_x][B][ch][bl] == y_coordinate[side_x][T][ch][bl])) {
/* VREF_EYE collapsed below MIN_VREF_EYE */
training_message(ch, rk, bl);
mrc_post_code(0xEE, (0x70 + (side_y * 2) + (side_x)));
} else {
/* update the VREF setting */
set_vref(ch, bl, y_coordinate[side_x][side_y][ch][bl]);
/* reset the X coordinate to begin the search at the new VREF */
x_coordinate[side_x][side_y][ch][rk][bl] =
(side_x == L) ? (RDQS_MIN) : (RDQS_MAX);
}
}
/* update the RDQS setting */
set_rdqs(ch, rk, bl, x_coordinate[side_x][side_y][ch][rk][bl]);
}
}
}
} while (result & 0xFF);
}
}
}
}
}
}
mrc_post_code(0x07, 0x20);
/* find final RDQS (X coordinate) & final VREF (Y coordinate) */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
uint32_t temp1;
uint32_t temp2;
/* x_coordinate */
DPF(D_INFO,
"RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n",
rk, bl,
x_coordinate[L][T][ch][rk][bl],
x_coordinate[R][T][ch][rk][bl],
x_coordinate[L][B][ch][rk][bl],
x_coordinate[R][B][ch][rk][bl]);
/* average the TOP side LEFT & RIGHT values */
temp1 = (x_coordinate[R][T][ch][rk][bl] + x_coordinate[L][T][ch][rk][bl]) / 2;
/* average the BOTTOM side LEFT & RIGHT values */
temp2 = (x_coordinate[R][B][ch][rk][bl] + x_coordinate[L][B][ch][rk][bl]) / 2;
/* average the above averages */
x_center[ch][rk][bl] = (uint8_t) ((temp1 + temp2) / 2);
/* y_coordinate */
DPF(D_INFO,
"VREF R/L eye lane%d : %d-%d %d-%d\n",
bl,
y_coordinate[R][B][ch][bl],
y_coordinate[R][T][ch][bl],
y_coordinate[L][B][ch][bl],
y_coordinate[L][T][ch][bl]);
/* average the RIGHT side TOP & BOTTOM values */
temp1 = (y_coordinate[R][T][ch][bl] + y_coordinate[R][B][ch][bl]) / 2;
/* average the LEFT side TOP & BOTTOM values */
temp2 = (y_coordinate[L][T][ch][bl] + y_coordinate[L][B][ch][bl]) / 2;
/* average the above averages */
y_center[ch][bl] = (uint8_t) ((temp1 + temp2) / 2);
}
}
}
}
}
+#ifdef RX_EYE_CHECK
/* perform an eye check */
for (side_y = B; side_y <= T; side_y++) {
for (side_x = L; side_x <= R; side_x++) {
mrc_post_code(0x07, (0x30 + (side_y * 2) + (side_x)));
/* update the settings for the eye check */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
if (side_x == L)
set_rdqs(ch, rk, bl, (x_center[ch][rk][bl] - (MIN_RDQS_EYE / 2)));
else
set_rdqs(ch, rk, bl, (x_center[ch][rk][bl] + (MIN_RDQS_EYE / 2)));
if (side_y == B)
set_vref(ch, bl, (y_center[ch][bl] - (MIN_VREF_EYE / 2)));
else
set_vref(ch, bl, (y_center[ch][bl] + (MIN_VREF_EYE / 2)));
}
}
}
}
}
/* request HTE reconfiguration */
mrc_params->hte_setup = 1;
/* check the eye */
if (check_bls_ex(mrc_params, address) & 0xFF) {
/* one or more byte lanes failed */
mrc_post_code(0xEE, (0x74 + (side_x * 2) + (side_y)));
}
}
}
+#endif
mrc_post_code(0x07, 0x40);
/* set final placements */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
+#ifdef R2R_SHARING
/* increment "num_ranks_enabled" */
num_ranks_enabled++;
+#endif
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
/* x_coordinate */
+#ifdef R2R_SHARING
final_delay[ch][bl] += x_center[ch][rk][bl];
set_rdqs(ch, rk, bl, ((final_delay[ch][bl]) / num_ranks_enabled));
+#else
set_rdqs(ch, rk, bl, x_center[ch][rk][bl]);
+#endif
/* y_coordinate */
set_vref(ch, bl, y_center[ch][bl]);
}
}
}
}
}
+#endif
LEAVEFN();
+}
+/*
- This function will perform the WRITE TRAINING Algorithm on all
- channels/ranks/byte_lanes simultaneously to minimize execution time.
- The idea here is to train the WDQ timings to achieve maximum WRITE margins.
- The algorithm will start with WDQ at the current WDQ setting (tracks WDQS
- in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data
- patterns pass. This is because WDQS will be aligned to WCLK by the
- Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window
- of validity.
- */
+void wr_train(struct mrc_params *mrc_params) +{
uint8_t ch; /* channel counter */
uint8_t rk; /* rank counter */
uint8_t bl; /* byte lane counter */
uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
+#ifdef BACKUP_WDQ +#else
uint8_t side; /* LEFT/RIGHT side indicator (0=L, 1=R) */
uint32_t temp; /* temporary DWORD */
/* 2 arrays, for L & R side passing delays */
uint32_t delay[2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
uint32_t address; /* target address for check_bls_ex() */
uint32_t result; /* result of check_bls_ex() */
uint32_t bl_mask; /* byte lane mask for result checking */
+#ifdef R2R_SHARING
/* used to find placement for rank2rank sharing configs */
uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
/* used to find placement for rank2rank sharing configs */
uint32_t num_ranks_enabled = 0;
+#endif +#endif
/* wr_train starts */
mrc_post_code(0x08, 0x00);
ENTERFN();
+#ifdef BACKUP_WDQ
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
for (bl = 0;
bl < (NUM_BYTE_LANES / bl_divisor);
bl++) {
set_wdq(ch, rk, bl, ddr_wdq[PLATFORM_ID]);
}
}
}
}
}
+#else
/* initialise "delay" */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
for (bl = 0;
bl < (NUM_BYTE_LANES / bl_divisor);
bl++) {
/*
* want to start with
* WDQ = (WDQS - QRTR_CLK)
* +/- QRTR_CLK
*/
temp = get_wdqs(ch, rk, bl) - QRTR_CLK;
delay[L][ch][rk][bl] = temp - QRTR_CLK;
delay[R][ch][rk][bl] = temp + QRTR_CLK;
}
}
}
}
}
/* initialise other variables */
bl_mask = byte_lane_mask(mrc_params);
address = get_addr(0, 0);
+#ifdef R2R_SHARING
/* need to set "final_delay[][]" elements to "0" */
memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
+#endif
/*
* start algorithm on the LEFT side and train each channel/bl
* until no failures are observed, then repeat for the RIGHT side.
*/
for (side = L; side <= R; side++) {
mrc_post_code(0x08, (0x10 + (side)));
/* set starting values */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables &
(1 << rk)) {
for (bl = 0;
bl < (NUM_BYTE_LANES / bl_divisor);
bl++) {
set_wdq(ch, rk, bl, delay[side][ch][rk][bl]);
}
}
}
}
}
/* find passing values */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables &
(1 << rk)) {
/* get an address in the target channel/rank */
address = get_addr(ch, rk);
/* request HTE reconfiguration */
mrc_params->hte_setup = 1;
/* check the settings */
do {
/* result[07:00] == failing byte lane (MAX 8) */
result = check_bls_ex(mrc_params, address);
/* check for failures */
if (result & 0xFF) {
/* at least 1 byte lane failed */
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
if (result &
(bl_mask << bl)) {
if (side == L)
delay[L][ch][rk][bl] += WDQ_STEP;
else
delay[R][ch][rk][bl] -= WDQ_STEP;
/* check for algorithm failure */
if (delay[L][ch][rk][bl] != delay[R][ch][rk][bl]) {
/*
* margin available
* update delay setting
*/
set_wdq(ch, rk, bl,
delay[side][ch][rk][bl]);
} else {
/*
* no margin available
* notify the user and halt
*/
training_message(ch, rk, bl);
mrc_post_code(0xEE, (0x80 + side));
}
}
}
}
/* stop when all byte lanes pass */
} while (result & 0xFF);
}
}
}
}
}
/* program WDQ to the middle of passing window */
for (ch = 0; ch < NUM_CHANNELS; ch++) {
if (mrc_params->channel_enables & (1 << ch)) {
for (rk = 0; rk < NUM_RANKS; rk++) {
if (mrc_params->rank_enables & (1 << rk)) {
+#ifdef R2R_SHARING
/* increment "num_ranks_enabled" */
num_ranks_enabled++;
+#endif
for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
DPF(D_INFO,
"WDQ eye rank%d lane%d : %d-%d\n",
rk, bl,
delay[L][ch][rk][bl],
delay[R][ch][rk][bl]);
temp = (delay[R][ch][rk][bl] + delay[L][ch][rk][bl]) / 2;
+#ifdef R2R_SHARING
final_delay[ch][bl] += temp;
set_wdq(ch, rk, bl,
((final_delay[ch][bl]) / num_ranks_enabled));
+#else
set_wdq(ch, rk, bl, temp);
+#endif
}
}
}
}
}
+#endif
LEAVEFN();
+}
+/*
- This function will store relevant timing data
- This data will be used on subsequent boots to speed up boot times
- and is required for Suspend To RAM capabilities.
- */
+void store_timings(struct mrc_params *mrc_params) +{
uint8_t ch, rk, bl;
struct mrc_timings *mt = &mrc_params->timings;
for (ch = 0; ch < NUM_CHANNELS; ch++) {
for (rk = 0; rk < NUM_RANKS; rk++) {
for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl);
mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl);
mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl);
mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);
if (rk == 0)
mt->vref[ch][bl] = get_vref(ch, bl);
}
mt->wctl[ch][rk] = get_wctl(ch, rk);
}
mt->wcmd[ch] = get_wcmd(ch);
}
/* need to save for a case of changing frequency after warm reset */
mt->ddr_speed = mrc_params->ddr_speed;
+}
+/*
- The purpose of this function is to ensure the SEC comes out of reset
- and IA initiates the SEC enabling Memory Scrambling.
- */
+void enable_scrambling(struct mrc_params *mrc_params) +{
uint32_t lfsr = 0;
uint8_t i;
if (mrc_params->scrambling_enables == 0)
return;
ENTERFN();
/* 32 bit seed is always stored in BIOS NVM */
lfsr = mrc_params->timings.scrambler_seed;
if (mrc_params->boot_mode == BM_COLD) {
/*
* factory value is 0 and in first boot,
* a clock based seed is loaded.
*/
if (lfsr == 0) {
/*
* get seed from system clock
* and make sure it is not all 1's
*/
lfsr = rdtsc() & 0x0FFFFFFF;
} else {
/*
* Need to replace scrambler
*
* get next 32bit LFSR 16 times which is the last
* part of the previous scrambler vector
*/
for (i = 0; i < 16; i++)
lfsr32(&lfsr);
}
/* save new seed */
mrc_params->timings.scrambler_seed = lfsr;
}
/*
* In warm boot or S3 exit, we have the previous seed.
* In cold boot, we have the last 32bit LFSR which is the new seed.
*/
lfsr32(&lfsr); /* shift to next value */
msg_port_write(MEM_CTLR, SCRMSEED, (lfsr & 0x0003FFFF));
for (i = 0; i < 2; i++)
msg_port_write(MEM_CTLR, SCRMLO + i, (lfsr & 0xAAAAAAAA));
LEAVEFN();
+}
+/*
- Configure MCU Power Management Control Register
- and Scheduler Control Register
- */
+void prog_ddr_control(struct mrc_params *mrc_params) +{
u32 dsch;
u32 dpmc0;
ENTERFN();
dsch = msg_port_read(MEM_CTLR, DSCH);
dsch &= ~(BIT8 | BIT9 | BIT12);
msg_port_write(MEM_CTLR, DSCH, dsch);
dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
dpmc0 &= ~BIT25;
dpmc0 |= (mrc_params->power_down_disable << 25);
dpmc0 &= ~BIT24;
dpmc0 &= ~(BIT16 | BIT17 | BIT18);
dpmc0 |= (4 << 16);
dpmc0 |= BIT21;
msg_port_write(MEM_CTLR, DPMC0, dpmc0);
/* CMDTRIST = 2h - CMD/ADDR are tristated when no valid command */
mrc_write_mask(MEM_CTLR, DPMC1, 2 << 4, BIT4 | BIT5);
LEAVEFN();
+}
+/*
- After training complete configure MCU Rank Population Register
- specifying: ranks enabled, device width, density, address mode
- */
+void prog_dra_drb(struct mrc_params *mrc_params) +{
u32 drp;
u32 dco;
u8 density = mrc_params->params.density;
ENTERFN();
dco = msg_port_read(MEM_CTLR, DCO);
dco &= ~BIT31;
msg_port_write(MEM_CTLR, DCO, dco);
drp = 0;
if (mrc_params->rank_enables & 1)
drp |= BIT0;
if (mrc_params->rank_enables & 2)
drp |= BIT1;
if (mrc_params->dram_width == X16) {
drp |= (1 << 4);
drp |= (1 << 9);
}
/*
* Density encoding in struct dram_params: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
* has to be mapped RANKDENSx encoding (0=1Gb)
*/
if (density == 0)
density = 4;
drp |= ((density - 1) << 6);
drp |= ((density - 1) << 11);
/* Address mode can be overwritten if ECC enabled */
drp |= (mrc_params->address_mode << 14);
msg_port_write(MEM_CTLR, DRP, drp);
dco &= ~BIT28;
dco |= BIT31;
msg_port_write(MEM_CTLR, DCO, dco);
LEAVEFN();
+}
+/* Send DRAM wake command */ +void perform_wake(struct mrc_params *mrc_params) +{
ENTERFN();
dram_wake_command();
LEAVEFN();
+}
+/*
- Configure refresh rate and short ZQ calibration interval
- Activate dynamic self refresh
- */
+void change_refresh_period(struct mrc_params *mrc_params) +{
u32 drfc;
u32 dcal;
u32 dpmc0;
ENTERFN();
drfc = msg_port_read(MEM_CTLR, DRFC);
drfc &= ~(BIT12 | BIT13 | BIT14);
drfc |= (mrc_params->refresh_rate << 12);
drfc |= BIT21;
msg_port_write(MEM_CTLR, DRFC, drfc);
dcal = msg_port_read(MEM_CTLR, DCAL);
dcal &= ~(BIT8 | BIT9 | BIT10);
dcal |= (3 << 8); /* 63ms */
msg_port_write(MEM_CTLR, DCAL, dcal);
dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
dpmc0 |= (BIT23 | BIT29);
msg_port_write(MEM_CTLR, DPMC0, dpmc0);
LEAVEFN();
+}
+/*
- Configure DDRPHY for Auto-Refresh, Periodic Compensations,
- Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
- */
+void set_auto_refresh(struct mrc_params *mrc_params) +{
uint32_t channel;
uint32_t rank;
uint32_t bl;
uint32_t bl_divisor = 1;
uint32_t temp;
ENTERFN();
/*
* Enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp,
* ZQSPERIOD, Auto-Precharge, CKE Power-Down
*/
for (channel = 0; channel < NUM_CHANNELS; channel++) {
if (mrc_params->channel_enables & (1 << channel)) {
/* Enable Periodic RCOMPS */
mrc_alt_write_mask(DDRPHY, CMPCTRL, BIT1, BIT1);
/* Enable Dynamic DiffAmp & Set Read ODT Value */
switch (mrc_params->rd_odt_value) {
case 0:
temp = 0x3F; /* OFF */
break;
default:
temp = 0x00; /* Auto */
break;
}
for (bl = 0; bl < ((NUM_BYTE_LANES / bl_divisor) / 2); bl++) {
/* Override: DIFFAMP, ODT */
mrc_alt_write_mask(DDRPHY,
(B0OVRCTL + (bl * DDRIODQ_BL_OFFSET) +
(channel * DDRIODQ_CH_OFFSET)),
(0x00 << 16) | (temp << 10),
(BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16 | BIT15 | BIT14 |
BIT13 | BIT12 | BIT11 | BIT10));
/* Override: DIFFAMP, ODT */
mrc_alt_write_mask(DDRPHY,
(B1OVRCTL + (bl * DDRIODQ_BL_OFFSET) +
(channel * DDRIODQ_CH_OFFSET)),
(0x00 << 16) | (temp << 10),
(BIT21 | BIT20 | BIT19 | BIT18 |
BIT17 | BIT16 | BIT15 | BIT14 |
BIT13 | BIT12 | BIT11 | BIT10));
}
/* Issue ZQCS command */
for (rank = 0; rank < NUM_RANKS; rank++) {
if (mrc_params->rank_enables & (1 << rank))
dram_init_command(DCMD_ZQCS(rank));
}
}
}
clear_pointers();
LEAVEFN();
+}
+/*
- Depending on configuration enables ECC support
- Available memory size is decreased, and updated with 0s
- in order to clear error status. Address mode 2 forced.
- */
+void ecc_enable(struct mrc_params *mrc_params) +{
u32 drp;
u32 dsch;
u32 ecc_ctrl;
if (mrc_params->ecc_enables == 0)
return;
ENTERFN();
/* Configuration required in ECC mode */
drp = msg_port_read(MEM_CTLR, DRP);
drp &= ~(BIT14 | BIT15);
drp |= BIT15;
drp |= BIT13;
msg_port_write(MEM_CTLR, DRP, drp);
/* Disable new request bypass */
dsch = msg_port_read(MEM_CTLR, DSCH);
dsch |= BIT12;
msg_port_write(MEM_CTLR, DSCH, dsch);
/* Enable ECC */
ecc_ctrl = (BIT0 | BIT1 | BIT17);
msg_port_write(MEM_CTLR, DECCCTRL, ecc_ctrl);
/* Assume 8 bank memory, one bank is gone for ECC */
mrc_params->mem_size -= mrc_params->mem_size / 8;
/* For S3 resume memory content has to be preserved */
if (mrc_params->boot_mode != BM_S3) {
select_hte();
hte_mem_init(mrc_params, MRC_MEM_INIT);
select_mem_mgr();
}
LEAVEFN();
+}
+/*
- Execute memory test
- if error detected it is indicated in mrc_params->status
- */
+void memory_test(struct mrc_params *mrc_params) +{
uint32_t result = 0;
ENTERFN();
select_hte();
result = hte_mem_init(mrc_params, MRC_MEM_TEST);
select_mem_mgr();
DPF(D_INFO, "Memory test result %x\n", result);
mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
LEAVEFN();
+}
+/* Lock MCU registers at the end of initialization sequence */ +void lock_registers(struct mrc_params *mrc_params) +{
u32 dco;
ENTERFN();
dco = msg_port_read(MEM_CTLR, DCO);
dco &= ~(BIT28 | BIT29);
dco |= (BIT0 | BIT8);
msg_port_write(MEM_CTLR, DCO, dco);
LEAVEFN();
+} diff --git a/arch/x86/cpu/quark/smc.h b/arch/x86/cpu/quark/smc.h new file mode 100644 index 0000000..f774cb3 --- /dev/null +++ b/arch/x86/cpu/quark/smc.h @@ -0,0 +1,446 @@ +/*
- Copyright (C) 2013, Intel Corporation
- Copyright (C) 2015, Bin Meng bmeng.cn@gmail.com
- Ported from Intel released Quark UEFI BIOS
- QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/
Removed the ending / in v2.
- SPDX-License-Identifier: Intel
- */
+#ifndef _SMC_H_ +#define _SMC_H_
+/* System Memory Controller Register Defines */
+/* Memory Controller Message Bus Registers Offsets */ +#define DRP 0x00 +#define DTR0 0x01 +#define DTR1 0x02 +#define DTR2 0x03 +#define DTR3 0x04 +#define DTR4 0x05 +#define DPMC0 0x06 +#define DPMC1 0x07 +#define DRFC 0x08 +#define DSCH 0x09 +#define DCAL 0x0A +#define DRMC 0x0B +#define PMSTS 0x0C +#define DCO 0x0F +#define DSTAT 0x20 +#define SSKPD0 0x4A +#define SSKPD1 0x4B +#define DECCCTRL 0x60 +#define DECCSTAT 0x61 +#define DECCSBECNT 0x62 +#define DECCSBECA 0x68 +#define DECCSBECS 0x69 +#define DECCDBECA 0x6A +#define DECCDBECS 0x6B +#define DFUSESTAT 0x70 +#define SCRMSEED 0x80 +#define SCRMLO 0x81 +#define SCRMHI 0x82
+/* DRAM init command */ +#define DCMD_MRS1(rnk, dat) (0 | ((rnk) << 22) | (1 << 3) | ((dat) << 6)) +#define DCMD_REF(rnk) (1 | ((rnk) << 22)) +#define DCMD_PRE(rnk) (2 | ((rnk) << 22)) +#define DCMD_PREA(rnk) (2 | ((rnk) << 22) | (BIT10 << 6)) +#define DCMD_ACT(rnk, row) (3 | ((rnk) << 22) | ((row) << 6)) +#define DCMD_WR(rnk, col) (4 | ((rnk) << 22) | ((col) << 6)) +#define DCMD_RD(rnk, col) (5 | ((rnk) << 22) | ((col) << 6)) +#define DCMD_ZQCS(rnk) (6 | ((rnk) << 22)) +#define DCMD_ZQCL(rnk) (6 | ((rnk) << 22) | (BIT10 << 6)) +#define DCMD_NOP(rnk) (7 | ((rnk) << 22))
We should have a #define for the 22 and a #define for the 6, and probably an enum for the 0, 1, 2, .. 7.
Acutally I have no idea about this DCMD macro group. They are undocumented in the Intel datasheet. I suspect it is something in the JEDEC DDR spec though. Did not change this in v2.
Then the C code should ideally do:
ENUM_NAME | (rnk << DCMD_XXX_SHIFT) | (col << DCMD_SHFIT)
instead of
DCMD_RD(rnk, col)
+#define DDR3_EMRS1_DIC_40 (0) +#define DDR3_EMRS1_DIC_34 (1)
+#define DDR3_EMRS1_RTTNOM_0 (0) +#define DDR3_EMRS1_RTTNOM_60 (BIT2) +#define DDR3_EMRS1_RTTNOM_120 (BIT6) +#define DDR3_EMRS1_RTTNOM_40 (BIT6 | BIT2) +#define DDR3_EMRS1_RTTNOM_20 (BIT9) +#define DDR3_EMRS1_RTTNOM_30 (BIT9 | BIT2)
Let's right out the value here
Fixed
+#define DDR3_EMRS2_RTTWR_60 (BIT9)
(1 << 9)
Fixed
+#define DDR3_EMRS2_RTTWR_120 (BIT10)
(1 << 10)
Fixed
+/* BEGIN DDRIO Registers */
+/* DDR IOs & COMPs */ +#define DDRIODQ_BL_OFFSET 0x0800 +#define DDRIODQ_CH_OFFSET ((NUM_BYTE_LANES / 2) * DDRIODQ_BL_OFFSET) +#define DDRIOCCC_CH_OFFSET 0x0800 +#define DDRCOMP_CH_OFFSET 0x0100
+/* CH0-BL01-DQ */ +#define DQOBSCKEBBCTL 0x0000
Are these accessed through the msg_port? If not, we could use a struct.
They are all accessed via msg port, and undocumented!!
+#define DQDLLTXCTL 0x0004 +#define DQDLLRXCTL 0x0008 +#define DQMDLLCTL 0x000C +#define B0RXIOBUFCTL 0x0010 +#define B0VREFCTL 0x0014 +#define B0RXOFFSET1 0x0018 +#define B0RXOFFSET0 0x001C +#define B1RXIOBUFCTL 0x0020 +#define B1VREFCTL 0x0024 +#define B1RXOFFSET1 0x0028 +#define B1RXOFFSET0 0x002C +#define DQDFTCTL 0x0030 +#define DQTRAINSTS 0x0034 +#define B1DLLPICODER0 0x0038 +#define B0DLLPICODER0 0x003C +#define B1DLLPICODER1 0x0040 +#define B0DLLPICODER1 0x0044 +#define B1DLLPICODER2 0x0048 +#define B0DLLPICODER2 0x004C +#define B1DLLPICODER3 0x0050 +#define B0DLLPICODER3 0x0054 +#define B1RXDQSPICODE 0x0058 +#define B0RXDQSPICODE 0x005C +#define B1RXDQPICODER32 0x0060 +#define B1RXDQPICODER10 0x0064 +#define B0RXDQPICODER32 0x0068 +#define B0RXDQPICODER10 0x006C +#define B01PTRCTL0 0x0070 +#define B01PTRCTL1 0x0074 +#define B01DBCTL0 0x0078 +#define B01DBCTL1 0x007C +#define B0LATCTL0 0x0080 +#define B1LATCTL0 0x0084 +#define B01LATCTL1 0x0088 +#define B0ONDURCTL 0x008C +#define B1ONDURCTL 0x0090 +#define B0OVRCTL 0x0094 +#define B1OVRCTL 0x0098 +#define DQCTL 0x009C +#define B0RK2RKCHGPTRCTRL 0x00A0 +#define B1RK2RKCHGPTRCTRL 0x00A4 +#define DQRK2RKCTL 0x00A8 +#define DQRK2RKPTRCTL 0x00AC +#define B0RK2RKLAT 0x00B0 +#define B1RK2RKLAT 0x00B4 +#define DQCLKALIGNREG0 0x00B8 +#define DQCLKALIGNREG1 0x00BC +#define DQCLKALIGNREG2 0x00C0 +#define DQCLKALIGNSTS0 0x00C4 +#define DQCLKALIGNSTS1 0x00C8 +#define DQCLKGATE 0x00CC +#define B0COMPSLV1 0x00D0 +#define B1COMPSLV1 0x00D4 +#define B0COMPSLV2 0x00D8 +#define B1COMPSLV2 0x00DC +#define B0COMPSLV3 0x00E0 +#define B1COMPSLV3 0x00E4 +#define DQVISALANECR0TOP 0x00E8 +#define DQVISALANECR1TOP 0x00EC +#define DQVISACONTROLCRTOP 0x00F0 +#define DQVISALANECR0BL 0x00F4 +#define DQVISALANECR1BL 0x00F8 +#define DQVISACONTROLCRBL 0x00FC +#define DQTIMINGCTRL 0x010C
+/* CH0-ECC */ +#define ECCDLLTXCTL 0x2004 +#define ECCDLLRXCTL 0x2008 +#define ECCMDLLCTL 0x200C +#define ECCB1DLLPICODER0 0x2038 +#define ECCB1DLLPICODER1 0x2040 +#define ECCB1DLLPICODER2 0x2048 +#define ECCB1DLLPICODER3 0x2050 +#define ECCB01DBCTL0 0x2078 +#define ECCB01DBCTL1 0x207C +#define ECCCLKALIGNREG0 0x20B8 +#define ECCCLKALIGNREG1 0x20BC +#define ECCCLKALIGNREG2 0x20C0
+/* CH0-CMD */ +#define CMDOBSCKEBBCTL 0x4800 +#define CMDDLLTXCTL 0x4808 +#define CMDDLLRXCTL 0x480C +#define CMDMDLLCTL 0x4810 +#define CMDRCOMPODT 0x4814 +#define CMDDLLPICODER0 0x4820 +#define CMDDLLPICODER1 0x4824 +#define CMDCFGREG0 0x4840 +#define CMDPTRREG 0x4844 +#define CMDCLKALIGNREG0 0x4850 +#define CMDCLKALIGNREG1 0x4854 +#define CMDCLKALIGNREG2 0x4858 +#define CMDPMCONFIG0 0x485C +#define CMDPMDLYREG0 0x4860 +#define CMDPMDLYREG1 0x4864 +#define CMDPMDLYREG2 0x4868 +#define CMDPMDLYREG3 0x486C +#define CMDPMDLYREG4 0x4870 +#define CMDCLKALIGNSTS0 0x4874 +#define CMDCLKALIGNSTS1 0x4878 +#define CMDPMSTS0 0x487C +#define CMDPMSTS1 0x4880 +#define CMDCOMPSLV 0x4884 +#define CMDBONUS0 0x488C +#define CMDBONUS1 0x4890 +#define CMDVISALANECR0 0x4894 +#define CMDVISALANECR1 0x4898 +#define CMDVISACONTROLCR 0x489C +#define CMDCLKGATE 0x48A0 +#define CMDTIMINGCTRL 0x48A4
+/* CH0-CLK-CTL */ +#define CCOBSCKEBBCTL 0x5800 +#define CCRCOMPIO 0x5804 +#define CCDLLTXCTL 0x5808 +#define CCDLLRXCTL 0x580C +#define CCMDLLCTL 0x5810 +#define CCRCOMPODT 0x5814 +#define CCDLLPICODER0 0x5820 +#define CCDLLPICODER1 0x5824 +#define CCDDR3RESETCTL 0x5830 +#define CCCFGREG0 0x5838 +#define CCCFGREG1 0x5840 +#define CCPTRREG 0x5844 +#define CCCLKALIGNREG0 0x5850 +#define CCCLKALIGNREG1 0x5854 +#define CCCLKALIGNREG2 0x5858 +#define CCPMCONFIG0 0x585C +#define CCPMDLYREG0 0x5860 +#define CCPMDLYREG1 0x5864 +#define CCPMDLYREG2 0x5868 +#define CCPMDLYREG3 0x586C +#define CCPMDLYREG4 0x5870 +#define CCCLKALIGNSTS0 0x5874 +#define CCCLKALIGNSTS1 0x5878 +#define CCPMSTS0 0x587C +#define CCPMSTS1 0x5880 +#define CCCOMPSLV1 0x5884 +#define CCCOMPSLV2 0x5888 +#define CCCOMPSLV3 0x588C +#define CCBONUS0 0x5894 +#define CCBONUS1 0x5898 +#define CCVISALANECR0 0x589C +#define CCVISALANECR1 0x58A0 +#define CCVISACONTROLCR 0x58A4 +#define CCCLKGATE 0x58A8 +#define CCTIMINGCTL 0x58AC
+/* COMP */ +#define CMPCTRL 0x6800 +#define SOFTRSTCNTL 0x6804 +#define MSCNTR 0x6808 +#define NMSCNTRL 0x680C +#define LATCH1CTL 0x6814 +#define COMPVISALANECR0 0x681C +#define COMPVISALANECR1 0x6820 +#define COMPVISACONTROLCR 0x6824 +#define COMPBONUS0 0x6830 +#define TCOCNTCTRL 0x683C +#define DQANAODTPUCTL 0x6840 +#define DQANAODTPDCTL 0x6844 +#define DQANADRVPUCTL 0x6848 +#define DQANADRVPDCTL 0x684C +#define DQANADLYPUCTL 0x6850 +#define DQANADLYPDCTL 0x6854 +#define DQANATCOPUCTL 0x6858 +#define DQANATCOPDCTL 0x685C +#define CMDANADRVPUCTL 0x6868 +#define CMDANADRVPDCTL 0x686C +#define CMDANADLYPUCTL 0x6870 +#define CMDANADLYPDCTL 0x6874 +#define CLKANAODTPUCTL 0x6880 +#define CLKANAODTPDCTL 0x6884 +#define CLKANADRVPUCTL 0x6888 +#define CLKANADRVPDCTL 0x688C +#define CLKANADLYPUCTL 0x6890 +#define CLKANADLYPDCTL 0x6894 +#define CLKANATCOPUCTL 0x6898 +#define CLKANATCOPDCTL 0x689C +#define DQSANAODTPUCTL 0x68A0 +#define DQSANAODTPDCTL 0x68A4 +#define DQSANADRVPUCTL 0x68A8 +#define DQSANADRVPDCTL 0x68AC +#define DQSANADLYPUCTL 0x68B0 +#define DQSANADLYPDCTL 0x68B4 +#define DQSANATCOPUCTL 0x68B8 +#define DQSANATCOPDCTL 0x68BC +#define CTLANADRVPUCTL 0x68C8 +#define CTLANADRVPDCTL 0x68CC +#define CTLANADLYPUCTL 0x68D0 +#define CTLANADLYPDCTL 0x68D4 +#define CHNLBUFSTATIC 0x68F0 +#define COMPOBSCNTRL 0x68F4 +#define COMPBUFFDBG0 0x68F8 +#define COMPBUFFDBG1 0x68FC +#define CFGMISCCH0 0x6900 +#define COMPEN0CH0 0x6904 +#define COMPEN1CH0 0x6908 +#define COMPEN2CH0 0x690C +#define STATLEGEN0CH0 0x6910 +#define STATLEGEN1CH0 0x6914 +#define DQVREFCH0 0x6918 +#define CMDVREFCH0 0x691C +#define CLKVREFCH0 0x6920 +#define DQSVREFCH0 0x6924 +#define CTLVREFCH0 0x6928 +#define TCOVREFCH0 0x692C +#define DLYSELCH0 0x6930 +#define TCODRAMBUFODTCH0 0x6934 +#define CCBUFODTCH0 0x6938 +#define RXOFFSETCH0 0x693C +#define DQODTPUCTLCH0 0x6940 +#define DQODTPDCTLCH0 0x6944 +#define DQDRVPUCTLCH0 0x6948 +#define DQDRVPDCTLCH0 0x694C +#define DQDLYPUCTLCH0 0x6950 +#define DQDLYPDCTLCH0 0x6954 +#define DQTCOPUCTLCH0 0x6958 +#define DQTCOPDCTLCH0 0x695C +#define CMDDRVPUCTLCH0 0x6968 +#define CMDDRVPDCTLCH0 0x696C +#define CMDDLYPUCTLCH0 0x6970 +#define CMDDLYPDCTLCH0 0x6974 +#define CLKODTPUCTLCH0 0x6980 +#define CLKODTPDCTLCH0 0x6984 +#define CLKDRVPUCTLCH0 0x6988 +#define CLKDRVPDCTLCH0 0x698C +#define CLKDLYPUCTLCH0 0x6990 +#define CLKDLYPDCTLCH0 0x6994 +#define CLKTCOPUCTLCH0 0x6998 +#define CLKTCOPDCTLCH0 0x699C +#define DQSODTPUCTLCH0 0x69A0 +#define DQSODTPDCTLCH0 0x69A4 +#define DQSDRVPUCTLCH0 0x69A8 +#define DQSDRVPDCTLCH0 0x69AC +#define DQSDLYPUCTLCH0 0x69B0 +#define DQSDLYPDCTLCH0 0x69B4 +#define DQSTCOPUCTLCH0 0x69B8 +#define DQSTCOPDCTLCH0 0x69BC +#define CTLDRVPUCTLCH0 0x69C8 +#define CTLDRVPDCTLCH0 0x69CC +#define CTLDLYPUCTLCH0 0x69D0 +#define CTLDLYPDCTLCH0 0x69D4 +#define FNLUPDTCTLCH0 0x69F0
+/* PLL */ +#define MPLLCTRL0 0x7800 +#define MPLLCTRL1 0x7808 +#define MPLLCSR0 0x7810 +#define MPLLCSR1 0x7814 +#define MPLLCSR2 0x7820 +#define MPLLDFT 0x7828 +#define MPLLMON0CTL 0x7830 +#define MPLLMON1CTL 0x7838 +#define MPLLMON2CTL 0x783C +#define SFRTRIM 0x7850 +#define MPLLDFTOUT0 0x7858 +#define MPLLDFTOUT1 0x785C +#define MASTERRSTN 0x7880 +#define PLLLOCKDEL 0x7884 +#define SFRDEL 0x7888 +#define CRUVISALANECR0 0x78F0 +#define CRUVISALANECR1 0x78F4 +#define CRUVISACONTROLCR 0x78F8 +#define IOSFVISALANECR0 0x78FC +#define IOSFVISALANECR1 0x7900 +#define IOSFVISACONTROLCR 0x7904
+/* END DDRIO Registers */
+/* DRAM Specific Message Bus OpCodes */ +#define MSG_OP_DRAM_INIT 0x68 +#define MSG_OP_DRAM_WAKE 0xCA
+#define SAMPLE_SIZE 6
+/* must be less than this number to enable early deadband */ +#define EARLY_DB 0x12 +/* must be greater than this number to enable late deadband */ +#define LATE_DB 0x34
+#define CHX_REGS (11 * 4) +#define FULL_CLK 128 +#define HALF_CLK 64 +#define QRTR_CLK 32
+#define MCEIL(num, den) ((uint8_t)((num + den - 1) / den)) +#define MMAX(a, b) ((a) > (b) ? (a) : (b)) +#define DEAD_LOOP() for (;;);
+#define MIN_RDQS_EYE 10 /* in PI Codes */ +#define MIN_VREF_EYE 10 /* in VREF Codes */ +/* how many RDQS codes to jump while margining */ +#define RDQS_STEP 1 +/* how many VREF codes to jump while margining */ +#define VREF_STEP 1 +/* offset into "vref_codes[]" for minimum allowed VREF setting */ +#define VREF_MIN 0x00 +/* offset into "vref_codes[]" for maximum allowed VREF setting */ +#define VREF_MAX 0x3F +#define RDQS_MIN 0x00 /* minimum RDQS delay value */ +#define RDQS_MAX 0x3F /* maximum RDQS delay value */
+/* how many WDQ codes to jump while margining */ +#define WDQ_STEP 1
+enum {
B, /* BOTTOM VREF */
T /* TOP VREF */
+};
+enum {
L, /* LEFT RDQS */
R /* RIGHT RDQS */
+};
+/* Memory Options */
+/* enable STATIC timing settings for RCVN (BACKUP_MODE) */ +#undef BACKUP_RCVN +/* enable STATIC timing settings for WDQS (BACKUP_MODE) */ +#undef BACKUP_WDQS +/* enable STATIC timing settings for RDQS (BACKUP_MODE) */ +#undef BACKUP_RDQS +/* enable STATIC timing settings for WDQ (BACKUP_MODE) */ +#undef BACKUP_WDQ +/* enable *COMP overrides (BACKUP_MODE) */ +#undef BACKUP_COMPS +/* enable the RD_TRAIN eye check */ +#undef RX_EYE_CHECK
+/* enable Host to Memory Clock Alignment */ +#define HMC_TEST +/* enable multi-rank support via rank2rank sharing */ +#define R2R_SHARING +/* disable signals not used in 16bit mode of DDRIO */ +#define FORCE_16BIT_DDRIO
+#define PLATFORM_ID 1
+void clear_self_refresh(struct mrc_params *mrc_params); +void prog_ddr_timing_control(struct mrc_params *mrc_params); +void prog_decode_before_jedec(struct mrc_params *mrc_params); +void perform_ddr_reset(struct mrc_params *mrc_params); +void ddrphy_init(struct mrc_params *mrc_params); +void perform_jedec_init(struct mrc_params *mrc_params); +void set_ddr_init_complete(struct mrc_params *mrc_params); +void restore_timings(struct mrc_params *mrc_params); +void default_timings(struct mrc_params *mrc_params); +void rcvn_cal(struct mrc_params *mrc_params); +void wr_level(struct mrc_params *mrc_params); +void prog_page_ctrl(struct mrc_params *mrc_params); +void rd_train(struct mrc_params *mrc_params); +void wr_train(struct mrc_params *mrc_params); +void store_timings(struct mrc_params *mrc_params); +void enable_scrambling(struct mrc_params *mrc_params); +void prog_ddr_control(struct mrc_params *mrc_params); +void prog_dra_drb(struct mrc_params *mrc_params); +void perform_wake(struct mrc_params *mrc_params); +void change_refresh_period(struct mrc_params *mrc_params); +void set_auto_refresh(struct mrc_params *mrc_params); +void ecc_enable(struct mrc_params *mrc_params); +void memory_test(struct mrc_params *mrc_params); +void lock_registers(struct mrc_params *mrc_params);
Function comments should go here.
They are only used internally in MRC.
+#endif /* _SMC_H_ */
1.8.2.1
Regards, Simon
Regards, Bin