9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/Main)
12 * @e \$Revision: 56322 $ @e \$Date: 2011-07-11 16:51:42 -0600 (Mon, 11 Jul 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
47 *----------------------------------------------------------------------------
50 *----------------------------------------------------------------------------
56 #include "cpuServices.h"
58 #include "OptionMemory.h"
59 #include "PlatformMemoryConfiguration.h"
63 #include "cpuFamilyTranslation.h"
64 #include "cpuCacheInit.h"
69 #define FILECODE PROC_MEM_MAIN_MUC_FILECODE
70 /*----------------------------------------------------------------------------
71 * DEFINITIONS AND MACROS
73 *----------------------------------------------------------------------------
75 CONST UINT32 Pattern2[16] = {
76 0x12345678, 0x87654321, 0x23456789, 0x98765432,
77 0x59385824, 0x30496724, 0x24490795, 0x99938733,
78 0x40385642, 0x38465245, 0x29432163, 0x05067894,
79 0x12349045, 0x98723467, 0x12387634, 0x34587623
82 CONST UINT32 MaxLatPat[48] = {
83 0x6E0E3FAC, 0x0C3CFF52,
84 0x4A688181, 0x49C5B613,
85 0x7C780BA6, 0x5C1650E3,
86 0x0C4F9D76, 0x0C6753E6,
87 0x205535A5, 0xBABFB6CA,
88 0x610E6E5F, 0x0C5F1C87,
89 0x488493CE, 0x14C9C383,
90 0xF5B9A5CD, 0x9CE8F615,
92 0xAAD714B5, 0xC38F1B4C,
93 0x72ED647C, 0x669F7562,
94 0x5233F802, 0x4A898B30,
95 0x10A40617, 0x3326B465,
96 0x55386E04, 0xC807E3D3,
97 0xAB49E193, 0x14B4E63A,
98 0x67DF2495, 0xEA517C45,
99 0x7624CE51, 0xF8140C51,
101 0x4824BD23, 0xB61DD0C9,
102 0x072BCFBE, 0xE8F3807D,
103 0x919EA373, 0x25E30C47,
104 0xFEB12958, 0x4DA80A5A,
105 0xE9A0DDF8, 0x792B0076,
106 0xE81C73DC, 0xF025B496,
107 0x1DB7E627, 0x808594FE,
108 0x82668268, 0x655C7783
111 CONST UINT8 PatternJD[9] = {0x44, 0xA6, 0x38, 0x4F, 0x4B, 0x2E, 0xEF, 0xD5, 0x54};
113 CONST UINT8 PatternJD_256[256] = {
114 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
115 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
116 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
117 0xFF, 0xFF, 0x00, 0xF7, 0x08, 0xF7, 0x00, 0xFF,
118 0x00, 0xF7, 0x00, 0xFF, 0x00, 0xF7, 0x00, 0xF7,
119 0x08, 0xF7, 0x08, 0xFF, 0x00, 0xFF, 0x08, 0xFF,
120 0x00, 0xFF, 0x08, 0xFF, 0x08, 0xF7, 0xFB, 0x04,
121 0xFB, 0xFB, 0x04, 0xFB, 0xFB, 0xFB, 0x04, 0xFB,
122 0xFB, 0xFB, 0xFB, 0x04, 0xFB, 0x04, 0x04, 0xFB,
123 0x04, 0x04, 0x04, 0xFB, 0x04, 0x04, 0x04, 0x04,
124 0xFB, 0x7F, 0x80, 0x7F, 0x00, 0xFF, 0x00, 0x7F,
125 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x7F, 0x80, 0x7F,
126 0x80, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x00, 0xFF,
127 0x80, 0xFF, 0x80, 0x7F, 0xBF, 0x40, 0xBF, 0xBF,
128 0x40, 0xBF, 0xBF, 0xBF, 0x40, 0xBF, 0xBF, 0xBF,
129 0xBF, 0x40, 0xBF, 0x40, 0x40, 0xBF, 0x40, 0x40,
130 0x40, 0xBF, 0x40, 0x40, 0x40, 0x40, 0xBF, 0xFD,
131 0x02, 0xFD, 0x00, 0xFF, 0x00, 0xFD, 0x00, 0xFF,
132 0x00, 0xFD, 0x00, 0xFD, 0x02, 0xFD, 0x02, 0xFF,
133 0x00, 0xFF, 0x02, 0xFF, 0x00, 0xFF, 0x02, 0xFF,
134 0x02, 0xFD, 0xFE, 0x01, 0xFE, 0xFE, 0x01, 0xFE,
135 0xFE, 0xFE, 0x01, 0xFE, 0xFE, 0xFE, 0xFE, 0x01,
136 0xFE, 0x01, 0x01, 0xFE, 0x01, 0x01, 0x01, 0xFE,
137 0x01, 0x01, 0x01, 0x01, 0xFE, 0xDF, 0x20, 0xDF,
138 0x00, 0xFF, 0x00, 0xDF, 0x00, 0xFF, 0x00, 0xDF,
139 0x00, 0xDF, 0x20, 0xDF, 0x20, 0xFF, 0x00, 0xFF,
140 0x20, 0xFF, 0x00, 0xFF, 0x20, 0xFF, 0x20, 0xDF,
141 0xEF, 0x10, 0xEF, 0xEF, 0x10, 0xEF, 0xEF, 0xEF,
142 0x10, 0xEF, 0xEF, 0xEF, 0xEF, 0x10, 0xEF, 0x10,
143 0x10, 0xEF, 0x10, 0x10, 0x10, 0xEF, 0x10, 0x10,
144 0x10, 0x10, 0xEF, 0xF7, 0x00, 0xFF, 0x04, 0x7F,
145 0x00, 0xFF, 0x40, 0xFD, 0x00, 0xFF, 0x01, 0xDF
148 /*----------------------------------------------------------------------------
149 * TYPEDEFS AND STRUCTURES
151 *----------------------------------------------------------------------------
154 /*----------------------------------------------------------------------------
155 * PROTOTYPES OF LOCAL FUNCTIONS
157 *----------------------------------------------------------------------------
161 /*----------------------------------------------------------------------------
164 *----------------------------------------------------------------------------
166 /* -----------------------------------------------------------------------------*/
169 * This function returns the (index)th UINT8
170 * from an indicated test pattern.
172 * @param[in] Pattern - encoding of test pattern type
173 * @param[in] Buffer[] - buffer to be filled
174 * @param[in] Size - Size of the buffer
176 * ----------------------------------------------------------------------------
180 MemUFillTrainPattern (
181 IN TRAIN_PATTERN Pattern,
192 for (Index = 0; Index < Size; Index++) {
194 // get one byte from Pattern
203 ASSERT (Index < sizeof (Pattern2));
204 Result = ((UINT8 *)Pattern2)[Index];
207 if (Size != 6 * 64) {
208 Result = ((UINT8 *)MaxLatPat)[Index];
210 Result = ((UINT8 *)MaxLatPat)[Index & 0xF7];
213 case TestPatternJD256B:
215 // break is not being used here because TestPatternJD256B also need
216 // to run TestPatternJD256A sequence.
217 case TestPatternJD256A:
219 ASSERT (k < sizeof (PatternJD_256));
220 Result = PatternJD_256[k];
222 case TestPatternJD1B:
224 // break is not being used here because TestPatternJD1B also need
225 // to run TestPatternJD1A sequence.
226 case TestPatternJD1A:
228 i = (UINT8) (k >> 3);
229 Mask = (UINT8) (0x80 >> (k & 7));
234 Result = (UINT16)1 << (i - 1);
237 ASSERT (i < sizeof (PatternJD));
238 if (PatternJD[i] & Mask) {
253 // fill in the Pattern buffer
254 Buffer[Index] = Result;
258 /* -----------------------------------------------------------------------------*/
261 * This function flushes cache lines
263 * @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
264 * @param[in] ClCount - Number of cache lines
265 * @param[in] Address - System Address [47:16]
267 * ----------------------------------------------------------------------------
274 IN OUT MEM_DATA_STRUCT *MemPtr
277 MemUSetTargetWTIO (Address, MemPtr);
278 MemUFlushPattern (MemUSetUpperFSbase (Address, MemPtr), ClCount);
279 MemUResetTargetWTIO (MemPtr);
282 /*----------------------------------------------------------------------------
285 *----------------------------------------------------------------------------
288 /* -----------------------------------------------------------------------------*/
291 * This function sets the upper 32-bits of the Base address, 4GB aligned) for the FS selector.
292 * @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
293 * @param[in] Address - System Address [47:16]
295 * @return Address - Lowest 32-bit of physical address
296 * ----------------------------------------------------------------------------
302 IN OUT MEM_DATA_STRUCT *MemPtr
308 SMsr.hi = Address >> 16;
309 LibAmdMsrWrite (FS_BASE, (UINT64 *)&SMsr, &MemPtr->StdHeader);
310 return Address << 16;
314 /* -----------------------------------------------------------------------------*/
317 * This function resets the target address space to Write Through IO by disabling IORRs
319 * @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
321 * ----------------------------------------------------------------------------
325 MemUResetTargetWTIO (
326 IN OUT MEM_DATA_STRUCT *MemPtr
332 LibAmdMsrWrite (IORR0_MASK, (UINT64 *)&SMsr, &MemPtr->StdHeader);
335 /* -----------------------------------------------------------------------------*/
338 * This function sets the target range to WT IO (using an IORR overlapping
339 * the already existing
341 * @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
342 * @param[in] Address - System Address [47:16]
344 * ----------------------------------------------------------------------------
350 IN OUT MEM_DATA_STRUCT *MemPtr
355 SMsr.lo = Address << 16;
356 SMsr.hi = Address >> 16;
357 LibAmdMsrWrite (IORR0_BASE,(UINT64 *)&SMsr, &MemPtr->StdHeader); // IORR0 Base
359 SMsr.lo = 0xFC000800;
360 LibAmdMsrWrite (IORR0_MASK, (UINT64 *)&SMsr, &MemPtr->StdHeader); // 64MB Mask
363 /* -----------------------------------------------------------------------------*/
366 * Waits specified number of 10ns cycles
367 * @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
368 * @param[in] Count - Number of 10ns cycles to wait; Note that Count must not exceed 1000000
370 * ----------------------------------------------------------------------------
376 IN OUT MEM_DATA_STRUCT *MemPtr
382 ASSERT (Count <= 1000000);
386 LibAmdMsrRead (TSC, &CurrentTsc, &MemPtr->StdHeader);
387 TargetTsc = CurrentTsc + ((Count * MemPtr->TscRate + 99) / 100);
389 LibAmdMsrRead (TSC, &CurrentTsc, &MemPtr->StdHeader);
390 } while (CurrentTsc < TargetTsc);
393 /* -----------------------------------------------------------------------------*/
396 * Find the entry of platform specific overriding table.
398 * @param[in] PlatformMemoryConfiguration - Platform config table
399 * @param[in] EntryType - Entry type
400 * @param[in] SocketID - Physical socket ID
401 * @param[in] ChannelID - Physical channel ID
402 * @param[in] DimmID - Physical Dimm ID
403 * @param[in] *LogicalIdPtr - Pointer to the CPU_LOGICAL_ID
404 * @param[in,out] *StdHeader - Pointer of AMD_CONFIG_PARAMS
405 * - If both *LogicalIdPtr and *StdHeader are "NULL" input,
406 * that means, the "EntryType" are not CPU family dependent,
407 * ex. PSO_MAX_DIMMS for NUMBER_OF_DIMMS_SUPPORTED macro.
410 * @return NULL - entry could not be found.
411 * @return Pointer - points to the entry's data.
413 * ----------------------------------------------------------------------------
417 FindPSOverrideEntry (
418 IN PSO_TABLE *PlatformMemoryConfiguration,
419 IN PSO_ENTRY EntryType,
423 IN CPU_LOGICAL_ID *LogicalIdPtr,
424 IN AMD_CONFIG_PARAMS *StdHeader
428 CPU_LOGICAL_ID LogicalCpuId;
431 LogicalCpuId.Family = AMD_FAMILY_UNKNOWN;
432 LogicalCpuId.Revision = 0;
435 Buffer = PlatformMemoryConfiguration;
437 // Do not need to look for CPU family specific PSO if LogicalIdPtr and StdHeader are NULL.
439 if ((LogicalIdPtr != NULL) && (StdHeader != NULL)) {
441 // Looking for the CPU family signature followed by CPUID value.
442 // And check to see if the CPUID value is matched with current CPU's :
443 // - If matched, Buffer points to following PSO macros' start address.
444 // - If not matched, Buffer points to PlatformMemoryConfiguration for global PSO parsing.
446 while (Buffer[0] != PSO_END) {
447 if (Buffer[0] == PSO_CPU_FAMILY_TO_OVERRIDE) {
448 RawCpuId = *(UINT32 *)&Buffer[2];
449 GetLogicalIdFromCpuid (RawCpuId, &LogicalCpuId, StdHeader);
450 if ((LogicalCpuId.Family & LogicalIdPtr->Family) != 0) {
451 if ((LogicalCpuId.Revision & LogicalIdPtr->Revision) != 0) {
452 Buffer += Buffer[1] + 2;
457 Buffer += Buffer[1] + 2;
460 // If no CPU family specific PSO macros exist, Buffer points to PlatformMemoryConfiguration again
462 if (Buffer[0] == PSO_END) {
463 Buffer = PlatformMemoryConfiguration;
467 while ((Buffer[0] != PSO_END) && (Buffer[0] != PSO_CPU_FAMILY_TO_OVERRIDE)) {
468 if (Buffer[0] == EntryType) {
469 if ((Buffer[2] & ((UINT8) 1 << SocketID)) != 0 ) {
470 if ((Buffer[3] & ((UINT8) 1 << ChannelID)) != 0 ) {
471 if ((Buffer[4] & ((UINT8) 1 << DimmID)) != 0 ) {
477 Buffer += Buffer[1] + 2;
483 /* -----------------------------------------------------------------------------*/
487 * This function returns the max dimms for a given memory channel on a given
488 * processor. It first searches the platform override table for the max dimms
489 * value. If it is not provided, the AGESA default value is returned. The target
490 * socket must be a valid present socket.
492 * @param[in] PlatformMemoryConfiguration - Platform config table
493 * @param[in] SocketID - ID of the processor that owns the channel
494 * @param[in] ChannelID - Channel to get max dimms for
497 * @return UINT8 - Max Number of Dimms for that channel
500 GetMaxDimmsPerChannel (
501 IN PSO_TABLE *PlatformMemoryConfiguration,
506 UINT8 *DimmsPerChPtr;
509 DimmsPerChPtr = FindPSOverrideEntry (PlatformMemoryConfiguration, PSO_MAX_DIMMS, SocketID, ChannelID, 0, NULL, NULL);
510 if (DimmsPerChPtr != NULL) {
511 MaxDimmPerCH = *DimmsPerChPtr;
513 MaxDimmPerCH = MAX_DIMMS_PER_CHANNEL;
515 // Maximum number of dimms per channel cannot be larger than its default value.
516 ASSERT (MaxDimmPerCH <= MAX_DIMMS_PER_CHANNEL);
521 /* -----------------------------------------------------------------------------*/
525 * This function returns the max memory channels on a given processor.
526 * It first searches the platform override table for the max channels value.
527 * If it is not provided, the AGESA default value is returned.
529 * @param[in] PlatformMemoryConfiguration - Platform config table
530 * @param[in] SocketID - ID of the processor
531 * @param[in] StdHeader - Header for library and services
534 * @return UINT8 - Max Number of Channels on that Processor
537 GetMaxChannelsPerSocket (
538 IN PSO_TABLE *PlatformMemoryConfiguration,
540 IN AMD_CONFIG_PARAMS *StdHeader
543 UINT8 *ChannelsPerSocketPtr;
544 UINT8 MaxChannelsPerSocket;
546 if (IsProcessorPresent (SocketID, StdHeader)) {
547 ChannelsPerSocketPtr = FindPSOverrideEntry (PlatformMemoryConfiguration, PSO_MAX_CHNLS, SocketID, 0, 0, NULL, NULL);
548 if (ChannelsPerSocketPtr != NULL) {
549 MaxChannelsPerSocket = *ChannelsPerSocketPtr;
551 MaxChannelsPerSocket = MAX_CHANNELS_PER_SOCKET;
553 // Maximum number of channels per socket cannot be larger than its default value.
554 ASSERT (MaxChannelsPerSocket <= MAX_CHANNELS_PER_SOCKET);
556 MaxChannelsPerSocket = 0;
559 return MaxChannelsPerSocket;
562 /* -----------------------------------------------------------------------------*/
566 * This function returns the max number of chip select on a given channel of
567 * a given processor. It first searches the platform override table for the max
568 * chip select value. If it is not provided, the AGESA default value is returned.
569 * The target socket must be a valid present socket.
571 * @param[in] PlatformMemoryConfiguration - Platform config table
572 * @param[in] SocketID - ID of the processor
573 * @param[in] ChannelID - ID of a channel
576 * @return UINT8 - Max Number of chip selects on the channel of the Processor
580 IN PSO_TABLE *PlatformMemoryConfiguration,
585 UINT8 *CSPerSocketPtr;
586 UINT8 MaxCSPerChannel;
588 CSPerSocketPtr = FindPSOverrideEntry (PlatformMemoryConfiguration, PSO_MAX_CHIPSELS, SocketID, ChannelID, 0, NULL, NULL);
589 if (CSPerSocketPtr != NULL) {
590 MaxCSPerChannel = *CSPerSocketPtr;
592 MaxCSPerChannel = MAX_CS_PER_CHANNEL;
594 // Max chip select per channel cannot be larger than its default value
595 ASSERT (MaxCSPerChannel <= MAX_CS_PER_CHANNEL);
597 return MaxCSPerChannel;
600 /* -----------------------------------------------------------------------------*/
604 * This function returns the index of the first Dimm SPD structure for a
605 * given processor socket. It checks the Max Dimms per channel for every memory
606 * channel on every processor up to the current one, and adds them together.
608 * This function may also be used to calculate the maximum dimms per system
609 * by passing the total number of dimm sockets
611 * @param[in] PlatformMemoryConfiguration - Platform config table
612 * @param[in] SocketID - ID of the processor
613 * @param[in] StdHeader - Header for library and services
615 * @return UINT8 - SPD Index
619 IN PSO_TABLE *PlatformMemoryConfiguration,
621 IN AMD_CONFIG_PARAMS *StdHeader
624 UINT8 SpdSocketIndex;
627 UINT8 MaxChannelsPerSocket;
630 for (Socket = 0; Socket < SocketID; Socket++) {
631 MaxChannelsPerSocket = GetMaxChannelsPerSocket (PlatformMemoryConfiguration, Socket, StdHeader);
632 for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
633 SpdSocketIndex = SpdSocketIndex + GetMaxDimmsPerChannel (PlatformMemoryConfiguration, Socket, Channel);
636 return SpdSocketIndex;
639 /* -----------------------------------------------------------------------------*/
643 * This function returns the index of the first Dimm SPD structure for a
644 * given channel relative to the processor socket. It checks the Max Dimms per
645 * channel for every memory channel on that processor up to the current one,
646 * and adds them together.
648 * This function may also be used to calculate the maximum dimms per system
649 * by passing the total number of DIMM sockets
651 * @param[in] PlatformMemoryConfiguration - Platform config table
652 * @param[in] SocketID - ID of the processor
653 * @param[in] ChannelID - ID of the Channel
654 * @param[in] StdHeader - Header for library and services
656 * @return UINT8 - SPD Index
660 IN PSO_TABLE *PlatformMemoryConfiguration,
663 IN AMD_CONFIG_PARAMS *StdHeader
666 UINT8 SpdChannelIndex;
670 ASSERT (ChannelID < GetMaxChannelsPerSocket (PlatformMemoryConfiguration, SocketID, StdHeader))
671 for (Channel = 0; Channel < ChannelID; Channel++) {
672 SpdChannelIndex = SpdChannelIndex + GetMaxDimmsPerChannel (PlatformMemoryConfiguration, SocketID, Channel);
674 return SpdChannelIndex;
677 /*-----------------------------------------------------------------------------*/
680 * This function returns the upper 32 bits mask for variable MTRR based on
681 * the CPU_LOGICAL_ID.
682 * @param[in] *LogicalIdPtr - Pointer to the CPU_LOGICAL_ID
683 * @param[in] StdHeader - Header for library and services
685 * @return UINT32 - MTRR mask for upper 32 bits
690 IN CPU_LOGICAL_ID *LogicalIdPtr,
691 IN AMD_CONFIG_PARAMS *StdHeader
695 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
696 CONST CACHE_INFO *CacheInfoPtr;
698 GetCpuServicesFromLogicalId (LogicalIdPtr, (CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
699 FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &TempNotCare, StdHeader);
700 return (UINT32) (CacheInfoPtr->VariableMtrrMask >> 32);
704 /*-----------------------------------------------------------------------------*/
707 * This function returns number of memclk converted from ns
708 * @param[in] Speed - memclk frequency
709 * @param[in] NumberOfns - number of ns to be converted
711 * @return UINT32 - number of memclk
716 IN MEMORY_BUS_SPEED Speed,
720 return (UINT32) ((NumberOfns * Speed + 999) / 1000);