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