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