summaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c')
-rw-r--r--src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c677
1 files changed, 677 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c b/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c
new file mode 100644
index 0000000000..213c3ccff6
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c
@@ -0,0 +1,677 @@
+/* $NoKeywords:$ */
+/**
+ * @file
+ *
+ * mfDMI.c
+ *
+ * Memory DMI table support.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project: AGESA
+ * @e sub-project: (Mem/Main)
+ * @e \$Revision: 64954 $ @e \$Date: 2012-02-03 03:04:45 -0600 (Fri, 03 Feb 2012) $
+ *
+ **/
+/*****************************************************************************
+ *
+ * Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
+ *
+ * AMD is granting you permission to use this software (the Materials)
+ * pursuant to the terms and conditions of your Software License Agreement
+ * with AMD. This header does *NOT* give you permission to use the Materials
+ * or any rights under AMD's intellectual property. Your use of any portion
+ * of these Materials shall constitute your acceptance of those terms and
+ * conditions. If you do not agree to the terms and conditions of the Software
+ * License Agreement, please do not use any portion of these Materials.
+ *
+ * CONFIDENTIALITY: The Materials and all other information, identified as
+ * confidential and provided to you by AMD shall be kept confidential in
+ * accordance with the terms and conditions of the Software License Agreement.
+ *
+ * LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION
+ * PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
+ * MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE,
+ * OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE.
+ * IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER
+ * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS
+ * INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE,
+ * GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER
+ * RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE
+ * EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES,
+ * THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
+ *
+ * AMD does not assume any responsibility for any errors which may appear in
+ * the Materials or any other related information provided to you by AMD, or
+ * result from use of the Materials or any related information.
+ *
+ * You agree that you will not reverse engineer or decompile the Materials.
+ *
+ * NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any
+ * further information, software, technical information, know-how, or show-how
+ * available to you. Additionally, AMD retains the right to modify the
+ * Materials at any time, without notice, and is not obligated to provide such
+ * modified Materials to you.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with
+ * "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is
+ * subject to the restrictions as set forth in FAR 52.227-14 and
+ * DFAR252.227-7013, et seq., or its successor. Use of the Materials by the
+ * Government constitutes acknowledgement of AMD's proprietary rights in them.
+ *
+ * EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any
+ * direct product thereof will be exported directly or indirectly, into any
+ * country prohibited by the United States Export Administration Act and the
+ * regulations thereunder, without the required authorization from the U.S.
+ * government nor will be used for any purpose prohibited by the same.
+ * ***************************************************************************
+ *
+ */
+
+/*
+ *----------------------------------------------------------------------------
+ * MODULES USED
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#include "AGESA.h"
+#include "Ids.h"
+#include "heapManager.h"
+#include "cpuServices.h"
+#include "mm.h"
+#include "mn.h"
+#include "mu.h"
+#include "GeneralServices.h"
+#include "Filecode.h"
+CODE_GROUP (G2_PEI)
+RDATA_GROUP (G2_PEI)
+
+#define FILECODE PROC_MEM_FEAT_DMI_MFDMI_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#define MAX_DCTS_PER_DIE 2
+
+/*----------------------------------------------------------------------------
+ * TYPEDEFS AND STRUCTURES
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ * PROTOTYPES OF LOCAL FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+BOOLEAN
+MemFDMISupport3 (
+ IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
+ );
+
+BOOLEAN
+MemFDMISupport2 (
+ IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
+ );
+
+/*----------------------------------------------------------------------------
+ * EXPORTED FUNCTIONS
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function gets DDR3 DMI information from SPD buffer and stores the info into heap
+ *
+ * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK
+ *
+ */
+BOOLEAN
+MemFDMISupport3 (
+ IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
+ )
+{
+ UINT8 i;
+ UINT8 Dimm;
+ UINT8 Socket;
+ UINT8 NodeId;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 temp;
+ UINT8 MaxDimms;
+ UINT8 DimmIndex;
+ UINT8 MaxChannelsPerSocket;
+ UINT8 MaxDimmsPerChannel;
+ UINT8 FormFactor;
+ UINT16 TotalWidth;
+ UINT16 Capacity;
+ UINT16 Width;
+ UINT16 Rank;
+ UINT16 BusWidth;
+ UINT64 ManufacturerIdCode;
+ UINT32 MaxSockets;
+ UINT32 Address;
+ UINT32 TotalSize;
+ UINT32 DimmSize;
+ UINT64 AddrValue;
+ UINT64 DctMemBase;
+ UINT64 NodeMemBase;
+ UINT64 SysMemSize;
+ INT32 MTB_ps;
+ INT32 FTB_ps;
+ INT32 Value32;
+ BOOLEAN DctInterleaveEnabled;
+ BOOLEAN NodeInterleaveEnabled;
+
+ MEM_NB_BLOCK *NBPtr;
+ MEM_DATA_STRUCT *MemPtr;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ MEM_DMI_INFO *DmiTable;
+ MEM_PARAMETER_STRUCT *RefPtr;
+
+ DIE_STRUCT *MCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ SPD_DEF_STRUCT *SpdDataStructure;
+
+ NBPtr = MemMainPtr->NBPtr;
+ MemPtr = MemMainPtr->MemPtr;
+ SpdDataStructure = MemPtr->SpdDataStructure;
+ MCTPtr = NBPtr->MCTPtr;
+ RefPtr = MemPtr->ParameterListPtr;
+
+ // Initialize local variables
+ MaxDimms = 0;
+ TotalSize = 0;
+ NodeMemBase = 0;
+ SysMemSize = 0;
+
+ AGESA_TESTPOINT (TpProcMemDmi, &MemPtr->StdHeader);
+
+ ASSERT (NBPtr != NULL);
+
+ MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
+ for (Socket = 0; Socket < MaxSockets; Socket++) {
+ for (Channel = 0; Channel < GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); Channel++) {
+ temp = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ MaxDimms = MaxDimms + temp;
+ }
+ }
+
+ // Allocate heap for memory DMI table 16, 17, 19, 20
+ AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 6 + sizeof (DMI_T17_MEMORY_TYPE);
+
+ AllocHeapParams.BufferHandle = AMD_DMI_MEM_DEV_INFO_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
+ PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_DMI_TABLE_DDR3, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader);
+ SetMemError (AGESA_CRITICAL, MCTPtr);
+ ASSERT(FALSE); // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR3
+ return FALSE;
+ }
+
+ DmiTable = (MEM_DMI_INFO *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 6 + sizeof (DMI_T17_MEMORY_TYPE));
+ *((UINT8 *) (AllocHeapParams.BufferPtr)) = MaxDimms; // Number of memory devices
+ *((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 0; // For Type Detail
+ *((DMI_T17_MEMORY_TYPE *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 6)) = Ddr3MemType; // Memory type
+
+ // Calculate the total memory size in the system
+ for (Socket = 0; Socket < MaxSockets; Socket++) {
+ SysMemSize += (NBPtr[Socket].MCTPtr->NodeMemSize << 6);
+ }
+ //
+ // Gather memory DMI info
+ //
+ DimmIndex = 0;
+ for (Socket = 0; Socket < MaxSockets; Socket++) {
+ MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
+ NodeInterleaveEnabled = (NBPtr[Socket].GetBitField (&NBPtr[Socket], BFDramIntlvEn) == 0) ? FALSE : TRUE;
+ DctInterleaveEnabled = (NBPtr[Socket].GetBitField (&NBPtr[Socket], BFDctSelIntLvEn) == 0) ? FALSE : TRUE;
+ DctMemBase = 0;
+ for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
+ //
+ // Get Node number and Dct number for this channel
+ //
+ ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
+ NodeId = ChannelPtr->MCTPtr->NodeId;
+ Dct = ChannelPtr->Dct;
+ NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct);
+ MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++, DimmIndex++) {
+ DmiTable[DimmIndex].TotalWidth = 0xFFFF;
+ DmiTable[DimmIndex].DataWidth = 0xFFFF;
+ DmiTable[DimmIndex].MemorySize = 0;
+ DmiTable[DimmIndex].Speed = 0;
+ DmiTable[DimmIndex].ManufacturerIdCode = 0;
+ DmiTable[DimmIndex].Attributes = 0;
+ DmiTable[DimmIndex].StartingAddr = 0;
+ DmiTable[DimmIndex].EndingAddr = 0;
+ DmiTable[DimmIndex].DimmPresent = 0;
+ DmiTable[DimmIndex].Socket = Socket;
+ DmiTable[DimmIndex].Channel = Channel;
+ DmiTable[DimmIndex].Dimm = Dimm;
+ DmiTable[DimmIndex].ConfigSpeed = 0;
+ DmiTable[DimmIndex].ExtSize = 0;
+ DmiTable[DimmIndex].ExtStartingAddr = 0;
+ DmiTable[DimmIndex].ExtEndingAddr = 0;
+ DmiTable[DimmIndex].FormFactor = UnknowFormFactor;
+
+ for (i = 0; i < 4; i++) {
+ DmiTable[DimmIndex].SerialNumber[i] = 0xFF;
+ }
+
+ for (i = 0; i < 18; i++) {
+ DmiTable[DimmIndex].PartNumber[i] = 0x0;
+ }
+
+ if (SpdDataStructure[DimmIndex].DimmPresent) {
+ // Total Width (offset 08h) & Data Width (offset 0Ah)
+ TotalWidth = (UINT16) SpdDataStructure[DimmIndex].Data[8];
+ if ((TotalWidth & 0x18) == 0) {
+ // non ECC
+ if ((TotalWidth & 0x07) == 0) {
+ DmiTable[DimmIndex].TotalWidth = 8; // 8 bits
+ } else if ((TotalWidth & 0x07) == 1) {
+ DmiTable[DimmIndex].TotalWidth = 16; // 16 bits
+ } else if ((TotalWidth & 0x07) == 2) {
+ DmiTable[DimmIndex].TotalWidth = 32; // 32 bits
+ } else if ((TotalWidth & 0x07) == 3) {
+ DmiTable[DimmIndex].TotalWidth = 64; // 64 bits
+ }
+ DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth ;
+ } else {
+ // ECC
+ if ((TotalWidth & 0x07) == 0) {
+ DmiTable[DimmIndex].TotalWidth = 8 + 8; // 8 bits
+ } else if ((TotalWidth & 0x07) == 1) {
+ DmiTable[DimmIndex].TotalWidth = 16 + 8; // 16 bits
+ } else if ((TotalWidth & 0x07) == 2) {
+ DmiTable[DimmIndex].TotalWidth = 32 + 8; // 32 bits
+ } else if ((TotalWidth & 0x07) == 3) {
+ DmiTable[DimmIndex].TotalWidth = 64 + 8; // 64 bits
+ }
+ DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth - 8;
+ }
+
+ // Memory Size (offset 0Ch)
+ Capacity = 0;
+ BusWidth = 0;
+ Width = 0;
+ Rank = 0;
+ temp = (UINT8) SpdDataStructure[DimmIndex].Data[4];
+ if ((temp & 0x0F) == 0) {
+ Capacity = 0x0100; // 256M
+ } else if ((temp & 0x0F) == 1) {
+ Capacity = 0x0200; // 512M
+ } else if ((temp & 0x0F) == 2) {
+ Capacity = 0x0400; // 1G
+ } else if ((temp & 0x0F) == 3) {
+ Capacity = 0x0800; // 2G
+ } else if ((temp & 0x0F) == 4) {
+ Capacity = 0x1000; // 4G
+ } else if ((temp & 0x0F) == 5) {
+ Capacity = 0x2000; // 8G
+ } else if ((temp & 0x0F) == 6) {
+ Capacity = 0x4000; // 16G
+ }
+
+ temp = (UINT8) SpdDataStructure[DimmIndex].Data[8];
+ if ((temp & 0x07) == 0) {
+ BusWidth = 8; // 8 bits
+ } else if ((temp & 0x07) == 1) {
+ BusWidth = 16; // 16 bits
+ } else if ((temp & 0x07) == 2) {
+ BusWidth = 32; // 32 bits
+ } else if ((temp & 0x07) == 3) {
+ BusWidth = 64; // 64 bits
+ }
+
+ temp = (UINT8) SpdDataStructure[DimmIndex].Data[7];
+ if ((temp & 0x07) == 0) {
+ Width = 4; // 4 bits
+ } else if ((temp & 0x07) == 1) {
+ Width = 8; // 8 bits
+ } else if ((temp & 0x07) == 2) {
+ Width = 16; // 16 bits
+ } else if ((temp & 0x07) == 3) {
+ Width = 32; // 32 bits
+ }
+
+ temp = (UINT8) SpdDataStructure[DimmIndex].Data[7];
+ if (((temp >> 3) & 0x07) == 0) {
+ Rank = 1; // 4 bits
+ DmiTable[DimmIndex].Attributes = 1; // Single Rank Dimm
+ } else if (((temp >> 3) & 0x07) == 1) {
+ Rank = 2; // 8 bits
+ DmiTable[DimmIndex].Attributes = 2; // Dual Rank Dimm
+ } else if (((temp >> 3) & 0x07) == 2) {
+ Rank = 3; // 16 bits
+ } else if (((temp >> 3) & 0x07) == 3) {
+ Rank = 4; // 32 bits
+ DmiTable[DimmIndex].Attributes = 4; // Quad Rank Dimm
+ }
+
+ DimmSize = (UINT32) (Capacity / 8 * BusWidth / Width * Rank);
+ if (DimmSize < 0x7FFF) {
+ DmiTable[DimmIndex].MemorySize = (UINT16) DimmSize;
+ } else {
+ DmiTable[DimmIndex].MemorySize = 0x7FFF;
+ DmiTable[DimmIndex].ExtSize = DimmSize;
+ }
+
+ // Form Factor (offset 0Eh)
+ FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[3];
+ if ((FormFactor & 0x0F) == 0x01 || (FormFactor & 0x0F) == 0x02) {
+ DmiTable[DimmIndex].FormFactor = 0x09; // RDIMM or UDIMM
+ } else if ((FormFactor & 0x0F) == 0x03) {
+ DmiTable[DimmIndex].FormFactor = 0x0D; // SO-DIMM
+ }
+
+ // Type Detail (offset 13h)
+ if ((FormFactor & 0x0F) == 0x01) {
+ *((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 1; // Registered (Buffered)
+ } else {
+ *((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 2; // Unbuffered (Unregistered)
+ }
+
+ // Speed (offset 15h)
+ MTB_ps = ((INT32) SpdDataStructure[DimmIndex].Data[10] * 1000) / SpdDataStructure[DimmIndex].Data[11];
+ FTB_ps = (SpdDataStructure[DimmIndex].Data[9] >> 4) / (SpdDataStructure[DimmIndex].Data[9] & 0xF);
+ Value32 = (MTB_ps * SpdDataStructure[DimmIndex].Data[12]) + (FTB_ps * (INT8) SpdDataStructure[DimmIndex].Data[34]) ;
+ if (Value32 <= 938) {
+ DmiTable[DimmIndex].Speed = 1067; // DDR3-2133
+ } else if (Value32 <= 1071) {
+ DmiTable[DimmIndex].Speed = 933; // DDR3-1866
+ } else if (Value32 <= 1250) {
+ DmiTable[DimmIndex].Speed = 800; // DDR3-1600
+ } else if (Value32 <= 1500) {
+ DmiTable[DimmIndex].Speed = 667; // DDR3-1333
+ } else if (Value32 <= 1875) {
+ DmiTable[DimmIndex].Speed = 533; // DDR3-1066
+ } else if (Value32 <= 2500) {
+ DmiTable[DimmIndex].Speed = 400; // DDR3-800
+ }
+
+ // Manufacturer (offset 17h)
+ ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[118];
+ DmiTable[DimmIndex].ManufacturerIdCode = (ManufacturerIdCode << 8) | ((UINT64) SpdDataStructure[DimmIndex].Data[117]);
+
+ // Serial Number (offset 18h)
+ for (i = 0; i < 4; i++) {
+ DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 122];
+ }
+ // Part Number (offset 1Ah)
+ for (i = 0; i < 18; i++) {
+ DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 128];
+ }
+
+ // Configured Memory Clock Speed (offset 20h)
+ DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed;
+
+ // Starting/Ending Address for each DIMM
+ // If Ending Address >= 0xFFFFFFFF, update Starting Address & Ending Address to 0xFFFFFFFF,
+ // and use the Extended Starting Address & Extended Ending Address instead.
+ if ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm) & 1) != 0) {
+ Address = (NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm)) & NBPtr->CsRegMsk;
+ Address = (Address & 0xFFFF0000) >> 2;
+ if (DctInterleaveEnabled) {
+ // When channel interleave is enabled, all the DIMMs on the node share the same starting address
+ Address = (UINT32)NodeMemBase;
+ } else {
+ Address += (UINT32) (NodeMemBase + DctMemBase);
+ }
+ if (NodeInterleaveEnabled) {
+ // When node interleave is enabled, all the DIMMs in the system share the same starting address
+ Address = 0;
+ }
+ DmiTable[DimmIndex].StartingAddr = Address;
+ AddrValue = (UINT64) Address + ((UINT64) ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSMask0Reg + Dimm) & 0xFFFF0000) + 0x00080000) >> 2) - 1;
+ if (DctInterleaveEnabled) {
+ // When channle interleave is enabled, all the DIMMs on the node share the same ending address
+ AddrValue = (NodeMemBase + (NBPtr[NodeId].MCTPtr->NodeMemSize << 6)) - 1;
+ }
+ if (NodeInterleaveEnabled) {
+ // When node interleave is enabled, all the DIMMs in the system share the same ending address
+ AddrValue = SysMemSize - 1;
+ }
+ if (AddrValue >= ((UINT64) 0xFFFFFFFF)) {
+ DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFFUL;
+ DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFFUL;
+ DmiTable[DimmIndex].ExtStartingAddr = (UINT64) Address;
+ DmiTable[DimmIndex].ExtEndingAddr = AddrValue;
+ } else {
+ DmiTable[DimmIndex].EndingAddr = (UINT32) AddrValue;
+ }
+ }
+ } // Dimm present
+ TotalSize += (UINT32) DmiTable[DimmIndex].MemorySize;
+ } // Dimm loop
+ DctMemBase += (NBPtr[Socket].DCTPtr->Timings.DctMemSize << 6);
+ } // Channel loop
+ NodeMemBase += (NBPtr[Socket].MCTPtr->NodeMemSize << 6);
+ } // Socket loop
+
+ *((UINT32 *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = TotalSize; // Max Capacity
+
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------*/
+/**
+ *
+ *
+ * This function gets DDR2 DMI information from SPD buffer and stores the info into heap
+ *
+ * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK
+ *
+ */
+BOOLEAN
+MemFDMISupport2 (
+ IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
+ )
+{
+ UINT8 i;
+ UINT8 Dimm;
+ UINT8 Socket;
+ UINT8 NodeId;
+ UINT8 Dct;
+ UINT8 Channel;
+ UINT8 temp;
+ UINT8 MaxDimms;
+ UINT8 DimmIndex;
+ UINT8 MaxChannelsPerSocket;
+ UINT8 MaxDimmsPerChannel;
+ UINT8 FormFactor;
+ UINT8 Temp;
+ UINT8 Rank;
+ UINT16 TotalWidth;
+ UINT32 Speed;
+ UINT32 MaxSockets;
+ UINT32 Address;
+
+ MEM_NB_BLOCK *NBPtr;
+ MEM_DATA_STRUCT *MemPtr;
+ ALLOCATE_HEAP_PARAMS AllocHeapParams;
+ MEM_DMI_INFO *DmiTable;
+ DIE_STRUCT *MCTPtr;
+ CH_DEF_STRUCT *ChannelPtr;
+ SPD_DEF_STRUCT *SpdDataStructure;
+ MEM_PARAMETER_STRUCT *RefPtr;
+
+ NBPtr = MemMainPtr->NBPtr;
+ MemPtr = MemMainPtr->MemPtr;
+ SpdDataStructure = MemPtr->SpdDataStructure;
+ MCTPtr = NBPtr->MCTPtr;
+ RefPtr = MemPtr->ParameterListPtr;
+
+ // Initialize local variables
+ MaxDimms = 0;
+
+ ASSERT (NBPtr != NULL);
+
+ MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
+ for (Socket = 0; Socket < MaxSockets; Socket++) {
+ for (Channel = 0; Channel < GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); Channel++) {
+ temp = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ MaxDimms = MaxDimms + temp;
+ }
+ }
+
+ // Allocate heap for memory DMI table 16, 17, 19, 20
+ AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 3;
+
+ AllocHeapParams.BufferHandle = AMD_DMI_MEM_DEV_INFO_HANDLE;
+ AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
+ if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
+ PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_DMI_TABLE_DDR2, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader);
+ SetMemError (AGESA_CRITICAL, MCTPtr);
+ ASSERT(FALSE); // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR2
+ return FALSE;
+ }
+
+ DmiTable = (MEM_DMI_INFO *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2 + sizeof (DMI_T17_MEMORY_TYPE));
+ *((UINT16 *) (AllocHeapParams.BufferPtr)) = MaxDimms; // Number of memory devices
+ *((DMI_T17_MEMORY_TYPE *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = Ddr2MemType; // Memory type
+
+ //
+ // DMI TYPE 17
+ //
+ DimmIndex = 0;
+ for (Socket = 0; Socket < MaxSockets; Socket++) {
+ MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
+ for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
+ //
+ // Get Node number and Dct number for this channel
+ //
+ ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
+ NodeId = ChannelPtr->MCTPtr->NodeId;
+ Dct = ChannelPtr->Dct;
+ NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct);
+ NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct);
+ MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
+ for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++, DimmIndex++) {
+ DmiTable[DimmIndex].TotalWidth = 0xFFFF;
+ DmiTable[DimmIndex].DataWidth = 0xFFFF;
+ DmiTable[DimmIndex].MemorySize = 0xFFFF;
+ DmiTable[DimmIndex].Speed = 0;
+ DmiTable[DimmIndex].ManufacturerIdCode = 0;
+ DmiTable[DimmIndex].Attributes = 0;
+ DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFF;
+ DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFF;
+ DmiTable[DimmIndex].DimmPresent = 0;
+ DmiTable[DimmIndex].ConfigSpeed = 0;
+
+ for (i = 0; i < 4; i++) {
+ DmiTable[DimmIndex].SerialNumber[i] = 0xFF;
+ }
+
+ for (i = 0; i < 18; i++) {
+ DmiTable[DimmIndex].PartNumber[i] = 0x0;
+ }
+
+ if (SpdDataStructure[DimmIndex].DimmPresent) {
+ // Total Width (offset 08h) & Data Width (offset 0Ah)
+ TotalWidth = (UINT16) SpdDataStructure[DimmIndex].Data[13];
+ if ((TotalWidth & 0x04) != 0) {
+ DmiTable[DimmIndex].TotalWidth = 4; // 4 bits
+ } else if ((TotalWidth & 0x08) != 0) {
+ DmiTable[DimmIndex].TotalWidth = 8; // 8 bits
+ } else if ((TotalWidth & 0x10) != 0) {
+ DmiTable[DimmIndex].TotalWidth = 16; // 16 bits
+ } else if ((TotalWidth & 0x20) != 0) {
+ DmiTable[DimmIndex].TotalWidth = 32; // 32 bits
+ }
+ DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth;
+
+ // Memory Size (offset 0Ch), Attributes (offset 1Bh)
+ Rank = (UINT8) SpdDataStructure[DimmIndex].Data[5] & 0x07;
+ if (Rank == 0) {
+ DmiTable[DimmIndex].Attributes = 1; // Single Rank Dimm
+ } else if (Rank == 1) {
+ DmiTable[DimmIndex].Attributes = 2; // Dual Rank Dimm
+ } else if (Rank == 3) {
+ DmiTable[DimmIndex].Attributes = 4; // Quad Rank Dimm
+ }
+
+ Temp = (UINT8) SpdDataStructure[DimmIndex].Data[31];
+ for (i = 0; i < 8; i++) {
+ if ((Temp & 0x01) == 1) {
+ DmiTable[DimmIndex].MemorySize = 0x80 * (i + 1) * (Rank + 1);
+ }
+ Temp = Temp >> 1;
+ }
+
+ // Form Factor (offset 0Eh)
+ FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[20];
+ if ((FormFactor & 0x04) == 4) {
+ DmiTable[DimmIndex].FormFactor = 0x0D; // SO-DIMM
+ } else {
+ DmiTable[DimmIndex].FormFactor = 0x09; // RDIMM or UDIMM
+ }
+
+ // DIMM Present
+ DmiTable[DimmIndex].DimmPresent = 1;
+
+ // DIMM Index
+ DmiTable[DimmIndex].Socket = Socket;
+ DmiTable[DimmIndex].Channel = Channel;
+ DmiTable[DimmIndex].Dimm = Dimm;
+
+ // Speed (offset 15h)
+ Speed = NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFDramConfigHiReg);
+ Speed = Speed & 0x00000007;
+ if (Speed == 0) {
+ DmiTable[DimmIndex].Speed = 400; // 400MHz
+ } else if (Speed == 1) {
+ DmiTable[DimmIndex].Speed = 533; // 533MHz
+ } else if (Speed == 2) {
+ DmiTable[DimmIndex].Speed = 667; // 667MHz
+ } else if (Speed == 3) {
+ DmiTable[DimmIndex].Speed = 800; // 800MHz
+ }
+
+ // Manufacturer (offset 17h)
+ DmiTable[DimmIndex].ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[64];
+
+ // Serial Number (offset 18h)
+ for (i = 0; i < 4; i++) {
+ DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 95];
+ }
+
+ // Part Number (offset 1Ah)
+ for (i = 0; i < 18; i++) {
+ DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 73];
+ }
+
+ // Configured Memory Clock Speed (offset 20h)
+ DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed;
+
+ // AGESA does NOT support this feature when bank interleaving is enabled.
+ if (!RefPtr->EnableBankIntlv) {
+ if ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm) & 1) != 0) {
+ Address = (NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm)) & NBPtr->CsRegMsk;
+ Address = Address >> 2;
+ DmiTable[DimmIndex].StartingAddr = Address;
+ DmiTable[DimmIndex].EndingAddr = Address + (UINT32) (DmiTable[DimmIndex].MemorySize * 0x0400);
+ }
+ }
+
+ } // DIMM Present
+ } // DIMM loop
+ }
+ }
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------------------
+ * L O C A L F U N C T I O N S
+ *---------------------------------------------------------------------------------------
+ */
+