summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c')
-rw-r--r--ReferenceCode/Haswell/PowerManagement/Dxe/PowerLimits.c1302
1 files changed, 1302 insertions, 0 deletions
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;
+}
+