]> git.sur5r.net Git - u-boot/blob - drivers/ddr/marvell/axp/ddr3_sdram.c
50c1bf8361f7f89db11c8ac6da35fc69296526b7
[u-boot] / drivers / ddr / marvell / axp / ddr3_sdram.c
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 }