blob: 3ffe92b67b20741908e72c5ca09cea8c2f5b8ddc [file] [log] [blame]
Bin Meng93b4a392015-02-05 23:42:24 +08001/*
2 * Copyright (C) 2013, Intel Corporation
3 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * Ported from Intel released Quark UEFI BIOS
6 * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
7 *
8 * SPDX-License-Identifier: Intel
9 */
10
11#include <common.h>
12#include <pci.h>
13#include <asm/arch/device.h>
14#include <asm/arch/mrc.h>
15#include <asm/arch/msg_port.h>
16#include "mrc_util.h"
17#include "hte.h"
18#include "smc.h"
19
20/* t_rfc values (in picoseconds) per density */
21static const uint32_t t_rfc[5] = {
22 90000, /* 512Mb */
23 110000, /* 1Gb */
24 160000, /* 2Gb */
25 300000, /* 4Gb */
26 350000, /* 8Gb */
27};
28
29/* t_ck clock period in picoseconds per speed index 800, 1066, 1333 */
30static const uint32_t t_ck[3] = {
31 2500,
32 1875,
33 1500
34};
35
36/* Global variables */
37static const uint16_t ddr_wclk[] = {193, 158};
38static const uint16_t ddr_wctl[] = {1, 217};
39static const uint16_t ddr_wcmd[] = {1, 220};
40
41#ifdef BACKUP_RCVN
42static const uint16_t ddr_rcvn[] = {129, 498};
43#endif
44
45#ifdef BACKUP_WDQS
46static const uint16_t ddr_wdqs[] = {65, 289};
47#endif
48
49#ifdef BACKUP_RDQS
50static const uint8_t ddr_rdqs[] = {32, 24};
51#endif
52
53#ifdef BACKUP_WDQ
54static const uint16_t ddr_wdq[] = {32, 257};
55#endif
56
57/* Stop self refresh driven by MCU */
58void clear_self_refresh(struct mrc_params *mrc_params)
59{
60 ENTERFN();
61
62 /* clear the PMSTS Channel Self Refresh bits */
Bin Meng15e3f282015-03-10 18:31:20 +080063 mrc_write_mask(MEM_CTLR, PMSTS, PMSTS_DISR, PMSTS_DISR);
Bin Meng93b4a392015-02-05 23:42:24 +080064
65 LEAVEFN();
66}
67
68/* It will initialize timing registers in the MCU (DTR0..DTR4) */
69void prog_ddr_timing_control(struct mrc_params *mrc_params)
70{
71 uint8_t tcl, wl;
72 uint8_t trp, trcd, tras, twr, twtr, trrd, trtp, tfaw;
73 uint32_t tck;
74 u32 dtr0, dtr1, dtr2, dtr3, dtr4;
75 u32 tmp1, tmp2;
76
77 ENTERFN();
78
79 /* mcu_init starts */
80 mrc_post_code(0x02, 0x00);
81
82 dtr0 = msg_port_read(MEM_CTLR, DTR0);
83 dtr1 = msg_port_read(MEM_CTLR, DTR1);
84 dtr2 = msg_port_read(MEM_CTLR, DTR2);
85 dtr3 = msg_port_read(MEM_CTLR, DTR3);
86 dtr4 = msg_port_read(MEM_CTLR, DTR4);
87
88 tck = t_ck[mrc_params->ddr_speed]; /* Clock in picoseconds */
89 tcl = mrc_params->params.cl; /* CAS latency in clocks */
90 trp = tcl; /* Per CAT MRC */
91 trcd = tcl; /* Per CAT MRC */
92 tras = MCEIL(mrc_params->params.ras, tck);
93
94 /* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
95 twr = MCEIL(15000, tck);
96
97 twtr = MCEIL(mrc_params->params.wtr, tck);
98 trrd = MCEIL(mrc_params->params.rrd, tck);
99 trtp = 4; /* Valid for 800 and 1066, use 5 for 1333 */
100 tfaw = MCEIL(mrc_params->params.faw, tck);
101
102 wl = 5 + mrc_params->ddr_speed;
103
Bin Meng15e3f282015-03-10 18:31:20 +0800104 dtr0 &= ~DTR0_DFREQ_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800105 dtr0 |= mrc_params->ddr_speed;
Bin Meng15e3f282015-03-10 18:31:20 +0800106 dtr0 &= ~DTR0_TCL_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800107 tmp1 = tcl - 5;
108 dtr0 |= ((tcl - 5) << 12);
Bin Meng15e3f282015-03-10 18:31:20 +0800109 dtr0 &= ~DTR0_TRP_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800110 dtr0 |= ((trp - 5) << 4); /* 5 bit DRAM Clock */
Bin Meng15e3f282015-03-10 18:31:20 +0800111 dtr0 &= ~DTR0_TRCD_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800112 dtr0 |= ((trcd - 5) << 8); /* 5 bit DRAM Clock */
113
Bin Meng15e3f282015-03-10 18:31:20 +0800114 dtr1 &= ~DTR1_TWCL_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800115 tmp2 = wl - 3;
116 dtr1 |= (wl - 3);
Bin Meng15e3f282015-03-10 18:31:20 +0800117 dtr1 &= ~DTR1_TWTP_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800118 dtr1 |= ((wl + 4 + twr - 14) << 8); /* Change to tWTP */
Bin Meng15e3f282015-03-10 18:31:20 +0800119 dtr1 &= ~DTR1_TRTP_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800120 dtr1 |= ((MMAX(trtp, 4) - 3) << 28); /* 4 bit DRAM Clock */
Bin Meng15e3f282015-03-10 18:31:20 +0800121 dtr1 &= ~DTR1_TRRD_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800122 dtr1 |= ((trrd - 4) << 24); /* 4 bit DRAM Clock */
Bin Meng15e3f282015-03-10 18:31:20 +0800123 dtr1 &= ~DTR1_TCMD_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800124 dtr1 |= (1 << 4);
Bin Meng15e3f282015-03-10 18:31:20 +0800125 dtr1 &= ~DTR1_TRAS_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800126 dtr1 |= ((tras - 14) << 20); /* 6 bit DRAM Clock */
Bin Meng15e3f282015-03-10 18:31:20 +0800127 dtr1 &= ~DTR1_TFAW_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800128 dtr1 |= ((((tfaw + 1) >> 1) - 5) << 16);/* 4 bit DRAM Clock */
129 /* Set 4 Clock CAS to CAS delay (multi-burst) */
Bin Meng15e3f282015-03-10 18:31:20 +0800130 dtr1 &= ~DTR1_TCCD_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800131
Bin Meng15e3f282015-03-10 18:31:20 +0800132 dtr2 &= ~DTR2_TRRDR_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800133 dtr2 |= 1;
Bin Meng15e3f282015-03-10 18:31:20 +0800134 dtr2 &= ~DTR2_TWWDR_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800135 dtr2 |= (2 << 8);
Bin Meng15e3f282015-03-10 18:31:20 +0800136 dtr2 &= ~DTR2_TRWDR_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800137 dtr2 |= (2 << 16);
138
Bin Meng15e3f282015-03-10 18:31:20 +0800139 dtr3 &= ~DTR3_TWRDR_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800140 dtr3 |= 2;
Bin Meng15e3f282015-03-10 18:31:20 +0800141 dtr3 &= ~DTR3_TXXXX_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800142 dtr3 |= (2 << 4);
143
Bin Meng15e3f282015-03-10 18:31:20 +0800144 dtr3 &= ~DTR3_TRWSR_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800145 if (mrc_params->ddr_speed == DDRFREQ_800) {
146 /* Extended RW delay (+1) */
147 dtr3 |= ((tcl - 5 + 1) << 8);
148 } else if (mrc_params->ddr_speed == DDRFREQ_1066) {
149 /* Extended RW delay (+1) */
150 dtr3 |= ((tcl - 5 + 1) << 8);
151 }
152
Bin Meng15e3f282015-03-10 18:31:20 +0800153 dtr3 &= ~DTR3_TWRSR_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800154 dtr3 |= ((4 + wl + twtr - 11) << 13);
155
Bin Meng15e3f282015-03-10 18:31:20 +0800156 dtr3 &= ~DTR3_TXP_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800157 if (mrc_params->ddr_speed == DDRFREQ_800)
158 dtr3 |= ((MMAX(0, 1 - 1)) << 22);
159 else
160 dtr3 |= ((MMAX(0, 2 - 1)) << 22);
161
Bin Meng15e3f282015-03-10 18:31:20 +0800162 dtr4 &= ~DTR4_WRODTSTRT_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800163 dtr4 |= 1;
Bin Meng15e3f282015-03-10 18:31:20 +0800164 dtr4 &= ~DTR4_WRODTSTOP_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800165 dtr4 |= (1 << 4);
Bin Meng15e3f282015-03-10 18:31:20 +0800166 dtr4 &= ~DTR4_XXXX1_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800167 dtr4 |= ((1 + tmp1 - tmp2 + 2) << 8);
Bin Meng15e3f282015-03-10 18:31:20 +0800168 dtr4 &= ~DTR4_XXXX2_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800169 dtr4 |= ((1 + tmp1 - tmp2 + 2) << 12);
Bin Meng15e3f282015-03-10 18:31:20 +0800170 dtr4 &= ~(DTR4_ODTDIS | DTR4_TRGSTRDIS);
Bin Meng93b4a392015-02-05 23:42:24 +0800171
172 msg_port_write(MEM_CTLR, DTR0, dtr0);
173 msg_port_write(MEM_CTLR, DTR1, dtr1);
174 msg_port_write(MEM_CTLR, DTR2, dtr2);
175 msg_port_write(MEM_CTLR, DTR3, dtr3);
176 msg_port_write(MEM_CTLR, DTR4, dtr4);
177
178 LEAVEFN();
179}
180
181/* Configure MCU before jedec init sequence */
182void prog_decode_before_jedec(struct mrc_params *mrc_params)
183{
184 u32 drp;
185 u32 drfc;
186 u32 dcal;
187 u32 dsch;
188 u32 dpmc0;
189
190 ENTERFN();
191
192 /* Disable power saving features */
193 dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
Bin Meng15e3f282015-03-10 18:31:20 +0800194 dpmc0 |= (DPMC0_CLKGTDIS | DPMC0_DISPWRDN);
195 dpmc0 &= ~DPMC0_PCLSTO_MASK;
196 dpmc0 &= ~DPMC0_DYNSREN;
Bin Meng93b4a392015-02-05 23:42:24 +0800197 msg_port_write(MEM_CTLR, DPMC0, dpmc0);
198
199 /* Disable out of order transactions */
200 dsch = msg_port_read(MEM_CTLR, DSCH);
Bin Meng15e3f282015-03-10 18:31:20 +0800201 dsch |= (DSCH_OOODIS | DSCH_NEWBYPDIS);
Bin Meng93b4a392015-02-05 23:42:24 +0800202 msg_port_write(MEM_CTLR, DSCH, dsch);
203
204 /* Disable issuing the REF command */
205 drfc = msg_port_read(MEM_CTLR, DRFC);
Bin Meng15e3f282015-03-10 18:31:20 +0800206 drfc &= ~DRFC_TREFI_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800207 msg_port_write(MEM_CTLR, DRFC, drfc);
208
209 /* Disable ZQ calibration short */
210 dcal = msg_port_read(MEM_CTLR, DCAL);
Bin Meng15e3f282015-03-10 18:31:20 +0800211 dcal &= ~DCAL_ZQCINT_MASK;
212 dcal &= ~DCAL_SRXZQCL_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +0800213 msg_port_write(MEM_CTLR, DCAL, dcal);
214
215 /*
216 * Training performed in address mode 0, rank population has limited
217 * impact, however simulator complains if enabled non-existing rank.
218 */
219 drp = 0;
220 if (mrc_params->rank_enables & 1)
Bin Meng15e3f282015-03-10 18:31:20 +0800221 drp |= DRP_RKEN0;
Bin Meng93b4a392015-02-05 23:42:24 +0800222 if (mrc_params->rank_enables & 2)
Bin Meng15e3f282015-03-10 18:31:20 +0800223 drp |= DRP_RKEN1;
Bin Meng93b4a392015-02-05 23:42:24 +0800224 msg_port_write(MEM_CTLR, DRP, drp);
225
226 LEAVEFN();
227}
228
229/*
230 * After Cold Reset, BIOS should set COLDWAKE bit to 1 before
231 * sending the WAKE message to the Dunit.
232 *
233 * For Standby Exit, or any other mode in which the DRAM is in
234 * SR, this bit must be set to 0.
235 */
236void perform_ddr_reset(struct mrc_params *mrc_params)
237{
238 ENTERFN();
239
240 /* Set COLDWAKE bit before sending the WAKE message */
Bin Meng15e3f282015-03-10 18:31:20 +0800241 mrc_write_mask(MEM_CTLR, DRMC, DRMC_COLDWAKE, DRMC_COLDWAKE);
Bin Meng93b4a392015-02-05 23:42:24 +0800242
243 /* Send wake command to DUNIT (MUST be done before JEDEC) */
244 dram_wake_command();
245
246 /* Set default value */
247 msg_port_write(MEM_CTLR, DRMC,
Bin Meng15e3f282015-03-10 18:31:20 +0800248 mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0);
Bin Meng93b4a392015-02-05 23:42:24 +0800249
250 LEAVEFN();
251}
252
253
254/*
255 * This function performs some initialization on the DDRIO unit.
256 * This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
257 */
258void ddrphy_init(struct mrc_params *mrc_params)
259{
260 uint32_t temp;
261 uint8_t ch; /* channel counter */
262 uint8_t rk; /* rank counter */
263 uint8_t bl_grp; /* byte lane group counter (2 BLs per module) */
264 uint8_t bl_divisor = 1; /* byte lane divisor */
265 /* For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 */
Bin Meng15e3f282015-03-10 18:31:20 +0800266 uint8_t speed = mrc_params->ddr_speed & 3;
Bin Meng93b4a392015-02-05 23:42:24 +0800267 uint8_t cas;
268 uint8_t cwl;
269
270 ENTERFN();
271
272 cas = mrc_params->params.cl;
273 cwl = 5 + mrc_params->ddr_speed;
274
275 /* ddrphy_init starts */
276 mrc_post_code(0x03, 0x00);
277
278 /*
279 * HSD#231531
280 * Make sure IOBUFACT is deasserted before initializing the DDR PHY
281 *
282 * HSD#234845
283 * Make sure WRPTRENABLE is deasserted before initializing the DDR PHY
284 */
285 for (ch = 0; ch < NUM_CHANNELS; ch++) {
286 if (mrc_params->channel_enables & (1 << ch)) {
287 /* Deassert DDRPHY Initialization Complete */
288 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800289 CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
290 ~(1 << 20), 1 << 20); /* SPID_INIT_COMPLETE=0 */
Bin Meng93b4a392015-02-05 23:42:24 +0800291 /* Deassert IOBUFACT */
292 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800293 CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
294 ~(1 << 2), 1 << 2); /* IOBUFACTRST_N=0 */
Bin Meng93b4a392015-02-05 23:42:24 +0800295 /* Disable WRPTR */
296 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800297 CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
298 ~(1 << 0), 1 << 0); /* WRPTRENABLE=0 */
Bin Meng93b4a392015-02-05 23:42:24 +0800299 }
300 }
301
302 /* Put PHY in reset */
Bin Meng15e3f282015-03-10 18:31:20 +0800303 mrc_alt_write_mask(DDRPHY, MASTERRSTN, 0, 1);
Bin Meng93b4a392015-02-05 23:42:24 +0800304
305 /* Initialize DQ01, DQ23, CMD, CLK-CTL, COMP modules */
306
307 /* STEP0 */
308 mrc_post_code(0x03, 0x10);
309 for (ch = 0; ch < NUM_CHANNELS; ch++) {
310 if (mrc_params->channel_enables & (1 << ch)) {
311 /* DQ01-DQ23 */
312 for (bl_grp = 0;
Bin Meng15e3f282015-03-10 18:31:20 +0800313 bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
Bin Meng93b4a392015-02-05 23:42:24 +0800314 bl_grp++) {
315 /* Analog MUX select - IO2xCLKSEL */
316 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800317 DQOBSCKEBBCTL +
318 bl_grp * DDRIODQ_BL_OFFSET +
319 ch * DDRIODQ_CH_OFFSET,
320 bl_grp ? 0 : (1 << 22), 1 << 22);
Bin Meng93b4a392015-02-05 23:42:24 +0800321
322 /* ODT Strength */
323 switch (mrc_params->rd_odt_value) {
324 case 1:
325 temp = 0x3;
326 break; /* 60 ohm */
327 case 2:
328 temp = 0x3;
329 break; /* 120 ohm */
330 case 3:
331 temp = 0x3;
332 break; /* 180 ohm */
333 default:
334 temp = 0x3;
335 break; /* 120 ohm */
336 }
337
338 /* ODT strength */
339 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800340 B0RXIOBUFCTL +
341 bl_grp * DDRIODQ_BL_OFFSET +
342 ch * DDRIODQ_CH_OFFSET,
343 temp << 5, 0x60);
Bin Meng93b4a392015-02-05 23:42:24 +0800344 /* ODT strength */
345 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800346 B1RXIOBUFCTL +
347 bl_grp * DDRIODQ_BL_OFFSET +
348 ch * DDRIODQ_CH_OFFSET,
349 temp << 5, 0x60);
Bin Meng93b4a392015-02-05 23:42:24 +0800350
351 /* Dynamic ODT/DIFFAMP */
Bin Meng15e3f282015-03-10 18:31:20 +0800352 temp = (cas << 24) | (cas << 16) |
353 (cas << 8) | (cas << 0);
Bin Meng93b4a392015-02-05 23:42:24 +0800354 switch (speed) {
355 case 0:
356 temp -= 0x01010101;
357 break; /* 800 */
358 case 1:
359 temp -= 0x02020202;
360 break; /* 1066 */
361 case 2:
362 temp -= 0x03030303;
363 break; /* 1333 */
364 case 3:
365 temp -= 0x04040404;
366 break; /* 1600 */
367 }
368
369 /* Launch Time: ODT, DIFFAMP, ODT, DIFFAMP */
370 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800371 B01LATCTL1 +
372 bl_grp * DDRIODQ_BL_OFFSET +
373 ch * DDRIODQ_CH_OFFSET,
374 temp, 0x1f1f1f1f);
Bin Meng93b4a392015-02-05 23:42:24 +0800375 switch (speed) {
376 /* HSD#234715 */
377 case 0:
Bin Meng15e3f282015-03-10 18:31:20 +0800378 temp = (0x06 << 16) | (0x07 << 8);
Bin Meng93b4a392015-02-05 23:42:24 +0800379 break; /* 800 */
380 case 1:
Bin Meng15e3f282015-03-10 18:31:20 +0800381 temp = (0x07 << 16) | (0x08 << 8);
Bin Meng93b4a392015-02-05 23:42:24 +0800382 break; /* 1066 */
383 case 2:
Bin Meng15e3f282015-03-10 18:31:20 +0800384 temp = (0x09 << 16) | (0x0a << 8);
Bin Meng93b4a392015-02-05 23:42:24 +0800385 break; /* 1333 */
386 case 3:
Bin Meng15e3f282015-03-10 18:31:20 +0800387 temp = (0x0a << 16) | (0x0b << 8);
Bin Meng93b4a392015-02-05 23:42:24 +0800388 break; /* 1600 */
389 }
390
391 /* On Duration: ODT, DIFFAMP */
392 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800393 B0ONDURCTL +
394 bl_grp * DDRIODQ_BL_OFFSET +
395 ch * DDRIODQ_CH_OFFSET,
396 temp, 0x003f3f00);
Bin Meng93b4a392015-02-05 23:42:24 +0800397 /* On Duration: ODT, DIFFAMP */
398 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800399 B1ONDURCTL +
400 bl_grp * DDRIODQ_BL_OFFSET +
401 ch * DDRIODQ_CH_OFFSET,
402 temp, 0x003f3f00);
Bin Meng93b4a392015-02-05 23:42:24 +0800403
404 switch (mrc_params->rd_odt_value) {
405 case 0:
406 /* override DIFFAMP=on, ODT=off */
Bin Meng15e3f282015-03-10 18:31:20 +0800407 temp = (0x3f << 16) | (0x3f << 10);
Bin Meng93b4a392015-02-05 23:42:24 +0800408 break;
409 default:
410 /* override DIFFAMP=on, ODT=on */
Bin Meng15e3f282015-03-10 18:31:20 +0800411 temp = (0x3f << 16) | (0x2a << 10);
Bin Meng93b4a392015-02-05 23:42:24 +0800412 break;
413 }
414
415 /* Override: DIFFAMP, ODT */
416 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800417 B0OVRCTL +
418 bl_grp * DDRIODQ_BL_OFFSET +
419 ch * DDRIODQ_CH_OFFSET,
420 temp, 0x003ffc00);
Bin Meng93b4a392015-02-05 23:42:24 +0800421 /* Override: DIFFAMP, ODT */
422 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800423 B1OVRCTL +
424 bl_grp * DDRIODQ_BL_OFFSET +
425 ch * DDRIODQ_CH_OFFSET,
426 temp, 0x003ffc00);
Bin Meng93b4a392015-02-05 23:42:24 +0800427
428 /* DLL Setup */
429
430 /* 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) */
431 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800432 B0LATCTL0 +
433 bl_grp * DDRIODQ_BL_OFFSET +
434 ch * DDRIODQ_CH_OFFSET,
435 ((cas + 7) << 16) | ((cas - 4) << 8) |
436 ((cwl - 2) << 0), 0x003f1f1f);
Bin Meng93b4a392015-02-05 23:42:24 +0800437 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800438 B1LATCTL0 +
439 bl_grp * DDRIODQ_BL_OFFSET +
440 ch * DDRIODQ_CH_OFFSET,
441 ((cas + 7) << 16) | ((cas - 4) << 8) |
442 ((cwl - 2) << 0), 0x003f1f1f);
Bin Meng93b4a392015-02-05 23:42:24 +0800443
444 /* RCVEN Bypass (PO) */
445 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800446 B0RXIOBUFCTL +
447 bl_grp * DDRIODQ_BL_OFFSET +
448 ch * DDRIODQ_CH_OFFSET,
449 0, 0x81);
Bin Meng93b4a392015-02-05 23:42:24 +0800450 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800451 B1RXIOBUFCTL +
452 bl_grp * DDRIODQ_BL_OFFSET +
453 ch * DDRIODQ_CH_OFFSET,
454 0, 0x81);
Bin Meng93b4a392015-02-05 23:42:24 +0800455
456 /* TX */
457 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800458 DQCTL +
459 bl_grp * DDRIODQ_BL_OFFSET +
460 ch * DDRIODQ_CH_OFFSET,
461 1 << 16, 1 << 16);
Bin Meng93b4a392015-02-05 23:42:24 +0800462 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800463 B01PTRCTL1 +
464 bl_grp * DDRIODQ_BL_OFFSET +
465 ch * DDRIODQ_CH_OFFSET,
466 1 << 8, 1 << 8);
Bin Meng93b4a392015-02-05 23:42:24 +0800467
468 /* RX (PO) */
469 /* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
470 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800471 B0VREFCTL +
472 bl_grp * DDRIODQ_BL_OFFSET +
473 ch * DDRIODQ_CH_OFFSET,
474 (0x03 << 2) | (0x0 << 1) | (0x0 << 0),
475 0xff);
Bin Meng93b4a392015-02-05 23:42:24 +0800476 /* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
477 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800478 B1VREFCTL +
479 bl_grp * DDRIODQ_BL_OFFSET +
480 ch * DDRIODQ_CH_OFFSET,
481 (0x03 << 2) | (0x0 << 1) | (0x0 << 0),
482 0xff);
Bin Meng93b4a392015-02-05 23:42:24 +0800483 /* Per-Bit De-Skew Enable */
484 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800485 B0RXIOBUFCTL +
486 bl_grp * DDRIODQ_BL_OFFSET +
487 ch * DDRIODQ_CH_OFFSET,
488 0, 0x10);
Bin Meng93b4a392015-02-05 23:42:24 +0800489 /* Per-Bit De-Skew Enable */
490 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800491 B1RXIOBUFCTL +
492 bl_grp * DDRIODQ_BL_OFFSET +
493 ch * DDRIODQ_CH_OFFSET,
494 0, 0x10);
Bin Meng93b4a392015-02-05 23:42:24 +0800495 }
496
497 /* CLKEBB */
498 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800499 CMDOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
500 0, 1 << 23);
Bin Meng93b4a392015-02-05 23:42:24 +0800501
502 /* Enable tristate control of cmd/address bus */
503 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800504 CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
505 0, 0x03);
Bin Meng93b4a392015-02-05 23:42:24 +0800506
507 /* ODT RCOMP */
508 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800509 CMDRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
510 (0x03 << 5) | (0x03 << 0), 0x3ff);
Bin Meng93b4a392015-02-05 23:42:24 +0800511
512 /* CMDPM* registers must be programmed in this order */
513
514 /* Turn On Delays: SFR (regulator), MPLL */
515 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800516 CMDPMDLYREG4 + ch * DDRIOCCC_CH_OFFSET,
517 0xffffffff, 0xffffffff);
Bin Meng93b4a392015-02-05 23:42:24 +0800518 /*
519 * Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3,
520 * VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT
521 * for_PM_MSG_gt0, MDLL Turn On
522 */
523 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800524 CMDPMDLYREG3 + ch * DDRIOCCC_CH_OFFSET,
525 0xfffff616, 0xffffffff);
Bin Meng93b4a392015-02-05 23:42:24 +0800526 /* MPLL Divider Reset Delays */
527 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800528 CMDPMDLYREG2 + ch * DDRIOCCC_CH_OFFSET,
529 0xffffffff, 0xffffffff);
Bin Meng93b4a392015-02-05 23:42:24 +0800530 /* Turn Off Delays: VREG, Staggered MDLL, MDLL, PI */
531 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800532 CMDPMDLYREG1 + ch * DDRIOCCC_CH_OFFSET,
533 0xffffffff, 0xffffffff);
Bin Meng93b4a392015-02-05 23:42:24 +0800534 /* Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT */
535 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800536 CMDPMDLYREG0 + ch * DDRIOCCC_CH_OFFSET,
537 0xffffffff, 0xffffffff);
Bin Meng93b4a392015-02-05 23:42:24 +0800538 /* Allow PUnit signals */
539 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800540 CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
541 (0x6 << 8) | (0x1 << 6) | (0x4 << 0),
542 0xffe00f4f);
Bin Meng93b4a392015-02-05 23:42:24 +0800543 /* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
544 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800545 CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
546 (0x3 << 4) | (0x7 << 0), 0x7f);
Bin Meng93b4a392015-02-05 23:42:24 +0800547
548 /* CLK-CTL */
549 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800550 CCOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
551 0, 1 << 24); /* CLKEBB */
Bin Meng93b4a392015-02-05 23:42:24 +0800552 /* Buffer Enable: CS,CKE,ODT,CLK */
553 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800554 CCCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
555 0x1f, 0x000ffff1);
Bin Meng93b4a392015-02-05 23:42:24 +0800556 /* ODT RCOMP */
557 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800558 CCRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
559 (0x03 << 8) | (0x03 << 0), 0x00001f1f);
Bin Meng93b4a392015-02-05 23:42:24 +0800560 /* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
561 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800562 CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
563 (0x3 << 4) | (0x7 << 0), 0x7f);
Bin Meng93b4a392015-02-05 23:42:24 +0800564
565 /*
566 * COMP (RON channel specific)
567 * - DQ/DQS/DM RON: 32 Ohm
568 * - CTRL/CMD RON: 27 Ohm
569 * - CLK RON: 26 Ohm
570 */
571 /* RCOMP Vref PU/PD */
572 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800573 DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
574 (0x08 << 24) | (0x03 << 16), 0x3f3f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800575 /* RCOMP Vref PU/PD */
576 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800577 CMDVREFCH0 + ch * DDRCOMP_CH_OFFSET,
578 (0x0C << 24) | (0x03 << 16), 0x3f3f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800579 /* RCOMP Vref PU/PD */
580 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800581 CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
582 (0x0F << 24) | (0x03 << 16), 0x3f3f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800583 /* RCOMP Vref PU/PD */
584 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800585 DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
586 (0x08 << 24) | (0x03 << 16), 0x3f3f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800587 /* RCOMP Vref PU/PD */
588 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800589 CTLVREFCH0 + ch * DDRCOMP_CH_OFFSET,
590 (0x0C << 24) | (0x03 << 16), 0x3f3f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800591
592 /* DQS Swapped Input Enable */
593 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800594 COMPEN1CH0 + ch * DDRCOMP_CH_OFFSET,
595 (1 << 19) | (1 << 17), 0xc00ac000);
Bin Meng93b4a392015-02-05 23:42:24 +0800596
597 /* ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) */
598 /* ODT Vref PU/PD */
599 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800600 DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
601 (0x32 << 8) | (0x03 << 0), 0x00003f3f);
Bin Meng93b4a392015-02-05 23:42:24 +0800602 /* ODT Vref PU/PD */
603 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800604 DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
605 (0x32 << 8) | (0x03 << 0), 0x00003f3f);
Bin Meng93b4a392015-02-05 23:42:24 +0800606 /* ODT Vref PU/PD */
607 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800608 CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
609 (0x0E << 8) | (0x05 << 0), 0x00003f3f);
Bin Meng93b4a392015-02-05 23:42:24 +0800610
611 /*
612 * Slew rate settings are frequency specific,
613 * numbers below are for 800Mhz (speed == 0)
614 * - DQ/DQS/DM/CLK SR: 4V/ns,
615 * - CTRL/CMD SR: 1.5V/ns
616 */
Bin Meng15e3f282015-03-10 18:31:20 +0800617 temp = (0x0e << 16) | (0x0e << 12) | (0x08 << 8) |
618 (0x0b << 4) | (0x0b << 0);
Bin Meng93b4a392015-02-05 23:42:24 +0800619 /* DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ */
620 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800621 DLYSELCH0 + ch * DDRCOMP_CH_OFFSET,
622 temp, 0x000fffff);
Bin Meng93b4a392015-02-05 23:42:24 +0800623 /* TCO Vref CLK,DQS,DQ */
624 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800625 TCOVREFCH0 + ch * DDRCOMP_CH_OFFSET,
626 (0x05 << 16) | (0x05 << 8) | (0x05 << 0),
627 0x003f3f3f);
Bin Meng93b4a392015-02-05 23:42:24 +0800628 /* ODTCOMP CMD/CTL PU/PD */
629 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800630 CCBUFODTCH0 + ch * DDRCOMP_CH_OFFSET,
631 (0x03 << 8) | (0x03 << 0),
632 0x00001f1f);
Bin Meng93b4a392015-02-05 23:42:24 +0800633 /* COMP */
634 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800635 COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
636 0, 0xc0000100);
Bin Meng93b4a392015-02-05 23:42:24 +0800637
638#ifdef BACKUP_COMPS
639 /* DQ COMP Overrides */
640 /* RCOMP PU */
641 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800642 DQDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
643 (1 << 31) | (0x0a << 16),
644 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800645 /* RCOMP PD */
646 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800647 DQDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
648 (1 << 31) | (0x0a << 16),
649 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800650 /* DCOMP PU */
651 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800652 DQDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
653 (1 << 31) | (0x10 << 16),
654 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800655 /* DCOMP PD */
656 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800657 DQDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
658 (1 << 31) | (0x10 << 16),
659 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800660 /* ODTCOMP PU */
661 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800662 DQODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
663 (1 << 31) | (0x0b << 16),
664 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800665 /* ODTCOMP PD */
666 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800667 DQODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
668 (1 << 31) | (0x0b << 16),
669 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800670 /* TCOCOMP PU */
671 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800672 DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
673 1 << 31, 1 << 31);
Bin Meng93b4a392015-02-05 23:42:24 +0800674 /* TCOCOMP PD */
675 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800676 DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
677 1 << 31, 1 << 31);
Bin Meng93b4a392015-02-05 23:42:24 +0800678
679 /* DQS COMP Overrides */
680 /* RCOMP PU */
681 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800682 DQSDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
683 (1 << 31) | (0x0a << 16),
684 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800685 /* RCOMP PD */
686 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800687 DQSDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
688 (1 << 31) | (0x0a << 16),
689 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800690 /* DCOMP PU */
691 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800692 DQSDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
693 (1 << 31) | (0x10 << 16),
694 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800695 /* DCOMP PD */
696 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800697 DQSDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
698 (1 << 31) | (0x10 << 16),
699 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800700 /* ODTCOMP PU */
701 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800702 DQSODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
703 (1 << 31) | (0x0b << 16),
704 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800705 /* ODTCOMP PD */
706 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800707 DQSODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
708 (1 << 31) | (0x0b << 16),
709 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800710 /* TCOCOMP PU */
711 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800712 DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
713 1 << 31, 1 << 31);
Bin Meng93b4a392015-02-05 23:42:24 +0800714 /* TCOCOMP PD */
715 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800716 DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
717 1 << 31, 1 << 31);
Bin Meng93b4a392015-02-05 23:42:24 +0800718
719 /* CLK COMP Overrides */
720 /* RCOMP PU */
721 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800722 CLKDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
723 (1 << 31) | (0x0c << 16),
724 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800725 /* RCOMP PD */
726 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800727 CLKDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
728 (1 << 31) | (0x0c << 16),
729 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800730 /* DCOMP PU */
731 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800732 CLKDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
733 (1 << 31) | (0x07 << 16),
734 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800735 /* DCOMP PD */
736 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800737 CLKDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
738 (1 << 31) | (0x07 << 16),
739 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800740 /* ODTCOMP PU */
741 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800742 CLKODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
743 (1 << 31) | (0x0b << 16),
744 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800745 /* ODTCOMP PD */
746 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800747 CLKODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
748 (1 << 31) | (0x0b << 16),
749 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800750 /* TCOCOMP PU */
751 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800752 CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
753 1 << 31, 1 << 31);
Bin Meng93b4a392015-02-05 23:42:24 +0800754 /* TCOCOMP PD */
755 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800756 CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
757 1 << 31, 1 << 31);
Bin Meng93b4a392015-02-05 23:42:24 +0800758
759 /* CMD COMP Overrides */
760 /* RCOMP PU */
761 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800762 CMDDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
763 (1 << 31) | (0x0d << 16),
764 0x803f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800765 /* RCOMP PD */
766 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800767 CMDDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
768 (1 << 31) | (0x0d << 16),
769 0x803f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800770 /* DCOMP PU */
771 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800772 CMDDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
773 (1 << 31) | (0x0a << 16),
774 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800775 /* DCOMP PD */
776 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800777 CMDDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
778 (1 << 31) | (0x0a << 16),
779 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800780
781 /* CTL COMP Overrides */
782 /* RCOMP PU */
783 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800784 CTLDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
785 (1 << 31) | (0x0d << 16),
786 0x803f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800787 /* RCOMP PD */
788 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800789 CTLDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
790 (1 << 31) | (0x0d << 16),
791 0x803f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800792 /* DCOMP PU */
793 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800794 CTLDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
795 (1 << 31) | (0x0a << 16),
796 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800797 /* DCOMP PD */
798 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800799 CTLDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
800 (1 << 31) | (0x0a << 16),
801 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800802#else
803 /* DQ TCOCOMP Overrides */
804 /* TCOCOMP PU */
805 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800806 DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
807 (1 << 31) | (0x1f << 16),
808 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800809 /* TCOCOMP PD */
810 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800811 DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
812 (1 << 31) | (0x1f << 16),
813 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800814
815 /* DQS TCOCOMP Overrides */
816 /* TCOCOMP PU */
817 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800818 DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
819 (1 << 31) | (0x1f << 16),
820 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800821 /* TCOCOMP PD */
822 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800823 DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
824 (1 << 31) | (0x1f << 16),
825 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800826
827 /* CLK TCOCOMP Overrides */
828 /* TCOCOMP PU */
829 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800830 CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
831 (1 << 31) | (0x1f << 16),
832 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800833 /* TCOCOMP PD */
834 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800835 CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
836 (1 << 31) | (0x1f << 16),
837 0x801f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800838#endif
839
840 /* program STATIC delays */
841#ifdef BACKUP_WCMD
842 set_wcmd(ch, ddr_wcmd[PLATFORM_ID]);
843#else
844 set_wcmd(ch, ddr_wclk[PLATFORM_ID] + HALF_CLK);
845#endif
846
847 for (rk = 0; rk < NUM_RANKS; rk++) {
Bin Meng15e3f282015-03-10 18:31:20 +0800848 if (mrc_params->rank_enables & (1 << rk)) {
Bin Meng93b4a392015-02-05 23:42:24 +0800849 set_wclk(ch, rk, ddr_wclk[PLATFORM_ID]);
850#ifdef BACKUP_WCTL
851 set_wctl(ch, rk, ddr_wctl[PLATFORM_ID]);
852#else
853 set_wctl(ch, rk, ddr_wclk[PLATFORM_ID] + HALF_CLK);
854#endif
855 }
856 }
857 }
858 }
859
860 /* COMP (non channel specific) */
861 /* RCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800862 mrc_alt_write_mask(DDRPHY, DQANADRVPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800863 /* RCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800864 mrc_alt_write_mask(DDRPHY, DQANADRVPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800865 /* RCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800866 mrc_alt_write_mask(DDRPHY, CMDANADRVPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800867 /* RCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800868 mrc_alt_write_mask(DDRPHY, CMDANADRVPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800869 /* RCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800870 mrc_alt_write_mask(DDRPHY, CLKANADRVPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800871 /* RCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800872 mrc_alt_write_mask(DDRPHY, CLKANADRVPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800873 /* RCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800874 mrc_alt_write_mask(DDRPHY, DQSANADRVPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800875 /* RCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800876 mrc_alt_write_mask(DDRPHY, DQSANADRVPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800877 /* RCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800878 mrc_alt_write_mask(DDRPHY, CTLANADRVPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800879 /* RCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800880 mrc_alt_write_mask(DDRPHY, CTLANADRVPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800881 /* ODT: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800882 mrc_alt_write_mask(DDRPHY, DQANAODTPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800883 /* ODT: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800884 mrc_alt_write_mask(DDRPHY, DQANAODTPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800885 /* ODT: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800886 mrc_alt_write_mask(DDRPHY, CLKANAODTPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800887 /* ODT: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800888 mrc_alt_write_mask(DDRPHY, CLKANAODTPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800889 /* ODT: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800890 mrc_alt_write_mask(DDRPHY, DQSANAODTPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800891 /* ODT: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800892 mrc_alt_write_mask(DDRPHY, DQSANAODTPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800893 /* DCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800894 mrc_alt_write_mask(DDRPHY, DQANADLYPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800895 /* DCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800896 mrc_alt_write_mask(DDRPHY, DQANADLYPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800897 /* DCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800898 mrc_alt_write_mask(DDRPHY, CMDANADLYPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800899 /* DCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800900 mrc_alt_write_mask(DDRPHY, CMDANADLYPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800901 /* DCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800902 mrc_alt_write_mask(DDRPHY, CLKANADLYPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800903 /* DCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800904 mrc_alt_write_mask(DDRPHY, CLKANADLYPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800905 /* DCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800906 mrc_alt_write_mask(DDRPHY, DQSANADLYPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800907 /* DCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800908 mrc_alt_write_mask(DDRPHY, DQSANADLYPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800909 /* DCOMP: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800910 mrc_alt_write_mask(DDRPHY, CTLANADLYPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800911 /* DCOMP: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800912 mrc_alt_write_mask(DDRPHY, CTLANADLYPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800913 /* TCO: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800914 mrc_alt_write_mask(DDRPHY, DQANATCOPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800915 /* TCO: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800916 mrc_alt_write_mask(DDRPHY, DQANATCOPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800917 /* TCO: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800918 mrc_alt_write_mask(DDRPHY, CLKANATCOPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800919 /* TCO: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800920 mrc_alt_write_mask(DDRPHY, CLKANATCOPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800921 /* TCO: Dither PU Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800922 mrc_alt_write_mask(DDRPHY, DQSANATCOPUCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800923 /* TCO: Dither PD Enable */
Bin Meng15e3f282015-03-10 18:31:20 +0800924 mrc_alt_write_mask(DDRPHY, DQSANATCOPDCTL, 1 << 30, 1 << 30);
Bin Meng93b4a392015-02-05 23:42:24 +0800925 /* TCOCOMP: Pulse Count */
Bin Meng15e3f282015-03-10 18:31:20 +0800926 mrc_alt_write_mask(DDRPHY, TCOCNTCTRL, 1, 3);
Bin Meng93b4a392015-02-05 23:42:24 +0800927 /* ODT: CMD/CTL PD/PU */
Bin Meng15e3f282015-03-10 18:31:20 +0800928 mrc_alt_write_mask(DDRPHY, CHNLBUFSTATIC,
929 (0x03 << 24) | (0x03 << 16), 0x1f1f0000);
Bin Meng93b4a392015-02-05 23:42:24 +0800930 /* Set 1us counter */
Bin Meng15e3f282015-03-10 18:31:20 +0800931 mrc_alt_write_mask(DDRPHY, MSCNTR, 0x64, 0xff);
932 mrc_alt_write_mask(DDRPHY, LATCH1CTL, 0x1 << 28, 0x70000000);
Bin Meng93b4a392015-02-05 23:42:24 +0800933
934 /* Release PHY from reset */
Bin Meng15e3f282015-03-10 18:31:20 +0800935 mrc_alt_write_mask(DDRPHY, MASTERRSTN, 1, 1);
Bin Meng93b4a392015-02-05 23:42:24 +0800936
937 /* STEP1 */
938 mrc_post_code(0x03, 0x11);
939
940 for (ch = 0; ch < NUM_CHANNELS; ch++) {
941 if (mrc_params->channel_enables & (1 << ch)) {
942 /* DQ01-DQ23 */
943 for (bl_grp = 0;
Bin Meng15e3f282015-03-10 18:31:20 +0800944 bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
Bin Meng93b4a392015-02-05 23:42:24 +0800945 bl_grp++) {
946 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800947 DQMDLLCTL +
948 bl_grp * DDRIODQ_BL_OFFSET +
949 ch * DDRIODQ_CH_OFFSET,
950 1 << 13,
951 1 << 13); /* Enable VREG */
Bin Meng93b4a392015-02-05 23:42:24 +0800952 delay_n(3);
953 }
954
955 /* ECC */
Bin Meng15e3f282015-03-10 18:31:20 +0800956 mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
957 1 << 13, 1 << 13); /* Enable VREG */
Bin Meng93b4a392015-02-05 23:42:24 +0800958 delay_n(3);
959 /* CMD */
960 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800961 CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
962 1 << 13, 1 << 13); /* Enable VREG */
Bin Meng93b4a392015-02-05 23:42:24 +0800963 delay_n(3);
964 /* CLK-CTL */
965 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800966 CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
967 1 << 13, 1 << 13); /* Enable VREG */
Bin Meng93b4a392015-02-05 23:42:24 +0800968 delay_n(3);
969 }
970 }
971
972 /* STEP2 */
973 mrc_post_code(0x03, 0x12);
974 delay_n(200);
975
976 for (ch = 0; ch < NUM_CHANNELS; ch++) {
977 if (mrc_params->channel_enables & (1 << ch)) {
978 /* DQ01-DQ23 */
979 for (bl_grp = 0;
Bin Meng15e3f282015-03-10 18:31:20 +0800980 bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
Bin Meng93b4a392015-02-05 23:42:24 +0800981 bl_grp++) {
982 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800983 DQMDLLCTL +
984 bl_grp * DDRIODQ_BL_OFFSET +
985 ch * DDRIODQ_CH_OFFSET,
986 1 << 17,
987 1 << 17); /* Enable MCDLL */
Bin Meng93b4a392015-02-05 23:42:24 +0800988 delay_n(50);
989 }
990
991 /* ECC */
Bin Meng15e3f282015-03-10 18:31:20 +0800992 mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
993 1 << 17, 1 << 17); /* Enable MCDLL */
Bin Meng93b4a392015-02-05 23:42:24 +0800994 delay_n(50);
995 /* CMD */
996 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +0800997 CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
998 1 << 18, 1 << 18); /* Enable MCDLL */
Bin Meng93b4a392015-02-05 23:42:24 +0800999 delay_n(50);
1000 /* CLK-CTL */
1001 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001002 CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
1003 1 << 18, 1 << 18); /* Enable MCDLL */
Bin Meng93b4a392015-02-05 23:42:24 +08001004 delay_n(50);
1005 }
1006 }
1007
1008 /* STEP3: */
1009 mrc_post_code(0x03, 0x13);
1010 delay_n(100);
1011
1012 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1013 if (mrc_params->channel_enables & (1 << ch)) {
1014 /* DQ01-DQ23 */
1015 for (bl_grp = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08001016 bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
Bin Meng93b4a392015-02-05 23:42:24 +08001017 bl_grp++) {
1018#ifdef FORCE_16BIT_DDRIO
Bin Meng15e3f282015-03-10 18:31:20 +08001019 temp = (bl_grp &&
Bin Meng93b4a392015-02-05 23:42:24 +08001020 (mrc_params->channel_width == X16)) ?
Bin Meng15e3f282015-03-10 18:31:20 +08001021 0x11ff : 0xffff;
Bin Meng93b4a392015-02-05 23:42:24 +08001022#else
Bin Meng15e3f282015-03-10 18:31:20 +08001023 temp = 0xffff;
Bin Meng93b4a392015-02-05 23:42:24 +08001024#endif
1025 /* Enable TXDLL */
1026 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001027 DQDLLTXCTL +
1028 bl_grp * DDRIODQ_BL_OFFSET +
1029 ch * DDRIODQ_CH_OFFSET,
1030 temp, 0xffff);
Bin Meng93b4a392015-02-05 23:42:24 +08001031 delay_n(3);
1032 /* Enable RXDLL */
1033 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001034 DQDLLRXCTL +
1035 bl_grp * DDRIODQ_BL_OFFSET +
1036 ch * DDRIODQ_CH_OFFSET,
1037 0xf, 0xf);
Bin Meng93b4a392015-02-05 23:42:24 +08001038 delay_n(3);
1039 /* Enable RXDLL Overrides BL0 */
1040 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001041 B0OVRCTL +
1042 bl_grp * DDRIODQ_BL_OFFSET +
1043 ch * DDRIODQ_CH_OFFSET,
1044 0xf, 0xf);
Bin Meng93b4a392015-02-05 23:42:24 +08001045 }
1046
1047 /* ECC */
Bin Meng15e3f282015-03-10 18:31:20 +08001048 temp = 0xffff;
1049 mrc_alt_write_mask(DDRPHY, ECCDLLTXCTL,
1050 temp, 0xffff);
Bin Meng93b4a392015-02-05 23:42:24 +08001051 delay_n(3);
1052
1053 /* CMD (PO) */
1054 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001055 CMDDLLTXCTL + ch * DDRIOCCC_CH_OFFSET,
1056 temp, 0xffff);
Bin Meng93b4a392015-02-05 23:42:24 +08001057 delay_n(3);
1058 }
1059 }
1060
1061 /* STEP4 */
1062 mrc_post_code(0x03, 0x14);
1063
1064 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1065 if (mrc_params->channel_enables & (1 << ch)) {
1066 /* Host To Memory Clock Alignment (HMC) for 800/1066 */
1067 for (bl_grp = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08001068 bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
Bin Meng93b4a392015-02-05 23:42:24 +08001069 bl_grp++) {
1070 /* CLK_ALIGN_MOD_ID */
1071 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001072 DQCLKALIGNREG2 +
1073 bl_grp * DDRIODQ_BL_OFFSET +
1074 ch * DDRIODQ_CH_OFFSET,
1075 bl_grp ? 3 : 1,
1076 0xf);
Bin Meng93b4a392015-02-05 23:42:24 +08001077 }
1078
1079 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001080 ECCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1081 0x2, 0xf);
Bin Meng93b4a392015-02-05 23:42:24 +08001082 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001083 CMDCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1084 0x0, 0xf);
Bin Meng93b4a392015-02-05 23:42:24 +08001085 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001086 CCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
1087 0x2, 0xf);
Bin Meng93b4a392015-02-05 23:42:24 +08001088 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001089 CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1090 0x20, 0x30);
Bin Meng93b4a392015-02-05 23:42:24 +08001091 /*
1092 * NUM_SAMPLES, MAX_SAMPLES,
1093 * MACRO_PI_STEP, MICRO_PI_STEP
1094 */
1095 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001096 CMDCLKALIGNREG1 + ch * DDRIOCCC_CH_OFFSET,
1097 (0x18 << 16) | (0x10 << 8) |
1098 (0x8 << 2) | (0x1 << 0),
1099 0x007f7fff);
Bin Meng93b4a392015-02-05 23:42:24 +08001100 /* TOTAL_NUM_MODULES, FIRST_U_PARTITION */
1101 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001102 CMDCLKALIGNREG2 + ch * DDRIOCCC_CH_OFFSET,
1103 (0x10 << 16) | (0x4 << 8) | (0x2 << 4),
1104 0x001f0ff0);
Bin Meng93b4a392015-02-05 23:42:24 +08001105#ifdef HMC_TEST
1106 /* START_CLK_ALIGN=1 */
1107 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001108 CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
1109 1 << 24, 1 << 24);
Bin Meng93b4a392015-02-05 23:42:24 +08001110 while (msg_port_alt_read(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001111 CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET) &
1112 (1 << 24))
Bin Meng93b4a392015-02-05 23:42:24 +08001113 ; /* wait for START_CLK_ALIGN=0 */
1114#endif
1115
1116 /* Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN */
1117 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001118 CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
1119 1, 1); /* WRPTRENABLE=1 */
Bin Meng93b4a392015-02-05 23:42:24 +08001120
1121 /* COMP initial */
1122 /* enable bypass for CLK buffer (PO) */
1123 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001124 COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1125 1 << 5, 1 << 5);
Bin Meng93b4a392015-02-05 23:42:24 +08001126 /* Initial COMP Enable */
Bin Meng15e3f282015-03-10 18:31:20 +08001127 mrc_alt_write_mask(DDRPHY, CMPCTRL, 1, 1);
Bin Meng93b4a392015-02-05 23:42:24 +08001128 /* wait for Initial COMP Enable = 0 */
Bin Meng15e3f282015-03-10 18:31:20 +08001129 while (msg_port_alt_read(DDRPHY, CMPCTRL) & 1)
Bin Meng93b4a392015-02-05 23:42:24 +08001130 ;
1131 /* disable bypass for CLK buffer (PO) */
1132 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001133 COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
1134 ~(1 << 5), 1 << 5);
Bin Meng93b4a392015-02-05 23:42:24 +08001135
1136 /* IOBUFACT */
1137
1138 /* STEP4a */
1139 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001140 CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
1141 1 << 2, 1 << 2); /* IOBUFACTRST_N=1 */
Bin Meng93b4a392015-02-05 23:42:24 +08001142
1143 /* DDRPHY initialization complete */
1144 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001145 CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
1146 1 << 20, 1 << 20); /* SPID_INIT_COMPLETE=1 */
Bin Meng93b4a392015-02-05 23:42:24 +08001147 }
1148 }
1149
1150 LEAVEFN();
1151}
1152
1153/* This function performs JEDEC initialization on all enabled channels */
1154void perform_jedec_init(struct mrc_params *mrc_params)
1155{
1156 uint8_t twr, wl, rank;
1157 uint32_t tck;
1158 u32 dtr0;
1159 u32 drp;
1160 u32 drmc;
1161 u32 mrs0_cmd = 0;
1162 u32 emrs1_cmd = 0;
1163 u32 emrs2_cmd = 0;
1164 u32 emrs3_cmd = 0;
1165
1166 ENTERFN();
1167
1168 /* jedec_init starts */
1169 mrc_post_code(0x04, 0x00);
1170
1171 /* DDR3_RESET_SET=0, DDR3_RESET_RESET=1 */
Bin Meng15e3f282015-03-10 18:31:20 +08001172 mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 2, 0x102);
Bin Meng93b4a392015-02-05 23:42:24 +08001173
1174 /* Assert RESET# for 200us */
1175 delay_u(200);
1176
1177 /* DDR3_RESET_SET=1, DDR3_RESET_RESET=0 */
Bin Meng15e3f282015-03-10 18:31:20 +08001178 mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 0x100, 0x102);
Bin Meng93b4a392015-02-05 23:42:24 +08001179
1180 dtr0 = msg_port_read(MEM_CTLR, DTR0);
1181
1182 /*
1183 * Set CKEVAL for populated ranks
1184 * then send NOP to each rank (#4550197)
1185 */
1186
1187 drp = msg_port_read(MEM_CTLR, DRP);
1188 drp &= 0x3;
1189
1190 drmc = msg_port_read(MEM_CTLR, DRMC);
Bin Meng15e3f282015-03-10 18:31:20 +08001191 drmc &= 0xfffffffc;
1192 drmc |= (DRMC_CKEMODE | drp);
Bin Meng93b4a392015-02-05 23:42:24 +08001193
1194 msg_port_write(MEM_CTLR, DRMC, drmc);
1195
1196 for (rank = 0; rank < NUM_RANKS; rank++) {
1197 /* Skip to next populated rank */
1198 if ((mrc_params->rank_enables & (1 << rank)) == 0)
1199 continue;
1200
1201 dram_init_command(DCMD_NOP(rank));
1202 }
1203
1204 msg_port_write(MEM_CTLR, DRMC,
Bin Meng15e3f282015-03-10 18:31:20 +08001205 (mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0));
Bin Meng93b4a392015-02-05 23:42:24 +08001206
1207 /*
1208 * setup for emrs 2
1209 * BIT[15:11] --> Always "0"
1210 * BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
1211 * BIT[08] --> Always "0"
1212 * BIT[07] --> SRT: use sr_temp_range
1213 * BIT[06] --> ASR: want "Manual SR Reference" (0)
1214 * BIT[05:03] --> CWL: use oem_tCWL
1215 * BIT[02:00] --> PASR: want "Full Array" (0)
1216 */
1217 emrs2_cmd |= (2 << 3);
1218 wl = 5 + mrc_params->ddr_speed;
1219 emrs2_cmd |= ((wl - 5) << 9);
1220 emrs2_cmd |= (mrc_params->sr_temp_range << 13);
1221
1222 /*
1223 * setup for emrs 3
1224 * BIT[15:03] --> Always "0"
1225 * BIT[02] --> MPR: want "Normal Operation" (0)
1226 * BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
1227 */
1228 emrs3_cmd |= (3 << 3);
1229
1230 /*
1231 * setup for emrs 1
1232 * BIT[15:13] --> Always "0"
1233 * BIT[12:12] --> Qoff: want "Output Buffer Enabled" (0)
1234 * BIT[11:11] --> TDQS: want "Disabled" (0)
1235 * BIT[10:10] --> Always "0"
1236 * BIT[09,06,02] --> Rtt_nom: use rtt_nom_value
1237 * BIT[08] --> Always "0"
1238 * BIT[07] --> WR_LVL: want "Disabled" (0)
1239 * BIT[05,01] --> DIC: use ron_value
1240 * BIT[04:03] --> AL: additive latency want "0" (0)
1241 * BIT[00] --> DLL: want "Enable" (0)
1242 *
1243 * (BIT5|BIT1) set Ron value
1244 * 00 --> RZQ/6 (40ohm)
1245 * 01 --> RZQ/7 (34ohm)
1246 * 1* --> RESERVED
1247 *
1248 * (BIT9|BIT6|BIT2) set Rtt_nom value
1249 * 000 --> Disabled
1250 * 001 --> RZQ/4 ( 60ohm)
1251 * 010 --> RZQ/2 (120ohm)
1252 * 011 --> RZQ/6 ( 40ohm)
1253 * 1** --> RESERVED
1254 */
1255 emrs1_cmd |= (1 << 3);
Bin Meng15e3f282015-03-10 18:31:20 +08001256 emrs1_cmd &= ~(1 << 6);
Bin Meng93b4a392015-02-05 23:42:24 +08001257
1258 if (mrc_params->ron_value == 0)
Bin Meng15e3f282015-03-10 18:31:20 +08001259 emrs1_cmd |= (1 << 7);
Bin Meng93b4a392015-02-05 23:42:24 +08001260 else
Bin Meng15e3f282015-03-10 18:31:20 +08001261 emrs1_cmd &= ~(1 << 7);
Bin Meng93b4a392015-02-05 23:42:24 +08001262
1263 if (mrc_params->rtt_nom_value == 0)
1264 emrs1_cmd |= (DDR3_EMRS1_RTTNOM_40 << 6);
1265 else if (mrc_params->rtt_nom_value == 1)
1266 emrs1_cmd |= (DDR3_EMRS1_RTTNOM_60 << 6);
1267 else if (mrc_params->rtt_nom_value == 2)
1268 emrs1_cmd |= (DDR3_EMRS1_RTTNOM_120 << 6);
1269
1270 /* save MRS1 value (excluding control fields) */
1271 mrc_params->mrs1 = emrs1_cmd >> 6;
1272
1273 /*
1274 * setup for mrs 0
1275 * BIT[15:13] --> Always "0"
1276 * BIT[12] --> PPD: for Quark (1)
1277 * BIT[11:09] --> WR: use oem_tWR
1278 * BIT[08] --> DLL: want "Reset" (1, self clearing)
1279 * BIT[07] --> MODE: want "Normal" (0)
1280 * BIT[06:04,02] --> CL: use oem_tCAS
1281 * BIT[03] --> RD_BURST_TYPE: want "Interleave" (1)
1282 * BIT[01:00] --> BL: want "8 Fixed" (0)
1283 * WR:
1284 * 0 --> 16
1285 * 1 --> 5
1286 * 2 --> 6
1287 * 3 --> 7
1288 * 4 --> 8
1289 * 5 --> 10
1290 * 6 --> 12
1291 * 7 --> 14
1292 * CL:
1293 * BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
1294 * BIT[06:04] use oem_tCAS-4
1295 */
Bin Meng15e3f282015-03-10 18:31:20 +08001296 mrs0_cmd |= (1 << 14);
1297 mrs0_cmd |= (1 << 18);
Bin Meng93b4a392015-02-05 23:42:24 +08001298 mrs0_cmd |= ((((dtr0 >> 12) & 7) + 1) << 10);
1299
1300 tck = t_ck[mrc_params->ddr_speed];
1301 /* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
1302 twr = MCEIL(15000, tck);
1303 mrs0_cmd |= ((twr - 4) << 15);
1304
1305 for (rank = 0; rank < NUM_RANKS; rank++) {
1306 /* Skip to next populated rank */
1307 if ((mrc_params->rank_enables & (1 << rank)) == 0)
1308 continue;
1309
1310 emrs2_cmd |= (rank << 22);
1311 dram_init_command(emrs2_cmd);
1312
1313 emrs3_cmd |= (rank << 22);
1314 dram_init_command(emrs3_cmd);
1315
1316 emrs1_cmd |= (rank << 22);
1317 dram_init_command(emrs1_cmd);
1318
1319 mrs0_cmd |= (rank << 22);
1320 dram_init_command(mrs0_cmd);
1321
1322 dram_init_command(DCMD_ZQCL(rank));
1323 }
1324
1325 LEAVEFN();
1326}
1327
1328/*
1329 * Dunit Initialization Complete
1330 *
1331 * Indicates that initialization of the Dunit has completed.
1332 *
1333 * Memory accesses are permitted and maintenance operation begins.
1334 * Until this bit is set to a 1, the memory controller will not accept
1335 * DRAM requests from the MEMORY_MANAGER or HTE.
1336 */
1337void set_ddr_init_complete(struct mrc_params *mrc_params)
1338{
1339 u32 dco;
1340
1341 ENTERFN();
1342
1343 dco = msg_port_read(MEM_CTLR, DCO);
Bin Meng15e3f282015-03-10 18:31:20 +08001344 dco &= ~DCO_PMICTL;
1345 dco |= DCO_IC;
Bin Meng93b4a392015-02-05 23:42:24 +08001346 msg_port_write(MEM_CTLR, DCO, dco);
1347
1348 LEAVEFN();
1349}
1350
1351/*
1352 * This function will retrieve relevant timing data
1353 *
1354 * This data will be used on subsequent boots to speed up boot times
1355 * and is required for Suspend To RAM capabilities.
1356 */
1357void restore_timings(struct mrc_params *mrc_params)
1358{
1359 uint8_t ch, rk, bl;
1360 const struct mrc_timings *mt = &mrc_params->timings;
1361
1362 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1363 for (rk = 0; rk < NUM_RANKS; rk++) {
1364 for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1365 set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]);
1366 set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]);
1367 set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]);
1368 set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);
1369 if (rk == 0) {
1370 /* VREF (RANK0 only) */
1371 set_vref(ch, bl, mt->vref[ch][bl]);
1372 }
1373 }
1374 set_wctl(ch, rk, mt->wctl[ch][rk]);
1375 }
1376 set_wcmd(ch, mt->wcmd[ch]);
1377 }
1378}
1379
1380/*
1381 * Configure default settings normally set as part of read training
1382 *
1383 * Some defaults have to be set earlier as they may affect earlier
1384 * training steps.
1385 */
1386void default_timings(struct mrc_params *mrc_params)
1387{
1388 uint8_t ch, rk, bl;
1389
1390 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1391 for (rk = 0; rk < NUM_RANKS; rk++) {
1392 for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
1393 set_rdqs(ch, rk, bl, 24);
1394 if (rk == 0) {
1395 /* VREF (RANK0 only) */
1396 set_vref(ch, bl, 32);
1397 }
1398 }
1399 }
1400 }
1401}
1402
1403/*
1404 * This function will perform our RCVEN Calibration Algorithm.
1405 * We will only use the 2xCLK domain timings to perform RCVEN Calibration.
1406 * All byte lanes will be calibrated "simultaneously" per channel per rank.
1407 */
1408void rcvn_cal(struct mrc_params *mrc_params)
1409{
1410 uint8_t ch; /* channel counter */
1411 uint8_t rk; /* rank counter */
1412 uint8_t bl; /* byte lane counter */
1413 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1414
1415#ifdef R2R_SHARING
1416 /* used to find placement for rank2rank sharing configs */
1417 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1418#ifndef BACKUP_RCVN
1419 /* used to find placement for rank2rank sharing configs */
1420 uint32_t num_ranks_enabled = 0;
1421#endif
1422#endif
1423
1424#ifdef BACKUP_RCVN
1425#else
1426 uint32_t temp;
1427 /* absolute PI value to be programmed on the byte lane */
1428 uint32_t delay[NUM_BYTE_LANES];
1429 u32 dtr1, dtr1_save;
1430#endif
1431
1432 ENTERFN();
1433
1434 /* rcvn_cal starts */
1435 mrc_post_code(0x05, 0x00);
1436
1437#ifndef BACKUP_RCVN
1438 /* need separate burst to sample DQS preamble */
1439 dtr1 = msg_port_read(MEM_CTLR, DTR1);
1440 dtr1_save = dtr1;
Bin Meng15e3f282015-03-10 18:31:20 +08001441 dtr1 |= DTR1_TCCD_12CLK;
Bin Meng93b4a392015-02-05 23:42:24 +08001442 msg_port_write(MEM_CTLR, DTR1, dtr1);
1443#endif
1444
1445#ifdef R2R_SHARING
1446 /* need to set "final_delay[][]" elements to "0" */
1447 memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1448#endif
1449
1450 /* loop through each enabled channel */
1451 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1452 if (mrc_params->channel_enables & (1 << ch)) {
1453 /* perform RCVEN Calibration on a per rank basis */
1454 for (rk = 0; rk < NUM_RANKS; rk++) {
1455 if (mrc_params->rank_enables & (1 << rk)) {
1456 /*
1457 * POST_CODE here indicates the current
1458 * channel and rank being calibrated
1459 */
Bin Meng15e3f282015-03-10 18:31:20 +08001460 mrc_post_code(0x05, 0x10 + ((ch << 4) | rk));
Bin Meng93b4a392015-02-05 23:42:24 +08001461
1462#ifdef BACKUP_RCVN
1463 /* et hard-coded timing values */
1464 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++)
1465 set_rcvn(ch, rk, bl, ddr_rcvn[PLATFORM_ID]);
1466#else
1467 /* enable FIFORST */
1468 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1469 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001470 B01PTRCTL1 +
1471 (bl >> 1) * DDRIODQ_BL_OFFSET +
1472 ch * DDRIODQ_CH_OFFSET,
1473 0, 1 << 8);
Bin Meng93b4a392015-02-05 23:42:24 +08001474 }
1475 /* initialize the starting delay to 128 PI (cas +1 CLK) */
1476 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1477 /* 1x CLK domain timing is cas-4 */
1478 delay[bl] = (4 + 1) * FULL_CLK;
1479
1480 set_rcvn(ch, rk, bl, delay[bl]);
1481 }
1482
1483 /* now find the rising edge */
1484 find_rising_edge(mrc_params, delay, ch, rk, true);
1485
1486 /* Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse */
1487 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1488 delay[bl] += QRTR_CLK;
1489 set_rcvn(ch, rk, bl, delay[bl]);
1490 }
1491 /* Now decrement delay by 128 PI (1 CLK) until we sample a "0" */
1492 do {
1493 temp = sample_dqs(mrc_params, ch, rk, true);
1494 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1495 if (temp & (1 << bl)) {
1496 if (delay[bl] >= FULL_CLK) {
1497 delay[bl] -= FULL_CLK;
1498 set_rcvn(ch, rk, bl, delay[bl]);
1499 } else {
1500 /* not enough delay */
1501 training_message(ch, rk, bl);
Bin Meng15e3f282015-03-10 18:31:20 +08001502 mrc_post_code(0xee, 0x50);
Bin Meng93b4a392015-02-05 23:42:24 +08001503 }
1504 }
1505 }
Bin Meng15e3f282015-03-10 18:31:20 +08001506 } while (temp & 0xff);
Bin Meng93b4a392015-02-05 23:42:24 +08001507
1508#ifdef R2R_SHARING
1509 /* increment "num_ranks_enabled" */
1510 num_ranks_enabled++;
1511 /* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1512 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1513 delay[bl] += QRTR_CLK;
1514 /* add "delay[]" values to "final_delay[][]" for rolling average */
1515 final_delay[ch][bl] += delay[bl];
1516 /* set timing based on rolling average values */
Bin Meng15e3f282015-03-10 18:31:20 +08001517 set_rcvn(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
Bin Meng93b4a392015-02-05 23:42:24 +08001518 }
1519#else
1520 /* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
1521 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1522 delay[bl] += QRTR_CLK;
1523 set_rcvn(ch, rk, bl, delay[bl]);
1524 }
1525#endif
1526
1527 /* disable FIFORST */
1528 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
1529 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001530 B01PTRCTL1 +
1531 (bl >> 1) * DDRIODQ_BL_OFFSET +
1532 ch * DDRIODQ_CH_OFFSET,
1533 1 << 8, 1 << 8);
Bin Meng93b4a392015-02-05 23:42:24 +08001534 }
1535#endif
1536 }
1537 }
1538 }
1539 }
1540
1541#ifndef BACKUP_RCVN
1542 /* restore original */
1543 msg_port_write(MEM_CTLR, DTR1, dtr1_save);
1544#endif
1545
1546 LEAVEFN();
1547}
1548
1549/*
1550 * This function will perform the Write Levelling algorithm
1551 * (align WCLK and WDQS).
1552 *
1553 * This algorithm will act on each rank in each channel separately.
1554 */
1555void wr_level(struct mrc_params *mrc_params)
1556{
1557 uint8_t ch; /* channel counter */
1558 uint8_t rk; /* rank counter */
1559 uint8_t bl; /* byte lane counter */
1560 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1561
1562#ifdef R2R_SHARING
1563 /* used to find placement for rank2rank sharing configs */
1564 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1565#ifndef BACKUP_WDQS
1566 /* used to find placement for rank2rank sharing configs */
1567 uint32_t num_ranks_enabled = 0;
1568#endif
1569#endif
1570
1571#ifdef BACKUP_WDQS
1572#else
1573 /* determines stop condition for CRS_WR_LVL */
1574 bool all_edges_found;
1575 /* absolute PI value to be programmed on the byte lane */
1576 uint32_t delay[NUM_BYTE_LANES];
1577 /*
1578 * static makes it so the data is loaded in the heap once by shadow(),
1579 * where non-static copies the data onto the stack every time this
1580 * function is called
1581 */
1582 uint32_t address; /* address to be checked during COARSE_WR_LVL */
1583 u32 dtr4, dtr4_save;
1584#endif
1585
1586 ENTERFN();
1587
1588 /* wr_level starts */
1589 mrc_post_code(0x06, 0x00);
1590
1591#ifdef R2R_SHARING
1592 /* need to set "final_delay[][]" elements to "0" */
1593 memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1594#endif
1595
1596 /* loop through each enabled channel */
1597 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1598 if (mrc_params->channel_enables & (1 << ch)) {
1599 /* perform WRITE LEVELING algorithm on a per rank basis */
1600 for (rk = 0; rk < NUM_RANKS; rk++) {
1601 if (mrc_params->rank_enables & (1 << rk)) {
1602 /*
1603 * POST_CODE here indicates the current
1604 * rank and channel being calibrated
1605 */
Bin Meng15e3f282015-03-10 18:31:20 +08001606 mrc_post_code(0x06, 0x10 + ((ch << 4) | rk));
Bin Meng93b4a392015-02-05 23:42:24 +08001607
1608#ifdef BACKUP_WDQS
1609 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1610 set_wdqs(ch, rk, bl, ddr_wdqs[PLATFORM_ID]);
Bin Meng15e3f282015-03-10 18:31:20 +08001611 set_wdq(ch, rk, bl, ddr_wdqs[PLATFORM_ID] - QRTR_CLK);
Bin Meng93b4a392015-02-05 23:42:24 +08001612 }
1613#else
1614 /*
1615 * perform a single PRECHARGE_ALL command to
1616 * make DRAM state machine go to IDLE state
1617 */
1618 dram_init_command(DCMD_PREA(rk));
1619
1620 /*
1621 * enable Write Levelling Mode
1622 * (EMRS1 w/ Write Levelling Mode Enable)
1623 */
Bin Meng15e3f282015-03-10 18:31:20 +08001624 dram_init_command(DCMD_MRS1(rk, 0x82));
Bin Meng93b4a392015-02-05 23:42:24 +08001625
1626 /*
1627 * set ODT DRAM Full Time Termination
1628 * disable in MCU
1629 */
1630
1631 dtr4 = msg_port_read(MEM_CTLR, DTR4);
1632 dtr4_save = dtr4;
Bin Meng15e3f282015-03-10 18:31:20 +08001633 dtr4 |= DTR4_ODTDIS;
Bin Meng93b4a392015-02-05 23:42:24 +08001634 msg_port_write(MEM_CTLR, DTR4, dtr4);
1635
Bin Meng15e3f282015-03-10 18:31:20 +08001636 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08001637 /*
1638 * Enable Sandy Bridge Mode (WDQ Tri-State) &
1639 * Ensure 5 WDQS pulses during Write Leveling
1640 */
1641 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001642 DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1643 0x10000154,
1644 0x100003fc);
Bin Meng93b4a392015-02-05 23:42:24 +08001645 }
1646
1647 /* Write Leveling Mode enabled in IO */
1648 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001649 CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1650 1 << 16, 1 << 16);
Bin Meng93b4a392015-02-05 23:42:24 +08001651
1652 /* Initialize the starting delay to WCLK */
1653 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1654 /*
1655 * CLK0 --> RK0
1656 * CLK1 --> RK1
1657 */
1658 delay[bl] = get_wclk(ch, rk);
1659
1660 set_wdqs(ch, rk, bl, delay[bl]);
1661 }
1662
1663 /* now find the rising edge */
1664 find_rising_edge(mrc_params, delay, ch, rk, false);
1665
1666 /* disable Write Levelling Mode */
1667 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001668 CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
1669 0, 1 << 16);
Bin Meng93b4a392015-02-05 23:42:24 +08001670
Bin Meng15e3f282015-03-10 18:31:20 +08001671 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08001672 /* Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation */
1673 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08001674 DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
1675 0x00000154,
1676 0x100003fc);
Bin Meng93b4a392015-02-05 23:42:24 +08001677 }
1678
1679 /* restore original DTR4 */
1680 msg_port_write(MEM_CTLR, DTR4, dtr4_save);
1681
1682 /*
1683 * restore original value
1684 * (Write Levelling Mode Disable)
1685 */
1686 dram_init_command(DCMD_MRS1(rk, mrc_params->mrs1));
1687
1688 /*
1689 * perform a single PRECHARGE_ALL command to
1690 * make DRAM state machine go to IDLE state
1691 */
1692 dram_init_command(DCMD_PREA(rk));
1693
Bin Meng15e3f282015-03-10 18:31:20 +08001694 mrc_post_code(0x06, 0x30 + ((ch << 4) | rk));
Bin Meng93b4a392015-02-05 23:42:24 +08001695
1696 /*
1697 * COARSE WRITE LEVEL:
1698 * check that we're on the correct clock edge
1699 */
1700
1701 /* hte reconfiguration request */
1702 mrc_params->hte_setup = 1;
1703
1704 /* start CRS_WR_LVL with WDQS = WDQS + 128 PI */
1705 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1706 delay[bl] = get_wdqs(ch, rk, bl) + FULL_CLK;
1707 set_wdqs(ch, rk, bl, delay[bl]);
1708 /*
1709 * program WDQ timings based on WDQS
1710 * (WDQ = WDQS - 32 PI)
1711 */
1712 set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
1713 }
1714
1715 /* get an address in the targeted channel/rank */
1716 address = get_addr(ch, rk);
1717 do {
1718 uint32_t coarse_result = 0x00;
1719 uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
1720 /* assume pass */
1721 all_edges_found = true;
1722
1723 mrc_params->hte_setup = 1;
1724 coarse_result = check_rw_coarse(mrc_params, address);
1725
1726 /* check for failures and margin the byte lane back 128 PI (1 CLK) */
Bin Meng15e3f282015-03-10 18:31:20 +08001727 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08001728 if (coarse_result & (coarse_result_mask << bl)) {
1729 all_edges_found = false;
1730 delay[bl] -= FULL_CLK;
1731 set_wdqs(ch, rk, bl, delay[bl]);
1732 /* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
Bin Meng15e3f282015-03-10 18:31:20 +08001733 set_wdq(ch, rk, bl, delay[bl] - QRTR_CLK);
Bin Meng93b4a392015-02-05 23:42:24 +08001734 }
1735 }
1736 } while (!all_edges_found);
1737
1738#ifdef R2R_SHARING
1739 /* increment "num_ranks_enabled" */
1740 num_ranks_enabled++;
1741 /* accumulate "final_delay[][]" values from "delay[]" values for rolling average */
Bin Meng15e3f282015-03-10 18:31:20 +08001742 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08001743 final_delay[ch][bl] += delay[bl];
Bin Meng15e3f282015-03-10 18:31:20 +08001744 set_wdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
Bin Meng93b4a392015-02-05 23:42:24 +08001745 /* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
Bin Meng15e3f282015-03-10 18:31:20 +08001746 set_wdq(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled - QRTR_CLK);
Bin Meng93b4a392015-02-05 23:42:24 +08001747 }
1748#endif
1749#endif
1750 }
1751 }
1752 }
1753 }
1754
1755 LEAVEFN();
1756}
1757
1758void prog_page_ctrl(struct mrc_params *mrc_params)
1759{
1760 u32 dpmc0;
1761
1762 ENTERFN();
1763
1764 dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
Bin Meng15e3f282015-03-10 18:31:20 +08001765 dpmc0 &= ~DPMC0_PCLSTO_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +08001766 dpmc0 |= (4 << 16);
Bin Meng15e3f282015-03-10 18:31:20 +08001767 dpmc0 |= DPMC0_PREAPWDEN;
Bin Meng93b4a392015-02-05 23:42:24 +08001768 msg_port_write(MEM_CTLR, DPMC0, dpmc0);
1769}
1770
1771/*
1772 * This function will perform the READ TRAINING Algorithm on all
1773 * channels/ranks/byte_lanes simultaneously to minimize execution time.
1774 *
1775 * The idea here is to train the VREF and RDQS (and eventually RDQ) values
1776 * to achieve maximum READ margins. The algorithm will first determine the
1777 * X coordinate (RDQS setting). This is done by collapsing the VREF eye
1778 * until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
1779 * Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX,
1780 * then average those; this will be the final X coordinate. The algorithm
1781 * will then determine the Y coordinate (VREF setting). This is done by
1782 * collapsing the RDQS eye until we find a minimum required VREF eye for
1783 * RDQS_MIN and RDQS_MAX. Then we take the averages of the VREF eye at
1784 * RDQS_MIN and RDQS_MAX, then average those; this will be the final Y
1785 * coordinate.
1786 *
1787 * NOTE: this algorithm assumes the eye curves have a one-to-one relationship,
1788 * meaning for each X the curve has only one Y and vice-a-versa.
1789 */
1790void rd_train(struct mrc_params *mrc_params)
1791{
1792 uint8_t ch; /* channel counter */
1793 uint8_t rk; /* rank counter */
1794 uint8_t bl; /* byte lane counter */
1795 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
1796#ifdef BACKUP_RDQS
1797#else
1798 uint8_t side_x; /* tracks LEFT/RIGHT approach vectors */
1799 uint8_t side_y; /* tracks BOTTOM/TOP approach vectors */
1800 /* X coordinate data (passing RDQS values) for approach vectors */
1801 uint8_t x_coordinate[2][2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1802 /* Y coordinate data (passing VREF values) for approach vectors */
1803 uint8_t y_coordinate[2][2][NUM_CHANNELS][NUM_BYTE_LANES];
1804 /* centered X (RDQS) */
1805 uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
1806 /* centered Y (VREF) */
1807 uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES];
1808 uint32_t address; /* target address for check_bls_ex() */
1809 uint32_t result; /* result of check_bls_ex() */
1810 uint32_t bl_mask; /* byte lane mask for result checking */
1811#ifdef R2R_SHARING
1812 /* used to find placement for rank2rank sharing configs */
1813 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
1814 /* used to find placement for rank2rank sharing configs */
1815 uint32_t num_ranks_enabled = 0;
1816#endif
1817#endif
1818
1819 /* rd_train starts */
1820 mrc_post_code(0x07, 0x00);
1821
1822 ENTERFN();
1823
1824#ifdef BACKUP_RDQS
1825 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1826 if (mrc_params->channel_enables & (1 << ch)) {
1827 for (rk = 0; rk < NUM_RANKS; rk++) {
1828 if (mrc_params->rank_enables & (1 << rk)) {
1829 for (bl = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08001830 bl < NUM_BYTE_LANES / bl_divisor;
Bin Meng93b4a392015-02-05 23:42:24 +08001831 bl++) {
1832 set_rdqs(ch, rk, bl, ddr_rdqs[PLATFORM_ID]);
1833 }
1834 }
1835 }
1836 }
1837 }
1838#else
1839 /* initialize x/y_coordinate arrays */
1840 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1841 if (mrc_params->channel_enables & (1 << ch)) {
1842 for (rk = 0; rk < NUM_RANKS; rk++) {
1843 if (mrc_params->rank_enables & (1 << rk)) {
1844 for (bl = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08001845 bl < NUM_BYTE_LANES / bl_divisor;
Bin Meng93b4a392015-02-05 23:42:24 +08001846 bl++) {
1847 /* x_coordinate */
1848 x_coordinate[L][B][ch][rk][bl] = RDQS_MIN;
1849 x_coordinate[R][B][ch][rk][bl] = RDQS_MAX;
1850 x_coordinate[L][T][ch][rk][bl] = RDQS_MIN;
1851 x_coordinate[R][T][ch][rk][bl] = RDQS_MAX;
1852 /* y_coordinate */
1853 y_coordinate[L][B][ch][bl] = VREF_MIN;
1854 y_coordinate[R][B][ch][bl] = VREF_MIN;
1855 y_coordinate[L][T][ch][bl] = VREF_MAX;
1856 y_coordinate[R][T][ch][bl] = VREF_MAX;
1857 }
1858 }
1859 }
1860 }
1861 }
1862
1863 /* initialize other variables */
1864 bl_mask = byte_lane_mask(mrc_params);
1865 address = get_addr(0, 0);
1866
1867#ifdef R2R_SHARING
1868 /* need to set "final_delay[][]" elements to "0" */
1869 memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
1870#endif
1871
1872 /* look for passing coordinates */
1873 for (side_y = B; side_y <= T; side_y++) {
1874 for (side_x = L; side_x <= R; side_x++) {
Bin Meng15e3f282015-03-10 18:31:20 +08001875 mrc_post_code(0x07, 0x10 + side_y * 2 + side_x);
Bin Meng93b4a392015-02-05 23:42:24 +08001876
1877 /* find passing values */
1878 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1879 if (mrc_params->channel_enables & (0x1 << ch)) {
1880 for (rk = 0; rk < NUM_RANKS; rk++) {
1881 if (mrc_params->rank_enables &
1882 (0x1 << rk)) {
1883 /* set x/y_coordinate search starting settings */
1884 for (bl = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08001885 bl < NUM_BYTE_LANES / bl_divisor;
Bin Meng93b4a392015-02-05 23:42:24 +08001886 bl++) {
1887 set_rdqs(ch, rk, bl,
1888 x_coordinate[side_x][side_y][ch][rk][bl]);
1889 set_vref(ch, bl,
1890 y_coordinate[side_x][side_y][ch][bl]);
1891 }
1892
1893 /* get an address in the target channel/rank */
1894 address = get_addr(ch, rk);
1895
1896 /* request HTE reconfiguration */
1897 mrc_params->hte_setup = 1;
1898
1899 /* test the settings */
1900 do {
1901 /* result[07:00] == failing byte lane (MAX 8) */
1902 result = check_bls_ex(mrc_params, address);
1903
1904 /* check for failures */
Bin Meng15e3f282015-03-10 18:31:20 +08001905 if (result & 0xff) {
Bin Meng93b4a392015-02-05 23:42:24 +08001906 /* at least 1 byte lane failed */
Bin Meng15e3f282015-03-10 18:31:20 +08001907 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08001908 if (result &
1909 (bl_mask << bl)) {
1910 /* adjust the RDQS values accordingly */
1911 if (side_x == L)
1912 x_coordinate[L][side_y][ch][rk][bl] += RDQS_STEP;
1913 else
1914 x_coordinate[R][side_y][ch][rk][bl] -= RDQS_STEP;
1915
1916 /* check that we haven't closed the RDQS_EYE too much */
1917 if ((x_coordinate[L][side_y][ch][rk][bl] > (RDQS_MAX - MIN_RDQS_EYE)) ||
1918 (x_coordinate[R][side_y][ch][rk][bl] < (RDQS_MIN + MIN_RDQS_EYE)) ||
1919 (x_coordinate[L][side_y][ch][rk][bl] ==
1920 x_coordinate[R][side_y][ch][rk][bl])) {
1921 /*
1922 * not enough RDQS margin available at this VREF
1923 * update VREF values accordingly
1924 */
1925 if (side_y == B)
1926 y_coordinate[side_x][B][ch][bl] += VREF_STEP;
1927 else
1928 y_coordinate[side_x][T][ch][bl] -= VREF_STEP;
1929
1930 /* check that we haven't closed the VREF_EYE too much */
1931 if ((y_coordinate[side_x][B][ch][bl] > (VREF_MAX - MIN_VREF_EYE)) ||
1932 (y_coordinate[side_x][T][ch][bl] < (VREF_MIN + MIN_VREF_EYE)) ||
1933 (y_coordinate[side_x][B][ch][bl] == y_coordinate[side_x][T][ch][bl])) {
1934 /* VREF_EYE collapsed below MIN_VREF_EYE */
1935 training_message(ch, rk, bl);
Bin Meng15e3f282015-03-10 18:31:20 +08001936 mrc_post_code(0xEE, 0x70 + side_y * 2 + side_x);
Bin Meng93b4a392015-02-05 23:42:24 +08001937 } else {
1938 /* update the VREF setting */
1939 set_vref(ch, bl, y_coordinate[side_x][side_y][ch][bl]);
1940 /* reset the X coordinate to begin the search at the new VREF */
1941 x_coordinate[side_x][side_y][ch][rk][bl] =
Bin Meng15e3f282015-03-10 18:31:20 +08001942 (side_x == L) ? RDQS_MIN : RDQS_MAX;
Bin Meng93b4a392015-02-05 23:42:24 +08001943 }
1944 }
1945
1946 /* update the RDQS setting */
1947 set_rdqs(ch, rk, bl, x_coordinate[side_x][side_y][ch][rk][bl]);
1948 }
1949 }
1950 }
Bin Meng15e3f282015-03-10 18:31:20 +08001951 } while (result & 0xff);
Bin Meng93b4a392015-02-05 23:42:24 +08001952 }
1953 }
1954 }
1955 }
1956 }
1957 }
1958
1959 mrc_post_code(0x07, 0x20);
1960
1961 /* find final RDQS (X coordinate) & final VREF (Y coordinate) */
1962 for (ch = 0; ch < NUM_CHANNELS; ch++) {
1963 if (mrc_params->channel_enables & (1 << ch)) {
1964 for (rk = 0; rk < NUM_RANKS; rk++) {
1965 if (mrc_params->rank_enables & (1 << rk)) {
1966 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
1967 uint32_t temp1;
1968 uint32_t temp2;
1969
1970 /* x_coordinate */
1971 DPF(D_INFO,
1972 "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n",
1973 rk, bl,
1974 x_coordinate[L][T][ch][rk][bl],
1975 x_coordinate[R][T][ch][rk][bl],
1976 x_coordinate[L][B][ch][rk][bl],
1977 x_coordinate[R][B][ch][rk][bl]);
1978
1979 /* average the TOP side LEFT & RIGHT values */
1980 temp1 = (x_coordinate[R][T][ch][rk][bl] + x_coordinate[L][T][ch][rk][bl]) / 2;
1981 /* average the BOTTOM side LEFT & RIGHT values */
1982 temp2 = (x_coordinate[R][B][ch][rk][bl] + x_coordinate[L][B][ch][rk][bl]) / 2;
1983 /* average the above averages */
1984 x_center[ch][rk][bl] = (uint8_t) ((temp1 + temp2) / 2);
1985
1986 /* y_coordinate */
1987 DPF(D_INFO,
1988 "VREF R/L eye lane%d : %d-%d %d-%d\n",
1989 bl,
1990 y_coordinate[R][B][ch][bl],
1991 y_coordinate[R][T][ch][bl],
1992 y_coordinate[L][B][ch][bl],
1993 y_coordinate[L][T][ch][bl]);
1994
1995 /* average the RIGHT side TOP & BOTTOM values */
1996 temp1 = (y_coordinate[R][T][ch][bl] + y_coordinate[R][B][ch][bl]) / 2;
1997 /* average the LEFT side TOP & BOTTOM values */
1998 temp2 = (y_coordinate[L][T][ch][bl] + y_coordinate[L][B][ch][bl]) / 2;
1999 /* average the above averages */
2000 y_center[ch][bl] = (uint8_t) ((temp1 + temp2) / 2);
2001 }
2002 }
2003 }
2004 }
2005 }
2006
2007#ifdef RX_EYE_CHECK
2008 /* perform an eye check */
2009 for (side_y = B; side_y <= T; side_y++) {
2010 for (side_x = L; side_x <= R; side_x++) {
Bin Meng15e3f282015-03-10 18:31:20 +08002011 mrc_post_code(0x07, 0x30 + side_y * 2 + side_x);
Bin Meng93b4a392015-02-05 23:42:24 +08002012
2013 /* update the settings for the eye check */
2014 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2015 if (mrc_params->channel_enables & (1 << ch)) {
2016 for (rk = 0; rk < NUM_RANKS; rk++) {
2017 if (mrc_params->rank_enables & (1 << rk)) {
Bin Meng15e3f282015-03-10 18:31:20 +08002018 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08002019 if (side_x == L)
Bin Meng15e3f282015-03-10 18:31:20 +08002020 set_rdqs(ch, rk, bl, x_center[ch][rk][bl] - (MIN_RDQS_EYE / 2));
Bin Meng93b4a392015-02-05 23:42:24 +08002021 else
Bin Meng15e3f282015-03-10 18:31:20 +08002022 set_rdqs(ch, rk, bl, x_center[ch][rk][bl] + (MIN_RDQS_EYE / 2));
Bin Meng93b4a392015-02-05 23:42:24 +08002023
2024 if (side_y == B)
Bin Meng15e3f282015-03-10 18:31:20 +08002025 set_vref(ch, bl, y_center[ch][bl] - (MIN_VREF_EYE / 2));
Bin Meng93b4a392015-02-05 23:42:24 +08002026 else
Bin Meng15e3f282015-03-10 18:31:20 +08002027 set_vref(ch, bl, y_center[ch][bl] + (MIN_VREF_EYE / 2));
Bin Meng93b4a392015-02-05 23:42:24 +08002028 }
2029 }
2030 }
2031 }
2032 }
2033
2034 /* request HTE reconfiguration */
2035 mrc_params->hte_setup = 1;
2036
2037 /* check the eye */
Bin Meng15e3f282015-03-10 18:31:20 +08002038 if (check_bls_ex(mrc_params, address) & 0xff) {
Bin Meng93b4a392015-02-05 23:42:24 +08002039 /* one or more byte lanes failed */
Bin Meng15e3f282015-03-10 18:31:20 +08002040 mrc_post_code(0xee, 0x74 + side_x * 2 + side_y);
Bin Meng93b4a392015-02-05 23:42:24 +08002041 }
2042 }
2043 }
2044#endif
2045
2046 mrc_post_code(0x07, 0x40);
2047
2048 /* set final placements */
2049 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2050 if (mrc_params->channel_enables & (1 << ch)) {
2051 for (rk = 0; rk < NUM_RANKS; rk++) {
2052 if (mrc_params->rank_enables & (1 << rk)) {
2053#ifdef R2R_SHARING
2054 /* increment "num_ranks_enabled" */
2055 num_ranks_enabled++;
2056#endif
2057 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
2058 /* x_coordinate */
2059#ifdef R2R_SHARING
2060 final_delay[ch][bl] += x_center[ch][rk][bl];
Bin Meng15e3f282015-03-10 18:31:20 +08002061 set_rdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
Bin Meng93b4a392015-02-05 23:42:24 +08002062#else
2063 set_rdqs(ch, rk, bl, x_center[ch][rk][bl]);
2064#endif
2065 /* y_coordinate */
2066 set_vref(ch, bl, y_center[ch][bl]);
2067 }
2068 }
2069 }
2070 }
2071 }
2072#endif
2073
2074 LEAVEFN();
2075}
2076
2077/*
2078 * This function will perform the WRITE TRAINING Algorithm on all
2079 * channels/ranks/byte_lanes simultaneously to minimize execution time.
2080 *
2081 * The idea here is to train the WDQ timings to achieve maximum WRITE margins.
2082 * The algorithm will start with WDQ at the current WDQ setting (tracks WDQS
2083 * in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data
2084 * patterns pass. This is because WDQS will be aligned to WCLK by the
2085 * Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window
2086 * of validity.
2087 */
2088void wr_train(struct mrc_params *mrc_params)
2089{
2090 uint8_t ch; /* channel counter */
2091 uint8_t rk; /* rank counter */
2092 uint8_t bl; /* byte lane counter */
2093 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
2094#ifdef BACKUP_WDQ
2095#else
2096 uint8_t side; /* LEFT/RIGHT side indicator (0=L, 1=R) */
2097 uint32_t temp; /* temporary DWORD */
2098 /* 2 arrays, for L & R side passing delays */
2099 uint32_t delay[2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
2100 uint32_t address; /* target address for check_bls_ex() */
2101 uint32_t result; /* result of check_bls_ex() */
2102 uint32_t bl_mask; /* byte lane mask for result checking */
2103#ifdef R2R_SHARING
2104 /* used to find placement for rank2rank sharing configs */
2105 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
2106 /* used to find placement for rank2rank sharing configs */
2107 uint32_t num_ranks_enabled = 0;
2108#endif
2109#endif
2110
2111 /* wr_train starts */
2112 mrc_post_code(0x08, 0x00);
2113
2114 ENTERFN();
2115
2116#ifdef BACKUP_WDQ
2117 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2118 if (mrc_params->channel_enables & (1 << ch)) {
2119 for (rk = 0; rk < NUM_RANKS; rk++) {
2120 if (mrc_params->rank_enables & (1 << rk)) {
2121 for (bl = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08002122 bl < NUM_BYTE_LANES / bl_divisor;
Bin Meng93b4a392015-02-05 23:42:24 +08002123 bl++) {
2124 set_wdq(ch, rk, bl, ddr_wdq[PLATFORM_ID]);
2125 }
2126 }
2127 }
2128 }
2129 }
2130#else
2131 /* initialize "delay" */
2132 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2133 if (mrc_params->channel_enables & (1 << ch)) {
2134 for (rk = 0; rk < NUM_RANKS; rk++) {
2135 if (mrc_params->rank_enables & (1 << rk)) {
2136 for (bl = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08002137 bl < NUM_BYTE_LANES / bl_divisor;
Bin Meng93b4a392015-02-05 23:42:24 +08002138 bl++) {
2139 /*
2140 * want to start with
2141 * WDQ = (WDQS - QRTR_CLK)
2142 * +/- QRTR_CLK
2143 */
2144 temp = get_wdqs(ch, rk, bl) - QRTR_CLK;
2145 delay[L][ch][rk][bl] = temp - QRTR_CLK;
2146 delay[R][ch][rk][bl] = temp + QRTR_CLK;
2147 }
2148 }
2149 }
2150 }
2151 }
2152
2153 /* initialize other variables */
2154 bl_mask = byte_lane_mask(mrc_params);
2155 address = get_addr(0, 0);
2156
2157#ifdef R2R_SHARING
2158 /* need to set "final_delay[][]" elements to "0" */
2159 memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
2160#endif
2161
2162 /*
2163 * start algorithm on the LEFT side and train each channel/bl
2164 * until no failures are observed, then repeat for the RIGHT side.
2165 */
2166 for (side = L; side <= R; side++) {
Bin Meng15e3f282015-03-10 18:31:20 +08002167 mrc_post_code(0x08, 0x10 + side);
Bin Meng93b4a392015-02-05 23:42:24 +08002168
2169 /* set starting values */
2170 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2171 if (mrc_params->channel_enables & (1 << ch)) {
2172 for (rk = 0; rk < NUM_RANKS; rk++) {
2173 if (mrc_params->rank_enables &
2174 (1 << rk)) {
2175 for (bl = 0;
Bin Meng15e3f282015-03-10 18:31:20 +08002176 bl < NUM_BYTE_LANES / bl_divisor;
Bin Meng93b4a392015-02-05 23:42:24 +08002177 bl++) {
2178 set_wdq(ch, rk, bl, delay[side][ch][rk][bl]);
2179 }
2180 }
2181 }
2182 }
2183 }
2184
2185 /* find passing values */
2186 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2187 if (mrc_params->channel_enables & (1 << ch)) {
2188 for (rk = 0; rk < NUM_RANKS; rk++) {
2189 if (mrc_params->rank_enables &
2190 (1 << rk)) {
2191 /* get an address in the target channel/rank */
2192 address = get_addr(ch, rk);
2193
2194 /* request HTE reconfiguration */
2195 mrc_params->hte_setup = 1;
2196
2197 /* check the settings */
2198 do {
2199 /* result[07:00] == failing byte lane (MAX 8) */
2200 result = check_bls_ex(mrc_params, address);
2201 /* check for failures */
Bin Meng15e3f282015-03-10 18:31:20 +08002202 if (result & 0xff) {
Bin Meng93b4a392015-02-05 23:42:24 +08002203 /* at least 1 byte lane failed */
Bin Meng15e3f282015-03-10 18:31:20 +08002204 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08002205 if (result &
2206 (bl_mask << bl)) {
2207 if (side == L)
2208 delay[L][ch][rk][bl] += WDQ_STEP;
2209 else
2210 delay[R][ch][rk][bl] -= WDQ_STEP;
2211
2212 /* check for algorithm failure */
2213 if (delay[L][ch][rk][bl] != delay[R][ch][rk][bl]) {
2214 /*
2215 * margin available
2216 * update delay setting
2217 */
2218 set_wdq(ch, rk, bl,
2219 delay[side][ch][rk][bl]);
2220 } else {
2221 /*
2222 * no margin available
2223 * notify the user and halt
2224 */
2225 training_message(ch, rk, bl);
Bin Meng15e3f282015-03-10 18:31:20 +08002226 mrc_post_code(0xee, 0x80 + side);
Bin Meng93b4a392015-02-05 23:42:24 +08002227 }
2228 }
2229 }
2230 }
2231 /* stop when all byte lanes pass */
Bin Meng15e3f282015-03-10 18:31:20 +08002232 } while (result & 0xff);
Bin Meng93b4a392015-02-05 23:42:24 +08002233 }
2234 }
2235 }
2236 }
2237 }
2238
2239 /* program WDQ to the middle of passing window */
2240 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2241 if (mrc_params->channel_enables & (1 << ch)) {
2242 for (rk = 0; rk < NUM_RANKS; rk++) {
2243 if (mrc_params->rank_enables & (1 << rk)) {
2244#ifdef R2R_SHARING
2245 /* increment "num_ranks_enabled" */
2246 num_ranks_enabled++;
2247#endif
Bin Meng15e3f282015-03-10 18:31:20 +08002248 for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08002249 DPF(D_INFO,
2250 "WDQ eye rank%d lane%d : %d-%d\n",
2251 rk, bl,
2252 delay[L][ch][rk][bl],
2253 delay[R][ch][rk][bl]);
2254
2255 temp = (delay[R][ch][rk][bl] + delay[L][ch][rk][bl]) / 2;
2256
2257#ifdef R2R_SHARING
2258 final_delay[ch][bl] += temp;
2259 set_wdq(ch, rk, bl,
Bin Meng15e3f282015-03-10 18:31:20 +08002260 final_delay[ch][bl] / num_ranks_enabled);
Bin Meng93b4a392015-02-05 23:42:24 +08002261#else
2262 set_wdq(ch, rk, bl, temp);
2263#endif
2264 }
2265 }
2266 }
2267 }
2268 }
2269#endif
2270
2271 LEAVEFN();
2272}
2273
2274/*
2275 * This function will store relevant timing data
2276 *
2277 * This data will be used on subsequent boots to speed up boot times
2278 * and is required for Suspend To RAM capabilities.
2279 */
2280void store_timings(struct mrc_params *mrc_params)
2281{
2282 uint8_t ch, rk, bl;
2283 struct mrc_timings *mt = &mrc_params->timings;
2284
2285 for (ch = 0; ch < NUM_CHANNELS; ch++) {
2286 for (rk = 0; rk < NUM_RANKS; rk++) {
2287 for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
2288 mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl);
2289 mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl);
2290 mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl);
2291 mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);
2292
2293 if (rk == 0)
2294 mt->vref[ch][bl] = get_vref(ch, bl);
2295 }
2296
2297 mt->wctl[ch][rk] = get_wctl(ch, rk);
2298 }
2299
2300 mt->wcmd[ch] = get_wcmd(ch);
2301 }
2302
2303 /* need to save for a case of changing frequency after warm reset */
2304 mt->ddr_speed = mrc_params->ddr_speed;
2305}
2306
2307/*
2308 * The purpose of this function is to ensure the SEC comes out of reset
2309 * and IA initiates the SEC enabling Memory Scrambling.
2310 */
2311void enable_scrambling(struct mrc_params *mrc_params)
2312{
2313 uint32_t lfsr = 0;
2314 uint8_t i;
2315
2316 if (mrc_params->scrambling_enables == 0)
2317 return;
2318
2319 ENTERFN();
2320
2321 /* 32 bit seed is always stored in BIOS NVM */
2322 lfsr = mrc_params->timings.scrambler_seed;
2323
2324 if (mrc_params->boot_mode == BM_COLD) {
2325 /*
2326 * factory value is 0 and in first boot,
2327 * a clock based seed is loaded.
2328 */
2329 if (lfsr == 0) {
2330 /*
2331 * get seed from system clock
2332 * and make sure it is not all 1's
2333 */
Bin Meng15e3f282015-03-10 18:31:20 +08002334 lfsr = rdtsc() & 0x0fffffff;
Bin Meng93b4a392015-02-05 23:42:24 +08002335 } else {
2336 /*
2337 * Need to replace scrambler
2338 *
2339 * get next 32bit LFSR 16 times which is the last
2340 * part of the previous scrambler vector
2341 */
2342 for (i = 0; i < 16; i++)
2343 lfsr32(&lfsr);
2344 }
2345
2346 /* save new seed */
2347 mrc_params->timings.scrambler_seed = lfsr;
2348 }
2349
2350 /*
2351 * In warm boot or S3 exit, we have the previous seed.
2352 * In cold boot, we have the last 32bit LFSR which is the new seed.
2353 */
2354 lfsr32(&lfsr); /* shift to next value */
Bin Meng15e3f282015-03-10 18:31:20 +08002355 msg_port_write(MEM_CTLR, SCRMSEED, (lfsr & 0x0003ffff));
Bin Meng93b4a392015-02-05 23:42:24 +08002356
2357 for (i = 0; i < 2; i++)
Bin Meng15e3f282015-03-10 18:31:20 +08002358 msg_port_write(MEM_CTLR, SCRMLO + i, (lfsr & 0xaaaaaaaa));
Bin Meng93b4a392015-02-05 23:42:24 +08002359
2360 LEAVEFN();
2361}
2362
2363/*
2364 * Configure MCU Power Management Control Register
2365 * and Scheduler Control Register
2366 */
2367void prog_ddr_control(struct mrc_params *mrc_params)
2368{
2369 u32 dsch;
2370 u32 dpmc0;
2371
2372 ENTERFN();
2373
2374 dsch = msg_port_read(MEM_CTLR, DSCH);
Bin Meng15e3f282015-03-10 18:31:20 +08002375 dsch &= ~(DSCH_OOODIS | DSCH_OOOST3DIS | DSCH_NEWBYPDIS);
Bin Meng93b4a392015-02-05 23:42:24 +08002376 msg_port_write(MEM_CTLR, DSCH, dsch);
2377
2378 dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
Bin Meng15e3f282015-03-10 18:31:20 +08002379 dpmc0 &= ~DPMC0_DISPWRDN;
Bin Meng93b4a392015-02-05 23:42:24 +08002380 dpmc0 |= (mrc_params->power_down_disable << 25);
Bin Meng15e3f282015-03-10 18:31:20 +08002381 dpmc0 &= ~DPMC0_CLKGTDIS;
2382 dpmc0 &= ~DPMC0_PCLSTO_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +08002383 dpmc0 |= (4 << 16);
Bin Meng15e3f282015-03-10 18:31:20 +08002384 dpmc0 |= DPMC0_PREAPWDEN;
Bin Meng93b4a392015-02-05 23:42:24 +08002385 msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2386
2387 /* CMDTRIST = 2h - CMD/ADDR are tristated when no valid command */
Bin Meng15e3f282015-03-10 18:31:20 +08002388 mrc_write_mask(MEM_CTLR, DPMC1, 0x20, 0x30);
Bin Meng93b4a392015-02-05 23:42:24 +08002389
2390 LEAVEFN();
2391}
2392
2393/*
2394 * After training complete configure MCU Rank Population Register
2395 * specifying: ranks enabled, device width, density, address mode
2396 */
2397void prog_dra_drb(struct mrc_params *mrc_params)
2398{
2399 u32 drp;
2400 u32 dco;
2401 u8 density = mrc_params->params.density;
2402
2403 ENTERFN();
2404
2405 dco = msg_port_read(MEM_CTLR, DCO);
Bin Meng15e3f282015-03-10 18:31:20 +08002406 dco &= ~DCO_IC;
Bin Meng93b4a392015-02-05 23:42:24 +08002407 msg_port_write(MEM_CTLR, DCO, dco);
2408
2409 drp = 0;
2410 if (mrc_params->rank_enables & 1)
Bin Meng15e3f282015-03-10 18:31:20 +08002411 drp |= DRP_RKEN0;
Bin Meng93b4a392015-02-05 23:42:24 +08002412 if (mrc_params->rank_enables & 2)
Bin Meng15e3f282015-03-10 18:31:20 +08002413 drp |= DRP_RKEN1;
Bin Meng93b4a392015-02-05 23:42:24 +08002414 if (mrc_params->dram_width == X16) {
2415 drp |= (1 << 4);
2416 drp |= (1 << 9);
2417 }
2418
2419 /*
2420 * Density encoding in struct dram_params: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
2421 * has to be mapped RANKDENSx encoding (0=1Gb)
2422 */
2423 if (density == 0)
2424 density = 4;
2425
2426 drp |= ((density - 1) << 6);
2427 drp |= ((density - 1) << 11);
2428
2429 /* Address mode can be overwritten if ECC enabled */
2430 drp |= (mrc_params->address_mode << 14);
2431
2432 msg_port_write(MEM_CTLR, DRP, drp);
2433
Bin Meng15e3f282015-03-10 18:31:20 +08002434 dco &= ~DCO_PMICTL;
2435 dco |= DCO_IC;
Bin Meng93b4a392015-02-05 23:42:24 +08002436 msg_port_write(MEM_CTLR, DCO, dco);
2437
2438 LEAVEFN();
2439}
2440
2441/* Send DRAM wake command */
2442void perform_wake(struct mrc_params *mrc_params)
2443{
2444 ENTERFN();
2445
2446 dram_wake_command();
2447
2448 LEAVEFN();
2449}
2450
2451/*
2452 * Configure refresh rate and short ZQ calibration interval
2453 * Activate dynamic self refresh
2454 */
2455void change_refresh_period(struct mrc_params *mrc_params)
2456{
2457 u32 drfc;
2458 u32 dcal;
2459 u32 dpmc0;
2460
2461 ENTERFN();
2462
2463 drfc = msg_port_read(MEM_CTLR, DRFC);
Bin Meng15e3f282015-03-10 18:31:20 +08002464 drfc &= ~DRFC_TREFI_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +08002465 drfc |= (mrc_params->refresh_rate << 12);
Bin Meng15e3f282015-03-10 18:31:20 +08002466 drfc |= DRFC_REFDBTCLR;
Bin Meng93b4a392015-02-05 23:42:24 +08002467 msg_port_write(MEM_CTLR, DRFC, drfc);
2468
2469 dcal = msg_port_read(MEM_CTLR, DCAL);
Bin Meng15e3f282015-03-10 18:31:20 +08002470 dcal &= ~DCAL_ZQCINT_MASK;
Bin Meng93b4a392015-02-05 23:42:24 +08002471 dcal |= (3 << 8); /* 63ms */
2472 msg_port_write(MEM_CTLR, DCAL, dcal);
2473
2474 dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
Bin Meng15e3f282015-03-10 18:31:20 +08002475 dpmc0 |= (DPMC0_DYNSREN | DPMC0_ENPHYCLKGATE);
Bin Meng93b4a392015-02-05 23:42:24 +08002476 msg_port_write(MEM_CTLR, DPMC0, dpmc0);
2477
2478 LEAVEFN();
2479}
2480
2481/*
2482 * Configure DDRPHY for Auto-Refresh, Periodic Compensations,
2483 * Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
2484 */
2485void set_auto_refresh(struct mrc_params *mrc_params)
2486{
2487 uint32_t channel;
2488 uint32_t rank;
2489 uint32_t bl;
2490 uint32_t bl_divisor = 1;
2491 uint32_t temp;
2492
2493 ENTERFN();
2494
2495 /*
2496 * Enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp,
2497 * ZQSPERIOD, Auto-Precharge, CKE Power-Down
2498 */
2499 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2500 if (mrc_params->channel_enables & (1 << channel)) {
2501 /* Enable Periodic RCOMPS */
Bin Meng15e3f282015-03-10 18:31:20 +08002502 mrc_alt_write_mask(DDRPHY, CMPCTRL, 2, 2);
Bin Meng93b4a392015-02-05 23:42:24 +08002503
2504 /* Enable Dynamic DiffAmp & Set Read ODT Value */
2505 switch (mrc_params->rd_odt_value) {
2506 case 0:
Bin Meng15e3f282015-03-10 18:31:20 +08002507 temp = 0x3f; /* OFF */
Bin Meng93b4a392015-02-05 23:42:24 +08002508 break;
2509 default:
2510 temp = 0x00; /* Auto */
2511 break;
2512 }
2513
Bin Meng15e3f282015-03-10 18:31:20 +08002514 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
Bin Meng93b4a392015-02-05 23:42:24 +08002515 /* Override: DIFFAMP, ODT */
2516 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08002517 B0OVRCTL + bl * DDRIODQ_BL_OFFSET +
2518 channel * DDRIODQ_CH_OFFSET,
2519 temp << 10,
2520 0x003ffc00);
Bin Meng93b4a392015-02-05 23:42:24 +08002521
2522 /* Override: DIFFAMP, ODT */
2523 mrc_alt_write_mask(DDRPHY,
Bin Meng15e3f282015-03-10 18:31:20 +08002524 B1OVRCTL + bl * DDRIODQ_BL_OFFSET +
2525 channel * DDRIODQ_CH_OFFSET,
2526 temp << 10,
2527 0x003ffc00);
Bin Meng93b4a392015-02-05 23:42:24 +08002528 }
2529
2530 /* Issue ZQCS command */
2531 for (rank = 0; rank < NUM_RANKS; rank++) {
2532 if (mrc_params->rank_enables & (1 << rank))
2533 dram_init_command(DCMD_ZQCS(rank));
2534 }
2535 }
2536 }
2537
2538 clear_pointers();
2539
2540 LEAVEFN();
2541}
2542
2543/*
2544 * Depending on configuration enables ECC support
2545 *
2546 * Available memory size is decreased, and updated with 0s
2547 * in order to clear error status. Address mode 2 forced.
2548 */
2549void ecc_enable(struct mrc_params *mrc_params)
2550{
2551 u32 drp;
2552 u32 dsch;
2553 u32 ecc_ctrl;
2554
2555 if (mrc_params->ecc_enables == 0)
2556 return;
2557
2558 ENTERFN();
2559
2560 /* Configuration required in ECC mode */
2561 drp = msg_port_read(MEM_CTLR, DRP);
Bin Meng15e3f282015-03-10 18:31:20 +08002562 drp &= ~DRP_ADDRMAP_MASK;
2563 drp |= DRP_ADDRMAP_MAP1;
2564 drp |= DRP_PRI64BSPLITEN;
Bin Meng93b4a392015-02-05 23:42:24 +08002565 msg_port_write(MEM_CTLR, DRP, drp);
2566
2567 /* Disable new request bypass */
2568 dsch = msg_port_read(MEM_CTLR, DSCH);
Bin Meng15e3f282015-03-10 18:31:20 +08002569 dsch |= DSCH_NEWBYPDIS;
Bin Meng93b4a392015-02-05 23:42:24 +08002570 msg_port_write(MEM_CTLR, DSCH, dsch);
2571
2572 /* Enable ECC */
Bin Meng15e3f282015-03-10 18:31:20 +08002573 ecc_ctrl = (DECCCTRL_SBEEN | DECCCTRL_DBEEN | DECCCTRL_ENCBGEN);
Bin Meng93b4a392015-02-05 23:42:24 +08002574 msg_port_write(MEM_CTLR, DECCCTRL, ecc_ctrl);
2575
2576 /* Assume 8 bank memory, one bank is gone for ECC */
2577 mrc_params->mem_size -= mrc_params->mem_size / 8;
2578
2579 /* For S3 resume memory content has to be preserved */
2580 if (mrc_params->boot_mode != BM_S3) {
2581 select_hte();
2582 hte_mem_init(mrc_params, MRC_MEM_INIT);
2583 select_mem_mgr();
2584 }
2585
2586 LEAVEFN();
2587}
2588
2589/*
2590 * Execute memory test
2591 * if error detected it is indicated in mrc_params->status
2592 */
2593void memory_test(struct mrc_params *mrc_params)
2594{
2595 uint32_t result = 0;
2596
2597 ENTERFN();
2598
2599 select_hte();
2600 result = hte_mem_init(mrc_params, MRC_MEM_TEST);
2601 select_mem_mgr();
2602
2603 DPF(D_INFO, "Memory test result %x\n", result);
2604 mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
2605 LEAVEFN();
2606}
2607
2608/* Lock MCU registers at the end of initialization sequence */
2609void lock_registers(struct mrc_params *mrc_params)
2610{
2611 u32 dco;
2612
2613 ENTERFN();
2614
2615 dco = msg_port_read(MEM_CTLR, DCO);
Bin Meng15e3f282015-03-10 18:31:20 +08002616 dco &= ~(DCO_PMICTL | DCO_PMIDIS);
2617 dco |= (DCO_DRPLOCK | DCO_CPGCLOCK);
Bin Meng93b4a392015-02-05 23:42:24 +08002618 msg_port_write(MEM_CTLR, DCO, dco);
2619
2620 LEAVEFN();
2621}