AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / NB / OR / mndctor.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mndctOr.c
6  *
7  * Northbridge DCT support for Orochi
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/NB/OR)
12  * @e \$Revision: 60556 $ @e \$Date: 2011-10-17 20:19:58 -0600 (Mon, 17 Oct 2011) $
13  *
14  **/
15 /*****************************************************************************
16 *
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 *     * Redistributions of source code must retain the above copyright
23 *       notice, this list of conditions and the following disclaimer.
24 *     * Redistributions in binary form must reproduce the above copyright
25 *       notice, this list of conditions and the following disclaimer in the
26 *       documentation and/or other materials provided with the distribution.
27 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 *       its contributors may be used to endorse or promote products derived
29 *       from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * ***************************************************************************
43 *
44 */
45
46
47 /*
48  *----------------------------------------------------------------------------
49  *                                MODULES USED
50  *
51  *----------------------------------------------------------------------------
52  */
53
54
55
56 #include "AGESA.h"
57 #include "amdlib.h"
58 #include "Ids.h"
59 #include "mport.h"
60 #include "mm.h"
61 #include "mn.h"
62 #include "mt.h"
63 #include "mu.h"
64 #include "OptionMemory.h"       // need def for MEM_FEAT_BLOCK_NB
65 #include "mnor.h"
66 #include "merrhdl.h"
67 #include "cpuFamRegisters.h"
68 #include "GeneralServices.h"
69 #include "cpuFamilyTranslation.h"
70 #include "cpuCommonF15Utilities.h"
71 #include "F15PackageType.h"
72 #include "Filecode.h"
73 CODE_GROUP (G3_DXE)
74 RDATA_GROUP (G3_DXE)
75
76
77 #define FILECODE PROC_MEM_NB_OR_MNDCTOR_FILECODE
78
79 /*----------------------------------------------------------------------------
80  *                          DEFINITIONS AND MACROS
81  *
82  *----------------------------------------------------------------------------
83  */
84 #define UNUSED_CLK 4
85 #define MAX_RD_DQS_DLY 0x1F
86
87 /*----------------------------------------------------------------------------
88  *                           TYPEDEFS AND STRUCTURES
89  *
90  *----------------------------------------------------------------------------
91  */
92
93 /*----------------------------------------------------------------------------
94  *                        PROTOTYPES OF LOCAL FUNCTIONS
95  *
96  *----------------------------------------------------------------------------
97  */
98 UINT32
99 STATIC
100 MemNTotalSyncComponentsOr (
101   IN OUT   MEM_NB_BLOCK *NBPtr
102   );
103
104 /*----------------------------------------------------------------------------
105  *                            EXPORTED FUNCTIONS
106  *
107  *----------------------------------------------------------------------------
108  */
109
110 extern BUILD_OPT_CFG UserOptions;
111
112 /* -----------------------------------------------------------------------------*/
113 /**
114  *
115  *
116  *      This function programs the memory controller with configuration parameters
117  *
118  *
119  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
120  *
121  *     @return          TRUE - An Error value lower than AGESA_FATAL may have occurred
122  *     @return          FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
123  *     @return          NBPtr->MCTPtr->ErrCode - Contains detailed AGESA_STATUS value
124  */
125
126 BOOLEAN
127 MemNAutoConfigOr (
128   IN OUT   MEM_NB_BLOCK *NBPtr
129   )
130 {
131   UINT8 i;
132   UINT8 NumDimmslots;
133   DIE_STRUCT *MCTPtr;
134   DCT_STRUCT *DCTPtr;
135   MEM_PARAMETER_STRUCT *RefPtr;
136   MEM_PS_BLOCK * PsPtr;
137   BOOLEAN ExtraAddrBits;
138   BOOLEAN RankMultEn;
139   UINT8 ROOD;
140
141   RefPtr = NBPtr->RefPtr;
142   MCTPtr = NBPtr->MCTPtr;
143   DCTPtr = NBPtr->DCTPtr;
144   PsPtr = NBPtr->PsPtr;
145
146   ExtraAddrBits = FALSE;
147   RankMultEn = FALSE;
148
149   ROOD = DEFAULT_RD_ODT_OR;
150   //
151   // Check for Extra Address bit requirement for LRDIMMs
152   //
153   if (MCTPtr->Status[SbLrdimms]) {
154     for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
155       if (PsPtr->LrdimmRowAddrBits[i] > 16) {
156         ExtraAddrBits = TRUE;
157       }
158       if (NBPtr->ChannelPtr->LrDimmRankMult[i] > 1) {
159         RankMultEn = TRUE;
160       }
161     }
162   }
163
164   NumDimmslots = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration,
165                                         MCTPtr->SocketId,
166                                         NBPtr->ChannelPtr->ChannelID);
167   //
168   //======================================================================
169   // Build Dram Config Lo Register Value
170   //======================================================================
171   //
172   // Disable Parity Prior to Dram init
173   //
174   MemNSetBitFieldNb (NBPtr, BFParEn, 0);
175   //
176   // LRDIMMS Extended Parity
177   //
178   MemNSetBitFieldNb (NBPtr, BFExtendedParityEn, 0);
179   //
180   // X4Dimm
181   //
182   MemNSetBitFieldNb (NBPtr, BFX4Dimm, NBPtr->ChannelPtr->DimmNibbleAccess & 0xF);
183   //
184   // UnBuffDimm
185   //
186   if (!(MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])) {
187     MemNSetBitFieldNb (NBPtr, BFUnBuffDimm, 1);
188   }
189   //
190   // DimmEccEn
191   //
192   if (MCTPtr->Status[SbEccDimms]) {
193     MemNSetBitFieldNb (NBPtr, BFDimmEccEn, 1);
194   }
195   //
196   // PendRefPayback, StatgRefEn, TStag[0:4]
197   //
198   MemNSetBitFieldNb (NBPtr, BFPendRefPaybackS3En, 1);
199   MemNSetBitFieldNb (NBPtr, BFStagRefEn, 1);
200   for (i = 0; i < 4; i++) {
201     MemNSetBitFieldNb (NBPtr, BFTstag0 + i, 0x14);
202   }
203   //
204   //======================================================================
205   // Build Dram Config Hi Register Value
206   //======================================================================
207   //
208   //
209   // MemClkFreq
210   //
211   MemNSetBitFieldNb (NBPtr, BFMemClkFreq, MemNGetMemClkFreqIdUnb (NBPtr, DCTPtr->Timings.Speed));
212   //
213   // FourRankRDimm0 , FourRankRDimm1 ( Reset Values are 0)
214   //
215   //======================================================================
216   // Build Dram MRS Register Value (Not used for MRS command)
217   //======================================================================
218   //
219   // PchgPDModeSel - This is done here so that the value can be used by
220   //                 MR0 function
221   //
222   if (NBPtr->IsSupported[PchgPDMode]) {
223     MemNSetBitFieldNb (NBPtr, BFPchgPDModeSel, 1);
224   }
225   MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 0);
226
227   //======================================================================
228   // Build Dram Config Misc Register Value
229   //======================================================================
230   //
231   //
232   // LRDIMMs CSMux45 and CSMux67
233   //
234   if (MCTPtr->Status[SbLrdimms]) {
235     if (NumDimmslots == 3) {
236       MemNSetBitFieldNb (NBPtr, BFCSMux45, 0);
237       MemNSetBitFieldNb (NBPtr, BFCSMux67, ExtraAddrBits ? 1 : 0);
238     } else if (NumDimmslots <= 2) {
239       MemNSetBitFieldNb (NBPtr, BFCSMux45, (PsPtr->LrdimmRowAddrBits[0] > 16) ? 1 : 0);
240       MemNSetBitFieldNb (NBPtr, BFCSMux67, (PsPtr->LrdimmRowAddrBits[1] > 16) ? 1 : 0);
241     }
242   }
243   //
244   // LrDimmMrsCtrl
245   //
246   MemNSetBitFieldNb (NBPtr, BFLrDimmMrsCtrl, RankMultEn ? 1 : 0);
247   //
248   // BFLrDimmEnhRefEn
249   //
250   MemNSetBitFieldNb (NBPtr, BFLrDimmEnhRefEn, RankMultEn ? 1 : 0);
251   //
252   // SubMemclkRegDly
253   //
254   MemNSetBitFieldNb (NBPtr, BFSubMemclkRegDly, (MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])? 1 : 0);
255   //======================================================================
256   // Other Registers
257   //======================================================================
258   //
259   //
260   // Non-SPD Timings
261   //
262   MemNSetBitFieldNb (NBPtr, BFTrwtWB, 0x17);
263   MemNSetBitFieldNb (NBPtr, BFTrwtTO, 0x16);
264   MemNSetBitFieldNb (NBPtr, BFTwrrd, 0xB );
265
266   MemNSetBitFieldNb (NBPtr, BFTrdrdSdSc, 0xB);
267   MemNSetBitFieldNb (NBPtr, BFTrdrdSdDc, 0xB);
268   MemNSetBitFieldNb (NBPtr, BFTrdrdDd, 0xB);
269
270   MemNSetBitFieldNb (NBPtr, BFTwrwrSdSc, 0xB);
271   MemNSetBitFieldNb (NBPtr, BFTwrwrSdDc, 0xB);
272   MemNSetBitFieldNb (NBPtr, BFTwrwrDd, 0xB);
273
274   if (NBPtr->MCTPtr->Status[SbLrdimms]) {
275     ROOD = ROOD + (UINT8) (MemNCalBufDatDelaySkewOr (NBPtr, GetBufDatDlySkew));
276   }
277   MemNSetBitFieldNb (NBPtr, BFWrOdtOnDuration, DEFAULT_WR_ODT_OR);
278   MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, ROOD);
279   MemNSetBitFieldNb (NBPtr, BFWrOdtTrnOnDly, 0);
280
281   MemNSetBitFieldNb (NBPtr, BFTmrd, (NBPtr->MCTPtr->Status[SbLrdimms] ? 6 : 4));
282
283   MemNSetBitFieldNb (NBPtr, BFFlushWrOnS3StpGnt, 1);
284   MemNSetBitFieldNb (NBPtr, BFFastSelfRefEntryDis, 0);
285
286   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
287 }
288
289 /* -----------------------------------------------------------------------------*/
290 /**
291  *
292  *
293  *   This function caps speed based on battery life check.
294  *
295  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
296  */
297 VOID
298 MemNCapSpeedBatteryLifeOr (
299   IN OUT   MEM_NB_BLOCK *NBPtr
300   )
301 {
302   CONST UINT16 SupportedFreq[] = {
303     DDR1866_FREQUENCY,
304     DDR1600_FREQUENCY,
305     DDR1333_FREQUENCY,
306     DDR1066_FREQUENCY,
307     DDR800_FREQUENCY,
308     DDR667_FREQUENCY
309   };
310
311   UINT32 FreqNumeratorInMHz;
312   UINT32 FreqDivisor;
313   UINT32 VoltageInuV;
314   UINT32 NBFreq;
315   UINT16 DdrFreq;
316   UINT16 j;
317   INT8   NbPs;
318   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
319
320   FamilySpecificServices = NULL;
321   GetCpuServicesOfSocket (NBPtr->MCTPtr->SocketId, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &(NBPtr->MemPtr->StdHeader));
322
323   // Find the lowest supported NB Pstate
324   NBFreq = 0;
325   for (NbPs = 3; NbPs >= 0; NbPs--) {
326     if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices,
327                                                   NBPtr->MemPtr->PlatFormConfig,
328                                                   &NBPtr->PciAddr,
329                                                   (UINT32) NbPs,
330                                                   &FreqNumeratorInMHz,
331                                                   &FreqDivisor,
332                                                   &VoltageInuV,
333                                                   &(NBPtr->MemPtr->StdHeader))) {
334       NBFreq = FreqNumeratorInMHz / FreqDivisor;
335       break;
336     }
337   }
338
339   ASSERT (NBFreq > 0);
340
341   // Pick Max MEMCLK that is less than or equal to (NCLK / 2)
342   DdrFreq = DDR800_FREQUENCY;
343   for (j = 0; j < GET_SIZE_OF (SupportedFreq); j++) {
344     if (NBFreq >= ((UINT32) 2 * SupportedFreq[j])) {
345       DdrFreq = SupportedFreq[j];
346       break;
347     }
348   }
349
350   // Cap MemClk frequency to lowest NCLK frequency
351   if (NBPtr->DCTPtr->Timings.TargetSpeed > DdrFreq) {
352     NBPtr->DCTPtr->Timings.TargetSpeed = DdrFreq;
353   }
354
355   // Initialize NbPsCtlReg
356   NBPtr->NbPsCtlReg = 0;
357 }
358
359 /* -----------------------------------------------------------------------------*/
360 /**
361  *
362  *
363  *   This function retrieves the Max latency parameters
364  *
365  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
366  *
367  *     @param[in]  *MinDlyPtr - Pointer to variable to store the Minimum Delay value
368  *     @param[in]  *MaxDlyPtr - Pointer to variable to store the Maximum Delay value
369  *     @param[in]  *DlyBiasPtr - Pointer to variable to store Delay Bias value
370  *     @param[in]  MaxRcvEnDly - Maximum receiver enable delay value
371  */
372
373 VOID
374 MemNGetMaxLatParamsOr (
375   IN OUT   MEM_NB_BLOCK *NBPtr,
376   IN       UINT16 MaxRcvEnDly,
377   IN OUT   UINT16 *MinDlyPtr,
378   IN OUT   UINT16 *MaxDlyPtr,
379   IN OUT   UINT16 *DlyBiasPtr
380   )
381 {
382   UINT32 N;
383   UINT32 T;
384   UINT32 P;
385   UINT32 MemClkPeriod;
386
387   // 1. P = N = T = 0.
388   P = N = T = 0;
389
390   // Get all sync components BKDG steps 3,4,6,7
391   P = MemNTotalSyncComponentsOr (NBPtr);
392
393   // 8. P = P + CEIL(MAX(D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] +
394   //    D18F2x9C_x0000_0[3:0]0[7:5]_dct[1:0][RdDqsTime] PCLKs))
395   P = P + (MaxRcvEnDly + 31) / 32;
396
397   // 10. T = T + 800 ps
398   T += 800;
399
400   // 11. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs.
401   MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
402   N = ((((P * MemClkPeriod + 1) / 2) + T) * NBPtr->NBClkFreq + 999999) / 1000000;
403
404   // 13. D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] = CEIL(N) - 1
405   N = N - 1;
406
407   // Calculate a starting MaxRdLatency delay value with steps 5, 9, and 12 excluded
408   *MinDlyPtr = (UINT16) N;
409
410   *MaxDlyPtr = 0x3FF;
411
412   // Left edge of MaxRdLat will be added with 1 NCLK and 3 PCLK
413   N = 1;
414   P = 3;
415   N += (((P * MemClkPeriod + 1) / 2) * NBPtr->NBClkFreq + 999999) / 1000000;
416   *DlyBiasPtr = (UINT16) N;
417 }
418
419 /* -----------------------------------------------------------------------------*/
420 /**
421  *
422  *
423  *   This function  sets the maximum round-trip latency in the system from the processor to the DRAM
424  *   devices and back.
425  *
426  *
427  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
428  *     @param[in]     MaxRcvEnDly - Maximum receiver enable delay value
429  *
430  */
431
432 VOID
433 MemNSetMaxLatencyOr (
434   IN OUT   MEM_NB_BLOCK *NBPtr,
435   IN       UINT16 MaxRcvEnDly
436   )
437 {
438   UINT32 N;
439   UINT32 T;
440   UINT32 P;
441   UINT32 MemClkPeriod;
442
443   AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader));
444
445   //
446   // Initial value for MaxRdLat used in training
447   //
448   N = 0x55;
449
450   if (MaxRcvEnDly != 0xFFFF) {
451     // 1. P = N = T = 0.
452     P = N = T = 0;
453
454     // Get all sync components BKDG steps 3,4,6,7
455     P = MemNTotalSyncComponentsOr (NBPtr);
456
457     // 5. P = P + 5
458     P += 5;
459
460     // 8. P = P + CEIL(MAX(D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] +
461     //    D18F2x9C_x0000_0[3:0]0[7:5]_dct[1:0][RdDqsTime] PCLKs))
462     P = P + ((MaxRcvEnDly + MAX_RD_DQS_DLY) + 31) / 32;
463
464     // 9. P = P + 5
465     P += 5;
466
467     // 10. T = T + 800 ps
468     T += 800;
469
470     // 11. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs.
471     MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
472     N = ((((P * MemClkPeriod + 1) / 2) + T) * NBPtr->NBClkFreq + 999999) / 1000000;
473
474     // 12. N = N - 1. See step 9.
475     N = N - 1;
476
477     // 13. D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] = CEIL(N) - 1
478     N = N - 1;
479   }
480
481   NBPtr->DCTPtr->Timings.MaxRdLat = (UINT16) N;
482   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", N);
483   MemNSetBitFieldNb (NBPtr, BFMaxLatency, N);
484 }
485
486 /*-----------------------------------------------------------------------------
487  *
488  *
489  *     This function set MaxRdLat after HW receiver enable training is completed
490  *
491  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
492  *     @param[in,out]  OptParam   - Optional parameter
493  *
494  *     @return    TRUE
495  * ----------------------------------------------------------------------------
496  */
497 BOOLEAN
498 MemNExitPhyAssistedTrainingOr (
499   IN OUT   MEM_NB_BLOCK *NBPtr,
500   IN OUT   VOID *OptParam
501   )
502 {
503   UINT8 Dct;
504   UINT8 ChipSel;
505   MEM_TECH_BLOCK  *TechPtr;
506
507   TechPtr = NBPtr->TechPtr;
508
509   MemNReEnablePhyCompNb (NBPtr, NULL);
510
511   // Calculate Max Latency for both channels to prepare for position training
512   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
513     IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
514     NBPtr->SwitchDCT (NBPtr, Dct);
515     //
516     // For Orochi, we need to reset DisAutoRefresh and ZqcsInterval for
517     // Position training.
518     //
519     if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
520       MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1);
521       MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0);
522     }
523
524     if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) {
525       NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat);
526     }
527   }
528
529   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
530 }
531
532 /*-----------------------------------------------------------------------------
533  *
534  *     This function send control words after MEMCLK frequency change
535  *
536  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
537  *     @param[in,out]  OptParam   - Optional parameter
538  *
539  *     @return    TRUE
540  * ----------------------------------------------------------------------------
541  */
542 BOOLEAN
543 MemNAfterMemClkFreqChgOr (
544   IN OUT   MEM_NB_BLOCK *NBPtr,
545   IN OUT   VOID *OptParam
546   )
547 {
548   UINT8 Dct;
549   MEM_TECH_BLOCK *TechPtr;
550
551   TechPtr = NBPtr->TechPtr;
552
553   // Reprogram the DIMMs' buffers right after MEMCLK frequency change
554   if (!(TechPtr->TechnologySpecificHook[LrdimmFreqChgCtrlWrd] (TechPtr, NULL))) {
555     if (NBPtr->MCTPtr->Status[SbRegistered]) {
556       for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
557         MemNSwitchDCTNb (NBPtr, Dct);
558         if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
559           TechPtr->FreqChgCtrlWrd (TechPtr);
560         }
561       }
562     }
563   }
564
565   return TRUE;
566 }
567
568 /*-----------------------------------------------------------------------------
569  *
570  *     This function modifies CS tri-state bit map
571  *
572  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
573  *     @param[in,out]  CsTriBitmap - Bitmap of chipselects to be tristated
574  *
575  *     @return    TRUE
576  * ----------------------------------------------------------------------------
577  */
578 BOOLEAN
579 MemNBeforeSetCsTriOr (
580   IN OUT   MEM_NB_BLOCK *NBPtr,
581   IN OUT   VOID *CsTriBitmap
582   )
583 {
584   //
585   // The tri-state of CS[7:4] for LrDIMM should be determined by
586   // D18F2xA8_dct[1:0][CsMux45]/[CsMux67]
587   if (NBPtr->MCTPtr->Status[SbLrdimms]) {
588     if (MemNGetBitFieldNb (NBPtr, BFCSMux45) == 1) {
589       *(UINT8*) CsTriBitmap &= 0xCF;
590     }
591     if (MemNGetBitFieldNb (NBPtr, BFCSMux67) == 1) {
592       *(UINT8*) CsTriBitmap &= 0x3F;
593     }
594   }
595
596   return TRUE;
597 }
598 /*----------------------------------------------------------------------------
599  *                              LOCAL FUNCTIONS
600  *
601  *----------------------------------------------------------------------------
602  */
603
604 /* -----------------------------------------------------------------------------*/
605 /**
606  *
607  *
608  *   This function gets the total of sync components for Max Read Latency calculation
609  *
610  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
611  *
612  *     @return      Total in PCLKs
613  */
614 UINT32
615 STATIC
616 MemNTotalSyncComponentsOr (
617   IN OUT   MEM_NB_BLOCK *NBPtr
618   )
619 {
620   UINT32 P;
621
622   P = 0;
623
624   // 3. If (D18F2x9C_x0000_0004_dct[1:0][AddrCmdSetup] = 0 & D18F2x9C_x0000_0004_dct[1:0][CsOdt-
625   // Setup] = 0 & D18F2x9C_x0000_0004_dct[1:0][CkeSetup] = 0)
626   // then P = P + 1
627   // else P = P + 2
628   if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
629     P += 1;
630   } else {
631     P += 2;
632   }
633
634   // 4. P = P + (8 - D18F2x210_dct[1:0]_nbp[3:0][RdPtrInit]) + 1
635   P = P + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit)) + 1;
636
637   // 6. If (D18F2xA8_dct[1:0][SubMemclkRegDly] = 0 & D18F2x90_dct[1:0][UnbuffDimm] = 0)
638   // then P = P + 2
639   if ((MemNGetBitFieldNb (NBPtr, BFSubMemclkRegDly) == 0) && (MemNGetBitFieldNb (NBPtr, BFUnBuffDimm) == 0)) {
640     P += 2;
641   }
642
643   // 7. P = P + (2 * (D18F2x200_dct[1:0][Tcl] - 1 clocks))
644   P = P + (2 * (MemNGetBitFieldNb (NBPtr, BFTcl) - 1));
645
646   return P;
647 }
648
649 /* -----------------------------------------------------------------------------*/
650 /**
651  *
652  *
653  *   This function is used to calculate BufDatDelay and BufDatDelaySkew value.
654  *
655  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
656  *     @param[in]   GetDelay   - Get either BufDatDly or BufDatDlySkew value
657  *
658  *     @return      BufDatDly or BufDatDlySkew value
659  */
660 UINT32
661 MemNCalBufDatDelaySkewOr (
662   IN OUT   MEM_NB_BLOCK *NBPtr,
663   IN       UINT8   GetDelay
664   )
665 {
666   UINT8 SpdOffset;
667   UINT8 Dimm;
668   UINT8 i;
669   UINT8 j;
670   UINT32 MinModuleDly;
671   UINT32 MaxModuleDly;
672   UINT8 SyncDelay;
673   UINT32 SmallestModuleDly;
674   UINT32 LargestModuleDly;
675   UINT32 BufDatDly;
676   UINT32 BufDatDlySkew;
677   MEM_TECH_BLOCK  *TechPtr;
678   UINT8 *SpdBufferPtr;
679
680   TechPtr = NBPtr->TechPtr;
681
682   i = 0;
683   j = 0;
684   SmallestModuleDly = 0;
685   LargestModuleDly = 0;
686   SyncDelay = 0;
687   BufDatDly = 0;
688   BufDatDlySkew = 0;
689   MinModuleDly = 0xFF;
690   MaxModuleDly = 0;
691   SpdOffset = (UINT8) (2 * CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage));
692
693   for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
694     if (TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, Dimm)) {
695       if ((SpdBufferPtr[90 + SpdOffset] & 0x7F) < (UINT8) MinModuleDly) {
696         MinModuleDly = SpdBufferPtr[90 + SpdOffset] & 0x7F;
697         i = Dimm;
698       }
699       if ((SpdBufferPtr[91 + SpdOffset] & 0x7F) > (UINT8) MaxModuleDly) {
700         MaxModuleDly = SpdBufferPtr[91 + SpdOffset] & 0x7F;
701         j = Dimm;
702       }
703     }
704   }
705   if (!(MinModuleDly >= 0x3C && MinModuleDly <= 0x58)) {
706     IDS_HDT_CONSOLE (MEM_FLOW, "\tMinModuleDly out of range (0x3C - 0x58): %02x\n", MinModuleDly);
707   }
708   if (!(MaxModuleDly >= 0x3C && MaxModuleDly <= 0x58)) {
709     IDS_HDT_CONSOLE (MEM_FLOW, "\tMaxModuleDly out of range (0x3C - 0x58): %02x\n", MaxModuleDly);
710   }
711   //
712   //Calculate BufDatDly
713   //
714   //SmallestModuleDelay = MinimumModuleDelay * .000125 us * 400 MHz * 0x40.
715   //MinimumModuleDelay is the minimum SPD module delay across all DIMMs on a channel.
716   //
717   SmallestModuleDly =  (UINT32) (MinModuleDly * 125 * 400 * 0x40 / 1000000);
718   //
719   //SyncDelay = (F0RC2[AddrCmdPrelaunch] ? 0x30 - (2*F1RC12[QCAPrelaunchDelay]) : 0x20) + 0x10.
720   //SyncDelay is calculated from the SPD values of the MinimumModuleDelay DIMM.
721   //
722   TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, i);
723   SyncDelay = (UINT8) ((((SpdBufferPtr[67] & 0x01) == 1) ? (0x30 - 2 * (SpdBufferPtr[70] & 0x07)) : 0x20) + 0x10);
724   //
725   //BufDatDelay = FLOOR((((SmallestModuleDelay - SynchDelay) * (MemClkFreq/400 MHz)) + SynchDelay)/0x40).
726   //
727   BufDatDly = (((SmallestModuleDly - SyncDelay) * NBPtr->DCTPtr->Timings.Speed / 400) + SyncDelay) / 0x40;
728
729   if (GetDelay == GetBufDatDly) {
730     return BufDatDly;
731   }
732   //
733   //Calculate BufDatDlySkew
734   //
735   //LargestModuleDelay = MaximumModuleDelay * .000125 us * 400 MHz * 0x40.
736   //MaximumModuleDelay is the maximum SPD module delay across all DIMMs on a channel.
737   //
738   LargestModuleDly = (UINT32) (MaxModuleDly * 125 * 400 * 0x40 / 1000000);
739   //
740   //SyncDelay = (F0RC2[AddrCmdPrelaunch] ? 0x30 - (2*F1RC12[QCAPrelaunchDelay]) : 0x20) + 0x10.
741   //SyncDelay is calculated from the SPD values of the MaximumModuleDelay DIMM.
742   //
743   TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, j);
744   SyncDelay = (UINT8) ((((SpdBufferPtr[67] & 0x01) == 1) ? (0x30 - 2 * (SpdBufferPtr[70] & 0x07)) : 0x20) + 0x10);
745   //
746   //BufDatDelaySkew = FLOOR((((LargestModuleDelay - SynchDelay) * (MemClkFreq/400 MHz)) + SynchDelay)/0x40) - BufDatDelay.
747   //
748   BufDatDlySkew = ((((((LargestModuleDly - SyncDelay) * NBPtr->DCTPtr->Timings.Speed + 200) / 400) + SyncDelay) - (BufDatDly * 0x40) + 0x20) / 0x40);
749
750   return BufDatDlySkew ;
751 }
752 /*-----------------------------------------------------------------------------
753  *
754  *     This function Enables parity on both DCTs if Parity is supported.
755  *
756  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
757  *     @param[in,out]  *OptParam  - Unused
758  *
759  *     @return    TRUE
760  * ----------------------------------------------------------------------------
761  */
762 BOOLEAN
763 MemNEnableParityAfterMemRstOr (
764   IN OUT   MEM_NB_BLOCK *NBPtr,
765   IN OUT   VOID *OptParam
766   )
767 {
768   DIE_STRUCT *MCTPtr;
769   MEM_PS_BLOCK * PsPtr;
770   UINT8 i;
771
772   MCTPtr = NBPtr->MCTPtr;
773   PsPtr = NBPtr->PsPtr;
774
775   if (NBPtr->MCTPtr->Status[SbParDimms]) {
776     //
777     // SbParDimms should be set for all DDR3 RDIMMS
778     // Cannot turn off ParEn for DDR3
779     //
780     MemNSetBitFieldNb (NBPtr, BFParEn, 1);
781     //
782     // LRDIMMS Extended Parity
783     //
784     if (MCTPtr->Status[SbLrdimms]) {
785       for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
786         if (PsPtr->LrdimmRowAddrBits[i] > 16) {
787           MemNSetBitFieldNb (NBPtr, BFExtendedParityEn, 1);
788           break;
789         }
790       }
791     }
792   }
793   return TRUE;
794 }
795
796 /*-----------------------------------------------------------------------------
797  *
798  *
799  *     This function calculates RdOdtTrnOnDly and RdOdtOnDuration when LrDimms
800  *     are present
801  *
802  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
803  *     @param[in,out]  *OptParam  - Not Used
804  *
805  *     @return  TRUE - always
806  * ----------------------------------------------------------------------------
807  */
808 BOOLEAN
809 MemNProgOdtControlOr (
810   IN OUT   MEM_NB_BLOCK *NBPtr,
811   IN OUT   VOID *OptParam
812   )
813 {
814   DCT_STRUCT *DCTPtr;
815   UINT8 Tcwl;
816   UINT8 RdOdtTrnOnDly;
817   UINT8 RdOdtOnDuration;
818
819   DCTPtr = NBPtr->DCTPtr;
820   Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
821   RdOdtTrnOnDly = (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0;
822   RdOdtOnDuration = 6;
823   if (NBPtr->MCTPtr->Status[SbLrdimms]) {
824     RdOdtTrnOnDly = RdOdtTrnOnDly + (UINT8) MemNCalBufDatDelaySkewOr (NBPtr, GetBufDatDly);
825     RdOdtOnDuration = RdOdtOnDuration + (UINT8) MemNCalBufDatDelaySkewOr (NBPtr, GetBufDatDlySkew);
826   }
827   MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, RdOdtTrnOnDly);
828   MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, RdOdtOnDuration);
829   IDS_HDT_CONSOLE (MEM_FLOW,"\n\t\t\tRdOdtTrnOnDly = %x",RdOdtTrnOnDly);
830   IDS_HDT_CONSOLE (MEM_FLOW,"\n\t\t\tRdOdtOnDuration = %x\n",RdOdtOnDuration);
831   return TRUE;
832 }
833
834 /* -----------------------------------------------------------------------------*/
835 /**
836  *
837  *
838  *   This is a general purpose function that executes before DRAM init
839  *
840  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
841  *
842  */
843
844 VOID
845 MemNBeforeDramInitOr (
846   IN OUT   MEM_NB_BLOCK *NBPtr
847   )
848 {
849   UINT8 Dct;
850
851   for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) {
852     MemNSwitchDCTNb (NBPtr, Dct);
853     if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
854       //
855       // 2.10.6.6 DCT Training Specific Configuration
856       //
857       MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 0);
858       MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1);
859       MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 1);
860       MemNSetBitFieldNb (NBPtr, BFForceAutoPchg, 0);
861       MemNSetBitFieldNb (NBPtr, BFDynPageCloseEn, 0);
862       MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 0);
863       MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0);
864       MemNSetBitFieldNb (NBPtr, BFPowerDownEn, 0);
865       MemNSetBitFieldNb (NBPtr, BFDisSimulRdWr, 0);
866       MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0);
867       MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0);
868       MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0);
869       MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, 0);
870       MemNSetBitFieldNb (NBPtr, BFBwCapEn, 0);
871       MemNSetBitFieldNb (NBPtr, BFODTSEn, 0);
872       MemNSetBitFieldNb (NBPtr, BFDctSelIntLvEn, 0);
873       MemNSetBitFieldNb (NBPtr, BFL3Scrub, 0);
874       MemNSetBitFieldNb (NBPtr, BFDramScrub, 0);
875       MemNSetBitFieldNb (NBPtr, BFScrubReDirEn, 0);
876       MemNSetBitFieldNb (NBPtr, BFL3ScrbRedirDis, 1);
877     }
878   }
879 }
880
881 /* -----------------------------------------------------------------------------*/
882 /**
883  *
884  *
885  *   This function releases the NB P-state force.
886  *
887  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
888  *     @param[in,out]   OptParam - Optional parameter
889  *
890  *     @return    TRUE
891  */
892 BOOLEAN
893 MemNReleaseNbPstateOr (
894   IN OUT   MEM_NB_BLOCK *NBPtr,
895   IN OUT   VOID *OptParam
896   )
897 {
898   // 6. Restore the initial D18F5x170[SwNbPstateLoDis, NbPstateDisOnP0] values.
899   MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF9FFF) | (NBPtr->NbPsCtlReg & 0x6000));
900
901   // 7. Restore the initial D18F5x170[NbPstateThreshold, NbPstateHi] values.
902   MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFFF13F) | (NBPtr->NbPsCtlReg & 0x0EC0));
903
904   return TRUE;
905 }
906
907 /* -----------------------------------------------------------------------------*/
908 /**
909  *
910  *
911  *   This function Sets Power Down options and enables Power Down
912  *
913  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
914  *
915  *     The following registers are set:
916  *      BFPowerDownMode         BFPrtlChPDEnhEn
917  *      BFTxp                   BFAggrPDDelay
918  *      BFTxpDll                BFAggrPDEn
919  *      BFPchgPDEnDelay         BFPowerDownEn
920  *
921  * NOTE:  Delay values must be set before turning on the associated Enable bit
922  */
923 VOID
924 MemNPowerDownCtlOr (
925   IN OUT   MEM_NB_BLOCK *NBPtr
926   )
927 {
928   UINT8 PowerDownMode;
929   UINT8 Tmod;
930   CONST UINT32 PwrMngm1[] = {0, 0, 0x05050403, 0x05050403, 0x06060403, 0x07070504, 0x08080504, 0x0A0A0605, 0x0B0B0706};
931   UINT8 i;
932   UINT16 Speed;
933   UINT32 PackageType;
934
935   if (NBPtr->RefPtr->EnablePowerDown) {
936     PackageType = LibAmdGetPackageType (&(NBPtr->MemPtr->StdHeader));
937     //
938     // PowerDownMode
939     //
940     PowerDownMode = (UINT8) UserOptions.CfgPowerDownMode;
941     PowerDownMode = (!NBPtr->IsSupported[ChannelPDMode]) ? PowerDownMode : 0;
942     IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader));
943     if (PowerDownMode == 1) {
944       MemNSetBitFieldNb (NBPtr, BFPowerDownMode, 1);
945     }
946     //
947     // Txp
948     //
949     MemNSetTxpNb (NBPtr);
950     //
951     // PchgPDModeSel is set elswhere.
952     //
953     Tmod = (UINT8) MemNGetBitFieldNb (NBPtr, BFTmod);
954     //
955     // Partial Channel Power Down
956     //
957     MemNSetBitFieldNb (NBPtr, BFPrtlChPDDynDly, 2);
958     MemNSetBitFieldNb (NBPtr, BFPrtlChPDEnhEn, 1);
959     //
960     // Aggressive PowerDown
961     // PchgPDEnDelay: IF (D18F2xA8_dct[1:0][AggrPDEn]) THEN 1 ELSE 0 ENDIF.
962     //
963     MemNSetBitFieldNb (NBPtr, BFAggrPDDelay, 0);
964     if (PackageType != PACKAGE_TYPE_AM3r2) {
965       MemNSetBitFieldNb (NBPtr, BFAggrPDEn, 1);
966       MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, 1);
967     }
968
969     // Program DRAM Power Management 1 register
970     Speed = NBPtr->DCTPtr->Timings.Speed;
971     i = (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
972     ASSERT ((i > 1) && (i < sizeof (PwrMngm1)));
973     MemNSetBitFieldNb (NBPtr, BFDramPwrMngm1Reg, PwrMngm1[i]);
974   }
975 }