/* $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 *--------------------------------------------------------------------------------------- */