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 
18 static void ddr3_flush_l1_line(u32 line);
19 
20 extern u32 pbs_pattern[2][LEN_16BIT_PBS_PATTERN];
21 extern u32 pbs_pattern_32b[2][LEN_PBS_PATTERN];
22 #if defined(MV88F78X60)
23 extern u32 pbs_pattern_64b[2][LEN_PBS_PATTERN];
24 #endif
25 extern u32 pbs_dq_mapping[PUP_NUM_64BIT][DQ_NUM];
26 
27 #if defined(MV88F78X60) || defined(MV88F672X)
28 /* PBS locked dq (per pup) */
29 u32 pbs_locked_dq[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
30 u32 pbs_locked_dm[MAX_PUP_NUM] = { 0 };
31 u32 pbs_locked_value[MAX_PUP_NUM][DQ_NUM] = { { 0 } };
32 
33 int per_bit_data[MAX_PUP_NUM][DQ_NUM];
34 #endif
35 
36 static u32 sdram_data[LEN_KILLER_PATTERN] __aligned(32) = { 0 };
37 
38 static struct crc_dma_desc dma_desc __aligned(32) = { 0 };
39 
40 #define XOR_TIMEOUT 0x8000000
41 
42 struct 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 
49 void 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 
74 timeout:
75 	return;
76 }
77 
78 static 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  */
92 static 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 
130 static 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  */
164 int 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  */
220 int 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  */
281 int 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  */
442 int 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  */
493 int 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  */
558 static 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 
583 int 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 
600 int 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 
637 void 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