blob: 46a068414be545feec9e70b47d9fe172560bf2af [file] [log] [blame]
Zheng Baoeb75f652010-04-23 17:32:48 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2010 Advanced Micro Devices, Inc.
Timothy Pearsonb8a355d2015-09-05 17:55:58 -05005 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
Zheng Baoeb75f652010-04-23 17:32:48 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Zheng Baoeb75f652010-04-23 17:32:48 +000015 */
16
Timothy Pearson730a0432015-10-16 13:51:51 -050017static uint8_t fam15_dimm_dic(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
18{
19 uint8_t dic;
20
21 /* Calculate DIC based on recommendations in MR1_dct[1:0] */
22 if (pDCTstat->Status & (1 << SB_LoadReduced)) {
23 /* TODO
24 * LRDIMM unimplemented
25 */
26 dic = 0x0;
27 } else {
28 dic = 0x1;
29 }
30
31 return dic;
32}
33
34static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
35{
36 uint8_t term = 0;
37 sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
38 uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
39 uint8_t frequency_index;
40 uint8_t rank_count = pDCTData->DimmRanks[dimm];
41
42 if (is_fam15h())
43 frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
44 else
45 frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7;
46
47 /* FIXME
48 * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
49 * For now assume a maximum of 2 DIMMs per channel can be installed
50 */
51 uint8_t MaxDimmsInstallable = 2;
52
53 if (is_fam15h()) {
54 if (pDCTstat->Status & (1 << SB_Registered)) {
55 /* TODO
56 * RDIMM unimplemented
57 */
58 } else {
59 if (package_type == PT_GR) {
60 /* Socket G34: Fam15h BKDG v3.14 Table 56 */
61 if (MaxDimmsInstallable == 1) {
62 term = 0x0;
63 } else if (MaxDimmsInstallable == 2) {
64 if ((number_of_dimms == 2) && (frequency_index == 0x12)) {
65 term = 0x1;
66 } else if (number_of_dimms == 1) {
67 term = 0x0;
68 } else {
69 term = 0x2;
70 }
71 } else if (MaxDimmsInstallable == 3) {
72 if (number_of_dimms == 1) {
73 if (frequency_index <= 0xa) {
74 term = 0x2;
75 } else {
76 if (rank_count < 3) {
77 term = 0x1;
78 } else {
79 term = 0x2;
80 }
81 }
82 } else if (number_of_dimms == 2) {
83 term = 0x2;
84 }
85 }
86 } else {
87 /* TODO
88 * Other sockets unimplemented
89 */
90 }
91 }
92 }
93
94 return term;
95}
96
97static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
98{
99 uint8_t term = 0;
100 sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
101 uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
102 uint8_t frequency_index;
103
104 if (is_fam15h())
105 frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
106 else
107 frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7;
108
109 /* FIXME
110 * Mainboards need to be able to specify the maximum number of DIMMs installable per channel
111 * For now assume a maximum of 2 DIMMs per channel can be installed
112 */
113 uint8_t MaxDimmsInstallable = 2;
114
115 if (is_fam15h()) {
116 if (pDCTstat->Status & (1 << SB_LoadReduced)) {
117 /* TODO
118 * LRDIMM unimplemented
119 */
120 } else if (pDCTstat->Status & (1 << SB_Registered)) {
121 /* TODO
122 * RDIMM unimplemented
123 */
124 } else {
125 if (package_type == PT_GR) {
126 /* Socket G34: Fam15h BKDG v3.14 Table 56 */
127 if (MaxDimmsInstallable == 1) {
128 if ((frequency_index == 0x4) || (frequency_index == 0x6))
129 term = 0x2;
130 else if ((frequency_index == 0xa) || (frequency_index == 0xe))
131 term = 0x1;
132 else
133 term = 0x3;
134 }
135 if (MaxDimmsInstallable == 2) {
136 if (number_of_dimms == 1) {
137 if (frequency_index <= 0x6) {
138 term = 0x2;
139 } else if (frequency_index <= 0xe) {
140 term = 0x1;
141 } else {
142 term = 0x3;
143 }
144 } else {
145 if (frequency_index <= 0xa) {
146 term = 0x3;
147 } else if (frequency_index <= 0xe) {
148 term = 0x5;
149 } else {
150 term = 0x4;
151 }
152 }
153 } else if (MaxDimmsInstallable == 3) {
154 if (number_of_dimms == 1) {
155 term = 0x0;
156 } else if (number_of_dimms == 2) {
157 if (frequency_index <= 0xa) {
158 if (rank == 1) {
159 term = 0x0;
160 } else {
161 term = 0x3;
162 }
163 } else if (frequency_index <= 0xe) {
164 if (rank == 1) {
165 term = 0x0;
166 } else {
167 term = 0x5;
168 }
169 }
170 }
171 }
172 } else {
173 /* TODO
174 * Other sockets unimplemented
175 */
176 }
177 }
178 }
179
180 return term;
181}
182
Zheng Baoeb75f652010-04-23 17:32:48 +0000183static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
184 struct DCTStatStruc *pDCTstat, u8 dct);
185
186static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
187{
Zheng Baoeb75f652010-04-23 17:32:48 +0000188 u32 dev = pDCTstat->dev_dct;
189 u32 val;
190
191 do {
Timothy Pearson730a0432015-10-16 13:51:51 -0500192 val = Get_NB32_DCT(dev, dct, 0x98);
Zheng Baoeb75f652010-04-23 17:32:48 +0000193 } while (!(val & (1 << DctAccessDone)));
194}
195
196static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting, u8 MrsChipSel, u8 dct)
197{
198 u16 word;
199 u32 ret;
200
201 if (!(pDCTstat->Status & (1 << SB_Registered))) {
202 word = pDCTstat->MirrPresU_NumRegR;
203 if (dct == 0) {
204 word &= 0x55;
205 word <<= 1;
206 } else
207 word &= 0xAA;
208
209 if (word & (1 << MrsChipSel)) {
210 /* A3<->A4,A5<->A6,A7<->A8,BA0<->BA1 */
211 ret = 0;
212 if (MR_register_setting & (1 << 3)) ret |= 1 << 4;
213 if (MR_register_setting & (1 << 4)) ret |= 1 << 3;
214 if (MR_register_setting & (1 << 5)) ret |= 1 << 6;
215 if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
216 if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
217 if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
Timothy Pearson730a0432015-10-16 13:51:51 -0500218 if (is_fam15h()) {
219 if (MR_register_setting & (1 << 18)) ret |= 1 << 19;
220 if (MR_register_setting & (1 << 19)) ret |= 1 << 18;
221 MR_register_setting &= ~0x000c01f8;
222 } else {
223 if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
224 if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
225 MR_register_setting &= ~0x000301f8;
226 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000227 MR_register_setting |= ret;
228 }
229 }
230 return MR_register_setting;
231}
232
233static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
234{
Zheng Baoeb75f652010-04-23 17:32:48 +0000235 u32 dev = pDCTstat->dev_dct;
236 u32 val;
237
Timothy Pearson730a0432015-10-16 13:51:51 -0500238 val = Get_NB32_DCT(dev, dct, 0x7c);
239 val &= ~0x00ffffff;
Zheng Baoeb75f652010-04-23 17:32:48 +0000240 val |= EMRS;
241 val |= 1 << SendMrsCmd;
Timothy Pearson730a0432015-10-16 13:51:51 -0500242 Set_NB32_DCT(dev, dct, 0x7c, val);
Zheng Baoeb75f652010-04-23 17:32:48 +0000243
244 do {
Timothy Pearson730a0432015-10-16 13:51:51 -0500245 val = Get_NB32_DCT(dev, dct, 0x7c);
Zheng Baoeb75f652010-04-23 17:32:48 +0000246 } while (val & (1 << SendMrsCmd));
247}
248
249static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
250 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
251{
Zheng Baoeb75f652010-04-23 17:32:48 +0000252 u32 dev = pDCTstat->dev_dct;
253 u32 dword, ret;
254
Timothy Pearson730a0432015-10-16 13:51:51 -0500255 if (is_fam15h()) {
256 uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
Zheng Baoeb75f652010-04-23 17:32:48 +0000257
Timothy Pearson730a0432015-10-16 13:51:51 -0500258 /* The formula for chip select number is: CS = dimm*2+rank */
259 uint8_t dimm = MrsChipSel / 2;
260 uint8_t rank = MrsChipSel % 2;
Zheng Baoeb75f652010-04-23 17:32:48 +0000261
Timothy Pearson730a0432015-10-16 13:51:51 -0500262 /* FIXME: These parameters should be configurable
263 * For now, err on the side of caution and enable automatic 2x refresh
264 * when the DDR temperature rises above the internal limits
265 */
266 uint8_t force_2x_self_refresh = 0; /* ASR */
267 uint8_t auto_2x_self_refresh = 1; /* SRT */
Zheng Baoeb75f652010-04-23 17:32:48 +0000268
Timothy Pearson730a0432015-10-16 13:51:51 -0500269 ret = 0x80000;
270 ret |= (MrsChipSel << 21);
Zheng Baoeb75f652010-04-23 17:32:48 +0000271
Timothy Pearson730a0432015-10-16 13:51:51 -0500272 /* Set self refresh parameters */
273 ret |= (force_2x_self_refresh << 6);
274 ret |= (auto_2x_self_refresh << 7);
275
276 /* Obtain Tcwl, adjust, and set CWL with the adjusted value */
277 dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
278 ret |= ((dword - 5) << 3);
279
280 /* Obtain and set RttWr */
281 ret |= (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
282 } else {
283 ret = 0x20000;
284 ret |= (MrsChipSel << 20);
285
286 /* program MrsAddress[5:3]=CAS write latency (CWL):
287 * based on F2x[1,0]84[Tcwl] */
288 dword = Get_NB32_DCT(dev, dct, 0x84);
289 dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
290
291 ret |= ((dword >> 20) & 7) << 3;
292
293 /* program MrsAddress[6]=auto self refresh method (ASR):
294 * based on F2x[1,0]84[ASR]
295 * program MrsAddress[7]=self refresh temperature range (SRT):
296 * based on F2x[1,0]84[ASR and SRT]
297 */
298 ret |= ((dword >> 18) & 3) << 6;
299
300 /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
301 * based on F2x[1,0]84[DramTermDyn]
302 */
303 ret |= ((dword >> 10) & 3) << 9;
304 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000305
306 return ret;
307}
308
309static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
310 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
311{
Zheng Baoeb75f652010-04-23 17:32:48 +0000312 u32 dev = pDCTstat->dev_dct;
313 u32 dword, ret;
314
Timothy Pearson730a0432015-10-16 13:51:51 -0500315 if (is_fam15h()) {
316 ret = 0xc0000;
317 ret |= (MrsChipSel << 21);
Zheng Baoeb75f652010-04-23 17:32:48 +0000318
Timothy Pearson730a0432015-10-16 13:51:51 -0500319 /* Program MPR and MPRLoc to 0 */
320 // ret |= 0x0; /* MPR */
321 // ret |= (0x0 << 2); /* MPRLoc */
322 } else {
323 ret = 0x30000;
324 ret |= (MrsChipSel << 20);
325
326 /* program MrsAddress[1:0]=multi purpose register address location
327 * (MPR Location):based on F2x[1,0]84[MprLoc]
328 * program MrsAddress[2]=multi purpose register
329 * (MPR):based on F2x[1,0]84[MprEn]
330 */
331 dword = Get_NB32_DCT(dev, dct, 0x84);
332 ret |= (dword >> 24) & 7;
333 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000334
335 return ret;
336}
337
338static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
339 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
340{
Zheng Baoeb75f652010-04-23 17:32:48 +0000341 u32 dev = pDCTstat->dev_dct;
342 u32 dword, ret;
343
Timothy Pearson730a0432015-10-16 13:51:51 -0500344 if (is_fam15h()) {
345 uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
Zheng Baoeb75f652010-04-23 17:32:48 +0000346
Timothy Pearson730a0432015-10-16 13:51:51 -0500347 /* Set defaults */
348 uint8_t qoff = 0; /* Enable output buffers */
349 uint8_t wrlvl = 0; /* Disable write levelling */
350 uint8_t tqds = 0;
351 uint8_t rttnom = 0;
352 uint8_t dic = 0;
353 uint8_t additive_latency = 0;
354 uint8_t dll_enable = 0;
Zheng Baoeb75f652010-04-23 17:32:48 +0000355
Timothy Pearson730a0432015-10-16 13:51:51 -0500356 ret = 0x40000;
357 ret |= (MrsChipSel << 21);
358
359 /* The formula for chip select number is: CS = dimm*2+rank */
360 uint8_t dimm = MrsChipSel / 2;
361 uint8_t rank = MrsChipSel % 2;
362
363 /* Determine if TQDS should be set */
364 if ((pDCTstat->Dimmx8Present & (1 << dimm))
365 && (((dimm & 0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
366 && (pDCTstat->Status & (1 << SB_LoadReduced)))
367 tqds = 1;
368
369 /* Obtain RttNom */
370 rttnom = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
371
372 /* Obtain DIC */
373 dic = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
374
375 /* Load data into MRS word */
376 ret |= (qoff & 0x1) << 12;
377 ret |= (tqds & 0x1) << 11;
378 ret |= ((rttnom & 0x4) >> 2) << 9;
379 ret |= ((rttnom & 0x2) >> 1) << 6;
380 ret |= ((rttnom & 0x1) >> 0) << 2;
381 ret |= (wrlvl & 0x1) << 7;
382 ret |= ((dic & 0x2) >> 1) << 5;
383 ret |= ((dic & 0x1) >> 0) << 1;
384 ret |= (additive_latency & 0x3) << 3;
385 ret |= (dll_enable & 0x1);
Zheng Baoeb75f652010-04-23 17:32:48 +0000386 } else {
Timothy Pearson730a0432015-10-16 13:51:51 -0500387 ret = 0x10000;
388 ret |= (MrsChipSel << 20);
Zheng Baoeb75f652010-04-23 17:32:48 +0000389
Timothy Pearson730a0432015-10-16 13:51:51 -0500390 /* program MrsAddress[5,1]=output driver impedance control (DIC):
391 * based on F2x[1,0]84[DrvImpCtrl]
392 */
393 dword = Get_NB32_DCT(dev, dct, 0x84);
394 if (dword & (1 << 3))
395 ret |= 1 << 5;
396 if (dword & (1 << 2))
397 ret |= 1 << 1;
Zheng Baoeb75f652010-04-23 17:32:48 +0000398
Timothy Pearson730a0432015-10-16 13:51:51 -0500399 /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
400 * based on F2x[1,0]84[DramTerm]
401 */
402 if (!(pDCTstat->Status & (1 << SB_Registered))) {
403 if (dword & (1 << 9))
404 ret |= 1 << 9;
405 if (dword & (1 << 8))
406 ret |= 1 << 6;
407 if (dword & (1 << 7))
408 ret |= 1 << 2;
409 } else {
410 ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
411 }
412
413 /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
414 if (Get_NB32_DCT(dev, dct, 0x94) & (1 << RDqsEn)) {
415 u8 bit;
416 /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
417 bit = (ret >> 21) << 1;
418 if ((dct & 1) != 0)
419 bit ++;
420 if (pDCTstat->Dimmx8Present & (1 << bit))
421 ret |= 1 << 11;
422 }
423
424 /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
425 if (dword & (1 << 13))
426 ret |= 1 << 12;
427 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000428
429 return ret;
430}
431
432static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
433 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
434{
Zheng Baoeb75f652010-04-23 17:32:48 +0000435 u32 dev = pDCTstat->dev_dct;
436 u32 dword, ret, dword2;
437
Timothy Pearson730a0432015-10-16 13:51:51 -0500438 if (is_fam15h()) {
439 ret = 0x00000;
440 ret |= (MrsChipSel << 21);
Zheng Baoeb75f652010-04-23 17:32:48 +0000441
Timothy Pearson730a0432015-10-16 13:51:51 -0500442 /* Set defaults */
443 uint8_t ppd = 0;
444 uint8_t wr_ap = 0;
445 uint8_t dll_reset = 1;
446 uint8_t test_mode = 0;
447 uint8_t cas_latency = 0;
448 uint8_t read_burst_type = 1;
449 uint8_t burst_length = 0;
Zheng Baoeb75f652010-04-23 17:32:48 +0000450
Timothy Pearson730a0432015-10-16 13:51:51 -0500451 /* Obtain PchgPDModeSel */
452 dword = Get_NB32_DCT(dev, dct, 0x84);
453 ppd = (dword >> 23) & 0x1;
Zheng Baoeb75f652010-04-23 17:32:48 +0000454
Timothy Pearson730a0432015-10-16 13:51:51 -0500455 /* Obtain Twr */
456 dword = Get_NB32_DCT(dev, dct, 0x22c) & 0x1f;
Zheng Baoeb75f652010-04-23 17:32:48 +0000457
Timothy Pearson730a0432015-10-16 13:51:51 -0500458 /* Calculate wr_ap (Fam15h BKDG v3.14 Table 82) */
459 if (dword == 0x10)
460 wr_ap = 0x0;
461 else if (dword == 0x5)
462 wr_ap = 0x1;
463 else if (dword == 0x6)
464 wr_ap = 0x2;
465 else if (dword == 0x7)
466 wr_ap = 0x3;
467 else if (dword == 0x8)
468 wr_ap = 0x4;
469 else if (dword == 0xa)
470 wr_ap = 0x5;
471 else if (dword == 0xc)
472 wr_ap = 0x6;
473 else if (dword == 0xe)
474 wr_ap = 0x7;
Zheng Baoeb75f652010-04-23 17:32:48 +0000475
Timothy Pearson730a0432015-10-16 13:51:51 -0500476 /* Obtain Tcl */
477 dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
Zheng Baoeb75f652010-04-23 17:32:48 +0000478
Timothy Pearson730a0432015-10-16 13:51:51 -0500479 /* Calculate cas_latency (Fam15h BKDG v3.14 Table 83) */
480 if (dword == 0x5)
481 cas_latency = 0x2;
482 else if (dword == 0x6)
483 cas_latency = 0x4;
484 else if (dword == 0x7)
485 cas_latency = 0x6;
486 else if (dword == 0x8)
487 cas_latency = 0x8;
488 else if (dword == 0x9)
489 cas_latency = 0xa;
490 else if (dword == 0xa)
491 cas_latency = 0xc;
492 else if (dword == 0xb)
493 cas_latency = 0xe;
494 else if (dword == 0xc)
495 cas_latency = 0x1;
496 else if (dword == 0xd)
497 cas_latency = 0x3;
498 else if (dword == 0xe)
499 cas_latency = 0x5;
500 else if (dword == 0xf)
501 cas_latency = 0x7;
502 else if (dword == 0x10)
503 cas_latency = 0x9;
504
505 /* Obtain BurstCtrl */
506 burst_length = Get_NB32_DCT(dev, dct, 0x84) & 0x3;
507
508 /* Load data into MRS word */
509 ret |= (ppd & 0x1) << 12;
510 ret |= (wr_ap & 0x3) << 9;
511 ret |= (dll_reset & 0x1) << 8;
512 ret |= (test_mode & 0x1) << 7;
513 ret |= ((cas_latency & 0xe) >> 1) << 4;
514 ret |= ((cas_latency & 0x1) >> 0) << 2;
515 ret |= (read_burst_type & 0x1) << 3;
516 ret |= (burst_length & 0x3);
517 } else {
518 ret = 0x00000;
519 ret |= (MrsChipSel << 20);
520
521 /* program MrsAddress[1:0]=burst length and control method
522 (BL):based on F2x[1,0]84[BurstCtrl] */
523 dword = Get_NB32_DCT(dev, dct, 0x84);
524 ret |= dword & 3;
525
526 /* program MrsAddress[3]=1 (BT):interleaved */
527 ret |= 1 << 3;
528
529 /* program MrsAddress[6:4,2]=read CAS latency
530 (CL):based on F2x[1,0]88[Tcl] */
531 dword2 = Get_NB32_DCT(dev, dct, 0x88);
532 ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */
533 ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */
534
535 /* program MrsAddress[12]=0 (PPD):slow exit */
536 if (dword & (1 << 23))
537 ret |= 1 << 12;
538
539 /* program MrsAddress[11:9]=write recovery for auto-precharge
540 (WR):based on F2x[1,0]84[Twr] */
541 ret |= ((dword >> 4) & 7) << 9;
542
543 /* program MrsAddress[8]=1 (DLL):DLL reset
544 just issue DLL reset at first time */
545 ret |= 1 << 8;
546 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000547
548 return ret;
549}
550
551static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
552{
Zheng Baoeb75f652010-04-23 17:32:48 +0000553 u32 dev = pDCTstat->dev_dct;
554 u32 dword;
555
556 /*1.Program MrsAddress[10]=1
557 2.Set SendZQCmd=1
558 */
Timothy Pearson730a0432015-10-16 13:51:51 -0500559 dword = Get_NB32_DCT(dev, dct, 0x7C);
Zheng Baoeb75f652010-04-23 17:32:48 +0000560 dword &= ~0xFFFFFF;
561 dword |= 1 << 10;
562 dword |= 1 << SendZQCmd;
Timothy Pearson730a0432015-10-16 13:51:51 -0500563 Set_NB32_DCT(dev, dct, 0x7C, dword);
Zheng Baoeb75f652010-04-23 17:32:48 +0000564
565 /* Wait for SendZQCmd=0 */
566 do {
Timothy Pearson730a0432015-10-16 13:51:51 -0500567 dword = Get_NB32_DCT(dev, dct, 0x7C);
Zheng Baoeb75f652010-04-23 17:32:48 +0000568 } while (dword & (1 << SendZQCmd));
569
570 /* 4.Wait 512 MEMCLKs */
571 mct_Wait(300);
572}
573
574void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
575 struct DCTStatStruc *pDCTstat, u8 dct)
576{
577 u8 MrsChipSel;
578 u32 dword;
Zheng Baoeb75f652010-04-23 17:32:48 +0000579 u32 dev = pDCTstat->dev_dct;
580
Timothy Pearson730a0432015-10-16 13:51:51 -0500581 if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
Zheng Baoeb75f652010-04-23 17:32:48 +0000582 /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
Timothy Pearson730a0432015-10-16 13:51:51 -0500583 dword = Get_NB32_DCT(dev, dct, 0x7c);
Zheng Baoeb75f652010-04-23 17:32:48 +0000584 dword |= 1 << EnDramInit;
Timothy Pearson730a0432015-10-16 13:51:51 -0500585 Set_NB32_DCT(dev, dct, 0x7c, dword);
Zheng Baoeb75f652010-04-23 17:32:48 +0000586 mct_DCTAccessDone(pDCTstat, dct);
587
588 /* 4.wait 200us */
589 mct_Wait(40000);
590
Timothy Pearson730a0432015-10-16 13:51:51 -0500591 /* 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. */
592 dword = Get_NB32_DCT(dev, dct, 0x7c);
Zheng Baoeb75f652010-04-23 17:32:48 +0000593 dword |= 1 << DeassertMemRstX;
Timothy Pearson730a0432015-10-16 13:51:51 -0500594 Set_NB32_DCT(dev, dct, 0x7c, dword);
Zheng Baoeb75f652010-04-23 17:32:48 +0000595
596 /* 6.wait 500us */
597 mct_Wait(200000);
598
599 /* 7.Program F2x[1,0]7C[AssertCke]=1 */
Timothy Pearson730a0432015-10-16 13:51:51 -0500600 dword = Get_NB32_DCT(dev, dct, 0x7c);
Zheng Baoeb75f652010-04-23 17:32:48 +0000601 dword |= 1 << AssertCke;
Timothy Pearson730a0432015-10-16 13:51:51 -0500602 Set_NB32_DCT(dev, dct, 0x7c, dword);
Zheng Baoeb75f652010-04-23 17:32:48 +0000603
604 /* 8.wait 360ns */
605 mct_Wait(80);
606
607 /* The following steps are performed with registered DIMMs only and
608 * must be done for each chip select pair */
609 if (pDCTstat->Status & (1 << SB_Registered))
610 mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
Timothy Pearson730a0432015-10-16 13:51:51 -0500611
612 /* The following steps are performed with load reduced DIMMs only and
613 * must be done for each DIMM */
614 // if (pDCTstat->Status & (1 << SB_LoadReduced))
615 /* TODO
616 * Implement LRDIMM configuration
617 */
Zheng Baoeb75f652010-04-23 17:32:48 +0000618 }
619
620 /* The following steps are performed once for unbuffered DIMMs and once for each
621 * chip select on registered DIMMs: */
622 for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
623 if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
624 u32 EMRS;
625 /* 13.Send EMRS(2) */
Timothy Pearson730a0432015-10-16 13:51:51 -0500626 EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel);
Zheng Baoeb75f652010-04-23 17:32:48 +0000627 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
628 mct_SendMrsCmd(pDCTstat, dct, EMRS);
629 /* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */
Timothy Pearson730a0432015-10-16 13:51:51 -0500630 EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel);
Zheng Baoeb75f652010-04-23 17:32:48 +0000631 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
632 mct_SendMrsCmd(pDCTstat, dct, EMRS);
633 /* 15.Send EMRS(1) */
Timothy Pearson730a0432015-10-16 13:51:51 -0500634 EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel);
Zheng Baoeb75f652010-04-23 17:32:48 +0000635 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
636 mct_SendMrsCmd(pDCTstat, dct, EMRS);
637 /* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
Timothy Pearson730a0432015-10-16 13:51:51 -0500638 EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel);
Zheng Baoeb75f652010-04-23 17:32:48 +0000639 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
640 mct_SendMrsCmd(pDCTstat, dct, EMRS);
641
Timothy Pearson730a0432015-10-16 13:51:51 -0500642 if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
Zheng Baoeb75f652010-04-23 17:32:48 +0000643 if (!(pDCTstat->Status & (1 << SB_Registered)))
644 break; /* For UDIMM, only send MR commands once per channel */
645 }
Zheng Baodd676dd2011-01-20 02:09:24 +0000646 if (pDCTstat->LogicalCPUID & (AMD_DR_Bx/* | AMD_RB_C0 */)) /* TODO: We dont support RB_C0 now. need to be added and tested. */
Zheng Baoeb75f652010-04-23 17:32:48 +0000647 if (!(pDCTstat->Status & (1 << SB_Registered)))
648 MrsChipSel ++;
649 }
650
Timothy Pearson730a0432015-10-16 13:51:51 -0500651 if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
Zheng Baoeb75f652010-04-23 17:32:48 +0000652 /* 17.Send two ZQCL commands */
653 mct_SendZQCmd(pDCTstat, dct);
654 mct_SendZQCmd(pDCTstat, dct);
Timothy Pearson730a0432015-10-16 13:51:51 -0500655
Zheng Baoeb75f652010-04-23 17:32:48 +0000656 /* 18.Program F2x[1,0]7C[EnDramInit]=0 */
Timothy Pearson730a0432015-10-16 13:51:51 -0500657 dword = Get_NB32_DCT(dev, dct, 0x7C);
Zheng Baoeb75f652010-04-23 17:32:48 +0000658 dword &= ~(1 << EnDramInit);
Timothy Pearson730a0432015-10-16 13:51:51 -0500659 Set_NB32_DCT(dev, dct, 0x7C, dword);
Zheng Baoeb75f652010-04-23 17:32:48 +0000660 mct_DCTAccessDone(pDCTstat, dct);
661 }
662}