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