AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / NB / mnmct.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mnmct.c
6  *
7  * Northbridge Common MCT supporting functions
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/NB)
12  * @e \$Revision: 58425 $ @e \$Date: 2011-08-29 08:29:04 -0600 (Mon, 29 Aug 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  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53
54
55 #include "AGESA.h"
56 #include "amdlib.h"
57 #include "Ids.h"
58 #include "mport.h"
59 #include "mm.h"
60 #include "mn.h"
61 #include "mu.h"
62 #include "OptionMemory.h"
63 #include "PlatformMemoryConfiguration.h"
64 #include "GeneralServices.h"
65 #include "cpuFeatures.h"
66 #include "merrhdl.h"
67 #include "Filecode.h"
68 CODE_GROUP (G1_PEICC)
69 RDATA_GROUP (G2_PEI)
70
71 #define FILECODE PROC_MEM_NB_MNMCT_FILECODE
72 /*----------------------------------------------------------------------------
73  *                          DEFINITIONS AND MACROS
74  *
75  *----------------------------------------------------------------------------
76  */
77 #define _16MB_RJ16  0x0100
78
79 /*----------------------------------------------------------------------------
80  *                           TYPEDEFS AND STRUCTURES
81  *
82  *----------------------------------------------------------------------------
83  */
84
85 /*----------------------------------------------------------------------------
86  *                        PROTOTYPES OF LOCAL FUNCTIONS
87  *
88  *----------------------------------------------------------------------------
89  */
90 BOOLEAN
91 STATIC
92 MemNSetMTRRrangeNb (
93   IN OUT   MEM_NB_BLOCK *NBPtr,
94   IN       UINT32 Base,
95   IN OUT   UINT32 *LimitPtr,
96   IN       UINT32 MtrrAddr,
97   IN       UINT8 MtrrType
98   );
99
100 /*----------------------------------------------------------------------------
101  *                            EXPORTED FUNCTIONS
102  *
103  *----------------------------------------------------------------------------
104  */
105 extern BUILD_OPT_CFG UserOptions;
106
107 /* -----------------------------------------------------------------------------*/
108 /**
109  *
110  *     Get max frequency from OEM platform definition, from
111  *     any user override (limiting) of max frequency, and
112  *     from any Si Revision Specific information.  Return
113  *     the least of these three in DIE_STRUCT.Timings.TargetSpeed.
114  *
115  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
116  *
117  */
118
119 VOID
120 MemNSyncTargetSpeedNb (
121   IN OUT   MEM_NB_BLOCK *NBPtr
122   )
123 {
124   CONST UINT16 DdrMaxRateTab[] = {
125     UNSUPPORTED_DDR_FREQUENCY,
126     DDR1600_FREQUENCY,
127     DDR1333_FREQUENCY,
128     DDR1066_FREQUENCY,
129     DDR800_FREQUENCY,
130     DDR667_FREQUENCY,
131     DDR533_FREQUENCY,
132     DDR400_FREQUENCY
133   };
134
135   UINT8  Dct;
136   UINT8  Channel;
137   UINT16 MinSpeed;
138   UINT16 DdrMaxRate;
139   DCT_STRUCT *DCTPtr;
140   USER_MEMORY_TIMING_MODE *ChnlTmgMod;
141   USER_MEMORY_TIMING_MODE Mode[MAX_CHANNELS_PER_SOCKET];
142   MEMORY_BUS_SPEED MemClkFreq;
143   MEMORY_BUS_SPEED ProposedFreq;
144
145   ASSERT (NBPtr->DctCount <= sizeof (Mode));
146   MinSpeed = 16000;
147   DdrMaxRate = 16000;
148   if (NBPtr->IsSupported[CheckMaxDramRate]) {
149     // Check maximum DRAM data rate that the processor is designed to support.
150     DdrMaxRate = DdrMaxRateTab[MemNGetBitFieldNb (NBPtr, BFDdrMaxRate)];
151     NBPtr->FamilySpecificHook[GetDdrMaxRate] (NBPtr, &DdrMaxRate);
152     IDS_OPTION_HOOK (IDS_SKIP_FUSED_MAX_RATE, &DdrMaxRate, &NBPtr->MemPtr->StdHeader);
153   }
154
155   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
156     MemNSwitchDCTNb (NBPtr, Dct);
157     DCTPtr = NBPtr->DCTPtr;
158
159     // Check if input user time mode is valid or not
160     ASSERT ((NBPtr->RefPtr->UserTimingMode == TIMING_MODE_SPECIFIC) ||
161         (NBPtr->RefPtr->UserTimingMode == TIMING_MODE_LIMITED) ||
162         (NBPtr->RefPtr->UserTimingMode == TIMING_MODE_AUTO));
163     Mode[Dct] = NBPtr->RefPtr->UserTimingMode;
164     // Check if input clock value is valid or not
165     ASSERT ((NBPtr->ChannelPtr->TechType == DDR3_TECHNOLOGY) ?
166       (NBPtr->RefPtr->MemClockValue >= DDR667_FREQUENCY) :
167       (NBPtr->RefPtr->MemClockValue <= DDR1066_FREQUENCY));
168     MemClkFreq = NBPtr->RefPtr->MemClockValue;
169     if (DCTPtr->Timings.DctDimmValid != 0) {
170       Channel = MemNGetSocketRelativeChannelNb (NBPtr, Dct, 0);
171       ChnlTmgMod = (USER_MEMORY_TIMING_MODE *) FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_BUS_SPEED, NBPtr->MCTPtr->SocketId, Channel, 0,
172                                                                     &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
173       if (ChnlTmgMod != NULL) {
174         // Check if input user timing mode is valid or not
175         ASSERT ((ChnlTmgMod[0] == TIMING_MODE_SPECIFIC) || (ChnlTmgMod[0] == TIMING_MODE_LIMITED) ||
176           (ChnlTmgMod[0] != TIMING_MODE_AUTO));
177         if (ChnlTmgMod[0] != TIMING_MODE_AUTO) {
178           Mode[Dct] = ChnlTmgMod[0];
179           // Check if input clock value is valid or not
180           ASSERT ((NBPtr->ChannelPtr->TechType == DDR3_TECHNOLOGY) ?
181             ((MEMORY_BUS_SPEED)ChnlTmgMod[1] >= DDR667_FREQUENCY) :
182             ((MEMORY_BUS_SPEED)ChnlTmgMod[1] <= DDR1066_FREQUENCY));
183           MemClkFreq = (MEMORY_BUS_SPEED)ChnlTmgMod[1];
184         }
185       }
186
187       ProposedFreq = UserOptions.CfgMemoryBusFrequencyLimit;
188       if (Mode[Dct] == TIMING_MODE_LIMITED) {
189         if (MemClkFreq < ProposedFreq) {
190           ProposedFreq = MemClkFreq;
191         }
192       } else if (Mode[Dct] == TIMING_MODE_SPECIFIC) {
193         ProposedFreq = MemClkFreq;
194       }
195
196       if (Mode[Dct] == TIMING_MODE_SPECIFIC) {
197         DCTPtr->Timings.TargetSpeed = (UINT16) ProposedFreq;
198       } else {
199         // "limit" mode
200         if (DCTPtr->Timings.TargetSpeed > ProposedFreq) {
201           DCTPtr->Timings.TargetSpeed = (UINT16) ProposedFreq;
202         }
203       }
204
205       NBPtr->MemNCapSpeedBatteryLife (NBPtr);
206
207       if (DCTPtr->Timings.TargetSpeed > DdrMaxRate) {
208         if (Mode[Dct] == TIMING_MODE_SPECIFIC) {
209           PutEventLog (AGESA_ALERT, MEM_ALERT_USER_TMG_MODE_OVERRULED, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
210           SetMemError (AGESA_ALERT, NBPtr->MCTPtr);
211         }
212         DCTPtr->Timings.TargetSpeed = DdrMaxRate;
213       }
214
215       IDS_SKIP_HOOK (IDS_POR_MEM_FREQ, NBPtr, &NBPtr->MemPtr->StdHeader) {
216         //
217         //Call Platform POR Frequency Override
218         //
219         if (!MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SPEEDLIMIT, ALL_DIMMS)) {
220           //
221           // Get the POR frequency limit
222           //
223           NBPtr->PsPtr->MemPGetPORFreqLimit (NBPtr);
224         }
225       }
226       IDS_OPTION_HOOK (IDS_STRETCH_FREQUENCY_LIMIT, NBPtr, &NBPtr->MemPtr->StdHeader);
227
228       if (MinSpeed > DCTPtr->Timings.TargetSpeed) {
229         MinSpeed = DCTPtr->Timings.TargetSpeed;
230       }
231     }
232   }
233
234   if (MinSpeed == DDR667_FREQUENCY) {
235     NBPtr->StartupSpeed = DDR667_FREQUENCY;
236   }
237
238   // Sync all DCTs to the same speed
239   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
240     MemNSwitchDCTNb (NBPtr, Dct);
241     NBPtr->DCTPtr->Timings.TargetSpeed = MinSpeed;
242   }
243 }
244
245 /* -----------------------------------------------------------------------------*/
246 /**
247  *
248  *
249  *   This function waits for all DCTs to be ready
250  *
251  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
252  *
253  *     @return          TRUE -  No fatal error occurs.
254  *     @return          FALSE - Fatal error occurs.
255  */
256
257 BOOLEAN
258 MemNSyncDctsReadyNb (
259   IN OUT   MEM_NB_BLOCK *NBPtr
260   )
261 {
262   if (NBPtr->MCTPtr->DimmValid) {
263     MemNPollBitFieldNb (NBPtr, BFDramEnabled, 1, PCI_ACCESS_TIMEOUT, FALSE);
264     // Re-enable phy compensation engine after Dram init has completed
265     MemNSwitchDCTNb (NBPtr, 0);
266     MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
267   }
268   // Wait 750 us for the phy compensation engine to reinitialize.
269   MemUWait10ns (75000, NBPtr->MemPtr);
270
271   MemNSyncAddrMapToAllNodesNb (NBPtr);
272   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
273 }
274
275 /* -----------------------------------------------------------------------------*/
276 /**
277  *
278  *
279  *   This function create the HT memory map
280  *
281  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
282  *
283  *     @return          TRUE -  No fatal error occurs.
284  *     @return          FALSE - Fatal error occurs.
285  */
286
287 BOOLEAN
288 MemNHtMemMapInitNb (
289   IN OUT   MEM_NB_BLOCK *NBPtr
290   )
291 {
292   UINT32 BottomIo;
293   UINT32 HoleOffset;
294   UINT32 DctSelBaseAddr;
295   UINT32 NodeSysBase;
296   UINT32 NodeSysLimit;
297   MEM_PARAMETER_STRUCT *RefPtr;
298   DIE_STRUCT *MCTPtr;
299
300   RefPtr = NBPtr->RefPtr;
301   MCTPtr = NBPtr->MCTPtr;
302   //
303   // Physical addresses in this function are right adjusted by 16 bits ([47:16])
304   // They are BottomIO, HoleOffset, DctSelBaseAddr, NodeSysBase, NodeSysLimit.
305   //
306
307   // Enforce bottom of IO be be 128MB aligned
308   ASSERT ((RefPtr->BottomIo < (_4GB_RJ16 >> 8)) && (RefPtr->BottomIo != 0));
309   BottomIo = (RefPtr->BottomIo & 0xF8) << 8;
310
311   if (!MCTPtr->GangedMode) {
312     DctSelBaseAddr = MCTPtr->DctData[0].Timings.DctMemSize;
313   } else {
314     DctSelBaseAddr = 0;
315   }
316
317   if (MCTPtr->NodeMemSize) {
318     NodeSysBase = NBPtr->SharedPtr->CurrentNodeSysBase;
319     NodeSysLimit = NodeSysBase + MCTPtr->NodeMemSize - 1;
320     DctSelBaseAddr += NodeSysBase;
321
322     if ((NBPtr->IsSupported[ForceEnMemHoleRemapping]) || (RefPtr->MemHoleRemapping)) {
323       if ((NodeSysBase < BottomIo) && (NodeSysLimit >= BottomIo)) {
324         // HW Dram Remap
325         MCTPtr->Status[SbHWHole] = TRUE;
326         RefPtr->GStatus[GsbHWHole] = TRUE;
327         MCTPtr->NodeHoleBase = BottomIo;
328         RefPtr->HoleBase = BottomIo;
329
330         HoleOffset = _4GB_RJ16 - BottomIo;
331
332         NodeSysLimit += HoleOffset;
333
334         if ((DctSelBaseAddr > 0) && (DctSelBaseAddr < BottomIo)) {
335           HoleOffset += DctSelBaseAddr;
336         } else {
337           if (DctSelBaseAddr >= BottomIo) {
338             DctSelBaseAddr += HoleOffset;
339           }
340           HoleOffset += NodeSysBase;
341         }
342
343         MemNSetBitFieldNb (NBPtr, BFDramHoleBase, BottomIo >> 8);
344         MemNSetBitFieldNb (NBPtr, BFDramHoleOffset, HoleOffset >> 7);
345         MemNSetBitFieldNb (NBPtr, BFDramHoleValid, 1);
346
347       } else if (NodeSysBase == BottomIo) {
348         // SW Node Hoist
349         MCTPtr->Status[SbSWNodeHole] = TRUE;
350         RefPtr->GStatus[GsbSpIntRemapHole] = TRUE;
351         RefPtr->GStatus[GsbSoftHole] = TRUE;
352
353         RefPtr->HoleBase = NodeSysBase;
354         DctSelBaseAddr = _4GB_RJ16 + (DctSelBaseAddr - NodeSysBase);
355         NodeSysLimit = _4GB_RJ16 + (NodeSysLimit - NodeSysBase);
356         NodeSysBase = _4GB_RJ16;
357
358       } else if ((NodeSysBase < HT_REGION_BASE_RJ16) && (NodeSysLimit >= HT_REGION_BASE_RJ16)) {
359         if (!NBPtr->SharedPtr->UndoHoistingAbove1TB) {
360           // SW Hoisting above 1TB to avoid HT Reserved region
361           DctSelBaseAddr = _1TB_RJ16 + (DctSelBaseAddr - NodeSysBase);
362           NodeSysLimit = _1TB_RJ16 + (NodeSysLimit - NodeSysBase);
363           NodeSysBase = _1TB_RJ16;
364
365           if (RefPtr->LimitMemoryToBelow1Tb) {
366             // Flag to undo 1TB hoisting after training
367             NBPtr->SharedPtr->UndoHoistingAbove1TB = TRUE;
368           }
369         }
370
371       } else {
372         // No Remapping.  Normal Contiguous mapping
373       }
374     } else {
375       // No Remapping.  Normal Contiguous mapping
376     }
377
378     if (NBPtr->IsSupported[Check1GAlign]) {
379       if (UserOptions.CfgNodeMem1GBAlign) {
380         NBPtr->MemPNodeMemBoundaryNb (NBPtr, (UINT32 *)&NodeSysLimit);
381       }
382     }
383
384     MCTPtr->NodeSysBase = NodeSysBase;
385     MCTPtr->NodeSysLimit = NodeSysLimit;
386     RefPtr->SysLimit = NodeSysLimit;
387     RefPtr->Sub1THoleBase = (NodeSysLimit < HT_REGION_BASE_RJ16) ? (NodeSysLimit + 1) : RefPtr->Sub1THoleBase;
388     IDS_OPTION_HOOK (IDS_MEM_SIZE_OVERLAY, NBPtr, &NBPtr->MemPtr->StdHeader);
389
390     NBPtr->SharedPtr->TopNode = NBPtr->Node;
391
392     NBPtr->SharedPtr->NodeMap[NBPtr->Node].IsValid = TRUE;
393     NBPtr->SharedPtr->NodeMap[NBPtr->Node].SysBase = NodeSysBase;
394     NBPtr->SharedPtr->NodeMap[NBPtr->Node].SysLimit = NodeSysLimit & 0xFFFFFF00;
395
396     MemNSetBitFieldNb (NBPtr, BFDramBaseAddr, NodeSysBase >> (27 - 16));
397     MemNSetBitFieldNb (NBPtr, BFDramLimitAddr, NodeSysLimit >> (27 - 16));
398
399     if ((MCTPtr->DctData[1].Timings.DctMemSize != 0) && (!NBPtr->Ganged)) {
400       MemNSetBitFieldNb (NBPtr, BFDctSelBaseAddr, DctSelBaseAddr >> 11);
401       MemNSetBitFieldNb (NBPtr, BFDctSelHiRngEn, 1);
402       MemNSetBitFieldNb (NBPtr, BFDctSelHi, 1);
403       MemNSetBitFieldNb (NBPtr, BFDctSelBaseOffset, DctSelBaseAddr >> 10);
404     }
405
406     NBPtr->SharedPtr->CurrentNodeSysBase = (NodeSysLimit + 1) & 0xFFFFFFF0;
407   }
408   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
409 }
410
411 /* -----------------------------------------------------------------------------*/
412 /**
413  *
414  *
415  *     Program system DRAM map to this node
416  *
417  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
418  *
419  */
420
421 VOID
422 MemNSyncAddrMapToAllNodesNb (
423   IN OUT   MEM_NB_BLOCK *NBPtr
424   )
425 {
426   UINT8 Node;
427   UINT32 NodeSysBase;
428   UINT32 NodeSysLimit;
429   UINT8  WeReMask;
430   MEM_PARAMETER_STRUCT *RefPtr;
431
432   RefPtr = NBPtr->RefPtr;
433   for (Node = 0; Node < NBPtr->NodeCount; Node++) {
434     NodeSysBase = NBPtr->SharedPtr->NodeMap[Node].SysBase;
435     NodeSysLimit = NBPtr->SharedPtr->NodeMap[Node].SysLimit;
436     if (NBPtr->SharedPtr->NodeMap[Node].IsValid) {
437       WeReMask = 3;
438     } else {
439       WeReMask = 0;
440     }
441     // Set the Dram base and set the WE and RE flags in the base.
442     MemNSetBitFieldNb (NBPtr, BFDramBaseReg0 + Node, (NodeSysBase << 8) | WeReMask);
443     MemNSetBitFieldNb (NBPtr, BFDramBaseHiReg0 + Node, NodeSysBase >> 24);
444     // Set the Dram limit and set DstNode.
445     MemNSetBitFieldNb (NBPtr, BFDramLimitReg0 + Node, (NodeSysLimit << 8) | Node);
446     MemNSetBitFieldNb (NBPtr, BFDramLimitHiReg0 + Node, NodeSysLimit >> 24);
447
448     if (RefPtr->GStatus[GsbHWHole]) {
449       MemNSetBitFieldNb (NBPtr, BFDramMemHoistValid, 1);
450       MemNSetBitFieldNb (NBPtr, BFDramHoleBase, (RefPtr->HoleBase >> 8));
451     }
452   }
453
454   NBPtr->FamilySpecificHook[InitExtMMIOAddr] (NBPtr, NULL);
455 }
456
457 /* -----------------------------------------------------------------------------*/
458 /**
459  *
460  *
461  *   This function enables power down mode
462  *
463  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
464  *
465  */
466
467 VOID
468 MemNPowerDownCtlNb (
469   IN OUT   MEM_NB_BLOCK *NBPtr
470   )
471 {
472   MEM_PARAMETER_STRUCT *RefPtr;
473   UINT8 PowerDownMode;
474
475   RefPtr = NBPtr->RefPtr;
476
477   // we can't enable powerdown mode when doing WL
478   if (RefPtr->EnablePowerDown) {
479     MemNSetBitFieldNb (NBPtr, BFPowerDownEn, 1);
480     PowerDownMode = (UINT8) ((UserOptions.CfgPowerDownMode == POWER_DOWN_MODE_AUTO) ? POWER_DOWN_BY_CHANNEL : UserOptions.CfgPowerDownMode);
481     IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader));
482     if (PowerDownMode) {
483       MemNSetBitFieldNb (NBPtr, BFPowerDownMode, 1);
484     }
485   }
486 }
487
488 /* -----------------------------------------------------------------------------*/
489 /**
490  *
491  *
492  *   This function gets the Optimal Critical Gross Delay Difference between
493  *   the delay parameters across all Dimms on each bytelane.  Then takes the
494  *   largest of all the bytelanes.
495  *
496  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
497  *     @param[in]       TrnDly1 - Type of first Gross Delay parameter
498  *     @param[in]       TrnDly2 - Type of second Gross Delay parameter
499  *
500  *     @return  The largest difference between the largest and smallest
501  *               of the two Gross delay types within a single bytelane
502  */
503 INT8
504 MemNGetOptimalCGDDNb (
505   IN OUT   MEM_NB_BLOCK *NBPtr,
506   IN       TRN_DLY_TYPE TrnDly1,
507   IN       TRN_DLY_TYPE TrnDly2
508   )
509 {
510   INT8  CGDD;
511   INT8  GDD;
512   UINT8  Dimm1;
513   UINT8  Dimm2;
514   UINT8  ByteLane;
515   UINT16 CsEnabled;
516   BOOLEAN CGDDInit;
517   BOOLEAN SameDelayType;
518
519   CGDD = 0;
520   CGDDInit = FALSE;
521   SameDelayType = (BOOLEAN) (TrnDly1 == TrnDly2);
522   CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
523
524   // If the two delay types compared are the same type, then no need to compare the same
525   // pair twice. Adjustments are made in the upper bound and lower bound of the loop to
526   // handle this.
527   for (Dimm1 = 0; Dimm1 < (SameDelayType ? (MAX_DIMMS_PER_CHANNEL - 1) : MAX_DIMMS_PER_CHANNEL); Dimm1 ++) {
528     if (CsEnabled & (UINT16) (3 << (Dimm1 << 1))) {
529       for (Dimm2 = (SameDelayType ? (Dimm1 + 1) : 0); Dimm2 < MAX_DIMMS_PER_CHANNEL; Dimm2 ++) {
530         if ((CsEnabled & (UINT16) (3 << (Dimm2 << 1)))) {
531           for (ByteLane = 0 ; ByteLane < 8 ; ByteLane++) {
532             // check each byte lane delay pair
533             GDD = (UINT8) (NBPtr->GetTrainDly (NBPtr, TrnDly1, DIMM_BYTE_ACCESS (Dimm1, ByteLane)) >> 5) -
534                   (UINT8) (NBPtr->GetTrainDly (NBPtr, TrnDly2, DIMM_BYTE_ACCESS (Dimm2, ByteLane)) >> 5);
535             // If the 2 delay types to be compared are the same, then keep the absolute difference
536             if (SameDelayType && (GDD < 0)) {
537               GDD = (-GDD);
538             }
539
540             // If CGDD is yet to be initialized, initialize it
541             // Otherwise, keep the largest difference so far
542             CGDD = (!CGDDInit) ? GDD : ((CGDD > GDD) ? CGDD : GDD);
543             if (!CGDDInit) {
544               CGDDInit = TRUE;
545             }
546           }
547         }
548       }
549     }
550   }
551   return CGDD;
552 }
553
554 /* -----------------------------------------------------------------------------*/
555 /**
556  *
557  *   This function calculates the critical delay difference (CDD)
558  *
559  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
560  *     @param[in]       TrnDlyType1 - Type of first Gross Delay parameter
561  *     @param[in]       TrnDlyType2 - Type of second Gross Delay parameter
562  *     @param[in]       SameDimm - CDD of same DIMMs
563  *     @param[in]       DiffDimm - CDD of different DIMMs
564  *
565  *     @return          CDD term - in 1/2 MEMCLK
566  */
567 INT16
568 MemNCalcCDDNb (
569   IN OUT   MEM_NB_BLOCK *NBPtr,
570   IN       TRN_DLY_TYPE TrnDlyType1,
571   IN       TRN_DLY_TYPE TrnDlyType2,
572   IN       BOOLEAN SameDimm,
573   IN       BOOLEAN DiffDimm
574   )
575 {
576   INT16 CDD;
577   INT16 CDDtemp;
578   UINT16 TrnDly1;
579   UINT16 TrnDly2;
580   UINT8 i;
581   UINT8 j;
582   UINT8 ByteLane;
583   UINT16 CsEnabled;
584   BOOLEAN SameDlyType;
585
586   SameDlyType = (BOOLEAN) (TrnDlyType1 == TrnDlyType2);
587   CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
588   CDD = -32000;
589   // If the two delay types compared are the same type, then no need to compare the same
590   // pair twice. Adjustments are made in the upper bound and lower bound of the loop to
591   // handle this.
592   for (i = 0; i < (SameDlyType ? (MAX_DIMMS_PER_CHANNEL - 1) : MAX_DIMMS_PER_CHANNEL); i++) {
593     if ((CsEnabled & (UINT16) (3 << (i << 1))) != 0) {
594       for (j = SameDlyType ? (i + 1) : 0; j < MAX_DIMMS_PER_CHANNEL; j++) {
595         if (((CsEnabled & (UINT16) (3 << (j << 1))) != 0) && ((SameDimm && (i == j)) || (DiffDimm && (i != j)))) {
596           for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
597             /// @todo: Gross delay mask should not be constant.
598             TrnDly1 = GetTrainDlyFromHeapNb (NBPtr, TrnDlyType1, DIMM_BYTE_ACCESS (i, ByteLane)) >> 5;  // Gross delay only
599             TrnDly2 = GetTrainDlyFromHeapNb (NBPtr, TrnDlyType2, DIMM_BYTE_ACCESS (j, ByteLane)) >> 5;  // Gross delay only
600
601             CDDtemp = TrnDly1 - TrnDly2;
602             // If the 2 delay types to be compared are the same, then keep the absolute difference
603             if ((SameDlyType) && (CDDtemp < 0)) {
604               CDDtemp = (-CDDtemp);
605             }
606
607             CDD = (CDD < CDDtemp) ? CDDtemp : CDD;
608           }
609         }
610       }
611     }
612   }
613
614   return CDD;
615 }
616
617 /* -----------------------------------------------------------------------------*/
618 /**
619  *
620  *
621  *   This function gets DQS timing from data saved in heap.
622  *
623  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
624  *     @param[in]   TrnDlyType - type of delay to be set
625  *     @param[in]   Drbn - encoding of Dimm-Rank-Byte-Nibble to be accessed
626  *                  (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
627  *
628  *     @return      value of the target timing.
629  */
630 UINT16
631 GetTrainDlyFromHeapNb (
632   IN OUT   MEM_NB_BLOCK *NBPtr,
633   IN       TRN_DLY_TYPE TrnDlyType,
634   IN       DRBN Drbn
635   )
636 {
637   UINT8 Dimm;
638   UINT8 Byte;
639   UINT16 TrainDly;
640   CH_DEF_STRUCT *ChannelPtr;
641   MEM_TECH_BLOCK *TechPtr;
642
643   Dimm = DRBN_DIMM (Drbn);
644   Byte = DRBN_BYTE (Drbn);
645   ChannelPtr = NBPtr->ChannelPtr;
646   TechPtr = NBPtr->TechPtr;
647
648   ASSERT (Dimm < 4);
649   ASSERT (Byte <= ECC_DLY);
650
651   if (NBPtr->MemPstate == MEMORY_PSTATE1) {
652     switch (TrnDlyType) {
653     case AccessRcvEnDly:
654       TrainDly = ChannelPtr->RcvEnDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
655       break;
656     case AccessWrDqsDly:
657       TrainDly = ChannelPtr->WrDqsDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
658       break;
659     case AccessWrDatDly:
660       TrainDly = ChannelPtr->WrDatDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
661       break;
662     case AccessRdDqsDly:
663       TrainDly = ChannelPtr->RdDqsDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
664       break;
665     default:
666       TrainDly = 0;
667       IDS_ERROR_TRAP;
668     }
669   } else {
670     switch (TrnDlyType) {
671     case AccessRcvEnDly:
672       TrainDly = ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
673       break;
674     case AccessWrDqsDly:
675       TrainDly = ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
676       break;
677     case AccessWrDatDly:
678       TrainDly = ChannelPtr->WrDatDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
679       break;
680     case AccessRdDqsDly:
681       TrainDly = ChannelPtr->RdDqsDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
682       break;
683     default:
684       TrainDly = 0;
685       IDS_ERROR_TRAP;
686     }
687   }
688
689   return TrainDly;
690 }
691
692 /* -----------------------------------------------------------------------------*/
693 /**
694  *
695  *
696  *   This function sets the fixed MTRRs for common legacy ranges.
697  *   It sets TOP_MEM and TOM2 and some variable MTRRs with WB Uncacheable type.
698  *
699  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
700  *
701  *     @return          TRUE - An Error value lower than AGESA_FATAL may have occurred
702  *     @return          FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
703  */
704
705 BOOLEAN
706 MemNCPUMemTypingNb (
707   IN OUT   MEM_NB_BLOCK *NBPtr
708   )
709 {
710   UINT32 Bottom32bIO;
711   UINT32 Bottom40bIO;
712   UINT32 Cache32bTOP;
713   S_UINT64 SMsr;
714
715   MEM_DATA_STRUCT *MemPtr;
716   MEM_PARAMETER_STRUCT *RefPtr;
717   RefPtr = NBPtr->RefPtr;
718   MemPtr = NBPtr->MemPtr;
719
720   //
721   //======================================================================
722   // Set temporary top of memory from Node structure data.
723   // Adjust temp top of memory down to accommodate 32-bit IO space.
724   //======================================================================
725   //Bottom40bIO=top of memory, right justified 16 bits  (defines dram versus IO space type)
726   //Bottom32bIO=sub 4GB top of memory, right justified 16 bits (defines dram versus IO space type)
727   //Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 16 bits
728   //
729   if (RefPtr->HoleBase != 0) {
730     Bottom32bIO = RefPtr->HoleBase;
731   } else if (RefPtr->BottomIo != 0) {
732     Bottom32bIO = (UINT32)RefPtr->BottomIo << (24 - 16);
733   } else {
734     Bottom32bIO = (UINT32)1 << (24 - 16);
735   }
736
737   Cache32bTOP = RefPtr->SysLimit + 1;
738   if (Cache32bTOP < _4GB_RJ16) {
739     Bottom40bIO = 0;
740     if (Bottom32bIO >= Cache32bTOP) {
741       Bottom32bIO = Cache32bTOP;
742     }
743   } else {
744     Bottom40bIO = Cache32bTOP;
745   }
746
747   Cache32bTOP = Bottom32bIO;
748
749
750   //
751   //======================================================================
752   // Set default values for CPU registers
753   //======================================================================
754   //
755   LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
756   SMsr.lo |= 0x1C0000;                // turn on modification enable bit and
757                                       // mtrr enable bits
758   LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
759
760   SMsr.lo = SMsr.hi = 0x1E1E1E1E;
761   LibAmdMsrWrite (0x250, (UINT64 *)&SMsr, &MemPtr->StdHeader);      // 0 - 512K = WB Mem
762   LibAmdMsrWrite (0x258, (UINT64 *)&SMsr, &MemPtr->StdHeader);      // 512K - 640K = WB Mem
763
764   //
765   //======================================================================
766   // Set variable MTRR values
767   //======================================================================
768   //
769   MemNSetMTRRrangeNb (NBPtr, 0, &Cache32bTOP, 0x200, 6);
770
771   RefPtr->Sub4GCacheTop = Cache32bTOP << 16;
772
773   //
774   //======================================================================
775   // Set TOP_MEM and TOM2 CPU registers
776   //======================================================================
777   //
778   SMsr.hi = Bottom32bIO >> (32 - 16);
779   SMsr.lo = Bottom32bIO << 16;
780   LibAmdMsrWrite (TOP_MEM, (UINT64 *)&SMsr, &MemPtr->StdHeader);
781   IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM:  %08x0000\n", Bottom32bIO);
782
783   if (Bottom40bIO) {
784     SMsr.hi = Bottom40bIO >> (32 - 16);
785     SMsr.lo = Bottom40bIO << 16;
786   } else {
787     SMsr.hi = 0;
788     SMsr.lo = 0;
789   }
790   LibAmdMsrWrite (TOP_MEM2, (UINT64 *)&SMsr, &MemPtr->StdHeader);
791
792   LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
793   if (Bottom40bIO) {
794     IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM2: %08x0000\n", Bottom40bIO);
795     IDS_HDT_CONSOLE (MEM_FLOW, "Sub1THoleBase: %08x0000\n", RefPtr->Sub1THoleBase);
796     // Enable TOM2
797     SMsr.lo |= 0x00600000;
798   } else {
799     // Disable TOM2
800     SMsr.lo &= ~0x00600000;
801   }
802   SMsr.lo &= 0xFFF7FFFF; // turn off modification enable bit
803   LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
804
805   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
806 }
807
808 /* -----------------------------------------------------------------------------*/
809 /**
810  *
811  *
812  *   This function runs on the BSP only, it sets the fixed MTRRs for common legacy ranges.
813  *   It sets TOP_MEM and TOM2 and some variable MTRRs with WB Uncacheable type.
814  *
815  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
816  *
817  */
818
819 VOID
820 MemNUMAMemTypingNb (
821   IN OUT   MEM_NB_BLOCK *NBPtr
822   )
823 {
824   UINT32 Bottom32bIO;
825   UINT32 Bottom32bUMA;
826   UINT32 Cache32bTOP;
827   UINT32 Value32;
828   UINT8 BitCount;
829   UINT8 i;
830
831   MEM_PARAMETER_STRUCT *RefPtr;
832   RefPtr = NBPtr->RefPtr;
833   BitCount = 0;
834   //
835   //======================================================================
836   // Adjust temp top of memory down to accommodate UMA memory start
837   //======================================================================
838   // Bottom32bIO=sub 4GB top of memory, right justified 16 bits (defines dram versus IO space type)
839   // Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 16 bits
840   //
841   Bottom32bIO = RefPtr->Sub4GCacheTop >> 16;
842   Bottom32bUMA = RefPtr->UmaBase;
843
844   if (Bottom32bUMA < Bottom32bIO) {
845     Cache32bTOP = Bottom32bUMA;
846     RefPtr->Sub4GCacheTop = Bottom32bUMA << 16;
847     //
848     //======================================================================
849     //Set variable MTRR values
850     //======================================================================
851     //
852     Value32 = Cache32bTOP;
853     //Pre-check the bit count of bottom Uma to see if it is potentially running out of Mtrr while typing.
854     while (Value32 != 0) {
855       i = LibAmdBitScanForward (Value32);
856       Value32 &= ~ (1 << i);
857       BitCount++;
858     }
859
860     if (BitCount > 5) {
861       NBPtr->RefPtr->GStatus[GsbMTRRshort] = TRUE;
862       MemNSetMTRRUmaRegionUCNb (NBPtr, &Cache32bTOP, &Bottom32bIO);
863     } else {
864       MemNSetMTRRrangeNb (NBPtr, 0, &Cache32bTOP, 0x200, 6);
865     }
866   }
867 }
868
869 /* -----------------------------------------------------------------------------*/
870 /**
871  *
872  *
873  *  Program MTRRs to describe given range as given cache type.  Use MTRR pairs
874  *  starting with the given MTRRphys Base address, and use as many as is
875  *  required up to (excluding) MSR 020C, which is reserved for OS.
876  *
877  *  "Limit" in the context of this procedure is not the numerically correct
878  *  limit, but rather the Last address+1, for purposes of coding efficiency
879  *  and readability.  Size of a region is then Limit-Base.
880  *
881  *  1. Size of each range must be a power of two
882  *  2. Each range must be naturally aligned (Base is same as size)
883  *
884  *  There are two code paths: the ascending path and descending path (analogous
885  *  to bsf and bsr), where the next limit is a function of the next set bit in
886  *  a forward or backward sequence of bits (as a function of the Limit).  We
887  *  start with the ascending path, to ensure that regions are naturally aligned,
888  *  then we switch to the descending path to maximize MTRR usage efficiency.
889  *  Base=0 is a special case where we start with the descending path.
890  *  Correct Mask for region is 2comp(Size-1)-1,
891  *  which is 2comp(Limit-Base-1)-1 *
892  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
893  *     @param[in]     Base - Base address[47:16] of specified range.
894  *     @param[in]     *LimitPtr - Limit address[47:16] of specified range.
895  *     @param[in]     MtrrAddr - address of var MTRR pair to start using.
896  *     @param[in]     MtrrType - Cache type for the range.
897  *
898  *     @return      TRUE - No failure occurred
899  *     @return      FALSE - Failure occurred because run out of variable-size MTRRs before completion.
900  */
901
902 BOOLEAN
903 STATIC
904 MemNSetMTRRrangeNb (
905   IN OUT   MEM_NB_BLOCK *NBPtr,
906   IN       UINT32 Base,
907   IN OUT   UINT32 *LimitPtr,
908   IN       UINT32 MtrrAddr,
909   IN       UINT8 MtrrType
910   )
911 {
912   S_UINT64 SMsr;
913   UINT32 CurBase;
914   UINT32 CurLimit;
915   UINT32 CurSize;
916   UINT32 CurAddr;
917   UINT32 Value32;
918
919   CurBase = Base;
920   CurLimit = *LimitPtr;
921   CurAddr = MtrrAddr;
922
923   while ((CurAddr >= 0x200) && (CurAddr < 0x20A) && (CurBase < *LimitPtr)) {
924     CurSize = CurLimit = (UINT32)1 << LibAmdBitScanForward (CurBase);
925     CurLimit += CurBase;
926     if ((CurBase == 0) || (*LimitPtr < CurLimit)) {
927       CurLimit = *LimitPtr - CurBase;
928       CurSize = CurLimit = (UINT32)1 << LibAmdBitScanReverse (CurLimit);
929       CurLimit += CurBase;
930     }
931
932     // prog. MTRR with current region Base
933     SMsr.lo = (CurBase << 16) | (UINT32)MtrrType;
934     SMsr.hi = CurBase >> (32 - 16);
935     LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
936
937     // prog. MTRR with current region Mask
938     CurAddr++;                              // other half of MSR pair
939     Value32 = CurSize - (UINT32)1;
940     Value32 = ~Value32;
941     SMsr.hi = (Value32 >> (32 - 16)) & NBPtr->VarMtrrHiMsk;
942     SMsr.lo = (Value32 << 16) | ((UINT32)1 << MTRR_VALID);
943     LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
944
945     CurBase = CurLimit;
946     CurAddr++;                              // next MSR pair
947   }
948
949   if (CurLimit < *LimitPtr) {
950     // Announce failure
951     *LimitPtr = CurLimit;
952     IDS_ERROR_TRAP;
953   }
954
955   while ((CurAddr >= 0x200) && (CurAddr < 0x20C)) {
956     SMsr.lo = SMsr.hi = 0;
957     LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
958     CurAddr++;
959   }
960
961   return TRUE;
962 }
963
964 /* -----------------------------------------------------------------------------*/
965 /**
966  *
967  *
968  *     Program one MTRR to describe Uma region as UC cache type if we detect running out of
969  *     Mtrr circumstance.
970  *
971  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
972  *     @param[in]     *BasePtr - Base address[47:24] of specified range.
973  *     @param[in]     *LimitPtr - Limit address[47:24] of specified range.
974  *
975  *     @return          TRUE -  No fatal error occurs.
976  *     @return          FALSE - Fatal error occurs.
977  */
978 BOOLEAN
979 MemNSetMTRRUmaRegionUCNb  (
980   IN OUT   MEM_NB_BLOCK *NBPtr,
981   IN       UINT32 *BasePtr,
982   IN OUT   UINT32 *LimitPtr
983   )
984 {
985   S_UINT64 SMsr;
986   UINT32 Mtrr;
987   UINT32 Size;
988   UINT32 Value32;
989
990   Size = *LimitPtr - *BasePtr;
991   // Check if Size is a power of 2
992   if ((Size & (Size - 1)) != 0) {
993     for (Mtrr = 0x200; Mtrr < 0x20A; Mtrr += 2) {
994       LibAmdMsrRead (Mtrr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
995       if ((SMsr.lo & ((UINT32) 1 << 11)) == 0) {
996         MemNSetMTRRrangeNb (NBPtr, *BasePtr, LimitPtr, Mtrr, 0);
997         break;
998       }
999     }
1000     if (Mtrr == 0x20A) {
1001       // Run out of MTRRs
1002       IDS_ERROR_TRAP;
1003     }
1004   } else {
1005     Mtrr = 0x20A; //Reserved pair of MTRR for UMA region.
1006
1007     // prog. MTRR with current region Base
1008     SMsr.lo = *BasePtr  << 16;
1009     SMsr.hi = *BasePtr >> (32 - 16);
1010     LibAmdMsrWrite (Mtrr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1011
1012     // prog. MTRR with current region Mask
1013     Mtrr++;                              // other half of MSR pair
1014     Value32 = Size - (UINT32)1;
1015     Value32 = ~Value32;
1016     SMsr.hi = (Value32 >> (32 - 16)) & NBPtr->VarMtrrHiMsk;
1017     SMsr.lo = (Value32 << 16) | ((UINT32)1 << MTRR_VALID);
1018     LibAmdMsrWrite (Mtrr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1019   }
1020
1021   return TRUE;
1022 }
1023
1024 /* -----------------------------------------------------------------------------*/
1025 /**
1026  *
1027  *
1028  *     Report the Uma size that is going to be allocated.
1029  *
1030  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1031  *
1032  *     @return          Uma size [31:0] = Addr [47:16]
1033  */
1034 UINT32
1035 MemNGetUmaSizeNb (
1036   IN OUT   MEM_NB_BLOCK *NBPtr
1037   )
1038 {
1039   return 0;
1040 }
1041
1042 /* -----------------------------------------------------------------------------*/
1043 /**
1044  *
1045  *     This function allocates 16MB of memory for C6 storage when it is requested to be enabled
1046  *
1047  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1048  *
1049  */
1050 VOID
1051 MemNAllocateC6StorageClientNb (
1052   IN OUT   MEM_NB_BLOCK *NBPtr
1053   )
1054 {
1055   UINT32 SysLimit;
1056
1057   if (IsFeatureEnabled (C6Cstate, NBPtr->MemPtr->PlatFormConfig, &(NBPtr->MemPtr->StdHeader))) {
1058     SysLimit = NBPtr->RefPtr->SysLimit;
1059     SysLimit -= _16MB_RJ16;
1060
1061     // Set Dram Limit
1062     NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1063     NBPtr->RefPtr->SysLimit = SysLimit;
1064     MemNSetBitFieldNb (NBPtr, BFDramLimitReg0, ((SysLimit << 8) & 0xFFFF0000));
1065
1066     // Set TOPMEM and MTRRs
1067     MemNC6AdjustMSRs (NBPtr);
1068
1069     // Set C6Base
1070     MemNSetBitFieldNb (NBPtr, BFC6Base, (SysLimit + 1) >> (24 - 16));
1071
1072     // C6DramLock will be set in FinalizeMCT
1073   }
1074 }
1075
1076 /* -----------------------------------------------------------------------------*/
1077 /**
1078  *
1079  *     This function allocates 16MB of memory for C6 storage when it is requested to be enabled
1080  *
1081  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1082  *
1083  */
1084 VOID
1085 MemNAllocateC6StorageUnb (
1086   IN OUT   MEM_NB_BLOCK *NBPtr
1087   )
1088 {
1089   UINT8  Node;
1090   UINT32 SysLimit;
1091   UINT32 DramLimitReg;
1092
1093   if (NBPtr->SharedPtr->C6Enabled || IsFeatureEnabled (C6Cstate, NBPtr->MemPtr->PlatFormConfig, &(NBPtr->MemPtr->StdHeader))) {
1094
1095     SysLimit = NBPtr->RefPtr->SysLimit;
1096
1097     // Calculate new SysLimit
1098     if (!NBPtr->SharedPtr->C6Enabled) {
1099       if (NBPtr->SharedPtr->NodeIntlv.NodeCnt >= 2) {
1100         // Node Interleave is enabled, system memory available is reduced by 16MB * number of nodes
1101         SysLimit -= _16MB_RJ16 * NBPtr->SharedPtr->NodeIntlv.NodeCnt;
1102       } else {
1103         // Otherwise, system memory available is reduced by 16MB
1104         SysLimit -= _16MB_RJ16;
1105       }
1106       NBPtr->RefPtr->SysLimit = SysLimit;
1107       NBPtr->SharedPtr->C6Enabled = TRUE;
1108
1109       // Set TOPMEM and MTRRs (only need to be done once for BSC)
1110       MemNC6AdjustMSRs (NBPtr);
1111     }
1112
1113     // Set Dram Limit
1114     if (NBPtr->SharedPtr->NodeIntlv.NodeCnt >= 2) {
1115       for (Node = 0; Node < NBPtr->NodeCount; Node++) {
1116         DramLimitReg = MemNGetBitFieldNb (NBPtr, BFDramLimitReg0 + Node);
1117         if ((DramLimitReg & 0xFFFF0000) != 0) {
1118           MemNSetBitFieldNb (NBPtr, BFDramLimitReg0 + Node, ((SysLimit << 8) & 0xFFFF0000) | (DramLimitReg & 0xFFFF));
1119           MemNSetBitFieldNb (NBPtr, BFDramLimitHiReg0 + Node, SysLimit >> 24);
1120         }
1121       }
1122       // Node Interleave is enabled, CoreStateSaveDestNode points to its own node
1123       MemNSetBitFieldNb (NBPtr, BFCoreStateSaveDestNode, NBPtr->Node);
1124       NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1125     } else {
1126       DramLimitReg = MemNGetBitFieldNb (NBPtr, BFDramLimitReg0 + NBPtr->SharedPtr->TopNode) & 0x0000FFFF;
1127       MemNSetBitFieldNb (NBPtr, BFDramLimitReg0 + NBPtr->SharedPtr->TopNode, ((SysLimit << 8) & 0xFFFF0000) | DramLimitReg);
1128       MemNSetBitFieldNb (NBPtr, BFDramLimitHiReg0 + NBPtr->SharedPtr->TopNode, SysLimit >> 24);
1129
1130       // Node Interleave is not enabled, CoreStateSaveDestNode points to the node that contains top memory
1131       MemNSetBitFieldNb (NBPtr, BFCoreStateSaveDestNode, NBPtr->SharedPtr->TopNode);
1132
1133       if (NBPtr->Node == NBPtr->SharedPtr->TopNode) {
1134         NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1135       }
1136     }
1137
1138     // Set BFCC6SaveEn
1139     MemNSetBitFieldNb (NBPtr, BFCC6SaveEn, 1);
1140
1141     // LockDramCfg will be set in FinalizeMCT
1142   }
1143 }
1144
1145
1146 /* -----------------------------------------------------------------------------*/
1147 /**
1148  *
1149  *     This function readjusts TOPMEM and MTRRs after allocating storage for C6
1150  *
1151  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1152  *
1153  */
1154 VOID
1155 MemNC6AdjustMSRs (
1156   IN OUT   MEM_NB_BLOCK *NBPtr
1157   )
1158 {
1159   UINT32 SysLimit;
1160   UINT32 CurAddr;
1161   S_UINT64 SMsr;
1162
1163   SysLimit = NBPtr->RefPtr->SysLimit + 1;
1164   SMsr.hi = SysLimit >> (32 - 16);
1165   SMsr.lo = SysLimit << 16;
1166   if (SysLimit < _4GB_RJ16) {
1167     LibAmdMsrWrite (TOP_MEM, (UINT64 *)&SMsr, &(NBPtr->MemPtr->StdHeader));
1168     IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM:  %08x0000\n", SysLimit);
1169     // If there is no UMA buffer, then set top of cache and MTRR.
1170     // Otherwise, top of cache and MTRR will be set when UMA buffer is set up.
1171     if (NBPtr->RefPtr->UmaMode == UMA_NONE) {
1172       NBPtr->RefPtr->Sub4GCacheTop = (SysLimit << 16);
1173       // Find unused MTRR to set C6 region to UC
1174       for (CurAddr = 0x200; CurAddr < 0x20C; CurAddr += 2) {
1175         LibAmdMsrRead (CurAddr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1176         if ((SMsr.lo & ((UINT32) 1 << 11)) == 0) {
1177           // Set region base as TOM
1178           SMsr.hi = SysLimit >> (32 - 16);
1179           SMsr.lo = SysLimit << 16;
1180           LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1181
1182           // set region mask to 16MB
1183           SMsr.hi = NBPtr->VarMtrrHiMsk;
1184           SMsr.lo = 0xFF000800;
1185           LibAmdMsrWrite (CurAddr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1186
1187           break;
1188         }
1189       }
1190     }
1191   } else {
1192     LibAmdMsrWrite (TOP_MEM2, (UINT64 *)&SMsr, &(NBPtr->MemPtr->StdHeader));
1193     IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM2: %08x0000\n", SysLimit);
1194   }
1195 }
1196
1197 /* -----------------------------------------------------------------------------*/
1198 /**
1199  *
1200  *     Family-specific hook to override the DdrMaxRate value for families with a
1201  *     non-GH-compatible encoding for BFDdrMaxRate
1202  *
1203  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1204  *     @param[in,out]   *DdrMaxRate - Void pointer to DdrMaxRate.  Used as INT16.
1205  *
1206  *     @return          TRUE
1207  *
1208  */
1209 BOOLEAN
1210 MemNGetMaxDdrRateUnb (
1211   IN OUT   MEM_NB_BLOCK *NBPtr,
1212   IN       VOID *DdrMaxRate
1213   )
1214 {
1215   UINT8 DdrMaxRateEncoded;
1216
1217   DdrMaxRateEncoded = (UINT8) MemNGetBitFieldNb (NBPtr, BFDdrMaxRate);
1218
1219   if (DdrMaxRateEncoded == 0) {
1220     * (UINT16 *) DdrMaxRate = UNSUPPORTED_DDR_FREQUENCY;
1221   } else {
1222     * (UINT16 *) DdrMaxRate = MemNGetMemClkFreqUnb (NBPtr, DdrMaxRateEncoded);
1223   }
1224   return TRUE;
1225 }
1226
1227 /* -----------------------------------------------------------------------------*/
1228 /**
1229  *
1230  *
1231  *      This function performs the action after save/restore execution
1232  *
1233  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
1234  *     @param[in,out]  OptParam   - Optional parameter
1235  *
1236  *     @return    TRUE
1237  *
1238  */
1239
1240 BOOLEAN
1241 MemNAfterSaveRestoreUnb (
1242   IN OUT   MEM_NB_BLOCK *NBPtr,
1243   IN OUT   VOID *OptParam
1244   )
1245 {
1246   // Sync. up DctCfgSel value with NBPtr->Dct
1247   MemNSetBitFieldNb (NBPtr, BFDctCfgSel, NBPtr->Dct);
1248
1249   return TRUE;
1250 }
1251
1252 /* -----------------------------------------------------------------------------*/
1253 /**
1254  *
1255  *
1256  *      This function performs the action before and after excluding dimms on CNB
1257  *
1258  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
1259  *     @param[in,out]  *IsBefore   - If the function is called before excluding dimms
1260  *
1261  *     @return    TRUE
1262  *
1263  */
1264
1265 BOOLEAN
1266 MemNBfAfExcludeDimmClientNb (
1267   IN OUT   MEM_NB_BLOCK *NBPtr,
1268   IN OUT   VOID *IsBefore
1269   )
1270 {
1271   if (*(BOOLEAN *) IsBefore == TRUE) {
1272     NBPtr->BrdcstSet (NBPtr, BFEnterSelfRef, 1);
1273     NBPtr->PollBitField (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1274   } else {
1275     NBPtr->BrdcstSet (NBPtr, BFExitSelfRef, 1);
1276     NBPtr->PollBitField (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1277   }
1278
1279   return TRUE;
1280 }
1281
1282 /*----------------------------------------------------------------------------
1283  *                              LOCAL FUNCTIONS
1284  *
1285  *----------------------------------------------------------------------------
1286  */