summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/PowerManagement/Dxe
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Dxe')
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c918
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/MiscFunctions.c853
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PerformanceStates.c930
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c1302
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtCommon.h877
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.cif19
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.dxs38
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.inf114
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.mak82
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.sdl25
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c840
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.h127
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/Thermal.c301
13 files changed, 6426 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c b/ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c
new file mode 100644
index 0000000..a450b5d
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/IdleStates.c
@@ -0,0 +1,918 @@
+/** @file
+ This file contains power management C State configuration functions for
+ Haswell processors.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM - Thermal Monitor
+ IST - Intel(R) Speedstep technology
+ HT - Hyper-Threading Technology
+
+@copyright
+ Copyright (c) 2012 - 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 "PowerMgmtCommon.h"
+
+/**
+ Initializes C States Power management features
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitializeCState (
+ IN POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ EFI_STATUS Status;
+ UINT16 mAcpiBaseAddr;
+ ///
+ /// Get the ACPI Base Address
+ ///
+ mAcpiBaseAddr = PchLpcPciCfg16 (R_PCH_LPC_ACPI_BASE) & 0xFFFE;
+
+ ///
+ /// Initialize C states, some are general, some are processor specific.
+ /// Dynamic loading of CST SSDT tables occurs at PpmPostInit.
+ ///
+ EnableCStates (mAcpiBaseAddr + PM_CST_LVL2);
+ ///
+ /// Calibrate C State 24MHz BCLK
+ ///
+//@todo: Need to finalize on whether or not re-calibration option should be provided
+ Status = CalibrateBclkForCStates ();
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_INFO, "24MHz BCLK calibration Failed \n"));
+//@todo: Need to finalize on how to handle failure of 24 MHz calibration
+ }
+
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) {
+ ///
+ /// Update Fadt table for C State support.
+ ///
+ ConfigureFadtCStates ();
+ }
+ InitCstatePreWake (mCpuPmConfig);
+
+}
+
+/**
+ Disable/Enable the CState Pre-Wake Feature
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitCstatePreWake (
+ IN POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER TempMsr;
+
+ TempMsr.Qword = AsmReadMsr64 (MSR_POWER_CTL);
+ TempMsr.Dwords.Low &= ~(B_MSR_POWER_CTL_CSTATE_PRE_WAKE_DISABLE);
+ if (CpuPmConfig->pFunctionEnables->CStatePreWake == PPM_DISABLE) {
+ TempMsr.Dwords.Low |= B_MSR_POWER_CTL_CSTATE_PRE_WAKE_DISABLE;
+ }
+ AsmWriteMsr64 (MSR_POWER_CTL, TempMsr.Qword);
+
+ return;
+}
+
+/**
+ Enables C-State support as specified by the input flags on all logical
+ processors and sets associated timing requirements in the chipset.
+
+ @param[in] C3IoAddress IO address to generate C3 states (PM base + 014 usually)
+**/
+VOID
+EnableCStates (
+ IN UINT16 C3IoAddress
+ )
+{
+ MSR_REGISTER PowerCtl;
+ MSR_REGISTER TempMsr;
+ UINT32 LCR0Latency;
+ UINT32 LCR1Latency;
+ UINT32 LCR2Latency;
+ UINT32 LCR3Latency;
+ UINT32 LCR4Latency;
+ UINT32 LCR5Latency;
+ UINT16 EnableCStateParameters;
+ CPU_FAMILY mCpuFamilyId;
+
+ mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ ///
+ /// Load the C-State parameters to pass to the core function.
+ ///
+ EnableCStateParameters = C3IoAddress;
+ ///
+ /// Enable C-States on all logical processors.
+ ///
+ RunOnAllLogicalProcessors (ApSafeEnableCStates, &EnableCStateParameters);
+ ///
+ /// If C-states are disabled or not supported, Disable C1e and retrun
+ ///
+ if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) == 0) {
+ PowerCtl.Qword = AsmReadMsr64 (MSR_POWER_CTL);
+ PowerCtl.Dwords.Low &= ~B_MSR_POWER_CTL_C1E;
+ AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Qword);
+ DEBUG (
+ (EFI_D_INFO,
+ "Setup C state disabled.Disable C1e. MSR(1FC) : %X %X\n",
+ PowerCtl.Dwords.High,
+ PowerCtl.Dwords.Low)
+ );
+ return;
+ }
+ ///
+ /// Configure supported enhanced C-states
+ ///
+ /// Read Power Ctl MSR
+ ///
+ PowerCtl.Qword = AsmReadMsr64 (MSR_POWER_CTL);
+ DEBUG ((EFI_D_INFO, "MSR(1FC) before configuring C1E: %X %X\n", PowerCtl.Dwords.High, PowerCtl.Dwords.Low));
+ ///
+ /// Enable supported states
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C1E) {
+ PowerCtl.Dwords.Low |= B_MSR_POWER_CTL_C1E;
+ } else {
+ PowerCtl.Dwords.Low &= ~B_MSR_POWER_CTL_C1E;
+ }
+ ///
+ /// Update Power Control MSR
+ ///
+ AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Qword);
+ DEBUG ((EFI_D_INFO, "MSR(1FC) after configuring C1E: %X %X\n", PowerCtl.Dwords.High, PowerCtl.Dwords.Low));
+ ///
+ /// Program Interrupt response time limits used by processor to decided when to get into
+ /// package C3, C6 and C7
+ ///
+ DEBUG ((EFI_D_INFO, "Programming the 0xC3/C6/C7 (MSR 0x60A, 0x60B ,0X60C Latencies \n"));
+ //
+ // Package C3 Interrupt response time
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_0);
+ DEBUG ((EFI_D_INFO, "MSR(60A) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low));
+ TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID);
+ ///
+ /// Program Interrupt Response Time Unit and Latency for MSR 0x60A
+ ///
+ TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl0Irtl;
+ TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl0TimeUnit, N_TIME_UNIT_OFFSET);
+ TempMsr.Dwords.Low |= B_PKG_IRTL_VALID;
+ AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_0, TempMsr.Qword);
+ //
+ // Package C6/C7 short Interrupt response time
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_1);
+ DEBUG ((EFI_D_INFO, "MSR(60B) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low));
+ TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID);
+ ///
+ /// Program Interrupt Response Time Unit and Latency for MSR 0x60B
+ ///
+ TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl1Irtl;
+ TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl1TimeUnit, N_TIME_UNIT_OFFSET);
+ TempMsr.Dwords.Low |= B_PKG_IRTL_VALID;
+ AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_1, TempMsr.Qword);
+ //
+ // Package C6/C7 long Interrupt response time
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_2);
+ DEBUG ((EFI_D_INFO, "MSR(60C) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low));
+ TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID);
+ ///
+ /// Program Interrupt Response Time Unit and Latency for MSR 0x60C
+ ///
+ TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl2Irtl;
+ TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl2TimeUnit, N_TIME_UNIT_OFFSET);
+ TempMsr.Dwords.Low |= B_PKG_IRTL_VALID;
+ AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_2, TempMsr.Qword);
+ if (mCpuFamilyId == EnumCpuHswUlt) {
+ //
+ // Package C8 Interrupt response time
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_3);
+ DEBUG ((EFI_D_INFO, "MSR(633) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low));
+ TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID);
+ ///
+ /// Program Interrupt Response Time Unit and Latency for MSR 0x633
+ ///
+ TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl3Irtl;
+ TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl3TimeUnit, N_TIME_UNIT_OFFSET);
+ TempMsr.Dwords.Low |= B_PKG_IRTL_VALID;
+ AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_3, TempMsr.Qword);
+ //
+ // Package C9 Interrupt response time
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_4);
+ DEBUG ((EFI_D_INFO, "MSR(634) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low));
+ TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID);
+ ///
+ /// Program Interrupt Response Time Unit and Latency for MSR 0x634
+ ///
+ TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl4Irtl;
+ TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl4TimeUnit, N_TIME_UNIT_OFFSET);
+ TempMsr.Dwords.Low |= B_PKG_IRTL_VALID;
+ AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_4, TempMsr.Qword);
+ //
+ // Package C10 Interrupt response time
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_C_STATE_LATENCY_CONTROL_5);
+ DEBUG ((EFI_D_INFO, "MSR(635) before configuring Latency: %X %X\n", TempMsr.Dwords.High, TempMsr.Dwords.Low));
+ TempMsr.Dwords.Low &= ~(B_INTERRUPT_RESPONSE_TIME_LIMIT_MASK | B_TIME_UNIT_MASK | B_PKG_IRTL_VALID);
+ ///
+ /// Program Interrupt Response Time Unit and Latency for MSR 0x635
+ ///
+ TempMsr.Dwords.Low |= mCpuPmConfig->CstateLatencyControl5Irtl;
+ TempMsr.Dwords.Low |= LShiftU64 (mCpuPmConfig->CstateLatencyControl5TimeUnit, N_TIME_UNIT_OFFSET);
+ TempMsr.Dwords.Low |= B_PKG_IRTL_VALID;
+ AsmWriteMsr64 (MSR_C_STATE_LATENCY_CONTROL_5, TempMsr.Qword);
+ }
+ ///
+ /// Update the PPM Global NVS Area
+ ///
+ LCR0Latency = (1 << (mCpuPmConfig->CstateLatencyControl0TimeUnit * 5));
+ LCR0Latency = (LCR0Latency * mCpuPmConfig->CstateLatencyControl0Irtl) / 1000;
+ //
+ // _CST Latency: WordConst, so limit the latency value to max 0xFFFF
+ //
+ if (LCR0Latency > 0xFFFF) {
+ LCR0Latency = 0xFFFF;
+ }
+ LCR1Latency = (1 << (mCpuPmConfig->CstateLatencyControl1TimeUnit * 5));
+ LCR1Latency = (LCR1Latency * mCpuPmConfig->CstateLatencyControl1Irtl) / 1000;
+ if (LCR1Latency > 0xFFFF) {
+ LCR1Latency = 0xFFFF;
+ }
+ LCR2Latency = (1 << (mCpuPmConfig->CstateLatencyControl2TimeUnit * 5));
+ LCR2Latency = (LCR2Latency * mCpuPmConfig->CstateLatencyControl2Irtl) / 1000;
+ if (LCR2Latency > 0xFFFF) {
+ LCR2Latency = 0xFFFF;
+ }
+
+ LCR3Latency = (1 << (mCpuPmConfig->CstateLatencyControl3TimeUnit * 5));
+ LCR3Latency = (LCR3Latency * mCpuPmConfig->CstateLatencyControl3Irtl) / 1000;
+ if (LCR3Latency > 0xFFFF) {
+ LCR3Latency = 0xFFFF;
+ }
+
+ LCR4Latency = (1 << (mCpuPmConfig->CstateLatencyControl4TimeUnit * 5));
+ LCR4Latency = (LCR4Latency * mCpuPmConfig->CstateLatencyControl4Irtl) / 1000;
+ if (LCR4Latency > 0xFFFF) {
+ LCR4Latency = 0xFFFF;
+ }
+
+ LCR5Latency = (1 << (mCpuPmConfig->CstateLatencyControl5TimeUnit * 5));
+ LCR5Latency = (LCR5Latency * mCpuPmConfig->CstateLatencyControl5Irtl) / 1000;
+ if (LCR5Latency > 0xFFFF) {
+ LCR5Latency = 0xFFFF;
+ }
+
+ ///
+ /// Update the PPM Global NVS Area.
+ /// Update the PPM NVRAM values for C3
+ ///
+ mPpmGlobalNvsAreaProtocol->Area->C3MwaitValue = 0x10;
+ mPpmGlobalNvsAreaProtocol->Area->C3Latency = (UINT16) LCR0Latency;
+ ///
+ /// Update PPM NVRAM Values for C6
+ ///
+ if ((mCpuPmConfig->pFunctionEnables->LongLatencyC6) &&( mPpmGlobalNvsAreaProtocol->Area->PpmFlags & C6_LONG_LATENCY_ENABLE)) {
+ mPpmGlobalNvsAreaProtocol->Area->C6MwaitValue = 0x21;
+ mPpmGlobalNvsAreaProtocol->Area->C6Latency = (UINT16) LCR2Latency;
+ } else {
+ mPpmGlobalNvsAreaProtocol->Area->C6MwaitValue = 0x20;
+ mPpmGlobalNvsAreaProtocol->Area->C6Latency = (UINT16) LCR1Latency;
+ }
+ ///
+ /// Update PPM NVRAM Values for C7 - select the C-state supported among- C7 / C7S
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7) { // Is C7 supported ?
+ if ((mCpuPmConfig->pFunctionEnables->LongLatencyC7) && (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & C7_LONG_LATENCY_ENABLE)) {
+ mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x31;
+ mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR2Latency;
+ } else {
+ mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x30;
+ mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR1Latency;
+ }
+ }
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7S) { // Is C7S supported ?
+ if ((mCpuPmConfig->pFunctionEnables->LongLatencyC7) && (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & C7s_LONG_LATENCY_ENABLE)) {
+ mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x33;
+ mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR2Latency;
+ } else {
+ mPpmGlobalNvsAreaProtocol->Area->C7MwaitValue = 0x32;
+ mPpmGlobalNvsAreaProtocol->Area->C7Latency = (UINT16) LCR1Latency;
+ }
+ }
+ ///
+ /// Update PPM NVRAM Values for CD - select the deepest C-state supported among- C8 / C9 / C10
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C10) { // C10 supported
+ mPpmGlobalNvsAreaProtocol->Area->CDIOLevel = PCH_ACPI_LV7;
+ mPpmGlobalNvsAreaProtocol->Area->CDPowerValue = C10_POWER;
+ mPpmGlobalNvsAreaProtocol->Area->CDMwaitValue = 0x60;
+ mPpmGlobalNvsAreaProtocol->Area->CDLatency = (UINT16) LCR5Latency;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C9) { // C9 supported
+ mPpmGlobalNvsAreaProtocol->Area->CDIOLevel = PCH_ACPI_LV6;
+ mPpmGlobalNvsAreaProtocol->Area->CDPowerValue = C9_POWER;
+ mPpmGlobalNvsAreaProtocol->Area->CDMwaitValue = 0x50;
+ mPpmGlobalNvsAreaProtocol->Area->CDLatency = (UINT16) LCR4Latency;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C8) { // C8 supported
+ mPpmGlobalNvsAreaProtocol->Area->CDIOLevel = PCH_ACPI_LV5;
+ mPpmGlobalNvsAreaProtocol->Area->CDPowerValue = C8_POWER;
+ mPpmGlobalNvsAreaProtocol->Area->CDMwaitValue = 0x40;
+ mPpmGlobalNvsAreaProtocol->Area->CDLatency = (UINT16) LCR3Latency;
+ }
+
+ return;
+}
+
+/**
+ BootScript for PCode Mailbox function for mailbox write commands.
+ This function will poll the mailbox interface for control, issue the command
+ during s3 resume
+
+ @param[IN] MailboxCommand,
+ @param[IN] MailboxData,
+**/
+VOID
+MailboxS3Write (
+ IN UINT32 MailboxCommand,
+ IN UINT32 MailboxData
+ )
+{
+#ifdef ULT_FLAG
+ UINT32 Data32Mask;
+ UINT32 Data32Value;
+ UINT16 StallCount;
+ UINT32 MchBar;
+
+ StallCount = 0;
+
+ ///
+ /// Poll the run/busy to ensure the interface is available
+ ///
+ Data32Mask = BIT31;
+ Data32Value = 0;
+ MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET),
+ &Data32Mask,
+ &Data32Value,
+ MAILBOX_WAIT_STALL,
+ MAILBOX_WAIT_TIMEOUT
+ );
+
+ ///
+ /// Write the PCODE mailbox DATA field
+ ///
+ MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) ((MchBar + PCODE_MAILBOX_DATA_OFFSET)),
+ 1,
+ &(MailboxData)
+ );
+ ///
+ /// Write the PCODE mailbox Command field
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET),
+ 1,
+ &(MailboxCommand)
+ );
+#endif // ULT_FLAG
+ return;
+}
+
+/**
+ Calibrate 24MHz BCLK support to reduce the power consumption in idle states.
+
+ @retval EFI_UNSUPPORTED Unrecognized 24MHz BCLK Calibration Type.
+ @retval EFI_SUCCESS Processor C-State 24MHz BCLK support calibrated successfully.
+**/
+EFI_STATUS
+CalibrateBclkForCStates (
+ VOID
+ )
+{
+ /*****************************************************************************************************************
+ - BIOS can choose to configure the conversion factor or allow PCODE to calibrate itself or have NO calibration at all.
+ - If NO Calibration then the below steps are needed
+ o BIOS should bypass all calibration process and write a constant value via "WRITE convert ratio"
+ - If BIOS chooses PCODE calibration then the below steps are needed
+ o BIOS writes FSM interval: A value of all Fs is recommended for this
+ o Read PCODE calibration factor
+ o Store and use if needed on next Power up for BIOS calibration
+ - If BIOS chooses to calibrate itself then the below steps are needed
+ o Send command for calibration to prevent BCLK shut off
+ o Read TSC counter values (send command for atomic sampling of TSC100 and TSC24, then read the values)
+ o Delay (what is the maximum tolerable delay?)
+ o Read counters again
+ o Divide 100 MHz ticks by 24 MHz ticks to get the calibration factor
+ o Store the calibration factor value
+ o Write calibration factor using mailbox command during subsequent power-ups
+
+ Command: Command Name: Description:
+ 0x80000009 WriteTsc24_100Cmd Sample 24 MHz and 100 MHz TSC simultaneously
+ 0x80000109 ReadTsc24LowerCmd Read lower 32 bits of 24 MHz TSC
+ 0x80000209 ReadTsc24UpperCmd Read upper 32 bits of 24 MHz TSC
+ 0x80000309 ReadTsc100LowerCmd Read lower 32 bits of 100 MHz TSC
+ 0x80000409 ReadTsc100UpperCmd Read upper 32 bits of 100 MHz TSC
+ 0x80000509 ReadPcodeCalibratedCmd Read PCODE calibrated conversion factor
+ 0x80000609 WriteConversionRatioCmd Command for writing the conversion ratio
+ 0x80000709 WritePreventBclkOffCmd Command for calibration prevents BCLK from shutting off and prevents package
+ from entering deep C states
+ 0x80000809 WRITE_MEASURE_INTERVAL_CMD Measurement interval for pCode calibration of TSC24-to-TSC100 conversion factor
+ 0x80000909 WriteFsmMeasureIntvlCmd Write FSM measure interval
+ 0x85000000 StartCalValue Constant value to start calibration
+ 0xFFFFFFFF PcodeIntervalValue PCODE flow calibration time value
+
+ ***************************************************************************************************************/
+
+ EFI_STATUS Status = EFI_SUCCESS;
+
+#ifdef ULT_FLAG
+ CPU_FAMILY mCpuFamilyId;
+ mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ if (mCpuFamilyId == EnumCpuHswUlt) {
+ UINT32 PcodeIntervalValue;
+ UINT32 BiosMeasureIntervalValue;
+ UINT32 PcalFactor_Lower;
+ UINT32 PcalFactor_Upper;
+ UINT32 LibStatus;
+ UINT64 Tsc24_64;
+ UINT64 Tsc100_64;
+ UINT64 Temp24_64;
+ UINT64 Temp100_64;
+ UINT64 PcalFactor;
+ UINT64 SafeCalibrationValue;
+ UINT64 TscRemainder;
+
+ PCODE_BCLK_CALIBRATION_MAILBOX ReturnCalVal;
+
+ PcodeIntervalValue = 0xFFFFFFFF;
+ BiosMeasureIntervalValue = 0x7270E00;
+ PcalFactor_Lower = 0x0;
+ PcalFactor_Upper = 0x0;
+ Tsc24_64 = 0x0;
+ Tsc100_64 = 0x0;
+ Temp24_64 = 0x0;
+ Temp100_64 = 0x0;
+ PcalFactor = 0x0;
+ SafeCalibrationValue = 0x0;
+ TscRemainder = 0x0;
+ LibStatus = 0x0;
+ DEBUG ((EFI_D_INFO, "Initializing 24MHz BCLK calibration \n"));
+
+ switch (mCpuPmConfig->PcodeCalibration) {
+ case NO_CALIBRATE:
+ ///
+ /// Bypass all calibration process
+ ///
+ DEBUG ((EFI_D_INFO, "Bypass the 24MHz BCLK calibration \n"));
+ ///
+ /// Write a constant value
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_CONVERTION_RATIO_CMD, START_CAL_VALUE, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed to write a constant value \n"));
+ break;
+ }
+ MailboxS3Write(WRITE_CONVERTION_RATIO_CMD, START_CAL_VALUE);
+ break;
+
+ case PCODE_CALIBRATE:
+ ///
+ /// Initiate the PCODE calibration
+ ///
+ DEBUG ((EFI_D_INFO, "Initiate PCODE 24MHz BCLK calibration \n"));
+ ///
+ /// BIOS writes FSM interval: A value of all F's is recommended for this
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_FSM_MEASURE_INTVL_CMD, PcodeIntervalValue, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed BIOS writes FSM interval \n"));
+ break;
+ }
+ MailboxS3Write(WRITE_FSM_MEASURE_INTVL_CMD, PcodeIntervalValue);
+ break;
+
+ case BIOS_CALIBRATE:
+ ///
+ /// Initiate Bios calibration
+ ///
+ DEBUG ((EFI_D_INFO, "Initiate BIOS 24MHz BCLK calibration \n"));
+ ///
+ /// Send command for calibration to prevent BCLK shut off
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_PREVENT_BCLKOFF_CMD, 1, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Send command for calibration to prevent BCLK shut off \n"));
+ break;
+ }
+ ///
+ /// Read TSC counter values (send command for atomic sampling of TSC100 and TSC24)
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, SAMPLE_TSC_24AND100_CMD, 0, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First Write TSC counter values (send command for atomic sampling of TSC100 and TSC24) \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_LOWER_CMD, &ReturnCalVal.TSC24_L1, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-24 Lower 32 bits \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_UPPER_CMD, &ReturnCalVal.TSC24_U1, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-24 Upper 32 bits \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_LOWER_CMD, &ReturnCalVal.TSC100_L1, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-100 Lower 32 bits \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_UPPER_CMD, &ReturnCalVal.TSC100_U1, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed First read TSC-100 Upper 32 bits \n"));
+ break;
+ }
+ ///
+ /// Store initial clock values
+ ///
+ Tsc24_64 = ((UINT64)ReturnCalVal.TSC24_U1 << 32);
+ Temp24_64 = (Tsc24_64 |= (ReturnCalVal.TSC24_L1));
+ Tsc100_64 = ((UINT64)ReturnCalVal.TSC100_U1 << 32);
+ Temp100_64 = (Tsc100_64 |= (ReturnCalVal.TSC100_L1));
+
+ ///
+ /// Delay for 22 ms
+ ///
+ gBS->Stall (PCODE_BCLK_CALIBRATION_TIMEOUT * STALL_ONE_MILLI_SECOND);
+
+ ///
+ /// Read TSC 24 and TSC 100 counters again, and calculate calibration factor
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, SAMPLE_TSC_24AND100_CMD, 0, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second Write TSC counter values (send command for atomic sampling of TSC100 and TSC24) \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_LOWER_CMD, &ReturnCalVal.TSC24_L2, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second read TSC-24 Lower 32 bits \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC24_UPPER_CMD, &ReturnCalVal.TSC24_U2, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second read TSC-24 Upper 32 bits \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_LOWER_CMD, &ReturnCalVal.TSC100_L2, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Second read TSC-100 Lower 32 bits \n"));
+ break;
+ }
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_TSC100_UPPER_CMD, &ReturnCalVal.TSC100_U2, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Second read TSC-100 Upper 32 bits \n"));
+ break;
+ }
+ ///
+ /// Store current clock values, and calculate difference
+ ///
+ Tsc24_64 = ((UINT64)ReturnCalVal.TSC24_U2 << 32);
+ Tsc24_64 = ((Tsc24_64 |= (ReturnCalVal.TSC24_L2)) - Temp24_64);
+ Tsc100_64 = ((UINT64)ReturnCalVal.TSC100_U2 << 32);
+ Tsc100_64 = ((Tsc100_64 |= (ReturnCalVal.TSC100_L2)) - Temp100_64);
+
+ ///
+ /// Calculate updated conversion factor in fixed point format (U32.3.29)
+ ///
+ Tsc100_64 = (Tsc100_64 << 29);
+ if (Tsc24_64 !=0) {
+ PcalFactor = InternalMathDivRemS64x64 (Tsc100_64, Tsc24_64, (INT64 *) &TscRemainder);
+ }
+
+ ///
+ /// Read the TSC24-to-TSC100 conversion factor currently in use by pCode
+ ///
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_PCODE_CALIBRATED_CMD, &ReturnCalVal.PCalFactor, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed read TSC24-to-TSC100 PCalFactor from pCode currently\n"));
+ break;
+ }
+
+ if (PcalFactor <= 0) {
+ ///
+ /// Set Safe Calibration Value as ReturnCalVal.PCalFactor which is TSC24-to-TSC100 PCalFactor read from pCode by READ_PCODE_CALIBRATED_CMD
+ ///
+ PcalFactor = ReturnCalVal.PCalFactor;
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Warning - SafeCalibrationValue used \n"));
+ }
+ PcalFactor_Lower |= PcalFactor;
+ PcalFactor_Upper |= (PcalFactor >> 32);
+ ///
+ /// Calibrate 24MHz BCLK using the calculated calibration factor value
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_CONVERTION_RATIO_CMD, PcalFactor_Lower, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Calibrate 24MHz BCLK using the calculated lower calibration factor value \n"));
+ break;
+ }
+ MailboxS3Write(WRITE_CONVERTION_RATIO_CMD, PcalFactor_Lower);
+
+ ///
+ /// Send command for calibration to turn BCLK on
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_PREVENT_BCLKOFF_CMD, 0, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Send command for calibration to turn BCLK on \n"));
+ break;
+ }
+ MailboxS3Write(WRITE_PREVENT_BCLKOFF_CMD, 0);
+
+ ///
+ /// Write measurement interval for pCode calibration of TSC24-to-TSC100 conversion factor
+ ///
+ Status = MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_MEASURE_INTERVAL_CMD, BiosMeasureIntervalValue, &LibStatus);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "24 MHz BCLK Calibration: Failed Send command for calibration to meature interval for pCode calibration \n"));
+ break;
+ }
+ MailboxS3Write(WRITE_MEASURE_INTERVAL_CMD, BiosMeasureIntervalValue);
+ break;
+
+ default:
+ DEBUG ((EFI_D_ERROR, "Unrecognized 24MHz BCLK Calibration Type \n"));
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ DEBUG ((EFI_D_INFO, "24MHz BCLK calibration completed \n"));
+
+ }
+#endif // ULT_FLAG
+
+ return Status;
+}
+
+/**
+ Enable C-State support as specified by the input flags on a logical processor.
+ Configure BIOS C1 Coordination (SMI coordination)
+ Enable IO redirection coordination
+ Choose proper coordination method
+ Configure extended C-States
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to a ENABLE_CSTATE_PARAMS containing the necessary
+ information to enable C-States
+
+ @retval EFI_SUCCESS Processor C-State support configured successfully.
+**/
+VOID
+EFIAPI
+ApSafeEnableCStates (
+ IN OUT VOID *Buffer
+ )
+{
+ MSR_REGISTER Ia32MiscEnable;
+ MSR_REGISTER PmCfgCtrl;
+ MSR_REGISTER IoCaptAddr;
+ UINT16 C3IoAddress;
+ CPU_STEPPING mCpuSteppingId;
+ CPU_FAMILY mCpuFamilyId;
+ mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ mCpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING;
+ ///
+ /// Extract parameters from the buffer
+ ///
+ C3IoAddress = *((UINT16 *) Buffer);
+ ///
+ /// If C-states are disabled in setup, disable C-states
+ ///
+ if (!(mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES)) {
+ PmCfgCtrl.Qword = AsmReadMsr64 (MSR_PMG_CST_CONFIG);
+ PmCfgCtrl.Dwords.Low &= ~B_PACKAGE_C_STATE_LIMIT;
+ AsmWriteMsr64 (MSR_PMG_CST_CONFIG, PmCfgCtrl.Qword);
+ return;
+ }
+ ///
+ /// Set C-state package limit to the highest C-state enabled
+ ///
+ PmCfgCtrl.Qword = AsmReadMsr64 (MSR_PMG_CST_CONFIG);
+ if (mCpuPmConfig->PkgCStateLimit != PkgCpuDefault) {
+ PmCfgCtrl.Dwords.Low &= ~B_PACKAGE_C_STATE_LIMIT;
+
+ if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C10) && (mCpuPmConfig->PkgCStateLimit == PkgAuto)) {
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C10;
+ } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C9) && (mCpuPmConfig->PkgCStateLimit == PkgAuto)) {
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C9;
+ } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C8) && (mCpuPmConfig->PkgCStateLimit == PkgAuto)) {
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C8;
+ } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7S) &&
+ !((mCpuFamilyId == EnumCpuHsw) && (mCpuSteppingId == EnumHswA0) && (mCpuPmConfig->PkgCStateLimit == PkgAuto))) { // When user selects Auto - Disable Package C7s state on Haswell A-step processors
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C7S;
+ } else if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7)&&
+ !((mCpuFamilyId == EnumCpuHsw) && (mCpuSteppingId == EnumHswA0) && (mCpuPmConfig->PkgCStateLimit == PkgAuto))) { // When user selects Auto - Disable Package C7 state on Haswell A-step processors
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C7;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C6) {
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C6;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) {
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C3;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C1) {
+ PmCfgCtrl.Dwords.Low |= V_CSTATE_LIMIT_C1;
+ }
+ if (mCpuPmConfig->PkgCStateLimit < PkgCMax) {
+ PmCfgCtrl.Dwords.Low &= ~B_PACKAGE_C_STATE_LIMIT;
+ PmCfgCtrl.Dwords.Low |= (mCpuPmConfig->PkgCStateLimit & B_PACKAGE_C_STATE_LIMIT);
+ }
+ }
+ ///
+ /// Enable C State IO redirection by default
+ ///
+ PmCfgCtrl.Dwords.Low |= B_IO_MWAIT_REDIRECTION_ENABLE;
+ //
+ // Enable TimedMwait
+ //
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TIMED_MWAIT) {
+ PmCfgCtrl.Dwords.Low &= (~B_TIMED_MWAIT_ENABLE);
+ PmCfgCtrl.Dwords.Low |= B_TIMED_MWAIT_ENABLE;
+ }
+ ///
+ /// Configure C-state auto-demotion
+ ///
+ PmCfgCtrl.Dwords.Low &= ~(B_C1_AUTO_DEMOTION_ENABLE | B_C3_AUTO_DEMOTION_ENABLE);
+ if (mCpuPmConfig->pFunctionEnables->C3AutoDemotion) {
+ ///
+ /// Enable C6/C7 Auto-demotion to C3
+ ///
+ PmCfgCtrl.Dwords.Low |= B_C3_AUTO_DEMOTION_ENABLE;
+ }
+ if (mCpuPmConfig->pFunctionEnables->C1AutoDemotion) {
+ ///
+ /// Enable C3/C6/C7 Auto-demotion to C1
+ ///
+ PmCfgCtrl.Dwords.Low |= B_C1_AUTO_DEMOTION_ENABLE;
+ }
+ ///
+ /// Configure C-state un-demotion
+ ///
+ PmCfgCtrl.Dwords.Low &= ~(B_C1_AUTO_UNDEMOTION_ENABLE | B_C3_AUTO_UNDEMOTION_ENABLE);
+ if (mCpuPmConfig->pFunctionEnables->C3UnDemotion) {
+ ///
+ /// Enable un-demotion from demoted C3
+ ///
+ PmCfgCtrl.Dwords.Low |= B_C3_AUTO_UNDEMOTION_ENABLE;
+ }
+ if (mCpuPmConfig->pFunctionEnables->C1UnDemotion) {
+ ///
+ /// Enable un-demotion from demoted C1
+ ///
+ PmCfgCtrl.Dwords.Low |= B_C1_AUTO_UNDEMOTION_ENABLE;
+ }
+ ///
+ /// Configure Package C-state Demotion / un-demotion - Supported only on HSW B0 and Above
+ ///
+ if (mCpuSteppingId > EnumHswA0) {
+ PmCfgCtrl.Dwords.Low &= ~(B_PKG_CSTATE_DEMOTION_ENABLE | B_PKG_CSTATE_UNDEMOTION_ENABLE);
+ if (mCpuPmConfig->pFunctionEnables->PkgCStateDemotion) {
+ ///
+ /// Enable Package C-state Demotion
+ ///
+ PmCfgCtrl.Dwords.Low |= B_PKG_CSTATE_DEMOTION_ENABLE;
+ }
+ if (mCpuPmConfig->pFunctionEnables->PkgCStateUnDemotion) {
+ ///
+ /// Enable Package C-state un-demotion
+ ///
+ PmCfgCtrl.Dwords.Low |= B_PKG_CSTATE_UNDEMOTION_ENABLE;
+ }
+ }
+ AsmWriteMsr64 (MSR_PMG_CST_CONFIG, PmCfgCtrl.Qword);
+ ///
+ /// Enable MONITOR/MWAIT support
+ /// (already done on BSP, but must be done on all components.)
+ ///
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ Ia32MiscEnable.Qword |= B_MSR_IA32_MISC_ENABLE_MONITOR;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+ ///
+ /// Haswell specific configuration of I/O capture and I/O coordination SMI MSR.
+ /// Configure the base port and range in the MSR to match LVL_X settings in ACPI tables
+ /// Set I/O capture base port and range
+ ///
+ IoCaptAddr.Qword = AsmReadMsr64 (MSR_PMG_IO_CAPTURE_BASE);
+ ///
+ /// Mask off CST range and set the CST range
+ ///
+ IoCaptAddr.Dwords.Low &= ~B_MSR_PMG_CST_RANGE;
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C10) {
+ IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL7;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C9) {
+ IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL6;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C8) {
+ IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL5;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C7) {
+ IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL4;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C6) {
+ IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL3;
+ } else if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) {
+ IoCaptAddr.Dwords.Low |= V_IO_CAPT_LVL2;
+ }
+ ///
+ /// Set the base CST address
+ ///
+ IoCaptAddr.Dwords.Low &= ~(V_IO_CAPT_LVL2_BASE_ADDR_MASK);
+ IoCaptAddr.Dwords.Low |= C3IoAddress;
+ AsmWriteMsr64 (MSR_PMG_IO_CAPTURE_BASE, IoCaptAddr.Qword);
+ return;
+}
+
+
+//
+// Update ACPI IdleStates tables
+//
+
+/**
+ Configure the FACP for C state support
+**/
+VOID
+ConfigureFadtCStates (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer;
+ INTN Index;
+ UINTN Handle;
+ EFI_ACPI_TABLE_VERSION Version;
+
+ ///
+ /// Locate table with matching ID
+ ///
+ Index = 0;
+ do {
+ Status = mAcpiSupport->GetAcpiTable (mAcpiSupport, Index, (VOID **) &Table, &Version, &Handle);
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+ ASSERT_EFI_ERROR (Status);
+ Index++;
+ } while (Table->Signature != EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
+ //
+ // Can't have ACPI without FADT, so safe to assert
+ //
+ ASSERT (Table->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
+ FadtPointer = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) Table;
+ //
+ // Verify expected state. Should be initialized to off during build.
+ //
+ ASSERT (FadtPointer->PLvl3Lat >= FADT_C3_LATENCY_DISABLED);
+ ///
+ /// Configure C states
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) {
+ ///
+ /// Enable C3 in FADT.
+ ///
+ FadtPointer->PLvl3Lat = FADT_C3_LATENCY;
+ }
+ ///
+ /// Update the table
+ ///
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ Table,
+ Table->Length,
+ &Handle
+ );
+ FreePool (Table);
+
+ return;
+} \ No newline at end of file
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/MiscFunctions.c b/ReferenceCode/Haswell/PowerManagement/Dxe/MiscFunctions.c
new file mode 100644
index 0000000..5ad9fc8
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/MiscFunctions.c
@@ -0,0 +1,853 @@
+/** @file
+ This file contains Processor Power Management ACPI related functions for
+ Haswell processors.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM - Thermal Monitor
+ IST - Intel(R) Speedstep technology
+ HT - Hyper-Threading Technology
+
+@copyright
+ Copyright (c) 2012-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 "PowerMgmtCommon.h"
+
+///
+/// Table to convert PL1 / Pl2 Seconds into equivalent MSR values
+/// This table is used for TDP Time Window programming
+///
+UINT8 mSecondsToMsrValueMapTable[][2] = {
+ ///
+ /// Seconds, MSR Value
+ ///
+ { 1, 0x0A },
+ { 2, 0x0B },
+ { 3, 0x4B },
+ { 4, 0x0C },
+ { 5, 0x2C },
+ { 6, 0x4C },
+ { 7, 0x6C },
+ { 8, 0x0D },
+ { 10, 0x2D },
+ { 12, 0x4D },
+ { 14, 0x6D },
+ { 16, 0x0E },
+ { 20, 0x2E },
+ { 24, 0x4E },
+ { 28, 0x6E },
+ { 32, 0x0F },
+ { 40, 0x2F },
+ { 48, 0x4F },
+ { 56, 0x6F },
+ { 64, 0x10 },
+ { 80, 0x30 },
+ { 96, 0x50 },
+ { 112, 0x70 },
+ { 128, 0x11 },
+ { END_OF_TABLE, END_OF_TABLE }
+};
+
+///
+/// Table to convert PL3 Milli Seconds into equivalent MSR values
+/// This table is used for TDP Time Window programming
+///
+UINT8 mMilliSecondsToMsrValueMapTable[][2] = {
+ ///
+ /// MilliSeconds, MSR Value
+ ///
+ { 3, 0x41 },
+ { 4, 0x02 },
+ { 5, 0x22 },
+ { 6, 0x42 },
+ { 7, 0x62 },
+ { 8, 0x03 },
+ { 10, 0x23 },
+ { 12, 0x43 },
+ { 14, 0x63 },
+ { 16, 0x04 },
+ { 20, 0x24 },
+ { 24, 0x44 },
+ { 28, 0x64 },
+ { 32, 0x05 },
+ { 40, 0x25 },
+ { 48, 0x45 },
+ { 56, 0x65 },
+ { 64, 0x06 },
+ { END_OF_TABLE, END_OF_TABLE }
+};
+
+/**
+ This will perform Miscellaneous Power Management related programming.
+
+ @param[in] CtdpSupport Status of InitializeConfigurableTdp funtion
+**/
+VOID
+InitMiscFeatures (
+ EFI_STATUS CtdpSupport
+ )
+{
+ InitPchPowerSharing(mCpuPmConfig);
+ ///
+ /// Configure Package Turbo Power Limits
+ ///
+ if (CtdpSupport == EFI_SUCCESS) {
+ ConfigureCtdp (mCpuPmConfig);
+ } else {
+ ConfigurePowerLimitsNonConfigTdpSkus (mCpuPmConfig);
+ }
+
+ ///
+ /// This will perform PowerLimit 1 algorithm will be used to control Thermal Throttling features
+ ///
+ InitPl1ThermalControl (mCpuPmConfig);
+
+ ///
+ /// Configure PL3
+ ///
+ ConfigurePL3PowerLimits(mCpuPmConfig);
+
+ ///
+ /// Configure DDR RAPL PowerLimits
+ ///
+ ConfigureDdrPowerLimits(mCpuPmConfig);
+}
+
+/**
+ Private helper function to convert various Turbo Power Limit Time from Seconds to CPU units
+
+ @param[in] TimeInSeconds Time in seconds
+ @param[in] PowerLimitLevel Power Limit Level
+
+ @retval UINT8 Converted time in CPU units
+**/
+UINT8
+GetConvertedTime (
+ IN UINT32 TimeInSeconds,
+ IN UINT8 PowerLimitLevel
+ )
+{
+ UINT8 ConvertedPowerLimitTime;
+ UINT8 Index;
+
+ ///
+ /// Convert seconds to MSR value. Since not all values are programmable, we'll select
+ /// the entry from mapping table which is either equal to the user selected value. OR to a value in the mapping table
+ /// which is closest (but less than) to the user-selected value.
+ ///
+ ConvertedPowerLimitTime = 0;
+ switch(PowerLimitLevel) {
+ case PL12TimeWindowCovert:
+ ConvertedPowerLimitTime = mSecondsToMsrValueMapTable[0][1];
+ for (Index = 0; mSecondsToMsrValueMapTable[Index][0] != END_OF_TABLE; Index++) {
+ if (TimeInSeconds == mSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mSecondsToMsrValueMapTable[Index][1];
+ break;
+ }
+ if (TimeInSeconds > mSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mSecondsToMsrValueMapTable[Index][1];
+ } else {
+ break;
+ }
+ }
+ break;
+ case PL3TimeWindowConvert:
+ ConvertedPowerLimitTime = mMilliSecondsToMsrValueMapTable[0][1];
+ for (Index = 0; mMilliSecondsToMsrValueMapTable[Index][0] != END_OF_TABLE; Index++) {
+ if (TimeInSeconds == mMilliSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mMilliSecondsToMsrValueMapTable[Index][1];
+ break;
+ }
+ if (TimeInSeconds > mMilliSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mMilliSecondsToMsrValueMapTable[Index][1];
+ } else {
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ConvertedPowerLimitTime;
+}
+
+/**
+ Configure PMSYNC_TPR_CFG and PMSYNC_TPR_CFG2 using values returned by CPU BIOS Mail box
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitPchPowerSharing (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ UINT32 PcodeMailBoxPchPowerLevels;
+ UINT32 MailBoxStatus;
+ UINT32 Rcba;
+ UINT32 Index;
+ UINT8 PchPowerLevel;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT16 LpcDeviceId;
+ UINT8 PchRevId;
+ UINT8 IsLptLp;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ CpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING;
+
+ ///
+ /// PCH Power sharing supported only on HSW ULT.
+ ///
+ if (CpuFamilyId != EnumCpuHswUlt) {
+ return;
+ }
+
+ ///
+ /// Read PCH Power Limit from PCODE Mail Box.
+ ///
+ MailboxRead (MAILBOX_TYPE_PCODE,READ_PCH_POWER_LEVELS_CMD,&PcodeMailBoxPchPowerLevels,&MailBoxStatus);
+
+ DEBUG ((EFI_D_ERROR, "Read PCH Power Limit from PCODE Mail Box : %x \n",PcodeMailBoxPchPowerLevels));
+ Rcba = MmioRead32 (
+ MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_RCBA
+ )
+ );
+ Rcba &= (UINT32) (~BIT0);
+ if (MailBoxStatus == PCODE_MAILBOX_CC_SUCCESS) {
+ ///
+ /// Program RCBA+PMSYNC_TPR_CONFIG PCH power limit values.
+ /// READ_PCH_POWER_LEVELS_CMD MailBox[0:5],MailBox[6:11],MailBox[12:17] to PCHReg [0:4],[8:12],[16:20]
+ ///
+ Data32And =0x0;
+ Data32Or =0x0;
+
+ for (Index = 0; Index < HSW_ULT_PCH_POWER_LEVELS; Index++) {
+ PchPowerLevel = PcodeMailBoxPchPowerLevels & 0x3F;
+ PcodeMailBoxPchPowerLevels = PcodeMailBoxPchPowerLevels >> 6;
+ Data32And |= 0x1F << (Index * 8);
+ Data32Or |= (PchPowerLevel & 0x1F) << (Index * 8);
+ }
+ Data32And = ~Data32And;
+ MmioAndThenOr32(Rcba+PMSYNC_TPR_CONFIG,Data32And,Data32Or);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (Rcba + PMSYNC_TPR_CONFIG),
+ 1,
+ (VOID *) (UINTN) (Rcba + PMSYNC_TPR_CONFIG)
+ );
+ } else {
+ DEBUG ((EFI_D_ERROR, "Failure - Read PCH Power Limit from PCODE Mail Box\n"));
+ }
+ ///
+ /// Extended PCH power sharing supported on HSW ULT C0 & LPT-LP B0 and later
+ ///
+ ///
+ PchRevId = MmioRead8 (
+ MmPciAddress (0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_RID)
+ );
+
+ LpcDeviceId = MmioRead16 (
+ MmPciAddress (0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_DEVICE_ID)
+ );
+ IsLptLp = IS_PCH_LPTLP_LPC_DEVICE_ID(LpcDeviceId);
+
+ if(IsLptLp && (PchRevId < V_PCH_LPT_LPC_RID_2) && (CpuSteppingId < EnumHswUltC0)) {
+ return;
+ }
+ ///
+ /// Program RCBA+PMSYNC_TPR_CONFIG Extnded PCH power limit values.
+ /// READ_PCH_POWER_LEVELS_CMD-MailBox[23:18],READ_EXT_PCH_POWER_LEVELS_CMD- MailBox[6:11],MailBox[12:17],MailBox[18:22] to PCHReg [0:4],[8:12],[16:20],[24:28]
+ ///
+ Data32And = 0x1F;
+ Data32Or = (PcodeMailBoxPchPowerLevels & 0x1F);
+ ///
+ /// Read Extended PCH Power Limit from PCODE Mail Box.
+ ///
+ MailboxRead (MAILBOX_TYPE_PCODE,READ_EXT_PCH_POWER_LEVELS_CMD,&PcodeMailBoxPchPowerLevels,&MailBoxStatus);
+ DEBUG ((EFI_D_ERROR, "Read Extended PCH Power Limit from PCODE Mail Box : %x \n",PcodeMailBoxPchPowerLevels));
+ if (MailBoxStatus == PCODE_MAILBOX_CC_SUCCESS) {
+ for (Index = 1; Index < EXTENDED_PCH_POWER_LEVELS; Index++) {
+ PchPowerLevel = PcodeMailBoxPchPowerLevels & 0x3F;
+ PcodeMailBoxPchPowerLevels = PcodeMailBoxPchPowerLevels >> 6;
+ Data32And |= 0x1F << (Index * 8);
+ Data32Or |= (PchPowerLevel & 0x1F) << (Index * 8);
+ }
+ Data32And = ~Data32And;
+ MmioAndThenOr32(Rcba+PMSYNC_TPR_CONFIG2,Data32And,Data32Or);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (Rcba + PMSYNC_TPR_CONFIG2),
+ 1,
+ (VOID *) (UINTN) (Rcba + PMSYNC_TPR_CONFIG2)
+ );
+ } else {
+ DEBUG ((EFI_D_ERROR, "Failure -Extended Read PCH Power Limit from PCODE Mail Box\n"));
+ }
+}
+
+/**
+ Locks down all settings.
+
+ @param[in] CpuPmConfig Pointer to PPM Policy structure.
+**/
+VOID
+PpmLockDown (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER TempMsr;
+ ///
+ /// Program PMG_CST_CONFIG MSR [15] (CFG lock bit)
+ ///
+ RunOnAllLogicalProcessors (ApSafeLockDown, CpuPmConfig);
+ ///
+ /// Lock Package power limit MSR
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ TempMsr.Dwords.High &= ~(B_POWER_LIMIT_LOCK);
+ if (CpuPmConfig->pTurboSettings->TurboPowerLimitLock) {
+ TempMsr.Dwords.High |= B_POWER_LIMIT_LOCK;
+ }
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, TempMsr.Qword);
+ ///
+ /// Program the OverClocking Lock Bit.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_FLEX_RATIO);
+ TempMsr.Dwords.Low &= ~(B_OVERCLOCKING_LOCK);
+ if (CpuPmConfig->pPpmLockEnables->OverclockingLock) {
+ TempMsr.Dwords.Low |= B_OVERCLOCKING_LOCK;
+ }
+ AsmWriteMsr64 (MSR_FLEX_RATIO, TempMsr.Qword);
+ ///
+ /// Program the PROCHOT_Lock
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_POWER_CTL);
+ TempMsr.Dwords.Low &= ~(B_MSR_POWER_CTL_PROC_HOT_LOCK);
+ if (CpuPmConfig->pPpmLockEnables->ProcHotLock) {
+ TempMsr.Dwords.Low |= B_MSR_POWER_CTL_PROC_HOT_LOCK;
+ }
+ AsmWriteMsr64 (MSR_POWER_CTL, TempMsr.Qword);
+ ///
+ /// Program Ddr RAPL LIMIT Lock
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_DDR_RAPL_LIMIT);
+ TempMsr.Dwords.High &= ~(B_POWER_LIMIT_LOCK);
+ if (CpuPmConfig->pTurboSettings->TurboPowerLimitLock) {
+ TempMsr.Dwords.High |= B_POWER_LIMIT_LOCK;
+ }
+ AsmWriteMsr64 (MSR_DDR_RAPL_LIMIT, TempMsr.Qword);
+
+ return;
+}
+
+/**
+ Lock MSR_PMG_CST_CONFIG.
+ This function must be MP safe.
+
+ @param[in] Buffer Not used (needed for API compatibility)
+
+ @retval EFI_SUCCESS Processor C-State locked successfully.
+**/
+VOID
+EFIAPI
+ApSafeLockDown (
+ IN OUT VOID *Buffer
+ )
+{
+ MSR_REGISTER PmCfgCtrl;
+ POWER_MGMT_CONFIG *CpuPmConfig;
+ UINT8 CfgLock;
+
+ CpuPmConfig = (POWER_MGMT_CONFIG *) Buffer;
+ if (CpuPmConfig == NULL) {
+ CfgLock = PPM_ENABLE;
+ } else {
+ CfgLock = (UINT8) CpuPmConfig->pPpmLockEnables->PmgCstCfgCtrlLock;
+ }
+ PmCfgCtrl.Qword = AsmReadMsr64 (MSR_PMG_CST_CONFIG);
+ PmCfgCtrl.Dwords.Low &= ~B_CST_CONTROL_LOCK;
+ if (CfgLock == PPM_ENABLE) {
+ PmCfgCtrl.Dwords.Low |= B_CST_CONTROL_LOCK;
+ }
+ AsmWriteMsr64 (MSR_PMG_CST_CONFIG, PmCfgCtrl.Qword);
+
+ return;
+}
+
+/**
+ Runs the specified procedure on all logical processors, passing in the
+ parameter buffer to the procedure.
+
+ @param[in] Procedure The function to be run.
+ @param[in] Buffer Pointer to a parameter buffer.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+RunOnAllLogicalProcessors (
+ IN OUT EFI_AP_PROCEDURE Procedure,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// Run the procedure on all logical processors.
+ ///
+ (*Procedure)(Buffer);
+ Status = mMpService->StartupAllAPs (
+ mMpService,
+ (EFI_AP_PROCEDURE) Procedure,
+ TRUE,
+ NULL,
+ MP_TIMEOUT_FOR_STARTUP_ALL_APS,
+ Buffer,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Configures the RFI Tunning MSR (0xE3) for FIVR switching freq.
+
+ @param[in] CpuPmConfig Pointer to PPM Policy structure.
+**/
+VOID
+InitFivrSwitchingFreq (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER RfiTuningValue;
+ UINT16 FreqTuningOffsetValue;
+ UINT32 Remainder;
+
+ ///
+ /// Check if we have to change the RFI Freq Tunning offset.
+ /// Check PLATFORM_INFO MSR[25] == 1 before accessing the MSR_RFI_TUNNING
+ ///
+ if ((CpuPmConfig->RfiFreqTunningOffset != AUTO) &&
+ ((AsmReadMsr64 (MSR_PLATFORM_INFO)) & B_FIVR_RFI_TUNING_AVAIL)
+ ) {
+ ///
+ /// Convert the Policy Freq Tunning offset.
+ /// Target frequency encoding = int(value*2^16+0.5) for positive offsets and inv(int(value*2^16+0.5))+1 for negative offsets
+ ///
+ FreqTuningOffsetValue = (UINT16) DivU64x32Remainder (
+ (UINT64) (CpuPmConfig->RfiFreqTunningOffset * (1 << 16)),
+ 1000,
+ &Remainder
+ );
+ if (Remainder >= 500) {
+ FreqTuningOffsetValue += 1;
+ }
+ ///
+ /// Check if Freq Tunning offset value is -ve
+ ///
+ if (CpuPmConfig->RfiFreqTunningOffsetIsNegative == 1) {
+ FreqTuningOffsetValue = (UINT16) (~FreqTuningOffsetValue + 1);
+ }
+ ///
+ /// Write to the RFI_TUNING_MSR. System BIOS must set the desired frequency offset in bits 15:0 of this MSR.
+ ///
+ RfiTuningValue.Qword = AsmReadMsr64 (MSR_RFI_TUNNING);
+
+ ///
+ /// Set the Tuning Frequency
+ ///
+ RfiTuningValue.Qword = ((RfiTuningValue.Qword & V_FREQ_TUNNING_MASK) | FreqTuningOffsetValue);
+ AsmWriteMsr64 (MSR_RFI_TUNNING, RfiTuningValue.Qword);
+ }
+}
+
+/**
+ Update the SSDT table pointers and config DWORD CFGD with the PpmFlags current configuration value
+**/
+VOID
+PatchCpuPmTable (
+ VOID
+ )
+{
+ UINT8 *CurrPtr;
+ UINT32 *Signature;
+ SSDT_LAYOUT *SsdtPackage;
+
+ ///
+ /// Locate the SSDT package
+ ///
+ SsdtPackage = NULL;
+ CurrPtr = (UINT8 *) mCpuPmTable;
+ for (CurrPtr; CurrPtr <= ((UINT8 *) mCpuPmTable + mCpuPmTable->Length); CurrPtr++) {
+ Signature = (UINT32 *) (CurrPtr + 1);
+ if ((*CurrPtr == AML_NAME_OP) && *Signature == EFI_SIGNATURE_32 ('S', 'S', 'D', 'T')) {
+ ///
+ /// Update the SSDT table pointers for dynamically loaded tables
+ ///
+ SsdtPackage = (SSDT_LAYOUT *) CurrPtr;
+ ///
+ /// Set the P-State SSDT table information
+ ///
+ SsdtPackage->Cpu0IstAddr = (UINT32) (UINTN) mCpu0IstTable;
+ SsdtPackage->Cpu0IstLen = mCpu0IstTable->Length;
+ SsdtPackage->ApIstAddr = (UINT32) (UINTN) mApIstTable;
+ SsdtPackage->ApIstLen = mApIstTable->Length;
+ ///
+ /// Set the C-State SSDT table information
+ ///
+ SsdtPackage->Cpu0CstAddr = (UINT32) (UINTN) mCpu0CstTable;
+ SsdtPackage->Cpu0CstLen = mCpu0CstTable->Length;
+ SsdtPackage->ApCstAddr = (UINT32) (UINTN) mApCstTable;
+ SsdtPackage->ApCstLen = mApCstTable->Length;
+ }
+ ///
+ /// Update the PPM GlobalNvs area
+ ///
+ if ((*CurrPtr == AML_OPREGION_OP) && *Signature == EFI_SIGNATURE_32 ('P', 'P', 'M', 'T')) {
+ ASSERT_EFI_ERROR (*(UINT32 *) (CurrPtr + 1 + sizeof (*Signature) + 2) == 0xFFFF0000);
+ ASSERT_EFI_ERROR (*(UINT16 *) (CurrPtr + 1 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) == 0xAA55);
+ ///
+ /// PPM Global NVS Area address
+ ///
+ *(UINT32 *) (CurrPtr + 1 + sizeof (*Signature) + 2) = (UINT32) (UINTN) mPpmGlobalNvsAreaProtocol->Area;
+ ///
+ /// PPM Global NVS Area size
+ ///
+ *(UINT16 *) (CurrPtr + 1 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) = sizeof (PPM_GLOBAL_NVS_AREA);
+ break;
+ }
+ }
+ //
+ // Assert if we didn't update the PM table
+ //
+ ASSERT (SsdtPackage != NULL);
+
+ return;
+}
+
+/**
+ Locate the PPM ACPI tables data file and read ACPI SSDT tables.
+ Publish the appropriate SSDT based on current configuration and capabilities.
+
+ @retval EFI_SUCCESS - On success
+ @retval EFI_NOT_FOUND - Required firmware volume not found
+ @retval - Appropiate failure code on error
+**/
+EFI_STATUS
+InitializePpmAcpiTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN i;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ INTN Instance;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ EFI_ACPI_DESCRIPTION_HEADER *TempTable;
+ UINTN AcpiTableHandle;
+
+ ///
+ /// Locate Firmware volume protocol.
+ /// There is little chance we can't find an FV protocol
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// Look for FV with ACPI storage file
+ ///
+ FwVol = NULL;
+ for (i = 0; i < NumberOfHandles; i++) {
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[i],
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gPowerMgmtAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+ ///
+ /// Our exit status is determined by the success of the previous operations
+ /// If the protocol was found, Instance already points to it.
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol != NULL);
+ if (FwVol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ///
+ /// By default, a table belongs in all ACPI table versions published.
+ ///
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+ ///
+ /// Read tables from the storage file.
+ ///
+ Instance = 0;
+ CurrentTable = NULL;
+ while (Status == EFI_SUCCESS) {
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gPowerMgmtAcpiTableStorageGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID **) &CurrentTable,
+ &Size,
+ &FvStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// Check the table ID to modify the table
+ ///
+ switch (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->OemTableId) {
+ case (EFI_SIGNATURE_64 ('C', 'p', 'u', '0', 'I', 's', 't', 0)):
+ mCpu0IstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) {
+ ///
+ /// Patch the native _PSS package with the GV3 values
+ ///
+ Status = AcpiPatchPss ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ break;
+ case (EFI_SIGNATURE_64 ('C', 'p', 'u', '0', 'C', 's', 't', 0)):
+ mCpu0CstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('C', 'p', 'u', '0', 'T', 's', 't', 0)):
+ mCpu0TstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('A', 'p', 'I', 's', 't', 0, 0, 0)):
+ mApIstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('A', 'p', 'C', 's', 't', 0, 0, 0)):
+ mApCstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('A', 'p', 'T', 's', 't', 0, 0, 0)):
+ mApTstTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('C', 'p', 'u', 'P', 'm', 0, 0, 0)):
+ mCpuPmTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('L', 'a', 'k', 'e', 'T','i', 'n', 'y')):
+ mLakeTinyTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ case (EFI_SIGNATURE_64 ('C', 't', 'd', 'p', 'B', 0, 0, 0)):
+ mCtdpTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ default:
+ break;
+ }
+ Instance++; // Increment the instance
+ CurrentTable = NULL;
+ }
+ }
+ ///
+ /// Statically load IST SSDT if EIST is enabled
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpu0IstTable,
+ mCpu0IstTable->Length,
+ &AcpiTableHandle
+ );
+ //
+ // Free this table as it has been copied into ACPI tables
+ //
+ FreePool (mCpu0IstTable);
+ }
+ ///
+ /// If we are CMP, then the PPM tables are dynamically loaded:
+ /// We need to publish the CpuPm table to the ACPI tables, and move the CST
+ /// tables that are dynamically loaded to a separate location so that we can fix the
+ /// addresses in the CpuPm table.
+ /// Otherwise (non-CMP):
+ /// We need to publish CPU 0 tables only, and CST tables only if CST is enabled
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP) {
+ //
+ // Copy tables to our own location and checksum them
+ //
+ Status = (gBS->AllocatePool) (EfiReservedMemoryType, mApIstTable->Length, (VOID **) &TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mApIstTable, mApIstTable->Length);
+ FreePool (mApIstTable);
+ mApIstTable = TempTable;
+ AcpiChecksum (mApIstTable, mApIstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ Status = (gBS->AllocatePool) (EfiReservedMemoryType, mCpu0CstTable->Length, (VOID **) &TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mCpu0CstTable, mCpu0CstTable->Length);
+ FreePool (mCpu0CstTable);
+ mCpu0CstTable = TempTable;
+ AcpiChecksum (mCpu0CstTable, mCpu0CstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ Status = (gBS->AllocatePool) (EfiReservedMemoryType, mApCstTable->Length, (VOID **) &TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mApCstTable, mApCstTable->Length);
+ FreePool (mApCstTable);
+ mApCstTable = TempTable;
+ AcpiChecksum (mApCstTable, mApCstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ } else {
+ //
+ // CMP disabled, so statically load the tables
+ //
+ // Add CST SSDT if C states are enabled
+ //
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpu0CstTable,
+ mCpu0CstTable->Length,
+ &AcpiTableHandle
+ );
+ }
+ ///
+ /// Since we are UP, there is no need for the CPU 1 tables
+ ///
+ ///
+ /// Free all tables, since they have been copied into ACPI tables by ACPI support protocol
+ ///
+ FreePool (mCpu0CstTable);
+ FreePool (mApIstTable);
+ FreePool (mApCstTable);
+ }
+ ///
+ /// Update the CpuPm SSDT table in the ACPI tables.
+ ///
+ PatchCpuPmTable ();
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpuPmTable,
+ mCpuPmTable->Length,
+ &AcpiTableHandle
+ );
+ FreePool (mCpuPmTable);
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TSTATES) {
+ ///
+ /// Load the Cpu0Tst SSDT table in the ACPI tables
+ ///
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpu0TstTable,
+ mCpu0TstTable->Length,
+ &AcpiTableHandle
+ );
+ FreePool (mCpu0TstTable);
+ ///
+ /// If the CMP is enabled then load the ApTst SSDT table in the ACPI tables
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mApTstTable,
+ mApTstTable->Length,
+ &AcpiTableHandle
+ );
+ }
+ }
+ FreePool (mApTstTable);
+ ///
+ /// Load LakeTiny SSDT only when it is enabled in policy and laketiny SSDT is included.
+ ///
+ if ((mCpuPmConfig->pFunctionEnables->LakeTiny) && (mLakeTinyTable != NULL)) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mLakeTinyTable,
+ mLakeTinyTable->Length,
+ &AcpiTableHandle
+ );
+ FreePool (mLakeTinyTable);
+ }
+ ///
+ /// Load Ctdp SSDT
+ ///
+ if (mCpuPmConfig->pTurboSettings->ConfigTdpBios == 1) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCtdpTable,
+ mCtdpTable->Length,
+ &AcpiTableHandle
+ );
+ FreePool (mCtdpTable);
+ }
+
+ return Status;
+} \ No newline at end of file
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PerformanceStates.c b/ReferenceCode/Haswell/PowerManagement/Dxe/PerformanceStates.c
new file mode 100644
index 0000000..bcb03b2
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PerformanceStates.c
@@ -0,0 +1,930 @@
+/** @file
+ This file contains P States and Turbo Power Management configuration functions for
+ Haswell processors.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM - Thermal Monitor
+ IST - Intel(R) Speedstep technology
+ HT - Hyper-Threading Technology
+
+@copyright
+ Copyright (c) 2012 - 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 "PowerMgmtCommon.h"
+
+//(AMI_CHG)>
+VOID
+EFIAPI
+ApSafeSetEnergyPolicy (
+ IN OUT VOID *Buffer
+ );
+//<(AMI_CHG)
+
+extern UINT16 mCpuConfigTdpBootRatio;
+
+/**
+ Initializes P States and Turbo Power management features
+**/
+VOID
+InitializePStates (
+ VOID
+ )
+{
+ MSR_REGISTER Ia32MiscEnableMsr;
+
+ //
+ // InitTurboRatioLimits has to be called before InitGV3 as InitGV3 uses the Turbo Ratio Limit programmed.
+ //
+ InitTurboRatioLimits (mCpuPmConfig); ///< Initialize InitTurboRatioLimits
+
+ InitEnergyEfficientPState (mCpuPmConfig); ///< Initialize Energy Efficient P-state
+
+ //
+ // Initialize P states
+ //
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) {
+ InitGv3 (mFvidPointer, mCpuPmConfig);
+ mNumberOfStates = mFvidPointer[0].FvidHeader.Gv3States;
+ } else {
+ //
+ // Clear EIST bit in IA32 Misc Enable MSR that was intially set in PEI
+ //
+ Ia32MiscEnableMsr.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ Ia32MiscEnableMsr.Qword &= ~B_MSR_IA32_MISC_ENABLE_EIST;
+ ///
+ /// Disable Turbo if EIST is disabled
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) {
+ Ia32MiscEnableMsr.Qword |= (UINT64)B_MSR_IA32_MISC_DISABLE_TURBO;
+ }
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnableMsr.Qword);
+ }
+
+ ///
+ /// Initialize PAIR Configuration
+ /// HSW BWG Rev 0.6.0, Section 16.4.1 Power Aware Interrupt Routing
+ ///
+ InitPpmIrmConfiguration (mCpuPmConfig);
+
+}
+
+/**
+ Initializes Turbo Ratio limits in the processor.
+
+ @param[in] CpuPmConfig Pointer to PPM Policy protocol instance
+**/
+VOID
+InitTurboRatioLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER TurboRatioLimit;
+ MSR_REGISTER CoreThreadCount;
+ MSR_REGISTER FlexRatioMsr;
+ UINT8 CoreCount;
+ UINT8 OverclockingBins;
+ UINT8 OneCoreRatioLimit;
+ UINT8 TwoCoreRatioLimit;
+ UINT8 ThreeCoreRatioLimit;
+ UINT8 FourCoreRatioLimit;
+
+ ///
+ /// Check if processor turbo-ratio can be overriden
+ ///
+ // Haswell BWG Section 15.13.7
+ // If PLATFORM INFO MSR [28] == 1
+ //
+ if (!mRatioLimitProgrammble) {
+ DEBUG ((EFI_D_WARN, "Turbo Ratio Limit is NOT programmable. Platform Info MSR (0xCE) [28] is not set \n"));
+ return;
+ }
+ ///
+ /// Read the overclocking bins
+ ///
+ FlexRatioMsr.Qword = AsmReadMsr64 (MSR_FLEX_RATIO);
+ OverclockingBins = (UINT8) RShiftU64 ((FlexRatioMsr.Dwords.Low & B_OVERCLOCKING_BINS), 17);
+ if (FlexRatioMsr.Dwords.Low & B_OVERCLOCKING_LOCK) { ///< Check for Overclocking Lock bit
+ DEBUG ((EFI_D_ERROR, "ERROR: OverClocking Lock Bit is set. Disable the Lock and reset the system\n"));
+ return;
+ }
+ TurboRatioLimit.Qword = AsmReadMsr64 (MSR_TURBO_RATIO_LIMIT);
+ OneCoreRatioLimit = (UINT8) (TurboRatioLimit.Dwords.Low & B_MSR_TURBO_RATIO_LIMIT_1C);
+ TwoCoreRatioLimit = (UINT8) RShiftU64 (
+ (TurboRatioLimit.Dwords.Low & B_MSR_TURBO_RATIO_LIMIT_2C),
+ N_MSR_TURBO_RATIO_LIMIT_2C
+ );
+ ThreeCoreRatioLimit = (UINT8) RShiftU64 (
+ (TurboRatioLimit.Dwords.Low & B_MSR_TURBO_RATIO_LIMIT_3C),
+ N_MSR_TURBO_RATIO_LIMIT_3C
+ );
+ FourCoreRatioLimit = (UINT8) RShiftU64 (
+ (TurboRatioLimit.Dwords.Low & B_MSR_TURBO_RATIO_LIMIT_4C),
+ N_MSR_TURBO_RATIO_LIMIT_4C
+ );
+ ///
+ /// For Overclocking and locked parts, verify ratio overide is within the allowable limits
+ /// Locked parts will have OverclockingBins value as 0 so the below condition will take care of locked parts also
+ ///
+ if (OverclockingBins < MAX_OVERCLOCKING_BINS) {
+ if (CpuPmConfig->pRatioLimit[0] > (OneCoreRatioLimit + OverclockingBins)) {
+ CpuPmConfig->pRatioLimit[0] = OneCoreRatioLimit + OverclockingBins;
+ }
+ if (CpuPmConfig->pRatioLimit[1] > (TwoCoreRatioLimit + OverclockingBins)) {
+ CpuPmConfig->pRatioLimit[1] = TwoCoreRatioLimit + OverclockingBins;
+ }
+ if (CpuPmConfig->pRatioLimit[2] > (ThreeCoreRatioLimit + OverclockingBins)) {
+ CpuPmConfig->pRatioLimit[2] = ThreeCoreRatioLimit + OverclockingBins;
+ }
+ if (CpuPmConfig->pRatioLimit[3] > (FourCoreRatioLimit + OverclockingBins)) {
+ CpuPmConfig->pRatioLimit[3] = FourCoreRatioLimit + OverclockingBins;
+ }
+ }
+
+ ///
+ /// Max Turbo ratio or P0 = Fused 1C Turbo Ratio Limit + No of over clocking Bins.
+ ///
+ mTurboBusRatio = OneCoreRatioLimit + OverclockingBins;
+ ///
+ /// Initialize turbo ratio limit MSR.
+ /// Find the number of active cores and initialize the ratio limits only if they are available.
+ ///
+ CoreThreadCount.Qword = AsmReadMsr64 (MSR_CORE_THREAD_COUNT);
+ CoreCount = (UINT8) RShiftU64 (CoreThreadCount.Dwords.Low, N_CORE_COUNT_OFFSET);
+ if (CpuPmConfig->pRatioLimit[0] >= CpuPmConfig->pRatioLimit[1] &&
+ CpuPmConfig->pRatioLimit[0] >= CpuPmConfig->pRatioLimit[2] &&
+ CpuPmConfig->pRatioLimit[0] >= CpuPmConfig->pRatioLimit[3] &&
+ CpuPmConfig->pRatioLimit[1] >= mMaxBusRatio &&
+ CpuPmConfig->pRatioLimit[2] >= mMaxBusRatio &&
+ CpuPmConfig->pRatioLimit[3] >= mMaxBusRatio
+ ) {
+ if (CoreCount >= 1) {
+ TurboRatioLimit.Dwords.Low &= ~B_MSR_TURBO_RATIO_LIMIT_1C;
+ TurboRatioLimit.Dwords.Low |= CpuPmConfig->pRatioLimit[0];
+ }
+ if (CoreCount >= 2) {
+ TurboRatioLimit.Dwords.Low &= ~B_MSR_TURBO_RATIO_LIMIT_2C;
+ TurboRatioLimit.Dwords.Low |= LShiftU64 (CpuPmConfig->pRatioLimit[1], 8);
+ }
+ if (CoreCount >= 3) {
+ TurboRatioLimit.Dwords.Low &= ~B_MSR_TURBO_RATIO_LIMIT_3C;
+ TurboRatioLimit.Dwords.Low |= LShiftU64 (CpuPmConfig->pRatioLimit[2], 16);
+ }
+ if (CoreCount >= 4) {
+ TurboRatioLimit.Dwords.Low &= ~B_MSR_TURBO_RATIO_LIMIT_4C;
+ TurboRatioLimit.Dwords.Low |= LShiftU64 (CpuPmConfig->pRatioLimit[3], 24);
+ }
+ AsmWriteMsr64 (MSR_TURBO_RATIO_LIMIT, TurboRatioLimit.Qword);
+ }
+ //
+ // For fully unlocked CPU's, configure Turbo Ratio as 0xFF (max possible P-State)
+ //
+ if (OverclockingBins == MAX_OVERCLOCKING_BINS) {
+ mTurboBusRatio = 0xFF;
+ }
+
+ return;
+}
+
+/**
+ Initializes Energy efficient P-state feature.
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitEnergyEfficientPState (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER PowerCtlMsr;
+
+ ///
+ /// Configure Energy Efficient P-state : POWER_CTL[18]
+ ///
+ PowerCtlMsr.Qword = AsmReadMsr64 (MSR_POWER_CTL);
+ PowerCtlMsr.Dwords.Low &= ~B_ENERGY_EFFICIENT_P_STATE_FEATURE_ENABLE;
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EEPST) {
+ PowerCtlMsr.Dwords.Low |= B_ENERGY_EFFICIENT_P_STATE_FEATURE_ENABLE;
+ }
+ AsmWriteMsr64 (MSR_POWER_CTL, PowerCtlMsr.Qword);
+
+//(AMI_CHG)>
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EEPST) {
+ RunOnAllLogicalProcessors (ApSafeSetEnergyPolicy, CpuPmConfig);
+ }
+//<(AMI_CHG)
+ return;
+}
+
+/**
+ Sets the MSR_IA32_ENERGY_PERFROMANCE_BIAS.Energy Efficiency Policy.
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to PPM Policy
+
+ @retval EFI_SUCCESS Energy policy is set successfully.
+**/
+//(AMI_CHG)>
+VOID
+EFIAPI
+ApSafeSetEnergyPolicy (
+ IN OUT VOID *Buffer
+ )
+{
+ POWER_MGMT_CONFIG *CpuPmConfig;
+ MSR_REGISTER Ia32EnergyPerfBiasMsr;
+
+ CpuPmConfig = (POWER_MGMT_CONFIG *) Buffer;
+ Ia32EnergyPerfBiasMsr.Qword = AsmReadMsr64 (MSR_IA32_ENERGY_PERFORMANCE_BIAS);
+ Ia32EnergyPerfBiasMsr.Dwords.Low &= ~B_ENERGY_POLICY_MASK;
+ Ia32EnergyPerfBiasMsr.Dwords.Low |= CpuPmConfig->pTurboSettings->EnergyPolicy;
+ AsmWriteMsr64 (MSR_IA32_ENERGY_PERFORMANCE_BIAS, Ia32EnergyPerfBiasMsr.Qword);
+
+ return;
+}
+/*EFI_STATUS
+ApSafeSetEnergyPolicy (
+ IN OUT VOID *Buffer
+ )
+{
+ POWER_MGMT_CONFIG *CpuPmConfig;
+ MSR_REGISTER Ia32EnergyPerfBiasMsr;
+
+ CpuPmConfig = (POWER_MGMT_CONFIG *) Buffer;
+ Ia32EnergyPerfBiasMsr.Qword = AsmReadMsr64 (MSR_IA32_ENERGY_PERFORMANCE_BIAS);
+ Ia32EnergyPerfBiasMsr.Dwords.Low &= ~B_ENERGY_POLICY_MASK;
+ Ia32EnergyPerfBiasMsr.Dwords.Low |= CpuPmConfig->pTurboSettings->EnergyPolicy;
+ AsmWriteMsr64 (MSR_IA32_ENERGY_PERFORMANCE_BIAS, Ia32EnergyPerfBiasMsr.Qword);
+
+ return EFI_SUCCESS;
+}*/
+//<(AMI_CHG)
+/**
+ Initializes required structures for P-State table creation and enables GV3
+ support in the processor.
+
+ @param[in] FvidPointer Table to update, must be initialized.
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitGv3 (
+ IN OUT FVID_TABLE *FvidPointer,
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER Ia32MiscEnableMsr;
+ EFI_CPUID_REGISTER Cpuid = { 0, 0, 0, 0 };
+
+ ///
+ /// Test for Turbo Mode supported and initialize if true.
+ ///
+ AsmCpuid (CPUID_POWER_MANAGEMENT_PARAMS, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx);
+ Ia32MiscEnableMsr.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) {
+ ///
+ /// Clear Turbo Mode disable bit in IA32 Misc Enable MSR
+ ///
+ Ia32MiscEnableMsr.Qword &= ~B_MSR_IA32_MISC_DISABLE_TURBO;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnableMsr.Qword);
+ } else if (((Ia32MiscEnableMsr.Qword & B_MSR_IA32_MISC_DISABLE_TURBO) == 0) &&
+ ((Cpuid.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == B_CPUID_POWER_MANAGEMENT_EAX_TURBO)) {
+ ///
+ /// If Turbo mode is supported but required to be disabled (by platform policy setting)
+ /// Set Turbo Mode disable bit in IA32 Misc Enable MSR since it might be temporarily enabled earlier.
+ ///
+ Ia32MiscEnableMsr.Qword |= B_MSR_IA32_MISC_DISABLE_TURBO;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnableMsr.Qword);
+ }
+
+ ///
+ /// Initialize the FVID tables.
+ ///
+ InitFvidTable (FvidPointer, FVID_MAX_STATES, FVID_MIN_STEP_SIZE, FALSE);
+ ASSERT (FvidPointer->FvidHeader.Gv3States != 0);
+
+ ///
+ /// Enable GV3 on all logical processors.
+ ///
+ RunOnAllLogicalProcessors (ApSafeEnableGv3, NULL);
+
+ return;
+}
+
+/**
+ Enables GV3 support in a logical processor.
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to arguments - not used
+
+ @retval EFI_SUCCESS
+**/
+VOID
+EFIAPI
+ApSafeEnableGv3 (
+ IN OUT VOID *Buffer
+ )
+{
+ MSR_REGISTER Ia32MiscEnable;
+ MSR_REGISTER MiscPwrMgmt;
+
+ ///
+ /// Enable GV3 in the CPU MSR.
+ ///
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ Ia32MiscEnable.Qword |= B_MSR_IA32_MISC_ENABLE_EIST;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+
+ ///
+ /// If CMP is disabled, disable hardware coordination.
+ ///
+ if (!(mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP)) {
+ MiscPwrMgmt.Qword = AsmReadMsr64 (MSR_MISC_PWR_MGMT);
+ MiscPwrMgmt.Qword |= B_MSR_MISC_PWR_MGMT_EIST_HW;
+ AsmWriteMsr64 (MSR_MISC_PWR_MGMT, MiscPwrMgmt.Qword);
+ }
+
+ return;
+}
+
+/**
+ Configures the Interrupt Redirection Mode Selection for Logical Interrupts.
+
+ @param[in] CpuPmConfig Pointer to PPM Policy structure.
+**/
+VOID
+InitPpmIrmConfiguration (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ UINTN PciD0F0RegBase;
+ UINTN MchBar;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT8 PpmIrmSetting;
+
+ //
+ ///
+ /// HSW BWG Rev 0.6.0, Section 16.4.1 Power Aware Interrupt Routing
+ /// Program Interrupt Routiong Control register MCHBAR+0x5418 as PAIR with Fixed Priority
+ ///
+ PpmIrmSetting = 4;
+ ///
+ /// Get the MCH space base address and program MMIO register MCHBAR+0x5418 to enable specific routing algorithm.
+ ///
+ PciD0F0RegBase = MmPciAddress (0, 0, 0, 0, 0);
+ MchBar = MmioRead32 (PciD0F0RegBase + 0x48) &~BIT0;
+ Data32And = (UINT32) ~(BIT2 + BIT1 + BIT0);
+ Data32Or = (UINT32) (PpmIrmSetting & (BIT2 + BIT1 + BIT0));
+ MmioAndThenOr32 (MchBar + 0x5418, Data32And, Data32Or);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + 0x5418),
+ 1,
+ (VOID *) (UINTN) (MchBar + 0x5418)
+ );
+}
+
+/**
+ This function updates the table provided with the FVID data for the processor.
+ If CreateDefaultTable is TRUE, a minimam FVID table will be provided.
+ The maximum number of states must be greater then or equal to two.
+ The table should be initialized in such a way as for the caller to determine if the
+ table was updated successfully. This function should be deprecated in the future when
+ Release 8 is integrated in favor of the EIST protocol calculating FVID information.
+
+ @param[in] FvidPointer Pointer to a table to be updated
+ @param[in] MaxNumberOfStates Number of entries in the table pointed to by FvidPointer
+ @param[in] MinStepSize Minimum step size for generating the FVID table
+ @param[in] CreateDefaultTable Create default FVID table rather then full state support
+**/
+VOID
+InitFvidTable (
+ IN OUT FVID_TABLE *FvidPointer,
+ IN UINT16 MaxNumberOfStates,
+ IN UINT16 MinStepSize,
+ IN BOOLEAN CreateDefaultTable
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// Return the function, if the FVID tables have already been created.
+ ///
+ if (FvidPointer[0].FvidHeader.Gv3States != 0) {
+ return;
+ }
+ ///
+ /// Create FVID table
+ ///
+ if (CreateDefaultTable) {
+ CreateDefaultFvidTable (FvidPointer);
+ mPpmGlobalNvsAreaProtocol->Area->PpmFlags &= ~PPM_TURBO;
+ } else {
+ Status = CreateFvidTable (FvidPointer, MaxNumberOfStates);
+ if (EFI_ERROR (Status)) {
+ CreateDefaultFvidTable (FvidPointer);
+ mPpmGlobalNvsAreaProtocol->Area->PpmFlags &= ~PPM_TURBO;
+ }
+ }
+
+ return;
+}
+
+/**
+ Create default FVID table with max and min states only.
+
+ @param[in] FvidPointer Pointer to a table to be updated
+**/
+VOID
+CreateDefaultFvidTable (
+ IN OUT FVID_TABLE *FvidPointer
+ )
+{
+ UINT64 wPower1;
+ UINT64 wPower2;
+
+ ///
+ /// Fill in the FVid table header.
+ ///
+ FvidPointer[0].FvidHeader.Stepping = mPpmGlobalNvsAreaProtocol->Area->Cpuid;
+ FvidPointer[0].FvidHeader.MaxBusRatio = mMaxBusRatio;
+ FvidPointer[0].FvidHeader.Gv3States = 2;
+ ///
+ /// First entry is state 0, highest state.
+ ///
+ FvidPointer[1].FvidState.State = 0;
+ FvidPointer[1].FvidState.BusRatio = mMaxBusRatio;
+ ///
+ /// Power is calculated in milliwatts
+ ///
+ FvidPointer[1].FvidState.Power = (mPackageTdpWatt * 1000);
+ ///
+ /// Second entry is state 1, lowest state.
+ ///
+ FvidPointer[2].FvidState.State = 1;
+ FvidPointer[2].FvidState.BusRatio = (UINT16) mMinBusRatio;
+ ///
+ /// Calculate Relative Power per HSW BWG (0.6.0 section 13.10.4)
+ ///
+ wPower1 = (mMaxBusRatio - FvidPointer[2].FvidState.BusRatio) * 625;
+ wPower1 = (110000 - wPower1);
+ wPower1 = DivU64x32 (wPower1, 11);
+ wPower1 = DivU64x32 (MultU64x64 (wPower1, wPower1), 1000);
+ //
+ // Power is calculated in milliwatts
+ //
+ wPower2 = (((FvidPointer[2].FvidState.BusRatio * 100000) / mMaxBusRatio) / 100);
+ wPower2 = DivU64x32 (MultU64x32 (MultU64x64 (wPower2, DivU64x32 (wPower1, 100)), mPackageTdpWatt), 1000);
+ FvidPointer[2].FvidState.Power = (UINT16) wPower2;
+}
+
+/**
+ Calculate the ratio for the requested p state based on HSW BWG recommendation
+
+ @param[in] MaxRatio Maximum Supported Ratio (HFM)
+ @param[in] MinRatio Minimum Supported Ratio (LFM)
+ @param[in] MaxNumberOfStates Number of entries in the table pointed to by FvidPointer
+ @param[in] PStateNumber Desired P State from range 0..MaxNumberOfStates
+
+ @retval Ratio for the requested Pstate
+**/
+UINT16
+ComputePstateRatio (
+ IN UINT16 MaxRatio,
+ IN UINT16 MinRatio,
+ IN UINT16 MaxNumberOfStates,
+ IN UINT16 PStateNumber
+ )
+{
+ UINT16 RatioRange;
+ UINT16 NumGaps;
+ UINT16 PStateRatio;
+
+ RatioRange = MaxRatio - MinRatio;
+ NumGaps = MaxNumberOfStates - 1;
+ PStateRatio = MaxRatio - (((PStateNumber * RatioRange) + (NumGaps / 2)) / NumGaps);
+
+ return PStateRatio;
+}
+
+/**
+ Create an FVID table based on the algorithm provided by the HSW BIOS writer's guide.
+
+ @param[in] FvidPointer Pointer to a table to be updated
+ @param[in] MaxNumberOfStates Number of entries in the table pointed to by FvidPointer
+
+ @retval EFI_SUCCESS FVID table created successfully.
+ @retval EFI_INVALID_PARAMETER The bus ratio range don't permit FVID table calculation;
+ a default FVID table should be constructed.
+**/
+EFI_STATUS
+CreateFvidTable (
+ IN OUT FVID_TABLE *FvidPointer,
+ IN UINT16 MaxNumberOfStates
+ )
+{
+ UINT16 BusRatioRange;
+ UINT16 PowerRange;
+ UINT16 NumberOfStates;
+ UINT16 Turbo;
+ UINT16 index;
+ UINT64 wPower1;
+ UINT64 wPower2;
+
+ ///
+ /// Determine the bus ratio range
+ ///
+ BusRatioRange = mMaxBusRatio - mMinBusRatio;
+ if (((INT16) BusRatioRange < 0) || (MaxNumberOfStates == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ ///
+ /// Determine the Power range
+ ///
+ PowerRange = FVID_MAX_POWER - FVID_MIN_POWER;
+ ///
+ /// Determine the HFM state index
+ ///
+ Turbo = ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) ? 1 : 0);
+ ///
+ /// Determine the number of states as cpu supported range or Maximum _PSS limit
+ ///
+ NumberOfStates = ((BusRatioRange + 1) < MaxNumberOfStates ? (BusRatioRange + 1) : MaxNumberOfStates);
+ ///
+ /// Ensure we have at least two states
+ ///
+ if ((NumberOfStates + Turbo) < 2) {
+ ///
+ /// In case HFM = LFM and no Turbo, at least have two states with same ratio values
+ ///
+ NumberOfStates = 2;
+ }
+ ///
+ /// Fill in the table header
+ ///
+ FvidPointer[0].FvidHeader.Stepping = mPpmGlobalNvsAreaProtocol->Area->Cpuid;
+ FvidPointer[0].FvidHeader.MaxBusRatio = (Turbo ? mTurboBusRatio : mMaxBusRatio);
+ FvidPointer[0].FvidHeader.Gv3States = (UINT16) (NumberOfStates < MaxNumberOfStates ? (NumberOfStates + Turbo) : NumberOfStates);
+ ///
+ /// Add Turbo as P0 if Turbo Mode supported and initialize.
+ ///
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) {
+ FvidPointer[1].FvidState.BusRatio = mTurboBusRatio;
+ FvidPointer[1].FvidState.Power = (mPackageTdpWatt * 1000); // power is calculated in milliwatts
+ ///
+ /// Reserve on P-State for Max Turbo
+ ///
+ if (NumberOfStates == MaxNumberOfStates) {
+ NumberOfStates--;
+ }
+ }
+ ///
+ /// Add HFM as P0 or P1 based on Max Turbo availablity
+ ///
+ FvidPointer[1 + Turbo].FvidState.State = Turbo;
+ FvidPointer[1 + Turbo].FvidState.BusRatio = mMaxBusRatio;
+ //
+ // Power is calculated in milliwatts
+ //
+ FvidPointer[1 + Turbo].FvidState.Power = (mPackageTdpWatt * 1000);
+ ///
+ /// Fill in the table starting at the last entry
+ /// The algorithm is available in the processor BIOS writer's guide.
+ ///
+ for (index = 1; index < NumberOfStates; index++) {
+ FvidPointer[index + 1 + Turbo].FvidState.State = index + Turbo;
+ FvidPointer[index + 1 + Turbo].FvidState.BusRatio = ComputePstateRatio (mMaxBusRatio, mMinBusRatio, NumberOfStates, index);
+ ///
+ /// Calculate Relative Power per HSW BWG
+ ///
+ wPower1 = (mMaxBusRatio - FvidPointer[index + 1 + Turbo].FvidState.BusRatio) * 625;
+ wPower1 = (110000 - wPower1);
+ wPower1 = DivU64x32 (wPower1, 11);
+ wPower1 = MultU64x64 (wPower1, wPower1);
+ ///
+ /// Power is calculated in milliwatts
+ ///
+ wPower2 = (((FvidPointer[index + 1 + Turbo].FvidState.BusRatio * 100) / mMaxBusRatio));
+ wPower2 = DivU64x32 (MultU64x32 (MultU64x64 (wPower2, wPower1), mPackageTdpWatt), 10000000);
+ FvidPointer[index + 1 + Turbo].FvidState.Power = (UINT32) wPower2;
+ ///
+ /// For Controllable Tdp -- Configure PPC as LFM (i.e fake LFM + 1)
+ ///
+ if (mControllableTdpEnable == 1 && FvidPointer[index + 1 + Turbo].FvidState.BusRatio == (mMinBusRatio + 1)) {
+ mPpmGlobalNvsAreaProtocol->Area->ConfigurablePpc = (UINT8)FvidPointer[index + 1 + Turbo].FvidState.State;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set processor P state to HFM or LFM.
+
+ @exception EFI_UNSUPPORTED EIST not supported.
+ @retval EFI_SUCCESS Processor P state has been set.
+**/
+VOID
+SetBootPState (
+ VOID
+ )
+{
+ MSR_REGISTER Ia32MiscEnable;
+ MSR_REGISTER Ia32PerfCtl;
+ BOOLEAN EistEnabled;
+
+ ///
+ /// This function will be executed even when EIST is disabled so processor can be switched to HFM
+ /// Only skip this when EIST is not capable.
+ ///
+ if ((mCpuid01.RegEcx & B_CPUID_VERSION_INFO_ECX_EIST) == 0) {
+ return;
+ }
+ ///
+ /// Read EIST.
+ ///
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ EistEnabled = (BOOLEAN) RShiftU64 (
+ (Ia32MiscEnable.Qword & B_MSR_IA32_MISC_ENABLE_EIST),
+ N_MSR_IA32_MISC_ENABLE_EIST_OFFSET
+ );
+ ///
+ /// If EIST is disabled, temporarily enable it
+ ///
+ if (EistEnabled == 0) {
+ Ia32MiscEnable.Qword |= B_MSR_IA32_MISC_ENABLE_EIST;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+ }
+ Ia32PerfCtl.Qword = AsmReadMsr64 (MSR_IA32_PERF_CTRL);
+ Ia32PerfCtl.Qword &= B_IA32_PERF_CTRLP_STATE_TARGET;
+ mBspBootRatio = (UINT16) RShiftU64 (Ia32PerfCtl.Qword, N_IA32_PERF_CTRLP_STATE_TARGET);
+ ///
+ /// Set P-state on all cores
+ ///
+ RunOnAllLogicalProcessors (ApSafeSetBootPState, NULL);
+ ///
+ /// Disable EIST if we enabled it previously
+ ///
+ if (EistEnabled == 0) {
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ Ia32MiscEnable.Qword &= ~B_MSR_IA32_MISC_ENABLE_EIST;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+ }
+
+ return;
+}
+
+/**
+ Set processor P state based on Boot ConfigTdp level.
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Processor MSR setting is saved.
+**/
+VOID
+EFIAPI
+ApSafeSetBootPState (
+ IN OUT VOID *Buffer
+ )
+{
+ MSR_REGISTER Ia32PerfCtl;
+ UINT16 BootRatio;
+
+ Ia32PerfCtl.Qword = AsmReadMsr64 (MSR_IA32_PERF_CTRL);
+ Ia32PerfCtl.Qword &= ~B_IA32_PERF_CTRLP_STATE_TARGET;
+ /*AMI_CHG+>
+ if (mCpuConfigTdpBootRatio != 0) {
+ ///
+ /// For ConfigTDP enabled SKU use (ConfigTDP boot ratio - 1 / TAR Ratio) as max non-turbo ratio
+ ///
+ BootRatio = mCpuConfigTdpBootRatio-1;
+ //
+ // If EIST is disabled use boot ratio ConfigTDP boot ratio / TAR+1.
+ //
+ if((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST)== 0) {
+ BootRatio = mCpuConfigTdpBootRatio;
+ }
+ } else {
+ ///
+ /// For Non-ConfigTDP enabled SKU set BSP ratio on all threads.
+ ///
+ BootRatio = mBspBootRatio;
+ }<AMI_CHG*/
+ BootRatio = mBspBootRatio;
+ Ia32PerfCtl.Qword |= LShiftU64 (BootRatio, N_IA32_PERF_CTRLP_STATE_TARGET);
+ AsmWriteMsr64 (MSR_IA32_PERF_CTRL, Ia32PerfCtl.Qword);
+
+ return;
+}
+
+//
+// Update ACPI PerfomanceStates tables
+//
+
+/**
+ Patch the native _PSS package with the GV3 values
+ Uses ratio/VID values from the FVID table to fix up the control values in the _PSS.
+
+ (1) Find _PSS package:
+ (1.1) Find the _PR_CPU0 scope.
+ (1.2) Save a pointer to the package length.
+ (1.3) Find the _PSS AML name object.
+ (2) Resize the _PSS package.
+ (3) Fix up the _PSS package entries
+ (3.1) Check Turbo mode support.
+ (3.2) Check Dynamic FSB support.
+ (4) Fix up the Processor block and \_PR_CPU0 Scope length.
+ (5) Update SSDT Header with new length.
+
+ @retval EFI_SUCCESS - on success
+ @retval EFI_NOT_FOUND - if _PR_.CPU0 scope is not foud in the ACPI tables
+**/
+EFI_STATUS
+AcpiPatchPss (
+ VOID
+ )
+{
+ UINT8 *CurrPtr;
+ UINT8 *EndOfTable;
+ UINT8 index;
+ UINT16 NewPackageLength;
+ UINT16 MaxPackageLength;
+ UINT16 Temp;
+ UINT16 *PackageLength;
+ UINT16 *ScopePackageLengthPtr;
+ UINT32 *Signature;
+ PSS_PACKAGE_LAYOUT *PssPackage;
+ MSR_REGISTER TempMsr;
+ UINT16 MaximumEfficiencyRatio;
+ UINT16 MaximumNonTurboRatio;
+ UINT16 PnPercent;
+
+ ScopePackageLengthPtr = NULL;
+ PssPackage = NULL;
+
+ //
+ // Get Maximum Efficiency bus ratio (LFM) from Platform Info MSR Bits[47:40]
+ // Get Maximum Non Turbo bus ratio from Platform Info MSR Bits[15:8]
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO);
+ MaximumEfficiencyRatio = TempMsr.Bytes.SixthByte;
+ MaximumNonTurboRatio = TempMsr.Bytes.SecondByte;
+
+ ///
+ /// Calculate new package length
+ ///
+ NewPackageLength = Temp = (UINT16) (mNumberOfStates * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ MaxPackageLength = (UINT16) (FVID_MAX_STATES * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ ///
+ /// Locate the SSDT package in the IST table
+ ///
+ CurrPtr = (UINT8 *) mCpu0IstTable;
+ EndOfTable = (UINT8 *) (CurrPtr + mCpu0IstTable->Length);
+ for (CurrPtr; CurrPtr <= EndOfTable; CurrPtr++) {
+ Signature = (UINT32 *) (CurrPtr + 1);
+ ///
+ /// If we find the _PR_CPU0 scope, save a pointer to the package length
+ ///
+ if ((*CurrPtr == AML_SCOPE_OP) &&
+ (*(Signature + 1) == EFI_SIGNATURE_32 ('_', 'P', 'R', '_')) &&
+ (*(Signature + 2) == EFI_SIGNATURE_32 ('C', 'P', 'U', '0'))
+ ) {
+ ScopePackageLengthPtr = (UINT16 *) (CurrPtr + 1);
+ }
+ ///
+ /// Patch the native _PSS package with the GV3 values
+ ///
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == EFI_SIGNATURE_32 ('_', 'P', 'S', 'S'))) {
+ ///
+ /// Check table dimensions.
+ /// PSS package reserve space for FVID_MAX_STATES number of P-states so check if the
+ /// current number of P- states is more than FVID_MAX_STATES. Also need to update the SSDT contents
+ /// if the current number of P-states is less than FVID_MAX_STATES.
+ ///
+ ASSERT (mNumberOfStates <= FVID_MAX_STATES);
+ if (mNumberOfStates <= FVID_MAX_STATES) {
+ *(CurrPtr + 8) = (UINT8) mNumberOfStates;
+ PackageLength = (UINT16 *) (CurrPtr + 6);
+ ///
+ /// Update the Package length in AML package length format
+ ///
+ *PackageLength = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00);
+ ///
+ /// Move SSDT contents
+ ///
+ CopyMem (
+ (CurrPtr + NewPackageLength),
+ (CurrPtr + MaxPackageLength),
+ EndOfTable - (CurrPtr + MaxPackageLength)
+ );
+ ///
+ /// Save the new end of the SSDT
+ ///
+ EndOfTable = EndOfTable - (MaxPackageLength - NewPackageLength);
+ }
+ PssPackage = (PSS_PACKAGE_LAYOUT *) (CurrPtr + 9);
+ for (index = 1; index <= mNumberOfStates; index++) {
+ ///
+ /// Update the _PSS table
+ ///
+ ///
+ /// If Turbo mode is supported, add one to the Max Non-Turbo frequency
+ ///
+ if ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) && (index == 1)) {
+ PssPackage->CoreFrequency = (UINT32)((mFvidPointer[index + 1].FvidState.BusRatio)* 100)+1;
+ }else if (mFvidPointer[index].FvidState.BusRatio < MaximumEfficiencyRatio) {
+ //
+ // If cTDP Down Ratio == LFM, set it to 1% lower than LFM.
+ //
+ PnPercent = (MaximumEfficiencyRatio * 100) / MaximumNonTurboRatio;
+ PssPackage->CoreFrequency = (MaximumNonTurboRatio * (PnPercent - 1)); // Simplified Calculation.
+ } else {
+ PssPackage->CoreFrequency = (UINT32)(mFvidPointer[index].FvidState.BusRatio) * 100;
+ }
+ PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power;
+ ///
+ /// If it's PSS table, Control is the PERF_CTL value.
+ /// Status entry is the same as control entry.
+ /// TransLatency uses 10
+ ///
+ PssPackage->TransLatency = NATIVE_PSTATE_LATENCY;
+ PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ //
+ // Ensure any future OS would not look for the IA32_PERF_STATUS MSR to check if the value matches
+ //
+ if (mFvidPointer[index].FvidState.BusRatio < MaximumEfficiencyRatio) {
+ PssPackage->Status = (UINT32) LShiftU64 (MaximumEfficiencyRatio, 8);
+ } else {
+ PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ }
+ PssPackage->BMLatency = PSTATE_BM_LATENCY;
+ PssPackage++;
+ }
+ }
+ }
+ ASSERT (ScopePackageLengthPtr != NULL);
+ if (ScopePackageLengthPtr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ///
+ /// Update the Package length in AML package length format
+ ///
+ CurrPtr = (UINT8 *) ScopePackageLengthPtr;
+ NewPackageLength = Temp = (UINT16) (EndOfTable - CurrPtr);
+ *ScopePackageLengthPtr = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00);
+ mCpu0IstTable->Length = (UINT32) (EndOfTable - (UINT8 *) mCpu0IstTable);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Completes processor power management initialization
+ (1) Initializes the TSC update variables.
+ (2) Initializes the GV state for processors.
+ (3) Adds a callback (SMI) in S3 resume script to restore the MSR
+ (4) Registers callback (SMI) for late PPM Initialization
+**/
+VOID
+PpmPostInit (
+ VOID
+ )
+{
+ UINT8 Data8;
+
+ ///
+ /// Set Boot P-state based on Policy.
+ ///
+ SetBootPState ();
+ ///
+ /// Save the SW SMI number to trigger SMI to restore the MSRs when resuming from S3
+ ///
+ Data8 = mCpuPmConfig->S3RestoreMsrSwSmiNumber;
+ SCRIPT_IO_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (R_PCH_APM_CNT),
+ 1,
+ &Data8
+ );
+ ///
+ /// Lock down all settings
+ ///
+ PpmLockDown (mCpuPmConfig);
+} \ No newline at end of file
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c
new file mode 100644
index 0000000..9c0c19e
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c
@@ -0,0 +1,1302 @@
+/** @file
+ This file contains power management configuration functions for
+ Haswell processors.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM - Thermal Monitor
+ IST - Intel(R) Speedstep technology
+ HT - Hyper-Threading Technology
+
+@copyright
+ Copyright (c) 2012 - 2014 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 "PowerMgmtCommon.h"
+
+PPM_CTDP_OVERRIDE_TABLE mHswUltPpmCtdpOverideTable[]={
+/// TDP Icc MSR PL1 MSR PL2 TdpUp TdpUp TdpNominal TdpNominal TdpDown TdpDown
+/// Max PL1 PL2 PL1 PL2 PL1 PL2
+ { 5700, 0, 6700, 8375, 0, 8375, 0, 8375, 0, 8375 }, /// 57W Sku Overrides
+ { 1500, 0, 2500, 2500, 0, 2500, 0, 2500, 0, 2500 }, /// 15W Sku Overrides
+ { 1150, 0, 0, 2500, 0, 2500, 0, 2500, 0, 2500 }, /// 11.5W Sku Overrides
+ { 2800, 40, 0, 3500, 0, 3500, 0, 3500, 0, 3500 } /// 28W 40A Sku Overrides
+};
+
+PPM_CTRL_TDP_SKU_TBL mHswCtrlTdpSkuTable[] = {
+ {"Celeron",03,{"2955U","2957U","2005U"}}
+};
+
+/**
+ Configurable TDP BIOS Initialization
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+ @param[in] FvidPointer Pointer to Fvid Table
+
+ @exception EFI_UNSUPPORTED Ctdp not Supported
+ @retval EFI_SUCCESS Ctdp Initiation done
+**/
+EFI_STATUS
+InitializeConfigurableTdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS CustomCtdpSettings;
+ UINTN Index;
+
+
+ if (mPpmGlobalNvsAreaProtocol == NULL) {
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Require mPpmGlobalNvsAreaProtocol.\n"));
+ return EFI_UNSUPPORTED;
+ }
+ ///
+ /// Intialize PPM Global NVS with custom CTDP level settings or CPU provided.
+ ///
+ CustomCtdpSettings = InitCustomConfigurableTdp (CpuPmConfig);
+ if (CustomCtdpSettings != EFI_SUCCESS) {
+ Status = InitConfigurableTdpSettings (CpuPmConfig);
+ if (Status != EFI_SUCCESS) {
+ ///
+ /// Check for Controllable TDP enable if Ctdp not supported
+ ///
+ InitControllableTdp(CpuPmConfig);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ ///
+ /// In case of LFM == TDP Down Ratio/Tdp Nominal , consider TDP Down TAR as the new LFM to insert fake P state.
+ ///
+ for (Index = 0; Index < (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported); Index++) {
+ if (mMinBusRatio == mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar+1) {
+ mMinBusRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar;
+ DEBUG ((EFI_D_INFO, "PPM:: mMinBusRatio Modified for Ctdp %d\n", mMinBusRatio));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Custom Configurable TDP Table BIOS Initialization
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+
+ @exception EFI_UNSUPPORTED Custom Ctdp settings are not available
+ @retval EFI_SUCCESS Successfully Initialized Custom Ctdp Settings
+**/
+EFI_STATUS
+InitCustomConfigurableTdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ UINT8 Index;
+
+ if (!CpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom) {
+ return EFI_UNSUPPORTED;
+ }
+ ///
+ /// CTC value should not be more Custom configured levels.
+ ///
+ if (CpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex > CpuPmConfig->pCustomCtdpSettings->CustomTdpCount - 1) {
+ CpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex = 0;
+ }
+ if (mPpmGlobalNvsAreaProtocol != NULL) {
+ ///
+ /// Update Custom ConfigTdp table for ACPI
+ ///
+ if (CpuPmConfig->pCustomCtdpSettings->CustomTdpCount != 0) {
+ mPpmGlobalNvsAreaProtocol->Area->CustomConfigTdp = PPM_ENABLE;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported = CpuPmConfig->pCustomCtdpSettings->CustomTdpCount;
+ mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex = CpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex;
+ for (Index = 0; Index < (CpuPmConfig->pCustomCtdpSettings->CustomTdpCount); Index++) {
+ ///
+ /// Verify and fix Custom configured CTDP Levels PL1 and PL2
+ ///
+ CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1 = VerifyAndFixCustomPowerLimit (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1,mCustomPowerUnit);
+ CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2 = VerifyAndFixCustomPowerLimit (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2,mCustomPowerUnit);
+ CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio = VerifyAndFixCustomRatio (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio+1)-1;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1 = (UINT16) CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2 = (UINT16) CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimitWindow = CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1Time;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar = CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpCtc = CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomConfigTdpControl;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verify and fix Custom Power Limit values
+
+ @param[in] CustomPowerLimit Custom Power Limit value
+ @param[in] CustomPlUnit Custom Power Limit Unit
+**/
+UINT16
+VerifyAndFixCustomPowerLimit (
+ IN UINT32 CustomPowerLimit,
+ IN UINT16 CustomPlUnit
+ )
+{
+ UINT16 ConvertedPowerLimit;
+ UINT16 CpuConvertedPowerLimitMaxLimit;
+
+ ConvertedPowerLimit = (UINT16) ((CustomPowerLimit * mProcessorPowerUnit) / CustomPlUnit);
+ if (mPackageMaxPower == 0 && ConvertedPowerLimit >= mPackageMinPower) {
+ ///
+ /// If PACKAGE_POWER_SKU_MSR [46:32] = 0 means there is no upper limit ( since this field is 15 bits, the max value is 2^15 - 1 )
+ ///
+ CpuConvertedPowerLimitMaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
+ if (ConvertedPowerLimit > CpuConvertedPowerLimitMaxLimit) {
+ ///
+ /// If new Power Limit 1 is > CpuConvertedPowerLimit1MaxLimit, program Power Limit 1 to CpuConvertedPowerLimit1MaxLimit
+ ///
+ ConvertedPowerLimit = CpuConvertedPowerLimitMaxLimit;
+ }
+ } else if (mPackageMinPower == 0 && ConvertedPowerLimit > 0 && ConvertedPowerLimit <= mPackageMaxPower) {
+ ///
+ /// If PACKAGE_POWER_SKU_MSR [30:16] = 0 means there is no lower limit
+ ///
+ ConvertedPowerLimit = (UINT16) ((CustomPowerLimit * mProcessorPowerUnit) / CustomPlUnit);
+ } else {
+ ///
+ /// Power Limit 1 needs to be between mPackageMinPower and mPackageMaxPower
+ ///
+ CpuConvertedPowerLimitMaxLimit = mPackageMaxPower;
+ if (ConvertedPowerLimit < mPackageMinPower) {
+ ///
+ /// If new Power Limit 1 is < mPackageMinPower, program Power Limit 1 to mPackageMinPower
+ ///
+ ConvertedPowerLimit = mPackageMinPower;
+ } else if (ConvertedPowerLimit > CpuConvertedPowerLimitMaxLimit) {
+ ///
+ /// If new Power Limit 1 is > mPackageMaxPower, program Power Limit 1 to mPackageMaxPower
+ ///
+ ConvertedPowerLimit = CpuConvertedPowerLimitMaxLimit;
+ }
+ }
+
+ return ConvertedPowerLimit;
+}
+
+/**
+ Verify and fix Custom Ratio values
+ Custom Ratio should be between MaxTurboFrequency and LFM
+
+ @param[in] CustomRatio Custom Ratio value
+**/
+UINT8
+VerifyAndFixCustomRatio (
+ IN UINT8 CustomRatio
+ )
+{
+ if (CustomRatio > mTurboBusRatio) {
+ ///
+ /// Use HFM as max value if Turbo is not supported
+ ///
+ if (mTurboBusRatio == 0) {
+ CustomRatio = (UINT8) mMaxBusRatio;
+ } else {
+ CustomRatio = (UINT8) mTurboBusRatio;
+ }
+ } else if (CustomRatio < mMinBusRatio) {
+ ///
+ /// Use LFM as min value
+ ///
+ CustomRatio = (UINT8) mMinBusRatio;
+ }
+
+ return CustomRatio;
+}
+
+/**
+ CTDP BIOS settings Initialization(From Msrs)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+
+ @exception EFI_UNSUPPORTED Ctdp not supported
+ @retval EFI_SUCCESS Ctdp Settings Initialized successfully from MSRs
+**/
+EFI_STATUS
+InitConfigurableTdpSettings (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER TempMsr;
+ UINTN Index;
+ UINT16 CpuConfigTdpNominalTdp;
+ UINT16 CpuConfigTdpLevel1Tdp;
+ UINT16 CpuConfigTdpLevel2Tdp;
+ UINT8 CpuConfigTdpNominalRatio;
+ UINT8 CpuConfigTdpLevel1Ratio;
+ UINT8 CpuConfigTdpLevel2Ratio;
+ UINT16 CpuConfigTdpLevels;
+
+ ///
+ /// Get the number of configurable TDP Levels supported
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO);
+ TempMsr.Qword &= V_CONFIG_TDP_NUM_LEVELS_MASK;
+ CpuConfigTdpLevels = (UINT8) RShiftU64 (TempMsr.Qword, N_MSR_PLATFORM_INFO_CONFIG_TDP_NUM_LEVELS_OFFSET);
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Supported Levels=%d\n", CpuConfigTdpLevels));
+ ///
+ /// Return if ConfigTDP Levels not supported
+ ///
+ if (CpuConfigTdpLevels == 0) {
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Levels not supported\n"));
+ return EFI_UNSUPPORTED;
+ }
+ mPpmGlobalNvsAreaProtocol->Area->CustomConfigTdp = PPM_DISABLE;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported = (UINT8) CpuConfigTdpLevels + 1;
+ mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex = CpuPmConfig->pTurboSettings->ConfigTdpLevel;
+ ///
+ /// Get PKG_TDP for Config TDP Nominal
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_NOMINAL);
+ CpuConfigTdpNominalRatio = (UINT8) (TempMsr.Dwords.Low & CONFIG_TDP_NOMINAL_RATIO_MASK);
+ CpuConfigTdpNominalTdp = mPackageTdp;
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Nominal Ratio=%d Tdp=%d\n", CpuConfigTdpNominalRatio, CpuConfigTdpNominalTdp));
+ ///
+ /// Set Level0 as Tdp Nominal
+ ///
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1 = mPackageTdp;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2 = GetCtdpPowerLimit2 (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1);
+ if (IS_SA_DEVICE_ID_MOBILE(mProcessorFlavor)) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow = MB_POWER_LIMIT1_TIME_DEFAULT;
+ } else {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow = DT_POWER_LIMIT1_TIME_DEFAULT;
+ }
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpTar = (UINT8) (CpuConfigTdpNominalRatio - 1);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpCtc = CONFIG_TDP_NOMINAL;
+ ///
+ /// Get PKG_TDP and Ratio for Config TDP Level1
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_LVL1);
+ CpuConfigTdpLevel1Ratio = (UINT8) RShiftU64 (
+ TempMsr.Qword & CONFIG_TDP_LVL1_RATIO_MASK,
+ CONFIG_TDP_LVL1_RATIO_OFFSET
+ );
+ CpuConfigTdpLevel1Tdp = (UINT16) (TempMsr.Dwords.Low & CONFIG_TDP_LVL1_PKG_TDP_MASK);
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Level1 Ratio=%d Tdp=%d\n", CpuConfigTdpLevel1Ratio, CpuConfigTdpLevel1Tdp));
+ ///
+ /// Set Level 1
+ ///
+ Index = 1;
+ if (CpuConfigTdpLevel1Ratio != 0) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1 = CpuConfigTdpLevel1Tdp;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2 = GetCtdpPowerLimit2 (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimitWindow = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar = (UINT8) (CpuConfigTdpLevel1Ratio - 1);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpCtc = CONFIG_TDP_LEVEL1;
+ Index++;
+ }
+ ///
+ /// If two levels are supported or Level1 was not valid
+ /// then read Level2 registers
+ ///
+ if (CpuConfigTdpLevels == CONFIG_TDP_LEVEL2 || CpuConfigTdpLevel1Ratio == 0) {
+ ///
+ /// Get PKG_TDP and Ratio for Config TDP Level2
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_LVL2);
+ CpuConfigTdpLevel2Ratio = (UINT8) RShiftU64 (
+ TempMsr.Qword & CONFIG_TDP_LVL2_RATIO_MASK,
+ CONFIG_TDP_LVL2_RATIO_OFFSET
+ );
+ CpuConfigTdpLevel2Tdp = (UINT16) (TempMsr.Dwords.Low & CONFIG_TDP_LVL2_PKG_TDP_MASK);
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP Level2 Ratio=%d Tdp=%d\n", CpuConfigTdpLevel2Ratio, CpuConfigTdpLevel2Tdp));
+ ///
+ /// Set Level2
+ ///
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1 = CpuConfigTdpLevel2Tdp;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2 = GetCtdpPowerLimit2 (mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimitWindow = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar = (UINT8) (CpuConfigTdpLevel2Ratio - 1);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpCtc = CONFIG_TDP_LEVEL2;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Power Limit2 based on Power Limit1 on Config TDP
+
+ @param[in] PowerLimit1 Power Limit 1 Value
+
+ @retval Calculated Power Limit2 value
+**/
+UINT16
+GetCtdpPowerLimit2 (
+ IN UINT16 PowerLimit1
+ )
+{
+ UINT16 ConvertedPowerLimit2;
+ UINT16 Mutliplier;
+
+ ///
+ /// By default,for Mobile & Desktop Processors: Short duration Power Limit = 1.25 * Package TDP
+ ///
+ Mutliplier = 125;
+ ///
+ /// For XE/non-ULV skus Configure PL2 as (1.25 x cTDP).
+ ///
+ ConvertedPowerLimit2 = EFI_IDIV_ROUND ((Mutliplier * PowerLimit1), 100);
+
+ return ConvertedPowerLimit2;
+}
+
+/**
+ Patch Fvid Table with Ctdp Tar ratio and Tar-1 Ratio
+
+ @param[in] FvidPointer Pointer to Fvid Table
+**/
+VOID
+CtdpPatchFvidTable (
+ IN OUT FVID_TABLE *FvidPointer
+ )
+{
+ UINTN PssIndex;
+ UINTN Index;
+ UINTN TempRatio;
+ UINT8 Turbo;
+
+ ///
+ /// Check P0 is Turbo Ratio or HFM
+ ///
+ Turbo = ((mPpmGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) ? 1 : 0);
+
+ ///
+ /// Check and patch Fvid table for TAR ratios
+ ///
+ for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) {
+ TempRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar;
+ for (PssIndex = (Turbo + 2); PssIndex < FvidPointer[0].FvidHeader.Gv3States; PssIndex++) {
+ if (FvidPointer[PssIndex].FvidState.BusRatio < TempRatio) {
+ if (FvidPointer[PssIndex - 1].FvidState.BusRatio != TempRatio) {
+ ///
+ /// If Tar not Found ,Replace Turbo Active ratio at PssIndex-1
+ /// P0 - Turbo ratio P1- HFM ,exclude these two ratios
+ ///
+ if (PssIndex == (Turbo + 2)) {
+ CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio);
+ DEBUG ((EFI_D_INFO, " TAR Ratio Replace at %x with %x \n", PssIndex, TempRatio));
+ } else {
+ CtdpReplaceFvidRatio (FvidPointer, PssIndex - 1, TempRatio);
+ DEBUG ((EFI_D_INFO, " TAR Ratio Replace at %x with %x \n", PssIndex-1, TempRatio));
+
+ }
+ }
+ break;
+ }
+ }
+ }
+ ///
+ /// Check and patch Fvid table for CTDP ratios.
+ /// This is done separately to make sure Ctdp ratios are not override by Tar ratios
+ /// when ctdp ratios are adjacent
+ ///
+ for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) {
+ TempRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpTar + 1;
+ for (PssIndex = (Turbo + 1); PssIndex < FvidPointer[0].FvidHeader.Gv3States; PssIndex++) {
+
+ if (FvidPointer[PssIndex].FvidState.BusRatio == TempRatio) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex].FvidState.State;
+ }
+
+ if (FvidPointer[PssIndex].FvidState.BusRatio < TempRatio) {
+ if (FvidPointer[PssIndex - 1].FvidState.BusRatio == TempRatio) {
+ ///
+ /// Found Turbo Active ratio at PssIndex-1
+ ///
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex - 1].FvidState.State;
+ break;
+ } else {
+ ///
+ /// If Tar not Found, Replace Turbo Active ratio at PssIndex-1
+ ///
+ if(PssIndex == (Turbo + 1)) {
+ CtdpReplaceFvidRatio (FvidPointer, PssIndex, TempRatio);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex].FvidState.State;
+ DEBUG ((EFI_D_INFO, " CTDP Ratio Replace at %x with %x \n", PssIndex, TempRatio));
+ } else {
+ CtdpReplaceFvidRatio (FvidPointer, PssIndex - 1, TempRatio);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPpc = (UINT8) FvidPointer[PssIndex - 1].FvidState.State;
+ DEBUG ((EFI_D_INFO, " CTDP Ratio Replace at %x with %x \n", PssIndex-1, TempRatio));
+
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ Replace P state with given ratio
+
+ @param[in] FvidPointer Pointer to Fvid Table
+ @param[in] PssIndex FVID table index of P state to be replaced
+ @param[in] Ratio Target Ratio to put in
+**/
+VOID
+CtdpReplaceFvidRatio (
+ IN OUT FVID_TABLE *FvidPointer,
+ UINTN PssIndex,
+ UINTN Ratio
+ )
+{
+ UINT64 wPower1;
+ UINT64 wPower2;
+
+ FvidPointer[PssIndex].FvidState.BusRatio = (UINT16) Ratio; ///< Replace Ratio
+ ///
+ /// Relative Power calculation per HSW BWG
+ ///
+ wPower1 = (mMaxBusRatio - FvidPointer[PssIndex].FvidState.BusRatio) * 625;
+ wPower1 = (110000 - wPower1);
+ wPower1 = DivU64x32 (wPower1, 11);
+ wPower1 = MultU64x64 (wPower1, wPower1);
+ //
+ // Power is calculated in milliwatts
+ //
+ wPower2 = (((FvidPointer[PssIndex].FvidState.BusRatio * 100) / mMaxBusRatio));
+ wPower2 = DivU64x32 (MultU64x32 (MultU64x64 (wPower2, wPower1), mPackageTdpWatt), 10000000);
+ FvidPointer[PssIndex].FvidState.Power = (UINT32) wPower2;
+}
+
+/**
+ Configures following fields of MSR 0x610 based on user configuration:
+ Configures Long duration Turbo Mode (power limit 1) power level and time window
+ Configures Short duration turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigurePowerLimitsNonConfigTdpSkus (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER PakagePowerLimitMsr;
+ UINT16 ConvertedPowerLimit1;
+ UINT8 ConvertedPowerLimit1Time;
+ UINT16 ConvertedShortDurationPowerLimit;
+ UINT16 CpuConvertedPowerLimit1MaxLimit;
+ UINT16 CpuConvertedPowerLimit2MaxLimit;
+ UINT16 Multiplier;
+
+ CpuConvertedPowerLimit1MaxLimit = 0;
+ CpuConvertedPowerLimit2MaxLimit = 0;
+ ConvertedPowerLimit1Time = 0;
+ ///
+ /// By default, for Mobile & Desktop Processors: Short duration Power Limit = 1.25 * Package TDP
+ ///
+ Multiplier = 125;
+ ///
+ /// Check if TDP limits are programmable
+ /// - Platform Info MSR (0xCE) [29]
+ ///
+ if (mTdpLimitProgrammble) {
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ ///
+ /// Initialize the Power Limit 1 and Power Limit 1 enable bit
+ /// - Power Limit 1: Turbo Power Limit MSR [14:0]
+ /// - Power Limit 1 Enable: Turbo Power Limit MSR [15]
+ ///
+ ///
+ /// By default, program Power Limit 1 to Package TDP limit
+ ///
+ ConvertedPowerLimit1 = mPackageTdp;
+ if (CpuPmConfig->pTurboSettings->PowerLimit1 != AUTO) {
+ ///
+ /// CpuPmConfig->pTurboSettings->PowerLimit1 is in mW or watts. We need to convert it to
+ /// CPU Power unit, specified in PACKAGE_POWER_SKU_UNIT_MSR[3:0].
+ /// Since we are converting from Watts to CPU power units, multiply by
+ /// PACKAGE_POWER_SKU_UNIT_MSR[3:0].
+ /// Refer to BWG 14.13.7 for Power Limit 1 limits.
+ ///
+ ConvertedPowerLimit1 = (UINT16) ((CpuPmConfig->pTurboSettings->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit);
+ if (mPackageMaxPower == 0 && ConvertedPowerLimit1 >= mPackageMinPower) {
+ ///
+ /// If PACKAGE_POWER_SKU_MSR [46:32] = 0 means there is no upper limit ( since this field is 15 bits, the max value is 2^15 - 1 )
+ ///
+ CpuConvertedPowerLimit1MaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
+ if (ConvertedPowerLimit1 > CpuConvertedPowerLimit1MaxLimit) {
+ ///
+ /// If new Power Limit 1 is > CpuConvertedPowerLimit1MaxLimit, program Power Limit 1 to CpuConvertedPowerLimit1MaxLimit
+ ///
+ ConvertedPowerLimit1 = CpuConvertedPowerLimit1MaxLimit;
+ }
+ } else if (mPackageMinPower == 0 && ConvertedPowerLimit1 > 0 && ConvertedPowerLimit1 <= mPackageMaxPower) {
+ ///
+ /// If PACKAGE_POWER_SKU_MSR [30:16] = 0 means there is no lower limit
+ ///
+ ConvertedPowerLimit1 = (UINT16) ((CpuPmConfig->pTurboSettings->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit);
+
+ } else {
+ ///
+ /// Power Limit 1 needs to be between mPackageMinPower and mPackageMaxPower
+ ///
+ CpuConvertedPowerLimit1MaxLimit = mPackageMaxPower;
+
+ if (ConvertedPowerLimit1 < mPackageMinPower) {
+ ///
+ /// If new Power Limit 1 is < mPackageMinPower, program Power Limit 1 to mPackageMinPower
+ ///
+ ConvertedPowerLimit1 = mPackageMinPower;
+ } else if (ConvertedPowerLimit1 > CpuConvertedPowerLimit1MaxLimit) {
+ ///
+ /// If new Power Limit 1 is > mPackageMaxPower, program Power Limit 1 to mPackageMaxPower
+ ///
+ ConvertedPowerLimit1 = CpuConvertedPowerLimit1MaxLimit;
+ }
+ }
+ }
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.Low |= (UINT32) (ConvertedPowerLimit1);
+ DEBUG (
+ (EFI_D_INFO,
+ "New Power Limit 1 %d watt (%d in CPU power unit)\n",
+ CpuPmConfig->pTurboSettings->PowerLimit1,
+ ConvertedPowerLimit1)
+ );
+ ///
+ /// Force Power Limit 1 override to be enabled
+ ///
+ PakagePowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE;
+ ///
+ /// Program Power Limit 1 (Long Duration Turbo) Time Window
+ /// If PowerLimit1Time is AUTO OR If PowerLimit1Time is > MAX_POWER_LIMIT_1_TIME_IN_SECONDS
+ /// program default values
+ ///
+ if ((CpuPmConfig->pTurboSettings->PowerLimit1Time == AUTO) ||
+ (CpuPmConfig->pTurboSettings->PowerLimit1Time > MAX_POWER_LIMIT_1_TIME_IN_SECONDS)
+ ) {
+ if (IS_SA_DEVICE_ID_MOBILE(mProcessorFlavor)) {
+ ///
+ /// For Mobile, default value is 28 seconds
+ ///
+ CpuPmConfig->pTurboSettings->PowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT;
+ } else {
+ ///
+ /// For Desktop, default value is 1 second
+ ///
+ CpuPmConfig->pTurboSettings->PowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT;
+ }
+ }
+ ConvertedPowerLimit1Time = GetConvertedTime (CpuPmConfig->pTurboSettings->PowerLimit1Time, PL12TimeWindowCovert);
+ ///
+ /// Configure Power Limit 1 (Long Duration Turbo) time windows: Turbo Power Limit MSR [23:17]
+ ///
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_1_TIME_MASK;
+ PakagePowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (ConvertedPowerLimit1Time, 17);
+ ///
+ /// Initialize Short Duration Power limit and enable bit
+ /// Short duration Power Limit: Turbo Power Limit MSR (0x450h) [46:32]
+ /// Short duration Power Limit Enable:Turbo Power Limit MSR (0x450h) [47]
+ ///
+ /// CpuPmConfig->pTurboSettings->PowerLimit2 value is in mW or watts. We need to convert it to
+ /// CPU Power unit, specified in PACKAGE_POWER_SKU_UNIT_MSR[3:0].
+ /// Since we are converting from Watts to CPU power units, multiply by
+ /// PACKAGE_POWER_SKU_UNIT_MSR[3:0]
+ ///
+ ConvertedShortDurationPowerLimit = (UINT16) ((CpuPmConfig->pTurboSettings->PowerLimit2 * mProcessorPowerUnit) / mCustomPowerUnit);
+ PakagePowerLimitMsr.Dwords.High &= ~(POWER_LIMIT_MASK | B_POWER_LIMIT_ENABLE);
+ ///
+ /// If PowerLimit2 is AUTO OR if PowerLimit2 is > mPackageMaxPower OR if PowerLimit2 < mPackageMinPower
+ /// program defaul values.
+ ///
+ CpuConvertedPowerLimit2MaxLimit = mPackageMaxPower;
+ if (CpuConvertedPowerLimit2MaxLimit == 0) {
+ CpuConvertedPowerLimit2MaxLimit = (UINT16) (LShiftU64 (2, 15) - 1);
+ }
+ if (CpuPmConfig->pTurboSettings->PowerLimit2 == AUTO) {
+ ConvertedShortDurationPowerLimit = EFI_IDIV_ROUND ((Multiplier * mPackageTdp), 100);
+
+ }
+ if (ConvertedShortDurationPowerLimit > CpuConvertedPowerLimit2MaxLimit) {
+ ConvertedShortDurationPowerLimit = CpuConvertedPowerLimit2MaxLimit;
+ }
+ if (ConvertedShortDurationPowerLimit < mPackageMinPower) {
+ ConvertedShortDurationPowerLimit = mPackageMinPower;
+ }
+ PakagePowerLimitMsr.Dwords.High |= (UINT32) (ConvertedShortDurationPowerLimit);
+
+ if (CpuPmConfig->pFunctionEnables->PowerLimit2 == PPM_ENABLE) {
+ PakagePowerLimitMsr.Dwords.High |= B_POWER_LIMIT_ENABLE;
+ } else {
+ PakagePowerLimitMsr.Dwords.High &= (~B_POWER_LIMIT_ENABLE);
+ }
+
+ DEBUG (
+ (EFI_D_INFO,
+ "Short duration Power limit enabled, Power Limit = %d Watts\n",
+ CpuPmConfig->pTurboSettings->PowerLimit2)
+ );
+
+ DEBUG ((EFI_D_INFO,"MSR(610h)=%08X%08X\n",PakagePowerLimitMsr.Dwords.High,PakagePowerLimitMsr.Dwords.Low));
+
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+ }
+
+ ///
+ /// Enable Power Clamp when Controllable TDP is enabled.
+ ///
+ if (mControllableTdpEnable) {
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ PakagePowerLimitMsr.Dwords.Low |= B_CRITICAL_POWER_CLAMP_ENABLE;
+ DEBUG ((EFI_D_INFO, "Critical Power Clamp1 enabled : %x\n",PakagePowerLimitMsr.Qword));
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+ }
+
+ ///
+ ///BIOS to override 41W PL1 for 47W 2C parts (Cahce Size = 3MB)
+ ///
+ if((CpuPmConfig->pTurboSettings->PowerLimit1 == AUTO) && (mPackageTdp == 47) && (mCpuCacheSize == 3 * 1024)) {
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.Low |= (UINT32) ((41 * mProcessorPowerUnit) & POWER_LIMIT_MASK);
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+ }
+ ///
+ /// PL1 and PL2 BIOS Overrides for 57W Non CTDP SKU
+ ///
+ if((CpuPmConfig->pTurboSettings->PowerLimit1 == AUTO) &&
+ (CpuPmConfig->pTurboSettings->PowerLimit2 == AUTO) &&
+ (mPackageTdp == 57 * mProcessorPowerUnit)) {
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ ///
+ /// PL1=67W
+ ///
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.Low |= (UINT32) ((67 * mProcessorPowerUnit) & POWER_LIMIT_MASK);
+ ///
+ /// PL2=83.75W
+ ///
+ PakagePowerLimitMsr.Dwords.High &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.High |= (UINT32) (((8375 * mProcessorPowerUnit) / 100) & POWER_LIMIT_MASK);
+
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+ }
+ //
+ // End if ((PlatformInfoMsr.Dwords.Low & B_EFI_PLATFORM_INFO_TDC_TDP_LIMIT))
+ //
+ ///
+ /// Pass the power limits of the non-CTDP part to the Global NVS Area for use by DPTF
+ ///
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1 = (UINT16) (PakagePowerLimitMsr.Dwords.Low & POWER_LIMIT_MASK);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2 = (UINT16) (PakagePowerLimitMsr.Dwords.High & POWER_LIMIT_MASK);
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimitWindow = (UINT8) CpuPmConfig->pTurboSettings->PowerLimit1Time;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpTar = (UINT8) mTurboBusRatio;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpCtc = 1;
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported = 1;
+ mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex = 0;
+}
+
+/**
+ Configures following fields of MSR 0x615
+ Configures power limit 3 power level and time window
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigurePL3PowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER PlatformPowerLimitMsr;
+ UINT16 ConvertedPowerLimit3;
+ UINT8 ConvertedPowerLimit3Time;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ CpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING;
+
+ ///
+ /// PL3 is supported on HSW ULT C0 & HSW C0 and later
+ ///
+ if(((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0))
+ || ((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId >= EnumHswUltC0))) {
+ ///
+ /// Return if No user overrides selected.
+ ///
+ if((CpuPmConfig->pTurboSettings->PowerLimit3 == AUTO)
+ && (CpuPmConfig->pTurboSettings->PowerLimit3Time == AUTO)
+ && (CpuPmConfig->pTurboSettings->PowerLimit3DutyCycle == AUTO)){
+ return;
+ }
+
+ PlatformPowerLimitMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_POWER_LIMIT);
+ DEBUG ((EFI_D_INFO," PL3 MSR 615 Before Writing %x ",PlatformPowerLimitMsr.Dwords.Low));
+ ///
+ /// Configure PL3 Power Limit if custom value is avaiable
+ ///
+ if (CpuPmConfig->pTurboSettings->PowerLimit3 != AUTO) {
+ ConvertedPowerLimit3 = (UINT16) ((CpuPmConfig->pTurboSettings->PowerLimit3 * mProcessorPowerUnit) / mCustomPowerUnit);
+ PlatformPowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ PlatformPowerLimitMsr.Dwords.Low |= (UINT32) (ConvertedPowerLimit3);
+ PlatformPowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE;
+ }
+
+ ///
+ /// Configure PL3 Time window if custom value is avaiable
+ ///
+ if (CpuPmConfig->pTurboSettings->PowerLimit3Time != AUTO) {
+ ConvertedPowerLimit3Time = GetConvertedTime (CpuPmConfig->pTurboSettings->PowerLimit3Time, PL3TimeWindowConvert);
+ PlatformPowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_3_TIME_MASK;
+ PlatformPowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (ConvertedPowerLimit3Time, 17);
+ PlatformPowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE;
+ }
+
+ ///
+ /// Configure PL3 Duty Cycle if custom value is avaiable
+ ///
+ if (CpuPmConfig->pTurboSettings->PowerLimit3DutyCycle != AUTO) {
+ PlatformPowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_3_DUTY_CYCLE_MASK;
+ PlatformPowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (CpuPmConfig->pTurboSettings->PowerLimit3DutyCycle, 24);
+ PlatformPowerLimitMsr.Dwords.Low |= B_POWER_LIMIT_ENABLE;
+ }
+ //
+ // Enable/Disable PL3 lock
+ //
+ if (CpuPmConfig->pTurboSettings->PowerLimit3Lock == PPM_ENABLE) {
+ PlatformPowerLimitMsr.Dwords.Low |= (UINT32) B_POWER_LIMIT_LOCK;
+ }else {
+ PlatformPowerLimitMsr.Dwords.Low &= (~((UINT32) B_POWER_LIMIT_LOCK));
+ }
+
+ AsmWriteMsr64 (MSR_PLATFORM_POWER_LIMIT, PlatformPowerLimitMsr.Qword);
+ DEBUG ((EFI_D_INFO," PL3 MSR 615 After Writing %x ",PlatformPowerLimitMsr.Dwords.Low));
+ } // End if Processor Check
+}
+
+/**
+ Configures following fields of MSR 0x610
+ Configures Long duration Turbo Mode (power limit 1) power level and time window
+ Configures Short duration turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigureCtdpPowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER PakagePowerLimitMsr;
+ UINT16 ConvertedPowerLimit1;
+ UINT16 ConvertedPowerLimit2;
+ UINT8 ConvertedPowerLimit1Time;
+ UINT16 Mutliplier;
+ UINTN Index;
+ CPU_FAMILY mCpuFamilyId;
+
+ mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ ConvertedPowerLimit1Time = 0;
+ ///
+ /// By default, for Mobile & Desktop Processors: Short duration Power Limit = 1.25 * Package TDP
+ ///
+ Mutliplier = 125;
+ //
+ // For ConfigTdp enabled skus
+ //
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.High &= ~POWER_LIMIT_MASK;
+ ///
+ /// Initialize the Power Limit 1/2 and Power Limit 2 enable bit in MSR
+ /// Power Limit 1: Turbo Power Limit MSR [14:0] and Power Limit 2: Turbo Power Limit MSR [46:32]
+ /// Set MSR value for Power Limit 1/2 to Max Package Power Value or Maximum Supported Value
+ ///
+ ///
+ if (mPackageMaxPower) {
+ ConvertedPowerLimit1 = mPackageMaxPower;
+ ///
+ /// Short duration Power Limit (PL2) = 1.25 * PL1
+ ///
+ ConvertedPowerLimit2 = EFI_IDIV_ROUND ((Mutliplier * ConvertedPowerLimit1), 100);
+ if (ConvertedPowerLimit2 > PACKAGE_TDP_POWER_MASK) {
+ ConvertedPowerLimit2 = PACKAGE_TDP_POWER_MASK;
+ }
+ } else {
+ ///
+ /// Set Maximum value for Turbo Power Limit MSR [14:0] and [46:32] =
+ /// Max of CTDP Level Power Limts
+ ///
+ ConvertedPowerLimit1 = 0;
+ for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) {
+ if (ConvertedPowerLimit1 < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1) {
+ ConvertedPowerLimit1 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit1;
+ }
+ }
+ ConvertedPowerLimit2 = 0;
+ for (Index = 0; Index < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported; Index++) {
+ if (ConvertedPowerLimit2 < mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2) {
+ ConvertedPowerLimit2 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[Index].CtdpPowerLimit2;
+ }
+ }
+ }
+ ///
+ /// Program Power Limit 1 (Long Duration Turbo) Time Window
+ /// If PowerLimit1Time is AUTO OR If PowerLimit1Time is > MAX_POWER_LIMIT_1_TIME_IN_SECONDS
+ /// program default values
+ ///
+ if (CpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom == PPM_ENABLE) {
+ ConvertedPowerLimit1Time = GetConvertedTime (CpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[0].CustomPowerLimit1Time, PL12TimeWindowCovert);
+ } else {
+ if (IS_SA_DEVICE_ID_MOBILE(mProcessorFlavor)) {
+ ///
+ /// For Mobile, default value is 28 seconds
+ ///
+ CpuPmConfig->pTurboSettings->PowerLimit1Time = MB_POWER_LIMIT1_TIME_DEFAULT;
+ } else {
+ ///
+ /// For Desktop, default value is 1 second
+ ///
+ CpuPmConfig->pTurboSettings->PowerLimit1Time = DT_POWER_LIMIT1_TIME_DEFAULT;
+ }
+ ConvertedPowerLimit1Time = GetConvertedTime (CpuPmConfig->pTurboSettings->PowerLimit1Time, PL12TimeWindowCovert);
+ }
+ ///
+ /// Configure Power Limit 1 (Long Duration Turbo) time windows: Turbo Power Limit MSR [23:17]
+ ///
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_1_TIME_MASK;
+ PakagePowerLimitMsr.Dwords.Low |= (UINT32) LShiftU64 (ConvertedPowerLimit1Time, 17);
+ PakagePowerLimitMsr.Dwords.High |= B_POWER_LIMIT_ENABLE;
+ PakagePowerLimitMsr.Dwords.Low |= (UINT32) (ConvertedPowerLimit1);
+ PakagePowerLimitMsr.Dwords.High |= (UINT32) (ConvertedPowerLimit2);
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+}
+
+/**
+ Configures BIOS overrides in MSR 0x610
+ Configures Long duration Turbo Mode (power limit 1) power level and time window
+ Configures Short duration turbo mode (power limit 2)
+
+ @param[in] None
+**/
+VOID
+ConfigureCtdpPowerLimitsOverrides (
+ ){
+ UINTN Index;
+ UINTN NoOfOverrides;
+ CPU_FAMILY mCpuFamilyId;
+ UINT32 LibStatus;
+ UINT32 IccMaxValue;
+ EFI_STATUS Status;
+ UINTN PackageTdp;
+ MSR_REGISTER PakagePowerLimitMsr;
+ PPM_CTDP_OVERRIDE_TABLE *PpmCtdpOverideTable;
+
+ mCpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+
+ if(mCpuFamilyId == EnumCpuHswUlt) {
+ PpmCtdpOverideTable = mHswUltPpmCtdpOverideTable;
+ NoOfOverrides = (sizeof(mHswUltPpmCtdpOverideTable))/(sizeof(PPM_CTDP_OVERRIDE_TABLE));
+ }else {
+ return;
+ }
+
+ PackageTdp = (mPackageTdpWatt * 100);
+ if((mPackageTdp % mProcessorPowerUnit) !=0) {
+ PackageTdp += ((mPackageTdp % mProcessorPowerUnit)* 100) / mProcessorPowerUnit ;
+ }
+
+ for(Index = 0; Index < NoOfOverrides;Index++,PpmCtdpOverideTable++) {
+ if(PpmCtdpOverideTable->SkuPackageTdp == PackageTdp) {
+
+ if(PpmCtdpOverideTable->SkuIccMax) {
+ ///
+ /// If SkuIccMax is not Zero check ICC Max for SKU detection.if No match go to next entry.
+ /// Read Icc Max from BIOS P code Mail box
+ ///
+ Status = MailboxRead(MAILBOX_TYPE_PCODE, READ_ICC_MAX_CMD, &IccMaxValue, &LibStatus);
+ IccMaxValue = IccMaxValue & 0x0FFF;
+ IccMaxValue = IccMaxValue /8;
+ if ((Status == EFI_SUCCESS) && (IccMaxValue != 0) && (IccMaxValue != PpmCtdpOverideTable->SkuIccMax)) {
+ continue;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "PPM:: Ctdp BIOS PL1/PL2 Override Ctdp SKU Found :%d override table index :%d\n",PpmCtdpOverideTable->SkuPackageTdp,Index));
+ ///
+ /// MSR Overrides
+ ///
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ if(PpmCtdpOverideTable->MsrCtdpPowerLimit1) {
+ PakagePowerLimitMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.Low |= ((PpmCtdpOverideTable->MsrCtdpPowerLimit1 * mProcessorPowerUnit)/100) & POWER_LIMIT_MASK;
+ }
+ if(PpmCtdpOverideTable->MsrCtdpPowerLimit2) {
+ PakagePowerLimitMsr.Dwords.High &= ~POWER_LIMIT_MASK;
+ PakagePowerLimitMsr.Dwords.High |=((PpmCtdpOverideTable->MsrCtdpPowerLimit2 * mProcessorPowerUnit)/100) & POWER_LIMIT_MASK;
+ }
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+
+ ///
+ /// MMIO Overrides
+ ///
+ if(PpmCtdpOverideTable->CtdpNominalPowerLimit1) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1 = (UINT16)(PpmCtdpOverideTable->CtdpNominalPowerLimit1 * mProcessorPowerUnit)/100;
+ }
+ if(PpmCtdpOverideTable->CtdpNominalPowerLimit2) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2 = (UINT16)(PpmCtdpOverideTable->CtdpNominalPowerLimit2 * mProcessorPowerUnit)/100;
+ }
+ if(PpmCtdpOverideTable->CtdpDownPowerLimit1) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[1].CtdpPowerLimit1 = (UINT16)(PpmCtdpOverideTable->CtdpDownPowerLimit1 * mProcessorPowerUnit)/100;
+ }
+ if(PpmCtdpOverideTable->CtdpDownPowerLimit2) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[1].CtdpPowerLimit2 = (UINT16)(PpmCtdpOverideTable->CtdpDownPowerLimit2 * mProcessorPowerUnit)/100;
+ }
+ if(PpmCtdpOverideTable->CtdpDownPowerLimit1) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[2].CtdpPowerLimit1 = (UINT16)(PpmCtdpOverideTable->CtdpUpPowerLimit1 * mProcessorPowerUnit)/100;
+ }
+ if(PpmCtdpOverideTable->CtdpUpPowerLimit2) {
+ mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[2].CtdpPowerLimit2 = (UINT16)(PpmCtdpOverideTable->CtdpUpPowerLimit2 * mProcessorPowerUnit)/100;
+ }
+ break;
+ }
+ }
+}
+
+/**
+ Configure cTDP BIOS MSRs to Boot Ctdp values
+ - Configures CONFIG_TDP_CONTROL MSR
+ - Configures TURBO_ACTIVATION_RATIO MSR
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+ @param[in] CpuConfigTdpBootLevel ConfigTdpBootLevel policy setting by user
+**/
+VOID
+SelectCtdpLevel (
+ IN POWER_MGMT_CONFIG *CpuPmConfig,
+ IN UINT8 CpuConfigTdpBootLevel
+ )
+{
+ MSR_REGISTER TempMsr;
+
+ ///
+ /// Select cTDP Nominal if Ctdp disabled or boot level not supported.
+ ///
+ if (CpuConfigTdpBootLevel == CONFIG_TDP_DEACTIVATE || CpuConfigTdpBootLevel >= mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported) {
+ CpuConfigTdpBootLevel = 0;
+ }
+
+ mCpuConfigTdpBootRatio = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpTar+1;
+ mPpmGlobalNvsAreaProtocol->Area->ConfigurablePpc = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpPpc;
+ ///
+ /// Program the selected level 00:nominal,01:level1,10:level2 to
+ /// CONFIG TDP CONTROL MSR.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_CONFIG_TDP_CONTROL);
+ if ((TempMsr.Qword & CONFIG_TDP_CONTROL_LOCK) == 0) {
+ TempMsr.Dwords.Low = (UINT16) TempMsr.Dwords.Low &~CONFIG_TDP_CONTROL_LVL_MASK;
+ TempMsr.Dwords.Low = (UINT16) TempMsr.Dwords.Low | (CpuConfigTdpBootLevel & CONFIG_TDP_CONTROL_LVL_MASK);
+ if (CpuPmConfig->pTurboSettings->ConfigTdpLock == PPM_ENABLE) {
+ TempMsr.Dwords.Low |= CONFIG_TDP_CONTROL_LOCK;
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_CONFIG_TDP_CONTROL is locked\n"));
+ }
+ AsmWriteMsr64 (MSR_CONFIG_TDP_CONTROL, TempMsr.Qword);
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_CONFIG_TDP_CONTROL=%x\n", TempMsr.Qword));
+ } else {
+ DEBUG ((EFI_D_INFO, "PPM:: Could not write MSR_CONFIG_TDP_CONTROL\n"));
+ }
+ ///
+ /// Program the max non-turbo ratio corresponding to default selected level
+ /// in TURBO_ACTIVATION_RATIO MSR.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_TURBO_ACTIVATION_RATIO);
+ if ((TempMsr.Qword & MSR_TURBO_ACTIVATION_RATIO_LOCK) == 0) {
+ TempMsr.Dwords.Low &= ~MSR_TURBO_ACTIVATION_RATIO_MASK;
+ TempMsr.Dwords.Low |= (UINT16) ((mCpuConfigTdpBootRatio-1) & MSR_TURBO_ACTIVATION_RATIO_MASK);
+ if (CpuPmConfig->pTurboSettings->ConfigTdpLock == PPM_ENABLE ) {
+ TempMsr.Dwords.Low |= MSR_TURBO_ACTIVATION_RATIO_LOCK;
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_TURBO_ACTIVATION_RATIO is locked\n"));
+ }
+ AsmWriteMsr64 (MSR_TURBO_ACTIVATION_RATIO, TempMsr.Qword);
+ DEBUG ((EFI_D_INFO, "PPM:: ConfigTDP MSR_TURBO_ACTIVATION_RATIO=%x\n", TempMsr.Qword));
+ } else {
+ DEBUG ((EFI_D_INFO, "PPM:: Could not write MSR_TURBO_ACTIVATION_RATIO\n"));
+ }
+}
+
+/**
+ Configures the TURBO_POWER_LIMIT MMIO for Boot ConfigTdp Level
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+ @param[in] CpuConfigTdpBootLevel ConfigTdpBootLevel policy setting by user
+**/
+VOID
+SelectCtdpPowerLimits (
+ IN POWER_MGMT_CONFIG *CpuPmConfig,
+ IN UINT8 CpuConfigTdpBootLevel
+ )
+{
+ UINTN PciD0F0RegBase;
+ UINTN MchBar;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT16 PowerLimit1;
+ UINT16 PowerLimit2;
+ MSR_REGISTER TempMsr;
+
+ ///
+ /// If Ctdp deactivate, Program MSRs to Nominal and MMIO to 0 to enable overclocking
+ ///
+ if (CpuConfigTdpBootLevel == CONFIG_TDP_DEACTIVATE) {
+ PowerLimit1 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit1;
+ PowerLimit2 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[0].CtdpPowerLimit2;
+ TempMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ TempMsr.Dwords.Low &= ~POWER_LIMIT_MASK;
+ TempMsr.Dwords.Low |= PowerLimit1;
+ TempMsr.Dwords.High &= ~POWER_LIMIT_MASK;
+ TempMsr.Dwords.High |= PowerLimit2;
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, TempMsr.Qword);
+ return;
+ }
+
+ ///
+ /// Select cTDP Nominal if Ctdp disabled or boot level not supported.
+ ///
+ if (CpuConfigTdpBootLevel >= mPpmGlobalNvsAreaProtocol->Area->CtdpLevelsSupported) {
+ CpuConfigTdpBootLevel = 0;
+ }
+
+ PowerLimit1 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpPowerLimit1;
+ PowerLimit2 = mPpmGlobalNvsAreaProtocol->Area->CtdpLevelSettings[CpuConfigTdpBootLevel].CtdpPowerLimit2;
+ ///
+ /// Get the MCH space base address.
+ /// Program Turbo Power Limit MMIO register MCHBAR+0x59A0 Bits [14:0] and [46:32]
+ /// for ConfigTdp mode PL1 and PL2
+ ///
+ PciD0F0RegBase = MmPciAddress (0, 0, 0, 0, 0);
+ MchBar = MmioRead32 (PciD0F0RegBase + 0x48) &~BIT0;
+ ///
+ /// Read PowerLimit MSR
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ ///
+ /// Program cTDP Power Limit1
+ ///
+ Data32And = (UINT32) ~(PACKAGE_TDP_POWER_MASK);
+ Data32Or = (UINT32) (PowerLimit1 | (TempMsr.Dwords.Low &~PACKAGE_TDP_POWER_MASK));
+ MmioAndThenOr32 (MchBar + MMIO_TURBO_POWER_LIMIT, Data32And, Data32Or);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT),
+ 1,
+ (VOID *) (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT)
+ );
+ ///
+ /// Program cTDP Power Limit2
+ ///
+ Data32And = (UINT32) ~(PACKAGE_TDP_POWER_MASK);
+ Data32Or = (UINT32) (PowerLimit2 | (TempMsr.Dwords.High &~PACKAGE_TDP_POWER_MASK));
+ MmioAndThenOr32 (MchBar + MMIO_TURBO_POWER_LIMIT + 4, Data32And, Data32Or);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT + 4),
+ 1,
+ (VOID *) (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT + 4)
+ );
+}
+
+
+/**
+ Configures following fields of MSR 0x618 based on corresponding MMIO register (MCHBAR+0x58E0):
+ Configures Long duration Turbo Mode (power limit 1) power level and time window for DDR domain
+ Configures Short duration Turbo Mode (power limit 2) power level and time window for DDR domain
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigureDdrPowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER DdrPowerLimitMsr;
+ UINTN PciD0F0RegBase;
+ UINTN MchBar;
+
+ PciD0F0RegBase = MmPciAddress (0, 0, 0, 0, 0);
+ MchBar = MmioRead32 (PciD0F0RegBase + 0x48) &~BIT0;
+
+ DdrPowerLimitMsr.Qword = 0;
+ DdrPowerLimitMsr.Qword = MmioRead64 (MchBar + MMIO_DDR_RAPL_LIMIT);
+
+ DEBUG (
+ (EFI_D_INFO,
+ "DDR Power Limit 1 = %d\n",
+ DdrPowerLimitMsr.Dwords.Low & POWER_LIMIT_MASK)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ "DDR Power Limit 2 = %d\n",
+ DdrPowerLimitMsr.Dwords.High & POWER_LIMIT_MASK)
+ );
+
+ AsmWriteMsr64 (MSR_DDR_RAPL_LIMIT, DdrPowerLimitMsr.Qword);
+}
+
+/**
+ Configures PowerLimits and Config TDP values
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigureCtdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ ///
+ /// Configure CTDP power limits.Refer Rev 0.6.0 BWG sec 16.7.1: Enabling Intel Configurable TDP support
+ ///
+ ConfigureCtdpPowerLimits (CpuPmConfig);
+
+ ///
+ /// BIOS power limit overrides
+ /// Don't override if custom ctdp settings are provided.
+ ///
+ if (!CpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom) {
+ ConfigureCtdpPowerLimitsOverrides();
+ }
+ ///
+ /// To avoid issues and race conditions it is recommended that the below order of be followed
+ /// - For TDP Up program the Config TDP Level followed by Power Limits
+ /// - For TDP down program the Power Limits followed by Config TDP level
+ ///
+ if (CpuPmConfig->pTurboSettings->ConfigTdpLevel == CONFIG_TDP_UP) {
+ SelectCtdpPowerLimits (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex);
+ SelectCtdpLevel (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex);
+ } else {
+ SelectCtdpLevel (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex);
+ SelectCtdpPowerLimits (CpuPmConfig, mPpmGlobalNvsAreaProtocol->Area->ConfigTdpBootModeIndex);
+ }
+}
+
+EFI_STATUS
+InitControllableTdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+/**
+ Check for Ctrl TDP enabled SKUs and enable Controllable TDP
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+
+ @exception EFI_UNSUPPORTED Controllable TDP not Supported
+ @retval EFI_SUCCESS Controllable TDP Supported
+**/
+{
+ UINTN CpuFamilyIndex;
+ UINTN CpuModelIndex;
+ UINT32 CtrlTdpSkuSize;
+ UINT8 CtrlTdpSkuDetected;
+ CHAR8 BrandIdString[MAXIMUM_CPU_BRAND_STRING_LENGTH + 1];
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ EFI_CPUID_REGISTER CpuExtendedSupport;
+ EFI_CPUID_REGISTER CpuBrandString;
+ PPM_CTRL_TDP_SKU_TBL *CtrlTdpSku;
+ MSR_REGISTER TempMsr;
+///
+/// Debug
+///
+
+ CtrlTdpSkuDetected = 0;
+ CtrlTdpSkuSize = 0;
+
+ CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ CpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING;
+
+ if((CpuFamilyId == EnumCpuHswUlt) || (CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ CtrlTdpSku = mHswCtrlTdpSkuTable;
+ CtrlTdpSkuSize = 1;
+ }else {
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((EFI_D_ERROR, "\n Function InitControllableTdp \n"));
+ //
+ // Get CPU Brand String
+ //
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &CpuExtendedSupport.RegEax, &CpuExtendedSupport.RegEbx, &CpuExtendedSupport.RegEcx, &CpuExtendedSupport.RegEdx);
+ AsmCpuid (CPUID_BRAND_STRING1, &CpuBrandString.RegEax, &CpuBrandString.RegEbx, &CpuBrandString.RegEcx, &CpuBrandString.RegEdx);
+ //
+ // Check if Brand ID String is supported or filled up
+ //
+ if (CpuExtendedSupport.RegEax == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ CopyMem ((CHAR8 *) &BrandIdString[0],(CHAR8 *) &CpuBrandString,16);
+ AsmCpuid (CPUID_BRAND_STRING2, &CpuBrandString.RegEax, &CpuBrandString.RegEbx, &CpuBrandString.RegEcx, &CpuBrandString.RegEdx);
+ CopyMem ((CHAR8 *) &BrandIdString[16],(CHAR8 *) &CpuBrandString,16);
+ AsmCpuid (CPUID_BRAND_STRING3, &CpuBrandString.RegEax, &CpuBrandString.RegEbx, &CpuBrandString.RegEcx, &CpuBrandString.RegEdx);
+ CopyMem ((CHAR8 *) &BrandIdString[31],(CHAR8 *) &CpuBrandString,16);
+ BrandIdString[MAXIMUM_CPU_BRAND_STRING_LENGTH] = 0;
+
+ //
+ // Check for Match with Controllable TDP SKU list
+ //
+ for(CpuFamilyIndex = 0;CpuFamilyIndex < CtrlTdpSkuSize;CpuFamilyIndex++) {
+ if(EfiAsciiStrStr((CHAR8 *) BrandIdString, (CHAR8 *) CtrlTdpSku[CpuFamilyIndex].CpuFamily)) {
+ //
+ // If NoOfCpus=0xff ,all processors in the family are ULV skus
+ //
+ if(CtrlTdpSku[CpuFamilyIndex].NoOfCpus == 0xFF) {
+ CtrlTdpSkuDetected = 1;
+ DEBUG ((EFI_D_ERROR, "\n Found Control TDP SKU"));
+ break;
+ }
+ for(CpuModelIndex = 0;CpuModelIndex < CtrlTdpSku[CpuFamilyIndex].NoOfCpus; CpuModelIndex++) {
+ if(EfiAsciiStrStr((CHAR8 *) BrandIdString,(CHAR8 *) CtrlTdpSku[CpuFamilyIndex].CpuModel[CpuModelIndex])) {
+ CtrlTdpSkuDetected = 1;
+ DEBUG ((EFI_D_ERROR, "\n Found Control TDP SKU"));
+ break;
+ }
+ } // end of CpuModelIndex
+ break;
+ }
+ } // end of if CpuFamilyIndex
+
+ ///
+ /// Enable Controllable TDp when
+ /// Power Limt1 is less than Package Tdp
+ /// Min Power is Zero
+ ///
+ if (CpuPmConfig->pTurboSettings->PowerLimit1 != AUTO && (CpuPmConfig->pTurboSettings->PowerLimit1 * mProcessorPowerUnit) / mCustomPowerUnit < mPackageTdp
+ && (mPackageMinPower == 0) && (CtrlTdpSkuDetected == 1)){
+ mControllableTdpEnable = 1;
+ //
+ // For ControllableTDP enabled systems add fake P-State below LFM and set PPC as LFM
+ //
+ mMinBusRatio = mMinBusRatio - 1;
+ //
+ // Set TAR MSR to LFM-1 (Fake LFM)
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_TURBO_ACTIVATION_RATIO);
+ TempMsr.Dwords.Low &= ~MSR_TURBO_ACTIVATION_RATIO_MASK;
+ TempMsr.Dwords.Low |= (UINT16)((mMinBusRatio) & MSR_TURBO_ACTIVATION_RATIO_MASK);
+ DEBUG ((EFI_D_INFO, "\n Wrting MSR_TURBO_ACTIVATION_RATIO : %x \n",TempMsr.Qword));
+ AsmWriteMsr64 (MSR_TURBO_ACTIVATION_RATIO, TempMsr.Qword);
+ }
+ return EFI_SUCCESS;
+}
+
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtCommon.h b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtCommon.h
new file mode 100644
index 0000000..2ee19bd
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtCommon.h
@@ -0,0 +1,877 @@
+/** @file
+ This header file contains power management definitions specific to
+ Haswell processors.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM Thermal Monitor
+ IST Intel(R) Speedstep technology
+ HT Hyper-Threading Technology
+
+@copyright
+ Copyright (c) 2012-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
+
+**/
+#ifndef _POWER_MGMT_COMMON_H_
+#define _POWER_MGMT_COMMON_H_
+
+#include "EdkIIGlueDxe.h"
+#include "EfiScriptLib.h"
+#include "PowerMgmtDefinitions.h"
+#include "Cpu.h"
+#include "CpuAccess.h"
+#include "CpuPlatformLib.h"
+#include "BaseLibInternal.h"
+#include "PchAccess.h"
+#include "PchPlatformLib.h"
+#include "SaAccess.h"
+#include "AslUpdateLib.h"
+
+#include EFI_PROTOCOL_DEPENDENCY (BootScriptSave)
+#include EFI_PROTOCOL_DEPENDENCY (CpuPlatformPolicy)
+#include EFI_PROTOCOL_PRODUCER (PowerMgmtInitDone)
+#include EFI_PROTOCOL_CONSUMER (MpService)
+#include EFI_PROTOCOL_CONSUMER (LoadedImage)
+#include EFI_PROTOCOL_DEPENDENCY (AcpiSupport)
+#include EFI_PROTOCOL_DEPENDENCY (AcpiTable)
+#include EFI_GUID_DEFINITION (PowerMgmtAcpiTableStorage)
+#include EFI_PROTOCOL_PRODUCER (PpmGlobalNvsArea)
+
+#define HSW_ULT_PCH_POWER_LEVELS 0x3
+#define EXTENDED_PCH_POWER_LEVELS 0x4
+#define PM_CST_LVL2 0x14
+
+#define FADT_C3_LATENCY 57
+#define FADT_C3_LATENCY_DISABLED 1001
+
+#define NATIVE_PSTATE_LATENCY 10
+#define PSTATE_BM_LATENCY 10
+
+#define MP_TIMEOUT_FOR_STARTUP_ALL_APS 0 ///< Set 0 for BSP always wait for APs
+
+#define NO_CALIBRATE 0
+#define PCODE_CALIBRATE 1
+#define BIOS_CALIBRATE 2
+#define PCODE_BCLK_CALIBRATION_TIMEOUT 22
+
+///
+/// Limit the number of P-states to 16. Up to Windows 7, the OS allocates 1KB buffer for the PSS package.
+/// So the maximum number of P-state OS can handle is 19. This is not an OS issue. Having too many P-states
+/// is not good for the system performance.
+///
+#define FVID_MAX_STATES 16
+#define FVID_MIN_STEP_SIZE 1
+
+///
+/// Cpu Brandstring length
+///
+#define MAXIMUM_CPU_BRAND_STRING_LENGTH 48
+
+///
+/// Power Limit Level
+///
+#define PL12TimeWindowCovert 1
+#define PL3TimeWindowConvert 3
+//
+// Global variables
+//
+///
+/// CpuPlatformPolicy Revision
+///
+extern UINT8 mCpuPolicyRevision;
+
+extern POWER_MGMT_CONFIG *mCpuPmConfig; ///< Power Managment policy configurations
+extern EFI_CPUID_REGISTER mCpuid01; // CPUID 01 values
+//
+// Values for FVID table calculate.
+//
+extern UINT16 mTurboBusRatio;
+extern UINT16 mMaxBusRatio;
+extern UINT16 mMinBusRatio;
+extern UINT16 mProcessorFlavor;
+extern UINT16 mBspBootRatio;
+extern UINT16 mPackageTdp;
+extern UINT16 mPackageTdpWatt;
+extern UINT16 mCpuConfigTdpBootRatio;
+extern UINT16 mCustomPowerUnit;
+extern UINT16 mCpuCacheSize;
+///
+/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit)
+///
+extern UINT8 mProcessorPowerUnit;
+///
+/// Fractional part of Processor Time Unit in seconds. (i.e Unit is 1/mProcessorTimeUnit)
+///
+extern UINT8 mProcessorTimeUnit;
+///
+/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+extern UINT16 mPackageMaxPower;
+///
+/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+extern UINT16 mPackageMinPower;
+extern UINT8 mControllableTdpEnable; ///< Controllable TDP Enable/Disable
+extern UINT8 mRatioLimitProgrammble; ///< Porgrammable Ratio Limit
+extern UINT8 mTdpLimitProgrammble; ///< Porgrammable TDP Limit
+
+extern PPM_GLOBAL_NVS_AREA_PROTOCOL *mPpmGlobalNvsAreaProtocol; ///< Ppm GlobalNvs Protocol
+extern EFI_MP_SERVICES_PROTOCOL *mMpService; ///< Mp Services Protocol
+
+//
+// Globals to support updating ACPI Tables
+//
+extern EFI_ACPI_SUPPORT_PROTOCOL *mAcpiSupport;
+extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApIstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApCstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpuPmTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApTstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mLakeTinyTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCtdpTable;
+
+//
+// Structure Declarations
+//
+
+typedef struct _FVID_HEADER {
+ UINT32 Stepping; ///< Matches value returned by CPUID function 1
+ UINT16 MaxBusRatio; ///< Matches BUS_RATIO_MAX field in PERF_STS_MSR
+ UINT16 Gv3States; ///< Number of states of FVID (N)
+} FVID_HEADER;
+
+typedef struct _FVID_STATE {
+ UINT32 State; ///< State Number (0 - N-1)
+ UINT16 BusRatio; ///< BUS_RATIO_SEL value to be written to PERF_CTL
+ UINT32 Power; ///< Typical power consumed by CPU in this state
+} FVID_STATE;
+
+typedef union _FVID_TABLE {
+ FVID_HEADER FvidHeader;
+ FVID_STATE FvidState;
+ UINT64 FvidData;
+} FVID_TABLE;
+
+typedef struct _ENABLE_CSTATE_PARAMS {
+ UINT16 C3IoAddress;
+} ENABLE_CSTATE_PARAMS;
+
+typedef struct _ENABLE_EMTTM_PARAMS {
+ FVID_TABLE *FvidPointer;
+} ENABLE_EMTTM_PARAMS;
+
+typedef struct _PCODE_BCLK_CALIBRATION_MAILBOX {
+ UINT32 PCalFactor;
+ UINT32 TSC24_L1;
+ UINT32 TSC24_L2;
+ UINT32 TSC24_U1;
+ UINT32 TSC24_U2;
+ UINT32 TSC100_L1;
+ UINT32 TSC100_L2;
+ UINT32 TSC100_U1;
+ UINT32 TSC100_U2;
+} PCODE_BCLK_CALIBRATION_MAILBOX;
+
+///
+/// ASL SSDT structure layout
+///
+#pragma pack(1)
+typedef struct {
+ UINT8 NameOp; ///< First opcode is a NameOp.
+ UINT32 NameString; ///< 'TDSS' ; Name of object.
+ UINT8 PackageOp; ///< db 12h ; Sixth OpCode is PackageOp.
+ UINT16 PackageLen; ///< dw 0h ; Seventh/Eighth OpCode is PackageLength.
+ UINT8 PackageEntryNum; ///< db 0Ch ; Ninth OpCode is number of package entries.
+ UINT8 StringPrefix1; ///< 0Dh
+ UINT64 Cpu0IstStr; ///< 00h
+ UINT8 StringNull1; ///< 00h
+ UINT8 DwordPrefix1a; ///< 0Ch
+ UINT32 Cpu0IstAddr; ///< 00h
+ UINT8 DwordPrefix1b; ///< 0Ch
+ UINT32 Cpu0IstLen; ///< 00h
+ UINT8 StringPrefix2; ///< 0Dh
+ UINT64 Cpu1IstStr; ///< 00h
+ UINT8 StringNull2; ///< 00h
+ UINT8 DwordPrefix2a; ///< 0Ch
+ UINT32 ApIstAddr; ///< 00h
+ UINT8 DwordPrefix2b; ///< 0Ch
+ UINT32 ApIstLen; ///< 00h
+ UINT8 StringPrefix3; ///< 0Dh
+ UINT64 Cpu0CstStr; ///< 00h
+ UINT8 StringNull3; ///< 00h
+ UINT8 DwordPrefix3a; ///< 0Ch
+ UINT32 Cpu0CstAddr; ///< 00h
+ UINT8 DwordPrefix3b; ///< 0Ch
+ UINT32 Cpu0CstLen; ///< 00h
+ UINT8 StringPrefix4; ///< 0Dh
+ UINT64 ApCstStr; ///< 00h
+ UINT8 StringNull4; ///< 00h
+ UINT8 DwordPrefix4a; ///< 0Ch
+ UINT32 ApCstAddr; ///< 00h
+ UINT8 DwordPrefix4b; ///< 0Ch
+ UINT32 ApCstLen; ///< 00h
+} SSDT_LAYOUT;
+#pragma pack()
+
+///
+/// ASL PCTP structure layout
+///
+#pragma pack(1)
+typedef struct {
+ UINT8 RegDes; ///< Byte [0]=0x82:Register descriptor code
+ UINT16 RegLen; ///< Byte [2:1]=0x0C:Register descriptor length
+ UINT8 RegType; ///< Byte [3]=0x01:Register type (System IO)
+ UINT8 RegWidth; ///< Byte [4]=0x10:Register width (16-bit)
+ UINT8 RegBitOffst; ///< Byte [5]=0x00:Register bit offset (0)
+ UINT8 RegAccSize; ///< Byte [6]=0x00:Register access size (0)
+ UINT64 RegAddress; ///< Byte [14:7]=Register address
+ UINT16 EndTag; ///< Byte [16:15]=End tag
+} PCTP_LAYOUT;
+#pragma pack()
+
+typedef struct {
+ UINT16 SkuPackageTdp;
+ UINTN SkuIccMax;
+ UINTN MsrCtdpPowerLimit1;
+ UINTN MsrCtdpPowerLimit2;
+ UINTN CtdpUpPowerLimit1;
+ UINTN CtdpUpPowerLimit2;
+ UINTN CtdpNominalPowerLimit1;
+ UINTN CtdpNominalPowerLimit2;
+ UINTN CtdpDownPowerLimit1;
+ UINTN CtdpDownPowerLimit2;
+ UINTN Reserved;
+} PPM_CTDP_OVERRIDE_TABLE;
+
+///
+/// PL1 Thermal Control structure layout
+///
+typedef union {
+ struct {
+ UINT8 Disable:1; ///< [0] Disable
+ UINT8 Reserved:7; ///< [7:2] Reserved
+ UINT8 FloorIA; ///< [15:8] Percent Throttle for IA component 255-0; 255=0%, 0=100%
+ UINT8 FloorGT; ///< [23:16] Percent Throttle for GT component 255-0; 255=0%, 0=100%
+ UINT8 FloorPCH; ///< [31:24] Percent Throttle for PCH component 255-0; 255=0%, 0=100%
+ } Bits;
+ UINT32 Uint32;
+ } PL1_THERMAL_CONTROL;
+
+typedef struct _PPM_CTRL_TDP_SKU_TBL{
+ UINT8 CpuFamily[MAXIMUM_CPU_BRAND_STRING_LENGTH]; ///< Cpu Family Brand String
+ UINTN NoOfCpus; ///< Number of Cpus,FF mean all cpus matching CpuFamily string above
+ UINT8 CpuModel[20][MAXIMUM_CPU_BRAND_STRING_LENGTH]; ///< Processor Model Number
+} PPM_CTRL_TDP_SKU_TBL;
+
+//
+// FVID Table Information
+// Default FVID table
+// One header field plus states
+//
+extern UINT16 mNumberOfStates;
+extern FVID_TABLE mEmptyFvidTable[FVID_MAX_STATES + 1];
+extern FVID_TABLE *mFvidPointer;
+
+//
+// Function prototypes
+//
+/**
+ Initializes P States and Turbo Power management features
+**/
+VOID
+InitializePStates (
+ VOID
+ );
+
+/**
+ Initializes XE support in the processor.
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitTurboRatioLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Initializes required structures for P-State table creation and enables GV3
+ support in the processor.
+
+ @param[in] FvidPointer Table to update, must be initialized.
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitGv3 (
+ IN OUT FVID_TABLE *FvidPointer,
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Enables GV3 support in a logical processor.
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to the function parameters passed in.
+
+ @retval EFI_SUCCESS
+**/
+VOID
+EFIAPI
+ApSafeEnableGv3 (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ This function updates the table provided with the FVID data for the processor.
+ If CreateDefaultTable is TRUE, a minimam FVID table will be provided.
+ The maximum number of states must be greater then or equal to two.
+ The table should be initialized in such a way as for the caller to determine if the
+ table was updated successfully. This function should be deprecated in the future when
+ Release 8 is integrated in favor of the EIST protocol calculating FVID information.
+
+ @param[in] FvidPointer Pointer to a table to be updated
+ @param[in] MaxNumberOfStates Number of entries in the table pointed to by FvidPointer
+ @param[in] MinStepSize Minimum step size for generating the FVID table
+ @param[in] CreateDefaultTable Create default FVID table rather then full state support
+**/
+VOID
+InitFvidTable (
+ IN OUT FVID_TABLE *FvidPointer,
+ IN UINT16 MaxNumberOfStates,
+ IN UINT16 MinStepSize,
+ IN BOOLEAN CreateDefaultTable
+ );
+
+/**
+ Create an FVID table based on the algorithm provided by the BIOS writer's guide.
+
+ @param[in] FvidPointer Pointer to a table to be updated
+ @param[in] MaxNumberOfStates Number of entries in the table pointed to by FvidPointer
+
+ @retval EFI_SUCCESS FVID table created successfully.
+ @retval EFI_INVALID_PARAMETER The bus ratio range don't permit FVID table calculation;
+ a default FVID table should be constructed.
+**/
+EFI_STATUS
+CreateFvidTable (
+ IN OUT FVID_TABLE *FvidPointer,
+ IN UINT16 MaxNumberOfStates
+ );
+
+/**
+ Create default FVID table with max and min states only.
+
+ @param[in] FvidPointer Pointer to a table to be updated
+**/
+VOID
+CreateDefaultFvidTable (
+ IN OUT FVID_TABLE *FvidPointer
+ );
+
+/**
+ Initializes Energy efficient P-state feature.
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitEnergyEfficientPState (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+
+/**
+ Configures the Interrupt Redirection Mode Selection for Logical Interrupts.
+
+ @param[in] CpuPmConfig Pointer to PPM Policy structure.
+**/
+VOID
+InitPpmIrmConfiguration (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Completes platform power management initialization
+ (1) Initializes the TSC update variables.
+ (2) Initializes the GV state for processors.
+ (3) Saves MSR state for S3
+ (4) Adds a callback (SMI) in S3 resume script to restore the MSR
+**/
+VOID
+PpmPostInit (
+ VOID
+ );
+
+/**
+ Set processor P state to HFM or LFM
+**/
+VOID
+SetBootPState (
+ VOID
+ );
+
+/**
+ Set processor P state to HFM or LFM.
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Processor MSR setting is saved.
+**/
+VOID
+EFIAPI
+ApSafeSetBootPState (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Initializes C States Power management features
+**/
+VOID
+InitializeCState (
+ IN POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Disable/Enable the CState Pre-Wake Feature
+
+ @param[in] CpuPmConfig - Pointer to policy protocol instance
+**/
+VOID
+InitCstatePreWake (
+ IN POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ BootScript for PCode Mailbox function for mailbox write commands.
+ This function will poll the mailbox interface for control, issue the command
+ during s3 resume
+
+ @param[IN] MailboxCommand,
+ @param[IN] MailboxData,
+**/
+VOID
+MailboxS3Write (
+ IN UINT32 MailboxCommand,
+ IN UINT32 MailboxData
+ );
+
+/**
+ Calibrate 24MHz BCLK support to reduce the power consumption in idle states.
+
+ @retval EFI_UNSUPPORTED Unrecognized 24MHz BCLK Calibration Type.
+ @retval EFI_SUCCESS Processor C-State 24MHz BCLK support calibrated successfully.
+**/
+EFI_STATUS
+CalibrateBclkForCStates (
+ VOID
+ );
+
+/**
+ Enables C-State support as specified by the input flags on all logical
+ processors and sets associated timing requirements in the chipset.
+
+ @param[in] This Pointer to the protocol instance
+ @param[in] C3IoAddress IO address to generate C3 states (PM base + 014 usually)
+**/
+VOID
+EnableCStates (
+ IN UINT16 C3IoAddress
+ );
+
+/**
+ Enable C-State support as specified by the input flags on a logical processor.
+ Configure BIOS C1 Coordination (SMI coordination)
+ Enable IO redirection coordination
+ Choose proper coordination method
+ Configure extended C-States
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to a ENABLE_CSTATE_PARAMS containing the necessary
+ information to enable C-States
+
+ @retval EFI_SUCCESS Processor C-State support configured successfully.
+**/
+VOID
+EFIAPI
+ApSafeEnableCStates (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ This will perform Miscellaneous Power Management related programming.
+
+ @param[in] CtdpSupport Status of InitializeConfigurableTdp funtion
+**/
+VOID
+InitMiscFeatures (
+ EFI_STATUS CtdpSupport
+ );
+
+/**
+ CTDP BIOS settings Initialization(Msr)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+ @param[in] FvidPointer Table to update, must be initialized.
+
+ @exception EFI_UNSUPPORTED Ctdp not supported
+ @retval EFI_SUCCESS Ctdp Settings Initialized successfully from MSRs
+**/
+EFI_STATUS
+InitializeConfigurableTdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Configures PowerLimits and Config TDP values
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigureCtdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ This will perform general thermal initialization other then TM1, TM2, or
+ PROCHOT# on all logical processors.
+
+ @param[in] This Pointer to the protocol instance
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitThermal (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ This will perform enable thermal initialization. TM1, TM2 and adaptive thermal
+ throttling are enabled/disabled together.
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to the function parameters passed in.
+
+ @retval EFI_SUCCESS General thermal initialization completed successfully
+**/
+VOID
+EFIAPI
+ApSafeInitThermal (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Enables the bi-directional PROCHOT# signal.
+
+ @retval EFI_SUCCESS PROCHOT# configured successfully
+**/
+EFI_STATUS
+EnableProcHot (
+ VOID
+ );
+
+
+/**
+ Locks down all settings.
+
+ @param[in] CpuPmConfig Pointer to PPM Policy structure.
+**/
+VOID
+PpmLockDown (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Lock MSR_PMG_CST_CONFIG
+ This function must be MP safe.
+
+ @param[in] Buffer Not used (needed for API compatibility)
+
+ @retval EFI_SUCCESS Processor C-State locked successfully.
+**/
+VOID
+EFIAPI
+ApSafeLockDown (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Runs the specified procedure on all logical processors, passing in the
+ parameter buffer to the procedure.
+
+ @param[in] Procedure The function to be run.
+ @param[in] Buffer Pointer to a parameter buffer.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+RunOnAllLogicalProcessors (
+ IN OUT EFI_AP_PROCEDURE Procedure,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Configures following fields of MSR 0x610 based on user configuration:
+ Configures Long duration Turbo Mode (power limit 1) power level and time window
+ Configures Short duration Turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigurePowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Configures following fields of MSR 0x610 based on user configuration:
+ Configures Long duration Turbo Mode (power limit 1) power level and time window
+ Configures Short duration Turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigurePowerLimitsNonConfigTdpSkus (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Configures following fields of PL3 MSR 0x615 based on user configuration:
+ Configures PL 3 power level and time window
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigurePL3PowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ This will perform PowerLimit 1 algorithm will be used to control Thermal Throttling features
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+
+/**
+ This will perform PowerLimit 1 algorithm will be used to control Thermal Throttling features
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitPl1ThermalControl (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Configures following fields of MSR 0x618 based on user configuration:
+ Configures Long duration Turbo Mode (power limit 1) power level and time window for DDR domain
+ Configures Short duration Turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigureDdrPowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Verify and fix Custom Power Limit values
+
+ @param[in] CustomPowerLimit Custom Power Limit value
+
+ @retval Verified Custom power limit value
+**/
+UINT16
+VerifyAndFixCustomPowerLimit (
+ IN UINT32 CustomPowerLimit,
+ IN UINT16 CustomPlUnit
+ );
+
+/**
+ Verify and fix Custom Ratio values
+ Custom Ratio should be between MaxTurboFrequency and LFM
+
+ @param[in] CustomPowerLimit Custom Power Limit value
+ @param[in] CustomPlUnit Custom Power Limit Unit
+
+ @retval Verified Custom Ratio value
+**/
+UINT8
+VerifyAndFixCustomRatio (
+ IN UINT8 CustomRatio
+ );
+
+/**
+ CTDP BIOS settings Initialization(From Msrs)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+
+ @exception EFI_UNSUPPORTED Ctdp not supported
+ @retval EFI_SUCCESS Ctdp Settings Initialized successfully from MSRs
+**/
+EFI_STATUS
+InitConfigurableTdpSettings (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Get Power Limit2 based on Power Limit1 on Config TDP
+
+ @param[in] PowerLimit1 Power Limit 1 Value
+
+ @retval Calculated Power Limit2 value
+**/
+UINT16
+GetCtdpPowerLimit2 (
+ IN UINT16 PowerLimit1
+ );
+
+/**
+ Custom Configurable TDP Table BIOS Initialization
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+
+ @exception EFI_UNSUPPORTED Custom Ctdp settings are not available
+ @retval EFI_SUCCESS Successfully Initialized Custom Ctdp Settings
+**/
+EFI_STATUS
+InitCustomConfigurableTdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Configures following fields of MSR 0x610 based on user configuration:
+ - Configures Long duration Turbo Mode (power limit 1) power level and time window
+ - Configures Short duration turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitPchPowerSharing (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Private helper function to convert various Turbo Power Limit Time from Seconds to CPU units
+
+ @param[in] TimeInSeconds Time in seconds
+ @param[in] PowerLimitLevel Power Limit Level
+
+ @retval UINT8 Converted time in CPU units
+**/
+UINT8
+GetConvertedTime (
+ IN UINT32 TimeInSeconds,
+ IN UINT8 PowerLimitLevel
+ );
+
+/**
+ Configures following fields of MSR 0x610
+ Configures Long duration Turbo Mode (power limit 1) power level and time window
+ Configures Short duration turbo mode (power limit 2)
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+ConfigureCtdpPowerLimits (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+
+/**
+ Patch Fvid Table with Ctdp Tar ratio and Tar-1 Ratio
+
+ @param[in] FvidPointer Pointer to Fvid Table
+**/
+VOID
+CtdpPatchFvidTable (
+ IN OUT FVID_TABLE *FvidPointer
+ );
+
+/**
+ Replace P state with given ratio
+
+ @param[in] FvidPointer Pointer to Fvid Table
+ @param[in] PssIndex FVID table index of P state to be replaced
+ @param[in] Ratio Target Ratio to put in
+**/
+VOID
+CtdpReplaceFvidRatio (
+ IN OUT FVID_TABLE *FvidPointer,
+ UINTN PssIndex,
+ UINTN Ratio
+ );
+
+/**
+ Patch the native _PSS package with the GV3 values
+ Uses ratio/VID values from the FVID table to fix up the control values in the _PSS.
+
+ (1) Find _PSS package:
+ (1.1) Find the _PR_CPU0 scope.
+ (1.2) Save a pointer to the package length.
+ (1.3) Find the _PSS AML name object.
+ (2) Resize the _PSS package.
+ (3) Fix up the _PSS package entries
+ (3.1) Check Turbo mode support.
+ (3.2) Check Dynamic FSB support.
+ (4) Fix up the Processor block and \_PR_CPU0 Scope length.
+ (5) Update SSDT Header with new length.
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_FOUND - If _PR_.CPU0 scope is not foud in the ACPI tables
+**/
+EFI_STATUS
+AcpiPatchPss (
+ VOID
+ );
+
+/**
+ Configure the FACP for C state support
+**/
+VOID
+ConfigureFadtCStates (
+ VOID
+ );
+
+/**
+ Locate the PPM ACPI tables data file and read ACPI SSDT tables.
+ Publish the appropriate SSDT based on current configuration and capabilities.
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval EFI_SUCCESS - on success
+ @retval Appropiate failure code on error
+**/
+EFI_STATUS
+InitializePpmAcpiTable (
+ VOID
+ );
+
+/**
+ Check for Ctrl TDP enabled SKUs and enable Controllable TDP
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+
+ @exception EFI_UNSUPPORTED Controllable TDP not Supported
+ @retval EFI_SUCCESS Controllable TDP Supported
+**/
+EFI_STATUS
+InitControllableTdp (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ );
+#endif
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.cif b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.cif
new file mode 100644
index 0000000..99b6d76
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.cif
@@ -0,0 +1,19 @@
+<component>
+ name = "PowerMgmtInit"
+ category = ModulePart
+ LocalRoot = "ReferenceCode\Haswell\PowerManagement\Dxe"
+ RefName = "PowerMgmtInit"
+[files]
+"PowerMgmtDxe.mak"
+"PowerMgmtDxe.sdl"
+"PowerMgmtDxe.inf"
+"PowerMgmtDxe.dxs"
+"PowerMgmtInit.c"
+"IdleStates.c"
+"MiscFunctions.c"
+"PerformanceStates.c"
+"PowerLimits.c"
+"Thermal.c"
+"PowerMgmtCommon.h"
+"PowerMgmtInit.h"
+<endComponent>
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.dxs b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.dxs
new file mode 100644
index 0000000..199a064
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.dxs
@@ -0,0 +1,38 @@
+/** @file
+ Dependency expression source file.
+
+@copyright
+ Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+
+
+#include "EfiDepex.h"
+
+#include EFI_PROTOCOL_DEFINITION (MpService)
+#include EFI_PROTOCOL_DEPENDENCY (BootScriptSave)
+#include EFI_PROTOCOL_DEPENDENCY (AcpiSupport)
+#include EFI_PROTOCOL_DEPENDENCY (CpuPlatformPolicy)
+#include EFI_PROTOCOL_DEPENDENCY (GlobalNvsArea)
+
+DEPENDENCY_START
+ EFI_BOOT_SCRIPT_SAVE_PROTOCOL_GUID AND
+ EFI_ACPI_SUPPORT_GUID AND
+ EFI_MP_SERVICES_PROTOCOL_GUID AND
+ EFI_GLOBAL_NVS_AREA_PROTOCOL_GUID AND
+ DXE_CPU_PLATFORM_POLICY_PROTOCOL_GUID
+DEPENDENCY_END
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.inf b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.inf
new file mode 100644
index 0000000..4eb4666
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.inf
@@ -0,0 +1,114 @@
+## @file
+# Component description file for Power Management module
+#
+#@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
+#
+
+[defines]
+BASE_NAME = PowerMgmtDxe
+FILE_GUID = f7731b4c-58a2-4df4-8980-5645d39ece58
+COMPONENT_TYPE = BS_DRIVER
+
+[sources.common]
+ PowerMgmtinit.h
+ PowerMgmtinit.c
+ PowerMgmtCommon.h
+ PerformanceStates.c
+ IdleStates.c
+ PowerLimits.c
+ Thermal.c
+ MiscFunctions.c
+
+#
+# Edk II Glue Driver Entry Point
+#
+ EdkIIGlueDxeDriverEntryPoint.c
+
+[includes.common]
+ .
+ $(EDK_SOURCE)/Foundation
+ $(EDK_SOURCE)/Foundation/Core/Dxe
+ $(EDK_SOURCE)/Foundation/Efi
+ $(EDK_SOURCE)/Foundation/Efi/Include
+ $(EDK_SOURCE)/Foundation/Framework
+ $(EDK_SOURCE)/Foundation/Framework/Include
+ $(EDK_SOURCE)/Foundation/Include
+ $(EDK_SOURCE)/Foundation/Include/IndustryStandard
+ $(EDK_SOURCE)/Foundation/Include/Pei
+ $(EDK_SOURCE)/Foundation/Library/Dxe/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Library/BaseLib
+ $(EFI_SOURCE)
+ $(EFI_SOURCE)/Framework
+ $(EFI_SOURCE)/Include
+ $(EFI_SOURCE)/Include/IndustryStandard
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include/Library
+#
+# Typically the sample code referenced will be available in the code base already
+# So keep this include at the end to defer to the source base definition
+# and only use the sample code definition if source base does not include these files.
+#
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/SampleCode
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/SampleCode/Include
+
+[libraries.common]
+ CpuGuidLib
+ CpuProtocolLib
+ DxeAslUpdateLib
+ EfiProtocolLib
+ EdkFrameworkProtocolLib
+ EdkIIGlueBaseLib
+ EdkIIGlueBaseIoLibIntrinsic
+ EdkIIGlueBaseMemoryLib
+ EdkIIGlueDxeMemoryAllocationLib
+ EdkIIGlueDxeDebugLibReportStatusCode
+ EdkIIGlueDxeReportStatusCodeLib
+ EdkIIGlueUefiBootServicesTableLib
+ EdkIIGlueUefiRuntimeServicesTableLib
+ EdkIIGlueUefiDevicePathLib
+ EfiScriptLib
+ EdkProtocolLib
+ CpuPlatformLib
+ EfiCommonLib
+
+[libraries.ia32,libraries.x64]
+ CpuIa32Lib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT = _ModuleEntryPoint
+ DPX_SOURCE = PowerMgmtDxe.dxs
+#
+# Module Entry Point
+#
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=InitializePowerManagement
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_LIB__ \
+ -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ -D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ -D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \
+ -D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ -D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \
+ -D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.mak b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.mak
new file mode 100644
index 0000000..3c65a6b
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.mak
@@ -0,0 +1,82 @@
+# MAK file for the eModule:PowerManagement
+
+EDK : PowerMgmtDxe
+
+BUILD_PowerMgmtDxe_DIR = $(BUILD_DIR)\$(PowerMgmtDxe_DIR)
+
+$(BUILD_DIR)\PowerMgmtDxe.mak : $(PowerMgmtDxe_DIR)\PowerMgmtDxe.cif $(BUILD_RULES)
+ $(CIF2MAK) $(PowerMgmtDxe_DIR)\PowerMgmtDxe.cif $(CIF2MAK_DEFAULTS)
+
+PowerMgmtDxe : $(BUILD_DIR)\PowerMgmtDxe.MAK PowerMgmtDxeBin
+
+PowerMgmtDxe_OBJECTS = \
+ $(BUILD_PowerMgmtDxe_DIR)\IdleStates.obj \
+ $(BUILD_PowerMgmtDxe_DIR)\MiscFunctions.obj \
+ $(BUILD_PowerMgmtDxe_DIR)\PerformanceStates.obj \
+ $(BUILD_PowerMgmtDxe_DIR)\PowerLimits.obj \
+ $(BUILD_PowerMgmtDxe_DIR)\Thermal.obj \
+ $(BUILD_PowerMgmtDxe_DIR)\PowerMgmtInit.obj
+
+PowerMgmtDxe_MY_INCLUDES= \
+ $(EdkIIGlueLib_INCLUDES)\
+ /I$(EdkIIGlueBaseLib_DIR)\
+ $(EDK_INCLUDES)\
+ $(PROJECT_CPU_INCLUDES)\
+ $(INTEL_PCH_INCLUDES)\
+ $(INTEL_MCH_INCLUDES)\
+ $(INTEL_PLATFORM_PROTOCOL_INCLUDES)
+
+PowerMgmtDxe_DEFINES = $(MY_DEFINES)\
+ /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializePowerManagement"\
+ /D __EDKII_GLUE_BASE_LIB__ \
+ /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ /D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ /D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \
+ /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ /D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \
+ /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__
+
+PowerMgmtDxe_LIBS =\
+ $(EFIGUIDLIB)\
+ $(EDKFRAMEWORKPROTOCOLLIB)\
+ $(EDKPROTOCOLLIB)\
+ $(EFISCRIPTLIB)\
+ $(EdkIIGlueBaseIoLibIntrinsic_LIB)\
+ $(EdkIIGlueBaseLib_LIB)\
+ $(EdkIIGlueBaseMemoryLib_LIB)\
+ $(EdkIIGlueDxeReportStatusCodeLib_LIB)\
+ $(EdkIIGlueDxeServicesTableLib_LIB)\
+ $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\
+ $(EdkIIGlueUefiBootServicesTableLib_LIB)\
+ $(EdkIIGlueUefiLib_LIB)\
+ $(EdkIIGlueBasePciLibPciExpress_LIB)\
+ $(EdkIIGlueDxeMemoryAllocationLib_LIB)\
+ $(EdkIIGlueBaseTimerLibLocalApic_LIB)\
+ $(EdkIIGlueDxeHobLib_LIB)\
+ $(EdkIIGlueHiiLib_LIB)\
+ $(EFIDRIVERLIB)\
+ $(UEFIEFIIFRSUPPORTLIB)\
+ $(CpuProtocolLib_LIB)\
+ $(CpuGuidLib_LIB)\
+ $(PchPlatformDxeLib_LIB)\
+ $(CpuPlatformLib_LIB)\
+ $(PpmAslUpdateLib_LIB)
+
+
+PowerMgmtDxeBin : $(PowerMgmtDxe_LIBS)
+ $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\
+ /f $(BUILD_DIR)\PowerMgmtDxe.mak all\
+ NAME=PowerMgmtDxe\
+ MAKEFILE=$(BUILD_DIR)\PowerMgmtDxe.mak \
+ "MY_INCLUDES=$(PowerMgmtDxe_MY_INCLUDES)" \
+ "MY_DEFINES=$(PowerMgmtDxe_DEFINES)"\
+ OBJECTS="$(PowerMgmtDxe_OBJECTS)" \
+ GUID=f7731b4c-58a2-4df4-8980-5645d39ece58\
+ ENTRY_POINT=_ModuleEntryPoint \
+ TYPE=RT_DRIVER \
+ EDKIIModule=DXEDRIVER\
+ DEPEX1=$(PowerMgmtDxe_DIR)\PowerMgmtDxe.dxs \
+ DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \
+ COMPRESS=1
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.sdl b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.sdl
new file mode 100644
index 0000000..af4c594
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtDxe.sdl
@@ -0,0 +1,25 @@
+TOKEN
+ Name = "Haswell_PowerMgmtDxe_SUPPORT"
+ Value = "1"
+ Help = "Main switch to enable Cpu Pei init support in Project"
+ TokenType = Boolean
+ TargetEQU = Yes
+ TargetMAK = Yes
+ TargetH = Yes
+ Master = Yes
+End
+
+PATH
+ Name = "PowerMgmtDxe_DIR"
+End
+
+MODULE
+ Help = "Includes PowerMgmtDxe.mak to Project"
+ File = "PowerMgmtDxe.mak"
+End
+
+ELINK
+ Name = "$(BUILD_DIR)\PowerMgmtDxe.ffs"
+ Parent = "FV_MAIN"
+ InvokeOrder = AfterParent
+End
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c
new file mode 100644
index 0000000..414167d
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.c
@@ -0,0 +1,840 @@
+/** @file
+ Processor Power Management initialization code. This code determines current
+ user configuration and modifies and loads ASL as well as initializing chipset
+ and processor features to enable the proper power management.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM - Thermal Monitor
+ IST - Intel(R) Speedstep technology
+ HT - Hyper-Threading Technology
+
+@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 "PowerMgmtInit.h"
+
+//
+// Global variables
+//
+#include <Protocol\GlobalNvsArea\GlobalNvsArea.h> // <<<<
+///
+/// Power Managment policy configurations
+///
+POWER_MGMT_CONFIG *mCpuPmConfig = NULL;
+EFI_CPUID_REGISTER mCpuid01 = { 0, 0, 0, 0 }; // CPUID 01 values
+//
+// Values for FVID table calculate.
+//
+UINT16 mTurboBusRatio = 0;
+UINT16 mMaxBusRatio = 0;
+UINT16 mMinBusRatio = 0;
+UINT16 mProcessorFlavor = 0;
+UINT16 mBspBootRatio = 0;
+UINT16 mPackageTdp = 0; ///< Processor TDP value in MSR_PACKAGE_POWER_SKU.
+UINT16 mPackageTdpWatt = 0; ///< Processor TDP value in Watts.
+UINT16 mCpuConfigTdpBootRatio = 0; ///< Config TDP Boot settings
+UINT16 mCustomPowerUnit = 1;
+UINT16 mCpuCacheSize = 0; ///< Cache Size in KB
+UINT8 mCpuPolicyRevision = 0;
+DXE_CPU_PLATFORM_POLICY_PROTOCOL *mCpuPlatformPolicy = NULL;
+
+///
+/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit)
+///
+UINT8 mProcessorPowerUnit = 0;
+///
+/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+UINT16 mPackageMaxPower = 0;
+///
+/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+UINT16 mPackageMinPower = 0;
+
+UINT8 mControllableTdpEnable = 0; ///< Controllable TDP enable/Disable
+UINT8 mRatioLimitProgrammble = 0; ///< Programmable Ratio Limit
+UINT8 mTdpLimitProgrammble = 0; ///< Porgrammable TDP Limit
+PPM_GLOBAL_NVS_AREA_PROTOCOL *mPpmGlobalNvsAreaProtocol = NULL; ///< Ppm GlobalNvs Protocol
+EFI_MP_SERVICES_PROTOCOL *mMpService = NULL; ///< Mp Services Protocol
+
+//
+// FVID Table Information
+// Default FVID table
+// One header field plus states
+//
+UINT16 mNumberOfStates = 0;
+FVID_TABLE mEmptyFvidTable[FVID_MAX_STATES + 1];
+FVID_TABLE *mFvidPointer = &mEmptyFvidTable[0];
+
+//
+// Globals to support updating ACPI Tables
+//
+EFI_ACPI_SUPPORT_PROTOCOL *mAcpiSupport = NULL;
+EFI_ACPI_TABLE_PROTOCOL *mAcpiTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mApIstTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mApCstTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mCpuPmTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mApTstTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mLakeTinyTable = NULL;
+EFI_ACPI_DESCRIPTION_HEADER *mCtdpTable = NULL;
+
+/**
+ Initialize the power management support.
+ This function will do boot time configuration:
+ Detect HW capabilities and SW configuration
+ Initialize HW and software state (primarily MSR and ACPI tables)
+
+ @param[in] ImageHandle Pointer to the loaded image protocol for this driver
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS The driver installes/initialized correctly.
+ @retval Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems.
+**/
+EFI_STATUS
+InitializePowerManagement (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ PPM_GLOBAL_NVS_AREA_PROTOCOL PpmGlobalNvsAreaProtocol;
+ EFI_GUID EfiPpmGlobalNvsAreaProtocolGuid = EFI_PPM_GLOBAL_NVS_AREA_PROTOCOL_GUID;
+
+ Handle = NULL;
+
+ ///
+ /// Locate platform configuration information
+ ///
+ Status = gBS->LocateProtocol (&gDxeCpuPlatformPolicyProtocolGuid, NULL, (VOID **) &mCpuPlatformPolicy);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Initialize the Global pointer for Power Managment Platform policy
+ ///
+ mCpuPmConfig = mCpuPlatformPolicy->PowerMgmtConfig;
+
+ Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (PPM_GLOBAL_NVS_AREA), (VOID **) &PpmGlobalNvsAreaProtocol.Area);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem ((VOID *) PpmGlobalNvsAreaProtocol.Area, sizeof (PPM_GLOBAL_NVS_AREA));
+
+ PpmGlobalNvsAreaProtocol.Area->Revision = PPM_GLOBAL_NVS_AREA_REVISION_1;
+ PpmGlobalNvsAreaProtocol.Area->MiscPowerManagementFlags |= mCpuPmConfig->pFunctionEnables->LakeTiny;
+
+ ///
+ /// Install Cpu Power management GlobalNVS Area protocol
+ ///
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &EfiPpmGlobalNvsAreaProtocolGuid,
+ &PpmGlobalNvsAreaProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DumpCpuPmConfig ();
+
+ ///
+ /// Locate the S3 resume scripting protocol
+ ///
+ INITIALIZE_SCRIPT (ImageHandle, SystemTable);
+
+ ///
+ /// Initialize Power management Global variables
+ ///
+ InitializePowerManagementGlobalVariables ();
+
+ ///
+ /// Initialize CPU Power management code (determine HW and configured state, configure hardware and software accordingly)
+ ///
+ Status = InitializePpm ();
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Install the PowerMgmtInitDone Protocol so that PowerMgmtS3 driver can load to save the MSRs for S3 resume
+ ///
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiPowerMgmtInitDoneProtocolGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes the platform power management global variable.
+ This must be called prior to any of the functions being used.
+
+ @retval EFI_SUCCESS Library was initialized successfully
+ @retval EFI_DEVICE_ERROR If CPU is not supported by this library
+**/
+VOID
+InitializePowerManagementGlobalVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ MSR_REGISTER TempMsr;
+ MSR_REGISTER PackagePowerSKUUnitMsr;
+ MSR_REGISTER PlatformInfoMsr;
+ EFI_GUID EfiMpServiceProtocolGuid = EFI_MP_SERVICES_PROTOCOL_GUID;
+ UINT16 Associativity;
+ UINT16 CachePartitions;
+ UINT16 CacheLineSize;
+ UINT16 CacheNumberofSets;
+ EFI_CPUID_REGISTER Cpuid04;
+// >>>>
+ EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsArea;
+ EFI_GUID gEfiGlobalNvsAreaProtocolGuid = EFI_GLOBAL_NVS_AREA_PROTOCOL_GUID;
+// <<<<
+ //
+ // Read the CPUID information
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &mCpuid01.RegEax, &mCpuid01.RegEbx, &mCpuid01.RegEcx, &mCpuid01.RegEdx);
+
+ ///
+ /// Locate Ppm GlobalNvs Protocol.
+ ///
+ Status = gBS->LocateProtocol (
+ &gPpmGlobalNvsAreaProtocolGuid,
+ NULL,
+ (VOID **) &mPpmGlobalNvsAreaProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Ppm GloableNvs protocol not found"));
+ }
+ ASSERT_EFI_ERROR (Status);
+ if (mPpmGlobalNvsAreaProtocol != NULL) {
+ mPpmGlobalNvsAreaProtocol->Area->Cpuid = GetCpuFamily() | GetCpuStepping();
+ }
+
+ ///
+ /// Locate MP service protocol
+ ///
+ Status = gBS->LocateProtocol (
+ &EfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **) &mMpService
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Get Platform ID by reading System Agent's Device ID (B0:D0:F0:R02)
+ ///
+ mProcessorFlavor = McD0PciCfg16 (R_SA_MC_DEVICE_ID);
+
+ //
+ // Read the CPUID4 information for LLC size
+ //
+ AsmCpuidEx (CPUID_FUNCTION_4, 0x3, &Cpuid04.RegEax, &Cpuid04.RegEbx, &Cpuid04.RegEcx, &Cpuid04.RegEdx);
+ //
+ // Determine Cache Size in Kilo Bytes
+ // This Cache Size in Bytes = (Associativity) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1)
+ // = (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1)
+ //
+ Associativity = (UINT16) (((Cpuid04.RegEbx >> 22) & CPU_CACHE_ASSOCIATIVITY_MASK) + 1);
+ CachePartitions = (UINT16) (((Cpuid04.RegEbx >> 12) & CPU_CACHE_PARTITION_MASK) + 1);
+ CacheLineSize = (UINT16) (((UINT16) Cpuid04.RegEbx & CPU_CACHE_LINE_SIZE_MASK) + 1);
+ CacheNumberofSets = (UINT16) (Cpuid04.RegEcx + 1);
+ mCpuCacheSize = (UINT16) ((Associativity * CachePartitions * CacheLineSize * CacheNumberofSets) / 1024);
+ ///
+ /// Get Maximum Non-Turbo bus ratio (HFM) from Platform Info MSR Bits[15:8]
+ ///
+ PlatformInfoMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO);
+ mMaxBusRatio = PlatformInfoMsr.Bytes.SecondByte;
+ ///
+ /// Get Maximum Efficiency bus ratio (LFM) from Platform Info MSR Bits[47:40]
+ ///
+ mMinBusRatio = PlatformInfoMsr.Bytes.SixthByte;
+ ///
+ /// Get Max Turbo Ratio from Turbo Ratio Limit MSR Bits [7:0]
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_TURBO_RATIO_LIMIT);
+ mTurboBusRatio = (UINT16) (TempMsr.Dwords.Low & B_MSR_TURBO_RATIO_LIMIT_1C);
+ ///
+ /// Check if Turbo Ratio Limit is programmable
+ /// Platform Info MSR (0xCE) [28]
+ ///
+ mRatioLimitProgrammble = (UINT8) RShiftU64 ((PlatformInfoMsr.Qword & B_PLATFORM_INFO_RATIO_LIMIT), 28);
+ ///
+ /// Check if TDP Limit is programmable
+ /// Platform Info MSR (0xCE) [29]
+ ///
+ mTdpLimitProgrammble = (UINT8) RShiftU64 ((PlatformInfoMsr.Qword & B_PLATFORM_INFO_TDC_TDP_LIMIT), 29);
+
+ ///
+ /// Get Processor TDP
+ /// Get Maximum Power from Turbo Power Limit MSR Bits[14:0]
+ /// and convert it to units specified by Package Power SKU
+ /// Unit MSR [3:0]
+ ///
+ TempMsr.Qword = EfiReadMsr (MSR_PACKAGE_POWER_SKU);
+ PackagePowerSKUUnitMsr.Qword = EfiReadMsr (MSR_PACKAGE_POWER_SKU_UNIT);
+ mProcessorPowerUnit = (PackagePowerSKUUnitMsr.Bytes.FirstByte & PACKAGE_POWER_UNIT_MASK);
+ if (mProcessorPowerUnit == 0) {
+ mProcessorPowerUnit = 1;
+ } else {
+ mProcessorPowerUnit = (UINT8) LShiftU64 (2, (mProcessorPowerUnit - 1));
+ }
+ mPackageTdp = (TempMsr.Dwords.Low & PACKAGE_TDP_POWER_MASK);
+ mPackageTdpWatt = (UINT16) DivU64x32 (mPackageTdp , mProcessorPowerUnit);
+ mPackageMaxPower = (UINT16) (TempMsr.Dwords.High & PACKAGE_MAX_POWER_MASK);
+ mPackageMinPower = (UINT16) RShiftU64 ((TempMsr.Dwords.Low & PACKAGE_MIN_POWER_MASK), 16);
+ mCpuPolicyRevision = mCpuPlatformPolicy->Revision;
+
+ ///
+ /// Set mCustomPowerUnit to user selected Power unit
+ ///
+ mCustomPowerUnit = 1;
+ if ((mCpuPlatformPolicy->Revision >= DXE_PLATFORM_CPU_POLICY_PROTOCOL_REVISION_6 )
+ && (mCpuPmConfig->CustomPowerUnit == PowerUnit125MilliWatts)) {
+ mCustomPowerUnit = 8; ///< Unit is 125 milli watt
+ }
+
+ ///
+ /// If specified, create a custom the FVID table.
+ /// (The settings populating the FVID table may not be correct for the
+ /// specific processor, and it is up to the user to specify settings
+ /// applicable to the processor being used.)
+ ///
+ ZeroMem (mFvidPointer, sizeof (mEmptyFvidTable));
+ if (mCpuPmConfig->pCustomRatioTable->NumberOfEntries >= 2) {
+ CreateCustomFvidTable (mFvidPointer);
+ }
+
+ ///
+ /// Initialize flags based on processor capablities
+ ///
+ SetPpmFlags ();
+
+ ///
+ /// Determine current user configuration
+ ///
+ SetUserConfigurationPpmFlags ();
+
+// >>>>
+ //
+ // Locate the Global NVS Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiGlobalNvsAreaProtocolGuid,
+ NULL, &GlobalNvsArea );
+ DEBUG((EFI_D_ERROR, "Status=gBS->LocateProtocol (&gEfiGlobalNvsAreaProtocolGuid) ===> %r !!!\n", Status));
+
+ if(!EFI_ERROR(Status)) {
+ GlobalNvsArea->Area->PpmFlags = mPpmGlobalNvsAreaProtocol->Area->PpmFlags;
+ }
+// <<<<
+ ///
+ /// Locate ACPI support protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, (VOID **) &mAcpiSupport);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable);
+ ASSERT_EFI_ERROR (Status);
+ return;
+}
+
+/**
+ Create a custom FVID table based on setup options.
+ Caller is responsible for providing a large enough table.
+
+ @param[in] FvidPointer Table to update, must be initialized.
+**/
+VOID
+CreateCustomFvidTable (
+ IN OUT FVID_TABLE *FvidPointer
+ )
+{
+ UINT16 Index;
+
+ ///
+ /// BWG Section 14.6.2 Determining Number of Operating Points
+ /// It is recommended that system BIOS limit the number of P states to 16
+ ///
+ if (mCpuPmConfig->pCustomRatioTable->NumberOfEntries > FVID_MAX_STATES) {
+ DEBUG (
+ (EFI_D_WARN,
+ "VidNumber(%d) is greater than maximum(%d) supported.",
+ mCpuPmConfig->pCustomRatioTable->NumberOfEntries,
+ FVID_MAX_STATES)
+ );
+ mCpuPmConfig->pCustomRatioTable->NumberOfEntries = FVID_MAX_STATES;
+ }
+ ///
+ /// Fill in the table header
+ ///
+ FvidPointer[0].FvidHeader.Stepping = mCpuPmConfig->pCustomRatioTable->Cpuid;
+ FvidPointer[0].FvidHeader.MaxBusRatio = mCpuPmConfig->pCustomRatioTable->MaxRatio;
+ FvidPointer[0].FvidHeader.Gv3States = mCpuPmConfig->pCustomRatioTable->NumberOfEntries;
+ ///
+ /// Fill in the state data
+ ///
+ for (Index = 0; Index < mCpuPmConfig->pCustomRatioTable->NumberOfEntries; Index++) {
+ FvidPointer[Index + 1].FvidState.State = Index;
+ FvidPointer[Index + 1].FvidState.BusRatio = mCpuPmConfig->pCustomRatioTable->StateRatio[Index];
+ }
+}
+
+/**
+ Set the PPM flags specific to Haswell processors
+
+ @retval EFI_SUCCESS PpmFlags updated with the features supported by the processor
+**/
+VOID
+SetPpmFlags (
+ VOID
+ )
+{
+ MSR_REGISTER CoreThreadCount;
+ MSR_REGISTER Ia32MiscEnable;
+ EFI_CPUID_REGISTER Cpuid01;
+ EFI_CPUID_REGISTER Cpuid05;
+ EFI_CPUID_REGISTER Cpuid06;
+ UINTN States;
+ BOOLEAN CpuidLimitingEnabled;
+ UINT32 PpmFlags;
+
+ ZeroMem (&Cpuid01, sizeof (Cpuid01));
+ ZeroMem (&Cpuid05, sizeof (Cpuid05));
+ ZeroMem (&Cpuid06, sizeof (Cpuid06));
+ PpmFlags = 0;
+
+ ///
+ /// Check if the processor has multiple cores
+ ///
+ CoreThreadCount.Qword = AsmReadMsr64 (MSR_CORE_THREAD_COUNT);
+ if ((CoreThreadCount.Dwords.Low & B_THREAD_COUNT_MASK) > 1) {
+ PpmFlags |= PPM_CMP;
+ }
+ if (mCpuid01.RegEdx & B_CPUID_VERSION_INFO_EDX_TM1) { ///< Check TM capable and update the flag
+ PpmFlags |= PPM_TM;
+ }
+ ///
+ /// Check EIST capable. If EIST capable, also set the boot P-state to HFM flag.
+ ///
+ if (mCpuid01.RegEcx & B_CPUID_VERSION_INFO_ECX_EIST) {
+ PpmFlags |= (PPM_EIST);
+ DEBUG ((EFI_D_INFO, "GV3 capable\n"));
+ }
+ ///
+ /// Disable CPUID limiting (and save current setting) if enabled
+ /// and enable MONITOR/MWAIT support
+ ///
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ CpuidLimitingEnabled = (BOOLEAN) (Ia32MiscEnable.Qword & B_MSR_IA32_MISC_ENABLE_CPUID_MAX);
+ if (CpuidLimitingEnabled) {
+ Ia32MiscEnable.Qword &= ~B_MSR_IA32_MISC_ENABLE_CPUID_MAX;
+ }
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+ ///
+ /// Read the CPUID values we care about. We cannot use the stored
+ /// values because they may have changes since we disabled limiting
+ /// and enabled MONITOR/MWAIT
+ ///
+ AsmCpuid (1, &Cpuid01.RegEax, &Cpuid01.RegEbx, &Cpuid01.RegEcx, &Cpuid01.RegEdx);
+ AsmCpuid (5, &Cpuid05.RegEax, &Cpuid05.RegEbx, &Cpuid05.RegEcx, &Cpuid05.RegEdx);
+ AsmCpuid (6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx);
+ ///
+ /// Determine if the MONITOR/MWAIT instructions are supported.
+ ///
+ if ((Cpuid01.RegEcx & B_CPUID_VERSION_INFO_ECX_MWAIT && Cpuid05.RegEcx & B_CPUID_MONITOR_MWAIT_ECX_EXTENSIONS)) {
+ PpmFlags |= PPM_MWAIT_EXT;
+ }
+ ///
+ /// Determine the C-State and Enhanced C-State support present.
+ /// Monitor/MWAIT parameters function describes the numbers supported.
+ ///
+ States = RShiftU64 (Cpuid05.RegEdx, 4) & 0xF;
+ if (States >= ENHANCED_CSTATE_SUPPORTED) {
+ PpmFlags |= PPM_C1 + PPM_C1E;
+ } else if (States == CSTATE_SUPPORTED) {
+ PpmFlags |= PPM_C1;
+ }
+ States = RShiftU64 (Cpuid05.RegEdx, 8) & 0xF;
+ if ((States >= CSTATE_SUPPORTED) && (PpmFlags & PPM_C1)) {
+ PpmFlags |= PPM_C3;
+ }
+ States = RShiftU64 (Cpuid05.RegEdx, 12) & 0xF;
+ if (States >= C6_C7_LONG_LATENCY_SUPPORTED) { // Both Long and Short Latency C6 supported
+ PpmFlags |= (PPM_C6 | C6_LONG_LATENCY_ENABLE);
+ } else if (States >= C6_C7_SHORT_LATENCY_SUPPORTED) { // Only Short Latency C6 supported.
+ PpmFlags |= PPM_C6;
+ }
+
+ States = RShiftU64 (Cpuid05.RegEdx, 16) & 0xF;
+ switch (States) {
+ case C7s_LONG_LATENCY_SUPPORTED:
+ //
+ // C7 & C7s Long and Short supported
+ //
+ PpmFlags |= (PPM_C7S | C7s_LONG_LATENCY_ENABLE | PPM_C7 | C7_LONG_LATENCY_ENABLE);
+ break;
+ case C7s_SHORT_LATENCY_SUPPORTED:
+ //
+ // C7s Long Latency is not supported.
+ //
+ PpmFlags |= (PPM_C7S | PPM_C7 | C7_LONG_LATENCY_ENABLE);
+ break;
+ case C6_C7_LONG_LATENCY_SUPPORTED:
+ //
+ // C7 Long and Short supported
+ //
+ PpmFlags |= (PPM_C7 | C7_LONG_LATENCY_ENABLE);
+ break;
+ case C6_C7_SHORT_LATENCY_SUPPORTED:
+ //
+ // C7 Long Latency is not supported.
+ //
+ PpmFlags |= PPM_C7;
+ break;
+ }
+
+ States = RShiftU64 (Cpuid05.RegEdx, 20) & 0xF;
+ if (States >= CSTATE_SUPPORTED) {
+ PpmFlags |= PPM_C8;
+ }
+ States = RShiftU64 (Cpuid05.RegEdx, 24) & 0xF;
+ if (States >= CSTATE_SUPPORTED) {
+ PpmFlags |= PPM_C9;
+ }
+ States = RShiftU64 (Cpuid05.RegEdx, 28) & 0xF;
+ if (States >= CSTATE_SUPPORTED) {
+ PpmFlags |= PPM_C10;
+ }
+ ///
+ /// Check TimedMwait is supported and update the flag
+ ///
+ if (AsmReadMsr64 (MSR_PLATFORM_INFO) & B_PLATFORM_INFO_TIMED_MWAIT_SUPPORTED) {
+ PpmFlags |= PPM_TIMED_MWAIT;
+ }
+ if (PpmFlags & (PPM_C8 |PPM_C9 | PPM_C10)) {
+ PpmFlags |= PPM_CD;
+ }
+ ///
+ /// Check if turbo mode is supported and update the flag
+ ///
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ if (((Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == 0) &&
+ ((Ia32MiscEnable.Qword & B_MSR_IA32_MISC_DISABLE_TURBO) == 0)
+ ) {
+ ///
+ /// Turbo Mode is not available in this physical processor package.
+ /// BIOS should not attempt to enable Turbo Mode via IA32_MISC_ENABLE MSR.
+ /// BIOS should show Turbo Mode as Disabled and Not Configurable.
+ ///
+ } else if ((Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == 0) {
+ ///
+ /// Turbo Mode is available but globally disabled for the all logical
+ /// processors in this processor package.
+ /// BIOS can enable Turbo Mode by IA32_MISC_ENABLE MSR 1A0h bit [38] = 0.
+ ///
+ PpmFlags |= PPM_TURBO;
+ } else if ((Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_TURBO) == B_CPUID_POWER_MANAGEMENT_EAX_TURBO) {
+ ///
+ /// Turbo Mode is factory-configured as available and enabled for all logical processors in this processor package.
+ /// This case handles the cases where turbo mode is enabled before PPM gets chance to enable it
+ ///
+ PpmFlags |= PPM_TURBO;
+ }
+ ///
+ /// Restore the CPUID limit setting.
+ ///
+ if (CpuidLimitingEnabled) {
+ Ia32MiscEnable.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ Ia32MiscEnable.Qword |= B_MSR_IA32_MISC_ENABLE_CPUID_MAX;
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+ }
+ PpmFlags |= PPM_TSTATES; ///< Set the T-states flag
+ ///
+ /// Determine if Fine grained clock modulation contol is supported
+ ///
+ if (Cpuid06.RegEax & B_CPUID_POWER_MANAGEMENT_EAX_FINE_GRAINED_CLOCK_MODULATION) {
+ PpmFlags |= PPM_TSTATE_FINE_GRAINED;
+ }
+ PpmFlags |= PPM_EEPST; ///< Energy Efficient P-state feature is supported
+ mPpmGlobalNvsAreaProtocol->Area->PpmFlags = PpmFlags; ///< Update the PPM NVS area PPM flags
+
+ return;
+}
+
+/**
+ Set the PPM flags based on current user configuration
+**/
+VOID
+SetUserConfigurationPpmFlags (
+ VOID
+ )
+{
+ UINT32 UserPpmFlag;
+ //
+ // In advance to clear following PPM flags which are related with policies that user can enabled/disabled.
+ //
+ UserPpmFlag = (UINT32)~(PPM_EIST | PPM_C1 | PPM_C1E | PPM_C3 | PPM_C6 | C6_LONG_LATENCY_ENABLE |
+ PPM_C7S | PPM_C7 | C7_LONG_LATENCY_ENABLE | C7s_LONG_LATENCY_ENABLE | PPM_CD |
+ PPM_C8 | PPM_C9 | PPM_C10 | PPM_TM | PPM_TURBO | PPM_TSTATES | PPM_TSTATE_FINE_GRAINED |
+ PPM_EEPST | PPM_TIMED_MWAIT);
+ ///
+ /// Configure flag based on user selections
+ ///
+ if (mCpuPmConfig->pFunctionEnables->Eist) {
+ UserPpmFlag |= PPM_EIST;
+ }
+ if (mCpuPmConfig->pFunctionEnables->Cx) {
+ UserPpmFlag |= PPM_C1;
+ if (mCpuPmConfig->pFunctionEnables->C1e) {
+ UserPpmFlag |= PPM_C1E;
+ }
+ if (mCpuPmConfig->pFunctionEnables->C3) {
+ UserPpmFlag |= PPM_C3;
+ }
+ if (mCpuPmConfig->pFunctionEnables->C6) {
+ UserPpmFlag |= PPM_C6;
+ }
+ if (mCpuPmConfig->pFunctionEnables->LongLatencyC6) {
+ UserPpmFlag |= C6_LONG_LATENCY_ENABLE;
+ }
+ switch (mCpuPmConfig->pFunctionEnables->DeepCState) {
+ case DeepC7S:
+ UserPpmFlag |= PPM_C7S;
+ case DeepC7:
+ UserPpmFlag |= PPM_C7;
+ break;
+ }
+ if (mCpuPmConfig->pFunctionEnables->LongLatencyC7) {
+ UserPpmFlag |= (C7_LONG_LATENCY_ENABLE | C7s_LONG_LATENCY_ENABLE);
+ }
+ if (mCpuPmConfig->pFunctionEnables->C8) {
+ UserPpmFlag |= PPM_C8;
+ }
+ if (mCpuPmConfig->pFunctionEnables->C9) {
+ UserPpmFlag |= PPM_C9;
+ }
+ if (mCpuPmConfig->pFunctionEnables->C10) {
+ UserPpmFlag |= PPM_C10;
+ }
+ if (UserPpmFlag & (PPM_C8 |PPM_C9 | PPM_C10)) {
+ UserPpmFlag |= PPM_CD;
+ }
+ }
+ if (mCpuPmConfig->ThermalFuncEnables->ThermalMonitor) {
+ UserPpmFlag |= PPM_TM;
+ }
+ if (mCpuPmConfig->pFunctionEnables->TurboMode) {
+ UserPpmFlag |= PPM_TURBO;
+ }
+ if (mCpuPmConfig->ThermalFuncEnables->TStates) {
+ UserPpmFlag |= (PPM_TSTATES | PPM_TSTATE_FINE_GRAINED);
+ }
+ if (mCpuPmConfig->pFunctionEnables->EnergyEfficientPState) {
+ UserPpmFlag |= PPM_EEPST;
+ }
+ if (mCpuPmConfig->pFunctionEnables->TimedMwait) {
+ UserPpmFlag |= PPM_TIMED_MWAIT;
+ }
+ ///
+ /// Modify PpmFlags based on user selections
+ ///
+ mPpmGlobalNvsAreaProtocol->Area->PpmFlags &= UserPpmFlag;
+}
+
+/**
+ Initialize the processor power management based on hardware capabilities
+ and user configuration settings.
+
+ @retval EFI_SUCCESS - on success
+ @retval Appropiate failure code on error
+**/
+EFI_STATUS
+InitializePpm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS CtdpSupport;
+
+ Status = EFI_SUCCESS;
+ CtdpSupport = EFI_UNSUPPORTED;
+
+ ///
+ /// Initialize Config TDP
+ ///
+ CtdpSupport = InitializeConfigurableTdp (mCpuPmConfig);
+
+ ///
+ /// Initialize P states
+ ///
+ InitializePStates();
+
+ ///
+ /// Initialize C State(IdleStates)
+ ///
+ InitializeCState(mCpuPmConfig);
+
+ //
+ // Patch P state table (Fvid table) with ctdp settings.
+ //
+ CtdpPatchFvidTable (mFvidPointer);
+
+ Status = InitializePpmAcpiTable ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ///
+ /// Initialize thermal features
+ ///
+ InitThermal (mCpuPmConfig);
+
+ ///
+ /// Initialise Miscellaneous features
+ ///
+ InitMiscFeatures(CtdpSupport);
+
+ ///
+ /// Complete with Ppmpost initialization
+ ///
+ PpmPostInit ();
+
+ return Status;
+}
+
+
+/**
+ This is a debug function to print PPM Policy
+**/
+VOID
+DumpCpuPmConfig (
+ VOID
+ )
+{
+#ifdef EFI_DEBUG
+ UINT32 Index;
+ DEBUG ((EFI_D_INFO, "\n\n------------------------ PowerMangement Policy dump Begin -----------------\n\n"));
+ DEBUG ((EFI_D_INFO, " S3RestoreMsrSwSmiNumber : %x\n", mCpuPmConfig->S3RestoreMsrSwSmiNumber));
+ DEBUG ((EFI_D_INFO, "\n Ppm Lock Enables... \n"));
+ DEBUG ((EFI_D_INFO, " PmgCstCfgCtrlLock : %x\n", mCpuPmConfig->pPpmLockEnables->PmgCstCfgCtrlLock));
+ DEBUG ((EFI_D_INFO, " ProcHotLock : %x\n", mCpuPmConfig->pPpmLockEnables->ProcHotLock));
+ DEBUG ((EFI_D_INFO, "\n FunctionEnables... \n"));
+ DEBUG ((EFI_D_INFO, " Eist : %x\n", mCpuPmConfig->pFunctionEnables->Eist));
+ DEBUG ((EFI_D_INFO, " Cx : %x\n", mCpuPmConfig->pFunctionEnables->Cx));
+ DEBUG ((EFI_D_INFO, " C1e : %x\n", mCpuPmConfig->pFunctionEnables->C1e));
+ DEBUG ((EFI_D_INFO, " C3 : %x\n", mCpuPmConfig->pFunctionEnables->C3));
+ DEBUG ((EFI_D_INFO, " C6 : %x\n", mCpuPmConfig->pFunctionEnables->C6));
+ DEBUG ((EFI_D_INFO, " C6 Long Latency: %x\n", mCpuPmConfig->pFunctionEnables->LongLatencyC6));
+ DEBUG ((EFI_D_INFO, " DeepCState : %x\n", mCpuPmConfig->pFunctionEnables->DeepCState));
+ DEBUG ((EFI_D_INFO, " C7 Long Latency : %x\n", mCpuPmConfig->pFunctionEnables->LongLatencyC7));
+ DEBUG ((EFI_D_INFO, " C1Autodemotion : %x\n", mCpuPmConfig->pFunctionEnables->C1AutoDemotion));
+ DEBUG ((EFI_D_INFO, " C3AutoDemotion : %x\n", mCpuPmConfig->pFunctionEnables->C3AutoDemotion));
+ DEBUG ((EFI_D_INFO, " C1Undemotion : %x\n", mCpuPmConfig->pFunctionEnables->C1UnDemotion));
+ DEBUG ((EFI_D_INFO, " C3UnDemotion : %x\n", mCpuPmConfig->pFunctionEnables->C3UnDemotion));
+ DEBUG ((EFI_D_INFO, " PkgCstateUndemotion : %x\n", mCpuPmConfig->pFunctionEnables->PkgCStateUnDemotion));
+ DEBUG ((EFI_D_INFO, " PkgCState Demotion : %x\n", mCpuPmConfig->pFunctionEnables->PkgCStateDemotion));
+ DEBUG ((EFI_D_INFO, " CStatePreWake : %x\n", mCpuPmConfig->pFunctionEnables->CStatePreWake));
+ DEBUG ((EFI_D_INFO, " TurboMode : %x\n", mCpuPmConfig->pFunctionEnables->TurboMode));
+ DEBUG ((EFI_D_INFO, " PowerLimit2 : %x\n", mCpuPmConfig->pFunctionEnables->PowerLimit2));
+ DEBUG ((EFI_D_INFO, " EnergyEfficientPState : %x\n", mCpuPmConfig->pFunctionEnables->EnergyEfficientPState));
+ DEBUG ((EFI_D_INFO, " LakeTiny Support : %x\n", mCpuPmConfig->pFunctionEnables->LakeTiny));
+ DEBUG ((EFI_D_INFO, " PkgCStateLimit : %x\n", mCpuPmConfig->PkgCStateLimit));
+ DEBUG ((EFI_D_INFO, " TimedMwait : %x\n", mCpuPmConfig->pFunctionEnables->TimedMwait));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl0TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl0TimeUnit));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl1TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl1TimeUnit));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl2TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl2TimeUnit));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl3TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl3TimeUnit));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl4TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl4TimeUnit));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl5TimeUnit : %x\n", mCpuPmConfig->CstateLatencyControl5TimeUnit));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl0Irtl : %x\n", mCpuPmConfig->CstateLatencyControl0Irtl));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl1Irtl : %x\n", mCpuPmConfig->CstateLatencyControl1Irtl));
+ DEBUG ((EFI_D_INFO, " CstateLatencyControl2Irtl : %x\n", mCpuPmConfig->CstateLatencyControl2Irtl));
+ DEBUG ((EFI_D_INFO, " RfiFreqTunningOffsetIsNegative : %x\n", mCpuPmConfig->RfiFreqTunningOffsetIsNegative));
+ DEBUG ((EFI_D_INFO, " RfiFreqTunningOffset : %x\n", mCpuPmConfig->RfiFreqTunningOffset));
+ DEBUG ((EFI_D_INFO, "\n Turbo settings... \n"));
+ DEBUG ((EFI_D_INFO, " PowerLimit1 : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit1));
+ DEBUG ((EFI_D_INFO, " PowerLimit1Time : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit1Time));
+ DEBUG ((EFI_D_INFO, " PowerLimit2 : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit2));
+ DEBUG ((EFI_D_INFO, " PowerLimit3 : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3));
+ DEBUG ((EFI_D_INFO, " PowerLimit3Time : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3Time));
+ DEBUG ((EFI_D_INFO, " PowerLimit3DutyCycle : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3DutyCycle));
+ DEBUG ((EFI_D_INFO, " PowerLimit3Lock : %x\n", mCpuPmConfig->pTurboSettings->PowerLimit3Lock));
+ DEBUG ((EFI_D_INFO, " TurboPowerLimitLock : %x\n", mCpuPmConfig->pTurboSettings->TurboPowerLimitLock));
+ DEBUG ((EFI_D_INFO, " ConfigTdpLevel : %x\n", mCpuPmConfig->pTurboSettings->ConfigTdpLevel));
+ DEBUG ((EFI_D_INFO, " ConfigTdpLock : %x\n", mCpuPmConfig->pTurboSettings->ConfigTdpLock));
+ DEBUG ((EFI_D_INFO, " ConfigTdpCustom : %x\n", mCpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom));
+ if (mCpuPmConfig->pCustomCtdpSettings->ConfigTdpCustom) {
+ DEBUG ((EFI_D_INFO, " CustomTdpCount : %d\n", mCpuPmConfig->pCustomCtdpSettings->CustomTdpCount));
+ DEBUG ((EFI_D_INFO, " CustomBootModeIndex : %d\n", mCpuPmConfig->pCustomCtdpSettings->CustomBootModeIndex));
+ for (Index = 0; Index < MAX_CUSTOM_CTDP_ENTRIES; Index++) {
+ DEBUG (
+ (EFI_D_INFO,
+ " CustomConfigTdpTable[%d] CustomPowerLimit1 : 0x%x\n",
+ Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ " CustomConfigTdpTable[%d] CustomPowerLimit2 : 0x%x\n",
+ Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit2)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ " CustomConfigTdpTable[%d] CustomPowerLimit1Time : %d\n",
+ Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomPowerLimit1Time)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ " CustomConfigTdpTable[%d] CustomTurboActivationRatio : %d\n",
+ Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomTurboActivationRatio)
+ );
+ DEBUG (
+ (EFI_D_INFO,
+ " ConfigTdpTable[%d] CustomConfigTdpControl : %d\n",
+ Index,mCpuPmConfig->pCustomCtdpSettings->CustomConfigTdpTable[Index].CustomConfigTdpControl)
+ );
+ }
+ }
+ DEBUG ((EFI_D_INFO, "\n CustomRatioTable... \n"));
+ DEBUG ((EFI_D_INFO, " VidNumber : %x\n", mCpuPmConfig->pCustomRatioTable->NumberOfEntries));
+ DEBUG ((EFI_D_INFO, " VidCpuid : %x\n", mCpuPmConfig->pCustomRatioTable->Cpuid));
+ DEBUG ((EFI_D_INFO, " VidMaxRatio : %x\n", mCpuPmConfig->pCustomRatioTable->MaxRatio));
+ for (Index = 0; Index < MAX_CUSTOM_RATIO_TABLE_ENTRIES; Index++) {
+ DEBUG ((EFI_D_INFO, " StateRatio[%d] : %x\n", Index, mCpuPmConfig->pCustomRatioTable->StateRatio[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n XeConfig... \n"));
+ DEBUG ((EFI_D_INFO, " Xe : %x\n", mCpuPmConfig->pFunctionEnables->Xe));
+ for (Index = 0; Index < 4; Index++) {
+ DEBUG ((EFI_D_INFO, " RatioLimit[%d] : %x\n", Index, mCpuPmConfig->pRatioLimit[Index]));
+ }
+ DEBUG ((EFI_D_INFO, " BiProcHot : %x\n", mCpuPmConfig->ThermalFuncEnables->BiProcHot));
+ DEBUG ((EFI_D_INFO, " DisableProcHotOut : %x\n", mCpuPmConfig->ThermalFuncEnables->DisableProcHotOut));
+ DEBUG ((EFI_D_INFO, " DisableVRThermalAlert : %x\n", mCpuPmConfig->ThermalFuncEnables->DisableVRThermalAlert));
+ DEBUG ((EFI_D_INFO, " ProcHotResponce : %x\n", mCpuPmConfig->ThermalFuncEnables->ProcHotResponce));
+ DEBUG ((EFI_D_INFO, " TStates : %x\n", mCpuPmConfig->ThermalFuncEnables->TStates));
+ DEBUG ((EFI_D_INFO, " AutoThermalReporting : %x\n", mCpuPmConfig->ThermalFuncEnables->AutoThermalReporting));
+ DEBUG ((EFI_D_INFO, " ThermalMonitor : %x\n", mCpuPmConfig->ThermalFuncEnables->ThermalMonitor));
+ DEBUG ((EFI_D_INFO, "\n\n------------------------ PowerMangement Policy dump End -------------------\n\n"));
+#endif
+}
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.h b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.h
new file mode 100644
index 0000000..9e138c6
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/PowerMgmtInit.h
@@ -0,0 +1,127 @@
+/** @file
+ This header file contains power management definitions specific to
+ Haswell processors.
+
+@copyright
+ Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+**/
+#ifndef _POWER_MANAGEMENT_H_
+#define _POWER_MANAGEMENT_H_
+
+#include "PowerMgmtCommon.h"
+
+//
+// Function prototypes
+//
+/**
+ Initialize the power management support.
+ This function will do boot time configuration:
+ Install into SMRAM/SMM
+ Detect HW capabilities and SW configuration
+ Initialize HW and software state (primarily MSR and ACPI tables)
+ Install SMI handlers for runtime interfacess
+
+ @param[in] ImageHandle Pointer to the loaded image protocol for this driver
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS The driver installed/initialized correctly.
+ @retval Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems.
+**/
+EFI_STATUS
+InitializePowerManagement (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Initializes the CPU power management global variable.
+ This must be called prior to any of the functions being used.
+
+ @retval EFI_SUCCESS Library was initialized successfully
+ @retval EFI_DEVICE_ERROR If CPU is not supported by this library
+**/
+VOID
+InitializePowerManagementGlobalVariables (
+ VOID
+ );
+
+/**
+ Create a custom FVID table based on setup options.
+ Caller is responsible for providing a large enough table.
+
+ @param[in] FvidPointer Table to update, must be initialized.
+**/
+VOID
+CreateCustomFvidTable (
+ IN OUT FVID_TABLE *FvidPointer
+ );
+
+/**
+ Sets up the PPM flags based upon capabilities
+
+ @param[in] This - None
+
+ @retval EFI_STATUS
+**/
+VOID
+SetPpmFlags (
+ VOID
+ );
+
+/**
+ Set the PPM flags based on current user configuration obtained from PPM platform policy protocol
+
+ @param[in] PpmFlagsMask Mask of feature options to be enabled as specified by the policy
+**/
+VOID
+SetUserConfigurationPpmFlags (
+ );
+
+/**
+ Initialize the platform power management based on hardware capabilities
+ and user configuration settings.
+
+ This includes creating FVID table, updating ACPI tables,
+ and updating processor and chipset hardware configuration.
+
+ This should be called prior to any Px, Cx, Tx activity.
+
+ @retval EFI_SUCCESS - on success
+ @retval Appropiate failure code on error
+**/
+EFI_STATUS
+InitializePpm (
+ VOID
+ );
+
+/**
+ This is a debug function to print PPM Policy
+**/
+VOID
+DumpCpuPmConfig (
+ VOID
+ );
+
+/**
+ This is a debug function to print PPM Global NVS area
+**/
+VOID
+DumpPPMGlobalNvs (
+ VOID
+ );
+
+#endif
diff --git a/ReferenceCode/Haswell/PowerManagement/Dxe/Thermal.c b/ReferenceCode/Haswell/PowerManagement/Dxe/Thermal.c
new file mode 100644
index 0000000..d60635e
--- /dev/null
+++ b/ReferenceCode/Haswell/PowerManagement/Dxe/Thermal.c
@@ -0,0 +1,301 @@
+/** @file
+ This library contains power management configuration functions for
+ Haswell processors.
+
+ Acronyms:
+ PPM - Processor Power Management
+ TM - Thermal Monitor
+ IST - Intel(R) Speedstep technology
+ HT - Hyper-Threading Technology
+
+@copyright
+ Copyright (c) 2012 - 2014 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 "PowerMgmtCommon.h"
+
+/**
+ This will perform general thermal initialization other then TM1, TM2, or
+ PROCHOT# on all logical processors.
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+ @param[in] PpmGlobalNvsAreaProtocol Pointer to PPM Global Nvs area
+
+ @retval EFI_SUCCESS General thermal initialization completed successfully
+**/
+VOID
+InitThermal (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ MSR_REGISTER TempMsr;
+ UINT8 MaxRefTemp;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuStepping;
+ UINT8 TccActivationOffsetMask;
+
+ ///
+ /// Run thermal code on all logical processors.
+ ///
+ RunOnAllLogicalProcessors (ApSafeInitThermal, CpuPmConfig);
+ ///
+ /// Automatic Thermal Reporting for Thermal Management
+ ///
+ if (CpuPmConfig->ThermalFuncEnables->AutoThermalReporting) {
+ ///
+ /// Thermal Reporting for Critical trip
+ /// MSR 1A2 bits 23:16 define the temperature that this specific processor can
+ /// function upto. It is recommended that this value + 5 be used as default Critical trip point
+ /// _CRT.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_TEMPERATURE_TARGET);
+ TempMsr.Qword &= B_MSR_TEMPERATURE_TARGET_TCC_ACTIVATION_TEMPERATURE_MASK;
+ MaxRefTemp = (UINT8) RShiftU64 (TempMsr.Qword, N_MSR_TEMPERATURE_TARGET_TCC_ACTIVATION_TEMPERATURE_OFFSET);
+ mPpmGlobalNvsAreaProtocol->Area->AutoCriticalTripPoint = MaxRefTemp + 5;
+ ///
+ /// Thermal Reporting for Active Thermal Management
+ /// It is recommended that the processor specific value in MSR 1A2 bits 15:8
+ /// be used as the highest Active trip point i.e. _AC0.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_TEMPERATURE_TARGET);
+ TempMsr.Qword &= B_MSR_TEMPERATURE_TARGET_FAN_TEMP_TARGET_OFFSET;
+ mPpmGlobalNvsAreaProtocol->Area->AutoActiveTripPoint = MaxRefTemp - (UINT8) RShiftU64 (
+ TempMsr.Qword,
+ N_MSR_TEMPERATURE_TARGET_FAN_TEMP_TARGET_OFFSET
+ );
+
+ ///
+ /// Tcc activation offset in temperature target MSR changes from 4 bits [27:24] to 6 bits [29:24] on ULT C step onwards
+ ///
+ CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ CpuStepping = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING;
+ if ((CpuFamilyId == EnumCpuHswUlt) && (CpuStepping >= EnumHswUltC0)) {
+ TccActivationOffsetMask = 0x3F;
+ } else {
+ TccActivationOffsetMask = 0xF;
+ }
+
+ ///
+ /// Thermal Reporting for Passive Thermal Management
+ /// On all turbo enabled systems, it is recommended that the ACPI _PSV point be
+ /// set to a temperature above the Active cooling temperature and Tcc activation
+ /// temperature.
+ /// If platform embedded controller will issue PECI commands to reduce power as a
+ /// passive thermal action, then it is recommended to use the package's max temperature
+ /// for passive thermal control.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_TEMPERATURE_TARGET);
+ TempMsr.Qword &= (TccActivationOffsetMask << N_MSR_TEMPERATURE_TARGET_TCC_OFFSET_LIMIT);
+ mPpmGlobalNvsAreaProtocol->Area->AutoPassiveTripPoint = mPpmGlobalNvsAreaProtocol->Area->AutoCriticalTripPoint+3;
+ }
+
+ EnableProcHot ();
+ return;
+}
+
+/**
+ This will perform enable thermal initialization. TM1, TM2 and adaptive thermal
+ throttling are enabled/disabled together.
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to the function parameters passed in.
+
+ @retval EFI_SUCCESS General thermal initialization completed successfully
+**/
+VOID
+EFIAPI
+ApSafeInitThermal (
+ IN OUT VOID *Buffer
+ )
+{
+ MSR_REGISTER TempMsr;
+ POWER_MGMT_CONFIG *This;
+
+ ///
+ /// Extract parameters from the buffer
+ ///
+ This = (POWER_MGMT_CONFIG *) Buffer;
+ ///
+ /// Configure Adaptive thermal monitor. IA32_MISC_ENABLE[3]
+ /// HSW BWG (1A0h)IA32_MISC_ENABLE - Bit3:Intel Adaptive Thermal Monitor Enable
+ /// System BIOS must always set this bit to be operating within spec.
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
+ TempMsr.Dwords.Low |= B_MSR_IA32_MISC_ENABLE_TME;
+ if (This->ThermalFuncEnables->ThermalMonitor == 0) {
+ TempMsr.Dwords.Low &= ~B_MSR_IA32_MISC_ENABLE_TME;
+ }
+ AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, TempMsr.Qword);
+ ///
+ /// Set the Lock TM interrupt bit so that thermal interrupts are routed to all the cores
+ ///
+ TempMsr.Qword = AsmReadMsr64 (MSR_MISC_PWR_MGMT);
+ TempMsr.Qword |= B_MSR_MISC_PWR_MGMT_LTMI;
+ AsmWriteMsr64 (MSR_MISC_PWR_MGMT, TempMsr.Qword);
+ ///
+ /// Enable Critical Temperature Interrupt
+ ///
+ TempMsr.Qword = AsmReadMsr64 (IA32_THERM_INTERRUPT);
+ TempMsr.Qword |= B_IA32_THERM_INTERRUPT_VIE;
+ AsmWriteMsr64 (IA32_THERM_INTERRUPT, TempMsr.Qword);
+
+ return;
+}
+
+/**
+ Enables the bi-directional PROCHOT# signal.
+
+ @retval EFI_SUCCESS PROCHOT# configured successfully
+**/
+EFI_STATUS
+EnableProcHot (
+ VOID
+ )
+{
+ MSR_REGISTER PowerCtl;
+
+ ///
+ /// Enable PROCHOT# in the CPU MSR if TM is enabled,
+ /// else disable it.
+ ///
+ PowerCtl.Qword = AsmReadMsr64 (MSR_POWER_CTL);
+ if (mPpmGlobalNvsAreaProtocol->Area->PpmFlags & (PPM_TM)) {
+ PowerCtl.Qword &= ~B_MSR_POWER_CTL_DISABLE_VR_THERMAL_ALERT;
+ if ((mCpuPmConfig->ThermalFuncEnables->DisableVRThermalAlert == 1)) {
+ DEBUG ((EFI_D_INFO, "VR Thermal Alert is disabled\n"));
+ PowerCtl.Qword |= B_MSR_POWER_CTL_DISABLE_VR_THERMAL_ALERT;
+ }
+ ///
+ /// Check PROCHOT Lock,skip programming the below as it will lock bits 0, 21, 22
+ ///
+ if (!(PowerCtl.Qword & B_MSR_POWER_CTL_PROC_HOT_LOCK)) {
+ PowerCtl.Qword &= ~B_MSR_POWER_CTL_BROCHOT;
+ if (mCpuPmConfig->ThermalFuncEnables->BiProcHot) {
+ PowerCtl.Qword |= B_MSR_POWER_CTL_BROCHOT;
+ ///
+ /// Initialize PROCHOT# OUT basing on Bi-directional PROCHOT# setting
+ /// If Bi-directional PROCHOT# is enabled, PROCHOT# OUT can be disabled selectively
+ ///
+ PowerCtl.Qword &= ~B_MSR_POWER_CTL_DISABLE_PHOT_OUT;
+ if ((mCpuPmConfig->ThermalFuncEnables->DisableProcHotOut == 1)) {
+ DEBUG ((EFI_D_INFO, "PROCHOT# OUT is disabled\n"));
+ PowerCtl.Qword |= B_MSR_POWER_CTL_DISABLE_PHOT_OUT;
+ }
+ }
+ PowerCtl.Qword &= ~B_MSR_POWER_CTL_PROC_HOT_RESPONSE;
+ if ((mCpuPmConfig->ThermalFuncEnables->ProcHotResponce == 1)) {
+ DEBUG ((EFI_D_INFO, "PROCHOT# Response is enabled\n"));
+ PowerCtl.Qword |= B_MSR_POWER_CTL_PROC_HOT_RESPONSE;
+ }
+ }
+ AsmWriteMsr64 (MSR_POWER_CTL, PowerCtl.Qword);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This will perform PowerLimit 1 algorithm will be used to control Thermal Throttling features
+
+ @param[in] CpuPmConfig Pointer to policy protocol instance
+**/
+VOID
+InitPl1ThermalControl (
+ IN OUT POWER_MGMT_CONFIG *CpuPmConfig
+ )
+{
+ UINT32 MailBoxStatus;
+ PL1_THERMAL_CONTROL WritePL1ThermalControl;
+ PL1_THERMAL_CONTROL ReadPL1ThermalControl;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ MSR_REGISTER PakagePowerLimitMsr;
+ UINTN PciD0F0RegBase;
+ UINTN MchBar;
+
+ MailBoxStatus = 0;
+ ReadPL1ThermalControl.Uint32 = 0;
+ WritePL1ThermalControl.Uint32 = 0;
+
+ CpuFamilyId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_FAMILY_MODEL;
+ CpuSteppingId = mPpmGlobalNvsAreaProtocol->Area->Cpuid & CPUID_FULL_STEPPING;
+
+
+ if (((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId >= EnumHswUltC0))
+ || ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0))
+ || ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))
+ ) {
+ ///
+ /// If User selects Auto,Enable by default on ULX and disable on orther processor
+ ///
+ if (CpuPmConfig->ThermalFuncEnables->Pl1ThermalControl == 1) { // 0 = disable, 1 = enable (manual), 2 = auto
+ WritePL1ThermalControl.Bits.Disable = 0;
+ } else if (CpuPmConfig->ThermalFuncEnables->Pl1ThermalControl == 2) {
+ if (mPackageTdp < 15 * mProcessorPowerUnit) { // ULX
+ WritePL1ThermalControl.Bits.Disable = 0;
+ } else {
+ WritePL1ThermalControl.Bits.Disable = 1;
+ }
+ } else {
+ WritePL1ThermalControl.Bits.Disable = 1;
+ }
+ if (mCpuPolicyRevision >= 7) {
+ WritePL1ThermalControl.Bits.FloorIA = CpuPmConfig->ThermalFuncEnables->Pl1ThermalControlFloor.FloorIA;
+ WritePL1ThermalControl.Bits.FloorGT = CpuPmConfig->ThermalFuncEnables->Pl1ThermalControlFloor.FloorGT;
+ WritePL1ThermalControl.Bits.FloorPCH = CpuPmConfig->ThermalFuncEnables->Pl1ThermalControlFloor.FloorPCH;
+ }
+
+ MailboxRead(MAILBOX_TYPE_PCODE, READ_PL1_DUTY_CYCLE_CLAMP_ENABLE, (UINT32 *) &ReadPL1ThermalControl, &MailBoxStatus);
+ if (MailBoxStatus != PCODE_MAILBOX_CC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Failure to read PowerLimit1 duty sysle clamp enable. \n"));
+ return;
+ }
+ DEBUG ((EFI_D_INFO, "Current Pl1ThermalControl reading from Mailbox : %d. Requested setting to Mailbox: %d\n", ReadPL1ThermalControl.Uint32, WritePL1ThermalControl.Uint32));
+ ///
+ /// If Mailbox returns differnt from user selection send command to set user selection
+ ///
+ if (ReadPL1ThermalControl.Uint32 != WritePL1ThermalControl.Uint32) {
+ MailboxWrite(MAILBOX_TYPE_PCODE, WRITE_PL1_DUTY_CYCLE_CLAMP_ENABLE, WritePL1ThermalControl.Uint32,&MailBoxStatus);
+ if (MailBoxStatus != PCODE_MAILBOX_CC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Failure to write PowerLimit1 duty sysle clamp enable. \n"));
+ return;
+ }
+ }
+ MailboxS3Write(WRITE_PL1_DUTY_CYCLE_CLAMP_ENABLE, WritePL1ThermalControl.Uint32);
+
+ ///
+ /// Set PACKAGE_POWER_LIMIT.CRITICAL_POWER_CLAMP_1(bit 16)
+ /// And MMIO_TURBO_POWER_LIMIT.CRITICAL_POWER_CLAMP_1(bit 16)
+ ///
+ PakagePowerLimitMsr.Qword = AsmReadMsr64 (MSR_PACKAGE_POWER_LIMIT);
+ PakagePowerLimitMsr.Dwords.Low |= B_CRITICAL_POWER_CLAMP_ENABLE;
+ AsmWriteMsr64 (MSR_PACKAGE_POWER_LIMIT, PakagePowerLimitMsr.Qword);
+
+ PciD0F0RegBase = MmPciAddress (0, 0, 0, 0, 0);
+ MchBar = MmioRead32 (PciD0F0RegBase + 0x48) &~BIT0;
+ MmioOr32 (MchBar + MMIO_TURBO_POWER_LIMIT, B_CRITICAL_POWER_CLAMP_ENABLE);
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT),
+ 1,
+ (VOID *) (UINTN) (MchBar + MMIO_TURBO_POWER_LIMIT)
+ );
+ }
+ return;
+}