summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-06-02 13:29:01 +0800
committerHao Wu <hao.a.wu@intel.com>2016-06-07 09:55:25 +0800
commite53f60302eb2449e230a6a42049718b5d32da2f0 (patch)
treec9049294433383930479e9c3ab1b15c9f1d804a7
parentbefee680da22361fa18b97ec5838b7b67fce81d5 (diff)
downloadedk2-platforms-e53f60302eb2449e230a6a42049718b5d32da2f0.tar.xz
ChvRefCodePkg: Add PowerManagement Smm module.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
-rw-r--r--ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.c183
-rw-r--r--ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.h104
-rw-r--r--ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.inf75
-rw-r--r--ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/Ppm.h452
-rw-r--r--ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmInitialization.c1280
-rw-r--r--ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmRuntime.c505
6 files changed, 2599 insertions, 0 deletions
diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.c b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.c
new file mode 100644
index 0000000000..8c1c997aed
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.c
@@ -0,0 +1,183 @@
+/** @file
+ Power management driver.
+ This SMM driver configures and supports the power management features
+ for the platform.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Statements that include other files
+//
+#include "PowerManagement.h"
+
+//
+// Global variables
+//
+
+//
+// FVID Table Information (Must be initialized by caller)
+//
+extern FVID_TABLE *mFvidPointer;
+
+//
+// PPM Processor support protocol
+//
+PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *mPpmProcessorSupportProtocol = NULL;
+
+//
+// Desired platform policy information
+//
+PPM_PLATFORM_POLICY_PROTOCOL mPpmPlatformPolicyProtocol;
+
+//
+// Globals used by the reference code
+//
+EFI_GLOBAL_NVS_AREA *mGlobalNvsAreaPtr = NULL;
+UINT16 mNumberOfStates = 0;
+UINT16 mNumberOfStatesTurbo = 0;
+
+//
+// Driver entry point
+//
+
+/**
+ PPM must restore runtime state of MSR. This is not supported by the S3 boot script.
+ In order to accomplish this, the ASL is modified to generate an SMI on S3 in the _WAK method.
+ This SMI handler reponds to that SW SMI.
+
+ @param[in]
+
+ DispatchHandle - The handle of this callback, obtained when registering
+ DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
+
+ @retval
+
+ None.
+
+**/
+EFI_STATUS
+S3RestoreMsrCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *DispatchContext,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN UINTN *CommBufferSize OPTIONAL
+ )
+{
+ mPpmProcessorSupportProtocol->S3RestoreMsr (mPpmProcessorSupportProtocol);
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+ SystemTable - Pointer to the EFI System Table
+
+ @retval
+
+ EFI_SUCCESS The driver installes/initialized correctly.
+ Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePowerManagement (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_HANDLE SwHandle;
+
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
+ EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsAreaProtocol;
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;
+
+ PPM_PLATFORM_POLICY_PROTOCOL *PpmPlatformPolicyProtocolPointer;
+
+ Handle = NULL;
+ SwHandle = NULL;
+
+ //
+ // Locate the ICH SMM SW dispatch protocol
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **) &SwDispatch);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate our shared data area
+ //
+ Status = gBS->LocateProtocol (&gEfiGlobalNvsAreaProtocolGuid, NULL, (VOID **) &GlobalNvsAreaProtocol);
+ ASSERT_EFI_ERROR (Status);
+ mGlobalNvsAreaPtr = GlobalNvsAreaProtocol->Area;
+
+ //
+ // Locate platform configuration information
+ // Then copy it to a global variable that we can utilize during SMM/Runtime
+ //
+ Status = gBS->LocateProtocol (&gPpmPlatformPolicyProtocolGuid, NULL, (VOID **) &PpmPlatformPolicyProtocolPointer);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (&mPpmPlatformPolicyProtocol, PpmPlatformPolicyProtocolPointer, sizeof (PPM_PLATFORM_POLICY_PROTOCOL));
+
+ //
+ // Initialize the PPM processor support protocol
+ // This is not currently a publicly exposed protocol, so the
+ // library just returns an updated pointer to the protocol
+ // rather then using locate protocol services.
+ //
+
+ mPpmProcessorSupportProtocol = NULL;
+ InitializeCherryviewPowerManagementLib(&mPpmProcessorSupportProtocol);
+
+ if (mPpmProcessorSupportProtocol == NULL) {
+ ASSERT(mPpmProcessorSupportProtocol != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Processor support library may or may not provide a P state transition function
+ // If it does not, we fill in a generic function
+ //
+ if (mPpmProcessorSupportProtocol->PStateTransition == NULL) {
+ mPpmProcessorSupportProtocol->PStateTransition = PpmTransition;
+ }
+
+ InitializeAslUpdateLib ();
+
+ //
+ // Register ACPI S3 MSR restore handler
+ //
+ SwContext.SwSmiInputValue = mPpmPlatformPolicyProtocol.S3RestoreMsrSwSmiNumber;
+ Status = SwDispatch->Register (
+ SwDispatch,
+ (EFI_SMM_HANDLER_ENTRY_POINT2) S3RestoreMsrCallback,
+ &SwContext,
+ &SwHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize PPM code (determine HW and configured state, configure hardware and software accordingly
+ //
+ InitializePpm (mPpmProcessorSupportProtocol);
+
+ return EFI_SUCCESS;
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.h b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.h
new file mode 100644
index 0000000000..9de6daadb8
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.h
@@ -0,0 +1,104 @@
+/** @file
+ Header file for the power management driver.
+ This driver loads power management support designed to be similar to
+ the mobile platform power management reference code.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _POWER_MANAGEMENT_H_
+#define _POWER_MANAGEMENT_H_
+
+//
+// Statements that include other files
+//
+#include <PiDxe.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/GlobalNvsArea.h>
+#include <Protocol/PpmPlatformPolicy.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadedImage.h>
+#include <Library/AslUpdateLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Guid/PowerManagementAcpiTableStorage.h>
+
+#include <Ppm.h>
+#include <CpuPpmLib.h>
+#include <PchAccess.h>
+
+typedef struct {
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+} EFI_CPUID_REGISTER;
+
+//
+// Callback function prototypes
+//
+/**
+ PPM must restore runtime state of MSR. This is not supported by the S3 boot script.
+ In order to accomplish this, the ASL is modified to generate an SMI on S3 in the _WAK method.
+ This SMI handler reponds to that SW SMI.
+
+ @param[in]
+
+ DispatchHandle - The handle of this callback, obtained when registering
+ DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
+
+ @retval
+
+ None.
+
+**/
+EFI_STATUS
+S3RestoreMsrCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *DispatchContext,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN UINTN *CommBufferSize OPTIONAL
+ );
+
+///VLV not support for Io Trap method
+/**
+ 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
+ SystemTable - Pointer to the EFI System Table
+
+ @retval
+
+ EFI_SUCCESS The driver installed/initialized correctly.
+ Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePowerManagement (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif
diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.inf b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.inf
new file mode 100644
index 0000000000..183613e1f8
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PowerManagement.inf
@@ -0,0 +1,75 @@
+## @file
+# Cpu Power Management Module
+#
+# Provides support to enable and utilize different power management features in
+# processors. This includes both P-States and C-States as well as
+# thermal protection features.
+#
+# Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PowerManagement2
+ FILE_GUID = 5BED7FD0-3B2F-4FEF-B323-D650085379B6
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = InitializePowerManagement
+
+[sources.common]
+ PowerManagement.h
+ PowerManagement.c
+ Ppm.h
+ PpmInitialization.c
+ PpmRuntime.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ChvRefCodePkg/ChvRefCodePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ S3BootScriptLib
+ DxeServicesTableLib
+ IoLib
+ PcdLib
+ AslUpdateLib
+ CherryviewPpmLib
+ SilvermontPpmLib
+ MemoryAllocationLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES
+
+[Guids]
+ gPowerManagementAcpiTableStorageGuid ## CONSUMES ## FV
+
+[Protocols]
+ gEfiSmmBase2ProtocolGuid ## CONSUMES
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiGlobalNvsAreaProtocolGuid ## CONSUMES
+ gPpmPlatformPolicyProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiAcpiSdtProtocolGuid ## CONSUMES
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiAcpiSdtProtocolGuid AND
+ gEfiAcpiTableProtocolGuid AND
+ gEfiSmmBase2ProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiGlobalNvsAreaProtocolGuid AND
+ gPpmPlatformPolicyProtocolGuid
+
+
diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/Ppm.h b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/Ppm.h
new file mode 100644
index 0000000000..6e2eae37d6
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/Ppm.h
@@ -0,0 +1,452 @@
+/** @file
+ IST/PPM reference code definitions.
+
+ Acronyms:
+ PPM Platform Power Management
+ GV Geyserville
+ TM Thermal Monitor
+ IST Intel(R) Speedstep technology
+ HT Hyper-Threading Technology
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PPM_H_
+#define _PPM_H_
+
+//
+// Statements that include other files
+//
+#include "PiDxe.h"
+#include "PpmCommon.h"
+#include "Protocol/PpmProcessorSupport2.h"
+#include <Library/AslUpdateLib.h>
+//
+// This is not a standard protocol, as it is never published.
+// It is more of a dynamic internal library.
+//
+
+#define PPM_IO_TRAP_LENGTH 0x10
+
+#define PM_PM1_STS R_PCH_ACPI_PM1_STS
+
+#define PM_PM1_CNT R_PCH_ACPI_PM1_CNT
+ #define PM_BM_RELOAD B_PCH_ACPI_PM1_CNT_BM_RLD
+
+#define PM_CST_LVL2 0x14
+
+#define SMI_PSTATE_LATENCY 110
+#define NATIVE_PSTATE_LATENCY 10
+#define PSTATE_BM_LATENCY 10
+
+#define FADT_C2_LATENCY 1
+#define FADT_C2_LATENCY_DISABLED 101
+#define FADT_C3_LATENCY 57
+#define FADT_C3_LATENCY_DISABLED 1001
+
+#define CSTATE_TRANSITION_C2 2
+#define CSTATE_TRANSITION_C3 3
+#define CSTATE_TRANSITION_C4 4
+
+#define C3_RESIDENCY_TIMER_ROLLOVER_BIT (1 << 24)
+
+#define ICHX_C3_RES 0x54
+
+//
+// MSR definitions
+//
+
+#define EFI_MSR_TIME_STAMP_COUNTER 0x10
+
+#define MSR_PM_CFG_CTRL 0xE2
+ #define TM1_ENABLE (1 << 3)
+
+#define MSR_IA32_PERF_STS 0x198
+ #define IA32_PERF_STS_VIP (1 << 17)
+
+#define MSR_IA32_PERF_CTL 0x199
+ #define VID_BYTE_MASK 0x3F
+ #define RATIO_BYTE_MASK 0x1F
+ #define RATIO_N2 (1 << 14)
+ #define DYNAMIC_FSB_CONTROL_ENABLE (1 << 15)
+ #define PSTATE_CTL_MASK (DYNAMIC_FSB_CONTROL_ENABLE | RATIO_N2 | (RATIO_BYTE_MASK << 8) | VID_BYTE_MASK)
+
+//#define EFI_MSR_IA32_MISC_ENABLE 0x1A0
+ #define FERR_MUX_ENABLE (1 << 10)
+
+//
+// Save-state definitions
+//
+#define SYNC_SMI_BIT (1 << 0)
+
+//
+// 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 CFGD structure layout
+//
+#pragma pack (1)
+typedef struct {
+ UINT8 NameOp; // Byte [0]=0x08:NameOp.
+ UINT32 NameString; // Byte [4:1]=Name of object.
+ UINT8 DWordPrefix; // Byte [5]=0x0C:DWord Prefix.
+ UINT32 Value; // 0 ; Value of named object.
+} CFGD_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;
+
+//
+// Private Driver Data
+//
+//
+// Define Union of IO APIC & Local APIC structure;
+//
+typedef union {
+ EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic;
+ EFI_ACPI_2_0_IO_APIC_STRUCTURE AcpiIoApic;
+ struct {
+ UINT8 Type;
+ UINT8 Length;
+ } AcpiApicCommon;
+} ACPI_APIC_STRUCTURE_PTR;
+
+#pragma pack()
+//
+// Function prototypes
+//
+
+/**
+ Initialize the processor 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.
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+InitializePpm (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ Initialize global variables used during PPM init
+ miFSBFrequency - CDV iFSB Freqeuncy
+ mCpuid01 - Set to CPUID01 values
+ mFvidPointer - Set FVID states
+ mAcpiSupport - Set ACPI support protocol instance
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+PpmPreInit (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ 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
+
+ @retval None
+
+**/
+VOID
+SetUserConfigurationPpmFlagsMask (
+ IN OUT UINT32 *PpmFlagsMask
+ );
+
+/**
+ Patch the SMI _PSS (SPSS) package with performance values and the native _PSS (NPSS) package with the GV3 values
+
+ Uses ratio/VID values from the FVID table to fix up the control values in the NPSS and SPSS.
+
+ (1) Find NPSS or SPSS package:
+ (1.1) Find the _PR_CPU0 scope.
+ (1.2) Save a pointer to the package length.
+ (1.3) Find the NPSS or SPSS AML name object.
+ (2) Resize the NPSS and SPSS package.
+ (3) Fix up the NPSS and SPSS 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.
+ (6) Renames PSS packages for ACPI utility evaluation
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+AcpiPatchSpssNpss (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ Enable FERR# Interrupt Reporting Enable of IA32_MISC_ENABLE bit10
+ When this flag is set and the processor is in the stop-clock state
+ (STPCLK# is asserted), asserting the FERR# pin signals to the processor
+ that an interrupt (such as, INIT#, BINIT#, INTR, NMI, SMI#, or RESET#)
+ is pending and that the processor should return to normal operation to handle the interrupt.
+
+ @param[in] None
+
+ @retval None
+
+**/
+VOID
+EnableFerr (
+ VOID
+ );
+/**
+ Completes processor 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
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+PpmPostInit (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+/**
+ Configure the FACP for C state support
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+EFI_STATUS
+ConfigureFadtCStates (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ Initialize any runtime required data for runtime PPM services. This should be called prior to invoking runtime functions.
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval EFI_SUCCESS PPM Runtime initialized.
+
+**/
+EFI_STATUS
+InitializePpmRuntime (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ Transition a single processor thread to a P state.
+
+ @param[in, out] This Unused
+ @param[in] FvidPointer Pointer to a table to be updated
+ @param[in] CpuNumber The processor thread to perform the transition on
+ @param[in] NextState The desired state (zero based) from the provided FVID table
+
+ @retval EFI_SUCCESS State transition success.
+ @retval EFI_INVALID_PARAMETER Requested state is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PpmTransition (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This,
+ IN FVID_TABLE *FvidPointer,
+ IN UINTN CpuNumber,
+ IN UINTN NextState
+ );
+
+/**
+ This function will poll for the completion of a voltage transition for a core.
+ This function must be MP safe.
+
+ @param[in] CpuNumber The processor thread to poll
+
+**/
+VOID
+EFIAPI
+WaitForPpmTransitionComplete (
+ IN VOID *Buffer
+ );
+
+/**
+ Perform a C state transition
+
+ @param[in] CState C state desired (1-based)
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Unsupported C state requested
+
+**/
+EFI_STATUS
+PpmCStateTransition (
+ UINT8 CState
+ );
+
+/**
+ Create a custom FVID table based on setup options.
+ Caller is responsible for providing a large enough table.
+
+ @param[in] This Pointer to the protocol instance
+ @param[in] FvidPointer Table to update, must be initialized.
+
+ @retval None
+
+**/
+VOID
+CreateCustomFvidTable (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This,
+ IN OUT FVID_TABLE *FvidPointer
+ );
+
+/**
+ Process a C state change request (SMI coordination method uses this).
+ Determine best C state possible
+ Save the PM timer and C3 timer entry times
+ Transition to lowest GV state if soft C2 desired
+ Update TSC MSR if C3 or C4
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+ProcessorCmpCState (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ This function will update the Time Stamp Counter MSR with mPpmCstTscTicks, which
+ contains the timer tick offset for timer ticks during C-states.
+ This function must be MP safe.
+
+ @param[in] Buffer Unused
+
+**/
+VOID
+EFIAPI
+PpmUpdateTimeStampCounter (
+ IN VOID *Buffer
+ );
+
+/**
+ 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 None
+
+**/
+VOID
+InitializePpmAcpiTable (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+/**
+ Returns the frequency of a given state based on the ratio
+
+ @param[in] RatioSetting The ratio settings for the state
+
+ @retval None
+
+**/
+UINT32
+FindStateFrequency (
+ IN UINT16 RatioSetting
+ );
+
+/**
+ Patch the MADT tables for Dual Core SKU based on the proper processor entries.
+ Swap the MADT processor entries, so that the active APIC's will be in order in Dual Core .
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+PatchMADTApicIds (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ );
+
+#endif
diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmInitialization.c b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmInitialization.c
new file mode 100644
index 0000000000..fab7929402
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmInitialization.c
@@ -0,0 +1,1280 @@
+/** @file
+ Platform 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 Platform Power Management
+ GV Geyserville
+ TM Thermal Monitor
+ IST Intel(R) Speedstep technology
+ HT Hyper-Threading Technology
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Statements that include other files
+//
+#include <Ppm.h>
+#include <PowerManagement.h>
+#include <PchAccess.h>
+#include <MchPpmLib.h>
+#include <CpuRegs.h>
+#include <IndustryStandard/Acpi30.h>
+#include <Library/AslUpdateLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <CpuPpmLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/GlobalNvsArea.h>
+#include <Protocol/PpmPlatformPolicy.h>
+#include <Guid/PowerManagementAcpiTableStorage.h>
+//
+// This is not a standard protocol, as it is never published.
+// It is more of a dynamic internal library.
+//
+#include <Protocol/PpmProcessorSupport2.h>
+
+//
+// Global variables
+//
+
+//
+// PPM policy configurations
+//
+extern PPM_PLATFORM_POLICY_PROTOCOL mPpmPlatformPolicyProtocol;
+
+//
+// FVID Table Information
+//
+extern UINT16 mNumberOfStates;
+extern UINT16 mNumberOfStatesTurbo;
+extern FVID_TABLE *mFvidPointer;
+
+//
+// Power management ACPI base address
+//
+UINT16 mAcpiBaseAddr;
+
+//
+// Global NVS area (communication buffer between SMM and ASL code)
+// This area is special because it is in ACPI NVS memory and should
+// not be relocated by the OS. It is accessed in BS, SMM, and by ASL.
+//
+extern EFI_GLOBAL_NVS_AREA *mGlobalNvsAreaPtr;
+
+//
+// CDV iFSB Frequency
+//
+UINT16 miFSBFrequency;
+
+//
+// Last requested GV state
+//
+UINT16 mRequestedState;
+
+//
+// Default FVID table
+// One header field plus states
+//
+FVID_TABLE mEmptyFvidTable[FVID_MAX_STATES + 1];
+FVID_TABLE *mFvidPointer = &mEmptyFvidTable[0];
+
+//
+// Timer global data
+//
+UINT8 mPpmCstTmrFlags;
+UINTN mPpmTscCorrFactor;
+UINTN mPpmTscCorrFactorRem;
+UINTN mPpmCstTscCorrRem;
+UINT64 mPpmCstTscTicks;
+
+//
+// Globals to support updating ACPI Tables
+//
+
+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;
+
+//
+// Function prototypes
+//
+
+/**
+ Initialize the processor power management based on hardware capabilities
+ and user configuration settings.
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+InitializePpm (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ UINT32 PpmFlagsMask; // User configuration mask
+
+ //
+ // Set PPM initialization global variables
+ //
+ PpmPreInit (This);
+
+ //
+ // Initialize flags for the current processor
+ //
+ This->SetPpmFlags (This);
+
+ //
+ // Save the hardware features.
+ //
+ This->PpmFeatureFlags = This->PpmFlags;
+
+ //
+ // Determine current user configuration
+ //
+ SetUserConfigurationPpmFlagsMask (&PpmFlagsMask);
+
+ //
+ // Modify PpmFlags based on user configuration
+ //
+ This->PpmFlags &= PpmFlagsMask;
+
+ //
+ // Initialize P states
+ //
+ if ((This->PpmFlags & PPM_GV3) && (This->InitGv3 != NULL) ) {
+ This->InitGv3 (This, mFvidPointer, &mPpmPlatformPolicyProtocol);
+ mNumberOfStates = mFvidPointer[0].FvidHeader.Gv3States;
+ mNumberOfStatesTurbo = (UINT16) (mFvidPointer[0].FvidHeader.Stepping);
+ if (This->PpmFlags & PPM_DYNAMIC_FSB) {
+ EnableMchDynamicFsbFrequencySwitching ();
+ }
+ }
+
+ //
+ // Test for EMTTM supported and requested and initialize if true.
+ //
+ if ((This->PpmFlags & (PPM_EMTTM | PPM_GV3)) == (PPM_EMTTM | PPM_GV3)) {
+ if (This->EnableEmttm != NULL) {
+ This->EnableEmttm (This, mFvidPointer);
+ }
+ }
+
+ //
+ // Save the number of states for easy access by SPSS and NPSS patching.
+ //
+
+ //
+ // Initialize C states, some is general, some is processor specific
+ // Dynamic loading of CST SSDT tables occurs at PpmPostInit.
+ //
+
+ //
+ // Configure C States setting and Enable C States if C-State setup option is enabled
+ //
+ This->EnableCStates (This, 0, 0);
+
+ //
+ // Initialize the TSC update
+ //
+ if ((This->PpmFlags & PPM_TSC) && (This->EnableTsc != NULL)) {
+ This->EnableTsc (This, mFvidPointer, miFSBFrequency, &mPpmCstTmrFlags, &mPpmTscCorrFactor, &mPpmTscCorrFactorRem);
+ mPpmCstTscCorrRem = 0;
+ }
+
+ //
+ // Initialize thermal features
+ //
+ This->InitThermal (This, &mPpmPlatformPolicyProtocol);
+
+ //
+ // Initialize TM1 before TM2 because some processors (Dothan)
+ // only support one at a time, so enabling TM2 later results in TM2
+ // instead of TM1.
+ //
+ if (This->PpmFlags & PPM_TM) {
+ This->EnableTm (This);
+ }
+ if (This->PpmFlags & PPM_PROC_HOT) {
+ This->EnableProcHot (This);
+ }
+
+ //
+ // Initialize PPM ASL code
+ //
+ mGlobalNvsAreaPtr->PpmFlags = This->PpmFlags;
+ InitializePpmAcpiTable (This);
+
+ //
+ //Patch MADT table for Dual Core Scenario
+ //
+ if (( This->PpmFlags & 0x800000 )!= PPM_QUAD)
+ {
+ DEBUG ((EFI_D_ERROR, "Patch MADT for Dual Core SKU"));
+ PatchMADTApicIds (This);
+ }
+ //
+ // Complete initialization
+ //
+ PpmPostInit (This);
+}
+
+/**
+ Initialize global variables used during PPM init
+ miFSBFrequency - iFSB frequency.
+ mFvidPointer - Set FVID states
+ mAcpiTable - Set ACPI Table protocol instance
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+PpmPreInit (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Get the ACPI Base Address
+ //
+ mAcpiBaseAddr = PchLpcPciCfg16 (R_PCH_LPC_ACPI_BASE) & B_PCH_LPC_PMC_BASE_BAR;
+
+ //
+ // Determine the processor core iFSB frequency
+ //
+
+ miFSBFrequency = DetermineiFsbFromMsr();
+
+ //
+ // 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.)
+ //
+ SetMem (mFvidPointer, sizeof (mEmptyFvidTable), 0);
+ if (mPpmPlatformPolicyProtocol.CustomVidTable.VidNumber >= 2) {
+ CreateCustomFvidTable (This, mFvidPointer);
+ }
+
+ //
+ // Locate ACPI Table protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize runtime PPM code
+ //
+ InitializePpmRuntime (This);
+}
+
+/**
+ Set the PPM flags based on current user configuration
+
+ @param[in] PpmFlagsMask Mask of feature options to be enabled as specified by the policy
+
+ @retval None
+
+**/
+VOID
+SetUserConfigurationPpmFlagsMask (
+ IN OUT UINT32 *PpmFlagsMask
+ )
+{
+ UINT32 Ecx = 0;
+ EFI_CPUID_REGISTER mCpuid0B = { 0, 0, 0, 0 };
+ //
+ // Initialize flags
+ //
+ *PpmFlagsMask = 0;
+ *PpmFlagsMask |= PPM_TSC;
+ *PpmFlagsMask |= PPM_MWAIT_EXT;
+
+ // Retrieve Processor Topology.
+ Ecx = 1;
+ AsmCpuidEx (EFI_CPUID_CORE_TOPOLOGY, Ecx, &mCpuid0B.RegEax, &mCpuid0B.RegEbx, &mCpuid0B.RegEcx, &mCpuid0B.RegEdx);
+ //
+ // Configure based on setup values
+ //
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableGv) {
+ *PpmFlagsMask |= PPM_GV3;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableCx) {
+ *PpmFlagsMask |= PPM_C1;
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableCxe) {
+ *PpmFlagsMask |= PPM_C1E;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableC4) {
+ *PpmFlagsMask |= PPM_C4;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableC6) {
+ *PpmFlagsMask |= (PPM_C6|PPM_C4);
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableC7) {
+ *PpmFlagsMask |= (PPM_C7|PPM_C6|PPM_C4);
+ }
+ }
+ //
+ // end if EnableCx
+ //
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableTm) {
+ *PpmFlagsMask |= PPM_TM;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableProcHot) {
+ *PpmFlagsMask |= PPM_PROC_HOT;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableCMP) {
+ if ((mCpuid0B.RegEbx & 0xFF) > 1) {
+ *PpmFlagsMask |= (PPM_CMP);
+ }
+ if ((mCpuid0B.RegEbx & 0xFF) > 2) {
+ *PpmFlagsMask |= (PPM_QUAD);
+ }
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableTurboMode) {
+ *PpmFlagsMask |= PPM_TURBO;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.EnableEmttm) {
+ *PpmFlagsMask |= PPM_EMTTM;
+ }
+
+ //
+ // Check if MCH supports dynamic FSB frequency switching
+ // We assume that the chipset will support it.
+ //
+ if ((mPpmPlatformPolicyProtocol.FunctionEnables.EnableDynamicFsb) && MchSupportDynamicFsbFrequencySwitching ()) {
+ *PpmFlagsMask |= PPM_DYNAMIC_FSB;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.TStatesEnable) {
+ *PpmFlagsMask |= PPM_TSTATES;
+ }
+
+ if (mPpmPlatformPolicyProtocol.BootInLfm == PPM_DISABLE) {
+ *PpmFlagsMask |= PPM_BOOT_P_ST_HFM;
+ }
+
+ if (mPpmPlatformPolicyProtocol.FunctionEnables.S0ixSupport) {
+ *PpmFlagsMask |= PPM_S0ix;
+ }
+}
+
+/**
+ Patch the SMI _PSS (SPSS) package with performance values and the native _PSS (NPSS) package with the GV3 values
+
+ Uses ratio/VID values from the FVID table to fix up the control values in the NPSS and SPSS.
+
+ (1) Find NPSS or SPSS package:
+ (1.1) Find the _PR_CPU0 scope.
+ (1.2) Save a pointer to the package length.
+ (1.3) Find the NPSS or SPSS AML name object.
+ (2) Resize the NPSS and SPSS package.
+ (3) Fix up the NPSS and SPSS 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.
+ (6) Renames PSS packages for ACPI utility evaluation
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+AcpiPatchSpssNpss (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ UINT8 *CurrPtr;
+ UINT8 *EndOfTable;
+ UINT8 i;
+ UINT16 NewPackageLength;
+ UINT16 MaxPackageLength;
+ UINT16 Temp;
+ UINT16 *PackageLength;
+ UINT16 *ScopePackageLengthPtr = NULL;
+ UINT32 *Signature;
+ PSS_PACKAGE_LAYOUT *PssPackage = NULL;
+
+ //
+ // 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 <= EndOfTable; CurrPtr++) {
+ Signature = (UINT32*) (CurrPtr + 1);
+
+ //
+ // If we found the the _PR_CPU0 scope, save a pointer to the package length
+ //
+ if ((*CurrPtr == AML_SCOPE_OP) && (*(Signature + 1) == SIGNATURE_32 ('_', 'P', 'R', '_')) && (*(Signature + 2) == SIGNATURE_32 ('C', 'P', 'U', '0'))) {
+ ScopePackageLengthPtr = (UINT16*) (CurrPtr + 1);
+ }
+ //
+ // Patch the native _PSS (NPSS or SPSS) package with the GV3 values
+ //
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == SIGNATURE_32 ('S', 'P', 'S', 'S'))) {
+ DEBUG ((EFI_D_ERROR, "S P S S start here\n"));
+ //
+ // Check table dimensions
+ // SPSS and NPSS packages 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.
+ //
+ NewPackageLength = Temp = (UINT16) ((mNumberOfStates - mNumberOfStatesTurbo + 1) * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ if (mNumberOfStates < FVID_MAX_STATES) {
+ *(CurrPtr + 8) = (UINT8) (mNumberOfStates - mNumberOfStatesTurbo + 1);
+ 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 (i = 1; i <= (mNumberOfStates - mNumberOfStatesTurbo + 1); i++) {
+ //
+ // If Turbo mode is supported, add one to the HFM frequency
+ //
+ PssPackage->Control = (UINT32) ((mFvidPointer[i].FvidState.BusRatio << 8) | (mFvidPointer[i].FvidState.Vid));
+ PssPackage->Status = (UINT32) ((mFvidPointer[i].FvidState.BusRatio << 8) | (mFvidPointer[i].FvidState.Vid));
+ PssPackage->Power = (UINT32) mFvidPointer[i].FvidState.Power;
+
+ if ((This->PpmFlags & PPM_TURBO) && (i == 1)) {
+ PssPackage->CoreFrequency = FindStateFrequency (mFvidPointer[i + mNumberOfStatesTurbo].FvidState.BusRatio);
+ PssPackage->CoreFrequency++;
+ PssPackage->Control = (UINT32) ((mFvidPointer[i].FvidState.BusRatio << 8) | (mFvidPointer[i].FvidState.Vid));
+ PssPackage->Status = (UINT32) ((mFvidPointer[i].FvidState.BusRatio << 8) | (mFvidPointer[i].FvidState.Vid));
+ } else if (This->PpmFlags & PPM_TURBO) {
+ PssPackage->CoreFrequency = FindStateFrequency (mFvidPointer[i + mNumberOfStatesTurbo -1].FvidState.BusRatio);
+ PssPackage->Control = (UINT32) ((mFvidPointer[i + mNumberOfStatesTurbo -1].FvidState.BusRatio << 8) | (mFvidPointer[i + mNumberOfStatesTurbo -1].FvidState.Vid));
+ PssPackage->Status = (UINT32) ((mFvidPointer[i + mNumberOfStatesTurbo -1].FvidState.BusRatio << 8) | (mFvidPointer[i + mNumberOfStatesTurbo -1].FvidState.Vid));
+ PssPackage->Power = (UINT32) mFvidPointer[i + mNumberOfStatesTurbo -1].FvidState.Power;
+ } else {
+ PssPackage->CoreFrequency = FindStateFrequency (mFvidPointer[i].FvidState.BusRatio);
+ }
+ PssPackage->TransLatency = NATIVE_PSTATE_LATENCY;
+
+ DEBUG ((EFI_D_ERROR, "PssPackage->CoreFrequency = %x\n", PssPackage->CoreFrequency));
+ DEBUG ((EFI_D_ERROR, "PssPackage->Control = %x\n", PssPackage->Control));
+ DEBUG ((EFI_D_ERROR, "PssPackage->Power = %x\n", PssPackage->Power));
+
+ PssPackage->BMLatency = PSTATE_BM_LATENCY;
+ PssPackage++;
+ }
+ }
+
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == SIGNATURE_32 ('N', 'P', 'S', 'S'))) {
+ DEBUG ((EFI_D_ERROR, "N P S S start here\n"));
+ //
+ // Check table dimensions
+ // SPSS and NPSS packages 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.
+ //
+ NewPackageLength = Temp = (UINT16) (mNumberOfStates * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ 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 (i = 1; i <= mNumberOfStates; i++) {
+ //
+ // Update the NPSS table
+ //
+
+ PssPackage->CoreFrequency = FindStateFrequency (mFvidPointer[i].FvidState.BusRatio);
+ PssPackage->Power = (UINT32) mFvidPointer[i].FvidState.Power;
+
+ PssPackage->TransLatency = NATIVE_PSTATE_LATENCY;
+ PssPackage->Control = (UINT32) ((mFvidPointer[i].FvidState.BusRatio << 8) | (mFvidPointer[i].FvidState.Vid));
+ PssPackage->Status = (UINT32) ((mFvidPointer[i].FvidState.BusRatio << 8) | (mFvidPointer[i].FvidState.Vid));
+
+ PssPackage->BMLatency = PSTATE_BM_LATENCY;
+ DEBUG ((EFI_D_ERROR, "PssPackage->CoreFrequency = %x\n", PssPackage->CoreFrequency));
+ DEBUG ((EFI_D_ERROR, "PssPackage->Control = %x\n", PssPackage->Control));
+ DEBUG ((EFI_D_ERROR, "PssPackage->Power = %x\n", PssPackage->Power));
+ PssPackage++;
+ }
+ }
+ }
+ //
+ // Update the Package length in AML package length format
+ //
+ ASSERT (ScopePackageLengthPtr != NULL);
+
+ CurrPtr = (UINT8*) ScopePackageLengthPtr;
+ NewPackageLength = Temp = (UINT16) (EndOfTable - CurrPtr);
+ if (ScopePackageLengthPtr != NULL) {
+ *ScopePackageLengthPtr = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00);
+ }
+ mCpu0IstTable->Length = (UINT32) (EndOfTable - (UINT8*) mCpu0IstTable);
+}
+
+/**
+ Enable FERR# Interrupt Reporting Enable of IA32_MISC_ENABLE bit10
+ When this flag is set and the processor is in the stop-clock state
+ (STPCLK# is asserted), asserting the FERR# pin signals to the processor
+ that an interrupt (such as, INIT#, BINIT#, INTR, NMI, SMI#, or RESET#)
+ is pending and that the processor should return to normal operation to handle the interrupt.
+
+ @param[in] None
+
+ @retval None
+
+**/
+VOID
+EnableFerr (
+ VOID
+ )
+{
+ MSR_REGISTER Ia32MiscEnable;
+
+ //
+ // Enable FERR# in the CPU MSR EFI_MSR_IA32_MISC_ENABLE
+ //
+ Ia32MiscEnable.Qword = AsmReadMsr64 (EFI_MSR_IA32_MISC_ENABLE);
+ Ia32MiscEnable.Qword |= (UINT64)FERR_MUX_ENABLE;
+ AsmWriteMsr64 (EFI_MSR_IA32_MISC_ENABLE, Ia32MiscEnable.Qword);
+}
+
+/**
+ Completes processor 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
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+PpmPostInit (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data8;
+
+ //
+ // Set Boot P-state based on Policy.
+ //
+ This->SetBootPState(This);
+
+ //
+ // Generate an SMI to restore the MSRs when resuming from S3
+ //
+ Data8 = mPpmPlatformPolicyProtocol.S3RestoreMsrSwSmiNumber;
+ Status = S3BootScriptSaveIoWrite(
+ EfiBootScriptWidthUint8,
+ (UINT64) R_PCH_APM_CNT,
+ (UINTN) 1,
+ &Data8
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Configure Turbo Power Limits
+ //
+ if (This->PpmFlags & PPM_TURBO) {
+ This->ConfigureTurboPowerLimit (This, &mPpmPlatformPolicyProtocol);
+ }
+ //
+ // Save the MSRs so that they can be restored while S3 resume
+ //
+ This->S3SaveMsr (This);
+}
+
+/**
+ Configure the FACP for C state support
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+EFI_STATUS
+ConfigureFadtCStates (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer;
+ UINTN Handle;
+
+ //
+ // Locate table with matching ID
+ //
+ InitializeAslUpdateLib();
+
+ Handle = 0;
+ Status = LocateAcpiTableBySignature (
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ (EFI_ACPI_DESCRIPTION_HEADER **) &Table,
+ &Handle
+ );
+ ASSERT (Status);
+
+ //
+ // 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->PLvl2Lat >= FADT_C2_LATENCY_DISABLED);
+ ASSERT (FadtPointer->PLvl3Lat >= FADT_C3_LATENCY_DISABLED);
+
+ //
+ // Configure C states
+ //
+ if (This->PpmFlags & PPM_C4) {
+ //
+ // Enable C2 in FADT.
+ //
+ FadtPointer->PLvl2Lat = FADT_C2_LATENCY;
+ }
+
+ if (This->PpmFlags & (PPM_C6)) {
+ //
+ // Enable C3 in FADT.
+ //
+ FadtPointer->PLvl3Lat = FADT_C3_LATENCY;
+ }
+
+ //
+ // Install the Table
+ //
+ Status = mAcpiTable->InstallAcpiTable (mAcpiTable, Table, Table->Length, &Handle);
+ ASSERT (Status);
+ gBS->FreePool (Table);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a custom FVID table based on setup options.
+ Caller is responsible for providing a large enough table.
+
+ @param[in, out]This Pointer to the protocol instance
+ @param[in, out]FvidPointer Table to update, must be initialized.
+
+ @retval None
+
+**/
+VOID
+CreateCustomFvidTable (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This,
+ IN OUT FVID_TABLE *FvidPointer
+ )
+{
+ UINT16 Index;
+
+ //
+ // Fill in the table header
+ //
+ FvidPointer[0].FvidHeader.Stepping = mPpmPlatformPolicyProtocol.CustomVidTable.VidCpuid;
+ FvidPointer[0].FvidHeader.MaxVid = mPpmPlatformPolicyProtocol.CustomVidTable.VidMaxVid;
+ FvidPointer[0].FvidHeader.MaxBusRatio = mPpmPlatformPolicyProtocol.CustomVidTable.VidMaxRatio;
+ FvidPointer[0].FvidHeader.Gv3States = mPpmPlatformPolicyProtocol.CustomVidTable.VidNumber;
+
+
+ //
+ // Fill in the state data
+ //
+ for (Index = 0; Index < mPpmPlatformPolicyProtocol.CustomVidTable.VidNumber; Index++) {
+ FvidPointer[Index + 1].FvidState.State = Index;
+ FvidPointer[Index + 1].FvidState.Vid = mPpmPlatformPolicyProtocol.CustomVidTable.StateVid[Index];
+ FvidPointer[Index + 1].FvidState.BusRatio = mPpmPlatformPolicyProtocol.CustomVidTable.StateRatio[Index];
+ }
+}
+
+/**
+ Update the SSDT table pointers and config DWORD CFGD with the PpmFlags current configuration value
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+PatchCpuPmTable (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ UINT8 *CurrPtr;
+ UINT32 *Signature;
+ SSDT_LAYOUT *SsdtPackage = NULL;
+ CFGD_LAYOUT *CfgdPackage = NULL;
+
+ //
+ // Locate the SSDT package
+ //
+ CurrPtr = (UINT8*) mCpuPmTable;
+ for (; CurrPtr <= ((UINT8*) mCpuPmTable + mCpuPmTable->Length); CurrPtr++) {
+ Signature = (UINT32*) (CurrPtr + 1);
+ if ((*CurrPtr == AML_NAME_OP) && *Signature == 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 config DWORD CFGD with the PpmFlags current configuration value
+ //
+ if ((*CurrPtr == AML_NAME_OP) && *Signature == SIGNATURE_32 ('C', 'F', 'G', 'D')) {
+ CfgdPackage = (CFGD_LAYOUT*) CurrPtr;
+ CfgdPackage->Value = This->PpmFlags;
+ break;
+ }
+ }
+
+ //
+ // Assert if we didn't update the PM table
+ //
+ ASSERT (SsdtPackage != NULL);
+ ASSERT (CfgdPackage != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the SPSS table with the control register address
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+PatchCpu0IstTable (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ UINT8 *CurrPtr;
+ UINT8 *EndPtr;
+ UINT32 PctLength;
+ UINT32 *Signature;
+ PCTP_LAYOUT *PctpPackage = NULL;
+
+
+ //
+ // Locate the SSDT package
+ //
+ CurrPtr = (UINT8*) mCpu0IstTable;
+ EndPtr = CurrPtr + mCpu0IstTable->Length;
+
+ for (; CurrPtr <= EndPtr; CurrPtr++) {
+ Signature = (UINT32*) (CurrPtr + 3);
+ //
+ // Update the address with the SMM P-State control port
+ //
+ if ((*CurrPtr == AML_METHOD_OP) && *Signature == SIGNATURE_32 ('_', 'P', 'C', 'T')) {
+ //
+ // This code assumes a two-byte package length encoding, ASSERT if not.
+ //
+ ASSERT ((*(CurrPtr + 1) & 0xC0) == 0x40);
+ PctLength = (((UINT32)(*(CurrPtr + 2))) << 4) + (((UINT32)(*(CurrPtr + 1))) & 0x0F);
+ EndPtr = CurrPtr + PctLength;
+ //
+ // There are four different resource packages in the provided _PCT method, so
+ // we search for the only one with a width of 16 and a default address of 0x8000.
+ //
+ for (; CurrPtr <= EndPtr; CurrPtr++) {
+ if ((*CurrPtr == 0x82) && (*(CurrPtr + 4) == 0x10) && (*((UINT32*)(CurrPtr + 7)) == 0x8000)) {
+ PctpPackage = (PCTP_LAYOUT*) CurrPtr;
+ PctpPackage->RegAddress = 0x8000;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ //
+ // Assert if we didn't update the _PCT port address
+ //
+ ASSERT (PctpPackage != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 None
+
+**/
+VOID
+InitializePpmAcpiTable (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ 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_VOLUME2_PROTOCOL *FwVol = NULL;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ EFI_ACPI_DESCRIPTION_HEADER *TempTable;
+ UINTN AcpiTableHandle;
+
+ //
+ // Locate protocol.
+ // There is little chance we can't find an FV protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Looking for FV with ACPI storage file
+ //
+ for (i = 0; i < NumberOfHandles; i++) {
+
+ //
+ // Get the protocol on this handle
+ // This should not fail because of LocateHandleBuffer
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[i],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // See if it has the ACPI storage file
+ //
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gPowerManagementAcpiTableStorageGuid,
+ 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
+ //
+ gBS->FreePool (HandleBuffer);
+
+ //
+ // Sanity check that we found our data file
+ //
+ ASSERT (FwVol != NULL);
+ if( FwVol == NULL ) {
+ return;
+ }
+
+ //
+ // Read tables from the storage file.
+ //
+ Instance = 0;
+ CurrentTable = NULL;
+ while (Status == EFI_SUCCESS) {
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gPowerManagementAcpiTableStorageGuid,
+ 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 (SIGNATURE_64 ('C', 'p', 'u', '0', 'I', 's', 't', 0)):
+ mCpu0IstTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ if ((This->PpmFlags & PPM_GV3 )||(This->PpmFlags & PPM_BOOT_P_ST_HFM)) {
+ //
+ // Patch the SMI _PSS (SPSS) package with performance values and
+ // the native _PSS (NPSS) package with the GV3 values
+ //
+ AcpiPatchSpssNpss (This);
+ //
+ // Update the Cpu0Ist SSDT table in the ACPI tables.
+ //
+ // @NOTE: This patching routine of SSDT is targetting IO interface for P-state control.
+ // VLV SoC does not support IO Trap.
+ //PatchCpu0IstTable (This);
+ }
+ break;
+
+ case (SIGNATURE_64 ('C', 'p', 'u', '0', 'C', 's', 't', 0)):
+ mCpu0CstTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ break;
+
+ case (SIGNATURE_64 ('C', 'p', 'u', '0', 'T', 's', 't', 0)):
+ mCpu0TstTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ break;
+
+ case (SIGNATURE_64 ('A', 'p', 'I', 's', 't', 0, 0, 0)):
+ mApIstTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ break;
+
+ case (SIGNATURE_64 ('A', 'p', 'C', 's', 't', 0, 0, 0)):
+ mApCstTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ break;
+
+ case (SIGNATURE_64 ('A', 'p', 'T', 's', 't', 0, 0, 0)):
+ mApTstTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ break;
+
+ case (SIGNATURE_64 ('C', 'p', 'u', 'P', 'm', 0, 0, 0)):
+ mCpuPmTable = (EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable;
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // Increment the instance
+ //
+ Instance++;
+ CurrentTable = NULL;
+ }
+ }
+
+ //
+ //Fixed the BSOD "ACPI_BIOS_USE_OS_MEMORY" when Disable CMP function
+ //
+ Status = gBS->AllocatePool (EfiReservedMemoryType, mApIstTable->Length, (VOID **)&TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mApIstTable, mApIstTable->Length);
+ gBS->FreePool (mApIstTable);
+ mApIstTable = TempTable;
+ AcpiChecksum (mApIstTable, mApIstTable->Length, OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+
+ Status = gBS->AllocatePool (EfiReservedMemoryType, mApCstTable->Length, (VOID **)&TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mApCstTable, mApCstTable->Length);
+ gBS->FreePool (mApCstTable);
+ mApCstTable = TempTable;
+ AcpiChecksum (mApCstTable, mApCstTable->Length, OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+
+ //
+ // 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 IST and 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 IST and CST tables only if IST and CST are enabled
+ //
+ if (This->PpmFlags & PPM_CMP) {
+ //
+ // Copy tables to our own location and checksum them
+ //
+
+ Status = gBS->AllocatePool (EfiReservedMemoryType, mCpu0IstTable->Length, (VOID **)&TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mCpu0IstTable, mCpu0IstTable->Length);
+ gBS->FreePool (mCpu0IstTable);
+ mCpu0IstTable = TempTable;
+ AcpiChecksum (mCpu0IstTable, mCpu0IstTable->Length, OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+
+ Status = gBS->AllocatePool (EfiReservedMemoryType, mCpu0CstTable->Length, (VOID **)&TempTable);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (TempTable, mCpu0CstTable, mCpu0CstTable->Length);
+ gBS->FreePool (mCpu0CstTable);
+ mCpu0CstTable = TempTable;
+ AcpiChecksum (mCpu0CstTable, mCpu0CstTable->Length, OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+
+ } else {
+ //
+ // CMP disabled, so statically load the tables
+ //
+
+ //
+ // Add IST SSDT if GV3 enabled
+ //
+ if (This->PpmFlags & PPM_GV3) {
+ AcpiTableHandle = 0;
+ //
+ // Install IST SSDT Tables
+ //
+ Status = mAcpiTable->InstallAcpiTable (mAcpiTable, mCpu0IstTable, mCpu0IstTable->Length, &AcpiTableHandle);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Add CST SSDT if C states are enabled
+ //
+ if (This->PpmFlags & PPM_C_STATES) {
+ AcpiTableHandle = 0;
+ //
+ // Install CST SSDT Tables
+ //
+ Status = mAcpiTable->InstallAcpiTable (mAcpiTable, mCpu0CstTable, mCpu0CstTable->Length, &AcpiTableHandle);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Since we are UP, there is no need for the CPU 1 tables
+ //
+
+ //
+ // At this time, we can free all tables, since they have been copied into ACPI tables by ACPI support protocol
+ //
+ gBS->FreePool (mCpu0IstTable);
+ gBS->FreePool (mCpu0CstTable);
+ }
+
+ //
+ // Update the CpuPm SSDT table in the ACPI tables.
+ //
+ PatchCpuPmTable (This);
+
+ AcpiTableHandle = 0;
+ //
+ // Install CpuPm SSDT Tables
+ //
+ Status = mAcpiTable->InstallAcpiTable (mAcpiTable, mCpuPmTable, mCpuPmTable->Length, &AcpiTableHandle);
+ ASSERT_EFI_ERROR (Status);
+ gBS->FreePool (mCpuPmTable);
+
+ if (This->PpmFlags & PPM_TSTATES) {
+ AcpiTableHandle = 0;
+ //
+ // Install Cpu0Tst SSDT Tables
+ //
+ Status = mAcpiTable->InstallAcpiTable (mAcpiTable, mCpu0TstTable, mCpu0TstTable->Length, &AcpiTableHandle);
+ ASSERT_EFI_ERROR (Status);
+ gBS->FreePool (mCpu0TstTable);
+
+ //
+ // If the CMP is enabled then load the ApTst SSDT table in the ACPI tables
+ //
+ if (This->PpmFlags & PPM_CMP) {
+ AcpiTableHandle = 0;
+ //
+ // Install ApTst SSDT Tables
+ //
+ Status = mAcpiTable->InstallAcpiTable (mAcpiTable, mApTstTable, mApTstTable->Length, &AcpiTableHandle);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ gBS->FreePool (mApTstTable);
+}
+
+/**
+ Returns the frequency (MHz) of a given state based on the ratio
+
+ @param[in] RatioSetting The ratio settings for the state
+
+ @retval None
+
+**/
+UINT32
+FindStateFrequency (
+ IN UINT16 RatioSetting
+ )
+{
+ UINT32 Frequency;
+
+ Frequency = (UINT32)(RatioSetting * miFSBFrequency);
+
+ return Frequency;
+}
+
+/**
+ Patch the MADT tables for Dual Core SKU.based on the proper processor entries.
+ Swap the MADT processor entries, so that the active APIC's will be in order in Dual Core .
+ APICID 0 and 4 are active processors in Dual Core SKU.
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+PatchMADTApicIds (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable = NULL;
+ UINTN Handle;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_STATUS Status;
+ UINT8 *CurrPtr, *EndPtr;
+ UINT8 ApicId=0, ApicEntrySwap=0;
+ UINT32 Flags=0;
+ ACPI_APIC_STRUCTURE_PTR *ApicPtr,*TempPtr = NULL ;
+ EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtTable = NULL;
+
+ //
+ // Locate ACPI tables Prpotocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+ //
+ // Locate MADT
+ //
+ if (!EFI_ERROR ( InitializeAslUpdateLib() ) )
+ {
+ Version = EFI_ACPI_TABLE_VERSION_2_0;
+ Status = LocateAcpiTableBySignature(EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, (EFI_ACPI_DESCRIPTION_HEADER**) &MadtTable, &Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ CurrPtr = (UINT8 *) &((EFI_ACPI_DESCRIPTION_HEADER *) MadtTable)[1];
+ CurrPtr = CurrPtr + 8;
+
+ EndPtr = (UINT8 *) MadtTable;
+ EndPtr = EndPtr + MadtTable->Header.Length;
+ while (CurrPtr < EndPtr) {
+ ApicPtr = (ACPI_APIC_STRUCTURE_PTR *) CurrPtr;
+ if (ApicPtr->AcpiApicCommon.Type == EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC ) {
+ if (ApicPtr->AcpiLocalApic.Flags == 0) {
+ ApicId = ApicPtr->AcpiLocalApic.ApicId;
+ Flags = ApicPtr->AcpiLocalApic.Flags;
+ TempPtr = (ACPI_APIC_STRUCTURE_PTR *)ApicPtr;
+ ApicEntrySwap =1;
+ }
+
+ if (ApicPtr->AcpiLocalApic.Flags == EFI_ACPI_1_0_LOCAL_APIC_ENABLED && ApicEntrySwap ==1) {
+ TempPtr->AcpiLocalApic.ApicId = ApicPtr->AcpiLocalApic.ApicId;
+ TempPtr->AcpiLocalApic.Flags = ApicPtr->AcpiLocalApic.Flags;
+ ApicPtr->AcpiLocalApic.ApicId = ApicId;
+ ApicPtr->AcpiLocalApic.Flags = Flags;
+ ApicEntrySwap =0;
+ }
+ }
+ CurrPtr = CurrPtr + ApicPtr->AcpiApicCommon.Length;
+ }
+ //
+ // Update the table
+ //
+ Status = AcpiTable->UninstallAcpiTable (AcpiTable, Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = AcpiTable->InstallAcpiTable (AcpiTable, MadtTable, MadtTable->Header.Length, &Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ if (MadtTable != NULL)
+ FreePool (MadtTable);
+ }
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmRuntime.c b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmRuntime.c
new file mode 100644
index 0000000000..b7f6c9fb3a
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/CPU/PowerManagement/Smm/PpmRuntime.c
@@ -0,0 +1,505 @@
+/** @file
+ Platform power management runtime code. This code implements the power management
+ settings during runtime. It must be runtime SMM safe.
+
+ Acronyms:
+ PPM Platform Power Management
+ GV Geyserville
+ TM Thermal Monitor
+ IST Intel(R) Speedstep technology
+ HT Hyper-Threading Technology
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Statements that include other files
+//
+#include <Ppm.h>
+#include <PowerManagement.h>
+#include <PchAccess.h>
+#include <CpuPpmLib.h>
+#include <CpuRegs.h>
+#include <Library/IoLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Protocol/GlobalNvsArea.h>
+
+//
+// Global variables
+//
+//
+
+//
+// PPM Processor support protocol
+//
+extern PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *mPpmProcessorSupportProtocol;
+
+//
+// FVID Table Information (Must be initialized by caller)
+//
+extern FVID_TABLE *mFvidPointer;
+
+//
+// Last requested GV state
+//
+extern UINT16 mRequestedState;
+
+//
+// CST time storage areas
+//
+extern UINT8 mPpmCstTmrFlags;
+extern UINTN mPpmTscCorrFactor;
+extern UINTN mPpmTscCorrFactorRem;
+extern UINTN mPpmCstTscCorrRem;
+extern UINT64 mPpmCstTscTicks;
+
+//
+// Power management ACPI base address
+//
+extern UINT16 mAcpiBaseAddr;
+
+//
+// Global NVS area (communication buffer between SMM and ASL code)
+// This area is special because it is in ACPI NVS memory and should
+// not be relocated by the OS. It is accessed in BS, SMM, and by ASL.
+//
+extern EFI_GLOBAL_NVS_AREA *mGlobalNvsAreaPtr;
+
+//
+// Function Implementations
+//
+
+/**
+ Initialize any runtime required data for runtime PPM services. This should be called prior to invoking runtime functions.
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval EFI_SUCCESS PPM Runtime initialized.
+
+**/
+EFI_STATUS
+InitializePpmRuntime (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ //
+ // AP service
+ //
+ if (gSmst == NULL) {
+ ASSERT(gSmst != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ASSERT (gSmst->SmmStartupThisAp);
+ ASSERT (mPpmProcessorSupportProtocol != NULL);
+ ASSERT (mGlobalNvsAreaPtr != NULL);
+ ASSERT (mAcpiBaseAddr);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process a C state change request (SMI coordination method uses this).
+ Determine best C state possible
+ Save the PM timer and C3 timer entry times
+ Transition to lowest GV state if soft C2 desired
+ Update TSC MSR if C3 or C4
+
+ @param[in] This Pointer to the protocol instance
+
+ @retval None
+
+**/
+VOID
+ProcessorCmpCState (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This
+ )
+{
+ UINT8 MaxCState;
+ UINTN Index;
+ MSR_REGISTER SavedPerformanceState;
+ UINTN PState;
+ UINTN CstCalculation = 0;
+ UINTN Data32;
+ UINT64 Data64;
+ UINTN PpmCstResEntryTime = 0;
+
+ SavedPerformanceState.Qword = 0;
+
+ //
+ // Determine if any C states are present that require coordination
+ // If not, return
+ //
+ if (!(This->PpmFlags & (PPM_C2 | PPM_C3 | PPM_C4))) {
+ return;
+ }
+
+ //
+ // Determine the maximum C state we can transition to
+ //
+ MaxCState = CSTATE_TRANSITION_C4;
+
+ //
+ // Eliminate C4 if not supported or on AC power
+ //
+ if (!(This->PpmFlags & PPM_C4) || mGlobalNvsAreaPtr->PowerState) {
+ MaxCState = CSTATE_TRANSITION_C3;
+ }
+
+ //
+ // Eliminate C3&C4 if not C3&C4 supported or bus master status
+ //
+ if (!(This->PpmFlags & (PPM_C3 | PPM_C4))/* || (BmSts & PM_BM_STS)*/) {
+ MaxCState = CSTATE_TRANSITION_C2;
+ }
+
+ //
+ // We don't do C3, so do C2
+ //
+ if (MaxCState == CSTATE_TRANSITION_C3) {
+ MaxCState--;
+ }
+
+ //
+ // Determine if SoftC2E
+ //
+ if (MaxCState == CSTATE_TRANSITION_C2 && (This->PpmFlags & PPM_GV3) && (This->PpmFlags & PPM_C2E)) {
+ //
+ // Save current P state
+ //
+ SavedPerformanceState.Qword = AsmReadMsr64 (MSR_IA32_PERF_CTL);
+
+ //
+ // Transition each core to lowest performance state
+ //
+ if (mFvidPointer == NULL) {
+ ASSERT(mFvidPointer != NULL);
+ return;
+ }
+
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ This->PStateTransition (This, mFvidPointer, Index, mFvidPointer->FvidHeader.Gv3States - 1);
+ }
+ //
+ // Wait for voltage transitions to complete on all threads
+ //
+ WaitForPpmTransitionComplete (NULL);
+ for (Index = 1; Index < gSmst->NumberOfCpus; Index++) {
+ gSmst->SmmStartupThisAp (WaitForPpmTransitionComplete, Index, NULL);
+ }
+ }
+
+ //
+ // Perform C state change
+ //
+ PpmCStateTransition (MaxCState);
+
+ //
+ // Determine if SoftC2E and restore P state
+ //
+ if (MaxCState == CSTATE_TRANSITION_C2 && (This->PpmFlags & PPM_GV3) && (This->PpmFlags & PPM_C2E)) {
+ //
+ // Determine what the state was based on saved IA32_PERF_CTL MSR data
+ //
+ PState = (UINT8) mFvidPointer->FvidHeader.Gv3States - 1;
+ for (Index = mFvidPointer->FvidHeader.Gv3States; Index > 0; Index--) {
+ if (mFvidPointer[Index].FvidState.BusRatio == (SavedPerformanceState.Bytes.SecondByte & RATIO_BYTE_MASK )) {
+
+ PState = Index - 1;
+ //
+ // Our VID should always match, since there should only be one VID per Bus ratio
+ //
+ ASSERT (mFvidPointer[Index].FvidState.Vid == (SavedPerformanceState.Bytes.FirstByte & VID_BYTE_MASK));
+ break;
+ }
+ }
+
+ //
+ // Transition each core to original performance state
+ //
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ This->PStateTransition (This, mFvidPointer, Index, PState);
+ }
+
+ //
+ // Wait for voltage transitions to complete on all threads
+ //
+ WaitForPpmTransitionComplete (NULL);
+ for (Index = 1; Index < gSmst->NumberOfCpus; Index++) {
+ gSmst->SmmStartupThisAp (WaitForPpmTransitionComplete, Index, NULL);
+ }
+ }
+
+ //
+ // Calculate C3 or C4 duration for CPU Time Stamp Counter update
+ //
+ if ((MaxCState > CSTATE_TRANSITION_C2) && (mPpmCstTmrFlags & CST_UPDT_TSC)) {
+
+ //
+ // Find the C3/C4 time using the C3 Residency Timer for TSC corrections.
+ //
+ CstCalculation |= (UINT64)C3_RESIDENCY_TIMER_ROLLOVER_BIT;
+ CstCalculation -= PpmCstResEntryTime;
+ CstCalculation &= (~(UINT64)C3_RESIDENCY_TIMER_ROLLOVER_BIT);
+
+ //
+ // Convert the C3 Residency Timer delta to TSC ticks for TSC updates
+ //
+
+ //
+ // Correct for differences in frequencies bewteen residency timer and TSC
+ //
+ mPpmCstTscTicks = MultU64x32 ((UINT64) mPpmTscCorrFactor, (UINT32)CstCalculation);
+ //
+ // Correct for frequency difference with correction factor remainder
+ //
+ Data64 = MultU64x32 ((UINT64) mPpmTscCorrFactorRem, (UINT32)CstCalculation);
+ mPpmCstTscTicks += DivU64x32Remainder (Data64, CST_DATA_TBASE, (UINT32 *)&Data32);
+ //
+ // Update PM Timer remainder
+ //
+ mPpmCstTscCorrRem += Data32;
+ //
+ // Check remainder rollover
+ //
+ if (mPpmCstTscCorrRem >= CST_DATA_TBASE) {
+ mPpmCstTscCorrRem -= CST_DATA_TBASE;
+ mPpmCstTscTicks++;
+ }
+ //
+ // Update Time Stamp Counter MSR for all CPUs
+ //
+ PpmUpdateTimeStampCounter (NULL);
+ for (Index = 1; Index < gSmst->NumberOfCpus; Index++) {
+ gSmst->SmmStartupThisAp (PpmUpdateTimeStampCounter, Index, NULL);
+ }
+ }
+}
+
+/**
+ Perform a C state transition
+
+ @param[in] CState C state desired (1-based)
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Unsupported C state requested
+
+**/
+EFI_STATUS
+PpmCStateTransition (
+ UINT8 CState
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data16;
+ UINT8 Data8;
+ UINT8 ArbiterState;
+ //
+ // Check for valid request (C2 to C4)
+ //
+ ASSERT (CState <= CSTATE_TRANSITION_C4 && CState >= CSTATE_TRANSITION_C2);
+
+ switch (CState) {
+ case CSTATE_TRANSITION_C2:
+ //
+ // Disable bus master reloading by clearing bit 1 of PM1_CNT
+ //
+ Status = gSmst->SmmIo.Io.Read (&gSmst->SmmIo, SMM_IO_UINT16, mAcpiBaseAddr + PM_PM1_CNT, 1, &Data16);
+ ASSERT_EFI_ERROR (Status);
+ Data16 &= ~PM_BM_RELOAD;
+ Status = gSmst->SmmIo.Io.Write (&gSmst->SmmIo, SMM_IO_UINT16, mAcpiBaseAddr + PM_PM1_CNT, 1, &Data16);
+ ASSERT_EFI_ERROR (Status);
+ break;
+
+ case CSTATE_TRANSITION_C3:
+ case CSTATE_TRANSITION_C4:
+ //
+ // Enable bus master reloading by setting bit 1 of PM1_CNT
+ //
+ Status = gSmst->SmmIo.Io.Read (&gSmst->SmmIo, SMM_IO_UINT16, mAcpiBaseAddr + PM_PM1_CNT, 1, &Data16);
+ ASSERT_EFI_ERROR (Status);
+ Data16 |= PM_BM_RELOAD;
+ Status = gSmst->SmmIo.Io.Write (&gSmst->SmmIo, SMM_IO_UINT16, mAcpiBaseAddr + PM_PM1_CNT, 1, &Data16);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Disable (save first) arbiter state
+ //
+ Status = gSmst->SmmIo.Io.Read (&gSmst->SmmIo, SMM_IO_UINT8, mAcpiBaseAddr + R_PCH_ACPI_PM2_CNT, 1, &ArbiterState);
+ ASSERT_EFI_ERROR (Status);
+ Data8 = ArbiterState | B_PCH_ACPI_PM2_CNT_ARB_DIS;
+ Status = gSmst->SmmIo.Io.Write (&gSmst->SmmIo, SMM_IO_UINT8, mAcpiBaseAddr + R_PCH_ACPI_PM2_CNT, 1, &Data8);
+ ASSERT_EFI_ERROR (Status);
+ break;
+
+ default:
+ //
+ // Should not be able to get here ever
+ //
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Do C state transition by reading appropriate LVx register
+ //
+ //Status = gSmst->SmmIo.Io.Read (&gSmst->SmmIo, SMM_IO_UINT8, mAcpiBaseAddr + (PM_CST_LVL2 - 2) + CState, 1, &Data8);
+ //ASSERT_EFI_ERROR (Status);
+
+ //
+ // Restore Arbiter State if modified previously
+ //
+ if (CState > CSTATE_TRANSITION_C2) {
+ Status = gSmst->SmmIo.Io.Write (&gSmst->SmmIo, SMM_IO_UINT8, mAcpiBaseAddr + R_PCH_ACPI_PM2_CNT, 1, &ArbiterState);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Clear bus master status
+ //
+ //Data16 = PM_BM_STS;
+ //Status = gSmst->SmmIo.Io.Write (&gSmst->SmmIo, SMM_IO_UINT16, mAcpiBaseAddr + PM_PM1_STS, 1, &Data16);
+ //ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ AP safe function to make a p-state change request.
+
+ @param[in] Buffer Value to write to the performance control MSR
+
+**/
+VOID
+EFIAPI
+SetPerfControl (
+ IN VOID *Buffer
+ )
+{
+ UINT64 PerformanceControl;
+
+ PerformanceControl = AsmReadMsr64 (MSR_IA32_PERF_CTL);
+
+ //
+ // Clear and then initialize fields: BUS_RATIO_SEL[12:8], VID_SEL[6:0]
+ //
+ PerformanceControl &= (~(UINT64)(PSTATE_CTL_MASK));
+ PerformanceControl |= ((*(UINT64*) Buffer) & PSTATE_CTL_MASK);
+
+ AsmWriteMsr64 (MSR_IA32_PERF_CTL, PerformanceControl);
+}
+
+/**
+ Transition a single processor thread to a P state.
+
+ @param[in, out] This Unused
+ @param[in] FvidPointer Pointer to a table to be updated
+ @param[in] CpuNumber The processor thread to perform the transition on
+ @param[in] NextState The desired state (zero based) from the provided FVID table
+
+ @retval EFI_SUCCESS State transition success.
+ @retval EFI_INVALID_PARAMETER Requested state is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PpmTransition (
+ IN OUT PPM_PROCESSOR_SUPPORT_PROTOCOL_2 *This,
+ IN FVID_TABLE *FvidPointer,
+ IN UINTN CpuNumber,
+ IN UINTN NextState
+ )
+{
+ UINT64 PerformanceControl;
+
+ //
+ // Make sure we have a supported state
+ //
+ if (NextState >= FvidPointer[0].FvidHeader.Gv3States) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Save the state in the current requested state global
+ //
+ mRequestedState = (UINT16) NextState;
+
+ //
+ // GV3 had better be enabled if a transition is attempted
+ //
+ ASSERT (This->PpmFlags & PPM_GV3);
+
+ //
+ // First, convert the requested point number into a BR/VID combo by looking up
+ // the value in the FVID table.
+ //
+
+ //
+ // Second, write the BR/VID combo to the MSR to cause the transition.
+ //
+ PerformanceControl = FvidPointer[NextState + 1].FvidState.BusRatio;
+ PerformanceControl = LShiftU64 (PerformanceControl, 8);
+ PerformanceControl |= (UINT64)FvidPointer[NextState + 1].FvidState.Vid;
+
+ if (CpuNumber == 0) {
+ SetPerfControl (&PerformanceControl);
+ } else {
+ gSmst->SmmStartupThisAp (SetPerfControl, CpuNumber, &PerformanceControl);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will poll for the completion of a voltage transition for a core.
+ This function must be MP safe.
+
+ @param[in] CpuNumber The processor thread to poll
+
+**/
+VOID
+EFIAPI
+WaitForPpmTransitionComplete (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER PerformanceStatusMsr;
+
+ //
+ // Poll voltage transition status until complete
+ //
+ do {
+ PerformanceStatusMsr.Qword = AsmReadMsr64 (MSR_IA32_PERF_STS);
+ } while (PerformanceStatusMsr.Qword & IA32_PERF_STS_VIP);
+}
+
+/**
+ This function will update the Time Stamp Counter MSR with mPpmCstTscTicks, which
+ contains the timer tick offset for timer ticks during C-states.
+ This function must be MP safe.
+
+ @param[in] Buffer Unused
+
+**/
+VOID
+EFIAPI
+PpmUpdateTimeStampCounter (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER TimeStampCounter;
+
+ TimeStampCounter.Qword = AsmReadMsr64 (EFI_MSR_TIME_STAMP_COUNTER);
+ TimeStampCounter.Qword += mPpmCstTscTicks;
+ AsmWriteMsr64 (EFI_MSR_TIME_STAMP_COUNTER, TimeStampCounter.Qword);
+}