diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI')
-rw-r--r-- | src/vendorcode/amd/agesa/f15tn/Proc/Mem/Feat/DMI/mfDMI.c | 677 |
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 + *--------------------------------------------------------------------------------------- + */ + |