[U-Boot] [RFC PATCH 5/9] x86: quark: Add System Memory Controller support
Simon Glass
sjg at chromium.org
Wed Feb 4 17:24:58 CET 2015
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/
> + *
> + * 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?
> +
> + 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.
> + 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.
> + 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
> + 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/
> + *
> + * 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.
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
> +
> +#define DDR3_EMRS2_RTTWR_60 (BIT9)
(1 << 9)
> +#define DDR3_EMRS2_RTTWR_120 (BIT10)
(1 << 10)
> +
> +/* 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.
> +#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.
> +
> +#endif /* _SMC_H_ */
> --
> 1.8.2.1
>
Regards,
Simon
More information about the U-Boot
mailing list