diff options
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c')
-rw-r--r-- | ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c new file mode 100644 index 0000000..89464a5 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c @@ -0,0 +1,481 @@ +/** @file + + Power state and boot mode save and restore data functions. + +@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 files +// +#include "MrcTypes.h" +#include "MrcCommon.h" +#include "MrcGeneral.h" +#include "MrcGlobal.h" +#include "MrcOem.h" +#include "MrcSaveRestore.h" +#include "MrcSpdProcessing.h" + +// +// ------- IMPORTANT NOTE -------- +// MRC_MC_REGISTER_COUNT in Global.h should match this table. +// Update this define whenever you add/remove registers from this table. +// +// Total register count = 1872 + 624 = 2496 +// +const SaveDataControl SaveDataArray[] = { + {0x0000, 0x003C}, {0x0048, 0x004C}, {0x005C, 0x0078}, // 40h + 8 + 20h = 68h => 104 * 18 = 1872 + {0x0100, 0x013C}, {0x0148, 0x014C}, {0x015C, 0x0178}, + {0x0200, 0x023C}, {0x0248, 0x024C}, {0x025C, 0x0278}, + {0x0300, 0x033C}, {0x0348, 0x034C}, {0x035C, 0x0378}, + {0x0400, 0x043C}, {0x0448, 0x044C}, {0x045C, 0x0478}, + {0x0500, 0x053C}, {0x0548, 0x054C}, {0x055C, 0x0578}, + {0x0600, 0x063C}, {0x0648, 0x064C}, {0x065C, 0x0678}, + {0x0700, 0x073C}, {0x0748, 0x074C}, {0x075C, 0x0778}, + {0x0800, 0x083C}, {0x0848, 0x084C}, {0x085C, 0x0878}, + {0x0900, 0x093C}, {0x0948, 0x094C}, {0x095C, 0x0978}, + {0x0A00, 0x0A3C}, {0x0A48, 0x0A4C}, {0x0A5C, 0x0A78}, + {0x0B00, 0x0B3C}, {0x0B48, 0x0B4C}, {0x0B5C, 0x0B78}, + {0x0C00, 0x0C3C}, {0x0C48, 0x0C4C}, {0x0C5C, 0x0C78}, + {0x0D00, 0x0D3C}, {0x0D48, 0x0D4C}, {0x0D5C, 0x0D78}, + {0x0E00, 0x0E3C}, {0x0E48, 0x0E4C}, {0x0E5C, 0x0E78}, + {0x0F00, 0x0F3C}, {0x0F48, 0x0F4C}, {0x0F5C, 0x0F78}, + {0x1000, 0x103C}, {0x1048, 0x104C}, {0x105C, 0x1078}, + {0x1100, 0x113C}, {0x1148, 0x114C}, {0x115C, 0x1178}, + {0x1204, 0x1208}, // 8 + {0x1214, 0x121C}, // 12 + {0x1304, 0x1308}, // 8 + {0x1314, 0x131C}, // 12 + {0x1404, 0x140C}, // 12 + {0x1504, 0x150C}, // 12 + {0x1808, 0x1810}, // 12 + {0x1908, 0x1910}, // 12 + {0x1A04, 0x1A0C}, // 12 + {0x1B04, 0x1B0C}, // 12 + {0x1C14, 0x1C1C}, // 12 + {0x1D14, 0x1D1C}, // 12 + {0x2000, 0x2008}, // 12 + {0x3A14, 0x3A1C}, // 12 + {0x3A24, 0x3A24}, // 4 + {0x4000, 0x4014}, // 24 + {0x4024, 0x4028}, // 8 + {0x40D0, 0x40D0}, // 4 + {0x4220, 0x4224}, // 8 + {0x4294, 0x4294}, // 4 + {0x429C, 0x42A0}, // 8 + {0x42EC, 0x42FC}, // 20 + {0x438C, 0x4390}, // 8 + {0x4328, 0x4328}, // 4 + {0x4400, 0x4414}, // 24 + {0x4424, 0x4428}, // 8 + {0x44D0, 0x44D0}, // 4 + {0x4620, 0x4624}, // 8 + {0x4694, 0x4694}, // 4 + {0x469C, 0x46A0}, // 8 + {0x46EC, 0x46FC}, // 20 + {0x4728, 0x4728}, // 4 + {0x478C, 0x4790}, // 8 + {0x5884, 0x5888}, // 8 + {0x5890, 0x589C}, // 16 + {0x58A4, 0x58A4}, // 4 + {0x58D0, 0x58E4}, // 24 + {0x5880, 0x5880}, // 4 + {0x5000, 0x50DC}, // 224 + {0x59b8, 0x59b8} // 4 +}; // = 624 + +/** +@brief + This function verifies that neither CPU fuses or DIMMs have changed. + + @param[in] MrcData - Include all MRC global data. + + @retval mrcSuccess if fast boot is allowed, otherwise mrcColdBootRequired. +**/ +MrcStatus +MrcFastBootPermitted ( + IN MrcParameters *const MrcData + ) +{ + const MrcInput *Inputs; + const MrcDimmIn *DimmIn; + const U8 *CrcStart; + MrcSaveData *Save; + MrcDimmOut *DimmSave; + MRC_PCI_000_CAPID0_STRUCT Capid0Reg; + U32 CrcSize; + U8 Controller; + U8 Channel; + U8 Dimm; + U16 DimmCrc; + U32 Offset; + + CrcStart = NULL; + CrcSize = 0; + Inputs = &MrcData->SysIn.Inputs; + Save = &MrcData->SysSave.Save.Data; + + // + // Obtain the capabilities of the memory controller and see if they have changed. + // + Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_CAPID0_REG); + MrcOemMmioRead (Offset, &Capid0Reg.Data32.A.Data, Inputs->PciEBaseAddress); + MrcOemMmioRead (Offset + 4, &Capid0Reg.Data32.B.Data, Inputs->PciEBaseAddress); + if (Capid0Reg.Data != Save->McCapId.Data) { + MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "Capabilities have changed, cold boot required\n"); + MRC_DEBUG_MSG ( + &Inputs->Debug, + MSG_LEVEL_NOTE, + " '%X_%X' --> '%X_%X'\n", + Save->McCapId.Data32[1], + Save->McCapId.Data32[0], + Capid0Reg.Data32.B.Data, + Capid0Reg.Data32.A.Data + ); + return mrcColdBootRequired; + } + // + // See if any of the DIMMs have changed. + // + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + DimmIn = &Inputs->Controller[Controller].Channel[Channel].Dimm[Dimm]; + DimmSave = &Save->Controller[Controller].Channel[Channel].Dimm[Dimm]; + if (DimmIn->Status == DIMM_DISABLED) { + DimmCrc = 0; + } else { + CrcStart = MrcSpdCrcArea (MrcData, Controller, Channel, Dimm, &CrcSize); + GetDimmCrc ((const U8 *const) CrcStart, CrcSize, &DimmCrc); + } + + if (DimmCrc != DimmSave->Crc) { + MRC_DEBUG_MSG ( + &Inputs->Debug, + MSG_LEVEL_NOTE, + "Channel %u Dimm %u has changed, cold boot required\n", + Channel, + Dimm + ); + MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, " DimmCrc %Xh, DimmSave->Crc %Xh\n", DimmCrc, DimmSave->Crc); + return mrcColdBootRequired; + } + } + } + } + // + // Set RestoreMRs flag to use trained Opt Param Values for Power Savings. + // + MrcData->SysOut.Outputs.RestoreMRs = TRUE; + + return mrcSuccess; +} + +/** +@brief + This function saves any values that need to be used during non-cold boots. + + @param[in, out] MrcData - Include all the MRC global data. + + @retval mrcSuccess if the save occurred with no errors, otherwise returns an error code. +**/ +MrcStatus +MrcSaveMCValues ( + IN OUT MrcParameters *const MrcData + ) +{ + const SaveDataControl *SaveIt; + const MrcInput *Inputs; + const MrcControllerIn *ControllerIn; + const MrcChannelIn *ChannelIn; + const MrcSpd *SpdIn; + MrcOutput *Outputs; + MrcSaveData *SaveData; + MrcSaveHeader *SaveHeader; + MrcControllerOut *ControllerOut; + MrcChannelOut *ChannelOut; + MrcContSave *ControllerSave; + MrcChannelSave *ChannelSave; + MrcSpdSave *SpdSavePtr; + U32 *McRegister; + U8 *SpdBegin; + MrcProfile Profile; + U32 Offset; + U32 Index; + U32 Value; + U8 Controller; + U8 Channel; + U8 Dimm; + U8 CopySize; + + // + // Copy channel and DIMM information to the data area that will be saved. + // + Inputs = &MrcData->SysIn.Inputs; + Outputs = &MrcData->SysOut.Outputs; + SaveData = &MrcData->SysSave.Save.Data; + SaveHeader = &MrcData->SysSave.Save.Header; + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + ControllerIn = &Inputs->Controller[Controller]; + ControllerOut = &Outputs->Controller[Controller]; + ControllerSave = &SaveData->Controller[Controller]; + ControllerSave->ChannelCount = ControllerOut->ChannelCount; + ControllerSave->Status = ControllerOut->Status; + + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + ChannelIn = &ControllerIn->Channel[Channel]; + ChannelOut = &ControllerOut->Channel[Channel]; + ChannelSave = &ControllerSave->Channel[Channel]; + ChannelSave->DimmCount = ChannelOut->DimmCount; + ChannelSave->ValidRankBitMask = ChannelOut->ValidRankBitMask; + ChannelSave->EccSupport = ChannelOut->EccSupport; + ChannelSave->Status = ChannelOut->Status; + for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) { + MrcOemMemoryCpy ((U8 *) &ChannelSave->Timing[Profile], (U8 *) &ChannelOut->Timing[Profile], sizeof (MrcTiming)); + } + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + MrcOemMemoryCpy ((U8 *) &ChannelSave->Dimm[Dimm], (U8 *) &ChannelOut->Dimm[Dimm], sizeof (MrcDimmOut)); + SpdIn = &ChannelIn->Dimm[Dimm].Spd; + SpdSavePtr = &ChannelSave->SpdSave[Dimm]; + { + SpdSavePtr->SmbiosData.ModuleType = SpdIn->Ddr3.General.ModuleType; + SpdSavePtr->SmbiosData.ModuleMemoryBusWidth = SpdIn->Ddr3.General.ModuleMemoryBusWidth; + SpdBegin = (U8 *) &SpdIn->Ddr3.ModuleId; + CopySize = sizeof (SpdSavePtr->ManufacturingData.Ddr3Data); + } + // + // Save just enough SPD information so it can be restored during non-cold boot. + // + MrcOemMemoryCpy ((U8 *) &SpdSavePtr->ManufacturingData, SpdBegin, CopySize); + } // for Dimm + } // for Channel + } // for Controller + + for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) { + SaveData->VddVoltage[Profile] = Outputs->VddVoltage[Profile]; + } + + // + // Copy specified memory controller MMIO registers to the data area that will be saved. + // + McRegister = SaveData->McRegister; + for (Index = 0; Index < (sizeof (SaveDataArray) / sizeof (SaveDataControl)); Index++) { + SaveIt = &SaveDataArray[Index]; + for (Offset = SaveIt->StartMchbarOffset; Offset <= SaveIt->EndMchbarOffset; Offset += sizeof (U32)) { + Value = MrcReadCR (MrcData, Offset); + *McRegister++ = Value; + } + } + +// +// ------- IMPORTANT NOTE -------- +// MeStolenSize should not be saved/restored. There is no rule stating that ME FW cannot request a different +// amount of ME UMA space from one boot to the next. Also, if ME FW is updated/changed, the UMA Size requested +// from the previous version should not be restored. +// + + MrcVersionGet (&SaveData->Version); + SaveData->CpuModel = Inputs->CpuModel; + SaveData->CpuStepping = Inputs->CpuStepping; + SaveData->Frequency = Outputs->Frequency; + SaveData->MemoryClock = Outputs->MemoryClock; + SaveData->Ratio = Outputs->Ratio; + SaveData->RefClk = Outputs->RefClk; + SaveData->EccSupport = Outputs->EccSupport; + SaveData->DdrType = Outputs->DdrType; + SaveData->XmpProfileEnable = Outputs->XmpProfileEnable; + + SaveData->SaMemCfgCrc = MrcCalculateCrc32 ((U8 *) Inputs->SaMemCfgAddress, Inputs->SaMemCfgSize); + SaveHeader->Crc = MrcCalculateCrc32 ((U8 *) SaveData, sizeof (MrcSaveData)); + MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "Saved data CRC = %xh\n", SaveHeader->Crc); + + return mrcSuccess; +} + +/** +@brief + This function copies the non-training information that needs to be restored + from the 'save' data structure to the 'Output' data structure. + + @param[in, out] MrcData - include all the MRC global data. + + @retval mrcSuccess if the copy completed with no errors, otherwise returns an error code. +**/ +MrcStatus +MrcRestoreNonTrainingValues ( + IN OUT MrcParameters *const MrcData + ) +{ + MrcInput *Inputs; + MrcControllerIn *ControllerIn; + MrcChannelIn *ChannelIn; + MrcSaveData *SaveData; + MrcContSave *ControllerSave; + MrcChannelSave *ChannelSave; + MrcDimmOut *DimmSave; + MrcOutput *Outputs; + MrcControllerOut *ControllerOut; + MrcChannelOut *ChannelOut; + MrcDimmOut *DimmOut; + MrcSpd *SpdIn; + MrcSpdSave *SpdSavePtr; + U8 *SpdBegin; + MrcProfile Profile; + U8 Controller; + U8 Channel; + U8 Dimm; + U8 CopySize; + + SaveData = &MrcData->SysSave.Save.Data; + Outputs = &MrcData->SysOut.Outputs; + Inputs = &MrcData->SysIn.Inputs; + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + ControllerIn = &Inputs->Controller[Controller]; + ControllerSave = &SaveData->Controller[Controller]; + ControllerOut = &Outputs->Controller[Controller]; + ControllerOut->ChannelCount = ControllerSave->ChannelCount; + ControllerOut->Status = ControllerSave->Status; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + ChannelIn = &ControllerIn->Channel[Channel]; + ChannelSave = &ControllerSave->Channel[Channel]; + ChannelOut = &ControllerOut->Channel[Channel]; + ChannelOut->DimmCount = ChannelSave->DimmCount; + ChannelOut->ValidRankBitMask = ChannelSave->ValidRankBitMask; + ChannelOut->EccSupport = ChannelSave->EccSupport; + ChannelOut->Status = ChannelSave->Status; + for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) { + MrcOemMemoryCpy ((U8 *) &ChannelOut->Timing[Profile], (U8 *) &ChannelSave->Timing[Profile], sizeof (MrcTiming)); + } + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + DimmSave = &ChannelSave->Dimm[Dimm]; + if (DimmSave->Status == DIMM_PRESENT || DimmSave->Status == DIMM_DISABLED) { + DimmOut = &ChannelOut->Dimm[Dimm]; + SpdIn = &ChannelIn->Dimm[Dimm].Spd; + SpdSavePtr = &ChannelSave->SpdSave[Dimm]; + MrcOemMemoryCpy ((U8 *) DimmOut, (U8 *) DimmSave, sizeof (MrcDimmOut)); + { + SpdIn->Ddr3.General.ModuleType = SpdSavePtr->SmbiosData.ModuleType; + SpdIn->Ddr3.General.ModuleMemoryBusWidth = SpdSavePtr->SmbiosData.ModuleMemoryBusWidth; + SpdBegin = (U8 *) &SpdIn->Ddr3.ModuleId; + CopySize = sizeof (SpdSavePtr->ManufacturingData.Ddr3Data); + } + // + // Restore just enough SPD information so it can be passed out in the HOB. + // + MrcOemMemoryCpy (SpdBegin, (U8 *) &SpdSavePtr->ManufacturingData, CopySize); + } // if + } // for Dimm + } // for Channel + } // for Controller + + for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) { + Outputs->VddVoltage[Profile] = SaveData->VddVoltage[Profile]; + } + +// +// ------- IMPORTANT NOTE -------- +// MeStolenSize should not be saved/restored. There is no rule stating that ME FW cannot request a different +// amount of ME UMA space from one boot to the next. Also, if ME FW is updated/changed, the UMA Size requested +// from the previous version should not be restored. +// + + Inputs->CpuModel = SaveData->CpuModel; + Inputs->CpuStepping = SaveData->CpuStepping; + Outputs->Frequency = SaveData->Frequency; + Outputs->MemoryClock = SaveData->MemoryClock; + Outputs->Ratio = SaveData->Ratio; + Outputs->RefClk = SaveData->RefClk; + Outputs->EccSupport = SaveData->EccSupport; + Outputs->DdrType = SaveData->DdrType; + Outputs->XmpProfileEnable = SaveData->XmpProfileEnable; + + return mrcSuccess; +} + +/** +@brief + This function writes the previously determined training values back to the memory controller. + + @param[in] MrcData - Include all the MRC global data. + + @retval mrcSuccess if the memory controller write back completed with no errors, otherwise returns an error code. +**/ +MrcStatus +MrcRestoreTrainingValues ( + IN MrcParameters *const MrcData + ) +{ + const SaveDataControl *RestoreIt; + U32 *McRegister; + U32 Offset; + U32 Index; + U32 Value; + + McRegister = MrcData->SysSave.Save.Data.McRegister; + for (Index = 0; Index < (sizeof (SaveDataArray) / sizeof (SaveDataControl)); Index++) { + RestoreIt = &SaveDataArray[Index]; + for (Offset = RestoreIt->StartMchbarOffset; Offset <= RestoreIt->EndMchbarOffset; Offset += sizeof (U32)) { + Value = *McRegister++; + MrcWriteCR (MrcData, Offset, Value); + } + } + + return mrcSuccess; +} + +/** +@brief + Calculates a CRC-32 of the specified data buffer. + + @param[in] Data - Pointer to the data buffer. + @param[in] DataSize - Size of the data buffer, in bytes. + + @retval The CRC-32 value. +**/ +U32 +MrcCalculateCrc32 ( + IN const U8 *const Data, + IN const U32 DataSize + ) +{ + U32 i; + U32 j; + U32 crc; + U32 CrcTable[256]; + + crc = (U32) (-1); + + // + // Initialize the CRC base table. + // + for (i = 0; i < 256; i++) { + CrcTable[i] = i; + for (j = 8; j > 0; j--) { + CrcTable[i] = (CrcTable[i] & 1) ? (CrcTable[i] >> 1) ^ 0xEDB88320 : CrcTable[i] >> 1; + } + } + // + // Calculate the CRC. + // + for (i = 0; i < DataSize; i++) { + crc = (crc >> 8) ^ CrcTable[(U8) crc ^ (Data)[i]]; + } + + return ~crc; +} |