blob: 5032eaf683955f2b12c24079847b6edf630ac7b5 [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $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: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 **/
15/*****************************************************************************
16*
Siyuan Wang641f00c2013-06-08 11:50:55 +080017 * Copyright (c) 2008 - 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.
zbao7d94cf92012-07-02 14:19:14 +080041* ***************************************************************************
42*
43*/
44
45/*
46 *----------------------------------------------------------------------------
47 * MODULES USED
48 *
49 *----------------------------------------------------------------------------
50 */
51
52
53
54#include "AGESA.h"
55#include "amdlib.h"
56#include "Ids.h"
57#include "mport.h"
58#include "mm.h"
59#include "mn.h"
60#include "mu.h"
61#include "OptionMemory.h"
62#include "PlatformMemoryConfiguration.h"
63#include "GeneralServices.h"
64#include "cpuFeatures.h"
65#include "merrhdl.h"
66#include "Filecode.h"
67CODE_GROUP (G1_PEICC)
68RDATA_GROUP (G1_PEICC)
69
70#define FILECODE PROC_MEM_NB_MNMCT_FILECODE
71/*----------------------------------------------------------------------------
72 * DEFINITIONS AND MACROS
73 *
74 *----------------------------------------------------------------------------
75 */
76#define _16MB_RJ16 0x0100
77
78/*----------------------------------------------------------------------------
79 * TYPEDEFS AND STRUCTURES
80 *
81 *----------------------------------------------------------------------------
82 */
83
84/*----------------------------------------------------------------------------
85 * PROTOTYPES OF LOCAL FUNCTIONS
86 *
87 *----------------------------------------------------------------------------
88 */
89BOOLEAN
90STATIC
91MemNSetMTRRrangeNb (
92 IN OUT MEM_NB_BLOCK *NBPtr,
93 IN UINT32 Base,
94 IN OUT UINT32 *LimitPtr,
95 IN UINT32 MtrrAddr,
96 IN UINT8 MtrrType
97 );
98
99/*----------------------------------------------------------------------------
100 * EXPORTED FUNCTIONS
101 *
102 *----------------------------------------------------------------------------
103 */
104extern BUILD_OPT_CFG UserOptions;
105
106/* -----------------------------------------------------------------------------*/
107/**
108 *
109 * Get max frequency from OEM platform definition, from
110 * any user override (limiting) of max frequency, and
111 * from any Si Revision Specific information. Return
112 * the least of these three in DIE_STRUCT.Timings.TargetSpeed.
113 *
114 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
115 *
116 */
117
118VOID
119MemNSyncTargetSpeedNb (
120 IN OUT MEM_NB_BLOCK *NBPtr
121 )
122{
123 CONST UINT16 DdrMaxRateTab[] = {
124 UNSUPPORTED_DDR_FREQUENCY,
Mike Banon4ddbc8b2020-04-17 16:07:54 +0300125 DDR1866_FREQUENCY,
zbao7d94cf92012-07-02 14:19:14 +0800126 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
257BOOLEAN
258MemNSyncDctsReadyNb (
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
287BOOLEAN
288MemNHtMemMapInitNb (
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
421VOID
422MemNSyncAddrMapToAllNodesNb (
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
467VOID
468MemNPowerDownCtlNb (
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 */
503INT8
504MemNGetOptimalCGDDNb (
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 */
567INT16
568MemNCalcCDDNb (
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 = -127;
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 ? (NBPtr->CsPerChannel - NBPtr->CsPerDelay) : NBPtr->CsPerChannel); i = i + NBPtr->CsPerDelay) {
593 if ((CsEnabled & ((UINT16) ((NBPtr->CsPerDelay == 2) ? 3 : 1) << i)) != 0) {
594 for (j = SameDlyType ? (i + NBPtr->CsPerDelay) : 0; j < NBPtr->CsPerChannel; j = j + NBPtr->CsPerDelay) {
595 if (((CsEnabled & ((UINT16) ((NBPtr->CsPerDelay == 2)? 3 : 1) << j)) != 0) &&
596 ((SameDimm && ((i / 2) == (j / 2))) || (DiffDimm && ((i / 2) != (j / 2))))) {
597 for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
598 /// @todo: Gross delay mask should not be constant.
599 TrnDly1 = GetTrainDlyFromHeapNb (NBPtr, TrnDlyType1, DIMM_BYTE_ACCESS (i / NBPtr->CsPerDelay, ByteLane)) >> 5; // Gross delay only
600 TrnDly2 = GetTrainDlyFromHeapNb (NBPtr, TrnDlyType2, DIMM_BYTE_ACCESS (j / NBPtr->CsPerDelay, ByteLane)) >> 5; // Gross delay only
601
602 CDDtemp = TrnDly1 - TrnDly2;
603 // If the 2 delay types to be compared are the same, then keep the absolute difference
604 if ((SameDlyType) && (CDDtemp < 0)) {
605 CDDtemp = (-CDDtemp);
606 }
607
608 CDD = (CDD < CDDtemp) ? CDDtemp : CDD;
609 }
610 }
611 }
612 }
613 }
614
615 return CDD;
616}
617
618/* -----------------------------------------------------------------------------*/
619/**
620 *
621 *
622 * This function gets DQS timing from data saved in heap.
623 *
624 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
625 * @param[in] TrnDlyType - type of delay to be set
626 * @param[in] Drbn - encoding of Dimm-Rank-Byte-Nibble to be accessed
627 * (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
628 *
629 * @return value of the target timing.
630 */
631UINT16
632GetTrainDlyFromHeapNb (
633 IN OUT MEM_NB_BLOCK *NBPtr,
634 IN TRN_DLY_TYPE TrnDlyType,
635 IN DRBN Drbn
636 )
637{
638 UINT8 Dimm;
639 UINT8 Byte;
640 UINT16 TrainDly;
641 CH_DEF_STRUCT *ChannelPtr;
642 MEM_TECH_BLOCK *TechPtr;
643
644 Dimm = DRBN_DIMM (Drbn);
645 Byte = DRBN_BYTE (Drbn);
646 ChannelPtr = NBPtr->ChannelPtr;
647 TechPtr = NBPtr->TechPtr;
648
649 ASSERT (Dimm < (NBPtr->CsPerChannel / NBPtr->CsPerDelay));
650 ASSERT (Byte <= ECC_DLY);
651
652 if (NBPtr->MemPstate == MEMORY_PSTATE1) {
653 switch (TrnDlyType) {
654 case AccessRcvEnDly:
655 TrainDly = ChannelPtr->RcvEnDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
656 break;
657 case AccessWrDqsDly:
658 TrainDly = ChannelPtr->WrDqsDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
659 break;
660 case AccessWrDatDly:
661 TrainDly = ChannelPtr->WrDatDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
662 break;
663 case AccessRdDqsDly:
664 TrainDly = ChannelPtr->RdDqsDlysMemPs1[Dimm * TechPtr->DlyTableWidth () + Byte];
665 break;
666 default:
667 TrainDly = 0;
668 IDS_ERROR_TRAP;
669 }
670 } else {
671 switch (TrnDlyType) {
672 case AccessRcvEnDly:
673 TrainDly = ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
674 break;
675 case AccessWrDqsDly:
676 TrainDly = ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
677 break;
678 case AccessWrDatDly:
679 TrainDly = ChannelPtr->WrDatDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
680 break;
681 case AccessRdDqsDly:
682 TrainDly = ChannelPtr->RdDqsDlys[Dimm * TechPtr->DlyTableWidth () + Byte];
683 break;
684 default:
685 TrainDly = 0;
686 IDS_ERROR_TRAP;
687 }
688 }
689
690 return TrainDly;
691}
692
693/* -----------------------------------------------------------------------------*/
694/**
695 *
696 *
697 * This function sets the fixed MTRRs for common legacy ranges.
698 * It sets TOP_MEM and TOM2 and some variable MTRRs with WB Uncacheable type.
699 *
700 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
701 *
702 * @return TRUE - An Error value lower than AGESA_FATAL may have occurred
703 * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
704 */
705
706BOOLEAN
707MemNCPUMemTypingNb (
708 IN OUT MEM_NB_BLOCK *NBPtr
709 )
710{
711 UINT32 Bottom32bIO;
712 UINT32 Bottom40bIO;
713 UINT32 Cache32bTOP;
714 S_UINT64 SMsr;
715
716 MEM_DATA_STRUCT *MemPtr;
717 MEM_PARAMETER_STRUCT *RefPtr;
718 RefPtr = NBPtr->RefPtr;
719 MemPtr = NBPtr->MemPtr;
720
721 //
722 //======================================================================
723 // Set temporary top of memory from Node structure data.
724 // Adjust temp top of memory down to accommodate 32-bit IO space.
725 //======================================================================
726 //Bottom40bIO=top of memory, right justified 16 bits (defines dram versus IO space type)
727 //Bottom32bIO=sub 4GB top of memory, right justified 16 bits (defines dram versus IO space type)
728 //Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 16 bits
729 //
730 if (RefPtr->HoleBase != 0) {
731 Bottom32bIO = RefPtr->HoleBase;
732 } else if (RefPtr->BottomIo != 0) {
733 Bottom32bIO = (UINT32)RefPtr->BottomIo << (24 - 16);
734 } else {
735 Bottom32bIO = (UINT32)1 << (24 - 16);
736 }
737
738 Cache32bTOP = RefPtr->SysLimit + 1;
739 if (Cache32bTOP < _4GB_RJ16) {
740 Bottom40bIO = 0;
741 if (Bottom32bIO >= Cache32bTOP) {
742 Bottom32bIO = Cache32bTOP;
743 }
744 } else {
745 Bottom40bIO = Cache32bTOP;
746 }
747
748 Cache32bTOP = Bottom32bIO;
749
750
751 //
752 //======================================================================
753 // Set default values for CPU registers
754 //======================================================================
755 //
756 LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
757 SMsr.lo |= 0x1C0000; // turn on modification enable bit and
758 // mtrr enable bits
759 LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
760
761 SMsr.lo = SMsr.hi = 0x1E1E1E1E;
762 LibAmdMsrWrite (0x250, (UINT64 *)&SMsr, &MemPtr->StdHeader); // 0 - 512K = WB Mem
763 LibAmdMsrWrite (0x258, (UINT64 *)&SMsr, &MemPtr->StdHeader); // 512K - 640K = WB Mem
764
765 //
766 //======================================================================
767 // Set variable MTRR values
768 //======================================================================
769 //
770 MemNSetMTRRrangeNb (NBPtr, 0, &Cache32bTOP, 0x200, 6);
771
772 RefPtr->Sub4GCacheTop = Cache32bTOP << 16;
773
774 //
775 //======================================================================
776 // Set TOP_MEM and TOM2 CPU registers
777 //======================================================================
778 //
779 SMsr.hi = Bottom32bIO >> (32 - 16);
780 SMsr.lo = Bottom32bIO << 16;
781 LibAmdMsrWrite (TOP_MEM, (UINT64 *)&SMsr, &MemPtr->StdHeader);
782 IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM: %08x0000\n", Bottom32bIO);
783
784 if (Bottom40bIO) {
785 SMsr.hi = Bottom40bIO >> (32 - 16);
786 SMsr.lo = Bottom40bIO << 16;
787 } else {
788 SMsr.hi = 0;
789 SMsr.lo = 0;
790 }
791 LibAmdMsrWrite (TOP_MEM2, (UINT64 *)&SMsr, &MemPtr->StdHeader);
792
793 LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
794 if (Bottom40bIO) {
795 IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM2: %08x0000\n", Bottom40bIO);
796 IDS_HDT_CONSOLE (MEM_FLOW, "Sub1THoleBase: %08x0000\n", RefPtr->Sub1THoleBase);
797 // Enable TOM2
798 SMsr.lo |= 0x00600000;
799 } else {
800 // Disable TOM2
801 SMsr.lo &= ~0x00600000;
802 }
803 SMsr.lo &= 0xFFF7FFFF; // turn off modification enable bit
804 LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader);
805
806 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
807}
808
809/* -----------------------------------------------------------------------------*/
810/**
811 *
812 *
813 * This function runs on the BSP only, it sets the fixed MTRRs for common legacy ranges.
814 * It sets TOP_MEM and TOM2 and some variable MTRRs with WB Uncacheable type.
815 *
816 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
817 *
818 */
819
820VOID
821MemNUMAMemTypingNb (
822 IN OUT MEM_NB_BLOCK *NBPtr
823 )
824{
825 UINT32 Bottom32bIO;
826 UINT32 Bottom32bUMA;
827 UINT32 Cache32bTOP;
828 UINT32 Value32;
829 UINT8 BitCount;
830 UINT8 i;
831
832 MEM_PARAMETER_STRUCT *RefPtr;
833 RefPtr = NBPtr->RefPtr;
834 BitCount = 0;
835 //
836 //======================================================================
837 // Adjust temp top of memory down to accommodate UMA memory start
838 //======================================================================
839 // Bottom32bIO=sub 4GB top of memory, right justified 16 bits (defines dram versus IO space type)
840 // Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 16 bits
841 //
842 Bottom32bIO = RefPtr->Sub4GCacheTop >> 16;
843 Bottom32bUMA = RefPtr->UmaBase;
844
845 if (Bottom32bUMA < Bottom32bIO) {
846 Cache32bTOP = Bottom32bUMA;
847 RefPtr->Sub4GCacheTop = Bottom32bUMA << 16;
848 //
849 //======================================================================
850 //Set variable MTRR values
851 //======================================================================
852 //
853 Value32 = Cache32bTOP;
854 //Pre-check the bit count of bottom Uma to see if it is potentially running out of Mtrr while typing.
855 while (Value32 != 0) {
856 i = LibAmdBitScanForward (Value32);
857 Value32 &= ~ (1 << i);
858 BitCount++;
859 }
860
861 if (BitCount > 5) {
862 NBPtr->RefPtr->GStatus[GsbMTRRshort] = TRUE;
863 MemNSetMTRRUmaRegionUCNb (NBPtr, &Cache32bTOP, &Bottom32bIO);
864 } else {
865 MemNSetMTRRrangeNb (NBPtr, 0, &Cache32bTOP, 0x200, 6);
866 }
867 }
868}
869
870/* -----------------------------------------------------------------------------*/
871/**
872 *
873 *
874 * Program MTRRs to describe given range as given cache type. Use MTRR pairs
875 * starting with the given MTRRphys Base address, and use as many as is
876 * required up to (excluding) MSR 020C, which is reserved for OS.
877 *
878 * "Limit" in the context of this procedure is not the numerically correct
879 * limit, but rather the Last address+1, for purposes of coding efficiency
880 * and readability. Size of a region is then Limit-Base.
881 *
882 * 1. Size of each range must be a power of two
883 * 2. Each range must be naturally aligned (Base is same as size)
884 *
885 * There are two code paths: the ascending path and descending path (analogous
886 * to bsf and bsr), where the next limit is a function of the next set bit in
887 * a forward or backward sequence of bits (as a function of the Limit). We
888 * start with the ascending path, to ensure that regions are naturally aligned,
889 * then we switch to the descending path to maximize MTRR usage efficiency.
890 * Base=0 is a special case where we start with the descending path.
891 * Correct Mask for region is 2comp(Size-1)-1,
892 * which is 2comp(Limit-Base-1)-1 *
893 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
894 * @param[in] Base - Base address[47:16] of specified range.
895 * @param[in] *LimitPtr - Limit address[47:16] of specified range.
896 * @param[in] MtrrAddr - address of var MTRR pair to start using.
897 * @param[in] MtrrType - Cache type for the range.
898 *
899 * @return TRUE - No failure occurred
900 * @return FALSE - Failure occurred because run out of variable-size MTRRs before completion.
901 */
902
903BOOLEAN
904STATIC
905MemNSetMTRRrangeNb (
906 IN OUT MEM_NB_BLOCK *NBPtr,
907 IN UINT32 Base,
908 IN OUT UINT32 *LimitPtr,
909 IN UINT32 MtrrAddr,
910 IN UINT8 MtrrType
911 )
912{
913 S_UINT64 SMsr;
914 UINT32 CurBase;
915 UINT32 CurLimit;
916 UINT32 CurSize;
917 UINT32 CurAddr;
918 UINT32 Value32;
919
920 CurBase = Base;
921 CurLimit = *LimitPtr;
922 CurAddr = MtrrAddr;
923
924 while ((CurAddr >= 0x200) && (CurAddr < 0x20A) && (CurBase < *LimitPtr)) {
925 CurSize = CurLimit = (UINT32)1 << LibAmdBitScanForward (CurBase);
926 CurLimit += CurBase;
927 if ((CurBase == 0) || (*LimitPtr < CurLimit)) {
928 CurLimit = *LimitPtr - CurBase;
929 CurSize = CurLimit = (UINT32)1 << LibAmdBitScanReverse (CurLimit);
930 CurLimit += CurBase;
931 }
932
933 // prog. MTRR with current region Base
934 SMsr.lo = (CurBase << 16) | (UINT32)MtrrType;
935 SMsr.hi = CurBase >> (32 - 16);
936 LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
937
938 // prog. MTRR with current region Mask
939 CurAddr++; // other half of MSR pair
940 Value32 = CurSize - (UINT32)1;
941 Value32 = ~Value32;
942 SMsr.hi = (Value32 >> (32 - 16)) & NBPtr->VarMtrrHiMsk;
943 SMsr.lo = (Value32 << 16) | ((UINT32)1 << MTRR_VALID);
944 LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
945
946 CurBase = CurLimit;
947 CurAddr++; // next MSR pair
948 }
949
950 if (CurLimit < *LimitPtr) {
951 // Announce failure
952 *LimitPtr = CurLimit;
953 IDS_ERROR_TRAP;
954 }
955
956 while ((CurAddr >= 0x200) && (CurAddr < 0x20C)) {
957 SMsr.lo = SMsr.hi = 0;
958 LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
959 CurAddr++;
960 }
961
962 return TRUE;
963}
964
965/* -----------------------------------------------------------------------------*/
966/**
967 *
968 *
969 * Program one MTRR to describe Uma region as UC cache type if we detect running out of
970 * Mtrr circumstance.
971 *
972 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
973 * @param[in] *BasePtr - Base address[47:24] of specified range.
974 * @param[in] *LimitPtr - Limit address[47:24] of specified range.
975 *
976 * @return TRUE - No fatal error occurs.
977 * @return FALSE - Fatal error occurs.
978 */
979BOOLEAN
980MemNSetMTRRUmaRegionUCNb (
981 IN OUT MEM_NB_BLOCK *NBPtr,
982 IN UINT32 *BasePtr,
983 IN OUT UINT32 *LimitPtr
984 )
985{
986 S_UINT64 SMsr;
987 UINT32 Mtrr;
988 UINT32 Size;
989 UINT32 Value32;
990
991 Size = *LimitPtr - *BasePtr;
992 // Check if Size is a power of 2
993 if ((Size & (Size - 1)) != 0) {
994 for (Mtrr = 0x200; Mtrr < 0x20A; Mtrr += 2) {
995 LibAmdMsrRead (Mtrr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
996 if ((SMsr.lo & ((UINT32) 1 << 11)) == 0) {
997 MemNSetMTRRrangeNb (NBPtr, *BasePtr, LimitPtr, Mtrr, 0);
998 break;
999 }
1000 }
1001 if (Mtrr == 0x20A) {
1002 // Run out of MTRRs
1003 IDS_ERROR_TRAP;
1004 }
1005 } else {
1006 Mtrr = 0x20A; //Reserved pair of MTRR for UMA region.
1007
1008 // prog. MTRR with current region Base
1009 SMsr.lo = *BasePtr << 16;
1010 SMsr.hi = *BasePtr >> (32 - 16);
1011 LibAmdMsrWrite (Mtrr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1012
1013 // prog. MTRR with current region Mask
1014 Mtrr++; // other half of MSR pair
1015 Value32 = Size - (UINT32)1;
1016 Value32 = ~Value32;
1017 SMsr.hi = (Value32 >> (32 - 16)) & NBPtr->VarMtrrHiMsk;
1018 SMsr.lo = (Value32 << 16) | ((UINT32)1 << MTRR_VALID);
1019 LibAmdMsrWrite (Mtrr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1020 }
1021
1022 return TRUE;
1023}
1024
1025/* -----------------------------------------------------------------------------*/
1026/**
1027 *
1028 *
1029 * Report the Uma size that is going to be allocated.
1030 *
1031 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1032 *
1033 * @return Uma size [31:0] = Addr [47:16]
1034 */
1035UINT32
1036MemNGetUmaSizeNb (
1037 IN OUT MEM_NB_BLOCK *NBPtr
1038 )
1039{
1040 return 0;
1041}
1042
1043/* -----------------------------------------------------------------------------*/
1044/**
1045 *
1046 * This function allocates 16MB of memory for C6 storage when it is requested to be enabled
1047 *
1048 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1049 *
1050 */
1051VOID
1052MemNAllocateC6StorageClientNb (
1053 IN OUT MEM_NB_BLOCK *NBPtr
1054 )
1055{
1056 UINT32 SysLimit;
1057
1058 if (IsFeatureEnabled (C6Cstate, NBPtr->MemPtr->PlatFormConfig, &(NBPtr->MemPtr->StdHeader))) {
1059 SysLimit = NBPtr->RefPtr->SysLimit;
1060 SysLimit -= _16MB_RJ16;
1061
1062 // Set Dram Limit
1063 NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1064 NBPtr->RefPtr->SysLimit = SysLimit;
1065 MemNSetBitFieldNb (NBPtr, BFDramLimitReg0, ((SysLimit << 8) & 0xFFFF0000));
1066
1067 // Set TOPMEM and MTRRs
1068 MemNC6AdjustMSRs (NBPtr);
1069
1070 // Set C6Base
1071 MemNSetBitFieldNb (NBPtr, BFC6Base, (SysLimit + 1) >> (24 - 16));
1072
1073 // C6DramLock will be set in FinalizeMCT
1074 }
1075}
1076
1077/* -----------------------------------------------------------------------------*/
1078/**
1079 *
1080 * This function allocates 16MB of memory for C6 storage when it is requested to be enabled
1081 *
1082 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1083 *
1084 */
1085VOID
1086MemNAllocateC6StorageUnb (
1087 IN OUT MEM_NB_BLOCK *NBPtr
1088 )
1089{
1090 UINT8 Node;
1091 UINT32 SysLimit;
1092 UINT32 DramLimitReg;
1093
1094 if (NBPtr->SharedPtr->C6Enabled || IsFeatureEnabled (C6Cstate, NBPtr->MemPtr->PlatFormConfig, &(NBPtr->MemPtr->StdHeader))) {
1095
1096 SysLimit = NBPtr->RefPtr->SysLimit;
1097
1098 // Calculate new SysLimit
1099 if (!NBPtr->SharedPtr->C6Enabled) {
1100 if (NBPtr->SharedPtr->NodeIntlv.NodeCnt >= 2) {
1101 // Node Interleave is enabled, system memory available is reduced by 16MB * number of nodes
1102 SysLimit -= _16MB_RJ16 * NBPtr->SharedPtr->NodeIntlv.NodeCnt;
1103 } else {
1104 // Otherwise, system memory available is reduced by 16MB
1105 SysLimit -= _16MB_RJ16;
1106 }
1107 NBPtr->RefPtr->SysLimit = SysLimit;
1108 NBPtr->SharedPtr->C6Enabled = TRUE;
1109
1110 // Set TOPMEM and MTRRs (only need to be done once for BSC)
1111 MemNC6AdjustMSRs (NBPtr);
1112 }
1113
1114 // Set Dram Limit
1115 if (NBPtr->SharedPtr->NodeIntlv.NodeCnt >= 2) {
1116 for (Node = 0; Node < NBPtr->NodeCount; Node++) {
1117 DramLimitReg = MemNGetBitFieldNb (NBPtr, BFDramLimitReg0 + Node);
1118 if ((DramLimitReg & 0xFFFF0000) != 0) {
1119 MemNSetBitFieldNb (NBPtr, BFDramLimitReg0 + Node, ((SysLimit << 8) & 0xFFFF0000) | (DramLimitReg & 0xFFFF));
1120 MemNSetBitFieldNb (NBPtr, BFDramLimitHiReg0 + Node, SysLimit >> 24);
1121 }
1122 }
1123 // Node Interleave is enabled, CoreStateSaveDestNode points to its own node
1124 MemNSetBitFieldNb (NBPtr, BFCoreStateSaveDestNode, NBPtr->Node);
1125 NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1126 } else {
1127 DramLimitReg = MemNGetBitFieldNb (NBPtr, BFDramLimitReg0 + NBPtr->SharedPtr->TopNode) & 0x0000FFFF;
1128 MemNSetBitFieldNb (NBPtr, BFDramLimitReg0 + NBPtr->SharedPtr->TopNode, ((SysLimit << 8) & 0xFFFF0000) | DramLimitReg);
1129 MemNSetBitFieldNb (NBPtr, BFDramLimitHiReg0 + NBPtr->SharedPtr->TopNode, SysLimit >> 24);
1130
1131 // Node Interleave is not enabled, CoreStateSaveDestNode points to the node that contains top memory
1132 MemNSetBitFieldNb (NBPtr, BFCoreStateSaveDestNode, NBPtr->SharedPtr->TopNode);
1133
1134 if (NBPtr->Node == NBPtr->SharedPtr->TopNode) {
1135 NBPtr->MCTPtr->NodeSysLimit = SysLimit;
1136 }
1137 }
1138
1139 // Set BFCC6SaveEn
1140 MemNSetBitFieldNb (NBPtr, BFCC6SaveEn, 1);
1141
1142 // LockDramCfg will be set in FinalizeMCT
1143 }
1144}
1145
1146
1147/* -----------------------------------------------------------------------------*/
1148/**
1149 *
1150 * This function readjusts TOPMEM and MTRRs after allocating storage for C6
1151 *
1152 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1153 *
1154 */
1155VOID
1156MemNC6AdjustMSRs (
1157 IN OUT MEM_NB_BLOCK *NBPtr
1158 )
1159{
1160 UINT32 SysLimit;
1161 UINT32 CurAddr;
1162 S_UINT64 SMsr;
1163
1164 SysLimit = NBPtr->RefPtr->SysLimit + 1;
1165 SMsr.hi = SysLimit >> (32 - 16);
1166 SMsr.lo = SysLimit << 16;
1167 if (SysLimit < _4GB_RJ16) {
1168 LibAmdMsrWrite (TOP_MEM, (UINT64 *)&SMsr, &(NBPtr->MemPtr->StdHeader));
1169 IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM: %08x0000\n", SysLimit);
1170 // If there is no UMA buffer, then set top of cache and MTRR.
1171 // Otherwise, top of cache and MTRR will be set when UMA buffer is set up.
1172 if (NBPtr->RefPtr->UmaMode == UMA_NONE) {
1173 NBPtr->RefPtr->Sub4GCacheTop = (SysLimit << 16);
1174 // Find unused MTRR to set C6 region to UC
1175 for (CurAddr = 0x200; CurAddr < 0x20C; CurAddr += 2) {
1176 LibAmdMsrRead (CurAddr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1177 if ((SMsr.lo & ((UINT32) 1 << 11)) == 0) {
1178 // Set region base as TOM
1179 SMsr.hi = SysLimit >> (32 - 16);
1180 SMsr.lo = SysLimit << 16;
1181 LibAmdMsrWrite (CurAddr, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1182
1183 // set region mask to 16MB
1184 SMsr.hi = NBPtr->VarMtrrHiMsk;
1185 SMsr.lo = 0xFF000800;
1186 LibAmdMsrWrite (CurAddr + 1, (UINT64 *)&SMsr, &NBPtr->MemPtr->StdHeader);
1187
1188 break;
1189 }
1190 }
1191 }
1192 } else {
1193 LibAmdMsrWrite (TOP_MEM2, (UINT64 *)&SMsr, &(NBPtr->MemPtr->StdHeader));
1194 IDS_HDT_CONSOLE (MEM_FLOW, "TOP_MEM2: %08x0000\n", SysLimit);
1195 }
1196}
1197
1198/* -----------------------------------------------------------------------------*/
1199/**
1200 *
1201 * Family-specific hook to override the DdrMaxRate value for families with a
1202 * non-GH-compatible encoding for BFDdrMaxRate
1203 *
1204 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1205 * @param[in,out] *DdrMaxRate - Void pointer to DdrMaxRate. Used as INT16.
1206 *
1207 * @return TRUE
1208 *
1209 */
1210BOOLEAN
1211MemNGetMaxDdrRateUnb (
1212 IN OUT MEM_NB_BLOCK *NBPtr,
1213 IN VOID *DdrMaxRate
1214 )
1215{
1216 UINT8 DdrMaxRateEncoded;
1217
1218 DdrMaxRateEncoded = (UINT8) MemNGetBitFieldNb (NBPtr, BFDdrMaxRate);
1219
1220 if (DdrMaxRateEncoded == 0) {
1221 * (UINT16 *) DdrMaxRate = UNSUPPORTED_DDR_FREQUENCY;
1222 } else {
1223 * (UINT16 *) DdrMaxRate = MemNGetMemClkFreqUnb (NBPtr, DdrMaxRateEncoded);
1224 }
1225 return TRUE;
1226}
1227
1228/* -----------------------------------------------------------------------------*/
1229/**
1230 *
1231 *
1232 * This function performs the action after save/restore execution
1233 *
1234 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1235 * @param[in,out] OptParam - Optional parameter
1236 *
1237 * @return TRUE
1238 *
1239 */
1240
1241BOOLEAN
1242MemNAfterSaveRestoreUnb (
1243 IN OUT MEM_NB_BLOCK *NBPtr,
1244 IN OUT VOID *OptParam
1245 )
1246{
1247 // Sync. up DctCfgSel value with NBPtr->Dct
1248 MemNSetBitFieldNb (NBPtr, BFDctCfgSel, NBPtr->Dct);
1249
1250 return TRUE;
1251}
1252
1253/* -----------------------------------------------------------------------------*/
1254/**
1255 *
1256 *
1257 * This function performs the action before and after excluding dimms on CNB
1258 *
1259 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1260 * @param[in,out] *IsBefore - If the function is called before excluding dimms
1261 *
1262 * @return TRUE
1263 *
1264 */
1265
1266BOOLEAN
1267MemNBfAfExcludeDimmClientNb (
1268 IN OUT MEM_NB_BLOCK *NBPtr,
1269 IN OUT VOID *IsBefore
1270 )
1271{
1272 if (*(BOOLEAN *) IsBefore == TRUE) {
1273 NBPtr->BrdcstSet (NBPtr, BFEnterSelfRef, 1);
1274 NBPtr->PollBitField (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1275 } else {
1276 NBPtr->BrdcstSet (NBPtr, BFExitSelfRef, 1);
1277 NBPtr->PollBitField (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1278 }
1279
1280 return TRUE;
1281}
1282
1283/*----------------------------------------------------------------------------
1284 * LOCAL FUNCTIONS
1285 *
1286 *----------------------------------------------------------------------------
1287 */