Home | History | Annotate | Download | only in axp
      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 
     17 static void ddr3_flush_l1_line(u32 line);
     18 
     19 extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
     20 extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
     21 #if defined(MV88F78X60)
     22 extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
     23 #endif
     24 extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
     25 
     26 #if defined(MV88F78X60) || defined(MV88F672X)
     27 /* PBS locked dq (per pup) */
     28 u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
     29 u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
     30 u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
     31 
     32 int per_bit_data[MAX_PUP_NUM][DQ_NUM];
     33 #endif
     34 
     35 static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
     36 
     37 static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
     38 
     39 #define XOR_TIMEOUT 0x8000000
     40 
     41 struct 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 
     48 void 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 
     73 timeout:
     74 	return;
     75 }
     76 
     77 static 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  */
     91 static 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 
    129 static 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  */
    163 int 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  */
    219 int 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  */
    280 int 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  */
    441 int 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  */
    492 int 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  */
    557 static 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 
    582 int 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 
    599 int 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 
    636 void 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