xref: /openbmc/u-boot/arch/x86/cpu/quark/smc.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: Intel
2b829f12aSBin Meng /*
3b829f12aSBin Meng  * Copyright (C) 2013, Intel Corporation
4b829f12aSBin Meng  * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
5b829f12aSBin Meng  *
6b829f12aSBin Meng  * Ported from Intel released Quark UEFI BIOS
7b829f12aSBin Meng  * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
8b829f12aSBin Meng  */
9b829f12aSBin Meng 
10b829f12aSBin Meng #include <common.h>
11b829f12aSBin Meng #include <pci.h>
12b829f12aSBin Meng #include <asm/arch/device.h>
13b829f12aSBin Meng #include <asm/arch/mrc.h>
14b829f12aSBin Meng #include <asm/arch/msg_port.h>
15b829f12aSBin Meng #include "mrc_util.h"
16b829f12aSBin Meng #include "hte.h"
17b829f12aSBin Meng #include "smc.h"
18b829f12aSBin Meng 
19b829f12aSBin Meng /* t_ck clock period in picoseconds per speed index 800, 1066, 1333 */
20b829f12aSBin Meng static const uint32_t t_ck[3] = {
21b829f12aSBin Meng 	2500,
22b829f12aSBin Meng 	1875,
23b829f12aSBin Meng 	1500
24b829f12aSBin Meng };
25b829f12aSBin Meng 
26b829f12aSBin Meng /* Global variables */
27b829f12aSBin Meng static const uint16_t ddr_wclk[] = {193, 158};
28d0c0752aSTom Rini #ifdef BACKUP_WCTL
29b829f12aSBin Meng static const uint16_t ddr_wctl[] = {1, 217};
30d0c0752aSTom Rini #endif
31d0c0752aSTom Rini #ifdef BACKUP_WCMD
32b829f12aSBin Meng static const uint16_t ddr_wcmd[] = {1, 220};
33d0c0752aSTom Rini #endif
34b829f12aSBin Meng 
35b829f12aSBin Meng #ifdef BACKUP_RCVN
36b829f12aSBin Meng static const uint16_t ddr_rcvn[] = {129, 498};
37b829f12aSBin Meng #endif
38b829f12aSBin Meng 
39b829f12aSBin Meng #ifdef BACKUP_WDQS
40b829f12aSBin Meng static const uint16_t ddr_wdqs[] = {65, 289};
41b829f12aSBin Meng #endif
42b829f12aSBin Meng 
43b829f12aSBin Meng #ifdef BACKUP_RDQS
44b829f12aSBin Meng static const uint8_t ddr_rdqs[] = {32, 24};
45b829f12aSBin Meng #endif
46b829f12aSBin Meng 
47b829f12aSBin Meng #ifdef BACKUP_WDQ
48b829f12aSBin Meng static const uint16_t ddr_wdq[] = {32, 257};
49b829f12aSBin Meng #endif
50b829f12aSBin Meng 
51b829f12aSBin Meng /* Stop self refresh driven by MCU */
clear_self_refresh(struct mrc_params * mrc_params)52b829f12aSBin Meng void clear_self_refresh(struct mrc_params *mrc_params)
53b829f12aSBin Meng {
54b829f12aSBin Meng 	ENTERFN();
55b829f12aSBin Meng 
56b829f12aSBin Meng 	/* clear the PMSTS Channel Self Refresh bits */
57312cc39eSBin Meng 	mrc_write_mask(MEM_CTLR, PMSTS, PMSTS_DISR, PMSTS_DISR);
58b829f12aSBin Meng 
59b829f12aSBin Meng 	LEAVEFN();
60b829f12aSBin Meng }
61b829f12aSBin Meng 
62b829f12aSBin Meng /* It will initialize timing registers in the MCU (DTR0..DTR4) */
prog_ddr_timing_control(struct mrc_params * mrc_params)63b829f12aSBin Meng void prog_ddr_timing_control(struct mrc_params *mrc_params)
64b829f12aSBin Meng {
65b829f12aSBin Meng 	uint8_t tcl, wl;
66b829f12aSBin Meng 	uint8_t trp, trcd, tras, twr, twtr, trrd, trtp, tfaw;
67b829f12aSBin Meng 	uint32_t tck;
68b829f12aSBin Meng 	u32 dtr0, dtr1, dtr2, dtr3, dtr4;
69b829f12aSBin Meng 	u32 tmp1, tmp2;
70b829f12aSBin Meng 
71b829f12aSBin Meng 	ENTERFN();
72b829f12aSBin Meng 
73b829f12aSBin Meng 	/* mcu_init starts */
74b829f12aSBin Meng 	mrc_post_code(0x02, 0x00);
75b829f12aSBin Meng 
76b829f12aSBin Meng 	dtr0 = msg_port_read(MEM_CTLR, DTR0);
77b829f12aSBin Meng 	dtr1 = msg_port_read(MEM_CTLR, DTR1);
78b829f12aSBin Meng 	dtr2 = msg_port_read(MEM_CTLR, DTR2);
79b829f12aSBin Meng 	dtr3 = msg_port_read(MEM_CTLR, DTR3);
80b829f12aSBin Meng 	dtr4 = msg_port_read(MEM_CTLR, DTR4);
81b829f12aSBin Meng 
82b829f12aSBin Meng 	tck = t_ck[mrc_params->ddr_speed];	/* Clock in picoseconds */
83b829f12aSBin Meng 	tcl = mrc_params->params.cl;		/* CAS latency in clocks */
84b829f12aSBin Meng 	trp = tcl;	/* Per CAT MRC */
85b829f12aSBin Meng 	trcd = tcl;	/* Per CAT MRC */
86b829f12aSBin Meng 	tras = MCEIL(mrc_params->params.ras, tck);
87b829f12aSBin Meng 
88b829f12aSBin Meng 	/* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
89b829f12aSBin Meng 	twr = MCEIL(15000, tck);
90b829f12aSBin Meng 
91b829f12aSBin Meng 	twtr = MCEIL(mrc_params->params.wtr, tck);
92b829f12aSBin Meng 	trrd = MCEIL(mrc_params->params.rrd, tck);
93b829f12aSBin Meng 	trtp = 4;	/* Valid for 800 and 1066, use 5 for 1333 */
94b829f12aSBin Meng 	tfaw = MCEIL(mrc_params->params.faw, tck);
95b829f12aSBin Meng 
96b829f12aSBin Meng 	wl = 5 + mrc_params->ddr_speed;
97b829f12aSBin Meng 
98312cc39eSBin Meng 	dtr0 &= ~DTR0_DFREQ_MASK;
99b829f12aSBin Meng 	dtr0 |= mrc_params->ddr_speed;
100312cc39eSBin Meng 	dtr0 &= ~DTR0_TCL_MASK;
101b829f12aSBin Meng 	tmp1 = tcl - 5;
102b829f12aSBin Meng 	dtr0 |= ((tcl - 5) << 12);
103312cc39eSBin Meng 	dtr0 &= ~DTR0_TRP_MASK;
104b829f12aSBin Meng 	dtr0 |= ((trp - 5) << 4);	/* 5 bit DRAM Clock */
105312cc39eSBin Meng 	dtr0 &= ~DTR0_TRCD_MASK;
106b829f12aSBin Meng 	dtr0 |= ((trcd - 5) << 8);	/* 5 bit DRAM Clock */
107b829f12aSBin Meng 
108312cc39eSBin Meng 	dtr1 &= ~DTR1_TWCL_MASK;
109b829f12aSBin Meng 	tmp2 = wl - 3;
110b829f12aSBin Meng 	dtr1 |= (wl - 3);
111312cc39eSBin Meng 	dtr1 &= ~DTR1_TWTP_MASK;
112b829f12aSBin Meng 	dtr1 |= ((wl + 4 + twr - 14) << 8);	/* Change to tWTP */
113312cc39eSBin Meng 	dtr1 &= ~DTR1_TRTP_MASK;
114b829f12aSBin Meng 	dtr1 |= ((MMAX(trtp, 4) - 3) << 28);	/* 4 bit DRAM Clock */
115312cc39eSBin Meng 	dtr1 &= ~DTR1_TRRD_MASK;
116b829f12aSBin Meng 	dtr1 |= ((trrd - 4) << 24);		/* 4 bit DRAM Clock */
117312cc39eSBin Meng 	dtr1 &= ~DTR1_TCMD_MASK;
118b829f12aSBin Meng 	dtr1 |= (1 << 4);
119312cc39eSBin Meng 	dtr1 &= ~DTR1_TRAS_MASK;
120b829f12aSBin Meng 	dtr1 |= ((tras - 14) << 20);		/* 6 bit DRAM Clock */
121312cc39eSBin Meng 	dtr1 &= ~DTR1_TFAW_MASK;
122b829f12aSBin Meng 	dtr1 |= ((((tfaw + 1) >> 1) - 5) << 16);/* 4 bit DRAM Clock */
123b829f12aSBin Meng 	/* Set 4 Clock CAS to CAS delay (multi-burst) */
124312cc39eSBin Meng 	dtr1 &= ~DTR1_TCCD_MASK;
125b829f12aSBin Meng 
126312cc39eSBin Meng 	dtr2 &= ~DTR2_TRRDR_MASK;
127b829f12aSBin Meng 	dtr2 |= 1;
128312cc39eSBin Meng 	dtr2 &= ~DTR2_TWWDR_MASK;
129b829f12aSBin Meng 	dtr2 |= (2 << 8);
130312cc39eSBin Meng 	dtr2 &= ~DTR2_TRWDR_MASK;
131b829f12aSBin Meng 	dtr2 |= (2 << 16);
132b829f12aSBin Meng 
133312cc39eSBin Meng 	dtr3 &= ~DTR3_TWRDR_MASK;
134b829f12aSBin Meng 	dtr3 |= 2;
135312cc39eSBin Meng 	dtr3 &= ~DTR3_TXXXX_MASK;
136b829f12aSBin Meng 	dtr3 |= (2 << 4);
137b829f12aSBin Meng 
138312cc39eSBin Meng 	dtr3 &= ~DTR3_TRWSR_MASK;
139b829f12aSBin Meng 	if (mrc_params->ddr_speed == DDRFREQ_800) {
140b829f12aSBin Meng 		/* Extended RW delay (+1) */
141b829f12aSBin Meng 		dtr3 |= ((tcl - 5 + 1) << 8);
142b829f12aSBin Meng 	} else if (mrc_params->ddr_speed == DDRFREQ_1066) {
143b829f12aSBin Meng 		/* Extended RW delay (+1) */
144b829f12aSBin Meng 		dtr3 |= ((tcl - 5 + 1) << 8);
145b829f12aSBin Meng 	}
146b829f12aSBin Meng 
147312cc39eSBin Meng 	dtr3 &= ~DTR3_TWRSR_MASK;
148b829f12aSBin Meng 	dtr3 |= ((4 + wl + twtr - 11) << 13);
149b829f12aSBin Meng 
150312cc39eSBin Meng 	dtr3 &= ~DTR3_TXP_MASK;
151b829f12aSBin Meng 	if (mrc_params->ddr_speed == DDRFREQ_800)
152b829f12aSBin Meng 		dtr3 |= ((MMAX(0, 1 - 1)) << 22);
153b829f12aSBin Meng 	else
154b829f12aSBin Meng 		dtr3 |= ((MMAX(0, 2 - 1)) << 22);
155b829f12aSBin Meng 
156312cc39eSBin Meng 	dtr4 &= ~DTR4_WRODTSTRT_MASK;
157b829f12aSBin Meng 	dtr4 |= 1;
158312cc39eSBin Meng 	dtr4 &= ~DTR4_WRODTSTOP_MASK;
159b829f12aSBin Meng 	dtr4 |= (1 << 4);
160312cc39eSBin Meng 	dtr4 &= ~DTR4_XXXX1_MASK;
161b829f12aSBin Meng 	dtr4 |= ((1 + tmp1 - tmp2 + 2) << 8);
162312cc39eSBin Meng 	dtr4 &= ~DTR4_XXXX2_MASK;
163b829f12aSBin Meng 	dtr4 |= ((1 + tmp1 - tmp2 + 2) << 12);
164312cc39eSBin Meng 	dtr4 &= ~(DTR4_ODTDIS | DTR4_TRGSTRDIS);
165b829f12aSBin Meng 
166b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR0, dtr0);
167b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR1, dtr1);
168b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR2, dtr2);
169b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR3, dtr3);
170b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR4, dtr4);
171b829f12aSBin Meng 
172b829f12aSBin Meng 	LEAVEFN();
173b829f12aSBin Meng }
174b829f12aSBin Meng 
175b829f12aSBin Meng /* Configure MCU before jedec init sequence */
prog_decode_before_jedec(struct mrc_params * mrc_params)176b829f12aSBin Meng void prog_decode_before_jedec(struct mrc_params *mrc_params)
177b829f12aSBin Meng {
178b829f12aSBin Meng 	u32 drp;
179b829f12aSBin Meng 	u32 drfc;
180b829f12aSBin Meng 	u32 dcal;
181b829f12aSBin Meng 	u32 dsch;
182b829f12aSBin Meng 	u32 dpmc0;
183b829f12aSBin Meng 
184b829f12aSBin Meng 	ENTERFN();
185b829f12aSBin Meng 
186b829f12aSBin Meng 	/* Disable power saving features */
187b829f12aSBin Meng 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
188312cc39eSBin Meng 	dpmc0 |= (DPMC0_CLKGTDIS | DPMC0_DISPWRDN);
189312cc39eSBin Meng 	dpmc0 &= ~DPMC0_PCLSTO_MASK;
190312cc39eSBin Meng 	dpmc0 &= ~DPMC0_DYNSREN;
191b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
192b829f12aSBin Meng 
193b829f12aSBin Meng 	/* Disable out of order transactions */
194b829f12aSBin Meng 	dsch = msg_port_read(MEM_CTLR, DSCH);
195312cc39eSBin Meng 	dsch |= (DSCH_OOODIS | DSCH_NEWBYPDIS);
196b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DSCH, dsch);
197b829f12aSBin Meng 
198b829f12aSBin Meng 	/* Disable issuing the REF command */
199b829f12aSBin Meng 	drfc = msg_port_read(MEM_CTLR, DRFC);
200312cc39eSBin Meng 	drfc &= ~DRFC_TREFI_MASK;
201b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRFC, drfc);
202b829f12aSBin Meng 
203b829f12aSBin Meng 	/* Disable ZQ calibration short */
204b829f12aSBin Meng 	dcal = msg_port_read(MEM_CTLR, DCAL);
205312cc39eSBin Meng 	dcal &= ~DCAL_ZQCINT_MASK;
206312cc39eSBin Meng 	dcal &= ~DCAL_SRXZQCL_MASK;
207b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DCAL, dcal);
208b829f12aSBin Meng 
209b829f12aSBin Meng 	/*
210b829f12aSBin Meng 	 * Training performed in address mode 0, rank population has limited
211b829f12aSBin Meng 	 * impact, however simulator complains if enabled non-existing rank.
212b829f12aSBin Meng 	 */
213b829f12aSBin Meng 	drp = 0;
214b829f12aSBin Meng 	if (mrc_params->rank_enables & 1)
215312cc39eSBin Meng 		drp |= DRP_RKEN0;
216b829f12aSBin Meng 	if (mrc_params->rank_enables & 2)
217312cc39eSBin Meng 		drp |= DRP_RKEN1;
218b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRP, drp);
219b829f12aSBin Meng 
220b829f12aSBin Meng 	LEAVEFN();
221b829f12aSBin Meng }
222b829f12aSBin Meng 
223b829f12aSBin Meng /*
224b829f12aSBin Meng  * After Cold Reset, BIOS should set COLDWAKE bit to 1 before
225b829f12aSBin Meng  * sending the WAKE message to the Dunit.
226b829f12aSBin Meng  *
227b829f12aSBin Meng  * For Standby Exit, or any other mode in which the DRAM is in
228b829f12aSBin Meng  * SR, this bit must be set to 0.
229b829f12aSBin Meng  */
perform_ddr_reset(struct mrc_params * mrc_params)230b829f12aSBin Meng void perform_ddr_reset(struct mrc_params *mrc_params)
231b829f12aSBin Meng {
232b829f12aSBin Meng 	ENTERFN();
233b829f12aSBin Meng 
234b829f12aSBin Meng 	/* Set COLDWAKE bit before sending the WAKE message */
235312cc39eSBin Meng 	mrc_write_mask(MEM_CTLR, DRMC, DRMC_COLDWAKE, DRMC_COLDWAKE);
236b829f12aSBin Meng 
237b829f12aSBin Meng 	/* Send wake command to DUNIT (MUST be done before JEDEC) */
238b829f12aSBin Meng 	dram_wake_command();
239b829f12aSBin Meng 
240b829f12aSBin Meng 	/* Set default value */
241b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRMC,
242312cc39eSBin Meng 		       mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0);
243b829f12aSBin Meng 
244b829f12aSBin Meng 	LEAVEFN();
245b829f12aSBin Meng }
246b829f12aSBin Meng 
247b829f12aSBin Meng 
248b829f12aSBin Meng /*
249b829f12aSBin Meng  * This function performs some initialization on the DDRIO unit.
250b829f12aSBin Meng  * This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
251b829f12aSBin Meng  */
ddrphy_init(struct mrc_params * mrc_params)252b829f12aSBin Meng void ddrphy_init(struct mrc_params *mrc_params)
253b829f12aSBin Meng {
254b829f12aSBin Meng 	uint32_t temp;
255b829f12aSBin Meng 	uint8_t ch;	/* channel counter */
256b829f12aSBin Meng 	uint8_t rk;	/* rank counter */
257b829f12aSBin Meng 	uint8_t bl_grp;	/*  byte lane group counter (2 BLs per module) */
258b829f12aSBin Meng 	uint8_t bl_divisor = 1;	/* byte lane divisor */
259b829f12aSBin Meng 	/* For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 */
260312cc39eSBin Meng 	uint8_t speed = mrc_params->ddr_speed & 3;
261b829f12aSBin Meng 	uint8_t cas;
262b829f12aSBin Meng 	uint8_t cwl;
263b829f12aSBin Meng 
264b829f12aSBin Meng 	ENTERFN();
265b829f12aSBin Meng 
266b829f12aSBin Meng 	cas = mrc_params->params.cl;
267b829f12aSBin Meng 	cwl = 5 + mrc_params->ddr_speed;
268b829f12aSBin Meng 
269b829f12aSBin Meng 	/* ddrphy_init starts */
270b829f12aSBin Meng 	mrc_post_code(0x03, 0x00);
271b829f12aSBin Meng 
272b829f12aSBin Meng 	/*
273b829f12aSBin Meng 	 * HSD#231531
274b829f12aSBin Meng 	 * Make sure IOBUFACT is deasserted before initializing the DDR PHY
275b829f12aSBin Meng 	 *
276b829f12aSBin Meng 	 * HSD#234845
277b829f12aSBin Meng 	 * Make sure WRPTRENABLE is deasserted before initializing the DDR PHY
278b829f12aSBin Meng 	 */
279b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
280b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
281b829f12aSBin Meng 			/* Deassert DDRPHY Initialization Complete */
282b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
283312cc39eSBin Meng 				CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
284312cc39eSBin Meng 				~(1 << 20), 1 << 20);	/* SPID_INIT_COMPLETE=0 */
285b829f12aSBin Meng 			/* Deassert IOBUFACT */
286b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
287312cc39eSBin Meng 				CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
288312cc39eSBin Meng 				~(1 << 2), 1 << 2);	/* IOBUFACTRST_N=0 */
289b829f12aSBin Meng 			/* Disable WRPTR */
290b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
291312cc39eSBin Meng 				CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
292312cc39eSBin Meng 				~(1 << 0), 1 << 0);	/* WRPTRENABLE=0 */
293b829f12aSBin Meng 		}
294b829f12aSBin Meng 	}
295b829f12aSBin Meng 
296b829f12aSBin Meng 	/* Put PHY in reset */
297312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, MASTERRSTN, 0, 1);
298b829f12aSBin Meng 
299b829f12aSBin Meng 	/* Initialize DQ01, DQ23, CMD, CLK-CTL, COMP modules */
300b829f12aSBin Meng 
301b829f12aSBin Meng 	/* STEP0 */
302b829f12aSBin Meng 	mrc_post_code(0x03, 0x10);
303b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
304b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
305b829f12aSBin Meng 			/* DQ01-DQ23 */
306b829f12aSBin Meng 			for (bl_grp = 0;
307312cc39eSBin Meng 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
308b829f12aSBin Meng 			     bl_grp++) {
309b829f12aSBin Meng 				/* Analog MUX select - IO2xCLKSEL */
310b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
311312cc39eSBin Meng 					DQOBSCKEBBCTL +
312312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
313312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
314312cc39eSBin Meng 					bl_grp ? 0 : (1 << 22), 1 << 22);
315b829f12aSBin Meng 
316b829f12aSBin Meng 				/* ODT Strength */
317b829f12aSBin Meng 				switch (mrc_params->rd_odt_value) {
318b829f12aSBin Meng 				case 1:
319b829f12aSBin Meng 					temp = 0x3;
320b829f12aSBin Meng 					break;	/* 60 ohm */
321b829f12aSBin Meng 				case 2:
322b829f12aSBin Meng 					temp = 0x3;
323b829f12aSBin Meng 					break;	/* 120 ohm */
324b829f12aSBin Meng 				case 3:
325b829f12aSBin Meng 					temp = 0x3;
326b829f12aSBin Meng 					break;	/* 180 ohm */
327b829f12aSBin Meng 				default:
328b829f12aSBin Meng 					temp = 0x3;
329b829f12aSBin Meng 					break;	/* 120 ohm */
330b829f12aSBin Meng 				}
331b829f12aSBin Meng 
332b829f12aSBin Meng 				/* ODT strength */
333b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
334312cc39eSBin Meng 					B0RXIOBUFCTL +
335312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
336312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
337312cc39eSBin Meng 					temp << 5, 0x60);
338b829f12aSBin Meng 				/* ODT strength */
339b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
340312cc39eSBin Meng 					B1RXIOBUFCTL +
341312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
342312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
343312cc39eSBin Meng 					temp << 5, 0x60);
344b829f12aSBin Meng 
345b829f12aSBin Meng 				/* Dynamic ODT/DIFFAMP */
346312cc39eSBin Meng 				temp = (cas << 24) | (cas << 16) |
347312cc39eSBin Meng 					(cas << 8) | (cas << 0);
348b829f12aSBin Meng 				switch (speed) {
349b829f12aSBin Meng 				case 0:
350b829f12aSBin Meng 					temp -= 0x01010101;
351b829f12aSBin Meng 					break;	/* 800 */
352b829f12aSBin Meng 				case 1:
353b829f12aSBin Meng 					temp -= 0x02020202;
354b829f12aSBin Meng 					break;	/* 1066 */
355b829f12aSBin Meng 				case 2:
356b829f12aSBin Meng 					temp -= 0x03030303;
357b829f12aSBin Meng 					break;	/* 1333 */
358b829f12aSBin Meng 				case 3:
359b829f12aSBin Meng 					temp -= 0x04040404;
360b829f12aSBin Meng 					break;	/* 1600 */
361b829f12aSBin Meng 				}
362b829f12aSBin Meng 
363b829f12aSBin Meng 				/* Launch Time: ODT, DIFFAMP, ODT, DIFFAMP */
364b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
365312cc39eSBin Meng 					B01LATCTL1 +
366312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
367312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
368312cc39eSBin Meng 					temp, 0x1f1f1f1f);
369b829f12aSBin Meng 				switch (speed) {
370b829f12aSBin Meng 				/* HSD#234715 */
371b829f12aSBin Meng 				case 0:
372312cc39eSBin Meng 					temp = (0x06 << 16) | (0x07 << 8);
373b829f12aSBin Meng 					break;	/* 800 */
374b829f12aSBin Meng 				case 1:
375312cc39eSBin Meng 					temp = (0x07 << 16) | (0x08 << 8);
376b829f12aSBin Meng 					break;	/* 1066 */
377b829f12aSBin Meng 				case 2:
378312cc39eSBin Meng 					temp = (0x09 << 16) | (0x0a << 8);
379b829f12aSBin Meng 					break;	/* 1333 */
380b829f12aSBin Meng 				case 3:
381312cc39eSBin Meng 					temp = (0x0a << 16) | (0x0b << 8);
382b829f12aSBin Meng 					break;	/* 1600 */
383b829f12aSBin Meng 				}
384b829f12aSBin Meng 
385b829f12aSBin Meng 				/* On Duration: ODT, DIFFAMP */
386b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
387312cc39eSBin Meng 					B0ONDURCTL +
388312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
389312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
390312cc39eSBin Meng 					temp, 0x003f3f00);
391b829f12aSBin Meng 				/* On Duration: ODT, DIFFAMP */
392b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
393312cc39eSBin Meng 					B1ONDURCTL +
394312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
395312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
396312cc39eSBin Meng 					temp, 0x003f3f00);
397b829f12aSBin Meng 
398b829f12aSBin Meng 				switch (mrc_params->rd_odt_value) {
399b829f12aSBin Meng 				case 0:
400b829f12aSBin Meng 					/* override DIFFAMP=on, ODT=off */
401312cc39eSBin Meng 					temp = (0x3f << 16) | (0x3f << 10);
402b829f12aSBin Meng 					break;
403b829f12aSBin Meng 				default:
404b829f12aSBin Meng 					/* override DIFFAMP=on, ODT=on */
405312cc39eSBin Meng 					temp = (0x3f << 16) | (0x2a << 10);
406b829f12aSBin Meng 					break;
407b829f12aSBin Meng 				}
408b829f12aSBin Meng 
409b829f12aSBin Meng 				/* Override: DIFFAMP, ODT */
410b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
411312cc39eSBin Meng 					B0OVRCTL +
412312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
413312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
414312cc39eSBin Meng 					temp, 0x003ffc00);
415b829f12aSBin Meng 				/* Override: DIFFAMP, ODT */
416b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
417312cc39eSBin Meng 					B1OVRCTL +
418312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
419312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
420312cc39eSBin Meng 					temp, 0x003ffc00);
421b829f12aSBin Meng 
422b829f12aSBin Meng 				/* DLL Setup */
423b829f12aSBin Meng 
424b829f12aSBin Meng 				/* 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) */
425b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
426312cc39eSBin Meng 					B0LATCTL0 +
427312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
428312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
429312cc39eSBin Meng 					((cas + 7) << 16) | ((cas - 4) << 8) |
430312cc39eSBin Meng 					((cwl - 2) << 0), 0x003f1f1f);
431b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
432312cc39eSBin Meng 					B1LATCTL0 +
433312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
434312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
435312cc39eSBin Meng 					((cas + 7) << 16) | ((cas - 4) << 8) |
436312cc39eSBin Meng 					((cwl - 2) << 0), 0x003f1f1f);
437b829f12aSBin Meng 
438b829f12aSBin Meng 				/* RCVEN Bypass (PO) */
439b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
440312cc39eSBin Meng 					B0RXIOBUFCTL +
441312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
442312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
443312cc39eSBin Meng 					0, 0x81);
444b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
445312cc39eSBin Meng 					B1RXIOBUFCTL +
446312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
447312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
448312cc39eSBin Meng 					0, 0x81);
449b829f12aSBin Meng 
450b829f12aSBin Meng 				/* TX */
451b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
452312cc39eSBin Meng 					DQCTL +
453312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
454312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
455312cc39eSBin Meng 					1 << 16, 1 << 16);
456b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
457312cc39eSBin Meng 					B01PTRCTL1 +
458312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
459312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
460312cc39eSBin Meng 					1 << 8, 1 << 8);
461b829f12aSBin Meng 
462b829f12aSBin Meng 				/* RX (PO) */
463b829f12aSBin Meng 				/* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
464b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
465312cc39eSBin Meng 					B0VREFCTL +
466312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
467312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
468312cc39eSBin Meng 					(0x03 << 2) | (0x0 << 1) | (0x0 << 0),
469312cc39eSBin Meng 					0xff);
470b829f12aSBin Meng 				/* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
471b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
472312cc39eSBin Meng 					B1VREFCTL +
473312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
474312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
475312cc39eSBin Meng 					(0x03 << 2) | (0x0 << 1) | (0x0 << 0),
476312cc39eSBin Meng 					0xff);
477b829f12aSBin Meng 				/* Per-Bit De-Skew Enable */
478b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
479312cc39eSBin Meng 					B0RXIOBUFCTL +
480312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
481312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
482312cc39eSBin Meng 					0, 0x10);
483b829f12aSBin Meng 				/* Per-Bit De-Skew Enable */
484b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
485312cc39eSBin Meng 					B1RXIOBUFCTL +
486312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
487312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
488312cc39eSBin Meng 					0, 0x10);
489b829f12aSBin Meng 			}
490b829f12aSBin Meng 
491b829f12aSBin Meng 			/* CLKEBB */
492b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
493312cc39eSBin Meng 				CMDOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
494312cc39eSBin Meng 				0, 1 << 23);
495b829f12aSBin Meng 
496b829f12aSBin Meng 			/* Enable tristate control of cmd/address bus */
497b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
498312cc39eSBin Meng 				CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
499312cc39eSBin Meng 				0, 0x03);
500b829f12aSBin Meng 
501b829f12aSBin Meng 			/* ODT RCOMP */
502b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
503312cc39eSBin Meng 				CMDRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
504312cc39eSBin Meng 				(0x03 << 5) | (0x03 << 0), 0x3ff);
505b829f12aSBin Meng 
506b829f12aSBin Meng 			/* CMDPM* registers must be programmed in this order */
507b829f12aSBin Meng 
508b829f12aSBin Meng 			/* Turn On Delays: SFR (regulator), MPLL */
509b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
510312cc39eSBin Meng 				CMDPMDLYREG4 + ch * DDRIOCCC_CH_OFFSET,
511312cc39eSBin Meng 				0xffffffff, 0xffffffff);
512b829f12aSBin Meng 			/*
513b829f12aSBin Meng 			 * Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3,
514b829f12aSBin Meng 			 * VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT
515b829f12aSBin Meng 			 * for_PM_MSG_gt0, MDLL Turn On
516b829f12aSBin Meng 			 */
517b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
518312cc39eSBin Meng 				CMDPMDLYREG3 + ch * DDRIOCCC_CH_OFFSET,
519312cc39eSBin Meng 				0xfffff616, 0xffffffff);
520b829f12aSBin Meng 			/* MPLL Divider Reset Delays */
521b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
522312cc39eSBin Meng 				CMDPMDLYREG2 + ch * DDRIOCCC_CH_OFFSET,
523312cc39eSBin Meng 				0xffffffff, 0xffffffff);
524b829f12aSBin Meng 			/* Turn Off Delays: VREG, Staggered MDLL, MDLL, PI */
525b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
526312cc39eSBin Meng 				CMDPMDLYREG1 + ch * DDRIOCCC_CH_OFFSET,
527312cc39eSBin Meng 				0xffffffff, 0xffffffff);
528b829f12aSBin Meng 			/* Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT */
529b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
530312cc39eSBin Meng 				CMDPMDLYREG0 + ch * DDRIOCCC_CH_OFFSET,
531312cc39eSBin Meng 				0xffffffff, 0xffffffff);
532b829f12aSBin Meng 			/* Allow PUnit signals */
533b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
534312cc39eSBin Meng 				CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
535312cc39eSBin Meng 				(0x6 << 8) | (0x1 << 6) | (0x4 << 0),
536312cc39eSBin Meng 				0xffe00f4f);
537b829f12aSBin Meng 			/* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
538b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
539312cc39eSBin Meng 				CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
540312cc39eSBin Meng 				(0x3 << 4) | (0x7 << 0), 0x7f);
541b829f12aSBin Meng 
542b829f12aSBin Meng 			/* CLK-CTL */
543b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
544312cc39eSBin Meng 				CCOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
545312cc39eSBin Meng 				0, 1 << 24);	/* CLKEBB */
546b829f12aSBin Meng 			/* Buffer Enable: CS,CKE,ODT,CLK */
547b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
548312cc39eSBin Meng 				CCCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
549312cc39eSBin Meng 				0x1f, 0x000ffff1);
550b829f12aSBin Meng 			/* ODT RCOMP */
551b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
552312cc39eSBin Meng 				CCRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
553312cc39eSBin Meng 				(0x03 << 8) | (0x03 << 0), 0x00001f1f);
554b829f12aSBin Meng 			/* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
555b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
556312cc39eSBin Meng 				CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
557312cc39eSBin Meng 				(0x3 << 4) | (0x7 << 0), 0x7f);
558b829f12aSBin Meng 
559b829f12aSBin Meng 			/*
560b829f12aSBin Meng 			 * COMP (RON channel specific)
561b829f12aSBin Meng 			 * - DQ/DQS/DM RON: 32 Ohm
562b829f12aSBin Meng 			 * - CTRL/CMD RON: 27 Ohm
563b829f12aSBin Meng 			 * - CLK RON: 26 Ohm
564b829f12aSBin Meng 			 */
565b829f12aSBin Meng 			/* RCOMP Vref PU/PD */
566b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
567312cc39eSBin Meng 				DQVREFCH0 +  ch * DDRCOMP_CH_OFFSET,
568312cc39eSBin Meng 				(0x08 << 24) | (0x03 << 16), 0x3f3f0000);
569b829f12aSBin Meng 			/* RCOMP Vref PU/PD */
570b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
571312cc39eSBin Meng 				CMDVREFCH0 + ch * DDRCOMP_CH_OFFSET,
572312cc39eSBin Meng 				(0x0C << 24) | (0x03 << 16), 0x3f3f0000);
573b829f12aSBin Meng 			/* RCOMP Vref PU/PD */
574b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
575312cc39eSBin Meng 				CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
576312cc39eSBin Meng 				(0x0F << 24) | (0x03 << 16), 0x3f3f0000);
577b829f12aSBin Meng 			/* RCOMP Vref PU/PD */
578b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
579312cc39eSBin Meng 				DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
580312cc39eSBin Meng 				(0x08 << 24) | (0x03 << 16), 0x3f3f0000);
581b829f12aSBin Meng 			/* RCOMP Vref PU/PD */
582b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
583312cc39eSBin Meng 				CTLVREFCH0 + ch * DDRCOMP_CH_OFFSET,
584312cc39eSBin Meng 				(0x0C << 24) | (0x03 << 16), 0x3f3f0000);
585b829f12aSBin Meng 
586b829f12aSBin Meng 			/* DQS Swapped Input Enable */
587b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
588312cc39eSBin Meng 				COMPEN1CH0 + ch * DDRCOMP_CH_OFFSET,
589312cc39eSBin Meng 				(1 << 19) | (1 << 17), 0xc00ac000);
590b829f12aSBin Meng 
591b829f12aSBin Meng 			/* ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) */
592b829f12aSBin Meng 			/* ODT Vref PU/PD */
593b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
594312cc39eSBin Meng 				DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
595312cc39eSBin Meng 				(0x32 << 8) | (0x03 << 0), 0x00003f3f);
596b829f12aSBin Meng 			/* ODT Vref PU/PD */
597b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
598312cc39eSBin Meng 				DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
599312cc39eSBin Meng 				(0x32 << 8) | (0x03 << 0), 0x00003f3f);
600b829f12aSBin Meng 			/* ODT Vref PU/PD */
601b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
602312cc39eSBin Meng 				CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
603312cc39eSBin Meng 				(0x0E << 8) | (0x05 << 0), 0x00003f3f);
604b829f12aSBin Meng 
605b829f12aSBin Meng 			/*
606b829f12aSBin Meng 			 * Slew rate settings are frequency specific,
607b829f12aSBin Meng 			 * numbers below are for 800Mhz (speed == 0)
608b829f12aSBin Meng 			 * - DQ/DQS/DM/CLK SR: 4V/ns,
609b829f12aSBin Meng 			 * - CTRL/CMD SR: 1.5V/ns
610b829f12aSBin Meng 			 */
611312cc39eSBin Meng 			temp = (0x0e << 16) | (0x0e << 12) | (0x08 << 8) |
612312cc39eSBin Meng 				(0x0b << 4) | (0x0b << 0);
613b829f12aSBin Meng 			/* DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ */
614b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
615312cc39eSBin Meng 				DLYSELCH0 + ch * DDRCOMP_CH_OFFSET,
616312cc39eSBin Meng 				temp, 0x000fffff);
617b829f12aSBin Meng 			/* TCO Vref CLK,DQS,DQ */
618b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
619312cc39eSBin Meng 				TCOVREFCH0 + ch * DDRCOMP_CH_OFFSET,
620312cc39eSBin Meng 				(0x05 << 16) | (0x05 << 8) | (0x05 << 0),
621312cc39eSBin Meng 				0x003f3f3f);
622b829f12aSBin Meng 			/* ODTCOMP CMD/CTL PU/PD */
623b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
624312cc39eSBin Meng 				CCBUFODTCH0 + ch * DDRCOMP_CH_OFFSET,
625312cc39eSBin Meng 				(0x03 << 8) | (0x03 << 0),
626312cc39eSBin Meng 				0x00001f1f);
627b829f12aSBin Meng 			/* COMP */
628b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
629312cc39eSBin Meng 				COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
630312cc39eSBin Meng 				0, 0xc0000100);
631b829f12aSBin Meng 
632b829f12aSBin Meng #ifdef BACKUP_COMPS
633b829f12aSBin Meng 			/* DQ COMP Overrides */
634b829f12aSBin Meng 			/* RCOMP PU */
635b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
636312cc39eSBin Meng 				DQDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
637312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
638312cc39eSBin Meng 				0x801f0000);
639b829f12aSBin Meng 			/* RCOMP PD */
640b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
641312cc39eSBin Meng 				DQDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
642312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
643312cc39eSBin Meng 				0x801f0000);
644b829f12aSBin Meng 			/* DCOMP PU */
645b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
646312cc39eSBin Meng 				DQDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
647312cc39eSBin Meng 				(1 << 31) | (0x10 << 16),
648312cc39eSBin Meng 				0x801f0000);
649b829f12aSBin Meng 			/* DCOMP PD */
650b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
651312cc39eSBin Meng 				DQDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
652312cc39eSBin Meng 				(1 << 31) | (0x10 << 16),
653312cc39eSBin Meng 				0x801f0000);
654b829f12aSBin Meng 			/* ODTCOMP PU */
655b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
656312cc39eSBin Meng 				DQODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
657312cc39eSBin Meng 				(1 << 31) | (0x0b << 16),
658312cc39eSBin Meng 				0x801f0000);
659b829f12aSBin Meng 			/* ODTCOMP PD */
660b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
661312cc39eSBin Meng 				DQODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
662312cc39eSBin Meng 				(1 << 31) | (0x0b << 16),
663312cc39eSBin Meng 				0x801f0000);
664b829f12aSBin Meng 			/* TCOCOMP PU */
665b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
666312cc39eSBin Meng 				DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
667312cc39eSBin Meng 				1 << 31, 1 << 31);
668b829f12aSBin Meng 			/* TCOCOMP PD */
669b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
670312cc39eSBin Meng 				DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
671312cc39eSBin Meng 				1 << 31, 1 << 31);
672b829f12aSBin Meng 
673b829f12aSBin Meng 			/* DQS COMP Overrides */
674b829f12aSBin Meng 			/* RCOMP PU */
675b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
676312cc39eSBin Meng 				DQSDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
677312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
678312cc39eSBin Meng 				0x801f0000);
679b829f12aSBin Meng 			/* RCOMP PD */
680b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
681312cc39eSBin Meng 				DQSDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
682312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
683312cc39eSBin Meng 				0x801f0000);
684b829f12aSBin Meng 			/* DCOMP PU */
685b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
686312cc39eSBin Meng 				DQSDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
687312cc39eSBin Meng 				(1 << 31) | (0x10 << 16),
688312cc39eSBin Meng 				0x801f0000);
689b829f12aSBin Meng 			/* DCOMP PD */
690b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
691312cc39eSBin Meng 				DQSDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
692312cc39eSBin Meng 				(1 << 31) | (0x10 << 16),
693312cc39eSBin Meng 				0x801f0000);
694b829f12aSBin Meng 			/* ODTCOMP PU */
695b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
696312cc39eSBin Meng 				DQSODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
697312cc39eSBin Meng 				(1 << 31) | (0x0b << 16),
698312cc39eSBin Meng 				0x801f0000);
699b829f12aSBin Meng 			/* ODTCOMP PD */
700b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
701312cc39eSBin Meng 				DQSODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
702312cc39eSBin Meng 				(1 << 31) | (0x0b << 16),
703312cc39eSBin Meng 				0x801f0000);
704b829f12aSBin Meng 			/* TCOCOMP PU */
705b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
706312cc39eSBin Meng 				DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
707312cc39eSBin Meng 				1 << 31, 1 << 31);
708b829f12aSBin Meng 			/* TCOCOMP PD */
709b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
710312cc39eSBin Meng 				DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
711312cc39eSBin Meng 				1 << 31, 1 << 31);
712b829f12aSBin Meng 
713b829f12aSBin Meng 			/* CLK COMP Overrides */
714b829f12aSBin Meng 			/* RCOMP PU */
715b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
716312cc39eSBin Meng 				CLKDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
717312cc39eSBin Meng 				(1 << 31) | (0x0c << 16),
718312cc39eSBin Meng 				0x801f0000);
719b829f12aSBin Meng 			/* RCOMP PD */
720b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
721312cc39eSBin Meng 				CLKDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
722312cc39eSBin Meng 				(1 << 31) | (0x0c << 16),
723312cc39eSBin Meng 				0x801f0000);
724b829f12aSBin Meng 			/* DCOMP PU */
725b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
726312cc39eSBin Meng 				CLKDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
727312cc39eSBin Meng 				(1 << 31) | (0x07 << 16),
728312cc39eSBin Meng 				0x801f0000);
729b829f12aSBin Meng 			/* DCOMP PD */
730b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
731312cc39eSBin Meng 				CLKDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
732312cc39eSBin Meng 				(1 << 31) | (0x07 << 16),
733312cc39eSBin Meng 				0x801f0000);
734b829f12aSBin Meng 			/* ODTCOMP PU */
735b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
736312cc39eSBin Meng 				CLKODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
737312cc39eSBin Meng 				(1 << 31) | (0x0b << 16),
738312cc39eSBin Meng 				0x801f0000);
739b829f12aSBin Meng 			/* ODTCOMP PD */
740b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
741312cc39eSBin Meng 				CLKODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
742312cc39eSBin Meng 				(1 << 31) | (0x0b << 16),
743312cc39eSBin Meng 				0x801f0000);
744b829f12aSBin Meng 			/* TCOCOMP PU */
745b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
746312cc39eSBin Meng 				CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
747312cc39eSBin Meng 				1 << 31, 1 << 31);
748b829f12aSBin Meng 			/* TCOCOMP PD */
749b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
750312cc39eSBin Meng 				CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
751312cc39eSBin Meng 				1 << 31, 1 << 31);
752b829f12aSBin Meng 
753b829f12aSBin Meng 			/* CMD COMP Overrides */
754b829f12aSBin Meng 			/* RCOMP PU */
755b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
756312cc39eSBin Meng 				CMDDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
757312cc39eSBin Meng 				(1 << 31) | (0x0d << 16),
758312cc39eSBin Meng 				0x803f0000);
759b829f12aSBin Meng 			/* RCOMP PD */
760b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
761312cc39eSBin Meng 				CMDDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
762312cc39eSBin Meng 				(1 << 31) | (0x0d << 16),
763312cc39eSBin Meng 				0x803f0000);
764b829f12aSBin Meng 			/* DCOMP PU */
765b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
766312cc39eSBin Meng 				CMDDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
767312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
768312cc39eSBin Meng 				0x801f0000);
769b829f12aSBin Meng 			/* DCOMP PD */
770b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
771312cc39eSBin Meng 				CMDDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
772312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
773312cc39eSBin Meng 				0x801f0000);
774b829f12aSBin Meng 
775b829f12aSBin Meng 			/* CTL COMP Overrides */
776b829f12aSBin Meng 			/* RCOMP PU */
777b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
778312cc39eSBin Meng 				CTLDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
779312cc39eSBin Meng 				(1 << 31) | (0x0d << 16),
780312cc39eSBin Meng 				0x803f0000);
781b829f12aSBin Meng 			/* RCOMP PD */
782b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
783312cc39eSBin Meng 				CTLDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
784312cc39eSBin Meng 				(1 << 31) | (0x0d << 16),
785312cc39eSBin Meng 				0x803f0000);
786b829f12aSBin Meng 			/* DCOMP PU */
787b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
788312cc39eSBin Meng 				CTLDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
789312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
790312cc39eSBin Meng 				0x801f0000);
791b829f12aSBin Meng 			/* DCOMP PD */
792b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
793312cc39eSBin Meng 				CTLDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
794312cc39eSBin Meng 				(1 << 31) | (0x0a << 16),
795312cc39eSBin Meng 				0x801f0000);
796b829f12aSBin Meng #else
797b829f12aSBin Meng 			/* DQ TCOCOMP Overrides */
798b829f12aSBin Meng 			/* TCOCOMP PU */
799b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
800312cc39eSBin Meng 				DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
801312cc39eSBin Meng 				(1 << 31) | (0x1f << 16),
802312cc39eSBin Meng 				0x801f0000);
803b829f12aSBin Meng 			/* TCOCOMP PD */
804b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
805312cc39eSBin Meng 				DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
806312cc39eSBin Meng 				(1 << 31) | (0x1f << 16),
807312cc39eSBin Meng 				0x801f0000);
808b829f12aSBin Meng 
809b829f12aSBin Meng 			/* DQS TCOCOMP Overrides */
810b829f12aSBin Meng 			/* TCOCOMP PU */
811b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
812312cc39eSBin Meng 				DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
813312cc39eSBin Meng 				(1 << 31) | (0x1f << 16),
814312cc39eSBin Meng 				0x801f0000);
815b829f12aSBin Meng 			/* TCOCOMP PD */
816b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
817312cc39eSBin Meng 				DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
818312cc39eSBin Meng 				(1 << 31) | (0x1f << 16),
819312cc39eSBin Meng 				0x801f0000);
820b829f12aSBin Meng 
821b829f12aSBin Meng 			/* CLK TCOCOMP Overrides */
822b829f12aSBin Meng 			/* TCOCOMP PU */
823b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
824312cc39eSBin Meng 				CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
825312cc39eSBin Meng 				(1 << 31) | (0x1f << 16),
826312cc39eSBin Meng 				0x801f0000);
827b829f12aSBin Meng 			/* TCOCOMP PD */
828b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
829312cc39eSBin Meng 				CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
830312cc39eSBin Meng 				(1 << 31) | (0x1f << 16),
831312cc39eSBin Meng 				0x801f0000);
832b829f12aSBin Meng #endif
833b829f12aSBin Meng 
834b829f12aSBin Meng 			/* program STATIC delays */
835b829f12aSBin Meng #ifdef BACKUP_WCMD
836b829f12aSBin Meng 			set_wcmd(ch, ddr_wcmd[PLATFORM_ID]);
837b829f12aSBin Meng #else
838b829f12aSBin Meng 			set_wcmd(ch, ddr_wclk[PLATFORM_ID] + HALF_CLK);
839b829f12aSBin Meng #endif
840b829f12aSBin Meng 
841b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
842b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
843b829f12aSBin Meng 					set_wclk(ch, rk, ddr_wclk[PLATFORM_ID]);
844b829f12aSBin Meng #ifdef BACKUP_WCTL
845b829f12aSBin Meng 					set_wctl(ch, rk, ddr_wctl[PLATFORM_ID]);
846b829f12aSBin Meng #else
847b829f12aSBin Meng 					set_wctl(ch, rk, ddr_wclk[PLATFORM_ID] + HALF_CLK);
848b829f12aSBin Meng #endif
849b829f12aSBin Meng 				}
850b829f12aSBin Meng 			}
851b829f12aSBin Meng 		}
852b829f12aSBin Meng 	}
853b829f12aSBin Meng 
854b829f12aSBin Meng 	/* COMP (non channel specific) */
855b829f12aSBin Meng 	/* RCOMP: Dither PU Enable */
856312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANADRVPUCTL, 1 << 30, 1 << 30);
857b829f12aSBin Meng 	/* RCOMP: Dither PD Enable */
858312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANADRVPDCTL, 1 << 30, 1 << 30);
859b829f12aSBin Meng 	/* RCOMP: Dither PU Enable */
860312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CMDANADRVPUCTL, 1 << 30, 1 << 30);
861b829f12aSBin Meng 	/* RCOMP: Dither PD Enable */
862312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CMDANADRVPDCTL, 1 << 30, 1 << 30);
863b829f12aSBin Meng 	/* RCOMP: Dither PU Enable */
864312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANADRVPUCTL, 1 << 30, 1 << 30);
865b829f12aSBin Meng 	/* RCOMP: Dither PD Enable */
866312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANADRVPDCTL, 1 << 30, 1 << 30);
867b829f12aSBin Meng 	/* RCOMP: Dither PU Enable */
868312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANADRVPUCTL, 1 << 30, 1 << 30);
869b829f12aSBin Meng 	/* RCOMP: Dither PD Enable */
870312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANADRVPDCTL, 1 << 30, 1 << 30);
871b829f12aSBin Meng 	/* RCOMP: Dither PU Enable */
872312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CTLANADRVPUCTL, 1 << 30, 1 << 30);
873b829f12aSBin Meng 	/* RCOMP: Dither PD Enable */
874312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CTLANADRVPDCTL, 1 << 30, 1 << 30);
875b829f12aSBin Meng 	/* ODT: Dither PU Enable */
876312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANAODTPUCTL, 1 << 30, 1 << 30);
877b829f12aSBin Meng 	/* ODT: Dither PD Enable */
878312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANAODTPDCTL, 1 << 30, 1 << 30);
879b829f12aSBin Meng 	/* ODT: Dither PU Enable */
880312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANAODTPUCTL, 1 << 30, 1 << 30);
881b829f12aSBin Meng 	/* ODT: Dither PD Enable */
882312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANAODTPDCTL, 1 << 30, 1 << 30);
883b829f12aSBin Meng 	/* ODT: Dither PU Enable */
884312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANAODTPUCTL, 1 << 30, 1 << 30);
885b829f12aSBin Meng 	/* ODT: Dither PD Enable */
886312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANAODTPDCTL, 1 << 30, 1 << 30);
887b829f12aSBin Meng 	/* DCOMP: Dither PU Enable */
888312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANADLYPUCTL, 1 << 30, 1 << 30);
889b829f12aSBin Meng 	/* DCOMP: Dither PD Enable */
890312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANADLYPDCTL, 1 << 30, 1 << 30);
891b829f12aSBin Meng 	/* DCOMP: Dither PU Enable */
892312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CMDANADLYPUCTL, 1 << 30, 1 << 30);
893b829f12aSBin Meng 	/* DCOMP: Dither PD Enable */
894312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CMDANADLYPDCTL, 1 << 30, 1 << 30);
895b829f12aSBin Meng 	/* DCOMP: Dither PU Enable */
896312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANADLYPUCTL, 1 << 30, 1 << 30);
897b829f12aSBin Meng 	/* DCOMP: Dither PD Enable */
898312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANADLYPDCTL, 1 << 30, 1 << 30);
899b829f12aSBin Meng 	/* DCOMP: Dither PU Enable */
900312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANADLYPUCTL, 1 << 30, 1 << 30);
901b829f12aSBin Meng 	/* DCOMP: Dither PD Enable */
902312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANADLYPDCTL, 1 << 30, 1 << 30);
903b829f12aSBin Meng 	/* DCOMP: Dither PU Enable */
904312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CTLANADLYPUCTL, 1 << 30, 1 << 30);
905b829f12aSBin Meng 	/* DCOMP: Dither PD Enable */
906312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CTLANADLYPDCTL, 1 << 30, 1 << 30);
907b829f12aSBin Meng 	/* TCO: Dither PU Enable */
908312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANATCOPUCTL, 1 << 30, 1 << 30);
909b829f12aSBin Meng 	/* TCO: Dither PD Enable */
910312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQANATCOPDCTL, 1 << 30, 1 << 30);
911b829f12aSBin Meng 	/* TCO: Dither PU Enable */
912312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANATCOPUCTL, 1 << 30, 1 << 30);
913b829f12aSBin Meng 	/* TCO: Dither PD Enable */
914312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CLKANATCOPDCTL, 1 << 30, 1 << 30);
915b829f12aSBin Meng 	/* TCO: Dither PU Enable */
916312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANATCOPUCTL, 1 << 30, 1 << 30);
917b829f12aSBin Meng 	/* TCO: Dither PD Enable */
918312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, DQSANATCOPDCTL, 1 << 30, 1 << 30);
919b829f12aSBin Meng 	/* TCOCOMP: Pulse Count */
920312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, TCOCNTCTRL, 1, 3);
921b829f12aSBin Meng 	/* ODT: CMD/CTL PD/PU */
922312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CHNLBUFSTATIC,
923312cc39eSBin Meng 		(0x03 << 24) | (0x03 << 16), 0x1f1f0000);
924b829f12aSBin Meng 	/* Set 1us counter */
925312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, MSCNTR, 0x64, 0xff);
926312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, LATCH1CTL, 0x1 << 28, 0x70000000);
927b829f12aSBin Meng 
928b829f12aSBin Meng 	/* Release PHY from reset */
929312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, MASTERRSTN, 1, 1);
930b829f12aSBin Meng 
931b829f12aSBin Meng 	/* STEP1 */
932b829f12aSBin Meng 	mrc_post_code(0x03, 0x11);
933b829f12aSBin Meng 
934b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
935b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
936b829f12aSBin Meng 			/* DQ01-DQ23 */
937b829f12aSBin Meng 			for (bl_grp = 0;
938312cc39eSBin Meng 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
939b829f12aSBin Meng 			     bl_grp++) {
940b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
941312cc39eSBin Meng 					DQMDLLCTL +
942312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
943312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
944312cc39eSBin Meng 					1 << 13,
945312cc39eSBin Meng 					1 << 13);	/* Enable VREG */
946b829f12aSBin Meng 				delay_n(3);
947b829f12aSBin Meng 			}
948b829f12aSBin Meng 
949b829f12aSBin Meng 			/* ECC */
950312cc39eSBin Meng 			mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
951312cc39eSBin Meng 				1 << 13, 1 << 13);	/* Enable VREG */
952b829f12aSBin Meng 			delay_n(3);
953b829f12aSBin Meng 			/* CMD */
954b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
955312cc39eSBin Meng 				CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
956312cc39eSBin Meng 				1 << 13, 1 << 13);	/* Enable VREG */
957b829f12aSBin Meng 			delay_n(3);
958b829f12aSBin Meng 			/* CLK-CTL */
959b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
960312cc39eSBin Meng 				CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
961312cc39eSBin Meng 				1 << 13, 1 << 13);	/* Enable VREG */
962b829f12aSBin Meng 			delay_n(3);
963b829f12aSBin Meng 		}
964b829f12aSBin Meng 	}
965b829f12aSBin Meng 
966b829f12aSBin Meng 	/* STEP2 */
967b829f12aSBin Meng 	mrc_post_code(0x03, 0x12);
968b829f12aSBin Meng 	delay_n(200);
969b829f12aSBin Meng 
970b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
971b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
972b829f12aSBin Meng 			/* DQ01-DQ23 */
973b829f12aSBin Meng 			for (bl_grp = 0;
974312cc39eSBin Meng 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
975b829f12aSBin Meng 			     bl_grp++) {
976b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
977312cc39eSBin Meng 					DQMDLLCTL +
978312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
979312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
980312cc39eSBin Meng 					1 << 17,
981312cc39eSBin Meng 					1 << 17);	/* Enable MCDLL */
982b829f12aSBin Meng 				delay_n(50);
983b829f12aSBin Meng 			}
984b829f12aSBin Meng 
985b829f12aSBin Meng 		/* ECC */
986312cc39eSBin Meng 		mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
987312cc39eSBin Meng 			1 << 17, 1 << 17);	/* Enable MCDLL */
988b829f12aSBin Meng 		delay_n(50);
989b829f12aSBin Meng 		/* CMD */
990b829f12aSBin Meng 		mrc_alt_write_mask(DDRPHY,
991312cc39eSBin Meng 			CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
992312cc39eSBin Meng 			1 << 18, 1 << 18);	/* Enable MCDLL */
993b829f12aSBin Meng 		delay_n(50);
994b829f12aSBin Meng 		/* CLK-CTL */
995b829f12aSBin Meng 		mrc_alt_write_mask(DDRPHY,
996312cc39eSBin Meng 			CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
997312cc39eSBin Meng 			1 << 18, 1 << 18);	/* Enable MCDLL */
998b829f12aSBin Meng 		delay_n(50);
999b829f12aSBin Meng 		}
1000b829f12aSBin Meng 	}
1001b829f12aSBin Meng 
1002b829f12aSBin Meng 	/* STEP3: */
1003b829f12aSBin Meng 	mrc_post_code(0x03, 0x13);
1004b829f12aSBin Meng 	delay_n(100);
1005b829f12aSBin Meng 
1006b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1007b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1008b829f12aSBin Meng 			/* DQ01-DQ23 */
1009b829f12aSBin Meng 			for (bl_grp = 0;
1010312cc39eSBin Meng 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
1011b829f12aSBin Meng 			     bl_grp++) {
1012b829f12aSBin Meng #ifdef FORCE_16BIT_DDRIO
1013312cc39eSBin Meng 				temp = (bl_grp &&
1014b829f12aSBin Meng 					(mrc_params->channel_width == X16)) ?
1015312cc39eSBin Meng 					0x11ff : 0xffff;
1016b829f12aSBin Meng #else
1017312cc39eSBin Meng 				temp = 0xffff;
1018b829f12aSBin Meng #endif
1019b829f12aSBin Meng 				/* Enable TXDLL */
1020b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
1021312cc39eSBin Meng 					DQDLLTXCTL +
1022312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
1023312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
1024312cc39eSBin Meng 					temp, 0xffff);
1025b829f12aSBin Meng 				delay_n(3);
1026b829f12aSBin Meng 				/* Enable RXDLL */
1027b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
1028312cc39eSBin Meng 					DQDLLRXCTL +
1029312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
1030312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
1031312cc39eSBin Meng 					0xf, 0xf);
1032b829f12aSBin Meng 				delay_n(3);
1033b829f12aSBin Meng 				/* Enable RXDLL Overrides BL0 */
1034b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
1035312cc39eSBin Meng 					B0OVRCTL +
1036312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
1037312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
1038312cc39eSBin Meng 					0xf, 0xf);
1039b829f12aSBin Meng 			}
1040b829f12aSBin Meng 
1041b829f12aSBin Meng 			/* ECC */
1042312cc39eSBin Meng 			temp = 0xffff;
1043312cc39eSBin Meng 			mrc_alt_write_mask(DDRPHY, ECCDLLTXCTL,
1044312cc39eSBin Meng 				temp, 0xffff);
1045b829f12aSBin Meng 			delay_n(3);
1046b829f12aSBin Meng 
1047b829f12aSBin Meng 			/* CMD (PO) */
1048b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1049312cc39eSBin Meng 				CMDDLLTXCTL + ch * DDRIOCCC_CH_OFFSET,
1050312cc39eSBin Meng 				temp, 0xffff);
1051b829f12aSBin Meng 			delay_n(3);
1052b829f12aSBin Meng 		}
1053b829f12aSBin Meng 	}
1054b829f12aSBin Meng 
1055b829f12aSBin Meng 	/* STEP4 */
1056b829f12aSBin Meng 	mrc_post_code(0x03, 0x14);
1057b829f12aSBin Meng 
1058b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1059b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1060b829f12aSBin Meng 			/* Host To Memory Clock Alignment (HMC) for 800/1066 */
1061b829f12aSBin Meng 			for (bl_grp = 0;
1062312cc39eSBin Meng 			     bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
1063b829f12aSBin Meng 			     bl_grp++) {
1064b829f12aSBin Meng 				/* CLK_ALIGN_MOD_ID */
1065b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
1066312cc39eSBin Meng 					DQCLKALIGNREG2 +
1067312cc39eSBin Meng 					bl_grp * DDRIODQ_BL_OFFSET +
1068312cc39eSBin Meng 					ch * DDRIODQ_CH_OFFSET,
1069312cc39eSBin Meng 					bl_grp ? 3 : 1,
1070312cc39eSBin Meng 					0xf);
1071b829f12aSBin Meng 			}
1072b829f12aSBin Meng 
1073b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1074312cc39eSBin Meng 				ECCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1075312cc39eSBin Meng 				0x2, 0xf);
1076b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1077312cc39eSBin Meng 				CMDCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1078312cc39eSBin Meng 				0x0, 0xf);
1079b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1080312cc39eSBin Meng 				CCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1081312cc39eSBin Meng 				0x2, 0xf);
1082b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1083312cc39eSBin Meng 				CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1084312cc39eSBin Meng 				0x20, 0x30);
1085b829f12aSBin Meng 			/*
1086b829f12aSBin Meng 			 * NUM_SAMPLES, MAX_SAMPLES,
1087b829f12aSBin Meng 			 * MACRO_PI_STEP, MICRO_PI_STEP
1088b829f12aSBin Meng 			 */
1089b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1090312cc39eSBin Meng 				CMDCLKALIGNREG1 + ch * DDRIOCCC_CH_OFFSET,
1091312cc39eSBin Meng 				(0x18 << 16) | (0x10 << 8) |
1092312cc39eSBin Meng 				(0x8 << 2) | (0x1 << 0),
1093312cc39eSBin Meng 				0x007f7fff);
1094b829f12aSBin Meng 			/* TOTAL_NUM_MODULES, FIRST_U_PARTITION */
1095b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1096312cc39eSBin Meng 				CMDCLKALIGNREG2 + ch * DDRIOCCC_CH_OFFSET,
1097312cc39eSBin Meng 				(0x10 << 16) | (0x4 << 8) | (0x2 << 4),
1098312cc39eSBin Meng 				0x001f0ff0);
1099b829f12aSBin Meng #ifdef HMC_TEST
1100b829f12aSBin Meng 			/* START_CLK_ALIGN=1 */
1101b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1102312cc39eSBin Meng 				CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1103312cc39eSBin Meng 				1 << 24, 1 << 24);
1104b829f12aSBin Meng 			while (msg_port_alt_read(DDRPHY,
1105312cc39eSBin Meng 				CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET) &
1106312cc39eSBin Meng 				(1 << 24))
1107b829f12aSBin Meng 				;	/* wait for START_CLK_ALIGN=0 */
1108b829f12aSBin Meng #endif
1109b829f12aSBin Meng 
1110b829f12aSBin Meng 			/* Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN */
1111b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1112312cc39eSBin Meng 				CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
1113312cc39eSBin Meng 				1, 1);	/* WRPTRENABLE=1 */
1114b829f12aSBin Meng 
1115b829f12aSBin Meng 			/* COMP initial */
1116b829f12aSBin Meng 			/* enable bypass for CLK buffer (PO) */
1117b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1118312cc39eSBin Meng 				COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1119312cc39eSBin Meng 				1 << 5, 1 << 5);
1120b829f12aSBin Meng 			/* Initial COMP Enable */
1121312cc39eSBin Meng 			mrc_alt_write_mask(DDRPHY, CMPCTRL, 1, 1);
1122b829f12aSBin Meng 			/* wait for Initial COMP Enable = 0 */
1123312cc39eSBin Meng 			while (msg_port_alt_read(DDRPHY, CMPCTRL) & 1)
1124b829f12aSBin Meng 				;
1125b829f12aSBin Meng 			/* disable bypass for CLK buffer (PO) */
1126b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1127312cc39eSBin Meng 				COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1128312cc39eSBin Meng 				~(1 << 5), 1 << 5);
1129b829f12aSBin Meng 
1130b829f12aSBin Meng 			/* IOBUFACT */
1131b829f12aSBin Meng 
1132b829f12aSBin Meng 			/* STEP4a */
1133b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1134312cc39eSBin Meng 				CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
1135312cc39eSBin Meng 				1 << 2, 1 << 2);	/* IOBUFACTRST_N=1 */
1136b829f12aSBin Meng 
1137b829f12aSBin Meng 			/* DDRPHY initialization complete */
1138b829f12aSBin Meng 			mrc_alt_write_mask(DDRPHY,
1139312cc39eSBin Meng 				CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
1140312cc39eSBin Meng 				1 << 20, 1 << 20);	/* SPID_INIT_COMPLETE=1 */
1141b829f12aSBin Meng 		}
1142b829f12aSBin Meng 	}
1143b829f12aSBin Meng 
1144b829f12aSBin Meng 	LEAVEFN();
1145b829f12aSBin Meng }
1146b829f12aSBin Meng 
1147b829f12aSBin Meng /* This function performs JEDEC initialization on all enabled channels */
perform_jedec_init(struct mrc_params * mrc_params)1148b829f12aSBin Meng void perform_jedec_init(struct mrc_params *mrc_params)
1149b829f12aSBin Meng {
1150b829f12aSBin Meng 	uint8_t twr, wl, rank;
1151b829f12aSBin Meng 	uint32_t tck;
1152b829f12aSBin Meng 	u32 dtr0;
1153b829f12aSBin Meng 	u32 drp;
1154b829f12aSBin Meng 	u32 drmc;
1155b829f12aSBin Meng 	u32 mrs0_cmd = 0;
1156b829f12aSBin Meng 	u32 emrs1_cmd = 0;
1157b829f12aSBin Meng 	u32 emrs2_cmd = 0;
1158b829f12aSBin Meng 	u32 emrs3_cmd = 0;
1159b829f12aSBin Meng 
1160b829f12aSBin Meng 	ENTERFN();
1161b829f12aSBin Meng 
1162b829f12aSBin Meng 	/* jedec_init starts */
1163b829f12aSBin Meng 	mrc_post_code(0x04, 0x00);
1164b829f12aSBin Meng 
1165b829f12aSBin Meng 	/* DDR3_RESET_SET=0, DDR3_RESET_RESET=1 */
1166312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 2, 0x102);
1167b829f12aSBin Meng 
1168b829f12aSBin Meng 	/* Assert RESET# for 200us */
1169b829f12aSBin Meng 	delay_u(200);
1170b829f12aSBin Meng 
1171b829f12aSBin Meng 	/* DDR3_RESET_SET=1, DDR3_RESET_RESET=0 */
1172312cc39eSBin Meng 	mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 0x100, 0x102);
1173b829f12aSBin Meng 
1174b829f12aSBin Meng 	dtr0 = msg_port_read(MEM_CTLR, DTR0);
1175b829f12aSBin Meng 
1176b829f12aSBin Meng 	/*
1177b829f12aSBin Meng 	 * Set CKEVAL for populated ranks
1178b829f12aSBin Meng 	 * then send NOP to each rank (#4550197)
1179b829f12aSBin Meng 	 */
1180b829f12aSBin Meng 
1181b829f12aSBin Meng 	drp = msg_port_read(MEM_CTLR, DRP);
1182b829f12aSBin Meng 	drp &= 0x3;
1183b829f12aSBin Meng 
1184b829f12aSBin Meng 	drmc = msg_port_read(MEM_CTLR, DRMC);
1185312cc39eSBin Meng 	drmc &= 0xfffffffc;
1186312cc39eSBin Meng 	drmc |= (DRMC_CKEMODE | drp);
1187b829f12aSBin Meng 
1188b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRMC, drmc);
1189b829f12aSBin Meng 
1190b829f12aSBin Meng 	for (rank = 0; rank < NUM_RANKS; rank++) {
1191b829f12aSBin Meng 		/* Skip to next populated rank */
1192b829f12aSBin Meng 		if ((mrc_params->rank_enables & (1 << rank)) == 0)
1193b829f12aSBin Meng 			continue;
1194b829f12aSBin Meng 
1195b829f12aSBin Meng 		dram_init_command(DCMD_NOP(rank));
1196b829f12aSBin Meng 	}
1197b829f12aSBin Meng 
1198b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRMC,
1199312cc39eSBin Meng 		(mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0));
1200b829f12aSBin Meng 
1201b829f12aSBin Meng 	/*
1202b829f12aSBin Meng 	 * setup for emrs 2
1203b829f12aSBin Meng 	 * BIT[15:11] --> Always "0"
1204b829f12aSBin Meng 	 * BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
1205b829f12aSBin Meng 	 * BIT[08]    --> Always "0"
1206b829f12aSBin Meng 	 * BIT[07]    --> SRT: use sr_temp_range
1207b829f12aSBin Meng 	 * BIT[06]    --> ASR: want "Manual SR Reference" (0)
1208b829f12aSBin Meng 	 * BIT[05:03] --> CWL: use oem_tCWL
1209b829f12aSBin Meng 	 * BIT[02:00] --> PASR: want "Full Array" (0)
1210b829f12aSBin Meng 	 */
1211b829f12aSBin Meng 	emrs2_cmd |= (2 << 3);
1212b829f12aSBin Meng 	wl = 5 + mrc_params->ddr_speed;
1213b829f12aSBin Meng 	emrs2_cmd |= ((wl - 5) << 9);
1214b829f12aSBin Meng 	emrs2_cmd |= (mrc_params->sr_temp_range << 13);
1215b829f12aSBin Meng 
1216b829f12aSBin Meng 	/*
1217b829f12aSBin Meng 	 * setup for emrs 3
1218b829f12aSBin Meng 	 * BIT[15:03] --> Always "0"
1219b829f12aSBin Meng 	 * BIT[02]    --> MPR: want "Normal Operation" (0)
1220b829f12aSBin Meng 	 * BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
1221b829f12aSBin Meng 	 */
1222b829f12aSBin Meng 	emrs3_cmd |= (3 << 3);
1223b829f12aSBin Meng 
1224b829f12aSBin Meng 	/*
1225b829f12aSBin Meng 	 * setup for emrs 1
1226b829f12aSBin Meng 	 * BIT[15:13]     --> Always "0"
1227b829f12aSBin Meng 	 * BIT[12:12]     --> Qoff: want "Output Buffer Enabled" (0)
1228b829f12aSBin Meng 	 * BIT[11:11]     --> TDQS: want "Disabled" (0)
1229b829f12aSBin Meng 	 * BIT[10:10]     --> Always "0"
1230b829f12aSBin Meng 	 * BIT[09,06,02]  --> Rtt_nom: use rtt_nom_value
1231b829f12aSBin Meng 	 * BIT[08]        --> Always "0"
1232b829f12aSBin Meng 	 * BIT[07]        --> WR_LVL: want "Disabled" (0)
1233b829f12aSBin Meng 	 * BIT[05,01]     --> DIC: use ron_value
1234b829f12aSBin Meng 	 * BIT[04:03]     --> AL: additive latency want "0" (0)
1235b829f12aSBin Meng 	 * BIT[00]        --> DLL: want "Enable" (0)
1236b829f12aSBin Meng 	 *
1237b829f12aSBin Meng 	 * (BIT5|BIT1) set Ron value
1238b829f12aSBin Meng 	 * 00 --> RZQ/6 (40ohm)
1239b829f12aSBin Meng 	 * 01 --> RZQ/7 (34ohm)
1240b829f12aSBin Meng 	 * 1* --> RESERVED
1241b829f12aSBin Meng 	 *
1242b829f12aSBin Meng 	 * (BIT9|BIT6|BIT2) set Rtt_nom value
1243b829f12aSBin Meng 	 * 000 --> Disabled
1244b829f12aSBin Meng 	 * 001 --> RZQ/4 ( 60ohm)
1245b829f12aSBin Meng 	 * 010 --> RZQ/2 (120ohm)
1246b829f12aSBin Meng 	 * 011 --> RZQ/6 ( 40ohm)
1247b829f12aSBin Meng 	 * 1** --> RESERVED
1248b829f12aSBin Meng 	 */
1249b829f12aSBin Meng 	emrs1_cmd |= (1 << 3);
1250312cc39eSBin Meng 	emrs1_cmd &= ~(1 << 6);
1251b829f12aSBin Meng 
1252b829f12aSBin Meng 	if (mrc_params->ron_value == 0)
1253312cc39eSBin Meng 		emrs1_cmd |= (1 << 7);
1254b829f12aSBin Meng 	else
1255312cc39eSBin Meng 		emrs1_cmd &= ~(1 << 7);
1256b829f12aSBin Meng 
1257b829f12aSBin Meng 	if (mrc_params->rtt_nom_value == 0)
1258b829f12aSBin Meng 		emrs1_cmd |= (DDR3_EMRS1_RTTNOM_40 << 6);
1259b829f12aSBin Meng 	else if (mrc_params->rtt_nom_value == 1)
1260b829f12aSBin Meng 		emrs1_cmd |= (DDR3_EMRS1_RTTNOM_60 << 6);
1261b829f12aSBin Meng 	else if (mrc_params->rtt_nom_value == 2)
1262b829f12aSBin Meng 		emrs1_cmd |= (DDR3_EMRS1_RTTNOM_120 << 6);
1263b829f12aSBin Meng 
1264b829f12aSBin Meng 	/* save MRS1 value (excluding control fields) */
1265b829f12aSBin Meng 	mrc_params->mrs1 = emrs1_cmd >> 6;
1266b829f12aSBin Meng 
1267b829f12aSBin Meng 	/*
1268b829f12aSBin Meng 	 * setup for mrs 0
1269b829f12aSBin Meng 	 * BIT[15:13]     --> Always "0"
1270b829f12aSBin Meng 	 * BIT[12]        --> PPD: for Quark (1)
1271b829f12aSBin Meng 	 * BIT[11:09]     --> WR: use oem_tWR
1272b829f12aSBin Meng 	 * BIT[08]        --> DLL: want "Reset" (1, self clearing)
1273b829f12aSBin Meng 	 * BIT[07]        --> MODE: want "Normal" (0)
1274b829f12aSBin Meng 	 * BIT[06:04,02]  --> CL: use oem_tCAS
1275b829f12aSBin Meng 	 * BIT[03]        --> RD_BURST_TYPE: want "Interleave" (1)
1276b829f12aSBin Meng 	 * BIT[01:00]     --> BL: want "8 Fixed" (0)
1277b829f12aSBin Meng 	 * WR:
1278b829f12aSBin Meng 	 * 0 --> 16
1279b829f12aSBin Meng 	 * 1 --> 5
1280b829f12aSBin Meng 	 * 2 --> 6
1281b829f12aSBin Meng 	 * 3 --> 7
1282b829f12aSBin Meng 	 * 4 --> 8
1283b829f12aSBin Meng 	 * 5 --> 10
1284b829f12aSBin Meng 	 * 6 --> 12
1285b829f12aSBin Meng 	 * 7 --> 14
1286b829f12aSBin Meng 	 * CL:
1287b829f12aSBin Meng 	 * BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
1288b829f12aSBin Meng 	 * BIT[06:04] use oem_tCAS-4
1289b829f12aSBin Meng 	 */
1290312cc39eSBin Meng 	mrs0_cmd |= (1 << 14);
1291312cc39eSBin Meng 	mrs0_cmd |= (1 << 18);
1292b829f12aSBin Meng 	mrs0_cmd |= ((((dtr0 >> 12) & 7) + 1) << 10);
1293b829f12aSBin Meng 
1294b829f12aSBin Meng 	tck = t_ck[mrc_params->ddr_speed];
1295b829f12aSBin Meng 	/* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
1296b829f12aSBin Meng 	twr = MCEIL(15000, tck);
1297b829f12aSBin Meng 	mrs0_cmd |= ((twr - 4) << 15);
1298b829f12aSBin Meng 
1299b829f12aSBin Meng 	for (rank = 0; rank < NUM_RANKS; rank++) {
1300b829f12aSBin Meng 		/* Skip to next populated rank */
1301b829f12aSBin Meng 		if ((mrc_params->rank_enables & (1 << rank)) == 0)
1302b829f12aSBin Meng 			continue;
1303b829f12aSBin Meng 
1304b829f12aSBin Meng 		emrs2_cmd |= (rank << 22);
1305b829f12aSBin Meng 		dram_init_command(emrs2_cmd);
1306b829f12aSBin Meng 
1307b829f12aSBin Meng 		emrs3_cmd |= (rank << 22);
1308b829f12aSBin Meng 		dram_init_command(emrs3_cmd);
1309b829f12aSBin Meng 
1310b829f12aSBin Meng 		emrs1_cmd |= (rank << 22);
1311b829f12aSBin Meng 		dram_init_command(emrs1_cmd);
1312b829f12aSBin Meng 
1313b829f12aSBin Meng 		mrs0_cmd |= (rank << 22);
1314b829f12aSBin Meng 		dram_init_command(mrs0_cmd);
1315b829f12aSBin Meng 
1316b829f12aSBin Meng 		dram_init_command(DCMD_ZQCL(rank));
1317b829f12aSBin Meng 	}
1318b829f12aSBin Meng 
1319b829f12aSBin Meng 	LEAVEFN();
1320b829f12aSBin Meng }
1321b829f12aSBin Meng 
1322b829f12aSBin Meng /*
1323b829f12aSBin Meng  * Dunit Initialization Complete
1324b829f12aSBin Meng  *
1325b829f12aSBin Meng  * Indicates that initialization of the Dunit has completed.
1326b829f12aSBin Meng  *
1327b829f12aSBin Meng  * Memory accesses are permitted and maintenance operation begins.
1328b829f12aSBin Meng  * Until this bit is set to a 1, the memory controller will not accept
1329b829f12aSBin Meng  * DRAM requests from the MEMORY_MANAGER or HTE.
1330b829f12aSBin Meng  */
set_ddr_init_complete(struct mrc_params * mrc_params)1331b829f12aSBin Meng void set_ddr_init_complete(struct mrc_params *mrc_params)
1332b829f12aSBin Meng {
1333b829f12aSBin Meng 	u32 dco;
1334b829f12aSBin Meng 
1335b829f12aSBin Meng 	ENTERFN();
1336b829f12aSBin Meng 
1337b829f12aSBin Meng 	dco = msg_port_read(MEM_CTLR, DCO);
1338312cc39eSBin Meng 	dco &= ~DCO_PMICTL;
1339312cc39eSBin Meng 	dco |= DCO_IC;
1340b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DCO, dco);
1341b829f12aSBin Meng 
1342b829f12aSBin Meng 	LEAVEFN();
1343b829f12aSBin Meng }
1344b829f12aSBin Meng 
1345b829f12aSBin Meng /*
1346b829f12aSBin Meng  * This function will retrieve relevant timing data
1347b829f12aSBin Meng  *
1348b829f12aSBin Meng  * This data will be used on subsequent boots to speed up boot times
1349b829f12aSBin Meng  * and is required for Suspend To RAM capabilities.
1350b829f12aSBin Meng  */
restore_timings(struct mrc_params * mrc_params)1351b829f12aSBin Meng void restore_timings(struct mrc_params *mrc_params)
1352b829f12aSBin Meng {
1353b829f12aSBin Meng 	uint8_t ch, rk, bl;
1354b829f12aSBin Meng 	const struct mrc_timings *mt = &mrc_params->timings;
1355b829f12aSBin Meng 
1356b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1357b829f12aSBin Meng 		for (rk = 0; rk < NUM_RANKS; rk++) {
1358b829f12aSBin Meng 			for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1359b829f12aSBin Meng 				set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]);
1360b829f12aSBin Meng 				set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]);
1361b829f12aSBin Meng 				set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]);
1362b829f12aSBin Meng 				set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);
1363b829f12aSBin Meng 				if (rk == 0) {
1364b829f12aSBin Meng 					/* VREF (RANK0 only) */
1365b829f12aSBin Meng 					set_vref(ch, bl, mt->vref[ch][bl]);
1366b829f12aSBin Meng 				}
1367b829f12aSBin Meng 			}
1368b829f12aSBin Meng 			set_wctl(ch, rk, mt->wctl[ch][rk]);
1369b829f12aSBin Meng 		}
1370b829f12aSBin Meng 		set_wcmd(ch, mt->wcmd[ch]);
1371b829f12aSBin Meng 	}
1372b829f12aSBin Meng }
1373b829f12aSBin Meng 
1374b829f12aSBin Meng /*
1375b829f12aSBin Meng  * Configure default settings normally set as part of read training
1376b829f12aSBin Meng  *
1377b829f12aSBin Meng  * Some defaults have to be set earlier as they may affect earlier
1378b829f12aSBin Meng  * training steps.
1379b829f12aSBin Meng  */
default_timings(struct mrc_params * mrc_params)1380b829f12aSBin Meng void default_timings(struct mrc_params *mrc_params)
1381b829f12aSBin Meng {
1382b829f12aSBin Meng 	uint8_t ch, rk, bl;
1383b829f12aSBin Meng 
1384b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1385b829f12aSBin Meng 		for (rk = 0; rk < NUM_RANKS; rk++) {
1386b829f12aSBin Meng 			for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1387b829f12aSBin Meng 				set_rdqs(ch, rk, bl, 24);
1388b829f12aSBin Meng 				if (rk == 0) {
1389b829f12aSBin Meng 					/* VREF (RANK0 only) */
1390b829f12aSBin Meng 					set_vref(ch, bl, 32);
1391b829f12aSBin Meng 				}
1392b829f12aSBin Meng 			}
1393b829f12aSBin Meng 		}
1394b829f12aSBin Meng 	}
1395b829f12aSBin Meng }
1396b829f12aSBin Meng 
1397b829f12aSBin Meng /*
1398b829f12aSBin Meng  * This function will perform our RCVEN Calibration Algorithm.
1399b829f12aSBin Meng  * We will only use the 2xCLK domain timings to perform RCVEN Calibration.
1400b829f12aSBin Meng  * All byte lanes will be calibrated "simultaneously" per channel per rank.
1401b829f12aSBin Meng  */
rcvn_cal(struct mrc_params * mrc_params)1402b829f12aSBin Meng void rcvn_cal(struct mrc_params *mrc_params)
1403b829f12aSBin Meng {
1404b829f12aSBin Meng 	uint8_t ch;	/* channel counter */
1405b829f12aSBin Meng 	uint8_t rk;	/* rank counter */
1406b829f12aSBin Meng 	uint8_t bl;	/* byte lane counter */
1407b829f12aSBin Meng 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1408b829f12aSBin Meng 
1409b829f12aSBin Meng #ifdef R2R_SHARING
1410b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
1411b829f12aSBin Meng 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1412b829f12aSBin Meng #ifndef BACKUP_RCVN
1413b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
1414b829f12aSBin Meng 	uint32_t num_ranks_enabled = 0;
1415b829f12aSBin Meng #endif
1416b829f12aSBin Meng #endif
1417b829f12aSBin Meng 
1418b829f12aSBin Meng #ifdef BACKUP_RCVN
1419b829f12aSBin Meng #else
1420b829f12aSBin Meng 	uint32_t temp;
1421b829f12aSBin Meng 	/* absolute PI value to be programmed on the byte lane */
1422b829f12aSBin Meng 	uint32_t delay[NUM_BYTE_LANES];
1423b829f12aSBin Meng 	u32 dtr1, dtr1_save;
1424b829f12aSBin Meng #endif
1425b829f12aSBin Meng 
1426b829f12aSBin Meng 	ENTERFN();
1427b829f12aSBin Meng 
1428b829f12aSBin Meng 	/* rcvn_cal starts */
1429b829f12aSBin Meng 	mrc_post_code(0x05, 0x00);
1430b829f12aSBin Meng 
1431b829f12aSBin Meng #ifndef BACKUP_RCVN
1432b829f12aSBin Meng 	/* need separate burst to sample DQS preamble */
1433b829f12aSBin Meng 	dtr1 = msg_port_read(MEM_CTLR, DTR1);
1434b829f12aSBin Meng 	dtr1_save = dtr1;
1435312cc39eSBin Meng 	dtr1 |= DTR1_TCCD_12CLK;
1436b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR1, dtr1);
1437b829f12aSBin Meng #endif
1438b829f12aSBin Meng 
1439b829f12aSBin Meng #ifdef R2R_SHARING
1440b829f12aSBin Meng 	/* need to set "final_delay[][]" elements to "0" */
1441b829f12aSBin Meng 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1442b829f12aSBin Meng #endif
1443b829f12aSBin Meng 
1444b829f12aSBin Meng 	/* loop through each enabled channel */
1445b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1446b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1447b829f12aSBin Meng 			/* perform RCVEN Calibration on a per rank basis */
1448b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
1449b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
1450b829f12aSBin Meng 					/*
1451b829f12aSBin Meng 					 * POST_CODE here indicates the current
1452b829f12aSBin Meng 					 * channel and rank being calibrated
1453b829f12aSBin Meng 					 */
1454312cc39eSBin Meng 					mrc_post_code(0x05, 0x10 + ((ch << 4) | rk));
1455b829f12aSBin Meng 
1456b829f12aSBin Meng #ifdef BACKUP_RCVN
1457b829f12aSBin Meng 					/* et hard-coded timing values */
1458b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++)
1459b829f12aSBin Meng 						set_rcvn(ch, rk, bl, ddr_rcvn[PLATFORM_ID]);
1460b829f12aSBin Meng #else
1461b829f12aSBin Meng 					/* enable FIFORST */
1462b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1463b829f12aSBin Meng 						mrc_alt_write_mask(DDRPHY,
1464312cc39eSBin Meng 							B01PTRCTL1 +
1465312cc39eSBin Meng 							(bl >> 1) * DDRIODQ_BL_OFFSET +
1466312cc39eSBin Meng 							ch * DDRIODQ_CH_OFFSET,
1467312cc39eSBin Meng 							0, 1 << 8);
1468b829f12aSBin Meng 					}
1469b829f12aSBin Meng 					/* initialize the starting delay to 128 PI (cas +1 CLK) */
1470b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1471b829f12aSBin Meng 						/* 1x CLK domain timing is cas-4 */
1472b829f12aSBin Meng 						delay[bl] = (4 + 1) * FULL_CLK;
1473b829f12aSBin Meng 
1474b829f12aSBin Meng 						set_rcvn(ch, rk, bl, delay[bl]);
1475b829f12aSBin Meng 					}
1476b829f12aSBin Meng 
1477b829f12aSBin Meng 					/* now find the rising edge */
1478b829f12aSBin Meng 					find_rising_edge(mrc_params, delay, ch, rk, true);
1479b829f12aSBin Meng 
1480b829f12aSBin Meng 					/* Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse */
1481b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1482b829f12aSBin Meng 						delay[bl] += QRTR_CLK;
1483b829f12aSBin Meng 						set_rcvn(ch, rk, bl, delay[bl]);
1484b829f12aSBin Meng 					}
1485b829f12aSBin Meng 					/* Now decrement delay by 128 PI (1 CLK) until we sample a "0" */
1486b829f12aSBin Meng 					do {
1487b829f12aSBin Meng 						temp = sample_dqs(mrc_params, ch, rk, true);
1488b829f12aSBin Meng 						for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1489b829f12aSBin Meng 							if (temp & (1 << bl)) {
1490b829f12aSBin Meng 								if (delay[bl] >= FULL_CLK) {
1491b829f12aSBin Meng 									delay[bl] -= FULL_CLK;
1492b829f12aSBin Meng 									set_rcvn(ch, rk, bl, delay[bl]);
1493b829f12aSBin Meng 								} else {
1494b829f12aSBin Meng 									/* not enough delay */
1495b829f12aSBin Meng 									training_message(ch, rk, bl);
1496312cc39eSBin Meng 									mrc_post_code(0xee, 0x50);
1497b829f12aSBin Meng 								}
1498b829f12aSBin Meng 							}
1499b829f12aSBin Meng 						}
1500312cc39eSBin Meng 					} while (temp & 0xff);
1501b829f12aSBin Meng 
1502b829f12aSBin Meng #ifdef R2R_SHARING
1503b829f12aSBin Meng 					/* increment "num_ranks_enabled" */
1504b829f12aSBin Meng 					num_ranks_enabled++;
1505b829f12aSBin Meng 					/* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1506b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1507b829f12aSBin Meng 						delay[bl] += QRTR_CLK;
1508b829f12aSBin Meng 						/* add "delay[]" values to "final_delay[][]" for rolling average */
1509b829f12aSBin Meng 						final_delay[ch][bl] += delay[bl];
1510b829f12aSBin Meng 						/* set timing based on rolling average values */
1511312cc39eSBin Meng 						set_rcvn(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
1512b829f12aSBin Meng 					}
1513b829f12aSBin Meng #else
1514b829f12aSBin Meng 					/* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1515b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1516b829f12aSBin Meng 						delay[bl] += QRTR_CLK;
1517b829f12aSBin Meng 						set_rcvn(ch, rk, bl, delay[bl]);
1518b829f12aSBin Meng 					}
1519b829f12aSBin Meng #endif
1520b829f12aSBin Meng 
1521b829f12aSBin Meng 					/* disable FIFORST */
1522b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1523b829f12aSBin Meng 						mrc_alt_write_mask(DDRPHY,
1524312cc39eSBin Meng 							B01PTRCTL1 +
1525312cc39eSBin Meng 							(bl >> 1) * DDRIODQ_BL_OFFSET +
1526312cc39eSBin Meng 							ch * DDRIODQ_CH_OFFSET,
1527312cc39eSBin Meng 							1 << 8, 1 << 8);
1528b829f12aSBin Meng 					}
1529b829f12aSBin Meng #endif
1530b829f12aSBin Meng 				}
1531b829f12aSBin Meng 			}
1532b829f12aSBin Meng 		}
1533b829f12aSBin Meng 	}
1534b829f12aSBin Meng 
1535b829f12aSBin Meng #ifndef BACKUP_RCVN
1536b829f12aSBin Meng 	/* restore original */
1537b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DTR1, dtr1_save);
1538b829f12aSBin Meng #endif
1539b829f12aSBin Meng 
1540b829f12aSBin Meng 	LEAVEFN();
1541b829f12aSBin Meng }
1542b829f12aSBin Meng 
1543b829f12aSBin Meng /*
1544b829f12aSBin Meng  * This function will perform the Write Levelling algorithm
1545b829f12aSBin Meng  * (align WCLK and WDQS).
1546b829f12aSBin Meng  *
1547b829f12aSBin Meng  * This algorithm will act on each rank in each channel separately.
1548b829f12aSBin Meng  */
wr_level(struct mrc_params * mrc_params)1549b829f12aSBin Meng void wr_level(struct mrc_params *mrc_params)
1550b829f12aSBin Meng {
1551b829f12aSBin Meng 	uint8_t ch;	/* channel counter */
1552b829f12aSBin Meng 	uint8_t rk;	/* rank counter */
1553b829f12aSBin Meng 	uint8_t bl;	/* byte lane counter */
1554b829f12aSBin Meng 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1555b829f12aSBin Meng 
1556b829f12aSBin Meng #ifdef R2R_SHARING
1557b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
1558b829f12aSBin Meng 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1559b829f12aSBin Meng #ifndef BACKUP_WDQS
1560b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
1561b829f12aSBin Meng 	uint32_t num_ranks_enabled = 0;
1562b829f12aSBin Meng #endif
1563b829f12aSBin Meng #endif
1564b829f12aSBin Meng 
1565b829f12aSBin Meng #ifdef BACKUP_WDQS
1566b829f12aSBin Meng #else
1567b829f12aSBin Meng 	/* determines stop condition for CRS_WR_LVL */
1568b829f12aSBin Meng 	bool all_edges_found;
1569b829f12aSBin Meng 	/* absolute PI value to be programmed on the byte lane */
1570b829f12aSBin Meng 	uint32_t delay[NUM_BYTE_LANES];
1571b829f12aSBin Meng 	/*
1572b829f12aSBin Meng 	 * static makes it so the data is loaded in the heap once by shadow(),
1573b829f12aSBin Meng 	 * where non-static copies the data onto the stack every time this
1574b829f12aSBin Meng 	 * function is called
1575b829f12aSBin Meng 	 */
1576b829f12aSBin Meng 	uint32_t address;	/* address to be checked during COARSE_WR_LVL */
1577b829f12aSBin Meng 	u32 dtr4, dtr4_save;
1578b829f12aSBin Meng #endif
1579b829f12aSBin Meng 
1580b829f12aSBin Meng 	ENTERFN();
1581b829f12aSBin Meng 
1582b829f12aSBin Meng 	/* wr_level starts */
1583b829f12aSBin Meng 	mrc_post_code(0x06, 0x00);
1584b829f12aSBin Meng 
1585b829f12aSBin Meng #ifdef R2R_SHARING
1586b829f12aSBin Meng 	/* need to set "final_delay[][]" elements to "0" */
1587b829f12aSBin Meng 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1588b829f12aSBin Meng #endif
1589b829f12aSBin Meng 
1590b829f12aSBin Meng 	/* loop through each enabled channel */
1591b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1592b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1593b829f12aSBin Meng 			/* perform WRITE LEVELING algorithm on a per rank basis */
1594b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
1595b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
1596b829f12aSBin Meng 					/*
1597b829f12aSBin Meng 					 * POST_CODE here indicates the current
1598b829f12aSBin Meng 					 * rank and channel being calibrated
1599b829f12aSBin Meng 					 */
1600312cc39eSBin Meng 					mrc_post_code(0x06, 0x10 + ((ch << 4) | rk));
1601b829f12aSBin Meng 
1602b829f12aSBin Meng #ifdef BACKUP_WDQS
1603b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1604b829f12aSBin Meng 						set_wdqs(ch, rk, bl, ddr_wdqs[PLATFORM_ID]);
1605312cc39eSBin Meng 						set_wdq(ch, rk, bl, ddr_wdqs[PLATFORM_ID] - QRTR_CLK);
1606b829f12aSBin Meng 					}
1607b829f12aSBin Meng #else
1608b829f12aSBin Meng 					/*
1609b829f12aSBin Meng 					 * perform a single PRECHARGE_ALL command to
1610b829f12aSBin Meng 					 * make DRAM state machine go to IDLE state
1611b829f12aSBin Meng 					 */
1612b829f12aSBin Meng 					dram_init_command(DCMD_PREA(rk));
1613b829f12aSBin Meng 
1614b829f12aSBin Meng 					/*
1615b829f12aSBin Meng 					 * enable Write Levelling Mode
1616b829f12aSBin Meng 					 * (EMRS1 w/ Write Levelling Mode Enable)
1617b829f12aSBin Meng 					 */
1618312cc39eSBin Meng 					dram_init_command(DCMD_MRS1(rk, 0x82));
1619b829f12aSBin Meng 
1620b829f12aSBin Meng 					/*
1621b829f12aSBin Meng 					 * set ODT DRAM Full Time Termination
1622b829f12aSBin Meng 					 * disable in MCU
1623b829f12aSBin Meng 					 */
1624b829f12aSBin Meng 
1625b829f12aSBin Meng 					dtr4 = msg_port_read(MEM_CTLR, DTR4);
1626b829f12aSBin Meng 					dtr4_save = dtr4;
1627312cc39eSBin Meng 					dtr4 |= DTR4_ODTDIS;
1628b829f12aSBin Meng 					msg_port_write(MEM_CTLR, DTR4, dtr4);
1629b829f12aSBin Meng 
1630312cc39eSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
1631b829f12aSBin Meng 						/*
1632b829f12aSBin Meng 						 * Enable Sandy Bridge Mode (WDQ Tri-State) &
1633b829f12aSBin Meng 						 * Ensure 5 WDQS pulses during Write Leveling
1634b829f12aSBin Meng 						 */
1635b829f12aSBin Meng 						mrc_alt_write_mask(DDRPHY,
1636312cc39eSBin Meng 							DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1637312cc39eSBin Meng 							0x10000154,
1638312cc39eSBin Meng 							0x100003fc);
1639b829f12aSBin Meng 					}
1640b829f12aSBin Meng 
1641b829f12aSBin Meng 					/* Write Leveling Mode enabled in IO */
1642b829f12aSBin Meng 					mrc_alt_write_mask(DDRPHY,
1643312cc39eSBin Meng 						CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1644312cc39eSBin Meng 						1 << 16, 1 << 16);
1645b829f12aSBin Meng 
1646b829f12aSBin Meng 					/* Initialize the starting delay to WCLK */
1647b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1648b829f12aSBin Meng 						/*
1649b829f12aSBin Meng 						 * CLK0 --> RK0
1650b829f12aSBin Meng 						 * CLK1 --> RK1
1651b829f12aSBin Meng 						 */
1652b829f12aSBin Meng 						delay[bl] = get_wclk(ch, rk);
1653b829f12aSBin Meng 
1654b829f12aSBin Meng 						set_wdqs(ch, rk, bl, delay[bl]);
1655b829f12aSBin Meng 					}
1656b829f12aSBin Meng 
1657b829f12aSBin Meng 					/* now find the rising edge */
1658b829f12aSBin Meng 					find_rising_edge(mrc_params, delay, ch, rk, false);
1659b829f12aSBin Meng 
1660b829f12aSBin Meng 					/* disable Write Levelling Mode */
1661b829f12aSBin Meng 					mrc_alt_write_mask(DDRPHY,
1662312cc39eSBin Meng 						CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1663312cc39eSBin Meng 						0, 1 << 16);
1664b829f12aSBin Meng 
1665312cc39eSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
1666b829f12aSBin Meng 						/* Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation */
1667b829f12aSBin Meng 						mrc_alt_write_mask(DDRPHY,
1668312cc39eSBin Meng 							DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1669312cc39eSBin Meng 							0x00000154,
1670312cc39eSBin Meng 							0x100003fc);
1671b829f12aSBin Meng 					}
1672b829f12aSBin Meng 
1673b829f12aSBin Meng 					/* restore original DTR4 */
1674b829f12aSBin Meng 					msg_port_write(MEM_CTLR, DTR4, dtr4_save);
1675b829f12aSBin Meng 
1676b829f12aSBin Meng 					/*
1677b829f12aSBin Meng 					 * restore original value
1678b829f12aSBin Meng 					 * (Write Levelling Mode Disable)
1679b829f12aSBin Meng 					 */
1680b829f12aSBin Meng 					dram_init_command(DCMD_MRS1(rk, mrc_params->mrs1));
1681b829f12aSBin Meng 
1682b829f12aSBin Meng 					/*
1683b829f12aSBin Meng 					 * perform a single PRECHARGE_ALL command to
1684b829f12aSBin Meng 					 * make DRAM state machine go to IDLE state
1685b829f12aSBin Meng 					 */
1686b829f12aSBin Meng 					dram_init_command(DCMD_PREA(rk));
1687b829f12aSBin Meng 
1688312cc39eSBin Meng 					mrc_post_code(0x06, 0x30 + ((ch << 4) | rk));
1689b829f12aSBin Meng 
1690b829f12aSBin Meng 					/*
1691b829f12aSBin Meng 					 * COARSE WRITE LEVEL:
1692b829f12aSBin Meng 					 * check that we're on the correct clock edge
1693b829f12aSBin Meng 					 */
1694b829f12aSBin Meng 
1695b829f12aSBin Meng 					/* hte reconfiguration request */
1696b829f12aSBin Meng 					mrc_params->hte_setup = 1;
1697b829f12aSBin Meng 
1698b829f12aSBin Meng 					/* start CRS_WR_LVL with WDQS = WDQS + 128 PI */
1699b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1700b829f12aSBin Meng 						delay[bl] = get_wdqs(ch, rk, bl) + FULL_CLK;
1701b829f12aSBin Meng 						set_wdqs(ch, rk, bl, delay[bl]);
1702b829f12aSBin Meng 						/*
1703b829f12aSBin Meng 						 * program WDQ timings based on WDQS
1704b829f12aSBin Meng 						 * (WDQ = WDQS - 32 PI)
1705b829f12aSBin Meng 						 */
1706b829f12aSBin Meng 						set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
1707b829f12aSBin Meng 					}
1708b829f12aSBin Meng 
1709b829f12aSBin Meng 					/* get an address in the targeted channel/rank */
1710b829f12aSBin Meng 					address = get_addr(ch, rk);
1711b829f12aSBin Meng 					do {
1712b829f12aSBin Meng 						uint32_t coarse_result = 0x00;
1713b829f12aSBin Meng 						uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
1714b829f12aSBin Meng 						/* assume pass */
1715b829f12aSBin Meng 						all_edges_found = true;
1716b829f12aSBin Meng 
1717b829f12aSBin Meng 						mrc_params->hte_setup = 1;
1718b829f12aSBin Meng 						coarse_result = check_rw_coarse(mrc_params, address);
1719b829f12aSBin Meng 
1720b829f12aSBin Meng 						/* check for failures and margin the byte lane back 128 PI (1 CLK) */
1721312cc39eSBin Meng 						for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1722b829f12aSBin Meng 							if (coarse_result & (coarse_result_mask << bl)) {
1723b829f12aSBin Meng 								all_edges_found = false;
1724b829f12aSBin Meng 								delay[bl] -= FULL_CLK;
1725b829f12aSBin Meng 								set_wdqs(ch, rk, bl, delay[bl]);
1726b829f12aSBin Meng 								/* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
1727312cc39eSBin Meng 								set_wdq(ch, rk, bl, delay[bl] - QRTR_CLK);
1728b829f12aSBin Meng 							}
1729b829f12aSBin Meng 						}
1730b829f12aSBin Meng 					} while (!all_edges_found);
1731b829f12aSBin Meng 
1732b829f12aSBin Meng #ifdef R2R_SHARING
1733b829f12aSBin Meng 					/* increment "num_ranks_enabled" */
1734b829f12aSBin Meng 					 num_ranks_enabled++;
1735b829f12aSBin Meng 					/* accumulate "final_delay[][]" values from "delay[]" values for rolling average */
1736312cc39eSBin Meng 					for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1737b829f12aSBin Meng 						final_delay[ch][bl] += delay[bl];
1738312cc39eSBin Meng 						set_wdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
1739b829f12aSBin Meng 						/* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
1740312cc39eSBin Meng 						set_wdq(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled - QRTR_CLK);
1741b829f12aSBin Meng 					}
1742b829f12aSBin Meng #endif
1743b829f12aSBin Meng #endif
1744b829f12aSBin Meng 				}
1745b829f12aSBin Meng 			}
1746b829f12aSBin Meng 		}
1747b829f12aSBin Meng 	}
1748b829f12aSBin Meng 
1749b829f12aSBin Meng 	LEAVEFN();
1750b829f12aSBin Meng }
1751b829f12aSBin Meng 
prog_page_ctrl(struct mrc_params * mrc_params)1752b829f12aSBin Meng void prog_page_ctrl(struct mrc_params *mrc_params)
1753b829f12aSBin Meng {
1754b829f12aSBin Meng 	u32 dpmc0;
1755b829f12aSBin Meng 
1756b829f12aSBin Meng 	ENTERFN();
1757b829f12aSBin Meng 
1758b829f12aSBin Meng 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
1759312cc39eSBin Meng 	dpmc0 &= ~DPMC0_PCLSTO_MASK;
1760b829f12aSBin Meng 	dpmc0 |= (4 << 16);
1761312cc39eSBin Meng 	dpmc0 |= DPMC0_PREAPWDEN;
1762b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
1763b829f12aSBin Meng }
1764b829f12aSBin Meng 
1765b829f12aSBin Meng /*
1766b829f12aSBin Meng  * This function will perform the READ TRAINING Algorithm on all
1767b829f12aSBin Meng  * channels/ranks/byte_lanes simultaneously to minimize execution time.
1768b829f12aSBin Meng  *
1769b829f12aSBin Meng  * The idea here is to train the VREF and RDQS (and eventually RDQ) values
1770b829f12aSBin Meng  * to achieve maximum READ margins. The algorithm will first determine the
1771b829f12aSBin Meng  * X coordinate (RDQS setting). This is done by collapsing the VREF eye
1772b829f12aSBin Meng  * until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
1773b829f12aSBin Meng  * Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX,
1774b829f12aSBin Meng  * then average those; this will be the final X coordinate. The algorithm
1775b829f12aSBin Meng  * will then determine the Y coordinate (VREF setting). This is done by
1776b829f12aSBin Meng  * collapsing the RDQS eye until we find a minimum required VREF eye for
1777b829f12aSBin Meng  * RDQS_MIN and RDQS_MAX. Then we take the averages of the VREF eye at
1778b829f12aSBin Meng  * RDQS_MIN and RDQS_MAX, then average those; this will be the final Y
1779b829f12aSBin Meng  * coordinate.
1780b829f12aSBin Meng  *
1781b829f12aSBin Meng  * NOTE: this algorithm assumes the eye curves have a one-to-one relationship,
1782b829f12aSBin Meng  * meaning for each X the curve has only one Y and vice-a-versa.
1783b829f12aSBin Meng  */
rd_train(struct mrc_params * mrc_params)1784b829f12aSBin Meng void rd_train(struct mrc_params *mrc_params)
1785b829f12aSBin Meng {
1786b829f12aSBin Meng 	uint8_t ch;	/* channel counter */
1787b829f12aSBin Meng 	uint8_t rk;	/* rank counter */
1788b829f12aSBin Meng 	uint8_t bl;	/* byte lane counter */
1789b829f12aSBin Meng 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1790b829f12aSBin Meng #ifdef BACKUP_RDQS
1791b829f12aSBin Meng #else
1792b829f12aSBin Meng 	uint8_t side_x;	/* tracks LEFT/RIGHT approach vectors */
1793b829f12aSBin Meng 	uint8_t side_y;	/* tracks BOTTOM/TOP approach vectors */
1794b829f12aSBin Meng 	/* X coordinate data (passing RDQS values) for approach vectors */
1795b829f12aSBin Meng 	uint8_t x_coordinate[2][2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1796b829f12aSBin Meng 	/* Y coordinate data (passing VREF values) for approach vectors */
1797b829f12aSBin Meng 	uint8_t y_coordinate[2][2][NUM_CHANNELS][NUM_BYTE_LANES];
1798b829f12aSBin Meng 	/* centered X (RDQS) */
1799b829f12aSBin Meng 	uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1800b829f12aSBin Meng 	/* centered Y (VREF) */
1801b829f12aSBin Meng 	uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES];
1802b829f12aSBin Meng 	uint32_t address;	/* target address for check_bls_ex() */
1803b829f12aSBin Meng 	uint32_t result;	/* result of check_bls_ex() */
1804b829f12aSBin Meng 	uint32_t bl_mask;	/* byte lane mask for result checking */
1805b829f12aSBin Meng #ifdef R2R_SHARING
1806b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
1807b829f12aSBin Meng 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1808b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
1809b829f12aSBin Meng 	uint32_t num_ranks_enabled = 0;
1810b829f12aSBin Meng #endif
1811b829f12aSBin Meng #endif
1812b829f12aSBin Meng 
1813b829f12aSBin Meng 	/* rd_train starts */
1814b829f12aSBin Meng 	mrc_post_code(0x07, 0x00);
1815b829f12aSBin Meng 
1816b829f12aSBin Meng 	ENTERFN();
1817b829f12aSBin Meng 
1818b829f12aSBin Meng #ifdef BACKUP_RDQS
1819b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1820b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1821b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
1822b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
1823b829f12aSBin Meng 					for (bl = 0;
1824312cc39eSBin Meng 					     bl < NUM_BYTE_LANES / bl_divisor;
1825b829f12aSBin Meng 					     bl++) {
1826b829f12aSBin Meng 						set_rdqs(ch, rk, bl, ddr_rdqs[PLATFORM_ID]);
1827b829f12aSBin Meng 					}
1828b829f12aSBin Meng 				}
1829b829f12aSBin Meng 			}
1830b829f12aSBin Meng 		}
1831b829f12aSBin Meng 	}
1832b829f12aSBin Meng #else
1833b829f12aSBin Meng 	/* initialize x/y_coordinate arrays */
1834b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1835b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1836b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
1837b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
1838b829f12aSBin Meng 					for (bl = 0;
1839312cc39eSBin Meng 					     bl < NUM_BYTE_LANES / bl_divisor;
1840b829f12aSBin Meng 					     bl++) {
1841b829f12aSBin Meng 						/* x_coordinate */
1842b829f12aSBin Meng 						x_coordinate[L][B][ch][rk][bl] = RDQS_MIN;
1843b829f12aSBin Meng 						x_coordinate[R][B][ch][rk][bl] = RDQS_MAX;
1844b829f12aSBin Meng 						x_coordinate[L][T][ch][rk][bl] = RDQS_MIN;
1845b829f12aSBin Meng 						x_coordinate[R][T][ch][rk][bl] = RDQS_MAX;
1846b829f12aSBin Meng 						/* y_coordinate */
1847b829f12aSBin Meng 						y_coordinate[L][B][ch][bl] = VREF_MIN;
1848b829f12aSBin Meng 						y_coordinate[R][B][ch][bl] = VREF_MIN;
1849b829f12aSBin Meng 						y_coordinate[L][T][ch][bl] = VREF_MAX;
1850b829f12aSBin Meng 						y_coordinate[R][T][ch][bl] = VREF_MAX;
1851b829f12aSBin Meng 					}
1852b829f12aSBin Meng 				}
1853b829f12aSBin Meng 			}
1854b829f12aSBin Meng 		}
1855b829f12aSBin Meng 	}
1856b829f12aSBin Meng 
1857b829f12aSBin Meng 	/* initialize other variables */
1858b829f12aSBin Meng 	bl_mask = byte_lane_mask(mrc_params);
1859b829f12aSBin Meng 	address = get_addr(0, 0);
1860b829f12aSBin Meng 
1861b829f12aSBin Meng #ifdef R2R_SHARING
1862b829f12aSBin Meng 	/* need to set "final_delay[][]" elements to "0" */
1863b829f12aSBin Meng 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1864b829f12aSBin Meng #endif
1865b829f12aSBin Meng 
1866b829f12aSBin Meng 	/* look for passing coordinates */
1867b829f12aSBin Meng 	for (side_y = B; side_y <= T; side_y++) {
1868b829f12aSBin Meng 		for (side_x = L; side_x <= R; side_x++) {
1869312cc39eSBin Meng 			mrc_post_code(0x07, 0x10 + side_y * 2 + side_x);
1870b829f12aSBin Meng 
1871b829f12aSBin Meng 			/* find passing values */
1872b829f12aSBin Meng 			for (ch = 0; ch < NUM_CHANNELS; ch++) {
1873b829f12aSBin Meng 				if (mrc_params->channel_enables & (0x1 << ch)) {
1874b829f12aSBin Meng 					for (rk = 0; rk < NUM_RANKS; rk++) {
1875b829f12aSBin Meng 						if (mrc_params->rank_enables &
1876b829f12aSBin Meng 							(0x1 << rk)) {
1877b829f12aSBin Meng 							/* set x/y_coordinate search starting settings */
1878b829f12aSBin Meng 							for (bl = 0;
1879312cc39eSBin Meng 							     bl < NUM_BYTE_LANES / bl_divisor;
1880b829f12aSBin Meng 							     bl++) {
1881b829f12aSBin Meng 								set_rdqs(ch, rk, bl,
1882b829f12aSBin Meng 									 x_coordinate[side_x][side_y][ch][rk][bl]);
1883b829f12aSBin Meng 								set_vref(ch, bl,
1884b829f12aSBin Meng 									 y_coordinate[side_x][side_y][ch][bl]);
1885b829f12aSBin Meng 							}
1886b829f12aSBin Meng 
1887b829f12aSBin Meng 							/* get an address in the target channel/rank */
1888b829f12aSBin Meng 							address = get_addr(ch, rk);
1889b829f12aSBin Meng 
1890b829f12aSBin Meng 							/* request HTE reconfiguration */
1891b829f12aSBin Meng 							mrc_params->hte_setup = 1;
1892b829f12aSBin Meng 
1893b829f12aSBin Meng 							/* test the settings */
1894b829f12aSBin Meng 							do {
1895b829f12aSBin Meng 								/* result[07:00] == failing byte lane (MAX 8) */
1896b829f12aSBin Meng 								result = check_bls_ex(mrc_params, address);
1897b829f12aSBin Meng 
1898b829f12aSBin Meng 								/* check for failures */
1899312cc39eSBin Meng 								if (result & 0xff) {
1900b829f12aSBin Meng 									/* at least 1 byte lane failed */
1901312cc39eSBin Meng 									for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
1902b829f12aSBin Meng 										if (result &
1903b829f12aSBin Meng 											(bl_mask << bl)) {
1904b829f12aSBin Meng 											/* adjust the RDQS values accordingly */
1905b829f12aSBin Meng 											if (side_x == L)
1906b829f12aSBin Meng 												x_coordinate[L][side_y][ch][rk][bl] += RDQS_STEP;
1907b829f12aSBin Meng 											else
1908b829f12aSBin Meng 												x_coordinate[R][side_y][ch][rk][bl] -= RDQS_STEP;
1909b829f12aSBin Meng 
1910b829f12aSBin Meng 											/* check that we haven't closed the RDQS_EYE too much */
1911b829f12aSBin Meng 											if ((x_coordinate[L][side_y][ch][rk][bl] > (RDQS_MAX - MIN_RDQS_EYE)) ||
1912b829f12aSBin Meng 												(x_coordinate[R][side_y][ch][rk][bl] < (RDQS_MIN + MIN_RDQS_EYE)) ||
1913b829f12aSBin Meng 												(x_coordinate[L][side_y][ch][rk][bl] ==
1914b829f12aSBin Meng 												x_coordinate[R][side_y][ch][rk][bl])) {
1915b829f12aSBin Meng 												/*
1916b829f12aSBin Meng 												 * not enough RDQS margin available at this VREF
1917b829f12aSBin Meng 												 * update VREF values accordingly
1918b829f12aSBin Meng 												 */
1919b829f12aSBin Meng 												if (side_y == B)
1920b829f12aSBin Meng 													y_coordinate[side_x][B][ch][bl] += VREF_STEP;
1921b829f12aSBin Meng 												else
1922b829f12aSBin Meng 													y_coordinate[side_x][T][ch][bl] -= VREF_STEP;
1923b829f12aSBin Meng 
1924b829f12aSBin Meng 												/* check that we haven't closed the VREF_EYE too much */
1925b829f12aSBin Meng 												if ((y_coordinate[side_x][B][ch][bl] > (VREF_MAX - MIN_VREF_EYE)) ||
1926b829f12aSBin Meng 													(y_coordinate[side_x][T][ch][bl] < (VREF_MIN + MIN_VREF_EYE)) ||
1927b829f12aSBin Meng 													(y_coordinate[side_x][B][ch][bl] == y_coordinate[side_x][T][ch][bl])) {
1928b829f12aSBin Meng 													/* VREF_EYE collapsed below MIN_VREF_EYE */
1929b829f12aSBin Meng 													training_message(ch, rk, bl);
1930312cc39eSBin Meng 													mrc_post_code(0xEE, 0x70 + side_y * 2 + side_x);
1931b829f12aSBin Meng 												} else {
1932b829f12aSBin Meng 													/* update the VREF setting */
1933b829f12aSBin Meng 													set_vref(ch, bl, y_coordinate[side_x][side_y][ch][bl]);
1934b829f12aSBin Meng 													/* reset the X coordinate to begin the search at the new VREF */
1935b829f12aSBin Meng 													x_coordinate[side_x][side_y][ch][rk][bl] =
1936312cc39eSBin Meng 														(side_x == L) ? RDQS_MIN : RDQS_MAX;
1937b829f12aSBin Meng 												}
1938b829f12aSBin Meng 											}
1939b829f12aSBin Meng 
1940b829f12aSBin Meng 											/* update the RDQS setting */
1941b829f12aSBin Meng 											set_rdqs(ch, rk, bl, x_coordinate[side_x][side_y][ch][rk][bl]);
1942b829f12aSBin Meng 										}
1943b829f12aSBin Meng 									}
1944b829f12aSBin Meng 								}
1945312cc39eSBin Meng 							} while (result & 0xff);
1946b829f12aSBin Meng 						}
1947b829f12aSBin Meng 					}
1948b829f12aSBin Meng 				}
1949b829f12aSBin Meng 			}
1950b829f12aSBin Meng 		}
1951b829f12aSBin Meng 	}
1952b829f12aSBin Meng 
1953b829f12aSBin Meng 	mrc_post_code(0x07, 0x20);
1954b829f12aSBin Meng 
1955b829f12aSBin Meng 	/* find final RDQS (X coordinate) & final VREF (Y coordinate) */
1956b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
1957b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
1958b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
1959b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
1960b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1961b829f12aSBin Meng 						uint32_t temp1;
1962b829f12aSBin Meng 						uint32_t temp2;
1963b829f12aSBin Meng 
1964b829f12aSBin Meng 						/* x_coordinate */
1965b829f12aSBin Meng 						DPF(D_INFO,
1966b829f12aSBin Meng 						    "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n",
1967b829f12aSBin Meng 						    rk, bl,
1968b829f12aSBin Meng 						    x_coordinate[L][T][ch][rk][bl],
1969b829f12aSBin Meng 						    x_coordinate[R][T][ch][rk][bl],
1970b829f12aSBin Meng 						    x_coordinate[L][B][ch][rk][bl],
1971b829f12aSBin Meng 						    x_coordinate[R][B][ch][rk][bl]);
1972b829f12aSBin Meng 
1973b829f12aSBin Meng 						/* average the TOP side LEFT & RIGHT values */
1974b829f12aSBin Meng 						temp1 = (x_coordinate[R][T][ch][rk][bl] + x_coordinate[L][T][ch][rk][bl]) / 2;
1975b829f12aSBin Meng 						/* average the BOTTOM side LEFT & RIGHT values */
1976b829f12aSBin Meng 						temp2 = (x_coordinate[R][B][ch][rk][bl] + x_coordinate[L][B][ch][rk][bl]) / 2;
1977b829f12aSBin Meng 						/* average the above averages */
1978b829f12aSBin Meng 						x_center[ch][rk][bl] = (uint8_t) ((temp1 + temp2) / 2);
1979b829f12aSBin Meng 
1980b829f12aSBin Meng 						/* y_coordinate */
1981b829f12aSBin Meng 						DPF(D_INFO,
1982b829f12aSBin Meng 						    "VREF R/L eye lane%d : %d-%d %d-%d\n",
1983b829f12aSBin Meng 						    bl,
1984b829f12aSBin Meng 						    y_coordinate[R][B][ch][bl],
1985b829f12aSBin Meng 						    y_coordinate[R][T][ch][bl],
1986b829f12aSBin Meng 						    y_coordinate[L][B][ch][bl],
1987b829f12aSBin Meng 						    y_coordinate[L][T][ch][bl]);
1988b829f12aSBin Meng 
1989b829f12aSBin Meng 						/* average the RIGHT side TOP & BOTTOM values */
1990b829f12aSBin Meng 						temp1 = (y_coordinate[R][T][ch][bl] + y_coordinate[R][B][ch][bl]) / 2;
1991b829f12aSBin Meng 						/* average the LEFT side TOP & BOTTOM values */
1992b829f12aSBin Meng 						temp2 = (y_coordinate[L][T][ch][bl] + y_coordinate[L][B][ch][bl]) / 2;
1993b829f12aSBin Meng 						/* average the above averages */
1994b829f12aSBin Meng 						y_center[ch][bl] = (uint8_t) ((temp1 + temp2) / 2);
1995b829f12aSBin Meng 					}
1996b829f12aSBin Meng 				}
1997b829f12aSBin Meng 			}
1998b829f12aSBin Meng 		}
1999b829f12aSBin Meng 	}
2000b829f12aSBin Meng 
2001b829f12aSBin Meng #ifdef RX_EYE_CHECK
2002b829f12aSBin Meng 	/* perform an eye check */
2003b829f12aSBin Meng 	for (side_y = B; side_y <= T; side_y++) {
2004b829f12aSBin Meng 		for (side_x = L; side_x <= R; side_x++) {
2005312cc39eSBin Meng 			mrc_post_code(0x07, 0x30 + side_y * 2 + side_x);
2006b829f12aSBin Meng 
2007b829f12aSBin Meng 			/* update the settings for the eye check */
2008b829f12aSBin Meng 			for (ch = 0; ch < NUM_CHANNELS; ch++) {
2009b829f12aSBin Meng 				if (mrc_params->channel_enables & (1 << ch)) {
2010b829f12aSBin Meng 					for (rk = 0; rk < NUM_RANKS; rk++) {
2011b829f12aSBin Meng 						if (mrc_params->rank_enables & (1 << rk)) {
2012312cc39eSBin Meng 							for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2013b829f12aSBin Meng 								if (side_x == L)
2014312cc39eSBin Meng 									set_rdqs(ch, rk, bl, x_center[ch][rk][bl] - (MIN_RDQS_EYE / 2));
2015b829f12aSBin Meng 								else
2016312cc39eSBin Meng 									set_rdqs(ch, rk, bl, x_center[ch][rk][bl] + (MIN_RDQS_EYE / 2));
2017b829f12aSBin Meng 
2018b829f12aSBin Meng 								if (side_y == B)
2019312cc39eSBin Meng 									set_vref(ch, bl, y_center[ch][bl] - (MIN_VREF_EYE / 2));
2020b829f12aSBin Meng 								else
2021312cc39eSBin Meng 									set_vref(ch, bl, y_center[ch][bl] + (MIN_VREF_EYE / 2));
2022b829f12aSBin Meng 							}
2023b829f12aSBin Meng 						}
2024b829f12aSBin Meng 					}
2025b829f12aSBin Meng 				}
2026b829f12aSBin Meng 			}
2027b829f12aSBin Meng 
2028b829f12aSBin Meng 			/* request HTE reconfiguration */
2029b829f12aSBin Meng 			mrc_params->hte_setup = 1;
2030b829f12aSBin Meng 
2031b829f12aSBin Meng 			/* check the eye */
2032312cc39eSBin Meng 			if (check_bls_ex(mrc_params, address) & 0xff) {
2033b829f12aSBin Meng 				/* one or more byte lanes failed */
2034312cc39eSBin Meng 				mrc_post_code(0xee, 0x74 + side_x * 2 + side_y);
2035b829f12aSBin Meng 			}
2036b829f12aSBin Meng 		}
2037b829f12aSBin Meng 	}
2038b829f12aSBin Meng #endif
2039b829f12aSBin Meng 
2040b829f12aSBin Meng 	mrc_post_code(0x07, 0x40);
2041b829f12aSBin Meng 
2042b829f12aSBin Meng 	/* set final placements */
2043b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2044b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
2045b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
2046b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
2047b829f12aSBin Meng #ifdef R2R_SHARING
2048b829f12aSBin Meng 					/* increment "num_ranks_enabled" */
2049b829f12aSBin Meng 					num_ranks_enabled++;
2050b829f12aSBin Meng #endif
2051b829f12aSBin Meng 					for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
2052b829f12aSBin Meng 						/* x_coordinate */
2053b829f12aSBin Meng #ifdef R2R_SHARING
2054b829f12aSBin Meng 						final_delay[ch][bl] += x_center[ch][rk][bl];
2055312cc39eSBin Meng 						set_rdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
2056b829f12aSBin Meng #else
2057b829f12aSBin Meng 						set_rdqs(ch, rk, bl, x_center[ch][rk][bl]);
2058b829f12aSBin Meng #endif
2059b829f12aSBin Meng 						/* y_coordinate */
2060b829f12aSBin Meng 						set_vref(ch, bl, y_center[ch][bl]);
2061b829f12aSBin Meng 					}
2062b829f12aSBin Meng 				}
2063b829f12aSBin Meng 			}
2064b829f12aSBin Meng 		}
2065b829f12aSBin Meng 	}
2066b829f12aSBin Meng #endif
2067b829f12aSBin Meng 
2068b829f12aSBin Meng 	LEAVEFN();
2069b829f12aSBin Meng }
2070b829f12aSBin Meng 
2071b829f12aSBin Meng /*
2072b829f12aSBin Meng  * This function will perform the WRITE TRAINING Algorithm on all
2073b829f12aSBin Meng  * channels/ranks/byte_lanes simultaneously to minimize execution time.
2074b829f12aSBin Meng  *
2075b829f12aSBin Meng  * The idea here is to train the WDQ timings to achieve maximum WRITE margins.
2076b829f12aSBin Meng  * The algorithm will start with WDQ at the current WDQ setting (tracks WDQS
2077b829f12aSBin Meng  * in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data
2078b829f12aSBin Meng  * patterns pass. This is because WDQS will be aligned to WCLK by the
2079b829f12aSBin Meng  * Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window
2080b829f12aSBin Meng  * of validity.
2081b829f12aSBin Meng  */
wr_train(struct mrc_params * mrc_params)2082b829f12aSBin Meng void wr_train(struct mrc_params *mrc_params)
2083b829f12aSBin Meng {
2084b829f12aSBin Meng 	uint8_t ch;	/* channel counter */
2085b829f12aSBin Meng 	uint8_t rk;	/* rank counter */
2086b829f12aSBin Meng 	uint8_t bl;	/* byte lane counter */
2087b829f12aSBin Meng 	uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
2088b829f12aSBin Meng #ifdef BACKUP_WDQ
2089b829f12aSBin Meng #else
2090b829f12aSBin Meng 	uint8_t side;		/* LEFT/RIGHT side indicator (0=L, 1=R) */
2091b829f12aSBin Meng 	uint32_t temp;		/* temporary DWORD */
2092b829f12aSBin Meng 	/* 2 arrays, for L & R side passing delays */
2093b829f12aSBin Meng 	uint32_t delay[2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
2094b829f12aSBin Meng 	uint32_t address;	/* target address for check_bls_ex() */
2095b829f12aSBin Meng 	uint32_t result;	/* result of check_bls_ex() */
2096b829f12aSBin Meng 	uint32_t bl_mask;	/* byte lane mask for result checking */
2097b829f12aSBin Meng #ifdef R2R_SHARING
2098b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
2099b829f12aSBin Meng 	uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
2100b829f12aSBin Meng 	/* used to find placement for rank2rank sharing configs */
2101b829f12aSBin Meng 	uint32_t num_ranks_enabled = 0;
2102b829f12aSBin Meng #endif
2103b829f12aSBin Meng #endif
2104b829f12aSBin Meng 
2105b829f12aSBin Meng 	/* wr_train starts */
2106b829f12aSBin Meng 	mrc_post_code(0x08, 0x00);
2107b829f12aSBin Meng 
2108b829f12aSBin Meng 	ENTERFN();
2109b829f12aSBin Meng 
2110b829f12aSBin Meng #ifdef BACKUP_WDQ
2111b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2112b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
2113b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
2114b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
2115b829f12aSBin Meng 					for (bl = 0;
2116312cc39eSBin Meng 					     bl < NUM_BYTE_LANES / bl_divisor;
2117b829f12aSBin Meng 					     bl++) {
2118b829f12aSBin Meng 						set_wdq(ch, rk, bl, ddr_wdq[PLATFORM_ID]);
2119b829f12aSBin Meng 					}
2120b829f12aSBin Meng 				}
2121b829f12aSBin Meng 			}
2122b829f12aSBin Meng 		}
2123b829f12aSBin Meng 	}
2124b829f12aSBin Meng #else
2125b829f12aSBin Meng 	/* initialize "delay" */
2126b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2127b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
2128b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
2129b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
2130b829f12aSBin Meng 					for (bl = 0;
2131312cc39eSBin Meng 					     bl < NUM_BYTE_LANES / bl_divisor;
2132b829f12aSBin Meng 					     bl++) {
2133b829f12aSBin Meng 						/*
2134b829f12aSBin Meng 						 * want to start with
2135b829f12aSBin Meng 						 * WDQ = (WDQS - QRTR_CLK)
2136b829f12aSBin Meng 						 * +/- QRTR_CLK
2137b829f12aSBin Meng 						 */
2138b829f12aSBin Meng 						temp = get_wdqs(ch, rk, bl) - QRTR_CLK;
2139b829f12aSBin Meng 						delay[L][ch][rk][bl] = temp - QRTR_CLK;
2140b829f12aSBin Meng 						delay[R][ch][rk][bl] = temp + QRTR_CLK;
2141b829f12aSBin Meng 					}
2142b829f12aSBin Meng 				}
2143b829f12aSBin Meng 			}
2144b829f12aSBin Meng 		}
2145b829f12aSBin Meng 	}
2146b829f12aSBin Meng 
2147b829f12aSBin Meng 	/* initialize other variables */
2148b829f12aSBin Meng 	bl_mask = byte_lane_mask(mrc_params);
2149b829f12aSBin Meng 	address = get_addr(0, 0);
2150b829f12aSBin Meng 
2151b829f12aSBin Meng #ifdef R2R_SHARING
2152b829f12aSBin Meng 	/* need to set "final_delay[][]" elements to "0" */
2153b829f12aSBin Meng 	memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
2154b829f12aSBin Meng #endif
2155b829f12aSBin Meng 
2156b829f12aSBin Meng 	/*
2157b829f12aSBin Meng 	 * start algorithm on the LEFT side and train each channel/bl
2158b829f12aSBin Meng 	 * until no failures are observed, then repeat for the RIGHT side.
2159b829f12aSBin Meng 	 */
2160b829f12aSBin Meng 	for (side = L; side <= R; side++) {
2161312cc39eSBin Meng 		mrc_post_code(0x08, 0x10 + side);
2162b829f12aSBin Meng 
2163b829f12aSBin Meng 		/* set starting values */
2164b829f12aSBin Meng 		for (ch = 0; ch < NUM_CHANNELS; ch++) {
2165b829f12aSBin Meng 			if (mrc_params->channel_enables & (1 << ch)) {
2166b829f12aSBin Meng 				for (rk = 0; rk < NUM_RANKS; rk++) {
2167b829f12aSBin Meng 					if (mrc_params->rank_enables &
2168b829f12aSBin Meng 						(1 << rk)) {
2169b829f12aSBin Meng 						for (bl = 0;
2170312cc39eSBin Meng 						     bl < NUM_BYTE_LANES / bl_divisor;
2171b829f12aSBin Meng 						     bl++) {
2172b829f12aSBin Meng 							set_wdq(ch, rk, bl, delay[side][ch][rk][bl]);
2173b829f12aSBin Meng 						}
2174b829f12aSBin Meng 					}
2175b829f12aSBin Meng 				}
2176b829f12aSBin Meng 			}
2177b829f12aSBin Meng 		}
2178b829f12aSBin Meng 
2179b829f12aSBin Meng 		/* find passing values */
2180b829f12aSBin Meng 		for (ch = 0; ch < NUM_CHANNELS; ch++) {
2181b829f12aSBin Meng 			if (mrc_params->channel_enables & (1 << ch)) {
2182b829f12aSBin Meng 				for (rk = 0; rk < NUM_RANKS; rk++) {
2183b829f12aSBin Meng 					if (mrc_params->rank_enables &
2184b829f12aSBin Meng 						(1 << rk)) {
2185b829f12aSBin Meng 						/* get an address in the target channel/rank */
2186b829f12aSBin Meng 						address = get_addr(ch, rk);
2187b829f12aSBin Meng 
2188b829f12aSBin Meng 						/* request HTE reconfiguration */
2189b829f12aSBin Meng 						mrc_params->hte_setup = 1;
2190b829f12aSBin Meng 
2191b829f12aSBin Meng 						/* check the settings */
2192b829f12aSBin Meng 						do {
2193b829f12aSBin Meng 							/* result[07:00] == failing byte lane (MAX 8) */
2194b829f12aSBin Meng 							result = check_bls_ex(mrc_params, address);
2195b829f12aSBin Meng 							/* check for failures */
2196312cc39eSBin Meng 							if (result & 0xff) {
2197b829f12aSBin Meng 								/* at least 1 byte lane failed */
2198312cc39eSBin Meng 								for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2199b829f12aSBin Meng 									if (result &
2200b829f12aSBin Meng 										(bl_mask << bl)) {
2201b829f12aSBin Meng 										if (side == L)
2202b829f12aSBin Meng 											delay[L][ch][rk][bl] += WDQ_STEP;
2203b829f12aSBin Meng 										else
2204b829f12aSBin Meng 											delay[R][ch][rk][bl] -= WDQ_STEP;
2205b829f12aSBin Meng 
2206b829f12aSBin Meng 										/* check for algorithm failure */
2207b829f12aSBin Meng 										if (delay[L][ch][rk][bl] != delay[R][ch][rk][bl]) {
2208b829f12aSBin Meng 											/*
2209b829f12aSBin Meng 											 * margin available
2210b829f12aSBin Meng 											 * update delay setting
2211b829f12aSBin Meng 											 */
2212b829f12aSBin Meng 											set_wdq(ch, rk, bl,
2213b829f12aSBin Meng 												delay[side][ch][rk][bl]);
2214b829f12aSBin Meng 										} else {
2215b829f12aSBin Meng 											/*
2216b829f12aSBin Meng 											 * no margin available
2217b829f12aSBin Meng 											 * notify the user and halt
2218b829f12aSBin Meng 											 */
2219b829f12aSBin Meng 											training_message(ch, rk, bl);
2220312cc39eSBin Meng 											mrc_post_code(0xee, 0x80 + side);
2221b829f12aSBin Meng 										}
2222b829f12aSBin Meng 									}
2223b829f12aSBin Meng 								}
2224b829f12aSBin Meng 							}
2225b829f12aSBin Meng 						/* stop when all byte lanes pass */
2226312cc39eSBin Meng 						} while (result & 0xff);
2227b829f12aSBin Meng 					}
2228b829f12aSBin Meng 				}
2229b829f12aSBin Meng 			}
2230b829f12aSBin Meng 		}
2231b829f12aSBin Meng 	}
2232b829f12aSBin Meng 
2233b829f12aSBin Meng 	/* program WDQ to the middle of passing window */
2234b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2235b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << ch)) {
2236b829f12aSBin Meng 			for (rk = 0; rk < NUM_RANKS; rk++) {
2237b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rk)) {
2238b829f12aSBin Meng #ifdef R2R_SHARING
2239b829f12aSBin Meng 					/* increment "num_ranks_enabled" */
2240b829f12aSBin Meng 					num_ranks_enabled++;
2241b829f12aSBin Meng #endif
2242312cc39eSBin Meng 					for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
2243b829f12aSBin Meng 						DPF(D_INFO,
2244b829f12aSBin Meng 						    "WDQ eye rank%d lane%d : %d-%d\n",
2245b829f12aSBin Meng 						    rk, bl,
2246b829f12aSBin Meng 						    delay[L][ch][rk][bl],
2247b829f12aSBin Meng 						    delay[R][ch][rk][bl]);
2248b829f12aSBin Meng 
2249b829f12aSBin Meng 						temp = (delay[R][ch][rk][bl] + delay[L][ch][rk][bl]) / 2;
2250b829f12aSBin Meng 
2251b829f12aSBin Meng #ifdef R2R_SHARING
2252b829f12aSBin Meng 						final_delay[ch][bl] += temp;
2253b829f12aSBin Meng 						set_wdq(ch, rk, bl,
2254312cc39eSBin Meng 							final_delay[ch][bl] / num_ranks_enabled);
2255b829f12aSBin Meng #else
2256b829f12aSBin Meng 						set_wdq(ch, rk, bl, temp);
2257b829f12aSBin Meng #endif
2258b829f12aSBin Meng 					}
2259b829f12aSBin Meng 				}
2260b829f12aSBin Meng 			}
2261b829f12aSBin Meng 		}
2262b829f12aSBin Meng 	}
2263b829f12aSBin Meng #endif
2264b829f12aSBin Meng 
2265b829f12aSBin Meng 	LEAVEFN();
2266b829f12aSBin Meng }
2267b829f12aSBin Meng 
2268b829f12aSBin Meng /*
2269b829f12aSBin Meng  * This function will store relevant timing data
2270b829f12aSBin Meng  *
2271b829f12aSBin Meng  * This data will be used on subsequent boots to speed up boot times
2272b829f12aSBin Meng  * and is required for Suspend To RAM capabilities.
2273b829f12aSBin Meng  */
store_timings(struct mrc_params * mrc_params)2274b829f12aSBin Meng void store_timings(struct mrc_params *mrc_params)
2275b829f12aSBin Meng {
2276b829f12aSBin Meng 	uint8_t ch, rk, bl;
2277b829f12aSBin Meng 	struct mrc_timings *mt = &mrc_params->timings;
2278b829f12aSBin Meng 
2279b829f12aSBin Meng 	for (ch = 0; ch < NUM_CHANNELS; ch++) {
2280b829f12aSBin Meng 		for (rk = 0; rk < NUM_RANKS; rk++) {
2281b829f12aSBin Meng 			for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
2282b829f12aSBin Meng 				mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl);
2283b829f12aSBin Meng 				mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl);
2284b829f12aSBin Meng 				mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl);
2285b829f12aSBin Meng 				mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);
2286b829f12aSBin Meng 
2287b829f12aSBin Meng 				if (rk == 0)
2288b829f12aSBin Meng 					mt->vref[ch][bl] = get_vref(ch, bl);
2289b829f12aSBin Meng 			}
2290b829f12aSBin Meng 
2291b829f12aSBin Meng 			mt->wctl[ch][rk] = get_wctl(ch, rk);
2292b829f12aSBin Meng 		}
2293b829f12aSBin Meng 
2294b829f12aSBin Meng 		mt->wcmd[ch] = get_wcmd(ch);
2295b829f12aSBin Meng 	}
2296b829f12aSBin Meng 
2297b829f12aSBin Meng 	/* need to save for a case of changing frequency after warm reset */
2298b829f12aSBin Meng 	mt->ddr_speed = mrc_params->ddr_speed;
2299b829f12aSBin Meng }
2300b829f12aSBin Meng 
2301b829f12aSBin Meng /*
2302b829f12aSBin Meng  * The purpose of this function is to ensure the SEC comes out of reset
2303b829f12aSBin Meng  * and IA initiates the SEC enabling Memory Scrambling.
2304b829f12aSBin Meng  */
enable_scrambling(struct mrc_params * mrc_params)2305b829f12aSBin Meng void enable_scrambling(struct mrc_params *mrc_params)
2306b829f12aSBin Meng {
2307b829f12aSBin Meng 	uint32_t lfsr = 0;
2308b829f12aSBin Meng 	uint8_t i;
2309b829f12aSBin Meng 
2310b829f12aSBin Meng 	if (mrc_params->scrambling_enables == 0)
2311b829f12aSBin Meng 		return;
2312b829f12aSBin Meng 
2313b829f12aSBin Meng 	ENTERFN();
2314b829f12aSBin Meng 
2315b829f12aSBin Meng 	/* 32 bit seed is always stored in BIOS NVM */
2316b829f12aSBin Meng 	lfsr = mrc_params->timings.scrambler_seed;
2317b829f12aSBin Meng 
2318b829f12aSBin Meng 	if (mrc_params->boot_mode == BM_COLD) {
2319b829f12aSBin Meng 		/*
2320b829f12aSBin Meng 		 * factory value is 0 and in first boot,
2321b829f12aSBin Meng 		 * a clock based seed is loaded.
2322b829f12aSBin Meng 		 */
2323b829f12aSBin Meng 		if (lfsr == 0) {
2324b829f12aSBin Meng 			/*
2325b829f12aSBin Meng 			 * get seed from system clock
2326b829f12aSBin Meng 			 * and make sure it is not all 1's
2327b829f12aSBin Meng 			 */
2328312cc39eSBin Meng 			lfsr = rdtsc() & 0x0fffffff;
2329b829f12aSBin Meng 		} else {
2330b829f12aSBin Meng 			/*
2331b829f12aSBin Meng 			 * Need to replace scrambler
2332b829f12aSBin Meng 			 *
2333b829f12aSBin Meng 			 * get next 32bit LFSR 16 times which is the last
2334b829f12aSBin Meng 			 * part of the previous scrambler vector
2335b829f12aSBin Meng 			 */
2336b829f12aSBin Meng 			for (i = 0; i < 16; i++)
2337b829f12aSBin Meng 				lfsr32(&lfsr);
2338b829f12aSBin Meng 		}
2339b829f12aSBin Meng 
2340b829f12aSBin Meng 		/* save new seed */
2341b829f12aSBin Meng 		mrc_params->timings.scrambler_seed = lfsr;
2342b829f12aSBin Meng 	}
2343b829f12aSBin Meng 
2344b829f12aSBin Meng 	/*
2345b829f12aSBin Meng 	 * In warm boot or S3 exit, we have the previous seed.
2346b829f12aSBin Meng 	 * In cold boot, we have the last 32bit LFSR which is the new seed.
2347b829f12aSBin Meng 	 */
2348b829f12aSBin Meng 	lfsr32(&lfsr);	/* shift to next value */
2349312cc39eSBin Meng 	msg_port_write(MEM_CTLR, SCRMSEED, (lfsr & 0x0003ffff));
2350b829f12aSBin Meng 
2351b829f12aSBin Meng 	for (i = 0; i < 2; i++)
2352312cc39eSBin Meng 		msg_port_write(MEM_CTLR, SCRMLO + i, (lfsr & 0xaaaaaaaa));
2353b829f12aSBin Meng 
2354b829f12aSBin Meng 	LEAVEFN();
2355b829f12aSBin Meng }
2356b829f12aSBin Meng 
2357b829f12aSBin Meng /*
2358b829f12aSBin Meng  * Configure MCU Power Management Control Register
2359b829f12aSBin Meng  * and Scheduler Control Register
2360b829f12aSBin Meng  */
prog_ddr_control(struct mrc_params * mrc_params)2361b829f12aSBin Meng void prog_ddr_control(struct mrc_params *mrc_params)
2362b829f12aSBin Meng {
2363b829f12aSBin Meng 	u32 dsch;
2364b829f12aSBin Meng 	u32 dpmc0;
2365b829f12aSBin Meng 
2366b829f12aSBin Meng 	ENTERFN();
2367b829f12aSBin Meng 
2368b829f12aSBin Meng 	dsch = msg_port_read(MEM_CTLR, DSCH);
2369312cc39eSBin Meng 	dsch &= ~(DSCH_OOODIS | DSCH_OOOST3DIS | DSCH_NEWBYPDIS);
2370b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DSCH, dsch);
2371b829f12aSBin Meng 
2372b829f12aSBin Meng 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
2373312cc39eSBin Meng 	dpmc0 &= ~DPMC0_DISPWRDN;
2374b829f12aSBin Meng 	dpmc0 |= (mrc_params->power_down_disable << 25);
2375312cc39eSBin Meng 	dpmc0 &= ~DPMC0_CLKGTDIS;
2376312cc39eSBin Meng 	dpmc0 &= ~DPMC0_PCLSTO_MASK;
2377b829f12aSBin Meng 	dpmc0 |= (4 << 16);
2378312cc39eSBin Meng 	dpmc0 |= DPMC0_PREAPWDEN;
2379b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2380b829f12aSBin Meng 
2381b829f12aSBin Meng 	/* CMDTRIST = 2h - CMD/ADDR are tristated when no valid command */
2382312cc39eSBin Meng 	mrc_write_mask(MEM_CTLR, DPMC1, 0x20, 0x30);
2383b829f12aSBin Meng 
2384b829f12aSBin Meng 	LEAVEFN();
2385b829f12aSBin Meng }
2386b829f12aSBin Meng 
2387b829f12aSBin Meng /*
2388b829f12aSBin Meng  * After training complete configure MCU Rank Population Register
2389b829f12aSBin Meng  * specifying: ranks enabled, device width, density, address mode
2390b829f12aSBin Meng  */
prog_dra_drb(struct mrc_params * mrc_params)2391b829f12aSBin Meng void prog_dra_drb(struct mrc_params *mrc_params)
2392b829f12aSBin Meng {
2393b829f12aSBin Meng 	u32 drp;
2394b829f12aSBin Meng 	u32 dco;
2395b829f12aSBin Meng 	u8 density = mrc_params->params.density;
2396b829f12aSBin Meng 
2397b829f12aSBin Meng 	ENTERFN();
2398b829f12aSBin Meng 
2399b829f12aSBin Meng 	dco = msg_port_read(MEM_CTLR, DCO);
2400312cc39eSBin Meng 	dco &= ~DCO_IC;
2401b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DCO, dco);
2402b829f12aSBin Meng 
2403b829f12aSBin Meng 	drp = 0;
2404b829f12aSBin Meng 	if (mrc_params->rank_enables & 1)
2405312cc39eSBin Meng 		drp |= DRP_RKEN0;
2406b829f12aSBin Meng 	if (mrc_params->rank_enables & 2)
2407312cc39eSBin Meng 		drp |= DRP_RKEN1;
2408b829f12aSBin Meng 	if (mrc_params->dram_width == X16) {
2409b829f12aSBin Meng 		drp |= (1 << 4);
2410b829f12aSBin Meng 		drp |= (1 << 9);
2411b829f12aSBin Meng 	}
2412b829f12aSBin Meng 
2413b829f12aSBin Meng 	/*
2414b829f12aSBin Meng 	 * Density encoding in struct dram_params: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
2415b829f12aSBin Meng 	 * has to be mapped RANKDENSx encoding (0=1Gb)
2416b829f12aSBin Meng 	 */
2417b829f12aSBin Meng 	if (density == 0)
2418b829f12aSBin Meng 		density = 4;
2419b829f12aSBin Meng 
2420b829f12aSBin Meng 	drp |= ((density - 1) << 6);
2421b829f12aSBin Meng 	drp |= ((density - 1) << 11);
2422b829f12aSBin Meng 
2423b829f12aSBin Meng 	/* Address mode can be overwritten if ECC enabled */
2424b829f12aSBin Meng 	drp |= (mrc_params->address_mode << 14);
2425b829f12aSBin Meng 
2426b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRP, drp);
2427b829f12aSBin Meng 
2428312cc39eSBin Meng 	dco &= ~DCO_PMICTL;
2429312cc39eSBin Meng 	dco |= DCO_IC;
2430b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DCO, dco);
2431b829f12aSBin Meng 
2432b829f12aSBin Meng 	LEAVEFN();
2433b829f12aSBin Meng }
2434b829f12aSBin Meng 
2435b829f12aSBin Meng /* Send DRAM wake command */
perform_wake(struct mrc_params * mrc_params)2436b829f12aSBin Meng void perform_wake(struct mrc_params *mrc_params)
2437b829f12aSBin Meng {
2438b829f12aSBin Meng 	ENTERFN();
2439b829f12aSBin Meng 
2440b829f12aSBin Meng 	dram_wake_command();
2441b829f12aSBin Meng 
2442b829f12aSBin Meng 	LEAVEFN();
2443b829f12aSBin Meng }
2444b829f12aSBin Meng 
2445b829f12aSBin Meng /*
2446b829f12aSBin Meng  * Configure refresh rate and short ZQ calibration interval
2447b829f12aSBin Meng  * Activate dynamic self refresh
2448b829f12aSBin Meng  */
change_refresh_period(struct mrc_params * mrc_params)2449b829f12aSBin Meng void change_refresh_period(struct mrc_params *mrc_params)
2450b829f12aSBin Meng {
2451b829f12aSBin Meng 	u32 drfc;
2452b829f12aSBin Meng 	u32 dcal;
2453b829f12aSBin Meng 	u32 dpmc0;
2454b829f12aSBin Meng 
2455b829f12aSBin Meng 	ENTERFN();
2456b829f12aSBin Meng 
2457b829f12aSBin Meng 	drfc = msg_port_read(MEM_CTLR, DRFC);
2458312cc39eSBin Meng 	drfc &= ~DRFC_TREFI_MASK;
2459b829f12aSBin Meng 	drfc |= (mrc_params->refresh_rate << 12);
2460312cc39eSBin Meng 	drfc |= DRFC_REFDBTCLR;
2461b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRFC, drfc);
2462b829f12aSBin Meng 
2463b829f12aSBin Meng 	dcal = msg_port_read(MEM_CTLR, DCAL);
2464312cc39eSBin Meng 	dcal &= ~DCAL_ZQCINT_MASK;
2465b829f12aSBin Meng 	dcal |= (3 << 8);	/* 63ms */
2466b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DCAL, dcal);
2467b829f12aSBin Meng 
2468b829f12aSBin Meng 	dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
2469312cc39eSBin Meng 	dpmc0 |= (DPMC0_DYNSREN | DPMC0_ENPHYCLKGATE);
2470b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2471b829f12aSBin Meng 
2472b829f12aSBin Meng 	LEAVEFN();
2473b829f12aSBin Meng }
2474b829f12aSBin Meng 
2475b829f12aSBin Meng /*
2476b829f12aSBin Meng  * Configure DDRPHY for Auto-Refresh, Periodic Compensations,
2477b829f12aSBin Meng  * Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
2478b829f12aSBin Meng  */
set_auto_refresh(struct mrc_params * mrc_params)2479b829f12aSBin Meng void set_auto_refresh(struct mrc_params *mrc_params)
2480b829f12aSBin Meng {
2481b829f12aSBin Meng 	uint32_t channel;
2482b829f12aSBin Meng 	uint32_t rank;
2483b829f12aSBin Meng 	uint32_t bl;
2484b829f12aSBin Meng 	uint32_t bl_divisor = 1;
2485b829f12aSBin Meng 	uint32_t temp;
2486b829f12aSBin Meng 
2487b829f12aSBin Meng 	ENTERFN();
2488b829f12aSBin Meng 
2489b829f12aSBin Meng 	/*
2490b829f12aSBin Meng 	 * Enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp,
2491b829f12aSBin Meng 	 * ZQSPERIOD, Auto-Precharge, CKE Power-Down
2492b829f12aSBin Meng 	 */
2493b829f12aSBin Meng 	for (channel = 0; channel < NUM_CHANNELS; channel++) {
2494b829f12aSBin Meng 		if (mrc_params->channel_enables & (1 << channel)) {
2495b829f12aSBin Meng 			/* Enable Periodic RCOMPS */
2496312cc39eSBin Meng 			mrc_alt_write_mask(DDRPHY, CMPCTRL, 2, 2);
2497b829f12aSBin Meng 
2498b829f12aSBin Meng 			/* Enable Dynamic DiffAmp & Set Read ODT Value */
2499b829f12aSBin Meng 			switch (mrc_params->rd_odt_value) {
2500b829f12aSBin Meng 			case 0:
2501312cc39eSBin Meng 				temp = 0x3f;	/* OFF */
2502b829f12aSBin Meng 				break;
2503b829f12aSBin Meng 			default:
2504b829f12aSBin Meng 				temp = 0x00;	/* Auto */
2505b829f12aSBin Meng 				break;
2506b829f12aSBin Meng 			}
2507b829f12aSBin Meng 
2508312cc39eSBin Meng 			for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
2509b829f12aSBin Meng 				/* Override: DIFFAMP, ODT */
2510b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
2511312cc39eSBin Meng 					B0OVRCTL + bl * DDRIODQ_BL_OFFSET +
2512312cc39eSBin Meng 					channel * DDRIODQ_CH_OFFSET,
2513312cc39eSBin Meng 					temp << 10,
2514312cc39eSBin Meng 					0x003ffc00);
2515b829f12aSBin Meng 
2516b829f12aSBin Meng 				/* Override: DIFFAMP, ODT */
2517b829f12aSBin Meng 				mrc_alt_write_mask(DDRPHY,
2518312cc39eSBin Meng 					B1OVRCTL + bl * DDRIODQ_BL_OFFSET +
2519312cc39eSBin Meng 					channel * DDRIODQ_CH_OFFSET,
2520312cc39eSBin Meng 					temp << 10,
2521312cc39eSBin Meng 					0x003ffc00);
2522b829f12aSBin Meng 			}
2523b829f12aSBin Meng 
2524b829f12aSBin Meng 			/* Issue ZQCS command */
2525b829f12aSBin Meng 			for (rank = 0; rank < NUM_RANKS; rank++) {
2526b829f12aSBin Meng 				if (mrc_params->rank_enables & (1 << rank))
2527b829f12aSBin Meng 					dram_init_command(DCMD_ZQCS(rank));
2528b829f12aSBin Meng 			}
2529b829f12aSBin Meng 		}
2530b829f12aSBin Meng 	}
2531b829f12aSBin Meng 
2532b829f12aSBin Meng 	clear_pointers();
2533b829f12aSBin Meng 
2534b829f12aSBin Meng 	LEAVEFN();
2535b829f12aSBin Meng }
2536b829f12aSBin Meng 
2537b829f12aSBin Meng /*
2538b829f12aSBin Meng  * Depending on configuration enables ECC support
2539b829f12aSBin Meng  *
2540b829f12aSBin Meng  * Available memory size is decreased, and updated with 0s
2541b829f12aSBin Meng  * in order to clear error status. Address mode 2 forced.
2542b829f12aSBin Meng  */
ecc_enable(struct mrc_params * mrc_params)2543b829f12aSBin Meng void ecc_enable(struct mrc_params *mrc_params)
2544b829f12aSBin Meng {
2545b829f12aSBin Meng 	u32 drp;
2546b829f12aSBin Meng 	u32 dsch;
2547b829f12aSBin Meng 	u32 ecc_ctrl;
2548b829f12aSBin Meng 
2549b829f12aSBin Meng 	if (mrc_params->ecc_enables == 0)
2550b829f12aSBin Meng 		return;
2551b829f12aSBin Meng 
2552b829f12aSBin Meng 	ENTERFN();
2553b829f12aSBin Meng 
2554b829f12aSBin Meng 	/* Configuration required in ECC mode */
2555b829f12aSBin Meng 	drp = msg_port_read(MEM_CTLR, DRP);
2556312cc39eSBin Meng 	drp &= ~DRP_ADDRMAP_MASK;
2557312cc39eSBin Meng 	drp |= DRP_ADDRMAP_MAP1;
2558312cc39eSBin Meng 	drp |= DRP_PRI64BSPLITEN;
2559b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DRP, drp);
2560b829f12aSBin Meng 
2561b829f12aSBin Meng 	/* Disable new request bypass */
2562b829f12aSBin Meng 	dsch = msg_port_read(MEM_CTLR, DSCH);
2563312cc39eSBin Meng 	dsch |= DSCH_NEWBYPDIS;
2564b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DSCH, dsch);
2565b829f12aSBin Meng 
2566b829f12aSBin Meng 	/* Enable ECC */
2567312cc39eSBin Meng 	ecc_ctrl = (DECCCTRL_SBEEN | DECCCTRL_DBEEN | DECCCTRL_ENCBGEN);
2568b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DECCCTRL, ecc_ctrl);
2569b829f12aSBin Meng 
2570b829f12aSBin Meng 	/* Assume 8 bank memory, one bank is gone for ECC */
2571b829f12aSBin Meng 	mrc_params->mem_size -= mrc_params->mem_size / 8;
2572b829f12aSBin Meng 
2573b829f12aSBin Meng 	/* For S3 resume memory content has to be preserved */
2574b829f12aSBin Meng 	if (mrc_params->boot_mode != BM_S3) {
2575b829f12aSBin Meng 		select_hte();
2576b829f12aSBin Meng 		hte_mem_init(mrc_params, MRC_MEM_INIT);
2577b829f12aSBin Meng 		select_mem_mgr();
2578b829f12aSBin Meng 	}
2579b829f12aSBin Meng 
2580b829f12aSBin Meng 	LEAVEFN();
2581b829f12aSBin Meng }
2582b829f12aSBin Meng 
2583b829f12aSBin Meng /*
2584b829f12aSBin Meng  * Execute memory test
2585b829f12aSBin Meng  * if error detected it is indicated in mrc_params->status
2586b829f12aSBin Meng  */
memory_test(struct mrc_params * mrc_params)2587b829f12aSBin Meng void memory_test(struct mrc_params *mrc_params)
2588b829f12aSBin Meng {
2589b829f12aSBin Meng 	uint32_t result = 0;
2590b829f12aSBin Meng 
2591b829f12aSBin Meng 	ENTERFN();
2592b829f12aSBin Meng 
2593b829f12aSBin Meng 	select_hte();
2594b829f12aSBin Meng 	result = hte_mem_init(mrc_params, MRC_MEM_TEST);
2595b829f12aSBin Meng 	select_mem_mgr();
2596b829f12aSBin Meng 
2597b829f12aSBin Meng 	DPF(D_INFO, "Memory test result %x\n", result);
2598b829f12aSBin Meng 	mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
2599b829f12aSBin Meng 	LEAVEFN();
2600b829f12aSBin Meng }
2601b829f12aSBin Meng 
2602b829f12aSBin Meng /* Lock MCU registers at the end of initialization sequence */
lock_registers(struct mrc_params * mrc_params)2603b829f12aSBin Meng void lock_registers(struct mrc_params *mrc_params)
2604b829f12aSBin Meng {
2605b829f12aSBin Meng 	u32 dco;
2606b829f12aSBin Meng 
2607b829f12aSBin Meng 	ENTERFN();
2608b829f12aSBin Meng 
2609b829f12aSBin Meng 	dco = msg_port_read(MEM_CTLR, DCO);
2610312cc39eSBin Meng 	dco &= ~(DCO_PMICTL | DCO_PMIDIS);
2611312cc39eSBin Meng 	dco |= (DCO_DRPLOCK | DCO_CPGCLOCK);
2612b829f12aSBin Meng 	msg_port_write(MEM_CTLR, DCO, dco);
2613b829f12aSBin Meng 
2614b829f12aSBin Meng 	LEAVEFN();
2615b829f12aSBin Meng }
2616