uboot/arch/x86/cpu/quark/smc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: Intel
   2/*
   3 * Copyright (C) 2013, Intel Corporation
   4 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
   5 *
   6 * Ported from Intel released Quark UEFI BIOS
   7 * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
   8 */
   9
  10#include <common.h>
  11#include <pci.h>
  12#include <asm/arch/device.h>
  13#include <asm/arch/mrc.h>
  14#include <asm/arch/msg_port.h>
  15#include "mrc_util.h"
  16#include "hte.h"
  17#include "smc.h"
  18
  19/* t_ck clock period in picoseconds per speed index 800, 1066, 1333 */
  20static const uint32_t t_ck[3] = {
  21        2500,
  22        1875,
  23        1500
  24};
  25
  26/* Global variables */
  27static const uint16_t ddr_wclk[] = {193, 158};
  28#ifdef BACKUP_WCTL
  29static const uint16_t ddr_wctl[] = {1, 217};
  30#endif
  31#ifdef BACKUP_WCMD
  32static const uint16_t ddr_wcmd[] = {1, 220};
  33#endif
  34
  35#ifdef BACKUP_RCVN
  36static const uint16_t ddr_rcvn[] = {129, 498};
  37#endif
  38
  39#ifdef BACKUP_WDQS
  40static const uint16_t ddr_wdqs[] = {65, 289};
  41#endif
  42
  43#ifdef BACKUP_RDQS
  44static const uint8_t ddr_rdqs[] = {32, 24};
  45#endif
  46
  47#ifdef BACKUP_WDQ
  48static const uint16_t ddr_wdq[] = {32, 257};
  49#endif
  50
  51/* Stop self refresh driven by MCU */
  52void clear_self_refresh(struct mrc_params *mrc_params)
  53{
  54        ENTERFN();
  55
  56        /* clear the PMSTS Channel Self Refresh bits */
  57        mrc_write_mask(MEM_CTLR, PMSTS, PMSTS_DISR, PMSTS_DISR);
  58
  59        LEAVEFN();
  60}
  61
  62/* It will initialize timing registers in the MCU (DTR0..DTR4) */
  63void prog_ddr_timing_control(struct mrc_params *mrc_params)
  64{
  65        uint8_t tcl, wl;
  66        uint8_t trp, trcd, tras, twr, twtr, trrd, trtp, tfaw;
  67        uint32_t tck;
  68        u32 dtr0, dtr1, dtr2, dtr3, dtr4;
  69        u32 tmp1, tmp2;
  70
  71        ENTERFN();
  72
  73        /* mcu_init starts */
  74        mrc_post_code(0x02, 0x00);
  75
  76        dtr0 = msg_port_read(MEM_CTLR, DTR0);
  77        dtr1 = msg_port_read(MEM_CTLR, DTR1);
  78        dtr2 = msg_port_read(MEM_CTLR, DTR2);
  79        dtr3 = msg_port_read(MEM_CTLR, DTR3);
  80        dtr4 = msg_port_read(MEM_CTLR, DTR4);
  81
  82        tck = t_ck[mrc_params->ddr_speed];      /* Clock in picoseconds */
  83        tcl = mrc_params->params.cl;            /* CAS latency in clocks */
  84        trp = tcl;      /* Per CAT MRC */
  85        trcd = tcl;     /* Per CAT MRC */
  86        tras = MCEIL(mrc_params->params.ras, tck);
  87
  88        /* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
  89        twr = MCEIL(15000, tck);
  90
  91        twtr = MCEIL(mrc_params->params.wtr, tck);
  92        trrd = MCEIL(mrc_params->params.rrd, tck);
  93        trtp = 4;       /* Valid for 800 and 1066, use 5 for 1333 */
  94        tfaw = MCEIL(mrc_params->params.faw, tck);
  95
  96        wl = 5 + mrc_params->ddr_speed;
  97
  98        dtr0 &= ~DTR0_DFREQ_MASK;
  99        dtr0 |= mrc_params->ddr_speed;
 100        dtr0 &= ~DTR0_TCL_MASK;
 101        tmp1 = tcl - 5;
 102        dtr0 |= ((tcl - 5) << 12);
 103        dtr0 &= ~DTR0_TRP_MASK;
 104        dtr0 |= ((trp - 5) << 4);       /* 5 bit DRAM Clock */
 105        dtr0 &= ~DTR0_TRCD_MASK;
 106        dtr0 |= ((trcd - 5) << 8);      /* 5 bit DRAM Clock */
 107
 108        dtr1 &= ~DTR1_TWCL_MASK;
 109        tmp2 = wl - 3;
 110        dtr1 |= (wl - 3);
 111        dtr1 &= ~DTR1_TWTP_MASK;
 112        dtr1 |= ((wl + 4 + twr - 14) << 8);     /* Change to tWTP */
 113        dtr1 &= ~DTR1_TRTP_MASK;
 114        dtr1 |= ((MMAX(trtp, 4) - 3) << 28);    /* 4 bit DRAM Clock */
 115        dtr1 &= ~DTR1_TRRD_MASK;
 116        dtr1 |= ((trrd - 4) << 24);             /* 4 bit DRAM Clock */
 117        dtr1 &= ~DTR1_TCMD_MASK;
 118        dtr1 |= (1 << 4);
 119        dtr1 &= ~DTR1_TRAS_MASK;
 120        dtr1 |= ((tras - 14) << 20);            /* 6 bit DRAM Clock */
 121        dtr1 &= ~DTR1_TFAW_MASK;
 122        dtr1 |= ((((tfaw + 1) >> 1) - 5) << 16);/* 4 bit DRAM Clock */
 123        /* Set 4 Clock CAS to CAS delay (multi-burst) */
 124        dtr1 &= ~DTR1_TCCD_MASK;
 125
 126        dtr2 &= ~DTR2_TRRDR_MASK;
 127        dtr2 |= 1;
 128        dtr2 &= ~DTR2_TWWDR_MASK;
 129        dtr2 |= (2 << 8);
 130        dtr2 &= ~DTR2_TRWDR_MASK;
 131        dtr2 |= (2 << 16);
 132
 133        dtr3 &= ~DTR3_TWRDR_MASK;
 134        dtr3 |= 2;
 135        dtr3 &= ~DTR3_TXXXX_MASK;
 136        dtr3 |= (2 << 4);
 137
 138        dtr3 &= ~DTR3_TRWSR_MASK;
 139        if (mrc_params->ddr_speed == DDRFREQ_800) {
 140                /* Extended RW delay (+1) */
 141                dtr3 |= ((tcl - 5 + 1) << 8);
 142        } else if (mrc_params->ddr_speed == DDRFREQ_1066) {
 143                /* Extended RW delay (+1) */
 144                dtr3 |= ((tcl - 5 + 1) << 8);
 145        }
 146
 147        dtr3 &= ~DTR3_TWRSR_MASK;
 148        dtr3 |= ((4 + wl + twtr - 11) << 13);
 149
 150        dtr3 &= ~DTR3_TXP_MASK;
 151        if (mrc_params->ddr_speed == DDRFREQ_800)
 152                dtr3 |= ((MMAX(0, 1 - 1)) << 22);
 153        else
 154                dtr3 |= ((MMAX(0, 2 - 1)) << 22);
 155
 156        dtr4 &= ~DTR4_WRODTSTRT_MASK;
 157        dtr4 |= 1;
 158        dtr4 &= ~DTR4_WRODTSTOP_MASK;
 159        dtr4 |= (1 << 4);
 160        dtr4 &= ~DTR4_XXXX1_MASK;
 161        dtr4 |= ((1 + tmp1 - tmp2 + 2) << 8);
 162        dtr4 &= ~DTR4_XXXX2_MASK;
 163        dtr4 |= ((1 + tmp1 - tmp2 + 2) << 12);
 164        dtr4 &= ~(DTR4_ODTDIS | DTR4_TRGSTRDIS);
 165
 166        msg_port_write(MEM_CTLR, DTR0, dtr0);
 167        msg_port_write(MEM_CTLR, DTR1, dtr1);
 168        msg_port_write(MEM_CTLR, DTR2, dtr2);
 169        msg_port_write(MEM_CTLR, DTR3, dtr3);
 170        msg_port_write(MEM_CTLR, DTR4, dtr4);
 171
 172        LEAVEFN();
 173}
 174
 175/* Configure MCU before jedec init sequence */
 176void prog_decode_before_jedec(struct mrc_params *mrc_params)
 177{
 178        u32 drp;
 179        u32 drfc;
 180        u32 dcal;
 181        u32 dsch;
 182        u32 dpmc0;
 183
 184        ENTERFN();
 185
 186        /* Disable power saving features */
 187        dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
 188        dpmc0 |= (DPMC0_CLKGTDIS | DPMC0_DISPWRDN);
 189        dpmc0 &= ~DPMC0_PCLSTO_MASK;
 190        dpmc0 &= ~DPMC0_DYNSREN;
 191        msg_port_write(MEM_CTLR, DPMC0, dpmc0);
 192
 193        /* Disable out of order transactions */
 194        dsch = msg_port_read(MEM_CTLR, DSCH);
 195        dsch |= (DSCH_OOODIS | DSCH_NEWBYPDIS);
 196        msg_port_write(MEM_CTLR, DSCH, dsch);
 197
 198        /* Disable issuing the REF command */
 199        drfc = msg_port_read(MEM_CTLR, DRFC);
 200        drfc &= ~DRFC_TREFI_MASK;
 201        msg_port_write(MEM_CTLR, DRFC, drfc);
 202
 203        /* Disable ZQ calibration short */
 204        dcal = msg_port_read(MEM_CTLR, DCAL);
 205        dcal &= ~DCAL_ZQCINT_MASK;
 206        dcal &= ~DCAL_SRXZQCL_MASK;
 207        msg_port_write(MEM_CTLR, DCAL, dcal);
 208
 209        /*
 210         * Training performed in address mode 0, rank population has limited
 211         * impact, however simulator complains if enabled non-existing rank.
 212         */
 213        drp = 0;
 214        if (mrc_params->rank_enables & 1)
 215                drp |= DRP_RKEN0;
 216        if (mrc_params->rank_enables & 2)
 217                drp |= DRP_RKEN1;
 218        msg_port_write(MEM_CTLR, DRP, drp);
 219
 220        LEAVEFN();
 221}
 222
 223/*
 224 * After Cold Reset, BIOS should set COLDWAKE bit to 1 before
 225 * sending the WAKE message to the Dunit.
 226 *
 227 * For Standby Exit, or any other mode in which the DRAM is in
 228 * SR, this bit must be set to 0.
 229 */
 230void perform_ddr_reset(struct mrc_params *mrc_params)
 231{
 232        ENTERFN();
 233
 234        /* Set COLDWAKE bit before sending the WAKE message */
 235        mrc_write_mask(MEM_CTLR, DRMC, DRMC_COLDWAKE, DRMC_COLDWAKE);
 236
 237        /* Send wake command to DUNIT (MUST be done before JEDEC) */
 238        dram_wake_command();
 239
 240        /* Set default value */
 241        msg_port_write(MEM_CTLR, DRMC,
 242                       mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0);
 243
 244        LEAVEFN();
 245}
 246
 247
 248/*
 249 * This function performs some initialization on the DDRIO unit.
 250 * This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
 251 */
 252void ddrphy_init(struct mrc_params *mrc_params)
 253{
 254        uint32_t temp;
 255        uint8_t ch;     /* channel counter */
 256        uint8_t rk;     /* rank counter */
 257        uint8_t bl_grp; /*  byte lane group counter (2 BLs per module) */
 258        uint8_t bl_divisor = 1; /* byte lane divisor */
 259        /* For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 */
 260        uint8_t speed = mrc_params->ddr_speed & 3;
 261        uint8_t cas;
 262        uint8_t cwl;
 263
 264        ENTERFN();
 265
 266        cas = mrc_params->params.cl;
 267        cwl = 5 + mrc_params->ddr_speed;
 268
 269        /* ddrphy_init starts */
 270        mrc_post_code(0x03, 0x00);
 271
 272        /*
 273         * HSD#231531
 274         * Make sure IOBUFACT is deasserted before initializing the DDR PHY
 275         *
 276         * HSD#234845
 277         * Make sure WRPTRENABLE is deasserted before initializing the DDR PHY
 278         */
 279        for (ch = 0; ch < NUM_CHANNELS; ch++) {
 280                if (mrc_params->channel_enables & (1 << ch)) {
 281                        /* Deassert DDRPHY Initialization Complete */
 282                        mrc_alt_write_mask(DDRPHY,
 283                                CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
 284                                ~(1 << 20), 1 << 20);   /* SPID_INIT_COMPLETE=0 */
 285                        /* Deassert IOBUFACT */
 286                        mrc_alt_write_mask(DDRPHY,
 287                                CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
 288                                ~(1 << 2), 1 << 2);     /* IOBUFACTRST_N=0 */
 289                        /* Disable WRPTR */
 290                        mrc_alt_write_mask(DDRPHY,
 291                                CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
 292                                ~(1 << 0), 1 << 0);     /* WRPTRENABLE=0 */
 293                }
 294        }
 295
 296        /* Put PHY in reset */
 297        mrc_alt_write_mask(DDRPHY, MASTERRSTN, 0, 1);
 298
 299        /* Initialize DQ01, DQ23, CMD, CLK-CTL, COMP modules */
 300
 301        /* STEP0 */
 302        mrc_post_code(0x03, 0x10);
 303        for (ch = 0; ch < NUM_CHANNELS; ch++) {
 304                if (mrc_params->channel_enables & (1 << ch)) {
 305                        /* DQ01-DQ23 */
 306                        for (bl_grp = 0;
 307                             bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
 308                             bl_grp++) {
 309                                /* Analog MUX select - IO2xCLKSEL */
 310                                mrc_alt_write_mask(DDRPHY,
 311                                        DQOBSCKEBBCTL +
 312                                        bl_grp * DDRIODQ_BL_OFFSET +
 313                                        ch * DDRIODQ_CH_OFFSET,
 314                                        bl_grp ? 0 : (1 << 22), 1 << 22);
 315
 316                                /* ODT Strength */
 317                                switch (mrc_params->rd_odt_value) {
 318                                case 1:
 319                                        temp = 0x3;
 320                                        break;  /* 60 ohm */
 321                                case 2:
 322                                        temp = 0x3;
 323                                        break;  /* 120 ohm */
 324                                case 3:
 325                                        temp = 0x3;
 326                                        break;  /* 180 ohm */
 327                                default:
 328                                        temp = 0x3;
 329                                        break;  /* 120 ohm */
 330                                }
 331
 332                                /* ODT strength */
 333                                mrc_alt_write_mask(DDRPHY,
 334                                        B0RXIOBUFCTL +
 335                                        bl_grp * DDRIODQ_BL_OFFSET +
 336                                        ch * DDRIODQ_CH_OFFSET,
 337                                        temp << 5, 0x60);
 338                                /* ODT strength */
 339                                mrc_alt_write_mask(DDRPHY,
 340                                        B1RXIOBUFCTL +
 341                                        bl_grp * DDRIODQ_BL_OFFSET +
 342                                        ch * DDRIODQ_CH_OFFSET,
 343                                        temp << 5, 0x60);
 344
 345                                /* Dynamic ODT/DIFFAMP */
 346                                temp = (cas << 24) | (cas << 16) |
 347                                        (cas << 8) | (cas << 0);
 348                                switch (speed) {
 349                                case 0:
 350                                        temp -= 0x01010101;
 351                                        break;  /* 800 */
 352                                case 1:
 353                                        temp -= 0x02020202;
 354                                        break;  /* 1066 */
 355                                case 2:
 356                                        temp -= 0x03030303;
 357                                        break;  /* 1333 */
 358                                case 3:
 359                                        temp -= 0x04040404;
 360                                        break;  /* 1600 */
 361                                }
 362
 363                                /* Launch Time: ODT, DIFFAMP, ODT, DIFFAMP */
 364                                mrc_alt_write_mask(DDRPHY,
 365                                        B01LATCTL1 +
 366                                        bl_grp * DDRIODQ_BL_OFFSET +
 367                                        ch * DDRIODQ_CH_OFFSET,
 368                                        temp, 0x1f1f1f1f);
 369                                switch (speed) {
 370                                /* HSD#234715 */
 371                                case 0:
 372                                        temp = (0x06 << 16) | (0x07 << 8);
 373                                        break;  /* 800 */
 374                                case 1:
 375                                        temp = (0x07 << 16) | (0x08 << 8);
 376                                        break;  /* 1066 */
 377                                case 2:
 378                                        temp = (0x09 << 16) | (0x0a << 8);
 379                                        break;  /* 1333 */
 380                                case 3:
 381                                        temp = (0x0a << 16) | (0x0b << 8);
 382                                        break;  /* 1600 */
 383                                }
 384
 385                                /* On Duration: ODT, DIFFAMP */
 386                                mrc_alt_write_mask(DDRPHY,
 387                                        B0ONDURCTL +
 388                                        bl_grp * DDRIODQ_BL_OFFSET +
 389                                        ch * DDRIODQ_CH_OFFSET,
 390                                        temp, 0x003f3f00);
 391                                /* On Duration: ODT, DIFFAMP */
 392                                mrc_alt_write_mask(DDRPHY,
 393                                        B1ONDURCTL +
 394                                        bl_grp * DDRIODQ_BL_OFFSET +
 395                                        ch * DDRIODQ_CH_OFFSET,
 396                                        temp, 0x003f3f00);
 397
 398                                switch (mrc_params->rd_odt_value) {
 399                                case 0:
 400                                        /* override DIFFAMP=on, ODT=off */
 401                                        temp = (0x3f << 16) | (0x3f << 10);
 402                                        break;
 403                                default:
 404                                        /* override DIFFAMP=on, ODT=on */
 405                                        temp = (0x3f << 16) | (0x2a << 10);
 406                                        break;
 407                                }
 408
 409                                /* Override: DIFFAMP, ODT */
 410                                mrc_alt_write_mask(DDRPHY,
 411                                        B0OVRCTL +
 412                                        bl_grp * DDRIODQ_BL_OFFSET +
 413                                        ch * DDRIODQ_CH_OFFSET,
 414                                        temp, 0x003ffc00);
 415                                /* Override: DIFFAMP, ODT */
 416                                mrc_alt_write_mask(DDRPHY,
 417                                        B1OVRCTL +
 418                                        bl_grp * DDRIODQ_BL_OFFSET +
 419                                        ch * DDRIODQ_CH_OFFSET,
 420                                        temp, 0x003ffc00);
 421
 422                                /* DLL Setup */
 423
 424                                /* 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) */
 425                                mrc_alt_write_mask(DDRPHY,
 426                                        B0LATCTL0 +
 427                                        bl_grp * DDRIODQ_BL_OFFSET +
 428                                        ch * DDRIODQ_CH_OFFSET,
 429                                        ((cas + 7) << 16) | ((cas - 4) << 8) |
 430                                        ((cwl - 2) << 0), 0x003f1f1f);
 431                                mrc_alt_write_mask(DDRPHY,
 432                                        B1LATCTL0 +
 433                                        bl_grp * DDRIODQ_BL_OFFSET +
 434                                        ch * DDRIODQ_CH_OFFSET,
 435                                        ((cas + 7) << 16) | ((cas - 4) << 8) |
 436                                        ((cwl - 2) << 0), 0x003f1f1f);
 437
 438                                /* RCVEN Bypass (PO) */
 439                                mrc_alt_write_mask(DDRPHY,
 440                                        B0RXIOBUFCTL +
 441                                        bl_grp * DDRIODQ_BL_OFFSET +
 442                                        ch * DDRIODQ_CH_OFFSET,
 443                                        0, 0x81);
 444                                mrc_alt_write_mask(DDRPHY,
 445                                        B1RXIOBUFCTL +
 446                                        bl_grp * DDRIODQ_BL_OFFSET +
 447                                        ch * DDRIODQ_CH_OFFSET,
 448                                        0, 0x81);
 449
 450                                /* TX */
 451                                mrc_alt_write_mask(DDRPHY,
 452                                        DQCTL +
 453                                        bl_grp * DDRIODQ_BL_OFFSET +
 454                                        ch * DDRIODQ_CH_OFFSET,
 455                                        1 << 16, 1 << 16);
 456                                mrc_alt_write_mask(DDRPHY,
 457                                        B01PTRCTL1 +
 458                                        bl_grp * DDRIODQ_BL_OFFSET +
 459                                        ch * DDRIODQ_CH_OFFSET,
 460                                        1 << 8, 1 << 8);
 461
 462                                /* RX (PO) */
 463                                /* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
 464                                mrc_alt_write_mask(DDRPHY,
 465                                        B0VREFCTL +
 466                                        bl_grp * DDRIODQ_BL_OFFSET +
 467                                        ch * DDRIODQ_CH_OFFSET,
 468                                        (0x03 << 2) | (0x0 << 1) | (0x0 << 0),
 469                                        0xff);
 470                                /* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
 471                                mrc_alt_write_mask(DDRPHY,
 472                                        B1VREFCTL +
 473                                        bl_grp * DDRIODQ_BL_OFFSET +
 474                                        ch * DDRIODQ_CH_OFFSET,
 475                                        (0x03 << 2) | (0x0 << 1) | (0x0 << 0),
 476                                        0xff);
 477                                /* Per-Bit De-Skew Enable */
 478                                mrc_alt_write_mask(DDRPHY,
 479                                        B0RXIOBUFCTL +
 480                                        bl_grp * DDRIODQ_BL_OFFSET +
 481                                        ch * DDRIODQ_CH_OFFSET,
 482                                        0, 0x10);
 483                                /* Per-Bit De-Skew Enable */
 484                                mrc_alt_write_mask(DDRPHY,
 485                                        B1RXIOBUFCTL +
 486                                        bl_grp * DDRIODQ_BL_OFFSET +
 487                                        ch * DDRIODQ_CH_OFFSET,
 488                                        0, 0x10);
 489                        }
 490
 491                        /* CLKEBB */
 492                        mrc_alt_write_mask(DDRPHY,
 493                                CMDOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
 494                                0, 1 << 23);
 495
 496                        /* Enable tristate control of cmd/address bus */
 497                        mrc_alt_write_mask(DDRPHY,
 498                                CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
 499                                0, 0x03);
 500
 501                        /* ODT RCOMP */
 502                        mrc_alt_write_mask(DDRPHY,
 503                                CMDRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
 504                                (0x03 << 5) | (0x03 << 0), 0x3ff);
 505
 506                        /* CMDPM* registers must be programmed in this order */
 507
 508                        /* Turn On Delays: SFR (regulator), MPLL */
 509                        mrc_alt_write_mask(DDRPHY,
 510                                CMDPMDLYREG4 + ch * DDRIOCCC_CH_OFFSET,
 511                                0xffffffff, 0xffffffff);
 512                        /*
 513                         * Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3,
 514                         * VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT
 515                         * for_PM_MSG_gt0, MDLL Turn On
 516                         */
 517                        mrc_alt_write_mask(DDRPHY,
 518                                CMDPMDLYREG3 + ch * DDRIOCCC_CH_OFFSET,
 519                                0xfffff616, 0xffffffff);
 520                        /* MPLL Divider Reset Delays */
 521                        mrc_alt_write_mask(DDRPHY,
 522                                CMDPMDLYREG2 + ch * DDRIOCCC_CH_OFFSET,
 523                                0xffffffff, 0xffffffff);
 524                        /* Turn Off Delays: VREG, Staggered MDLL, MDLL, PI */
 525                        mrc_alt_write_mask(DDRPHY,
 526                                CMDPMDLYREG1 + ch * DDRIOCCC_CH_OFFSET,
 527                                0xffffffff, 0xffffffff);
 528                        /* Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT */
 529                        mrc_alt_write_mask(DDRPHY,
 530                                CMDPMDLYREG0 + ch * DDRIOCCC_CH_OFFSET,
 531                                0xffffffff, 0xffffffff);
 532                        /* Allow PUnit signals */
 533                        mrc_alt_write_mask(DDRPHY,
 534                                CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
 535                                (0x6 << 8) | (0x1 << 6) | (0x4 << 0),
 536                                0xffe00f4f);
 537                        /* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
 538                        mrc_alt_write_mask(DDRPHY,
 539                                CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
 540                                (0x3 << 4) | (0x7 << 0), 0x7f);
 541
 542                        /* CLK-CTL */
 543                        mrc_alt_write_mask(DDRPHY,
 544                                CCOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
 545                                0, 1 << 24);    /* CLKEBB */
 546                        /* Buffer Enable: CS,CKE,ODT,CLK */
 547                        mrc_alt_write_mask(DDRPHY,
 548                                CCCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
 549                                0x1f, 0x000ffff1);
 550                        /* ODT RCOMP */
 551                        mrc_alt_write_mask(DDRPHY,
 552                                CCRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
 553                                (0x03 << 8) | (0x03 << 0), 0x00001f1f);
 554                        /* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
 555                        mrc_alt_write_mask(DDRPHY,
 556                                CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
 557                                (0x3 << 4) | (0x7 << 0), 0x7f);
 558
 559                        /*
 560                         * COMP (RON channel specific)
 561                         * - DQ/DQS/DM RON: 32 Ohm
 562                         * - CTRL/CMD RON: 27 Ohm
 563                         * - CLK RON: 26 Ohm
 564                         */
 565                        /* RCOMP Vref PU/PD */
 566                        mrc_alt_write_mask(DDRPHY,
 567                                DQVREFCH0 +  ch * DDRCOMP_CH_OFFSET,
 568                                (0x08 << 24) | (0x03 << 16), 0x3f3f0000);
 569                        /* RCOMP Vref PU/PD */
 570                        mrc_alt_write_mask(DDRPHY,
 571                                CMDVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 572                                (0x0C << 24) | (0x03 << 16), 0x3f3f0000);
 573                        /* RCOMP Vref PU/PD */
 574                        mrc_alt_write_mask(DDRPHY,
 575                                CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 576                                (0x0F << 24) | (0x03 << 16), 0x3f3f0000);
 577                        /* RCOMP Vref PU/PD */
 578                        mrc_alt_write_mask(DDRPHY,
 579                                DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 580                                (0x08 << 24) | (0x03 << 16), 0x3f3f0000);
 581                        /* RCOMP Vref PU/PD */
 582                        mrc_alt_write_mask(DDRPHY,
 583                                CTLVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 584                                (0x0C << 24) | (0x03 << 16), 0x3f3f0000);
 585
 586                        /* DQS Swapped Input Enable */
 587                        mrc_alt_write_mask(DDRPHY,
 588                                COMPEN1CH0 + ch * DDRCOMP_CH_OFFSET,
 589                                (1 << 19) | (1 << 17), 0xc00ac000);
 590
 591                        /* ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) */
 592                        /* ODT Vref PU/PD */
 593                        mrc_alt_write_mask(DDRPHY,
 594                                DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 595                                (0x32 << 8) | (0x03 << 0), 0x00003f3f);
 596                        /* ODT Vref PU/PD */
 597                        mrc_alt_write_mask(DDRPHY,
 598                                DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 599                                (0x32 << 8) | (0x03 << 0), 0x00003f3f);
 600                        /* ODT Vref PU/PD */
 601                        mrc_alt_write_mask(DDRPHY,
 602                                CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 603                                (0x0E << 8) | (0x05 << 0), 0x00003f3f);
 604
 605                        /*
 606                         * Slew rate settings are frequency specific,
 607                         * numbers below are for 800Mhz (speed == 0)
 608                         * - DQ/DQS/DM/CLK SR: 4V/ns,
 609                         * - CTRL/CMD SR: 1.5V/ns
 610                         */
 611                        temp = (0x0e << 16) | (0x0e << 12) | (0x08 << 8) |
 612                                (0x0b << 4) | (0x0b << 0);
 613                        /* DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ */
 614                        mrc_alt_write_mask(DDRPHY,
 615                                DLYSELCH0 + ch * DDRCOMP_CH_OFFSET,
 616                                temp, 0x000fffff);
 617                        /* TCO Vref CLK,DQS,DQ */
 618                        mrc_alt_write_mask(DDRPHY,
 619                                TCOVREFCH0 + ch * DDRCOMP_CH_OFFSET,
 620                                (0x05 << 16) | (0x05 << 8) | (0x05 << 0),
 621                                0x003f3f3f);
 622                        /* ODTCOMP CMD/CTL PU/PD */
 623                        mrc_alt_write_mask(DDRPHY,
 624                                CCBUFODTCH0 + ch * DDRCOMP_CH_OFFSET,
 625                                (0x03 << 8) | (0x03 << 0),
 626                                0x00001f1f);
 627                        /* COMP */
 628                        mrc_alt_write_mask(DDRPHY,
 629                                COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
 630                                0, 0xc0000100);
 631
 632#ifdef BACKUP_COMPS
 633                        /* DQ COMP Overrides */
 634                        /* RCOMP PU */
 635                        mrc_alt_write_mask(DDRPHY,
 636                                DQDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 637                                (1 << 31) | (0x0a << 16),
 638                                0x801f0000);
 639                        /* RCOMP PD */
 640                        mrc_alt_write_mask(DDRPHY,
 641                                DQDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 642                                (1 << 31) | (0x0a << 16),
 643                                0x801f0000);
 644                        /* DCOMP PU */
 645                        mrc_alt_write_mask(DDRPHY,
 646                                DQDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 647                                (1 << 31) | (0x10 << 16),
 648                                0x801f0000);
 649                        /* DCOMP PD */
 650                        mrc_alt_write_mask(DDRPHY,
 651                                DQDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 652                                (1 << 31) | (0x10 << 16),
 653                                0x801f0000);
 654                        /* ODTCOMP PU */
 655                        mrc_alt_write_mask(DDRPHY,
 656                                DQODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 657                                (1 << 31) | (0x0b << 16),
 658                                0x801f0000);
 659                        /* ODTCOMP PD */
 660                        mrc_alt_write_mask(DDRPHY,
 661                                DQODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 662                                (1 << 31) | (0x0b << 16),
 663                                0x801f0000);
 664                        /* TCOCOMP PU */
 665                        mrc_alt_write_mask(DDRPHY,
 666                                DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 667                                1 << 31, 1 << 31);
 668                        /* TCOCOMP PD */
 669                        mrc_alt_write_mask(DDRPHY,
 670                                DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 671                                1 << 31, 1 << 31);
 672
 673                        /* DQS COMP Overrides */
 674                        /* RCOMP PU */
 675                        mrc_alt_write_mask(DDRPHY,
 676                                DQSDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 677                                (1 << 31) | (0x0a << 16),
 678                                0x801f0000);
 679                        /* RCOMP PD */
 680                        mrc_alt_write_mask(DDRPHY,
 681                                DQSDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 682                                (1 << 31) | (0x0a << 16),
 683                                0x801f0000);
 684                        /* DCOMP PU */
 685                        mrc_alt_write_mask(DDRPHY,
 686                                DQSDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 687                                (1 << 31) | (0x10 << 16),
 688                                0x801f0000);
 689                        /* DCOMP PD */
 690                        mrc_alt_write_mask(DDRPHY,
 691                                DQSDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 692                                (1 << 31) | (0x10 << 16),
 693                                0x801f0000);
 694                        /* ODTCOMP PU */
 695                        mrc_alt_write_mask(DDRPHY,
 696                                DQSODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 697                                (1 << 31) | (0x0b << 16),
 698                                0x801f0000);
 699                        /* ODTCOMP PD */
 700                        mrc_alt_write_mask(DDRPHY,
 701                                DQSODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 702                                (1 << 31) | (0x0b << 16),
 703                                0x801f0000);
 704                        /* TCOCOMP PU */
 705                        mrc_alt_write_mask(DDRPHY,
 706                                DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 707                                1 << 31, 1 << 31);
 708                        /* TCOCOMP PD */
 709                        mrc_alt_write_mask(DDRPHY,
 710                                DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 711                                1 << 31, 1 << 31);
 712
 713                        /* CLK COMP Overrides */
 714                        /* RCOMP PU */
 715                        mrc_alt_write_mask(DDRPHY,
 716                                CLKDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 717                                (1 << 31) | (0x0c << 16),
 718                                0x801f0000);
 719                        /* RCOMP PD */
 720                        mrc_alt_write_mask(DDRPHY,
 721                                CLKDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 722                                (1 << 31) | (0x0c << 16),
 723                                0x801f0000);
 724                        /* DCOMP PU */
 725                        mrc_alt_write_mask(DDRPHY,
 726                                CLKDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 727                                (1 << 31) | (0x07 << 16),
 728                                0x801f0000);
 729                        /* DCOMP PD */
 730                        mrc_alt_write_mask(DDRPHY,
 731                                CLKDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 732                                (1 << 31) | (0x07 << 16),
 733                                0x801f0000);
 734                        /* ODTCOMP PU */
 735                        mrc_alt_write_mask(DDRPHY,
 736                                CLKODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 737                                (1 << 31) | (0x0b << 16),
 738                                0x801f0000);
 739                        /* ODTCOMP PD */
 740                        mrc_alt_write_mask(DDRPHY,
 741                                CLKODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 742                                (1 << 31) | (0x0b << 16),
 743                                0x801f0000);
 744                        /* TCOCOMP PU */
 745                        mrc_alt_write_mask(DDRPHY,
 746                                CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 747                                1 << 31, 1 << 31);
 748                        /* TCOCOMP PD */
 749                        mrc_alt_write_mask(DDRPHY,
 750                                CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 751                                1 << 31, 1 << 31);
 752
 753                        /* CMD COMP Overrides */
 754                        /* RCOMP PU */
 755                        mrc_alt_write_mask(DDRPHY,
 756                                CMDDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 757                                (1 << 31) | (0x0d << 16),
 758                                0x803f0000);
 759                        /* RCOMP PD */
 760                        mrc_alt_write_mask(DDRPHY,
 761                                CMDDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 762                                (1 << 31) | (0x0d << 16),
 763                                0x803f0000);
 764                        /* DCOMP PU */
 765                        mrc_alt_write_mask(DDRPHY,
 766                                CMDDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 767                                (1 << 31) | (0x0a << 16),
 768                                0x801f0000);
 769                        /* DCOMP PD */
 770                        mrc_alt_write_mask(DDRPHY,
 771                                CMDDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 772                                (1 << 31) | (0x0a << 16),
 773                                0x801f0000);
 774
 775                        /* CTL COMP Overrides */
 776                        /* RCOMP PU */
 777                        mrc_alt_write_mask(DDRPHY,
 778                                CTLDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 779                                (1 << 31) | (0x0d << 16),
 780                                0x803f0000);
 781                        /* RCOMP PD */
 782                        mrc_alt_write_mask(DDRPHY,
 783                                CTLDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 784                                (1 << 31) | (0x0d << 16),
 785                                0x803f0000);
 786                        /* DCOMP PU */
 787                        mrc_alt_write_mask(DDRPHY,
 788                                CTLDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 789                                (1 << 31) | (0x0a << 16),
 790                                0x801f0000);
 791                        /* DCOMP PD */
 792                        mrc_alt_write_mask(DDRPHY,
 793                                CTLDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 794                                (1 << 31) | (0x0a << 16),
 795                                0x801f0000);
 796#else
 797                        /* DQ TCOCOMP Overrides */
 798                        /* TCOCOMP PU */
 799                        mrc_alt_write_mask(DDRPHY,
 800                                DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 801                                (1 << 31) | (0x1f << 16),
 802                                0x801f0000);
 803                        /* TCOCOMP PD */
 804                        mrc_alt_write_mask(DDRPHY,
 805                                DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 806                                (1 << 31) | (0x1f << 16),
 807                                0x801f0000);
 808
 809                        /* DQS TCOCOMP Overrides */
 810                        /* TCOCOMP PU */
 811                        mrc_alt_write_mask(DDRPHY,
 812                                DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 813                                (1 << 31) | (0x1f << 16),
 814                                0x801f0000);
 815                        /* TCOCOMP PD */
 816                        mrc_alt_write_mask(DDRPHY,
 817                                DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 818                                (1 << 31) | (0x1f << 16),
 819                                0x801f0000);
 820
 821                        /* CLK TCOCOMP Overrides */
 822                        /* TCOCOMP PU */
 823                        mrc_alt_write_mask(DDRPHY,
 824                                CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 825                                (1 << 31) | (0x1f << 16),
 826                                0x801f0000);
 827                        /* TCOCOMP PD */
 828                        mrc_alt_write_mask(DDRPHY,
 829                                CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
 830                                (1 << 31) | (0x1f << 16),
 831                                0x801f0000);
 832#endif
 833
 834                        /* program STATIC delays */
 835#ifdef BACKUP_WCMD
 836                        set_wcmd(ch, ddr_wcmd[PLATFORM_ID]);
 837#else
 838                        set_wcmd(ch, ddr_wclk[PLATFORM_ID] + HALF_CLK);
 839#endif
 840
 841                        for (rk = 0; rk < NUM_RANKS; rk++) {
 842                                if (mrc_params->rank_enables & (1 << rk)) {
 843                                        set_wclk(ch, rk, ddr_wclk[PLATFORM_ID]);
 844#ifdef BACKUP_WCTL
 845                                        set_wctl(ch, rk, ddr_wctl[PLATFORM_ID]);
 846#else
 847                                        set_wctl(ch, rk, ddr_wclk[PLATFORM_ID] + HALF_CLK);
 848#endif
 849                                }
 850                        }
 851                }
 852        }
 853
 854        /* COMP (non channel specific) */
 855        /* RCOMP: Dither PU Enable */
 856        mrc_alt_write_mask(DDRPHY, DQANADRVPUCTL, 1 << 30, 1 << 30);
 857        /* RCOMP: Dither PD Enable */
 858        mrc_alt_write_mask(DDRPHY, DQANADRVPDCTL, 1 << 30, 1 << 30);
 859        /* RCOMP: Dither PU Enable */
 860        mrc_alt_write_mask(DDRPHY, CMDANADRVPUCTL, 1 << 30, 1 << 30);
 861        /* RCOMP: Dither PD Enable */
 862        mrc_alt_write_mask(DDRPHY, CMDANADRVPDCTL, 1 << 30, 1 << 30);
 863        /* RCOMP: Dither PU Enable */
 864        mrc_alt_write_mask(DDRPHY, CLKANADRVPUCTL, 1 << 30, 1 << 30);
 865        /* RCOMP: Dither PD Enable */
 866        mrc_alt_write_mask(DDRPHY, CLKANADRVPDCTL, 1 << 30, 1 << 30);
 867        /* RCOMP: Dither PU Enable */
 868        mrc_alt_write_mask(DDRPHY, DQSANADRVPUCTL, 1 << 30, 1 << 30);
 869        /* RCOMP: Dither PD Enable */
 870        mrc_alt_write_mask(DDRPHY, DQSANADRVPDCTL, 1 << 30, 1 << 30);
 871        /* RCOMP: Dither PU Enable */
 872        mrc_alt_write_mask(DDRPHY, CTLANADRVPUCTL, 1 << 30, 1 << 30);
 873        /* RCOMP: Dither PD Enable */
 874        mrc_alt_write_mask(DDRPHY, CTLANADRVPDCTL, 1 << 30, 1 << 30);
 875        /* ODT: Dither PU Enable */
 876        mrc_alt_write_mask(DDRPHY, DQANAODTPUCTL, 1 << 30, 1 << 30);
 877        /* ODT: Dither PD Enable */
 878        mrc_alt_write_mask(DDRPHY, DQANAODTPDCTL, 1 << 30, 1 << 30);
 879        /* ODT: Dither PU Enable */
 880        mrc_alt_write_mask(DDRPHY, CLKANAODTPUCTL, 1 << 30, 1 << 30);
 881        /* ODT: Dither PD Enable */
 882        mrc_alt_write_mask(DDRPHY, CLKANAODTPDCTL, 1 << 30, 1 << 30);
 883        /* ODT: Dither PU Enable */
 884        mrc_alt_write_mask(DDRPHY, DQSANAODTPUCTL, 1 << 30, 1 << 30);
 885        /* ODT: Dither PD Enable */
 886        mrc_alt_write_mask(DDRPHY, DQSANAODTPDCTL, 1 << 30, 1 << 30);
 887        /* DCOMP: Dither PU Enable */
 888        mrc_alt_write_mask(DDRPHY, DQANADLYPUCTL, 1 << 30, 1 << 30);
 889        /* DCOMP: Dither PD Enable */
 890        mrc_alt_write_mask(DDRPHY, DQANADLYPDCTL, 1 << 30, 1 << 30);
 891        /* DCOMP: Dither PU Enable */
 892        mrc_alt_write_mask(DDRPHY, CMDANADLYPUCTL, 1 << 30, 1 << 30);
 893        /* DCOMP: Dither PD Enable */
 894        mrc_alt_write_mask(DDRPHY, CMDANADLYPDCTL, 1 << 30, 1 << 30);
 895        /* DCOMP: Dither PU Enable */
 896        mrc_alt_write_mask(DDRPHY, CLKANADLYPUCTL, 1 << 30, 1 << 30);
 897        /* DCOMP: Dither PD Enable */
 898        mrc_alt_write_mask(DDRPHY, CLKANADLYPDCTL, 1 << 30, 1 << 30);
 899        /* DCOMP: Dither PU Enable */
 900        mrc_alt_write_mask(DDRPHY, DQSANADLYPUCTL, 1 << 30, 1 << 30);
 901        /* DCOMP: Dither PD Enable */
 902        mrc_alt_write_mask(DDRPHY, DQSANADLYPDCTL, 1 << 30, 1 << 30);
 903        /* DCOMP: Dither PU Enable */
 904        mrc_alt_write_mask(DDRPHY, CTLANADLYPUCTL, 1 << 30, 1 << 30);
 905        /* DCOMP: Dither PD Enable */
 906        mrc_alt_write_mask(DDRPHY, CTLANADLYPDCTL, 1 << 30, 1 << 30);
 907        /* TCO: Dither PU Enable */
 908        mrc_alt_write_mask(DDRPHY, DQANATCOPUCTL, 1 << 30, 1 << 30);
 909        /* TCO: Dither PD Enable */
 910        mrc_alt_write_mask(DDRPHY, DQANATCOPDCTL, 1 << 30, 1 << 30);
 911        /* TCO: Dither PU Enable */
 912        mrc_alt_write_mask(DDRPHY, CLKANATCOPUCTL, 1 << 30, 1 << 30);
 913        /* TCO: Dither PD Enable */
 914        mrc_alt_write_mask(DDRPHY, CLKANATCOPDCTL, 1 << 30, 1 << 30);
 915        /* TCO: Dither PU Enable */
 916        mrc_alt_write_mask(DDRPHY, DQSANATCOPUCTL, 1 << 30, 1 << 30);
 917        /* TCO: Dither PD Enable */
 918        mrc_alt_write_mask(DDRPHY, DQSANATCOPDCTL, 1 << 30, 1 << 30);
 919        /* TCOCOMP: Pulse Count */
 920        mrc_alt_write_mask(DDRPHY, TCOCNTCTRL, 1, 3);
 921        /* ODT: CMD/CTL PD/PU */
 922        mrc_alt_write_mask(DDRPHY, CHNLBUFSTATIC,
 923                (0x03 << 24) | (0x03 << 16), 0x1f1f0000);
 924        /* Set 1us counter */
 925        mrc_alt_write_mask(DDRPHY, MSCNTR, 0x64, 0xff);
 926        mrc_alt_write_mask(DDRPHY, LATCH1CTL, 0x1 << 28, 0x70000000);
 927
 928        /* Release PHY from reset */
 929        mrc_alt_write_mask(DDRPHY, MASTERRSTN, 1, 1);
 930
 931        /* STEP1 */
 932        mrc_post_code(0x03, 0x11);
 933
 934        for (ch = 0; ch < NUM_CHANNELS; ch++) {
 935                if (mrc_params->channel_enables & (1 << ch)) {
 936                        /* DQ01-DQ23 */
 937                        for (bl_grp = 0;
 938                             bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
 939                             bl_grp++) {
 940                                mrc_alt_write_mask(DDRPHY,
 941                                        DQMDLLCTL +
 942                                        bl_grp * DDRIODQ_BL_OFFSET +
 943                                        ch * DDRIODQ_CH_OFFSET,
 944                                        1 << 13,
 945                                        1 << 13);       /* Enable VREG */
 946                                delay_n(3);
 947                        }
 948
 949                        /* ECC */
 950                        mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
 951                                1 << 13, 1 << 13);      /* Enable VREG */
 952                        delay_n(3);
 953                        /* CMD */
 954                        mrc_alt_write_mask(DDRPHY,
 955                                CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
 956                                1 << 13, 1 << 13);      /* Enable VREG */
 957                        delay_n(3);
 958                        /* CLK-CTL */
 959                        mrc_alt_write_mask(DDRPHY,
 960                                CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
 961                                1 << 13, 1 << 13);      /* Enable VREG */
 962                        delay_n(3);
 963                }
 964        }
 965
 966        /* STEP2 */
 967        mrc_post_code(0x03, 0x12);
 968        delay_n(200);
 969
 970        for (ch = 0; ch < NUM_CHANNELS; ch++) {
 971                if (mrc_params->channel_enables & (1 << ch)) {
 972                        /* DQ01-DQ23 */
 973                        for (bl_grp = 0;
 974                             bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
 975                             bl_grp++) {
 976                                mrc_alt_write_mask(DDRPHY,
 977                                        DQMDLLCTL +
 978                                        bl_grp * DDRIODQ_BL_OFFSET +
 979                                        ch * DDRIODQ_CH_OFFSET,
 980                                        1 << 17,
 981                                        1 << 17);       /* Enable MCDLL */
 982                                delay_n(50);
 983                        }
 984
 985                /* ECC */
 986                mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
 987                        1 << 17, 1 << 17);      /* Enable MCDLL */
 988                delay_n(50);
 989                /* CMD */
 990                mrc_alt_write_mask(DDRPHY,
 991                        CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
 992                        1 << 18, 1 << 18);      /* Enable MCDLL */
 993                delay_n(50);
 994                /* CLK-CTL */
 995                mrc_alt_write_mask(DDRPHY,
 996                        CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
 997                        1 << 18, 1 << 18);      /* Enable MCDLL */
 998                delay_n(50);
 999                }
