summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSpdDriver.c291
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);
+}