/** @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 #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].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; }