1000        }
1001
1002        /* STEP3: */
1003        mrc_post_code(0x03, 0x13);
1004        delay_n(100);
1005
1006        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1007                if (mrc_params->channel_enables & (1 << ch)) {
1008                        /* DQ01-DQ23 */
1009                        for (bl_grp = 0;
1010                             bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
1011                             bl_grp++) {
1012#ifdef FORCE_16BIT_DDRIO
1013                                temp = (bl_grp &&
1014                                        (mrc_params->channel_width == X16)) ?
1015                                        0x11ff : 0xffff;
1016#else
1017                                temp = 0xffff;
1018#endif
1019                                /* Enable TXDLL */
1020                                mrc_alt_write_mask(DDRPHY,
1021                                        DQDLLTXCTL +
1022                                        bl_grp * DDRIODQ_BL_OFFSET +
1023                                        ch * DDRIODQ_CH_OFFSET,
1024                                        temp, 0xffff);
1025                                delay_n(3);
1026                                /* Enable RXDLL */
1027                                mrc_alt_write_mask(DDRPHY,
1028                                        DQDLLRXCTL +
1029                                        bl_grp * DDRIODQ_BL_OFFSET +
1030                                        ch * DDRIODQ_CH_OFFSET,
1031                                        0xf, 0xf);
1032                                delay_n(3);
1033                                /* Enable RXDLL Overrides BL0 */
1034                                mrc_alt_write_mask(DDRPHY,
1035                                        B0OVRCTL +
1036                                        bl_grp * DDRIODQ_BL_OFFSET +
1037                                        ch * DDRIODQ_CH_OFFSET,
1038                                        0xf, 0xf);
1039                        }
1040
1041                        /* ECC */
1042                        temp = 0xffff;
1043                        mrc_alt_write_mask(DDRPHY, ECCDLLTXCTL,
1044                                temp, 0xffff);
1045                        delay_n(3);
1046
1047                        /* CMD (PO) */
1048                        mrc_alt_write_mask(DDRPHY,
1049                                CMDDLLTXCTL + ch * DDRIOCCC_CH_OFFSET,
1050                                temp, 0xffff);
1051                        delay_n(3);
1052                }
1053        }
1054
1055        /* STEP4 */
1056        mrc_post_code(0x03, 0x14);
1057
1058        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1059                if (mrc_params->channel_enables & (1 << ch)) {
1060                        /* Host To Memory Clock Alignment (HMC) for 800/1066 */
1061                        for (bl_grp = 0;
1062                             bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
1063                             bl_grp++) {
1064                                /* CLK_ALIGN_MOD_ID */
1065                                mrc_alt_write_mask(DDRPHY,
1066                                        DQCLKALIGNREG2 +
1067                                        bl_grp * DDRIODQ_BL_OFFSET +
1068                                        ch * DDRIODQ_CH_OFFSET,
1069                                        bl_grp ? 3 : 1,
1070                                        0xf);
1071                        }
1072
1073                        mrc_alt_write_mask(DDRPHY,
1074                                ECCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1075                                0x2, 0xf);
1076                        mrc_alt_write_mask(DDRPHY,
1077                                CMDCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1078                                0x0, 0xf);
1079                        mrc_alt_write_mask(DDRPHY,
1080                                CCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1081                                0x2, 0xf);
1082                        mrc_alt_write_mask(DDRPHY,
1083                                CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1084                                0x20, 0x30);
1085                        /*
1086                         * NUM_SAMPLES, MAX_SAMPLES,
1087                         * MACRO_PI_STEP, MICRO_PI_STEP
1088                         */
1089                        mrc_alt_write_mask(DDRPHY,
1090                                CMDCLKALIGNREG1 + ch * DDRIOCCC_CH_OFFSET,
1091                                (0x18 << 16) | (0x10 << 8) |
1092                                (0x8 << 2) | (0x1 << 0),
1093                                0x007f7fff);
1094                        /* TOTAL_NUM_MODULES, FIRST_U_PARTITION */
1095                        mrc_alt_write_mask(DDRPHY,
1096                                CMDCLKALIGNREG2 + ch * DDRIOCCC_CH_OFFSET,
1097                                (0x10 << 16) | (0x4 << 8) | (0x2 << 4),
1098                                0x001f0ff0);
1099#ifdef HMC_TEST
1100                        /* START_CLK_ALIGN=1 */
1101                        mrc_alt_write_mask(DDRPHY,
1102                                CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1103                                1 << 24, 1 << 24);
1104                        while (msg_port_alt_read(DDRPHY,
1105                                CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET) &
1106                                (1 << 24))
1107                                ;       /* wait for START_CLK_ALIGN=0 */
1108#endif
1109
1110                        /* Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN */
1111                        mrc_alt_write_mask(DDRPHY,
1112                                CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
1113                                1, 1);  /* WRPTRENABLE=1 */
1114
1115                        /* COMP initial */
1116                        /* enable bypass for CLK buffer (PO) */
1117                        mrc_alt_write_mask(DDRPHY,
1118                                COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1119                                1 << 5, 1 << 5);
1120                        /* Initial COMP Enable */
1121                        mrc_alt_write_mask(DDRPHY, CMPCTRL, 1, 1);
1122                        /* wait for Initial COMP Enable = 0 */
1123                        while (msg_port_alt_read(DDRPHY, CMPCTRL) & 1)
1124                                ;
1125                        /* disable bypass for CLK buffer (PO) */
1126                        mrc_alt_write_mask(DDRPHY,
1127                                COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1128                                ~(1 << 5), 1 << 5);
1129
1130                        /* IOBUFACT */
1131
1132                        /* STEP4a */
1133                        mrc_alt_write_mask(DDRPHY,
1134                                CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
1135                                1 << 2, 1 << 2);        /* IOBUFACTRST_N=1 */
1136
1137                        /* DDRPHY initialization complete */
1138                        mrc_alt_write_mask(DDRPHY,
1139                                CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
1140                                1 << 20, 1 << 20);      /* SPID_INIT_COMPLETE=1 */
1141                }
1142        }
1143
1144        LEAVEFN();
1145}
1146
1147/* This function performs JEDEC initialization on all enabled channels */
1148void perform_jedec_init(struct mrc_params *mrc_params)
1149{
1150        uint8_t twr, wl, rank;
1151        uint32_t tck;
1152        u32 dtr0;
1153        u32 drp;
1154        u32 drmc;
1155        u32 mrs0_cmd = 0;
1156        u32 emrs1_cmd = 0;
1157        u32 emrs2_cmd = 0;
1158        u32 emrs3_cmd = 0;
1159
1160        ENTERFN();
1161
1162        /* jedec_init starts */
1163        mrc_post_code(0x04, 0x00);
1164
1165        /* DDR3_RESET_SET=0, DDR3_RESET_RESET=1 */
1166        mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 2, 0x102);
1167
1168        /* Assert RESET# for 200us */
1169        delay_u(200);
1170
1171        /* DDR3_RESET_SET=1, DDR3_RESET_RESET=0 */
1172        mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 0x100, 0x102);
1173
1174        dtr0 = msg_port_read(MEM_CTLR, DTR0);
1175
1176        /*
1177         * Set CKEVAL for populated ranks
1178         * then send NOP to each rank (#4550197)
1179         */
1180
1181        drp = msg_port_read(MEM_CTLR, DRP);
1182        drp &= 0x3;
1183
1184        drmc = msg_port_read(MEM_CTLR, DRMC);
1185        drmc &= 0xfffffffc;
1186        drmc |= (DRMC_CKEMODE | drp);
1187
1188        msg_port_write(MEM_CTLR, DRMC, drmc);
1189
1190        for (rank = 0; rank < NUM_RANKS; rank++) {
1191                /* Skip to next populated rank */
1192                if ((mrc_params->rank_enables & (1 << rank)) == 0)
1193                        continue;
1194
1195                dram_init_command(DCMD_NOP(rank));
1196        }
1197
1198        msg_port_write(MEM_CTLR, DRMC,
1199                (mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0));
1200
1201        /*
1202         * setup for emrs 2
1203         * BIT[15:11] --> Always "0"
1204         * BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
1205         * BIT[08]    --> Always "0"
1206         * BIT[07]    --> SRT: use sr_temp_range
1207         * BIT[06]    --> ASR: want "Manual SR Reference" (0)
1208         * BIT[05:03] --> CWL: use oem_tCWL
1209         * BIT[02:00] --> PASR: want "Full Array" (0)
1210         */
1211        emrs2_cmd |= (2 << 3);
1212        wl = 5 + mrc_params->ddr_speed;
1213        emrs2_cmd |= ((wl - 5) << 9);
1214        emrs2_cmd |= (mrc_params->sr_temp_range << 13);
1215
1216        /*
1217         * setup for emrs 3
1218         * BIT[15:03] --> Always "0"
1219         * BIT[02]    --> MPR: want "Normal Operation" (0)
1220         * BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
1221         */
1222        emrs3_cmd |= (3 << 3);
1223
1224        /*
1225         * setup for emrs 1
1226         * BIT[15:13]     --> Always "0"
1227         * BIT[12:12]     --> Qoff: want "Output Buffer Enabled" (0)
1228         * BIT[11:11]     --> TDQS: want "Disabled" (0)
1229         * BIT[10:10]     --> Always "0"
1230         * BIT[09,06,02]  --> Rtt_nom: use rtt_nom_value
1231         * BIT[08]        --> Always "0"
1232         * BIT[07]        --> WR_LVL: want "Disabled" (0)
1233         * BIT[05,01]     --> DIC: use ron_value
1234         * BIT[04:03]     --> AL: additive latency want "0" (0)
1235         * BIT[00]        --> DLL: want "Enable" (0)
1236         *
1237         * (BIT5|BIT1) set Ron value
1238         * 00 --> RZQ/6 (40ohm)
1239         * 01 --> RZQ/7 (34ohm)
1240         * 1* --> RESERVED
1241         *
1242         * (BIT9|BIT6|BIT2) set Rtt_nom value
1243         * 000 --> Disabled
1244         * 001 --> RZQ/4 ( 60ohm)
1245         * 010 --> RZQ/2 (120ohm)
1246         * 011 --> RZQ/6 ( 40ohm)
1247         * 1** --> RESERVED
1248         */
1249        emrs1_cmd |= (1 << 3);
1250        emrs1_cmd &= ~(1 << 6);
1251
1252        if (mrc_params->ron_value == 0)
1253                emrs1_cmd |= (1 << 7);
1254        else
1255                emrs1_cmd &= ~(1 << 7);
1256
1257        if (mrc_params->rtt_nom_value == 0)
1258                emrs1_cmd |= (DDR3_EMRS1_RTTNOM_40 << 6);
1259        else if (mrc_params->rtt_nom_value == 1)
1260                emrs1_cmd |= (DDR3_EMRS1_RTTNOM_60 << 6);
1261        else if (mrc_params->rtt_nom_value == 2)
1262                emrs1_cmd |= (DDR3_EMRS1_RTTNOM_120 << 6);
1263
1264        /* save MRS1 value (excluding control fields) */
1265        mrc_params->mrs1 = emrs1_cmd >> 6;
1266
1267        /*
1268         * setup for mrs 0
1269         * BIT[15:13]     --> Always "0"
1270         * BIT[12]        --> PPD: for Quark (1)
1271         * BIT[11:09]     --> WR: use oem_tWR
1272         * BIT[08]        --> DLL: want "Reset" (1, self clearing)
1273         * BIT[07]        --> MODE: want "Normal" (0)
1274         * BIT[06:04,02]  --> CL: use oem_tCAS
1275         * BIT[03]        --> RD_BURST_TYPE: want "Interleave" (1)
1276         * BIT[01:00]     --> BL: want "8 Fixed" (0)
1277         * WR:
1278         * 0 --> 16
1279         * 1 --> 5
1280         * 2 --> 6
1281         * 3 --> 7
1282         * 4 --> 8
1283         * 5 --> 10
1284         * 6 --> 12
1285         * 7 --> 14
1286         * CL:
1287         * BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
1288         * BIT[06:04] use oem_tCAS-4
1289         */
1290        mrs0_cmd |= (1 << 14);
1291        mrs0_cmd |= (1 << 18);
1292        mrs0_cmd |= ((((dtr0 >> 12) & 7) + 1) << 10);
1293
1294        tck = t_ck[mrc_params->ddr_speed];
1295        /* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
1296        twr = MCEIL(15000, tck);
1297        mrs0_cmd |= ((twr - 4) << 15);
1298
1299        for (rank = 0; rank < NUM_RANKS; rank++) {
1300                /* Skip to next populated rank */
1301                if ((mrc_params->rank_enables & (1 << rank)) == 0)
1302                        continue;
1303
1304                emrs2_cmd |= (rank << 22);
1305                dram_init_command(emrs2_cmd);
1306
1307                emrs3_cmd |= (rank << 22);
1308                dram_init_command(emrs3_cmd);
1309
1310                emrs1_cmd |= (rank << 22);
1311                dram_init_command(emrs1_cmd);
1312
1313                mrs0_cmd |= (rank << 22);
1314                dram_init_command(mrs0_cmd);
1315
1316                dram_init_command(DCMD_ZQCL(rank));
1317        }
1318
1319        LEAVEFN();
1320}
1321
1322/*
1323 * Dunit Initialization Complete
1324 *
1325 * Indicates that initialization of the Dunit has completed.
1326 *
1327 * Memory accesses are permitted and maintenance operation begins.
1328 * Until this bit is set to a 1, the memory controller will not accept
1329 * DRAM requests from the MEMORY_MANAGER or HTE.
1330 */
1331void set_ddr_init_complete(struct mrc_params *mrc_params)
1332{
1333        u32 dco;
1334
1335        ENTERFN();
1336
1337        dco = msg_port_read(MEM_CTLR, DCO);
1338        dco &= ~DCO_PMICTL;
1339        dco |= DCO_IC;
1340        msg_port_write(MEM_CTLR, DCO, dco);
1341
1342        LEAVEFN();
1343}
1344
1345/*
1346 * This function will retrieve relevant timing data
1347 *
1348 * This data will be used on subsequent boots to speed up boot times
1349 * and is required for Suspend To RAM capabilities.
1350 */
1351void restore_timings(struct mrc_params *mrc_params)
1352{
1353        uint8_t ch, rk, bl;
1354        const struct mrc_timings *mt = &mrc_params->timings;
1355
1356        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1357                for (rk = 0; rk < NUM_RANKS; rk++) {
1358                        for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1359                                set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]);
1360                                set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]);
1361                                set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]);
1362                                set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);
1363                                if (rk == 0) {
1364                                        /* VREF (RANK0 only) */
1365                                        set_vref(ch, bl, mt->vref[ch][bl]);
1366                                }
1367                        }
1368                        set_wctl(ch, rk, mt->wctl[ch][rk]);
1369                }
1370                set_wcmd(ch, mt->wcmd[ch]);
1371        }
1372}
1373
1374/*
1375 * Configure default settings normally set as part of read training
1376 *
1377 * Some defaults have to be set earlier as they may affect earlier
1378 * training steps.
1379 */
1380void default_timings(struct mrc_params *mrc_params)
1381{
1382        uint8_t ch, rk, bl;
1383
1384        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1385                for (rk = 0; rk < NUM_RANKS; rk++) {
1386                        for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1387                                set_rdqs(ch, rk, bl, 24);
1388                                if (rk == 0) {
1389                                        /* VREF (RANK0 only) */
1390                                        set_vref(ch, bl, 32);
1391                                }
1392                        }
1393                }
1394        }
1395}
1396
1397/*
1398 * This function will perform our RCVEN Calibration Algorithm.
1399 * We will only use the 2xCLK domain timings to perform RCVEN Calibration.
1400 * All byte lanes will be calibrated "simultaneously" per channel per rank.
1401 */
1402void rcvn_cal(struct mrc_params *mrc_params)
1403{
1404        uint8_t ch;     /* channel counter */
1405        uint8_t rk;     /* rank counter */
1406        uint8_t bl;     /* byte lane counter */
1407        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1408
1409#ifdef R2R_SHARING
1410        /* used to find placement for rank2rank sharing configs */
1411        uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1412#ifndef BACKUP_RCVN
1413        /* used to find placement for rank2rank sharing configs */
1414        uint32_t num_ranks_enabled = 0;
1415#endif
1416#endif
1417
1418#ifdef BACKUP_RCVN
1419#else
1420        uint32_t temp;
1421        /* absolute PI value to be programmed on the byte lane */
1422        uint32_t delay[NUM_BYTE_LANES];
1423        u32 dtr1, dtr1_save;
1424#endif
1425
1426        ENTERFN();
1427
1428        /* rcvn_cal starts */
1429        mrc_post_code(0x05, 0x00);
1430
1431#ifndef BACKUP_RCVN
1432        /* need separate burst to sample DQS preamble */
1433        dtr1 = msg_port_read(MEM_CTLR, DTR1);
1434        dtr1_save = dtr1;
1435        dtr1 |= DTR1_TCCD_12CLK;
1436        msg_port_write(MEM_CTLR, DTR1, dtr1);
1437#endif
1438
1439#ifdef R2R_SHARING
1440        /* need to set "final_delay[][]" elements to "0" */
1441        memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1442#endif
1443
1444        /* loop through each enabled channel */
1445        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1446                if (mrc_params->channel_enables & (1 << ch)) {
1447                        /* perform RCVEN Calibration on a per rank basis */
1448                        for (rk = 0; rk < NUM_RANKS; rk++) {
1449                                if (mrc_params->rank_enables & (1 << rk)) {
1450                                        /*
1451                                         * POST_CODE here indicates the current
1452                                         * channel and rank being calibrated
1453                                         */
1454                                        mrc_post_code(0x05, 0x10 + ((ch << 4) | rk));
1455
1456#ifdef BACKUP_RCVN
1457                                        /* et hard-coded timing values */
1458                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++)
1459                                                set_rcvn(ch, rk, bl, ddr_rcvn[PLATFORM_ID]);
1460#else
1461                                        /* enable FIFORST */
1462                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1463                                                mrc_alt_write_mask(DDRPHY,
1464                                                        B01PTRCTL1 +
1465                                                        (bl >> 1) * DDRIODQ_BL_OFFSET +
1466                                                        ch * DDRIODQ_CH_OFFSET,
1467                                                        0, 1 << 8);
1468                                        }
1469                                        /* initialize the starting delay to 128 PI (cas +1 CLK) */
1470                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1471                                                /* 1x CLK domain timing is cas-4 */
1472                                                delay[bl] = (4 + 1) * FULL_CLK;
1473
1474                                                set_rcvn(ch, rk, bl, delay[bl]);
1475                                        }
1476
1477                                        /* now find the rising edge */
1478                                        find_rising_edge(mrc_params, delay, ch, rk, true);
1479
1480                                        /* Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse */
1481                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1482                                                delay[bl] += QRTR_CLK;
1483                                                set_rcvn(ch, rk, bl, delay[bl]);
1484                                        }
1485                                        /* Now decrement delay by 128 PI (1 CLK) until we sample a "0" */
1486                                        do {
1487                                                temp = sample_dqs(mrc_params, ch, rk, true);
1488                                                for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1489                                                        if (temp & (1 << bl)) {
1490                                                                if (delay[bl] >= FULL_CLK) {
1491                                                                        delay[bl] -= FULL_CLK;
1492                                                                        set_rcvn(ch, rk, bl, delay[bl]);
1493                                                                } else {
1494                                                                        /* not enough delay */
1495                                                                        training_message(ch, rk, bl);
1496                                                                        mrc_post_code(0xee, 0x50);
1497                                                                }
1498                                                        }
1499                                                }
1500                                        } while (temp & 0xff);
1501
1502#ifdef R2R_SHARING
1503                                        /* increment "num_ranks_enabled" */
1504                                        num_ranks_enabled++;
1505                                        /* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1506                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1507                                                delay[bl] += QRTR_CLK;
1508                                                /* add "delay[]" values to "final_delay[][]" for rolling average */
1509                                                final_delay[ch][bl] += delay[bl];
1510                                                /* set timing based on rolling average values */
1511                                                set_rcvn(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
1512                                        }
1513#else
1514                                        /* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1515                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1516                                                delay[bl] += QRTR_CLK;
1517                                                set_rcvn(ch, rk, bl, delay[bl]);
1518                                        }
1519#endif
1520
1521                                        /* disable FIFORST */
1522                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1523                                                mrc_alt_write_mask(DDRPHY,
1524                                                        B01PTRCTL1 +
1525                                                        (bl >> 1) * DDRIODQ_BL_OFFSET +
1526                                                        ch * DDRIODQ_CH_OFFSET,
1527                                                        1 << 8, 1 << 8);
1528                                        }
1529#endif
1530                                }
1531                        }
1532                }
1533        }
1534
1535#ifndef BACKUP_RCVN
1536        /* restore original */
1537        msg_port_write(MEM_CTLR, DTR1, dtr1_save);
1538#endif
1539
1540        LEAVEFN();
1541}
1542
1543/*
1544 * This function will perform the Write Levelling algorithm
1545 * (align WCLK and WDQS).
1546 *
1547 * This algorithm will act on each rank in each channel separately.
1548 */
1549void wr_level(struct mrc_params *mrc_params)
1550{
1551        uint8_t ch;     /* channel counter */
1552        uint8_t rk;     /* rank counter */
1553        uint8_t bl;     /* byte lane counter */
1554        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1555
1556#ifdef R2R_SHARING
1557        /* used to find placement for rank2rank sharing configs */
1558        uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1559#ifndef BACKUP_WDQS
1560        /* used to find placement for rank2rank sharing configs */
1561        uint32_t num_ranks_enabled = 0;
1562#endif
1563#endif
1564
1565#ifdef BACKUP_WDQS
1566#else
1567        /* determines stop condition for CRS_WR_LVL */
1568        bool all_edges_found;
1569        /* absolute PI value to be programmed on the byte lane */
1570        uint32_t delay[NUM_BYTE_LANES];
1571        /*
1572         * static makes it so the data is loaded in the heap once by shadow(),
1573         * where non-static copies the data onto the stack every time this
1574         * function is called
1575         */
1576        uint32_t address;       /* address to be checked during COARSE_WR_LVL */
1577        u32 dtr4, dtr4_save;
1578#endif
1579
1580        ENTERFN();
1581
1582        /* wr_level starts */
1583        mrc_post_code(0x06, 0x00);
1584
1585#ifdef R2R_SHARING
1586        /* need to set "final_delay[][]" elements to "0" */
1587        memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1588#endif
1589
1590        /* loop through each enabled channel */
1591        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1592                if (mrc_params->channel_enables & (1 << ch)) {
1593                        /* perform WRITE LEVELING algorithm on a per rank basis */
1594                        for (rk = 0; rk < NUM_RANKS; rk++) {
1595                                if (mrc_params->rank_enables & (1 << rk)) {
1596                                        /*
1597                                         * POST_CODE here indicates the current
1598                                         * rank and channel being calibrated
1599                                         */
1600                                        mrc_post_code(0x06, 0x10 + ((ch << 4) | rk));
1601
1602#ifdef BACKUP_WDQS
1603                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1604                                                set_wdqs(ch, rk, bl, ddr_wdqs[PLATFORM_ID]);
1605                                                set_wdq(ch, rk, bl, ddr_wdqs[PLATFORM_ID] - QRTR_CLK);
1606                                        }
1607#else
1608                                        /*
1609                                         * perform a single PRECHARGE_ALL command to
1610                                         * make DRAM state machine go to IDLE state
1611                                         */
1612                                        dram_init_command(DCMD_PREA(rk));
1613
1614                                        /*
1615                                         * enable Write Levelling Mode
1616                                         * (EMRS1 w/ Write Levelling Mode Enable)
1617                                         */
1618                                        dram_init_command(DCMD_MRS1(rk, 0x82));
1619
1620                                        /*
1621                                         * set ODT DRAM Full Time Termination
1622                                         * disable in MCU
1623                                         */
1624
1625                                        dtr4 = msg_port_read(MEM_CTLR, DTR4);
1626                                        dtr4_save = dtr4;
1627                                        dtr4 |= DTR4_ODTDIS;
1628                                        msg_port_write(MEM_CTLR, DTR4, dtr4);
1629
1630                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
1631                                                /*
1632                                                 * Enable Sandy Bridge Mode (WDQ Tri-State) &
1633                                                 * Ensure 5 WDQS pulses during Write Leveling
1634                                                 */
1635                                                mrc_alt_write_mask(DDRPHY,
1636                                                        DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1637                                                        0x10000154,
1638                                                        0x100003fc);
1639                                        }
1640
1641                                        /* Write Leveling Mode enabled in IO */
1642                                        mrc_alt_write_mask(DDRPHY,
1643                                                CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1644                                                1 << 16, 1 << 16);
1645
1646                                        /* Initialize the starting delay to WCLK */
1647                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1648                                                /*
1649                                                 * CLK0 --> RK0
1650                                                 * CLK1 --> RK1
1651                                                 */
1652                                                delay[bl] = get_wclk(ch, rk);
1653
1654                                                set_wdqs(ch, rk, bl, delay[bl]);
1655                                        }
1656
1657                                        /* now find the rising edge */
1658                                        find_rising_edge(mrc_params, delay, ch, rk, false);
1659
1660                                        /* disable Write Levelling Mode */
1661                                        mrc_alt_write_mask(DDRPHY,
1662                                                CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1663                                                0, 1 << 16);
1664
1665                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
1666                                                /* Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation */
1667                                                mrc_alt_write_mask(DDRPHY,
1668                                                        DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1669                                                        0x00000154,
1670                                                        0x100003fc);
1671                                        }
1672
1673                                        /* restore original DTR4 */
1674                                        msg_port_write(MEM_CTLR, DTR4, dtr4_save);
1675
1676                                        /*
1677                                         * restore original value
1678                                         * (Write Levelling Mode Disable)
1679                                         */
1680                                        dram_init_command(DCMD_MRS1(rk, mrc_params->mrs1));
1681
1682                                        /*
1683                                         * perform a single PRECHARGE_ALL command to
1684                                         * make DRAM state machine go to IDLE state
1685                                         */
1686                                        dram_init_command(DCMD_PREA(rk));
1687
1688                                        mrc_post_code(0x06, 0x30 + ((ch << 4) | rk));
1689
1690                                        /*
1691                                         * COARSE WRITE LEVEL:
1692                                         * check that we're on the correct clock edge
1693                                         */
1694
1695                                        /* hte reconfiguration request */
1696                                        mrc_params->hte_setup = 1;
1697
1698                                        /* start CRS_WR_LVL with WDQS = WDQS + 128 PI */
1699                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1700                                                delay[bl] = get_wdqs(ch, rk, bl) + FULL_CLK;
1701                                                set_wdqs(ch, rk, bl, delay[bl]);
1702                                                /*
1703                                                 * program WDQ timings based on WDQS
1704                                                 * (WDQ = WDQS - 32 PI)
1705                                                 */
1706                                                set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
1707                                        }
1708
1709                                        /* get an address in the targeted channel/rank */
1710                                        address = get_addr(ch, rk);
1711                                        do {
1712                                                uint32_t coarse_result = 0x00;
1713                                                uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
1714                                                /* assume pass */
1715                                                all_edges_found = true;
1716
1717                                                mrc_params->hte_setup = 1;
1718                                                coarse_result = check_rw_coarse(mrc_params, address);
1719
1720                                                /* check for failures and margin the byte lane back 128 PI (1 CLK) */
1721                                                for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1722                                                        if (coarse_result & (coarse_result_mask << bl)) {
1723                                                                all_edges_found = false;
1724                                                                delay[bl] -= FULL_CLK;
1725                                                                set_wdqs(ch, rk, bl, delay[bl]);
1726                                                                /* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
1727                                                                set_wdq(ch, rk, bl, delay[bl] - QRTR_CLK);
1728                                                        }
1729                                                }
1730                                        } while (!all_edges_found);
1731
1732#ifdef R2R_SHARING
1733                                        /* increment "num_ranks_enabled" */
1734                                         num_ranks_enabled++;
1735                                        /* accumulate "final_delay[][]" values from "delay[]" values for rolling average */
1736                                        for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1737                                                final_delay[ch][bl] += delay[bl];
1738                                                set_wdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
1739                                                /* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
1740                                                set_wdq(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled - QRTR_CLK);
1741                                        }
1742#endif
1743#endif
1744                                }
1745                        }
1746                }
1747        }
1748
1749        LEAVEFN();
1750}
1751
1752void prog_page_ctrl(struct mrc_params *mrc_params)
1753{
1754        u32 dpmc0;
1755
1756        ENTERFN();
1757
1758        dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
1759        dpmc0 &= ~DPMC0_PCLSTO_MASK;
1760        dpmc0 |= (4 << 16);
1761        dpmc0 |= DPMC0_PREAPWDEN;
1762        msg_port_write(MEM_CTLR, DPMC0, dpmc0);
1763}
1764
1765/*
1766 * This function will perform the READ TRAINING Algorithm on all
1767 * channels/ranks/byte_lanes simultaneously to minimize execution time.
1768 *
1769 * The idea here is to train the VREF and RDQS (and eventually RDQ) values
1770 * to achieve maximum READ margins. The algorithm will first determine the
1771 * X coordinate (RDQS setting). This is done by collapsing the VREF eye
1772 * until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
1773 * Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX,
1774 * then average those; this will be the final X coordinate. The algorithm
1775 * will then determine the Y coordinate (VREF setting). This is done by
1776 * collapsing the RDQS eye until we find a minimum required VREF eye for
1777 * RDQS_MIN and RDQS_MAX. Then we take the averages of the VREF eye at
1778 * RDQS_MIN and RDQS_MAX, then average those; this will be the final Y
1779 * coordinate.
1780 *
1781 * NOTE: this algorithm assumes the eye curves have a one-to-one relationship,
1782 * meaning for each X the curve has only one Y and vice-a-versa.
1783 */
1784void rd_train(struct mrc_params *mrc_params)
1785{
1786        uint8_t ch;     /* channel counter */
1787        uint8_t rk;     /* rank counter */
1788        uint8_t bl;     /* byte lane counter */
1789        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1790#ifdef BACKUP_RDQS
1791#else
1792        uint8_t side_x; /* tracks LEFT/RIGHT approach vectors */
1793        uint8_t side_y; /* tracks BOTTOM/TOP approach vectors */
1794        /* X coordinate data (passing RDQS values) for approach vectors */
1795        uint8_t x_coordinate[2][2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1796        /* Y coordinate data (passing VREF values) for approach vectors */
1797        uint8_t y_coordinate[2][2][NUM_CHANNELS][NUM_BYTE_LANES];
1798        /* centered X (RDQS) */
1799        uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1800        /* centered Y (VREF) */
1801        uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES];
1802        uint32_t address;       /* target address for check_bls_ex() */
1803        uint32_t result;        /* result of check_bls_ex() */
1804        uint32_t bl_mask;       /* byte lane mask for result checking */
1805#ifdef R2R_SHARING
1806        /* used to find placement for rank2rank sharing configs */
1807        uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1808        /* used to find placement for rank2rank sharing configs */
1809        uint32_t num_ranks_enabled = 0;
1810#endif
1811#endif
1812
1813        /* rd_train starts */
1814        mrc_post_code(0x07, 0x00);
1815
1816        ENTERFN();
1817
1818#ifdef BACKUP_RDQS
1819        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1820                if (mrc_params->channel_enables & (1 << ch)) {
1821                        for (rk = 0; rk < NUM_RANKS; rk++) {
1822                                if (mrc_params->rank_enables & (1 << rk)) {
1823                                        for (bl = 0;
1824                                             bl < NUM_BYTE_LANES / bl_divisor;
1825                                             bl++) {
1826                                                set_rdqs(ch, rk, bl, ddr_rdqs[PLATFORM_ID]);
1827                                        }
1828                                }
1829                        }
1830                }
1831        }
1832#else
1833        /* initialize x/y_coordinate arrays */
1834        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1835                if (mrc_params->channel_enables & (1 << ch)) {
1836                        for (rk = 0; rk < NUM_RANKS; rk++) {
1837                                if (mrc_params->rank_enables & (1 << rk)) {
1838                                        for (bl = 0;
1839                                             bl < NUM_BYTE_LANES / bl_divisor;
1840                                             bl++) {
1841                                                /* x_coordinate */
1842                                                x_coordinate[L][B][ch][rk][bl] = RDQS_MIN;
1843                                                x_coordinate[R][B][ch][rk][bl] = RDQS_MAX;
1844                                                x_coordinate[L][T][ch][rk][bl] = RDQS_MIN;
1845                                                x_coordinate[R][T][ch][rk][bl] = RDQS_MAX;
1846                                                /* y_coordinate */
1847                                                y_coordinate[L][B][ch][bl] = VREF_MIN;
1848                                                y_coordinate[R][B][ch][bl] = VREF_MIN;
1849                                                y_coordinate[L][T][ch][bl] = VREF_MAX;
1850                                                y_coordinate[R][T][ch][bl] = VREF_MAX;
1851                                        }
1852                                }
1853                        }
1854                }
1855        }
1856
1857        /* initialize other variables */
1858        bl_mask = byte_lane_mask(mrc_params);
1859        address = get_addr(0, 0);
1860
1861#ifdef R2R_SHARING
1862        /* need to set "final_delay[][]" elements to "0" */
1863        memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1864#endif
1865
1866        /* look for passing coordinates */
1867        for (side_y = B; side_y <= T; side_y++) {
1868                for (side_x = L; side_x <= R; side_x++) {
1869                        mrc_post_code(0x07, 0x10 + side_y * 2 + side_x);
1870
1871                        /* find passing values */
1872                        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1873                                if (mrc_params->channel_enables & (0x1 << ch)) {
1874                                        for (rk = 0; rk < NUM_RANKS; rk++) {
1875                                                if (mrc_params->rank_enables &
1876                                                        (0x1 << rk)) {
1877                                                        /* set x/y_coordinate search starting settings */
1878                                                        for (bl = 0;
1879                                                             bl < NUM_BYTE_LANES / bl_divisor;
1880                                                             bl++) {
1881                                                                set_rdqs(ch, rk, bl,
1882                                                                         x_coordinate[side_x][side_y][ch][rk][bl]);
1883                                                                set_vref(ch, bl,
1884                                                                         y_coordinate[side_x][side_y][ch][bl]);
1885                                                        }
1886
1887                                                        /* get an address in the target channel/rank */
1888                                                        address = get_addr(ch, rk);
1889
1890                                                        /* request HTE reconfiguration */
1891                                                        mrc_params->hte_setup = 1;
1892
1893                                                        /* test the settings */
1894                                                        do {
1895                                                                /* result[07:00] == failing byte lane (MAX 8) */
1896                                                                result = check_bls_ex(mrc_params, address);
1897
1898                                                                /* check for failures */
1899                                                                if (result & 0xff) {
1900                                                                        /* at least 1 byte lane failed */
1901                                                                        for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1902                                                                                if (result &
1903                                                                                        (bl_mask << bl)) {
1904                                                                                        /* adjust the RDQS values accordingly */
1905                                                                                        if (side_x == L)
1906                                                                                                x_coordinate[L][side_y][ch][rk][bl] += RDQS_STEP;
1907                                                                                        else
1908                                                                                                x_coordinate[R][side_y][ch][rk][bl] -= RDQS_STEP;
1909
1910                                                                                        /* check that we haven't closed the RDQS_EYE too much */
1911                                                                                        if ((x_coordinate[L][side_y][ch][rk][bl] > (RDQS_MAX - MIN_RDQS_EYE)) ||
1912                                                                                                (x_coordinate[R][side_y][ch][rk][bl] < (RDQS_MIN + MIN_RDQS_EYE)) ||
1913                                                                                                (x_coordinate[L][side_y][ch][rk][bl] ==
1914                                                                                                x_coordinate[R][side_y][ch][rk][bl])) {
1915                                                                                                /*
1916                                                                                                 * not enough RDQS margin available at this VREF
1917                                                                                                 * update VREF values accordingly
1918                                                                                                 */
1919                                                                                                if (side_y == B)
1920                                                                                                        y_coordinate[side_x][B][ch][bl] += VREF_STEP;
1921                                                                                                else
1922                                                                                                        y_coordinate[side_x][T][ch][bl] -= VREF_STEP;
1923
1924                                                                                                /* check that we haven't closed the VREF_EYE too much */
1925                                                                                                if ((y_coordinate[side_x][B][ch][bl] > (VREF_MAX - MIN_VREF_EYE)) ||
1926                                                                                                        (y_coordinate[side_x][T][ch][bl] < (VREF_MIN + MIN_VREF_EYE)) ||
1927                                                                                                        (y_coordinate[side_x][B][ch][bl] == y_coordinate[side_x][T][ch][bl])) {
1928                                                                                                        /* VREF_EYE collapsed below MIN_VREF_EYE */
1929                                                                                                        training_message(ch, rk, bl);
1930                                                                                                        mrc_post_code(0xEE, 0x70 + side_y * 2 + side_x);
1931                                                                                                } else {
1932                                                                                                        /* update the VREF setting */
1933                                                                                                        set_vref(ch, bl, y_coordinate[side_x][side_y][ch][bl]);
1934                                                                                                        /* reset the X coordinate to begin the search at the new VREF */
1935                                                                                                        x_coordinate[side_x][side_y][ch][rk][bl] =
1936                                                                                                                (side_x == L) ? RDQS_MIN : RDQS_MAX;
1937                                                                                                }
1938                                                                                        }
1939
1940                                                                                        /* update the RDQS setting */
1941                                                                                        set_rdqs(ch, rk, bl, x_coordinate[side_x][side_y][ch][rk][bl]);
1942                                                                                }
1943                                                                        }
1944                                                                }
1945                                                        } while (result & 0xff);
1946                                                }
1947                                        }
1948                                }
1949                        }
1950                }
1951        }
1952
1953        mrc_post_code(0x07, 0x20);
1954
1955        /* find final RDQS (X coordinate) & final VREF (Y coordinate) */
1956        for (ch = 0; ch < NUM_CHANNELS; ch++) {
1957                if (mrc_params->channel_enables & (1 << ch)) {
1958                        for (rk = 0; rk < NUM_RANKS; rk++) {
1959                                if (mrc_params->rank_enables & (1 << rk)) {
1960                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1961                                                uint32_t temp1;
1962                                                uint32_t temp2;
1963
1964                                                /* x_coordinate */
1965                                                DPF(D_INFO,
1966                                                    "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n",
1967                                                    rk, bl,
1968                                                    x_coordinate[L][T][ch][rk][bl],
1969                                                    x_coordinate[R][T][ch][rk][bl],
1970                                                    x_coordinate[L][B][ch][rk][bl],
1971                                                    x_coordinate[R][B][ch][rk][bl]);
1972
1973                                                /* average the TOP side LEFT & RIGHT values */
1974                                                temp1 = (x_coordinate[R][T][ch][rk][bl] + x_coordinate[L][T][ch][rk][bl]) / 2;
1975                                                /* average the BOTTOM side LEFT & RIGHT values */
1976                                                temp2 = (x_coordinate[R][B][ch][rk][bl] + x_coordinate[L][B][ch][rk][bl]) / 2;
1977                                                /* average the above averages */
1978                                                x_center[ch][rk][bl] = (uint8_t) ((temp1 + temp2) / 2);
1979
1980                                                /* y_coordinate */
1981                                                DPF(D_INFO,
1982                                                    "VREF R/L eye lane%d : %d-%d %d-%d\n",
1983                                                    bl,
1984                                                    y_coordinate[R][B][ch][bl],
1985                                                    y_coordinate[R][T][ch][bl],
1986                                                    y_coordinate[L][B][ch][bl],
1987                                                    y_coordinate[L][T][ch][bl]);
1988
1989                                                /* average the RIGHT side TOP & BOTTOM values */
1990                                                temp1 = (y_coordinate[R][T][ch][bl] + y_coordinate[R][B][ch][bl]) / 2;
1991                                                /* average the LEFT side TOP & BOTTOM values */
1992                                                temp2 = (y_coordinate[L][T][ch][bl] + y_coordinate[L][B][ch][bl]) / 2;
1993                                                /* average the above averages */
1994                                                y_center[ch][bl] = (uint8_t) ((temp1 + temp2) / 2);
1995                                        }
1996                                }
1997                        }
1998                }
1999        }
2000
2001#ifdef RX_EYE_CHECK
2002        /* perform an eye check */
2003        for (side_y = B; side_y <= T; side_y++) {
2004                for (side_x = L; side_x <= R; side_x++) {
2005                        mrc_post_code(0x07, 0x30 + side_y * 2 + side_x);
2006
2007                        /* update the settings for the eye check */
2008                        for (ch = 0; ch < NUM_CHANNELS; ch++) {
2009                                if (mrc_params->channel_enables & (1 << ch)) {
2010                                        for (rk = 0; rk < NUM_RANKS; rk++) {
2011                                                if (mrc_params->rank_enables & (1 << rk)) {
2012                                                        for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2013                                                                if (side_x == L)
2014                                                                        set_rdqs(ch, rk, bl, x_center[ch][rk][bl] - (MIN_RDQS_EYE / 2));
2015                                                                else
2016                                                                        set_rdqs(ch, rk, bl, x_center[ch][rk][bl] + (MIN_RDQS_EYE / 2));
2017
2018                                                                if (side_y == B)
2019                                                                        set_vref(ch, bl, y_center[ch][bl] - (MIN_VREF_EYE / 2));
2020                                                                else
2021                                                                        set_vref(ch, bl, y_center[ch][bl] + (MIN_VREF_EYE / 2));
2022                                                        }
2023                                                }
2024                                        }
2025                                }
2026                        }
2027
2028                        /* request HTE reconfiguration */
2029                        mrc_params->hte_setup = 1;
2030
2031                        /* check the eye */
2032                        if (check_bls_ex(mrc_params, address) & 0xff) {
2033                                /* one or more byte lanes failed */
2034                                mrc_post_code(0xee, 0x74 + side_x * 2 + side_y);
2035                        }
2036                }
2037        }
2038#endif
2039
2040        mrc_post_code(0x07, 0x40);
2041
2042        /* set final placements */
2043        for (ch = 0; ch < NUM_CHANNELS; ch++) {
2044                if (mrc_params->channel_enables & (1 << ch)) {
2045                        for (rk = 0; rk < NUM_RANKS; rk++) {
2046                                if (mrc_params->rank_enables & (1 << rk)) {
2047#ifdef R2R_SHARING
2048                                        /* increment "num_ranks_enabled" */
2049                                        num_ranks_enabled++;
2050#endif
2051                                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
2052                                                /* x_coordinate */
2053#ifdef R2R_SHARING
2054                                                final_delay[ch][bl] += x_center[ch][rk][bl];
2055                                                set_rdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
2056#else
2057                                                set_rdqs(ch, rk, bl, x_center[ch][rk][bl]);
2058#endif
2059                                                /* y_coordinate */
2060                                                set_vref(ch, bl, y_center[ch][bl]);
2061                                        }
2062                                }
2063                        }
2064                }
2065        }
2066#endif
2067
2068        LEAVEFN();
2069}
2070
2071/*
2072 * This function will perform the WRITE TRAINING Algorithm on all
2073 * channels/ranks/byte_lanes simultaneously to minimize execution time.
2074 *
2075 * The idea here is to train the WDQ timings to achieve maximum WRITE margins.
2076 * The algorithm will start with WDQ at the current WDQ setting (tracks WDQS
2077 * in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data
2078 * patterns pass. This is because WDQS will be aligned to WCLK by the
2079 * Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window
2080 * of validity.
2081 */
2082void wr_train(struct mrc_params *mrc_params)
2083{
2084        uint8_t ch;     /* channel counter */
2085        uint8_t rk;     /* rank counter */
2086        uint8_t bl;     /* byte lane counter */
2087        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
2088#ifdef BACKUP_WDQ
2089#else
2090        uint8_t side;           /* LEFT/RIGHT side indicator (0=L, 1=R) */
2091        uint32_t temp;          /* temporary DWORD */
2092        /* 2 arrays, for L & R side passing delays */
2093        uint32_t delay[2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
2094        uint32_t address;       /* target address for check_bls_ex() */
2095        uint32_t result;        /* result of check_bls_ex() */
2096        uint32_t bl_mask;       /* byte lane mask for result checking */
2097#ifdef R2R_SHARING
2098        /* used to find placement for rank2rank sharing configs */
2099        uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
2100        /* used to find placement for rank2rank sharing configs */
2101        uint32_t num_ranks_enabled = 0;
2102#endif
2103#endif
2104
2105        /* wr_train starts */
2106        mrc_post_code(0x08, 0x00);
2107
2108        ENTERFN();
2109
2110#ifdef BACKUP_WDQ
2111        for (ch = 0; ch < NUM_CHANNELS; ch++) {
2112                if (mrc_params->channel_enables & (1 << ch)) {
2113                        for (rk = 0; rk < NUM_RANKS; rk++) {
2114                                if (mrc_params->rank_enables & (1 << rk)) {
2115                                        for (bl = 0;
2116                                             bl < NUM_BYTE_LANES / bl_divisor;
2117                                             bl++) {
2118                                                set_wdq(ch, rk, bl, ddr_wdq[PLATFORM_ID]);
2119                                        }
2120                                }
2121                        }
2122                }
2123        }
2124#else
2125        /* initialize "delay" */
2126        for (ch = 0; ch < NUM_CHANNELS; ch++) {
2127                if (mrc_params->channel_enables & (1 << ch)) {
2128                        for (rk = 0; rk < NUM_RANKS; rk++) {
2129                                if (mrc_params->rank_enables & (1 << rk)) {
2130                                        for (bl = 0;
2131                                             bl < NUM_BYTE_LANES / bl_divisor;
2132                                             bl++) {
2133                                                /*
2134                                                 * want to start with
2135                                                 * WDQ = (WDQS - QRTR_CLK)
2136                                                 * +/- QRTR_CLK
2137                                                 */
2138                                                temp = get_wdqs(ch, rk, bl) - QRTR_CLK;
2139                                                delay[L][ch][rk][bl] = temp - QRTR_CLK;
2140                                                delay[R][ch][rk][bl] = temp + QRTR_CLK;
2141                                        }
2142                                }
2143                        }
2144                }
2145        }
2146
2147        /* initialize other variables */
2148        bl_mask = byte_lane_mask(mrc_params);
2149        address = get_addr(0, 0);
2150
2151#ifdef R2R_SHARING
2152        /* need to set "final_delay[][]" elements to "0" */
2153        memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
2154#endif
2155
2156        /*
2157         * start algorithm on the LEFT side and train each channel/bl
2158         * until no failures are observed, then repeat for the RIGHT side.
2159         */
2160        for (side = L; side <= R; side++) {
2161                mrc_post_code(0x08, 0x10 + side);
2162
2163                /* set starting values */
2164                for (ch = 0; ch < NUM_CHANNELS; ch++) {
2165                        if (mrc_params->channel_enables & (1 << ch)) {
2166                                for (rk = 0; rk < NUM_RANKS; rk++) {
2167                                        if (mrc_params->rank_enables &
2168                                                (1 << rk)) {
2169                                                for (bl = 0;
2170                                                     bl < NUM_BYTE_LANES / bl_divisor;
2171                                                     bl++) {
2172                                                        set_wdq(ch, rk, bl, delay[side][ch][rk][bl]);
2173                                                }
2174                                        }
2175                                }
2176                        }
2177                }
2178
2179                /* find passing values */
2180                for (ch = 0; ch < NUM_CHANNELS; ch++) {
2181                        if (mrc_params->channel_enables & (1 << ch)) {
2182                                for (rk = 0; rk < NUM_RANKS; rk++) {
2183                                        if (mrc_params->rank_enables &
2184                                                (1 << rk)) {
2185                                                /* get an address in the target channel/rank */
2186                                                address = get_addr(ch, rk);
2187
2188                                                /* request HTE reconfiguration */
2189                                                mrc_params->hte_setup = 1;
2190
2191                                                /* check the settings */
2192                                                do {
2193                                                        /* result[07:00] == failing byte lane (MAX 8) */
2194                                                        result = check_bls_ex(mrc_params, address);
2195                                                        /* check for failures */
2196                                                        if (result & 0xff) {
2197                                                                /* at least 1 byte lane failed */
2198                                                                for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2199                                                                        if (result &
2200                                                                                (bl_mask << bl)) {
2201                                                                                if (side == L)
2202                                                                                        delay[L][ch][rk][bl] += WDQ_STEP;
2203                                                                                else
2204                                                                                        delay[R][ch][rk][bl] -= WDQ_STEP;
2205
2206                                                                                /* check for algorithm failure */
2207                                                                                if (delay[L][ch][rk][bl] != delay[R][ch][rk][bl]) {
2208                                                                                        /*
2209                                                                                         * margin available
2210                                                                                         * update delay setting
2211                                                                                         */
2212                                                                                        set_wdq(ch, rk, bl,
2213                                                                                                delay[side][ch][rk][bl]);
2214                                                                                } else {
2215                                                                                        /*
2216                                                                                         * no margin available
2217                                                                                         * notify the user and halt
2218                                                                                         */
2219                                                                                        training_message(ch, rk, bl);
2220                                                                                        mrc_post_code(0xee, 0x80 + side);
2221                                                                                }
2222                                                                        }
2223                                                                }
2224                                                        }
2225                                                /* stop when all byte lanes pass */
2226                                                } while (result & 0xff);
2227                                        }
2228                                }
2229                        }
2230                }
2231        }
2232
2233        /* program WDQ to the middle of passing window */
2234        for (ch = 0; ch < NUM_CHANNELS; ch++) {
2235                if (mrc_params->channel_enables & (1 << ch)) {
2236                        for (rk = 0; rk < NUM_RANKS; rk++) {
2237                                if (mrc_params->rank_enables & (1 << rk)) {
2238#ifdef R2R_SHARING
2239                                        /* increment "num_ranks_enabled" */
2240                                        num_ranks_enabled++;
2241#endif
2242                                        for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2243                                                DPF(D_INFO,
2244                                                    "WDQ eye rank%d lane%d : %d-%d\n",
2245                                                    rk, bl,
2246                                                    delay[L][ch][rk][bl],
2247                                                    delay[R][ch][rk][bl]);
2248
2249                                                temp = (delay[R][ch][rk][bl] + delay[L][ch][rk][bl]) / 2;
2250
2251#ifdef R2R_SHARING
2252                                                final_delay[ch][bl] += temp;
2253                                                set_wdq(ch, rk, bl,
2254                                                        final_delay[ch][bl] / num_ranks_enabled);
2255#else
2256                                                set_wdq(ch, rk, bl, temp);
2257#endif
2258                                        }
2259                                }
2260                        }
2261                }
2262        }
2263#endif
2264
2265        LEAVEFN();
2266}
2267
2268/*
2269 * This function will store relevant timing data
2270 *
2271 * This data will be used on subsequent boots to speed up boot times
2272 * and is required for Suspend To RAM capabilities.
2273 */
2274void store_timings(struct mrc_params *mrc_params)
2275{
2276        uint8_t ch, rk, bl;
2277        struct mrc_timings *mt = &mrc_params->timings;
2278
2279        for (ch = 0; ch < NUM_CHANNELS; ch++) {
2280                for (rk = 0; rk < NUM_RANKS; rk++) {
2281                        for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
2282                                mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl);
2283                                mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl);
2284                                mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl);
2285                                mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);
2286
2287                                if (rk == 0)
2288                                        mt->vref[ch][bl] = get_vref(ch, bl);
2289                        }
2290
2291                        mt->wctl[ch][rk] = get_wctl(ch, rk);
2292                }
2293
2294                mt->wcmd[ch] = get_wcmd(ch);
2295        }
2296
2297        /* need to save for a case of changing frequency after warm reset */
2298        mt->ddr_speed = mrc_params->ddr_speed;
2299}
2300
2301/*
2302 * The purpose of this function is to ensure the SEC comes out of reset
2303 * and IA initiates the SEC enabling Memory Scrambling.
2304 */
2305void enable_scrambling(struct mrc_params *mrc_params)
2306{
2307        uint32_t lfsr = 0;
2308        uint8_t i;
2309
2310        if (mrc_params->scrambling_enables == 0)
2311                return;
2312
2313        ENTERFN();
2314
2315        /* 32 bit seed is always stored in BIOS NVM */
2316        lfsr = mrc_params->timings.scrambler_seed;
2317
2318        if (mrc_params->boot_mode == BM_COLD) {
2319                /*
2320                 * factory value is 0 and in first boot,
2321                 * a clock based seed is loaded.
2322                 */
2323                if (lfsr == 0) {
2324                        /*
2325                         * get seed from system clock
2326                         * and make sure it is not all 1's
2327                         */
2328                        lfsr = rdtsc() & 0x0fffffff;
2329                } else {
2330                        /*
2331                         * Need to replace scrambler
2332                         *
2333                         * get next 32bit LFSR 16 times which is the last
2334                         * part of the previous scrambler vector
2335                         */
2336                        for (i = 0; i < 16; i++)
2337                                lfsr32(&lfsr);
2338                }
2339
2340                /* save new seed */
2341                mrc_params->timings.scrambler_seed = lfsr;
2342        }
2343
2344        /*
2345         * In warm boot or S3 exit, we have the previous seed.
2346         * In cold boot, we have the last 32bit LFSR which is the new seed.
2347         */
2348        lfsr32(&lfsr);  /* shift to next value */
2349        msg_port_write(MEM_CTLR, SCRMSEED, (lfsr & 0x0003ffff));
2350
2351        for (i = 0; i < 2; i++)
2352                msg_port_write(MEM_CTLR, SCRMLO + i, (lfsr & 0xaaaaaaaa));
2353
2354        LEAVEFN();
2355}
2356
2357/*
2358 * Configure MCU Power Management Control Register
2359 * and Scheduler Control Register
2360 */
2361void prog_ddr_control(struct mrc_params *mrc_params)
2362{
2363        u32 dsch;
2364        u32 dpmc0;
2365
2366        ENTERFN();
2367
2368        dsch = msg_port_read(MEM_CTLR, DSCH);
2369        dsch &= ~(DSCH_OOODIS | DSCH_OOOST3DIS | DSCH_NEWBYPDIS);
2370        msg_port_write(MEM_CTLR, DSCH, dsch);
2371
2372        dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
2373        dpmc0 &= ~DPMC0_DISPWRDN;
2374        dpmc0 |= (mrc_params->power_down_disable << 25);
2375        dpmc0 &= ~DPMC0_CLKGTDIS;
2376        dpmc0 &= ~DPMC0_PCLSTO_MASK;
2377        dpmc0 |= (4 << 16);
2378        dpmc0 |= DPMC0_PREAPWDEN;
2379        msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2380
2381        /* CMDTRIST = 2h - CMD/ADDR are tristated when no valid command */
2382        mrc_write_mask(MEM_CTLR, DPMC1, 0x20, 0x30);
2383
2384        LEAVEFN();
2385}
2386
2387/*
2388 * After training complete configure MCU Rank Population Register
2389 * specifying: ranks enabled, device width, density, address mode
2390 */
2391void prog_dra_drb(struct mrc_params *mrc_params)
2392{
2393        u32 drp;
2394        u32 dco;
2395        u8 density = mrc_params->params.density;
2396
2397        ENTERFN();
2398
2399        dco = msg_port_read(MEM_CTLR, DCO);
2400        dco &= ~DCO_IC;
2401        msg_port_write(MEM_CTLR, DCO, dco);
2402
2403        drp = 0;
2404        if (mrc_params->rank_enables & 1)
2405                drp |= DRP_RKEN0;
2406        if (mrc_params->rank_enables & 2)
2407                drp |= DRP_RKEN1;
2408        if (mrc_params->dram_width == X16) {
2409                drp |= (1 << 4);
2410                drp |= (1 << 9);
2411        }
2412
2413        /*
2414         * Density encoding in struct dram_params: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
2415         * has to be mapped RANKDENSx encoding (0=1Gb)
2416         */
2417        if (density == 0)
2418                density = 4;
2419
2420        drp |= ((density - 1) << 6);
2421        drp |= ((density - 1) << 11);
2422
2423        /* Address mode can be overwritten if ECC enabled */
2424        drp |= (mrc_params->address_mode << 14);
2425
2426        msg_port_write(MEM_CTLR, DRP, drp);
2427
2428        dco &= ~DCO_PMICTL;
2429        dco |= DCO_IC;
2430        msg_port_write(MEM_CTLR, DCO, dco);
2431
2432        LEAVEFN();
2433}
2434
2435/* Send DRAM wake command */
2436void perform_wake(struct mrc_params *mrc_params)
2437{
2438        ENTERFN();
2439
2440        dram_wake_command();
2441
2442        LEAVEFN();
2443}
2444
2445/*
2446 * Configure refresh rate and short ZQ calibration interval
2447 * Activate dynamic self refresh
2448 */
2449void change_refresh_period(struct mrc_params *mrc_params)
2450{
2451        u32 drfc;
2452        u32 dcal;
2453        u32 dpmc0;
2454
2455        ENTERFN();
2456
2457        drfc = msg_port_read(MEM_CTLR, DRFC);
2458        drfc &= ~DRFC_TREFI_MASK;
2459        drfc |= (mrc_params->refresh_rate << 12);
2460        drfc |= DRFC_REFDBTCLR;
2461        msg_port_write(MEM_CTLR, DRFC, drfc);
2462
2463        dcal = msg_port_read(MEM_CTLR, DCAL);
2464        dcal &= ~DCAL_ZQCINT_MASK;
2465        dcal |= (3 << 8);       /* 63ms */
2466        msg_port_write(MEM_CTLR, DCAL, dcal);
2467
2468        dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
2469        dpmc0 |= (DPMC0_DYNSREN | DPMC0_ENPHYCLKGATE);
2470        msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2471
2472        LEAVEFN();
2473}
2474
2475/*
2476 * Configure DDRPHY for Auto-Refresh, Periodic Compensations,
2477 * Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
2478 */
2479void set_auto_refresh(struct mrc_params *mrc_params)
2480{
2481        uint32_t channel;
2482        uint32_t rank;
2483        uint32_t bl;
2484        uint32_t bl_divisor = 1;
2485        uint32_t temp;
2486
2487        ENTERFN();
2488
2489        /*
2490         * Enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp,
2491         * ZQSPERIOD, Auto-Precharge, CKE Power-Down
2492         */
2493        for (channel = 0; channel < NUM_CHANNELS; channel++) {
2494                if (mrc_params->channel_enables & (1 << channel)) {
2495                        /* Enable Periodic RCOMPS */
2496                        mrc_alt_write_mask(DDRPHY, CMPCTRL, 2, 2);
2497
2498                        /* Enable Dynamic DiffAmp & Set Read ODT Value */
2499                        switch (mrc_params->rd_odt_value) {
2500                        case 0:
2501                                temp = 0x3f;    /* OFF */
2502                                break;
2503                        default:
2504                                temp = 0x00;    /* Auto */
2505                                break;
2506                        }
2507
2508                        for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
2509                                /* Override: DIFFAMP, ODT */
2510                                mrc_alt_write_mask(DDRPHY,
2511                                        B0OVRCTL + bl * DDRIODQ_BL_OFFSET +
2512                                        channel * DDRIODQ_CH_OFFSET,
2513                                        temp << 10,
2514                                        0x003ffc00);
2515
2516                                /* Override: DIFFAMP, ODT */
2517                                mrc_alt_write_mask(DDRPHY,
2518                                        B1OVRCTL + bl * DDRIODQ_BL_OFFSET +
2519                                        channel * DDRIODQ_CH_OFFSET,
2520                                        temp << 10,
2521                                        0x003ffc00);
2522                        }
2523
2524                        /* Issue ZQCS command */
2525                        for (rank = 0; rank < NUM_RANKS; rank++) {
2526                                if (mrc_params->rank_enables & (1 << rank))
2527                                        dram_init_command(DCMD_ZQCS(rank));
2528                        }
2529                }
2530        }
2531
2532        clear_pointers();
2533
2534        LEAVEFN();
2535}
2536
2537/*
2538 * Depending on configuration enables ECC support
2539 *
2540 * Available memory size is decreased, and updated with 0s
2541 * in order to clear error status. Address mode 2 forced.
2542 */
2543void ecc_enable(struct mrc_params *mrc_params)
2544{
2545        u32 drp;
2546        u32 dsch;
2547        u32 ecc_ctrl;
2548
2549        if (mrc_params->ecc_enables == 0)
2550                return;
2551
2552        ENTERFN();
2553
2554        /* Configuration required in ECC mode */
2555        drp = msg_port_read(MEM_CTLR, DRP);
2556        drp &= ~DRP_ADDRMAP_MASK;
2557        drp |= DRP_ADDRMAP_MAP1;
2558        drp |= DRP_PRI64BSPLITEN;
2559        msg_port_write(MEM_CTLR, DRP, drp);
2560
2561        /* Disable new request bypass */
2562        dsch = msg_port_read(MEM_CTLR, DSCH);
2563        dsch |= DSCH_NEWBYPDIS;
2564        msg_port_write(MEM_CTLR, DSCH, dsch);
2565
2566        /* Enable ECC */
2567        ecc_ctrl = (DECCCTRL_SBEEN | DECCCTRL_DBEEN | DECCCTRL_ENCBGEN);
2568        msg_port_write(MEM_CTLR, DECCCTRL, ecc_ctrl);
2569
2570        /* Assume 8 bank memory, one bank is gone for ECC */
2571        mrc_params->mem_size -= mrc_params->mem_size / 8;
2572
2573        /* For S3 resume memory content has to be preserved */
2574        if (mrc_params->boot_mode != BM_S3) {
2575                select_hte();
2576                hte_mem_init(mrc_params, MRC_MEM_INIT);
2577                select_mem_mgr();
2578        }
2579
2580        LEAVEFN();
2581}
2582
2583/*
2584 * Execute memory test
2585 * if error detected it is indicated in mrc_params->status
2586 */
2587void memory_test(struct mrc_params *mrc_params)
2588{
2589        uint32_t result = 0;
2590
2591        ENTERFN();
2592
2593        select_hte();
2594        result = hte_mem_init(mrc_params, MRC_MEM_TEST);
2595        select_mem_mgr();
2596
2597        DPF(D_INFO, "Memory test result %x\n", result);
2598        mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
2599        LEAVEFN();
2600}
2601
2602/* Lock MCU registers at the end of initialization sequence */
2603void lock_registers(struct mrc_params *mrc_params)
2604{
2605        u32 dco;
2606
2607        ENTERFN();
2608
2609        dco = msg_port_read(MEM_CTLR, DCO);
2610        dco &= ~(DCO_PMICTL | DCO_PMIDIS);
2611        dco |= (DCO_DRPLOCK | DCO_CPGCLOCK);
2612        msg_port_write(MEM_CTLR, DCO, dco);
2613
2614        LEAVEFN();
2615}
2616