uboot/arch/x86/cpu/quark/mrc_util.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 <asm/arch/device.h>
  12#include <asm/arch/mrc.h>
  13#include <asm/arch/msg_port.h>
  14#include <asm/arch/quark.h>
  15#include "mrc_util.h"
  16#include "hte.h"
  17#include "smc.h"
  18
  19static const uint8_t vref_codes[64] = {
  20        /* lowest to highest */
  21        0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
  22        0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
  23        0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
  24        0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
  25        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  26        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  27        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
  28        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
  29};
  30
  31void mrc_write_mask(u32 unit, u32 addr, u32 data, u32 mask)
  32{
  33        msg_port_write(unit, addr,
  34                       (msg_port_read(unit, addr) & ~(mask)) |
  35                       ((data) & (mask)));
  36}
  37
  38void mrc_alt_write_mask(u32 unit, u32 addr, u32 data, u32 mask)
  39{
  40        msg_port_alt_write(unit, addr,
  41                           (msg_port_alt_read(unit, addr) & ~(mask)) |
  42                           ((data) & (mask)));
  43}
  44
  45void mrc_post_code(uint8_t major, uint8_t minor)
  46{
  47        /* send message to UART */
  48        DPF(D_INFO, "POST: 0x%01x%02x\n", major, minor);
  49
  50        /* error check */
  51        if (major == 0xee)
  52                hang();
  53}
  54
  55/* Delay number of nanoseconds */
  56void delay_n(uint32_t ns)
  57{
  58        /* 1000 MHz clock has 1ns period --> no conversion required */
  59        uint64_t final_tsc = rdtsc();
  60
  61        final_tsc += ((get_tbclk_mhz() * ns) / 1000);
  62
  63        while (rdtsc() < final_tsc)
  64                ;
  65}
  66
  67/* Delay number of microseconds */
  68void delay_u(uint32_t ms)
  69{
  70        /* 64-bit math is not an option, just use loops */
  71        while (ms--)
  72                delay_n(1000);
  73}
  74
  75/* Select Memory Manager as the source for PRI interface */
  76void select_mem_mgr(void)
  77{
  78        u32 dco;
  79
  80        ENTERFN();
  81
  82        dco = msg_port_read(MEM_CTLR, DCO);
  83        dco &= ~DCO_PMICTL;
  84        msg_port_write(MEM_CTLR, DCO, dco);
  85
  86        LEAVEFN();
  87}
  88
  89/* Select HTE as the source for PRI interface */
  90void select_hte(void)
  91{
  92        u32 dco;
  93
  94        ENTERFN();
  95
  96        dco = msg_port_read(MEM_CTLR, DCO);
  97        dco |= DCO_PMICTL;
  98        msg_port_write(MEM_CTLR, DCO, dco);
  99
 100        LEAVEFN();
 101}
 102
 103/*
 104 * Send DRAM command
 105 * data should be formated using DCMD_Xxxx macro or emrsXCommand structure
 106 */
 107void dram_init_command(uint32_t data)
 108{
 109        qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, data);
 110        qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG, 0);
 111        msg_port_setup(MSG_OP_DRAM_INIT, MEM_CTLR, 0);
 112
 113        DPF(D_REGWR, "WR32 %03X %08X %08X\n", MEM_CTLR, 0, data);
 114}
 115
 116/* Send DRAM wake command using special MCU side-band WAKE opcode */
 117void dram_wake_command(void)
 118{
 119        ENTERFN();
 120
 121        msg_port_setup(MSG_OP_DRAM_WAKE, MEM_CTLR, 0);
 122
 123        LEAVEFN();
 124}
 125
 126void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane)
 127{
 128        /* send message to UART */
 129        DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane);
 130}
 131
 132/*
 133 * This function will program the RCVEN delays
 134 *
 135 * (currently doesn't comprehend rank)
 136 */
 137void set_rcvn(uint8_t channel, uint8_t rank,
 138              uint8_t byte_lane, uint32_t pi_count)
 139{
 140        uint32_t reg;
 141        uint32_t msk;
 142        uint32_t temp;
 143
 144        ENTERFN();
 145
 146        DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n",
 147            channel, rank, byte_lane, pi_count);
 148
 149        /*
 150         * RDPTR (1/2 MCLK, 64 PIs)
 151         * BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
 152         * BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
 153         */
 154        reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 155                channel * DDRIODQ_CH_OFFSET;
 156        msk = (byte_lane & 1) ? 0xf00000 : 0xf00;
 157        temp = (byte_lane & 1) ? (pi_count / HALF_CLK) << 20 :
 158                (pi_count / HALF_CLK) << 8;
 159        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 160
 161        /* Adjust PI_COUNT */
 162        pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
 163
 164        /*
 165         * PI (1/64 MCLK, 1 PIs)
 166         * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
 167         * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
 168         */
 169        reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
 170        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 171                channel * DDRIODQ_CH_OFFSET);
 172        msk = 0x3f000000;
 173        temp = pi_count << 24;
 174        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 175
 176        /*
 177         * DEADBAND
 178         * BL0/1 -> B01DBCTL1[08/11] (+1 select)
 179         * BL0/1 -> B01DBCTL1[02/05] (enable)
 180         */
 181        reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 182                channel * DDRIODQ_CH_OFFSET;
 183        msk = 0x00;
 184        temp = 0x00;
 185
 186        /* enable */
 187        msk |= (byte_lane & 1) ? (1 << 5) : (1 << 2);
 188        if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
 189                temp |= msk;
 190
 191        /* select */
 192        msk |= (byte_lane & 1) ? (1 << 11) : (1 << 8);
 193        if (pi_count < EARLY_DB)
 194                temp |= msk;
 195
 196        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 197
 198        /* error check */
 199        if (pi_count > 0x3f) {
 200                training_message(channel, rank, byte_lane);
 201                mrc_post_code(0xee, 0xe0);
 202        }
 203
 204        LEAVEFN();
 205}
 206
 207/*
 208 * This function will return the current RCVEN delay on the given
 209 * channel, rank, byte_lane as an absolute PI count.
 210 *
 211 * (currently doesn't comprehend rank)
 212 */
 213uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane)
 214{
 215        uint32_t reg;
 216        uint32_t temp;
 217        uint32_t pi_count;
 218
 219        ENTERFN();
 220
 221        /*
 222         * RDPTR (1/2 MCLK, 64 PIs)
 223         * BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
 224         * BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
 225         */
 226        reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 227                channel * DDRIODQ_CH_OFFSET;
 228        temp = msg_port_alt_read(DDRPHY, reg);
 229        temp >>= (byte_lane & 1) ? 20 : 8;
 230        temp &= 0xf;
 231
 232        /* Adjust PI_COUNT */
 233        pi_count = temp * HALF_CLK;
 234
 235        /*
 236         * PI (1/64 MCLK, 1 PIs)
 237         * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
 238         * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
 239         */
 240        reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
 241        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 242                channel * DDRIODQ_CH_OFFSET);
 243        temp = msg_port_alt_read(DDRPHY, reg);
 244        temp >>= 24;
 245        temp &= 0x3f;
 246
 247        /* Adjust PI_COUNT */
 248        pi_count += temp;
 249
 250        LEAVEFN();
 251
 252        return pi_count;
 253}
 254
 255/*
 256 * This function will program the RDQS delays based on an absolute
 257 * amount of PIs.
 258 *
 259 * (currently doesn't comprehend rank)
 260 */
 261void set_rdqs(uint8_t channel, uint8_t rank,
 262              uint8_t byte_lane, uint32_t pi_count)
 263{
 264        uint32_t reg;
 265        uint32_t msk;
 266        uint32_t temp;
 267
 268        ENTERFN();
 269        DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n",
 270            channel, rank, byte_lane, pi_count);
 271
 272        /*
 273         * PI (1/128 MCLK)
 274         * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
 275         * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
 276         */
 277        reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
 278        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 279                channel * DDRIODQ_CH_OFFSET);
 280        msk = 0x7f;
 281        temp = pi_count << 0;
 282        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 283
 284        /* error check (shouldn't go above 0x3F) */
 285        if (pi_count > 0x47) {
 286                training_message(channel, rank, byte_lane);
 287                mrc_post_code(0xee, 0xe1);
 288        }
 289
 290        LEAVEFN();
 291}
 292
 293/*
 294 * This function will return the current RDQS delay on the given
 295 * channel, rank, byte_lane as an absolute PI count.
 296 *
 297 * (currently doesn't comprehend rank)
 298 */
 299uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane)
 300{
 301        uint32_t reg;
 302        uint32_t temp;
 303        uint32_t pi_count;
 304
 305        ENTERFN();
 306
 307        /*
 308         * PI (1/128 MCLK)
 309         * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
 310         * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
 311         */
 312        reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
 313        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 314                channel * DDRIODQ_CH_OFFSET);
 315        temp = msg_port_alt_read(DDRPHY, reg);
 316
 317        /* Adjust PI_COUNT */
 318        pi_count = temp & 0x7f;
 319
 320        LEAVEFN();
 321
 322        return pi_count;
 323}
 324
 325/*
 326 * This function will program the WDQS delays based on an absolute
 327 * amount of PIs.
 328 *
 329 * (currently doesn't comprehend rank)
 330 */
 331void set_wdqs(uint8_t channel, uint8_t rank,
 332              uint8_t byte_lane, uint32_t pi_count)
 333{
 334        uint32_t reg;
 335        uint32_t msk;
 336        uint32_t temp;
 337
 338        ENTERFN();
 339
 340        DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n",
 341            channel, rank, byte_lane, pi_count);
 342
 343        /*
 344         * RDPTR (1/2 MCLK, 64 PIs)
 345         * BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
 346         * BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
 347         */
 348        reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 349                channel * DDRIODQ_CH_OFFSET;
 350        msk = (byte_lane & 1) ? 0xf0000 : 0xf0;
 351        temp = pi_count / HALF_CLK;
 352        temp <<= (byte_lane & 1) ? 16 : 4;
 353        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 354
 355        /* Adjust PI_COUNT */
 356        pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
 357
 358        /*
 359         * PI (1/64 MCLK, 1 PIs)
 360         * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
 361         * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
 362         */
 363        reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
 364        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 365                channel * DDRIODQ_CH_OFFSET);
 366        msk = 0x3f0000;
 367        temp = pi_count << 16;
 368        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 369
 370        /*
 371         * DEADBAND
 372         * BL0/1 -> B01DBCTL1[07/10] (+1 select)
 373         * BL0/1 -> B01DBCTL1[01/04] (enable)
 374         */
 375        reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 376                channel * DDRIODQ_CH_OFFSET;
 377        msk = 0x00;
 378        temp = 0x00;
 379
 380        /* enable */
 381        msk |= (byte_lane & 1) ? (1 << 4) : (1 << 1);
 382        if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
 383                temp |= msk;
 384
 385        /* select */
 386        msk |= (byte_lane & 1) ? (1 << 10) : (1 << 7);
 387        if (pi_count < EARLY_DB)
 388                temp |= msk;
 389
 390        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 391
 392        /* error check */
 393        if (pi_count > 0x3f) {
 394                training_message(channel, rank, byte_lane);
 395                mrc_post_code(0xee, 0xe2);
 396        }
 397
 398        LEAVEFN();
 399}
 400
 401/*
 402 * This function will return the amount of WDQS delay on the given
 403 * channel, rank, byte_lane as an absolute PI count.
 404 *
 405 * (currently doesn't comprehend rank)
 406 */
 407uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane)
 408{
 409        uint32_t reg;
 410        uint32_t temp;
 411        uint32_t pi_count;
 412
 413        ENTERFN();
 414
 415        /*
 416         * RDPTR (1/2 MCLK, 64 PIs)
 417         * BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
 418         * BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
 419         */
 420        reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 421                channel * DDRIODQ_CH_OFFSET;
 422        temp = msg_port_alt_read(DDRPHY, reg);
 423        temp >>= (byte_lane & 1) ? 16 : 4;
 424        temp &= 0xf;
 425
 426        /* Adjust PI_COUNT */
 427        pi_count = (temp * HALF_CLK);
 428
 429        /*
 430         * PI (1/64 MCLK, 1 PIs)
 431         * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
 432         * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
 433         */
 434        reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
 435        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 436                channel * DDRIODQ_CH_OFFSET);
 437        temp = msg_port_alt_read(DDRPHY, reg);
 438        temp >>= 16;
 439        temp &= 0x3f;
 440
 441        /* Adjust PI_COUNT */
 442        pi_count += temp;
 443
 444        LEAVEFN();
 445
 446        return pi_count;
 447}
 448
 449/*
 450 * This function will program the WDQ delays based on an absolute
 451 * number of PIs.
 452 *
 453 * (currently doesn't comprehend rank)
 454 */
 455void set_wdq(uint8_t channel, uint8_t rank,
 456             uint8_t byte_lane, uint32_t pi_count)
 457{
 458        uint32_t reg;
 459        uint32_t msk;
 460        uint32_t temp;
 461
 462        ENTERFN();
 463
 464        DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n",
 465            channel, rank, byte_lane, pi_count);
 466
 467        /*
 468         * RDPTR (1/2 MCLK, 64 PIs)
 469         * BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
 470         * BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
 471         */
 472        reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 473                channel * DDRIODQ_CH_OFFSET;
 474        msk = (byte_lane & 1) ? 0xf000 : 0xf;
 475        temp = pi_count / HALF_CLK;
 476        temp <<= (byte_lane & 1) ? 12 : 0;
 477        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 478
 479        /* Adjust PI_COUNT */
 480        pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
 481
 482        /*
 483         * PI (1/64 MCLK, 1 PIs)
 484         * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
 485         * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
 486         */
 487        reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
 488        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 489                channel * DDRIODQ_CH_OFFSET);
 490        msk = 0x3f00;
 491        temp = pi_count << 8;
 492        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 493
 494        /*
 495         * DEADBAND
 496         * BL0/1 -> B01DBCTL1[06/09] (+1 select)
 497         * BL0/1 -> B01DBCTL1[00/03] (enable)
 498         */
 499        reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 500                channel * DDRIODQ_CH_OFFSET;
 501        msk = 0x00;
 502        temp = 0x00;
 503
 504        /* enable */
 505        msk |= (byte_lane & 1) ? (1 << 3) : (1 << 0);
 506        if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
 507                temp |= msk;
 508
 509        /* select */
 510        msk |= (byte_lane & 1) ? (1 << 9) : (1 << 6);
 511        if (pi_count < EARLY_DB)
 512                temp |= msk;
 513
 514        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 515
 516        /* error check */
 517        if (pi_count > 0x3f) {
 518                training_message(channel, rank, byte_lane);
 519                mrc_post_code(0xee, 0xe3);
 520        }
 521
 522        LEAVEFN();
 523}
 524
 525/*
 526 * This function will return the amount of WDQ delay on the given
 527 * channel, rank, byte_lane as an absolute PI count.
 528 *
 529 * (currently doesn't comprehend rank)
 530 */
 531uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane)
 532{
 533        uint32_t reg;
 534        uint32_t temp;
 535        uint32_t pi_count;
 536
 537        ENTERFN();
 538
 539        /*
 540         * RDPTR (1/2 MCLK, 64 PIs)
 541         * BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
 542         * BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
 543         */
 544        reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 545                channel * DDRIODQ_CH_OFFSET;
 546        temp = msg_port_alt_read(DDRPHY, reg);
 547        temp >>= (byte_lane & 1) ? 12 : 0;
 548        temp &= 0xf;
 549
 550        /* Adjust PI_COUNT */
 551        pi_count = temp * HALF_CLK;
 552
 553        /*
 554         * PI (1/64 MCLK, 1 PIs)
 555         * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
 556         * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
 557         */
 558        reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
 559        reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
 560                channel * DDRIODQ_CH_OFFSET);
 561        temp = msg_port_alt_read(DDRPHY, reg);
 562        temp >>= 8;
 563        temp &= 0x3f;
 564
 565        /* Adjust PI_COUNT */
 566        pi_count += temp;
 567
 568        LEAVEFN();
 569
 570        return pi_count;
 571}
 572
 573/*
 574 * This function will program the WCMD delays based on an absolute
 575 * number of PIs.
 576 */
 577void set_wcmd(uint8_t channel, uint32_t pi_count)
 578{
 579        uint32_t reg;
 580        uint32_t msk;
 581        uint32_t temp;
 582
 583        ENTERFN();
 584
 585        /*
 586         * RDPTR (1/2 MCLK, 64 PIs)
 587         * CMDPTRREG[11:08] (0x0-0xF)
 588         */
 589        reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
 590        msk = 0xf00;
 591        temp = pi_count / HALF_CLK;
 592        temp <<= 8;
 593        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 594
 595        /* Adjust PI_COUNT */
 596        pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
 597
 598        /*
 599         * PI (1/64 MCLK, 1 PIs)
 600         * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
 601         * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
 602         * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
 603         * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
 604         * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
 605         * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
 606         * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
 607         * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
 608         */
 609        reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
 610        msk = 0x3f3f3f3f;
 611        temp = (pi_count << 24) | (pi_count << 16) |
 612                (pi_count << 8) | (pi_count << 0);
 613
 614        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 615        reg = CMDDLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;    /* PO */
 616        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 617
 618        /*
 619         * DEADBAND
 620         * CMDCFGREG0[17] (+1 select)
 621         * CMDCFGREG0[16] (enable)
 622         */
 623        reg = CMDCFGREG0 + channel * DDRIOCCC_CH_OFFSET;
 624        msk = 0x00;
 625        temp = 0x00;
 626
 627        /* enable */
 628        msk |= (1 << 16);
 629        if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
 630                temp |= msk;
 631
 632        /* select */
 633        msk |= (1 << 17);
 634        if (pi_count < EARLY_DB)
 635                temp |= msk;
 636
 637        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 638
 639        /* error check */
 640        if (pi_count > 0x3f)
 641                mrc_post_code(0xee, 0xe4);
 642
 643        LEAVEFN();
 644}
 645
 646/*
 647 * This function will return the amount of WCMD delay on the given
 648 * channel as an absolute PI count.
 649 */
 650uint32_t get_wcmd(uint8_t channel)
 651{
 652        uint32_t reg;
 653        uint32_t temp;
 654        uint32_t pi_count;
 655
 656        ENTERFN();
 657
 658        /*
 659         * RDPTR (1/2 MCLK, 64 PIs)
 660         * CMDPTRREG[11:08] (0x0-0xF)
 661         */
 662        reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
 663        temp = msg_port_alt_read(DDRPHY, reg);
 664        temp >>= 8;
 665        temp &= 0xf;
 666
 667        /* Adjust PI_COUNT */
 668        pi_count = temp * HALF_CLK;
 669
 670        /*
 671         * PI (1/64 MCLK, 1 PIs)
 672         * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
 673         * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
 674         * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
 675         * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
 676         * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
 677         * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
 678         * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
 679         * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
 680         */
 681        reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
 682        temp = msg_port_alt_read(DDRPHY, reg);
 683        temp >>= 16;
 684        temp &= 0x3f;
 685
 686        /* Adjust PI_COUNT */
 687        pi_count += temp;
 688
 689        LEAVEFN();
 690
 691        return pi_count;
 692}
 693
 694/*
 695 * This function will program the WCLK delays based on an absolute
 696 * number of PIs.
 697 */
 698void set_wclk(uint8_t channel, uint8_t rank, uint32_t pi_count)
 699{
 700        uint32_t reg;
 701        uint32_t msk;
 702        uint32_t temp;
 703
 704        ENTERFN();
 705
 706        /*
 707         * RDPTR (1/2 MCLK, 64 PIs)
 708         * CCPTRREG[15:12] -> CLK1 (0x0-0xF)
 709         * CCPTRREG[11:08] -> CLK0 (0x0-0xF)
 710         */
 711        reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
 712        msk = 0xff00;
 713        temp = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8);
 714        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 715
 716        /* Adjust PI_COUNT */
 717        pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
 718
 719        /*
 720         * PI (1/64 MCLK, 1 PIs)
 721         * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
 722         * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
 723         */
 724        reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0;
 725        reg += (channel * DDRIOCCC_CH_OFFSET);
 726        msk = 0x3f3f00;
 727        temp = (pi_count << 16) | (pi_count << 8);
 728        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 729
 730        reg = rank ? ECCB1DLLPICODER1 : ECCB1DLLPICODER1;
 731        reg += (channel * DDRIOCCC_CH_OFFSET);
 732        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 733
 734        reg = rank ? ECCB1DLLPICODER2 : ECCB1DLLPICODER2;
 735        reg += (channel * DDRIOCCC_CH_OFFSET);
 736        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 737
 738        reg = rank ? ECCB1DLLPICODER3 : ECCB1DLLPICODER3;
 739        reg += (channel * DDRIOCCC_CH_OFFSET);
 740        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 741
 742        /*
 743         * DEADBAND
 744         * CCCFGREG1[11:08] (+1 select)
 745         * CCCFGREG1[03:00] (enable)
 746         */
 747        reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
 748        msk = 0x00;
 749        temp = 0x00;
 750
 751        /* enable */
 752        msk |= 0xf;
 753        if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
 754                temp |= msk;
 755
 756        /* select */
 757        msk |= 0xf00;
 758        if (pi_count < EARLY_DB)
 759                temp |= msk;
 760
 761        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 762
 763        /* error check */
 764        if (pi_count > 0x3f)
 765                mrc_post_code(0xee, 0xe5);
 766
 767        LEAVEFN();
 768}
 769
 770/*
 771 * This function will return the amout of WCLK delay on the given
 772 * channel, rank as an absolute PI count.
 773 */
 774uint32_t get_wclk(uint8_t channel, uint8_t rank)
 775{
 776        uint32_t reg;
 777        uint32_t temp;
 778        uint32_t pi_count;
 779
 780        ENTERFN();
 781
 782        /*
 783         * RDPTR (1/2 MCLK, 64 PIs)
 784         * CCPTRREG[15:12] -> CLK1 (0x0-0xF)
 785         * CCPTRREG[11:08] -> CLK0 (0x0-0xF)
 786         */
 787        reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
 788        temp = msg_port_alt_read(DDRPHY, reg);
 789        temp >>= rank ? 12 : 8;
 790        temp &= 0xf;
 791
 792        /* Adjust PI_COUNT */
 793        pi_count = temp * HALF_CLK;
 794
 795        /*
 796         * PI (1/64 MCLK, 1 PIs)
 797         * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
 798         * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
 799         */
 800        reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0;
 801        reg += (channel * DDRIOCCC_CH_OFFSET);
 802        temp = msg_port_alt_read(DDRPHY, reg);
 803        temp >>= rank ? 16 : 8;
 804        temp &= 0x3f;
 805
 806        pi_count += temp;
 807
 808        LEAVEFN();
 809
 810        return pi_count;
 811}
 812
 813/*
 814 * This function will program the WCTL delays based on an absolute
 815 * number of PIs.
 816 *
 817 * (currently doesn't comprehend rank)
 818 */
 819void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count)
 820{
 821        uint32_t reg;
 822        uint32_t msk;
 823        uint32_t temp;
 824
 825        ENTERFN();
 826
 827        /*
 828         * RDPTR (1/2 MCLK, 64 PIs)
 829         * CCPTRREG[31:28] (0x0-0xF)
 830         * CCPTRREG[27:24] (0x0-0xF)
 831         */
 832        reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
 833        msk = 0xff000000;
 834        temp = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24);
 835        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 836
 837        /* Adjust PI_COUNT */
 838        pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
 839
 840        /*
 841         * PI (1/64 MCLK, 1 PIs)
 842         * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
 843         * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
 844         */
 845        reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
 846        msk = 0x3f000000;
 847        temp = (pi_count << 24);
 848        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 849
 850        reg = ECCB1DLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
 851        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 852
 853        reg = ECCB1DLLPICODER2 + channel * DDRIOCCC_CH_OFFSET;
 854        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 855
 856        reg = ECCB1DLLPICODER3 + channel * DDRIOCCC_CH_OFFSET;
 857        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 858
 859        /*
 860         * DEADBAND
 861         * CCCFGREG1[13:12] (+1 select)
 862         * CCCFGREG1[05:04] (enable)
 863         */
 864        reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
 865        msk = 0x00;
 866        temp = 0x00;
 867
 868        /* enable */
 869        msk |= 0x30;
 870        if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
 871                temp |= msk;
 872
 873        /* select */
 874        msk |= 0x3000;
 875        if (pi_count < EARLY_DB)
 876                temp |= msk;
 877
 878        mrc_alt_write_mask(DDRPHY, reg, temp, msk);
 879
 880        /* error check */
 881        if (pi_count > 0x3f)
 882                mrc_post_code(0xee, 0xe6);
 883
 884        LEAVEFN();
 885}
 886
 887/*
 888 * This function will return the amount of WCTL delay on the given
 889 * channel, rank as an absolute PI count.
 890 *
 891 * (currently doesn't comprehend rank)
 892 */
 893uint32_t get_wctl(uint8_t channel, uint8_t rank)
 894{
 895        uint32_t reg;
 896        uint32_t temp;
 897        uint32_t pi_count;
 898
 899        ENTERFN();
 900
 901        /*
 902         * RDPTR (1/2 MCLK, 64 PIs)
 903         * CCPTRREG[31:28] (0x0-0xF)
 904         * CCPTRREG[27:24] (0x0-0xF)
 905         */
 906        reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
 907        temp = msg_port_alt_read(DDRPHY, reg);
 908        temp >>= 24;
 909        temp &= 0xf;
 910
 911        /* Adjust PI_COUNT */
 912        pi_count = temp * HALF_CLK;
 913
 914        /*
 915         * PI (1/64 MCLK, 1 PIs)
 916         * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
 917         * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
 918         */
 919        reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
 920        temp = msg_port_alt_read(DDRPHY, reg);
 921        temp >>= 24;
 922        temp &= 0x3f;
 923
 924        /* Adjust PI_COUNT */
 925        pi_count += temp;
 926
 927        LEAVEFN();
 928
 929        return pi_count;
 930}
 931
 932/*
 933 * This function will program the internal Vref setting in a given
 934 * byte lane in a given channel.
 935 */
 936void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting)
 937{
 938        uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
 939
 940        ENTERFN();
 941
 942        DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n",
 943            channel, byte_lane, setting);
 944
 945        mrc_alt_write_mask(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
 946                (byte_lane >> 1) * DDRIODQ_BL_OFFSET,
 947                vref_codes[setting] << 2, 0xfc);
 948
 949        /*
 950         * need to wait ~300ns for Vref to settle
 951         * (check that this is necessary)
 952         */
 953        delay_n(300);
 954
 955        /* ??? may need to clear pointers ??? */
 956
 957        LEAVEFN();
 958}
 959
 960/*
 961 * This function will return the internal Vref setting for the given
 962 * channel, byte_lane.
 963 */
 964uint32_t get_vref(uint8_t channel, uint8_t byte_lane)
 965{
 966        uint8_t j;
 967        uint32_t ret_val = sizeof(vref_codes) / 2;
 968        uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
 969        uint32_t temp;
 970
 971        ENTERFN();
 972
 973        temp = msg_port_alt_read(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
 974                (byte_lane >> 1) * DDRIODQ_BL_OFFSET);
 975        temp >>= 2;
 976        temp &= 0x3f;
 977
 978        for (j = 0; j < sizeof(vref_codes); j++) {
 979                if (vref_codes[j] == temp) {
 980                        ret_val = j;
 981                        break;
 982                }
 983        }
 984
 985        LEAVEFN();
 986
 987        return ret_val;
 988}
 989
 990/*
 991 * This function will return a 32-bit address in the desired
 992 * channel and rank.
 993 */
 994uint32_t get_addr(uint8_t channel, uint8_t rank)
 995{
 996        uint32_t offset = 32 * 1024 * 1024;     /* 32MB */
 997
 998        /* Begin product specific code */
 999        if (channel > 0) {
1000                DPF(D_ERROR, "ILLEGAL CHANNEL\n");
1001                DEAD_LOOP();
1002        }
1003
1004        if (rank > 1) {
1005                DPF(D_ERROR, "ILLEGAL RANK\n");
1006                DEAD_LOOP();
1007        }
1008
1009        /* use 256MB lowest density as per DRP == 0x0003 */
1010        offset += rank * (256 * 1024 * 1024);
1011
1012        return offset;
1013}
1014
1015/*
1016 * This function will sample the DQTRAINSTS registers in the given
1017 * channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'.
1018 *
1019 * It will return an encoded 32-bit date in which each bit corresponds to
1020 * the sampled value on the byte lane.
1021 */
1022uint32_t sample_dqs(struct mrc_params *mrc_params, uint8_t channel,
1023                    uint8_t rank, bool rcvn)
1024{
1025        uint8_t j;      /* just a counter */
1026        uint8_t bl;     /* which BL in the module (always 2 per module) */
1027        uint8_t bl_grp; /* which BL module */
1028        /* byte lane divisor */
1029        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1030        uint32_t msk[2];        /* BLx in module */
1031        /* DQTRAINSTS register contents for each sample */
1032        uint32_t sampled_val[SAMPLE_SIZE];
1033        uint32_t num_0s;        /* tracks the number of '0' samples */
1034        uint32_t num_1s;        /* tracks the number of '1' samples */
1035        uint32_t ret_val = 0x00;        /* assume all '0' samples */
1036        uint32_t address = get_addr(channel, rank);
1037
1038        /* initialise msk[] */
1039        msk[0] = rcvn ? (1 << 1) : (1 << 9);    /* BL0 */
1040        msk[1] = rcvn ? (1 << 0) : (1 << 8);    /* BL1 */
1041
1042        /* cycle through each byte lane group */
1043        for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++) {
1044                /* take SAMPLE_SIZE samples */
1045                for (j = 0; j < SAMPLE_SIZE; j++) {
1046                        hte_mem_op(address, mrc_params->first_run,
1047                                   rcvn ? 0 : 1);
1048                        mrc_params->first_run = 0;
1049
1050                        /*
1051                         * record the contents of the proper
1052                         * DQTRAINSTS register
1053                         */
1054                        sampled_val[j] = msg_port_alt_read(DDRPHY,
1055                                DQTRAINSTS +
1056                                bl_grp * DDRIODQ_BL_OFFSET +
1057                                channel * DDRIODQ_CH_OFFSET);
1058                }
1059
1060                /*
1061                 * look for a majority value (SAMPLE_SIZE / 2) + 1
1062                 * on the byte lane and set that value in the corresponding
1063                 * ret_val bit
1064                 */
1065                for (bl = 0; bl < 2; bl++) {
1066                        num_0s = 0x00;  /* reset '0' tracker for byte lane */
1067                        num_1s = 0x00;  /* reset '1' tracker for byte lane */
1068                        for (j = 0; j < SAMPLE_SIZE; j++) {
1069                                if (sampled_val[j] & msk[bl])
1070                                        num_1s++;
1071                                else
1072                                        num_0s++;
1073                        }
1074                if (num_1s > num_0s)
1075                        ret_val |= (1 << (bl + bl_grp * 2));
1076                }
1077        }
1078
1079        /*
1080         * "ret_val.0" contains the status of BL0
1081         * "ret_val.1" contains the status of BL1
1082         * "ret_val.2" contains the status of BL2
1083         * etc.
1084         */
1085        return ret_val;
1086}
1087
1088/* This function will find the rising edge transition on RCVN or WDQS */
1089void find_rising_edge(struct mrc_params *mrc_params, uint32_t delay[],
1090                      uint8_t channel, uint8_t rank, bool rcvn)
1091{
1092        bool all_edges_found;   /* determines stop condition */
1093        bool direction[NUM_BYTE_LANES]; /* direction indicator */
1094        uint8_t sample; /* sample counter */
1095        uint8_t bl;     /* byte lane counter */
1096        /* byte lane divisor */
1097        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1098        uint32_t sample_result[SAMPLE_CNT];     /* results of sample_dqs() */
1099        uint32_t temp;
1100        uint32_t transition_pattern;
1101
1102        ENTERFN();
1103
1104        /* select hte and request initial configuration */
1105        select_hte();
1106        mrc_params->first_run = 1;
1107
1108        /* Take 3 sample points (T1,T2,T3) to obtain a transition pattern */
1109        for (sample = 0; sample < SAMPLE_CNT; sample++) {
1110                /* program the desired delays for sample */
1111                for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1112                        /* increase sample delay by 26 PI (0.2 CLK) */
1113                        if (rcvn) {
1114                                set_rcvn(channel, rank, bl,
1115                                         delay[bl] + sample * SAMPLE_DLY);
1116                        } else {
1117                                set_wdqs(channel, rank, bl,
1118                                         delay[bl] + sample * SAMPLE_DLY);
1119                        }
1120                }
1121
1122                /* take samples (Tsample_i) */
1123                sample_result[sample] = sample_dqs(mrc_params,
1124                        channel, rank, rcvn);
1125
1126                DPF(D_TRN,
1127                    "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n",
1128                    rcvn ? "RCVN" : "WDQS", channel, rank, sample,
1129                    sample * SAMPLE_DLY, sample_result[sample]);
1130        }
1131
1132        /*
1133         * This pattern will help determine where we landed and ultimately
1134         * how to place RCVEN/WDQS.
1135         */
1136        for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1137                /* build transition_pattern (MSB is 1st sample) */
1138                transition_pattern = 0;
1139                for (sample = 0; sample < SAMPLE_CNT; sample++) {
1140                        transition_pattern |=
1141                                ((sample_result[sample] & (1 << bl)) >> bl) <<
1142                                (SAMPLE_CNT - 1 - sample);
1143                }
1144
1145                DPF(D_TRN, "=== transition pattern %d\n", transition_pattern);
1146
1147                /*
1148                 * set up to look for rising edge based on
1149                 * transition_pattern
1150                 */
1151                switch (transition_pattern) {
1152                case 0: /* sampled 0->0->0 */
1153                        /* move forward from T3 looking for 0->1 */
1154                        delay[bl] += 2 * SAMPLE_DLY;
1155                        direction[bl] = FORWARD;
1156                        break;
1157                case 1: /* sampled 0->0->1 */
1158                case 5: /* sampled 1->0->1 (bad duty cycle) *HSD#237503* */
1159                        /* move forward from T2 looking for 0->1 */
1160                        delay[bl] += 1 * SAMPLE_DLY;
1161                        direction[bl] = FORWARD;
1162                        break;
1163                case 2: /* sampled 0->1->0 (bad duty cycle) *HSD#237503* */
1164                case 3: /* sampled 0->1->1 */
1165                        /* move forward from T1 looking for 0->1 */
1166                        delay[bl] += 0 * SAMPLE_DLY;
1167                        direction[bl] = FORWARD;
1168                        break;
1169                case 4: /* sampled 1->0->0 (assumes BL8, HSD#234975) */
1170                        /* move forward from T3 looking for 0->1 */
1171                        delay[bl] += 2 * SAMPLE_DLY;
1172                        direction[bl] = FORWARD;
1173                        break;
1174                case 6: /* sampled 1->1->0 */
1175                case 7: /* sampled 1->1->1 */
1176                        /* move backward from T1 looking for 1->0 */
1177                        delay[bl] += 0 * SAMPLE_DLY;
1178                        direction[bl] = BACKWARD;
1179                        break;
1180                default:
1181                        mrc_post_code(0xee, 0xee);
1182                        break;
1183                }
1184
1185                /* program delays */
1186                if (rcvn)
1187                        set_rcvn(channel, rank, bl, delay[bl]);
1188                else
1189                        set_wdqs(channel, rank, bl, delay[bl]);
1190        }
1191
1192        /*
1193         * Based on the observed transition pattern on the byte lane,
1194         * begin looking for a rising edge with single PI granularity.
1195         */
1196        do {
1197                all_edges_found = true; /* assume all byte lanes passed */
1198                /* take a sample */
1199                temp = sample_dqs(mrc_params, channel, rank, rcvn);
1200                /* check all each byte lane for proper edge */
1201                for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1202                        if (temp & (1 << bl)) {
1203                                /* sampled "1" */
1204                                if (direction[bl] == BACKWARD) {
1205                                        /*
1206                                         * keep looking for edge
1207                                         * on this byte lane
1208                                         */
1209                                        all_edges_found = false;
1210                                        delay[bl] -= 1;
1211                                        if (rcvn) {
1212                                                set_rcvn(channel, rank,
1213                                                         bl, delay[bl]);
1214                                        } else {
1215                                                set_wdqs(channel, rank,
1216                                                         bl, delay[bl]);
1217                                        }
1218                                }
1219                        } else {
1220                                /* sampled "0" */
1221                                if (direction[bl] == FORWARD) {
1222                                        /*
1223                                         * keep looking for edge
1224                                         * on this byte lane
1225                                         */
1226                                        all_edges_found = false;
1227                                        delay[bl] += 1;
1228                                        if (rcvn) {
1229                                                set_rcvn(channel, rank,
1230                                                         bl, delay[bl]);
1231                                        } else {
1232                                                set_wdqs(channel, rank,
1233                                                         bl, delay[bl]);
1234                                        }
1235                                }
1236                        }
1237                }
1238        } while (!all_edges_found);
1239
1240        /* restore DDR idle state */
1241        dram_init_command(DCMD_PREA(rank));
1242
1243        DPF(D_TRN, "Delay %03X %03X %03X %03X\n",
1244            delay[0], delay[1], delay[2], delay[3]);
1245
1246        LEAVEFN();
1247}
1248
1249/*
1250 * This function will return a 32 bit mask that will be used to
1251 * check for byte lane failures.
1252 */
1253uint32_t byte_lane_mask(struct mrc_params *mrc_params)
1254{
1255        uint32_t j;
1256        uint32_t ret_val = 0x00;
1257
1258        /*
1259         * set ret_val based on NUM_BYTE_LANES such that you will check
1260         * only BL0 in result
1261         *
1262         * (each bit in result represents a byte lane)
1263         */
1264        for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES)
1265                ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES));
1266
1267        /*
1268         * HSD#235037
1269         * need to adjust the mask for 16-bit mode
1270         */
1271        if (mrc_params->channel_width == X16)
1272                ret_val |= (ret_val << 2);
1273
1274        return ret_val;
1275}
1276
1277/*
1278 * Check memory executing simple write/read/verify at the specified address.
1279 *
1280 * Bits in the result indicate failure on specific byte lane.
1281 */
1282uint32_t check_rw_coarse(struct mrc_params *mrc_params, uint32_t address)
1283{
1284        uint32_t result = 0;
1285        uint8_t first_run = 0;
1286
1287        if (mrc_params->hte_setup) {
1288                mrc_params->hte_setup = 0;
1289                first_run = 1;
1290                select_hte();
1291        }
1292
1293        result = hte_basic_write_read(mrc_params, address, first_run,
1294                                      WRITE_TRAIN);
1295
1296        DPF(D_TRN, "check_rw_coarse result is %x\n", result);
1297
1298        return result;
1299}
1300
1301/*
1302 * Check memory executing write/read/verify of many data patterns
1303 * at the specified address. Bits in the result indicate failure
1304 * on specific byte lane.
1305 */
1306uint32_t check_bls_ex(struct mrc_params *mrc_params, uint32_t address)
1307{
1308        uint32_t result;
1309        uint8_t first_run = 0;
1310
1311        if (mrc_params->hte_setup) {
1312                mrc_params->hte_setup = 0;
1313                first_run = 1;
1314                select_hte();
1315        }
1316
1317        result = hte_write_stress_bit_lanes(mrc_params, address, first_run);
1318
1319        DPF(D_TRN, "check_bls_ex result is %x\n", result);
1320
1321        return result;
1322}
1323
1324/*
1325 * 32-bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1
1326 *
1327 * The function takes pointer to previous 32 bit value and
1328 * modifies it to next value.
1329 */
1330void lfsr32(uint32_t *lfsr_ptr)
1331{
1332        uint32_t bit;
1333        uint32_t lfsr;
1334        int i;
1335
1336        lfsr = *lfsr_ptr;
1337
1338        for (i = 0; i < 32; i++) {
1339                bit = 1 ^ (lfsr & 1);
1340                bit = bit ^ ((lfsr & 2) >> 1);
1341                bit = bit ^ ((lfsr & 4) >> 2);
1342                bit = bit ^ ((lfsr & 0x400000) >> 22);
1343
1344                lfsr = ((lfsr >> 1) | (bit << 31));
1345        }
1346
1347        *lfsr_ptr = lfsr;
1348}
1349
1350/* Clear the pointers in a given byte lane in a given channel */
1351void clear_pointers(void)
1352{
1353        uint8_t channel;
1354        uint8_t bl;
1355
1356        ENTERFN();
1357
1358        for (channel = 0; channel < NUM_CHANNELS; channel++) {
1359                for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1360                        mrc_alt_write_mask(DDRPHY,
1361                                           B01PTRCTL1 +
1362                                           channel * DDRIODQ_CH_OFFSET +
1363                                           (bl >> 1) * DDRIODQ_BL_OFFSET,
1364                                           ~(1 << 8), (1 << 8));
1365
1366                        mrc_alt_write_mask(DDRPHY,
1367                                           B01PTRCTL1 +
1368                                           channel * DDRIODQ_CH_OFFSET +
1369                                           (bl >> 1) * DDRIODQ_BL_OFFSET,
1370                                           (1 << 8), (1 << 8));
1371                }
1372        }
1373
1374        LEAVEFN();
1375}
1376
1377static void print_timings_internal(uint8_t algo, uint8_t channel, uint8_t rank,
1378                                   uint8_t bl_divisor)
1379{
1380        uint8_t bl;
1381
1382        switch (algo) {
1383        case RCVN:
1384                DPF(D_INFO, "\nRCVN[%02d:%02d]", channel, rank);
1385                break;
1386        case WDQS:
1387                DPF(D_INFO, "\nWDQS[%02d:%02d]", channel, rank);
1388                break;
1389        case WDQX:
1390                DPF(D_INFO, "\nWDQx[%02d:%02d]", channel, rank);
1391                break;
1392        case RDQS:
1393                DPF(D_INFO, "\nRDQS[%02d:%02d]", channel, rank);
1394                break;
1395        case VREF:
1396                DPF(D_INFO, "\nVREF[%02d:%02d]", channel, rank);
1397                break;
1398        case WCMD:
1399                DPF(D_INFO, "\nWCMD[%02d:%02d]", channel, rank);
1400                break;
1401        case WCTL:
1402                DPF(D_INFO, "\nWCTL[%02d:%02d]", channel, rank);
1403                break;
1404        case WCLK:
1405                DPF(D_INFO, "\nWCLK[%02d:%02d]", channel, rank);
1406                break;
1407        default:
1408                break;
1409        }
1410
1411        for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1412                switch (algo) {
1413                case RCVN:
1414                        DPF(D_INFO, " %03d", get_rcvn(channel, rank, bl));
1415                        break;
1416                case WDQS:
1417                        DPF(D_INFO, " %03d", get_wdqs(channel, rank, bl));
1418                        break;
1419                case WDQX:
1420                        DPF(D_INFO, " %03d", get_wdq(channel, rank, bl));
1421                        break;
1422                case RDQS:
1423                        DPF(D_INFO, " %03d", get_rdqs(channel, rank, bl));
1424                        break;
1425                case VREF:
1426                        DPF(D_INFO, " %03d", get_vref(channel, bl));
1427                        break;
1428                case WCMD:
1429                        DPF(D_INFO, " %03d", get_wcmd(channel));
1430                        break;
1431                case WCTL:
1432                        DPF(D_INFO, " %03d", get_wctl(channel, rank));
1433                        break;
1434                case WCLK:
1435                        DPF(D_INFO, " %03d", get_wclk(channel, rank));
1436                        break;
1437                default:
1438                        break;
1439                }
1440        }
1441}
1442
1443void print_timings(struct mrc_params *mrc_params)
1444{
1445        uint8_t algo;
1446        uint8_t channel;
1447        uint8_t rank;
1448        uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1449
1450        DPF(D_INFO, "\n---------------------------");
1451        DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3");
1452        DPF(D_INFO, "\n===========================");
1453
1454        for (algo = 0; algo < MAX_ALGOS; algo++) {
1455                for (channel = 0; channel < NUM_CHANNELS; channel++) {
1456                        if (mrc_params->channel_enables & (1 << channel)) {
1457                                for (rank = 0; rank < NUM_RANKS; rank++) {
1458                                        if (mrc_params->rank_enables &
1459                                                (1 << rank)) {
1460                                                print_timings_internal(algo,
1461                                                        channel, rank,
1462                                                        bl_divisor);
1463                                        }
1464                                }
1465                        }
1466                }
1467        }
1468
1469        DPF(D_INFO, "\n---------------------------");
1470        DPF(D_INFO, "\n");
1471}
1472