7 * Northbridge Common MCT supporting functions
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/NB)
12 * @e \$Revision: 58425 $ @e \$Date: 2011-08-29 08:29:04 -0600 (Mon, 29 Aug 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
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.
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.
42 * ***************************************************************************
47 *----------------------------------------------------------------------------
50 *----------------------------------------------------------------------------
62 #include "OptionMemory.h"
63 #include "PlatformMemoryConfiguration.h"
64 #include "GeneralServices.h"
65 #include "cpuFeatures.h"
71 #define FILECODE PROC_MEM_NB_MNMCT_FILECODE
72 /*----------------------------------------------------------------------------
73 * DEFINITIONS AND MACROS
75 *----------------------------------------------------------------------------
77 #define _16MB_RJ16 0x0100
79 /*----------------------------------------------------------------------------
80 * TYPEDEFS AND STRUCTURES
82 *----------------------------------------------------------------------------
85 /*----------------------------------------------------------------------------
86 * PROTOTYPES OF LOCAL FUNCTIONS
88 *----------------------------------------------------------------------------
93 IN OUT MEM_NB_BLOCK *NBPtr,
95 IN OUT UINT32 *LimitPtr,
100 /*----------------------------------------------------------------------------
103 *----------------------------------------------------------------------------
105 extern BUILD_OPT_CFG UserOptions;
107 /* -----------------------------------------------------------------------------*/
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.
115 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
120 MemNSyncTargetSpeedNb (
121 IN OUT MEM_NB_BLOCK *NBPtr
124 CONST UINT16 DdrMaxRateTab[] = {
125 UNSUPPORTED_DDR_FREQUENCY,
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;
145 ASSERT (NBPtr->DctCount <= sizeof (Mode));
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);
155 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
156 MemNSwitchDCTNb (NBPtr, Dct);
157 DCTPtr = NBPtr->DCTPtr;
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];
187 ProposedFreq = UserOptions.CfgMemoryBusFrequencyLimit;
188 if (Mode[Dct] == TIMING_MODE_LIMITED) {
189 if (MemClkFreq < ProposedFreq) {
190 ProposedFreq = MemClkFreq;
192 } else if (Mode[Dct] == TIMING_MODE_SPECIFIC) {
193 ProposedFreq = MemClkFreq;
196 if (Mode[Dct] == TIMING_MODE_SPECIFIC) {
197 DCTPtr->Timings.TargetSpeed = (UINT16) ProposedFreq;
200 if (DCTPtr->Timings.TargetSpeed > ProposedFreq) {
201 DCTPtr->Timings.TargetSpeed = (UINT16) ProposedFreq;
205 NBPtr->MemNCapSpeedBatteryLife (NBPtr);
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);
212 DCTPtr->Timings.TargetSpeed = DdrMaxRate;
215 IDS_SKIP_HOOK (IDS_POR_MEM_FREQ, NBPtr, &NBPtr->MemPtr->StdHeader) {
217 //Call Platform POR Frequency Override
219 if (!MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SPEEDLIMIT, ALL_DIMMS)) {
221 // Get the POR frequency limit
223 NBPtr->PsPtr->MemPGetPORFreqLimit (NBPtr);
226 IDS_OPTION_HOOK (IDS_STRETCH_FREQUENCY_LIMIT, NBPtr, &NBPtr->MemPtr->StdHeader);
228 if (MinSpeed > DCTPtr->Timings.TargetSpeed) {
229 MinSpeed = DCTPtr->Timings.TargetSpeed;
234 if (MinSpeed == DDR667_FREQUENCY) {
235 NBPtr->StartupSpeed = DDR667_FREQUENCY;
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;
245 /* -----------------------------------------------------------------------------*/
249 * This function waits for all DCTs to be ready
251 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
253 * @return TRUE - No fatal error occurs.
254 * @return FALSE - Fatal error occurs.
258 MemNSyncDctsReadyNb (
259 IN OUT MEM_NB_BLOCK *NBPtr
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);
268 // Wait 750 us for the phy compensation engine to reinitialize.
269 MemUWait10ns (75000, NBPtr->MemPtr);
271 MemNSyncAddrMapToAllNodesNb (NBPtr);
272 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
275 /* -----------------------------------------------------------------------------*/
279 * This function create the HT memory map
281 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
283 * @return TRUE - No fatal error occurs.
284 * @return FALSE - Fatal error occurs.
289 IN OUT MEM_NB_BLOCK *NBPtr
294 UINT32 DctSelBaseAddr;
297 MEM_PARAMETER_STRUCT *RefPtr;
300 RefPtr = NBPtr->RefPtr;
301 MCTPtr = NBPtr->MCTPtr;
303 // Physical addresses in this function are right adjusted by 16 bits ([47:16])
304 // They are BottomIO, HoleOffset, DctSelBaseAddr, NodeSysBase, NodeSysLimit.
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;
311 if (!MCTPtr->GangedMode) {
312 DctSelBaseAddr = MCTPtr->DctData[0].Timings.DctMemSize;
317 if (MCTPtr->NodeMemSize) {
318 NodeSysBase = NBPtr->SharedPtr->CurrentNodeSysBase;
319 NodeSysLimit = NodeSysBase + MCTPtr->NodeMemSize - 1;
320 DctSelBaseAddr += NodeSysBase;
322 if ((NBPtr->IsSupported[ForceEnMemHoleRemapping]) || (RefPtr->MemHoleRemapping)) {
323 if ((NodeSysBase < BottomIo) && (NodeSysLimit >= BottomIo)) {
325 MCTPtr->Status[SbHWHole] = TRUE;
326 RefPtr->GStatus[GsbHWHole] = TRUE;
327 MCTPtr->NodeHoleBase = BottomIo;
328 RefPtr->HoleBase = BottomIo;
330 HoleOffset = _4GB_RJ16 - BottomIo;
332 NodeSysLimit += HoleOffset;
334 if ((DctSelBaseAddr > 0) && (DctSelBaseAddr < BottomIo)) {
335 HoleOffset += DctSelBaseAddr;
337 if (DctSelBaseAddr >= BottomIo) {
338 DctSelBaseAddr += HoleOffset;
340 HoleOffset += NodeSysBase;
343 MemNSetBitFieldNb (NBPtr, BFDramHoleBase, BottomIo >> 8);
344 MemNSetBitFieldNb (NBPtr, BFDramHoleOffset, HoleOffset >> 7);
345 MemNSetBitFieldNb (NBPtr, BFDramHoleValid, 1);
347 } else if (NodeSysBase == BottomIo) {
349 MCTPtr->Status[SbSWNodeHole] = TRUE;
350 RefPtr->GStatus[GsbSpIntRemapHole] = TRUE;
351 RefPtr->GStatus[GsbSoftHole] = TRUE;
353 RefPtr->HoleBase = NodeSysBase;
354 DctSelBaseAddr = _4GB_RJ16 + (DctSelBaseAddr - NodeSysBase);
355 NodeSysLimit = _4GB_RJ16 + (NodeSysLimit - NodeSysBase);
356 NodeSysBase = _4GB_RJ16;
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;
365 if (RefPtr->LimitMemoryToBelow1Tb) {
366 // Flag to undo 1TB hoisting after training
367 NBPtr->SharedPtr->UndoHoistingAbove1TB = TRUE;
372 // No Remapping. Normal Contiguous mapping
375 // No Remapping. Normal Contiguous mapping
378 if (NBPtr->IsSupported[Check1GAlign]) {
379 if (UserOptions.CfgNodeMem1GBAlign) {
380 NBPtr->MemPNodeMemBoundaryNb (NBPtr, (UINT32 *)&NodeSysLimit);
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);
390 NBPtr->SharedPtr->TopNode = NBPtr->Node;
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;
396 MemNSetBitFieldNb (NBPtr, BFDramBaseAddr, NodeSysBase >> (27 - 16));
397 MemNSetBitFieldNb (NBPtr, BFDramLimitAddr, NodeSysLimit >> (27 - 16));
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);
406 NBPtr->SharedPtr->CurrentNodeSysBase = (NodeSysLimit + 1) & 0xFFFFFFF0;
408 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
411 /* -----------------------------------------------------------------------------*/
415 * Program system DRAM map to this node
417 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
422 MemNSyncAddrMapToAllNodesNb (
423 IN OUT MEM_NB_BLOCK *NBPtr
430 MEM_PARAMETER_STRUCT *RefPtr;
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) {
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);
448 if (RefPtr->GStatus[GsbHWHole]) {
449 MemNSetBitFieldNb (NBPtr, BFDramMemHoistValid, 1);
450 MemNSetBitFieldNb (NBPtr, BFDramHoleBase, (RefPtr->HoleBase >> 8));
454 NBPtr->FamilySpecificHook[InitExtMMIOAddr] (NBPtr, NULL);
457 /* -----------------------------------------------------------------------------*/
461 * This function enables power down mode
463 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
469 IN OUT MEM_NB_BLOCK *NBPtr
472 MEM_PARAMETER_STRUCT *RefPtr;
475 RefPtr = NBPtr->RefPtr;
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));
483 MemNSetBitFieldNb (NBPtr, BFPowerDownMode, 1);
488 /* -----------------------------------------------------------------------------*/
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.
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
500 * @return The largest difference between the largest and smallest
501 * of the two Gross delay types within a single bytelane
504 MemNGetOptimalCGDDNb (
505 IN OUT MEM_NB_BLOCK *NBPtr,
506 IN TRN_DLY_TYPE TrnDly1,
507 IN TRN_DLY_TYPE TrnDly2
517 BOOLEAN SameDelayType;
521 SameDelayType = (BOOLEAN) (TrnDly1 == TrnDly2);
522 CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
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
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)) {
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);
554 /* -----------------------------------------------------------------------------*/
557 * This function calculates the critical delay difference (CDD)
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
565 * @return CDD term - in 1/2 MEMCLK
569 IN OUT MEM_NB_BLOCK *NBPtr,
570 IN TRN_DLY_TYPE TrnDlyType1,
571 IN TRN_DLY_TYPE TrnDlyType2,
586 SameDlyType = (BOOLEAN) (TrnDlyType1 == TrnDlyType2);
587 CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
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
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
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);
607 CDD = (CDD < CDDtemp) ? CDDtemp : CDD;
617 /* -----------------------------------------------------------------------------*/
621 * This function gets DQS timing from data saved in heap.
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
628 * @return value of the target timing.
631 GetTrainDlyFromHeapNb (
632 IN OUT MEM_NB_BLOCK *NBPtr,
633 IN TRN_DLY_TYPE TrnDlyType,
640 CH_DEF_STRUCT *ChannelPtr;
641 MEM_TECH_BLOCK *TechPtr;
643 Dimm = DRBN_DIMM (Drbn);
644 Byte = DRBN_BYTE (Drbn);
645 ChannelPtr = NBPtr->ChannelPtr;
646 TechPtr = NBPtr->TechPtr;
649 ASSERT (Byte <= ECC_DLY);
651 if (NBPtr->MemPstate == MEMORY_PSTATE1) {
652 switch (TrnDlyType) {
654 TrainDly = ChannelPtr->RcvEnDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
657 TrainDly = ChannelPtr->WrDqsDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
660 TrainDly = ChannelPtr->WrDatDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
663 TrainDly = ChannelPtr->RdDqsDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
670 switch (TrnDlyType) {
672 TrainDly = ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
675 TrainDly = ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
678 TrainDly = ChannelPtr->WrDatDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
681 TrainDly = ChannelPtr->RdDqsDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
692 /* -----------------------------------------------------------------------------*/
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.
699 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
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
707 IN OUT MEM_NB_BLOCK *NBPtr
715 MEM_DATA_STRUCT *MemPtr;
716 MEM_PARAMETER_STRUCT *RefPtr;
717 RefPtr = NBPtr->RefPtr;
718 MemPtr = NBPtr->MemPtr;
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
729 if (RefPtr->HoleBase != 0) {
730 Bottom32bIO = RefPtr->HoleBase;
731 } else if (RefPtr->BottomIo != 0) {
732 Bottom32bIO = (UINT32)RefPtr->BottomIo << (24 - 16);
734 Bottom32bIO = (UINT32)1 << (24 - 16);
737 Cache32bTOP = RefPtr->SysLimit + 1;
738 if (Cache32bTOP < _4GB_RJ16) {
740 if (Bottom32bIO >= Cache32bTOP) {
741 Bottom32bIO = Cache32bTOP;
744 Bottom40bIO = Cache32bTOP;
747 Cache32bTOP = Bottom32bIO;
751 //======================================================================
752 // Set default values for CPU registers
753 //======================================================================
755 LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
756 SMsr.lo |= 0x1C0000; // turn on modification enable bit and
758 LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
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
765 //======================================================================
766 // Set variable MTRR values
767 //======================================================================
769 MemNSetMTRRrangeNb (NBPtr, 0, &Cache32bTOP, 0x200, 6);
771 RefPtr->Sub4GCacheTop = Cache32bTOP << 16;
774 //======================================================================
775 // Set TOP_MEM and TOM2 CPU registers
776 //======================================================================
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);
784 SMsr.hi = Bottom40bIO >> (32 - 16);
785 SMsr.lo = Bottom40bIO << 16;
790 LibAmdMsrWrite (TOP_MEM2, (UINT64 *)&SMsr, &MemPtr->StdHeader);
792 LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
794 IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM2: %08x0000\n", Bottom40bIO);
795 IDS_HDT_CONSOLE (MEM_FLOW, "Sub1THoleBase: %08x0000\n", RefPtr->Sub1THoleBase);
797 SMsr.lo |= 0x00600000;
800 SMsr.lo &= ~0x00600000;
802 SMsr.lo &= 0xFFF7FFFF; // turn off modification enable bit
803 LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
805 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
808 /* -----------------------------------------------------------------------------*/
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.
815 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
821 IN OUT MEM_NB_BLOCK *NBPtr
831 MEM_PARAMETER_STRUCT *RefPtr;
832 RefPtr = NBPtr->RefPtr;
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
841 Bottom32bIO = RefPtr->Sub4GCacheTop >> 16;
842 Bottom32bUMA = RefPtr->UmaBase;
844 if (Bottom32bUMA < Bottom32bIO) {
845 Cache32bTOP = Bottom32bUMA;
846 RefPtr->Sub4GCacheTop = Bottom32bUMA << 16;
848 //======================================================================
849 //Set variable MTRR values
850 //======================================================================
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);
861 NBPtr->RefPtr->GStatus[GsbMTRRshort] = TRUE;
862 MemNSetMTRRUmaRegionUCNb (NBPtr, &Cache32bTOP, &Bottom32bIO);
864 MemNSetMTRRrangeNb (NBPtr, 0, &Cache32bTOP, 0x200, 6);
869 /* -----------------------------------------------------------------------------*/
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.
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.
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)
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.
898 * @return TRUE - No failure occurred
899 * @return FALSE - Failure occurred because run out of variable-size MTRRs before completion.
905 IN OUT MEM_NB_BLOCK *NBPtr,
907 IN OUT UINT32 *LimitPtr,
920 CurLimit = *LimitPtr;
923 while ((CurAddr >= 0x200) && (CurAddr < 0x20A) && (CurBase < *LimitPtr)) {
924 CurSize = CurLimit = (UINT32)1 << LibAmdBitScanForward (CurBase);
926 if ((CurBase == 0) || (*LimitPtr < CurLimit)) {
927 CurLimit = *LimitPtr - CurBase;
928 CurSize = CurLimit = (UINT32)1 << LibAmdBitScanReverse (CurLimit);
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);
937 // prog. MTRR with current region Mask
938 CurAddr++; // other half of MSR pair
939 Value32 = CurSize - (UINT32)1;
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);
946 CurAddr++; // next MSR pair
949 if (CurLimit < *LimitPtr) {
951 *LimitPtr = CurLimit;
955 while ((CurAddr >= 0x200) && (CurAddr < 0x20C)) {
956 SMsr.lo = SMsr.hi = 0;
957 LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
964 /* -----------------------------------------------------------------------------*/
968 * Program one MTRR to describe Uma region as UC cache type if we detect running out of
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.
975 * @return TRUE - No fatal error occurs.
976 * @return FALSE - Fatal error occurs.
979 MemNSetMTRRUmaRegionUCNb (
980 IN OUT MEM_NB_BLOCK *NBPtr,
982 IN OUT UINT32 *LimitPtr
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);
1000 if (Mtrr == 0x20A) {
1005 Mtrr = 0x20A; //Reserved pair of MTRR for UMA region.
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);
1012 // prog. MTRR with current region Mask
1013 Mtrr++; // other half of MSR pair
1014 Value32 = Size - (UINT32)1;
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);
1024 /* -----------------------------------------------------------------------------*/
1028 * Report the Uma size that is going to be allocated.
1030 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1032 * @return Uma size [31:0] = Addr [47:16]
1036 IN OUT MEM_NB_BLOCK *NBPtr
1042 /* -----------------------------------------------------------------------------*/
1045 * This function allocates 16MB of memory for C6 storage when it is requested to be enabled
1047 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1051 MemNAllocateC6StorageClientNb (
1052 IN OUT MEM_NB_BLOCK *NBPtr
1057 if (IsFeatureEnabled (C6Cstate, NBPtr->MemPtr->PlatFormConfig, &(NBPtr->MemPtr->StdHeader))) {
1058 SysLimit = NBPtr->RefPtr->SysLimit;
1059 SysLimit -= _16MB_RJ16;
1062 NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1063 NBPtr->RefPtr->SysLimit = SysLimit;
1064 MemNSetBitFieldNb (NBPtr, BFDramLimitReg0, ((SysLimit << 8) & 0xFFFF0000));
1066 // Set TOPMEM and MTRRs
1067 MemNC6AdjustMSRs (NBPtr);
1070 MemNSetBitFieldNb (NBPtr, BFC6Base, (SysLimit + 1) >> (24 - 16));
1072 // C6DramLock will be set in FinalizeMCT
1076 /* -----------------------------------------------------------------------------*/
1079 * This function allocates 16MB of memory for C6 storage when it is requested to be enabled
1081 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1085 MemNAllocateC6StorageUnb (
1086 IN OUT MEM_NB_BLOCK *NBPtr
1091 UINT32 DramLimitReg;
1093 if (NBPtr->SharedPtr->C6Enabled || IsFeatureEnabled (C6Cstate, NBPtr->MemPtr->PlatFormConfig, &(NBPtr->MemPtr->StdHeader))) {
1095 SysLimit = NBPtr->RefPtr->SysLimit;
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;
1103 // Otherwise, system memory available is reduced by 16MB
1104 SysLimit -= _16MB_RJ16;
1106 NBPtr->RefPtr->SysLimit = SysLimit;
1107 NBPtr->SharedPtr->C6Enabled = TRUE;
1109 // Set TOPMEM and MTRRs (only need to be done once for BSC)
1110 MemNC6AdjustMSRs (NBPtr);
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);
1122 // Node Interleave is enabled, CoreStateSaveDestNode points to its own node
1123 MemNSetBitFieldNb (NBPtr, BFCoreStateSaveDestNode, NBPtr->Node);
1124 NBPtr->MCTPtr->NodeSysLimit = SysLimit;
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);
1130 // Node Interleave is not enabled, CoreStateSaveDestNode points to the node that contains top memory
1131 MemNSetBitFieldNb (NBPtr, BFCoreStateSaveDestNode, NBPtr->SharedPtr->TopNode);
1133 if (NBPtr->Node == NBPtr->SharedPtr->TopNode) {
1134 NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1139 MemNSetBitFieldNb (NBPtr, BFCC6SaveEn, 1);
1141 // LockDramCfg will be set in FinalizeMCT
1146 /* -----------------------------------------------------------------------------*/
1149 * This function readjusts TOPMEM and MTRRs after allocating storage for C6
1151 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1156 IN OUT MEM_NB_BLOCK *NBPtr
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);
1182 // set region mask to 16MB
1183 SMsr.hi = NBPtr->VarMtrrHiMsk;
1184 SMsr.lo = 0xFF000800;
1185 LibAmdMsrWrite (CurAddr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1192 LibAmdMsrWrite (TOP_MEM2, (UINT64 *)&SMsr, &(NBPtr->MemPtr->StdHeader));
1193 IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM2: %08x0000\n", SysLimit);
1197 /* -----------------------------------------------------------------------------*/
1200 * Family-specific hook to override the DdrMaxRate value for families with a
1201 * non-GH-compatible encoding for BFDdrMaxRate
1203 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1204 * @param[in,out] *DdrMaxRate - Void pointer to DdrMaxRate. Used as INT16.
1210 MemNGetMaxDdrRateUnb (
1211 IN OUT MEM_NB_BLOCK *NBPtr,
1215 UINT8 DdrMaxRateEncoded;
1217 DdrMaxRateEncoded = (UINT8) MemNGetBitFieldNb (NBPtr, BFDdrMaxRate);
1219 if (DdrMaxRateEncoded == 0) {
1220 * (UINT16 *) DdrMaxRate = UNSUPPORTED_DDR_FREQUENCY;
1222 * (UINT16 *) DdrMaxRate = MemNGetMemClkFreqUnb (NBPtr, DdrMaxRateEncoded);
1227 /* -----------------------------------------------------------------------------*/
1231 * This function performs the action after save/restore execution
1233 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1234 * @param[in,out] OptParam - Optional parameter
1241 MemNAfterSaveRestoreUnb (
1242 IN OUT MEM_NB_BLOCK *NBPtr,
1243 IN OUT VOID *OptParam
1246 // Sync. up DctCfgSel value with NBPtr->Dct
1247 MemNSetBitFieldNb (NBPtr, BFDctCfgSel, NBPtr->Dct);
1252 /* -----------------------------------------------------------------------------*/
1256 * This function performs the action before and after excluding dimms on CNB
1258 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1259 * @param[in,out] *IsBefore - If the function is called before excluding dimms
1266 MemNBfAfExcludeDimmClientNb (
1267 IN OUT MEM_NB_BLOCK *NBPtr,
1268 IN OUT VOID *IsBefore
1271 if (*(BOOLEAN *) IsBefore == TRUE) {
1272 NBPtr->BrdcstSet (NBPtr, BFEnterSelfRef, 1);
1273 NBPtr->PollBitField (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1275 NBPtr->BrdcstSet (NBPtr, BFExitSelfRef, 1);
1276 NBPtr->PollBitField (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1282 /*----------------------------------------------------------------------------
1285 *----------------------------------------------------------------------------