]> git.sur5r.net Git - u-boot/blob - arch/x86/cpu/quark/mrc_util.c
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / arch / x86 / cpu / quark / mrc_util.c
1 // SPDX-License-Identifier: Intel
2 /*
3  * Copyright (C) 2013, Intel Corporation
4  * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
5  *
6  * Ported from Intel released Quark UEFI BIOS
7  * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
8  */
9
10 #include <common.h>
11 #include <asm/arch/device.h>
12 #include <asm/arch/mrc.h>
13 #include <asm/arch/msg_port.h>
14 #include <asm/arch/quark.h>
15 #include "mrc_util.h"
16 #include "hte.h"
17 #include "smc.h"
18
19 static const uint8_t vref_codes[64] = {
20         /* lowest to highest */
21         0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
22         0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
23         0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
24         0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
25         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
26         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
27         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
28         0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
29 };
30
31 void mrc_write_mask(u32 unit, u32 addr, u32 data, u32 mask)
32 {
33         msg_port_write(unit, addr,
34                        (msg_port_read(unit, addr) & ~(mask)) |
35                        ((data) & (mask)));
36 }
37
38 void mrc_alt_write_mask(u32 unit, u32 addr, u32 data, u32 mask)
39 {
40         msg_port_alt_write(unit, addr,
41                            (msg_port_alt_read(unit, addr) & ~(mask)) |
42                            ((data) & (mask)));
43 }
44
45 void mrc_post_code(uint8_t major, uint8_t minor)
46 {
47         /* send message to UART */
48         DPF(D_INFO, "POST: 0x%01x%02x\n", major, minor);
49
50         /* error check */
51         if (major == 0xee)
52                 hang();
53 }
54
55 /* Delay number of nanoseconds */
56 void delay_n(uint32_t ns)
57 {
58         /* 1000 MHz clock has 1ns period --> no conversion required */
59         uint64_t final_tsc = rdtsc();
60
61         final_tsc += ((get_tbclk_mhz() * ns) / 1000);
62
63         while (rdtsc() < final_tsc)
64                 ;
65 }
66
67 /* Delay number of microseconds */
68 void delay_u(uint32_t ms)
69 {
70         /* 64-bit math is not an option, just use loops */
71         while (ms--)
72                 delay_n(1000);
73 }
74
75 /* Select Memory Manager as the source for PRI interface */
76 void select_mem_mgr(void)
77 {
78         u32 dco;
79
80         ENTERFN();
81
82         dco = msg_port_read(MEM_CTLR, DCO);
83         dco &= ~DCO_PMICTL;
84         msg_port_write(MEM_CTLR, DCO, dco);
85
86         LEAVEFN();
87 }
88
89 /* Select HTE as the source for PRI interface */
90 void select_hte(void)
91 {
92         u32 dco;
93
94         ENTERFN();
95
96         dco = msg_port_read(MEM_CTLR, DCO);
97         dco |= DCO_PMICTL;
98         msg_port_write(MEM_CTLR, DCO, dco);
99
100         LEAVEFN();
101 }
102
103 /*
104  * Send DRAM command
105  * data should be formated using DCMD_Xxxx macro or emrsXCommand structure
106  */
107 void dram_init_command(uint32_t data)
108 {
109         qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, data);
110         qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG, 0);
111         msg_port_setup(MSG_OP_DRAM_INIT, MEM_CTLR, 0);
112
113         DPF(D_REGWR, "WR32 %03X %08X %08X\n", MEM_CTLR, 0, data);
114 }
115
116 /* Send DRAM wake command using special MCU side-band WAKE opcode */
117 void dram_wake_command(void)
118 {
119         ENTERFN();
120
121         msg_port_setup(MSG_OP_DRAM_WAKE, MEM_CTLR, 0);
122
123         LEAVEFN();
124 }
125
126 void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane)
127 {
128         /* send message to UART */
129         DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane);
130 }
131
132 /*
133  * This function will program the RCVEN delays
134  *
135  * (currently doesn't comprehend rank)
136  */
137 void set_rcvn(uint8_t channel, uint8_t rank,
138               uint8_t byte_lane, uint32_t pi_count)
139 {
140         uint32_t reg;
141         uint32_t msk;
142         uint32_t temp;
143
144         ENTERFN();
145
146         DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n",
147             channel, rank, byte_lane, pi_count);
148
149         /*
150          * RDPTR (1/2 MCLK, 64 PIs)
151          * BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
152          * BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
153          */
154         reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
155                 channel * DDRIODQ_CH_OFFSET;
156         msk = (byte_lane & 1) ? 0xf00000 : 0xf00;
157         temp = (byte_lane & 1) ? (pi_count / HALF_CLK) << 20 :
158                 (pi_count / HALF_CLK) << 8;
159         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
160
161         /* Adjust PI_COUNT */
162         pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
163
164         /*
165          * PI (1/64 MCLK, 1 PIs)
166          * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
167          * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
168          */
169         reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
170         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
171                 channel * DDRIODQ_CH_OFFSET);
172         msk = 0x3f000000;
173         temp = pi_count << 24;
174         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
175
176         /*
177          * DEADBAND
178          * BL0/1 -> B01DBCTL1[08/11] (+1 select)
179          * BL0/1 -> B01DBCTL1[02/05] (enable)
180          */
181         reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
182                 channel * DDRIODQ_CH_OFFSET;
183         msk = 0x00;
184         temp = 0x00;
185
186         /* enable */
187         msk |= (byte_lane & 1) ? (1 << 5) : (1 << 2);
188         if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
189                 temp |= msk;
190
191         /* select */
192         msk |= (byte_lane & 1) ? (1 << 11) : (1 << 8);
193         if (pi_count < EARLY_DB)
194                 temp |= msk;
195
196         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
197
198         /* error check */
199         if (pi_count > 0x3f) {
200                 training_message(channel, rank, byte_lane);
201                 mrc_post_code(0xee, 0xe0);
202         }
203
204         LEAVEFN();
205 }
206
207 /*
208  * This function will return the current RCVEN delay on the given
209  * channel, rank, byte_lane as an absolute PI count.
210  *
211  * (currently doesn't comprehend rank)
212  */
213 uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane)
214 {
215         uint32_t reg;
216         uint32_t temp;
217         uint32_t pi_count;
218
219         ENTERFN();
220
221         /*
222          * RDPTR (1/2 MCLK, 64 PIs)
223          * BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
224          * BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
225          */
226         reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
227                 channel * DDRIODQ_CH_OFFSET;
228         temp = msg_port_alt_read(DDRPHY, reg);
229         temp >>= (byte_lane & 1) ? 20 : 8;
230         temp &= 0xf;
231
232         /* Adjust PI_COUNT */
233         pi_count = temp * HALF_CLK;
234
235         /*
236          * PI (1/64 MCLK, 1 PIs)
237          * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
238          * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
239          */
240         reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
241         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
242                 channel * DDRIODQ_CH_OFFSET);
243         temp = msg_port_alt_read(DDRPHY, reg);
244         temp >>= 24;
245         temp &= 0x3f;
246
247         /* Adjust PI_COUNT */
248         pi_count += temp;
249
250         LEAVEFN();
251
252         return pi_count;
253 }
254
255 /*
256  * This function will program the RDQS delays based on an absolute
257  * amount of PIs.
258  *
259  * (currently doesn't comprehend rank)
260  */
261 void set_rdqs(uint8_t channel, uint8_t rank,
262               uint8_t byte_lane, uint32_t pi_count)
263 {
264         uint32_t reg;
265         uint32_t msk;
266         uint32_t temp;
267
268         ENTERFN();
269         DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n",
270             channel, rank, byte_lane, pi_count);
271
272         /*
273          * PI (1/128 MCLK)
274          * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
275          * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
276          */
277         reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
278         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
279                 channel * DDRIODQ_CH_OFFSET);
280         msk = 0x7f;
281         temp = pi_count << 0;
282         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
283
284         /* error check (shouldn't go above 0x3F) */
285         if (pi_count > 0x47) {
286                 training_message(channel, rank, byte_lane);
287                 mrc_post_code(0xee, 0xe1);
288         }
289
290         LEAVEFN();
291 }
292
293 /*
294  * This function will return the current RDQS delay on the given
295  * channel, rank, byte_lane as an absolute PI count.
296  *
297  * (currently doesn't comprehend rank)
298  */
299 uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane)
300 {
301         uint32_t reg;
302         uint32_t temp;
303         uint32_t pi_count;
304
305         ENTERFN();
306
307         /*
308          * PI (1/128 MCLK)
309          * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
310          * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
311          */
312         reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
313         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
314                 channel * DDRIODQ_CH_OFFSET);
315         temp = msg_port_alt_read(DDRPHY, reg);
316
317         /* Adjust PI_COUNT */
318         pi_count = temp & 0x7f;
319
320         LEAVEFN();
321
322         return pi_count;
323 }
324
325 /*
326  * This function will program the WDQS delays based on an absolute
327  * amount of PIs.
328  *
329  * (currently doesn't comprehend rank)
330  */
331 void set_wdqs(uint8_t channel, uint8_t rank,
332               uint8_t byte_lane, uint32_t pi_count)
333 {
334         uint32_t reg;
335         uint32_t msk;
336         uint32_t temp;
337
338         ENTERFN();
339
340         DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n",
341             channel, rank, byte_lane, pi_count);
342
343         /*
344          * RDPTR (1/2 MCLK, 64 PIs)
345          * BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
346          * BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
347          */
348         reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
349                 channel * DDRIODQ_CH_OFFSET;
350         msk = (byte_lane & 1) ? 0xf0000 : 0xf0;
351         temp = pi_count / HALF_CLK;
352         temp <<= (byte_lane & 1) ? 16 : 4;
353         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
354
355         /* Adjust PI_COUNT */
356         pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
357
358         /*
359          * PI (1/64 MCLK, 1 PIs)
360          * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
361          * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
362          */
363         reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
364         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
365                 channel * DDRIODQ_CH_OFFSET);
366         msk = 0x3f0000;
367         temp = pi_count << 16;
368         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
369
370         /*
371          * DEADBAND
372          * BL0/1 -> B01DBCTL1[07/10] (+1 select)
373          * BL0/1 -> B01DBCTL1[01/04] (enable)
374          */
375         reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
376                 channel * DDRIODQ_CH_OFFSET;
377         msk = 0x00;
378         temp = 0x00;
379
380         /* enable */
381         msk |= (byte_lane & 1) ? (1 << 4) : (1 << 1);
382         if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
383                 temp |= msk;
384
385         /* select */
386         msk |= (byte_lane & 1) ? (1 << 10) : (1 << 7);
387         if (pi_count < EARLY_DB)
388                 temp |= msk;
389
390         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
391
392         /* error check */
393         if (pi_count > 0x3f) {
394                 training_message(channel, rank, byte_lane);
395                 mrc_post_code(0xee, 0xe2);
396         }
397
398         LEAVEFN();
399 }
400
401 /*
402  * This function will return the amount of WDQS delay on the given
403  * channel, rank, byte_lane as an absolute PI count.
404  *
405  * (currently doesn't comprehend rank)
406  */
407 uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane)
408 {
409         uint32_t reg;
410         uint32_t temp;
411         uint32_t pi_count;
412
413         ENTERFN();
414
415         /*
416          * RDPTR (1/2 MCLK, 64 PIs)
417          * BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
418          * BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
419          */
420         reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
421                 channel * DDRIODQ_CH_OFFSET;
422         temp = msg_port_alt_read(DDRPHY, reg);
423         temp >>= (byte_lane & 1) ? 16 : 4;
424         temp &= 0xf;
425
426         /* Adjust PI_COUNT */
427         pi_count = (temp * HALF_CLK);
428
429         /*
430          * PI (1/64 MCLK, 1 PIs)
431          * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
432          * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
433          */
434         reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
435         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
436                 channel * DDRIODQ_CH_OFFSET);
437         temp = msg_port_alt_read(DDRPHY, reg);
438         temp >>= 16;
439         temp &= 0x3f;
440
441         /* Adjust PI_COUNT */
442         pi_count += temp;
443
444         LEAVEFN();
445
446         return pi_count;
447 }
448
449 /*
450  * This function will program the WDQ delays based on an absolute
451  * number of PIs.
452  *
453  * (currently doesn't comprehend rank)
454  */
455 void set_wdq(uint8_t channel, uint8_t rank,
456              uint8_t byte_lane, uint32_t pi_count)
457 {
458         uint32_t reg;
459         uint32_t msk;
460         uint32_t temp;
461
462         ENTERFN();
463
464         DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n",
465             channel, rank, byte_lane, pi_count);
466
467         /*
468          * RDPTR (1/2 MCLK, 64 PIs)
469          * BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
470          * BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
471          */
472         reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
473                 channel * DDRIODQ_CH_OFFSET;
474         msk = (byte_lane & 1) ? 0xf000 : 0xf;
475         temp = pi_count / HALF_CLK;
476         temp <<= (byte_lane & 1) ? 12 : 0;
477         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
478
479         /* Adjust PI_COUNT */
480         pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
481
482         /*
483          * PI (1/64 MCLK, 1 PIs)
484          * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
485          * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
486          */
487         reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
488         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
489                 channel * DDRIODQ_CH_OFFSET);
490         msk = 0x3f00;
491         temp = pi_count << 8;
492         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
493
494         /*
495          * DEADBAND
496          * BL0/1 -> B01DBCTL1[06/09] (+1 select)
497          * BL0/1 -> B01DBCTL1[00/03] (enable)
498          */
499         reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
500                 channel * DDRIODQ_CH_OFFSET;
501         msk = 0x00;
502         temp = 0x00;
503
504         /* enable */
505         msk |= (byte_lane & 1) ? (1 << 3) : (1 << 0);
506         if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
507                 temp |= msk;
508
509         /* select */
510         msk |= (byte_lane & 1) ? (1 << 9) : (1 << 6);
511         if (pi_count < EARLY_DB)
512                 temp |= msk;
513
514         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
515
516         /* error check */
517         if (pi_count > 0x3f) {
518                 training_message(channel, rank, byte_lane);
519                 mrc_post_code(0xee, 0xe3);
520         }
521
522         LEAVEFN();
523 }
524
525 /*
526  * This function will return the amount of WDQ delay on the given
527  * channel, rank, byte_lane as an absolute PI count.
528  *
529  * (currently doesn't comprehend rank)
530  */
531 uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane)
532 {
533         uint32_t reg;
534         uint32_t temp;
535         uint32_t pi_count;
536
537         ENTERFN();
538
539         /*
540          * RDPTR (1/2 MCLK, 64 PIs)
541          * BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
542          * BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
543          */
544         reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
545                 channel * DDRIODQ_CH_OFFSET;
546         temp = msg_port_alt_read(DDRPHY, reg);
547         temp >>= (byte_lane & 1) ? 12 : 0;
548         temp &= 0xf;
549
550         /* Adjust PI_COUNT */
551         pi_count = temp * HALF_CLK;
552
553         /*
554          * PI (1/64 MCLK, 1 PIs)
555          * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
556          * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
557          */
558         reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
559         reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
560                 channel * DDRIODQ_CH_OFFSET);
561         temp = msg_port_alt_read(DDRPHY, reg);
562         temp >>= 8;
563         temp &= 0x3f;
564
565         /* Adjust PI_COUNT */
566         pi_count += temp;
567
568         LEAVEFN();
569
570         return pi_count;
571 }
572
573 /*
574  * This function will program the WCMD delays based on an absolute
575  * number of PIs.
576  */
577 void set_wcmd(uint8_t channel, uint32_t pi_count)
578 {
579         uint32_t reg;
580         uint32_t msk;
581         uint32_t temp;
582
583         ENTERFN();
584
585         /*
586          * RDPTR (1/2 MCLK, 64 PIs)
587          * CMDPTRREG[11:08] (0x0-0xF)
588          */
589         reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
590         msk = 0xf00;
591         temp = pi_count / HALF_CLK;
592         temp <<= 8;
593         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
594
595         /* Adjust PI_COUNT */
596         pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
597
598         /*
599          * PI (1/64 MCLK, 1 PIs)
600          * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
601          * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
602          * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
603          * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
604          * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
605          * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
606          * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
607          * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
608          */
609         reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
610         msk = 0x3f3f3f3f;
611         temp = (pi_count << 24) | (pi_count << 16) |
612                 (pi_count << 8) | (pi_count << 0);
613
614         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
615         reg = CMDDLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;    /* PO */
616         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
617
618         /*
619          * DEADBAND
620          * CMDCFGREG0[17] (+1 select)
621          * CMDCFGREG0[16] (enable)
622          */
623         reg = CMDCFGREG0 + channel * DDRIOCCC_CH_OFFSET;
624         msk = 0x00;
625         temp = 0x00;
626
627         /* enable */
628         msk |= (1 << 16);
629         if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
630                 temp |= msk;
631
632         /* select */
633         msk |= (1 << 17);
634         if (pi_count < EARLY_DB)
635                 temp |= msk;
636
637         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
638
639         /* error check */
640         if (pi_count > 0x3f)
641                 mrc_post_code(0xee, 0xe4);
642
643         LEAVEFN();
644 }
645
646 /*
647  * This function will return the amount of WCMD delay on the given
648  * channel as an absolute PI count.
649  */
650 uint32_t get_wcmd(uint8_t channel)
651 {
652         uint32_t reg;
653         uint32_t temp;
654         uint32_t pi_count;
655
656         ENTERFN();
657
658         /*
659          * RDPTR (1/2 MCLK, 64 PIs)
660          * CMDPTRREG[11:08] (0x0-0xF)
661          */
662         reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
663         temp = msg_port_alt_read(DDRPHY, reg);
664         temp >>= 8;
665         temp &= 0xf;
666
667         /* Adjust PI_COUNT */
668         pi_count = temp * HALF_CLK;
669
670         /*
671          * PI (1/64 MCLK, 1 PIs)
672          * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
673          * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
674          * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
675          * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
676          * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
677          * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
678          * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
679          * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
680          */
681         reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
682         temp = msg_port_alt_read(DDRPHY, reg);
683         temp >>= 16;
684         temp &= 0x3f;
685
686         /* Adjust PI_COUNT */
687         pi_count += temp;
688
689         LEAVEFN();
690
691         return pi_count;
692 }
693
694 /*
695  * This function will program the WCLK delays based on an absolute
696  * number of PIs.
697  */
698 void set_wclk(uint8_t channel, uint8_t rank, uint32_t pi_count)
699 {
700         uint32_t reg;
701         uint32_t msk;
702         uint32_t temp;
703
704         ENTERFN();
705
706         /*
707          * RDPTR (1/2 MCLK, 64 PIs)
708          * CCPTRREG[15:12] -> CLK1 (0x0-0xF)
709          * CCPTRREG[11:08] -> CLK0 (0x0-0xF)
710          */
711         reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
712         msk = 0xff00;
713         temp = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8);
714         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
715
716         /* Adjust PI_COUNT */
717         pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
718
719         /*
720          * PI (1/64 MCLK, 1 PIs)
721          * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
722          * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
723          */
724         reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0;
725         reg += (channel * DDRIOCCC_CH_OFFSET);
726         msk = 0x3f3f00;
727         temp = (pi_count << 16) | (pi_count << 8);
728         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
729
730         reg = rank ? ECCB1DLLPICODER1 : ECCB1DLLPICODER1;
731         reg += (channel * DDRIOCCC_CH_OFFSET);
732         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
733
734         reg = rank ? ECCB1DLLPICODER2 : ECCB1DLLPICODER2;
735         reg += (channel * DDRIOCCC_CH_OFFSET);
736         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
737
738         reg = rank ? ECCB1DLLPICODER3 : ECCB1DLLPICODER3;
739         reg += (channel * DDRIOCCC_CH_OFFSET);
740         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
741
742         /*
743          * DEADBAND
744          * CCCFGREG1[11:08] (+1 select)
745          * CCCFGREG1[03:00] (enable)
746          */
747         reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
748         msk = 0x00;
749         temp = 0x00;
750
751         /* enable */
752         msk |= 0xf;
753         if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
754                 temp |= msk;
755
756         /* select */
757         msk |= 0xf00;
758         if (pi_count < EARLY_DB)
759                 temp |= msk;
760
761         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
762
763         /* error check */
764         if (pi_count > 0x3f)
765                 mrc_post_code(0xee, 0xe5);
766
767         LEAVEFN();
768 }
769
770 /*
771  * This function will return the amout of WCLK delay on the given
772  * channel, rank as an absolute PI count.
773  */
774 uint32_t get_wclk(uint8_t channel, uint8_t rank)
775 {
776         uint32_t reg;
777         uint32_t temp;
778         uint32_t pi_count;
779
780         ENTERFN();
781
782         /*
783          * RDPTR (1/2 MCLK, 64 PIs)
784          * CCPTRREG[15:12] -> CLK1 (0x0-0xF)
785          * CCPTRREG[11:08] -> CLK0 (0x0-0xF)
786          */
787         reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
788         temp = msg_port_alt_read(DDRPHY, reg);
789         temp >>= rank ? 12 : 8;
790         temp &= 0xf;
791
792         /* Adjust PI_COUNT */
793         pi_count = temp * HALF_CLK;
794
795         /*
796          * PI (1/64 MCLK, 1 PIs)
797          * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
798          * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
799          */
800         reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0;
801         reg += (channel * DDRIOCCC_CH_OFFSET);
802         temp = msg_port_alt_read(DDRPHY, reg);
803         temp >>= rank ? 16 : 8;
804         temp &= 0x3f;
805
806         pi_count += temp;
807
808         LEAVEFN();
809
810         return pi_count;
811 }
812
813 /*
814  * This function will program the WCTL delays based on an absolute
815  * number of PIs.
816  *
817  * (currently doesn't comprehend rank)
818  */
819 void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count)
820 {
821         uint32_t reg;
822         uint32_t msk;
823         uint32_t temp;
824
825         ENTERFN();
826
827         /*
828          * RDPTR (1/2 MCLK, 64 PIs)
829          * CCPTRREG[31:28] (0x0-0xF)
830          * CCPTRREG[27:24] (0x0-0xF)
831          */
832         reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
833         msk = 0xff000000;
834         temp = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24);
835         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
836
837         /* Adjust PI_COUNT */
838         pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
839
840         /*
841          * PI (1/64 MCLK, 1 PIs)
842          * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
843          * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
844          */
845         reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
846         msk = 0x3f000000;
847         temp = (pi_count << 24);
848         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
849
850         reg = ECCB1DLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
851         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
852
853         reg = ECCB1DLLPICODER2 + channel * DDRIOCCC_CH_OFFSET;
854         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
855
856         reg = ECCB1DLLPICODER3 + channel * DDRIOCCC_CH_OFFSET;
857         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
858
859         /*
860          * DEADBAND
861          * CCCFGREG1[13:12] (+1 select)
862          * CCCFGREG1[05:04] (enable)
863          */
864         reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
865         msk = 0x00;
866         temp = 0x00;
867
868         /* enable */
869         msk |= 0x30;
870         if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
871                 temp |= msk;
872
873         /* select */
874         msk |= 0x3000;
875         if (pi_count < EARLY_DB)
876                 temp |= msk;
877
878         mrc_alt_write_mask(DDRPHY, reg, temp, msk);
879
880         /* error check */
881         if (pi_count > 0x3f)
882                 mrc_post_code(0xee, 0xe6);
883
884         LEAVEFN();
885 }
886
887 /*
888  * This function will return the amount of WCTL delay on the given
889  * channel, rank as an absolute PI count.
890  *
891  * (currently doesn't comprehend rank)
892  */
893 uint32_t get_wctl(uint8_t channel, uint8_t rank)
894 {
895         uint32_t reg;
896         uint32_t temp;
897         uint32_t pi_count;
898
899         ENTERFN();
900
901         /*
902          * RDPTR (1/2 MCLK, 64 PIs)
903          * CCPTRREG[31:28] (0x0-0xF)
904          * CCPTRREG[27:24] (0x0-0xF)
905          */
906         reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
907         temp = msg_port_alt_read(DDRPHY, reg);
908         temp >>= 24;
909         temp &= 0xf;
910
911         /* Adjust PI_COUNT */
912         pi_count = temp * HALF_CLK;
913
914         /*
915          * PI (1/64 MCLK, 1 PIs)
916          * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
917          * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
918          */
919         reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
920         temp = msg_port_alt_read(DDRPHY, reg);
921         temp >>= 24;
922         temp &= 0x3f;
923
924         /* Adjust PI_COUNT */
925         pi_count += temp;
926
927         LEAVEFN();
928
929         return pi_count;
930 }
931
932 /*
933  * This function will program the internal Vref setting in a given
934  * byte lane in a given channel.
935  */
936 void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting)
937 {
938         uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
939
940         ENTERFN();
941
942         DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n",
943             channel, byte_lane, setting);
944
945         mrc_alt_write_mask(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
946                 (byte_lane >> 1) * DDRIODQ_BL_OFFSET,
947                 vref_codes[setting] << 2, 0xfc);
948
949         /*
950          * need to wait ~300ns for Vref to settle
951          * (check that this is necessary)
952          */
953         delay_n(300);
954
955         /* ??? may need to clear pointers ??? */
956
957         LEAVEFN();
958 }
959
960 /*
961  * This function will return the internal Vref setting for the given
962  * channel, byte_lane.
963  */
964 uint32_t get_vref(uint8_t channel, uint8_t byte_lane)
965 {
966         uint8_t j;
967         uint32_t ret_val = sizeof(vref_codes) / 2;
968         uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
969         uint32_t temp;
970
971         ENTERFN();
972
973         temp = msg_port_alt_read(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
974                 (byte_lane >> 1) * DDRIODQ_BL_OFFSET);
975         temp >>= 2;
976         temp &= 0x3f;
977
978         for (j = 0; j < sizeof(vref_codes); j++) {
979                 if (vref_codes[j] == temp) {
980                         ret_val = j;
981                         break;
982                 }
983         }
984
985         LEAVEFN();
986
987         return ret_val;
988 }
989
990 /*
991  * This function will return a 32-bit address in the desired
992  * channel and rank.
993  */
994 uint32_t get_addr(uint8_t channel, uint8_t rank)
995 {
996         uint32_t offset = 32 * 1024 * 1024;     /* 32MB */
997
998         /* Begin product specific code */
999         if (channel > 0) {
1000                 DPF(D_ERROR, "ILLEGAL CHANNEL\n");
1001                 DEAD_LOOP();
1002         }
1003
1004         if (rank > 1) {
1005                 DPF(D_ERROR, "ILLEGAL RANK\n");
1006                 DEAD_LOOP();
1007         }
1008
1009         /* use 256MB lowest density as per DRP == 0x0003 */
1010         offset += rank * (256 * 1024 * 1024);
1011
1012         return offset;
1013 }
1014
1015 /*
1016  * This function will sample the DQTRAINSTS registers in the given
1017  * channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'.
1018  *
1019  * It will return an encoded 32-bit date in which each bit corresponds to
1020  * the sampled value on the byte lane.
1021  */
1022 uint32_t sample_dqs(struct mrc_params *mrc_params, uint8_t channel,
1023                     uint8_t rank, bool rcvn)
1024 {
1025         uint8_t j;      /* just a counter */
1026         uint8_t bl;     /* which BL in the module (always 2 per module) */
1027         uint8_t bl_grp; /* which BL module */
1028         /* byte lane divisor */
1029         uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1030         uint32_t msk[2];        /* BLx in module */
1031         /* DQTRAINSTS register contents for each sample */
1032         uint32_t sampled_val[SAMPLE_SIZE];
1033         uint32_t num_0s;        /* tracks the number of '0' samples */
1034         uint32_t num_1s;        /* tracks the number of '1' samples */
1035         uint32_t ret_val = 0x00;        /* assume all '0' samples */
1036         uint32_t address = get_addr(channel, rank);
1037
1038         /* initialise msk[] */
1039         msk[0] = rcvn ? (1 << 1) : (1 << 9);    /* BL0 */
1040         msk[1] = rcvn ? (1 << 0) : (1 << 8);    /* BL1 */
1041
1042         /* cycle through each byte lane group */
1043         for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++) {
1044                 /* take SAMPLE_SIZE samples */
1045                 for (j = 0; j < SAMPLE_SIZE; j++) {
1046                         hte_mem_op(address, mrc_params->first_run,
1047                                    rcvn ? 0 : 1);
1048                         mrc_params->first_run = 0;
1049
1050                         /*
1051                          * record the contents of the proper
1052                          * DQTRAINSTS register
1053                          */
1054                         sampled_val[j] = msg_port_alt_read(DDRPHY,
1055                                 DQTRAINSTS +
1056                                 bl_grp * DDRIODQ_BL_OFFSET +
1057                                 channel * DDRIODQ_CH_OFFSET);
1058                 }
1059
1060                 /*
1061                  * look for a majority value (SAMPLE_SIZE / 2) + 1
1062                  * on the byte lane and set that value in the corresponding
1063                  * ret_val bit
1064                  */
1065                 for (bl = 0; bl < 2; bl++) {
1066                         num_0s = 0x00;  /* reset '0' tracker for byte lane */
1067                         num_1s = 0x00;  /* reset '1' tracker for byte lane */
1068                         for (j = 0; j < SAMPLE_SIZE; j++) {
1069                                 if (sampled_val[j] & msk[bl])
1070                                         num_1s++;
1071                                 else
1072                                         num_0s++;
1073                         }
1074                 if (num_1s > num_0s)
1075                         ret_val |= (1 << (bl + bl_grp * 2));
1076                 }
1077         }
1078
1079         /*
1080          * "ret_val.0" contains the status of BL0
1081          * "ret_val.1" contains the status of BL1
1082          * "ret_val.2" contains the status of BL2
1083          * etc.
1084          */
1085         return ret_val;
1086 }
1087
1088 /* This function will find the rising edge transition on RCVN or WDQS */
1089 void find_rising_edge(struct mrc_params *mrc_params, uint32_t delay[],
1090                       uint8_t channel, uint8_t rank, bool rcvn)
1091 {
1092         bool all_edges_found;   /* determines stop condition */
1093         bool direction[NUM_BYTE_LANES]; /* direction indicator */
1094         uint8_t sample; /* sample counter */
1095         uint8_t bl;     /* byte lane counter */
1096         /* byte lane divisor */
1097         uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1098         uint32_t sample_result[SAMPLE_CNT];     /* results of sample_dqs() */
1099         uint32_t temp;
1100         uint32_t transition_pattern;
1101
1102         ENTERFN();
1103
1104         /* select hte and request initial configuration */
1105         select_hte();
1106         mrc_params->first_run = 1;
1107
1108         /* Take 3 sample points (T1,T2,T3) to obtain a transition pattern */
1109         for (sample = 0; sample < SAMPLE_CNT; sample++) {
1110                 /* program the desired delays for sample */
1111                 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1112                         /* increase sample delay by 26 PI (0.2 CLK) */
1113                         if (rcvn) {
1114                                 set_rcvn(channel, rank, bl,
1115                                          delay[bl] + sample * SAMPLE_DLY);
1116                         } else {
1117                                 set_wdqs(channel, rank, bl,
1118                                          delay[bl] + sample * SAMPLE_DLY);
1119                         }
1120                 }
1121
1122                 /* take samples (Tsample_i) */
1123                 sample_result[sample] = sample_dqs(mrc_params,
1124                         channel, rank, rcvn);
1125
1126                 DPF(D_TRN,
1127                     "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n",
1128                     rcvn ? "RCVN" : "WDQS", channel, rank, sample,
1129                     sample * SAMPLE_DLY, sample_result[sample]);
1130         }
1131
1132         /*
1133          * This pattern will help determine where we landed and ultimately
1134          * how to place RCVEN/WDQS.
1135          */
1136         for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1137                 /* build transition_pattern (MSB is 1st sample) */
1138                 transition_pattern = 0;
1139                 for (sample = 0; sample < SAMPLE_CNT; sample++) {
1140                         transition_pattern |=
1141                                 ((sample_result[sample] & (1 << bl)) >> bl) <<
1142                                 (SAMPLE_CNT - 1 - sample);
1143                 }
1144
1145                 DPF(D_TRN, "=== transition pattern %d\n", transition_pattern);
1146
1147                 /*
1148                  * set up to look for rising edge based on
1149                  * transition_pattern
1150                  */
1151                 switch (transition_pattern) {
1152                 case 0: /* sampled 0->0->0 */
1153                         /* move forward from T3 looking for 0->1 */
1154                         delay[bl] += 2 * SAMPLE_DLY;
1155                         direction[bl] = FORWARD;
1156                         break;
1157                 case 1: /* sampled 0->0->1 */
1158                 case 5: /* sampled 1->0->1 (bad duty cycle) *HSD#237503* */
1159                         /* move forward from T2 looking for 0->1 */
1160                         delay[bl] += 1 * SAMPLE_DLY;
1161                         direction[bl] = FORWARD;
1162                         break;
1163                 case 2: /* sampled 0->1->0 (bad duty cycle) *HSD#237503* */
1164                 case 3: /* sampled 0->1->1 */
1165                         /* move forward from T1 looking for 0->1 */
1166                         delay[bl] += 0 * SAMPLE_DLY;
1167                         direction[bl] = FORWARD;
1168                         break;
1169                 case 4: /* sampled 1->0->0 (assumes BL8, HSD#234975) */
1170                         /* move forward from T3 looking for 0->1 */
1171                         delay[bl] += 2 * SAMPLE_DLY;
1172                         direction[bl] = FORWARD;
1173                         break;
1174                 case 6: /* sampled 1->1->0 */
1175                 case 7: /* sampled 1->1->1 */
1176                         /* move backward from T1 looking for 1->0 */
1177                         delay[bl] += 0 * SAMPLE_DLY;
1178                         direction[bl] = BACKWARD;
1179                         break;
1180                 default:
1181                         mrc_post_code(0xee, 0xee);
1182                         break;
1183                 }
1184
1185                 /* program delays */
1186                 if (rcvn)
1187                         set_rcvn(channel, rank, bl, delay[bl]);
1188                 else
1189                         set_wdqs(channel, rank, bl, delay[bl]);
1190         }
1191
1192         /*
1193          * Based on the observed transition pattern on the byte lane,
1194          * begin looking for a rising edge with single PI granularity.
1195          */
1196         do {
1197                 all_edges_found = true; /* assume all byte lanes passed */
1198                 /* take a sample */
1199                 temp = sample_dqs(mrc_params, channel, rank, rcvn);
1200                 /* check all each byte lane for proper edge */
1201                 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1202                         if (temp & (1 << bl)) {
1203                                 /* sampled "1" */
1204                                 if (direction[bl] == BACKWARD) {
1205                                         /*
1206                                          * keep looking for edge
1207                                          * on this byte lane
1208                                          */
1209                                         all_edges_found = false;
1210                                         delay[bl] -= 1;
1211                                         if (rcvn) {
1212                                                 set_rcvn(channel, rank,
1213                                                          bl, delay[bl]);
1214                                         } else {
1215                                                 set_wdqs(channel, rank,
1216                                                          bl, delay[bl]);
1217                                         }
1218                                 }
1219                         } else {
1220                                 /* sampled "0" */
1221                                 if (direction[bl] == FORWARD) {
1222                                         /*
1223                                          * keep looking for edge
1224                                          * on this byte lane
1225                                          */
1226                                         all_edges_found = false;
1227                                         delay[bl] += 1;
1228                                         if (rcvn) {
1229                                                 set_rcvn(channel, rank,
1230                                                          bl, delay[bl]);
1231                                         } else {
1232                                                 set_wdqs(channel, rank,
1233                                                          bl, delay[bl]);
1234                                         }
1235                                 }
1236                         }
1237                 }
1238         } while (!all_edges_found);
1239
1240         /* restore DDR idle state */
1241         dram_init_command(DCMD_PREA(rank));
1242
1243         DPF(D_TRN, "Delay %03X %03X %03X %03X\n",
1244             delay[0], delay[1], delay[2], delay[3]);
1245
1246         LEAVEFN();
1247 }
1248
1249 /*
1250  * This function will return a 32 bit mask that will be used to
1251  * check for byte lane failures.
1252  */
1253 uint32_t byte_lane_mask(struct mrc_params *mrc_params)
1254 {
1255         uint32_t j;
1256         uint32_t ret_val = 0x00;
1257
1258         /*
1259          * set ret_val based on NUM_BYTE_LANES such that you will check
1260          * only BL0 in result
1261          *
1262          * (each bit in result represents a byte lane)
1263          */
1264         for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES)
1265                 ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES));
1266
1267         /*
1268          * HSD#235037
1269          * need to adjust the mask for 16-bit mode
1270          */
1271         if (mrc_params->channel_width == X16)
1272                 ret_val |= (ret_val << 2);
1273
1274         return ret_val;
1275 }
1276
1277 /*
1278  * Check memory executing simple write/read/verify at the specified address.
1279  *
1280  * Bits in the result indicate failure on specific byte lane.
1281  */
1282 uint32_t check_rw_coarse(struct mrc_params *mrc_params, uint32_t address)
1283 {
1284         uint32_t result = 0;
1285         uint8_t first_run = 0;
1286
1287         if (mrc_params->hte_setup) {
1288                 mrc_params->hte_setup = 0;
1289                 first_run = 1;
1290                 select_hte();
1291         }
1292
1293         result = hte_basic_write_read(mrc_params, address, first_run,
1294                                       WRITE_TRAIN);
1295
1296         DPF(D_TRN, "check_rw_coarse result is %x\n", result);
1297
1298         return result;
1299 }
1300
1301 /*
1302  * Check memory executing write/read/verify of many data patterns
1303  * at the specified address. Bits in the result indicate failure
1304  * on specific byte lane.
1305  */
1306 uint32_t check_bls_ex(struct mrc_params *mrc_params, uint32_t address)
1307 {
1308         uint32_t result;
1309         uint8_t first_run = 0;
1310
1311         if (mrc_params->hte_setup) {
1312                 mrc_params->hte_setup = 0;
1313                 first_run = 1;
1314                 select_hte();
1315         }
1316
1317         result = hte_write_stress_bit_lanes(mrc_params, address, first_run);
1318
1319         DPF(D_TRN, "check_bls_ex result is %x\n", result);
1320
1321         return result;
1322 }
1323
1324 /*
1325  * 32-bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1
1326  *
1327  * The function takes pointer to previous 32 bit value and
1328  * modifies it to next value.
1329  */
1330 void lfsr32(uint32_t *lfsr_ptr)
1331 {
1332         uint32_t bit;
1333         uint32_t lfsr;
1334         int i;
1335
1336         lfsr = *lfsr_ptr;
1337
1338         for (i = 0; i < 32; i++) {
1339                 bit = 1 ^ (lfsr & 1);
1340                 bit = bit ^ ((lfsr & 2) >> 1);
1341                 bit = bit ^ ((lfsr & 4) >> 2);
1342                 bit = bit ^ ((lfsr & 0x400000) >> 22);
1343
1344                 lfsr = ((lfsr >> 1) | (bit << 31));
1345         }
1346
1347         *lfsr_ptr = lfsr;
1348 }
1349
1350 /* Clear the pointers in a given byte lane in a given channel */
1351 void clear_pointers(void)
1352 {
1353         uint8_t channel;
1354         uint8_t bl;
1355
1356         ENTERFN();
1357
1358         for (channel = 0; channel < NUM_CHANNELS; channel++) {
1359                 for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1360                         mrc_alt_write_mask(DDRPHY,
1361                                            B01PTRCTL1 +
1362                                            channel * DDRIODQ_CH_OFFSET +
1363                                            (bl >> 1) * DDRIODQ_BL_OFFSET,
1364                                            ~(1 << 8), (1 << 8));
1365
1366                         mrc_alt_write_mask(DDRPHY,
1367                                            B01PTRCTL1 +
1368                                            channel * DDRIODQ_CH_OFFSET +
1369                                            (bl >> 1) * DDRIODQ_BL_OFFSET,
1370                                            (1 << 8), (1 << 8));
1371                 }
1372         }
1373
1374         LEAVEFN();
1375 }
1376
1377 static void print_timings_internal(uint8_t algo, uint8_t channel, uint8_t rank,
1378                                    uint8_t bl_divisor)
1379 {
1380         uint8_t bl;
1381
1382         switch (algo) {
1383         case RCVN:
1384                 DPF(D_INFO, "\nRCVN[%02d:%02d]", channel, rank);
1385                 break;
1386         case WDQS:
1387                 DPF(D_INFO, "\nWDQS[%02d:%02d]", channel, rank);
1388                 break;
1389         case WDQX:
1390                 DPF(D_INFO, "\nWDQx[%02d:%02d]", channel, rank);
1391                 break;
1392         case RDQS:
1393                 DPF(D_INFO, "\nRDQS[%02d:%02d]", channel, rank);
1394                 break;
1395         case VREF:
1396                 DPF(D_INFO, "\nVREF[%02d:%02d]", channel, rank);
1397                 break;
1398         case WCMD:
1399                 DPF(D_INFO, "\nWCMD[%02d:%02d]", channel, rank);
1400                 break;
1401         case WCTL:
1402                 DPF(D_INFO, "\nWCTL[%02d:%02d]", channel, rank);
1403                 break;
1404         case WCLK:
1405                 DPF(D_INFO, "\nWCLK[%02d:%02d]", channel, rank);
1406                 break;
1407         default:
1408                 break;
1409         }
1410
1411         for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1412                 switch (algo) {
1413                 case RCVN:
1414                         DPF(D_INFO, " %03d", get_rcvn(channel, rank, bl));
1415                         break;
1416                 case WDQS:
1417                         DPF(D_INFO, " %03d", get_wdqs(channel, rank, bl));
1418                         break;
1419                 case WDQX:
1420                         DPF(D_INFO, " %03d", get_wdq(channel, rank, bl));
1421                         break;
1422                 case RDQS:
1423                         DPF(D_INFO, " %03d", get_rdqs(channel, rank, bl));
1424                         break;
1425                 case VREF:
1426                         DPF(D_INFO, " %03d", get_vref(channel, bl));
1427                         break;
1428                 case WCMD:
1429                         DPF(D_INFO, " %03d", get_wcmd(channel));
1430                         break;
1431                 case WCTL:
1432                         DPF(D_INFO, " %03d", get_wctl(channel, rank));
1433                         break;
1434                 case WCLK:
1435                         DPF(D_INFO, " %03d", get_wclk(channel, rank));
1436                         break;
1437                 default:
1438                         break;
1439                 }
1440         }
1441 }
1442
1443 void print_timings(struct mrc_params *mrc_params)
1444 {
1445         uint8_t algo;
1446         uint8_t channel;
1447         uint8_t rank;
1448         uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1449
1450         DPF(D_INFO, "\n---------------------------");
1451         DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3");
1452         DPF(D_INFO, "\n===========================");
1453
1454         for (algo = 0; algo < MAX_ALGOS; algo++) {
1455                 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1456                         if (mrc_params->channel_enables & (1 << channel)) {
1457                                 for (rank = 0; rank < NUM_RANKS; rank++) {
1458                                         if (mrc_params->rank_enables &
1459                                                 (1 << rank)) {
1460                                                 print_timings_internal(algo,
1461                                                         channel, rank,
1462                                                         bl_divisor);
1463                                         }
1464                                 }
1465                         }
1466                 }
1467         }
1468
1469         DPF(D_INFO, "\n---------------------------");
1470         DPF(D_INFO, "\n");
1471 }