uboot/drivers/ddr/marvell/axp/ddr3_sdram.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Marvell International Ltd. and its affiliates
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0
   5 */
   6
   7#include <common.h>
   8#include <i2c.h>
   9#include <spl.h>
  10#include <asm/io.h>
  11#include <asm/arch/cpu.h>
  12#include <asm/arch/soc.h>
  13
  14#include "ddr3_hw_training.h"
  15#include "xor.h"
  16#include "xor_regs.h"
  17
  18static void ddr3_flush_l1_line(u32 line);
  19
  20extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
  21extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
  22#if defined(MV88F78X60)
  23extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
  24#endif
  25extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
  26
  27#if defined(MV88F78X60) || defined(MV88F672X)
  28/* PBS locked dq (per pup) */
  29u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
  30u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
  31u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
  32
  33int per_bit_data[MAX_PUP_NUM][DQ_NUM];
  34#endif
  35
  36static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
  37
  38static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
  39
  40#define XOR_TIMEOUT 0x8000000
  41
  42struct xor_channel_t {
  43        struct crc_dma_desc *desc;
  44        unsigned long desc_phys_addr;
  45};
  46
  47#define XOR_CAUSE_DONE_MASK(chan)       ((0x1 | 0x2) << (chan * 16))
  48
  49void xor_waiton_eng(int chan)
  50{
  51        int timeout;
  52
  53        timeout = 0;
  54        while (!(reg_read(XOR_CAUSE_REG(XOR_UNIT(chan))) &
  55                 XOR_CAUSE_DONE_MASK(XOR_CHAN(chan)))) {
  56                if (timeout > XOR_TIMEOUT)
  57                        goto timeout;
  58
  59                timeout++;
  60        }
  61
  62        timeout = 0;
  63        while (mv_xor_state_get(chan) != MV_IDLE) {
  64                if (timeout > XOR_TIMEOUT)
  65                        goto timeout;
  66
  67                timeout++;
  68        }
  69
  70        /* Clear int */
  71        reg_write(XOR_CAUSE_REG(XOR_UNIT(chan)),
  72                  ~(XOR_CAUSE_DONE_MASK(XOR_CHAN(chan))));
  73
  74timeout:
  75        return;
  76}
  77
  78static int special_compare_pattern(u32 uj)
  79{
  80        if ((uj == 30) || (uj == 31) || (uj == 61) || (uj == 62) ||
  81            (uj == 93) || (uj == 94) || (uj == 126) || (uj == 127))
  82                return 1;
  83
  84        return 0;
  85}
  86
  87/*
  88 * Compare code extracted as its used by multiple functions. This
  89 * reduces code-size and makes it easier to maintain it. Additionally
  90 * the code is not indented that much and therefore easier to read.
  91 */
  92static void compare_pattern_v1(u32 uj, u32 *pup, u32 *pattern,
  93                               u32 pup_groups, int debug_dqs)
  94{
  95        u32 val;
  96        u32 uk;
  97        u32 var1;
  98        u32 var2;
  99        __maybe_unused u32 dq;
 100
 101        if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0xFF)) {
 102                for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
 103                        val = CMP_BYTE_SHIFT * uk;
 104                        var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
 105                        var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
 106
 107                        if (var1 != var2) {
 108                                *pup |= (1 << (uk + (PUP_NUM_32BIT *
 109                                                     (uj % pup_groups))));
 110
 111#ifdef MV_DEBUG_DQS
 112                                if (!debug_dqs)
 113                                        continue;
 114
 115                                for (dq = 0; dq < DQ_NUM; dq++) {
 116                                        val = uk + (PUP_NUM_32BIT *
 117                                                    (uj % pup_groups));
 118                                        if (((var1 >> dq) & 0x1) !=
 119                                            ((var2 >> dq) & 0x1))
 120                                                per_bit_data[val][dq] = 1;
 121                                        else
 122                                                per_bit_data[val][dq] = 0;
 123                                }
 124#endif
 125                        }
 126                }
 127        }
 128}
 129
 130static void compare_pattern_v2(u32 uj, u32 *pup, u32 *pattern)
 131{
 132        u32 val;
 133        u32 uk;
 134        u32 var1;
 135        u32 var2;
 136
 137        if (((sdram_data[uj]) != (pattern[uj])) && (*pup != 0x3)) {
 138                /* Found error */
 139                for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
 140                        val = CMP_BYTE_SHIFT * uk;
 141                        var1 = (sdram_data[uj] >> val) & CMP_BYTE_MASK;
 142                        var2 = (pattern[uj] >> val) & CMP_BYTE_MASK;
 143                        if (var1 != var2)
 144                                *pup |= (1 << (uk % PUP_NUM_16BIT));
 145                }
 146        }
 147}
 148
 149/*
 150 * Name:     ddr3_sdram_compare
 151 * Desc:     Execute compare per PUP
 152 * Args:     unlock_pup      Bit array of the unlock pups
 153 *           new_locked_pup  Output  bit array of the pups with failed compare
 154 *           pattern         Pattern to compare
 155 *           pattern_len     Length of pattern (in bytes)
 156 *           sdram_offset    offset address to the SDRAM
 157 *           write           write to the SDRAM before read
 158 *           mask            compare pattern with mask;
 159 *           mask_pattern    Mask to compare pattern
 160 *
 161 * Notes:
 162 * Returns:  MV_OK if success, other error code if fail.
 163 */
 164int ddr3_sdram_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
 165                       u32 *new_locked_pup, u32 *pattern,
 166                       u32 pattern_len, u32 sdram_offset, int write,
 167                       int mask, u32 *mask_pattern,
 168                       int special_compare)
 169{
 170        u32 uj;
 171        __maybe_unused u32 pup_groups;
 172        __maybe_unused u32 dq;
 173
 174#if !defined(MV88F67XX)
 175        if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
 176                pup_groups = 2;
 177        else
 178                pup_groups = 1;
 179#endif
 180
 181        ddr3_reset_phy_read_fifo();
 182
 183        /* Check if need to write to sdram before read */
 184        if (write == 1)
 185                ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
 186
 187        ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
 188
 189        /* Compare read result to write */
 190        for (uj = 0; uj < pattern_len; uj++) {
 191                if (special_compare && special_compare_pattern(uj))
 192                        continue;
 193
 194#if defined(MV88F78X60) || defined(MV88F672X)
 195                compare_pattern_v1(uj, new_locked_pup, pattern, pup_groups, 1);
 196#elif defined(MV88F67XX)
 197                compare_pattern_v2(uj, new_locked_pup, pattern);
 198#endif
 199        }
 200
 201        return MV_OK;
 202}
 203
 204#if defined(MV88F78X60) || defined(MV88F672X)
 205/*
 206 * Name:     ddr3_sdram_dm_compare
 207 * Desc:     Execute compare per PUP
 208 * Args:     unlock_pup      Bit array of the unlock pups
 209 *           new_locked_pup  Output  bit array of the pups with failed compare
 210 *           pattern         Pattern to compare
 211 *           pattern_len     Length of pattern (in bytes)
 212 *           sdram_offset    offset address to the SDRAM
 213 *           write           write to the SDRAM before read
 214 *           mask            compare pattern with mask;
 215 *           mask_pattern    Mask to compare pattern
 216 *
 217 * Notes:
 218 * Returns:  MV_OK if success, other error code if fail.
 219 */
 220int ddr3_sdram_dm_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
 221                          u32 *new_locked_pup, u32 *pattern,
 222                          u32 sdram_offset)
 223{
 224        u32 uj, uk, var1, var2, pup_groups;
 225        u32 val;
 226        u32 pup = 0;
 227
 228        if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
 229                pup_groups = 2;
 230        else
 231                pup_groups = 1;
 232
 233        ddr3_dram_sram_burst((u32)pattern, SDRAM_PBS_TX_OFFS,
 234                             LEN_PBS_PATTERN);
 235        ddr3_dram_sram_burst(SDRAM_PBS_TX_OFFS, (u32)sdram_data,
 236                             LEN_PBS_PATTERN);
 237
 238        /* Validate the correctness of the results */
 239        for (uj = 0; uj < LEN_PBS_PATTERN; uj++)
 240                compare_pattern_v1(uj, &pup, pattern, pup_groups, 0);
 241
 242        /* Test the DM Signals */
 243        *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10) = 0x12345678;
 244        *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14) = 0x12345678;
 245
 246        sdram_data[0] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x10);
 247        sdram_data[1] = *(u32 *)(SDRAM_PBS_TX_OFFS + 0x14);
 248
 249        for (uj = 0; uj < 2; uj++) {
 250                if (((sdram_data[uj]) != (pattern[uj])) &&
 251                    (*new_locked_pup != 0xFF)) {
 252                        for (uk = 0; uk < PUP_NUM_32BIT; uk++) {
 253                                val = CMP_BYTE_SHIFT * uk;
 254                                var1 = ((sdram_data[uj] >> val) & CMP_BYTE_MASK);
 255                                var2 = ((pattern[uj] >> val) & CMP_BYTE_MASK);
 256                                if (var1 != var2) {
 257                                        *new_locked_pup |= (1 << (uk +
 258                                                (PUP_NUM_32BIT * (uj % pup_groups))));
 259                                        *new_locked_pup |= pup;
 260                                }
 261                        }
 262                }
 263        }
 264
 265        return MV_OK;
 266}
 267
 268/*
 269 * Name:     ddr3_sdram_pbs_compare
 270 * Desc:     Execute SRAM compare per PUP and DQ.
 271 * Args:     pup_locked             bit array of locked pups
 272 *           is_tx                  Indicate whether Rx or Tx
 273 *           pbs_pattern_idx        Index of PBS pattern
 274 *           pbs_curr_val           The PBS value
 275 *           pbs_lock_val           The value to set to locked PBS
 276 *           skew_array             Global array to update with the compare results
 277 *           ai_unlock_pup_dq_array bit array of the locked / unlocked pups per dq.
 278 * Notes:
 279 * Returns:  MV_OK if success, other error code if fail.
 280 */
 281int ddr3_sdram_pbs_compare(MV_DRAM_INFO *dram_info, u32 pup_locked,
 282                           int is_tx, u32 pbs_pattern_idx,
 283                           u32 pbs_curr_val, u32 pbs_lock_val,
 284                           u32 *skew_array, u8 *unlock_pup_dq_array,
 285                           u32 ecc)
 286{
 287        /* bit array failed dq per pup for current compare */
 288        u32 pbs_write_pup[DQ_NUM] = { 0 };
 289        u32 update_pup; /* pup as HW convention */
 290        u32 max_pup;    /* maximal pup index */
 291        u32 pup_addr;
 292        u32 ui, dq, pup;
 293        int var1, var2;
 294        u32 sdram_offset, pup_groups, tmp_pup;
 295        u32 *pattern_ptr;
 296        u32 val;
 297
 298        /* Choose pattern */
 299        switch (dram_info->ddr_width) {
 300#if defined(MV88F672X)
 301        case 16:
 302                pattern_ptr = (u32 *)&pbs_pattern[pbs_pattern_idx];
 303                break;
 304#endif
 305        case 32:
 306                pattern_ptr = (u32 *)&pbs_pattern_32b[pbs_pattern_idx];
 307                break;
 308#if defined(MV88F78X60)
 309        case 64:
 310                pattern_ptr = (u32 *)&pbs_pattern_64b[pbs_pattern_idx];
 311                break;
 312#endif
 313        default:
 314                return MV_FAIL;
 315        }
 316
 317        max_pup = dram_info->num_of_std_pups;
 318
 319        sdram_offset = SDRAM_PBS_I_OFFS + pbs_pattern_idx * SDRAM_PBS_NEXT_OFFS;
 320
 321        if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
 322                pup_groups = 2;
 323        else
 324                pup_groups = 1;
 325
 326        ddr3_reset_phy_read_fifo();
 327
 328        /* Check if need to write to sdram before read */
 329        if (is_tx == 1) {
 330                ddr3_dram_sram_burst((u32)pattern_ptr, sdram_offset,
 331                                     LEN_PBS_PATTERN);
 332        }
 333
 334        ddr3_dram_sram_read(sdram_offset, (u32)sdram_data, LEN_PBS_PATTERN);
 335
 336        /* Compare read result to write */
 337        for (ui = 0; ui < LEN_PBS_PATTERN; ui++) {
 338                if ((sdram_data[ui]) != (pattern_ptr[ui])) {
 339                        /* found error */
 340                        /* error in low pup group */
 341                        for (pup = 0; pup < PUP_NUM_32BIT; pup++) {
 342                                val = CMP_BYTE_SHIFT * pup;
 343                                var1 = ((sdram_data[ui] >> val) &
 344                                        CMP_BYTE_MASK);
 345                                var2 = ((pattern_ptr[ui] >> val) &
 346                                        CMP_BYTE_MASK);
 347
 348                                if (var1 != var2) {
 349                                        if (dram_info->ddr_width > 16) {
 350                                                tmp_pup = (pup + PUP_NUM_32BIT *
 351                                                           (ui % pup_groups));
 352                                        } else {
 353                                                tmp_pup = (pup % PUP_NUM_16BIT);
 354                                        }
 355
 356                                        update_pup = (1 << tmp_pup);
 357                                        if (ecc && (update_pup != 0x1))
 358                                                continue;
 359
 360                                        /*
 361                                         * Pup is failed - Go over all DQs and
 362                                         * look for failures
 363                                         */
 364                                        for (dq = 0; dq < DQ_NUM; dq++) {
 365                                                val = tmp_pup * (1 - ecc) +
 366                                                        ecc * ECC_PUP;
 367                                                if (((var1 >> dq) & 0x1) !=
 368                                                    ((var2 >> dq) & 0x1)) {
 369                                                        if (pbs_locked_dq[val][dq] == 1 &&
 370                                                            pbs_locked_value[val][dq] != pbs_curr_val)
 371                                                                continue;
 372
 373                                                        /*
 374                                                         * Activate write to
 375                                                         * update PBS to
 376                                                         * pbs_lock_val
 377                                                         */
 378                                                        pbs_write_pup[dq] |=
 379                                                                update_pup;
 380
 381                                                        /*
 382                                                         * Update the
 383                                                         * unlock_pup_dq_array
 384                                                         */
 385                                                        unlock_pup_dq_array[dq] &=
 386                                                                ~update_pup;
 387
 388                                                        /*
 389                                                         * Lock PBS value for
 390                                                         * failed bits in
 391                                                         * compare operation
 392                                                         */
 393                                                        skew_array[tmp_pup * DQ_NUM + dq] =
 394                                                                pbs_curr_val;
 395                                                }
 396                                        }
 397                                }
 398                        }
 399                }
 400        }
 401
 402        pup_addr = (is_tx == 1) ? PUP_PBS_TX : PUP_PBS_RX;
 403
 404        /* Set last failed bits PBS to min / max pbs value */
 405        for (dq = 0; dq < DQ_NUM; dq++) {
 406                for (pup = 0; pup < max_pup; pup++) {
 407                        if (pbs_write_pup[dq] & (1 << pup)) {
 408                                val = pup * (1 - ecc) + ecc * ECC_PUP;
 409                                if (pbs_locked_dq[val][dq] == 1 &&
 410                                    pbs_locked_value[val][dq] != pbs_curr_val)
 411                                        continue;
 412
 413                                /* Mark the dq as locked */
 414                                pbs_locked_dq[val][dq] = 1;
 415                                pbs_locked_value[val][dq] = pbs_curr_val;
 416                                ddr3_write_pup_reg(pup_addr +
 417                                                   pbs_dq_mapping[val][dq],
 418                                                   CS0, val, 0, pbs_lock_val);
 419                        }
 420                }
 421        }
 422
 423        return MV_OK;
 424}
 425#endif
 426
 427/*
 428 * Name:     ddr3_sdram_direct_compare
 429 * Desc:     Execute compare  per PUP without DMA (no burst mode)
 430 * Args:     unlock_pup       Bit array of the unlock pups
 431 *           new_locked_pup   Output  bit array of the pups with failed compare
 432 *           pattern          Pattern to compare
 433 *           pattern_len      Length of pattern (in bytes)
 434 *           sdram_offset     offset address to the SDRAM
 435 *           write            write to the SDRAM before read
 436 *           mask             compare pattern with mask;
 437 *           auiMaskPatter    Mask to compare pattern
 438 *
 439 * Notes:
 440 * Returns:  MV_OK if success, other error code if fail.
 441 */
 442int ddr3_sdram_direct_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
 443                              u32 *new_locked_pup, u32 *pattern,
 444                              u32 pattern_len, u32 sdram_offset,
 445                              int write, int mask, u32 *mask_pattern)
 446{
 447        u32 uj, uk, pup_groups;
 448        u32 *sdram_addr;        /* used to read from SDRAM */
 449
 450        sdram_addr = (u32 *)sdram_offset;
 451
 452        if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
 453                pup_groups = 2;
 454        else
 455                pup_groups = 1;
 456
 457        /* Check if need to write before read */
 458        if (write == 1) {
 459                for (uk = 0; uk < pattern_len; uk++) {
 460                        *sdram_addr = pattern[uk];
 461                        sdram_addr++;
 462                }
 463        }
 464
 465        sdram_addr = (u32 *)sdram_offset;
 466
 467        for (uk = 0; uk < pattern_len; uk++) {
 468                sdram_data[uk] = *sdram_addr;
 469                sdram_addr++;
 470        }
 471
 472        /* Compare read result to write */
 473        for (uj = 0; uj < pattern_len; uj++) {
 474                if (dram_info->ddr_width > 16) {
 475                        compare_pattern_v1(uj, new_locked_pup, pattern,
 476                                           pup_groups, 0);
 477                } else {
 478                        compare_pattern_v2(uj, new_locked_pup, pattern);
 479                }
 480        }
 481
 482        return MV_OK;
 483}
 484
 485/*
 486 * Name:     ddr3_dram_sram_burst
 487 * Desc:     Read from the SDRAM in burst of 64 bytes
 488 * Args:     src
 489 *           dst
 490 * Notes:    Using the XOR mechanism
 491 * Returns:  MV_OK if success, other error code if fail.
 492 */
 493int ddr3_dram_sram_burst(u32 src, u32 dst, u32 len)
 494{
 495        u32 chan, byte_count, cs_num, byte;
 496        struct xor_channel_t channel;
 497
 498        chan = 0;
 499        byte_count = len * 4;
 500
 501        /* Wait for previous transfer completion */
 502        while (mv_xor_state_get(chan) != MV_IDLE)
 503                ;
 504
 505        /* Build the channel descriptor */
 506        channel.desc = &dma_desc;
 507
 508        /* Enable Address Override and set correct src and dst */
 509        if (src < SRAM_BASE) {
 510                /* src is DRAM CS, dst is SRAM */
 511                cs_num = (src / (1 + SDRAM_CS_SIZE));
 512                reg_write(XOR_ADDR_OVRD_REG(0, 0),
 513                          ((cs_num << 1) | (1 << 0)));
 514                channel.desc->src_addr0 = (src % (1 + SDRAM_CS_SIZE));
 515                channel.desc->dst_addr = dst;
 516        } else {
 517                /* src is SRAM, dst is DRAM CS */
 518                cs_num = (dst / (1 + SDRAM_CS_SIZE));
 519                reg_write(XOR_ADDR_OVRD_REG(0, 0),
 520                          ((cs_num << 25) | (1 << 24)));
 521                channel.desc->src_addr0 = (src);
 522                channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
 523                channel.desc->src_addr0 = src;
 524                channel.desc->dst_addr = (dst % (1 + SDRAM_CS_SIZE));
 525        }
 526
 527        channel.desc->src_addr1 = 0;
 528        channel.desc->byte_cnt = byte_count;
 529        channel.desc->next_desc_ptr = 0;
 530        channel.desc->status = 1 << 31;
 531        channel.desc->desc_cmd = 0x0;
 532        channel.desc_phys_addr = (unsigned long)&dma_desc;
 533
 534        ddr3_flush_l1_line((u32)&dma_desc);
 535
 536        /* Issue the transfer */
 537        if (mv_xor_transfer(chan, MV_DMA, channel.desc_phys_addr) != MV_OK)
 538                return MV_FAIL;
 539
 540        /* Wait for completion */
 541        xor_waiton_eng(chan);
 542
 543        if (dst > SRAM_BASE) {
 544                for (byte = 0; byte < byte_count; byte += 0x20)
 545                        cache_inv(dst + byte);
 546        }
 547
 548        return MV_OK;
 549}
 550
 551/*
 552 * Name:     ddr3_flush_l1_line
 553 * Desc:
 554 * Args:
 555 * Notes:
 556 * Returns:  MV_OK if success, other error code if fail.
 557 */
 558static void ddr3_flush_l1_line(u32 line)
 559{
 560        u32 reg;
 561
 562#if defined(MV88F672X)
 563        reg = 1;
 564#else
 565        reg = reg_read(REG_SAMPLE_RESET_LOW_ADDR) &
 566                (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
 567#ifdef MV88F67XX
 568        reg = ~reg & (1 << REG_SAMPLE_RESET_CPU_ARCH_OFFS);
 569#endif
 570#endif
 571
 572        if (reg) {
 573                /* V7 Arch mode */
 574                flush_l1_v7(line);
 575                flush_l1_v7(line + CACHE_LINE_SIZE);
 576        } else {
 577                /* V6 Arch mode */
 578                flush_l1_v6(line);
 579                flush_l1_v6(line + CACHE_LINE_SIZE);
 580        }
 581}
 582
 583int ddr3_dram_sram_read(u32 src, u32 dst, u32 len)
 584{
 585        u32 ui;
 586        u32 *dst_ptr, *src_ptr;
 587
 588        dst_ptr = (u32 *)dst;
 589        src_ptr = (u32 *)src;
 590
 591        for (ui = 0; ui < len; ui++) {
 592                *dst_ptr = *src_ptr;
 593                dst_ptr++;
 594                src_ptr++;
 595        }
 596
 597        return MV_OK;
 598}
 599
 600int ddr3_sdram_dqs_compare(MV_DRAM_INFO *dram_info, u32 unlock_pup,
 601                           u32 *new_locked_pup, u32 *pattern,
 602                           u32 pattern_len, u32 sdram_offset, int write,
 603                           int mask, u32 *mask_pattern,
 604                           int special_compare)
 605{
 606        u32 uj, pup_groups;
 607
 608        if (dram_info->num_of_std_pups == PUP_NUM_64BIT)
 609                pup_groups = 2;
 610        else
 611                pup_groups = 1;
 612
 613        ddr3_reset_phy_read_fifo();
 614
 615        /* Check if need to write to sdram before read */
 616        if (write == 1)
 617                ddr3_dram_sram_burst((u32)pattern, sdram_offset, pattern_len);
 618
 619        ddr3_dram_sram_burst(sdram_offset, (u32)sdram_data, pattern_len);
 620
 621        /* Compare read result to write */
 622        for (uj = 0; uj < pattern_len; uj++) {
 623                if (special_compare && special_compare_pattern(uj))
 624                        continue;
 625
 626                if (dram_info->ddr_width > 16) {
 627                        compare_pattern_v1(uj, new_locked_pup, pattern,
 628                                           pup_groups, 1);
 629                } else {
 630                        compare_pattern_v2(uj, new_locked_pup, pattern);
 631                }
 632        }
 633
 634        return MV_OK;
 635}
 636
 637void ddr3_reset_phy_read_fifo(void)
 638{
 639        u32 reg;
 640
 641        /* reset read FIFO */
 642        reg = reg_read(REG_DRAM_TRAINING_ADDR);
 643        /* Start Auto Read Leveling procedure */
 644        reg |= (1 << REG_DRAM_TRAINING_RL_OFFS);
 645
 646        /* 0x15B0 - Training Register */
 647        reg_write(REG_DRAM_TRAINING_ADDR, reg);
 648
 649        reg = reg_read(REG_DRAM_TRAINING_2_ADDR);
 650        reg |= ((1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS) +
 651                (1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS));
 652
 653        /* [0] = 1 - Enable SW override, [4] = 1 - FIFO reset  */
 654        /* 0x15B8 - Training SW 2 Register */
 655        reg_write(REG_DRAM_TRAINING_2_ADDR, reg);
 656
 657        do {
 658                reg = reg_read(REG_DRAM_TRAINING_2_ADDR) &
 659                        (1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
 660        } while (reg);  /* Wait for '0' */
 661
 662        reg = reg_read(REG_DRAM_TRAINING_ADDR);
 663
 664        /* Clear Auto Read Leveling procedure */
 665        reg &= ~(1 << REG_DRAM_TRAINING_RL_OFFS);
 666
 667        /* 0x15B0 - Training Register */
 668        reg_write(REG_DRAM_TRAINING_ADDR, reg);
 669}
 670