summaryrefslogtreecommitdiff
path: root/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm')
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c1267
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h369
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h32
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c221
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c102
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h117
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf63
7 files changed, 2171 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c
new file mode 100644
index 0000000000..7a2bb7f76b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.c
@@ -0,0 +1,1267 @@
+/** @file
+ Digital Thermal Sensor (DTS) driver.
+ This SMM driver configures and supports the Digital Thermal Sensor features for the platform.
+
+ Copyright (c) 1999 - 2016, 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.
+
+**/
+
+#include "PowerMgmtSmm.h"
+#include "PowerMgmtDts.h"
+
+//
+// Global variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_GLOBAL_NVS_AREA *mCpuGlobalNvsAreaPtr;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDtsValue;
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mDtsEnabled;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDtsTjMax;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mUpdateDtsInEverySmi;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mNoOfThresholdRanges;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 (*mDtsThresholdTable)[3];
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mIsPackageTempMsrAvailable;
+///
+/// The table is updated for the current CPU.
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mDigitalThermalSensorThresholdTable[DTS_NUMBER_THRESHOLD_RANGES][3] = {
+ ///
+ /// TJ_MAX = 110 ///< Current Temp. Low Temp. High Temp.
+ ///
+ {TJ_MAX-80,100,75}, ///< <= 30 10 35
+ {TJ_MAX-70,85,65}, ///< 30 ~ 39 25 45
+ {TJ_MAX-60,75,55}, ///< 40 ~ 49 35 55
+ {TJ_MAX-50,65,45}, ///< 50 ~ 59 45 65
+ {TJ_MAX-40,55,35}, ///< 60 ~ 69 55 75
+ {TJ_MAX-30,45,25}, ///< 70 ~ 79 65 85
+ {TJ_MAX-20,35,15}, ///< 80 ~ 89 75 95
+ {TJ_MAX-10,25,05}, ///< 90 ~ 99 85 105
+ {TJ_MAX-00,15,00} ///< 100 ~ 109 95 110
+};
+
+//
+// Function implementations
+//
+/**
+ Read the temperature data per core/thread.
+ This function must be AP safe.
+
+ @param[in] Buffer Pointer to UINT8 to update with the current temperature
+
+ @retval EFI_SUCCESS Digital Thermal Sensor temperature has updated successfully.
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorUpdateTemperature (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER MsrData;
+ UINT8 Temperature;
+ UINT8 DefApicId;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ UINT8 *TempPointer;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+
+ //
+ // Default APIC ID = CPUID Function 01, EBX[31:24]
+ //
+ DefApicId = (UINT8) RShiftU64 (CpuidRegisters.RegEbx, 24);
+
+ //
+ // Read the temperature
+ //
+ MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS);
+
+ //
+ // Find the DTS temperature.
+ //
+ Temperature = mDtsTjMax - (MsrData.Bytes.ThirdByte & OFFSET_MASK);
+
+ //
+ // We only update the temperature if it is above the current temperature.
+ //
+ TempPointer = Buffer;
+ if (Temperature > *((UINT8 *) (TempPointer + DefApicId))) {
+ *((UINT8 *) (TempPointer + DefApicId)) = Temperature;
+ }
+
+ return;
+}
+
+
+/**
+ SMI handler to handle Digital Thermal Sensor CPU Local APIC SMI
+ for thermal Out Of Spec interrupt
+
+ @param[in] SmmImageHandle Image handle returned by the SMM driver.
+ @param[in] ContextData Pointer to data buffer to be used for handler.
+ @param[in, out] CommunicationBuffer Pointer to the buffer that contains the communication Message
+ @param[in, out] SourceSize Size of the memory image to be used for handler.
+
+ @retval EFI_SUCCESS Callback Function Executed
+
+**/
+EFI_STATUS
+EFIAPI
+DtsOutOfSpecSmiCallback (
+ IN EFI_HANDLE SmmImageHandle,
+ IN CONST VOID *ContextData, OPTIONAL
+ IN OUT VOID *CommunicationBuffer, OPTIONAL
+ IN OUT UINTN *SourceSize OPTIONAL
+ )
+{
+ DTS_EVENT_TYPE EventType;
+
+ //
+ // If not enabled; return. (The DTS will be disabled upon S3 entry
+ // and will remain disabled until after re-initialized upon wake.)
+ //
+ if (!mDtsEnabled) {
+ return EFI_SUCCESS;
+ }
+
+ EventType = DtsEventNone;
+
+ if (mIsPackageTempMsrAvailable) {
+ //
+ // Get the Package DTS Event Type
+ //
+ DigitalThermalSensorEventCheckPackageMsr (&EventType);
+ } else {
+ //
+ // Get the DTS Event Type
+ //
+ DigitalThermalSensorEventCheck (&EventType);
+ }
+
+ //
+ // Check if this a DTS Out Of Spec SMI event
+ //
+ if (EventType == DtsEventOutOfSpec) {
+
+ //
+ // Return Critical temperature value to _TMP and generate GPE event for critical shutdown.
+ //
+ mCpuGlobalNvsAreaPtr->EnableDigitalThermalSensor = DTS_OUT_OF_SPEC_OCCURRED;
+
+ //
+ // Generate SCI to shut down the system
+ //
+ DigitalThermalSensorSetSwGpeSts ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Call from SMI handler to handle Package thermal temperature Digital Thermal Sensor CPU Local APIC SMI
+ for thermal threshold interrupt
+
+**/
+VOID
+PackageThermalDTS (
+ VOID
+ )
+{
+ DTS_EVENT_TYPE PkgEventType;
+
+ PkgEventType = DtsEventNone;
+
+ //
+ // Check is this a Platform SMI event or the flag of update DTS temperature and threshold value in every SMI
+ //
+ if (DigitalThermalSensorEventCheckPackageMsr (&PkgEventType) || mUpdateDtsInEverySmi) {
+ //
+ // Disable Local APIC SMI before programming the threshold
+ //
+ RunOnAllLogicalProcessors (DigitalThermalSensorDisableSmi, NULL);
+
+ do {
+ //
+ // Handle Package events
+ //
+ if ((PkgEventType == DtsEventOutOfSpec) && (mCpuGlobalNvsAreaPtr->DtsAcpiEnable == 0)) {
+
+ }
+ //
+ // Set the thermal trip toints as needed.
+ //
+ mCpuGlobalNvsAreaPtr->PackageDTSTemperature = 0;
+
+ //
+ // Set the Package thermal sensor thresholds
+ //
+ PackageDigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->PackageDTSTemperature);
+
+ //
+ // Set SWGPE Status to generate an SCI if we had any events
+ //
+ if ((PkgEventType != DtsEventNone) || mUpdateDtsInEverySmi) {
+ DigitalThermalSensorSetSwGpeSts ();
+ }
+
+ } while (DigitalThermalSensorEventCheckPackageMsr (&PkgEventType));
+
+ //
+ // Enable Local APIC SMI on all logical processors
+ //
+ RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL);
+ }
+}
+
+
+/**
+ SMI handler to handle Digital Thermal Sensor CPU Local APIC SMI
+ for thermal threshold interrupt
+
+ @param[in] SmmImageHandle Image handle returned by the SMM driver.
+ @param[in] ContextData Pointer to data buffer to be used for handler.
+ @param[in, out] CommunicationBuffer Pointer to the buffer that contains the communication Message
+ @param[in, out] SourceSize Size of the memory image to be used for handler.
+
+ @retval EFI_SUCCESS Callback Function Executed
+
+**/
+EFI_STATUS
+EFIAPI
+DtsSmiCallback (
+ IN EFI_HANDLE SmmImageHandle,
+ IN CONST VOID *ContextData, OPTIONAL
+ IN OUT VOID *CommunicationBuffer, OPTIONAL
+ IN OUT UINTN *SourceSize OPTIONAL
+ )
+{
+ UINTN Index;
+ DTS_EVENT_TYPE EventType;
+
+ //
+ // If not enabled; return. (The DTS will be disabled upon S3 entry
+ // and will remain disabled until after re-initialized upon wake.)
+ //
+ if (!mDtsEnabled) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Get the Package thermal temperature
+ //
+ if (mIsPackageTempMsrAvailable) {
+ RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL);
+ PackageThermalDTS ();
+ } else {
+ //
+ // We enable the Thermal interrupt on the AP's prior to the event check
+ // for the case where the AP has gone through the INIT-SIPI-SIPI sequence
+ // and does not have the interrupt enabled. (This allows the AP thermal
+ // interrupt to be re-enabled due to chipset-based SMIs without waiting
+ // to receive a DTS event on the BSP.)
+ //
+ for (Index = 1; Index < gSmst->NumberOfCpus; Index++) {
+ RunOnSpecificLogicalProcessor (DigitalThermalSensorEnableSmi, Index, NULL);
+ }
+ //
+ // Check is this a DTS SMI event or the flag of update DTS temperature and threshold value in every SMI
+ //
+ if (DigitalThermalSensorEventCheck (&EventType) || mUpdateDtsInEverySmi) {
+ //
+ // Disable Local APIC SMI before programming the threshold
+ //
+ RunOnAllLogicalProcessors (DigitalThermalSensorDisableSmi, NULL);
+ do {
+ //
+ // Handle BSP events
+ //
+
+ //
+ // Set the thermal trip toints as needed.
+ // Note: We only save the highest temperature of each die in
+ // the NVS area when more than two logical processors are
+ // present as only the highest DTS reading is actually used by
+ // the current ASL solution.
+ //
+ mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0;
+ mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0;
+
+ //
+ // Set the BSP thermal sensor thresholds
+ //
+ DigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature);
+
+ //
+ // Set the AP thermal sensor thresholds and update temperatures
+ //
+ for (Index = 1; Index < gSmst->NumberOfCpus / 2; Index++) {
+ RunOnSpecificLogicalProcessor (
+ DigitalThermalSensorSetThreshold,
+ Index,
+ &mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature
+ );
+ }
+
+ for (Index = gSmst->NumberOfCpus / 2; Index < gSmst->NumberOfCpus; Index++) {
+ RunOnSpecificLogicalProcessor (
+ DigitalThermalSensorSetThreshold,
+ Index,
+ &mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature
+ );
+ }
+ //
+ // Set SWGPE Status to generate an SCI if we had any events
+ //
+ if ((EventType != DtsEventNone) || mUpdateDtsInEverySmi) {
+ DigitalThermalSensorSetSwGpeSts ();
+ }
+
+ } while (DigitalThermalSensorEventCheck (&EventType));
+ //
+ // Enable Local APIC SMI on all logical processors
+ //
+ RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function executes DTS procedures for preparing to enter S3.
+
+ @param[in] Handle Handle of the callback
+ @param[in] Context The dispatch context
+ @param[in, out] CommBuffer Pointer to the buffer that contains the communication Message
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS DTS disabled
+
+**/
+EFI_STATUS
+EFIAPI
+DtsS3EntryCallBack (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+
+ //
+ // Clear the Digital Thermal Sensor flag in ACPI NVS.
+ //
+ mCpuGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_DISABLE;
+
+ //
+ // Clear the enable flag.
+ //
+ mDtsEnabled = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Performs initialization of the threshold table.
+
+ @retval EFI_SUCCESS Threshold tables initialized successfully.
+
+**/
+EFI_STATUS
+InitThresholdTable (
+ VOID
+ )
+{
+ UINTN i;
+ UINT8 Delta;
+
+ //
+ // If the table must be updated, shift the thresholds by the difference between
+ // TJ_MAX=110 and DtsTjMax.
+ //
+ if (mDtsTjMax != TJ_MAX) {
+ Delta = TJ_MAX - mDtsTjMax;
+
+ for (i = 0; i < mNoOfThresholdRanges; i++) {
+ if (mDtsThresholdTable[i][1] <= mDtsTjMax) {
+ mDtsThresholdTable[i][0] = mDtsThresholdTable[i][0] - Delta;
+ } else {
+ mDtsThresholdTable[i][0] = 0;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Perform first time initialization of the Digital Thermal Sensor
+
+ @retval EFI_SUCCESS Init Digital Thermal Sensor successfully
+
+**/
+EFI_STATUS
+InitDigitalThermalSensor (
+ VOID
+ )
+{
+ UINTN Index;
+
+ if (mDtsValue != DTS_OUT_OF_SPEC_ONLY) {
+ //
+ // Initialize the DTS threshold table.
+ //
+ InitThresholdTable ();
+
+ //
+ // Set the thermal trip points on all logical processors.
+ // Note: We only save the highest temperature of each die in the NVS area when
+ // more than two logical processors are present as only the highest DTS reading
+ // is actually used by the current ASL solution.
+ //
+ mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature = 0;
+ mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature = 0;
+ mCpuGlobalNvsAreaPtr->PackageDTSTemperature = 0;
+ if (mIsPackageTempMsrAvailable) {
+ PackageDigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->PackageDTSTemperature);
+ } else {
+ DigitalThermalSensorSetThreshold (&mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature);
+ for (Index = 1; Index < gSmst->NumberOfCpus / 2; Index++) {
+ RunOnSpecificLogicalProcessor (
+ DigitalThermalSensorSetThreshold,
+ Index,
+ &mCpuGlobalNvsAreaPtr->BspDigitalThermalSensorTemperature
+ );
+ }
+ for (Index = gSmst->NumberOfCpus / 2; Index < gSmst->NumberOfCpus; Index++) {
+ RunOnSpecificLogicalProcessor (
+ DigitalThermalSensorSetThreshold,
+ Index,
+ &mCpuGlobalNvsAreaPtr->ApDigitalThermalSensorTemperature
+ );
+ }
+ }
+ mCpuGlobalNvsAreaPtr->EnableDigitalThermalSensor = CPU_FEATURE_ENABLE;
+ } else {
+ //
+ // Enable Out Of Spec Interrupt
+ //
+ if (mIsPackageTempMsrAvailable) {
+ PackageDigitalThermalSensorSetOutOfSpecInterrupt (NULL);
+ } else {
+ RunOnAllLogicalProcessors (DigitalThermalSensorSetOutOfSpecInterrupt, NULL);
+ }
+
+ mCpuGlobalNvsAreaPtr->EnableDigitalThermalSensor = DTS_OUT_OF_SPEC_ONLY;
+ }
+
+ //
+ // Enable the Local APIC SMI on all logical processors
+ //
+ RunOnAllLogicalProcessors (DigitalThermalSensorEnableSmi, NULL);
+
+ //
+ // Set Digital Thermal Sensor flag in ACPI NVS
+ //
+ mUpdateDtsInEverySmi = UPDATE_DTS_EVERY_SMI;
+ mDtsEnabled = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes the Thermal Sensor Control MSR
+
+ This function must be AP safe.
+
+ @param[in] Buffer Unused.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorEnable (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER MsrData;
+
+ //
+ // First, clear our log bits
+ //
+ MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS);
+ if (mDtsValue != DTS_OUT_OF_SPEC_ONLY) {
+ MsrData.Qword &= (UINT64) ~THERM_STATUS_LOG_MASK;
+ } else {
+ MsrData.Qword &= (UINT64) ~B_OUT_OF_SPEC_STATUS_LOG;
+ }
+
+ AsmWriteMsr64 (MSR_IA32_THERM_STATUS, MsrData.Qword);
+
+ //
+ // Second, configure the thermal sensor control
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_MISC_PWR_MGMT);
+
+ //
+ // Only lock interrupts if in CMP mode
+ //
+ if (gSmst->NumberOfCpus > 1) {
+ MsrData.Qword |= (UINT64) B_LOCK_THERMAL_INT;
+ }
+
+ AsmWriteMsr64 (EFI_MSR_MISC_PWR_MGMT, MsrData.Qword);
+
+ return;
+}
+
+
+/**
+ Initializes the Package Thermal Sensor Control MSR
+
+ @param[in] Buffer Unused.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+PackageDigitalThermalSensorEnable (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER MsrData;
+
+ //
+ // First, clear our log bits
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS);
+ if (mDtsValue != DTS_OUT_OF_SPEC_ONLY) {
+ MsrData.Qword &= ~THERM_STATUS_LOG_MASK;
+ } else {
+ MsrData.Qword &= ~B_OUT_OF_SPEC_STATUS_LOG;
+ }
+
+ AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS, MsrData.Qword);
+
+ //
+ // Second, configure the thermal sensor control
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_MISC_PWR_MGMT);
+
+ //
+ // Only lock interrupts if in CMP mode
+ //
+ if (gSmst->NumberOfCpus > 1) {
+ MsrData.Qword |= B_LOCK_THERMAL_INT;
+ }
+
+ AsmWriteMsr64 (EFI_MSR_MISC_PWR_MGMT, MsrData.Qword);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Generates a _GPE._L02 SCI to an ACPI OS.
+
+**/
+VOID
+DigitalThermalSensorSetSwGpeSts (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Pm1Cntl;
+ UINT8 GpeCntl;
+
+ //
+ // Check SCI enable
+ //
+ Status = gSmst->SmmIo.Io.Read (
+ &gSmst->SmmIo,
+ SMM_IO_UINT8,
+ mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT,
+ 1,
+ &Pm1Cntl
+ );
+
+ if ((Pm1Cntl & B_PCH_ACPI_PM1_CNT_SCI_EN) != 0) {
+ //
+ // Set SWGPE Status
+ //
+ Status = gSmst->SmmIo.Io.Read (
+ &gSmst->SmmIo,
+ SMM_IO_UINT8,
+ mAcpiBaseAddr + R_ACPI_GPE_CNTL,
+ 1,
+ &GpeCntl
+ );
+ GpeCntl |= B_SWGPE_CTRL;
+ Status = gSmst->SmmIo.Io.Write (
+ &gSmst->SmmIo,
+ SMM_IO_UINT8,
+ mAcpiBaseAddr + R_ACPI_GPE_CNTL,
+ 1,
+ &GpeCntl
+ );
+ }
+}
+
+
+/**
+ Checks for a Core Thermal Event on any processor
+
+ @param[in] EventType DTS_EVENT_TYPE to indicate which DTS event type has been detected.
+
+ @retval TRUE Means this is a DTS Thermal event
+ @retval FALSE Means this is not a DTS Thermal event.
+
+**/
+BOOLEAN
+DigitalThermalSensorEventCheck (
+ IN DTS_EVENT_TYPE *EventType
+ )
+{
+ //
+ // Clear event status
+ //
+ *EventType = DtsEventNone;
+
+ RunOnAllLogicalProcessors (DigitalThermalSensorEventCheckMsr, EventType);
+
+ //
+ // Return TRUE if any logical processor reported an event.
+ //
+ if (*EventType != DtsEventNone) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Checks for a Package Thermal Event by reading MSR.
+
+ @param[in] PkgEventType DTS_EVENT_TYPE to indicate which DTS event type has been detected.
+
+ @retval TRUE Means this is a Package DTS Thermal event
+ @retval FALSE Means this is not a Package DTS Thermal event.
+
+**/
+BOOLEAN
+DigitalThermalSensorEventCheckPackageMsr (
+ IN DTS_EVENT_TYPE *PkgEventType
+ )
+{
+ MSR_REGISTER MsrData;
+
+ //
+ // Clear event status
+ //
+ *PkgEventType = DtsEventNone;
+
+ //
+ // If Processor has already been flagged as Out-Of-Spec,
+ // just return.
+ //
+ if (*PkgEventType != DtsEventOutOfSpec) {
+ //
+ // Read thermal status
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS);
+
+ //
+ // Check for Out-Of-Spec status.
+ //
+ if (MsrData.Qword & B_OUT_OF_SPEC_STATUS_LOG) {
+ *PkgEventType = DtsEventOutOfSpec;
+
+ //
+ // Check thresholds.
+ //
+ } else if ((mDtsValue != DTS_OUT_OF_SPEC_ONLY) &&
+ (MsrData.Qword & (B_THERMAL_THRESHOLD_1_STATUS_LOG | B_THERMAL_THRESHOLD_2_STATUS_LOG))
+ ) {
+ *PkgEventType = DtsEventThreshold;
+ }
+ }
+
+ //
+ // Return TRUE if processor reported an event.
+ //
+ if (*PkgEventType != DtsEventNone) {
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+
+/**
+ Checks for a Core Thermal Event by reading MSR.
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to DTS_EVENT_TYPE
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorEventCheckMsr (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER MsrData;
+ DTS_EVENT_TYPE *EventType;
+
+ //
+ // Cast to enhance readability.
+ //
+ EventType = (DTS_EVENT_TYPE *) Buffer;
+
+ //
+ // If any processor has already been flagged as Out-Of-Spec,
+ // just return.
+ //
+ if (*EventType != DtsEventOutOfSpec) {
+ //
+ // Read thermal status
+ //
+ MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS);
+
+ //
+ // Check for Out-Of-Spec status.
+ //
+ if (MsrData.Qword & B_OUT_OF_SPEC_STATUS_LOG) {
+ *EventType = DtsEventOutOfSpec;
+
+ //
+ // Check thresholds.
+ //
+ } else if ((mDtsValue != DTS_OUT_OF_SPEC_ONLY) &&
+ (MsrData.Qword & (B_THERMAL_THRESHOLD_1_STATUS_LOG | B_THERMAL_THRESHOLD_2_STATUS_LOG))
+ ) {
+ *EventType = DtsEventThreshold;
+ }
+ }
+}
+
+
+/**
+ Set the Out Of Spec Interrupt in all cores
+ This function must be AP safe.
+
+ @param[in] Buffer Unused
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorSetOutOfSpecInterrupt (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER MsrData;
+
+ //
+ // Enable Out Of Spec interrupt
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_INTERRUPT);
+ MsrData.Qword |= (UINT64) OVERHEAT_INTERRUPT_ENABLE;
+ AsmWriteMsr64 (EFI_MSR_IA32_THERM_INTERRUPT, MsrData.Qword);
+
+ return;
+}
+
+/**
+ Set the Out Of Spec Interrupt on the package
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Out Of Spec Interrupt programmed successfully
+
+**/
+EFI_STATUS
+PackageDigitalThermalSensorSetOutOfSpecInterrupt (
+ IN VOID *Buffer
+ )
+{
+ MSR_REGISTER MsrData;
+
+ //
+ // Enable Out Of Spec interrupt
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT);
+ MsrData.Qword |= OVERHEAT_INTERRUPT_ENABLE;
+ AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT, MsrData.Qword);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read the temperature and reconfigure the thresholds.
+ This function must be AP safe.
+
+ @param[in] Buffer Pointer to UINT8 to update with the current temperature
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorSetThreshold (
+ IN VOID *Buffer
+ )
+{
+ UINT8 ThresholdEntry;
+ MSR_REGISTER MsrData;
+ UINT8 Temperature;
+
+ //
+ // Read the temperature
+ //
+ MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS);
+
+ //
+ // If Out-Of-Spec, return the critical shutdown temperature.
+ //
+ if (MsrData.Qword & B_OUT_OF_SPEC_STATUS) {
+ *((UINT8 *) Buffer) = DTS_CRITICAL_TEMPERATURE;
+ return;
+ } else if (MsrData.Qword & B_READING_VALID) {
+ //
+ // Find the DTS temperature.
+ //
+ Temperature = mDtsTjMax - (MsrData.Bytes.ThirdByte & OFFSET_MASK);
+ //
+ // We only update the temperature if it is above the current temperature.
+ //
+ if (Temperature > *((UINT8 *) Buffer)) {
+ *((UINT8 *) Buffer) = Temperature;
+ }
+ //
+ // Compare the current temperature to the Digital Thermal Sensor Threshold Table until
+ // a matching Value is found.
+ //
+ ThresholdEntry = 0;
+ while ((Temperature > mDtsThresholdTable[ThresholdEntry][0]) && (ThresholdEntry < (mNoOfThresholdRanges - 1))) {
+ ThresholdEntry++;
+ }
+ //
+ // Update the threshold values
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_THERM_INTERRUPT);
+ //
+ // Low temp is threshold #2
+ //
+ MsrData.Bytes.ThirdByte = mDtsThresholdTable[ThresholdEntry][1];
+ //
+ // High temp is threshold #1
+ //
+ MsrData.Bytes.SecondByte = mDtsThresholdTable[ThresholdEntry][2];
+ DEBUG ((DEBUG_INFO, "CPU DTS Threshold #1 - %x\n", MsrData.Bytes.SecondByte));
+ DEBUG ((DEBUG_INFO, "CPU DTS Threshold #2 - %x\n", MsrData.Bytes.ThirdByte));
+ //
+ // Enable interrupts
+ //
+ MsrData.Qword |= (UINT64) TH1_ENABLE;
+ MsrData.Qword |= (UINT64) TH2_ENABLE;
+
+ //
+ // If the high temp is at TjMax (offset == 0)
+ // We disable the int to avoid generating a large number of SMI because of TM1/TM2
+ // causing many threshold crossings
+ //
+ if (MsrData.Bytes.SecondByte == 0x80) {
+ MsrData.Qword &= (UINT64) ~TH1_ENABLE;
+ }
+
+ AsmWriteMsr64 (EFI_MSR_IA32_THERM_INTERRUPT, MsrData.Qword);
+ }
+
+ //
+ // Clear the threshold log bits
+ //
+ MsrData.Qword = AsmReadMsr64 (MSR_IA32_THERM_STATUS);
+ MsrData.Qword &= (UINT64) ~THERM_STATUS_THRESHOLD_LOG_MASK;
+ AsmWriteMsr64 (MSR_IA32_THERM_STATUS, MsrData.Qword);
+
+ return;
+}
+
+/**
+ Read the temperature and reconfigure the thresholds on the package
+
+ @param[in] Buffer Pointer to UINT8 to update with the current temperature
+
+ @retval EFI_SUCCESS Digital Thermal Sensor threshold programmed successfully
+
+**/
+EFI_STATUS
+PackageDigitalThermalSensorSetThreshold (
+ IN VOID *Buffer
+ )
+{
+ UINT8 ThresholdEntry;
+ MSR_REGISTER MsrData;
+ UINT8 Temperature;
+
+ //
+ // Read the temperature
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS);
+
+ //
+ // If Out-Of-Spec, return the critical shutdown temperature.
+ //
+ if (MsrData.Qword & B_OUT_OF_SPEC_STATUS) {
+ *((UINT8 *) Buffer) = DTS_CRITICAL_TEMPERATURE;
+ return EFI_SUCCESS;
+ } else if (MsrData.Qword & B_READING_VALID) {
+ //
+ // Find the DTS temperature.
+ //
+ Temperature = mDtsTjMax - (MsrData.Bytes.ThirdByte & OFFSET_MASK);
+ //
+ // We only update the temperature if it is above the current temperature.
+ //
+ if (Temperature > *((UINT8 *) Buffer)) {
+ *((UINT8 *) Buffer) = Temperature;
+ }
+ //
+ // Compare the current temperature to the Digital Thermal Sensor Threshold Table until
+ // a matching Value is found.
+ //
+ ThresholdEntry = 0;
+ while ((Temperature > mDtsThresholdTable[ThresholdEntry][0]) && (ThresholdEntry < (mNoOfThresholdRanges - 1))) {
+ ThresholdEntry++;
+ }
+ //
+ // Update the threshold values
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT);
+ //
+ // Low temp is threshold #2
+ //
+ MsrData.Bytes.ThirdByte = mDtsThresholdTable[ThresholdEntry][1];
+ //
+ // High temp is threshold #1
+ //
+ MsrData.Bytes.SecondByte = mDtsThresholdTable[ThresholdEntry][2];
+
+ //
+ // Enable interrupts
+ //
+ MsrData.Qword |= TH1_ENABLE;
+ MsrData.Qword |= TH2_ENABLE;
+
+ //
+ // If the high temp is at TjMax (offset == 0)
+ // We disable the int to avoid generating a large number of SMI because of TM1/TM2
+ // causing many threshold crossings
+ //
+ if (MsrData.Bytes.SecondByte == 0x80) {
+ MsrData.Qword &= ~TH1_ENABLE;
+ }
+
+ AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT, MsrData.Qword);
+ }
+
+ //
+ // Clear the threshold log bits
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS);
+ MsrData.Qword &= ~THERM_STATUS_THRESHOLD_LOG_MASK;
+ AsmWriteMsr64 (EFI_MSR_IA32_PACKAGE_THERM_STATUS, MsrData.Qword);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enables the Thermal Interrupt in the core Local APIC.
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Enable Local APIC to generate a SMI successfully
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorEnableSmi (
+ IN VOID *Buffer
+ )
+{
+ UINT32 ApicThermalValue;
+ BOOLEAN x2ApicEnabled;
+
+ x2ApicEnabled = (BOOLEAN) (((AsmReadMsr64 (EFI_MSR_XAPIC_BASE)) & (BIT11 + BIT10)) == BIT11 + BIT10);
+
+ //
+ // Configure the Local APIC to generate an SMI on Thermal events. First,
+ // Clear BIT16, BIT10-BIT8, BIT7-BIT0. Then, set BIT9 (delivery mode).
+ // Don't enable the interrupt if it's already enabled
+ //
+ if (x2ApicEnabled) {
+ ApicThermalValue = (UINT32) AsmReadMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM);
+ } else {
+ ApicThermalValue = *(UINT32 *) (UINTN) LOCAL_APIC_THERMAL_DEF;
+ }
+
+ if ((ApicThermalValue & (B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) != V_MODE_SMI) {
+ ApicThermalValue = (ApicThermalValue &~(B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) | V_MODE_SMI;
+ if (x2ApicEnabled) {
+ AsmWriteMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM, ApicThermalValue);
+ } else {
+ *(UINT32 *) (UINTN) (LOCAL_APIC_THERMAL_DEF) = (UINT32) ApicThermalValue;
+ }
+ }
+
+ return;
+}
+
+
+/**
+ Disables the Thermal Interrupt in the core Local APIC.
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Disable Local APIC to generate a SMI successfully
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorDisableSmi (
+ IN VOID *Buffer
+ )
+{
+ UINT32 ApicThermalValue;
+ BOOLEAN x2ApicEnabled;
+
+ x2ApicEnabled = (BOOLEAN) (((AsmReadMsr64 (EFI_MSR_XAPIC_BASE)) & (BIT11 + BIT10)) == BIT11 + BIT10);
+
+ //
+ // Disable Local APIC thermal entry
+ //
+ if (x2ApicEnabled) {
+ ApicThermalValue = (UINT32) AsmReadMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM);
+ } else {
+ ApicThermalValue = *(UINT32 *) (UINTN) LOCAL_APIC_THERMAL_DEF;
+ }
+ //
+ // Following descriptions were from SSE BIOS
+ // We set the interrupt mode at the same time as the interrupt is disabled to
+ // avoid the "Received Illegal Vector" being set in the Error Status Register.
+ // and eax, 0FFFEF800h
+ // or eax, 000010200h ; Clear Mask, Set Delivery
+ //
+ ApicThermalValue = (ApicThermalValue &~(B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) | (B_INTERRUPT_MASK | V_MODE_SMI);
+ if (x2ApicEnabled) {
+ AsmWriteMsr64 (EFI_MSR_EXT_XAPIC_LVT_THERM, ApicThermalValue);
+ } else {
+ *(UINT32 *) (UINTN) (LOCAL_APIC_THERMAL_DEF) = (UINT32) ApicThermalValue;
+ }
+
+ return;
+}
+
+
+/**
+ Runs the specified procedure on one specific logical processors, passing in the
+ parameter buffer to the procedure.
+
+ @param[in, out] Procedure The function to be run.
+ @param[in] Index Indicate which logical processor should execute this procedure
+ @param[in, out] Buffer Pointer to a parameter buffer.
+
+ @retval EFI_SUCCESS Function executed successfully.
+
+**/
+STATIC
+EFI_STATUS
+RunOnSpecificLogicalProcessor (
+ IN OUT EFI_AP_PROCEDURE Procedure,
+ IN UINTN Index,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 RetryIteration;
+
+ //
+ // Run the procedure on one specific logical processor.
+ //
+ Status = EFI_NOT_READY;
+ for (RetryIteration = 0; (RetryIteration < DTS_AP_SAFE_RETRY_LIMIT) && (Status != EFI_SUCCESS); RetryIteration++) {
+ Status = gSmst->SmmStartupThisAp (Procedure, Index, Buffer);
+ if (Status != EFI_SUCCESS) {
+ //
+ // SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again.
+ //
+ MicroSecondDelay (DTS_WAIT_PERIOD);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Digital Thermal Sensor (DTS) SMM driver function.
+
+ @param[in] ImageHandle Image handle for this driver image
+
+ @retval EFI_SUCCESS Driver initialization completed successfully
+ @retval EFI_OUT_OF_RESOURCES Error when allocating required memory buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallDigitalThermalSensor (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ MSR_REGISTER MsrData;
+ CPU_GLOBAL_NVS_AREA_PROTOCOL *CpuGlobalNvsAreaProtocol;
+ EFI_HANDLE SxDispatchHandle;
+ EFI_CPUID_REGISTER Cpuid06;
+ EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext;
+ EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatchProtocol;
+ VOID *Hob;
+ CPU_INIT_DATA_HOB *mCpuInitDataHob;
+ CPU_CONFIG *mCpuConfig;
+
+ Handle = NULL;
+
+ //
+ // Get CPU Init Data Hob
+ //
+ Hob = GetFirstGuidHob (&gCpuInitDataHobGuid);
+ if (Hob == NULL) {
+ DEBUG ((DEBUG_ERROR, "CPU Data HOB not available\n"));
+ return EFI_NOT_FOUND;
+ }
+ mCpuInitDataHob = (CPU_INIT_DATA_HOB *) ((UINTN) Hob + sizeof (EFI_HOB_GUID_TYPE));
+ mCpuConfig = (CPU_CONFIG *) ((UINTN) mCpuInitDataHob->CpuConfig);
+
+ //
+ // Check if DTS disabled in setup.
+ //
+ if (mCpuConfig->EnableDts == CPU_FEATURE_DISABLE) {
+ DEBUG ((DEBUG_WARN, "DTS not enabled/supported, so driver not loaded into SMM\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Verify the code supports the number of processors present.
+ //
+ ASSERT_EFI_ERROR (gSmst->NumberOfCpus <= MAX_NUMBER_OF_THREADS_SUPPORTED);
+
+ //
+ // Get the ACPI Base Address
+ //
+ mAcpiBaseAddr = (UINT16)PcdGet16(PcdScAcpiIoPortBaseAddress);
+
+ //
+ // Initialize DTS setup value
+ //
+ mDtsValue = (UINT8) mCpuConfig->EnableDts;
+
+ //
+ // Locate CPU Global NVS area
+ //
+ Status = gBS->LocateProtocol (&gCpuGlobalNvsAreaProtocolGuid, NULL, (VOID **) &CpuGlobalNvsAreaProtocol);
+ ASSERT_EFI_ERROR (Status);
+ mCpuGlobalNvsAreaPtr = CpuGlobalNvsAreaProtocol->Area;
+
+ //
+ // CPU_ID 6, EAX bit 6 for the Package temperature MSR support
+ //
+ ZeroMem (&Cpuid06, sizeof (Cpuid06));
+ AsmCpuid (6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx);
+
+ mIsPackageTempMsrAvailable = (((UINT8) (mCpuConfig->PackageDts) && ((Cpuid06.RegEax >> 6) & 0x01) ) ? 1: 0);
+ DEBUG ((DEBUG_INFO, "Is Package DTS Supported: %x\n", mIsPackageTempMsrAvailable));
+ mCpuGlobalNvsAreaPtr->IsPackageTempMSRAvailable = mIsPackageTempMsrAvailable;
+
+ //
+ // Register a callback function to handle Digital Thermal Sensor SMIs.
+ //
+ if (mCpuConfig->EnableDts != DTS_OUT_OF_SPEC_ONLY) {
+ Status = gSmst->SmiHandlerRegister (DtsSmiCallback, NULL, &Handle);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ Status = gSmst->SmiHandlerRegister (DtsOutOfSpecSmiCallback, NULL, &Handle);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Locate the Sx Dispatch Protocol
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmSxDispatch2ProtocolGuid, NULL, (VOID **) &SxDispatchProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the callback for S3 entry
+ //
+ SxDispatchContext.Type = SxS3;
+ SxDispatchContext.Phase = SxEntry;
+ Status = SxDispatchProtocol->Register (
+ SxDispatchProtocol,
+ DtsS3EntryCallBack,
+ &SxDispatchContext,
+ &SxDispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (mCpuConfig->EnableDts != DTS_OUT_OF_SPEC_ONLY) {
+ //
+ // Get the TCC Activation Temperature and use it for TjMax.
+ //
+ MsrData.Qword = AsmReadMsr64 (EFI_MSR_IA32_TEMPERATURE_TARGET);
+
+ mDtsTjMax = (MsrData.Bytes.ThirdByte);
+ mDtsThresholdTable = mDigitalThermalSensorThresholdTable;
+ mNoOfThresholdRanges = DTS_NUMBER_THRESHOLD_RANGES;
+ }
+
+ if (mIsPackageTempMsrAvailable) {
+ //
+ // Enable the DTS on package.
+ //
+ PackageDigitalThermalSensorEnable (NULL);
+ } else {
+ //
+ // Enable the DTS on all logical processors.
+ //
+ RunOnAllLogicalProcessors (DigitalThermalSensorEnable, NULL);
+ }
+
+ //
+ // Initialize Digital Thermal Sensor Function in POST
+ //
+ InitDigitalThermalSensor ();
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h
new file mode 100644
index 0000000000..b8a5c54538
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDts.h
@@ -0,0 +1,369 @@
+/** @file
+ Defines and prototypes for the Digital Thermal Sensor SMM driver.
+
+ Copyright (c) 1999 - 2016, 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_MGMT_DTS_H_
+#define _POWER_MGMT_DTS_H_
+
+//
+// Include files
+//
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmIoTrapDispatch2.h>
+#include <CpuDataStruct.h>
+#include <Protocol/CpuGlobalNvsArea.h>
+#include <Private/CpuInitDataHob.h>
+#include <Library/MmPciLib.h>
+#include <Library/AslUpdateLib.h>
+#include "PowerMgmtDtsLib.h"
+
+#define MSR_IA32_THERM_STATUS 0x0000019C
+///
+/// Stall period in microseconds
+///
+#define DTS_WAIT_PERIOD 1
+#define DTS_AP_SAFE_RETRY_LIMIT 3
+///
+/// Define module definitions
+///
+#define TJ_MAX 110
+#define DTS_CRITICAL_TEMPERATURE 255
+
+//
+// Generic definitions for DTS
+//
+#define DTS_OUT_OF_SPEC_ONLY 2
+#define DTS_OUT_OF_SPEC_OCCURRED 3
+
+#define DTS_SAMPLE_RATE 0x10
+#define EFI_MSR_XAPIC_BASE 0x1B
+#define TH1_VALUE 8
+#define TH1_ENABLE (1 << 15)
+#define TH2_VALUE 16
+#define TH2_ENABLE (1 << 23)
+#define OFFSET_MASK (0x7F)
+#define OVERHEAT_INTERRUPT_ENABLE (1 << 4)
+
+#define B_OUT_OF_SPEC_STATUS (1 << 4)
+#define B_OUT_OF_SPEC_STATUS_LOG (1 << 5)
+#define B_THERMAL_THRESHOLD_1_STATUS (1 << 6)
+#define B_THERMAL_THRESHOLD_1_STATUS_LOG (1 << 7)
+#define B_THERMAL_THRESHOLD_2_STATUS (1 << 8)
+#define B_THERMAL_THRESHOLD_2_STATUS_LOG (1 << 9)
+#define B_READING_VALID (1 << 31)
+
+#define EFI_MSR_IA32_TEMPERATURE_TARGET 0x1A2
+#define EFI_MSR_EXT_XAPIC_LVT_THERM 0x833
+#define EFI_MSR_MISC_PWR_MGMT 0x1AA
+#define B_LOCK_THERMAL_INT (1 << 22)
+
+#define THERM_STATUS_LOG_MASK (B_THERMAL_THRESHOLD_2_STATUS_LOG | B_THERMAL_THRESHOLD_1_STATUS_LOG | B_OUT_OF_SPEC_STATUS_LOG)
+#define THERM_STATUS_THRESHOLD_LOG_MASK (B_THERMAL_THRESHOLD_2_STATUS_LOG | B_THERMAL_THRESHOLD_1_STATUS_LOG)
+
+#define EFI_MSR_IA32_PACKAGE_THERM_STATUS 0x1B1
+#define EFI_MSR_IA32_PACKAGE_THERM_INTERRUPT 0x1B2
+
+#define B_DTS_IO_TRAP (1 << 2)
+#define B_SWGPE_CTRL (1 << 1)
+#define DTS_IO_TRAP_REGISTER_LOW_DWORD (0x00040001 + ICH_DTS_IO_TRAP_BASE_ADDRESS) ///< DigitalThermalSensor IO Trap High DWord value
+#define DTS_IO_TRAP_REGISTER_HIGH_DWORD 0x000200F0 ///< DigitalThermalSensor IO Trap High DWord value
+#define LOCAL_APIC_THERMAL_DEF 0xFEE00330
+#define B_INTERRUPT_MASK (1 << 16)
+#define B_DELIVERY_MODE (0x07 << 8)
+#define V_MODE_SMI (0x02 << 8)
+#define B_VECTOR (0xFF << 0)
+
+#define DTS_NUMBER_THRESHOLD_RANGES 9 ///< How many ranges are in the threshold table
+#define IO_TRAP_INIT_AP_DTS_FUNCTION 0x0A ///< Enable AP DigitalThermalSensor function
+#define IO_TRAP_INIT_DTS_FUNCTION_AFTER_S3 0x14 ///< Enable Digital Thermal Sensor function after resume from S3
+#define IO_TRAP_DISABLE_UPDATE_DTS 0x1E ///< Disable update DTS temperature and threshold value in every SMI
+#define INIT_DTS_SCF_MIN 0x10 ///< SCF Minimum value.
+#define INIT_DTS_SCF_UNITY 0x20 ///< SCF Unity Value.
+#define INIT_DTS_SCF_MAX 0x30 ///< SCF Maximum value.
+#define UPDATE_DTS_EVERY_SMI TRUE ///< Update DTS temperature and threshold value in every SMI
+#define R_PCH_ACPI_PM1_CNT 0x04
+#define B_PCH_ACPI_PM1_CNT_SCI_EN 0x00000001
+#define R_PCH_LPC_ACPI_BASE 0x40
+#define PCI_DEVICE_NUMBER_PCH_LPC 31
+#define MAX_NUMBER_OF_THREADS_SUPPORTED 8 ///< Max number of threads supported by processor.
+
+
+///
+/// Enumerate a DTS event type
+///
+typedef enum {
+ DtsEventNone,
+ DtsEventThreshold,
+ DtsEventOutOfSpec,
+ DtsEventMax
+} DTS_EVENT_TYPE;
+
+//
+// Function declarations
+//
+/**
+ Runs the specified procedure on one specific logical processors, passing in the
+ parameter buffer to the procedure.
+
+ @param[in, out] Procedure The function to be run.
+ @param[in] Index Indicate which logical processor should execute this procedure
+ @param[in, out] Buffer Pointer to a parameter buffer.
+
+ @retval EFI_SUCCESS Function executed successfully.
+
+**/
+STATIC
+EFI_STATUS
+RunOnSpecificLogicalProcessor (
+ IN OUT EFI_AP_PROCEDURE Procedure,
+ IN UINTN Index,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ SMI handler to handle Digital Thermal Sensor CPU Local APIC SMI
+ for thermal threshold interrupt
+
+ @param[in] SmmImageHandle Image handle returned by the SMM driver.
+ @param[in] ContextData Pointer to data buffer to be used for handler.
+ @param[in, out] CommunicationBuffer Pointer to the buffer that contains the communication Message
+ @param[in, out] SourceSize Size of the memory image to be used for handler.
+
+ @retval EFI_SUCCESS Callback Function Executed
+
+**/
+EFI_STATUS
+EFIAPI
+DtsSmiCallback (
+ IN EFI_HANDLE SmmImageHandle,
+ IN CONST VOID *ContextData, OPTIONAL
+ IN OUT VOID *CommunicationBuffer, OPTIONAL
+ IN OUT UINTN *SourceSize OPTIONAL
+ );
+
+/**
+ Call from SMI handler to handle Package thermal temperature Digital Thermal Sensor CPU Local APIC SMI
+ for thermal threshold interrupt
+
+ @retval None
+
+**/
+VOID
+PackageThermalDTS (
+ VOID
+ );
+
+/**
+ Perform first time initialization of the Digital Thermal Sensor
+
+ @retval EFI_SUCCESS Init Digital Thermal Sensor successfully
+
+**/
+EFI_STATUS
+InitDigitalThermalSensor (
+ VOID
+ );
+
+/**
+ Initializes the Thermal Sensor Control MSR
+
+ This function must be AP safe.
+
+ @param[in] Buffer Unused.
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorEnable (
+ IN VOID *Buffer
+ );
+
+/**
+ Initializes the Package Thermal Sensor Control MSR
+
+ @param[in] Buffer Unused.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+PackageDigitalThermalSensorEnable (
+ IN VOID *Buffer
+ );
+
+/**
+ Generates a _GPE._L02 SCI to an ACPI OS.
+
+**/
+VOID
+DigitalThermalSensorSetSwGpeSts (
+ VOID
+ );
+
+/**
+ Checks for a Core Thermal Event by reading MSR.
+
+ This function must be MP safe.
+
+ @param[in] Buffer Pointer to DTS_EVENT_TYPE
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorEventCheckMsr (
+ IN VOID *Buffer
+ );
+
+/**
+ Checks for a Package Thermal Event by reading MSR.
+
+ @param[in] PkgEventType DTS_EVENT_TYPE to indicate which DTS event type has been detected.
+
+ @retval TRUE Means this is a Package DTS Thermal event.
+ @retval FALSE Means this is not a Package DTS Thermal event.
+
+**/
+BOOLEAN
+DigitalThermalSensorEventCheckPackageMsr (
+ IN DTS_EVENT_TYPE *PkgEventType
+ );
+
+/**
+ Checks for a Core Thermal Event on any processor
+
+ @param[in] EventType DTS_EVENT_TYPE to indicate which DTS event type has been detected.
+
+ @retval TRUE Means this is a DTS Thermal event
+ @retval FALSE Means this is not a DTS Thermal event.
+
+**/
+BOOLEAN
+DigitalThermalSensorEventCheck (
+ IN DTS_EVENT_TYPE *EventType
+ );
+
+/**
+ Read the temperature and reconfigure the thresholds.
+ This function must be AP safe.
+
+ @param[in] Buffer Pointer to UINT8 to update with the current temperature
+
+ @retval EFI_SUCCESS Digital Thermal Sensor threshold programmed successfully.
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorSetThreshold (
+ IN VOID *Buffer
+ );
+
+/**
+ Read the temperature and reconfigure the thresholds on the package
+
+ @param[in] Buffer Pointer to UINT8 to update with the current temperature
+
+ @retval EFI_SUCCESS Digital Thermal Sensor threshold programmed successfully.
+
+**/
+EFI_STATUS
+PackageDigitalThermalSensorSetThreshold (
+ IN VOID *Buffer
+ );
+
+/**
+ Set the Out Of Spec Interrupt in all cores
+ This function must be AP safe.
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Out Of Spec Interrupt programmed successfully.
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorSetOutOfSpecInterrupt (
+ IN VOID *Buffer
+ );
+
+/**
+ Set the Out Of Spec Interrupt on the package
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Out Of Spec Interrupt programmed successfully.
+
+**/
+EFI_STATUS
+PackageDigitalThermalSensorSetOutOfSpecInterrupt (
+ IN VOID *Buffer
+ );
+
+/**
+ Enables the Thermal Interrupt in the core Local APIC.
+
+ @param[in] Buffer Unused
+
+ @retval EFI_SUCCESS Enable Local APIC to generate a SMI successfully.
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorEnableSmi (
+ IN VOID *Buffer
+ );
+
+/**
+ Disables the Thermal Interrupt in the core Local APIC.
+
+ @param[in] Buffer Unused
+
+**/
+VOID
+EFIAPI
+DigitalThermalSensorDisableSmi (
+ IN VOID *Buffer
+ );
+
+/**
+ Performs initialization of the threshold table.
+
+ @retval EFI_SUCCESS Threshold tables initialized successfully.
+
+**/
+EFI_STATUS
+InitThresholdTable (
+ VOID
+ );
+
+/**
+ This function executes DTS procedures for preparing to enter S3.
+
+ @param[in] Handle Handle of the callback
+ @param[in] Context The dispatch context
+ @param[in, out] CommBuffer Pointer to the buffer that contains the communication Message
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS DTS disabled
+
+**/
+EFI_STATUS
+EFIAPI
+DtsS3EntryCallBack (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h
new file mode 100644
index 0000000000..f66f90bbb2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtDtsLib.h
@@ -0,0 +1,32 @@
+/** @file
+ Defines and prototypes for the DigitalThermalSensor SMM driver.
+
+ Copyright (c) 1999 - 2016, 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_MGMT_DTS_LIB_H_
+#define _POWER_MGMT_DTS_LIB_H_
+
+
+/**
+ Read CPU temperature from platform diode
+
+ @retval TemperatureOfDiode Return the CPU temperature of platform diode
+
+**/
+UINT8
+ReadPlatformThermalDiode (
+ VOID
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c
new file mode 100644
index 0000000000..4385320544
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtS3.c
@@ -0,0 +1,221 @@
+/** @file
+ This is the SMM driver for saving and restoring the powermanagement related MSRs.
+
+ Copyright (c) 2011 - 2016, 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.
+
+**/
+
+#include "PowerMgmtSmm.h"
+
+///
+/// MSR table for S3 resume
+///
+STATIC EFI_MSR_VALUES mMsrValues[] = {
+ { MSR_IA32_PERF_CTRL, 0, B_IA32_PERF_CTRLP_STATE_TARGET, TRUE },
+ { MSR_PMG_IO_CAPTURE_BASE, 0, 0xFFFFFFFFFFFFFFFF, TRUE },
+ { MSR_PMG_CST_CONFIG, 0, 0xFFFFFFFFFFFFFFFF, TRUE },
+ { MSR_MISC_PWR_MGMT, 0, 0xFFFFFFFFFFFFFFFF, TRUE },
+ { MSR_IA32_MISC_ENABLE, 0, B_CPUID_POWER_MANAGEMENT_EAX_TURBO | B_MSR_IA32_MISC_DISABLE_TURBO | B_MSR_IA32_MISC_ENABLE_MONITOR | B_MSR_IA32_MISC_ENABLE_TME | B_MSR_IA32_MISC_ENABLE_EIST, TRUE },
+ { MSR_POWER_CTL, 0, 0xFFFFFFFFFFFFFFFF, TRUE },
+ { MSR_PACKAGE_POWER_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, TRUE },
+ { MSR_PL3_CONTROL, 0, 0xFFFFFFFFFFFFFFFF, FALSE },
+ { MSR_IA32_ENERGY_PERFORMANCE_BIAS, 0, 0xFFFFFFFFFFFFFFFF, TRUE },
+ { MSR_DDR_RAPL_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, FALSE },
+ { MSR_TURBO_RATIO_LIMIT, 0, 0xFFFFFFFFFFFFFFFF, TRUE }
+};
+
+/**
+ Save processor MSR runtime settings for S3.
+
+ @retval EFI_SUCCESS Processor MSR setting is saved.
+
+**/
+EFI_STATUS
+S3SaveMsr (
+ VOID
+ )
+{
+ UINT32 Index;
+ EFI_CPUID_REGISTER Cpuid06 = { 0, 0, 0, 0 };
+ UINT64 MsrValue;
+
+ for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) {
+ DEBUG ((DEBUG_INFO, " MSR Number: %x\n", mMsrValues[Index].Index));
+ if (mMsrValues[Index].Index == MSR_IA32_ENERGY_PERFORMANCE_BIAS) {
+ //
+ // MSR_IA32_ENERGY_PERFORMANCE_BIAS (1B0h) is accessible only if CPUID(6), ECX[3] = 1 to indicate feature availability.
+ //
+ AsmCpuid (CPUID_FUNCTION_6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx);
+ if (!(Cpuid06.RegEcx & B_CPUID_POWER_MANAGEMENT_ECX_ENERGY_EFFICIENT_POLICY_SUPPORT)) {
+ mMsrValues[Index].RestoreFlag = FALSE;
+ continue;
+ }
+ }
+ //
+ // Read Platform Info MSR
+ //
+ MsrValue = AsmReadMsr64 (MSR_PLATFORM_INFO);
+
+ //
+ // Check PLATFORM_INFO MSR[34:33] > 0 before accessing the MSR_CONFIG_TDP_CONTROL
+ //
+ if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) &&
+ ((RShiftU64 (MsrValue, N_MSR_PLATFORM_INFO_CONFIG_TDP_NUM_LEVELS_OFFSET) & 0x03))
+ ) {
+ mMsrValues[Index].RestoreFlag = TRUE;
+ }
+
+ if (mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) {
+ mMsrValues[Index].RestoreFlag = TRUE;
+ }
+ if (mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) {
+ mMsrValues[Index].RestoreFlag = TRUE;
+ }
+
+ //
+ // PL3 is supported
+ //
+ if (mMsrValues[Index].Index == MSR_PL3_CONTROL) {
+ mMsrValues[Index].RestoreFlag = TRUE;
+ }
+
+ if (mMsrValues[Index].RestoreFlag == TRUE) {
+ mMsrValues[Index].Value = AsmReadMsr64 (mMsrValues[Index].Index);
+ DEBUG ((DEBUG_INFO, " MSR Number %x read Done \n", mMsrValues[Index].Index));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Restore processor MSR runtime settings for S3.
+
+ @param[in] DispatchHandle The handle of this callback, obtained when registering
+ @param[in] DispatchContex Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
+
+**/
+VOID
+S3RestoreMsr (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext
+ )
+{
+ //
+ // Restore MSR's on all logical processors.
+ //
+ RunOnAllLogicalProcessors (ApSafeRestoreMsr, NULL);
+}
+
+
+/**
+ Runs the specified procedure on all logical processors, passing in the
+ parameter buffer to the procedure.
+
+ @param[in, out] Procedure The function to be run.
+ @param[in, out] Buffer Pointer to a parameter buffer.
+
+ @retval EFI_SUCCESS Run the procedure on all logical processors
+
+**/
+EFI_STATUS
+RunOnAllLogicalProcessors (
+ IN OUT EFI_AP_PROCEDURE Procedure,
+ IN OUT VOID *Buffer
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Run the procedure on all logical processors.
+ //
+ (*Procedure) (Buffer);
+ for (Index = 1; Index < gSmst->NumberOfCpus; Index++) {
+ Status = EFI_NOT_READY;
+ while (Status != EFI_SUCCESS) {
+ Status = gSmst->SmmStartupThisAp (Procedure, Index, Buffer);
+ if (Status != EFI_SUCCESS) {
+ //
+ // SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again.
+ //
+ MicroSecondDelay (PPM_WAIT_PERIOD);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will restore MSR settings.
+
+ This function must be MP safe.
+
+ @param[in, out] Buffer Unused
+
+**/
+VOID
+EFIAPI
+ApSafeRestoreMsr (
+ IN OUT VOID *Buffer
+ )
+{
+ UINT32 Index;
+ UINT64 MsrValue;
+
+ for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) {
+ //
+ // Check RestoreFlag and skip restoring the MSR if it is set to FALSE
+ //
+ if (mMsrValues[Index].RestoreFlag == FALSE) {
+#ifdef EFI_DEBUG
+ if (IsBsp ()) {
+ DEBUG ((DEBUG_INFO, "Skipping MSR : %x as RestoreFalg is set to FALSE \n", mMsrValues[Index].Index));
+ }
+#endif
+ continue;
+ }
+ //
+ // Check for Lock bits before programming
+ //
+ MsrValue = AsmReadMsr64 (mMsrValues[Index].Index);
+ if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) && (MsrValue & CONFIG_TDP_CONTROL_LOCK)) {
+ continue;
+ }
+
+ if ((mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) && (MsrValue & MSR_TURBO_ACTIVATION_RATIO_LOCK)) {
+ continue;
+ }
+
+ if ((mMsrValues[Index].Index == MSR_PACKAGE_POWER_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) {
+ continue;
+ }
+
+ if ((mMsrValues[Index].Index == MSR_PL3_CONTROL) && (MsrValue & B_POWER_LIMIT_LOCK)) {
+ continue;
+ }
+
+ if ((mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) {
+ continue;
+ }
+
+ MsrValue = AsmReadMsr64 (mMsrValues[Index].Index);
+ MsrValue &= ~mMsrValues[Index].BitMask;
+ MsrValue |= (mMsrValues[Index].Value & mMsrValues[Index].BitMask);
+ AsmWriteMsr64 (mMsrValues[Index].Index, MsrValue);
+ }
+
+ return;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c
new file mode 100644
index 0000000000..f27b0de904
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.c
@@ -0,0 +1,102 @@
+/** @file
+ This is the SMM driver for saving and restoring the powermanagement related MSRs.
+
+ Copyright (c) 2013 - 2016, 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.
+
+**/
+
+#include "PowerMgmtSmm.h"
+
+///
+/// Global variables
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_CONFIG *mCpuConfig;
+GLOBAL_REMOVE_IF_UNREFERENCED POWER_MGMT_CONFIG *mPowerMgmtConfig;
+
+/**
+ Initialize the SMM power management Handler.
+
+ @param[in] ImageHandle Pointer to the loaded image protocol for this driver
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS The driver installes/initialized correctly.
+ @retval EFI_NOT_FOUND CPU Data HOB not available.
+
+**/
+EFI_STATUS
+EFIAPI
+PowerMgmtSmmEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_HANDLE SwHandle;
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
+ VOID *Hob;
+ CPU_INIT_DATA_HOB *mCpuInitDataHob;
+
+ SwHandle = 0;
+ DEBUG ((DEBUG_INFO, " PpmSmmEntryPoint Started\n"));
+
+ //
+ // Get CPU Init Data Hob
+ //
+ Hob = GetFirstGuidHob (&gCpuInitDataHobGuid);
+ if (Hob == NULL) {
+ DEBUG ((DEBUG_ERROR, "CPU Data HOB not available\n"));
+ return EFI_NOT_FOUND;
+ }
+ mCpuInitDataHob = (CPU_INIT_DATA_HOB *) ((UINTN) Hob + sizeof (EFI_HOB_GUID_TYPE));
+ mCpuConfig = (CPU_CONFIG *) (UINTN) mCpuInitDataHob->CpuConfig;
+ mPowerMgmtConfig = (POWER_MGMT_CONFIG *) (UINTN)mCpuInitDataHob->PowerMgmtConfig;
+
+ //
+ // Locate the ICH SMM SW dispatch protocol
+ //
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmSwDispatch2ProtocolGuid,
+ NULL,
+ (VOID**) &SwDispatch
+ );
+
+ //
+ // Register ACPI S3 MSR restore handler
+ //
+ SwContext.SwSmiInputValue = mPowerMgmtConfig->S3RestoreMsrSwSmiNumber;
+
+ Status = SwDispatch->Register (
+ SwDispatch,
+ (EFI_SMM_HANDLER_ENTRY_POINT2) S3RestoreMsr,
+ &SwContext,
+ &SwHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Digital Thermal Sensor
+ //
+ if (mCpuConfig->EnableDts > 0) {
+ DEBUG ((DEBUG_INFO, " Install Digital Thermal Sensor \n"));
+ InstallDigitalThermalSensor ();
+ }
+
+ //
+ // Save MSRs for S3 Resume.
+ //
+ DEBUG ((DEBUG_INFO, " Saving Processor MSR for S3 Resume \n"));
+ S3SaveMsr ();
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h
new file mode 100644
index 0000000000..5261ad5a36
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.h
@@ -0,0 +1,117 @@
+/** @file
+ Header file for PowerMgmt Smm Driver.
+
+ Copyright (c) 2011 - 2016, 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_MGMT_SMM_H_
+#define _POWER_MGMT_SMM_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Library/HobLib.h>
+#include <Library/CpuPlatformLib.h>
+#include <Private/CpuInitDataHob.h>
+#include <Private/Library/CpuCommonLib.h>
+#include <CpuAccess.h>
+#include <ScAccess.h>
+#include <Private/PowerMgmtNvsStruct.h>
+
+#define PPM_WAIT_PERIOD 15
+
+extern POWER_MGMT_CONFIG *PowerMgmtConfig;
+
+typedef struct _EFI_MSR_VALUES {
+ UINT16 Index;
+ UINT64 Value;
+ UINT64 BitMask;
+ BOOLEAN RestoreFlag;
+} EFI_MSR_VALUES;
+
+/**
+ Save processor MSR runtime settings for S3.
+
+ @retval EFI_SUCCESS Processor MSR setting is saved.
+
+**/
+EFI_STATUS
+S3SaveMsr (
+ VOID
+ );
+
+/**
+ Runs the specified procedure on all logical processors, passing in the
+ parameter buffer to the procedure.
+
+ @param[in, out] Procedure The function to be run.
+ @param[in, out] Buffer Pointer to a parameter buffer.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+RunOnAllLogicalProcessors (
+ IN OUT EFI_AP_PROCEDURE Procedure,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ This function will restore MSR settings.
+
+ This function must be MP safe.
+
+ @param[in, out] Buffer Unused
+
+**/
+VOID
+EFIAPI
+ApSafeRestoreMsr (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Restore processor MSR runtime settings for S3.
+
+ @param[in] DispatchHandle The handle of this callback, obtained when registering
+ @param[in] DispatchContex Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
+
+**/
+VOID
+S3RestoreMsr (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext
+ );
+
+/**
+ Digital Thermal Sensor (DTS) SMM driver function.
+
+ @param[in] ImageHandle Image handle for this driver image
+
+ @retval EFI_SUCCESS Driver initialization completed successfully
+ @retval EFI_OUT_OF_RESOURCES Error when allocating required memory buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallDigitalThermalSensor (
+ VOID
+ );
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf
new file mode 100644
index 0000000000..a598e91df2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Smm/PowerMgmtSmm.inf
@@ -0,0 +1,63 @@
+## @file
+# Component description file for PowerManagementSmm driver.
+#
+# Copyright (c) 2011 - 2016, 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 = 0x00010017
+ BASE_NAME = PowerMgmtSmm
+ FILE_GUID = 8F0B5301-C79B-44f1-8FD3-26D73E316700
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 1.10
+ ENTRY_POINT = PowerMgmtSmmEntryPoint
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ HobLib
+ DebugLib
+ TimerLib
+ BaseMemoryLib
+ CpuPlatformLib
+ SmmServicesTableLib
+ AslUpdateLib
+ MmPciLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[Sources]
+ PowerMgmtSmm.h
+ PowerMgmtSmm.c
+ PowerMgmtS3.c
+ PowerMgmtDts.h
+ PowerMgmtDts.c
+ PowerMgmtDtsLib.h
+
+[Protocols]
+ gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gCpuGlobalNvsAreaProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiBxtTokenSpaceGuid.PcdScAcpiIoPortBaseAddress ## SOMETIMES_CONSUMES
+
+[Guids]
+ gCpuInitDataHobGuid ## UNDEFINED
+
+[Depex]
+ gEfiSmmControl2ProtocolGuid AND
+ gPowerMgmtInitDoneProtocolGuid