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