diff options
author | Guo Mang <mang.guo@intel.com> | 2016-12-23 10:49:27 +0800 |
---|---|---|
committer | Guo Mang <mang.guo@intel.com> | 2016-12-26 19:15:03 +0800 |
commit | fb0e8cef4ee3c2060181fb12fc8e3a2f8b78b22e (patch) | |
tree | 9dbe549421a36f4dc52d72c3813f45752b9f0d34 | |
parent | 423dd3b025d44e768da358390c06def185f22247 (diff) | |
download | edk2-platforms-fb0e8cef4ee3c2060181fb12fc8e3a2f8b78b22e.tar.xz |
BroxtonSiPkg: Add PowerManagement
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Guo Mang <mang.guo@intel.com>
13 files changed, 3526 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c new file mode 100644 index 0000000000..a0dc451a84 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/MiscFunctions.c @@ -0,0 +1,428 @@ +/** @file
+ This file contains Processor Power Management ACPI related functions for
+ processors.
+
+ <b>Acronyms:</b>
+ PPM: Processor Power Management
+ TM: Thermal Monitor
+ IST: Intel(R) Speedstep technology
+ HT: Hyper-Threading Technology
+
+ Copyright (c) 2012 - 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 "PowerMgmtCommon.h"
+
+/**
+ Update the SSDT table pointers and config DWORD CFGD with the PpmFlags current configuration value
+
+**/
+VOID
+PatchCpuSsdtTable (
+ VOID
+ )
+{
+ UINT8 *CurrPtr;
+ UINT32 *Signature;
+ SSDT_LAYOUT *SsdtPackage;
+
+ //
+ // Locate the SSDT package
+ //
+ SsdtPackage = NULL;
+ CurrPtr = (UINT8 *) mCpuSsdtTable;
+ for (CurrPtr = (UINT8 *) mCpuSsdtTable; CurrPtr <= ((UINT8 *) mCpuSsdtTable + mCpuSsdtTable->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;
+ DEBUG ((DEBUG_INFO, "\n Cpu0Ist :%x :%x \n",SsdtPackage->Cpu0IstAddr,SsdtPackage->Cpu0CstLen));
+ DEBUG ((DEBUG_INFO, "\n Cpu0Cst :%x :%x \n",SsdtPackage->Cpu0CstAddr,SsdtPackage->Cpu0CstLen));
+ }
+ //
+ // Update the CPU GlobalNvs area
+ //
+ if ((*CurrPtr == AML_EXT_REGION_OP) && *Signature == SIGNATURE_32 ('P', 'N', 'V', 'S')) {
+ ASSERT_EFI_ERROR (*(UINT32 *) (CurrPtr + 1 + sizeof (*Signature) + 2) == 0xFFFF0000);
+ ASSERT_EFI_ERROR (*(UINT16 *) (CurrPtr + 1 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) == 0xAA55);
+ //
+ // CPU Global NVS Area address
+ //
+ *(UINT32 *) (CurrPtr + 1 + sizeof (*Signature) + 2) = (UINT32) (UINTN) gCpuGlobalNvsAreaProtocol->Area;
+ //
+ // CPU Global NVS Area size
+ //
+ *(UINT16 *) (CurrPtr + 1 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) = sizeof (CPU_GLOBAL_NVS_AREA);
+ break;
+ }
+ }
+ //
+ // Assert if we didn't update the SSDT table
+ //
+ ASSERT (SsdtPackage != NULL);
+
+ return;
+}
+
+
+/**
+ Locate the PPM ACPI tables data file and read ACPI SSDT tables.
+ Publish the appropriate SSDT based on current configuration and capabilities.
+
+ @retval EFI_SUCCESS On success
+ @retval EFI_NOT_FOUND Required firmware volume not found
+ @retval EFI_OUT_OF_RESOURCES No enough resoruces (such as out of memory).
+ @retval Appropiate failure code on error
+
+**/
+EFI_STATUS
+InitCpuAcpiTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN i;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
+ INTN Instance;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ EFI_ACPI_DESCRIPTION_HEADER *TempTable;
+ UINTN AcpiTableHandle;
+
+ FwVol = NULL;
+
+ //
+ // Locate Firmware volume protocol.
+ // There is little chance we can't find an FV protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Look for FV with ACPI storage file
+ //
+ FwVol = NULL;
+ for (i = 0; i < NumberOfHandles; i++) {
+ //
+ // Get the protocol on this handle
+ // This should not fail because of LocateHandleBuffer
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[i],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // See if it has the ACPI storage file
+ //
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gCpuAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+ //
+ // If we found it, then we are done
+ //
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+ //
+ // Our exit status is determined by the success of the previous operations
+ // If the protocol was found, Instance already points to it.
+ // Free any allocated buffers
+ //
+ FreePool (HandleBuffer);
+ //
+ // Sanity check that we found our data file
+ //
+ ASSERT (FwVol != NULL);
+ if (FwVol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // By default, a table belongs in all ACPI table versions published.
+ //
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+ //
+ // Read tables from the storage file.
+ //
+ Instance = 0;
+ CurrentTable = NULL;
+ while (Status == EFI_SUCCESS) {
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gCpuAcpiTableStorageGuid,
+ 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 (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) {
+ //
+ // Patch the native _PSS package with the EIST values
+ //
+ Status = AcpiPatchPss ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ 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', 'S', 's', 'd', 't', 0)):
+ mCpuSsdtTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ break;
+ default:
+ break;
+ }
+ Instance++; // Increment the instance
+ CurrentTable = NULL;
+ }
+ }
+ //
+ // Copy CpuoIst SSDT if EIST is enabled
+ //
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_EIST) {
+ TempTable = AllocateReservedPool (mCpu0IstTable->Length);
+ if (TempTable == NULL) {
+ ASSERT (TempTable != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (TempTable, mCpu0IstTable, mCpu0IstTable->Length);
+ FreePool (mCpu0IstTable);
+ mCpu0IstTable = TempTable;
+ AcpiChecksum (mCpu0IstTable, mCpu0IstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpu0IstTable,
+ mCpu0IstTable->Length,
+ &AcpiTableHandle
+ );
+ }
+ //
+ // If we are CMP, then the PPM tables are dynamically loaded:
+ // We need to publish the CpuPm table to the ACPI tables, and move the CST
+ // tables that are dynamically loaded to a separate location so that we can fix the
+ // addresses in the CpuPm table.
+ // Otherwise (non-CMP):
+ // We need to publish CPU 0 tables only, and CST tables only if CST is enabled
+ //
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP) {
+ //
+ // Copy tables to our own location and checksum them
+ //
+ TempTable = AllocateReservedPool (mApIstTable->Length);
+ if (TempTable == NULL) {
+ ASSERT (TempTable != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (TempTable, mApIstTable, mApIstTable->Length);
+ FreePool (mApIstTable);
+ mApIstTable = TempTable;
+ AcpiChecksum (mApIstTable, mApIstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ TempTable = AllocateReservedPool (mCpu0CstTable->Length);
+ if (TempTable == NULL) {
+ ASSERT (TempTable != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (TempTable, mCpu0CstTable, mCpu0CstTable->Length);
+ FreePool (mCpu0CstTable);
+ mCpu0CstTable = TempTable;
+ AcpiChecksum (mCpu0CstTable, mCpu0CstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ TempTable = AllocateReservedPool (mApCstTable->Length);
+ if (TempTable == NULL) {
+ ASSERT (TempTable != NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (TempTable, mApCstTable, mApCstTable->Length);
+ FreePool (mApCstTable);
+ mApCstTable = TempTable;
+ AcpiChecksum (mApCstTable, mApCstTable->Length, EFI_FIELD_OFFSET (EFI_ACPI_DESCRIPTION_HEADER, Checksum));
+ } else {
+ //
+ // CMP disabled, so statically load the tables
+ //
+ // Add CST SSDT if C states are enabled
+ //
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpu0CstTable,
+ mCpu0CstTable->Length,
+ &AcpiTableHandle
+ );
+ }
+ //
+ // Since we are UP, there is no need for the CPU 1 tables
+ //
+ //
+ // Free all tables, since they have been copied into ACPI tables by ACPI support protocol
+ //
+ FreePool (mCpu0CstTable);
+ FreePool (mApIstTable);
+ FreePool (mApCstTable);
+ }
+ //
+ // Update the CpuSsdt SSDT table in the ACPI tables.
+ //
+ PatchCpuSsdtTable ();
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpuSsdtTable,
+ mCpuSsdtTable->Length,
+ &AcpiTableHandle
+ );
+ FreePool (mCpuSsdtTable);
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TSTATES) {
+ //
+ // Load the Cpu0Tst SSDT table in the ACPI tables
+ //
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mCpu0TstTable,
+ mCpu0TstTable->Length,
+ &AcpiTableHandle
+ );
+ FreePool (mCpu0TstTable);
+ //
+ // If the CMP is enabled then load the ApTst SSDT table in the ACPI tables
+ //
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_CMP) {
+ AcpiTableHandle = 0;
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ mApTstTable,
+ mApTstTable->Length,
+ &AcpiTableHandle
+ );
+ }
+ }
+ FreePool (mApTstTable);
+
+ return Status;
+}
+
+
+/**
+ Configure the FACP for C state support
+
+**/
+VOID
+ConfigureFadtCStates (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer;
+ 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
+ );
+ //
+ // 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;
+
+ //
+ // Configure C states
+ //
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C3) {
+ //
+ // Enable C3 in FADT.
+ //
+ FadtPointer->PLvl3Lat = FADT_C3_LATENCY;
+ }
+ //
+ // Update the table
+ //
+ Status = mAcpiTable->InstallAcpiTable (
+ mAcpiTable,
+ Table,
+ Table->Length,
+ &Handle
+ );
+ FreePool (Table);
+
+ return;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c new file mode 100644 index 0000000000..b4307ba872 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PerformanceStates.c @@ -0,0 +1,249 @@ +/** @file
+ This file contains P States and Turbo Power Management configuration functions for
+ processors.
+
+ <b>Acronyms:</b>
+ PPM: Processor Power Management
+ TM: Thermal Monitor
+ IST: Intel(R) Speedstep technology
+ HT: Hyper-Threading Technology
+
+ Copyright (c) 2012 - 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 "PowerMgmtCommon.h"
+#include <CpuDataStruct.h>
+
+extern UINT16 mCpuConfigTdpBootRatio;
+
+//
+// Update ACPI PerfomanceStates tables
+//
+
+/**
+ Patch the native _PSS package with the EIST values
+ Uses ratio/VID values from the FVID table to fix up the control values in the _PSS.
+
+ (1) Find _PSS package:
+ (1.1) Find the _PR_CPU0 scope.
+ (1.2) Save a pointer to the package length.
+ (1.3) Find the _PSS AML name object.
+ (2) Resize the _PSS package.
+ (3) Fix up the _PSS package entries
+ (3.1) Check Turbo mode support.
+ (3.2) Check Dynamic FSB support.
+ (4) Fix up the Processor block and \_PR_CPU0 Scope length.
+ (5) Update SSDT Header with new length.
+
+ @retval EFI_SUCCESS On success
+ @retval EFI_NOT_FOUND If _PR_.CPU0 scope is not foud in the ACPI tables
+
+**/
+EFI_STATUS
+AcpiPatchPss (
+ VOID
+ )
+{
+ UINT8 *CurrPtr;
+ UINT8 *EndOfTable;
+ UINT8 index;
+ UINT16 NewPackageLength;
+ UINT16 MaxPackageLength;
+ UINT16 Temp;
+ UINT16 *PackageLength;
+ UINT16 *ScopePackageLengthPtr;
+ UINT32 *Signature;
+ PSS_PACKAGE_LAYOUT *PssPackage;
+ MSR_REGISTER TempMsr;
+ UINT16 MinBusRatio;
+ UINT16 MaxNonTurboRatio;
+ UINT16 NumberOfStatesTurbo;
+ UINT16 Turbo;
+
+ ScopePackageLengthPtr = NULL;
+ PssPackage = NULL;
+
+ //
+ // Get Maximum Efficiency bus ratio (LFM) from Platform Info MSR Bits[47:40]
+ // Get Maximum Non Turbo bus ratio from Platform Info MSR Bits[15:8]
+ //
+ TempMsr.Qword = AsmReadMsr64 (MSR_PLATFORM_INFO);
+ MinBusRatio = TempMsr.Bytes.SixthByte;
+ MaxNonTurboRatio = TempMsr.Bytes.SecondByte;
+ mNumberOfStates = mFvidPointer[0].FvidHeader.EistStates;
+ NumberOfStatesTurbo = mNumberOfStates - (MaxNonTurboRatio - MinBusRatio + 1);
+ Turbo = ((gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) ? 1 : 0);
+
+ DEBUG ((EFI_D_INFO, "mNumberOfStates = %x\n", mNumberOfStates));
+ DEBUG ((EFI_D_INFO, "NumberOfStatesTurbo = %x\n", NumberOfStatesTurbo));
+
+ //
+ // Locate the SSDT package in the IST table
+ //
+ CurrPtr = (UINT8 *) mCpu0IstTable;
+ EndOfTable = (UINT8 *) (CurrPtr + mCpu0IstTable->Length);
+ for (CurrPtr = (UINT8 *) mCpu0IstTable; CurrPtr <= EndOfTable; CurrPtr++) {
+ Signature = (UINT32 *) (CurrPtr + 1);
+ //
+ // If we find the _PR_CPU0 scope, save a pointer to the package length
+ //
+ if ((*CurrPtr == AML_SCOPE_OP) &&
+ (*(Signature + 1) == SIGNATURE_32 ('_', 'P', 'R', '_')) &&
+ (*(Signature + 2) == SIGNATURE_32 ('C', 'P', 'U', '0'))
+ ) {
+ ScopePackageLengthPtr = (UINT16 *) (CurrPtr + 1);
+ }
+ //
+ // Patch the NPSS package for Windows usage
+ //
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == SIGNATURE_32 ('N', 'P', 'S', 'S'))) {
+ DEBUG ((EFI_D_INFO, "N P S S start here\n"));
+ ///
+ /// Calculate new package length
+ ///
+ NewPackageLength = Temp = (UINT16) ((Turbo + MaxNonTurboRatio - MinBusRatio + 1) * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ MaxPackageLength = (UINT16) (FVID_MAX_STATES * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ //
+ // Check table dimensions.
+ // PSS package reserve space for FVID_MAX_STATES number of P-states so check if the
+ // current number of P- states is more than FVID_MAX_STATES. Also need to update the SSDT contents
+ // if the current number of P-states is less than FVID_MAX_STATES.
+ //
+ ASSERT (mNumberOfStates <= FVID_MAX_STATES);
+ if (mNumberOfStates <= FVID_MAX_STATES) {
+ *(CurrPtr + 8) = (UINT8) (Turbo + MaxNonTurboRatio - MinBusRatio + 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 (index = 1; index <= (Turbo + MaxNonTurboRatio - MinBusRatio + 1); index++) {
+ //
+ // If Turbo mode is supported, add one to the Max Non-Turbo frequency
+ //
+ if ((gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) && (index == 1)) {
+ PssPackage->CoreFrequency = (UINT32) ((mFvidPointer[index + NumberOfStatesTurbo].FvidState.BusRatio)* 100) + 1;
+ PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power;
+ } else if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_TURBO) {
+ PssPackage->CoreFrequency = (UINT32) (mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.BusRatio) * 100;
+ PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.BusRatio, 8);
+ PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.BusRatio, 8);
+ PssPackage->Power = (UINT32) mFvidPointer[index + NumberOfStatesTurbo - 1].FvidState.Power;
+ } else {
+ PssPackage->CoreFrequency = (UINT32) (mFvidPointer[index].FvidState.BusRatio) * 100;
+ PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power;
+ }
+
+ PssPackage->TransLatency = NATIVE_PSTATE_LATENCY;
+ PssPackage->BMLatency = PSTATE_BM_LATENCY;
+
+ //
+ // Check Pss Package
+ //
+ DEBUG ((EFI_D_INFO, "PssPackage->CoreFrequency = %x\n", PssPackage->CoreFrequency));
+ DEBUG ((EFI_D_INFO, "PssPackage->Control = %x\n", PssPackage->Control));
+ DEBUG ((EFI_D_INFO, "PssPackage->Power = %x\n", PssPackage->Power));
+
+ PssPackage++;
+ }
+ }
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == SIGNATURE_32 ('S', 'P', 'S', 'S'))) {
+ DEBUG ((EFI_D_INFO, "S P S S start here\n"));
+ //
+ // Calculate new package length
+ //
+ NewPackageLength = Temp = (UINT16) (mNumberOfStates * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ MaxPackageLength = (UINT16) (FVID_MAX_STATES * sizeof (PSS_PACKAGE_LAYOUT) + 3);
+ //
+ // Check table dimensions.
+ // PSS package reserve space for FVID_MAX_STATES number of P-states so check if the
+ // current number of P- states is more than FVID_MAX_STATES. Also need to update the SSDT contents
+ // if the current number of P-states is less than FVID_MAX_STATES.
+ //
+ ASSERT (mNumberOfStates <= FVID_MAX_STATES);
+ if (mNumberOfStates <= FVID_MAX_STATES) {
+ *(CurrPtr + 8) = (UINT8) mNumberOfStates;
+ PackageLength = (UINT16 *) (CurrPtr + 6);
+ //
+ // Update the Package length in AML package length format
+ //
+ *PackageLength = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00);
+ //
+ // Move SSDT contents
+ //
+ CopyMem (
+ (CurrPtr + NewPackageLength),
+ (CurrPtr + MaxPackageLength),
+ EndOfTable - (CurrPtr + MaxPackageLength)
+ );
+ //
+ // Save the new end of the SSDT
+ //
+ EndOfTable = EndOfTable - (MaxPackageLength - NewPackageLength);
+ }
+ PssPackage = (PSS_PACKAGE_LAYOUT *) (CurrPtr + 9);
+ for (index = 1; index <= mNumberOfStates; index++) {
+ //
+ // If Turbo mode is supported, expose all entries
+ //
+ PssPackage->CoreFrequency = (UINT32)((mFvidPointer[index].FvidState.BusRatio)* 100);
+ PssPackage->Control = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ PssPackage->Status = (UINT32) LShiftU64 (mFvidPointer[index].FvidState.BusRatio, 8);
+ PssPackage->Power = (UINT32) mFvidPointer[index].FvidState.Power;
+ PssPackage->TransLatency = NATIVE_PSTATE_LATENCY;
+ PssPackage->BMLatency = PSTATE_BM_LATENCY;
+
+ //
+ // Check Pss Package
+ //
+ DEBUG ((EFI_D_INFO, "PssPackage->CoreFrequency = %x\n", PssPackage->CoreFrequency));
+ DEBUG ((EFI_D_INFO, "PssPackage->Control = %x\n", PssPackage->Control));
+ DEBUG ((EFI_D_INFO, "PssPackage->Power = %x\n", PssPackage->Power));
+
+ PssPackage++;
+ }
+ }
+ }
+ ASSERT (ScopePackageLengthPtr != NULL);
+ if (ScopePackageLengthPtr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Update the Package length in AML package length format
+ //
+ CurrPtr = (UINT8 *) ScopePackageLengthPtr;
+ NewPackageLength = Temp = (UINT16) (EndOfTable - CurrPtr);
+ *ScopePackageLengthPtr = ((NewPackageLength & 0x0F) | 0x40) | ((Temp << 4) & 0x0FF00);
+ mCpu0IstTable->Length = (UINT32) (EndOfTable - (UINT8 *) mCpu0IstTable);
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h new file mode 100644 index 0000000000..8ff281ff48 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtCommon.h @@ -0,0 +1,263 @@ +/** @file
+ This header file contains the processor power management definitions.
+
+ Acronyms:
+ PPM Processor Power Management
+ TM Thermal Monitor
+ IST Intel(R) Speedstep technology
+ HT Hyper-Threading Technology
+
+ Copyright (c) 2012 - 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_COMMON_H_
+#define _POWER_MGMT_COMMON_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PciLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/MpService.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <ScAccess.h>
+#include <SaAccess.h>
+#include <CpuAccess.h>
+#include <Protocol/CpuGlobalNvsArea.h>
+#include <Private/Protocol/PowerMgmtInitDone.h>
+#include <Library/CpuPlatformLib.h>
+#include <Private/PowerMgmtNvsStruct.h>
+#include <Library/AslUpdateLib.h>
+#include <Library/MmPciLib.h>
+#include <Private/CpuInitDataHob.h>
+#include <Library/TimerLib.h>
+
+#define PM_CST_LVL2 0x14
+
+#define FADT_C3_LATENCY 57
+#define FADT_C3_LATENCY_DISABLED 1001
+
+#define NATIVE_PSTATE_LATENCY 10
+#define PSTATE_BM_LATENCY 10
+#define MP_TIMEOUT_FOR_STARTUP_ALL_APS 0 ///< Set 0 for BSP always wait for APs
+
+///
+/// Limit the number of P-states to 16. Up to Windows 7, the OS allocates 1KB buffer for the PSS package.
+/// So the maximum number of P-state OS can handle is 19. This is not an OS issue. Having too many P-states
+/// is not good for the system performance.
+///
+#define FVID_MAX_STATES 20
+#define FVID_MIN_STEP_SIZE 1
+
+///
+/// Cpu Brandstring length
+///
+#define MAXIMUM_CPU_BRAND_STRING_LENGTH 48
+#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field)))
+#define EFI_IDIV_ROUND(r, s) ((r) / (s) + (((2 * ((r) % (s))) < (s)) ? 0 : 1))
+
+///
+/// Global variables
+///
+extern EFI_GUID gCpuAcpiTableStorageGuid;
+
+///
+/// SiCpuPolicy Revision
+///
+extern UINT8 mCpuPolicyRevision;
+
+extern POWER_MGMT_CONFIG *mPowerMgmtConfig; ///< Power Managment policy configurations
+extern EFI_CPUID_REGISTER mCpuid01; // CPUID 01 values
+///
+/// Values for FVID table calculate.
+///
+extern UINT16 mTurboBusRatio;
+extern UINT16 mMaxBusRatio;
+extern UINT16 mMinBusRatio;
+extern UINT16 mProcessorFlavor;
+extern UINT16 mBspBootRatio;
+extern UINT16 mPackageTdp;
+extern UINT16 mPackageTdpWatt;
+extern UINT16 mCpuConfigTdpBootRatio;
+extern UINT16 mCustomPowerUnit;
+extern UINT16 mCpuCacheSize;
+///
+/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit)
+///
+extern UINT8 mProcessorPowerUnit;
+///
+/// Fractional part of Processor Time Unit in seconds. (i.e Unit is 1/mProcessorTimeUnit)
+///
+extern UINT8 mProcessorTimeUnit;
+///
+/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+extern UINT16 mPackageMaxPower;
+///
+/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+extern UINT16 mPackageMinPower;
+extern UINT8 mControllableTdpEnable; ///< Controllable TDP Enable/Disable
+extern UINT8 mRatioLimitProgrammble; ///< Programmable Ratio Limit
+extern UINT8 mTdpLimitProgrammble; ///< Programmable TDP Limit
+extern CPU_GLOBAL_NVS_AREA_PROTOCOL *gCpuGlobalNvsAreaProtocol; ///< CPU GlobalNvs Protocol
+extern EFI_MP_SERVICES_PROTOCOL *mMpService; ///< EFI MP SERVICES PROTOCOL
+
+///
+/// Globals to support updating ACPI Tables
+///
+extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApIstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApCstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpuSsdtTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApTstTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCtdpTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mCpu0HwpTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mApHwpTable;
+extern EFI_ACPI_DESCRIPTION_HEADER *mHwpLvtTable;
+
+///
+/// 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
+ UINT8 StringPrefix5; ///< 0Dh
+ UINT64 Cpu0HwpStr; ///< 00h
+ UINT8 StringNull5; ///< 00h
+ UINT8 DwordPrefix5a; ///< 0Ch
+ UINT32 Cpu0HwpAddr; ///< 00h
+ UINT8 DwordPrefix5b; ///< 0Ch
+ UINT32 Cpu0HwpLen; ///< 00h
+ UINT8 StringPrefix6; ///< 0Dh
+ UINT64 ApHwpStr; ///< 00h
+ UINT8 StringNull6; ///< 00h
+ UINT8 DwordPrefix6a; ///< 0Ch
+ UINT32 ApHwpAddr; ///< 00h
+ UINT8 DwordPrefix6b; ///< 0Ch
+ UINT32 ApHwpLen; ///< 00h
+ UINT8 StringPrefix7; ///< 0Dh
+ UINT64 HwpLvtStr; ///< 00h
+ UINT8 StringNull7; ///< 00h
+ UINT8 DwordPrefix7a; ///< 0Ch
+ UINT32 HwpLvtAddr; ///< 00h
+ UINT8 DwordPrefix7b; ///< 0Ch
+ UINT32 HwpLvtLen; ///< 00h
+} SSDT_LAYOUT;
+#pragma pack()
+
+//
+// FVID Table Information
+// Default FVID table
+// One header field plus states
+//
+extern UINT16 mNumberOfStates;
+extern FVID_TABLE *mFvidPointer;
+
+//
+// Function prototypes
+//
+
+/**
+ Patch the native _PSS package with the EIST values
+ Uses ratio/VID values from the FVID table to fix up the control values in the _PSS.
+
+ (1) Find _PSS package:
+ (1.1) Find the _PR_CPU0 scope.
+ (1.2) Save a pointer to the package length.
+ (1.3) Find the _PSS AML name object.
+ (2) Resize the _PSS package.
+ (3) Fix up the _PSS package entries
+ (3.1) Check Turbo mode support.
+ (3.2) Check Dynamic FSB support.
+ (4) Fix up the Processor block and \_PR_CPU0 Scope length.
+ (5) Update SSDT Header with new length.
+
+ @retval EFI_SUCCESS On success
+ @retval EFI_NOT_FOUND If _PR_.CPU0 scope is not foud in the ACPI tables
+
+**/
+EFI_STATUS
+AcpiPatchPss (
+ VOID
+ );
+
+/**
+ Configure the FACP for C state support
+
+**/
+VOID
+ConfigureFadtCStates (
+ VOID
+ );
+
+/**
+ Locate the CPU ACPI tables data file and read ACPI SSDT tables.
+ Publish the appropriate SSDT based on current configuration and capabilities.
+
+ @retval EFI_SUCCESS - On success
+ @retval EFI_NOT_FOUND - Required firmware volume not found
+ @retval EFI_OUT_OF_RESOURCES - No enough resoruces (such as out of memory).
+ @retval Appropiate failure code on error
+
+**/
+EFI_STATUS
+InitCpuAcpiTable (
+ VOID
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf new file mode 100644 index 0000000000..470a0b1b4d --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtDxe.inf @@ -0,0 +1,67 @@ +## @file
+# Power Management module.
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = PowerMgmtDxe
+ FILE_GUID = f7731b4c-58a2-4df4-8980-5645d39ece58
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ ENTRY_POINT = InitPowerManagement
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ IoLib
+ PciLib
+ HobLib
+ AslUpdateLib
+ PcdLib
+ S3BootScriptLib
+ CpuPlatformLib
+ MmPciLib
+ TimerLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[Pcd]
+
+[Sources]
+ PowerMgmtInit.h
+ PowerMgmtInit.c
+ PowerMgmtCommon.h
+ PerformanceStates.c
+ MiscFunctions.c
+
+[Protocols]
+ gPowerMgmtInitDoneProtocolGuid ## PRODUCES
+ gEfiMpServiceProtocolGuid ## CONSUMES
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+ gCpuGlobalNvsAreaProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gCpuInfoProtocolGuid ## CONSUMES
+
+[Guids]
+ gCpuAcpiTableStorageGuid ## UNDEFINED
+ gCpuInitDataHobGuid ## UNDEFINED
+
+[Depex]
+ gEfiAcpiTableProtocolGuid AND
+ gEfiMpServiceProtocolGuid AND
+ gCpuGlobalNvsAreaProtocolGuid AND
+ gEfiGlobalNvsAreaProtocolGuid
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c new file mode 100644 index 0000000000..71392c9de6 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.c @@ -0,0 +1,273 @@ +/** @file
+ Processor Power Management initialization code. This code determines current
+ user configuration and modifies and loads ASL as well as initializing chipset
+ and processor features to enable the proper power management.
+
+ Acronyms:
+ PPM: Processor Power Management
+ TM: Thermal Monitor
+ IST: Intel(R) Speedstep technology
+ HT: Hyper-Threading Technology
+
+ Copyright (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 "PowerMgmtInit.h"
+#include "PowerMgmtCommon.h"
+#include <Library/MmPciLib.h>
+#include <Protocol/CpuInfo.h>
+
+///
+/// Global variables
+///
+
+///
+/// Power Managment policy configurations
+///
+GLOBAL_REMOVE_IF_UNREFERENCED POWER_MGMT_CONFIG *mPowerMgmtConfig = NULL;
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_CPUID_REGISTER mCpuid01 = { 0, 0, 0, 0 }; // CPUID 01 values
+
+///
+/// Values for FVID table calculate.
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTurboBusRatio = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMaxBusRatio = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMinBusRatio = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mProcessorFlavor = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mBspBootRatio = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageTdp = 0; ///< Processor TDP value in MSR_PACKAGE_POWER_SKU.
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageTdpWatt = 0; ///< Processor TDP value in Watts.
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mCpuConfigTdpBootRatio = 0; ///< Config TDP Boot settings
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mCustomPowerUnit = 1;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mCpuCacheSize = 0; ///< Cache Size in KB
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mCpuPolicyRevision = 0;
+
+///
+/// Fractional part of Processor Power Unit in Watts. (i.e. Unit is 1/mProcessorPowerUnit)
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mProcessorPowerUnit = 0;
+
+///
+/// Maximum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageMaxPower = 0;
+
+///
+/// Minimum allowed power limit value in TURBO_POWER_LIMIT_MSR and PRIMARY_PLANE_POWER_LIMIT_MSR
+/// in units specified by PACKAGE_POWER_SKU_UNIT_MSR
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPackageMinPower = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mControllableTdpEnable = 0; ///< Controllable TDP enable/Disable
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mRatioLimitProgrammble = 0; ///< Programmable Ratio Limit
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTdpLimitProgrammble = 0; ///< Porgrammable TDP Limit
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_GLOBAL_NVS_AREA_PROTOCOL *gCpuGlobalNvsAreaProtocol = NULL; ///< CPU GlobalNvs Protocol
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_MP_SERVICES_PROTOCOL *mMpService = NULL;
+
+///
+/// FVID Table Information
+/// Default FVID table
+/// One header field plus states
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mNumberOfStates = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED FVID_TABLE *mFvidPointer = NULL;
+
+///
+/// Globals to support updating ACPI Tables
+///
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_TABLE_PROTOCOL *mAcpiTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0IstTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApIstTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0CstTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApCstTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpuSsdtTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mCpu0TstTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_DESCRIPTION_HEADER *mApTstTable = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_INIT_DATA_HOB *mCpuInitDataHob = NULL;
+
+/**
+ Initialize the power management support.
+ This function will do boot time configuration:
+ Detect HW capabilities and SW configuration
+ Initialize HW and software state (primarily MSR and ACPI tables)
+
+ @param[in] ImageHandle Pointer to the loaded image protocol for this driver
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS The driver installes/initialized correctly.
+ @retval Driver will ASSERT in debug builds on error.
+ PPM functionality is considered critical for mobile systems.
+
+**/
+EFI_STATUS
+EFIAPI
+InitPowerManagement (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ VOID *Hob;
+
+ 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));
+
+ //
+ // Initialize the Global pointer for Power Managment Policy
+ //
+ mPowerMgmtConfig = (POWER_MGMT_CONFIG *) (UINTN) mCpuInitDataHob->PowerMgmtConfig;
+ mFvidPointer = (FVID_TABLE *) (UINTN) mCpuInitDataHob->FvidTable;
+
+ //
+ // Initialize Power management Global variables
+ //
+ InitPowerManagementGlobalVariables ();
+
+ //
+ // Initialize CPU Power management code (Patch and install CPU ACPI tables, save S3 boot script info)
+ //
+ Status = InitPpmDxe ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the PowerMgmtInitDone Protocol so that PowerMgmtS3 driver can load to save the MSRs for S3 resume
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gPowerMgmtInitDoneProtocolGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initializes the platform power management global variable.
+ This must be called prior to any of the functions being used.
+
+**/
+VOID
+InitPowerManagementGlobalVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate CPU GlobalNvs Protocol.
+ //
+ Status = gBS->LocateProtocol (
+ &gCpuGlobalNvsAreaProtocolGuid,
+ NULL,
+ (VOID **) &gCpuGlobalNvsAreaProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CPU GloableNvs protocol not found"));
+ }
+ ASSERT_EFI_ERROR (Status);
+ if (gCpuGlobalNvsAreaProtocol != NULL) {
+ gCpuGlobalNvsAreaProtocol->Area->Cpuid = GetCpuFamily () | GetCpuStepping ();
+ }
+
+ //
+ // Locate MP service protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **) &mMpService
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate ACPI table protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable);
+ ASSERT_EFI_ERROR (Status);
+
+ return;
+}
+
+
+/**
+ Initialize the processor power management based on hardware capabilities
+ and user configuration settings.
+
+ @retval EFI_SUCCESS On success
+ @retval Appropiate failure code on error
+
+**/
+EFI_STATUS
+InitPpmDxe (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+#if (ENBDT_PF_ENABLE == 1)
+ UINT8 Data8;
+#endif
+ UINTN MaximumNumberOfCpus;
+ UINTN NumberOfEnabledCpus;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Update Fadt table for C State support.
+ //
+ if (gCpuGlobalNvsAreaProtocol->Area->PpmFlags & PPM_C_STATES) {
+ ConfigureFadtCStates ();
+ }
+
+ Status = InitCpuAcpiTable ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Update Logical Processor Count
+ //
+ mMpService->GetNumberOfProcessors (
+ mMpService,
+ &MaximumNumberOfCpus,
+ &NumberOfEnabledCpus
+ );
+ gCpuGlobalNvsAreaProtocol->Area->LogicalProcessorCount = (UINT8) MaximumNumberOfCpus;
+
+ //
+ // Save the SW SMI number to trigger SMI to restore the MSRs when resuming from S3
+ //
+#if (ENBDT_PF_ENABLE == 1)
+ Data8 = mPowerMgmtConfig->S3RestoreMsrSwSmiNumber;
+ S3BootScriptSaveIoWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (R_PCH_APM_CNT),
+ 1,
+ &Data8
+ );
+#endif
+
+ return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h new file mode 100644 index 0000000000..3062c92a31 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/PowerManagement/Dxe/PowerMgmtInit.h @@ -0,0 +1,75 @@ +/** @file
+ This header file contains processors power management definitions.
+
+ 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_MANAGEMENT_H_
+#define _POWER_MANAGEMENT_H_
+
+#include "PowerMgmtCommon.h"
+
+//
+// Function prototypes
+//
+/**
+ Initialize the power management support.
+ This function will do boot time configuration:
+ Install into SMRAM/SMM
+ Detect HW capabilities and SW configuration
+ Initialize HW and software state (primarily MSR and ACPI tables)
+ Install SMI handlers for runtime interfacess
+
+ @param[in] ImageHandle Pointer to the loaded image protocol for this driver
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS The driver installed/initialized correctly.
+ @retval Driver will ASSERT in debug builds on error. PPM functionality is considered critical for mobile systems.
+
+**/
+EFI_STATUS
+EFIAPI
+InitPowerManagement (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Initializes the CPU power management global variable.
+ This must be called prior to any of the functions being used.
+
+**/
+VOID
+InitPowerManagementGlobalVariables (
+ VOID
+ );
+
+/**
+ Initialize the platform power management based on hardware capabilities
+ and user configuration settings.
+
+ This includes creating FVID table, updating ACPI tables,
+ and updating processor and chipset hardware configuration.
+
+ This should be called prior to any Px, Cx, Tx activity.
+
+ @retval EFI_SUCCESS On success
+ @retval Appropiate failure code on error
+
+**/
+EFI_STATUS
+InitPpmDxe (
+ VOID
+ );
+#endif
+
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
|