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