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