blob: 49d803d794c0e75c4560ca8ade5c27def00345ec [file] [log] [blame]
Bin Meng38ad43e2015-02-05 23:42:23 +08001/*
2 * Copyright (C) 2013, Intel Corporation
3 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * Ported from Intel released Quark UEFI BIOS
6 * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
7 *
8 * SPDX-License-Identifier: Intel
9 */
10
11#include <common.h>
12#include <asm/arch/device.h>
13#include <asm/arch/mrc.h>
14#include <asm/arch/msg_port.h>
15#include "mrc_util.h"
16#include "hte.h"
17#include "smc.h"
18
19static const uint8_t vref_codes[64] = {
20 /* lowest to highest */
Bin Meng312cc392015-03-10 18:31:20 +080021 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
Bin Meng38ad43e2015-02-05 23:42:23 +080022 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
Bin Meng312cc392015-03-10 18:31:20 +080023 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
Bin Meng38ad43e2015-02-05 23:42:23 +080024 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
25 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Bin Meng312cc392015-03-10 18:31:20 +080026 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
Bin Meng38ad43e2015-02-05 23:42:23 +080027 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
Bin Meng312cc392015-03-10 18:31:20 +080028 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
Bin Meng38ad43e2015-02-05 23:42:23 +080029};
30
31void 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
38void 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
45void 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 */
56void 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 */
68void 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 */
76void select_mem_mgr(void)
77{
78 u32 dco;
79
80 ENTERFN();
81
82 dco = msg_port_read(MEM_CTLR, DCO);
Bin Meng312cc392015-03-10 18:31:20 +080083 dco &= ~DCO_PMICTL;
Bin Meng38ad43e2015-02-05 23:42:23 +080084 msg_port_write(MEM_CTLR, DCO, dco);
85
86 LEAVEFN();
87}
88
89/* Select HTE as the source for PRI interface */
90void select_hte(void)
91{
92 u32 dco;
93
94 ENTERFN();
95
96 dco = msg_port_read(MEM_CTLR, DCO);
Bin Meng312cc392015-03-10 18:31:20 +080097 dco |= DCO_PMICTL;
Bin Meng38ad43e2015-02-05 23:42:23 +080098 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 */
107void dram_init_command(uint32_t data)
108{
109 pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, data);
110 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 */
117void dram_wake_command(void)
118{
119 ENTERFN();
120
121 msg_port_setup(MSG_OP_DRAM_WAKE, MEM_CTLR, 0);
122
123 LEAVEFN();
124}
125
126void 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 */
137void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800154 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;
Bin Meng38ad43e2015-02-05 23:42:23 +0800159 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
160
161 /* Adjust PI_COUNT */
Bin Meng312cc392015-03-10 18:31:20 +0800162 pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
Bin Meng38ad43e2015-02-05 23:42:23 +0800163
164 /*
165 * PI (1/64 MCLK, 1 PIs)
166 * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
167 * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
168 */
Bin Meng312cc392015-03-10 18:31:20 +0800169 reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
170 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
171 channel * DDRIODQ_CH_OFFSET);
172 msk = 0x3f000000;
Bin Meng38ad43e2015-02-05 23:42:23 +0800173 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800181 reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
182 channel * DDRIODQ_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800183 msk = 0x00;
184 temp = 0x00;
185
186 /* enable */
Bin Meng312cc392015-03-10 18:31:20 +0800187 msk |= (byte_lane & 1) ? (1 << 5) : (1 << 2);
Bin Meng38ad43e2015-02-05 23:42:23 +0800188 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
189 temp |= msk;
190
191 /* select */
Bin Meng312cc392015-03-10 18:31:20 +0800192 msk |= (byte_lane & 1) ? (1 << 11) : (1 << 8);
Bin Meng38ad43e2015-02-05 23:42:23 +0800193 if (pi_count < EARLY_DB)
194 temp |= msk;
195
196 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
197
198 /* error check */
Bin Meng312cc392015-03-10 18:31:20 +0800199 if (pi_count > 0x3f) {
Bin Meng38ad43e2015-02-05 23:42:23 +0800200 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 */
213uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800226 reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
227 channel * DDRIODQ_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800228 temp = msg_port_alt_read(DDRPHY, reg);
Bin Meng312cc392015-03-10 18:31:20 +0800229 temp >>= (byte_lane & 1) ? 20 : 8;
230 temp &= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800231
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 */
Bin Meng312cc392015-03-10 18:31:20 +0800240 reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
241 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
242 channel * DDRIODQ_CH_OFFSET);
Bin Meng38ad43e2015-02-05 23:42:23 +0800243 temp = msg_port_alt_read(DDRPHY, reg);
244 temp >>= 24;
Bin Meng312cc392015-03-10 18:31:20 +0800245 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800246
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 */
261void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800277 reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
278 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
279 channel * DDRIODQ_CH_OFFSET);
280 msk = 0x7f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800281 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 */
299uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800312 reg = (byte_lane & 1) ? B1RXDQSPICODE : B0RXDQSPICODE;
313 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
314 channel * DDRIODQ_CH_OFFSET);
Bin Meng38ad43e2015-02-05 23:42:23 +0800315 temp = msg_port_alt_read(DDRPHY, reg);
316
317 /* Adjust PI_COUNT */
Bin Meng312cc392015-03-10 18:31:20 +0800318 pi_count = temp & 0x7f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800319
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 */
331void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800348 reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
349 channel * DDRIODQ_CH_OFFSET;
350 msk = (byte_lane & 1) ? 0xf0000 : 0xf0;
Bin Meng38ad43e2015-02-05 23:42:23 +0800351 temp = pi_count / HALF_CLK;
Bin Meng312cc392015-03-10 18:31:20 +0800352 temp <<= (byte_lane & 1) ? 16 : 4;
Bin Meng38ad43e2015-02-05 23:42:23 +0800353 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
354
355 /* Adjust PI_COUNT */
Bin Meng312cc392015-03-10 18:31:20 +0800356 pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
Bin Meng38ad43e2015-02-05 23:42:23 +0800357
358 /*
359 * PI (1/64 MCLK, 1 PIs)
360 * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
361 * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
362 */
Bin Meng312cc392015-03-10 18:31:20 +0800363 reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
364 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
365 channel * DDRIODQ_CH_OFFSET);
366 msk = 0x3f0000;
Bin Meng38ad43e2015-02-05 23:42:23 +0800367 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800375 reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
376 channel * DDRIODQ_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800377 msk = 0x00;
378 temp = 0x00;
379
380 /* enable */
Bin Meng312cc392015-03-10 18:31:20 +0800381 msk |= (byte_lane & 1) ? (1 << 4) : (1 << 1);
Bin Meng38ad43e2015-02-05 23:42:23 +0800382 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
383 temp |= msk;
384
385 /* select */
Bin Meng312cc392015-03-10 18:31:20 +0800386 msk |= (byte_lane & 1) ? (1 << 10) : (1 << 7);
Bin Meng38ad43e2015-02-05 23:42:23 +0800387 if (pi_count < EARLY_DB)
388 temp |= msk;
389
390 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
391
392 /* error check */
Bin Meng312cc392015-03-10 18:31:20 +0800393 if (pi_count > 0x3f) {
Bin Meng38ad43e2015-02-05 23:42:23 +0800394 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 */
407uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800420 reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
421 channel * DDRIODQ_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800422 temp = msg_port_alt_read(DDRPHY, reg);
Bin Meng312cc392015-03-10 18:31:20 +0800423 temp >>= (byte_lane & 1) ? 16 : 4;
424 temp &= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800425
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 */
Bin Meng312cc392015-03-10 18:31:20 +0800434 reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
435 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
436 channel * DDRIODQ_CH_OFFSET);
Bin Meng38ad43e2015-02-05 23:42:23 +0800437 temp = msg_port_alt_read(DDRPHY, reg);
438 temp >>= 16;
Bin Meng312cc392015-03-10 18:31:20 +0800439 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800440
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 */
455void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800472 reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
473 channel * DDRIODQ_CH_OFFSET;
474 msk = (byte_lane & 1) ? 0xf000 : 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800475 temp = pi_count / HALF_CLK;
Bin Meng312cc392015-03-10 18:31:20 +0800476 temp <<= (byte_lane & 1) ? 12 : 0;
Bin Meng38ad43e2015-02-05 23:42:23 +0800477 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
478
479 /* Adjust PI_COUNT */
Bin Meng312cc392015-03-10 18:31:20 +0800480 pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
Bin Meng38ad43e2015-02-05 23:42:23 +0800481
482 /*
483 * PI (1/64 MCLK, 1 PIs)
484 * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
485 * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
486 */
Bin Meng312cc392015-03-10 18:31:20 +0800487 reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
488 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
489 channel * DDRIODQ_CH_OFFSET);
490 msk = 0x3f00;
Bin Meng38ad43e2015-02-05 23:42:23 +0800491 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800499 reg = B01DBCTL1 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
500 channel * DDRIODQ_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800501 msk = 0x00;
502 temp = 0x00;
503
504 /* enable */
Bin Meng312cc392015-03-10 18:31:20 +0800505 msk |= (byte_lane & 1) ? (1 << 3) : (1 << 0);
Bin Meng38ad43e2015-02-05 23:42:23 +0800506 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
507 temp |= msk;
508
509 /* select */
Bin Meng312cc392015-03-10 18:31:20 +0800510 msk |= (byte_lane & 1) ? (1 << 9) : (1 << 6);
Bin Meng38ad43e2015-02-05 23:42:23 +0800511 if (pi_count < EARLY_DB)
512 temp |= msk;
513
514 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
515
516 /* error check */
Bin Meng312cc392015-03-10 18:31:20 +0800517 if (pi_count > 0x3f) {
Bin Meng38ad43e2015-02-05 23:42:23 +0800518 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 */
531uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800544 reg = B01PTRCTL0 + (byte_lane >> 1) * DDRIODQ_BL_OFFSET +
545 channel * DDRIODQ_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800546 temp = msg_port_alt_read(DDRPHY, reg);
Bin Meng312cc392015-03-10 18:31:20 +0800547 temp >>= (byte_lane & 1) ? 12 : 0;
548 temp &= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800549
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 */
Bin Meng312cc392015-03-10 18:31:20 +0800558 reg = (byte_lane & 1) ? B1DLLPICODER0 : B0DLLPICODER0;
559 reg += ((byte_lane >> 1) * DDRIODQ_BL_OFFSET +
560 channel * DDRIODQ_CH_OFFSET);
Bin Meng38ad43e2015-02-05 23:42:23 +0800561 temp = msg_port_alt_read(DDRPHY, reg);
562 temp >>= 8;
Bin Meng312cc392015-03-10 18:31:20 +0800563 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800564
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 */
577void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800589 reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
590 msk = 0xf00;
Bin Meng38ad43e2015-02-05 23:42:23 +0800591 temp = pi_count / HALF_CLK;
592 temp <<= 8;
593 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
594
595 /* Adjust PI_COUNT */
Bin Meng312cc392015-03-10 18:31:20 +0800596 pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
Bin Meng38ad43e2015-02-05 23:42:23 +0800597
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 */
Bin Meng312cc392015-03-10 18:31:20 +0800609 reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
610 msk = 0x3f3f3f3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800611 temp = (pi_count << 24) | (pi_count << 16) |
612 (pi_count << 8) | (pi_count << 0);
613
614 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800615 reg = CMDDLLPICODER0 + channel * DDRIOCCC_CH_OFFSET; /* PO */
Bin Meng38ad43e2015-02-05 23:42:23 +0800616 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
617
618 /*
619 * DEADBAND
620 * CMDCFGREG0[17] (+1 select)
621 * CMDCFGREG0[16] (enable)
622 */
Bin Meng312cc392015-03-10 18:31:20 +0800623 reg = CMDCFGREG0 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800624 msk = 0x00;
625 temp = 0x00;
626
627 /* enable */
Bin Meng312cc392015-03-10 18:31:20 +0800628 msk |= (1 << 16);
Bin Meng38ad43e2015-02-05 23:42:23 +0800629 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
630 temp |= msk;
631
632 /* select */
Bin Meng312cc392015-03-10 18:31:20 +0800633 msk |= (1 << 17);
Bin Meng38ad43e2015-02-05 23:42:23 +0800634 if (pi_count < EARLY_DB)
635 temp |= msk;
636
637 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
638
639 /* error check */
Bin Meng312cc392015-03-10 18:31:20 +0800640 if (pi_count > 0x3f)
Bin Meng38ad43e2015-02-05 23:42:23 +0800641 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 */
650uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800662 reg = CMDPTRREG + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800663 temp = msg_port_alt_read(DDRPHY, reg);
664 temp >>= 8;
Bin Meng312cc392015-03-10 18:31:20 +0800665 temp &= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800666
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 */
Bin Meng312cc392015-03-10 18:31:20 +0800681 reg = CMDDLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800682 temp = msg_port_alt_read(DDRPHY, reg);
683 temp >>= 16;
Bin Meng312cc392015-03-10 18:31:20 +0800684 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800685
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 */
698void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800711 reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
712 msk = 0xff00;
Bin Meng38ad43e2015-02-05 23:42:23 +0800713 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800717 pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
Bin Meng38ad43e2015-02-05 23:42:23 +0800718
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);
Bin Meng312cc392015-03-10 18:31:20 +0800726 msk = 0x3f3f00;
Bin Meng38ad43e2015-02-05 23:42:23 +0800727 temp = (pi_count << 16) | (pi_count << 8);
728 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800729
Bin Meng38ad43e2015-02-05 23:42:23 +0800730 reg = rank ? ECCB1DLLPICODER1 : ECCB1DLLPICODER1;
731 reg += (channel * DDRIOCCC_CH_OFFSET);
732 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800733
Bin Meng38ad43e2015-02-05 23:42:23 +0800734 reg = rank ? ECCB1DLLPICODER2 : ECCB1DLLPICODER2;
735 reg += (channel * DDRIOCCC_CH_OFFSET);
736 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800737
Bin Meng38ad43e2015-02-05 23:42:23 +0800738 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800747 reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800748 msk = 0x00;
749 temp = 0x00;
750
751 /* enable */
Bin Meng312cc392015-03-10 18:31:20 +0800752 msk |= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800753 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
754 temp |= msk;
755
756 /* select */
Bin Meng312cc392015-03-10 18:31:20 +0800757 msk |= 0xf00;
Bin Meng38ad43e2015-02-05 23:42:23 +0800758 if (pi_count < EARLY_DB)
759 temp |= msk;
760
761 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
762
763 /* error check */
Bin Meng312cc392015-03-10 18:31:20 +0800764 if (pi_count > 0x3f)
Bin Meng38ad43e2015-02-05 23:42:23 +0800765 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 */
774uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800787 reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800788 temp = msg_port_alt_read(DDRPHY, reg);
789 temp >>= rank ? 12 : 8;
Bin Meng312cc392015-03-10 18:31:20 +0800790 temp &= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800791
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;
Bin Meng312cc392015-03-10 18:31:20 +0800804 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800805
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 */
819void 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800832 reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
833 msk = 0xff000000;
Bin Meng38ad43e2015-02-05 23:42:23 +0800834 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 */
Bin Meng312cc392015-03-10 18:31:20 +0800838 pi_count -= ((pi_count / HALF_CLK) & 0xf) * HALF_CLK;
Bin Meng38ad43e2015-02-05 23:42:23 +0800839
840 /*
841 * PI (1/64 MCLK, 1 PIs)
842 * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
843 * ECCB1DLLPICODER?[29:24] (0x00-0x3F)
844 */
Bin Meng312cc392015-03-10 18:31:20 +0800845 reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
846 msk = 0x3f000000;
Bin Meng38ad43e2015-02-05 23:42:23 +0800847 temp = (pi_count << 24);
848 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800849
850 reg = ECCB1DLLPICODER1 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800851 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800852
853 reg = ECCB1DLLPICODER2 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800854 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
Bin Meng312cc392015-03-10 18:31:20 +0800855
856 reg = ECCB1DLLPICODER3 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800857 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
858
859 /*
860 * DEADBAND
861 * CCCFGREG1[13:12] (+1 select)
862 * CCCFGREG1[05:04] (enable)
863 */
Bin Meng312cc392015-03-10 18:31:20 +0800864 reg = CCCFGREG1 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800865 msk = 0x00;
866 temp = 0x00;
867
868 /* enable */
Bin Meng312cc392015-03-10 18:31:20 +0800869 msk |= 0x30;
Bin Meng38ad43e2015-02-05 23:42:23 +0800870 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
871 temp |= msk;
872
873 /* select */
Bin Meng312cc392015-03-10 18:31:20 +0800874 msk |= 0x3000;
Bin Meng38ad43e2015-02-05 23:42:23 +0800875 if (pi_count < EARLY_DB)
876 temp |= msk;
877
878 mrc_alt_write_mask(DDRPHY, reg, temp, msk);
879
880 /* error check */
Bin Meng312cc392015-03-10 18:31:20 +0800881 if (pi_count > 0x3f)
Bin Meng38ad43e2015-02-05 23:42:23 +0800882 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 */
893uint32_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 */
Bin Meng312cc392015-03-10 18:31:20 +0800906 reg = CCPTRREG + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800907 temp = msg_port_alt_read(DDRPHY, reg);
908 temp >>= 24;
Bin Meng312cc392015-03-10 18:31:20 +0800909 temp &= 0xf;
Bin Meng38ad43e2015-02-05 23:42:23 +0800910
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 */
Bin Meng312cc392015-03-10 18:31:20 +0800919 reg = ECCB1DLLPICODER0 + channel * DDRIOCCC_CH_OFFSET;
Bin Meng38ad43e2015-02-05 23:42:23 +0800920 temp = msg_port_alt_read(DDRPHY, reg);
921 temp >>= 24;
Bin Meng312cc392015-03-10 18:31:20 +0800922 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800923
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 */
936void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting)
937{
Bin Meng312cc392015-03-10 18:31:20 +0800938 uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
Bin Meng38ad43e2015-02-05 23:42:23 +0800939
940 ENTERFN();
941
942 DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n",
943 channel, byte_lane, setting);
944
Bin Meng312cc392015-03-10 18:31:20 +0800945 mrc_alt_write_mask(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
946 (byte_lane >> 1) * DDRIODQ_BL_OFFSET,
947 vref_codes[setting] << 2, 0xfc);
Bin Meng38ad43e2015-02-05 23:42:23 +0800948
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 */
964uint32_t get_vref(uint8_t channel, uint8_t byte_lane)
965{
966 uint8_t j;
967 uint32_t ret_val = sizeof(vref_codes) / 2;
Bin Meng312cc392015-03-10 18:31:20 +0800968 uint32_t reg = (byte_lane & 0x1) ? B1VREFCTL : B0VREFCTL;
Bin Meng38ad43e2015-02-05 23:42:23 +0800969 uint32_t temp;
970
971 ENTERFN();
972
Bin Meng312cc392015-03-10 18:31:20 +0800973 temp = msg_port_alt_read(DDRPHY, reg + channel * DDRIODQ_CH_OFFSET +
974 (byte_lane >> 1) * DDRIODQ_BL_OFFSET);
Bin Meng38ad43e2015-02-05 23:42:23 +0800975 temp >>= 2;
Bin Meng312cc392015-03-10 18:31:20 +0800976 temp &= 0x3f;
Bin Meng38ad43e2015-02-05 23:42:23 +0800977
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 */
994uint32_t get_addr(uint8_t channel, uint8_t rank)
995{
Bin Meng312cc392015-03-10 18:31:20 +0800996 uint32_t offset = 32 * 1024 * 1024; /* 32MB */
Bin Meng38ad43e2015-02-05 23:42:23 +0800997
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 */
1022uint32_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[] */
Bin Meng312cc392015-03-10 18:31:20 +08001039 msk[0] = rcvn ? (1 << 1) : (1 << 9); /* BL0 */
1040 msk[1] = rcvn ? (1 << 0) : (1 << 8); /* BL1 */
Bin Meng38ad43e2015-02-05 23:42:23 +08001041
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,
Bin Meng312cc392015-03-10 18:31:20 +08001055 DQTRAINSTS +
1056 bl_grp * DDRIODQ_BL_OFFSET +
1057 channel * DDRIODQ_CH_OFFSET);
Bin Meng38ad43e2015-02-05 23:42:23 +08001058 }
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)
Bin Meng312cc392015-03-10 18:31:20 +08001075 ret_val |= (1 << (bl + bl_grp * 2));
Bin Meng38ad43e2015-02-05 23:42:23 +08001076 }
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 */
1089void 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,
Bin Meng312cc392015-03-10 18:31:20 +08001115 delay[bl] + sample * SAMPLE_DLY);
Bin Meng38ad43e2015-02-05 23:42:23 +08001116 } else {
1117 set_wdqs(channel, rank, bl,
Bin Meng312cc392015-03-10 18:31:20 +08001118 delay[bl] + sample * SAMPLE_DLY);
Bin Meng38ad43e2015-02-05 23:42:23 +08001119 }
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",
Bin Meng312cc392015-03-10 18:31:20 +08001128 rcvn ? "RCVN" : "WDQS", channel, rank, sample,
Bin Meng38ad43e2015-02-05 23:42:23 +08001129 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 */
Bin Meng312cc392015-03-10 18:31:20 +08001136 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng38ad43e2015-02-05 23:42:23 +08001137 /* 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 */
Bin Meng312cc392015-03-10 18:31:20 +08001201 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng38ad43e2015-02-05 23:42:23 +08001202 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 */
1253uint32_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 */
1282uint32_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 */
1306uint32_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 */
1330void 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++) {
Bin Meng312cc392015-03-10 18:31:20 +08001339 bit = 1 ^ (lfsr & 1);
1340 bit = bit ^ ((lfsr & 2) >> 1);
1341 bit = bit ^ ((lfsr & 4) >> 2);
1342 bit = bit ^ ((lfsr & 0x400000) >> 22);
Bin Meng38ad43e2015-02-05 23:42:23 +08001343
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 */
1351void 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,
Bin Meng312cc392015-03-10 18:31:20 +08001361 B01PTRCTL1 +
1362 channel * DDRIODQ_CH_OFFSET +
1363 (bl >> 1) * DDRIODQ_BL_OFFSET,
1364 ~(1 << 8), (1 << 8));
Bin Meng38ad43e2015-02-05 23:42:23 +08001365
1366 mrc_alt_write_mask(DDRPHY,
Bin Meng312cc392015-03-10 18:31:20 +08001367 B01PTRCTL1 +
1368 channel * DDRIODQ_CH_OFFSET +
1369 (bl >> 1) * DDRIODQ_BL_OFFSET,
1370 (1 << 8), (1 << 8));
Bin Meng38ad43e2015-02-05 23:42:23 +08001371 }
1372 }
1373
1374 LEAVEFN();
1375}
1376
1377static 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
Bin Meng312cc392015-03-10 18:31:20 +08001411 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng38ad43e2015-02-05 23:42:23 +08001412 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
1443void 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}