• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <pci.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 
19 /* t_ck clock period in picoseconds per speed index 800, 1066, 1333 */
20 static const uint32_t t_ck[3] = {
21 	2500,
22 	1875,
23 	1500
24 };
25 
26 /* Global variables */
27 static const uint16_t ddr_wclk[] = {193, 158};
28 #ifdef BACKUP_WCTL
29 static const uint16_t ddr_wctl[] = {1, 217};
30 #endif
31 #ifdef BACKUP_WCMD
32 static const uint16_t ddr_wcmd[] = {1, 220};
33 #endif
34 
35 #ifdef BACKUP_RCVN
36 static const uint16_t ddr_rcvn[] = {129, 498};
37 #endif
38 
39 #ifdef BACKUP_WDQS
40 static const uint16_t ddr_wdqs[] = {65, 289};
41 #endif
42 
43 #ifdef BACKUP_RDQS
44 static const uint8_t ddr_rdqs[] = {32, 24};
45 #endif
46 
47 #ifdef BACKUP_WDQ
48 static const uint16_t ddr_wdq[] = {32, 257};
49 #endif
50 
51 /* Stop self refresh driven by MCU */
clear_self_refresh(struct mrc_params * mrc_params)52 void clear_self_refresh(struct mrc_params *mrc_params)
53 {
54 	ENTERFN();
55 
56 	/* clear the PMSTS Channel Self Refresh bits */
57 	mrc_write_mask(MEM_CTLR, PMSTS, PMSTS_DISR, PMSTS_DISR);
58 
59 	LEAVEFN();
60 }
61 
62 /* It will initialize timing registers in the MCU (DTR0..DTR4) */
prog_ddr_timing_control(struct mrc_params * mrc_params)63 void prog_ddr_timing_control(struct mrc_params *mrc_params)
64 {
65 	uint8_t tcl, wl;
66 	uint8_t trp, trcd, tras, twr, twtr, trrd, trtp, tfaw;
67 	uint32_t tck;
68 	u32 dtr0, dtr1, dtr2, dtr3, dtr4;
69 	u32 tmp1, tmp2;
70 
71 	ENTERFN();
72 
73 	/* mcu_init starts */
74 	mrc_post_code(0x02, 0x00);
75 
76 	dtr0 = msg_port_read(MEM_CTLR, DTR0);
77 	dtr1 = msg_port_read(MEM_CTLR, DTR1);
78 	dtr2 = msg_port_read(MEM_CTLR, DTR2);
79 	dtr3 = msg_port_read(MEM_CTLR, DTR3);
80 	dtr4 = msg_port_read(MEM_CTLR, DTR4);
81 
82 	tck = t_ck[mrc_params->ddr_speed];	/* Clock in picoseconds */
83 	tcl = mrc_params->params.cl;		/* CAS latency in clocks */
84 	trp = tcl;	/* Per CAT MRC */
85 	trcd = tcl;	/* Per CAT MRC */
86 	tras = MCEIL(mrc_params->params.ras, tck);
87 
88 	/* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
89 	twr = MCEIL(15000, tck);
90 
91 	twtr = MCEIL(mrc_params->params.wtr, tck);
92 	trrd = MCEIL(mrc_params->params.rrd, tck);
93 	trtp = 4;	/* Valid for 800 and 1066, use 5 for 1333 */
94 	tfaw = MCEIL(mrc_params->params.faw, tck);
95 
96 	wl = 5 + mrc_params->ddr_speed;
97 
98 	dtr0 &= ~DTR0_DFREQ_MASK;
99 	dtr0 |= mrc_params->ddr_speed;
100 	dtr0 &= ~DTR0_TCL_MASK;
101 	tmp1 = tcl - 5;
102 	dtr0 |= ((tcl - 5) << 12);
103 	dtr0 &= ~DTR0_TRP_MASK;
104 	dtr0 |= ((trp - 5) << 4);	/* 5 bit DRAM Clock */
105 	dtr0 &= ~DTR0_TRCD_MASK;
106 	dtr0 |= ((trcd - 5) << 8);	/* 5 bit DRAM Clock */
107 
108 	dtr1 &= ~DTR1_TWCL_MASK;
109 	tmp2 = wl - 3;
110 	dtr1 |= (wl - 3);
111 	dtr1 &= ~DTR1_TWTP_MASK;
112 	dtr1 |= ((wl + 4 + twr - 14) << 8);	/* Change to tWTP */
113 	dtr1 &= ~DTR1_TRTP_MASK;
114 	dtr1 |= ((MMAX(trtp, 4) - 3) << 28);	/* 4 bit DRAM Clock */
115 	dtr1 &= ~DTR1_TRRD_MASK;
116 	dtr1 |= ((trrd - 4) << 24);		/* 4 bit DRAM Clock */
117 	dtr1 &= ~DTR1_TCMD_MASK;
118 	dtr1 |= (1 << 4);
119 	dtr1 &= ~DTR1_TRAS_MASK;
120 	dtr1 |= ((tras - 14) << 20);		/* 6 bit DRAM Clock */
121 	dtr1 &= ~DTR1_TFAW_MASK;
122 	dtr1 |= ((((tfaw + 1) >> 1) - 5) << 16);/* 4 bit DRAM Clock */
123 	/* Set 4 Clock CAS to CAS delay (multi-burst) */
124 	dtr1 &= ~DTR1_TCCD_MASK;
125 
126 	dtr2 &= ~DTR2_TRRDR_MASK;
127 	dtr2 |= 1;
128 	dtr2 &= ~DTR2_TWWDR_MASK;
129 	dtr2 |= (2 << 8);
130 	dtr2 &= ~DTR2_TRWDR_MASK;
131 	dtr2 |= (2 << 16);
132 
133 	dtr3 &= ~DTR3_TWRDR_MASK;
134 	dtr3 |= 2;
135 	dtr3 &= ~DTR3_TXXXX_MASK;
136 	dtr3 |= (2 << 4);
137 
138 	dtr3 &= ~DTR3_TRWSR_MASK;
139 	if (mrc_params->ddr_speed == DDRFREQ_800) {
140 		/* Extended RW delay (+1) */
141 		dtr3 |= ((tcl - 5 + 1) << 8);
142 	} else if (mrc_params->ddr_speed == DDRFREQ_1066) {
143 		/* Extended RW delay (+1) */
144 		dtr3 |= ((tcl - 5 + 1) << 8);
145 	}
146 
147 	dtr3 &= ~DTR3_TWRSR_MASK;
148 	dtr3 |= ((4 + wl + twtr - 11) << 13);
149 
150 	dtr3 &= ~DTR3_TXP_MASK;
151 	if (mrc_params->ddr_speed == DDRFREQ_800)
152 		dtr3 |= ((MMAX(0, 1 - 1)) << 22);
153 	else
154 		dtr3 |= ((MMAX(0, 2 - 1)) << 22);
155 
156 	dtr4 &= ~DTR4_WRODTSTRT_MASK;
157 	dtr4 |= 1;
158 	dtr4 &= ~DTR4_WRODTSTOP_MASK;
159 	dtr4 |= (1 << 4);
160 	dtr4 &= ~DTR4_XXXX1_MASK;
161 	dtr4 |= ((1 + tmp1 - tmp2 + 2) << 8);
162 	dtr4 &= ~DTR4_XXXX2_MASK;
163 	dtr4 |= ((1 + tmp1 - tmp2 + 2) << 12);
164 	dtr4 &= ~(DTR4_ODTDIS | DTR4_TRGSTRDIS);
165 
166 	msg_port_write(MEM_CTLR, DTR0, dtr0);
167 	msg_port_write(MEM_CTLR, DTR1, dtr1);
168 	msg_port_write(MEM_CTLR, DTR2, dtr2);
169 	msg_port_write(MEM_CTLR, DTR3, dtr3);
170 	msg_port_write(MEM_CTLR, DTR4, dtr4);
171 
172 	LEAVEFN();
173 }
174 
175 /* Configure MCU before jedec init sequence */
prog_decode_before_jedec(struct mrc_params * mrc_params)176 void prog_decode_before_jedec(struct mrc_params *mrc_params)
177 {
178 	u32 drp;
179 	u32 drfc;
180 	u32 dcal;
181 	u32 dsch;
182 	u32 dpmc0;
183 
184 	ENTERFN();
185 
186 	/* Disable power saving features */
187 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
188 	dpmc0 |= (DPMC0_CLKGTDIS | DPMC0_DISPWRDN);
189 	dpmc0 &= ~DPMC0_PCLSTO_MASK;
190 	dpmc0 &= ~DPMC0_DYNSREN;
191 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
192 
193 	/* Disable out of order transactions */
194 	dsch = msg_port_read(MEM_CTLR, DSCH);
195 	dsch |= (DSCH_OOODIS | DSCH_NEWBYPDIS);
196 	msg_port_write(MEM_CTLR, DSCH, dsch);
197 
198 	/* Disable issuing the REF command */
199 	drfc = msg_port_read(MEM_CTLR, DRFC);
200 	drfc &= ~DRFC_TREFI_MASK;
201 	msg_port_write(MEM_CTLR, DRFC, drfc);
202 
203 	/* Disable ZQ calibration short */
204 	dcal = msg_port_read(MEM_CTLR, DCAL);
205 	dcal &= ~DCAL_ZQCINT_MASK;
206 	dcal &= ~DCAL_SRXZQCL_MASK;
207 	msg_port_write(MEM_CTLR, DCAL, dcal);
208 
209 	/*
210 	 * Training performed in address mode 0, rank population has limited
211 	 * impact, however simulator complains if enabled non-existing rank.
212 	 */
213 	drp = 0;
214 	if (mrc_params->rank_enables & 1)
215 		drp |= DRP_RKEN0;
216 	if (mrc_params->rank_enables & 2)
217 		drp |= DRP_RKEN1;
218 	msg_port_write(MEM_CTLR, DRP, drp);
219 
220 	LEAVEFN();
221 }
222 
223 /*
224  * After Cold Reset, BIOS should set COLDWAKE bit to 1 before
225  * sending the WAKE message to the Dunit.
226  *
227  * For Standby Exit, or any other mode in which the DRAM is in
228  * SR, this bit must be set to 0.
229  */
perform_ddr_reset(struct mrc_params * mrc_params)230 void perform_ddr_reset(struct mrc_params *mrc_params)
231 {
232 	ENTERFN();
233 
234 	/* Set COLDWAKE bit before sending the WAKE message */
235 	mrc_write_mask(MEM_CTLR, DRMC, DRMC_COLDWAKE, DRMC_COLDWAKE);
236 
237 	/* Send wake command to DUNIT (MUST be done before JEDEC) */
238 	dram_wake_command();
239 
240 	/* Set default value */
241 	msg_port_write(MEM_CTLR, DRMC,
242 		       mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0);
243 
244 	LEAVEFN();
245 }
246 
247 
248 /*
249  * This function performs some initialization on the DDRIO unit.
250  * This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
251  */
ddrphy_init(struct mrc_params * mrc_params)252 void ddrphy_init(struct mrc_params *mrc_params)
253 {
254 	uint32_t temp;
255 	uint8_t ch;	/* channel counter */
256 	uint8_t rk;	/* rank counter */
257 	uint8_t bl_grp;	/*  byte lane group counter (2 BLs per module) */
258 	uint8_t bl_divisor = 1;	/* byte lane divisor */
259 	/* For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 */
260 	uint8_t speed = mrc_params->ddr_speed & 3;
261 	uint8_t cas;
262 	uint8_t cwl;
263 
264 	ENTERFN();
265 
266 	cas = mrc_params->params.cl;
267 	cwl = 5 + mrc_params->ddr_speed;
268 
269 	/* ddrphy_init starts */
270 	mrc_post_code(0x03, 0x00);
271 
272 	/*
273 	 * HSD#231531
274 	 * Make sure IOBUFACT is deasserted before initializing the DDR PHY
275 	 *
276 	 * HSD#234845
277 	 * Make sure WRPTRENABLE is deasserted before initializing the DDR PHY
278 	 */
279 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
280 		if (mrc_params->channel_enables & (1 << ch)) {
281 			/* Deassert DDRPHY Initialization Complete */
282 			mrc_alt_write_mask(DDRPHY,
283 				CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
284 				~(1 << 20), 1 << 20);	/* SPID_INIT_COMPLETE=0 */
285 			/* Deassert IOBUFACT */
286 			mrc_alt_write_mask(DDRPHY,
287 				CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
288 				~(1 << 2), 1 << 2);	/* IOBUFACTRST_N=0 */
289 			/* Disable WRPTR */
290 			mrc_alt_write_mask(DDRPHY,
291 				CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
292 				~(1 << 0), 1 << 0);	/* WRPTRENABLE=0 */
293 		}
294 	}
295 
296 	/* Put PHY in reset */
297 	mrc_alt_write_mask(DDRPHY, MASTERRSTN, 0, 1);
298 
299 	/* Initialize DQ01, DQ23, CMD, CLK-CTL, COMP modules */
300 
301 	/* STEP0 */
302 	mrc_post_code(0x03, 0x10);
303 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
304 		if (mrc_params->channel_enables & (1 << ch)) {
305 			/* DQ01-DQ23 */
306 			for (bl_grp = 0;
307 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
308 			     bl_grp++) {
309 				/* Analog MUX select - IO2xCLKSEL */
310 				mrc_alt_write_mask(DDRPHY,
311 					DQOBSCKEBBCTL +
312 					bl_grp * DDRIODQ_BL_OFFSET +
313 					ch * DDRIODQ_CH_OFFSET,
314 					bl_grp ? 0 : (1 << 22), 1 << 22);
315 
316 				/* ODT Strength */
317 				switch (mrc_params->rd_odt_value) {
318 				case 1:
319 					temp = 0x3;
320 					break;	/* 60 ohm */
321 				case 2:
322 					temp = 0x3;
323 					break;	/* 120 ohm */
324 				case 3:
325 					temp = 0x3;
326 					break;	/* 180 ohm */
327 				default:
328 					temp = 0x3;
329 					break;	/* 120 ohm */
330 				}
331 
332 				/* ODT strength */
333 				mrc_alt_write_mask(DDRPHY,
334 					B0RXIOBUFCTL +
335 					bl_grp * DDRIODQ_BL_OFFSET +
336 					ch * DDRIODQ_CH_OFFSET,
337 					temp << 5, 0x60);
338 				/* ODT strength */
339 				mrc_alt_write_mask(DDRPHY,
340 					B1RXIOBUFCTL +
341 					bl_grp * DDRIODQ_BL_OFFSET +
342 					ch * DDRIODQ_CH_OFFSET,
343 					temp << 5, 0x60);
344 
345 				/* Dynamic ODT/DIFFAMP */
346 				temp = (cas << 24) | (cas << 16) |
347 					(cas << 8) | (cas << 0);
348 				switch (speed) {
349 				case 0:
350 					temp -= 0x01010101;
351 					break;	/* 800 */
352 				case 1:
353 					temp -= 0x02020202;
354 					break;	/* 1066 */
355 				case 2:
356 					temp -= 0x03030303;
357 					break;	/* 1333 */
358 				case 3:
359 					temp -= 0x04040404;
360 					break;	/* 1600 */
361 				}
362 
363 				/* Launch Time: ODT, DIFFAMP, ODT, DIFFAMP */
364 				mrc_alt_write_mask(DDRPHY,
365 					B01LATCTL1 +
366 					bl_grp * DDRIODQ_BL_OFFSET +
367 					ch * DDRIODQ_CH_OFFSET,
368 					temp, 0x1f1f1f1f);
369 				switch (speed) {
370 				/* HSD#234715 */
371 				case 0:
372 					temp = (0x06 << 16) | (0x07 << 8);
373 					break;	/* 800 */
374 				case 1:
375 					temp = (0x07 << 16) | (0x08 << 8);
376 					break;	/* 1066 */
377 				case 2:
378 					temp = (0x09 << 16) | (0x0a << 8);
379 					break;	/* 1333 */
380 				case 3:
381 					temp = (0x0a << 16) | (0x0b << 8);
382 					break;	/* 1600 */
383 				}
384 
385 				/* On Duration: ODT, DIFFAMP */
386 				mrc_alt_write_mask(DDRPHY,
387 					B0ONDURCTL +
388 					bl_grp * DDRIODQ_BL_OFFSET +
389 					ch * DDRIODQ_CH_OFFSET,
390 					temp, 0x003f3f00);
391 				/* On Duration: ODT, DIFFAMP */
392 				mrc_alt_write_mask(DDRPHY,
393 					B1ONDURCTL +
394 					bl_grp * DDRIODQ_BL_OFFSET +
395 					ch * DDRIODQ_CH_OFFSET,
396 					temp, 0x003f3f00);
397 
398 				switch (mrc_params->rd_odt_value) {
399 				case 0:
400 					/* override DIFFAMP=on, ODT=off */
401 					temp = (0x3f << 16) | (0x3f << 10);
402 					break;
403 				default:
404 					/* override DIFFAMP=on, ODT=on */
405 					temp = (0x3f << 16) | (0x2a << 10);
406 					break;
407 				}
408 
409 				/* Override: DIFFAMP, ODT */
410 				mrc_alt_write_mask(DDRPHY,
411 					B0OVRCTL +
412 					bl_grp * DDRIODQ_BL_OFFSET +
413 					ch * DDRIODQ_CH_OFFSET,
414 					temp, 0x003ffc00);
415 				/* Override: DIFFAMP, ODT */
416 				mrc_alt_write_mask(DDRPHY,
417 					B1OVRCTL +
418 					bl_grp * DDRIODQ_BL_OFFSET +
419 					ch * DDRIODQ_CH_OFFSET,
420 					temp, 0x003ffc00);
421 
422 				/* DLL Setup */
423 
424 				/* 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) */
425 				mrc_alt_write_mask(DDRPHY,
426 					B0LATCTL0 +
427 					bl_grp * DDRIODQ_BL_OFFSET +
428 					ch * DDRIODQ_CH_OFFSET,
429 					((cas + 7) << 16) | ((cas - 4) << 8) |
430 					((cwl - 2) << 0), 0x003f1f1f);
431 				mrc_alt_write_mask(DDRPHY,
432 					B1LATCTL0 +
433 					bl_grp * DDRIODQ_BL_OFFSET +
434 					ch * DDRIODQ_CH_OFFSET,
435 					((cas + 7) << 16) | ((cas - 4) << 8) |
436 					((cwl - 2) << 0), 0x003f1f1f);
437 
438 				/* RCVEN Bypass (PO) */
439 				mrc_alt_write_mask(DDRPHY,
440 					B0RXIOBUFCTL +
441 					bl_grp * DDRIODQ_BL_OFFSET +
442 					ch * DDRIODQ_CH_OFFSET,
443 					0, 0x81);
444 				mrc_alt_write_mask(DDRPHY,
445 					B1RXIOBUFCTL +
446 					bl_grp * DDRIODQ_BL_OFFSET +
447 					ch * DDRIODQ_CH_OFFSET,
448 					0, 0x81);
449 
450 				/* TX */
451 				mrc_alt_write_mask(DDRPHY,
452 					DQCTL +
453 					bl_grp * DDRIODQ_BL_OFFSET +
454 					ch * DDRIODQ_CH_OFFSET,
455 					1 << 16, 1 << 16);
456 				mrc_alt_write_mask(DDRPHY,
457 					B01PTRCTL1 +
458 					bl_grp * DDRIODQ_BL_OFFSET +
459 					ch * DDRIODQ_CH_OFFSET,
460 					1 << 8, 1 << 8);
461 
462 				/* RX (PO) */
463 				/* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
464 				mrc_alt_write_mask(DDRPHY,
465 					B0VREFCTL +
466 					bl_grp * DDRIODQ_BL_OFFSET +
467 					ch * DDRIODQ_CH_OFFSET,
468 					(0x03 << 2) | (0x0 << 1) | (0x0 << 0),
469 					0xff);
470 				/* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
471 				mrc_alt_write_mask(DDRPHY,
472 					B1VREFCTL +
473 					bl_grp * DDRIODQ_BL_OFFSET +
474 					ch * DDRIODQ_CH_OFFSET,
475 					(0x03 << 2) | (0x0 << 1) | (0x0 << 0),
476 					0xff);
477 				/* Per-Bit De-Skew Enable */
478 				mrc_alt_write_mask(DDRPHY,
479 					B0RXIOBUFCTL +
480 					bl_grp * DDRIODQ_BL_OFFSET +
481 					ch * DDRIODQ_CH_OFFSET,
482 					0, 0x10);
483 				/* Per-Bit De-Skew Enable */
484 				mrc_alt_write_mask(DDRPHY,
485 					B1RXIOBUFCTL +
486 					bl_grp * DDRIODQ_BL_OFFSET +
487 					ch * DDRIODQ_CH_OFFSET,
488 					0, 0x10);
489 			}
490 
491 			/* CLKEBB */
492 			mrc_alt_write_mask(DDRPHY,
493 				CMDOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
494 				0, 1 << 23);
495 
496 			/* Enable tristate control of cmd/address bus */
497 			mrc_alt_write_mask(DDRPHY,
498 				CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
499 				0, 0x03);
500 
501 			/* ODT RCOMP */
502 			mrc_alt_write_mask(DDRPHY,
503 				CMDRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
504 				(0x03 << 5) | (0x03 << 0), 0x3ff);
505 
506 			/* CMDPM* registers must be programmed in this order */
507 
508 			/* Turn On Delays: SFR (regulator), MPLL */
509 			mrc_alt_write_mask(DDRPHY,
510 				CMDPMDLYREG4 + ch * DDRIOCCC_CH_OFFSET,
511 				0xffffffff, 0xffffffff);
512 			/*
513 			 * Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3,
514 			 * VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT
515 			 * for_PM_MSG_gt0, MDLL Turn On
516 			 */
517 			mrc_alt_write_mask(DDRPHY,
518 				CMDPMDLYREG3 + ch * DDRIOCCC_CH_OFFSET,
519 				0xfffff616, 0xffffffff);
520 			/* MPLL Divider Reset Delays */
521 			mrc_alt_write_mask(DDRPHY,
522 				CMDPMDLYREG2 + ch * DDRIOCCC_CH_OFFSET,
523 				0xffffffff, 0xffffffff);
524 			/* Turn Off Delays: VREG, Staggered MDLL, MDLL, PI */
525 			mrc_alt_write_mask(DDRPHY,
526 				CMDPMDLYREG1 + ch * DDRIOCCC_CH_OFFSET,
527 				0xffffffff, 0xffffffff);
528 			/* Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT */
529 			mrc_alt_write_mask(DDRPHY,
530 				CMDPMDLYREG0 + ch * DDRIOCCC_CH_OFFSET,
531 				0xffffffff, 0xffffffff);
532 			/* Allow PUnit signals */
533 			mrc_alt_write_mask(DDRPHY,
534 				CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
535 				(0x6 << 8) | (0x1 << 6) | (0x4 << 0),
536 				0xffe00f4f);
537 			/* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
538 			mrc_alt_write_mask(DDRPHY,
539 				CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
540 				(0x3 << 4) | (0x7 << 0), 0x7f);
541 
542 			/* CLK-CTL */
543 			mrc_alt_write_mask(DDRPHY,
544 				CCOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
545 				0, 1 << 24);	/* CLKEBB */
546 			/* Buffer Enable: CS,CKE,ODT,CLK */
547 			mrc_alt_write_mask(DDRPHY,
548 				CCCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
549 				0x1f, 0x000ffff1);
550 			/* ODT RCOMP */
551 			mrc_alt_write_mask(DDRPHY,
552 				CCRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
553 				(0x03 << 8) | (0x03 << 0), 0x00001f1f);
554 			/* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
555 			mrc_alt_write_mask(DDRPHY,
556 				CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
557 				(0x3 << 4) | (0x7 << 0), 0x7f);
558 
559 			/*
560 			 * COMP (RON channel specific)
561 			 * - DQ/DQS/DM RON: 32 Ohm
562 			 * - CTRL/CMD RON: 27 Ohm
563 			 * - CLK RON: 26 Ohm
564 			 */
565 			/* RCOMP Vref PU/PD */
566 			mrc_alt_write_mask(DDRPHY,
567 				DQVREFCH0 +  ch * DDRCOMP_CH_OFFSET,
568 				(0x08 << 24) | (0x03 << 16), 0x3f3f0000);
569 			/* RCOMP Vref PU/PD */
570 			mrc_alt_write_mask(DDRPHY,
571 				CMDVREFCH0 + ch * DDRCOMP_CH_OFFSET,
572 				(0x0C << 24) | (0x03 << 16), 0x3f3f0000);
573 			/* RCOMP Vref PU/PD */
574 			mrc_alt_write_mask(DDRPHY,
575 				CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
576 				(0x0F << 24) | (0x03 << 16), 0x3f3f0000);
577 			/* RCOMP Vref PU/PD */
578 			mrc_alt_write_mask(DDRPHY,
579 				DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
580 				(0x08 << 24) | (0x03 << 16), 0x3f3f0000);
581 			/* RCOMP Vref PU/PD */
582 			mrc_alt_write_mask(DDRPHY,
583 				CTLVREFCH0 + ch * DDRCOMP_CH_OFFSET,
584 				(0x0C << 24) | (0x03 << 16), 0x3f3f0000);
585 
586 			/* DQS Swapped Input Enable */
587 			mrc_alt_write_mask(DDRPHY,
588 				COMPEN1CH0 + ch * DDRCOMP_CH_OFFSET,
589 				(1 << 19) | (1 << 17), 0xc00ac000);
590 
591 			/* ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) */
592 			/* ODT Vref PU/PD */
593 			mrc_alt_write_mask(DDRPHY,
594 				DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
595 				(0x32 << 8) | (0x03 << 0), 0x00003f3f);
596 			/* ODT Vref PU/PD */
597 			mrc_alt_write_mask(DDRPHY,
598 				DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
599 				(0x32 << 8) | (0x03 << 0), 0x00003f3f);
600 			/* ODT Vref PU/PD */
601 			mrc_alt_write_mask(DDRPHY,
602 				CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
603 				(0x0E << 8) | (0x05 << 0), 0x00003f3f);
604 
605 			/*
606 			 * Slew rate settings are frequency specific,
607 			 * numbers below are for 800Mhz (speed == 0)
608 			 * - DQ/DQS/DM/CLK SR: 4V/ns,
609 			 * - CTRL/CMD SR: 1.5V/ns
610 			 */
611 			temp = (0x0e << 16) | (0x0e << 12) | (0x08 << 8) |
612 				(0x0b << 4) | (0x0b << 0);
613 			/* DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ */
614 			mrc_alt_write_mask(DDRPHY,
615 				DLYSELCH0 + ch * DDRCOMP_CH_OFFSET,
616 				temp, 0x000fffff);
617 			/* TCO Vref CLK,DQS,DQ */
618 			mrc_alt_write_mask(DDRPHY,
619 				TCOVREFCH0 + ch * DDRCOMP_CH_OFFSET,
620 				(0x05 << 16) | (0x05 << 8) | (0x05 << 0),
621 				0x003f3f3f);
622 			/* ODTCOMP CMD/CTL PU/PD */
623 			mrc_alt_write_mask(DDRPHY,
624 				CCBUFODTCH0 + ch * DDRCOMP_CH_OFFSET,
625 				(0x03 << 8) | (0x03 << 0),
626 				0x00001f1f);
627 			/* COMP */
628 			mrc_alt_write_mask(DDRPHY,
629 				COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
630 				0, 0xc0000100);
631 
632 #ifdef BACKUP_COMPS
633 			/* DQ COMP Overrides */
634 			/* RCOMP PU */
635 			mrc_alt_write_mask(DDRPHY,
636 				DQDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
637 				(1 << 31) | (0x0a << 16),
638 				0x801f0000);
639 			/* RCOMP PD */
640 			mrc_alt_write_mask(DDRPHY,
641 				DQDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
642 				(1 << 31) | (0x0a << 16),
643 				0x801f0000);
644 			/* DCOMP PU */
645 			mrc_alt_write_mask(DDRPHY,
646 				DQDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
647 				(1 << 31) | (0x10 << 16),
648 				0x801f0000);
649 			/* DCOMP PD */
650 			mrc_alt_write_mask(DDRPHY,
651 				DQDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
652 				(1 << 31) | (0x10 << 16),
653 				0x801f0000);
654 			/* ODTCOMP PU */
655 			mrc_alt_write_mask(DDRPHY,
656 				DQODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
657 				(1 << 31) | (0x0b << 16),
658 				0x801f0000);
659 			/* ODTCOMP PD */
660 			mrc_alt_write_mask(DDRPHY,
661 				DQODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
662 				(1 << 31) | (0x0b << 16),
663 				0x801f0000);
664 			/* TCOCOMP PU */
665 			mrc_alt_write_mask(DDRPHY,
666 				DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
667 				1 << 31, 1 << 31);
668 			/* TCOCOMP PD */
669 			mrc_alt_write_mask(DDRPHY,
670 				DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
671 				1 << 31, 1 << 31);
672 
673 			/* DQS COMP Overrides */
674 			/* RCOMP PU */
675 			mrc_alt_write_mask(DDRPHY,
676 				DQSDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
677 				(1 << 31) | (0x0a << 16),
678 				0x801f0000);
679 			/* RCOMP PD */
680 			mrc_alt_write_mask(DDRPHY,
681 				DQSDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
682 				(1 << 31) | (0x0a << 16),
683 				0x801f0000);
684 			/* DCOMP PU */
685 			mrc_alt_write_mask(DDRPHY,
686 				DQSDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
687 				(1 << 31) | (0x10 << 16),
688 				0x801f0000);
689 			/* DCOMP PD */
690 			mrc_alt_write_mask(DDRPHY,
691 				DQSDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
692 				(1 << 31) | (0x10 << 16),
693 				0x801f0000);
694 			/* ODTCOMP PU */
695 			mrc_alt_write_mask(DDRPHY,
696 				DQSODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
697 				(1 << 31) | (0x0b << 16),
698 				0x801f0000);
699 			/* ODTCOMP PD */
700 			mrc_alt_write_mask(DDRPHY,
701 				DQSODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
702 				(1 << 31) | (0x0b << 16),
703 				0x801f0000);
704 			/* TCOCOMP PU */
705 			mrc_alt_write_mask(DDRPHY,
706 				DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
707 				1 << 31, 1 << 31);
708 			/* TCOCOMP PD */
709 			mrc_alt_write_mask(DDRPHY,
710 				DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
711 				1 << 31, 1 << 31);
712 
713 			/* CLK COMP Overrides */
714 			/* RCOMP PU */
715 			mrc_alt_write_mask(DDRPHY,
716 				CLKDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
717 				(1 << 31) | (0x0c << 16),
718 				0x801f0000);
719 			/* RCOMP PD */
720 			mrc_alt_write_mask(DDRPHY,
721 				CLKDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
722 				(1 << 31) | (0x0c << 16),
723 				0x801f0000);
724 			/* DCOMP PU */
725 			mrc_alt_write_mask(DDRPHY,
726 				CLKDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
727 				(1 << 31) | (0x07 << 16),
728 				0x801f0000);
729 			/* DCOMP PD */
730 			mrc_alt_write_mask(DDRPHY,
731 				CLKDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
732 				(1 << 31) | (0x07 << 16),
733 				0x801f0000);
734 			/* ODTCOMP PU */
735 			mrc_alt_write_mask(DDRPHY,
736 				CLKODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
737 				(1 << 31) | (0x0b << 16),
738 				0x801f0000);
739 			/* ODTCOMP PD */
740 			mrc_alt_write_mask(DDRPHY,
741 				CLKODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
742 				(1 << 31) | (0x0b << 16),
743 				0x801f0000);
744 			/* TCOCOMP PU */
745 			mrc_alt_write_mask(DDRPHY,
746 				CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
747 				1 << 31, 1 << 31);
748 			/* TCOCOMP PD */
749 			mrc_alt_write_mask(DDRPHY,
750 				CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
751 				1 << 31, 1 << 31);
752 
753 			/* CMD COMP Overrides */
754 			/* RCOMP PU */
755 			mrc_alt_write_mask(DDRPHY,
756 				CMDDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
757 				(1 << 31) | (0x0d << 16),
758 				0x803f0000);
759 			/* RCOMP PD */
760 			mrc_alt_write_mask(DDRPHY,
761 				CMDDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
762 				(1 << 31) | (0x0d << 16),
763 				0x803f0000);
764 			/* DCOMP PU */
765 			mrc_alt_write_mask(DDRPHY,
766 				CMDDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
767 				(1 << 31) | (0x0a << 16),
768 				0x801f0000);
769 			/* DCOMP PD */
770 			mrc_alt_write_mask(DDRPHY,
771 				CMDDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
772 				(1 << 31) | (0x0a << 16),
773 				0x801f0000);
774 
775 			/* CTL COMP Overrides */
776 			/* RCOMP PU */
777 			mrc_alt_write_mask(DDRPHY,
778 				CTLDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
779 				(1 << 31) | (0x0d << 16),
780 				0x803f0000);
781 			/* RCOMP PD */
782 			mrc_alt_write_mask(DDRPHY,
783 				CTLDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
784 				(1 << 31) | (0x0d << 16),
785 				0x803f0000);
786 			/* DCOMP PU */
787 			mrc_alt_write_mask(DDRPHY,
788 				CTLDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
789 				(1 << 31) | (0x0a << 16),
790 				0x801f0000);
791 			/* DCOMP PD */
792 			mrc_alt_write_mask(DDRPHY,
793 				CTLDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
794 				(1 << 31) | (0x0a << 16),
795 				0x801f0000);
796 #else
797 			/* DQ TCOCOMP Overrides */
798 			/* TCOCOMP PU */
799 			mrc_alt_write_mask(DDRPHY,
800 				DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
801 				(1 << 31) | (0x1f << 16),
802 				0x801f0000);
803 			/* TCOCOMP PD */
804 			mrc_alt_write_mask(DDRPHY,
805 				DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
806 				(1 << 31) | (0x1f << 16),
807 				0x801f0000);
808 
809 			/* DQS TCOCOMP Overrides */
810 			/* TCOCOMP PU */
811 			mrc_alt_write_mask(DDRPHY,
812 				DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
813 				(1 << 31) | (0x1f << 16),
814 				0x801f0000);
815 			/* TCOCOMP PD */
816 			mrc_alt_write_mask(DDRPHY,
817 				DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
818 				(1 << 31) | (0x1f << 16),
819 				0x801f0000);
820 
821 			/* CLK TCOCOMP Overrides */
822 			/* TCOCOMP PU */
823 			mrc_alt_write_mask(DDRPHY,
824 				CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
825 				(1 << 31) | (0x1f << 16),
826 				0x801f0000);
827 			/* TCOCOMP PD */
828 			mrc_alt_write_mask(DDRPHY,
829 				CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
830 				(1 << 31) | (0x1f << 16),
831 				0x801f0000);
832 #endif
833 
834 			/* program STATIC delays */
835 #ifdef BACKUP_WCMD
836 			set_wcmd(ch, ddr_wcmd[PLATFORM_ID]);
837 #else
838 			set_wcmd(ch, ddr_wclk[PLATFORM_ID] + HALF_CLK);
839 #endif
840 
841 			for (rk = 0; rk < NUM_RANKS; rk++) {
842 				if (mrc_params->rank_enables & (1 << rk)) {
843 					set_wclk(ch, rk, ddr_wclk[PLATFORM_ID]);
844 #ifdef BACKUP_WCTL
845 					set_wctl(ch, rk, ddr_wctl[PLATFORM_ID]);
846 #else
847 					set_wctl(ch, rk, ddr_wclk[PLATFORM_ID] + HALF_CLK);
848 #endif
849 				}
850 			}
851 		}
852 	}
853 
854 	/* COMP (non channel specific) */
855 	/* RCOMP: Dither PU Enable */
856 	mrc_alt_write_mask(DDRPHY, DQANADRVPUCTL, 1 << 30, 1 << 30);
857 	/* RCOMP: Dither PD Enable */
858 	mrc_alt_write_mask(DDRPHY, DQANADRVPDCTL, 1 << 30, 1 << 30);
859 	/* RCOMP: Dither PU Enable */
860 	mrc_alt_write_mask(DDRPHY, CMDANADRVPUCTL, 1 << 30, 1 << 30);
861 	/* RCOMP: Dither PD Enable */
862 	mrc_alt_write_mask(DDRPHY, CMDANADRVPDCTL, 1 << 30, 1 << 30);
863 	/* RCOMP: Dither PU Enable */
864 	mrc_alt_write_mask(DDRPHY, CLKANADRVPUCTL, 1 << 30, 1 << 30);
865 	/* RCOMP: Dither PD Enable */
866 	mrc_alt_write_mask(DDRPHY, CLKANADRVPDCTL, 1 << 30, 1 << 30);
867 	/* RCOMP: Dither PU Enable */
868 	mrc_alt_write_mask(DDRPHY, DQSANADRVPUCTL, 1 << 30, 1 << 30);
869 	/* RCOMP: Dither PD Enable */
870 	mrc_alt_write_mask(DDRPHY, DQSANADRVPDCTL, 1 << 30, 1 << 30);
871 	/* RCOMP: Dither PU Enable */
872 	mrc_alt_write_mask(DDRPHY, CTLANADRVPUCTL, 1 << 30, 1 << 30);
873 	/* RCOMP: Dither PD Enable */
874 	mrc_alt_write_mask(DDRPHY, CTLANADRVPDCTL, 1 << 30, 1 << 30);
875 	/* ODT: Dither PU Enable */
876 	mrc_alt_write_mask(DDRPHY, DQANAODTPUCTL, 1 << 30, 1 << 30);
877 	/* ODT: Dither PD Enable */
878 	mrc_alt_write_mask(DDRPHY, DQANAODTPDCTL, 1 << 30, 1 << 30);
879 	/* ODT: Dither PU Enable */
880 	mrc_alt_write_mask(DDRPHY, CLKANAODTPUCTL, 1 << 30, 1 << 30);
881 	/* ODT: Dither PD Enable */
882 	mrc_alt_write_mask(DDRPHY, CLKANAODTPDCTL, 1 << 30, 1 << 30);
883 	/* ODT: Dither PU Enable */
884 	mrc_alt_write_mask(DDRPHY, DQSANAODTPUCTL, 1 << 30, 1 << 30);
885 	/* ODT: Dither PD Enable */
886 	mrc_alt_write_mask(DDRPHY, DQSANAODTPDCTL, 1 << 30, 1 << 30);
887 	/* DCOMP: Dither PU Enable */
888 	mrc_alt_write_mask(DDRPHY, DQANADLYPUCTL, 1 << 30, 1 << 30);
889 	/* DCOMP: Dither PD Enable */
890 	mrc_alt_write_mask(DDRPHY, DQANADLYPDCTL, 1 << 30, 1 << 30);
891 	/* DCOMP: Dither PU Enable */
892 	mrc_alt_write_mask(DDRPHY, CMDANADLYPUCTL, 1 << 30, 1 << 30);
893 	/* DCOMP: Dither PD Enable */
894 	mrc_alt_write_mask(DDRPHY, CMDANADLYPDCTL, 1 << 30, 1 << 30);
895 	/* DCOMP: Dither PU Enable */
896 	mrc_alt_write_mask(DDRPHY, CLKANADLYPUCTL, 1 << 30, 1 << 30);
897 	/* DCOMP: Dither PD Enable */
898 	mrc_alt_write_mask(DDRPHY, CLKANADLYPDCTL, 1 << 30, 1 << 30);
899 	/* DCOMP: Dither PU Enable */
900 	mrc_alt_write_mask(DDRPHY, DQSANADLYPUCTL, 1 << 30, 1 << 30);
901 	/* DCOMP: Dither PD Enable */
902 	mrc_alt_write_mask(DDRPHY, DQSANADLYPDCTL, 1 << 30, 1 << 30);
903 	/* DCOMP: Dither PU Enable */
904 	mrc_alt_write_mask(DDRPHY, CTLANADLYPUCTL, 1 << 30, 1 << 30);
905 	/* DCOMP: Dither PD Enable */
906 	mrc_alt_write_mask(DDRPHY, CTLANADLYPDCTL, 1 << 30, 1 << 30);
907 	/* TCO: Dither PU Enable */
908 	mrc_alt_write_mask(DDRPHY, DQANATCOPUCTL, 1 << 30, 1 << 30);
909 	/* TCO: Dither PD Enable */
910 	mrc_alt_write_mask(DDRPHY, DQANATCOPDCTL, 1 << 30, 1 << 30);
911 	/* TCO: Dither PU Enable */
912 	mrc_alt_write_mask(DDRPHY, CLKANATCOPUCTL, 1 << 30, 1 << 30);
913 	/* TCO: Dither PD Enable */
914 	mrc_alt_write_mask(DDRPHY, CLKANATCOPDCTL, 1 << 30, 1 << 30);
915 	/* TCO: Dither PU Enable */
916 	mrc_alt_write_mask(DDRPHY, DQSANATCOPUCTL, 1 << 30, 1 << 30);
917 	/* TCO: Dither PD Enable */
918 	mrc_alt_write_mask(DDRPHY, DQSANATCOPDCTL, 1 << 30, 1 << 30);
919 	/* TCOCOMP: Pulse Count */
920 	mrc_alt_write_mask(DDRPHY, TCOCNTCTRL, 1, 3);
921 	/* ODT: CMD/CTL PD/PU */
922 	mrc_alt_write_mask(DDRPHY, CHNLBUFSTATIC,
923 		(0x03 << 24) | (0x03 << 16), 0x1f1f0000);
924 	/* Set 1us counter */
925 	mrc_alt_write_mask(DDRPHY, MSCNTR, 0x64, 0xff);
926 	mrc_alt_write_mask(DDRPHY, LATCH1CTL, 0x1 << 28, 0x70000000);
927 
928 	/* Release PHY from reset */
929 	mrc_alt_write_mask(DDRPHY, MASTERRSTN, 1, 1);
930 
931 	/* STEP1 */
932 	mrc_post_code(0x03, 0x11);
933 
934 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
935 		if (mrc_params->channel_enables & (1 << ch)) {
936 			/* DQ01-DQ23 */
937 			for (bl_grp = 0;
938 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
939 			     bl_grp++) {
940 				mrc_alt_write_mask(DDRPHY,
941 					DQMDLLCTL +
942 					bl_grp * DDRIODQ_BL_OFFSET +
943 					ch * DDRIODQ_CH_OFFSET,
944 					1 << 13,
945 					1 << 13);	/* Enable VREG */
946 				delay_n(3);
947 			}
948 
949 			/* ECC */
950 			mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
951 				1 << 13, 1 << 13);	/* Enable VREG */
952 			delay_n(3);
953 			/* CMD */
954 			mrc_alt_write_mask(DDRPHY,
955 				CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
956 				1 << 13, 1 << 13);	/* Enable VREG */
957 			delay_n(3);
958 			/* CLK-CTL */
959 			mrc_alt_write_mask(DDRPHY,
960 				CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
961 				1 << 13, 1 << 13);	/* Enable VREG */
962 			delay_n(3);
963 		}
964 	}
965 
966 	/* STEP2 */
967 	mrc_post_code(0x03, 0x12);
968 	delay_n(200);
969 
970 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
971 		if (mrc_params->channel_enables & (1 << ch)) {
972 			/* DQ01-DQ23 */
973 			for (bl_grp = 0;
974 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
975 			     bl_grp++) {
976 				mrc_alt_write_mask(DDRPHY,
977 					DQMDLLCTL +
978 					bl_grp * DDRIODQ_BL_OFFSET +
979 					ch * DDRIODQ_CH_OFFSET,
980 					1 << 17,
981 					1 << 17);	/* Enable MCDLL */
982 				delay_n(50);
983 			}
984 
985 		/* ECC */
986 		mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
987 			1 << 17, 1 << 17);	/* Enable MCDLL */
988 		delay_n(50);
989 		/* CMD */
990 		mrc_alt_write_mask(DDRPHY,
991 			CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
992 			1 << 18, 1 << 18);	/* Enable MCDLL */
993 		delay_n(50);
994 		/* CLK-CTL */
995 		mrc_alt_write_mask(DDRPHY,
996 			CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
997 			1 << 18, 1 << 18);	/* Enable MCDLL */
998 		delay_n(50);
999 		}
1000 	}
1001 
1002 	/* STEP3: */
1003 	mrc_post_code(0x03, 0x13);
1004 	delay_n(100);
1005 
1006 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1007 		if (mrc_params->channel_enables & (1 << ch)) {
1008 			/* DQ01-DQ23 */
1009 			for (bl_grp = 0;
1010 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
1011 			     bl_grp++) {
1012 #ifdef FORCE_16BIT_DDRIO
1013 				temp = (bl_grp &&
1014 					(mrc_params->channel_width == X16)) ?
1015 					0x11ff : 0xffff;
1016 #else
1017 				temp = 0xffff;
1018 #endif
1019 				/* Enable TXDLL */
1020 				mrc_alt_write_mask(DDRPHY,
1021 					DQDLLTXCTL +
1022 					bl_grp * DDRIODQ_BL_OFFSET +
1023 					ch * DDRIODQ_CH_OFFSET,
1024 					temp, 0xffff);
1025 				delay_n(3);
1026 				/* Enable RXDLL */
1027 				mrc_alt_write_mask(DDRPHY,
1028 					DQDLLRXCTL +
1029 					bl_grp * DDRIODQ_BL_OFFSET +
1030 					ch * DDRIODQ_CH_OFFSET,
1031 					0xf, 0xf);
1032 				delay_n(3);
1033 				/* Enable RXDLL Overrides BL0 */
1034 				mrc_alt_write_mask(DDRPHY,
1035 					B0OVRCTL +
1036 					bl_grp * DDRIODQ_BL_OFFSET +
1037 					ch * DDRIODQ_CH_OFFSET,
1038 					0xf, 0xf);
1039 			}
1040 
1041 			/* ECC */
1042 			temp = 0xffff;
1043 			mrc_alt_write_mask(DDRPHY, ECCDLLTXCTL,
1044 				temp, 0xffff);
1045 			delay_n(3);
1046 
1047 			/* CMD (PO) */
1048 			mrc_alt_write_mask(DDRPHY,
1049 				CMDDLLTXCTL + ch * DDRIOCCC_CH_OFFSET,
1050 				temp, 0xffff);
1051 			delay_n(3);
1052 		}
1053 	}
1054 
1055 	/* STEP4 */
1056 	mrc_post_code(0x03, 0x14);
1057 
1058 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1059 		if (mrc_params->channel_enables & (1 << ch)) {
1060 			/* Host To Memory Clock Alignment (HMC) for 800/1066 */
1061 			for (bl_grp = 0;
1062 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
1063 			     bl_grp++) {
1064 				/* CLK_ALIGN_MOD_ID */
1065 				mrc_alt_write_mask(DDRPHY,
1066 					DQCLKALIGNREG2 +
1067 					bl_grp * DDRIODQ_BL_OFFSET +
1068 					ch * DDRIODQ_CH_OFFSET,
1069 					bl_grp ? 3 : 1,
1070 					0xf);
1071 			}
1072 
1073 			mrc_alt_write_mask(DDRPHY,
1074 				ECCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1075 				0x2, 0xf);
1076 			mrc_alt_write_mask(DDRPHY,
1077 				CMDCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1078 				0x0, 0xf);
1079 			mrc_alt_write_mask(DDRPHY,
1080 				CCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1081 				0x2, 0xf);
1082 			mrc_alt_write_mask(DDRPHY,
1083 				CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1084 				0x20, 0x30);
1085 			/*
1086 			 * NUM_SAMPLES, MAX_SAMPLES,
1087 			 * MACRO_PI_STEP, MICRO_PI_STEP
1088 			 */
1089 			mrc_alt_write_mask(DDRPHY,
1090 				CMDCLKALIGNREG1 + ch * DDRIOCCC_CH_OFFSET,
1091 				(0x18 << 16) | (0x10 << 8) |
1092 				(0x8 << 2) | (0x1 << 0),
1093 				0x007f7fff);
1094 			/* TOTAL_NUM_MODULES, FIRST_U_PARTITION */
1095 			mrc_alt_write_mask(DDRPHY,
1096 				CMDCLKALIGNREG2 + ch * DDRIOCCC_CH_OFFSET,
1097 				(0x10 << 16) | (0x4 << 8) | (0x2 << 4),
1098 				0x001f0ff0);
1099 #ifdef HMC_TEST
1100 			/* START_CLK_ALIGN=1 */
1101 			mrc_alt_write_mask(DDRPHY,
1102 				CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1103 				1 << 24, 1 << 24);
1104 			while (msg_port_alt_read(DDRPHY,
1105 				CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET) &
1106 				(1 << 24))
1107 				;	/* wait for START_CLK_ALIGN=0 */
1108 #endif
1109 
1110 			/* Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN */
1111 			mrc_alt_write_mask(DDRPHY,
1112 				CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
1113 				1, 1);	/* WRPTRENABLE=1 */
1114 
1115 			/* COMP initial */
1116 			/* enable bypass for CLK buffer (PO) */
1117 			mrc_alt_write_mask(DDRPHY,
1118 				COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1119 				1 << 5, 1 << 5);
1120 			/* Initial COMP Enable */
1121 			mrc_alt_write_mask(DDRPHY, CMPCTRL, 1, 1);
1122 			/* wait for Initial COMP Enable = 0 */
1123 			while (msg_port_alt_read(DDRPHY, CMPCTRL) & 1)
1124 				;
1125 			/* disable bypass for CLK buffer (PO) */
1126 			mrc_alt_write_mask(DDRPHY,
1127 				COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1128 				~(1 << 5), 1 << 5);
1129 
1130 			/* IOBUFACT */
1131 
1132 			/* STEP4a */
1133 			mrc_alt_write_mask(DDRPHY,
1134 				CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
1135 				1 << 2, 1 << 2);	/* IOBUFACTRST_N=1 */
1136 
1137 			/* DDRPHY initialization complete */
1138 			mrc_alt_write_mask(DDRPHY,
1139 				CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
1140 				1 << 20, 1 << 20);	/* SPID_INIT_COMPLETE=1 */
1141 		}
1142 	}
1143 
1144 	LEAVEFN();
1145 }
1146 
1147 /* This function performs JEDEC initialization on all enabled channels */
perform_jedec_init(struct mrc_params * mrc_params)1148 void perform_jedec_init(struct mrc_params *mrc_params)
1149 {
1150 	uint8_t twr, wl, rank;
1151 	uint32_t tck;
1152 	u32 dtr0;
1153 	u32 drp;
1154 	u32 drmc;
1155 	u32 mrs0_cmd = 0;
1156 	u32 emrs1_cmd = 0;
1157 	u32 emrs2_cmd = 0;
1158 	u32 emrs3_cmd = 0;
1159 
1160 	ENTERFN();
1161 
1162 	/* jedec_init starts */
1163 	mrc_post_code(0x04, 0x00);
1164 
1165 	/* DDR3_RESET_SET=0, DDR3_RESET_RESET=1 */
1166 	mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 2, 0x102);
1167 
1168 	/* Assert RESET# for 200us */
1169 	delay_u(200);
1170 
1171 	/* DDR3_RESET_SET=1, DDR3_RESET_RESET=0 */
1172 	mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 0x100, 0x102);
1173 
1174 	dtr0 = msg_port_read(MEM_CTLR, DTR0);
1175 
1176 	/*
1177 	 * Set CKEVAL for populated ranks
1178 	 * then send NOP to each rank (#4550197)
1179 	 */
1180 
1181 	drp = msg_port_read(MEM_CTLR, DRP);
1182 	drp &= 0x3;
1183 
1184 	drmc = msg_port_read(MEM_CTLR, DRMC);
1185 	drmc &= 0xfffffffc;
1186 	drmc |= (DRMC_CKEMODE | drp);
1187 
1188 	msg_port_write(MEM_CTLR, DRMC, drmc);
1189 
1190 	for (rank = 0; rank < NUM_RANKS; rank++) {
1191 		/* Skip to next populated rank */
1192 		if ((mrc_params->rank_enables & (1 << rank)) == 0)
1193 			continue;
1194 
1195 		dram_init_command(DCMD_NOP(rank));
1196 	}
1197 
1198 	msg_port_write(MEM_CTLR, DRMC,
1199 		(mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0));
1200 
1201 	/*
1202 	 * setup for emrs 2
1203 	 * BIT[15:11] --> Always "0"
1204 	 * BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
1205 	 * BIT[08]    --> Always "0"
1206 	 * BIT[07]    --> SRT: use sr_temp_range
1207 	 * BIT[06]    --> ASR: want "Manual SR Reference" (0)
1208 	 * BIT[05:03] --> CWL: use oem_tCWL
1209 	 * BIT[02:00] --> PASR: want "Full Array" (0)
1210 	 */
1211 	emrs2_cmd |= (2 << 3);
1212 	wl = 5 + mrc_params->ddr_speed;
1213 	emrs2_cmd |= ((wl - 5) << 9);
1214 	emrs2_cmd |= (mrc_params->sr_temp_range << 13);
1215 
1216 	/*
1217 	 * setup for emrs 3
1218 	 * BIT[15:03] --> Always "0"
1219 	 * BIT[02]    --> MPR: want "Normal Operation" (0)
1220 	 * BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
1221 	 */
1222 	emrs3_cmd |= (3 << 3);
1223 
1224 	/*
1225 	 * setup for emrs 1
1226 	 * BIT[15:13]     --> Always "0"
1227 	 * BIT[12:12]     --> Qoff: want "Output Buffer Enabled" (0)
1228 	 * BIT[11:11]     --> TDQS: want "Disabled" (0)
1229 	 * BIT[10:10]     --> Always "0"
1230 	 * BIT[09,06,02]  --> Rtt_nom: use rtt_nom_value
1231 	 * BIT[08]        --> Always "0"
1232 	 * BIT[07]        --> WR_LVL: want "Disabled" (0)
1233 	 * BIT[05,01]     --> DIC: use ron_value
1234 	 * BIT[04:03]     --> AL: additive latency want "0" (0)
1235 	 * BIT[00]        --> DLL: want "Enable" (0)
1236 	 *
1237 	 * (BIT5|BIT1) set Ron value
1238 	 * 00 --> RZQ/6 (40ohm)
1239 	 * 01 --> RZQ/7 (34ohm)
1240 	 * 1* --> RESERVED
1241 	 *
1242 	 * (BIT9|BIT6|BIT2) set Rtt_nom value
1243 	 * 000 --> Disabled
1244 	 * 001 --> RZQ/4 ( 60ohm)
1245 	 * 010 --> RZQ/2 (120ohm)
1246 	 * 011 --> RZQ/6 ( 40ohm)
1247 	 * 1** --> RESERVED
1248 	 */
1249 	emrs1_cmd |= (1 << 3);
1250 	emrs1_cmd &= ~(1 << 6);
1251 
1252 	if (mrc_params->ron_value == 0)
1253 		emrs1_cmd |= (1 << 7);
1254 	else
1255 		emrs1_cmd &= ~(1 << 7);
1256 
1257 	if (mrc_params->rtt_nom_value == 0)
1258 		emrs1_cmd |= (DDR3_EMRS1_RTTNOM_40 << 6);
1259 	else if (mrc_params->rtt_nom_value == 1)
1260 		emrs1_cmd |= (DDR3_EMRS1_RTTNOM_60 << 6);
1261 	else if (mrc_params->rtt_nom_value == 2)
1262 		emrs1_cmd |= (DDR3_EMRS1_RTTNOM_120 << 6);
1263 
1264 	/* save MRS1 value (excluding control fields) */
1265 	mrc_params->mrs1 = emrs1_cmd >> 6;
1266 
1267 	/*
1268 	 * setup for mrs 0
1269 	 * BIT[15:13]     --> Always "0"
1270 	 * BIT[12]        --> PPD: for Quark (1)
1271 	 * BIT[11:09]     --> WR: use oem_tWR
1272 	 * BIT[08]        --> DLL: want "Reset" (1, self clearing)
1273 	 * BIT[07]        --> MODE: want "Normal" (0)
1274 	 * BIT[06:04,02]  --> CL: use oem_tCAS
1275 	 * BIT[03]        --> RD_BURST_TYPE: want "Interleave" (1)
1276 	 * BIT[01:00]     --> BL: want "8 Fixed" (0)
1277 	 * WR:
1278 	 * 0 --> 16
1279 	 * 1 --> 5
1280 	 * 2 --> 6
1281 	 * 3 --> 7
1282 	 * 4 --> 8
1283 	 * 5 --> 10
1284 	 * 6 --> 12
1285 	 * 7 --> 14
1286 	 * CL:
1287 	 * BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
1288 	 * BIT[06:04] use oem_tCAS-4
1289 	 */
1290 	mrs0_cmd |= (1 << 14);
1291 	mrs0_cmd |= (1 << 18);
1292 	mrs0_cmd |= ((((dtr0 >> 12) & 7) + 1) << 10);
1293 
1294 	tck = t_ck[mrc_params->ddr_speed];
1295 	/* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
1296 	twr = MCEIL(15000, tck);
1297 	mrs0_cmd |= ((twr - 4) << 15);
1298 
1299 	for (rank = 0; rank < NUM_RANKS; rank++) {
1300 		/* Skip to next populated rank */
1301 		if ((mrc_params->rank_enables & (1 << rank)) == 0)
1302 			continue;
1303 
1304 		emrs2_cmd |= (rank << 22);
1305 		dram_init_command(emrs2_cmd);
1306 
1307 		emrs3_cmd |= (rank << 22);
1308 		dram_init_command(emrs3_cmd);
1309 
1310 		emrs1_cmd |= (rank << 22);
1311 		dram_init_command(emrs1_cmd);
1312 
1313 		mrs0_cmd |= (rank << 22);
1314 		dram_init_command(mrs0_cmd);
1315 
1316 		dram_init_command(DCMD_ZQCL(rank));
1317 	}
1318 
1319 	LEAVEFN();
1320 }
1321 
1322 /*
1323  * Dunit Initialization Complete
1324  *
1325  * Indicates that initialization of the Dunit has completed.
1326  *
1327  * Memory accesses are permitted and maintenance operation begins.
1328  * Until this bit is set to a 1, the memory controller will not accept
1329  * DRAM requests from the MEMORY_MANAGER or HTE.
1330  */
set_ddr_init_complete(struct mrc_params * mrc_params)1331 void set_ddr_init_complete(struct mrc_params *mrc_params)
1332 {
1333 	u32 dco;
1334 
1335 	ENTERFN();
1336 
1337 	dco = msg_port_read(MEM_CTLR, DCO);
1338 	dco &= ~DCO_PMICTL;
1339 	dco |= DCO_IC;
1340 	msg_port_write(MEM_CTLR, DCO, dco);
1341 
1342 	LEAVEFN();
1343 }
1344 
1345 /*
1346  * This function will retrieve relevant timing data
1347  *
1348  * This data will be used on subsequent boots to speed up boot times
1349  * and is required for Suspend To RAM capabilities.
1350  */
restore_timings(struct mrc_params * mrc_params)1351 void restore_timings(struct mrc_params *mrc_params)
1352 {
1353 	uint8_t ch, rk, bl;
1354 	const struct mrc_timings *mt = &mrc_params->timings;
1355 
1356 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1357 		for (rk = 0; rk < NUM_RANKS; rk++) {
1358 			for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1359 				set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]);
1360 				set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]);
1361 				set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]);
1362 				set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);
1363 				if (rk == 0) {
1364 					/* VREF (RANK0 only) */
1365 					set_vref(ch, bl, mt->vref[ch][bl]);
1366 				}
1367 			}
1368 			set_wctl(ch, rk, mt->wctl[ch][rk]);
1369 		}
1370 		set_wcmd(ch, mt->wcmd[ch]);
1371 	}
1372 }
1373 
1374 /*
1375  * Configure default settings normally set as part of read training
1376  *
1377  * Some defaults have to be set earlier as they may affect earlier
1378  * training steps.
1379  */
default_timings(struct mrc_params * mrc_params)1380 void default_timings(struct mrc_params *mrc_params)
1381 {
1382 	uint8_t ch, rk, bl;
1383 
1384 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1385 		for (rk = 0; rk < NUM_RANKS; rk++) {
1386 			for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1387 				set_rdqs(ch, rk, bl, 24);
1388 				if (rk == 0) {
1389 					/* VREF (RANK0 only) */
1390 					set_vref(ch, bl, 32);
1391 				}
1392 			}
1393 		}
1394 	}
1395 }
1396 
1397 /*
1398  * This function will perform our RCVEN Calibration Algorithm.
1399  * We will only use the 2xCLK domain timings to perform RCVEN Calibration.
1400  * All byte lanes will be calibrated "simultaneously" per channel per rank.
1401  */
rcvn_cal(struct mrc_params * mrc_params)1402 void rcvn_cal(struct mrc_params *mrc_params)
1403 {
1404 	uint8_t ch;	/* channel counter */
1405 	uint8_t rk;	/* rank counter */
1406 	uint8_t bl;	/* byte lane counter */
1407 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1408 
1409 #ifdef R2R_SHARING
1410 	/* used to find placement for rank2rank sharing configs */
1411 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1412 #ifndef BACKUP_RCVN
1413 	/* used to find placement for rank2rank sharing configs */
1414 	uint32_t num_ranks_enabled = 0;
1415 #endif
1416 #endif
1417 
1418 #ifdef BACKUP_RCVN
1419 #else
1420 	uint32_t temp;
1421 	/* absolute PI value to be programmed on the byte lane */
1422 	uint32_t delay[NUM_BYTE_LANES];
1423 	u32 dtr1, dtr1_save;
1424 #endif
1425 
1426 	ENTERFN();
1427 
1428 	/* rcvn_cal starts */
1429 	mrc_post_code(0x05, 0x00);
1430 
1431 #ifndef BACKUP_RCVN
1432 	/* need separate burst to sample DQS preamble */
1433 	dtr1 = msg_port_read(MEM_CTLR, DTR1);
1434 	dtr1_save = dtr1;
1435 	dtr1 |= DTR1_TCCD_12CLK;
1436 	msg_port_write(MEM_CTLR, DTR1, dtr1);
1437 #endif
1438 
1439 #ifdef R2R_SHARING
1440 	/* need to set "final_delay[][]" elements to "0" */
1441 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1442 #endif
1443 
1444 	/* loop through each enabled channel */
1445 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1446 		if (mrc_params->channel_enables & (1 << ch)) {
1447 			/* perform RCVEN Calibration on a per rank basis */
1448 			for (rk = 0; rk < NUM_RANKS; rk++) {
1449 				if (mrc_params->rank_enables & (1 << rk)) {
1450 					/*
1451 					 * POST_CODE here indicates the current
1452 					 * channel and rank being calibrated
1453 					 */
1454 					mrc_post_code(0x05, 0x10 + ((ch << 4) | rk));
1455 
1456 #ifdef BACKUP_RCVN
1457 					/* et hard-coded timing values */
1458 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++)
1459 						set_rcvn(ch, rk, bl, ddr_rcvn[PLATFORM_ID]);
1460 #else
1461 					/* enable FIFORST */
1462 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1463 						mrc_alt_write_mask(DDRPHY,
1464 							B01PTRCTL1 +
1465 							(bl >> 1) * DDRIODQ_BL_OFFSET +
1466 							ch * DDRIODQ_CH_OFFSET,
1467 							0, 1 << 8);
1468 					}
1469 					/* initialize the starting delay to 128 PI (cas +1 CLK) */
1470 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1471 						/* 1x CLK domain timing is cas-4 */
1472 						delay[bl] = (4 + 1) * FULL_CLK;
1473 
1474 						set_rcvn(ch, rk, bl, delay[bl]);
1475 					}
1476 
1477 					/* now find the rising edge */
1478 					find_rising_edge(mrc_params, delay, ch, rk, true);
1479 
1480 					/* Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse */
1481 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1482 						delay[bl] += QRTR_CLK;
1483 						set_rcvn(ch, rk, bl, delay[bl]);
1484 					}
1485 					/* Now decrement delay by 128 PI (1 CLK) until we sample a "0" */
1486 					do {
1487 						temp = sample_dqs(mrc_params, ch, rk, true);
1488 						for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1489 							if (temp & (1 << bl)) {
1490 								if (delay[bl] >= FULL_CLK) {
1491 									delay[bl] -= FULL_CLK;
1492 									set_rcvn(ch, rk, bl, delay[bl]);
1493 								} else {
1494 									/* not enough delay */
1495 									training_message(ch, rk, bl);
1496 									mrc_post_code(0xee, 0x50);
1497 								}
1498 							}
1499 						}
1500 					} while (temp & 0xff);
1501 
1502 #ifdef R2R_SHARING
1503 					/* increment "num_ranks_enabled" */
1504 					num_ranks_enabled++;
1505 					/* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1506 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1507 						delay[bl] += QRTR_CLK;
1508 						/* add "delay[]" values to "final_delay[][]" for rolling average */
1509 						final_delay[ch][bl] += delay[bl];
1510 						/* set timing based on rolling average values */
1511 						set_rcvn(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
1512 					}
1513 #else
1514 					/* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1515 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1516 						delay[bl] += QRTR_CLK;
1517 						set_rcvn(ch, rk, bl, delay[bl]);
1518 					}
1519 #endif
1520 
1521 					/* disable FIFORST */
1522 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1523 						mrc_alt_write_mask(DDRPHY,
1524 							B01PTRCTL1 +
1525 							(bl >> 1) * DDRIODQ_BL_OFFSET +
1526 							ch * DDRIODQ_CH_OFFSET,
1527 							1 << 8, 1 << 8);
1528 					}
1529 #endif
1530 				}
1531 			}
1532 		}
1533 	}
1534 
1535 #ifndef BACKUP_RCVN
1536 	/* restore original */
1537 	msg_port_write(MEM_CTLR, DTR1, dtr1_save);
1538 #endif
1539 
1540 	LEAVEFN();
1541 }
1542 
1543 /*
1544  * This function will perform the Write Levelling algorithm
1545  * (align WCLK and WDQS).
1546  *
1547  * This algorithm will act on each rank in each channel separately.
1548  */
wr_level(struct mrc_params * mrc_params)1549 void wr_level(struct mrc_params *mrc_params)
1550 {
1551 	uint8_t ch;	/* channel counter */
1552 	uint8_t rk;	/* rank counter */
1553 	uint8_t bl;	/* byte lane counter */
1554 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1555 
1556 #ifdef R2R_SHARING
1557 	/* used to find placement for rank2rank sharing configs */
1558 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1559 #ifndef BACKUP_WDQS
1560 	/* used to find placement for rank2rank sharing configs */
1561 	uint32_t num_ranks_enabled = 0;
1562 #endif
1563 #endif
1564 
1565 #ifdef BACKUP_WDQS
1566 #else
1567 	/* determines stop condition for CRS_WR_LVL */
1568 	bool all_edges_found;
1569 	/* absolute PI value to be programmed on the byte lane */
1570 	uint32_t delay[NUM_BYTE_LANES];
1571 	/*
1572 	 * static makes it so the data is loaded in the heap once by shadow(),
1573 	 * where non-static copies the data onto the stack every time this
1574 	 * function is called
1575 	 */
1576 	uint32_t address;	/* address to be checked during COARSE_WR_LVL */
1577 	u32 dtr4, dtr4_save;
1578 #endif
1579 
1580 	ENTERFN();
1581 
1582 	/* wr_level starts */
1583 	mrc_post_code(0x06, 0x00);
1584 
1585 #ifdef R2R_SHARING
1586 	/* need to set "final_delay[][]" elements to "0" */
1587 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1588 #endif
1589 
1590 	/* loop through each enabled channel */
1591 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1592 		if (mrc_params->channel_enables & (1 << ch)) {
1593 			/* perform WRITE LEVELING algorithm on a per rank basis */
1594 			for (rk = 0; rk < NUM_RANKS; rk++) {
1595 				if (mrc_params->rank_enables & (1 << rk)) {
1596 					/*
1597 					 * POST_CODE here indicates the current
1598 					 * rank and channel being calibrated
1599 					 */
1600 					mrc_post_code(0x06, 0x10 + ((ch << 4) | rk));
1601 
1602 #ifdef BACKUP_WDQS
1603 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1604 						set_wdqs(ch, rk, bl, ddr_wdqs[PLATFORM_ID]);
1605 						set_wdq(ch, rk, bl, ddr_wdqs[PLATFORM_ID] - QRTR_CLK);
1606 					}
1607 #else
1608 					/*
1609 					 * perform a single PRECHARGE_ALL command to
1610 					 * make DRAM state machine go to IDLE state
1611 					 */
1612 					dram_init_command(DCMD_PREA(rk));
1613 
1614 					/*
1615 					 * enable Write Levelling Mode
1616 					 * (EMRS1 w/ Write Levelling Mode Enable)
1617 					 */
1618 					dram_init_command(DCMD_MRS1(rk, 0x82));
1619 
1620 					/*
1621 					 * set ODT DRAM Full Time Termination
1622 					 * disable in MCU
1623 					 */
1624 
1625 					dtr4 = msg_port_read(MEM_CTLR, DTR4);
1626 					dtr4_save = dtr4;
1627 					dtr4 |= DTR4_ODTDIS;
1628 					msg_port_write(MEM_CTLR, DTR4, dtr4);
1629 
1630 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
1631 						/*
1632 						 * Enable Sandy Bridge Mode (WDQ Tri-State) &
1633 						 * Ensure 5 WDQS pulses during Write Leveling
1634 						 */
1635 						mrc_alt_write_mask(DDRPHY,
1636 							DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1637 							0x10000154,
1638 							0x100003fc);
1639 					}
1640 
1641 					/* Write Leveling Mode enabled in IO */
1642 					mrc_alt_write_mask(DDRPHY,
1643 						CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1644 						1 << 16, 1 << 16);
1645 
1646 					/* Initialize the starting delay to WCLK */
1647 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1648 						/*
1649 						 * CLK0 --> RK0
1650 						 * CLK1 --> RK1
1651 						 */
1652 						delay[bl] = get_wclk(ch, rk);
1653 
1654 						set_wdqs(ch, rk, bl, delay[bl]);
1655 					}
1656 
1657 					/* now find the rising edge */
1658 					find_rising_edge(mrc_params, delay, ch, rk, false);
1659 
1660 					/* disable Write Levelling Mode */
1661 					mrc_alt_write_mask(DDRPHY,
1662 						CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1663 						0, 1 << 16);
1664 
1665 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
1666 						/* Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation */
1667 						mrc_alt_write_mask(DDRPHY,
1668 							DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1669 							0x00000154,
1670 							0x100003fc);
1671 					}
1672 
1673 					/* restore original DTR4 */
1674 					msg_port_write(MEM_CTLR, DTR4, dtr4_save);
1675 
1676 					/*
1677 					 * restore original value
1678 					 * (Write Levelling Mode Disable)
1679 					 */
1680 					dram_init_command(DCMD_MRS1(rk, mrc_params->mrs1));
1681 
1682 					/*
1683 					 * perform a single PRECHARGE_ALL command to
1684 					 * make DRAM state machine go to IDLE state
1685 					 */
1686 					dram_init_command(DCMD_PREA(rk));
1687 
1688 					mrc_post_code(0x06, 0x30 + ((ch << 4) | rk));
1689 
1690 					/*
1691 					 * COARSE WRITE LEVEL:
1692 					 * check that we're on the correct clock edge
1693 					 */
1694 
1695 					/* hte reconfiguration request */
1696 					mrc_params->hte_setup = 1;
1697 
1698 					/* start CRS_WR_LVL with WDQS = WDQS + 128 PI */
1699 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1700 						delay[bl] = get_wdqs(ch, rk, bl) + FULL_CLK;
1701 						set_wdqs(ch, rk, bl, delay[bl]);
1702 						/*
1703 						 * program WDQ timings based on WDQS
1704 						 * (WDQ = WDQS - 32 PI)
1705 						 */
1706 						set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
1707 					}
1708 
1709 					/* get an address in the targeted channel/rank */
1710 					address = get_addr(ch, rk);
1711 					do {
1712 						uint32_t coarse_result = 0x00;
1713 						uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
1714 						/* assume pass */
1715 						all_edges_found = true;
1716 
1717 						mrc_params->hte_setup = 1;
1718 						coarse_result = check_rw_coarse(mrc_params, address);
1719 
1720 						/* check for failures and margin the byte lane back 128 PI (1 CLK) */
1721 						for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1722 							if (coarse_result & (coarse_result_mask << bl)) {
1723 								all_edges_found = false;
1724 								delay[bl] -= FULL_CLK;
1725 								set_wdqs(ch, rk, bl, delay[bl]);
1726 								/* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
1727 								set_wdq(ch, rk, bl, delay[bl] - QRTR_CLK);
1728 							}
1729 						}
1730 					} while (!all_edges_found);
1731 
1732 #ifdef R2R_SHARING
1733 					/* increment "num_ranks_enabled" */
1734 					 num_ranks_enabled++;
1735 					/* accumulate "final_delay[][]" values from "delay[]" values for rolling average */
1736 					for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1737 						final_delay[ch][bl] += delay[bl];
1738 						set_wdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
1739 						/* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
1740 						set_wdq(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled - QRTR_CLK);
1741 					}
1742 #endif
1743 #endif
1744 				}
1745 			}
1746 		}
1747 	}
1748 
1749 	LEAVEFN();
1750 }
1751 
prog_page_ctrl(struct mrc_params * mrc_params)1752 void prog_page_ctrl(struct mrc_params *mrc_params)
1753 {
1754 	u32 dpmc0;
1755 
1756 	ENTERFN();
1757 
1758 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
1759 	dpmc0 &= ~DPMC0_PCLSTO_MASK;
1760 	dpmc0 |= (4 << 16);
1761 	dpmc0 |= DPMC0_PREAPWDEN;
1762 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
1763 }
1764 
1765 /*
1766  * This function will perform the READ TRAINING Algorithm on all
1767  * channels/ranks/byte_lanes simultaneously to minimize execution time.
1768  *
1769  * The idea here is to train the VREF and RDQS (and eventually RDQ) values
1770  * to achieve maximum READ margins. The algorithm will first determine the
1771  * X coordinate (RDQS setting). This is done by collapsing the VREF eye
1772  * until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
1773  * Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX,
1774  * then average those; this will be the final X coordinate. The algorithm
1775  * will then determine the Y coordinate (VREF setting). This is done by
1776  * collapsing the RDQS eye until we find a minimum required VREF eye for
1777  * RDQS_MIN and RDQS_MAX. Then we take the averages of the VREF eye at
1778  * RDQS_MIN and RDQS_MAX, then average those; this will be the final Y
1779  * coordinate.
1780  *
1781  * NOTE: this algorithm assumes the eye curves have a one-to-one relationship,
1782  * meaning for each X the curve has only one Y and vice-a-versa.
1783  */
rd_train(struct mrc_params * mrc_params)1784 void rd_train(struct mrc_params *mrc_params)
1785 {
1786 	uint8_t ch;	/* channel counter */
1787 	uint8_t rk;	/* rank counter */
1788 	uint8_t bl;	/* byte lane counter */
1789 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1790 #ifdef BACKUP_RDQS
1791 #else
1792 	uint8_t side_x;	/* tracks LEFT/RIGHT approach vectors */
1793 	uint8_t side_y;	/* tracks BOTTOM/TOP approach vectors */
1794 	/* X coordinate data (passing RDQS values) for approach vectors */
1795 	uint8_t x_coordinate[2][2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1796 	/* Y coordinate data (passing VREF values) for approach vectors */
1797 	uint8_t y_coordinate[2][2][NUM_CHANNELS][NUM_BYTE_LANES];
1798 	/* centered X (RDQS) */
1799 	uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1800 	/* centered Y (VREF) */
1801 	uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES];
1802 	uint32_t address;	/* target address for check_bls_ex() */
1803 	uint32_t result;	/* result of check_bls_ex() */
1804 	uint32_t bl_mask;	/* byte lane mask for result checking */
1805 #ifdef R2R_SHARING
1806 	/* used to find placement for rank2rank sharing configs */
1807 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1808 	/* used to find placement for rank2rank sharing configs */
1809 	uint32_t num_ranks_enabled = 0;
1810 #endif
1811 #endif
1812 
1813 	/* rd_train starts */
1814 	mrc_post_code(0x07, 0x00);
1815 
1816 	ENTERFN();
1817 
1818 #ifdef BACKUP_RDQS
1819 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1820 		if (mrc_params->channel_enables & (1 << ch)) {
1821 			for (rk = 0; rk < NUM_RANKS; rk++) {
1822 				if (mrc_params->rank_enables & (1 << rk)) {
1823 					for (bl = 0;
1824 					     bl < NUM_BYTE_LANES / bl_divisor;
1825 					     bl++) {
1826 						set_rdqs(ch, rk, bl, ddr_rdqs[PLATFORM_ID]);
1827 					}
1828 				}
1829 			}
1830 		}
1831 	}
1832 #else
1833 	/* initialize x/y_coordinate arrays */
1834 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1835 		if (mrc_params->channel_enables & (1 << ch)) {
1836 			for (rk = 0; rk < NUM_RANKS; rk++) {
1837 				if (mrc_params->rank_enables & (1 << rk)) {
1838 					for (bl = 0;
1839 					     bl < NUM_BYTE_LANES / bl_divisor;
1840 					     bl++) {
1841 						/* x_coordinate */
1842 						x_coordinate[L][B][ch][rk][bl] = RDQS_MIN;
1843 						x_coordinate[R][B][ch][rk][bl] = RDQS_MAX;
1844 						x_coordinate[L][T][ch][rk][bl] = RDQS_MIN;
1845 						x_coordinate[R][T][ch][rk][bl] = RDQS_MAX;
1846 						/* y_coordinate */
1847 						y_coordinate[L][B][ch][bl] = VREF_MIN;
1848 						y_coordinate[R][B][ch][bl] = VREF_MIN;
1849 						y_coordinate[L][T][ch][bl] = VREF_MAX;
1850 						y_coordinate[R][T][ch][bl] = VREF_MAX;
1851 					}
1852 				}
1853 			}
1854 		}
1855 	}
1856 
1857 	/* initialize other variables */
1858 	bl_mask = byte_lane_mask(mrc_params);
1859 	address = get_addr(0, 0);
1860 
1861 #ifdef R2R_SHARING
1862 	/* need to set "final_delay[][]" elements to "0" */
1863 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1864 #endif
1865 
1866 	/* look for passing coordinates */
1867 	for (side_y = B; side_y <= T; side_y++) {
1868 		for (side_x = L; side_x <= R; side_x++) {
1869 			mrc_post_code(0x07, 0x10 + side_y * 2 + side_x);
1870 
1871 			/* find passing values */
1872 			for (ch = 0; ch < NUM_CHANNELS; ch++) {
1873 				if (mrc_params->channel_enables & (0x1 << ch)) {
1874 					for (rk = 0; rk < NUM_RANKS; rk++) {
1875 						if (mrc_params->rank_enables &
1876 							(0x1 << rk)) {
1877 							/* set x/y_coordinate search starting settings */
1878 							for (bl = 0;
1879 							     bl < NUM_BYTE_LANES / bl_divisor;
1880 							     bl++) {
1881 								set_rdqs(ch, rk, bl,
1882 									 x_coordinate[side_x][side_y][ch][rk][bl]);
1883 								set_vref(ch, bl,
1884 									 y_coordinate[side_x][side_y][ch][bl]);
1885 							}
1886 
1887 							/* get an address in the target channel/rank */
1888 							address = get_addr(ch, rk);
1889 
1890 							/* request HTE reconfiguration */
1891 							mrc_params->hte_setup = 1;
1892 
1893 							/* test the settings */
1894 							do {
1895 								/* result[07:00] == failing byte lane (MAX 8) */
1896 								result = check_bls_ex(mrc_params, address);
1897 
1898 								/* check for failures */
1899 								if (result & 0xff) {
1900 									/* at least 1 byte lane failed */
1901 									for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1902 										if (result &
1903 											(bl_mask << bl)) {
1904 											/* adjust the RDQS values accordingly */
1905 											if (side_x == L)
1906 												x_coordinate[L][side_y][ch][rk][bl] += RDQS_STEP;
1907 											else
1908 												x_coordinate[R][side_y][ch][rk][bl] -= RDQS_STEP;
1909 
1910 											/* check that we haven't closed the RDQS_EYE too much */
1911 											if ((x_coordinate[L][side_y][ch][rk][bl] > (RDQS_MAX - MIN_RDQS_EYE)) ||
1912 												(x_coordinate[R][side_y][ch][rk][bl] < (RDQS_MIN + MIN_RDQS_EYE)) ||
1913 												(x_coordinate[L][side_y][ch][rk][bl] ==
1914 												x_coordinate[R][side_y][ch][rk][bl])) {
1915 												/*
1916 												 * not enough RDQS margin available at this VREF
1917 												 * update VREF values accordingly
1918 												 */
1919 												if (side_y == B)
1920 													y_coordinate[side_x][B][ch][bl] += VREF_STEP;
1921 												else
1922 													y_coordinate[side_x][T][ch][bl] -= VREF_STEP;
1923 
1924 												/* check that we haven't closed the VREF_EYE too much */
1925 												if ((y_coordinate[side_x][B][ch][bl] > (VREF_MAX - MIN_VREF_EYE)) ||
1926 													(y_coordinate[side_x][T][ch][bl] < (VREF_MIN + MIN_VREF_EYE)) ||
1927 													(y_coordinate[side_x][B][ch][bl] == y_coordinate[side_x][T][ch][bl])) {
1928 													/* VREF_EYE collapsed below MIN_VREF_EYE */
1929 													training_message(ch, rk, bl);
1930 													mrc_post_code(0xEE, 0x70 + side_y * 2 + side_x);
1931 												} else {
1932 													/* update the VREF setting */
1933 													set_vref(ch, bl, y_coordinate[side_x][side_y][ch][bl]);
1934 													/* reset the X coordinate to begin the search at the new VREF */
1935 													x_coordinate[side_x][side_y][ch][rk][bl] =
1936 														(side_x == L) ? RDQS_MIN : RDQS_MAX;
1937 												}
1938 											}
1939 
1940 											/* update the RDQS setting */
1941 											set_rdqs(ch, rk, bl, x_coordinate[side_x][side_y][ch][rk][bl]);
1942 										}
1943 									}
1944 								}
1945 							} while (result & 0xff);
1946 						}
1947 					}
1948 				}
1949 			}
1950 		}
1951 	}
1952 
1953 	mrc_post_code(0x07, 0x20);
1954 
1955 	/* find final RDQS (X coordinate) & final VREF (Y coordinate) */
1956 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1957 		if (mrc_params->channel_enables & (1 << ch)) {
1958 			for (rk = 0; rk < NUM_RANKS; rk++) {
1959 				if (mrc_params->rank_enables & (1 << rk)) {
1960 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1961 						uint32_t temp1;
1962 						uint32_t temp2;
1963 
1964 						/* x_coordinate */
1965 						DPF(D_INFO,
1966 						    "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n",
1967 						    rk, bl,
1968 						    x_coordinate[L][T][ch][rk][bl],
1969 						    x_coordinate[R][T][ch][rk][bl],
1970 						    x_coordinate[L][B][ch][rk][bl],
1971 						    x_coordinate[R][B][ch][rk][bl]);
1972 
1973 						/* average the TOP side LEFT & RIGHT values */
1974 						temp1 = (x_coordinate[R][T][ch][rk][bl] + x_coordinate[L][T][ch][rk][bl]) / 2;
1975 						/* average the BOTTOM side LEFT & RIGHT values */
1976 						temp2 = (x_coordinate[R][B][ch][rk][bl] + x_coordinate[L][B][ch][rk][bl]) / 2;
1977 						/* average the above averages */
1978 						x_center[ch][rk][bl] = (uint8_t) ((temp1 + temp2) / 2);
1979 
1980 						/* y_coordinate */
1981 						DPF(D_INFO,
1982 						    "VREF R/L eye lane%d : %d-%d %d-%d\n",
1983 						    bl,
1984 						    y_coordinate[R][B][ch][bl],
1985 						    y_coordinate[R][T][ch][bl],
1986 						    y_coordinate[L][B][ch][bl],
1987 						    y_coordinate[L][T][ch][bl]);
1988 
1989 						/* average the RIGHT side TOP & BOTTOM values */
1990 						temp1 = (y_coordinate[R][T][ch][bl] + y_coordinate[R][B][ch][bl]) / 2;
1991 						/* average the LEFT side TOP & BOTTOM values */
1992 						temp2 = (y_coordinate[L][T][ch][bl] + y_coordinate[L][B][ch][bl]) / 2;
1993 						/* average the above averages */
1994 						y_center[ch][bl] = (uint8_t) ((temp1 + temp2) / 2);
1995 					}
1996 				}
1997 			}
1998 		}
1999 	}
2000 
2001 #ifdef RX_EYE_CHECK
2002 	/* perform an eye check */
2003 	for (side_y = B; side_y <= T; side_y++) {
2004 		for (side_x = L; side_x <= R; side_x++) {
2005 			mrc_post_code(0x07, 0x30 + side_y * 2 + side_x);
2006 
2007 			/* update the settings for the eye check */
2008 			for (ch = 0; ch < NUM_CHANNELS; ch++) {
2009 				if (mrc_params->channel_enables & (1 << ch)) {
2010 					for (rk = 0; rk < NUM_RANKS; rk++) {
2011 						if (mrc_params->rank_enables & (1 << rk)) {
2012 							for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2013 								if (side_x == L)
2014 									set_rdqs(ch, rk, bl, x_center[ch][rk][bl] - (MIN_RDQS_EYE / 2));
2015 								else
2016 									set_rdqs(ch, rk, bl, x_center[ch][rk][bl] + (MIN_RDQS_EYE / 2));
2017 
2018 								if (side_y == B)
2019 									set_vref(ch, bl, y_center[ch][bl] - (MIN_VREF_EYE / 2));
2020 								else
2021 									set_vref(ch, bl, y_center[ch][bl] + (MIN_VREF_EYE / 2));
2022 							}
2023 						}
2024 					}
2025 				}
2026 			}
2027 
2028 			/* request HTE reconfiguration */
2029 			mrc_params->hte_setup = 1;
2030 
2031 			/* check the eye */
2032 			if (check_bls_ex(mrc_params, address) & 0xff) {
2033 				/* one or more byte lanes failed */
2034 				mrc_post_code(0xee, 0x74 + side_x * 2 + side_y);
2035 			}
2036 		}
2037 	}
2038 #endif
2039 
2040 	mrc_post_code(0x07, 0x40);
2041 
2042 	/* set final placements */
2043 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2044 		if (mrc_params->channel_enables & (1 << ch)) {
2045 			for (rk = 0; rk < NUM_RANKS; rk++) {
2046 				if (mrc_params->rank_enables & (1 << rk)) {
2047 #ifdef R2R_SHARING
2048 					/* increment "num_ranks_enabled" */
2049 					num_ranks_enabled++;
2050 #endif
2051 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
2052 						/* x_coordinate */
2053 #ifdef R2R_SHARING
2054 						final_delay[ch][bl] += x_center[ch][rk][bl];
2055 						set_rdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
2056 #else
2057 						set_rdqs(ch, rk, bl, x_center[ch][rk][bl]);
2058 #endif
2059 						/* y_coordinate */
2060 						set_vref(ch, bl, y_center[ch][bl]);
2061 					}
2062 				}
2063 			}
2064 		}
2065 	}
2066 #endif
2067 
2068 	LEAVEFN();
2069 }
2070 
2071 /*
2072  * This function will perform the WRITE TRAINING Algorithm on all
2073  * channels/ranks/byte_lanes simultaneously to minimize execution time.
2074  *
2075  * The idea here is to train the WDQ timings to achieve maximum WRITE margins.
2076  * The algorithm will start with WDQ at the current WDQ setting (tracks WDQS
2077  * in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data
2078  * patterns pass. This is because WDQS will be aligned to WCLK by the
2079  * Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window
2080  * of validity.
2081  */
wr_train(struct mrc_params * mrc_params)2082 void wr_train(struct mrc_params *mrc_params)
2083 {
2084 	uint8_t ch;	/* channel counter */
2085 	uint8_t rk;	/* rank counter */
2086 	uint8_t bl;	/* byte lane counter */
2087 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
2088 #ifdef BACKUP_WDQ
2089 #else
2090 	uint8_t side;		/* LEFT/RIGHT side indicator (0=L, 1=R) */
2091 	uint32_t temp;		/* temporary DWORD */
2092 	/* 2 arrays, for L & R side passing delays */
2093 	uint32_t delay[2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
2094 	uint32_t address;	/* target address for check_bls_ex() */
2095 	uint32_t result;	/* result of check_bls_ex() */
2096 	uint32_t bl_mask;	/* byte lane mask for result checking */
2097 #ifdef R2R_SHARING
2098 	/* used to find placement for rank2rank sharing configs */
2099 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
2100 	/* used to find placement for rank2rank sharing configs */
2101 	uint32_t num_ranks_enabled = 0;
2102 #endif
2103 #endif
2104 
2105 	/* wr_train starts */
2106 	mrc_post_code(0x08, 0x00);
2107 
2108 	ENTERFN();
2109 
2110 #ifdef BACKUP_WDQ
2111 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2112 		if (mrc_params->channel_enables & (1 << ch)) {
2113 			for (rk = 0; rk < NUM_RANKS; rk++) {
2114 				if (mrc_params->rank_enables & (1 << rk)) {
2115 					for (bl = 0;
2116 					     bl < NUM_BYTE_LANES / bl_divisor;
2117 					     bl++) {
2118 						set_wdq(ch, rk, bl, ddr_wdq[PLATFORM_ID]);
2119 					}
2120 				}
2121 			}
2122 		}
2123 	}
2124 #else
2125 	/* initialize "delay" */
2126 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2127 		if (mrc_params->channel_enables & (1 << ch)) {
2128 			for (rk = 0; rk < NUM_RANKS; rk++) {
2129 				if (mrc_params->rank_enables & (1 << rk)) {
2130 					for (bl = 0;
2131 					     bl < NUM_BYTE_LANES / bl_divisor;
2132 					     bl++) {
2133 						/*
2134 						 * want to start with
2135 						 * WDQ = (WDQS - QRTR_CLK)
2136 						 * +/- QRTR_CLK
2137 						 */
2138 						temp = get_wdqs(ch, rk, bl) - QRTR_CLK;
2139 						delay[L][ch][rk][bl] = temp - QRTR_CLK;
2140 						delay[R][ch][rk][bl] = temp + QRTR_CLK;
2141 					}
2142 				}
2143 			}
2144 		}
2145 	}
2146 
2147 	/* initialize other variables */
2148 	bl_mask = byte_lane_mask(mrc_params);
2149 	address = get_addr(0, 0);
2150 
2151 #ifdef R2R_SHARING
2152 	/* need to set "final_delay[][]" elements to "0" */
2153 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
2154 #endif
2155 
2156 	/*
2157 	 * start algorithm on the LEFT side and train each channel/bl
2158 	 * until no failures are observed, then repeat for the RIGHT side.
2159 	 */
2160 	for (side = L; side <= R; side++) {
2161 		mrc_post_code(0x08, 0x10 + side);
2162 
2163 		/* set starting values */
2164 		for (ch = 0; ch < NUM_CHANNELS; ch++) {
2165 			if (mrc_params->channel_enables & (1 << ch)) {
2166 				for (rk = 0; rk < NUM_RANKS; rk++) {
2167 					if (mrc_params->rank_enables &
2168 						(1 << rk)) {
2169 						for (bl = 0;
2170 						     bl < NUM_BYTE_LANES / bl_divisor;
2171 						     bl++) {
2172 							set_wdq(ch, rk, bl, delay[side][ch][rk][bl]);
2173 						}
2174 					}
2175 				}
2176 			}
2177 		}
2178 
2179 		/* find passing values */
2180 		for (ch = 0; ch < NUM_CHANNELS; ch++) {
2181 			if (mrc_params->channel_enables & (1 << ch)) {
2182 				for (rk = 0; rk < NUM_RANKS; rk++) {
2183 					if (mrc_params->rank_enables &
2184 						(1 << rk)) {
2185 						/* get an address in the target channel/rank */
2186 						address = get_addr(ch, rk);
2187 
2188 						/* request HTE reconfiguration */
2189 						mrc_params->hte_setup = 1;
2190 
2191 						/* check the settings */
2192 						do {
2193 							/* result[07:00] == failing byte lane (MAX 8) */
2194 							result = check_bls_ex(mrc_params, address);
2195 							/* check for failures */
2196 							if (result & 0xff) {
2197 								/* at least 1 byte lane failed */
2198 								for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2199 									if (result &
2200 										(bl_mask << bl)) {
2201 										if (side == L)
2202 											delay[L][ch][rk][bl] += WDQ_STEP;
2203 										else
2204 											delay[R][ch][rk][bl] -= WDQ_STEP;
2205 
2206 										/* check for algorithm failure */
2207 										if (delay[L][ch][rk][bl] != delay[R][ch][rk][bl]) {
2208 											/*
2209 											 * margin available
2210 											 * update delay setting
2211 											 */
2212 											set_wdq(ch, rk, bl,
2213 												delay[side][ch][rk][bl]);
2214 										} else {
2215 											/*
2216 											 * no margin available
2217 											 * notify the user and halt
2218 											 */
2219 											training_message(ch, rk, bl);
2220 											mrc_post_code(0xee, 0x80 + side);
2221 										}
2222 									}
2223 								}
2224 							}
2225 						/* stop when all byte lanes pass */
2226 						} while (result & 0xff);
2227 					}
2228 				}
2229 			}
2230 		}
2231 	}
2232 
2233 	/* program WDQ to the middle of passing window */
2234 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2235 		if (mrc_params->channel_enables & (1 << ch)) {
2236 			for (rk = 0; rk < NUM_RANKS; rk++) {
2237 				if (mrc_params->rank_enables & (1 << rk)) {
2238 #ifdef R2R_SHARING
2239 					/* increment "num_ranks_enabled" */
2240 					num_ranks_enabled++;
2241 #endif
2242 					for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2243 						DPF(D_INFO,
2244 						    "WDQ eye rank%d lane%d : %d-%d\n",
2245 						    rk, bl,
2246 						    delay[L][ch][rk][bl],
2247 						    delay[R][ch][rk][bl]);
2248 
2249 						temp = (delay[R][ch][rk][bl] + delay[L][ch][rk][bl]) / 2;
2250 
2251 #ifdef R2R_SHARING
2252 						final_delay[ch][bl] += temp;
2253 						set_wdq(ch, rk, bl,
2254 							final_delay[ch][bl] / num_ranks_enabled);
2255 #else
2256 						set_wdq(ch, rk, bl, temp);
2257 #endif
2258 					}
2259 				}
2260 			}
2261 		}
2262 	}
2263 #endif
2264 
2265 	LEAVEFN();
2266 }
2267 
2268 /*
2269  * This function will store relevant timing data
2270  *
2271  * This data will be used on subsequent boots to speed up boot times
2272  * and is required for Suspend To RAM capabilities.
2273  */
store_timings(struct mrc_params * mrc_params)2274 void store_timings(struct mrc_params *mrc_params)
2275 {
2276 	uint8_t ch, rk, bl;
2277 	struct mrc_timings *mt = &mrc_params->timings;
2278 
2279 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2280 		for (rk = 0; rk < NUM_RANKS; rk++) {
2281 			for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
2282 				mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl);
2283 				mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl);
2284 				mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl);
2285 				mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);
2286 
2287 				if (rk == 0)
2288 					mt->vref[ch][bl] = get_vref(ch, bl);
2289 			}
2290 
2291 			mt->wctl[ch][rk] = get_wctl(ch, rk);
2292 		}
2293 
2294 		mt->wcmd[ch] = get_wcmd(ch);
2295 	}
2296 
2297 	/* need to save for a case of changing frequency after warm reset */
2298 	mt->ddr_speed = mrc_params->ddr_speed;
2299 }
2300 
2301 /*
2302  * The purpose of this function is to ensure the SEC comes out of reset
2303  * and IA initiates the SEC enabling Memory Scrambling.
2304  */
enable_scrambling(struct mrc_params * mrc_params)2305 void enable_scrambling(struct mrc_params *mrc_params)
2306 {
2307 	uint32_t lfsr = 0;
2308 	uint8_t i;
2309 
2310 	if (mrc_params->scrambling_enables == 0)
2311 		return;
2312 
2313 	ENTERFN();
2314 
2315 	/* 32 bit seed is always stored in BIOS NVM */
2316 	lfsr = mrc_params->timings.scrambler_seed;
2317 
2318 	if (mrc_params->boot_mode == BM_COLD) {
2319 		/*
2320 		 * factory value is 0 and in first boot,
2321 		 * a clock based seed is loaded.
2322 		 */
2323 		if (lfsr == 0) {
2324 			/*
2325 			 * get seed from system clock
2326 			 * and make sure it is not all 1's
2327 			 */
2328 			lfsr = rdtsc() & 0x0fffffff;
2329 		} else {
2330 			/*
2331 			 * Need to replace scrambler
2332 			 *
2333 			 * get next 32bit LFSR 16 times which is the last
2334 			 * part of the previous scrambler vector
2335 			 */
2336 			for (i = 0; i < 16; i++)
2337 				lfsr32(&lfsr);
2338 		}
2339 
2340 		/* save new seed */
2341 		mrc_params->timings.scrambler_seed = lfsr;
2342 	}
2343 
2344 	/*
2345 	 * In warm boot or S3 exit, we have the previous seed.
2346 	 * In cold boot, we have the last 32bit LFSR which is the new seed.
2347 	 */
2348 	lfsr32(&lfsr);	/* shift to next value */
2349 	msg_port_write(MEM_CTLR, SCRMSEED, (lfsr & 0x0003ffff));
2350 
2351 	for (i = 0; i < 2; i++)
2352 		msg_port_write(MEM_CTLR, SCRMLO + i, (lfsr & 0xaaaaaaaa));
2353 
2354 	LEAVEFN();
2355 }
2356 
2357 /*
2358  * Configure MCU Power Management Control Register
2359  * and Scheduler Control Register
2360  */
prog_ddr_control(struct mrc_params * mrc_params)2361 void prog_ddr_control(struct mrc_params *mrc_params)
2362 {
2363 	u32 dsch;
2364 	u32 dpmc0;
2365 
2366 	ENTERFN();
2367 
2368 	dsch = msg_port_read(MEM_CTLR, DSCH);
2369 	dsch &= ~(DSCH_OOODIS | DSCH_OOOST3DIS | DSCH_NEWBYPDIS);
2370 	msg_port_write(MEM_CTLR, DSCH, dsch);
2371 
2372 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
2373 	dpmc0 &= ~DPMC0_DISPWRDN;
2374 	dpmc0 |= (mrc_params->power_down_disable << 25);
2375 	dpmc0 &= ~DPMC0_CLKGTDIS;
2376 	dpmc0 &= ~DPMC0_PCLSTO_MASK;
2377 	dpmc0 |= (4 << 16);
2378 	dpmc0 |= DPMC0_PREAPWDEN;
2379 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2380 
2381 	/* CMDTRIST = 2h - CMD/ADDR are tristated when no valid command */
2382 	mrc_write_mask(MEM_CTLR, DPMC1, 0x20, 0x30);
2383 
2384 	LEAVEFN();
2385 }
2386 
2387 /*
2388  * After training complete configure MCU Rank Population Register
2389  * specifying: ranks enabled, device width, density, address mode
2390  */
prog_dra_drb(struct mrc_params * mrc_params)2391 void prog_dra_drb(struct mrc_params *mrc_params)
2392 {
2393 	u32 drp;
2394 	u32 dco;
2395 	u8 density = mrc_params->params.density;
2396 
2397 	ENTERFN();
2398 
2399 	dco = msg_port_read(MEM_CTLR, DCO);
2400 	dco &= ~DCO_IC;
2401 	msg_port_write(MEM_CTLR, DCO, dco);
2402 
2403 	drp = 0;
2404 	if (mrc_params->rank_enables & 1)
2405 		drp |= DRP_RKEN0;
2406 	if (mrc_params->rank_enables & 2)
2407 		drp |= DRP_RKEN1;
2408 	if (mrc_params->dram_width == X16) {
2409 		drp |= (1 << 4);
2410 		drp |= (1 << 9);
2411 	}
2412 
2413 	/*
2414 	 * Density encoding in struct dram_params: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
2415 	 * has to be mapped RANKDENSx encoding (0=1Gb)
2416 	 */
2417 	if (density == 0)
2418 		density = 4;
2419 
2420 	drp |= ((density - 1) << 6);
2421 	drp |= ((density - 1) << 11);
2422 
2423 	/* Address mode can be overwritten if ECC enabled */
2424 	drp |= (mrc_params->address_mode << 14);
2425 
2426 	msg_port_write(MEM_CTLR, DRP, drp);
2427 
2428 	dco &= ~DCO_PMICTL;
2429 	dco |= DCO_IC;
2430 	msg_port_write(MEM_CTLR, DCO, dco);
2431 
2432 	LEAVEFN();
2433 }
2434 
2435 /* Send DRAM wake command */
perform_wake(struct mrc_params * mrc_params)2436 void perform_wake(struct mrc_params *mrc_params)
2437 {
2438 	ENTERFN();
2439 
2440 	dram_wake_command();
2441 
2442 	LEAVEFN();
2443 }
2444 
2445 /*
2446  * Configure refresh rate and short ZQ calibration interval
2447  * Activate dynamic self refresh
2448  */
change_refresh_period(struct mrc_params * mrc_params)2449 void change_refresh_period(struct mrc_params *mrc_params)
2450 {
2451 	u32 drfc;
2452 	u32 dcal;
2453 	u32 dpmc0;
2454 
2455 	ENTERFN();
2456 
2457 	drfc = msg_port_read(MEM_CTLR, DRFC);
2458 	drfc &= ~DRFC_TREFI_MASK;
2459 	drfc |= (mrc_params->refresh_rate << 12);
2460 	drfc |= DRFC_REFDBTCLR;
2461 	msg_port_write(MEM_CTLR, DRFC, drfc);
2462 
2463 	dcal = msg_port_read(MEM_CTLR, DCAL);
2464 	dcal &= ~DCAL_ZQCINT_MASK;
2465 	dcal |= (3 << 8);	/* 63ms */
2466 	msg_port_write(MEM_CTLR, DCAL, dcal);
2467 
2468 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
2469 	dpmc0 |= (DPMC0_DYNSREN | DPMC0_ENPHYCLKGATE);
2470 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2471 
2472 	LEAVEFN();
2473 }
2474 
2475 /*
2476  * Configure DDRPHY for Auto-Refresh, Periodic Compensations,
2477  * Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
2478  */
set_auto_refresh(struct mrc_params * mrc_params)2479 void set_auto_refresh(struct mrc_params *mrc_params)
2480 {
2481 	uint32_t channel;
2482 	uint32_t rank;
2483 	uint32_t bl;
2484 	uint32_t bl_divisor = 1;
2485 	uint32_t temp;
2486 
2487 	ENTERFN();
2488 
2489 	/*
2490 	 * Enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp,
2491 	 * ZQSPERIOD, Auto-Precharge, CKE Power-Down
2492 	 */
2493 	for (channel = 0; channel < NUM_CHANNELS; channel++) {
2494 		if (mrc_params->channel_enables & (1 << channel)) {
2495 			/* Enable Periodic RCOMPS */
2496 			mrc_alt_write_mask(DDRPHY, CMPCTRL, 2, 2);
2497 
2498 			/* Enable Dynamic DiffAmp & Set Read ODT Value */
2499 			switch (mrc_params->rd_odt_value) {
2500 			case 0:
2501 				temp = 0x3f;	/* OFF */
2502 				break;
2503 			default:
2504 				temp = 0x00;	/* Auto */
2505 				break;
2506 			}
2507 
2508 			for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
2509 				/* Override: DIFFAMP, ODT */
2510 				mrc_alt_write_mask(DDRPHY,
2511 					B0OVRCTL + bl * DDRIODQ_BL_OFFSET +
2512 					channel * DDRIODQ_CH_OFFSET,
2513 					temp << 10,
2514 					0x003ffc00);
2515 
2516 				/* Override: DIFFAMP, ODT */
2517 				mrc_alt_write_mask(DDRPHY,
2518 					B1OVRCTL + bl * DDRIODQ_BL_OFFSET +
2519 					channel * DDRIODQ_CH_OFFSET,
2520 					temp << 10,
2521 					0x003ffc00);
2522 			}
2523 
2524 			/* Issue ZQCS command */
2525 			for (rank = 0; rank < NUM_RANKS; rank++) {
2526 				if (mrc_params->rank_enables & (1 << rank))
2527 					dram_init_command(DCMD_ZQCS(rank));
2528 			}
2529 		}
2530 	}
2531 
2532 	clear_pointers();
2533 
2534 	LEAVEFN();
2535 }
2536 
2537 /*
2538  * Depending on configuration enables ECC support
2539  *
2540  * Available memory size is decreased, and updated with 0s
2541  * in order to clear error status. Address mode 2 forced.
2542  */
ecc_enable(struct mrc_params * mrc_params)2543 void ecc_enable(struct mrc_params *mrc_params)
2544 {
2545 	u32 drp;
2546 	u32 dsch;
2547 	u32 ecc_ctrl;
2548 
2549 	if (mrc_params->ecc_enables == 0)
2550 		return;
2551 
2552 	ENTERFN();
2553 
2554 	/* Configuration required in ECC mode */
2555 	drp = msg_port_read(MEM_CTLR, DRP);
2556 	drp &= ~DRP_ADDRMAP_MASK;
2557 	drp |= DRP_ADDRMAP_MAP1;
2558 	drp |= DRP_PRI64BSPLITEN;
2559 	msg_port_write(MEM_CTLR, DRP, drp);
2560 
2561 	/* Disable new request bypass */
2562 	dsch = msg_port_read(MEM_CTLR, DSCH);
2563 	dsch |= DSCH_NEWBYPDIS;
2564 	msg_port_write(MEM_CTLR, DSCH, dsch);
2565 
2566 	/* Enable ECC */
2567 	ecc_ctrl = (DECCCTRL_SBEEN | DECCCTRL_DBEEN | DECCCTRL_ENCBGEN);
2568 	msg_port_write(MEM_CTLR, DECCCTRL, ecc_ctrl);
2569 
2570 	/* Assume 8 bank memory, one bank is gone for ECC */
2571 	mrc_params->mem_size -= mrc_params->mem_size / 8;
2572 
2573 	/* For S3 resume memory content has to be preserved */
2574 	if (mrc_params->boot_mode != BM_S3) {
2575 		select_hte();
2576 		hte_mem_init(mrc_params, MRC_MEM_INIT);
2577 		select_mem_mgr();
2578 	}
2579 
2580 	LEAVEFN();
2581 }
2582 
2583 /*
2584  * Execute memory test
2585  * if error detected it is indicated in mrc_params->status
2586  */
memory_test(struct mrc_params * mrc_params)2587 void memory_test(struct mrc_params *mrc_params)
2588 {
2589 	uint32_t result = 0;
2590 
2591 	ENTERFN();
2592 
2593 	select_hte();
2594 	result = hte_mem_init(mrc_params, MRC_MEM_TEST);
2595 	select_mem_mgr();
2596 
2597 	DPF(D_INFO, "Memory test result %x\n", result);
2598 	mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
2599 	LEAVEFN();
2600 }
2601 
2602 /* Lock MCU registers at the end of initialization sequence */
lock_registers(struct mrc_params * mrc_params)2603 void lock_registers(struct mrc_params *mrc_params)
2604 {
2605 	u32 dco;
2606 
2607 	ENTERFN();
2608 
2609 	dco = msg_port_read(MEM_CTLR, DCO);
2610 	dco &= ~(DCO_PMICTL | DCO_PMIDIS);
2611 	dco |= (DCO_DRPLOCK | DCO_CPGCLOCK);
2612 	msg_port_write(MEM_CTLR, DCO, dco);
2613 
2614 	LEAVEFN();
2615 }
2616