diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c | |
download | zprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz |
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c')
-rw-r--r-- | ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c new file mode 100644 index 0000000..fe916cc --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c @@ -0,0 +1,291 @@ +/** @file + + This file contains functions that read the SPD data for each DIMM slot over + the SMBus interface. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved. + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement. + +**/ + +#include "MrcSpdDriver.h" +#include "MrcSpdProcessing.h" + +#define MAX_SPD_PAGE_COUNT (1) +#define MAX_SPD_PAGE_SIZE (256) +#define MAX_SPD_SIZE (MAX_SPD_PAGE_SIZE * MAX_SPD_PAGE_COUNT) +#define SPD_PAGE_ADDRESS_0 (0x6C) +#define SPD_PAGE_ADDRESS_1 (0x6E) + +/** +@brief + Read the SPD data over the SMBus, at the specified SPD address, starting at + the specified starting offset and read the given amount of data. + + @param[in, out] Inputs - Mrc Inputs structure + @param[in] SpdAddress - SPD SMBUS address + @param[in, out] Buffer - Buffer to store the data. + @param[in] Start - Starting SPD offset + @param[in] Size - The number of bytes of data to read and also the size of the buffer. + @param[in, out] Page - The final page that is being pointed to. + + @retval mrcSuccess if the read is successful, otherwise mrcDimmNotExist, which + @retval indicates that no slots are populated. +**/ +static +MrcStatus +MrcDoSpdRead ( + IN OUT MrcInput *const Inputs, + IN const U8 SpdAddress, + IN OUT U8 *const Buffer, + IN const U16 Start, + IN U16 Size, + IN OUT U8 *Page + ) +{ + MrcDebug *Debug; + MrcStatus Status; + BOOL PageUpdate; + U16 Count; + U16 Index; + + Debug = &Inputs->Debug; + Status = mrcFail; + if ((Buffer != NULL) && (Start < MAX_SPD_SIZE) && ((Start + Size) < MAX_SPD_SIZE)) { + Count = 0; + PageUpdate = FALSE; + while (Size--) { + Index = Start + Count; + if ((Index / MAX_SPD_PAGE_SIZE) != *Page) { + *Page = (U8) (Index / MAX_SPD_PAGE_SIZE); + PageUpdate = TRUE; + } + Index %= MAX_SPD_PAGE_SIZE; + if (PageUpdate == TRUE) { + PageUpdate = FALSE; + MrcOemSmbusWrite8 (Inputs->SmbusBaseAddress, (*Page == 0) ? SPD_PAGE_ADDRESS_0 : SPD_PAGE_ADDRESS_1, 0, 0); + } + Status = MrcOemSmbusRead8 (Inputs->SmbusBaseAddress, SpdAddress, (U8) Index, &Buffer[Count]); + if (mrcSuccess != Status) { + break; + } + Count++; + } + } + return (Status); +} + +/** +@brief + See if there is valid XMP SPD data. + + @param[in] Debug - Mrc debug structure. + @param[in, out] Spd - Mrc SPD structure. + @param[in] XmpStart - The current offset in the SPD. + + @retval TRUE if valid, FALSE in not. +**/ +static +BOOL +VerifyXmp ( + IN MrcDebug *Debug, + IN OUT MrcSpd *const Spd, + IN const U16 XmpStart + ) +{ + SPD_EXTREME_MEMORY_PROFILE_HEADER *Header; + + switch (Spd->Ddr3.General.DramDeviceType.Bits.Type) { +#if ((SUPPORT_DDR3 == SUPPORT) || (SUPPORT_LPDDR3 == SUPPORT)) +#if (SUPPORT_DDR3 == SUPPORT) + case MRC_SPD_DDR3_SDRAM_TYPE_NUMBER: +#endif +#if (SUPPORT_LPDDR3 == SUPPORT) + case MRC_SPD_LPDDR3_SDRAM_TYPE_NUMBER: +#endif + Header = &Spd->Ddr3.Xmp.Header; + break; +#endif + default: + return (FALSE); + } + if (XmpStart == ((U32) (Header) - (U32) Spd)) { + if ((XMP_ID_STRING == Header->XmpId) && ((Header->XmpRevision.Data & 0xFE) == 0x12)) { + return (TRUE); + } else { + Header->XmpId = 0; + Header->XmpOrgConf.Data = 0; + Header->XmpRevision.Data = 0; + } + } else { + return (TRUE); + } + return (FALSE); +} + +/** +@brief + Read the SPD data over the SMBus, for all DIMM slots and copy the data to the MrcData structure. + The SPD data locations read is controlled by the current boot mode. + + @param[in] BootMode - Mrc Boot Mode + @param[in, out] Inputs - Mrc Inputs structure + + @retval mrcSuccess if the read is successful, otherwise mrcDimmNotExist, which + @retval indicates that no slots are populated. +**/ +MrcStatus +MrcGetSpdData ( + IN const MrcBootMode BootMode, + IN OUT MrcInput *const Inputs + ) +{ +#pragma pack (push, 1) + typedef struct { + U16 Start; + U16 End; + U8 BootMode; + U8 Profile; + } SpdOffsetTable; +#pragma pack (pop) + const SpdOffsetTable Table3[] = { +#ifdef ULT_FLAG + { 0, 40, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, +#else // ULT_FLAG + { 0, 38, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, +#endif // ULT_FLAG + { 60, 63, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, + { SPD3_MANUF_START, SPD3_MANUF_END, (1 << bmCold) | (1 << bmWarm) | (1 << bmFast), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, + { 128, 145, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, +#if (SUPPORT_SPD_CRC == SUPPORT) + { 39, 59, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, + { 64, 125, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, +#endif +#if SUPPORT_XMP == SUPPORT + { 176, 179, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, + { 180, 184, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, + { 185, 215, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, + { 220, 250, (1 << bmCold), (1 << STD_PROFILE) | (1 << XMP_PROFILE1) | (1 << XMP_PROFILE2) | (1 << USER_PROFILE) }, +#endif + }; + MrcDebug *Debug; + MrcControllerIn *ControllerIn; + MrcChannelIn *ChannelIn; + MrcDimmIn *DimmIn; + U8 *Buffer; + const SpdOffsetTable *Tbl; + const SpdOffsetTable *TableSelect; + MrcStatus Status; + U16 Offset; +#ifdef MRC_DEBUG_PRINT + U16 Line; + U16 Address; +#endif + U8 Controller; + U8 Channel; + U8 Dimm; + U8 Count; + U8 Index; + U8 Stop; + U8 Page; + + Debug = &Inputs->Debug; + Count = 0; + Page = 0; + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + ControllerIn = &Inputs->Controller[Controller]; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + ChannelIn = &ControllerIn->Channel[Channel]; + if (ChannelIn->Status == CHANNEL_PRESENT) { + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + Status = mrcSuccess; + DimmIn = &ChannelIn->Dimm[Dimm]; + if ((DimmIn->Status == DIMM_ENABLED) || (DimmIn->Status == DIMM_DISABLED)) { + Buffer = (U8 *) &DimmIn->Spd; + if (DimmIn->SpdAddress > 0) { + TableSelect = Table3; + Stop = (sizeof (Table3) / sizeof (SpdOffsetTable)); + for (Index = 0; (Status == mrcSuccess) && (Index < Stop); Index++) { + Tbl = &TableSelect[Index]; + if (((1 << BootMode) & Tbl->BootMode) && ((1 << Inputs->MemoryProfile) & Tbl->Profile)) { + Status = MrcDoSpdRead ( + Inputs, + DimmIn->SpdAddress, + &Buffer[Tbl->Start], + Tbl->Start, + Tbl->End - Tbl->Start + 1, + &Page + ); + if (Status == mrcSuccess) { + for (Offset = Tbl->Start; Offset <= Tbl->End; Offset++) { + DimmIn->SpdValid[Offset / CHAR_BITS] |= 1 << (Offset % CHAR_BITS); + } +#if SUPPORT_XMP == SUPPORT + if (bmCold == BootMode) { + if (FALSE == VerifyXmp (Debug, (MrcSpd *) Buffer, Tbl->Start)) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "VerifyXmp FALSE\n" + ); + break; + } + } +#endif // SUPPORT_XMP + } else { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_WARNING, + "ERROR! Fail to read SMB DimmAddress %Xh Offset %Xh - %Xh\n", + DimmIn->SpdAddress, + Tbl->Start, + Tbl->End + ); + } // if (Status... + } // if (((1 << BootMode)... + } // for (Index... + } else { // if (DimmIn->SpdAddress > 0), 0 = MemoryDown, see EnableMemoryDown() + Status = mrcSuccess; + } + + if (Status == mrcSuccess) { + Count++; +#ifdef MRC_DEBUG_PRINT + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\nChannel %d Dimm %d\n", Channel, Dimm); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "SPD: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); + for (Line = 0; Line < (sizeof (MrcSpd) / 16); Line++) { + Address = Line * 16; + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " % 4Xh(% 5u): ", Address, Address); + for (Offset = 0; Offset < 16; Offset++) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "%02X ", Buffer[Address + Offset]); + } + for (Offset = 0; Offset < 16; Offset++) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "%c", isprint (Buffer[Address + Offset]) ? Buffer[Address + Offset] : '.'); + } + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\n"); + } +#endif + } else { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_WARNING, "DIMM is not populated on channel %u, slot %u\n", Channel, Dimm); + } // if (Status... + } // if (DimmIn->Status == DIMM_ENABLED) + } // for (Dimm... + } // if (ChannelIn->Status... + } // for (Channel... + } // for (Controller... + return ((Count > 0) ? mrcSuccess : mrcDimmNotExist); +} |