diff options
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MemoryInit.c')
-rw-r--r-- | ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MemoryInit.c | 2722 |
1 files changed, 2722 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MemoryInit.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MemoryInit.c new file mode 100644 index 0000000..2dbc444 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MemoryInit.c @@ -0,0 +1,2722 @@ +/** @file + Memory Initialization PEIM. + +@copyright + Copyright (c) 1999 - 2013 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 "CpuIA32.h" +#include "EdkIIGluePeim.h" +#include "SaAccess.h" +#include "MemInfoHob.h" +#include "MemoryInit.h" +#include "MrcDebugHook.h" +#include "MrcOemDebugPrint.h" +#include "MrcOemIo.h" +#include "MrcOemPlatform.h" +#include "MrcSaveRestore.h" +#include "MrcSpdDriver.h" +#include "McGdxcbar.h" +#include "CpuRegs.h" +#include "CpuPlatformLib.h" +#include "MrcCommon.h" +#include "TxtLibrary.h" +#include "PttHciRegs.h" + +// The next extern is temporary, including MrcCommon.h causes compile problems. +extern +MrcFrequency +MrcGetCurrentMemoryFrequency ( + MrcParameters * const MrcData, + U32 * const MemoryClock, + MrcClockRatio * const Ratio, + MrcRefClkSelect * const RefClk + ); + +// +// Driver Dependent PPI Prototypes +// +#include EFI_PPI_DEPENDENCY (BaseMemoryTest) +#include EFI_PPI_DEPENDENCY (Capsule) +#include EFI_PPI_DEPENDENCY (PlatformMemoryRange) +#include EFI_PPI_DEPENDENCY (PlatformMemorySize) +#include EFI_PPI_DEPENDENCY (SaPlatformPolicy) +#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy) +#include EFI_GUID_DEFINITION (TxtInfoHob) +#include EFI_PPI_DEPENDENCY (Stall) +#include EFI_PPI_DEPENDENCY (Variable) +#include EFI_PPI_CONSUMER (Wdt) + +// +// Driver Consumed GUID +// +#include EFI_GUID_DEFINITION (AcpiVariable) +#include EFI_GUID_DEFINITION (MemoryTypeInformation) +#include EFI_GUID_DEFINITION (SmramMemoryReserve) +//#ifdef MRC_DEBUG_PRINT +//#include EFI_GUID_DEFINITION (GlobalVariable) +//#include EFI_PPI_DEFINITION (DebugMask) +//#endif // MRC_DEBUG_PRINT + +// +// Driver PPI Definitions +// +#ifdef RAPID_START_FLAG +#include EFI_PPI_DEFINITION (RapidStart) +#include "RapidStartCommonLib.h" +#include "RapidStartPeiLib.h" +#include EFI_PPI_CONSUMER (PchReset) +#endif // RAPID_START_FLAG +#include EFI_PPI_DEFINITION (PchInit) +#include EFI_PPI_DEFINITION (PchMeUma) +#include "PchMeUma.h" +#if 0//def MRC_DEBUG_PRINT +#include "DebugMask.h" +#endif + +#ifndef AMI_OVERRIDE_FOR_NOTIFY_MRC +#define __HOB__H__ +#include <Ppi\NBPPI.h> +#endif // AMI_OVERRIDE_FOR_NOTIFY_MRC + +// +// Driver GUID Definitions +// +EFI_GUID gMemRestoreDataGuid = EFI_MEMORY_RESTORE_DATA_GUID; +EFI_GUID gPeiCapsulePpiGuid = PEI_CAPSULE_PPI_GUID; +EFI_GUID gEfiAcpiVariableGuid = EFI_ACPI_VARIABLE_GUID; +#if 0//def MRC_DEBUG_PRINT +EFI_GUID gEfiGenericVariableGuid = EFI_GENERIC_VARIABLE_GUID; +#endif + + +#ifdef MRC_DEBUG_PRINT +const UINT8 BootStringFc[] = "BOOT_WITH_FULL_CONFIGURATION"; +const UINT8 BootStringMc[] = "BOOT_WITH_MINIMAL_CONFIGURATION"; +const UINT8 BootStringNc[] = "BOOT_ASSUMING_NO_CONFIGURATION_CHANGES"; +const UINT8 BootStringFcd[] = "BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS"; +const UINT8 BootStringDs[] = "BOOT_WITH_DEFAULT_SETTINGS"; +const UINT8 BootStringS4[] = "BOOT_ON_S4_RESUME"; +const UINT8 BootStringS5[] = "BOOT_ON_S5_RESUME"; +const UINT8 BootStringS2[] = "BOOT_ON_S2_RESUME"; +const UINT8 BootStringS3[] = "BOOT_ON_S3_RESUME"; +const UINT8 BootStringFu[] = "BOOT_ON_FLASH_UPDATE"; +const UINT8 BootStringRm[] = "BOOT_IN_RECOVERY_MODE"; +const UINT8 BootStringRmm[] = "BOOT_IN_RECOVERY_MODE_MASK"; +const UINT8 BootStringSm[] = "BOOT_SPECIAL_MASK"; +const UINT8 BootStringUnk[] = "BOOT_MODE_UNKNOWN"; +#endif + +#ifndef AMI_OVERRIDE_FOR_NOTIFY_MRC +static EFI_PEI_PPI_DESCRIPTOR mAmiPeiBeforeMrcDesc[] = { + { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), \ + &gAmiPeiBeforeMrcGuid, \ + NULL } +}; + +static EFI_PEI_PPI_DESCRIPTOR mAmiPeiCompelteMrcDesc[] = { + { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), \ + &gAmiPeiAfterMrcGuid, \ + NULL } +}; + +static EFI_PEI_PPI_DESCRIPTOR mAmiPeiEndOfMrcDesc[] = { + { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), \ + &gAmiPeiEndOfMemDetectGuid, \ + NULL } +}; +#endif // AMI_OVERRIDE_FOR_NOTIFY_MRC + +EFI_PEIM_ENTRY_POINT (PeimMemoryInit); + +/** + Main starting point for system memory initialization. + 1. Get SysBootMode and MrcBootMode + 2. Locate SaPlatformPolicy PPI + 3. Locate S3DataPtr from SaPlatformPolicy. + 4. SaveDataValid := TRUE if S3DataPtr is not NULL. + 5. If SysBootMode is BOOT_ON_S3_RESUME and S3Data is not valid: + -> ASSERT. + 6. If MrcBootMode is Warm boot, but S3 data is not valid : + -> change MrcBootMode to Cold boot. + 7. If MrcBootMode is Cold boot: + -> Run MRC code + -> Save S3 Restore Data + Else + -> Run MRC_S3Resume + 8. Run MRC_Done(). + 9. Install EFI memory HOBs. + + @param[in] FfsHeader - Not used. + @param[in] PeiServices - General purpose services available to every PEIM. + + @retval EFI_SUCCESS - Memory initialization completed successfully. + @retval EFI_NOT_READY - Cannot locate SA Platform Policy. + @retval EFI_NOT_FOUND - No S3 data in S3 Boot Mode. + @retval EFI_DEVICE_ERROR - MemoryInit failed or IOSAV Memory test failed. +**/ +EFI_STATUS +PeimMemoryInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + PEI_READ_ONLY_VARIABLE_PPI *VariableServices; + SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi; + HOB_SAVE_MEMORY_DATA *Hob; + MrcParameters *MrcData; + MrcInput *Inputs; + MrcOutput *Outputs; + SysSave *SaveSys; + MrcSave *Save; + MrcCpuModel CpuModel; + MrcCpuStepping CpuStep; + UINT32 CpuModelStep; + BOOLEAN CpuDetected; + MrcParameters MrcGlobalData; + EFI_STATUS Status; + EFI_BOOT_MODE SysBootMode; + MrcStatus MrcStatus; + MrcBootMode MrcBootMode; + MrcVersion Version; + BOOLEAN SaveDataValid; + UINT32 Crc32; + UINT64 SskpdValue; +#ifdef MRC_DEBUG_PRINT + MrcDebug *Debug; + const UINT8 *Str; +#endif + PCH_ME_UMA_PPI *PchMeUma; + UINT8 InitStat; + UINT8 ForceFullTraining; + UINT8 OrigMrcBootMode; +#ifdef RAPID_START_FLAG + PCH_RESET_PPI *PchResetPpi; + RAPID_START_PPI *RapidStartPpi; +#endif + UINT8 TotalDprSizeMB; + UINT32 MemoryClock; + MrcClockRatio Ratio; + MrcUpmPwrRetrainLimits RetrainLimits[MRC_NUMBER_UPM_PWR_RETRAIN_MARGINS]; + + MrcData = &MrcGlobalData; + Inputs = &MrcData->SysIn.Inputs; + Outputs = &MrcData->SysOut.Outputs; + ZeroMem (MrcData, sizeof (MrcParameters)); + Outputs->UpmPwrRetrainLimits.Pointer = RetrainLimits; + MrcOemMemoryCpy ( + (U8 *) RetrainLimits, + (U8 *) InitialLimits, + sizeof (MrcUpmPwrRetrainLimits) * MRC_NUMBER_UPM_PWR_RETRAIN_MARGINS + ); + + //;;## ...AMI_OVERRIDE... Notify BeforeMrc + // Install the NB Before Mrc Notify PPI + Status = (*PeiServices)->InstallPpi(PeiServices, &mAmiPeiBeforeMrcDesc[0]); + ASSERT_EFI_ERROR (Status); + //;;## ...AMI_OVERRIDE... Notify BeforeMrc end + + // + // Obtain boot mode. + // + Status = (*PeiServices)->GetBootMode (PeiServices, &SysBootMode); + ASSERT_EFI_ERROR (Status); + + if (SysBootMode != BOOT_ON_S3_RESUME) { + Status = MrcGetHobForDataStorage (PeiServices, &Hob, sizeof (HOB_SAVE_MEMORY_DATA)); + ASSERT_EFI_ERROR (Status); + } else { + Hob = 0; + } + +#ifdef SSA_FLAG + Status = (**PeiServices).LocatePpi (PeiServices, &gSsaBiosCallBacksPpiGuid, 0, NULL, (VOID **) &Inputs->SsaCallbackPpi); + if (EFI_SUCCESS != Status) { + Inputs->SsaCallbackPpi = 0; + } + Inputs->Debug.Stream = (U32) PeiServices; + Inputs->SsaHeapBase = (U32) &Hob->MrcData; + Inputs->SsaHeapSize = MRC_HOB_SIZE_TOTAL - sizeof (EFI_HOB_GUID_TYPE); + PEI_DEBUG (((void *) PeiServices, EFI_D_ERROR, "SsaCallbackPpi = %Xh\n", Inputs->SsaCallbackPpi)); + PEI_DEBUG (((void *) PeiServices, EFI_D_ERROR, "SSA heap. Base = %Xh, Size = %d\n", Inputs->SsaHeapBase, Inputs->SsaHeapSize)); +#endif // SSA_FLAG + + // + // Obtain platform policy settings. + // + Status = (**PeiServices).LocatePpi (PeiServices, &gSaPlatformPolicyPpiGuid, 0, NULL, (VOID **) &SaPlatformPolicyPpi); + ASSERT_EFI_ERROR (Status); + + MrcOemDebugHook (MrcData, MRC_INITIALIZATION_START); +#ifdef MRC_DEBUG_PRINT + Debug = &Inputs->Debug; +#endif + + MRC_DEBUG_MSG_OPEN ( + Debug, + (SaPlatformPolicyPpi->MemConfig->MrcTimeMeasure > 0) ? MSG_LEVEL_TIME : SaPlatformPolicyPpi->MemConfig->SerialDebug, + (U32) PeiServices, + (SysBootMode == BOOT_ON_S3_RESUME) ? 0 : (U32) &Hob->MrcData, + (SysBootMode == BOOT_ON_S3_RESUME) ? 0 : (MRC_HOB_SIZE_TOTAL - sizeof (EFI_HOB_GUID_TYPE)) + ); + + InitStat = 0; + ForceFullTraining = 0; + + MrcStatus = mrcSuccess; + + // + // Obtain variable services. + // + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiReadOnlyVariablePpiGuid, 0, NULL, (VOID **) &VariableServices); + ASSERT_EFI_ERROR (Status); + +#ifndef TXT_SUPPORT_FLAG + // + // Unlock memory if it is necessary. + // + UnlockMemory (MrcData, PeiServices); +#endif // TXT_SUPPORT_FLAG + + // + // Get MRC BootMode + // + MrcBootMode = (SysBootMode == BOOT_ON_S3_RESUME) ? bmS3 : MrcGetBootMode (); + +#ifdef MRC_DEBUG_PRINT + if ((SysBootMode == BOOT_ON_S3_RESUME) && (bmCold == MrcGetBootMode ())) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "SysBootMode = %Xh and MrcBootMode = %d - Check PCH SR bit\n", + SysBootMode, + MrcBootMode + ); + } +#endif // MRC_DEBUG_PRINT + +#ifdef RAPID_START_FLAG + // + // Locate RapidStart PPI + // + Status = (*PeiServices)->LocatePpi (PeiServices, &gRapidStartPpiGuid, 0, NULL, &RapidStartPpi); + ASSERT_EFI_ERROR (Status); +#endif // RAPID_START_FLAG + + MrcVersionGet (&Version); + MrcVersionPrint (MrcData, &Version); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\nSystem boot mode = %Xh\n", SysBootMode); +#ifdef MRC_DEBUG_PRINT + switch (SysBootMode) { + case BOOT_WITH_FULL_CONFIGURATION: Str = BootStringFc; break; + case BOOT_WITH_MINIMAL_CONFIGURATION: Str = BootStringMc; break; + case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: Str = BootStringNc; break; + case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: Str = BootStringFcd; break; + case BOOT_WITH_DEFAULT_SETTINGS: Str = BootStringDs; break; + case BOOT_ON_S4_RESUME: Str = BootStringS4; break; + case BOOT_ON_S5_RESUME: Str = BootStringS5; break; + case BOOT_ON_S2_RESUME: Str = BootStringS2; break; + case BOOT_ON_S3_RESUME: Str = BootStringS3; break; + case BOOT_ON_FLASH_UPDATE: Str = BootStringFu; break; + case BOOT_IN_RECOVERY_MODE: Str = BootStringRm; break; + case BOOT_IN_RECOVERY_MODE_MASK: Str = BootStringRmm; break; + case BOOT_SPECIAL_MASK: Str = BootStringSm; break; + default: Str = BootStringUnk; break; + } + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\nSystem boot mode = %s\n", Str); +#endif //MRC_DEBUG_PRINT + + // + // Locate and determine if memory configuration save data is valid. + // + SaveDataValid = FALSE; + if ((SaPlatformPolicyPpi->S3DataPtr != NULL) && (SysBootMode != BOOT_WITH_DEFAULT_SETTINGS)) { + SaveSys = (SysSave *) (SaPlatformPolicyPpi->S3DataPtr); + Save = &SaveSys->Save; + Crc32 = MrcCalculateCrc32 ((U8 *) (&Save->Data), sizeof (MrcSaveData)); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Calc. crc = 0x%x, Header crc = 0x%x\n", Crc32, Save->Header.Crc); + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "S3DataPtr = 0x%x - &MrcData = 0x%x - sizeof (MrcParameters) = 0x%x\n", + SaPlatformPolicyPpi->S3DataPtr, + &MrcData, + sizeof (MrcParameters) + ); + + if (Crc32 == Save->Header.Crc) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Saved memory configuration data is valid\n"); + ((*PeiServices)->CopyMem) ((VOID *) &MrcData->SysSave, (VOID *) SaveSys, sizeof (SysSave)); + SaveDataValid = TRUE; + } + } + + // + // We must have memory configuration save data in order to resume from S3. + // + if ((SysBootMode == BOOT_ON_S3_RESUME) && (!SaveDataValid)) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "Unable to resume from S3 without valid saved memory configuration data\n"); + PEI_ASSERT (PeiServices, FALSE); + return EFI_NOT_FOUND; + } + + // + // Locate PchMeUma PPI. + // + Status = (*PeiServices)->LocatePpi (PeiServices, &gPchMeUmaPpiGuid, 0, NULL, &PchMeUma); + ASSERT_EFI_ERROR (Status); + + if (MrcBootMode != bmS3 && MrcBootMode != bmWarm) { + // + // Check CPU Replaced Status, if so a system non-power cycle reset will be required. + // + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Calling CpuReplacementCheck\n"); + Status = PchMeUma->CpuReplacementCheck(PeiServices, FfsHeader, &ForceFullTraining); + + if (ForceFullTraining == 0x1) { + SaveDataValid = FALSE; + } + } + + // Keep track of the original MRC Boot mode before an alternate flow is determined below. + OrigMrcBootMode = MrcBootMode; + + CpuModel = GetCpuFamily(); + CpuStep = GetCpuStepping(); + CpuModelStep = CpuModel | CpuStep; + CpuDetected = (MrcSetCpuInformation (MrcData, CpuModel, CpuStep) == mrcSuccess) ? TRUE : FALSE; + + if (!CpuDetected) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "ERROR: CPU Family/Model/Step %Xh is not supported:\n", CpuModelStep); + ASSERT_EFI_ERROR (EFI_DEVICE_ERROR); + } + + // + // MrcBootMode can ONLY be bmCold, bmWarm or bmS3 at this point. + // + switch (MrcBootMode) { + case bmCold: + // Advance the MRC boot mode to fast boot if the following condition is met. + if ((SaveDataValid == TRUE) && + (SaPlatformPolicyPpi->MemConfig->MrcFastBoot > 0) && + (ColdBootRequired (MrcData, SaPlatformPolicyPpi)) == FALSE) { + MrcBootMode = bmFast; + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Fast boot is possible, so forcing it\n"); + } + else { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Cold boot\n"); + SaveDataValid = FALSE; + } + break; + + case bmWarm: + case bmS3: + if (SaveDataValid == FALSE) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_WARNING, "Saved memory configuration data is not valid, forcing a cold boot\n"); + MrcBootMode = bmCold; + break; + } else { + if (ColdBootRequired (MrcData, SaPlatformPolicyPpi) == TRUE) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_WARNING, + "Platform settings or configuration have changed, forcing a cold boot\n" + ); + MrcBootMode = bmCold; + SaveDataValid = FALSE; + break; + } + // + // Check SSKPD register to determine if Warm Reset occured before MRC was reached during a cold boot. + // If so, we need to force the cold boot path. + // + MrcOemMmioRead64 (PCU_CR_SSKPD_PCU_REG, &SskpdValue, SaPlatformPolicyPpi->PlatformData->MchBar); + if ((SskpdValue == 0) && (MrcBootMode == bmWarm)) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_WARNING, + "Reset occured in the cold boot path before reaching MRC. Forcing Cold Boot\n" + ); + MrcBootMode = bmCold; + SaveDataValid = FALSE; + break; + } + } + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "%s\n", (MrcBootMode == bmS3) ? "Resume from S3" : "Warm reset"); + break; + + default: + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Cold boot\n"); + MrcBootMode = bmCold; + SaveDataValid = FALSE; + break; + } + + // + // Clear MrcSave if not valid saved data. We don't want to end up with Ghost DIMMs + // + if (SaveDataValid == FALSE) { + ZeroMem (&MrcData->SysSave.Save, sizeof (MrcSave)); + } + +#ifdef MRC_DEBUG_PRINT + ((*PeiServices)->CopyMem) ((VOID *) &MrcData->SysIn.Inputs.Debug, Debug, sizeof (MrcDebug)); + Debug = &Inputs->Debug; +#endif // MRC_DEBUG_PRINT + + // + //Calculate Total DPR Size + // + CalculateTotalDprMemorySize (PeiServices, &TotalDprSizeMB); + + if(TotalDprSizeMB != 0){ + Inputs->DprSize = (U32) TotalDprSizeMB; + } + + // + // Set up the MRC input data structure. + // + Inputs->BootMode = MrcSetupMrcData (SysBootMode, MrcBootMode, Inputs, PeiServices, SaPlatformPolicyPpi); + + // + // Initialize MeStolenSize to 0 before we retrieving from ME FW. + // + Inputs->MeStolenSize = 0; + +#ifdef RAPID_START_FLAG + if ((SysBootMode != BOOT_ON_S3_RESUME) && (RapidStartPpi->GetMode (RapidStartPpi) == RapidStartExit)) { + // + // Need to erase whole memory for Rapid Start Resume + // + Inputs->OemCleanMemory = TRUE; + } +#endif // RAPID_START_FLAG + + // + // ME Stolen Size in MB units + // + DEBUG ((EFI_D_ERROR, "Calling MeSendUmaSize\n")); + Inputs->MeStolenSize = PchMeUma->MeSendUmaSize (PeiServices, FfsHeader); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "ME UMA size = %u MB\n", Inputs->MeStolenSize); + + do { + if (Inputs->BootMode == bmCold) { + // + // Clear DRAM Init Bit if we are doing a cold boot, to prevent hang if a warm reset occurs in the training flow + // where an old memory config is saved. + // + MrcResetDISB (); + } + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "MRC Start Memory Configuration\n"); + MrcStatus = MrcStartMemoryConfiguration (MrcData); + + switch (MrcStatus) { + case mrcSuccess: + break; + + case mrcRetrain: + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "Rerunning training with higher UPM/PWR limits!\n"); + ZeroMem (Outputs, sizeof (MrcOutput)); + Outputs->UpmPwrRetrainLimits.Pointer = RetrainLimits; + Inputs->Iteration++; + break; + + case mrcFrequencyError: + MrcGetCurrentMemoryFrequency (MrcData, &MemoryClock, &Ratio, NULL); + if (Ratio >= Outputs->Ratio) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "Memory initialization has failed\n"); + // + // Get lower byte and set the error bit + // +#ifndef AMI_OVERRIDE_FOR_MRC_ERROR_REPORT + MrcOemDebugHook (MrcData, MrcOemInPort8 (0x80) | MRC_FAILURE_INDICATION); +#else + MrcOemOutPort8 (0x80, MrcOemInPort8 (0x80) | MRC_FAILURE_INDICATION); +#endif + ASSERT_EFI_ERROR (EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; + } else { + // Restart memory configuration, using the lower frequency. + MrcStatus = mrcColdBootRequired; + } + // no break; + + case mrcColdBootRequired: + if (Inputs->BootMode == bmFast) { + // At this point, input structure has limited data. + // We need to initialize the input structure for the cold boot. + Inputs->BootMode = MrcSetupMrcData (SysBootMode, bmCold, Inputs, PeiServices, SaPlatformPolicyPpi); + } else { + Inputs->BootMode = bmCold; + } + break; + + case mrcDimmNotExist: + // + // Set memory init status = 0x1 and send DRAM Init Done to ME FW, + // indicating that no memory exists in the system. + // + InitStat = 0x1; + Status = PchMeUma->MeConfigDidReg (PeiServices, FfsHeader, MrcBootMode, InitStat, Outputs->MemoryMapData.FtpmStolenBase, Inputs->MeStolenSize); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "FtpmStolenBase = 0x%08X \n", Outputs->MemoryMapData.FtpmStolenBase); + MrcOemDebugHook (MrcData, MRC_NO_MEMORY_DETECTED); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "There are no DIMMs present in the system\n"); + // + //Indicate to the caller that memory has not been detected. + // + (*PeiServices)->PeiReportStatusCode ( + PeiServices, + EFI_ERROR_CODE, + EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_NONE_DETECTED, + 0, + NULL, + NULL + ); + // no break; + + default: + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "Memory initialization has failed\n"); + // + // Get lower byte and set the error bit + // +#ifndef AMI_OVERRIDE_FOR_MRC_ERROR_REPORT + MrcOemDebugHook (MrcData, MrcOemInPort8 (0x80) | MRC_FAILURE_INDICATION); +#else + MrcOemOutPort8 (0x80, MrcOemInPort8 (0x80) | MRC_FAILURE_INDICATION); +#endif + ASSERT_EFI_ERROR (EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; + } + } while ((MrcStatus == mrcColdBootRequired) || (MrcStatus == mrcRetrain)); + + // + // Intel Silicon View Technology (ISVT) IO Reading port 0x84 with AH = 1 for End of MRC + // +#if defined __GNUC__ // GCC compiler + __asm__ __volatile__ ( + "\n\t mov $0x100, %eax" + "\n\t in $0x84, %al" + ); +#else //MSFT compiler + ASM { + mov EAX, 100h + in AL, 84h + } +#endif + + // + // Configure "ME DRAM Init Done Register" + // + // + // ME UMA Size outside of a 0MB-32MB range is not defined or if BDF 0:22:0 is not present, exit. + // +#ifdef RAPID_START_FLAG + // + // Check wake conditions to determine if a Rapid Start transition is to be performed + // and set the RapidStart flag in DID. + // + if (RapidStartPpi->GetMode (RapidStartPpi) != RapidStartNone) { + InitStat |= 0x80; + } +#endif // RAPID_START_FLAG + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Check for Memory Retrain on warm reset -- MrcBootMode=0x%02X OrigBootMode=0x%02X\n", MrcBootMode, OrigMrcBootMode); + // On warm reset if memory coherency was not maintained (forced Cold Reset flow), set the DID message + // to indicate that memory was not preserved across reset, so that ME will reload the FW from NV memory. + if (bmWarm == OrigMrcBootMode && bmCold == MrcBootMode) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Memory retrain occurred during warm reset. Force ME FW reload.\n"); + // Set the flag to tell FW that memory was not maintained InitStat bits 3:0 = (3). + InitStat = (InitStat & 0xF0) | 0x3; + } + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "ME UMA Size requested: %d MB\n", Inputs->MeStolenSize); + if ((Inputs->MeStolenSize > 0x20) || (PchD22PciCfg32 (0x10) == 0xffffffff)) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "Invalid ME UMA Size requested.\n"); + } else { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Calling MeConfigDidReg\n"); + Status = PchMeUma->MeConfigDidReg (PeiServices, FfsHeader, MrcBootMode, InitStat, Outputs->MemoryMapData.FtpmStolenBase,Inputs->MeStolenSize); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "MeDramInitDone Complete.\n"); + } + + // + // SATA must be initialized before Rapid Start transition. + // + //remove for PCH RC updated to V44, the code would be elimated if SA/MRC sync to V44 as well + // Status = PchInitPpi->SataInit (PeiServices); + // ASSERT_PEI_ERROR (PeiServices, Status); + +#ifdef RAPID_START_FLAG + // + // Perform Rapid Start transition if necessary (BootMode mode may change here!) + // Rapid Start requires MRC Fast boot to be enabled for best performance. + // In Rapid Start Resume flow if MRC boot mode is not bmFast that means memory + // configuration has changed and Rapid Start resume should be aborted. + // + if ((SaPlatformPolicyPpi->MemConfig->MrcFastBoot) && (RapidStartPpi->GetMode (RapidStartPpi) == RapidStartExit) && (Inputs->BootMode != bmFast)) { + DEBUG ((EFI_D_ERROR, "Memory Configuration changed! Rapid Start Resume is aborted!\n")); + RapidStartAfterTransition (PeiServices, RapidStartExit, EFI_MEDIA_CHANGED, 0); + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gPchResetPpiGuid, + 0, + NULL, + &PchResetPpi + ); + ASSERT_EFI_ERROR (Status); + PchResetPpi->Reset (PchResetPpi, PowerCycleReset); + } else { + RapidStartPpi->TransitionEntryPoint (RapidStartPpi, &SysBootMode); + } +#endif // RAPID_START_FLAG + +#ifndef AMI_OVERRIDE_FOR_NOTIFY_MRC + // Install the NB End of Mrc Notify PPI + Status = (*PeiServices)->InstallPpi(PeiServices, &mAmiPeiCompelteMrcDesc[0]); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_ERROR, "Install Complete MRC Ppi.\n")); +#endif // AMI_OVERRIDE_FOR_NOTIFY_MRC +#ifndef AMI_OVERRIDE_FOR_EIP102852 + Status = (*PeiServices)->GetBootMode( PeiServices, &SysBootMode ); +#endif // AMI_OVERRIDE_FOR_EIP102852 + + // + // Install EFI memory HOBs + // + if (SysBootMode == BOOT_ON_S3_RESUME) { + Status = InstallS3Memory (Inputs, PeiServices, VariableServices); + ASSERT_EFI_ERROR (Status); + } else { + if ((MrcBootMode == bmCold) || (MrcBootMode == bmFast)) { + // + // Perform simple memory test. + // + if (mrcFail == BasicMemoryTest (Inputs)) { + MrcOemDebugHook (MrcData, MRC_MEM_INIT_DONE_WITH_ERRORS); + ASSERT_EFI_ERROR (EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; + } + } + MrcData->SaveSize = sizeof (MrcSave); +#ifdef MRC_DEBUG_PRINT + Debug->Current = 0; +#endif // MRC_DEBUG_PRINT + ((*PeiServices)->CopyMem) ((VOID *) &Hob->MrcData, MrcData, sizeof (MrcParameters)); + ZeroMem ((VOID *) &Hob->Buffer, MRC_HOB_SIZE_BUFFER); + + Status = InstallEfiMemory (Inputs, PeiServices, SysBootMode); + ASSERT_EFI_ERROR (Status); + } + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "MemoryInit Complete.\n"); + MrcOemDebugHook (MrcData, MRC_MEM_INIT_DONE); + +#ifndef AMI_OVERRIDE_FOR_NOTIFY_MRC + // Install the NB End of Mrc Notify PPI + Status = (*PeiServices)->InstallPpi(PeiServices, &mAmiPeiEndOfMrcDesc[0]); + ASSERT_EFI_ERROR (Status); +#endif // AMI_OVERRIDE_FOR_NOTIFY_MRC + + return Status; +} + +/** + This function installs memory for all paths except S3 resume. + + @param[in] Inputs - MRC input structure. + @param[in] PeiServices - PEI Services table. + @param[in] SysBootMode - The specific boot path that is being followed. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of Resources. +**/ +EFI_STATUS +InstallEfiMemory ( + IN const MrcInput *const Inputs, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_BOOT_MODE SysBootMode + ) +{ + EFI_STATUS Status; + UINT8 Index; + UINT8 NumRanges; + UINT8 SmramIndex; + UINT8 SmramRanges; + UINT64 PeiMemoryLength; + UINT64 RangeLength; + UINTN BufferSize; + UINTN CapsuleBufferLength; + UINTN PeiMemoryIndex; + UINTN RequiredMemSize; + VOID *CapsuleBuffer; + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress; + EFI_PHYSICAL_ADDRESS TopUseableMemAddr; + EFI_PHYSICAL_ADDRESS TopUseableMemSize; + EFI_PHYSICAL_ADDRESS Tom; + PEI_MEMORY_TEST_OP MemoryTestOp; + PEI_BASE_MEMORY_TEST_PPI *BaseMemoryTestPpi; + PEI_CAPSULE_PPI *Capsule; + PEI_PLATFORM_MEMORY_SIZE_PPI *MemSize; + EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock; + EFI_SMRAM_DESCRIPTOR *SmramDescriptor; + PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES]; + EFI_PHYSICAL_ADDRESS BadMemoryAddress; + EFI_RESOURCE_TYPE ResourceType; + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; + const MrcDebug *Debug; + + Debug = &Inputs->Debug; + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Install EFI memory.\n"); + + // + // Get the Memory Map + // + NumRanges = MAX_RANGES; + ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges); + Status = GetMemoryMap (PeiServices, (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap, &NumRanges); + ASSERT_EFI_ERROR (Status); + + // + // Find the highest memory range in processor native address space to give to + // PEI. Then take the top. + // If this algorithm changes, then we need to fix the capsule memory + // selection algorithm below. + // + PeiMemoryBaseAddress = 0; + + // + // Query the platform for the minimum memory size. + // + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiPlatformMemorySizePpiGuid, 0, NULL, (VOID **) &MemSize); + ASSERT_EFI_ERROR (Status); + + Status = MemSize->GetPlatformMemorySize (PeiServices, MemSize, &PeiMemoryLength); + ASSERT_EFI_ERROR (Status); + + // + // Get required memory size for ACPI use. This helps to put ACPI memory on the top. + // + RequiredMemSize = 0; + RetrieveRequiredMemorySize (PeiServices, &RequiredMemSize); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Required memory size = %Xh (%u) bytes\n", RequiredMemSize, RequiredMemSize); + + PeiMemoryIndex = 0; + for (Index = 0; Index < NumRanges; Index++) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Found %016Xh bytes at ", MemoryMap[Index].RangeLength); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "%016Xh\n", MemoryMap[Index].PhysicalAddress); + if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) && + (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < EFI_MAX_ADDRESS) && + (MemoryMap[Index].PhysicalAddress >= PeiMemoryBaseAddress) && + (MemoryMap[Index].RangeLength >= PeiMemoryLength)) { + PeiMemoryBaseAddress = MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength - PeiMemoryLength; + PeiMemoryIndex = Index; + } + } + + // + // Test only the PEI memory if necessary. Some platforms do not require the + // Base Memory PEIM to be present. + // + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiBaseMemoryTestPpiGuid, 0, NULL, (VOID **) &BaseMemoryTestPpi); + + switch (SysBootMode) { + + case BOOT_WITH_FULL_CONFIGURATION: + MemoryTestOp = Quick; + break; + + case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: + MemoryTestOp = Extensive; + break; + + default: + MemoryTestOp = Ignore; + break; + } + + (*PeiServices)->PeiReportStatusCode ( + PeiServices, + EFI_PROGRESS_CODE, // Type + EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_PC_TEST, // Value + 0, // Instance + NULL, // *CallerId OPTIONAL + NULL // *Data OPTIONAL + ); + + Status = BaseMemoryTestPpi->BaseMemoryTest ( + PeiServices, + BaseMemoryTestPpi, + PeiMemoryBaseAddress, + PeiMemoryLength, + MemoryTestOp, + &BadMemoryAddress + ); + if (EFI_ERROR (Status)) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "Memory test failure at %lXh.\n", BadMemoryAddress); + } + + ASSERT_EFI_ERROR (Status); + + Capsule = NULL; + CapsuleBuffer = NULL; + CapsuleBufferLength = 0; + + if (SysBootMode == BOOT_ON_FLASH_UPDATE) { + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiCapsulePpiGuid, 0, NULL, (VOID **) &Capsule); +#ifdef AMI_OVERRIDE_FOR_EIP102852 + ASSERT_EFI_ERROR (Status); +#endif // AMI_OVERRIDE_FOR_EIP102852 + + if (Status == EFI_SUCCESS) { + // + // Find the largest memory range excluding that given to PEI. + // + for (Index = 0; Index < NumRanges; Index++) { + if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) && + (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < EFI_MAX_ADDRESS)) { + if (Index != PeiMemoryIndex) { + if (MemoryMap[Index].RangeLength > CapsuleBufferLength) { + CapsuleBuffer = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress); + CapsuleBufferLength = (UINTN) MemoryMap[Index].RangeLength; + } + } else { + if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= CapsuleBufferLength) { + CapsuleBuffer = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress); + CapsuleBufferLength = (UINTN) (MemoryMap[Index].RangeLength - PeiMemoryLength); + } + } + } + } + // + // Call the Capsule PPI Coalesce function to coalesce the capsule data. + // + Status = Capsule->Coalesce (PeiServices, &CapsuleBuffer, &CapsuleBufferLength); + } + // + // If it failed, then NULL out our capsule PPI pointer so that the capsule + // HOB does not get created below. + // + if (Status != EFI_SUCCESS) { + Capsule = NULL; + } + } + // + // Carve out the top memory reserved for ACPI. + // + Status = (*PeiServices)->InstallPeiMemory (PeiServices, PeiMemoryBaseAddress, PeiMemoryLength - RequiredMemSize); + ASSERT_EFI_ERROR (Status); + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Building RESOURCE_SYSTEM_MEMORY Hob: \n"); + DEBUG ((EFI_D_ERROR, "PeiMemoryBaseAddress = %lXh, PeiMemoryLength = %lXh\n", PeiMemoryBaseAddress, PeiMemoryLength)); + + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + PeiMemoryBaseAddress, + PeiMemoryLength + ); + + // + // Install physical memory descriptor hobs for each memory range. + // + SmramRanges = 0; + for (Index = 0; Index < NumRanges; Index++) { + if (MemoryMap[Index].Type == DualChannelDdrMainMemory) { + if (Index == PeiMemoryIndex) { + // + // This is a partially tested Main Memory range, give it to EFI + // + RangeLength = MemoryMap[Index].RangeLength - PeiMemoryLength; + } else { + // + // This is an untested Main Memory range, give it to EFI. + // + RangeLength = MemoryMap[Index].RangeLength; + } + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + // + // RC Override: mark <4G available memory as tested to give DXE enough memory space, so that default + // memory allocations won't occupy the bins for specific memory types. + // + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + MemoryMap[Index].PhysicalAddress, + RangeLength + ); + + // + // Test this memory range + // + Status = BaseMemoryTestPpi->BaseMemoryTest ( + PeiServices, + BaseMemoryTestPpi, + MemoryMap[Index].PhysicalAddress, + RangeLength, + MemoryTestOp, + &BadMemoryAddress + ); + ASSERT_EFI_ERROR (Status); + } else { + if (( + (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) + ) && + (MemoryMap[Index].PhysicalAddress != MC_ABSEG_HSEG_PHYSICAL_START)) { + // + // Only count and report TSEG. + // + SmramRanges++; + } + // + // Make sure non-system memory is marked as reserved. + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_MEMORY_RESERVED, // MemoryType, +// 0, // MemoryAttribute + (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable)? EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE : 0, + MemoryMap[Index].PhysicalAddress, // MemoryBegin + MemoryMap[Index].RangeLength // MemoryLength + ); + } + } + + BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK); + if (SmramRanges > 0) { + BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR)); + } + + Hob.Raw = BuildGuidHob (&gEfiSmmPeiSmramMemoryReserve, BufferSize); + if (Hob.Raw == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SmramHobDescriptorBlock = (void *) (Hob.Raw); + SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges; + + SmramIndex = 0; + for (Index = 0; Index < NumRanges; Index++) { + if (( + (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) + ) && + (MemoryMap[Index].PhysicalAddress != MC_ABSEG_HSEG_PHYSICAL_START)) { + // + // This is an SMRAM range (not reporting AB_SEG or H_SEG), create an SMRAM descriptor. + // + SmramDescriptor = &SmramHobDescriptorBlock->Descriptor[SmramIndex]; + SmramDescriptor->PhysicalStart = MemoryMap[Index].PhysicalAddress; + SmramDescriptor->CpuStart = MemoryMap[Index].CpuAddress; + + // + // RangeLength includes alignment adjustment. + // + if (SmramDescriptor->PhysicalStart < 0x100000) { + SmramDescriptor->PhysicalSize = MemoryMap[Index].RangeLength; + } else { + SmramDescriptor->PhysicalSize = (Inputs->TsegSize - Inputs->IedSize )* 0x100000; + } + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "TSeg base is %Xh\n", SmramDescriptor->PhysicalStart); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "TSeg SMRAM size is %Xh\n", SmramDescriptor->PhysicalSize); + + + if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) { + SmramDescriptor->RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE; + } else { + SmramDescriptor->RegionState = EFI_SMRAM_CLOSED; + } + SmramIndex++; + } + } + // + // Get the current "Top of Upper Usable Memory" address from TOUUD. + // If TOUUD > 4G, it means memory is re-mapped. + // + TopUseableMemSize = McD0PciCfg64 (R_SA_TOUUD) & B_SA_TOUUD_TOUUD_MASK; + TopUseableMemAddr = MEM_EQU_4GB; + Tom = McD0PciCfg64 (R_SA_TOM) & B_SA_TOM_TOM_MASK; + + if (TopUseableMemSize > MEM_EQU_4GB) { + // + // This is above 4G memory address, give it to EFI. + // If memory hob length is above 4G length, cut and separate it. + // + while ((TopUseableMemSize - MEM_EQU_4GB) > MEM_EQU_4GB) { + PEI_DEBUG ((PeiServices, EFI_D_ERROR, "Found 0x100000000 bytes at 0x%016lX\n", TopUseableMemAddr)); + + if (Inputs->MemoryTrace && (TopUseableMemAddr + MEM_EQU_4GB > RShiftU64 (Tom, 1))) { + // + // Mark memory above 4GB as reserved if it's used for Memory Trace + // + ResourceType = EFI_RESOURCE_MEMORY_RESERVED; + ResourceAttribute = 0; + } else { + ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; + ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE; + } + BuildResourceDescriptorHob ( + ResourceType, // MemoryType, + ResourceAttribute, // MemoryAttribute + TopUseableMemAddr, // MemoryBegin + MEM_EQU_4GB // MemoryLength + ); + TopUseableMemSize = TopUseableMemSize - MEM_EQU_4GB; + TopUseableMemAddr = TopUseableMemAddr + MEM_EQU_4GB; + } + // + // Create hob for remaining memory which is above 4G memory address. + // + if (TopUseableMemSize > MEM_EQU_4GB) { + PEI_DEBUG ((PeiServices, EFI_D_ERROR, "Found 0x%016lX bytes at ", TopUseableMemSize - MEM_EQU_4GB)); + PEI_DEBUG ((PeiServices, EFI_D_ERROR, "0x%016lX\n", TopUseableMemAddr)); + } + if (Inputs->MemoryTrace) { + // + // Mark memory above 4GB as reserved if it's used for Memory Trace + // + ResourceType = EFI_RESOURCE_MEMORY_RESERVED; + ResourceAttribute = 0; + } else { + ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; + ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE; + } + BuildResourceDescriptorHob ( + ResourceType, // MemoryType, + ResourceAttribute, // MemoryAttribute + TopUseableMemAddr, // MemoryBegin + (TopUseableMemSize - MEM_EQU_4GB) // MemoryLength + ); + } + // + // If we found the capsule PPI (and we didn't have errors), then + // call the capsule PEIM to allocate memory for the capsule. + // + if (Capsule != NULL) { + Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength); + } + + return EFI_SUCCESS; +} + +/** + This function installs memory for the S3 resume path. + + @param[in] Inputs - Mrc input data structure + @param[in] PeiServices - PEI services table. + @param[in] VariableServices - Pointer to EFI Variable PPI + + @retval EFI_SUCCESS - The function completed successfully. + @retval EFI_OUT_OF_RESOURCES - Out of Resources. +**/ +EFI_STATUS +InstallS3Memory ( + IN const MrcInput *const Inputs, + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_READ_ONLY_VARIABLE_PPI *VariableServices +) +{ + EFI_STATUS Status; + UINTN VarSize; + UINTN VarAttrib; + EFI_PHYSICAL_ADDRESS TopUseableMemAddr; + EFI_PHYSICAL_ADDRESS TopUseableMemSize; + EFI_PHYSICAL_ADDRESS Tom; + UINT64 AcpiVariableSet64; + ACPI_VARIABLE_SET *AcpiVariableSet; + UINTN S3MemoryBase; + UINTN S3MemorySize; + UINT8 NumRanges; + PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES]; + EFI_PEI_HOB_POINTERS Hob; + EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock; + EFI_SMRAM_DESCRIPTOR *SmramDescriptor; + EFI_RESOURCE_TYPE ResourceType; + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; + UINT8 Index; + UINT8 SmramIndex; + UINT8 SmramRanges; + UINTN BufferSize; + const MrcDebug *Debug; + + Debug = &Inputs->Debug; + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Install S3 resume memory.\n"); + NumRanges = MAX_RANGES; + ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges); + // + // Call to GetMemoryMap to initialize TSEG registers. + // + Status = GetMemoryMap (PeiServices, (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap, &NumRanges); + ASSERT_EFI_ERROR (Status); + + AcpiVariableSet = NULL; + VarSize = sizeof (AcpiVariableSet64); + VarAttrib = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE; + + Status = VariableServices->PeiGetVariable ( + PeiServices, + ACPI_GLOBAL_VARIABLE, + &gEfiAcpiVariableGuid, + &VarAttrib, + &VarSize, + &AcpiVariableSet64 + ); + AcpiVariableSet = (ACPI_VARIABLE_SET *) (UINTN) AcpiVariableSet64; + + if (EFI_ERROR (Status) || (AcpiVariableSet == NULL)) { + return EFI_OUT_OF_RESOURCES; + } + + BuildGuidDataHob (&gEfiAcpiVariableGuid, AcpiVariableSet, sizeof (ACPI_VARIABLE_SET)); + + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "AcpiVariableSet at = 0x%x. 0x%x\n", + AcpiVariableSet, + &AcpiVariableSet->AcpiReservedMemoryBase + ); + + S3MemoryBase = (UINTN) (AcpiVariableSet->AcpiReservedMemoryBase); + S3MemorySize = (UINTN) (AcpiVariableSet->AcpiReservedMemorySize); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "S3MemoryBase = 0x%x - S3MemorySize = 0x%x.\n", S3MemoryBase, S3MemorySize); + Status = (*PeiServices)->InstallPeiMemory (PeiServices, S3MemoryBase, S3MemorySize); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve the system memory length and build memory hob for the system + // memory above 1MB, so memory callback can set cache for the system memory + // correctly on S3 resume path, just like it does on normal boot path. + // + PEI_ASSERT (PeiServices, (AcpiVariableSet->SystemMemoryLength - 0x100000) > 0); + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ), + 0x100000, + AcpiVariableSet->SystemMemoryLength - 0x100000 + ); + + // + // Get the current "Top of Upper Usable Memory" address from TOUUD. + // If TOUUD > 4G, it means memory is re-mapped. + // + TopUseableMemSize = McD0PciCfg64 (R_SA_TOUUD) & B_SA_TOUUD_TOUUD_MASK; + TopUseableMemAddr = MEM_EQU_4GB; + Tom = McD0PciCfg64 (R_SA_TOM) & B_SA_TOM_TOM_MASK; + + if (TopUseableMemSize > MEM_EQU_4GB) { + // + // This is a above 4G memory, give it to EFI + // if memory hob length is above 4G length,cut and separate it. + // + if (Inputs->MemoryTrace && (TopUseableMemAddr + MEM_EQU_4GB > RShiftU64 (Tom, 1))) { + if (Inputs->MemoryTrace) { + // + // Mark memory above 4GB as reserved if it's used for Memory Trace + // + ResourceType = EFI_RESOURCE_MEMORY_RESERVED; + ResourceAttribute = 0; + } else { + ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; + ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE; + } + BuildResourceDescriptorHob ( + ResourceType, // MemoryType, + ResourceAttribute, // MemoryAttribute + TopUseableMemAddr, // MemoryBegin + MEM_EQU_4GB // MemoryLength + ); + TopUseableMemSize = TopUseableMemSize - MEM_EQU_4GB; + TopUseableMemAddr = TopUseableMemAddr + MEM_EQU_4GB; + } + // + // Create hob for remaining memory which is above 4G memory address. + // + if (Inputs->MemoryTrace) { + // + // Mark memory above 4GB as reserved if it's used for Memory Trace + // + ResourceType = EFI_RESOURCE_MEMORY_RESERVED; + ResourceAttribute = 0; + } else { + ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; + ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE; + } + BuildResourceDescriptorHob ( + ResourceType, // MemoryType, + ResourceAttribute, // MemoryAttribute + TopUseableMemAddr, // MemoryBegin + (TopUseableMemSize - MEM_EQU_4GB) // MemoryLength + ); + } + + // + // Report SMRAM ranges + // + + SmramRanges = 0; + for (Index = 0; Index < NumRanges; Index++) { + if (( + (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) + ) && + (MemoryMap[Index].PhysicalAddress != MC_ABSEG_HSEG_PHYSICAL_START) + ) { + // + // Only count TSEG + // + SmramRanges++; + } + } + + BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK); + if (SmramRanges > 0) { + BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR)); + } + + Hob.Raw = BuildGuidHob (&gEfiSmmPeiSmramMemoryReserve, BufferSize); + + SmramHobDescriptorBlock = (void *) (Hob.Raw); + SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges; + + SmramIndex = 0; + for (Index = 0; Index < NumRanges; Index++) { + if (( + (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) || + (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) + ) && + (MemoryMap[Index].PhysicalAddress != MC_ABSEG_HSEG_PHYSICAL_START)) { + + // + // This is an SMRAM range (not reporting AB_SEG or H_SEG, create an SMRAM descriptor + // + SmramDescriptor = &SmramHobDescriptorBlock->Descriptor[SmramIndex]; + SmramDescriptor->PhysicalStart = MemoryMap[Index].PhysicalAddress; + SmramDescriptor->CpuStart = MemoryMap[Index].CpuAddress; + + // + // RangeLength includes alignment adjustment. + // + if (SmramDescriptor->PhysicalStart < 0x100000) { + SmramDescriptor->PhysicalSize = MemoryMap[Index].RangeLength; + } else { + SmramDescriptor->PhysicalSize = (Inputs->TsegSize - Inputs->IedSize )* 0x100000; + } + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "TSeg base is %Xh\n", SmramDescriptor->PhysicalStart); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "TSeg SMRAM size is %Xh\n", SmramDescriptor->PhysicalSize); + + if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) { + SmramDescriptor->RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE; + } else { + SmramDescriptor->RegionState = EFI_SMRAM_CLOSED; + } + SmramIndex++; + } + } + + return EFI_SUCCESS; +} + +/** + Determine the memory size desired based on HOB memory information. + + @param[in] PeiServices - PEI Services table. + @param[in, out] Size - The memory size to return. + + @retval Nothing. +**/ +void +RetrieveRequiredMemorySize ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT UINTN *Size + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + EFI_MEMORY_TYPE_INFORMATION *MemoryData; + UINT8 Index; + UINTN TempPageNum; + + *Size = 0; + MemoryData = NULL; + Status = (*PeiServices)->GetHobList (PeiServices, (VOID **) &Hob.Raw); + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION && + CompareGuid (&Hob.Guid->Name, &gEfiMemoryTypeInformationGuid)) { + MemoryData = (EFI_MEMORY_TYPE_INFORMATION *) (Hob.Raw + sizeof (EFI_HOB_GENERIC_HEADER) + sizeof (EFI_GUID)); + break; + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + // + // Platform PEIM should supply the information. Generic PEIM doesn't assume any default value. + // + if (MemoryData == NULL) { + return; + } + + TempPageNum = 0; + for (Index = 0; MemoryData[Index].Type != EfiMaxMemoryType; Index++) { + // + // Accumulate default memory size requirements + // + TempPageNum += MemoryData[Index].NumberOfPages; + } + + if (TempPageNum == 0) { + return; + } + // + // 16 additional pages are used by DXE memory manager. + // + *Size = (TempPageNum + 16) * EFI_PAGE_SIZE; + + return; +} + +/** + Determine the Total DPR memory size needed based on the DPR directory in the SA Data HOB. + + @param[in] PeiServices - PEI Services table. + @param[in, out] Size - The memory size in MB to return. + + @retval Nothing. +**/ +void +CalculateTotalDprMemorySize ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT UINT8 *Size + ) +{ + UINT8 DprEntryIndex; + SA_DATA_HOB *SaDataHob; + DPR_DIRECTORY_ENTRY *DirectoryEntry; + + *Size = 0; + DprEntryIndex = 0; + DirectoryEntry = NULL; + SaDataHob = NULL; + + SaDataHob = GetFirstGuidHob (&gSaDataHobGuid); + if (SaDataHob != NULL) { + DirectoryEntry = SaDataHob->DprDirectory; + while(DprEntryIndex < DPR_DIRECTORY_MAX){ + *Size += DirectoryEntry->Size; + DirectoryEntry++; + DprEntryIndex++; + } + } + return; +} + +/** + Calculates the bases for each technology consuming the DPR region + and updates the SA Data HOB with the appropriate values in the Dpr + directory + + @param[in] PeiServices - PEI Services table. + @param[in] Base - The memory base to return. + @param[in] TotalDprSizeMB - The total DPR size in MB + + @retval Nothing. +**/ +void +UpdateDprHobInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PHYSICAL_ADDRESS Base, + IN UINT8 TotalDprSizeMB + ) +{ + UINT32 TopOfDpr; + UINT8 DprEntryIndex; + SA_DATA_HOB *SaDataHob; + DPR_DIRECTORY_ENTRY *DirectoryEntry; + + DprEntryIndex = 0; + DirectoryEntry = NULL; + SaDataHob = NULL; + TopOfDpr = (UINT32) Base + (UINT32) LShiftU64(TotalDprSizeMB, 20); + + SaDataHob = GetFirstGuidHob (&gSaDataHobGuid); + if (SaDataHob != NULL) { + DirectoryEntry = SaDataHob->DprDirectory; + while(DprEntryIndex < DPR_DIRECTORY_MAX){ + switch (DirectoryEntry->Type) { + case DPR_DIRECTORY_TYPE_TXT: + DirectoryEntry->PhysBase = (UINT32) TopOfDpr - (UINT32) LShiftU64(DirectoryEntry->Size, 20); + break; + case DPR_DIRECTORY_TYPE_PFAT: + DirectoryEntry->PhysBase = (UINT32) Base; + break; + default: + break; + } + DirectoryEntry++; + DprEntryIndex++; + } + } + return; +} + +/** + Determine the memory size desired by GDXC + + @param[in] PeiServices - PEI Services table. + @param[in, out] MotSize - The MOT memory size + @param[in, out] GdxcSize - The GDXC memory size + + @retval Nothing. +**/ +void +RetrieveGdxcMemorySize ( + IN EFI_PEI_SERVICES **PeiServices, + OUT UINT64 *MotSize, + OUT UINT64 *GdxcSize + ) +{ + UINT32 MchBar; + UINT32 GdxcBar; + UINT32 TempMotSize; + MPCOHTRK_CR_GDXC_MOT_REGION_STRUCT MotRange; + MPCOHTRK_CR_GDXC_OCLA_REGION_STRUCT OclaRange; + + *MotSize = 0; + *GdxcSize = 0; + + // + // Get MchBAR + // + MchBar = McD0PciCfg32 (R_SA_MCHBAR) & B_SA_MCHBAR_MCHBAR_MASK; + // + // Get GdxcBar + // + MrcOemMmioRead (NCDECS_CR_GDXCBAR_NCU_REG, (U32 *) &GdxcBar, MchBar); + GdxcBar &= NCDECS_CR_GDXCBAR_NCU_MAX; + // + // Determine Gdxc size: Includes MOT\PSMI\IOT (OCLA) + // + MrcOemMmioRead(MPCOHTRK_CR_GDXC_MOT_REGION_REG, (U32 *) &MotRange, GdxcBar); + TempMotSize = MotRange.Bits.END_ADDRESS - MotRange.Bits.START_ADDRESS; + if (TempMotSize > 0) { + *GdxcSize = *MotSize = MrcOemMemoryLeftShiftU64 ((UINT64) (TempMotSize + 1), 23); + } + + MrcOemMmioRead(MPCOHTRK_CR_GDXC_OCLA_REGION_REG, (U32 *) &OclaRange, GdxcBar); + *GdxcSize += MrcOemMemoryLeftShiftU64 ((UINT64) (OclaRange.Bits.END_ADDRESS - OclaRange.Bits.START_ADDRESS), 23); + + // Add 16MB if some allocated to MOT and/or IOT + if (*GdxcSize != 0) { + *GdxcSize += (16 << 20); + } + + return; +} + +/** + This function returns the memory ranges to be enabled, along with information + describing how the range should be used. The MemoryMap buffer will be filled in and + NumRanges will contain the actual number of memory ranges that are to be enabled. + + @param[in] PeiServices - PEI Services Table. + @param[in, out] MemoryMap - Buffer to record details of the memory ranges to be enabled. + @param[in, out] NumRanges - On input, this contains the maximum number of memory ranges that + can be described in the MemoryMap buffer. + + @retval EFI_SUCCESS - The function completed successfully. + @retval EFI_BUFFER_TOO_SMALL - The specified number of ranges is too large. +**/ +EFI_STATUS +GetMemoryMap ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap, + IN OUT UINT8 *NumRanges + ) +{ + BOOLEAN EnableSmram; + EFI_PHYSICAL_ADDRESS MemorySize; + EFI_PHYSICAL_ADDRESS RowLength; + EFI_PHYSICAL_ADDRESS AlignedTsegBase; + EFI_PHYSICAL_ADDRESS AlignedGdxcBase; + EFI_STATUS Status; + PEI_MEMORY_RANGE_GRAPHICS_MEMORY GraphicsMemoryMask; + PEI_MEMORY_RANGE_PCI_MEMORY PciMemoryMask; + PEI_MEMORY_RANGE_OPTION_ROM OptionRomMask; + PEI_MEMORY_RANGE_SMRAM SmramMask; + PEI_MEMORY_RANGE_SMRAM TsegMask; + PEI_PLATFORM_MEMORY_RANGE_PPI *MemoryRangePpi; + UINT32 BlockNum; + UINT8 EsmramcRegister; + UINT8 ExtendedMemoryIndex; + UINT8 Index; + UINT8 TotalDprSizeMB; + UINT64 GdxcRequiredMemSize; + UINT64 GdxcMotMemSize; +#ifdef PTT_FLAG + UINT32 PttSts; +#endif + if ((*NumRanges) < MAX_RANGES) { + return EFI_BUFFER_TOO_SMALL; + } + + *NumRanges = 0; + + // + // Get platform memory range service + // + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiPlatformMemoryRangePpiGuid, 0, NULL, (VOID **) &MemoryRangePpi); + ASSERT_EFI_ERROR (Status); + + // + // Find out which memory ranges to reserve on this platform + // + Status = MemoryRangePpi->ChooseRanges ( + PeiServices, + MemoryRangePpi, + &OptionRomMask, + &SmramMask, + &GraphicsMemoryMask, + &PciMemoryMask + ); + ASSERT_EFI_ERROR (Status); + // + // MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "OptionRomMask = %Xh\n", OptionRomMask); + // MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "SmramMask = %Xh\n", SmramMask); + // MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "GraphicsMemoryMask = %Xh\n", GraphicsMemoryMask); + // MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "PciMemoryMask = %Xh\n", PciMemoryMask); + // + // + // Generate memory ranges for the memory map. + // + EnableSmram = FALSE; + EsmramcRegister = 0; + MemorySize = 0; + Index = 0; + + // + // Get the current "max usable memory" address from TOLUD because we will not + // support any memory above 4Gig. Will ignore the memory between 4G and TOUUD. + // + RowLength = McD0PciCfg32 (R_SA_TOLUD) & B_SA_TOLUD_TOLUD_MASK; + + // + // System is very unlikely to work with less than 32MB + // + PEI_ASSERT (PeiServices, RowLength >= (32 * 1024 * 1024)); + + // + // Add memory below 640KB to the memory map. Make sure memory between + // 640KB and 1MB are reserved, even if not used for SMRAM + // + MemoryMap[*NumRanges].RowNumber = Index; + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[*NumRanges].RangeLength = 0xA0000; + MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory; + (*NumRanges)++; + + // + // Reserve ABSEG or HSEG SMRAM if needed + // + if (SmramMask & (PEI_MR_SMRAM_ABSEG_MASK | PEI_MR_SMRAM_HSEG_MASK)) { + EnableSmram = TRUE; + MemoryMap[*NumRanges].PhysicalAddress = MC_ABSEG_HSEG_PHYSICAL_START; + MemoryMap[*NumRanges].RangeLength = MC_ABSEG_HSEG_LENGTH; + MemoryMap[*NumRanges].CpuAddress = (SmramMask & PEI_MR_SMRAM_ABSEG_MASK) ? + MC_ABSEG_CPU_START : + MC_HSEG_CPU_START; + // + // Chipset only supports cacheable SMRAM. + // + MemoryMap[*NumRanges].Type = DualChannelDdrSmramNonCacheable; + } + else { + // + // Just mark this range reserved. + // + MemoryMap[*NumRanges].PhysicalAddress = MC_ABSEG_HSEG_PHYSICAL_START; + MemoryMap[*NumRanges].CpuAddress = MC_ABSEG_CPU_START; + MemoryMap[*NumRanges].RangeLength = 0x60000; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + } + + MemoryMap[*NumRanges].RowNumber = Index; + (*NumRanges)++; + + RowLength -= 0x100000; + MemorySize = 0x100000; + + // + // Add remaining memory to the memory map. + // + if (RowLength > 0) { + MemoryMap[*NumRanges].RowNumber = Index; + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[*NumRanges].RangeLength = RowLength; + MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory; + (*NumRanges)++; + MemorySize += RowLength; + } + + ExtendedMemoryIndex = (UINT8) (*NumRanges - 1); + + // + // See if we need to trim Graphics Memory out of the highest memory range. + // + if (GraphicsMemoryMask != PEI_MR_GRAPHICS_MEMORY_NONE) { + // + // Create the new range for Graphics Memory from the previous SdrDdrMainMemory range. + // + MemoryMap[*NumRanges].RangeLength = ((GraphicsMemoryMask & PEI_MR_GRAPHICS_MEMORY_SIZE_MASK) * 512 * 1024); + MemoryMap[*NumRanges].RowNumber = MemoryMap[ExtendedMemoryIndex].RowNumber; + MemorySize -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].Type = (GraphicsMemoryMask & PEI_MR_GRAPHICS_MEMORY_CACHEABLE) ? + DualChannelDdrGraphicsMemoryCacheable : DualChannelDdrGraphicsMemoryNonCacheable; + + (*NumRanges)++; + } + // + // See if we need to trim TSEG out of the highest memory range. + // + if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) { + // + // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range. + // + TsegMask = (SmramMask & PEI_MR_SMRAM_SIZE_MASK); + + BlockNum = 1; + while (TsegMask) { + TsegMask >>= 1; + BlockNum <<= 1; + } + + BlockNum >>= 1; + + switch (BlockNum) { + case PEI_MR_SMRAM_SIZE_1024K_MASK: + break; + + case PEI_MR_SMRAM_SIZE_2048K_MASK: + break; + + case PEI_MR_SMRAM_SIZE_8192K_MASK: + break; + + case PEI_MR_SMRAM_SIZE_16384K_MASK: + break; + + case PEI_MR_SMRAM_SIZE_32768K_MASK: + break; + + case PEI_MR_SMRAM_SIZE_65536K_MASK: + break; + + default: + // + // Non supported size. Set to 0. + // + BlockNum = 0; + break; + } + + if (BlockNum) { + EnableSmram = TRUE; + + MemoryMap[*NumRanges].RangeLength = (BlockNum * 128 * 1024); + MemoryMap[*NumRanges].RowNumber = MemoryMap[ExtendedMemoryIndex].RowNumber; + MemorySize -= MemoryMap[*NumRanges].RangeLength; + + // + // MRC aligns TSEG base on 8MB boundary. + // Need to adjust memory map accordingly. + // + AlignedTsegBase = MemorySize & ~(MemoryMap[*NumRanges].RangeLength - 1); + MemoryMap[*NumRanges].RangeLength += (MemorySize - AlignedTsegBase); + MemorySize = AlignedTsegBase; + MemoryMap[*NumRanges].PhysicalAddress = AlignedTsegBase; + MemoryMap[*NumRanges].CpuAddress = AlignedTsegBase; + MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength; + } + // + // Chipset only supports cacheable SMRAM. + // + MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable; + + (*NumRanges)++; + } + +//;;## ...AMI_OVERRIDE... Disable compatible SMM space A00000 and B00000 start. +#ifndef SMM_THUNK_NO_AB_SEG_FLAG + // + // Turn on SMRAM if required. + // + if (EnableSmram) { + McD0PciCfg8Or (R_SA_SMRAMC, B_SA_SMRAMC_G_SMRAME_MASK); + } +#endif +//;;## ...AMI_OVERRIDE... Disable compatible SMM space A00000 and B00000 end. + // + // Reserve DPR based on Total size required by all technologies using DPR + // + CalculateTotalDprMemorySize (PeiServices, &TotalDprSizeMB); + + if (TotalDprSizeMB != 0) { + + MemoryMap[*NumRanges].RangeLength = (UINT64) LShiftU64 (TotalDprSizeMB, 20); + MemoryMap[*NumRanges].RowNumber = MemoryMap[ExtendedMemoryIndex].RowNumber; + MemorySize -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + + UpdateDprHobInfo (PeiServices, MemorySize, TotalDprSizeMB); + + (*NumRanges)++; + } + + // + // Reserve GDXC + // + RetrieveGdxcMemorySize (PeiServices, &GdxcMotMemSize, &GdxcRequiredMemSize); + + if (GdxcRequiredMemSize) { + MemoryMap[*NumRanges].RangeLength = GdxcMotMemSize; + MemoryMap[*NumRanges].RowNumber = MemoryMap[ExtendedMemoryIndex].RowNumber; + MemorySize -= MemoryMap[*NumRanges].RangeLength; + + // + // MRC aligns Mot base on 16MB boundary. + // Need to adjust memory map accordingly. + // + AlignedGdxcBase = MemorySize &~(MRC_BIT24 - 1); + // + // Now subtract rest of GdxcRequiredMemsize - GdxcMotMemSize + // + AlignedGdxcBase -= GdxcRequiredMemSize - GdxcMotMemSize; + MemoryMap[*NumRanges].RangeLength += (MemorySize - AlignedGdxcBase); + MemorySize = AlignedGdxcBase; + MemoryMap[*NumRanges].PhysicalAddress = AlignedGdxcBase; + MemoryMap[*NumRanges].CpuAddress = AlignedGdxcBase; + MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + + (*NumRanges)++; + } + +#ifdef PTT_FLAG + if (GetCpuFamily() == cmHSW_ULT) { + MrcOemMmioRead (R_PTT_HCI_STS, (U32 *) &PttSts, R_PTT_HCI_BASE_ADDRESS); + if ((PttSts & B_PTT_HCI_STS_ENABLED) == B_PTT_HCI_STS_ENABLED) { + MemoryMap[*NumRanges].RangeLength = 0x1000; + MemoryMap[*NumRanges].RowNumber = MemoryMap[ExtendedMemoryIndex].RowNumber; + MemorySize -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].PhysicalAddress = MemorySize; + MemoryMap[*NumRanges].CpuAddress = MemorySize; + MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength; + MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory; + + (*NumRanges)++; + } + } +#endif + + return EFI_SUCCESS; +} + +/** + This function returns a pointer to the allocated hand off buffer. + + @param[in] PeiServices - A pointer to the EFI PEI services table + @param[in, out] Hob - A pointer to where to store the pointer to the allocated data buffer. + @param[in] Size - The size of the buffer to get. + + @retval EFI_SUCCESS - Hob is successfully built. + @retval Others - Error occured while creating the Hob. +**/ +EFI_STATUS +MrcGetHobForDataStorage ( + IN EFI_PEI_SERVICES **PeiServices, + IN OUT HOB_SAVE_MEMORY_DATA **Hob, + IN UINT16 BlockSize + ) +{ + EFI_STATUS Status; + + Status = (*PeiServices)->CreateHob (PeiServices, EFI_HOB_TYPE_GUID_EXTENSION, BlockSize, (VOID **) Hob); + if (EFI_ERROR (Status)) { + return Status; + } + (*Hob)->EfiHobGuidType.Name = gMemRestoreDataGuid; + ZeroMem (&((*Hob)->MrcData), sizeof (MrcParameters)); + return EFI_SUCCESS; +} + +/** + A small memory test to quickly point out severe memory issues. + + @param[in] Inputs - Pointer to the MRC Input data structure + + @retval mrcFail on failure, otherwise mrcSuccess. +**/ +MrcStatus +BasicMemoryTest ( + IN const MrcInput * const Inputs + ) +{ + const UINT32 BlockSize = 0x1000; + UINT8 *Addr; + UINT8 Pattern; + UINT8 Value; + UINTN LoopCount; + const MrcDebug *Debug; + + Debug = &Inputs->Debug; + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Normal mode memory test started.\n"); + + Addr = 0; + Pattern = 0; + while ((UINT32) Addr < BlockSize) { + *Addr = Pattern++; + Addr++; + } + + for (LoopCount = 0; LoopCount < 20; LoopCount++) { + Addr = 0; + Pattern = 0; + while ((UINT32) Addr < BlockSize) { + Value = *Addr; + if (Value != Pattern) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "!!! Normal mode memory test FAILED !!!\n"); + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_ERROR, + "Address: %Xh, Expected data: %Xh, Actual data: %Xh.\n", + Addr, + Pattern, + Value + ); + return mrcFail; + } + Addr++; + Pattern++; + } + } + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Normal mode memory test passed.\n"); + return mrcSuccess; +} + +#ifndef TXT_SUPPORT_FLAG +/** + Determines whether or not the platform has executed a TXT launch by + examining the TPM Establishment bit. + + @param[in] PeiServices - General purpose services available to every PEIM. + + @retval TRUE - If the TPM establishment bit is asserted. + @retval FALSE - If the TPM establishment bit is unasserted. +**/ +BOOLEAN +IsEstablishmentBitAsserted ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + UINT8 Access; + UINT16 TimeOutCount; + EFI_STATUS Status; + PEI_STALL_PPI *StallPpi; + Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, (VOID **) &StallPpi); + ASSERT_EFI_ERROR (Status); + + + // + // Set TPM.ACCESS polling timeout about 750ms. + // + TimeOutCount = TPM_TIME_OUT; + do { + // + // Read TPM status register + // + + Access = (*PeiServices)->CpuIo->MemRead8 ( + PeiServices, + (*PeiServices)->CpuIo, + TPM_STATUS_REG_ADDRESS + ); + + // + // if TPM.Access == 0xFF, TPM is not present. + // + if (Access == 0xFF) { + return FALSE; + } + // + // Check tpmRegValidSts bit before checking establishment bit. + // + if ((Access & 0x80) == 0x80) { + // + // tpmRegValidSts set, we can check establishment bit now. + // + break; + } + else { + // + // Delay 1ms + // + StallPpi->Stall (PeiServices, StallPpi, 1000); + } + + TimeOutCount--; + } while (TimeOutCount != 0); + + // + // ValidSts is not set. + // + if ((Access & 0x80) != 0x80) { + return FALSE; + } + // + // The bit we're interested in uses negative logic: + // If bit 0 == 1 then return False, + // Else return True. + // + return (BOOLEAN) ((Access & 0x1) ? FALSE : TRUE); +} + +/** + Unlock memory when security is set and TxT is not enabled. + + @param[in] MrcData - Mrc global data. + @param[in] PeiServices - PEI Services Table. + + @retval Nothing +**/ +void +UnlockMemory ( + IN const MrcParameters *const MrcData, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_CPUID_REGISTER Reg; + UINT32 Data32; + const MrcDebug *Debug; + + Debug = &MrcData->SysIn.Inputs.Debug; + + Data32 = 0; + + EfiCpuid (1, &Reg); + if ((Reg.RegEcx & BIT6)) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Processor supports TXT\n"); + + Data32 = CheckSmxCapabilities(); + + if (Data32 & BIT0) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Platform / PCH supports TXT\n"); + if (!(IsEstablishmentBitAsserted (PeiServices))) { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Unlock memory\n"); + EfiWriteMsr (0x2e6, 0); + } + } + else { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Platform / PCH does not support TxT\n"); + } + } + else { + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Processor does not support TxT\n"); + } +} +#endif // TXT_SUPPORT_FLAG + +/** + Determine whether a cold reset of the platform is required. + Note that the memory configuration saved data must be valid. + + @param[in] MrcData - The MRC "global data" area. + @param[in] SaPlatformPolicyPpi - SA Platform Policy structure. + + @retval TRUE if cold reset is required, otherwise returns FALSE. +**/ +BOOLEAN +ColdBootRequired ( + IN const MrcParameters *const MrcData, + IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi + ) +{ + const MrcDebug *Debug; + const MrcInput *Inputs; + const MrcSaveData *SaveData; + MEMORY_CONFIGURATION *MemConfig; + MrcVersion Version; + U32 CurrentCrc; + + Inputs = &MrcData->SysIn.Inputs; + Debug = &Inputs->Debug; + SaveData = &MrcData->SysSave.Save.Data; + MemConfig = SaPlatformPolicyPpi->MemConfig; + + MrcVersionGet (&Version); + CurrentCrc = MrcCalculateCrc32 ((U8 *) MemConfig, sizeof (MEMORY_CONFIGURATION)); + + if ((Version.Major != SaveData->Version.Major) || + (Version.Minor != SaveData->Version.Minor) || + (Version.Rev != SaveData->Version.Rev) || + (Version.Build != SaveData->Version.Build)) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "MRC change detected, prev. ver. %u.%u.%u.%u, curr. ver. %u.%u.%u.%u\n", + SaveData->Version.Major, + SaveData->Version.Minor, + SaveData->Version.Rev, + SaveData->Version.Build, + Version.Major, + Version.Minor, + Version.Rev, + Version.Build + ); + return TRUE; + } + if ((Inputs->CpuModel != SaveData->CpuModel) || (Inputs->CpuStepping != SaveData->CpuStepping)) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "CPU change detected, prev. CPU %x.%x, curr. CPU %x.%x\n", + SaveData->CpuModel, + SaveData->CpuStepping, + Inputs->CpuModel, + Inputs->CpuStepping + ); + return TRUE; + } + if (CurrentCrc != SaveData->SaMemCfgCrc) { + MRC_DEBUG_MSG ( + Debug, + MSG_LEVEL_NOTE, + "System Agent input parameter change detected, prev. CRC %xh, curr. CRC %xh.\n", + SaveData->SaMemCfgCrc, + CurrentCrc + ); + + return TRUE; + } + return FALSE; +} + +/** + Set up the MRC input data structure. + + @param[in] SysBootMode - Boot mode of the system. + @param[in] BootMode - Boot mode of the Mrc. + @param[out] Inputs - Pointer to the Mrc Input data structure. + @param[in] PeiServices - PEI Services Table. + @param[in] SaPlatformPolicyPpi - SA Platform Policy structure. + + @retval Always returns mrcSuccess. +**/ +MrcBootMode +MrcSetupMrcData ( + IN const EFI_BOOT_MODE SysBootMode, + IN const MrcBootMode BootMode, + OUT MrcInput *const Inputs, + IN EFI_PEI_SERVICES **const PeiServices, + IN SA_PLATFORM_POLICY_PPI *const SaPlatformPolicyPpi + ) +{ + const MEMORY_CONFIGURATION *MemConfig; + const MrcDebug *Debug; + MrcControllerIn *ControllerIn; + MrcChannelIn *ChannelIn; + U16 DeviceId; + U8 Controller; + U8 Channel; + U8 Dimm; + + Debug = &Inputs->Debug; + MemConfig = SaPlatformPolicyPpi->MemConfig; + + Inputs->SaMemCfgAddress = (U32) MemConfig; + Inputs->SaMemCfgSize = sizeof (MEMORY_CONFIGURATION); + Inputs->RefClk = 0; + Inputs->Ratio = 0; + Inputs->VddVoltage = VDD_INVALID; + + // Setup the memory profile (Standard/XMP/Custom) + switch (MemConfig->SpdProfileSelected) { +#if (SUPPORT_XMP == SUPPORT) + case XMPProfile1: + Inputs->MemoryProfile = (SysBootMode == BOOT_WITH_DEFAULT_SETTINGS) ? STD_PROFILE : XMP_PROFILE1; + break; + case XMPProfile2: + Inputs->MemoryProfile = (SysBootMode == BOOT_WITH_DEFAULT_SETTINGS) ? STD_PROFILE : XMP_PROFILE2; + break; +#endif // SUPPORT_XMP + case UserDefined: + if (SysBootMode == BOOT_WITH_DEFAULT_SETTINGS) { + Inputs->MemoryProfile = STD_PROFILE; + } else { + Inputs->MemoryProfile = USER_PROFILE; + Inputs->RefClk = MemConfig->RefClk; + Inputs->Ratio = MemConfig->Ratio; + Inputs->VddVoltage = MemConfig->DDR3Voltage; + } + break; + case Default: + default: + Inputs->MemoryProfile = STD_PROFILE; + break; + } + + // Setup the base addresses. + Inputs->MchBarBaseAddress = SaPlatformPolicyPpi->PlatformData->MchBar; + Inputs->PciEBaseAddress = SaPlatformPolicyPpi->PlatformData->PciExpressBar; + Inputs->SmbusBaseAddress = SaPlatformPolicyPpi->PlatformData->SmbusBar; + Inputs->GdxcBaseAddress = SaPlatformPolicyPpi->PlatformData->GdxcBar; + Inputs->HpetBaseAddress = 0xFED00000; + + // + // MMIO size in MB units (below 4GB) + // + Inputs->MmioSize = SaPlatformPolicyPpi->GtConfig->MmioSize; + + // + // DDR maximum frequency + // + Inputs->FreqMax = MemConfig->DdrFreqLimit; + + // + // TSEG Size in MB units + // + Inputs->TsegSize = (SaPlatformPolicyPpi->PlatformData->TsegSize) >> 20; + + // + // Graphics Stolen Size + // + Inputs->GraphicsGttSize = SaPlatformPolicyPpi->GtConfig->GttSize; + // IgdDvmt50PreAlloc value 17 represents 1024M memory - WA for GMS limitation of 5 bits. + if (SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc == 17) { + Inputs->GraphicsStolenSize = 32 * 32; + } else { + Inputs->GraphicsStolenSize = 32 * SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc; + } + Inputs->GfxIsVersatileAcceleration = FALSE; + + // + //Get RTC time + // + MrcOemGetRtcTime(&(Inputs->BaseTime.Seconds),&(Inputs->BaseTime.Minutes), + &(Inputs->BaseTime.Hours), &(Inputs->BaseTime.DayOfMonth), + &(Inputs->BaseTime.Month), &(Inputs->BaseTime.Year) ); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "RTC %u/%u/%u %u:%u:%u\n", + Inputs->BaseTime.Month, Inputs->BaseTime.DayOfMonth, + Inputs->BaseTime.Year, Inputs->BaseTime.Hours, + Inputs->BaseTime.Minutes, Inputs->BaseTime.Seconds); + + // + // Get BoardType (Mobile - 0; Desktop/UpServer - 1) + // + Inputs->BoardType = SaPlatformPolicyPpi->PlatformData->UserBd; + DeviceId = McD0PciCfg16 (R_SA_MC_DEVICE_ID); + Inputs->MobilePlatform = (IS_SA_DEVICE_ID_MOBILE(DeviceId)) ? TRUE : FALSE; + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "BoardType=%d, MobilePlatform=%d\n", Inputs->BoardType, Inputs->MobilePlatform); + + // + // Get memory voltages requested value. + // + Inputs->VddSettleWaitTime = MemConfig->DDR3VoltageWaitTime; + Inputs->VccIomV = 1000; // Assume 1.0 volts + + Inputs->SetRxDqs32 = FALSE; + Inputs->McLock = MemConfig->McLock; + + Inputs->Gdxc.GdxcEnable = MemConfig->GdxcEnable; // Enable/disable GDXC support + Inputs->Gdxc.GdxcIotSize = MemConfig->GdxcIotSize; // Value in 8MB + Inputs->Gdxc.GdxcMotSize = MemConfig->GdxcMotSize; // Value in 8MB + + Inputs->MemoryTrace = MemConfig->MemoryTrace; // Memory Trace to second DDR channel using Stacked Mode + + // + // Options for training steps + // + Inputs->TrainingEnables.ECT = MemConfig->ECT; + Inputs->TrainingEnables.SOT = MemConfig->SOT; + Inputs->TrainingEnables.RDMPRT = MemConfig->RDMPRT; + Inputs->TrainingEnables.RCVET = MemConfig->RCVET; + Inputs->TrainingEnables.JWRL = MemConfig->JWRL; + Inputs->TrainingEnables.FWRL = MemConfig->FWRL; + Inputs->TrainingEnables.WRTC1D = MemConfig->WRTC1D; + Inputs->TrainingEnables.RDTC1D = MemConfig->RDTC1D; + Inputs->TrainingEnables.DIMMODTT = MemConfig->DIMMODTT; + Inputs->TrainingEnables.WRDST = MemConfig->WRDST; + Inputs->TrainingEnables.WREQT = MemConfig->WREQT; + Inputs->TrainingEnables.RDODTT = MemConfig->RDODTT; + Inputs->TrainingEnables.RDEQT = MemConfig->RDEQT; + Inputs->TrainingEnables.RDAPT = MemConfig->RDAPT; + Inputs->TrainingEnables.WRTC2D = MemConfig->WRTC2D; + Inputs->TrainingEnables.RDTC2D = MemConfig->RDTC2D; + Inputs->TrainingEnables.WRVC2D = MemConfig->WRVC2D; + Inputs->TrainingEnables.RDVC2D = MemConfig->RDVC2D; + Inputs->TrainingEnables.LCT = MemConfig->LCT; + Inputs->TrainingEnables.RTL = MemConfig->RTL; + Inputs->TrainingEnables.TAT = MemConfig->TAT; + Inputs->TrainingEnables.RMT = MemConfig->RMT; + Inputs->TrainingEnables.MEMTST = MemConfig->MEMTST; + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) { + Inputs->TrainingEnables.DIMMODTT1D = MemConfig->DIMMODTT1D; + Inputs->TrainingEnables.WRSRT = MemConfig->WRSRT; + Inputs->TrainingEnables.DIMMRONT = MemConfig->DIMMRONT; + } else { + Inputs->TrainingEnables.DIMMODTT1D = 0; + Inputs->TrainingEnables.WRSRT = 0; + Inputs->TrainingEnables.DIMMRONT = 1; + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_4) { + Inputs->TrainingEnables.CMDVC = MemConfig->CMDVC; + Inputs->PowerDownMode = MemConfig->PowerDownMode; + Inputs->PwdwnIdleCounter = MemConfig->PwdwnIdleCounter; + Inputs->RankInterleave = MemConfig->RankInterleave; + Inputs->EnhancedInterleave = MemConfig->EnhancedInterleave; + Inputs->WeaklockEn = MemConfig->WeaklockEn; + Inputs->EnCmdRate = MemConfig->EnCmdRate; + Inputs->CmdTriStateDis = MemConfig->CmdTriStateDis; + } else { + Inputs->TrainingEnables.CMDVC = 1; + Inputs->PowerDownMode = 0xFF; + Inputs->PwdwnIdleCounter = 0x40; + Inputs->RankInterleave = TRUE; + Inputs->EnhancedInterleave = TRUE; + Inputs->WeaklockEn = FALSE; + Inputs->EnCmdRate = 7; + Inputs->CmdTriStateDis = FALSE; + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_5) { + Inputs->BClkFrequency = (MemConfig->BClkFrequency < (BCLK_DEFAULT - (10 * 1000 * 1000))) ? + BCLK_DEFAULT : ((MemConfig->BClkFrequency / 1000000) * 1000000); + } else { + Inputs->BClkFrequency = BCLK_DEFAULT; + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_6) { + Inputs->TrainingEnables.ALIASCHK = MemConfig->ALIASCHK; + } else { + Inputs->TrainingEnables.ALIASCHK = 1; + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_9) { + Inputs->IedSize = (SaPlatformPolicyPpi->PlatformData->IedSize) >> 20; + Inputs->RefreshRate2x = MemConfig->RefreshRate2x; // Tells the MRC to enable 2x Refresh. + Inputs->ChHashEnable = MemConfig->ChHashEnable; // Enale/disable CH HASH support + Inputs->ChHashMask = MemConfig->ChHashMask; // Addr bits[19:6] to include in Channel XOR function. + Inputs->ChHashInterleaveBit = MemConfig->ChHashInterleaveBit; // Valid values are 0 - 3 for BITS 6 -9 + } else { + Inputs->IedSize = 0x04; + Inputs->RefreshRate2x = FALSE; + Inputs->ChHashEnable = TRUE; // Enale CH HASH support + Inputs->ChHashMask = 0x30CE; // Addr bits[19:6] to include in Channel XOR function. + Inputs->ChHashInterleaveBit = 1; // Valid values are 0 - 3 for BITS 6 -9 + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_10) { + // + // Options for Thermal settings + // + Inputs->ThermalEnables.EnableExtts = MemConfig->EnableExtts; + Inputs->ThermalEnables.EnableCltm = MemConfig->EnableCltm; + Inputs->ThermalEnables.EnableOltm = MemConfig->EnableOltm; + Inputs->ThermalEnables.EnablePwrDn = MemConfig->EnablePwrDn; +#ifdef ULT_FLAG + if (Inputs->CpuModel == cmHSW_ULT) { + Inputs->ThermalEnables.EnablePwrDnLpddr = MemConfig->EnablePwrDnLpddr; + } +#endif // ULT_FLAG + Inputs->ThermalEnables.Refresh2X = MemConfig->Refresh2X; + Inputs->ThermalEnables.LpddrThermalSensor = MemConfig->LpddrThermalSensor; // LPDDR MR4 temperature reads + Inputs->ThermalEnables.LockPTMregs = MemConfig->LockPTMregs; + Inputs->ThermalEnables.UserPowerWeightsEn = MemConfig->UserPowerWeightsEn; + Inputs->ThermalEnables.EnergyScaleFact = MemConfig->EnergyScaleFact; + Inputs->ThermalEnables.RaplPwrFl[1] = MemConfig->RaplPwrFlCh1; + Inputs->ThermalEnables.RaplPwrFl[0] = MemConfig->RaplPwrFlCh0; + Inputs->ThermalEnables.RaplLim2Lock = MemConfig->RaplLim2Lock; + Inputs->ThermalEnables.RaplLim2WindX = MemConfig->RaplLim2WindX; + Inputs->ThermalEnables.RaplLim2WindY = MemConfig->RaplLim2WindY; + Inputs->ThermalEnables.RaplLim2Ena = MemConfig->RaplLim2Ena; + Inputs->ThermalEnables.RaplLim2Pwr = MemConfig->RaplLim2Pwr; + Inputs->ThermalEnables.RaplLim1WindX = MemConfig->RaplLim1WindX; + Inputs->ThermalEnables.RaplLim1WindY = MemConfig->RaplLim1WindY; + Inputs->ThermalEnables.RaplLim1Ena = MemConfig->RaplLim1Ena; + Inputs->ThermalEnables.RaplLim1Pwr = MemConfig->RaplLim1Pwr; + Inputs->ThermalEnables.WarmThreshold[0][0] = MemConfig->WarmThresholdCh0Dimm0; + Inputs->ThermalEnables.WarmThreshold[0][1] = MemConfig->WarmThresholdCh0Dimm1; + Inputs->ThermalEnables.WarmThreshold[1][0] = MemConfig->WarmThresholdCh1Dimm0; + Inputs->ThermalEnables.WarmThreshold[1][1] = MemConfig->WarmThresholdCh1Dimm1; + Inputs->ThermalEnables.HotThreshold[0][0] = MemConfig->HotThresholdCh0Dimm0; + Inputs->ThermalEnables.HotThreshold[0][1] = MemConfig->HotThresholdCh0Dimm1; + Inputs->ThermalEnables.HotThreshold[1][0] = MemConfig->HotThresholdCh1Dimm0; + Inputs->ThermalEnables.HotThreshold[1][1] = MemConfig->HotThresholdCh1Dimm1; + Inputs->ThermalEnables.WarmBudget[0][0] = MemConfig->WarmBudgetCh0Dimm0; + Inputs->ThermalEnables.WarmBudget[0][1] = MemConfig->WarmBudgetCh0Dimm1; + Inputs->ThermalEnables.WarmBudget[1][0] = MemConfig->WarmBudgetCh1Dimm0; + Inputs->ThermalEnables.WarmBudget[1][1] = MemConfig->WarmBudgetCh1Dimm1; + Inputs->ThermalEnables.HotBudget[0][0] = MemConfig->HotBudgetCh0Dimm0; + Inputs->ThermalEnables.HotBudget[0][1] = MemConfig->HotBudgetCh0Dimm1; + Inputs->ThermalEnables.HotBudget[1][0] = MemConfig->HotBudgetCh1Dimm0; + Inputs->ThermalEnables.HotBudget[1][1] = MemConfig->HotBudgetCh1Dimm1; + Inputs->ThermalEnables.IdleEnergy[0][1] = MemConfig->IdleEnergyCh0Dimm1; + Inputs->ThermalEnables.IdleEnergy[0][0] = MemConfig->IdleEnergyCh0Dimm0; + Inputs->ThermalEnables.IdleEnergy[1][1] = MemConfig->IdleEnergyCh1Dimm1; + Inputs->ThermalEnables.IdleEnergy[1][0] = MemConfig->IdleEnergyCh1Dimm0; + Inputs->ThermalEnables.PdEnergy[0][1] = MemConfig->PdEnergyCh0Dimm1; + Inputs->ThermalEnables.PdEnergy[0][0] = MemConfig->PdEnergyCh0Dimm0; + Inputs->ThermalEnables.PdEnergy[1][1] = MemConfig->PdEnergyCh1Dimm1; + Inputs->ThermalEnables.PdEnergy[1][0] = MemConfig->PdEnergyCh1Dimm0; + Inputs->ThermalEnables.ActEnergy[0][1] = MemConfig->ActEnergyCh0Dimm1; + Inputs->ThermalEnables.ActEnergy[0][0] = MemConfig->ActEnergyCh0Dimm0; + Inputs->ThermalEnables.ActEnergy[1][1] = MemConfig->ActEnergyCh1Dimm1; + Inputs->ThermalEnables.ActEnergy[1][0] = MemConfig->ActEnergyCh1Dimm0; + Inputs->ThermalEnables.RdEnergy[0][1] = MemConfig->RdEnergyCh0Dimm1; + Inputs->ThermalEnables.RdEnergy[0][0] = MemConfig->RdEnergyCh0Dimm0; + Inputs->ThermalEnables.RdEnergy[1][1] = MemConfig->RdEnergyCh1Dimm1; + Inputs->ThermalEnables.RdEnergy[1][0] = MemConfig->RdEnergyCh1Dimm0; + Inputs->ThermalEnables.WrEnergy[0][1] = MemConfig->WrEnergyCh0Dimm1; + Inputs->ThermalEnables.WrEnergy[0][0] = MemConfig->WrEnergyCh0Dimm0; + Inputs->ThermalEnables.WrEnergy[1][1] = MemConfig->WrEnergyCh1Dimm1; + Inputs->ThermalEnables.WrEnergy[1][0] = MemConfig->WrEnergyCh1Dimm0; + Inputs->ThermalEnables.SrefCfgEna = MemConfig->SrefCfgEna; + Inputs->ThermalEnables.SrefCfgIdleTmr = MemConfig->SrefCfgIdleTmr; + Inputs->ThermalEnables.ThrtCkeMinDefeat = MemConfig->ThrtCkeMinDefeat; + Inputs->ThermalEnables.ThrtCkeMinTmr = MemConfig->ThrtCkeMinTmr; +#ifdef ULT_FLAG + if (Inputs->CpuModel == cmHSW_ULT) { + Inputs->ThermalEnables.ThrtCkeMinDefeatLpddr = MemConfig->ThrtCkeMinDefeatLpddr; + Inputs->ThermalEnables.ThrtCkeMinTmrLpddr = MemConfig->ThrtCkeMinTmrLpddr; + } +#endif // ULT_FLAG + } else { + Inputs->ThermalEnables.EnableExtts = 0; + Inputs->ThermalEnables.EnableCltm = 0; + Inputs->ThermalEnables.EnableOltm = 0; + Inputs->ThermalEnables.EnablePwrDn = 1; +#ifdef ULT_FLAG + if (Inputs->CpuModel == cmHSW_ULT) { + Inputs->ThermalEnables.EnablePwrDnLpddr = 0; + } +#endif // ULT_FLAG + Inputs->ThermalEnables.Refresh2X = 0; + Inputs->ThermalEnables.LpddrThermalSensor = 1; // Enable LPDDR MR4 temperature reads + Inputs->ThermalEnables.LockPTMregs = 0; + Inputs->ThermalEnables.EnergyScaleFact = 3; + Inputs->ThermalEnables.RaplLim2Lock = 0; + Inputs->ThermalEnables.RaplLim2WindX = 0; + Inputs->ThermalEnables.RaplLim2WindY = 0; + Inputs->ThermalEnables.RaplLim2Ena = 0; + Inputs->ThermalEnables.RaplLim2Pwr = 0; + Inputs->ThermalEnables.RaplLim1WindX = 0; + Inputs->ThermalEnables.RaplLim1WindY = 0; + Inputs->ThermalEnables.RaplLim1Ena = 0; + Inputs->ThermalEnables.RaplLim1Pwr = 0; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + Inputs->ThermalEnables.RaplPwrFl[Channel] = 0; + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + Inputs->ThermalEnables.WarmThreshold[Channel][Dimm] = 0xFF; + Inputs->ThermalEnables.HotThreshold[Channel][Dimm] = 0xFF; + Inputs->ThermalEnables.WarmBudget[Channel][Dimm] = 0xFF; + Inputs->ThermalEnables.HotBudget[Channel][Dimm] = 0xFF; + Inputs->ThermalEnables.IdleEnergy[Channel][Dimm] = 0; + Inputs->ThermalEnables.PdEnergy[Channel][Dimm] = 0; + Inputs->ThermalEnables.ActEnergy[Channel][Dimm] = 0; + Inputs->ThermalEnables.RdEnergy[Channel][Dimm] = 0; + Inputs->ThermalEnables.WrEnergy[Channel][Dimm] = 0; + } + } + Inputs->ThermalEnables.SrefCfgEna = 1; + Inputs->ThermalEnables.SrefCfgIdleTmr = 0x200; + Inputs->ThermalEnables.ThrtCkeMinDefeat = 0; + Inputs->ThermalEnables.ThrtCkeMinTmr = 0x30; +#ifdef ULT_FLAG + if (Inputs->CpuModel == cmHSW_ULT) { + Inputs->ThermalEnables.ThrtCkeMinDefeatLpddr = 1; + Inputs->ThermalEnables.ThrtCkeMinTmrLpddr = 0x40; + } +#endif //ULT_FLAG + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_11) { + Inputs->AutoSelfRefreshSupport = MemConfig->AutoSelfRefreshSupport; + Inputs->ExtTemperatureSupport = MemConfig->ExtTemperatureSupport; + Inputs->MaxRttWr = MemConfig->MaxRttWr; + } else { + Inputs->AutoSelfRefreshSupport = TRUE; + Inputs->ExtTemperatureSupport = TRUE; + Inputs->MaxRttWr = 0; + } + + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_12) { + Inputs->TrainingEnables.RCVENC1D = MemConfig->RCVENC1D; + } else { + Inputs->TrainingEnables.RCVENC1D = 1; + } + + Inputs->TrainingEnables.RMC = (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_15) ? + MemConfig->RMC : 1; + + Inputs->MrcMode = MrcModeFull; + Inputs->Iteration = 0; + + // + // Scrambler Suppport. + // + Inputs->ScramblerEnable = MemConfig->ScramblerSupport; + + // + // Remap above 4G Support + // + Inputs->RemapEnable = MemConfig->RemapEnable; + + // ECC support. + Inputs->EccSupport = MemConfig->EccSupport; + + // RMT BDAT support. + Inputs->RmtBdatEnable = MemConfig->RmtBdatEnable; + + +#ifdef ULT_FLAG + if (Inputs->CpuModel == cmHSW_ULT) { + // + // Interleaving mode of DQ/DQS pins - depends on board routing + // + Inputs->DqPinsInterleaved = MemConfig->DqPinsInterleaved; + + // + // DRAM ODT is not used + // + Inputs->LpddrDramOdt = 0; + + // + // Initialize the board-specific CMD/CTL/CLK and DQ/DQS mapping for LPDDR3 + // + MrcOemLpddrBoardMapping (Inputs, SaPlatformPolicyPpi->PlatformData->BoardId); + } +#endif // ULT_FLAG + + // Decide which channels and DIMMs are enabled. + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + ControllerIn = &Inputs->Controller[Controller]; + ControllerIn->ChannelCount = 0; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + ChannelIn = &ControllerIn->Channel[Channel]; + switch (MemConfig->DisableDimmChannel[Channel]) { + case 1: + ChannelIn->Dimm[0].Status = DIMM_DISABLED; + ChannelIn->Dimm[1].Status = DIMM_ENABLED; + ChannelIn->Status = CHANNEL_PRESENT; + ControllerIn->ChannelCount++; + ChannelIn->DimmCount = 1; + break; + case 2: + ChannelIn->Dimm[0].Status = DIMM_ENABLED; + ChannelIn->Dimm[1].Status = DIMM_DISABLED; + ChannelIn->Status = CHANNEL_PRESENT; + ControllerIn->ChannelCount++; + ChannelIn->DimmCount = 1; + break; + case 3: + ChannelIn->Dimm[0].Status = DIMM_DISABLED; + ChannelIn->Dimm[1].Status = DIMM_DISABLED; + ChannelIn->Status = CHANNEL_DISABLED; + ChannelIn->DimmCount = 0; + break; + default: + ChannelIn->Dimm[0].Status = DIMM_ENABLED; + ChannelIn->Dimm[1].Status = DIMM_ENABLED; + ChannelIn->Status = CHANNEL_PRESENT; + ControllerIn->ChannelCount++; + ChannelIn->DimmCount = 2; + break; + } + } + } + + // + // Get DIMM SpdBaseAddresses. + // + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + ControllerIn = &Inputs->Controller[Controller]; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + ChannelIn = &ControllerIn->Channel[Channel]; + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + ChannelIn->Dimm[Dimm].SpdAddress = + SaPlatformPolicyPpi->PlatformData->SpdAddressTable[(Channel * MAX_DIMMS_IN_CHANNEL) + Dimm]; + /// @todo Need code to detect disabling of individual DIMMs. + } + } + } + +#if (defined MEMORY_DOWN_SUPPORT && (MEMORY_DOWN_SUPPORT > 0)) + EnableMemoryDown (Inputs, SaPlatformPolicyPpi->PlatformData->BoardId); +#endif + + switch (BootMode) { + case bmWarm: + CheckForTimingOverride (Inputs, SaPlatformPolicyPpi); + return bmWarm; + + case bmS3: + CheckForTimingOverride (Inputs, SaPlatformPolicyPpi); + return bmS3; + + case bmFast: + // + // Read SPD data. + // + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "FAST BOOT GetSpdData\n"); + MrcGetSpdData (BootMode, Inputs); + CheckForTimingOverride (Inputs, SaPlatformPolicyPpi); + return bmFast; + + default: + MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "ERROR: Invalid flow specified, defaulting to cold flow\n"); + // No break. Note that the boot mode changes to bmCold. + + case bmCold: + // + // Read SPD data. + // + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "COLD BOOT GetSpdData\n"); + MrcGetSpdData (BootMode, Inputs); + CheckForTimingOverride (Inputs, SaPlatformPolicyPpi); + break; + } + + return bmCold; +} + +/** + Check to see if user defined profile is selected and if it is, then copy the + timing settings for this profile to the timing override structure. If user + defined profile is not selected, then set the timing override structure to 0. + + Note that even though we set timings on a DIMM by DIMM basis, the controller + may force DIMM timings to be the same for all DIMMs in a channel. + + @param[in, out] Inputs - The MRC Input data structure. + @param[in] SaPlatformPolicyPpi - The Peim to Peim interface of SaPlatformPolicy. + + @retval Nothing +**/ +void +CheckForTimingOverride ( + IN OUT MrcInput *const Inputs, + IN SA_PLATFORM_POLICY_PPI *const SaPlatformPolicyPpi + ) +{ + const MEMORY_CONFIGURATION *MemConfig; + MrcControllerIn *ControllerIn; + MrcChannelIn *ChannelIn; + MrcDimmIn *DimmIn; + U8 Controller; + U8 Channel; + U8 Dimm; + + // + // Override DIMM timing settings for customer profile setting. + // + if (Inputs->MemoryProfile == USER_PROFILE) { + MemConfig = SaPlatformPolicyPpi->MemConfig; + for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) { + ControllerIn = &Inputs->Controller[Controller]; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + ChannelIn = &ControllerIn->Channel[Channel]; + for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) { + DimmIn = &ChannelIn->Dimm[Dimm]; + DimmIn->Timing.NMode = MemConfig->NModeSupport; + DimmIn->Timing.tCL = MemConfig->tCL; + DimmIn->Timing.tCWL = MemConfig->tCWL; + DimmIn->Timing.tFAW = MemConfig->tFAW; + DimmIn->Timing.tRAS = MemConfig->tRAS; + DimmIn->Timing.tRC = MemConfig->tRC; + DimmIn->Timing.tRCD = MemConfig->tRCD; + DimmIn->Timing.tREFI = MemConfig->tREFI; + DimmIn->Timing.tRFC = MemConfig->tRFC; + DimmIn->Timing.tRP = MemConfig->tRP; + if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_6) { + DimmIn->Timing.tRPab = MemConfig->tRPab; + } else { + DimmIn->Timing.tRPab = 0; + } + DimmIn->Timing.tRRD = MemConfig->tRRD; + DimmIn->Timing.tRTP = MemConfig->tRTP; + DimmIn->Timing.tWR = MemConfig->tWR; + DimmIn->Timing.tWTR = MemConfig->tWTR; + } + } + } + } + + return; +} + |