DDR3 support for AMD Fam10.
[coreboot.git] / src / northbridge / amd / amdmct / mct_ddr3 / mhwlc_d.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2010 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 /*
21  *-----------------------------------------------------------------------------
22  *                      MODULES USED
23  *
24  *-----------------------------------------------------------------------------
25  */
26
27 /*----------------------------------------------------------------------------
28  *                      PROTOTYPES OF LOCAL FUNCTIONS
29  *
30  *----------------------------------------------------------------------------
31  */
32 u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue);
33 u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue);
34 void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl);
35 void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm);
36 void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass);
37 void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr);
38 void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
39 /*
40  *-----------------------------------------------------------------------------
41  *              EXPORTED FUNCTIONS
42  *
43  *-----------------------------------------------------------------------------
44  */
45
46 /*-----------------------------------------------------------------------------
47  * void AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct *DCTData,
48  *                  u8 Dimm, u8 Pass)
49  *
50  *  Description:
51  *       This function initialized Hardware based write levelization phase 1
52  *
53  *   Parameters:
54  *       IN  OUT   *SPDData - Pointer to buffer with information about each DIMMs
55  *                            SPD information
56  *                 *MCTData - Pointer to buffer with runtime parameters,
57  *                 *DCTData - Pointer to buffer with information about each DCT
58  *
59  *       IN        DIMM - Logical DIMM number
60  *                 Pass - First or Second Pass
61  *       OUT
62  *-----------------------------------------------------------------------------
63  */
64 void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
65                 u8 dimm, u8 pass)
66 {
67         u8 ByteLane;
68         u32 Value, Addr;
69         u16 Addl_Data_Offset, Addl_Data_Port;
70
71         pDCTData->WLPass = pass;
72         /* 1. Specify the target DIMM that is to be trained by programming
73          * F2x[1, 0]9C_x08[TrDimmSel].
74          */
75         set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
76                         DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
77                         TrDimmSelEnd,(u32)dimm);
78         /* 2. Prepare the DIMMs for write levelization using DDR3-defined
79          * MR commands. */
80         prepareDimms(pMCTData, pDCTData,dimm, TRUE);
81         /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
82          *    satisfy DDR3-defined internal DRAM timing.
83          */
84         pMCTData->AgesaDelay(40);
85         /* 4. Configure the processor's DDR phy for write levelization training: */
86         procConifg(pMCTData,pDCTData, dimm, pass);
87         /* 5. Begin write levelization training:
88          *  Program F2x[1, 0]9C_x08[WrtLevelTrEn]=1. */
89         if (pDCTData->LogicalCPUID & AMD_DR_Cx)
90                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
91                                 DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 1);
92         else
93         {
94                 /* Broadcast write to all D3Dbyte chiplet register offset 0xc
95                  * Set bit 0 (wrTrain)
96                  * Program bit 4 to nibble being trained (only matters for x4dimms)
97                  * retain value of 3:2 (Trdimmsel)
98                  * reset bit 5 (FrzPR)
99                  */
100                 if (pDCTData->DctTrain)
101                 {
102                         Addl_Data_Offset=0x198;
103                         Addl_Data_Port=0x19C;
104                 }
105                 else
106                 {
107                         Addl_Data_Offset=0x98;
108                         Addl_Data_Port=0x9C;
109                 }
110                 Addr=0x0D00000C;
111                 AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
112                 while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
113                                 DctAccessDone, DctAccessDone)) == 0);
114                 AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
115                 Value = bitTestSet(Value, 0);   /* enable WL training */
116                 Value = bitTestReset(Value, 4); /* for x8 only */
117                 Value = bitTestReset(Value, 5); /* for harward WL training */
118                 AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
119                 Addr=0x4D030F0C;
120                 AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
121                 while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
122                                 DctAccessDone, DctAccessDone)) == 0);
123         }
124
125         /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
126         pMCTData->AgesaDelay(140);
127         /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
128         set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
129                         DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
130         /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
131          * to get the gross and fine delay settings
132          * for the target DIMM and save these values. */
133         ByteLane = 0;
134         while (ByteLane < MAX_BYTE_LANES)
135         {
136                 getWLByteDelay(pDCTData,ByteLane, dimm);
137                 setWLByteDelay(pDCTData,ByteLane, dimm, 1);
138                 ByteLane++;
139         }
140
141         /* 6. Configure DRAM Phy Control Register so that the phy stops driving
142          *    write levelization ODT. */
143         set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
144                         DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
145
146         /* Wait 10 MEMCLKs to allow for ODT signal settling. */
147         pMCTData->AgesaDelay(10);
148
149         /* 7. Program the target DIMM back to normal operation by configuring
150          * the following (See section 2.8.5.4.1.1
151          * [Phy Assisted Write Levelization] on page 97 pass 1, step #2):
152          * Configure all ranks of the target DIMM for normal operation.
153          * Enable the output drivers of all ranks of the target DIMM.
154          * For a two DIMM system, program the Rtt value for the target DIMM
155          * to the normal operating termination:
156          */
157         prepareDimms(pMCTData, pDCTData,dimm,FALSE);
158 }
159
160 /*----------------------------------------------------------------------------
161  *      LOCAL FUNCTIONS
162  *
163  *----------------------------------------------------------------------------
164  */
165
166 /*-----------------------------------------------------------------------------
167  * u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
168  *
169  * Description:
170  *      This function swaps the bits in MSR register value
171  *
172  * Parameters:
173  *      IN  OUT   *DCTData - Pointer to buffer with information about each DCT
174  *      IN      u32: MRS value
175  *      OUT     u32: sWAPPED BANK BITS
176  *
177  * ----------------------------------------------------------------------------
178  */
179 u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
180 {
181         u32 tempW, tempW1;
182
183         tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
184                         FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
185         if (tempW1 & 1)
186         {
187                 if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
188                 {
189                         /* swap A3/A4,A5/A6,A7/A8 */
190                         tempW = MRSValue;
191                         tempW1 = MRSValue;
192                         tempW &= 0x0A8;
193                         tempW1 &= 0x0150;
194                         MRSValue &= 0xFE07;
195                         MRSValue |= (tempW<<1);
196                         MRSValue |= (tempW1>>1);
197                 }
198         }
199         return MRSValue;
200 }
201
202 /*-----------------------------------------------------------------------------
203  *  u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
204  *
205  *  Description:
206  *       This function swaps the bits in MSR register value
207  *
208  *   Parameters:
209  *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
210  *       IN     u32: MRS value
211  *       OUT       u32: sWAPPED BANK BITS
212  *
213  * ----------------------------------------------------------------------------
214  */
215 u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
216 {
217         u32 tempW, tempW1;
218
219         tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
220                         FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
221         if (tempW1 & 1)
222         {
223                 if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
224                 {
225                         /* swap BA0/BA1 */
226                         tempW = MRSValue;
227                         tempW1 = MRSValue;
228                         tempW &= 0x01;
229                         tempW1 &= 0x02;
230                         MRSValue = 0;
231                         MRSValue |= (tempW<<1);
232                         MRSValue |= (tempW1>>1);
233                 }
234         }
235         return MRSValue;
236 }
237
238 /*-----------------------------------------------------------------------------
239  *  void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *DCTData, u8 Dimm, BOOL WL)
240  *
241  *  Description:
242  *       This function prepares DIMMS for training
243  *
244  *   Parameters:
245  *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
246  *               *SPDData - Pointer to buffer with information about each DIMMs
247  *                          SPD information
248  *               *MCTData - Pointer to buffer with runtime parameters,
249  *       IN     Dimm - Logical DIMM number
250  *               WL - indicates if the routine is used for Write levelization
251  *                    training
252  *
253  *       OUT
254  *
255  * ----------------------------------------------------------------------------
256  */
257 void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
258 {
259         u32 tempW, tempW1, tempW2, MrsBank;
260         u8 rank, currDimm, MemClkFreq;
261
262         MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
263                         FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
264         /* Configure the DCT to send initialization MR commands to the target DIMM
265          * ;by programming the F2x[1,0]7C register using the following steps.
266          */
267         rank = 0;
268         while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
269         {
270                 /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to be trained. */
271                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
272                         DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, dimm*2+rank);
273                 /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
274                  * ;register that defines the required DDR3-defined function for write
275                  * ; levelization.
276                  */
277                 MrsBank = swapBankBits(pDCTData,1);
278                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
279                         DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
280                 /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
281                  * ; for write levelization.
282                  */
283                 tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
284
285                 /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
286                 tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
287                                 FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
288                 if (tempW2)
289                 {
290                         if (pDCTData->DimmX8Present[dimm])
291                                 tempW |= 0x800;
292                 }
293
294                 /* determine Rtt_Nom for WL & Normal mode */
295                 if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
296                         tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
297                 } else {
298                         if (wl)
299                         {
300                                 if (pDCTData->MaxDimmsInstalled == 1)
301                                 {
302                                         if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 0))
303                                         {
304                                                 tempW1 = 0x00;  /* Rtt_Nom=OFF */
305                                         }
306                                         else
307                                         {
308                                                 tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
309                                         }
310                                 }
311                                 else    /* 2 Dimms or more per channel */
312                                 {
313                                         if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 1))
314                                         {
315                                                 tempW1 = 0x00;  /* Rtt_Nom=OFF */
316                                         }
317                                         else
318                                         {
319                                                 if (MemClkFreq == 6) {
320                                                         tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
321                                                 } else {
322                                                         tempW1 = 0x40;/* Rtt_Nom=RZQ/2=120 Ohm */
323                                                 }
324                                         }
325                                 }
326                         }
327                         else {  /* 1 or 4 Dimms per channel */
328                                 if ((pDCTData->MaxDimmsInstalled == 1) || (pDCTData->MaxDimmsInstalled == 4))
329                                 {
330                                         tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
331                                 }
332                                 else    /* 2 or 3 Dimms per channel */
333                                 {
334                                         if (MemClkFreq < 5) {
335                                                 tempW1 = 0x0044;        /* Rtt_Nom=RZQ/6=40 Ohm */
336                                         } else {
337                                                 tempW1 = 0x0204;        /* Rtt_Nom=RZQ/8=30 Ohm */
338                                         }
339                                 }
340                         }
341                 }
342                 tempW=tempW|tempW1;
343
344                 /* All ranks of the target DIMM are set to write levelization mode. */
345                 if (wl)
346                 {
347                         tempW1 = bitTestSet(tempW, MRS_Level);
348                         if (rank == 0)
349                         {
350                                 /* ?Enable the output driver of the first rank of the target DIMM. */
351                                 tempW = tempW1;
352                         }
353                         else
354                         {
355                                 /* Disable the output drivers of all other ranks for
356                                  * the target DIMM. */
357                                 tempW = bitTestSet(tempW1, Qoff);
358                         }
359                 }
360                 /* program MrsAddress[5,1]=output driver impedance control (DIC):
361                  * based on F2x[1,0]84[DrvImpCtrl] */
362                 tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
363                                 FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
364                 if (bitTest(tempW1,1))
365                 {tempW = bitTestSet(tempW, 5);}
366                 if (bitTest(tempW1,0))
367                 {tempW = bitTestSet(tempW, 1);}
368
369                 tempW = swapAddrBits_wl(pDCTData,tempW);
370
371                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
372                         DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
373                 /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
374                  * ;the specified DIMM.
375                  */
376                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
377                         DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
378                 /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
379                 while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
380                                 FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
381                 {
382                 }
383                 /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
384                  * ;register that defines the required DDR3-defined function for Rtt_WR.
385                  */
386                 MrsBank = swapBankBits(pDCTData,2);
387                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
388                         DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
389                 /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
390                  * ; for Rtt_WR (DRAMTermDyn).
391                  */
392                 tempW = 0;/* PASR = 0,*/
393                 /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
394                  * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
395                 tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
396                                 FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
397                 if (bitTest(tempW1,19))
398                 {tempW = bitTestSet(tempW, 7);}
399                 if (bitTest(tempW1,18))
400                 {tempW = bitTestSet(tempW, 6);}
401                 /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
402                 tempW=tempW|((tempW1&0x00700000)>>17);
403                 /* workaround for DR-B0 */
404                 if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
405                         tempW+=0x8;
406                 /* determine Rtt_WR for WL & Normal mode */
407                 if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
408                         tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
409                 } else {
410                         if (wl)
411                         {
412                                 tempW1 = 0x00;  /* Rtt_WR=off */
413                         }
414                         else
415                         {
416                                 if (pDCTData->MaxDimmsInstalled == 1)
417                                 {
418                                         tempW1 = 0x00;  /* Rtt_WR=off */
419                                 }
420                                 else
421                                 {
422                                         if (MemClkFreq == 6) {
423                                                 tempW1 = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */
424                                         } else {
425                                                 tempW1 = 0x400; /* Rtt_WR=RZQ/2 */
426                                         }
427                                 }
428                         }
429                 }
430                 tempW=tempW|tempW1;
431                 tempW = swapAddrBits_wl(pDCTData,tempW);
432                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
433                         DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
434                 /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
435                    the specified DIMM.*/
436                 set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
437                         DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
438                 /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
439                 while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
440                                 FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
441                 {
442                 }
443
444                 rank++;
445         }
446
447         /* Configure the non-target DIMM normally. */
448         currDimm = 0;
449         while (currDimm < MAX_LDIMMS)
450         {
451                 if (pDCTData->DimmPresent[currDimm])
452                 {
453                         if (currDimm != dimm)
454                         {
455                                 rank = 0;
456                                 while ((rank < pDCTData->DimmRanks[currDimm]) && (rank < 2))
457                                 {
458
459                                         /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank
460                                          * ;to be trained.
461                                          */
462                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
463                                                 FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, currDimm*2+rank);
464                                         /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal
465                                          * ;DRAM register that defines the required DDR3-defined function
466                                          * ; for write levelization.
467                                          */
468                                         MrsBank = swapBankBits(pDCTData,1);
469                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
470                                                 FUN_DCT, DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
471                                         /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required
472                                          * ;DDR3-defined function for write levelization.
473                                          */
474                                         tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0, Level=0, Qoff=0 */
475
476                                         /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
477                                         tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
478                                                         FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
479                                         if (tempW2)
480                                         {
481                                                 if (pDCTData->DimmX8Present[currDimm])
482                                                         tempW |= 0x800;
483                                         }
484
485                                         /* determine Rtt_Nom for WL & Normal mode */
486                                         if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
487                                                 tempW1 = RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
488                                         } else {
489                                                 if (wl)
490                                                 {
491                                                         if ((pDCTData->DimmRanks[currDimm] == 2) && (rank == 1))
492                                                         {
493                                                                 tempW1 = 0x00;  /* Rtt_Nom=OFF */
494                                                         }
495                                                         else
496                                                         {
497                                                                 if (MemClkFreq < 5) {
498                                                                         tempW1 = 0x0044;/* Rtt_Nom=RZQ/6=40 Ohm */
499                                                                 } else {
500                                                                         tempW1 = 0x0204;/* Rtt_Nom=RZQ/8=30 Ohm */
501                                                                 }
502                                                         }
503                                                 }
504                                                 else {  /* 1 or 4 Dimms per channel */
505                                                         if ((pDCTData->MaxDimmsInstalled == 4))
506                                                         {
507                                                                 tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm */
508                                                         }
509                                                         else {  /* 2 or 3 Dimms per channel */
510                                                                 if (MemClkFreq < 5) {
511                                                                         tempW1 = 0x0044;        /* Rtt_Nom=RZQ/6=40 Ohm */
512                                                                 } else {
513                                                                         tempW1 = 0x0204;        /* Rtt_Nom=RZQ/8=30 Ohm */
514                                                                 }
515                                                         }
516                                                 }
517                                         }
518                                         tempW=tempW|tempW1;
519                                         /* program MrsAddress[5,1]=output driver impedance control (DIC):
520                                          * based on F2x[1,0]84[DrvImpCtrl] */
521                                         tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
522                                                         FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
523                                         if (bitTest(tempW1,1))
524                                         {tempW = bitTestSet(tempW, 5);}
525                                         if (bitTest(tempW1,0))
526                                         {tempW = bitTestSet(tempW, 1);}
527                                         tempW = swapAddrBits_wl(pDCTData,tempW);
528                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
529                                                 FUN_DCT, DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
530                                         /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command
531                                          * ; to the specified DIMM.
532                                          */
533                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
534                                                 FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
535                                         /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
536                                         while ((get_Bits(pDCTData, pDCTData->CurrDct,
537                                                         pDCTData->NodeId, FUN_DCT, DRAM_INIT,
538                                                         SendMrsCmd, SendMrsCmd)) == 1);
539                                         /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
540                                          * ;register that defines the required DDR3-defined function for Rtt_WR.
541                                          */
542                                         MrsBank = swapBankBits(pDCTData,2);
543                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
544                                                 DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
545                                         /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
546                                          * ; for Rtt_WR (DRAMTermDyn).
547                                          */
548                                         tempW = 0;/* PASR = 0,*/
549                                         /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
550                                          * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
551                                         tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
552                                                         FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
553                                         if (bitTest(tempW1,19))
554                                         {tempW = bitTestSet(tempW, 7);}
555                                         if (bitTest(tempW1,18))
556                                         {tempW = bitTestSet(tempW, 6);}
557                                         /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
558                                         tempW=tempW|((tempW1&0x00700000)>>17);
559                                         /* workaround for DR-B0 */
560                                         if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
561                                                 tempW+=0x8;
562                                         /* determine Rtt_WR for WL & Normal mode */
563                                         if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
564                                                 tempW1 = RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
565                                         } else {
566                                                 if (wl)
567                                                 {
568                                                         tempW1 = 0x00;  /* Rtt_WR=off */
569                                                 }
570                                                 else
571                                                 {
572                                                         if (MemClkFreq == 6) {
573                                                                 tempW1 = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */
574                                                         } else {
575                                                                 tempW1 = 0x400; /* Rtt_WR=RZQ/2 */
576                                                         }
577                                                 }
578                                         }
579                                         tempW=tempW|tempW1;
580                                         tempW = swapAddrBits_wl(pDCTData,tempW);
581                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
582                                                 DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
583                                         /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
584                                            the specified DIMM.*/
585                                         set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
586                                                 DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
587                                         /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
588                                         while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
589                                                         FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
590                                         {
591                                         }
592                                         rank++;
593                                 }
594                         }
595                 }
596                 currDimm++;
597         }
598 }
599
600 /*-----------------------------------------------------------------------------
601  * void programODT(sMCTStruct *pMCTData, DCTStruct *DCTData, u8 dimm)
602  *
603  *  Description:
604  *       This function programs the ODT values for the NB
605  *
606  *   Parameters:
607  *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
608  *       IN
609  *       OUT
610  * ----------------------------------------------------------------------------
611  */
612 void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
613 {
614         u8 WrLvOdt1=0;
615
616         if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
617                 if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
618                         WrLvOdt1 = 0x03;
619                 } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
620                         WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
621                 } else {
622                         WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
623                 }
624         } else {
625                 WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
626         }
627
628         set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
629                         DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
630
631 }
632
633 /*-----------------------------------------------------------------------------
634  * void procConifg(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
635  *
636  *  Description:
637  *       This function programs the ODT values for the NB
638  *
639  *   Parameters:
640  *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
641  *               *MCTData - Pointer to buffer with runtime parameters,
642  *       IN     Dimm - Logical DIMM
643  *               Pass - First of Second Pass
644  *       OUT
645  * ----------------------------------------------------------------------------
646  */
647 void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
648 {
649         u8 ByteLane, Seed_Gross, Seed_Fine;
650         u32 Value, Addr;
651         u16 Addl_Data_Offset, Addl_Data_Port;
652
653         /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for the
654          * ;current memory subsystem configuration.
655          */
656         programODT(pMCTData, pDCTData, dimm);
657
658         /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
659         if (pDCTData->LogicalCPUID & AMD_DR_Cx)
660                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
661                                 DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn,(u32) 1);
662         else
663         {
664                 /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 0 for Rev.B*/
665                 if (pDCTData->DctTrain)
666                 {
667                         Addl_Data_Offset=0x198;
668                         Addl_Data_Port=0x19C;
669                 }
670                 else
671                 {
672                         Addl_Data_Offset=0x98;
673                         Addl_Data_Port=0x9C;
674                 }
675                 Addr=0x0D008000;
676                 AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
677                 while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
678                                 DctAccessDone, DctAccessDone)) == 0);
679                 AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
680                 Value = bitTestSet(Value, 12);
681                 AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
682                 Addr=0x4D088F00;
683                 AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
684                 while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
685                                 DctAccessDone, DctAccessDone)) == 0);
686         }
687
688         /* Wait 10 MEMCLKs to allow for ODT signal settling. */
689         pMCTData->AgesaDelay(10);
690         ByteLane = 0;
691         if (pass == 1)
692         {
693                 if (pDCTData->Status[DCT_STATUS_REGISTERED])
694                 {
695                         if(pDCTData->RegMan1Present & ((1<<(dimm*2+pDCTData->DctTrain))))
696                         {
697                                 Seed_Gross = 0x02;
698                                 Seed_Fine = 0x16;
699                         }
700                         else
701                         {
702                                 Seed_Gross = 0x02;
703                                 Seed_Fine = 0x00;
704                         }
705                 }
706                 else
707                 {
708                         Seed_Gross = 0x00;
709                         Seed_Fine = 0x1A;
710                 }
711                 while(ByteLane < MAX_BYTE_LANES)
712                 {
713                         /* Program an initialization value to registers F2x[1, 0]9C_x[51:50] and
714                          * ;F2x[1, 0]9C_x52 to set the gross and fine delay for all the byte lane fields
715                          * ; If the target frequency is different than 400MHz, BIOS must
716                          * execute two training passes for each DIMM.
717                          * For pass 1 at a 400MHz MEMCLK frequency, use an initial total delay value
718                          * ; of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined
719                          * ;by design.
720                          */
721                         pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
722                         pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
723                         ByteLane++;
724                 }
725         }
726         setWLByteDelay(pDCTData, ByteLane, dimm, 0);
727 }
728
729 /*-----------------------------------------------------------------------------
730  *  void setWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm){
731  *
732  *  Description:
733  *       This function writes the write levelization byte delay for the Phase
734  *       Recovery control registers
735  *
736  *   Parameters:
737  *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
738  *       IN     Dimm - Dimm Number
739  *               DCTData->WLGrossDelay[index+ByteLane] - gross write delay for each
740  *                                                   logical DIMM
741  *               DCTData->WLFineDelay[index+ByteLane] - fine write delay for each
742  *                                                  logical DIMM
743  *               ByteLane - target byte lane to write
744  *        targetAddr -    0: write to DRAM phase recovery control register
745  *                        1: write to DQS write register
746  *       OUT
747  *
748  *-----------------------------------------------------------------------------
749  */
750 void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
751 {
752         u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr;
753         u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, EccValue, tempW;
754
755         if (targetAddr == 0)
756         {
757                 index = (u8)(MAX_BYTE_LANES * dimm);
758                 ValueLow = 0;
759                 ValueHigh = 0;
760                 ByteLane = 0;
761                 EccValue = 0;
762                 while (ByteLane < MAX_BYTE_LANES)
763                 {
764                         /* This subtract 0xC workaround might be temporary. */
765                         if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+pDCTData->DctTrain))))
766                         {
767                                 tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
768                                 tempW -= 0xC;
769                                 pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
770                                 pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
771                         }
772                         grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
773                         /* Adjust seed gross delay overflow (greater than 3):
774                          *      - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
775                          *      - Keep original seed gross delay for later reference.
776                          */
777                         if(grossDelayValue >= 3)
778                         {
779                                 grossDelayValue = (grossDelayValue&1)? 1 : 2;
780                         }
781                         fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
782                         if (ByteLane < 4)
783                                 ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
784                         else if(ByteLane < 8)
785                                 ValueHigh |= ((grossDelayValue << 5) | fineDelayValue) << 8*(ByteLane-4);
786                         else
787                                 EccValue = ((grossDelayValue << 5) | fineDelayValue);
788                         ByteLane++;
789                 }
790                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
791                                 DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, (u32)ValueLow);
792                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
793                                 DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, (u32)ValueHigh);
794                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
795                                 DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, (u32)EccValue);
796         }
797         else
798         {
799                 index = (u8)(MAX_BYTE_LANES * dimm);
800                 grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
801                 fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
802
803                 tempB = 0;
804                 offsetAddr = (u8)(3 * dimm);
805                 if (ByteLane < 2)
806                 {
807                         tempB = (u8)(16 * ByteLane);
808                         addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01;
809                 }
810                 else if (ByteLane <4)
811                 {
812                         tempB = (u8)(16 * ByteLane);
813                         addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 1;
814                 }
815                 else if (ByteLane <6)
816                 {
817                         tempB = (u8)(16 * ByteLane);
818                         addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45;
819                 }
820                 else if (ByteLane <8)
821                 {
822                         tempB = (u8)(16 * ByteLane);
823                         addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 + 1;
824                 }
825                 else
826                 {
827                         tempB = 0;
828                         addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 2;
829                 }
830                 addr += offsetAddr;
831
832                 fineStartLoc = (u8)(tempB % 32);
833                 fineEndLoc = (u8)(fineStartLoc + 4);
834                 grossStartLoc = (u8)(fineEndLoc + 1);
835                 grossEndLoc = (u8)(grossStartLoc + 1);
836
837                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
838                                 (u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
839                 set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
840                                 (u16)addr, grossStartLoc, grossEndLoc, (u32)grossDelayValue);
841         }
842
843 }
844
845 /*-----------------------------------------------------------------------------
846  *  void getWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm)
847  *
848  *  Description:
849  *       This function reads the write levelization byte delay from the Phase
850  *       Recovery control registers
851  *
852  *   Parameters:
853  *       IN  OUT   *DCTData - Pointer to buffer with information about each DCT
854  *       IN     Dimm - Dimm Number
855  *               ByteLane - target byte lane to read
856  *       OUT
857  *               DCTData->WLGrossDelay[index+ByteLane] - gross write delay for current
858  *                                                   byte for logical DIMM
859  *               DCTData->WLFineDelay[index+ByteLane] - fine write delay for current
860  *                                                  byte for logical DIMM
861  *
862  *-----------------------------------------------------------------------------
863  */
864 void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
865 {
866         u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index;
867         u32 addr, fine, gross;
868         tempB = 0;
869         index = (u8)(MAX_BYTE_LANES*dimm);
870         if (ByteLane < 4)
871         {
872                 tempB = (u8)(8 * ByteLane);
873                 addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;
874         }
875         else if (ByteLane < 8)
876         {
877                 tempB1 = (u8)(ByteLane - 4);
878                 tempB = (u8)(8 * tempB1);
879                 addr = DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH;
880         }
881         else
882         {
883                 tempB = 0;
884                 addr = DRAM_CONT_ADD_ECC_PHASE_REC_CTRL;
885         }
886         fineStartLoc = tempB;
887         fineEndLoc = (u8)(fineStartLoc + 4);
888         grossStartLoc = (u8)(fineEndLoc + 1);
889         grossEndLoc = (u8)(grossStartLoc + 1);
890
891         fine = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
892                                 FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
893         gross = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
894                                 FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
895         /* Adjust seed gross delay overflow (greater than 3):
896          * - Adjust the trained gross delay to the original seed gross delay.
897          */
898         if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
899         {
900                 gross += pDCTData->WLGrossDelay[index+ByteLane];
901                 if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
902                         gross -= 1;
903                 else
904                         gross -= 2;
905         }
906         else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
907         {
908                 /* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
909                  * We will then round the negative number to 0.
910                  */
911                 gross = 0;
912                 fine = 0;
913         }
914         pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
915         pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
916 }