[U-Boot] [RFC PATCH 5/9] x86: quark: Add System Memory Controller support

Bin Meng bmeng.cn at gmail.com
Thu Feb 5 16:17:14 CET 2015


Hi Simon,

On Thu, Feb 5, 2015 at 12:24 AM, Simon Glass <sjg at chromium.org> wrote:
> Hi Bin,
>
> On 3 February 2015 at 04:45, Bin Meng <bmeng.cn at gmail.com> wrote:
>> The codes are actually doing the memory initialization stuff.
>>
>> Signed-off-by: Bin Meng <bmeng.cn at 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 at 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 at 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


More information about the U-Boot mailing list