[edk2-devel] [edk2-platforms] [PATCH V1 05/18] PurleyRefreshSiliconPkg/Pch: Add libraries

Nate DeSimone nathaniel.l.desimone at intel.com
Tue May 11 09:48:13 UTC 2021


Cc: Chasel Chiu <chasel.chiu at intel.com>
Cc: Mike Kinney <michael.d.kinney at intel.com>
Cc: Isaac Oram <isaac.w.oram at intel.com>
Cc: Mohamed Abbas <mohamed.abbas at intel.com>
Cc: Michael Kubacki <michael.kubacki at microsoft.com>
Cc: Zachary Bobroff <zacharyb at ami.com>
Cc: Harikrishna Doppalapudi <harikrishnad at ami.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone at intel.com>
---
 .../DxeRuntimeResetSystemLib.inf              |   63 +
 .../DxeRuntimeResetSystemLib/PchReset.c       |  633 ++++
 .../DxeRuntimeResetSystemLib/PchReset.h       |  105 +
 .../Pch/Library/PeiDxeSmmGpioLib/GpioInit.c   |  403 +++
 .../Pch/Library/PeiDxeSmmGpioLib/GpioLib.c    | 2738 +++++++++++++++++
 .../Library/PeiDxeSmmGpioLib/GpioLibrary.h    |  216 ++
 .../Library/PeiDxeSmmGpioLib/GpioNativeLib.c  |  448 +++
 .../Library/PeiDxeSmmGpioLib/PchSklGpioData.c |   59 +
 .../PeiDxeSmmGpioLib/PeiDxeSmmGpioLib.inf     |   48 +
 .../PchCycleDecodingLib.c                     | 1169 +++++++
 .../PeiDxeSmmPchCycleDecodingLib.inf          |   33 +
 .../Library/PeiDxeSmmPchGbeLib/PchGbeLib.c    |  160 +
 .../PeiDxeSmmPchGbeLib/PeiDxeSmmPchGbeLib.inf |   37 +
 .../Library/PeiDxeSmmPchInfoLib/PchInfoLib.c  |  505 +++
 .../PeiDxeSmmPchInfoLib/PchInfoStrLib.c       |  291 ++
 .../PeiDxeSmmPchInfoLib.inf                   |   32 +
 .../Library/PeiDxeSmmPchP2sbLib/PchP2sbLib.c  |  331 ++
 .../PeiDxeSmmPchP2sbLib.inf                   |   30 +
 .../Library/PeiDxeSmmPchPcrLib/PchPcrLib.c    |  453 +++
 .../PeiDxeSmmPchPcrLib/PeiDxeSmmPchPcrLib.inf |   31 +
 .../Library/PeiDxeSmmPchPmcLib/PchPmcLib.c    |  153 +
 .../PeiDxeSmmPchPmcLib/PeiDxeSmmPchPmcLib.inf |   31 +
 .../PchSbiAccessLib.c                         |  370 +++
 .../PeiDxeSmmPchSbiAccessLib.inf              |   31 +
 .../Library/PeiPchPolicyLib/PchPrintPolicy.c  |  730 +++++
 .../Library/PeiPchPolicyLib/PeiPchPolicyLib.c |  581 ++++
 .../PeiPchPolicyLib/PeiPchPolicyLib.inf       |   48 +
 .../PeiPchPolicyLib/PeiPchPolicyLibrary.h     |   25 +
 .../Library/PeiPchPolicyLib/Rvp3PolicyLib.c   |  205 ++
 .../SmmSpiFlashCommonLib.inf                  |   50 +
 .../SmmSpiFlashCommonLib/SpiFlashCommon.c     |  192 ++
 .../SpiFlashCommonSmmLib.c                    |   53 +
 .../BasePchResetCommonLib.inf                 |   27 +
 .../BasePchResetCommonLib/PchResetCommon.c    |  168 +
 34 files changed, 10449 insertions(+)
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/DxeRuntimeResetSystemLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.h
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioInit.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioNativeLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PchSklGpioData.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PeiDxeSmmGpioLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PchGbeLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PeiDxeSmmPchGbeLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoStrLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PeiDxeSmmPchInfoLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PchP2sbLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PeiDxeSmmPchP2sbLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PchPcrLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PeiDxeSmmPchPcrLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PchPmcLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PeiDxeSmmPchPmcLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PchSbiAccessLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PeiDxeSmmPchSbiAccessLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PchPrintPolicy.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLibrary.h
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/Rvp3PolicyLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/BasePchResetCommonLib.inf
 create mode 100644 Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/PchResetCommon.c

diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/DxeRuntimeResetSystemLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/DxeRuntimeResetSystemLib.inf
new file mode 100644
index 0000000000..01ca2c9e96
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/DxeRuntimeResetSystemLib.inf
@@ -0,0 +1,63 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = DxeRuntimeResetSystemLib
+  FILE_GUID                      = 5602DBE0-2576-44CB-95FF-53D5A18C775F
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  LIBRARY_CLASS                  = ResetSystemLib
+  CONSTRUCTOR                    = InstallPchReset
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[LibraryClasses]
+  IoLib
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  UefiRuntimeLib
+  PchCycleDecodingLib
+  DxeServicesTableLib
+  PchResetCommonLib
+  HobLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Sources]
+  PchReset.c
+  PchReset.h
+
+
+[Protocols]
+  gPchResetCallbackProtocolGuid          ## CONSUMES
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
+  gEfiCapsuleVendorGuid
+  gPchPowerCycleResetGuid
+  gPchGlobalResetGuid
+  gPchGlobalResetWithEcGuid
+  gPchPolicyHobGuid
+
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid   AND # SERVER_BIOS_FLAG
+  TRUE
\ No newline at end of file
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.c
new file mode 100644
index 0000000000..f34f98bcf0
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.c
@@ -0,0 +1,633 @@
+/** @file
+
+Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PchReset.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_RESET_INSTANCE  *mPchResetInstance;
+STATIC UINT8 mDaysOfMonthInfo[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_RESET_DATA mPchPowerCycleReset = {
+  PCH_PLATFORM_SPECIFIC_RESET_STRING,
+  PCH_POWER_CYCLE_RESET_GUID
+};
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_RESET_DATA mPchGlobalReset = {
+  PCH_PLATFORM_SPECIFIC_RESET_STRING,
+  PCH_GLOBAL_RESET_GUID
+};
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_RESET_DATA mPchGlobalResetWithEc = {
+  PCH_PLATFORM_SPECIFIC_RESET_STRING,
+  PCH_GLOBAL_RESET_WITH_EC_GUID
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mCapsuleResetType = 0;
+
+/**
+  Check if it is leap year
+
+  @param[in] Year            year to be check
+
+  @retval True               year is leap year
+  @retval FALSE              year is not a leap year
+**/
+BOOLEAN
+IsLeapYear (
+  IN UINT16 Year
+  )
+{
+  return (Year % 4 == 0) && ((Year % 100 != 0) || (Year % 400 == 0));
+}
+
+/**
+  Set System Wakeup Alarm.
+
+  @param[in] WakeAfter       Time offset in seconds to wake from S3
+
+  @retval EFI_SUCCESS        Timer started successfully
+**/
+STATIC
+EFI_STATUS
+SetSystemWakeupAlarm (
+  IN       UINT32          WakeAfter
+  )
+{
+  EFI_STATUS              Status;
+  EFI_TIME                Time;
+  EFI_TIME_CAPABILITIES   Capabilities;
+  UINT32                  Reminder;
+  UINT16                  ABase;
+  UINT8                   DayOfMonth;
+
+  ///
+  /// For an instant wake 2 seconds is a safe value
+  ///
+  if (WakeAfter < 2) {
+    WakeAfter = 2;
+  }
+
+  Status = EfiGetTime (&Time, &Capabilities);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Reminder = WakeAfter + (UINT32) Time.Second;
+  Time.Second = Reminder % 60;
+  Reminder = Reminder / 60;
+  Reminder = Reminder + (UINT32) Time.Minute;
+  Time.Minute = Reminder % 60;
+  Reminder = Reminder / 60;
+  Reminder = Reminder + (UINT32) Time.Hour;
+  Time.Hour = Reminder % 24;
+  Reminder = Reminder / 24;
+
+  if (Reminder > 0) {
+    Reminder = Reminder + (UINT32) Time.Day;
+    if ((Time.Month == 2) && IsLeapYear (Time.Year)) {
+      DayOfMonth = 29;
+    } else {
+      DayOfMonth = mDaysOfMonthInfo[Time.Month - 1];
+    }
+    if (Reminder > DayOfMonth) {
+      Time.Day = (UINT8)Reminder - DayOfMonth;
+      Reminder = 1;
+    } else {
+      Time.Day = (UINT8)Reminder;
+      Reminder = 0;
+    }
+  }
+  if (Reminder > 0) {
+    if (Time.Month == 12) {
+      Time.Month = 1;
+      Time.Year = Time.Year + 1;
+    } else {
+      Time.Month = Time.Month + 1;
+    }
+  }
+
+  Status = EfiSetWakeupTime (TRUE, &Time);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ABase = mPchResetInstance->PchAcpiBase;
+
+
+  ///
+  /// Clear RTC PM1 status
+  ///
+  IoWrite16 (ABase + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
+
+  ///
+  /// set RTC_EN bit in PM1_EN to wake up from the alarm
+  ///
+  IoWrite16 (
+    ABase + R_PCH_ACPI_PM1_EN,
+    (IoRead16 (ABase + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC)
+    );
+  return Status;
+}
+
+/**
+  Retrieve PCH platform specific ResetData
+
+  @param[in]  Guid      PCH platform specific reset GUID.
+  @param[out] DataSize  The size of ResetData in bytes.
+
+  @retval ResetData     A platform specific reset that the exact type of
+                        the reset is defined by the EFI_GUID that follows
+                        the Null-terminated Unicode string.
+  @retval NULL          If Guid is not defined in PCH platform specific reset.
+**/
+VOID *
+EFIAPI
+GetResetData (
+  IN   EFI_GUID *Guid,
+  OUT  UINTN    *DataSize
+  )
+{
+  *DataSize = 0;
+  if (CompareGuid (Guid, &gPchPowerCycleResetGuid)) {
+    *DataSize = sizeof (mPchPowerCycleReset);
+    return (VOID *)&mPchPowerCycleReset;
+  } else if (CompareGuid (Guid, &gPchGlobalResetGuid)) {
+    *DataSize = sizeof (mPchGlobalReset);
+    return (VOID *)&mPchGlobalReset;
+  } else if (CompareGuid (Guid, &gPchGlobalResetWithEcGuid)) {
+    *DataSize = sizeof (mPchGlobalResetWithEc);
+    return (VOID *)&mPchGlobalResetWithEc;
+  }
+
+   return NULL;
+}
+
+/**
+  Execute Pch Reset from the host controller.
+
+  @param[in] This                 Pointer to the PCH_RESET_PROTOCOL instance.
+  @param[in] ResetType            UEFI defined reset type.
+  @param[in] DataSize             The size of ResetData in bytes.
+  @param[in] ResetData            Optional element used to introduce a platform specific reset.
+                                  The exact type of the reset is defined by the EFI_GUID that follows
+                                  the Null-terminated Unicode string.
+
+  @retval EFI_SUCCESS             Successfully completed.
+  @retval EFI_INVALID_PARAMETER   If ResetType is invalid.
+**/
+EFI_STATUS
+EFIAPI
+Reset (
+  IN PCH_RESET_PROTOCOL *This,
+  IN EFI_RESET_TYPE     ResetType,
+  IN UINTN              DataSize,
+  IN VOID               *ResetData OPTIONAL
+  )
+{
+  PCH_RESET_INSTANCE  *PchResetInstance;
+  EFI_STATUS          Status;
+  PCH_RESET_TYPE      PchResetType;
+
+  PchResetInstance = PCH_RESET_INSTANCE_FROM_THIS (This);
+  PchResetType     = (PCH_RESET_TYPE)ResetType;
+
+  Status = PchReset (PchResetInstance, PchResetType);
+
+  return Status;
+}
+
+/**
+  Calling this function causes a system-wide reset. This sets
+  all circuitry within the system to its initial state. This type of reset
+  is asynchronous to system operation and operates without regard to
+  cycle boundaries.
+
+  System reset should not return, if it returns, it means the system does
+  not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+  VOID
+  )
+{
+  PchReset (mPchResetInstance, (PCH_RESET_TYPE) EfiResetCold);
+}
+
+/**
+  Calling this function causes a system-wide initialization. The processors
+  are set to their initial state, and pending cycles are not corrupted.
+
+  System reset should not return, if it returns, it means the system does
+  not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+  VOID
+  )
+{
+  PchReset (mPchResetInstance, (PCH_RESET_TYPE) EfiResetWarm);
+}
+
+/**
+  Calling this function causes the system to enter a power state equivalent
+  to the ACPI G2/S5 or G3 states.
+
+  System shutdown should not return, if it returns, it means the system does
+  not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+  VOID
+  )
+{
+  PchReset (mPchResetInstance, (PCH_RESET_TYPE) EfiResetShutdown);
+}
+
+/**
+  Calling this function causes the system to enter a power state for platform specific.
+
+  @param[in] DataSize             The size of ResetData in bytes.
+  @param[in] ResetData            Optional element used to introduce a platform specific reset.
+                                  The exact type of the reset is defined by the EFI_GUID that follows
+                                  the Null-terminated Unicode string.
+
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+  IN UINTN            DataSize,
+  IN VOID             *ResetData OPTIONAL
+  )
+{
+  EFI_GUID            *GuidPtr;
+
+  if (ResetData == NULL) {
+    if (!EfiAtRuntime ()) {
+      DEBUG ((DEBUG_ERROR, "[DxeRuntimeResetSystemLib] ResetData is not available.\n"));
+    }
+    return;
+  }
+  GuidPtr = (EFI_GUID *) ((UINT8 *) ResetData + DataSize - sizeof (EFI_GUID));
+  if (CompareGuid (GuidPtr, &gPchPowerCycleResetGuid)) {
+    PchReset (mPchResetInstance, (PCH_RESET_TYPE) PowerCycleReset);
+  } else if (CompareGuid (GuidPtr, &gPchGlobalResetGuid)) {
+    PchReset (mPchResetInstance, (PCH_RESET_TYPE) GlobalReset);
+  } else if (CompareGuid (GuidPtr, &gPchGlobalResetWithEcGuid)) {
+    PchReset (mPchResetInstance, (PCH_RESET_TYPE) GlobalResetWithEc);
+  } else {
+    return;
+  }
+}
+
+/**
+  Calling this function causes the system to enter a power state for capsule update.
+
+  Reset update should not return, if it returns, it means the system does
+  not support capsule update.
+
+**/
+VOID
+EFIAPI
+EnterS3WithImmediateWake (
+  VOID
+  )
+{
+  PchReset (mPchResetInstance, (PCH_RESET_TYPE) EfiResetWarm);
+}
+
+/**
+  The ResetSystem function resets the entire platform.
+
+  @param[in] ResetType      The type of reset to perform.
+  @param[in] ResetStatus    The status code for the reset.
+  @param[in] DataSize       The size, in bytes, of ResetData.
+  @param[in] ResetData      For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+                            the data buffer starts with a Null-terminated string, optionally
+                            followed by additional binary data. The string is a description
+                            that the caller may use to further indicate the reason for the
+                            system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+  IN EFI_RESET_TYPE               ResetType,
+  IN EFI_STATUS                   ResetStatus,
+  IN UINTN                        DataSize,
+  IN VOID                         *ResetData OPTIONAL
+  )
+{
+  switch (ResetType) {
+  case EfiResetWarm:
+    ResetWarm ();
+    break;
+
+  case EfiResetCold:
+    ResetCold ();
+    break;
+
+  case EfiResetShutdown:
+    ResetShutdown ();
+    return;
+
+  case EfiResetPlatformSpecific:
+    ResetPlatformSpecific (DataSize, ResetData);
+    return;
+
+  default:
+    return;
+  }
+}
+
+/**
+  <b>PchReset Runtime  DXE Driver Entry Point</b>\n
+  - <b>Introduction</b>\n
+    The PchReset Runtime DXE driver provide a standard way for other modules to
+    use the PCH Reset Interface in DXE/SMM/Runtime environments. It has no longer
+    hooked ResetSystem() function of the runtime service table.
+
+  - @pre
+    - If there is any driver which needs to run the callback function right before
+      issuing the reset, PCH Reset Callback Protocol will need to be installed
+      before PCH Reset Runtime DXE driver. If PchReset Runtime DXE driver is run
+      before Status Code Runtime Protocol is installed and there is the need
+      to use Status code in the driver, it will be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID
+      to the dependency file.
+    - @link _PCH_RESET_CALLBACK_PROTOCOL  PCH_RESET_CALLBACK_PROTOCOL @endlink
+
+  - @result
+    The Reset driver produces @link _PCH_RESET_PROTOCOL PCH_RESET_PROTOCOL @endlink
+
+  @param[in] ImageHandle          Image handle of the loaded driver
+  @param[in] SystemTable          Pointer to the System Table
+
+  @retval EFI_SUCCESS             Thread can be successfully created
+  @retval EFI_OUT_OF_RESOURCES    Cannot allocate protocol data structure
+  @retval EFI_DEVICE_ERROR        Cannot create the timer service
+**/
+EFI_STATUS
+EFIAPI
+InstallPchReset (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                      Status;
+  UINT64                          BaseAddress;
+  UINT64                          Length;
+  UINT32                          PwrmBaseAddress;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemorySpaceDescriptor;
+  UINT64                          Attributes;
+  EFI_EVENT                       AddressChangeEvent;
+  EFI_PEI_HOB_POINTERS            HobPtr;
+  PCH_POLICY_HOB                  *PchPolicyHob;
+
+  DEBUG ((DEBUG_INFO, "InstallPchReset() Start\n"));
+
+  //
+  // Set PMC PCI address space to RUNTIME MEMORY.
+  //
+  BaseAddress = MmPciBase(
+                  DEFAULT_PCI_BUS_NUMBER_PCH,
+                  PCI_DEVICE_NUMBER_PCH_PMC,
+                  PCI_FUNCTION_NUMBER_PCH_PMC
+                  );
+  Length  = 0x1000; // 4KB
+
+  Status  = gDS->GetMemorySpaceDescriptor (BaseAddress, &MemorySpaceDescriptor);
+  ASSERT_EFI_ERROR (Status);
+
+  Attributes = MemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  BaseAddress,
+                  Length,
+                  Attributes
+                  );
+  ASSERT_EFI_ERROR (Status);
+  //
+  // Set PWRM MMIO address space to RUNTIME MEMORY.
+  //
+  PchPwrmBaseGet (&PwrmBaseAddress);
+  Length = 0x10000; // 64KB
+
+  Status  = gDS->GetMemorySpaceDescriptor (PwrmBaseAddress, &MemorySpaceDescriptor);
+  ASSERT_EFI_ERROR (Status);
+
+  Attributes = MemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  PwrmBaseAddress,
+                  Length,
+                  Attributes
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Allocate Runtime memory for the PchReset protocol instance.
+  ///
+  mPchResetInstance = AllocateRuntimeZeroPool (sizeof (PCH_RESET_INSTANCE));
+  if (mPchResetInstance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = PchResetConstructor (mPchResetInstance);
+
+  ///
+  /// Create Address Change event
+  ///
+  ///
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  PchResetVirtualAddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &AddressChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  HobPtr.Guid   = GetFirstGuidHob (&gPchPolicyHobGuid);
+  if (HobPtr.Guid != NULL) {
+    PchPolicyHob = GET_GUID_HOB_DATA (HobPtr.Guid);
+    mCapsuleResetType = PchPolicyHob->PmConfig.CapsuleResetType;
+  }
+  ///
+  /// The Lib Deconstruct will automatically be called when entrypoint return error.
+  ///
+  DEBUG ((DEBUG_INFO, "InstallPchReset() End\n"));
+
+  return Status;
+}
+
+/**
+  If need be, do any special reset required for capsules. For this
+  implementation where we're called from the ResetSystem() api,
+  just set our capsule variable and return to let the caller
+  do a soft reset.
+**/
+VOID
+CapsuleS3Reset (
+  VOID
+  )
+{
+  UINT32      Data32;
+  UINT32      Eflags;
+  UINT16      ABase;
+
+  DEBUG ((DEBUG_INFO, "Capsule Present: Will be issuing S3 reset.\n"));
+
+  ///
+  /// Wake up system 2 seconds after putting system into S3 to complete the reset operation.
+  ///
+  SetSystemWakeupAlarm (2);
+  ///
+  /// Process capsules across a system reset.
+  ///
+  ABase = mPchResetInstance->PchAcpiBase;
+  ASSERT (ABase != 0);
+
+  Data32  = IoRead32 ((UINTN) (ABase + R_PCH_ACPI_PM1_CNT));
+
+  Data32  = (UINT32) ((Data32 & ~(B_PCH_ACPI_PM1_CNT_SLP_TYP + B_PCH_ACPI_PM1_CNT_SLP_EN)) | V_PCH_ACPI_PM1_CNT_S3);
+
+  Eflags  = (UINT32) AsmReadEflags ();
+
+  if ((Eflags & 0x200)) {
+    DisableInterrupts ();
+  }
+
+  AsmWbinvd ();
+  AsmWriteCr0 (AsmReadCr0 () | 0x060000000);
+
+  IoWrite32 (
+    (UINTN) (ABase + R_PCH_ACPI_PM1_CNT),
+    (UINT32) Data32
+    );
+
+  Data32 = Data32 | B_PCH_ACPI_PM1_CNT_SLP_EN;
+
+  IoWrite32 (
+    (UINTN) (ABase + R_PCH_ACPI_PM1_CNT),
+    (UINT32) Data32
+    );
+
+  if ((Eflags & 0x200)) {
+    EnableInterrupts ();
+  }
+  ///
+  /// Should not return
+  ///
+  CpuDeadLoop ();
+}
+
+/**
+  Execute call back function for Pch Reset.
+
+  @param[in] PchResetType         Pch Reset Types which includes PowerCycle, Globalreset.
+
+  @retval EFI_SUCCESS             The callback function has been done successfully
+  @retval EFI_NOT_FOUND           Failed to find Pch Reset Callback protocol. Or, none of
+                                  callback protocol is installed.
+  @retval Others                  Do not do any reset from PCH
+**/
+EFI_STATUS
+EFIAPI
+PchResetCallback (
+  IN     PCH_RESET_TYPE           PchResetType
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       NumHandles;
+  EFI_HANDLE                  *HandleBuffer;
+  UINTN                       Index;
+  PCH_RESET_CALLBACK_PROTOCOL *PchResetCallback;
+  UINTN                       Size;
+  UINTN                       CapsuleDataPtr;
+
+  if (EfiAtRuntime () == FALSE) {
+    DEBUG((DEBUG_ERROR, "Not in Runtime"));
+    ///
+    /// Retrieve all instances of Pch Reset Callback protocol
+    ///
+    Status = gBS->LocateHandleBuffer (
+                    ByProtocol,
+                    &gPchResetCallbackProtocolGuid,
+                    NULL,
+                    &NumHandles,
+                    &HandleBuffer
+                    );
+
+    if (EFI_ERROR (Status)) {
+      ///
+      /// Those drivers that need to install Pch Reset Callback protocol have the responsibility
+      /// to make sure themselves execute before Pch Reset Runtime driver.
+      ///
+      if (Status == EFI_NOT_FOUND) {
+        DEBUG ((DEBUG_ERROR | DEBUG_INFO, "Or, none of Pch Reset callback protocol is installed.\n"));
+      }
+
+      return Status;
+    }
+
+    for (Index = 0; Index < NumHandles; Index++) {
+      Status = gBS->HandleProtocol (
+                      HandleBuffer[Index],
+                      &gPchResetCallbackProtocolGuid,
+                      (VOID **) &PchResetCallback
+                      );
+      ASSERT_EFI_ERROR (Status);
+
+      if (!EFI_ERROR (Status)) {
+        DEBUG((EFI_D_ERROR, "Calling PchResetCallback %d\n", Index));
+        PchResetCallback->ResetCallback (PchResetType);
+      } else {
+        DEBUG ((DEBUG_ERROR | DEBUG_INFO, "Failed to locate Pch Reset Callback protocol.\n"));
+        return Status;
+      }
+    }
+  }
+  DEBUG((EFI_D_ERROR, "PchResetCallback After Runtime Check\n"));
+  if(PchResetType == WarmReset) {
+    ///
+    /// Check if there are pending capsules to process
+    ///
+    DEBUG((EFI_D_ERROR, "PchResetCallback Warmreset\n"));
+    Size = sizeof (CapsuleDataPtr);
+    Status = EfiGetVariable (
+               EFI_CAPSULE_VARIABLE_NAME,
+               &gEfiCapsuleVendorGuid,
+               NULL,
+               &Size,
+               (VOID *) &CapsuleDataPtr
+               );
+    if (Status == EFI_SUCCESS) {
+      if (mCapsuleResetType == CAPSULE_RESET_S3) { //default value S3 resume
+        CapsuleS3Reset ();
+      }
+      AsmWbinvd ();
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+  @param[in] Event                The event registered.
+  @param[in] Context              Event context. Not used in this event handler.
+
+**/
+VOID
+EFIAPI
+PchResetVirtualAddressChangeEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mPchResetInstance->PchPmcBase));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mPchResetInstance->PchPwrmBase));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mPchResetInstance));
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.h b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.h
new file mode 100644
index 0000000000..742ca70498
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/DxeRuntimeResetSystemLib/PchReset.h
@@ -0,0 +1,105 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCH_RESET_H
+#define _PCH_RESET_H
+
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Guid/EventGroup.h>
+#include <Library/MmPciBaseLib.h>
+#include <Protocol/PchReset.h>
+#include <PchAccess.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <IncludePrivate/Library/PchResetCommonLib.h>
+#include <IncludePrivate/PchPolicyHob.h>
+#include <Library/HobLib.h>
+
+#define EFI_INTERNAL_POINTER 0x04
+
+#define PCH_RESET_INSTANCE_FROM_THIS(a) \
+  CR ( \
+  a, \
+  PCH_RESET_INSTANCE, \
+  PchResetInterface.PchResetProtocol, \
+  PCH_RESET_SIGNATURE \
+  )
+
+#define CAPSULE_RESET_S3         0
+#define CAPSULE_RESET_WARM       1
+
+/**
+  <b>PchReset Runtime  DXE Driver Entry Point</b>\n
+  - <b>Introduction</b>\n
+    The PchReset Runtime DXE driver provide a standard way for other modules to
+    use the PCH Reset Interface in DXE/SMM/Runtime environments. It has no longer
+    hooked ResetSystem() function of the runtime service table.
+
+  - @pre
+    - If there is any driver which needs to run the callback function right before
+    issuing the reset, PCH Reset Callback Protocol will need to be installed
+    before PCH Reset Runtime DXE driver. If PchReset Runtime DXE driver is run
+    before Status Code Runtime Protocol is installed and there is the need
+    to use Status code in the driver, it will be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID
+    to the dependency file.
+    - @link _PCH_RESET_CALLBACK_PROTOCOL  PCH_RESET_CALLBACK_PROTOCOL @endlink
+
+  - @result
+    The Reset driver produces @link _PCH_RESET_PROTOCOL PCH_RESET_PROTOCOL @endlink
+
+  @param[in] ImageHandle          Image handle of the loaded driver
+  @param[in] SystemTable          Pointer to the System Table
+
+  @retval EFI_SUCCESS             Thread can be successfully created
+  @retval EFI_OUT_OF_RESOURCES    Cannot allocate protocol data structure
+  @retval EFI_DEVICE_ERROR        Cannot create the timer service
+**/
+EFI_STATUS
+EFIAPI
+InstallPchReset (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  Execute call back function for Pch Reset.
+
+  @param[in] PchResetType         Pch Reset Types which includes PowerCycle, Globalreset.
+
+  @retval EFI_SUCCESS             The callback function has been done successfully
+  @retval EFI_NOT_FOUND           Failed to find Pch Reset Callback protocol. Or, none of
+                                  callback protocol is installed.
+  @retval Others                  Do not do any reset from PCH
+**/
+EFI_STATUS
+EFIAPI
+PchResetCallback (
+  IN     PCH_RESET_TYPE           PchResetType
+  );
+
+/**
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+  @param[in] Event                The event registered.
+  @param[in] Context              Event context. Not used in this event handler.
+
+**/
+VOID
+EFIAPI
+PchResetVirtualAddressChangeEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  );
+#endif
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioInit.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioInit.c
new file mode 100644
index 0000000000..89f601736a
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioInit.c
@@ -0,0 +1,403 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GpioLibrary.h"
+
+
+/**
+  This procedure will handle requirement on SATA DEVSLPx pins.
+
+  @param[in]     GpioPad        GPIO pad
+  @param[in]     PadMode        GPIO PadMode value
+  @param[in out] Dw0Reg         Value for PADCFG_DW0 register
+  @param[in out] Dw0RegMask     Mask of bits which will change in PADCFG_DWO register
+
+  @retval None
+
+**/
+static
+VOID
+GpioHandleSataDevSlpPad (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    PadMode,
+  IN OUT UINT32                *Dw0Reg,
+  IN OUT UINT32                *Dw0RegMask
+  )
+{
+  //
+  // For SATA DEVSLPx pins if used in native 1 mode then ensure that PadRstCfg
+  // is set to "00" - Powergood
+  //
+  if (GpioIsPadASataDevSlpPin (GpioPad, PadMode)) {
+    //
+    // Set PadRstCfg to Powergood
+    //
+    *Dw0RegMask |= B_PCH_GPIO_RST_CONF;
+    *Dw0Reg |= ((GpioResetPwrGood >> 1) << N_PCH_GPIO_RST_CONF);
+  }
+}
+
+/**
+  This SKL PCH specific procedure will initialize multiple SKL PCH GPIO pins
+
+  @param[in] NumberofItem               Number of GPIO pads to be updated
+  @param[in] GpioInitTableAddress       GPIO initialization table
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_INVALID_PARAMETER         Invalid group or pad number
+**/
+static
+EFI_STATUS
+GpioConfigureSklPch (
+  IN UINT32                    NumberOfItems,
+  IN GPIO_INIT_CONFIG          *GpioInitTableAddress
+  )
+{
+  UINT32               Index;
+  UINT32               Dw0Reg;
+  UINT32               Dw0RegMask;
+  UINT32               Dw1Reg;
+  UINT32               Dw1RegMask;
+  UINT32               PadCfgReg;
+  UINT32               HostSoftOwnReg[V_PCH_GPIO_GROUP_MAX];
+  UINT32               HostSoftOwnRegMask[V_PCH_GPIO_GROUP_MAX];
+  UINT32               GpiGpeEnReg[V_PCH_GPIO_GROUP_MAX];
+  UINT32               GpiGpeEnRegMask[V_PCH_GPIO_GROUP_MAX];
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  GPIO_GROUP           GpioGroupOffset;
+  UINT32               NumberOfGroups;
+  GPIO_PAD_OWN         PadOwnVal;
+  GPIO_INIT_CONFIG     *GpioData;
+  GPIO_GROUP           Group;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  PCH_SERIES           PchSeries;
+
+  PchSeries = GetPchSeries ();
+  PadOwnVal = GpioPadOwnHost;
+
+  ZeroMem (HostSoftOwnReg, sizeof (HostSoftOwnReg));
+  ZeroMem (HostSoftOwnRegMask, sizeof (HostSoftOwnRegMask));
+  ZeroMem (GpiGpeEnReg, sizeof (GpiGpeEnReg));
+  ZeroMem (GpiGpeEnRegMask, sizeof (GpiGpeEnRegMask));
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GpioGroupOffset = GpioGetLowestGroup ();
+  NumberOfGroups = GpioGetNumberOfGroups ();
+
+  for (Index = 0; Index < NumberOfItems; Index ++) {
+
+    Dw0RegMask = 0;
+    Dw0Reg = 0;
+    Dw1RegMask = 0;
+    Dw1Reg = 0;
+
+    GpioData   = &GpioInitTableAddress[Index];
+
+    Group      = GpioGetGroupFromGpioPad (GpioData->GpioPad);
+    GroupIndex = GpioGetGroupIndexFromGpioPad (GpioData->GpioPad);
+    PadNumber  = GpioGetPadNumberFromGpioPad (GpioData->GpioPad);
+
+    if (GroupIndex >= V_PCH_GPIO_GROUP_MAX) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Invalid Group Index (GroupIndex=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+      ASSERT (FALSE);
+      continue;
+    }
+
+DEBUG_CODE_BEGIN();
+    if (!(((PchSeries == PchH) && (GPIO_GET_CHIPSET_ID(GpioData->GpioPad) == GPIO_SKL_H_CHIPSET_ID)) ||
+        ((PchSeries == PchLp) && (GPIO_GET_CHIPSET_ID(GpioData->GpioPad) == GPIO_SKL_LP_CHIPSET_ID)))) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+      ASSERT (FALSE);
+      return EFI_UNSUPPORTED;
+    }
+DEBUG_CODE_END();
+
+    //
+    // Check if group argument exceeds GPIO group range
+    //
+    if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Check if legal pin number
+    //
+    if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (GpioIsPadLocked (GroupIndex, PadNumber)) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pad is locked (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+      continue;
+    }
+
+    if (DebugCodeEnabled ()) {
+
+    //
+    // Check if selected GPIO Pad is not owned by CSME/ISH
+    //
+    GpioGetPadOwnership (GpioData->GpioPad, &PadOwnVal);
+
+    if (PadOwnVal != GpioPadOwnHost) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+      DEBUG ((DEBUG_ERROR, "** Please make sure the GPIO usage in sync between CSME and BIOS configuration. \n"));
+      DEBUG ((DEBUG_ERROR, "** All the GPIO occupied by CSME should not do any configuration by BIOS.\n"));
+      continue;
+    }
+
+    }
+
+    //
+    // Configure Reset Type (PadRstCfg)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.PowerConfig & GPIO_CONF_RESET_MASK) >> GPIO_CONF_RESET_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RST_CONF);
+    Dw0Reg |= (((GpioData->GpioConfig.PowerConfig & GPIO_CONF_RESET_MASK) >> (GPIO_CONF_RESET_BIT_POS + 1)) << N_PCH_GPIO_RST_CONF);
+
+    //
+    // Configure how interrupt is triggered (RxEvCfg)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.InterruptConfig & GPIO_CONF_INT_TRIG_MASK) >> GPIO_CONF_INT_TRIG_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RX_LVL_EDG);
+    Dw0Reg |= (((GpioData->GpioConfig.InterruptConfig & GPIO_CONF_INT_TRIG_MASK) >> (GPIO_CONF_INT_TRIG_BIT_POS + 1)) << N_PCH_GPIO_RX_LVL_EDG);
+
+
+    //
+    // Configure interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.InterruptConfig & GPIO_CONF_INT_ROUTE_MASK) >> GPIO_CONF_INT_ROUTE_BIT_POS) == GpioHardwareDefault)  ? 0x0 : (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE));
+    Dw0Reg |= (((GpioData->GpioConfig.InterruptConfig & GPIO_CONF_INT_ROUTE_MASK) >> (GPIO_CONF_INT_ROUTE_BIT_POS + 1)) << N_PCH_GPIO_RX_NMI_ROUTE);
+
+    //
+    // Configure GPIO direction (GPIORxDis and GPIOTxDis)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.Direction & GPIO_CONF_DIR_MASK) >> GPIO_CONF_DIR_BIT_POS) == GpioHardwareDefault) ? 0x0 : (B_PCH_GPIO_RXDIS | B_PCH_GPIO_TXDIS));
+    Dw0Reg |= (((GpioData->GpioConfig.Direction & GPIO_CONF_DIR_MASK) >> (GPIO_CONF_DIR_BIT_POS + 1)) << N_PCH_GPIO_TXDIS);
+
+    //
+    // Configure GPIO input inversion (RXINV)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.Direction & GPIO_CONF_INV_MASK) >> GPIO_CONF_INV_BIT_POS) == GpioHardwareDefault) ?  0x0 : B_PCH_GPIO_RXINV);
+    Dw0Reg |= (((GpioData->GpioConfig.Direction & GPIO_CONF_INV_MASK) >> (GPIO_CONF_INV_BIT_POS + 1)) << N_PCH_GPIO_RXINV);
+
+    //
+    // Configure GPIO output state (GPIOTxState)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.OutputState & GPIO_CONF_OUTPUT_MASK) >> GPIO_CONF_OUTPUT_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_TX_STATE);
+    Dw0Reg |= (((GpioData->GpioConfig.OutputState & GPIO_CONF_OUTPUT_MASK) >> (GPIO_CONF_OUTPUT_BIT_POS + 1)) << N_PCH_GPIO_TX_STATE);
+
+    //
+    // Configure GPIO RX raw override to '1' (RXRAW1)
+    //
+    Dw0RegMask |= ((((GpioData->GpioConfig.OtherSettings & GPIO_CONF_RXRAW_MASK) >> GPIO_CONF_RXRAW_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RX_RAW1);
+    Dw0Reg |= (((GpioData->GpioConfig.OtherSettings & GPIO_CONF_RXRAW_MASK) >> (GPIO_CONF_RXRAW_BIT_POS + 1)) << N_PCH_GPIO_RX_RAW1);
+
+    //
+    // Configure GPIO Pad Mode (PMode)
+    //
+    if (((GpioData->GpioPad == GPIO_SKL_H_GPP_B2) ||
+        (GpioData->GpioPad == GPIO_SKL_H_GPD7) ||
+        (GpioData->GpioPad == GPIO_SKL_H_GPD9)) &&
+        (GpioData->GpioConfig.PadMode != GpioPadModeGpio)) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group/Index: %d/%d, Pad: %d cannot be set as NATIVE. Force it to GPIO mode!\n", Group, GroupIndex, PadNumber));
+      Dw0RegMask |= B_PCH_GPIO_PAD_MODE;
+      Dw0Reg |= ((GpioPadModeGpio >> (GPIO_CONF_PAD_MODE_BIT_POS + 1)) << N_PCH_GPIO_PAD_MODE);
+    } else {
+      Dw0RegMask |= ((((GpioData->GpioConfig.PadMode & GPIO_CONF_PAD_MODE_MASK) >> GPIO_CONF_PAD_MODE_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PAD_MODE);
+      Dw0Reg |= (((GpioData->GpioConfig.PadMode & GPIO_CONF_PAD_MODE_MASK) >> (GPIO_CONF_PAD_MODE_BIT_POS + 1)) << N_PCH_GPIO_PAD_MODE);
+    }
+
+    //
+    // Configure GPIO termination (Term)
+    //
+    Dw1RegMask |= ((((GpioData->GpioConfig.ElectricalConfig & GPIO_CONF_TERM_MASK) >> GPIO_CONF_TERM_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_TERM);
+    Dw1Reg |= (((GpioData->GpioConfig.ElectricalConfig & GPIO_CONF_TERM_MASK) >> (GPIO_CONF_TERM_BIT_POS + 1)) << N_PCH_GPIO_TERM);
+
+    //
+    // Configure GPIO pad tolerance (padtol)
+    //
+    Dw1RegMask |= ((((GpioData->GpioConfig.ElectricalConfig & GPIO_CONF_PADTOL_MASK) >> GPIO_CONF_PADTOL_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PADTOL);
+    Dw1Reg |= (((GpioData->GpioConfig.ElectricalConfig & GPIO_CONF_PADTOL_MASK) >> (GPIO_CONF_PADTOL_BIT_POS + 1)) << N_PCH_GPIO_PADTOL);
+
+    //
+    // Check for additional requirements on setting PADCFG register
+    //
+    GpioHandleSataDevSlpPad (GpioData->GpioPad, GpioData->GpioConfig.PadMode, &Dw0Reg, &Dw0RegMask);
+
+    //
+    // Create PADCFG register offset using group and pad number
+    //
+    PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+    //
+    // Write PADCFG DW0 register
+    //
+    MmioAndThenOr32 (
+      (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg),
+      ~(UINT32)Dw0RegMask,
+      (UINT32)Dw0Reg
+    );
+
+    //
+    // Write PADCFG DW1 register
+    //
+    MmioAndThenOr32 (
+      (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg + 0x4),
+      ~(UINT32)Dw1RegMask,
+      (UINT32)Dw1Reg
+    );
+    //
+    // Update value to be programmed in HOSTSW_OWN register
+    //
+    HostSoftOwnRegMask[GroupIndex] |= (GpioData->GpioConfig.HostSoftPadOwn & 0x1) << PadNumber;
+    HostSoftOwnReg[GroupIndex] |= (GpioData->GpioConfig.HostSoftPadOwn >> 0x1) << PadNumber;
+
+    //
+    // Update value to be programmed in GPI_GPE_EN register
+    //
+    GpiGpeEnRegMask[GroupIndex] |= (GpioData->GpioConfig.InterruptConfig & 0x1) << PadNumber;
+    GpiGpeEnReg[GroupIndex] |= ((GpioData->GpioConfig.InterruptConfig & GpioIntSci) >> 3) << PadNumber;
+  }
+
+  for (Index = 0; Index < NumberOfGroups; Index++) {
+    //
+    // Write HOSTSW_OWN registers
+    //
+    if (GpioGroupInfo[Index].HostOwnOffset != NO_REGISTER_FOR_PROPERTY) {
+      MmioAndThenOr32 (
+        (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[Index].Community, GpioGroupInfo[Index].HostOwnOffset),
+        ~(UINT32)HostSoftOwnRegMask[Index],
+        (UINT32)HostSoftOwnReg[Index]
+        );
+    }
+
+    //
+    // Write GPI_GPE_EN registers
+    //
+    if (GpioGroupInfo[Index].GpiGpeEnOffset != NO_REGISTER_FOR_PROPERTY) {
+      MmioAndThenOr32 (
+        (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[Index].Community, GpioGroupInfo[Index].GpiGpeEnOffset),
+        ~(UINT32)GpiGpeEnRegMask[Index],
+        (UINT32)GpiGpeEnReg[Index]
+        );
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will clear all status bits of any GPIO interrupts.
+
+  @param[in] none
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_INVALID_PARAMETER         Invalid group or pad number
+**/
+static
+EFI_STATUS
+GpioClearAllGpioInterrupts (
+  VOID
+  )
+{
+  GPIO_GROUP           Group;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  GPIO_GROUP           GpioGroupLowest;
+  GPIO_GROUP           GpioGroupHighest;
+  UINT32               GroupIndex;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GpioGroupLowest = GpioGetLowestGroup ();
+  GpioGroupHighest = GpioGetHighestGroup ();
+
+  for (Group = GpioGroupLowest; Group <= GpioGroupHighest; Group++) {
+    GroupIndex = GpioGetGroupIndexFromGroup (Group);
+    //
+    // Check if group has GPI IS register
+    //
+    if (GpioGroupInfo[Group].GpiIsOffset != NO_REGISTER_FOR_PROPERTY) {
+      //
+      // Clear all GPI_IS Status bits by writing '1'
+      //
+      MmioWrite32 (
+        PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiIsOffset),
+        (UINT32)0xFFFFFFFF
+        );
+    }
+
+    //
+    // Check if group has GPI_GPE_STS register
+    //
+    if (GpioGroupInfo[GroupIndex].GpiGpeStsOffset != NO_REGISTER_FOR_PROPERTY) {
+      //
+      // Clear all GPI_GPE_STS Status bits by writing '1'
+      //
+      MmioWrite32 (
+        PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeStsOffset),
+        (UINT32)0xFFFFFFFF
+        );
+    }
+
+    //
+    // Check if group has SMI_STS register
+    //
+    if (GpioGroupInfo[GroupIndex].SmiStsOffset != NO_REGISTER_FOR_PROPERTY) {
+      //
+      // Clear all SMI_STS Status bits by writing '1'
+      //
+      MmioWrite32 (
+        PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiStsOffset),
+        (UINT32)0xFFFFFFFF
+        );
+    }
+
+    //
+    // Check if group has NMI_STS register
+    //
+    if (GpioGroupInfo[GroupIndex].NmiStsOffset != NO_REGISTER_FOR_PROPERTY) {
+      //
+      // Clear all NMI_STS Status bits by writing '1'
+      //
+      MmioWrite32 (
+        PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].NmiStsOffset),
+        (UINT32)0xFFFFFFFF
+        );
+    }
+
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will initialize multiple GPIO pins. Use GPIO_INIT_CONFIG structure.
+  Structure contains fields that can be used to configure each pad.
+  Pad not configured using GPIO_INIT_CONFIG will be left with hardware default values.
+  Separate fields could be set to hardware default if it does not matter, except
+  GpioPad and PadMode.
+  Some GpioPads are configured and switched to native mode by RC, those include:
+  SerialIo pins, ISH pins, ClkReq Pins
+
+  @param[in] NumberofItem               Number of GPIO pads to be updated
+  @param[in] GpioInitTableAddress       GPIO initialization table
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_INVALID_PARAMETER         Invalid group or pad number
+**/
+EFI_STATUS
+GpioConfigurePads (
+  IN UINT32                    NumberOfItems,
+  IN GPIO_INIT_CONFIG          *GpioInitTableAddress
+  )
+{
+  EFI_STATUS   Status;
+  Status =  GpioConfigureSklPch (NumberOfItems, GpioInitTableAddress);
+  GpioClearAllGpioInterrupts ();
+  return Status;
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLib.c
new file mode 100644
index 0000000000..d94ff8a693
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLib.c
@@ -0,0 +1,2738 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GpioLibrary.h"
+#include <Uefi/UefiMultiPhase.h>
+#include <Pi/PiMultiPhase.h>
+#include <Library/HobLib.h>
+
+//
+// Possible registers to be accessed using GpioReadWriteReg() function
+//
+typedef enum {
+  GpioHostOwnershipRegister = 0,
+  GpioGpeEnableRegister,
+  GpioSmiEnableRegister,
+  GpioNmiEnableRegister,
+  GpioPadConfigLockRegister,
+  GpioPadLockOutputRegister
+} GPIO_REG;
+
+/**
+  This procedure will write or read GPIO Pad Configuration register
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] DwReg                Choose PADCFG register: 0:DW0, 1:DW1
+  @param[in] Mask                 Mask
+  @param[in] Write                Perform read(0) or write(1)
+  @param[in,out] ReadWriteValue   Read/Write data
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+  @retval EFI_UNSUPPORTED         Host cannot access this pad
+**/
+static
+EFI_STATUS
+GpioReadWritePadCfgReg (
+  IN GPIO_PAD             GpioPad,
+  IN UINT8                DwReg,
+  IN UINT32               Mask,
+  IN BOOLEAN              Write,
+  IN OUT UINT32           *ReadWriteVal
+  )
+{
+  UINT32               PadCfgReg;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+
+
+  GPIO_PAD_OWN         PadOwnVal;
+
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pin number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Write && (DwReg == 1 || (Mask & ~B_PCH_GPIO_TX_STATE) != 0) && GpioIsPadLocked (GroupIndex, PadNumber)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pad is locked (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_WRITE_PROTECTED;
+  }
+
+DEBUG_CODE_BEGIN();
+  //
+  // Check if selected GPIO Pad is not owned by CSME/ISH
+  // If GPIO is not owned by Host all access to PadCfg will be dropped
+  //
+  GpioGetPadOwnership (GpioPad, &PadOwnVal);
+  if (PadOwnVal != GpioPadOwnHost) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+DEBUG_CODE_END();
+
+  //
+  // Create Pad Configuration register offset
+  //
+  PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+  if(DwReg == 1) {
+    PadCfgReg += 0x4;
+  }
+
+  if (Write) {
+    MmioAndThenOr32 (
+      (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg),
+      (UINT32)(~Mask),
+      (UINT32)(*ReadWriteVal & Mask)
+    );
+  } else {
+    *ReadWriteVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg));
+    *ReadWriteVal &= Mask;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will write or read GPIO register
+
+  @param[in] RegType              GPIO register type
+  @param[in] Group                GPIO group
+  @param[in] DwNum                Register number for current group (parameter applicable in accessing whole register).
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in] GpioPad              GPIO pad
+  @param[in] Write                Perform read(0) or write(1)
+  @param[in] OnePad               Access whole register(0) or one pad(1)
+  @param[in,out] ReadWriteValue   Read/Write data
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group, pad or DwNum parameter number
+**/
+static
+EFI_STATUS
+GpioReadWriteReg (
+  IN GPIO_REG                  RegType,
+  IN GPIO_GROUP                Group,
+  IN UINT32                    DwNum,
+  IN GPIO_PAD                  GpioPad,
+  IN BOOLEAN                   Write,
+  IN BOOLEAN                   OnePad,
+  IN OUT UINT32                *ReadWriteVal
+  )
+{
+  UINT32               Mask;
+  UINT32               RegOffset;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  RegOffset = 0;
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  if (OnePad) {
+    GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+    PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+DEBUG_CODE_BEGIN();
+    if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+      return EFI_UNSUPPORTED;
+    }
+DEBUG_CODE_END();
+  } else {
+    GroupIndex = GpioGetGroupIndexFromGroup (Group);
+    PadNumber = 0;
+  }
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  switch (RegType) {
+    case GpioHostOwnershipRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].HostOwnOffset;
+      break;
+    case GpioGpeEnableRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].GpiGpeEnOffset;
+      break;
+    case GpioSmiEnableRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].SmiEnOffset;
+      break;
+    case GpioNmiEnableRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].NmiEnOffset;
+      break;
+    case GpioPadConfigLockRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockOffset;
+      break;
+    case GpioPadLockOutputRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockTxOffset;
+      break;
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+
+  //
+  // Check if selected register exists
+  //
+  if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Access one GPIO Pad
+  //
+  if (OnePad) {
+    //
+    // Check if legal pin number
+    //
+    if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+      return EFI_INVALID_PARAMETER;
+    }
+    //
+    // For future use. If there are more then 32 pads per group then certain
+    // group information would be split into more then one DWord register.
+    //
+    RegOffset += (PadNumber >> 5) * 0x4;
+    //
+    // Calculate pad bit position within DWord register
+    //
+    PadNumber %= 32;
+    Mask = BIT0 << PadNumber;
+
+    if (Write) {
+      MmioAndThenOr32 (
+        (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset),
+        (UINT32)(~Mask),
+        (UINT32)((*ReadWriteVal << PadNumber) & Mask)
+      );
+    } else {
+      *ReadWriteVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
+      *ReadWriteVal = (*ReadWriteVal & Mask) >> PadNumber;
+    }
+  //
+  // Access whole register
+  //
+  } else {
+    //
+    // Check if DwNum argument does not exceed number of DWord registers
+    // resulting from available pads for certain group
+    //
+    if (DwNum > ((GpioGroupInfo[GroupIndex].PadPerGroup - 1) >> 5)){
+      return EFI_INVALID_PARAMETER;
+    }
+    //
+    // For future use. If there are more then 32 pads per group then certain
+    // group information would be split into more then one DWord register.
+    // For SKL PCH DwNum must be 0.
+    //
+    RegOffset += DwNum *0x4;
+
+    if (Write) {
+      MmioWrite32 (
+        (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset),
+        (UINT32)(*ReadWriteVal)
+      );
+    } else {
+      *ReadWriteVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will write GPIO Lock/LockTx register using SBI.
+
+  @param[in] RegType              GPIO register (Lock or LockTx)
+  @param[in] Unlock               Lock pads(0) or unlock(1)
+  @param[in] Group                GPIO group number
+  @param[in] DwNum                Register number for current group (parameter applicable in accessing whole register).
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in] PadsToModify         Bit mask for pads that are going to be modified
+  @param[in] GpioPad              GPIO pad
+  @param[in] OnePad               Access whole register(0) or one pad(1)
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group, pad or DwNum parameter number
+**/
+static
+EFI_STATUS
+GpioLockPadsUsingSbi (
+  IN GPIO_REG                  RegType,
+  IN BOOLEAN                   Unlock,
+  IN GPIO_GROUP                Group,
+  IN UINT32                    DwNum,
+  IN UINT32                    PadsToModify,
+  IN GPIO_PAD                  GpioPad,
+  IN BOOLEAN                   OnePad
+  )
+{
+  UINT8                Response;
+  EFI_STATUS           Status;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  UINT32               RegOffset;
+  UINT32               OldPadCfgLockRegVal;
+  UINT32               NewPadCfgLockRegVal;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+
+  RegOffset = 0;
+  OldPadCfgLockRegVal = 0;
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  if (OnePad) {
+    GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+    PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+    Group = GpioGetGroupFromGpioPad (GpioPad);
+DEBUG_CODE_BEGIN();
+    if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+      return EFI_UNSUPPORTED;
+    }
+DEBUG_CODE_END();
+  } else {
+    GroupIndex = GpioGetGroupIndexFromGroup (Group);
+    PadNumber = 0;
+  }
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  switch (RegType) {
+    case GpioPadConfigLockRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockOffset;
+      break;
+    case GpioPadLockOutputRegister:
+      RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockTxOffset;
+      break;
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+
+  //
+  // Check if selected register exists
+  //
+  if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Access one GPIO Pad
+  //
+  if (OnePad) {
+    //
+    // Check if legal pin number
+    //
+    if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+      DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // For future use. If there are more then 32 pads per group then certain
+    // group information would be split into more then one DWord register.
+    //
+    DwNum = (PadNumber >> 5);
+    RegOffset += DwNum * 0x4;
+    //
+    // Calculate pad bit position within DWord register
+    //
+    PadNumber %= 32;
+
+    switch (RegType) {
+      case GpioPadConfigLockRegister:
+        GpioGetPadCfgLockForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+        break;
+      case GpioPadLockOutputRegister:
+        GpioGetPadCfgLockTxForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+        break;
+    }
+    if (Unlock) {
+      NewPadCfgLockRegVal = OldPadCfgLockRegVal & (~(0x1 << PadNumber));
+    } else {
+      NewPadCfgLockRegVal = OldPadCfgLockRegVal | (0x1 << PadNumber);
+    }
+
+  } else {
+    //
+    // Access whole register
+    //
+
+    //
+    // Check if DwNum argument does not exceed number of DWord registers
+    // resulting from available pads for certain group
+    //
+    if (DwNum > ((GpioGroupInfo[GroupIndex].PadPerGroup - 1) >> 5)){
+      return EFI_INVALID_PARAMETER;
+    }
+    //
+    // For future use. If there are more then 32 pads per group then certain
+    // group information would be split into more then one DWord register.
+    // For SKL PCH DwNum must be 0.
+    //
+    RegOffset += DwNum *0x4;
+
+    switch (RegType) {
+      case GpioPadConfigLockRegister:
+        GpioGetPadCfgLockForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+        break;
+      case GpioPadLockOutputRegister:
+        GpioGetPadCfgLockTxForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+        break;
+    }
+    if (Unlock) {
+      NewPadCfgLockRegVal = OldPadCfgLockRegVal & (~PadsToModify);
+    } else {
+      NewPadCfgLockRegVal = OldPadCfgLockRegVal | PadsToModify;
+    }
+  }
+
+  Status = PchSbiExecution (
+             GpioGroupInfo[GroupIndex].Community,
+             RegOffset,
+             GpioLockUnlock,
+             FALSE,
+             &NewPadCfgLockRegVal,
+             &Response
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will read multiple GPIO settings
+
+  @param[in]  GpioPad                   GPIO Pad
+  @param[out] GpioData                  GPIO data structure
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_INVALID_PARAMETER         Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadConfig (
+  IN  GPIO_PAD               GpioPad,
+  OUT GPIO_CONFIG            *GpioData
+  )
+{
+  UINT32               Dw0Reg;
+  UINT32               Dw1Reg;
+  UINT32               PadCfgReg;
+  UINT32               RegVal;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  GPIO_GROUP           Group;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+
+  GPIO_PAD_OWN         PadOwnVal;
+
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  Group = GpioGetGroupFromGpioPad (GpioPad);
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  GpioGetPadOwnership (GpioPad, &PadOwnVal);
+  if (PadOwnVal != GpioPadOwnHost) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  //
+  // Check if group argument exceeds GPIO group range
+  //
+  if ((Group < GpioGetLowestGroup ()) || (Group > GpioGetHighestGroup ())) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pin number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create PADCFG register offset using group and pad number
+  //
+  PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+  //
+  // Read PADCFG DW0 register
+  //
+  Dw0Reg = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg));
+
+  //
+  // Read PADCFG DW1 register
+  //
+  Dw1Reg = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg + 0x4));
+
+
+  //
+  // Get Reset Type (PadRstCfg)
+  //
+  GpioData->PowerConfig = ((Dw0Reg & B_PCH_GPIO_RST_CONF) >> (N_PCH_GPIO_RST_CONF - (GPIO_CONF_RESET_BIT_POS + 1))) | (0x1 << GPIO_CONF_RESET_BIT_POS);
+
+  //
+  // Get how interrupt is triggered (RxEvCfg)
+  //
+  GpioData->InterruptConfig = ((Dw0Reg & B_PCH_GPIO_RX_LVL_EDG) >> (N_PCH_GPIO_RX_LVL_EDG - (GPIO_CONF_INT_TRIG_BIT_POS + 1))) | (0x1 << GPIO_CONF_INT_TRIG_BIT_POS);
+
+  //
+  // Get interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
+  //
+  GpioData->InterruptConfig |= ((Dw0Reg & (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE)) >> (N_PCH_GPIO_RX_NMI_ROUTE - (GPIO_CONF_INT_ROUTE_BIT_POS + 1))) | (0x1 << GPIO_CONF_INT_ROUTE_BIT_POS);
+
+  //
+  // Get GPIO direction (GPIORxDis and GPIOTxDis)
+  //
+  GpioData->Direction = ((Dw0Reg & (B_PCH_GPIO_RXDIS | B_PCH_GPIO_TXDIS)) >> (N_PCH_GPIO_TXDIS - (GPIO_CONF_DIR_BIT_POS + 1))) | (0x1 << GPIO_CONF_DIR_BIT_POS);
+
+  //
+  // Get GPIO input inversion (RXINV)
+  //
+  GpioData->Direction |= ((Dw0Reg & B_PCH_GPIO_RXINV) >> (N_PCH_GPIO_RXINV - (GPIO_CONF_INV_BIT_POS + 1))) | (0x1 << GPIO_CONF_INV_BIT_POS);
+
+  //
+  // Get GPIO output state (GPIOTxState)
+  //
+  GpioData->OutputState = ((Dw0Reg & B_PCH_GPIO_TX_STATE) << (N_PCH_GPIO_TX_STATE + (GPIO_CONF_OUTPUT_BIT_POS + 1))) | (0x1 << GPIO_CONF_OUTPUT_BIT_POS) ;
+
+  //
+  // Configure GPIO RX raw override to '1' (RXRAW1)
+  //
+  GpioData->OtherSettings = ((Dw0Reg & B_PCH_GPIO_RX_RAW1) >> (N_PCH_GPIO_RX_RAW1 - (GPIO_CONF_RXRAW_BIT_POS + 1))) | (0x1 << GPIO_CONF_RXRAW_BIT_POS) ;
+
+  //
+  // Get GPIO Pad Mode (PMode)
+  //
+  GpioData->PadMode = ((Dw0Reg & B_PCH_GPIO_PAD_MODE) >> (N_PCH_GPIO_PAD_MODE - (GPIO_CONF_PAD_MODE_BIT_POS + 1))) | (0x1 << GPIO_CONF_PAD_MODE_BIT_POS);
+
+  //
+  // Get GPIO termination (Term)
+  //
+  GpioData->ElectricalConfig = ((Dw1Reg & B_PCH_GPIO_TERM) >> (N_PCH_GPIO_TERM - (GPIO_CONF_TERM_BIT_POS + 1))) | (0x1 << GPIO_CONF_TERM_BIT_POS) ;
+
+  //
+  // Get GPIO pad tolerance (padtol)
+  //
+  GpioData->ElectricalConfig |= ((Dw1Reg & B_PCH_GPIO_PADTOL) >> (N_PCH_GPIO_PADTOL - (GPIO_CONF_PADTOL_BIT_POS + 1))) | (0x1 << GPIO_CONF_PADTOL_BIT_POS) ;
+
+  //
+  // Read HOSTSW_OWN registers
+  //
+  RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].HostOwnOffset));
+
+  //
+  // Get Host Software Ownership
+  //
+  GpioData->HostSoftPadOwn = (((RegVal >> PadNumber) & 0x1) << (GPIO_CONF_HOST_OWN_BIT_POS + 1)) | (0x1 << GPIO_CONF_HOST_OWN_BIT_POS);
+
+  //
+  // Read PADCFGLOCK register
+  //
+  RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].PadCfgLockOffset));
+
+  //
+  // Get Pad Configuration Lock state
+  //
+  GpioData->LockConfig = (((RegVal >> PadNumber) & 0x1) << 1) | 0x1;
+
+  //
+  // Read PADCFGLOCKTX register
+  //
+  RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].PadCfgLockTxOffset));
+
+  //
+  // Get Pad Configuration Lock Tx state
+  //
+  GpioData->LockConfig |= (((RegVal >> PadNumber) & 0x1) << 2) | 0x1;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will configure multiple GPIO settings
+
+  @param[in] GpioPad                    GPIO Pad
+  @param[in] GpioData                   GPIO data structure
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_INVALID_PARAMETER         Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadConfig (
+  IN GPIO_PAD                  GpioPad,
+  IN GPIO_CONFIG               *GpioData
+  )
+{
+  UINT32               Dw0Reg;
+  UINT32               Dw0RegMask;
+  UINT32               Dw1Reg;
+  UINT32               Dw1RegMask;
+  UINT32               PadCfgReg;
+  UINT32               HostSoftOwnReg;
+  UINT32               HostSoftOwnRegMask;
+  UINT32               GpiGpeEnReg;
+  UINT32               GpiGpeEnRegMask;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  GPIO_GROUP           Group;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+
+  GPIO_PAD_OWN         PadOwnVal;
+
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  Dw0RegMask = 0;
+  Dw0Reg = 0;
+  Dw1RegMask = 0;
+  Dw1Reg = 0;
+
+  Group = GpioGetGroupFromGpioPad (GpioPad);
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  GpioGetPadOwnership (GpioPad, &PadOwnVal);
+  if (PadOwnVal != GpioPadOwnHost) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+  //
+  // Check if group argument exceeds GPIO group range
+  //
+  if ((Group < GpioGetLowestGroup ()) || (Group > GpioGetHighestGroup ())) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pin number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (GpioIsPadLocked (GroupIndex, PadNumber)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pad is locked (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_WRITE_PROTECTED;
+  }
+
+  //
+  // Configure Reset Type (PadRstCfg)
+  //
+  Dw0RegMask |= ((((GpioData->PowerConfig & GPIO_CONF_RESET_MASK) >> GPIO_CONF_RESET_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RST_CONF);
+  Dw0Reg |= (((GpioData->PowerConfig & GPIO_CONF_RESET_MASK) >> (GPIO_CONF_RESET_BIT_POS + 1)) << N_PCH_GPIO_RST_CONF);
+
+  //
+  // Configure how interrupt is triggered (RxEvCfg)
+  //
+  Dw0RegMask |= ((((GpioData->InterruptConfig & GPIO_CONF_INT_TRIG_MASK) >> GPIO_CONF_INT_TRIG_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RX_LVL_EDG);
+  Dw0Reg |= (((GpioData->InterruptConfig & GPIO_CONF_INT_TRIG_MASK) >> (GPIO_CONF_INT_TRIG_BIT_POS + 1)) << N_PCH_GPIO_RX_LVL_EDG);
+
+  //
+  // Configure interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
+  //
+  Dw0RegMask |= ((((GpioData->InterruptConfig & GPIO_CONF_INT_ROUTE_MASK) >> GPIO_CONF_INT_ROUTE_BIT_POS) == GpioHardwareDefault)  ? 0x0 : (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE));
+  Dw0Reg |= (((GpioData->InterruptConfig & GPIO_CONF_INT_ROUTE_MASK) >> (GPIO_CONF_INT_ROUTE_BIT_POS + 1)) << N_PCH_GPIO_RX_NMI_ROUTE);
+
+  //
+  // Configure GPIO direction (GPIORxDis and GPIOTxDis)
+  //
+  Dw0RegMask |= ((((GpioData->Direction & GPIO_CONF_DIR_MASK) >> GPIO_CONF_DIR_BIT_POS) == GpioHardwareDefault) ? 0x0 : (B_PCH_GPIO_RXDIS | B_PCH_GPIO_TXDIS));
+  Dw0Reg |= (((GpioData->Direction & GPIO_CONF_DIR_MASK) >> (GPIO_CONF_DIR_BIT_POS + 1)) << N_PCH_GPIO_TXDIS);
+
+  //
+  // Configure GPIO input inversion (RXINV)
+  //
+  Dw0RegMask |= ((((GpioData->Direction & GPIO_CONF_INV_MASK) >> GPIO_CONF_INV_BIT_POS) == GpioHardwareDefault) ?  0x0 : B_PCH_GPIO_RXINV);
+  Dw0Reg |= (((GpioData->Direction & GPIO_CONF_INV_MASK) >> (GPIO_CONF_INV_BIT_POS + 1)) << N_PCH_GPIO_RXINV);
+
+  //
+  // Configure GPIO output state (GPIOTxState)
+  //
+  Dw0RegMask |= ((((GpioData->OutputState & GPIO_CONF_OUTPUT_MASK) >> GPIO_CONF_OUTPUT_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_TX_STATE);
+  Dw0Reg |= (((GpioData->OutputState & GPIO_CONF_OUTPUT_MASK) >> (GPIO_CONF_OUTPUT_BIT_POS + 1)) << N_PCH_GPIO_TX_STATE);
+
+  //
+  // Configure GPIO RX raw override to '1' (RXRAW1)
+  //
+  Dw0RegMask |= ((((GpioData->OtherSettings & GPIO_CONF_RXRAW_MASK) >> GPIO_CONF_RXRAW_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RX_RAW1);
+  Dw0Reg |= (((GpioData->OtherSettings & GPIO_CONF_RXRAW_MASK) >> (GPIO_CONF_RXRAW_BIT_POS + 1)) << N_PCH_GPIO_RX_RAW1);
+
+  //
+  // Configure GPIO Pad Mode (PMode)
+  //
+  Dw0RegMask |= ((((GpioData->PadMode & GPIO_CONF_PAD_MODE_MASK) >> GPIO_CONF_PAD_MODE_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PAD_MODE);
+  Dw0Reg |= (((GpioData->PadMode & GPIO_CONF_PAD_MODE_MASK) >> (GPIO_CONF_PAD_MODE_BIT_POS + 1)) << N_PCH_GPIO_PAD_MODE);
+
+  //
+  // Configure GPIO termination (Term)
+  //
+  Dw1RegMask |= ((((GpioData->ElectricalConfig & GPIO_CONF_TERM_MASK) >> GPIO_CONF_TERM_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_TERM);
+  Dw1Reg |= (((GpioData->ElectricalConfig & GPIO_CONF_TERM_MASK) >> (GPIO_CONF_TERM_BIT_POS + 1)) << N_PCH_GPIO_TERM);
+
+  //
+  // Configure GPIO pad tolerance (padtol)
+  //
+  Dw1RegMask |= ((((GpioData->ElectricalConfig & GPIO_CONF_PADTOL_MASK) >> GPIO_CONF_PADTOL_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PADTOL);
+  Dw1Reg |= (((GpioData->ElectricalConfig & GPIO_CONF_PADTOL_MASK) >> (GPIO_CONF_PADTOL_BIT_POS + 1)) << N_PCH_GPIO_PADTOL);
+
+  //
+  // Create PADCFG register offset using group and pad number
+  //
+  PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+  //
+  // Write PADCFG DW0 register
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg),
+    ~(UINT32)Dw0RegMask,
+    (UINT32)Dw0Reg
+  );
+
+  //
+  // Write PADCFG DW1 register
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg + 0x4),
+    ~(UINT32)Dw1RegMask,
+    (UINT32)Dw1Reg
+  );
+
+  //
+  // Update value to be programmed in HOSTSW_OWN register
+  //
+  HostSoftOwnRegMask = (GpioData->HostSoftPadOwn & 0x1) << PadNumber;
+  HostSoftOwnReg = (GpioData->HostSoftPadOwn >> 0x1) << PadNumber;
+
+  //
+  // Write HOSTSW_OWN registers
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].HostOwnOffset),
+    ~(UINT32)HostSoftOwnRegMask,
+    (UINT32)HostSoftOwnReg
+    );
+
+  //
+  // Update value to be programmed in GPI_GPE_EN register
+  //
+  GpiGpeEnRegMask = (GpioData->InterruptConfig & 0x1) << PadNumber;
+  GpiGpeEnReg = ((GpioData->InterruptConfig & GpioIntSci) >> 3) << PadNumber;
+
+  //
+  // Write GPI_GPE_EN registers
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeEnOffset),
+    ~(UINT32)GpiGpeEnRegMask,
+    (UINT32)GpiGpeEnReg
+    );
+
+  //
+  // Program Pad Configuration Lock
+  //
+  if ((GpioData->LockConfig & GpioPadConfigLock) == GpioPadConfigLock) {
+    GpioLockPadsUsingSbi (
+                 GpioPadConfigLockRegister,
+                 FALSE,
+                 0,
+                 0,
+                 0,
+                 GpioPad,
+                 TRUE
+                 );
+  }
+
+  //
+  // Program Pad Configuration Lock Tx
+  //
+  if ((GpioData->LockConfig & GpioOutputStateLock) == GpioOutputStateLock) {
+    GpioLockPadsUsingSbi (
+                 GpioPadLockOutputRegister,
+                 FALSE,
+                 0,
+                 0,
+                 0,
+                 GpioPad,
+                 TRUE
+                 );
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will set GPIO output level
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] Value                Output value
+                                  0: OutputLow, 1: OutputHigh
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetOutputValue (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    Value
+  )
+{
+  EFI_STATUS Status;
+
+  Status = GpioReadWritePadCfgReg (
+            GpioPad,
+            0,
+            B_PCH_GPIO_TX_STATE,
+            TRUE,
+            &Value
+            );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will get GPIO output level
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] OutputVal           GPIO Output value
+                                  0: OutputLow, 1: OutputHigh
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetOutputValue (
+  IN GPIO_PAD                  GpioPad,
+  OUT UINT32                   *OutputVal
+  )
+{
+  EFI_STATUS Status;
+
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_TX_STATE,
+             FALSE,
+             OutputVal
+             );
+  ASSERT_EFI_ERROR (Status);
+  *OutputVal >>= N_PCH_GPIO_TX_STATE;
+
+  return Status;
+}
+
+/**
+  This procedure will get GPIO input level
+
+  @param[in] GpioPad              GPIO pad
+  @param[out] InputVal            GPIO Input value
+                                  0: InputLow, 1: InpuHigh
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetInputValue (
+  IN GPIO_PAD                  GpioPad,
+  OUT UINT32                   *InputVal
+  )
+{
+  EFI_STATUS Status;
+
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_RX_STATE,
+             FALSE,
+             InputVal
+             );
+  ASSERT_EFI_ERROR (Status);
+  *InputVal >>= N_PCH_GPIO_RX_STATE;
+
+  return Status;
+}
+
+/**
+  This procedure will get GPIO IOxAPIC interrupt number
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] IrqNum              IRQ number
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadIoApicIrqNumber (
+  IN GPIO_PAD                  GpioPad,
+  OUT UINT32                   *IrqNum
+  )
+{
+  EFI_STATUS Status;
+
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             1,
+             B_PCH_GPIO_INTSEL,
+             FALSE,
+             IrqNum
+             );
+  ASSERT_EFI_ERROR (Status);
+  *IrqNum >>= N_PCH_GPIO_INTSEL;
+
+  return Status;
+}
+
+/**
+  This procedure will configure GPIO input inversion
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] Value                Value for GPIO input inversion
+                                  0: No input inversion, 1: Invert input
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetInputInversion (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    Value
+  )
+{
+  EFI_STATUS Status;
+
+  Value <<= N_PCH_GPIO_RXINV;
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_RXINV,
+             TRUE,
+             &Value
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will get GPIO pad input inversion value
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] InvertState         GPIO inversion state
+                                  0: No input inversion, 1: Inverted input
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetInputInversion (
+  IN  GPIO_PAD                 GpioPad,
+  OUT UINT32                   *InvertState
+  )
+{
+  EFI_STATUS Status;
+
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_RXINV,
+             FALSE,
+             InvertState
+             );
+  ASSERT_EFI_ERROR (Status);
+  *InvertState >>= N_PCH_GPIO_RXINV;
+
+  return Status;
+}
+
+/**
+  This procedure will set GPIO interrupt settings
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] Value                Value of Level/Edge
+                                  use GPIO_INT_CONFIG as argument
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadInterruptConfig (
+  IN GPIO_PAD                 GpioPad,
+  IN GPIO_INT_CONFIG          Value
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      RxLvlEdgeValue;
+  UINT32      IntRouteValue;
+  UINT32      GpeEnable;
+
+  Status = EFI_SUCCESS;
+
+  if (((Value & GPIO_CONF_INT_TRIG_MASK) >> GPIO_CONF_INT_TRIG_BIT_POS) != GpioHardwareDefault) {
+    RxLvlEdgeValue = ((Value & GPIO_CONF_INT_TRIG_MASK) >> (GPIO_CONF_INT_TRIG_BIT_POS + 1)) << N_PCH_GPIO_RX_LVL_EDG;
+
+    Status = GpioReadWritePadCfgReg (
+               GpioPad,
+               0,
+               B_PCH_GPIO_RX_LVL_EDG,
+               TRUE,
+               &RxLvlEdgeValue
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (((Value & GPIO_CONF_INT_ROUTE_MASK) >> GPIO_CONF_INT_ROUTE_BIT_POS) != GpioHardwareDefault) {
+
+    IntRouteValue = ((Value & GPIO_CONF_INT_ROUTE_MASK) >> (GPIO_CONF_INT_ROUTE_BIT_POS + 1)) << N_PCH_GPIO_RX_NMI_ROUTE;
+
+    Status = GpioReadWritePadCfgReg (
+               GpioPad,
+               0,
+               (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE),
+               TRUE,
+               &IntRouteValue
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    if ((Value & GpioIntSci) == GpioIntSci) {
+      GpeEnable = 0x1;
+    } else {
+      GpeEnable = 0x0;
+    }
+
+    Status = GpioReadWriteReg (
+               GpioGpeEnableRegister,
+               0,
+               0,
+               GpioPad,
+               TRUE,
+               TRUE,
+               &GpeEnable
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return Status;
+}
+
+/**
+  This procedure will set GPIO electrical settings
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] Value                Value of termination
+                                  use GPIO_ELECTRICAL_CONFIG as argument
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadElectricalConfig (
+  IN GPIO_PAD                  GpioPad,
+  IN GPIO_ELECTRICAL_CONFIG    Value
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      TermValue;
+  UINT32      PadTolValue;
+
+  Status = EFI_SUCCESS;
+
+  if (((Value & GPIO_CONF_TERM_MASK) >> GPIO_CONF_TERM_BIT_POS) != GpioHardwareDefault) {
+    TermValue = ((Value & GPIO_CONF_TERM_MASK) >> (GPIO_CONF_TERM_BIT_POS + 1)) << N_PCH_GPIO_TERM;
+
+    Status = GpioReadWritePadCfgReg (
+               GpioPad,
+               1,
+               B_PCH_GPIO_TERM,
+               TRUE,
+               &TermValue
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (((Value & GPIO_CONF_PADTOL_MASK) >> GPIO_CONF_PADTOL_BIT_POS) != GpioHardwareDefault) {
+    PadTolValue = ((Value & GPIO_CONF_PADTOL_MASK) >> (GPIO_CONF_PADTOL_BIT_POS + 1)) << N_PCH_GPIO_PADTOL;
+
+    Status = GpioReadWritePadCfgReg (
+               GpioPad,
+               1,
+               B_PCH_GPIO_PADTOL,
+               TRUE,
+               &PadTolValue
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+  return Status;
+}
+
+/**
+  This procedure will set GPIO Reset settings
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] Value                Value for Pad Reset Configuration
+                                  use GPIO_RESET_CONFIG as argument
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadResetConfig (
+  IN GPIO_PAD                  GpioPad,
+  IN GPIO_RESET_CONFIG         Value
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      ResetValue;
+
+  Status = EFI_SUCCESS;
+
+  if (((Value & GPIO_CONF_RESET_MASK) >> GPIO_CONF_RESET_BIT_POS) != GpioHardwareDefault) {
+    ResetValue = ((Value & GPIO_CONF_RESET_MASK) >> (GPIO_CONF_RESET_BIT_POS + 1)) << N_PCH_GPIO_RST_CONF;
+
+    Status = GpioReadWritePadCfgReg (
+               GpioPad,
+               0,
+               B_PCH_GPIO_RST_CONF,
+               TRUE,
+               &ResetValue
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+  return Status;
+}
+
+/**
+  This procedure will get GPIO Reset settings
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] Value                Value of Pad Reset Configuration
+                                  based on GPIO_RESET_CONFIG
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadResetConfig (
+  IN GPIO_PAD                  GpioPad,
+  IN GPIO_RESET_CONFIG         *Value
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      ResetValue;
+
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_RST_CONF,
+             FALSE,
+             &ResetValue
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Get Reset Type (PadRstCfg)
+  //
+  *Value = (ResetValue >> (N_PCH_GPIO_RST_CONF - (GPIO_CONF_RESET_BIT_POS + 1))) | (0x1 << GPIO_CONF_RESET_BIT_POS);
+
+  return Status;
+}
+
+/**
+  This procedure will get GPIO Host Software Pad Ownership for certain group
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               Host Ownership register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[out] HostSwRegVal        Value of Host Software Pad Ownership register
+                                  Bit position - PadNumber
+                                  Bit value - 0: ACPI Mode, 1: GPIO Driver mode
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioGetHostSwOwnershipForGroupDw (
+  IN  GPIO_GROUP                  Group,
+  IN  UINT32                      DwNum,
+  OUT UINT32                      *HostSwRegVal
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioHostOwnershipRegister,
+             Group,
+             DwNum,
+             0,
+             FALSE,
+             FALSE,
+             HostSwRegVal
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will get GPIO Host Software Pad Ownership for certain group
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               Host Ownership register number for current group
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in]  HostSwRegVal        Value of Host Software Pad Ownership register
+                                  Bit position - PadNumber
+                                  Bit value - 0: ACPI Mode, 1: GPIO Driver mode
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioSetHostSwOwnershipForGroupDw (
+  IN GPIO_GROUP                   Group,
+  IN UINT32                       DwNum,
+  IN UINT32                       HostSwRegVal
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioHostOwnershipRegister,
+             Group,
+             DwNum,
+             0,
+             TRUE,
+             FALSE,
+             &HostSwRegVal
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will get Gpio Pad Host Software Ownership
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] PadHostSwOwn        Value of Host Software Pad Owner
+                                  0: ACPI Mode, 1: GPIO Driver mode
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetHostSwOwnershipForPad (
+  IN GPIO_PAD                 GpioPad,
+  OUT UINT32                  *PadHostSwOwn
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioHostOwnershipRegister,
+             0,
+             0,
+             GpioPad,
+             FALSE,
+             TRUE,
+             PadHostSwOwn
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set Gpio Pad Host Software Ownership
+
+  @param[in] GpioPad              GPIO pad
+  @param[in] PadHostSwOwn         Pad Host Software Owner
+                                  0: ACPI Mode, 1: GPIO Driver mode
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetHostSwOwnershipForPad (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    PadHostSwOwn
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioHostOwnershipRegister,
+             0,
+             0,
+             GpioPad,
+             TRUE,
+             TRUE,
+             &PadHostSwOwn
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will get Gpio Pad Ownership
+
+  @param[in] GpioPad              GPIO pad
+  @param[out] PadOwnVal           Value of Pad Ownership
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadOwnership (
+  IN  GPIO_PAD                GpioPad,
+  OUT GPIO_PAD_OWN            *PadOwnVal
+  )
+{
+  UINT32               Mask;
+  UINT32               RegOffset;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  UINT32               PadOwnRegValue;
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    ASSERT(FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pin number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    ASSERT(FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Calculate RegOffset using Pad Ownership offset and GPIO Pad number.
+  // One DWord register contains information for 8 pads.
+  //
+  RegOffset = GpioGroupInfo[GroupIndex].PadOwnOffset + (PadNumber >> 3) * 0x4;
+
+  //
+  // Calculate pad bit position within DWord register
+  //
+  PadNumber %= 8;
+  Mask = (BIT1 | BIT0) << (PadNumber * 4);
+
+  PadOwnRegValue = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
+
+  *PadOwnVal = (GPIO_PAD_OWN)((PadOwnRegValue & Mask) >> (PadNumber * 4));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will check state of Pad Config Lock for pads within one group
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               PadCfgLock register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[out] PadCfgLockRegVal    Value of PadCfgLock register
+                                  Bit position - PadNumber
+                                  Bit value - 0: NotLocked, 1: Locked
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioGetPadCfgLockForGroupDw (
+  IN  GPIO_GROUP                  Group,
+  IN  UINT32                      DwNum,
+  OUT UINT32                      *PadCfgLockRegVal
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioPadConfigLockRegister,
+             Group,
+             DwNum,
+             0,
+             FALSE,
+             FALSE,
+             PadCfgLockRegVal
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will check state of Pad Config Lock for selected pad
+
+  @param[in] GpioPad              GPIO pad
+  @param[out] PadCfgLock          PadCfgLock for selected pad
+                                  0: NotLocked, 1: Locked
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadCfgLock (
+  IN GPIO_PAD                   GpioPad,
+  OUT UINT32                    *PadCfgLock
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioPadConfigLockRegister,
+             0,
+             0,
+             GpioPad,
+             FALSE,
+             TRUE,
+             PadCfgLock
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will check state of Pad Config Tx Lock for pads within one group
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               PadCfgLockTx register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[out] PadCfgLockTxRegVal  Value of PadCfgLockTx register
+                                  Bit position - PadNumber
+                                  Bit value - 0: NotLockedTx, 1: LockedTx
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioGetPadCfgLockTxForGroupDw (
+  IN  GPIO_GROUP                  Group,
+  IN  UINT32                      DwNum,
+  OUT UINT32                      *PadCfgLockTxRegVal
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioPadLockOutputRegister,
+             Group,
+             DwNum,
+             0,
+             FALSE,
+             FALSE,
+             PadCfgLockTxRegVal
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will check state of Pad Config Tx Lock for selected pad
+
+  @param[in] GpioPad              GPIO pad
+  @param[out] PadCfgLock          PadCfgLockTx for selected pad
+                                  0: NotLockedTx, 1: LockedTx
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadCfgLockTx (
+  IN GPIO_PAD                   GpioPad,
+  OUT UINT32                    *PadCfgLockTx
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GpioReadWriteReg (
+             GpioPadLockOutputRegister,
+             0,
+             0,
+             GpioPad,
+             FALSE,
+             TRUE,
+             PadCfgLockTx
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will clear PadCfgLock for selected pads within one group.
+  This function should be used only inside SMI.
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               PadCfgLock register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in]  PadsToUnlock        Bitmask for pads which are going to be unlocked,
+                                  Bit position - PadNumber
+                                  Bit value - 0: DoNotUnlock, 1: Unlock
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfgForGroupDw (
+  IN GPIO_GROUP                Group,
+  IN UINT32                    DwNum,
+  IN UINT32                    PadsToUnlock
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadConfigLockRegister,
+             TRUE,
+             Group,
+             DwNum,
+             PadsToUnlock,
+             0,
+             FALSE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will clear PadCfgLock for selected pad.
+  This function should be used only inside SMI.
+
+  @param[in] GpioPad              GPIO pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfg (
+    IN GPIO_PAD                   GpioPad
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadConfigLockRegister,
+             TRUE,
+             0,
+             0,
+             0,
+             GpioPad,
+             TRUE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set PadCfgLock for selected pads within one group
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               PadCfgLock register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in]  PadsToLock          Bitmask for pads which are going to be locked
+                                  Bit position - PadNumber
+                                  Bit value - 0: DoNotLock, 1: Lock
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioLockPadCfgForGroupDw (
+  IN GPIO_GROUP                   Group,
+  IN UINT32                       DwNum,
+  IN UINT32                       PadsToLock
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadConfigLockRegister,
+             FALSE,
+             Group,
+             DwNum,
+             PadsToLock,
+             0,
+             FALSE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set PadCfgLock for selected pad
+
+  @param[in] GpioPad              GPIO pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioLockPadCfg (
+  IN GPIO_PAD                   GpioPad
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadConfigLockRegister,
+             FALSE,
+             0,
+             0,
+             0,
+             GpioPad,
+             TRUE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will clear PadCfgLockTx for selected pads within one group.
+  This function should be used only inside SMI.
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               PadCfgLockTx register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in]  PadsToUnlockTx      Bitmask for pads which are going to be unlocked,
+                                  Bit position - PadNumber
+                                  Bit value - 0: DoNotUnLockTx, 1: LockTx
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfgTxForGroupDw (
+  IN GPIO_GROUP                Group,
+  IN UINT32                    DwNum,
+  IN UINT32                    PadsToUnlockTx
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadLockOutputRegister,
+             TRUE,
+             Group,
+             DwNum,
+             PadsToUnlockTx,
+             0,
+             FALSE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will clear PadCfgLockTx for selected pad.
+  This function should be used only inside SMI.
+
+  @param[in] GpioPad              GPIO pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfgTx (
+  IN GPIO_PAD                   GpioPad
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadLockOutputRegister,
+             TRUE,
+             0,
+             0,
+             0,
+             GpioPad,
+             TRUE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set PadCfgLockTx for selected pads within one group
+
+  @param[in]  Group               GPIO group
+  @param[in]  DwNum               PadCfgLock register number for current group.
+                                  For group which has less then 32 pads per group DwNum must be 0.
+  @param[in]  PadsToLockTx        Bitmask for pads which are going to be locked,
+                                  Bit position - PadNumber
+                                  Bit value - 0: DoNotLockTx, 1: LockTx
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioLockPadCfgTxForGroupDw (
+  IN GPIO_GROUP                   Group,
+  IN UINT32                       DwNum,
+  IN UINT32                       PadsToLockTx
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadLockOutputRegister,
+             FALSE,
+             Group,
+             DwNum,
+             PadsToLockTx,
+             0,
+             FALSE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set PadCfgLockTx for selected pad
+
+  @param[in] GpioPad              GPIO pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioLockPadCfgTx (
+  IN GPIO_PAD                   GpioPad
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = GpioLockPadsUsingSbi (
+             GpioPadLockOutputRegister,
+             FALSE,
+             0,
+             0,
+             0,
+             GpioPad,
+             TRUE
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+
+/**
+  This procedure will get Group to GPE mapping.
+
+  @param[out] GroupToGpeDw0       GPIO group to be mapped to GPE_DW0
+  @param[out] GroupToGpeDw1       GPIO group to be mapped to GPE_DW1
+  @param[out] GroupToGpeDw2       GPIO group to be mapped to GPE_DW2
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGroupToGpeDwX (
+  IN GPIO_GROUP               *GroupToGpeDw0,
+  IN GPIO_GROUP               *GroupToGpeDw1,
+  IN GPIO_GROUP               *GroupToGpeDw2
+  )
+{
+  UINT32               Data32;
+  UINT32               PchPwrmBase;
+  GPIO_GROUP           GpioGroupOffset;
+
+  GpioGroupOffset = GpioGetLowestGroup ();
+
+
+  PchPwrmBaseGet (&PchPwrmBase);
+
+  Data32 = MmioRead32 ((UINTN) (PchPwrmBase + R_PCH_PWRM_GPIO_CFG));
+
+  *GroupToGpeDw0 = ((Data32 & B_PCH_PWRM_GPIO_CFG_GPE0_DW0) >> N_PCH_PWRM_GPIO_CFG_GPE0_DW0) + GpioGroupOffset;
+  *GroupToGpeDw1 = ((Data32 & B_PCH_PWRM_GPIO_CFG_GPE0_DW1) >> N_PCH_PWRM_GPIO_CFG_GPE0_DW1) + GpioGroupOffset;
+  *GroupToGpeDw2 = ((Data32 & B_PCH_PWRM_GPIO_CFG_GPE0_DW2) >> N_PCH_PWRM_GPIO_CFG_GPE0_DW2) + GpioGroupOffset;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will set Group to GPE mapping.
+
+  @param[in]  GroupToGpeDw0       GPIO group to be mapped to GPE_DW0
+  @param[in]  GroupToGpeDw1       GPIO group to be mapped to GPE_DW1
+  @param[in]  GroupToGpeDw2       GPIO group to be mapped to GPE_DW2
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGroupToGpeDwX (
+  IN GPIO_GROUP                GroupToGpeDw0,
+  IN GPIO_GROUP                GroupToGpeDw1,
+  IN GPIO_GROUP                GroupToGpeDw2
+  )
+{
+  UINT32               Data32Or;
+  UINT32               Data32And;
+  UINT32               PchPwrmBase;
+  GPIO_GROUP           GpioGroupLowest;
+  GPIO_GROUP           GpioGroupHighest;
+
+  GpioGroupLowest = GpioGetLowestGroup ();
+  GpioGroupHighest = GpioGetHighestGroup ();
+
+  //
+  // Check if group argument exceeds GPIO group range
+  //
+  if (((UINT32)GroupToGpeDw0 < GpioGroupLowest) || ((UINT32)GroupToGpeDw0 > GpioGroupHighest) ||
+    ((UINT32)GroupToGpeDw1 < GpioGroupLowest) || ((UINT32)GroupToGpeDw1 > GpioGroupHighest) ||
+    ((UINT32)GroupToGpeDw2 < GpioGroupLowest) || ((UINT32)GroupToGpeDw2 > GpioGroupHighest)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument exceeds GPIO group range\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if each group number is unique
+  //
+  if ((GroupToGpeDw0 == GroupToGpeDw1) ||
+    (GroupToGpeDw0 == GroupToGpeDw2) ||
+    (GroupToGpeDw1 == GroupToGpeDw2)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Values in GPE0_DWx registers are 0 based (GPP_A = 0h)
+  //
+  GroupToGpeDw0 = GpioGetGroupIndexFromGroup(GroupToGpeDw0);
+  GroupToGpeDw1 = GpioGetGroupIndexFromGroup(GroupToGpeDw1);
+  GroupToGpeDw2 = GpioGetGroupIndexFromGroup(GroupToGpeDw2);
+
+  PchPwrmBaseGet (&PchPwrmBase);
+
+  //
+  // Program GPIO_CFG (PMRMBASE + 120h) register
+  //
+  Data32And = (UINT32) ~(B_PCH_PWRM_GPIO_CFG_GPE0_DW2 | B_PCH_PWRM_GPIO_CFG_GPE0_DW1 | B_PCH_PWRM_GPIO_CFG_GPE0_DW0);
+  Data32Or  = (UINT32)((GroupToGpeDw2 << N_PCH_PWRM_GPIO_CFG_GPE0_DW2) |
+              (GroupToGpeDw1 << N_PCH_PWRM_GPIO_CFG_GPE0_DW1) |
+              (GroupToGpeDw0 << N_PCH_PWRM_GPIO_CFG_GPE0_DW0));
+
+  MmioAndThenOr32 (
+    (UINTN) (PchPwrmBase + R_PCH_PWRM_GPIO_CFG),
+    Data32And,
+    Data32Or
+    );
+
+  Data32And = (UINT32) ~(B_PCH_PCR_GPIO_MISCCFG_GPE0_DW2 | B_PCH_PCR_GPIO_MISCCFG_GPE0_DW1 | B_PCH_PCR_GPIO_MISCCFG_GPE0_DW0);
+  Data32Or = (UINT32)((GroupToGpeDw2 << N_PCH_PCR_GPIO_MISCCFG_GPE0_DW2) |
+             (GroupToGpeDw1 << N_PCH_PCR_GPIO_MISCCFG_GPE0_DW1) |
+             (GroupToGpeDw0 << N_PCH_PCR_GPIO_MISCCFG_GPE0_DW0));
+  //
+  // Program MISCCFG register for Community 0
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM0, R_PCH_PCR_GPIO_MISCCFG),
+    Data32And,
+    Data32Or
+    );
+
+  //
+  // Program MISCCFG register for Community 1
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM1, R_PCH_PCR_GPIO_MISCCFG),
+    Data32And,
+    Data32Or
+    );
+
+  //
+  // Program MISCCFG register for Community 2
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM2, R_PCH_PCR_GPIO_MISCCFG),
+    Data32And,
+    Data32Or
+    );
+
+  //
+  // Program MISCCFG register for Community 3
+  //
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM3, R_PCH_PCR_GPIO_MISCCFG),
+    Data32And,
+    Data32Or
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will get GPE number for provided GpioPad.
+  PCH allows to configure mapping between GPIO groups and related GPE (GpioSetGroupToGpeDwX())
+  what results in the fact that certain Pad can cause different General Purpose Event. Only three
+  GPIO groups can be mapped to cause unique GPE (1-tier), all others groups will be under one common
+  event (GPE_111 for 2-tier).
+
+  1-tier:
+  Returned GpeNumber is in range <0,95>. GpioGetGpeNumber() can be used
+  to determine what _LXX ACPI method would be called on event on selected GPIO pad
+
+  2-tier:
+  Returned GpeNumber is 0x6F (111). All GPIO pads which are not mapped to 1-tier GPE
+  will be under one master GPE_111 which is linked to _L6F ACPI method. If it is needed to determine
+  what Pad from 2-tier has caused the event, _L6F method should check GPI_GPE_STS and GPI_GPE_EN
+  registers for all GPIO groups not mapped to 1-tier GPE.
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] GpeNumber           GPE number
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGpeNumber (
+  IN  GPIO_PAD                  GpioPad,
+  OUT UINT32                    *GpeNumber
+  )
+{
+  GPIO_GROUP           GroupToGpeDw0;
+  GPIO_GROUP           GroupToGpeDw1;
+  GPIO_GROUP           GroupToGpeDw2;
+  GPIO_GROUP           GpioGroupLowest;
+  GPIO_GROUP           GpioGroupHighest;
+  UINT32               GroupIndex;
+  GPIO_GROUP           Group;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  Group = GpioGetGroupFromGpioPad (GpioPad);
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  GpioGroupLowest = GpioGetLowestGroup ();
+  GpioGroupHighest = GpioGetHighestGroup ();
+
+  //
+  // Check if group argument exceeds GPIO group range
+  //
+  if ((GroupIndex < GpioGetGroupIndexFromGroup (GpioGroupLowest)) || (GroupIndex > GpioGetGroupIndexFromGroup (GpioGroupHighest))) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pad number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Get GPIO groups mapping to 1-tier GPE
+  //
+  GpioGetGroupToGpeDwX (&GroupToGpeDw0,&GroupToGpeDw1,&GroupToGpeDw2);
+
+  if (Group == GroupToGpeDw0) {
+    *GpeNumber = PadNumber;
+  } else if (Group== GroupToGpeDw1) {
+    *GpeNumber = PadNumber + 32;
+  } else if (Group == GroupToGpeDw2) {
+    *GpeNumber = PadNumber + 64;
+  } else {
+    //
+    // If Group number doesn't match any of above then
+    // it means than certain pad is routed to 2-tier GPE
+    // which all are under GPE_111 (0x6F)
+    //
+    *GpeNumber = PCH_GPIO_2_TIER_MASTER_GPE_NUMBER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure is used to clear SMI STS for a specified Pad
+
+  @param[in]  GpioPad             GPIO pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioClearGpiSmiSts (
+  IN GPIO_PAD                   GpioPad
+  )
+{
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pad number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if group has GPI SMI register
+  //
+  if (GpioGroupInfo[GroupIndex].SmiStsOffset == NO_REGISTER_FOR_PROPERTY) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Clear all GPI SMI Status bits by writing '1'
+  //
+  MmioWrite32 (
+    PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiStsOffset),
+    (UINT32)(BIT0 << PadNumber)
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure is used by PchSmiDispatcher and will clear
+  all GPI SMI Status bits
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioClearAllGpiSmiSts (
+  VOID
+  )
+{
+  UINT32               GroupIndex;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) {
+    //
+    // Check if group has GPI SMI register
+    //
+    if (GpioGroupInfo[GroupIndex].SmiStsOffset == NO_REGISTER_FOR_PROPERTY) {
+      continue;
+    }
+    //
+    // Clear all GPI SMI Status bits by writing '1'
+    //
+    MmioWrite32 (
+      PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiStsOffset),
+      (UINT32)0xFFFFFFFF
+      );
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure is used to disable all GPI SMI
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioDisableAllGpiSmi (
+  VOID
+  )
+{
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINT32               GroupIndex;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) {
+    //
+    // Check if group has GPI SMI register
+    //
+    if (GpioGroupInfo[GroupIndex].SmiEnOffset == NO_REGISTER_FOR_PROPERTY) {
+      continue;
+    }
+
+    //
+    // Disable all GPI SMI
+    //
+    MmioWrite32 (
+      PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiEnOffset),
+      (UINT32)0x0
+      );
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure is used to register GPI SMI dispatch function.
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] GpiNum              GPI number
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGpiSmiNum (
+  IN GPIO_PAD          GpioPad,
+  OUT UINTN            *GpiNum
+  )
+{
+  UINT32               GroupIndex;
+  UINT32               Index;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pad number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *GpiNum = 0;
+
+  for (Index = 0; Index < (UINT32)GroupIndex; Index++) {
+    *GpiNum += (UINTN)(GpioGroupInfo[Index].PadPerGroup);
+  }
+  *GpiNum += (UINTN)PadNumber;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure is used to check GPIO inputs belongs to 2 tier or 1 tier architecture
+
+  @param[in]  GpioPad             GPIO pad
+
+  @retval     Data                0 means 1-tier, 1 means 2-tier
+**/
+BOOLEAN
+GpioCheckFor2Tier (
+  IN GPIO_PAD                  GpioPad
+  )
+{
+  UINT32               Data32;
+
+  GpioGetGpeNumber (GpioPad, &Data32);
+  if(Data32 == PCH_GPIO_2_TIER_MASTER_GPE_NUMBER) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  This procedure is used to clear GPE STS for a specified GpioPad
+
+  @param[in]  GpioPad             GPIO pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioClearGpiGpeSts (
+  IN GPIO_PAD                  GpioPad
+  )
+{
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pad number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if group has GPI GPE register
+  //
+  if (GpioGroupInfo[GroupIndex].GpiGpeStsOffset == NO_REGISTER_FOR_PROPERTY) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check for 2-tier
+  if(!(GpioCheckFor2Tier (GpioPad))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Clear all GPI SMI Status bits by writing '1'
+  //
+  MmioWrite32 (
+    PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeStsOffset),
+    (UINT32)(BIT0 << PadNumber)
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure is used to read GPE STS for a specified Pad
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] Data                GPE STS data
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGpiGpeSts (
+  IN GPIO_PAD                  GpioPad,
+  OUT UINT32*                  Data
+  )
+{
+  UINT32               Data32;
+  UINT32               Mask;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  *Data = 0xFFFFFFFF;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if legal pad number
+  //
+  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check if group has GPI GPE register
+  //
+  if (GpioGroupInfo[GroupIndex].GpiGpeStsOffset == NO_REGISTER_FOR_PROPERTY) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check for 2-tier
+  if(!(GpioCheckFor2Tier (GpioPad))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Read GPI GPE Status bits
+  //
+  Data32 = MmioRead32(
+    PCH_PCR_ADDRESS(GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeStsOffset)
+    );
+
+  Mask = (UINT32)(BIT0 << PadNumber);
+  Data32 = (Data32 & Mask) >> PadNumber;
+  *Data = Data32;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will set GPIO Input Rout SCI
+
+  @param[in] GpioPad             GPIO pad
+  @param[in] Value                Value for GPIRoutSCI
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiRoutSci (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    Value
+  )
+{
+  EFI_STATUS           Status;
+
+  Value <<= N_PCH_GPIO_RX_SCI_ROUTE;
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_RX_SCI_ROUTE,
+             TRUE,
+             &Value
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set GPIO Input Rout SMI
+
+  @param[in] GpioPad             GPIO pad
+  @param[in] Value                Value for GPIRoutSMI
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiRoutSmi (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    Value
+  )
+{
+  EFI_STATUS  Status;
+
+  Value <<= N_PCH_GPIO_RX_SMI_ROUTE;
+  Status = GpioReadWritePadCfgReg (
+             GpioPad,
+             0,
+             B_PCH_GPIO_RX_SMI_ROUTE,
+             TRUE,
+             &Value
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set GPI SMI Enable setting for selected pad
+
+  @param[in]  GpioPad               GPIO pad
+  @param[in]  PadGpiSmiEn         GPI SMI Enable setting for selected pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiSmiPadEn (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    PadGpiSmiEn
+  )
+{
+  GPIO_GROUP           Group;
+  GPIO_GROUP           GpioGroupOffset;
+  UINT32               NumberOfGroups;
+  EFI_STATUS  Status;
+
+  GpioGroupOffset = GpioGetLowestGroup ();
+  NumberOfGroups = GpioGetNumberOfGroups ();
+
+  Group = GpioGetGroupFromGpioPad (GpioPad);
+
+  //
+  // Check if group argument exceeds GPIO group range
+  //
+  if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GpioReadWriteReg (
+             GpioSmiEnableRegister,
+             Group,
+             0,
+             GpioPad,
+             TRUE,
+             TRUE,
+             &PadGpiSmiEn
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  This procedure will set GPI General Purpose Event Enable setting for selected pad
+
+  @param[in]  GpioPad               GPIO pad
+  @param[in]  PadGpiGpeEn         GPI General Purpose Event Enable setting for selected pad
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiGpePadEn (
+  IN GPIO_PAD                  GpioPad,
+  IN UINT32                    PadGpiGpeEn
+  )
+{
+  GPIO_GROUP           Group;
+  GPIO_GROUP           GpioGroupOffset;
+  UINT32               NumberOfGroups;
+  EFI_STATUS           Status;
+
+  GpioGroupOffset = GpioGetLowestGroup ();
+  NumberOfGroups = GpioGetNumberOfGroups ();
+
+  Group = GpioGetGroupFromGpioPad (GpioPad);
+
+  //
+  // Check if group argument exceeds GPIO group range
+  //
+  if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+
+  Status = GpioReadWriteReg (
+             GpioGpeEnableRegister,
+             Group,
+             0,
+             GpioPad,
+             TRUE,
+             TRUE,
+             &PadGpiGpeEn
+             );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  Check if given GPIO Pad is locked
+
+  @param[in]  GroupIndex                GPIO group index
+  @param[in]  PadNumber                 GPIO pad number
+
+  @retval TRUE                          Pad is locked
+  @retval FALSE                         Pad is not locked
+**/
+BOOLEAN
+GpioIsPadLocked (
+  IN  UINT32                 GroupIndex,
+  IN  GPIO_PAD               PadNumber
+  )
+{
+  UINT32               RegVal;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  // Read PADCFGLOCK register
+  //
+  RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].PadCfgLockOffset));
+
+  return (((RegVal >> PadNumber) & 0x1) == 1);
+}
+
+/**
+  Locks multiple GPIO pads using GPIO_INIT_CONFIG array.
+  Only locking is applied and no other GPIO pad configuration is changed.
+
+  @param[in] NumberOfItems              Number of GPIO pads to be locked
+  @param[in] GpioInitTableAddress       GPIO initialization table
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_INVALID_PARAMETER         Invalid group or pad number
+  @retval EFI_UNSUPPORTED               Incorrect GPIO pad definition
+**/
+static
+EFI_STATUS
+GpioLockPads (
+  IN UINT32                    NumberOfItems,
+  IN GPIO_INIT_CONFIG          *GpioInitTableAddress
+  )
+{
+  UINT32               Index;
+  UINT32               PadsToLock[V_PCH_GPIO_GROUP_MAX];
+  UINT32               PadsToLockTx[V_PCH_GPIO_GROUP_MAX];
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  GPIO_GROUP           GpioGroupOffset;
+  UINT32               NumberOfGroups;
+  GPIO_PAD_OWN         PadOwnVal;
+  GPIO_INIT_CONFIG     *GpioData;
+  GPIO_GROUP           Group;
+  UINT32               GroupIndex;
+  UINT32               PadNumber;
+  PCH_SERIES           PchSeries;
+
+  PchSeries = GetPchSeries ();
+  PadOwnVal = GpioPadOwnHost;
+
+  ZeroMem (PadsToLock, sizeof (PadsToLock));
+  ZeroMem (PadsToLockTx, sizeof (PadsToLockTx));
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GpioGroupOffset = GpioGetLowestGroup ();
+  NumberOfGroups = GpioGetNumberOfGroups ();
+
+  for (Index = 0; Index < NumberOfItems; Index ++) {
+
+    GpioData   = &GpioInitTableAddress[Index];
+
+    Group      = GpioGetGroupFromGpioPad (GpioData->GpioPad);
+    GroupIndex = GpioGetGroupIndexFromGpioPad (GpioData->GpioPad);
+    PadNumber  = GpioGetPadNumberFromGpioPad (GpioData->GpioPad);
+
+    //
+    // Checking GroupIndex to avoid Buffer Overflows or Array Out of Index
+    //
+    if (GroupIndex >= V_PCH_GPIO_GROUP_MAX) {
+      ASSERT (FALSE);
+      continue;
+    }
+
+    //
+    // Check if group argument exceeds GPIO group range
+    //
+    if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Check if legal pin number
+    //
+    if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Check if selected GPIO Pad is not owned by CSME/ISH
+    //
+    GpioGetPadOwnership (GpioData->GpioPad, &PadOwnVal);
+
+    if (PadOwnVal != GpioPadOwnHost) {
+      continue;
+    }
+
+    //
+    // Update information on Pad Configuration Lock
+    //
+    PadsToLock[GroupIndex] |= ((GpioData->GpioConfig.LockConfig >> 0x1) & 0x1) << PadNumber;
+
+    //
+    // Update information on Pad Configuration Lock Tx
+    //
+    PadsToLockTx[GroupIndex] |= ((GpioData->GpioConfig.LockConfig >> 0x2) & 0x1) << PadNumber;
+  }
+
+  for (Index = 0; Index < NumberOfGroups; Index++) {
+    //
+    // Write Pad Configuration Lock
+    //
+    if (PadsToLock[Index] != 0) {
+      GpioLockPadCfgForGroupDw (Index + GpioGroupOffset, 0, PadsToLock[Index]);
+    }
+
+    //
+    // Write Pad Configuration Lock Tx
+    //
+    if (PadsToLockTx[Index] != 0) {
+      GpioLockPadCfgTxForGroupDw (Index + GpioGroupOffset, 0, PadsToLockTx[Index]);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Locks GPIO pads according to GPIO_INIT_CONFIG array from
+  gPlatformGpioConfigGuid HOB. Only locking is applied and no other GPIO pad
+  configuration is changed.
+
+  @retval EFI_SUCCESS                   The function completed successfully
+  @retval EFI_NOT_FOUND                 gPlatformGpioConfigGuid not found
+**/
+EFI_STATUS
+GpioLockGpios (
+  VOID
+  )
+{
+  EFI_HOB_GUID_TYPE *GpioConfigHob;
+  GPIO_INIT_CONFIG  *GpioConfig;
+  UINT16            GpioConfigSize;
+
+  GpioConfigHob = GetFirstGuidHob (&gPlatformGpioConfigGuid);
+  if (GpioConfigHob == NULL) {
+    return EFI_NOT_FOUND;
+  }
+  ASSERT (GET_GUID_HOB_DATA_SIZE (GpioConfigHob) % sizeof (GpioConfig[0]) == 0);
+  GpioConfigSize = GET_GUID_HOB_DATA_SIZE (GpioConfigHob) / sizeof (GpioConfig[0]);
+  GpioConfig = GET_GUID_HOB_DATA (GpioConfigHob);
+  GpioLockPads (GpioConfigSize, GpioConfig);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unlocks all PCH GPIO pads
+
+  @retval None
+**/
+VOID
+GpioUnlockAllGpios (
+  VOID
+  )
+{
+  GPIO_GROUP           GpioGroupOffset;
+  UINT32               NumberOfGroups;
+  UINT32               Index;
+
+  GpioGroupOffset = GpioGetLowestGroup ();
+  NumberOfGroups = GpioGetNumberOfGroups ();
+
+  for (Index = 0; Index < NumberOfGroups; Index++) {
+    //
+    // Reset Pad Configuration Lock
+    //
+    GpioUnlockPadCfgForGroupDw (Index + GpioGroupOffset, 0, 0xFFFFFFFF);
+
+    //
+    // Reset Pad Configuration Lock Tx
+    //
+    GpioUnlockPadCfgTxForGroupDw (Index + GpioGroupOffset, 0, 0xFFFFFFFF);
+  }
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h
new file mode 100644
index 0000000000..6cb918fd38
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h
@@ -0,0 +1,216 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GPIO_LIBRARY_H_
+#define _GPIO_LIBRARY_H_
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <PchAccess.h>
+#include <Library/PchPcrLib.h>
+#include <GpioPinsSklH.h>
+#include <Library/GpioLib.h>
+#include <Library/GpioNativeLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <Library/PchInfoLib.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PchSbiAccessLib.h>
+
+typedef struct {
+  GPIO_PAD       Pad;
+  GPIO_PAD_MODE  Mode;
+} GPIO_PAD_NATIVE_FUNCTION;
+
+
+// BIT15-0  - pad number
+// BIT31-16 - group info
+//   BIT23- 16 - group index
+//   BIT31- 24 - chipset ID
+#define PAD_INFO_MASK          0x0000FFFF
+#define GROUP_INFO_POSITION    16
+#define GROUP_INFO_MASK        0xFFFF0000
+#define GROUP_INDEX_MASK       0x00FF0000
+#define UNIQUE_ID_MASK         0xFF000000
+#define UNIQUE_ID_POSITION     24
+
+#define GPIO_PAD_DEF(Group,Pad)               (UINT32)((Group << 16) + Pad)
+#define GPIO_GROUP_DEF(Index,ChipsetId)       (Index | (ChipsetId << 8))
+#define GPIO_GET_GROUP_INDEX(Group)           (Group & 0xFF)
+#define GPIO_GET_GROUP_FROM_PAD(Pad)          (Pad >> 16)
+#define GPIO_GET_GROUP_INDEX_FROM_PAD(Pad)    GPIO_GET_GROUP_INDEX ((Pad >> 16))
+#define GPIO_GET_PAD_NUMBER(Pad)              (Pad & 0xFFFF)
+#define GPIO_GET_CHIPSET_ID(Pad)              (Pad >> 24)
+
+//
+// Unique ID used in GpioPad defines
+//
+#define GPIO_SKL_H_CHIPSET_ID       0x1
+#define GPIO_SKL_LP_CHIPSET_ID      0x2
+
+//
+// Below defines are based on GPIO_CONFIG structure fields
+//
+#define GPIO_CONF_PAD_MODE_MASK     0xF
+#define GPIO_CONF_PAD_MODE_BIT_POS  0
+#define GPIO_CONF_HOST_OWN_MASK     0x3
+#define GPIO_CONF_HOST_OWN_BIT_POS  0
+#define GPIO_CONF_DIR_MASK          0x7
+#define GPIO_CONF_DIR_BIT_POS       0
+#define GPIO_CONF_INV_MASK          0x18
+#define GPIO_CONF_INV_BIT_POS       3
+#define GPIO_CONF_OUTPUT_MASK       0x3
+#define GPIO_CONF_OUTPUT_BIT_POS    0
+#define GPIO_CONF_INT_ROUTE_MASK    0x1F
+#define GPIO_CONF_INT_ROUTE_BIT_POS 0
+#define GPIO_CONF_INT_TRIG_MASK     0xE0
+#define GPIO_CONF_INT_TRIG_BIT_POS  5
+#define GPIO_CONF_RESET_MASK        0x7
+#define GPIO_CONF_RESET_BIT_POS     0
+#define GPIO_CONF_TERM_MASK         0x1F
+#define GPIO_CONF_TERM_BIT_POS      0
+#define GPIO_CONF_PADTOL_MASK       0x60
+#define GPIO_CONF_PADTOL_BIT_POS    5
+#define GPIO_CONF_LOCK_MASK         0x7
+#define GPIO_CONF_LOCK_BIT_POS      0
+#define GPIO_CONF_RXRAW_MASK        0x3
+#define GPIO_CONF_RXRAW_BIT_POS     0
+
+//
+// Structure for storing information about registers offset, community,
+// maximal pad number for available groups
+//
+typedef struct {
+  UINT32 Community;
+  UINT32 PadOwnOffset;
+  UINT32 HostOwnOffset;
+  UINT32 GpiIsOffset;
+  UINT32 GpiIeOffset;
+  UINT32 GpiGpeStsOffset;
+  UINT32 GpiGpeEnOffset;
+  UINT32 SmiStsOffset;
+  UINT32 SmiEnOffset;
+  UINT32 NmiStsOffset;
+  UINT32 NmiEnOffset;
+  UINT32 PadCfgLockOffset;
+  UINT32 PadCfgLockTxOffset;
+  UINT32 PadCfgOffset;
+  UINT32 PadPerGroup;
+} GPIO_GROUP_INFO;
+
+//
+// If in GPIO_GROUP_INFO structure certain register doesn't exist
+// it will have value equal to NO_REGISTER_FOR_PROPERTY
+//
+#define NO_REGISTER_FOR_PROPERTY (~0u)
+
+
+/**
+  This procedure is used to check if GpioPad is valid for certain chipset
+
+  @param[in]  GpioPad             GPIO pad
+
+  @retval TRUE                    This pin is valid on this chipset
+          FALSE                   Incorrect pin
+**/
+BOOLEAN
+GpioIsCorrectPadForThisChipset (
+  IN  GPIO_PAD        GpioPad
+  );
+
+
+/**
+  This procedure will retrieve address and length of GPIO info table
+
+  @param[out]  GpioGroupInfoTableLength   Length of GPIO group table
+
+  @retval Pointer to GPIO group table
+
+**/
+GPIO_GROUP_INFO*
+GpioGetGroupInfoTable (
+  OUT UINTN               *GpioGroupInfoTableLength
+  );
+
+/**
+  This procedure will set GPIO mode
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] PadModeValue        GPIO pad mode value
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+SetGpioPadMode (
+  IN GPIO_PAD                GpioPad,
+  IN GPIO_PAD_MODE           PadModeValue
+  );
+
+/**
+  This procedure will get GPIO mode
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] PadModeValue        GPIO pad mode value
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GetGpioPadMode (
+  IN  GPIO_PAD                 GpioPad,
+  OUT GPIO_PAD_MODE            *PadModeValue
+  );
+
+/**
+  This function checks if GPIO pin is a GSPI chip select pin
+
+  @param[in]  GpioPad             GPIO pad
+  @param[in]  PadMode             GPIO pad mode
+
+  @retval TRUE                    Pin is in GPIO mode
+          FALSE                   Pin is in native mode
+**/
+BOOLEAN
+GpioIsGpioPadAGSpiCsbPin (
+  IN  GPIO_PAD        GpioPad,
+  IN  GPIO_PAD_MODE   PadMode
+  );
+
+/**
+  This function checks if GPIO pin is a SataDevSlp pin
+
+  @param[in]  GpioPad             GPIO pad
+  @param[in]  PadMode             GPIO pad mode
+
+  @retval TRUE                    Pin is in GPIO mode
+          FALSE                   Pin is in native mode
+**/
+BOOLEAN
+GpioIsPadASataDevSlpPin (
+  IN  GPIO_PAD        GpioPad,
+  IN  GPIO_PAD_MODE   PadMode
+  );
+
+/**
+  Check if given GPIO Pad is locked
+
+  @param[in]  GroupIndex                GPIO group index
+  @param[in]  PadNumber                 GPIO pad number
+
+  @retval TRUE                          Pad is locked
+  @retval FALSE                         Pad is not locked
+**/
+BOOLEAN
+GpioIsPadLocked (
+  IN  UINT32                 GroupIndex,
+  IN  GPIO_PAD               PadNumber
+  );
+
+#endif // _GPIO_LIBRARY_H_
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioNativeLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioNativeLib.c
new file mode 100644
index 0000000000..314e8d5c98
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/GpioNativeLib.c
@@ -0,0 +1,448 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GpioLibrary.h"
+
+//
+// Chipset specific data
+//
+//SATA
+extern GPIO_PAD_NATIVE_FUNCTION mPchHSataPortResetToGpioMap[PCH_H_AHCI_MAX_PORTS];
+extern GPIO_PAD_NATIVE_FUNCTION mPchHSataDevSlpPinToGpioMap[PCH_H_AHCI_MAX_PORTS];
+
+//
+// SKX specific
+//
+extern GPIO_GROUP_INFO mPchGpioGroupInfo[V_PCH_GPIO_GROUP_MAX];
+
+/**
+  This procedure will set GPIO mode
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] PadModeValue        GPIO pad mode value
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+SetGpioPadMode (
+  IN GPIO_PAD                GpioPad,
+  IN GPIO_PAD_MODE           PadModeValue
+  )
+{
+  GPIO_PAD_OWN         PadOwnVal;
+  UINT32               PadCfgReg;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  UINT32               PadNumber;
+  UINT32               GroupIndex;
+  UINT32               Dw0Reg;
+  UINT32               Dw0RegMask;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  GpioGetPadOwnership (GpioPad, &PadOwnVal);
+
+  if (PadOwnVal != GpioPadOwnHost) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_UNSUPPORTED;
+  }
+
+  if (GpioIsPadLocked (GroupIndex, PadNumber)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pad is locked (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_WRITE_PROTECTED;
+  }
+
+  //
+  // Create Pad Configuration register offset
+  //
+  PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+  Dw0RegMask = ((((PadModeValue & GPIO_CONF_PAD_MODE_MASK) >> GPIO_CONF_PAD_MODE_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PAD_MODE);
+  Dw0Reg = (((PadModeValue & GPIO_CONF_PAD_MODE_MASK) >> (GPIO_CONF_PAD_MODE_BIT_POS + 1)) << N_PCH_GPIO_PAD_MODE);
+
+  MmioAndThenOr32 (
+    (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg),
+    ~(UINT32)Dw0RegMask,
+    (UINT32)Dw0Reg
+  );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This procedure will get GPIO mode
+
+  @param[in]  GpioPad             GPIO pad
+  @param[out] PadModeValue        GPIO pad mode value
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
+**/
+EFI_STATUS
+GetGpioPadMode (
+  IN  GPIO_PAD                 GpioPad,
+  OUT GPIO_PAD_MODE            *PadModeValue
+  )
+{
+  GPIO_PAD_OWN         PadOwnVal;
+  UINT32               PadCfgReg;
+  GPIO_GROUP_INFO      *GpioGroupInfo;
+  UINTN                GpioGroupInfoLength;
+  UINT32               PadNumber;
+  UINT32               GroupIndex;
+  UINT32               Dw0Reg;
+
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+DEBUG_CODE_END();
+
+  GpioGetPadOwnership (GpioPad, &PadOwnVal);
+
+  if (PadOwnVal != GpioPadOwnHost) {
+    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Create Pad Configuration register offset
+  //
+  PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+  Dw0Reg = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg));
+
+  *PadModeValue = ((Dw0Reg & B_PCH_GPIO_PAD_MODE) >> (N_PCH_GPIO_PAD_MODE - (GPIO_CONF_PAD_MODE_BIT_POS + 1))) | (0x1 << GPIO_CONF_PAD_MODE_BIT_POS);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This procedure will retrieve address and length of GPIO info table
+
+  @param[out]  GpioGroupInfoTableLength   Length of GPIO group table
+
+  @retval Pointer to GPIO group table
+
+**/
+GPIO_GROUP_INFO*
+GpioGetGroupInfoTable (
+  OUT UINTN               *GpioGroupInfoTableLength
+  )
+{
+  if (GetPchGeneration () == SklPch) {
+      *GpioGroupInfoTableLength = sizeof (mPchGpioGroupInfo) / sizeof (GPIO_GROUP_INFO);
+      return mPchGpioGroupInfo;
+  } else {
+    *GpioGroupInfoTableLength = 0;
+    return NULL;
+  }
+}
+
+
+/**
+  This procedure is used to check if GpioPad is valid for certain chipset
+
+  @param[in]  GpioPad             GPIO pad
+
+  @retval TRUE                    This pin is valid on this chipset
+          FALSE                   Incorrect pin
+**/
+BOOLEAN
+GpioIsCorrectPadForThisChipset (
+  IN  GPIO_PAD        GpioPad
+  )
+{
+DEBUG_CODE_BEGIN();
+  PCH_SERIES PchSeries;
+
+  PchSeries = GetPchSeries ();
+
+  if ((PchSeries == PchH) && (GPIO_GET_CHIPSET_ID(GpioPad) == GPIO_SKL_H_CHIPSET_ID)) {
+    return TRUE;
+  } else if ((PchSeries == PchLp) && (GPIO_GET_CHIPSET_ID(GpioPad) == GPIO_SKL_LP_CHIPSET_ID)) {
+    return TRUE;
+  }
+
+DEBUG_CODE_END();
+  return FALSE;
+}
+
+
+/**
+  This procedure will get number of pads for certain GPIO group
+
+  @param[in] Group            GPIO group number
+
+  @retval Value               Pad number for group
+                              If illegal group number then return 0
+**/
+UINT32
+GpioGetPadPerGroup (
+  IN GPIO_GROUP      Group
+  )
+{
+  GPIO_GROUP_INFO     *GpioGroupInfo;
+  UINTN               GpioGroupInfoLength;
+  UINT32              GroupIndex;
+  //
+  // Check if group argument exceeds GPIO GROUP INFO array
+  //
+  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+  GroupIndex = GpioGetGroupIndexFromGroup (Group);
+
+  if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+    ASSERT(FALSE);
+    return 0;
+  } else {
+    return GpioGroupInfo[GroupIndex].PadPerGroup;
+  }
+}
+
+/**
+  This procedure will get number of groups
+
+  @param[in] none
+
+  @retval Value               Group number
+**/
+UINT8
+GpioGetNumberOfGroups (
+  VOID
+  )
+{
+    return V_PCH_H_GPIO_GROUP_MAX;
+}
+/**
+  This procedure will get lowest group
+
+  @param[in] none
+
+  @retval Value               Lowest Group
+**/
+GPIO_GROUP
+GpioGetLowestGroup (
+  VOID
+  )
+{
+    return (UINT32)GPIO_SKL_H_GROUP_GPP_A;
+}
+/**
+  This procedure will get highest group
+
+  @param[in] none
+
+  @retval Value               Highest Group
+**/
+GPIO_GROUP
+GpioGetHighestGroup (
+  VOID
+  )
+{
+    return (UINT32)GPIO_SKL_H_GROUP_GPD;
+}
+
+/**
+  This procedure will get group number
+
+  @param[in] GpioPad          Gpio Pad
+
+  @retval Value               Group number
+**/
+GPIO_GROUP
+GpioGetGroupFromGpioPad (
+  IN GPIO_PAD         GpioPad
+  )
+{
+  return GPIO_GET_GROUP_FROM_PAD (GpioPad);
+}
+
+/**
+  This procedure will get group index (0 based)
+
+  @param[in] GpioPad          Gpio Pad
+
+  @retval Value               Group Index
+**/
+UINT32
+GpioGetGroupIndexFromGpioPad (
+  IN GPIO_PAD        GpioPad
+  )
+{
+  return (UINT32)GPIO_GET_GROUP_INDEX_FROM_PAD (GpioPad);
+}
+
+/**
+  This procedure will get group index (0 based) from group
+
+  @param[in] GpioGroup        Gpio Group
+
+  @retval Value               Group Index
+**/
+UINT32
+GpioGetGroupIndexFromGroup (
+  IN GPIO_GROUP        GpioGroup
+  )
+{
+  return (UINT32)GPIO_GET_GROUP_INDEX (GpioGroup);
+}
+
+/**
+  This procedure will get pad number (0 based) from Gpio Pad
+
+  @param[in] GpioPad          Gpio Pad
+
+  @retval Value               Pad Number
+**/
+UINT32
+GpioGetPadNumberFromGpioPad (
+  IN GPIO_PAD        GpioPad
+  )
+{
+  return (UINT32)GPIO_GET_PAD_NUMBER (GpioPad);
+}
+/**
+  This procedure will return GpioPad from Group and PadNumber
+
+  @param[in] Group              GPIO group
+  @param[in] PadNumber          GPIO PadNumber
+
+  @retval GpioPad               GpioPad
+**/
+GPIO_PAD
+GpioGetGpioPadFromGroupAndPadNumber (
+  IN GPIO_GROUP      Group,
+  IN UINT32          PadNumber
+  )
+{
+    return GPIO_PAD_DEF(Group,PadNumber);
+}
+
+
+
+/**
+  This function checks if GPIO pin for SATA reset port is in GPIO MODE
+
+  @param[in]  SataPort            SATA port number
+
+  @retval TRUE                    Pin is in GPIO mode
+          FALSE                   Pin is in native mode
+**/
+BOOLEAN
+GpioIsSataResetPortInGpioMode (
+  IN  UINTN           SataPort
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         GpioPin;
+  GPIO_PAD_MODE  GpioMode;
+
+
+    ASSERT (SataPort < PCH_H_AHCI_MAX_PORTS);
+    GpioPin = mPchHSataPortResetToGpioMap[SataPort].Pad;
+
+  Status =  GetGpioPadMode (GpioPin, &GpioMode);
+  if ((EFI_ERROR (Status)) || (GpioMode != GpioPadModeGpio)) {
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+
+/**
+  This function checks if GPIO pin is a SataDevSlp pin
+
+  @param[in]  GpioPad             GPIO pad
+  @param[in]  PadMode             GPIO pad mode
+
+  @retval TRUE                    Pin is in GPIO mode
+          FALSE                   Pin is in native mode
+**/
+BOOLEAN
+GpioIsPadASataDevSlpPin (
+  IN  GPIO_PAD        GpioPad,
+  IN  GPIO_PAD_MODE   PadMode
+  )
+{
+  UINT32                    SataDevSlpPinMax;
+  UINT32                    SataDevSlpPinIndex;
+  GPIO_PAD_OWN              PadOwnership;
+  GPIO_PAD_NATIVE_FUNCTION  *SataDevSlpPinToGpioMap;
+
+    SataDevSlpPinToGpioMap = mPchHSataDevSlpPinToGpioMap;
+    SataDevSlpPinMax = sizeof(mPchHSataDevSlpPinToGpioMap)/sizeof(GPIO_PAD_NATIVE_FUNCTION);
+
+  for (SataDevSlpPinIndex = 0; SataDevSlpPinIndex < SataDevSlpPinMax; SataDevSlpPinIndex++) {
+    if ((GpioPad == SataDevSlpPinToGpioMap[SataDevSlpPinIndex].Pad) &&
+      (PadMode == SataDevSlpPinToGpioMap[SataDevSlpPinIndex].Mode)) {
+      GpioGetPadOwnership (SataDevSlpPinToGpioMap[SataDevSlpPinIndex].Pad , &PadOwnership);
+      if (PadOwnership == GpioPadOwnHost) {
+        return TRUE;
+      } else {
+        return FALSE;
+      }
+    }
+  }
+  return FALSE;
+}
+
+/**
+  This function checks if SataDevSlp pin is in native mode
+
+  @param[in]  SataPort            SATA port
+  @param[out] DevSlpPad           DevSlpPad
+
+  @retval TRUE                    DevSlp is in native mode
+          FALSE                   DevSlp is not in native mode
+**/
+BOOLEAN
+GpioIsSataDevSlpPinEnabled (
+    IN  UINTN           SataPort,
+    OUT GPIO_PAD        *DevSlpPad
+  )
+{
+  GPIO_PAD_MODE  DevSlpPadMode;
+  GPIO_PAD       DevSlpGpioPad;
+  GPIO_PAD_MODE  GpioMode;
+  EFI_STATUS     Status;
+
+    ASSERT (SataPort < PCH_H_AHCI_MAX_PORTS);
+    DevSlpGpioPad = mPchHSataDevSlpPinToGpioMap[SataPort].Pad;
+    DevSlpPadMode = mPchHSataDevSlpPinToGpioMap[SataPort].Mode;
+
+  Status = GetGpioPadMode (DevSlpGpioPad, &GpioMode);
+
+  if (EFI_ERROR (Status) || (GpioMode != DevSlpPadMode)) {
+    *DevSlpPad = 0x0;
+    return FALSE;
+  } else {
+    *DevSlpPad = DevSlpGpioPad;
+    return TRUE;
+  }
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PchSklGpioData.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PchSklGpioData.c
new file mode 100644
index 0000000000..f62e71b9de
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PchSklGpioData.c
@@ -0,0 +1,59 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GpioLibrary.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED GPIO_GROUP_INFO mPchGpioGroupInfo[] = {
+  {PID_GPIOCOM0, R_PCH_H_PCR_GPIO_GPP_A_PAD_OWN,  R_PCH_PCR_GPIO_GPP_A_HOSTSW_OWN,    R_PCH_PCR_GPIO_GPP_A_GPI_IS,    R_PCH_PCR_GPIO_GPP_A_GPI_IE,    R_PCH_PCR_GPIO_GPP_A_GPI_GPE_STS,   R_PCH_PCR_GPIO_GPP_A_GPI_GPE_EN,    NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_A_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_A_PADCFGLOCKTX,  R_PCH_PCR_GPIO_GPP_A_PADCFG_OFFSET,    V_PCH_GPIO_GPP_A_PAD_MAX},    //SKX PCH-Server GPP_A
+  {PID_GPIOCOM0, R_PCH_H_PCR_GPIO_GPP_B_PAD_OWN,  R_PCH_PCR_GPIO_GPP_B_HOSTSW_OWN,    R_PCH_PCR_GPIO_GPP_B_GPI_IS,    R_PCH_PCR_GPIO_GPP_B_GPI_IE,    R_PCH_PCR_GPIO_GPP_B_GPI_GPE_STS,   R_PCH_PCR_GPIO_GPP_B_GPI_GPE_EN,    R_PCH_PCR_GPIO_GPP_B_SMI_STS,  R_PCH_PCR_GPIO_GPP_B_SMI_EN,   R_PCH_PCR_GPIO_GPP_B_NMI_STS,  R_PCH_PCR_GPIO_GPP_B_NMI_EN,   R_PCH_H_PCR_GPIO_GPP_B_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_B_PADCFGLOCKTX,  R_PCH_PCR_GPIO_GPP_B_PADCFG_OFFSET,    V_PCH_GPIO_GPP_B_PAD_MAX},    //SKX PCH-Server GPP_B
+  {PID_GPIOCOM1, R_PCH_H_PCR_GPIO_GPP_C_PAD_OWN,  R_PCH_PCR_GPIO_GPP_C_HOSTSW_OWN,    R_PCH_PCR_GPIO_GPP_C_GPI_IS,    R_PCH_PCR_GPIO_GPP_C_GPI_IE,    R_PCH_PCR_GPIO_GPP_C_GPI_GPE_STS,   R_PCH_PCR_GPIO_GPP_C_GPI_GPE_EN,    R_PCH_PCR_GPIO_GPP_C_SMI_STS,  R_PCH_PCR_GPIO_GPP_C_SMI_EN,   R_PCH_PCR_GPIO_GPP_C_NMI_STS,  R_PCH_PCR_GPIO_GPP_C_NMI_EN,   R_PCH_H_PCR_GPIO_GPP_C_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_C_PADCFGLOCKTX,  R_PCH_PCR_GPIO_GPP_C_PADCFG_OFFSET,    V_PCH_GPIO_GPP_C_PAD_MAX},    //SKX PCH-Server GPP_C
+  {PID_GPIOCOM1, R_PCH_H_PCR_GPIO_GPP_D_PAD_OWN,  R_PCH_PCR_GPIO_GPP_D_HOSTSW_OWN,    R_PCH_PCR_GPIO_GPP_D_GPI_IS,    R_PCH_PCR_GPIO_GPP_D_GPI_IE,    R_PCH_PCR_GPIO_GPP_D_GPI_GPE_STS,   R_PCH_PCR_GPIO_GPP_D_GPI_GPE_EN,    R_PCH_PCR_GPIO_GPP_D_SMI_STS,  R_PCH_PCR_GPIO_GPP_D_SMI_EN,   R_PCH_PCR_GPIO_GPP_D_NMI_STS,  R_PCH_PCR_GPIO_GPP_D_NMI_EN,   R_PCH_H_PCR_GPIO_GPP_D_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_D_PADCFGLOCKTX,  R_PCH_PCR_GPIO_GPP_D_PADCFG_OFFSET,    V_PCH_GPIO_GPP_D_PAD_MAX},    //SKX PCH-Server GPP_D
+  {PID_GPIOCOM1, R_PCH_H_PCR_GPIO_GPP_E_PAD_OWN,  R_PCH_PCR_GPIO_GPP_E_HOSTSW_OWN,    R_PCH_PCR_GPIO_GPP_E_GPI_IS,    R_PCH_PCR_GPIO_GPP_E_GPI_IE,    R_PCH_PCR_GPIO_GPP_E_GPI_GPE_STS,   R_PCH_PCR_GPIO_GPP_E_GPI_GPE_EN,    R_PCH_PCR_GPIO_GPP_E_SMI_STS,  R_PCH_PCR_GPIO_GPP_E_SMI_EN,   R_PCH_PCR_GPIO_GPP_E_NMI_STS,  R_PCH_PCR_GPIO_GPP_E_NMI_EN,   R_PCH_H_PCR_GPIO_GPP_E_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_E_PADCFGLOCKTX,  R_PCH_PCR_GPIO_GPP_E_PADCFG_OFFSET,    V_PCH_H_GPIO_GPP_E_PAD_MAX},  //SKX PCH-Server GPP_E
+  {PID_GPIOCOM0, R_PCH_H_PCR_GPIO_GPP_F_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_F_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_F_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_F_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_F_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_F_GPI_GPE_EN,  NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_F_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_F_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_F_PADCFG_OFFSET,  V_PCH_GPIO_GPP_F_PAD_MAX},    //SKX PCH-Server GPP_F
+  {PID_GPIOCOM5, R_PCH_H_PCR_GPIO_GPP_G_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_G_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_G_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_G_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_G_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_G_GPI_GPE_EN,  NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_G_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_G_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_G_PADCFG_OFFSET,  V_PCH_H_GPIO_GPP_G_PAD_MAX},  //SKX PCH-Server GPP_G
+  {PID_GPIOCOM5, R_PCH_H_PCR_GPIO_GPP_H_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_H_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_H_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_H_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_H_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_H_GPI_GPE_EN,  NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_H_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_H_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_H_PADCFG_OFFSET,  V_PCH_H_GPIO_GPP_H_PAD_MAX},  //SKX PCH-Server GPP_H
+  {PID_GPIOCOM3, R_PCH_H_PCR_GPIO_GPP_I_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_I_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_I_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_I_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_I_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_I_GPI_GPE_EN,  R_PCH_H_PCR_GPIO_GPP_I_SMI_STS,R_PCH_H_PCR_GPIO_GPP_I_SMI_EN, R_PCH_H_PCR_GPIO_GPP_I_NMI_STS,R_PCH_H_PCR_GPIO_GPP_I_NMI_EN, R_PCH_H_PCR_GPIO_GPP_I_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_I_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_I_PADCFG_OFFSET,  V_PCH_H_GPIO_GPP_I_PAD_MAX},  //SKX PCH-Server GPP_I
+  {PID_GPIOCOM4, R_PCH_H_PCR_GPIO_GPP_J_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_J_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_J_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_J_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_J_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_J_GPI_GPE_EN,  NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_J_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_J_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_J_PADCFG_OFFSET,  V_PCH_H_GPIO_GPP_J_PAD_MAX},  //SKX PCH-Server GPP_J
+  {PID_GPIOCOM4, R_PCH_H_PCR_GPIO_GPP_K_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_K_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_K_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_K_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_K_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_K_GPI_GPE_EN,  NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_K_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_K_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_K_PADCFG_OFFSET,  V_PCH_H_GPIO_GPP_K_PAD_MAX},  //SKX PCH-Server GPP_K
+  {PID_GPIOCOM5, R_PCH_H_PCR_GPIO_GPP_L_PAD_OWN,  R_PCH_H_PCR_GPIO_GPP_L_HOSTSW_OWN,  R_PCH_H_PCR_GPIO_GPP_L_GPI_IS,  R_PCH_H_PCR_GPIO_GPP_L_GPI_IE,  R_PCH_H_PCR_GPIO_GPP_K_GPI_GPE_STS, R_PCH_H_PCR_GPIO_GPP_L_GPI_GPE_EN,  NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPP_L_PADCFGLOCK,  R_PCH_H_PCR_GPIO_GPP_L_PADCFGLOCKTX,  R_PCH_H_PCR_GPIO_GPP_L_PADCFG_OFFSET,  V_PCH_H_GPIO_GPP_L_PAD_MAX},  //SKX PCH-Server GPP_L
+  {PID_GPIOCOM2, R_PCH_H_PCR_GPIO_GPD_PAD_OWN,    R_PCH_PCR_GPIO_GPD_HOSTSW_OWN,      R_PCH_PCR_GPIO_GPD_GPI_IS,      R_PCH_PCR_GPIO_GPD_GPI_IE,      R_PCH_PCR_GPIO_GPD_GPI_GPE_STS,     R_PCH_PCR_GPIO_GPD_GPI_GPE_EN,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      NO_REGISTER_FOR_PROPERTY,      R_PCH_H_PCR_GPIO_GPD_PADCFGLOCK,    R_PCH_H_PCR_GPIO_GPD_PADCFGLOCKTX,    R_PCH_PCR_GPIO_GPD_PADCFG_OFFSET,      V_PCH_GPIO_GPD_PAD_MAX}       //SKX PCH-Server GPD
+};
+
+
+//
+// SATA reset port to GPIO pin mapping
+// SATAGP_x -> GPIO pin y
+//
+
+GPIO_PAD_NATIVE_FUNCTION mPchHSataPortResetToGpioMap[PCH_H_AHCI_MAX_PORTS]  =
+{
+  {GPIO_SKL_H_GPP_E0, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_E1, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_E2, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_F0, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_F1, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_F2, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_F3, GpioPadModeNative2},
+  {GPIO_SKL_H_GPP_F4, GpioPadModeNative2}
+};
+
+//
+// SATADevSlpPin to GPIO pin mapping
+// SATA_DEVSLP_x -> GPIO pin y
+//
+
+GPIO_PAD_NATIVE_FUNCTION mPchHSataDevSlpPinToGpioMap[PCH_H_AHCI_MAX_PORTS] =
+{
+  {GPIO_SKL_H_GPP_E4, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_E5, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_E6, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_F5, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_F6, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_F7, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_F8, GpioPadModeNative1},
+  {GPIO_SKL_H_GPP_F9, GpioPadModeNative1}
+};
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PeiDxeSmmGpioLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PeiDxeSmmGpioLib.inf
new file mode 100644
index 0000000000..c1e06f000e
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmGpioLib/PeiDxeSmmGpioLib.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmGpioLib
+  FILE_GUID = 16EC5CA8-8195-4847-B6CB-662BD7B763F2
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = GpioLib
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+  PchCycleDecodingLib
+  PchSbiAccessLib
+  PchPcrLib                                 #SERVER_BIOS
+  HobLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+
+[Sources]
+  GpioLib.c
+  GpioLibrary.h
+  GpioNativeLib.c
+  GpioInit.c
+  PchSklGpioData.c
+
+[Guids]
+  gPlatformGpioConfigGuid
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c
new file mode 100644
index 0000000000..e91546aa1f
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c
@@ -0,0 +1,1169 @@
+/** @file
+
+Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <PchAccess.h>
+#include <Library/PchInfoLib.h>
+#include <Library/PchPcrLib.h>
+#include <Library/PchP2sbLib.h>
+#include <Library/PchCycleDecodingLib.h>
+
+/**
+  Set PCH ACPI base address.
+  The Address should not be 0 and should be 256 bytes alignment, and it is IO space, so must not exceed 0xFFFF.
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Programming steps:
+  1. clear PMC PCI offset 44h [7] to diable ACPI base address first before changing base address.
+  2. program PMC PCI offset 40h [15:2] to ACPI base address.
+  3. set PMC PCI offset 44h [7] to enable ACPI base address.
+  4. program "ACPI Base Address" PCR[DMI] + 27B4h[23:18, 15:2, 0] to [0x3F, PMC PCI Offset 40h bit[15:2],  1].
+  5. Program "ACPI Base Destination ID"
+      For SPT-LP:  Program PCR[DMI] + 27B8h[31:0] to 0x23A0
+      For SPT-H:   Program PCR[DMI] + 27B8h[31:0] to 0x23A8
+
+  @param[in] Address                    Address for ACPI base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiBaseSet (
+  IN  UINT16                            Address
+  )
+{
+  UINTN                                 PmcBase;
+  UINT32                                Dmic;
+  UINT32                                Data32;
+  PCH_SERIES                            PchSeries;
+
+  PchSeries = GetPchSeries ();
+
+  if (((Address & 0x00FF) != 0) ||
+      (Address == 0))
+  {
+    DEBUG((DEBUG_ERROR, "PchAcpiBaseSet Error. Invalid Address: %x.\n", Address));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    DEBUG((DEBUG_ERROR, "PchAcpiBaseSet Error. DMIC.SRL is set.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  PmcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_PMC,
+                   PCI_FUNCTION_NUMBER_PCH_PMC
+                   );
+  if (MmioRead16 (PmcBase) == 0xFFFF) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Disable ABASE in PMC Device first before changing base address.
+  //
+  MmioAnd8 (
+    PmcBase + R_PCH_PMC_ACPI_CNT,
+    (UINT8) ~B_PCH_PMC_ACPI_CNT_ACPI_EN
+    );
+  //
+  // Program ABASE in PMC Device
+  //
+  MmioAndThenOr16 (
+    PmcBase + R_PCH_PMC_ACPI_BASE,
+    (UINT16) (~B_PCH_PMC_ACPI_BASE_BAR),
+    Address
+    );
+  //
+  // Enable ABASE in PMC Device
+  //
+  MmioOr8 (
+    PmcBase + R_PCH_PMC_ACPI_CNT,
+    B_PCH_PMC_ACPI_CNT_ACPI_EN
+    );
+  //
+  // Program "ACPI Base Address" PCR[DMI] + 27B4h[23:18, 15:2, 0] to [0x3F, PMC PCI Offset 40h bit[15:2],  1]
+  //
+  PchPcrWrite32 (
+    PID_DMI, R_PCH_PCR_DMI_ACPIBA,
+    (0x00FC0001 + Address)
+    );
+  //
+  // Program "ACPI Base Destination ID"
+  // For SPT-LP:
+  //   Program PCR[DMI] + 27B8h[31:0] to 0x23A0
+  // For SPT-H:
+  //   Program PCR[DMI] + 27B8h[31:0] to 0x23A8
+  //
+  if(PchSeries == PchLp){
+    Data32 = 0x23A0;
+  } else {
+    Data32 = 0x23A8;
+  }
+  PchPcrWrite32 (
+    PID_DMI, R_PCH_PCR_DMI_ACPIBDID,
+    Data32
+    );
+  return EFI_SUCCESS;
+}
+
+/**
+  Get PCH ACPI base address.
+
+  @param[out] Address                   Address of ACPI base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid pointer passed.
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiBaseGet (
+  OUT UINT16                            *Address
+  )
+{
+  UINTN                                 PmcBase;
+
+  if (Address == NULL) {
+    DEBUG((DEBUG_ERROR, "PchAcpiBaseGet Error. Invalid pointer.\n"));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PmcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_PMC,
+                   PCI_FUNCTION_NUMBER_PCH_PMC
+                   );
+  if (MmioRead16 (PmcBase) == 0xFFFF) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+  *Address = MmioRead16 (PmcBase + R_PCH_PMC_ACPI_BASE) & B_PCH_PMC_ACPI_BASE_BAR;
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH PWRM base address.
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Programming steps:
+  1. clear PMC PCI offset 44h [8] to diable PWRM base address first before changing PWRM base address.
+  2. program PMC PCI offset 48h [31:16] to PM base address.
+  3. set PMC PCI offset 44h [8] to enable PWRM base address.
+  4. program "PM Base Address Memory Range Base" PCR[DMI] + 27ACh[15:0] to the same value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the PWRMBASE to be 64KB aligned.
+     program "PM Base Address Memory Range Limit" PCR[DMI] + 27ACh[31:16] to the value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the memory allocated to PWRMBASE to be 64KB in size.
+  5. Program "PM Base Control"
+      For SPT-LP: Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A0]
+      For SPT-H:  Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A8]
+
+  @param[in] Address                    Address for PWRM base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchPwrmBaseSet (
+  IN  UINT32                            Address
+  )
+{
+  UINTN                                 PmcBase;
+  UINT32                                Dmic;
+  UINT32                                Data32;
+  PCH_SERIES                            PchSeries;
+
+  PchSeries = GetPchSeries ();
+
+  if (((Address & (~B_PCH_PMC_PWRM_BASE_BAR)) != 0) ||
+      (Address == 0))
+  {
+    DEBUG((DEBUG_ERROR, "PchPwrmBaseSet Error. Invalid Address: %x.\n", Address));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    DEBUG((DEBUG_ERROR, "PchPwrmBaseSet Error. DMIC.SRL is set.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  PmcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_PMC,
+                   PCI_FUNCTION_NUMBER_PCH_PMC
+                   );
+  if (MmioRead16 (PmcBase) == 0xFFFF) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Disable PWRMBASE in PMC Device first before changing PWRM base address.
+  //
+  MmioAnd16 (
+    PmcBase + R_PCH_PMC_ACPI_CNT,
+    (UINT16) ~B_PCH_PMC_ACPI_CNT_PWRM_EN
+    );
+  //
+  // Program PWRMBASE in PMC Device
+  //
+  MmioAndThenOr32 (
+    PmcBase + R_PCH_PMC_PWRM_BASE,
+    (UINT32) (~B_PCH_PMC_PWRM_BASE_BAR),
+    Address
+    );
+  //
+  // Enable PWRMBASE in PMC Device
+  //
+  MmioOr16 (
+    PmcBase + R_PCH_PMC_ACPI_CNT,
+    B_PCH_PMC_ACPI_CNT_PWRM_EN
+    );
+  //
+  // Program "PM Base Address Memory Range Base" PCR[DMI] + 27ACh[15:0] to the same value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the PWRMBASE to be 64KB aligned.
+  // Program "PM Base Address Memory Range Limit" PCR[DMI] + 27ACh[31:16] to the value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the memory allocated to PWRMBASE to be 64KB in size.
+  //
+  PchPcrWrite32 (
+    PID_DMI, R_PCH_PCR_DMI_PMBASEA,
+    ((Address & 0xFFFF0000) | (Address >> 16))
+    );
+  //
+  // Program "PM Base Control"
+  // For SPT-LP:
+  //   Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A0]
+  // For SPT-H:
+  //   Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A8]
+  //
+  if(PchSeries == PchLp){
+    Data32 = 0x800023A0;
+  } else {
+    Data32 = 0x800023A8;
+  }
+  PchPcrWrite32 (
+    PID_DMI, R_PCH_PCR_DMI_PMBASEC,
+    Data32
+    );
+  return EFI_SUCCESS;
+}
+
+/**
+  Get PCH PWRM base address.
+
+  @param[out] Address                   Address of PWRM base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid pointer passed.
+**/
+EFI_STATUS
+EFIAPI
+PchPwrmBaseGet (
+  OUT UINT32                            *Address
+  )
+{
+  UINTN                                 PmcBase;
+
+  if (Address == NULL) {
+    DEBUG((DEBUG_ERROR, "PchPwrmBaseGet Error. Invalid pointer.\n"));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PmcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_PMC,
+                   PCI_FUNCTION_NUMBER_PCH_PMC
+                   );
+  if (MmioRead16 (PmcBase) == 0xFFFF) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+  *Address = MmioRead32 (PmcBase + R_PCH_PMC_PWRM_BASE) & B_PCH_PMC_PWRM_BASE_BAR;
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH TCO base address.
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Programming steps:
+  1. set Smbus PCI offset 54h [8] to enable TCO base address.
+  2. program Smbus PCI offset 50h [15:5] to TCO base address.
+  3. set Smbus PCI offset 54h [8] to enable TCO base address.
+  4. program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1] to [Smbus PCI offset 50h[15:5], 1].
+
+  @param[in] Address                    Address for TCO base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchTcoBaseSet (
+  IN  UINT16                            Address
+  )
+{
+  UINTN                                 SmbusBase;
+  UINT32                                Dmic;
+
+  if ((Address & ~B_PCH_SMBUS_TCOBASE_BAR) != 0) {
+    DEBUG((DEBUG_ERROR, "PchTcoBaseSet Error. Invalid Address: %x.\n", Address));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    DEBUG((DEBUG_ERROR, "PchTcoBaseSet Error. DMIC.SRL is set.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  SmbusBase = MmPciBase (
+                DEFAULT_PCI_BUS_NUMBER_PCH,
+                PCI_DEVICE_NUMBER_PCH_SMBUS,
+                PCI_FUNCTION_NUMBER_PCH_SMBUS
+                );
+  if (MmioRead16 (SmbusBase) == 0xFFFF) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Verify TCO base is not locked.
+  //
+  if ((MmioRead8 (SmbusBase + R_PCH_SMBUS_TCOCTL) & B_PCH_SMBUS_TCOCTL_TCO_BASE_LOCK) != 0) {
+    ASSERT (FALSE);
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Disable TCO in SMBUS Device first before changing base address.
+  //
+  MmioAnd8 (
+    SmbusBase + R_PCH_SMBUS_TCOCTL + 1,
+    (UINT8) ~(B_PCH_SMBUS_TCOCTL_TCO_BASE_EN >> 8)
+    );
+  //
+  // Program TCO in SMBUS Device
+  //
+  MmioAndThenOr16 (
+    SmbusBase + R_PCH_SMBUS_TCOBASE,
+    (UINT16) (~B_PCH_SMBUS_TCOBASE_BAR),
+    Address
+    );
+  //
+  // Enable TCO in SMBUS Device
+  //
+  MmioOr8 (
+    SmbusBase + R_PCH_SMBUS_TCOCTL + 1,
+    (B_PCH_SMBUS_TCOCTL_TCO_BASE_EN >> 8)
+    );
+  //
+  // Program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1] to [SMBUS PCI offset 50h[15:5], 1].
+  //
+  PchPcrWrite16 (
+    PID_DMI, R_PCH_PCR_DMI_TCOBASE,
+    (Address | BIT1)
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get PCH TCO base address.
+
+  @param[out] Address                   Address of TCO base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid pointer passed.
+**/
+EFI_STATUS
+EFIAPI
+PchTcoBaseGet (
+  OUT UINT16                            *Address
+  )
+{
+  if (Address == NULL) {
+    DEBUG((DEBUG_ERROR, "PchTcoBaseGet Error. Invalid pointer.\n"));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Read "TCO Base Address" PCR[DMI] + 2778h[15:5]
+  // Don't read TCO base address from SMBUS PCI register since SMBUS might be disabled.
+  //
+  PchPcrRead16 (
+    PID_DMI, R_PCH_PCR_DMI_TCOBASE,
+    Address
+    );
+  *Address &= B_PCH_PCR_DMI_TCOBASE_TCOBA;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH LPC/eSPI generic IO range.
+  For generic IO range, the base address must align to 4 and less than 0xFFFF, and the length must be power of 2
+  and less than or equal to 256. Moreover, the address must be length aligned.
+  This function basically checks the address and length, which should not overlap with all other generic ranges.
+  If no more generic range register available, it returns out of resource error.
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Some IO ranges below 0x100 have fixed target. The target might be ITSS,RTC,LPC,PMC or terminated inside P2SB
+  but all predefined and can't be changed. IO range below 0x100 will be rejected in this function except below ranges:
+    0x00-0x1F,
+    0x44-0x4B,
+    0x54-0x5F,
+    0x68-0x6F,
+    0x80-0x8F,
+    0xC0-0xFF
+  Steps of programming generic IO range:
+  1. Program LPC/eSPI PCI Offset 84h ~ 93h of Mask, Address, and Enable.
+  2. Program LPC/eSPI Generic IO Range #, PCR[DMI] + 2730h ~ 273Fh to the same value programmed in LPC/eSPI PCI Offset 84h~93h.
+
+  @param[in] Address                    Address for generic IO range base address.
+  @param[in] Length                     Length of generic IO range.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address or length passed.
+  @retval EFI_OUT_OF_RESOURCES          No more generic range available.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcGenIoRangeSet (
+  IN  UINT16                            Address,
+  IN  UINTN                             Length
+  , IN  UINT8                           SlaveDevice
+  )
+{
+  EFI_STATUS                            Status;
+  PCH_LPC_GEN_IO_RANGE_LIST             LpcGenIoRangeList;
+  UINTN                                 LpcBase;
+  UINTN                                 Index;
+  UINTN                                 BaseAddr;
+  UINTN                                 MaskLength;
+  UINTN                                 TempMaxAddr;
+  UINT32                                Data32;
+  UINTN                                 ArraySize;
+  static struct EXCEPT_RANGE {
+    UINT8 Start;
+    UINT8 Length;
+  } ExceptRanges[] = { {0x00, 0x20}, {0x44, 0x08}, {0x54, 0x0C}, {0x68, 0x08}, {0x80, 0x10}, {0xC0, 0x40} };
+
+  Index = 0;
+  //
+  // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+  //
+
+  //
+  // For generic IO range, the base address must align to 4 and less than 0xFFFF,
+  // the length must be power of 2 and less than or equal to 256, and the address must be length aligned.
+  // IO range below 0x100 will be rejected in this function except below ranges:
+  //   0x00-0x1F,
+  //   0x44-0x4B,
+  //   0x54-0x5F,
+  //   0x68-0x6F,
+  //   0x80-0x8F,
+  //   0xC0-0xFF
+  //
+  if (((Length & (Length - 1)) != 0)  ||
+      ((Address & (UINT16)~B_PCH_LPC_GENX_DEC_IOBAR) != 0) ||
+      (Length > 256))
+  {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  if (Address < 0x100) {
+    ArraySize = sizeof (ExceptRanges) / sizeof (struct EXCEPT_RANGE);
+    for (Index = 0; Index < ArraySize; Index++) {
+      if ((Address >= ExceptRanges[Index].Start) &&
+          ((Address + Length) <= ((UINTN)ExceptRanges[Index].Start + (UINTN)ExceptRanges[Index].Length)))
+      {
+        break;
+      }
+    }
+    if (Index >= ArraySize) {
+      ASSERT (FALSE);
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // check if range overlap
+  //
+  Status  = PchLpcGenIoRangeGet (&LpcGenIoRangeList, SlaveDevice);
+  if (EFI_ERROR (Status)) {
+    ASSERT (FALSE);
+    return Status;
+  }
+  if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+    for (Index = 0; Index < PCH_LPC_GEN_IO_RANGE_MAX; Index++) {
+      BaseAddr = LpcGenIoRangeList.Range[Index].BaseAddr;
+      MaskLength   = LpcGenIoRangeList.Range[Index].Length;
+      if (BaseAddr == 0) {
+        continue;
+      }
+      if (((Address >= BaseAddr) && (Address < (BaseAddr + MaskLength))) ||
+          (((Address + Length) > BaseAddr) && ((Address + Length) <= (BaseAddr + MaskLength))))
+      {
+        if ((Address >= BaseAddr) && (Length <= MaskLength)) {
+          //
+          // return SUCCESS while range is covered.
+          //
+          return EFI_SUCCESS;
+        }
+
+        if ((Address + Length) > (BaseAddr + MaskLength)) {
+          TempMaxAddr = Address + Length;
+        } else {
+          TempMaxAddr = BaseAddr + MaskLength;
+        }
+        if (Address > BaseAddr) {
+          Address = (UINT16) BaseAddr;
+        }
+        Length = TempMaxAddr - Address;
+        break;
+      }
+    }
+    //
+    // If no range overlap
+    //
+    if (Index >= PCH_LPC_GEN_IO_RANGE_MAX) {
+      //
+      // Find a empty register
+      //
+      for (Index = 0; Index < PCH_LPC_GEN_IO_RANGE_MAX; Index++) {
+        BaseAddr = LpcGenIoRangeList.Range[Index].BaseAddr;
+        if (BaseAddr == 0) {
+          break;
+        }
+      }
+      if (Index >= PCH_LPC_GEN_IO_RANGE_MAX) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+  } else {
+    BaseAddr = LpcGenIoRangeList.Range[0].BaseAddr;
+    MaskLength   = LpcGenIoRangeList.Range[0].Length;
+    if (BaseAddr != 0) {
+      if (((Address >= BaseAddr) && (Address < (BaseAddr + MaskLength))) ||
+          (((Address + Length) > BaseAddr) && ((Address + Length) <= (BaseAddr + MaskLength))))
+      {
+        if ((Address >= BaseAddr) && (Length <= MaskLength)) {
+          //
+          // return SUCCESS while range is covered.
+          //
+          return EFI_SUCCESS;
+        } else {
+          return EFI_OUT_OF_RESOURCES;
+        }
+      }
+    }
+  }
+  //
+  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
+  //
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Data32);
+  if ((Data32 & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Program LPC/eSPI generic IO range register accordingly.
+  //
+  LpcBase = MmPciBase (
+              DEFAULT_PCI_BUS_NUMBER_PCH,
+              PCI_DEVICE_NUMBER_PCH_LPC,
+              PCI_FUNCTION_NUMBER_PCH_LPC
+              );
+  Data32 =  (UINT32) (((Length - 1) << 16) & B_PCH_LPC_GENX_DEC_IODRA);
+  Data32 |= (UINT32) Address;
+  Data32 |= B_PCH_LPC_GENX_DEC_EN;
+
+  if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+    //
+    // Program LPC/eSPI PCI Offset 84h ~ 93h of Mask, Address, and Enable.
+    //
+    MmioWrite32 (
+      LpcBase + R_PCH_LPC_GEN1_DEC + Index * 4,
+      Data32
+      );
+    //
+    // Program LPC Generic IO Range #, PCR[DMI] + 2730h ~ 273Fh to the same value programmed in LPC/eSPI PCI Offset 84h~93h.
+    //
+    PchPcrWrite32 (
+      PID_DMI, (UINT16) (R_PCH_PCR_DMI_LPCLGIR1 + Index * 4),
+      Data32
+      );
+  } else {
+    ASSERT(FALSE);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Get PCH LPC/eSPI generic IO range list.
+  This function returns a list of base address, length, and enable for all LPC/eSPI generic IO range regsiters.
+
+  @param[out] LpcGenIoRangeList         Return all LPC/eSPI generic IO range register status.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcGenIoRangeGet (
+  OUT PCH_LPC_GEN_IO_RANGE_LIST         *LpcGenIoRangeList
+  , IN  UINT8                           SlaveDevice
+  )
+{
+  UINTN                                 Index;
+  UINTN                                 LpcBase;
+  UINT32                                Data32;
+
+  //
+  // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+  //
+
+  if (LpcGenIoRangeList == NULL) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  LpcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_LPC,
+                   PCI_FUNCTION_NUMBER_PCH_LPC
+                   );
+
+  if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+    for (Index = 0; Index < PCH_LPC_GEN_IO_RANGE_MAX; Index++) {
+      Data32 = MmioRead32 (LpcBase + R_PCH_LPC_GEN1_DEC + Index * 4);
+      LpcGenIoRangeList->Range[Index].BaseAddr = Data32 & B_PCH_LPC_GENX_DEC_IOBAR;
+      LpcGenIoRangeList->Range[Index].Length   = ((Data32 & B_PCH_LPC_GENX_DEC_IODRA) >> 16) + 4;
+      LpcGenIoRangeList->Range[Index].Enable   = Data32 & B_PCH_LPC_GENX_DEC_EN;
+    }
+  } else {
+    ASSERT(FALSE);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH LPC/eSPI memory range decoding.
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Programming steps:
+  1. Program LPC/eSPI PCI Offset 98h [0] to [0] to disable memory decoding first before changing base address.
+  2. Program LPC/eSPI PCI Offset 98h [31:16, 0] to [Address, 1].
+  3. Program LPC/eSPI Memory Range, PCR[DMI] + 2740h to the same value programmed in LPC/eSPI PCI Offset 98h.
+
+  @param[in] Address                    Address for memory base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address or length passed.
+  @retval EFI_OUT_OF_RESOURCES          No more generic range available.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcMemRangeSet (
+  IN  UINT32                            Address
+  , IN  UINT8                           SlaveDevice
+  )
+{
+  UINTN                                 LpcBase;
+  UINT32                                Dmic;
+  UINTN                                 LpcReg;
+  UINT16                                DmiReg;
+
+  if ((Address & (~B_PCH_LPC_LGMR_MA)) != 0) {
+    DEBUG((DEBUG_ERROR, "PchLpcMemRangeSet Error. Invalid Address: %x.\n", Address));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    DEBUG((DEBUG_ERROR, "PchLpcMemRangeSet Error. DMIC.SRL is set.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  LpcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_LPC,
+                   PCI_FUNCTION_NUMBER_PCH_LPC
+                   );
+  if (SlaveDevice == ESPI_SECONDARY_SLAVE) {
+    ASSERT(FALSE);
+  } else {
+    LpcReg = LpcBase + R_PCH_LPC_LGMR;
+    DmiReg = R_PCH_PCR_DMI_LPCGMR;
+  }
+  //
+  // Program LPC/eSPI PCI Offset 98h [0] (LPC/ePSI first slave) or A8h [0] (eSPI secondary slave) to [0] to disable memory decoding first before changing base address.
+  //
+  MmioAnd32 (
+    LpcReg,
+    (UINT32) ~B_PCH_LPC_LGMR_LMRD_EN
+    );
+  //
+  // Program LPC/eSPI PCI Offset 98h [31:16, 0] (LPC/ eSPI first slave) or A8h [31:16, 0] (eSPI secondary slave) to [Address, 1].
+  //
+  MmioWrite32 (
+    LpcReg,
+    (Address | B_PCH_LPC_LGMR_LMRD_EN)
+    );
+  //
+  // Program LPC Memory Range, PCR[DMI] + 2740h (LPC/eSPI first slave) or 27C0h (eSPI secondary slave) to the same value programmed in LPC/eSPI PCI Offset 98h.
+  //
+  PchPcrWrite32 (
+    PID_DMI, DmiReg,
+    (Address | B_PCH_LPC_LGMR_LMRD_EN)
+    );
+  return EFI_SUCCESS;
+}
+
+/**
+  Get PCH LPC/eSPI memory range decoding address.
+
+  @param[out] Address                   Address of LPC/eSPI memory decoding base address.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcMemRangeGet (
+  OUT UINT32                            *Address
+    , IN  UINT8                           SlaveDevice
+  )
+{
+  UINTN                                 LpcBase;
+
+  if (Address == NULL) {
+    DEBUG((DEBUG_ERROR, "PchLpcMemRangeGet Error. Invalid pointer.\n"));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  LpcBase      = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_LPC,
+                   PCI_FUNCTION_NUMBER_PCH_LPC
+                   );
+  if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+    *Address = MmioRead32 (LpcBase + R_PCH_LPC_LGMR) & B_PCH_LPC_LGMR_MA;
+  } else {
+    ASSERT(FALSE);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH BIOS range deocding.
+  This will check General Control and Status bit 10 (GCS.BBS) to identify SPI or LPC/eSPI and program BDE register accordingly.
+  Please check EDS for detail of BiosDecodeEnable bit definition.
+    bit 15: F8-FF Enable
+    bit 14: F0-F8 Enable
+    bit 13: E8-EF Enable
+    bit 12: E0-E8 Enable
+    bit 11: D8-DF Enable
+    bit 10: D0-D7 Enable
+    bit  9: C8-CF Enable
+    bit  8: C0-C7 Enable
+    bit  7: Legacy F Segment Enable
+    bit  6: Legacy E Segment Enable
+    bit  5: Reserved
+    bit  4: Reserved
+    bit  3: 70-7F Enable
+    bit  2: 60-6F Enable
+    bit  1: 50-5F Enable
+    bit  0: 40-4F Enable
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Programming steps:
+  1. if GCS.BBS is 0 (SPI), program SPI offset D8h to BiosDecodeEnable.
+     if GCS.BBS is 1 (LPC/eSPi), program LPC offset D8h to BiosDecodeEnable.
+  2. program LPC BIOS Decode Enable, PCR[DMI] + 2744h to the same value programmed in LPC or SPI Offset D8h.
+
+  @param[in] BiosDecodeEnable           Bios decode enable setting.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchBiosDecodeEnableSet (
+  IN  UINT16                            BiosDecodeEnable
+  )
+{
+  UINTN                                 BaseAddr;
+  UINT32                                DmiGcsBbs;
+  UINT32                                Dmic;
+
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    DEBUG((DEBUG_ERROR, "PchBiosDecodeEnableSet Error. DMIC.SRL is set.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_GCS, &DmiGcsBbs);
+  DmiGcsBbs &= B_PCH_PCR_DMI_BBS;
+  //
+  // Check General Control and Status (GCS) [10]
+  // '0': SPI
+  // '1': LPC/eSPI
+  //
+  if (DmiGcsBbs == 0) {
+    BaseAddr = MmPciBase (
+                 DEFAULT_PCI_BUS_NUMBER_PCH,
+                 PCI_DEVICE_NUMBER_PCH_SPI,
+                 PCI_FUNCTION_NUMBER_PCH_SPI
+                 );
+    //
+    // if GCS.BBS is 0 (SPI), program SPI offset D8h to BiosDecodeEnable.
+    //
+    MmioWrite16 (BaseAddr + R_PCH_SPI_BDE, BiosDecodeEnable);
+  } else {
+    BaseAddr = MmPciBase (
+                 DEFAULT_PCI_BUS_NUMBER_PCH,
+                 PCI_DEVICE_NUMBER_PCH_LPC,
+                 PCI_FUNCTION_NUMBER_PCH_LPC
+                 );
+    //
+    // if GCS.BBS is 1 (LPC/eSPi), program LPC offset D8h to BiosDecodeEnable.
+    //
+    MmioWrite16 (BaseAddr + R_PCH_LPC_BDE, BiosDecodeEnable);
+  }
+
+  //
+  // program LPC BIOS Decode Enable, PCR[DMI] + 2744h to the same value programmed in LPC or SPI Offset D8h.
+  //
+  PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_LPCBDE, BiosDecodeEnable);
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH LPC/eSPI IO decode ranges.
+  Program LPC/eSPI I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same value programmed in LPC/eSPI PCI offset 80h.
+  Please check EDS for detail of LPC/eSPI IO decode ranges bit definition.
+  Bit  12: FDD range
+  Bit 9:8: LPT range
+  Bit 6:4: ComB range
+  Bit 2:0: ComA range
+
+  @param[in] LpcIoDecodeRanges          LPC/eSPI IO decode ranges bit settings.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcIoDecodeRangesSet (
+  IN  UINT16                            LpcIoDecodeRanges
+  )
+{
+  UINTN                                 LpcBaseAddr;
+  UINT32                                Dmic;
+
+  //
+  // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+  //
+
+  LpcBaseAddr  = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_LPC,
+                   PCI_FUNCTION_NUMBER_PCH_LPC
+                   );
+  //
+  // check if setting is identical
+  //
+  if (LpcIoDecodeRanges == MmioRead16 (LpcBaseAddr + R_PCH_LPC_IOD)) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
+  //
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // program LPC/eSPI PCI offset 80h.
+  //
+  MmioWrite16 (LpcBaseAddr + R_PCH_LPC_IOD, LpcIoDecodeRanges);
+
+  //
+  // program LPC I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same value programmed in LPC/eSPI PCI offset 80h.
+  //
+  PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_LPCIOD, LpcIoDecodeRanges);
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PCH LPC/eSPI IO enable decoding.
+  Setup LPC/eSPI I/O Enables, PCR[DMI] + 2774h[15:0] to the same value program in LPC/eSPI PCI offset 82h.
+  Note: Bit[15:10] of the source decode register is Read-Only. The IO range indicated by the Enables field
+  in LPC/eSPI PCI offset 82h[13:10] is always forwarded by DMI to subtractive agent for handling.
+  Please check EDS for detail of Lpc/eSPI IO decode ranges bit definition.
+
+  @param[in] LpcIoEnableDecoding        LPC/eSPI IO enable decoding bit settings.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcIoEnableDecodingSet (
+  IN  UINT16                            LpcIoEnableDecoding
+  , IN  UINT8                           SlaveDevice
+  )
+{
+  UINTN                                 LpcBaseAddr;
+  UINT32                                Dmic;
+  UINTN                                 LpcReg;
+
+  if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+    LpcReg = R_PCH_LPC_IOE;
+  } else {
+    ASSERT(FALSE);
+  }
+
+  //
+  // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+  //
+
+  LpcBaseAddr  = MmPciBase (
+                   DEFAULT_PCI_BUS_NUMBER_PCH,
+                   PCI_DEVICE_NUMBER_PCH_LPC,
+                   PCI_FUNCTION_NUMBER_PCH_LPC
+                   );
+  if (LpcIoEnableDecoding == MmioRead16 (LpcBaseAddr + LpcReg)) {
+    return EFI_SUCCESS;
+  }
+  //
+  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
+  //
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // program PCI offset 82h for LPC/eSPI CS#0 or offset A0h for eSPI CS#1.
+  //
+  MmioWrite16 (LpcBaseAddr + LpcReg, LpcIoEnableDecoding);
+
+  if (SlaveDevice == ESPI_SECONDARY_SLAVE) {
+    //
+    // For eSPI CS#1 device program PCI offset 82h respectively
+    //
+    MmioWrite16 (LpcBaseAddr + R_PCH_LPC_IOE, (LpcIoEnableDecoding | MmioRead16(LpcBaseAddr + R_PCH_LPC_IOE)));
+  }
+
+  //
+  // program LPC I/O Decode Ranges, PCR[DMI] + 2774h[15:0] to the same value programmed in LPC/eSPI PCI offset 82h.
+  //
+  PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_LPCIOE, LpcIoEnableDecoding);
+  return EFI_SUCCESS;
+}
+
+
+//
+// PCH-LP RPR destination ID table
+//
+UINT16 PchLpRprDidTable[] = {
+  0x2188, // Dest ID of RP1
+  0x2189, // Dest ID of RP2
+  0x218A, // Dest ID of RP3
+  0x218B, // Dest ID of RP4
+  0x2198, // Dest ID of RP5
+  0x2199, // Dest ID of RP6
+  0x219A, // Dest ID of RP7
+  0x219B, // Dest ID of RP8
+  0x21A8, // Dest ID of RP9
+  0x21A9, // Dest ID of RP10
+  0x21AA, // Dest ID of RP11
+  0x21AB  // Dest ID of RP12
+};
+
+//
+// PCH-H RPR destination ID table
+//
+UINT16 PchHRprDidTable[] = {
+  0x2180, // Dest ID of RP1
+  0x2181, // Dest ID of RP2
+  0x2182, // Dest ID of RP3
+  0x2183, // Dest ID of RP4
+  0x2188, // Dest ID of RP5
+  0x2189, // Dest ID of RP6
+  0x218A, // Dest ID of RP7
+  0x218B, // Dest ID of RP8
+  0x2198, // Dest ID of RP9
+  0x2199, // Dest ID of RP10
+  0x219A, // Dest ID of RP11
+  0x219B, // Dest ID of RP12
+  0x21A8, // Dest ID of RP13
+  0x21A9, // Dest ID of RP14
+  0x21AA, // Dest ID of RP15
+  0x21AB, // Dest ID of RP16
+  0x21B8, // Dest ID of RP17
+  0x21B9, // Dest ID of RP18
+  0x21BA, // Dest ID of RP19
+  0x21BB, // Dest ID of RP20
+};
+
+/**
+  Set PCH IO port 80h cycle decoding to PCIE root port.
+  System BIOS is likely to do this very soon after reset before PCI bus enumeration.
+  This cycle decoding is allowed to set when DMIC.SRL is 0.
+  Programming steps:
+  1. Program "RPR Destination ID", PCR[DMI] + 274Ch[31:16] to the Dest ID of RP.
+  2. Program "Reserved Page Route", PCR[DMI] + 274Ch[11] to '1'. Use byte write on GCS+1 and leave the BILD bit which is RWO.
+
+  @param[in] RpPhyNumber                PCIE root port physical number.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+**/
+EFI_STATUS
+EFIAPI
+PchIoPort80DecodeSet (
+  IN  UINTN                             RpPhyNumber
+  )
+{
+  UINT32                                Dmic;
+  UINT16                                *PchRprDidTable;
+
+  PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+  if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+    DEBUG((DEBUG_ERROR, "PchIoPort80DecodeSet Error. DMIC.SRL is set.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  ///
+  /// IO port 80h is typically used by decoder/LED hardware for debug purposes.
+  /// By default PCH will forward IO port 80h cycles to LPC bus. The Reserved Page Route (RPR) bit
+  /// of General Control and Status register, located at PCR[DMI] + 274Ch[11] , allows software to
+  /// re-direct IO port 80h cycles to PCIe bus so that a target (for example, a debug card) on
+  /// PCIe bus can receive and claim these cycles.
+  /// The "RPR Destination ID", PCR[DMI] + 274Ch[31:16] need to be set accordingly to point
+  /// to the root port that decode this range. Reading from Port 80h may not return valid values
+  /// if the POST-card itself do not shadow the writes. Unlike LPC, PCIe does not shadow the Port 80 writes.
+  ///
+
+  if (GetPchSeries () == PchLp) {
+    PchRprDidTable = PchLpRprDidTable;
+  } else {
+    PchRprDidTable = PchHRprDidTable;
+  }
+
+  //
+  // Program "RPR Destination ID", PCR[DMI] + 274Ch[31:16] to the Dest ID of RP.
+  //
+  PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_GCS + 2, PchRprDidTable[RpPhyNumber]);
+  //
+  // Program "Reserved Page Route", PCR[DMI] + 274Ch[11] to '1'.
+  // Use byte write on GCS+1 and leave the BILD bit which is RWO.
+  //
+  PchPcrAndThenOr8 (PID_DMI, R_PCH_PCR_DMI_GCS + 1, 0xFF, (B_PCH_PCR_DMI_RPR >> 8));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get IO APIC regsiters base address.
+  It returns IO APIC INDEX, DATA, and EOI regsiter address once the parameter is not NULL.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[out] IoApicIndex               Buffer of IO APIC INDEX regsiter address
+  @param[out] IoApicData                Buffer of IO APIC DATA regsiter address
+
+  @retval EFI_SUCCESS                   Successfully completed.
+**/
+EFI_STATUS
+PchIoApicBaseGet (
+  OPTIONAL OUT UINT32                   *IoApicIndex,
+  OPTIONAL OUT UINT32                   *IoApicData
+  )
+{
+  EFI_STATUS                            Status;
+  UINT16                                RegIoac;
+  UINT32                                RangeSelect;
+
+  Status = PchP2sbCfgGet16 (R_PCH_P2SB_IOAC, &RegIoac);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  RangeSelect = (RegIoac & B_PCH_P2SB_IOAC_ASEL) << N_PCH_IO_APIC_ASEL;
+
+  if (IoApicIndex != NULL) {
+    *IoApicIndex = R_PCH_IO_APIC_INDEX + RangeSelect;
+  }
+  if (IoApicData != NULL) {
+    *IoApicData  = R_PCH_IO_APIC_DATA + RangeSelect;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get HPET base address.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[out] HpetBase                  Buffer of HPET base address
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchHpetBaseGet (
+  OUT UINT32                            *HpetBase
+  )
+{
+  EFI_STATUS                            Status;
+  UINT8                                 RegHptc;
+
+  if (HpetBase == NULL) {
+    DEBUG((DEBUG_ERROR, "PchHpetBaseGet Error. Invalid pointer.\n"));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = PchP2sbCfgGet8 (R_PCH_P2SB_HPTC, &RegHptc);
+
+  switch (RegHptc & B_PCH_P2SB_HPTC_AS) {
+  case 0:
+    *HpetBase = V_PCH_HPET_BASE0;
+    break;
+  case 1:
+    *HpetBase = V_PCH_HPET_BASE1;
+    break;
+  case 2:
+    *HpetBase = V_PCH_HPET_BASE2;
+    break;
+  case 3:
+    *HpetBase = V_PCH_HPET_BASE3;
+    break;
+  default:
+    break;
+ }
+
+ return Status;
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf
new file mode 100644
index 0000000000..9e14d40365
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchCycleDecodingLib/PeiDxeSmmPchCycleDecodingLib.inf
@@ -0,0 +1,33 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchCycleDecodingLib
+  FILE_GUID = 676C749F-9CD1-46B7-BAFD-4B1BC36B4C8E
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchCycleDecodingLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+  PchInfoLib
+  PchPcrLib
+  PchP2sbLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+
+[Sources]
+  PchCycleDecodingLib.c
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PchGbeLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PchGbeLib.c
new file mode 100644
index 0000000000..181334cce9
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PchGbeLib.c
@@ -0,0 +1,160 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <Library/PchPmcLib.h>
+#include <PchAccess.h>
+#include <Library/PchInfoLib.h>
+#include <Library/PchPcrLib.h>
+#include <Library/PchCycleDecodingLib.h>
+
+#include <PiPei.h>
+#include <Ppi/Spi.h>
+#include <Library/PeiServicesLib.h>
+extern EFI_GUID  gPeiSpiPpiGuid;
+/**
+  Check whether GbE region is valid
+  Check SPI region directly since GbE might be disabled in SW.
+
+  @retval TRUE                    Gbe Region is valid
+  @retval FALSE                   Gbe Region is invalid
+**/
+BOOLEAN
+PchIsGbeRegionValid (
+  VOID
+  )
+{
+  UINT32  SpiBar;
+  SpiBar = MmioRead32 (MmPciBase (
+                        DEFAULT_PCI_BUS_NUMBER_PCH,
+                        PCI_DEVICE_NUMBER_PCH_SPI,
+                        PCI_FUNCTION_NUMBER_PCH_SPI)
+                        + R_PCH_SPI_BAR0) & ~B_PCH_SPI_BAR0_MASK;
+  ASSERT (SpiBar != 0);
+  if (MmioRead32 (SpiBar + R_PCH_SPI_FREG3_GBE) != B_PCH_SPI_FREGX_BASE_MASK) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+  Returns GbE over PCIe port number based on a soft strap.
+
+  @return                         Root port number (1-based)
+  @retval 0                       GbE over PCIe disabled
+**/
+UINT32
+PchGetGbePortNumber (
+  VOID
+  )
+{
+  UINT32   GbePortSel;
+  UINT32   PcieStrapFuse;
+
+  PchPcrRead32 (PID_FIAWM26, R_PCH_PCR_FIA_STRPFUSECFG1_REG_BASE, &PcieStrapFuse);
+  if ((PcieStrapFuse & B_PCH_PCR_FIA_STRPFUSECFG1_GBE_PCIE_PEN) == 0) {
+    return 0; // GbE disabled
+  }
+  GbePortSel = (PcieStrapFuse & B_PCH_PCR_FIA_STRPFUSECFG1_GBE_PCIEPORTSEL) >> N_PCH_PCR_FIA_STRPFUSECFG1_GBE_PCIEPORTSEL;
+
+    switch (GbePortSel) {
+      case 0: return  3 + 1;
+      case 1: return  4 + 1;
+      case 2: return  5 + 1;
+      case 3: return  8 + 1;
+      case 4: return 11 + 1;
+    }
+
+  DEBUG((DEBUG_ERROR, "Invalid GbE port\n"));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Check whether LAN controller is enabled in the platform.
+
+  @retval TRUE                    GbE is enabled
+  @retval FALSE                   GbE is disabled
+**/
+BOOLEAN
+PchIsGbePresent (
+  VOID
+  )
+{
+
+  UINT32                  SoftstrapVal;
+  EFI_SPI_PROTOCOL        *SpiProtocol = NULL;
+  EFI_STATUS              Status;
+  UINTN                   GbePciBase;
+
+  if (PchIsDwrFlow() == TRUE) {
+    return FALSE;
+  }
+
+  GbePciBase = MmPciBase (
+                 DEFAULT_PCI_BUS_NUMBER_PCH,
+                 PCI_DEVICE_NUMBER_PCH_LAN,
+                 PCI_FUNCTION_NUMBER_PCH_LAN
+                 );
+
+  //
+  // Check GBE disable strap
+  //
+  Status = PeiServicesLocatePpi (
+               &gPeiSpiPpiGuid,
+               0,
+               NULL,
+               (VOID **) &SpiProtocol
+               );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = SpiProtocol->ReadPchSoftStrap(SpiProtocol, 0x1DC, 4, &SoftstrapVal);
+  if (!EFI_ERROR(Status)) {
+    if ((SoftstrapVal & BIT14) == BIT14) {
+      return FALSE;
+    }
+  }
+  //
+  // Check FIA strap/fuse
+  //
+  if (PchGetGbePortNumber () == 0) {
+    return FALSE;
+  }
+  //
+  // Check GbE NVM
+  //
+  if (PchIsGbeRegionValid () == FALSE) {
+    return FALSE;
+  }
+  if (MmioRead32 (GbePciBase) == 0xFFFFFFFF) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Check whether LAN controller is enabled in the platform.
+
+  @deprecated Use PchIsGbePresent instead.
+
+  @retval TRUE                    GbE is enabled
+  @retval FALSE                   GbE is disabled
+**/
+BOOLEAN
+PchIsGbeAvailable (
+  VOID
+  )
+{
+  return PchIsGbePresent ();
+}
+
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PeiDxeSmmPchGbeLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PeiDxeSmmPchGbeLib.inf
new file mode 100644
index 0000000000..93e31f8cf4
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchGbeLib/PeiDxeSmmPchGbeLib.inf
@@ -0,0 +1,37 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchGbeLib
+  FILE_GUID = FC022ED0-6EB3-43E1-A740-0BA27CBBD010
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchGbeLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+  PchInfoLib
+  PchPcrLib
+  PchCycleDecodingLib
+  PchPmcLib                   #SERVER_BIOS
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Sources]
+  PchGbeLib.c
+
+[Ppis]
+  gPeiSpiPpiGuid
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoLib.c
new file mode 100644
index 0000000000..ef77a342d6
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoLib.c
@@ -0,0 +1,505 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <Library/PchInfoLib.h>
+#include <PchAccess.h>
+
+#define PCH_DO_STRINGIFY(x) #x
+#define PCH_STRINGIFY(x) PCH_DO_STRINGIFY(x)
+
+//
+// This module variables are used for cache the static result.
+// @note: please pay attention to the PEI phase, the module variables on ROM
+//       and can't be modified.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN            mLpcBaseAddr      = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_STEPPING     mPchStepping      = PchSteppingMax;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8            mIsPchSupported   = 0xFF;
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SERIES       mPchSeries        = PchUnknownSeries;
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_GENERATION   mPchGeneration    = PchUnknownGeneration;
+
+/**
+  Return Pch stepping type
+
+  @retval PCH_STEPPING            Pch stepping type
+**/
+PCH_STEPPING
+EFIAPI
+PchStepping (
+  VOID
+  )
+{
+  UINT8         RevId;
+  UINT16        LpcDeviceId;
+  UINTN         LpcBaseAddress;
+
+  if (mPchStepping != PchSteppingMax) {
+    return mPchStepping;
+  }
+
+  LpcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_LPC,
+                     PCI_FUNCTION_NUMBER_PCH_LPC
+                     );
+  RevId = MmioRead8 (LpcBaseAddress + PCI_REVISION_ID_OFFSET);
+
+  LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
+
+  if (IS_PCH_H_LPC_DEVICE_ID (LpcDeviceId)) {
+    switch (RevId) {
+       case V_PCH_LPC_RID_0:
+         mPchStepping = PchHA0;
+         return PchHA0;
+
+      case V_PCH_LPC_RID_10:
+        mPchStepping = PchHB0;
+        return PchHB0;
+
+      case V_PCH_LPC_RID_20:
+        mPchStepping = PchHC0;
+        return PchHC0;
+
+      case V_PCH_LPC_RID_30:
+        mPchStepping = PchHD0;
+        return PchHD0;
+
+      case V_PCH_LPC_RID_31:
+        mPchStepping = PchHD1;
+        return PchHD1;
+
+      default:
+        DEBUG ((DEBUG_ERROR, "Unsupported PCH Stepping. Supporting PCH stepping starting from %a and above\n", PCH_STRINGIFY(PCH_H_MIN_SUPPORTED_STEPPING))) ;
+        return PchSteppingMax;
+    }
+  }
+
+  if (IS_PCH_LP_LPC_DEVICE_ID (LpcDeviceId)) {
+    switch (RevId) {
+#ifdef SIMICS_FLAG
+      case V_PCH_LPC_RID_0:
+        mPchStepping = PchLpA0;
+        return PchLpA0;
+#endif
+
+      case V_PCH_LPC_RID_10:
+        mPchStepping = PchLpB0;
+        return PchLpB0;
+
+      case V_PCH_LPC_RID_11:
+        mPchStepping = PchLpB1;
+        return PchLpB1;
+
+      case V_PCH_LPC_RID_20:
+        mPchStepping = PchLpC0;
+        return PchLpC0;
+
+      case V_PCH_LPC_RID_21:
+        mPchStepping = PchLpC1;
+        return PchLpC1;
+
+      default:
+        DEBUG ((DEBUG_ERROR, "Unsupported PCH Stepping. Supporting PCH stepping starting from %a and above\n", PCH_STRINGIFY(PCH_LP_MIN_SUPPORTED_STEPPING))) ;
+        return PchSteppingMax;
+    }
+  }
+
+#ifdef SKXD_EN
+  if (IS_PCH_LBG_D_SSKU_LPC_DEVICE_ID (LpcDeviceId)) {
+    switch (RevId) {
+      case V_PCH_LBG_LPC_RID_3:
+        return LbgB1_D;
+      default:
+        DEBUG ((DEBUG_ERROR, "Unsupported PCH Stepping. Supporting PCH stepping starting from %s and above\n", PCH_STRINGIFY(V_PCH_LBG_LPC_RID_3)));
+        return PchSteppingMax;
+      }
+  }
+#endif // SKXD_EN
+
+  if (IS_PCH_LBG_LPC_DEVICE_ID (LpcDeviceId)) {
+    if (RevId == 0) {
+      return LbgA0;
+    } else {
+    switch (RevId) {
+      case V_PCH_LBG_LPC_RID_0:
+        return LbgA0;
+      case V_PCH_LBG_LPC_RID_2:
+        return LbgB0;
+      case V_PCH_LBG_LPC_RID_3:
+        return LbgB1;
+      case V_PCH_LBG_LPC_RID_4:
+        return LbgB2;
+      case V_PCH_LBG_LPC_RID_8:
+        return LbgS0;
+      case V_PCH_LBG_LPC_RID_9:
+        return LbgS1;
+      default:
+        DEBUG ((DEBUG_ERROR, "Unsupported PCH Stepping. Supporting PCH stepping starting from %s and above\n", PCH_STRINGIFY(PCH_LBG_MIN_SUPPORTED_STEPPING)));
+        ASSERT (FALSE);
+        return PchSteppingMax;
+      }
+    }
+  }
+  return PchSteppingMax;
+}
+
+/**
+  Determine if PCH is supported
+
+  @retval TRUE                    PCH is supported
+  @retval FALSE                   PCH is not supported
+**/
+BOOLEAN
+IsPchSupported (
+  VOID
+  )
+{
+  UINT16  LpcDeviceId;
+  UINT16  LpcVendorId;
+  UINTN   LpcBaseAddress;
+
+  if (mIsPchSupported != 0xFF) {
+    return (BOOLEAN) mIsPchSupported;
+  }
+
+  LpcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_LPC,
+                     PCI_FUNCTION_NUMBER_PCH_LPC
+                     );
+
+  LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
+  LpcVendorId = MmioRead16 (LpcBaseAddress + PCI_VENDOR_ID_OFFSET);
+
+  ///
+  /// Verify that this is a supported chipset
+  ///
+  if ((LpcVendorId == V_PCH_LPC_VENDOR_ID) &&
+      (IS_PCH_LBG_LPC_DEVICE_ID (LpcDeviceId)))
+  {
+    mIsPchSupported = TRUE;
+    return TRUE;
+  } else {
+    DEBUG ((DEBUG_ERROR, "PCH code doesn't support the LpcDeviceId: 0x%04x!\n", LpcDeviceId));
+    mIsPchSupported = FALSE;
+    return FALSE;
+  }
+}
+
+/**
+  Return Pch Series
+
+  @retval PCH_SERIES            Pch Series
+**/
+PCH_SERIES
+EFIAPI
+GetPchSeries (
+  VOID
+  )
+{
+  UINT16  LpcDeviceId;
+  UINT32  PchSeries;
+  UINTN   LpcBaseAddress;
+
+  if (mPchSeries != PchUnknownSeries) {
+    return mPchSeries;
+  }
+
+  LpcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_LPC,
+                     PCI_FUNCTION_NUMBER_PCH_LPC
+                     );
+
+  LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
+
+  if (IS_PCH_LBG_LPC_DEVICE_ID (LpcDeviceId)) {
+    PchSeries = PchH;
+  } else if (IS_PCH_LP_LPC_DEVICE_ID (LpcDeviceId)) {
+    PchSeries = PchLp;
+  } else {
+    PchSeries = PchUnknownSeries;
+    DEBUG ((DEBUG_ERROR, "Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n", LpcDeviceId));
+    ASSERT (FALSE);
+  }
+  mPchSeries = PchSeries;
+
+  return PchSeries;
+}
+
+/**
+  Return Pch Generation
+
+  @retval PCH_GENERATION            Pch Generation
+**/
+PCH_GENERATION
+EFIAPI
+GetPchGeneration (
+  VOID
+  )
+{
+  UINT16  LpcDeviceId;
+  UINT32  PchGen;
+  UINTN   LpcBaseAddress;
+
+  if (mPchGeneration != PchUnknownGeneration) {
+    return mPchGeneration;
+  }
+
+  LpcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_LPC,
+                     PCI_FUNCTION_NUMBER_PCH_LPC
+                     );
+  LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
+
+  if (IS_PCH_LBG_LPC_DEVICE_ID (LpcDeviceId)) {
+    PchGen = SklPch;
+  } else {
+    PchGen = PchUnknownGeneration;
+    DEBUG ((DEBUG_ERROR, "Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n", LpcDeviceId));
+    ASSERT (FALSE);
+  }
+  mPchGeneration = PchGen;
+
+  return PchGen;
+}
+
+/**
+  Get Pch Maximum Pcie Root Port Number
+
+  @retval Pch Maximum Pcie Root Port Number
+**/
+UINT8
+EFIAPI
+GetPchMaxPciePortNum (
+  VOID
+  )
+{
+  PCH_SERIES  PchSeries;
+
+  PchSeries = GetPchSeries ();
+  switch (PchSeries) {
+    case PchLp:
+      return PCH_LP_PCIE_MAX_ROOT_PORTS;
+
+    case PchH:
+      return PCH_H_PCIE_MAX_ROOT_PORTS;
+
+    default:
+      return 0;
+  }
+}
+
+
+/**
+  Get Pch Maximum Sata Port Number
+
+  @retval Pch Maximum Sata Port Number
+**/
+UINT8
+EFIAPI
+GetPchMaxSataPortNum (
+  VOID
+  )
+{
+  PCH_SERIES  PchSeries;
+
+  PchSeries = GetPchSeries ();
+  switch (PchSeries) {
+    case PchLp:
+      return PCH_LP_AHCI_MAX_PORTS;
+
+    case PchH:
+      return PCH_H_AHCI_MAX_PORTS;
+
+    default:
+      return 0;
+  }
+}
+
+/**
+  Get Pch Usb Maximum Physical Port Number
+
+  @retval Pch Usb Maximum Physical Port Number
+**/
+UINT8
+EFIAPI
+GetPchUsbMaxPhysicalPortNum (
+  VOID
+  )
+{
+  PCH_SERIES  PchSeries;
+
+  PchSeries = GetPchSeries ();
+  switch (PchSeries) {
+    case PchLp:
+      return PCH_LP_XHCI_MAX_USB2_PHYSICAL_PORTS;
+
+    case PchH:
+      return PCH_H_XHCI_MAX_USB2_PHYSICAL_PORTS;
+
+    default:
+      return 0;
+  }
+}
+
+/**
+  Get Pch Maximum Usb2 Port Number of XHCI Controller
+
+  @retval Pch Maximum Usb2 Port Number of XHCI Controller
+**/
+UINT8
+EFIAPI
+GetPchXhciMaxUsb2PortNum (
+  VOID
+  )
+{
+  PCH_SERIES  PchSeries;
+
+  PchSeries = GetPchSeries ();
+  switch (PchSeries) {
+    case PchLp:
+      return PCH_LP_XHCI_MAX_USB2_PORTS;
+
+    case PchH:
+      return PCH_H_XHCI_MAX_USB2_PORTS;
+
+    default:
+      return 0;
+  }
+}
+
+/**
+  Get Pch Maximum Usb3 Port Number of XHCI Controller
+
+  @retval Pch Maximum Usb3 Port Number of XHCI Controller
+**/
+UINT8
+EFIAPI
+GetPchXhciMaxUsb3PortNum (
+  VOID
+  )
+{
+  PCH_SERIES  PchSeries;
+
+  PchSeries = GetPchSeries ();
+  switch (PchSeries) {
+    case PchLp:
+      return PCH_LP_XHCI_MAX_USB3_PORTS;
+
+    case PchH:
+      return PCH_H_XHCI_MAX_USB3_PORTS;
+
+    default:
+      return 0;
+  }
+}
+
+/**
+  Determine if sSata controller is present or not
+
+  @param[in] None
+
+  @retval TRUE or FALSE
+**/
+BOOLEAN
+EFIAPI
+GetIsPchsSataPresent (
+  VOID
+  )
+{
+  UINT16  sSataDeviceId;
+  UINTN   sSataBaseAddress;
+
+  sSataBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_EVA,
+                     PCI_FUNCTION_NUMBER_PCH_SSATA
+                     );
+
+  sSataDeviceId = MmioRead16 ( sSataBaseAddress + PCI_DEVICE_ID_OFFSET);
+
+  if (sSataDeviceId != 0xffff){
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+/**
+  Get Pch Maximum sSata Controller Number
+
+  @param[in] None
+
+  @retval Pch Maximum sSata Controller Number
+**/
+
+UINT8
+EFIAPI
+GetPchMaxsSataPortNum (
+  VOID
+  )
+{
+  return PCH_SSATA_MAX_PORTS;
+}
+
+/**
+
+  Get Pch Maximum Sata Controller Number
+
+  @param[in] None
+
+  @retval Pch Maximum Sata Controller Number
+
+**/
+UINT8
+EFIAPI
+GetPchMaxsSataControllerNum (
+  VOID
+  )
+{
+  return PCH_SSATA_MAX_CONTROLLERS;
+}
+
+/**
+  Return Pch Lpc Device Id
+
+  @retval UINT16            Pch DeviceId
+**/
+UINT16
+EFIAPI
+GetPchLpcDeviceId (
+  VOID
+  )
+{
+  UINTN   LpcBaseAddress;
+
+  if (mPchSeries != PchUnknownSeries) {
+    return mPchSeries;
+  }
+
+  LpcBaseAddress = mLpcBaseAddr;
+  if (LpcBaseAddress == 0) {
+  LpcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_LPC,
+                     PCI_FUNCTION_NUMBER_PCH_LPC
+                     );
+    mLpcBaseAddr   = LpcBaseAddress;
+  }
+
+  return MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoStrLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoStrLib.c
new file mode 100644
index 0000000000..e13b7877af
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PchInfoStrLib.c
@@ -0,0 +1,291 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <Library/PchInfoLib.h>
+#include <PchAccess.h>
+
+/**
+  Structure for PCH stepping string mapping
+**/
+struct PCH_STEPPING_STRING {
+  PCH_STEPPING  Stepping;
+  CHAR8         *String;
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+struct PCH_STEPPING_STRING mSteppingStrs[] = {
+  {PchHA0,  "A0"},
+  {PchHB0,  "B0"},
+  {PchHC0,  "C0"},
+  {PchHD0,  "D0"},
+  {PchHD1,  "D1"},
+#ifdef SIMICS_FLAG
+  {PchLpA0, "A0"},
+#endif
+  {PchLpB0, "B0"},
+  {PchLpB1, "B1"},
+  {PchLpC0, "C0"},
+  {PchLpC1, "C1"},
+  {LbgA0,   "A0"},
+  {LbgB0,   "B0"},
+  {LbgB1,   "B1"},
+  {LbgB2,   "B2"},
+  {LbgS0,   "S0"},
+  {LbgS1,   "S1"},
+  {PchSteppingMax, NULL}
+};
+
+/**
+  Structure for PCH series string mapping
+**/
+struct PCH_SERIES_STRING {
+  PCH_SERIES    Series;
+  CHAR8         *String;
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+struct PCH_SERIES_STRING mSeriesStrs[] = {
+  {PchH,  "SKL PCH-H"},
+  {PchLp, "SKL PCH-LP"},
+  {PchUnknownSeries, NULL}
+};
+
+/**
+  Structure for PCH sku string mapping
+**/
+struct PCH_SKU_STRING {
+  UINT16        Id;
+  CHAR8         *String;
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+struct PCH_SKU_STRING mSkuStrs[] = {
+  //
+  // SKL PCH H Desktop LPC Device IDs
+  //
+  {V_PCH_H_LPC_DEVICE_ID_DT_SUPER_SKU, "Super SKU"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_0, "Super SKU (locked)"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_1, "H110"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_2, "H170"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_3, "Z170"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_4, "Q170"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_5, "Q150"},
+  {V_PCH_H_LPC_DEVICE_ID_DT_6, "B150"},
+  {V_PCH_H_LPC_DEVICE_ID_UNFUSE, "Unfused SKU"},
+  //
+  // SKL PCH H Server/WS LPC Device IDs
+  //
+  {V_PCH_H_LPC_DEVICE_ID_SVR_0, "C236"},
+  {V_PCH_H_LPC_DEVICE_ID_SVR_1, "C232"},
+  {V_PCH_H_LPC_DEVICE_ID_SVR_2, "CM236"},
+  {V_PCH_H_LPC_DEVICE_ID_A14B, "Super SKU (Unlocked)"},
+  {V_PCH_LBG_LPC_DEVICE_ID_UNFUSED, "LBG Unfused SKU"},
+  {V_PCH_LBG_LPC_DEVICE_ID_SS_0, "LBG SuperSKU - 0"},
+  {V_PCH_LBG_LPC_DEVICE_ID_SS_4_SD, "LBG SuperSKU - 4/SD"},
+  {V_PCH_LBG_LPC_DEVICE_ID_SS_T80_NS, "LBG SuperSKU - T80/SD"},
+  {V_PCH_LBG_LPC_DEVICE_ID_SS_1G, "LBG SuperSKU - 1G"},
+  {V_PCH_LBG_LPC_DEVICE_ID_SS_T, "LBG SuperSKU - T"},
+  {V_PCH_LBG_LPC_DEVICE_ID_SS_L, "LBG SuperSKU - L"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_0, "LBG QS/PRQ - 0"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_1G, "LBG QS/PRQ - 1G"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_2, "LBG QS/PRQ - 2"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_4, "LBG QS/PRQ - 4"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_E, "LBG QS/PRQ - E"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_M, "LBG QS/PRQ - M"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_T, "LBG QS/PRQ - T"},
+  {V_PCH_LBG_PROD_LPC_DEVICE_ID_LP, "LBG QS/PRQ - LP"},
+  //
+  // SKL PCH H Mobile LPC Device IDs
+  //
+  {V_PCH_H_LPC_DEVICE_ID_MB_0, "QM170"},
+  {V_PCH_H_LPC_DEVICE_ID_MB_1, "HM170"},
+  {V_PCH_H_LPC_DEVICE_ID_MB_2, "QMS170"},
+  {V_PCH_H_LPC_DEVICE_ID_MB_SUPER_SKU, "Super SKU"},
+  //
+  // SKL PCH LP Mobile LPC Device IDs
+  //
+  {V_PCH_LP_LPC_DEVICE_ID_UNFUSE, "Unfused SKU"},
+  {V_PCH_LP_LPC_DEVICE_ID_MB_SUPER_SKU, "Super SKU"},
+  {V_PCH_LP_LPC_DEVICE_ID_MB_0, "Super SKU (locked)"},
+  {V_PCH_LP_LPC_DEVICE_ID_MB_1, "(U) Base SKU"},
+  {V_PCH_LP_LPC_DEVICE_ID_MB_2, "(Y) Premium SKU"},
+  {V_PCH_LP_LPC_DEVICE_ID_MB_3, "(U) Premium  SKU"},
+  {0xFFFF, NULL}
+};
+
+/**
+  Get PCH stepping ASCII string
+  The return string is zero terminated.
+
+  @param [in]      PchStep              Pch stepping
+  @param [out]     Buffer               Output buffer of string
+  @param [in,out]  BufferSize           Size of input buffer,
+                                        and return required string size when buffer is too small.
+
+  @retval EFI_SUCCESS                   String copy successfully
+  @retval EFI_INVALID_PARAMETER         The stepping is not supported, or parameters are NULL
+  @retval EFI_BUFFER_TOO_SMALL          Input buffer size is too small
+**/
+EFI_STATUS
+PchGetSteppingStr (
+  IN     PCH_STEPPING                   PchStep,
+  OUT    CHAR8                          *Buffer,
+  IN OUT UINT32                         *BufferSize
+  )
+{
+  UINTN  Index;
+  UINT32 StrLength;
+  CHAR8  *Str;
+  EFI_STATUS Status;
+
+  if ((Buffer == NULL) || (BufferSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*BufferSize > 0) {
+    Buffer[0] = 0;
+  }
+
+  Str = NULL;
+  StrLength = 0;
+  for (Index = 0; mSteppingStrs[Index].Stepping != PchSteppingMax; Index++) {
+    if (PchStep == mSteppingStrs[Index].Stepping) {
+      StrLength = (UINT32) AsciiStrLen (mSteppingStrs[Index].String);
+      Str       = mSteppingStrs[Index].String;
+      break;
+    }
+  }
+  if (StrLength == 0) {
+    // Unsupported Stepping
+    // ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  if (*BufferSize <= StrLength) {
+    *BufferSize = StrLength + 1;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  Status = AsciiStrCpyS (Buffer, *BufferSize, Str);
+  ASSERT_EFI_ERROR(Status);
+  return Status;
+}
+
+/**
+  Get PCH series ASCII string
+  The return string is zero terminated.
+
+  @param [in]      PchSeries            Pch series
+  @param [out]     Buffer               Output buffer of string
+  @param [in,out]  BufferSize           Size of input buffer,
+                                        and return required string size when buffer is too small.
+
+  @retval EFI_SUCCESS                   String copy successfully
+  @retval EFI_INVALID_PARAMETER         The series is not supported, or parameters are NULL
+  @retval EFI_BUFFER_TOO_SMALL          Input buffer size is too small
+**/
+EFI_STATUS
+PchGetSeriesStr (
+  IN     PCH_SERIES                     PchSeries,
+  OUT    CHAR8                          *Buffer,
+  IN OUT UINT32                         *BufferSize
+  )
+{
+  UINTN  Index;
+  UINT32 StrLength;
+  CHAR8  *Str;
+  EFI_STATUS Status;
+
+  if ((Buffer == NULL) || (BufferSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*BufferSize > 0) {
+    Buffer[0] = 0;
+  }
+
+  Str = NULL;
+  StrLength = 0;
+  for (Index = 0; mSeriesStrs[Index].Series != PchUnknownSeries; Index++) {
+    if (PchSeries == mSeriesStrs[Index].Series) {
+      StrLength = (UINT32) AsciiStrLen (mSeriesStrs[Index].String);
+      Str       = mSeriesStrs[Index].String;
+      break;
+    }
+  }
+  if (StrLength == 0) {
+    // Unsupported Series
+    // ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  if (*BufferSize <= StrLength) {
+    *BufferSize = StrLength + 1;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  Status = AsciiStrCpyS (Buffer, *BufferSize, Str);
+  ASSERT_EFI_ERROR(Status);
+  return Status;
+}
+
+/**
+  Get PCH Sku ASCII string
+  The return string is zero terminated.
+
+  @param [in]      LpcDid               LPC device id
+  @param [out]     Buffer               Output buffer of string
+  @param [in,out]  BufferSize           Size of input buffer,
+                                        and return required string size when buffer is too small.
+
+  @retval EFI_SUCCESS                   String copy successfully
+  @retval EFI_INVALID_PARAMETER         The series is not supported, or parameters are NULL
+  @retval EFI_BUFFER_TOO_SMALL          Input buffer size is too small
+**/
+EFI_STATUS
+PchGetSkuStr (
+  IN     UINT16                         LpcDid,
+  OUT    CHAR8                          *Buffer,
+  IN OUT UINT32                         *BufferSize
+  )
+{
+  UINTN  Index;
+  UINT32 StrLength;
+  CHAR8  *Str;
+  EFI_STATUS Status;
+
+  if ((Buffer == NULL) || (BufferSize == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*BufferSize > 0) {
+    Buffer[0] = 0;
+  }
+
+  Str = NULL;
+  StrLength = 0;
+  for (Index = 0; mSkuStrs[Index].Id != 0xFFFF; Index++) {
+    if (LpcDid == mSkuStrs[Index].Id) {
+      StrLength = (UINT32) AsciiStrLen (mSkuStrs[Index].String);
+      Str       = mSkuStrs[Index].String;
+    }
+  }
+  if (StrLength == 0) {
+    // Unsupported Sku
+    // ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  if (*BufferSize <= StrLength) {
+    *BufferSize = StrLength + 1;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  Status = AsciiStrCpyS (Buffer, *BufferSize, Str);
+  ASSERT_EFI_ERROR(Status);
+  return Status;
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PeiDxeSmmPchInfoLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PeiDxeSmmPchInfoLib.inf
new file mode 100644
index 0000000000..0c00fb9258
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchInfoLib/PeiDxeSmmPchInfoLib.inf
@@ -0,0 +1,32 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchInfoLib
+  FILE_GUID = D43F3086-1D7E-4FF5-AE6A-3B0E15B11329
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchInfoLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+
+[Sources]
+  PchInfoLib.c
+  PchInfoStrLib.c
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PchP2sbLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PchP2sbLib.c
new file mode 100644
index 0000000000..5e8af8915d
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PchP2sbLib.c
@@ -0,0 +1,331 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <PchAccess.h>
+
+/**
+  Get P2SB pci configuration register. (This is internal function)
+  It returns register at Offset of P2SB controller and size in 1byte/2bytes/4bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[in]  Size                      Size for read. Must be 1 or 2 or 4.
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+STATIC
+EFI_STATUS
+PchP2sbCfgGet (
+  IN  UINTN                             Offset,
+  IN  UINTN                             Size,
+  OUT UINT32                            *OutData
+  )
+{
+  UINTN                                 P2sbBase;
+  BOOLEAN                               DevicePresent;
+
+  if ((Offset > 255) ||
+      ((Offset & (Size - 1)) != 0))
+  {
+    DEBUG ((DEBUG_ERROR, "PchP2sbCfgGet error. Invalid Offset: %x Size: %x", Offset, Size));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  P2sbBase      = MmPciBase (
+                    DEFAULT_PCI_BUS_NUMBER_PCH,
+                    PCI_DEVICE_NUMBER_PCH_P2SB,
+                    PCI_FUNCTION_NUMBER_PCH_P2SB
+                    );
+  DevicePresent = (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF);
+  if (!DevicePresent) {
+    MmioWrite8 (P2sbBase + R_PCH_P2SB_E0 + 1, 0);
+  }
+  ASSERT (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF);
+
+  switch (Size) {
+  case 4:
+    *(UINT32*)OutData = MmioRead32 (P2sbBase + Offset);
+    break;
+  case 2:
+    *(UINT16*)OutData = MmioRead16 (P2sbBase + Offset);
+    break;
+  case 1:
+    *(UINT8*) OutData = MmioRead8  (P2sbBase + Offset);
+    break;
+  default:
+    break;
+  }
+
+  if (!DevicePresent) {
+    MmioWrite8 (P2sbBase + R_PCH_P2SB_E0 + 1, BIT0);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Get P2SB pci configuration register.
+  It returns register at Offset of P2SB controller and size in 4bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchP2sbCfgGet32 (
+  IN  UINTN                             Offset,
+  OUT UINT32                            *OutData
+  )
+{
+  return PchP2sbCfgGet (Offset, 4, (UINT32*) OutData);
+}
+
+/**
+  Get P2SB pci configuration register.
+  It returns register at Offset of P2SB controller and size in 2bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchP2sbCfgGet16 (
+  IN  UINTN                             Offset,
+  OUT UINT16                            *OutData
+  )
+{
+  return PchP2sbCfgGet (Offset, 2, (UINT32*) OutData);
+}
+
+/**
+  Get P2SB pci configuration register.
+  It returns register at Offset of P2SB controller and size in 1byte.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchP2sbCfgGet8 (
+  IN  UINTN                             Offset,
+  OUT UINT8                             *OutData
+  )
+{
+  return PchP2sbCfgGet (Offset, 1, (UINT32*) OutData);
+}
+
+/**
+  Set P2SB pci configuration register. (This is internal function)
+  It programs register at Offset of P2SB controller and size in 1byte/2bytes/4bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[in]  Size                      Size for read. Must be 1 or 2 or 4.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+STATIC
+EFI_STATUS
+PchP2sbCfgSet (
+  IN  UINTN                             Offset,
+  IN  UINTN                             Size,
+  IN  UINT32                            AndData,
+  IN  UINT32                            OrData
+  )
+{
+  UINTN                                 P2sbBase;
+  BOOLEAN                               DevicePresent;
+  UINT32                                Data32;
+
+  if ((Offset > 255) ||
+      ((Offset & (Size - 1)) != 0))
+  {
+    DEBUG ((DEBUG_ERROR, "PchP2sbCfgSet error. Invalid Offset: %x Size: %x", Offset, Size));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data32 = 0;
+
+  P2sbBase      = MmPciBase (
+                    DEFAULT_PCI_BUS_NUMBER_PCH,
+                    PCI_DEVICE_NUMBER_PCH_P2SB,
+                    PCI_FUNCTION_NUMBER_PCH_P2SB
+                    );
+  DevicePresent = (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF);
+  if (!DevicePresent) {
+    MmioWrite8 (P2sbBase + R_PCH_P2SB_E0 + 1, 0);
+  }
+  ASSERT (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF);
+
+  switch (Size) {
+  case 4:
+    Data32 = MmioRead32 (P2sbBase + Offset);
+    Data32 &= AndData;
+    Data32 |= OrData;
+    MmioWrite32 (P2sbBase + Offset, (UINT32) Data32);
+    break;
+  case 2:
+    Data32 = MmioRead16 (P2sbBase + Offset);
+    Data32 &= AndData;
+    Data32 |= OrData;
+    MmioWrite16 (P2sbBase + Offset, (UINT16) Data32);
+    break;
+  case 1:
+    Data32 = MmioRead8 (P2sbBase + Offset);
+    Data32 &= AndData;
+    Data32 |= OrData;
+    MmioWrite8  (P2sbBase + Offset, (UINT8)  Data32);
+    break;
+  default:
+    break;
+  }
+
+  if (!DevicePresent) {
+    MmioWrite8 (P2sbBase + R_PCH_P2SB_E0 + 1, BIT0);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Set P2SB pci configuration register.
+  It programs register at Offset of P2SB controller and size in 4bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchP2sbCfgSet32 (
+  IN  UINTN                             Offset,
+  IN  UINT32                            AndData,
+  IN  UINT32                            OrData
+  )
+{
+  return PchP2sbCfgSet (Offset, 4, AndData, OrData);
+}
+
+/**
+  Set P2SB pci configuration register.
+  It programs register at Offset of P2SB controller and size in 2bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchP2sbCfgSet16 (
+  IN  UINTN                             Offset,
+  IN  UINT16                            AndData,
+  IN  UINT16                            OrData
+  )
+{
+  return PchP2sbCfgSet (Offset, 2, AndData, OrData);
+}
+
+/**
+  Set P2SB pci configuration register.
+  It programs register at Offset of P2SB controller and size in 1bytes.
+  The Offset should not exceed 255 and must be aligned with size.
+  This function will be unavailable after P2SB is hidden by PSF.
+
+  @param[in]  Offset                    Register offset of P2SB controller.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchP2sbCfgSet8 (
+  IN  UINTN                             Offset,
+  IN  UINT8                             AndData,
+  IN  UINT8                             OrData
+  )
+{
+  return PchP2sbCfgSet (Offset, 1, AndData, OrData);
+}
+
+/**
+  Hide P2SB device.
+
+  @param[in]  P2sbBase                  Pci base address of P2SB controller.
+
+  @retval EFI_SUCCESS                   Always return success.
+**/
+EFI_STATUS
+PchHideP2sb (
+  IN  UINTN                             P2sbBase
+  )
+{
+  MmioWrite8 (P2sbBase + R_PCH_P2SB_E0 + 1, BIT0);
+  return EFI_SUCCESS;
+}
+
+/**
+  Reveal P2SB device.
+  Also return the original P2SB status which is for Hidding P2SB or not after.
+  If OrgStatus is not NULL, then TRUE means P2SB is unhidden,
+  and FALSE means P2SB is hidden originally.
+
+  @param[in]  P2sbBase                  Pci base address of P2SB controller.
+  @param[out] OrgStatus                 Original P2SB hidding/unhidden status
+
+  @retval EFI_SUCCESS                   Always return success.
+**/
+EFI_STATUS
+PchRevealP2sb (
+  IN  UINTN                             P2sbBase,
+  OUT BOOLEAN                           *OrgStatus
+  )
+{
+  BOOLEAN                               DevicePresent;
+
+  DevicePresent = (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF);
+  if (OrgStatus != NULL) {
+    *OrgStatus = DevicePresent;
+  }
+  if (!DevicePresent) {
+    MmioWrite8 (P2sbBase + R_PCH_P2SB_E0 + 1, 0);
+  }
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PeiDxeSmmPchP2sbLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PeiDxeSmmPchP2sbLib.inf
new file mode 100644
index 0000000000..d659aed8dc
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchP2sbLib/PeiDxeSmmPchP2sbLib.inf
@@ -0,0 +1,30 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchP2sbLib
+  FILE_GUID = FB044F6F-5F9F-48AB-AE12-1C0B829C8AD7
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchP2sbLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Sources]
+  PchP2sbLib.c
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PchPcrLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PchPcrLib.c
new file mode 100644
index 0000000000..5bb0f13eeb
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PchPcrLib.c
@@ -0,0 +1,453 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <PchAccess.h>
+#include <Library/PchInfoLib.h>
+
+/**
+  Read PCR register. (This is internal function)
+  It returns PCR register and size in 1byte/2bytes/4bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of this Port ID
+  @param[in]  Size                      Size for read. Must be 1 or 2 or 4.
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+STATIC
+EFI_STATUS
+PchPcrRead (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINTN                             Size,
+  OUT UINT32                            *OutData
+  )
+{
+  if ((Offset & (Size - 1)) != 0) {
+    DEBUG ((DEBUG_ERROR, "PchPcrRead error. Invalid Offset: %x Size: %x", Offset, Size));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // @todo SKL PCH: check PID that not expected to use this routine, such as CAM_FLIS, CSME0
+  //
+
+  switch (Size) {
+  case 4:
+    *(UINT32*)OutData = MmioRead32 (PCH_PCR_ADDRESS (Pid, Offset));
+    break;
+  case 2:
+    *(UINT16*)OutData = MmioRead16 (PCH_PCR_ADDRESS (Pid, Offset));
+    break;
+  case 1:
+    *(UINT8*) OutData = MmioRead8  (PCH_PCR_ADDRESS (Pid, Offset));
+    break;
+  default:
+    break;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Read PCR register.
+  It returns PCR register and size in 4bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of this Port ID
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrRead32 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  OUT UINT32                            *OutData
+  )
+{
+  return PchPcrRead (Pid, Offset, 4, (UINT32*) OutData);
+}
+
+/**
+  Read PCR register.
+  It returns PCR register and size in 2bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of this Port ID
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrRead16 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  OUT UINT16                            *OutData
+  )
+{
+  return PchPcrRead (Pid, Offset, 2, (UINT32*) OutData);
+}
+
+/**
+  Read PCR register.
+  It returns PCR register and size in 1bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of this Port ID
+  @param[out] OutData                   Buffer of Output Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrRead8 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  OUT UINT8                             *OutData
+  )
+{
+  return PchPcrRead (Pid, Offset, 1, (UINT32*) OutData);
+}
+
+BOOLEAN
+PchPcrWriteMmioCheck (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset
+  )
+{
+DEBUG_CODE_BEGIN();
+  PCH_SERIES  PchSeries;
+
+  PchSeries = GetPchSeries ();
+  //
+  // 1. USB2 AFE register must use SBI method
+  //
+
+  //
+  // 2. GPIO unlock register field must use SBI method
+  //
+  if (Pid == PID_GPIOCOM0) {
+    if (((PchSeries == PchLp) &&
+      ((Offset == R_PCH_LP_PCR_GPIO_GPP_A_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_A_PADCFGLOCKTX) ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_B_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_B_PADCFGLOCKTX))) ||
+       ((PchSeries == PchH) &&
+      ((Offset == R_PCH_H_PCR_GPIO_GPP_A_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_A_PADCFGLOCKTX) ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_B_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_B_PADCFGLOCKTX))))
+    {
+      return FALSE;
+    }
+  }
+  if (Pid == PID_GPIOCOM1) {
+    if (((PchSeries == PchLp) &&
+      ((Offset == R_PCH_LP_PCR_GPIO_GPP_C_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_C_PADCFGLOCKTX) ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_D_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_D_PADCFGLOCKTX) ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_E_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_E_PADCFGLOCKTX))) ||
+       ((PchSeries == PchH) &&
+      ((Offset == R_PCH_H_PCR_GPIO_GPP_C_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_C_PADCFGLOCKTX) ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_D_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_D_PADCFGLOCKTX) ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_E_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_E_PADCFGLOCKTX) ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_F_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_F_PADCFGLOCKTX) ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_G_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_G_PADCFGLOCKTX) ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_H_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_H_PADCFGLOCKTX))))
+    {
+      return FALSE;
+    }
+  }
+  if (Pid == PID_GPIOCOM2) {
+    if (((PchSeries == PchLp) &&
+      ((Offset == R_PCH_LP_PCR_GPIO_GPD_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPD_PADCFGLOCKTX))) ||
+       ((PchSeries == PchH) &&
+      ((Offset == R_PCH_H_PCR_GPIO_GPD_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPD_PADCFGLOCKTX))))
+    {
+      return FALSE;
+    }
+  }
+  if (Pid == PID_GPIOCOM3) {
+    if (((PchSeries == PchLp) &&
+      ((Offset == R_PCH_LP_PCR_GPIO_GPP_F_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_F_PADCFGLOCKTX) ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_G_PADCFGLOCK)   ||
+       (Offset == R_PCH_LP_PCR_GPIO_GPP_G_PADCFGLOCKTX))) ||
+       ((PchSeries == PchH) &&
+      ((Offset == R_PCH_H_PCR_GPIO_GPP_I_PADCFGLOCK)   ||
+       (Offset == R_PCH_H_PCR_GPIO_GPP_I_PADCFGLOCKTX))))
+    {
+      return FALSE;
+    }
+  }
+  //
+  // 3. CIO2 FLIS regsiter must use SBI method
+  //
+
+  //
+  // 4. CSME0 based PCR should use the SBI method due to the FID requirement
+  //
+  if (Pid == PID_CSME0) {
+    return FALSE;
+  }
+DEBUG_CODE_END();
+  return TRUE;
+
+}
+
+/**
+  Write PCR register. (This is internal function)
+  It programs PCR register and size in 1byte/2bytes/4bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  Size                      Size for read. Must be 1 or 2 or 4.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+STATIC
+EFI_STATUS
+PchPcrWrite (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINTN                             Size,
+  IN  UINT32                            InData
+  )
+{
+  if ((Offset & (Size - 1)) != 0) {
+    DEBUG ((DEBUG_ERROR, "PchPcrWrite error. Invalid Offset: %x Size: %x", Offset, Size));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+DEBUG_CODE_BEGIN();
+  if (!PchPcrWriteMmioCheck (Pid, Offset)) {
+    DEBUG ((DEBUG_ERROR, "PchPcrWrite error. Pid: %x Offset: %x should access through SBI interface", Pid, Offset));
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+DEBUG_CODE_END();
+
+  //
+  // Write the PCR register with provided data
+  // Then read back PCR register to prevent from back to back write.
+  //
+  switch (Size) {
+    case 4:
+      MmioWrite32 (PCH_PCR_ADDRESS (Pid, Offset), (UINT32)InData);
+      break;
+    case 2:
+      MmioWrite16 (PCH_PCR_ADDRESS (Pid, Offset), (UINT16)InData);
+      break;
+    case 1:
+      MmioWrite8  (PCH_PCR_ADDRESS (Pid, Offset), (UINT8) InData);
+      break;
+    default:
+      break;
+  }
+  MmioRead32  (PCH_PCR_ADDRESS (PID_LPC, R_PCH_PCR_LPC_GCFD));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Write PCR register.
+  It programs PCR register and size in 4bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  InData                    Input Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrWrite32 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINT32                            InData
+  )
+{
+  return PchPcrWrite (Pid, Offset, 4, InData);
+}
+
+/**
+  Write PCR register.
+  It programs PCR register and size in 2bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  InData                    Input Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrWrite16 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINT16                            InData
+  )
+{
+  return PchPcrWrite (Pid, Offset, 2, InData);
+}
+
+/**
+  Write PCR register.
+  It programs PCR register and size in 1bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  InData                    Input Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrWrite8 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINT8                             InData
+  )
+{
+  return PchPcrWrite (Pid, Offset, 1, InData);
+}
+
+/**
+  Write PCR register.
+  It programs PCR register and size in 4bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrAndThenOr32 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINT32                            AndData,
+  IN  UINT32                            OrData
+  )
+{
+  EFI_STATUS                            Status;
+  UINT32                                Data32;
+
+  Data32 = 0x00;
+  Status  = PchPcrRead (Pid, Offset, 4, &Data32);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Data32 &= AndData;
+  Data32 |= OrData;
+  Status  = PchPcrWrite (Pid, Offset, 4, Data32);
+  return Status;
+}
+
+/**
+  Write PCR register.
+  It programs PCR register and size in 2bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrAndThenOr16 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINT16                            AndData,
+  IN  UINT16                            OrData
+  )
+{
+  EFI_STATUS                            Status;
+  UINT16                                Data16;
+
+  Data16 = 0x00;
+  Status  = PchPcrRead (Pid, Offset, 2, (UINT32*) &Data16);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Data16 &= AndData;
+  Data16 |= OrData;
+  Status  = PchPcrWrite (Pid, Offset, 2, Data16);
+  return Status;
+}
+
+/**
+  Write PCR register.
+  It programs PCR register and size in 1bytes.
+  The Offset should not exceed 0xFFFF and must be aligned with size.
+
+  @param[in]  Pid                       Port ID
+  @param[in]  Offset                    Register offset of Port ID.
+  @param[in]  AndData                   AND Data. Must be the same size as Size parameter.
+  @param[in]  OrData                    OR Data. Must be the same size as Size parameter.
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_INVALID_PARAMETER         Invalid offset passed.
+**/
+EFI_STATUS
+PchPcrAndThenOr8 (
+  IN  PCH_SBI_PID                       Pid,
+  IN  UINT16                            Offset,
+  IN  UINT8                             AndData,
+  IN  UINT8                             OrData
+  )
+{
+  EFI_STATUS                            Status;
+  UINT8                                 Data8;
+
+  Status  = PchPcrRead (Pid, Offset, 1, (UINT32*) &Data8);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Data8 &= AndData;
+  Data8 |= OrData;
+  Status  = PchPcrWrite (Pid, Offset, 1, Data8);
+  return Status;
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PeiDxeSmmPchPcrLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PeiDxeSmmPchPcrLib.inf
new file mode 100644
index 0000000000..05da628164
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPcrLib/PeiDxeSmmPchPcrLib.inf
@@ -0,0 +1,31 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchPcrLib
+  FILE_GUID = 117C8D19-445B-46BF-B624-109F63709375
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchPcrLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+  PchInfoLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Sources]
+  PchPcrLib.c
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PchPmcLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PchPmcLib.c
new file mode 100644
index 0000000000..9ac1b1ee66
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PchPmcLib.c
@@ -0,0 +1,153 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <PchAccess.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PchPmcLib.h>
+
+/**
+  Query PCH to determine the Pm Status
+  NOTE:
+  It's matter when did platform code use this library, since some status could be cleared by write one clear.
+  Therefore this funciton is not always return the same result in one boot.
+  It's suggested that platform code read this status in the beginning of post.
+  For the ColdBoot case, this function only returns one case of the cold boot. Some cold boot case might
+  depends on the power cycle scenario and should check with different condtion.
+
+  @param[in] PmStatus - The Pch Pm Status to be probed
+
+  @retval Return TRUE if Status querried is Valid or FALSE if otherwise
+**/
+BOOLEAN
+GetPchPmStatus (
+  PCH_PM_STATUS PmStatus
+  )
+{
+  UINTN  PmcRegBase;
+  UINT32 PchPwrmBase;
+  UINT32 PmConA;
+  UINT32 PmConB;
+  UINT32 GblRst0;
+
+  PmcRegBase = MmPciBase (
+                 DEFAULT_PCI_BUS_NUMBER_PCH,
+                 PCI_DEVICE_NUMBER_PCH_PMC,
+                 PCI_FUNCTION_NUMBER_PCH_PMC
+                 );
+  PchPwrmBaseGet (&PchPwrmBase);
+
+  PmConA     = MmioRead32 (PmcRegBase + R_PCH_PMC_GEN_PMCON_A);
+  PmConB     = MmioRead32 (PmcRegBase + R_PCH_PMC_GEN_PMCON_B);
+  GblRst0    = MmioRead32 (PchPwrmBase + R_PCH_PWRM_124);
+
+  switch(PmStatus){
+        case PchWarmBoot:
+
+      if (PmConA & B_PCH_PMC_GEN_PMCON_A_MEM_SR) {
+        return TRUE;
+      }
+      break;
+
+    case PwrFlr:
+      if (PmConB & B_PCH_PMC_GEN_PMCON_B_PWR_FLR) {
+        return TRUE;
+      }
+      break;
+
+    case PwrFlrSys:
+      if (GblRst0 & BIT12) {
+        return TRUE;
+      }
+      break;
+
+    case PwrFlrPch:
+      if (GblRst0 & BIT11) {
+        return TRUE;
+      }
+      break;
+
+        case PchColdBoot:
+      ///
+      /// Check following conditions for cold boot.
+      ///
+      if ((GblRst0 & BIT11) &&  // PCHPWR_FLR
+          (GblRst0 & BIT12) &&  // SYSPWR_FLR
+          (!(PmConA & B_PCH_PMC_GEN_PMCON_A_MEM_SR))) {
+        return TRUE;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  return FALSE;
+}
+
+/**
+  Funtion to check if Battery lost or CMOS cleared.
+
+  @reval TRUE  Battery is always present.
+  @reval FALSE CMOS is cleared.
+**/
+BOOLEAN
+EFIAPI
+PchIsRtcBatteryGood (
+  VOID
+  )
+{
+  UINTN    Data;
+  UINTN    PmcBaseAddress;
+
+  //
+  // Check if the CMOS battery is present
+  // Checks RTC_PWR_STS bit in the GEN_PMCON_3 register
+  //
+  PmcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_PMC,
+                     PCI_FUNCTION_NUMBER_PCH_PMC
+                     );
+
+  Data = MmioRead32 (PmcBaseAddress + R_PCH_PMC_GEN_PMCON_B);
+  if ((Data & B_PCH_PMC_GEN_PMCON_B_RTC_PWR_STS) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+  Funtion to check if DWR occurs
+
+  @reval TRUE DWR occurs
+  @reval FALSE Normal boot flow
+**/
+BOOLEAN
+EFIAPI
+PchIsDwrFlow (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      PchPwrmBase;
+
+  Status = PchPwrmBaseGet (&PchPwrmBase);
+  ASSERT (PchPwrmBase != 0);
+
+  if ((PchPwrmBase != 0) &&
+      (MmioRead32 (PchPwrmBase + R_PCH_PWRM_HPR_CAUSE0) & B_PCH_PWRM_HPR_CAUSE0_GBL_TO_HOST)) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PeiDxeSmmPchPmcLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PeiDxeSmmPchPmcLib.inf
new file mode 100644
index 0000000000..c0ec7b70e4
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchPmcLib/PeiDxeSmmPchPmcLib.inf
@@ -0,0 +1,31 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchPmcLib
+  FILE_GUID = 9D60C364-5086-41E3-BC9D-C62AB7233DBF
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchPmcLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+  PchCycleDecodingLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Sources]
+  PchPmcLib.c
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PchSbiAccessLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PchSbiAccessLib.c
new file mode 100644
index 0000000000..6f0030ac33
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PchSbiAccessLib.c
@@ -0,0 +1,370 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <PchAccess.h>
+#include <Library/PchP2sbLib.h>
+#include <Library/PchSbiAccessLib.h>
+
+/**
+  Execute PCH SBI message
+  Take care of that there is no lock protection when using SBI programming in both POST time and SMI.
+  It will clash with POST time SBI programming when SMI happen.
+  Programmer MUST do the save and restore opration while using the PchSbiExecution inside SMI
+  to prevent from racing condition.
+  This function will reveal P2SB and hide P2SB if it's originally hidden. If more than one SBI access
+  needed, it's better to unhide the P2SB before calling and hide it back after done.
+
+  When the return value is "EFI_SUCCESS", the "Response" do not need to be checked as it would have been
+  SBI_SUCCESS. If the return value is "EFI_DEVICE_ERROR", then this would provide additional information
+  when needed.
+
+  @param[in] Pid                        Port ID of the SBI message
+  @param[in] Offset                     Offset of the SBI message
+  @param[in] Opcode                     Opcode
+  @param[in] Posted                     Posted message
+  @param[in, out] Data32                Read/Write data
+  @param[out] Response                  Response
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_DEVICE_ERROR              Transaction fail
+  @retval EFI_INVALID_PARAMETER         Invalid parameter
+**/
+EFI_STATUS
+EFIAPI
+PchSbiExecution (
+  IN     PCH_SBI_PID                    Pid,
+  IN     UINT64                         Offset,
+  IN     PCH_SBI_OPCODE                 Opcode,
+  IN     BOOLEAN                        Posted,
+  IN OUT UINT32                         *Data32,
+  OUT    UINT8                          *Response
+  )
+{
+
+
+  return PchSbiExecutionEx ( Pid,
+                             Offset,
+                             Opcode,
+                             Posted,
+                             0x000F,
+                             0x0000,
+                             0x0000,
+                             Data32,
+                             Response
+                             );
+}
+
+/**
+  Full function for executing PCH SBI message
+  Take care of that there is no lock protection when using SBI programming in both POST time and SMI.
+  It will clash with POST time SBI programming when SMI happen.
+  Programmer MUST do the save and restore opration while using the PchSbiExecution inside SMI
+  to prevent from racing condition.
+  This function will reveal P2SB and hide P2SB if it's originally hidden. If more than one SBI access
+  needed, it's better to unhide the P2SB before calling and hide it back after done.
+
+  When the return value is "EFI_SUCCESS", the "Response" do not need to be checked as it would have been
+  SBI_SUCCESS. If the return value is "EFI_DEVICE_ERROR", then this would provide additional information
+  when needed.
+
+  @param[in] Pid                        Port ID of the SBI message
+  @param[in] Offset                     Offset of the SBI message
+  @param[in] Opcode                     Opcode
+  @param[in] Posted                     Posted message
+  @param[in] Fbe                        First byte enable
+  @param[in] Bar                        Bar
+  @param[in] Fid                        Function ID
+  @param[in, out] Data32                Read/Write data
+  @param[out] Response                  Response
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_DEVICE_ERROR              Transaction fail
+  @retval EFI_INVALID_PARAMETER         Invalid parameter
+**/
+EFI_STATUS
+EFIAPI
+PchSbiExecutionEx (
+  IN     PCH_SBI_PID                    Pid,
+  IN     UINT64                         Offset,
+  IN     PCH_SBI_OPCODE                 Opcode,
+  IN     BOOLEAN                        Posted,
+  IN     UINT16                         Fbe,
+  IN     UINT16                         Bar,
+  IN     UINT16                         Fid,
+  IN OUT UINT32                         *Data32,
+  OUT    UINT8                          *Response
+  )
+{
+  EFI_STATUS                            Status;
+  UINTN                                 P2sbBase;
+  BOOLEAN                               P2sbOrgStatus;
+  UINTN                                 Timeout;
+  UINT16                                SbiStat;
+
+  //
+  // Check opcode valid
+  //
+  switch (Opcode) {
+    case PciConfigRead:
+    case PciConfigWrite:
+    case PrivateControlRead:
+    case PrivateControlWrite:
+    case GpioLockUnlock:
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+      break;
+  }
+
+  P2sbOrgStatus = FALSE;
+  P2sbBase      = MmPciBase (
+                    DEFAULT_PCI_BUS_NUMBER_PCH,
+                    PCI_DEVICE_NUMBER_PCH_P2SB,
+                    PCI_FUNCTION_NUMBER_PCH_P2SB
+                    );
+  PchRevealP2sb (P2sbBase, &P2sbOrgStatus);
+  ///
+  /// BWG Section 2.2.1
+  /// 1. Poll P2SB PCI offset D8h[0] = 0b
+  /// Make sure the previous opeartion is completed.
+  ///
+  Timeout = 0xFFFFFFF;
+  while (Timeout > 0){
+    SbiStat = MmioRead16 (P2sbBase + R_PCH_P2SB_SBISTAT);
+    if ((SbiStat & B_PCH_P2SB_SBISTAT_INITRDY) == 0) {
+        break;
+    }
+    Timeout--;
+  }
+  if (Timeout == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto ExitPchSbiExecutionEx;
+  }
+  //
+  // Initial Response status
+  //
+  *Response = SBI_INVALID_RESPONSE;
+  Status    = EFI_SUCCESS;
+  SbiStat   = 0;
+  ///
+  /// 2. Write P2SB PCI offset D0h[31:0] with Address and Destination Port ID
+  ///
+  MmioWrite32 (P2sbBase + R_PCH_P2SB_SBIADDR, (UINT32) ((Pid << 24) | (UINT16)Offset));
+  ///
+  /// 3. Write P2SB PCI offset DCh[31:0] with extended address, which is expected to be 0 in SKL PCH.
+  ///
+  MmioWrite32 (P2sbBase + R_PCH_P2SB_SBIEXTADDR, (UINT32) RShiftU64 (Offset, 16));
+  ///
+  /// 5. Set P2SB PCI offset D8h[15:8] = 00000110b for read
+  ///    Set P2SB PCI offset D8h[15:8] = 00000111b for write
+  //
+  // Set SBISTAT[15:8] to the opcode passed in
+  // Set SBISTAT[7] to the posted passed in
+  //
+  MmioAndThenOr16 (
+    (P2sbBase + R_PCH_P2SB_SBISTAT),
+    (UINT16) ~(B_PCH_P2SB_SBISTAT_OPCODE | B_PCH_P2SB_SBISTAT_POSTED),
+    (UINT16) ((Opcode << 8) | (Posted << 7))
+    );
+  ///
+  /// 6. Write P2SB PCI offset DAh[15:0] = F000h
+  ///
+  //
+  // Set RID[15:0] = Fbe << 12 | Bar << 8 | Fid
+  //
+  MmioWrite16 (
+    (P2sbBase + R_PCH_P2SB_SBIRID),
+    (((Fbe & 0x000F) << 12) | ((Bar & 0x0007) << 8) | (Fid & 0x00FF))
+    );
+
+  switch (Opcode) {
+    case PciConfigWrite:
+    case PrivateControlWrite:
+    case GpioLockUnlock:
+      ///
+      /// 4. Write P2SB PCI offset D4h[31:0] with the intended data accordingly
+      ///
+      MmioWrite32 ((P2sbBase + R_PCH_P2SB_SBIDATA), *Data32);
+      break;
+    default:
+      ///
+      /// 4. Write P2SB PCI offset D4h[31:0] with dummy data such as 0,
+      /// because all D0-DFh register range must be touched in SKL PCH
+      /// for a successful SBI transaction.
+      ///
+      MmioWrite32 ((P2sbBase + R_PCH_P2SB_SBIDATA), 0);
+      break;
+  }
+  ///
+  /// 7. Set P2SB PCI offset D8h[0] = 1b, Poll P2SB PCI offset D8h[0] = 0b
+  ///
+  //
+  // Set SBISTAT[0] = 1b, trigger the SBI operation
+  //
+  MmioOr16 (P2sbBase + R_PCH_P2SB_SBISTAT, (UINT16) B_PCH_P2SB_SBISTAT_INITRDY);
+  //
+  // Poll SBISTAT[0] = 0b, Polling for Busy bit
+  //
+  Timeout = 0xFFFFFFF;
+  while (Timeout > 0){
+    SbiStat = MmioRead16 (P2sbBase + R_PCH_P2SB_SBISTAT);
+    if ((SbiStat & B_PCH_P2SB_SBISTAT_INITRDY) == 0) {
+        break;
+    }
+    Timeout--;
+  }
+  if (Timeout == 0) {
+    //
+    // If timeout, it's fatal error.
+    //
+    Status = EFI_DEVICE_ERROR;
+  } else {
+    ///
+    /// 8. Check if P2SB PCI offset D8h[2:1] = 00b for successful transaction
+    ///
+    *Response = (UINT8)((SbiStat & B_PCH_P2SB_SBISTAT_RESPONSE) >> N_PCH_P2SB_SBISTAT_RESPONSE);
+    if (*Response == SBI_SUCCESSFUL) {
+      switch (Opcode) {
+      case PciConfigRead:
+      case PrivateControlRead:
+        ///
+        /// 9. Read P2SB PCI offset D4h[31:0] for SBI data
+        ///
+        *Data32 = MmioRead32 (P2sbBase + R_PCH_P2SB_SBIDATA);
+        break;
+      default:
+        break;
+      }
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+ExitPchSbiExecutionEx:
+  if (!P2sbOrgStatus) {
+    PchHideP2sb (P2sbBase);
+  }
+  return Status;
+}
+
+/**
+  This function saves all PCH SBI registers.
+  The save and restore operations must be done while using the PchSbiExecution inside SMM.
+  It prevents the racing condition of PchSbiExecution re-entry between POST and SMI.
+  Before using this function, make sure the P2SB is not hidden.
+
+  @param[in, out] PchSbiRegister        Structure for saving the registers
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_DEVICE_ERROR              Device is hidden.
+**/
+EFI_STATUS
+EFIAPI
+PchSbiRegisterSave (
+  IN OUT PCH_SBI_REGISTER_STRUCT        *PchSbiRegister
+  )
+{
+  UINTN                                 P2sbBase;
+  UINTN                                 Timeout;
+  UINT16                                SbiStat;
+
+  P2sbBase      = MmPciBase (
+                    DEFAULT_PCI_BUS_NUMBER_PCH,
+                    PCI_DEVICE_NUMBER_PCH_P2SB,
+                    PCI_FUNCTION_NUMBER_PCH_P2SB
+                    );
+  if (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Make sure it's not busy.
+  // Poll SBISTAT[0] = 0b
+  //
+  Timeout = 0xFFFFFFF;
+  while ((Timeout--) > 0){
+    SbiStat = MmioRead16 (P2sbBase + R_PCH_P2SB_SBISTAT);
+    if ((SbiStat & B_PCH_P2SB_SBISTAT_INITRDY) == 0) {
+        break;
+    }
+  }
+  if (Timeout == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Save original SBI registers
+  //
+  PchSbiRegister->SbiAddr    = MmioRead32 (P2sbBase + R_PCH_P2SB_SBIADDR);
+  PchSbiRegister->SbiExtAddr = MmioRead32 (P2sbBase + R_PCH_P2SB_SBIEXTADDR);
+  PchSbiRegister->SbiData    = MmioRead32 (P2sbBase + R_PCH_P2SB_SBIDATA);
+  PchSbiRegister->SbiStat    = MmioRead16 (P2sbBase + R_PCH_P2SB_SBISTAT);
+  PchSbiRegister->SbiRid     = MmioRead16 (P2sbBase + R_PCH_P2SB_SBIRID);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function restores all PCH SBI registers
+  The save and restore operations must be done while using the PchSbiExecution inside SMM.
+  It prevents the racing condition of PchSbiExecution re-entry between POST and SMI.
+  Before using this function, make sure the P2SB is not hidden.
+
+  @param[in] PchSbiRegister             Structure for restoring the registers
+
+  @retval EFI_SUCCESS                   Successfully completed.
+  @retval EFI_DEVICE_ERROR              Device is hidden.
+**/
+EFI_STATUS
+EFIAPI
+PchSbiRegisterRestore (
+  IN PCH_SBI_REGISTER_STRUCT            *PchSbiRegister
+  )
+{
+  UINTN                                 P2sbBase;
+  UINTN                                 Timeout;
+  UINT16                                SbiStat;
+
+  P2sbBase      = MmPciBase (
+                    DEFAULT_PCI_BUS_NUMBER_PCH,
+                    PCI_DEVICE_NUMBER_PCH_P2SB,
+                    PCI_FUNCTION_NUMBER_PCH_P2SB
+                    );
+  if (MmioRead16 (P2sbBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Make sure it's not busy.
+  // Poll SBISTAT[0] = 0b
+  //
+  Timeout = 0xFFFFFFF;
+  while ((Timeout--) > 0){
+    SbiStat = MmioRead16 (P2sbBase + R_PCH_P2SB_SBISTAT);
+    if ((SbiStat & B_PCH_P2SB_SBISTAT_INITRDY) == 0) {
+        break;
+    }
+  }
+  if (Timeout == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Restore original SBI registers
+  //
+  MmioWrite32 (P2sbBase + R_PCH_P2SB_SBIADDR   , PchSbiRegister->SbiAddr);
+  MmioWrite32 (P2sbBase + R_PCH_P2SB_SBIEXTADDR, PchSbiRegister->SbiExtAddr);
+  MmioWrite32 (P2sbBase + R_PCH_P2SB_SBIDATA   , PchSbiRegister->SbiData);
+  MmioWrite16 (P2sbBase + R_PCH_P2SB_SBISTAT   , PchSbiRegister->SbiStat);
+  MmioWrite16 (P2sbBase + R_PCH_P2SB_SBIRID    , PchSbiRegister->SbiRid);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PeiDxeSmmPchSbiAccessLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PeiDxeSmmPchSbiAccessLib.inf
new file mode 100644
index 0000000000..eaba8483ba
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiDxeSmmPchSbiAccessLib/PeiDxeSmmPchSbiAccessLib.inf
@@ -0,0 +1,31 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION = 0x00010017
+  BASE_NAME = PeiDxeSmmPchSbiAccessLib
+  FILE_GUID = 96ECB0FB-A975-4DC8-B88A-D90C3378CE87
+  VERSION_STRING = 1.0
+  MODULE_TYPE = BASE
+  LIBRARY_CLASS = PchSbiAccessLib
+
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  DebugLib
+  MmPciLib
+  PchP2sbLib
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Sources]
+  PchSbiAccessLib.c
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PchPrintPolicy.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PchPrintPolicy.c
new file mode 100644
index 0000000000..33fa00b25f
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PchPrintPolicy.c
@@ -0,0 +1,730 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiPchPolicyLibrary.h"
+
+/**
+  Print PCH_USB_CONFIG and serial out.
+
+  @param[in] UsbConfig         Pointer to a PCH_USB_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintUsbConfig (
+  IN CONST PCH_USB_CONFIG     *UsbConfig
+  )
+{
+  UINT32 i;
+
+  DEBUG ((DEBUG_INFO, "------------------ PCH USB Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " UsbPrecondition= %x\n", UsbConfig->UsbPrecondition));
+  DEBUG ((DEBUG_INFO, " DisableComplianceMode= %x\n", UsbConfig->DisableComplianceMode));
+
+  for (i = 0; i < GetPchUsbMaxPhysicalPortNum (); i++) {
+    DEBUG ((DEBUG_INFO, " PortUsb20[%d].Enabled= %x\n", i, UsbConfig->PortUsb20[i].Enable));
+    DEBUG ((DEBUG_INFO, " PortUsb20[%d].OverCurrentPin= OC%x\n", i, UsbConfig->PortUsb20[i].OverCurrentPin));
+    DEBUG ((DEBUG_INFO, " PortUsb20[%d].Afe.Petxiset= %x\n", i, UsbConfig->PortUsb20[i].Afe.Petxiset));
+    DEBUG ((DEBUG_INFO, " PortUsb20[%d].Afe.Txiset= %x\n", i, UsbConfig->PortUsb20[i].Afe.Txiset));
+    DEBUG ((DEBUG_INFO, " PortUsb20[%d].Afe.Predeemp= %x\n", i, UsbConfig->PortUsb20[i].Afe.Predeemp));
+    DEBUG ((DEBUG_INFO, " PortUsb20[%d].Afe.Pehalfbit= %x\n", i, UsbConfig->PortUsb20[i].Afe.Pehalfbit));
+  }
+
+  for (i = 0; i < GetPchXhciMaxUsb3PortNum (); i++) {
+    DEBUG ((DEBUG_INFO, " PortUsb30[%d] Enabled= %x\n", i, UsbConfig->PortUsb30[i].Enable));
+    DEBUG ((DEBUG_INFO, " PortUsb30[%d].OverCurrentPin= OC%x\n", i, UsbConfig->PortUsb30[i].OverCurrentPin));
+    DEBUG ((DEBUG_INFO, " PortUsb30[%d].HsioTxDeEmph         = %x\n", i, UsbConfig->PortUsb30[i].HsioTxDeEmph));
+    DEBUG ((DEBUG_INFO, " PortUsb30[%d].HsioTxDeEmphEnable   = %x\n", i, UsbConfig->PortUsb30[i].HsioTxDeEmphEnable));
+    DEBUG ((DEBUG_INFO, " PortUsb30[%d].HsioTxDownscaleAmp          = %x\n", i, UsbConfig->PortUsb30[i].HsioTxDownscaleAmp));
+    DEBUG ((DEBUG_INFO, " PortUsb30[%d].HsioTxDownscaleAmpEnable    = %x\n", i, UsbConfig->PortUsb30[i].HsioTxDownscaleAmpEnable));
+  }
+
+  DEBUG ((DEBUG_INFO, " XdciConfig.Enable= %x\n", UsbConfig->XdciConfig.Enable));
+
+  for (i = 0; i < PCH_XHCI_MAX_SSIC_PORT_COUNT; i++) {
+    DEBUG ((DEBUG_INFO, " SsicPort[%d].Enable    = %x\n", i, UsbConfig->SsicConfig.SsicPort[i].Enable));
+  }
+
+}
+
+/**
+  Print PCH_PCIE_CONFIG and serial out.
+
+  @param[in] PcieConfig         Pointer to a PCH_PCIE_CONFIG that provides the platform setting
+  @param[in] HsioPcieConfig     Pointer to a PCH_HSIO_PCIE_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintPcieConfig (
+  IN CONST PCH_PCIE_CONFIG      *PcieConfig,
+  IN CONST PCH_HSIO_PCIE_CONFIG *HsioPcieConfig
+  )
+{
+  UINT32 i;
+
+  DEBUG ((DEBUG_INFO, "------------------ PCH PCIE Config ------------------\n"));
+  for (i = 0; i < GetPchMaxPciePortNum (); i++) {
+    DEBUG ((DEBUG_INFO, " RootPort[%d] Enabled= %x\n", i, PcieConfig->RootPort[i].Enable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HotPlug= %x\n", i, PcieConfig->RootPort[i].HotPlug));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] PmSci= %x\n", i, PcieConfig->RootPort[i].PmSci));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] ExtSync= %x\n", i, PcieConfig->RootPort[i].ExtSync));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] ClkReqSupported= %x\n", i, PcieConfig->RootPort[i].ClkReqSupported));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] ClkReqNumber= %x\n", i, PcieConfig->RootPort[i].ClkReqNumber));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] ClkReqDetect= %x\n", i, PcieConfig->RootPort[i].ClkReqDetect));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] UnsupportedRequestReport= %x\n", i, PcieConfig->RootPort[i].UnsupportedRequestReport));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] FatalErrorReport= %x\n", i, PcieConfig->RootPort[i].FatalErrorReport));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] NoFatalErrorReport= %x\n", i, PcieConfig->RootPort[i].NoFatalErrorReport));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] CorrectableErrorReport= %x\n", i, PcieConfig->RootPort[i].CorrectableErrorReport));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SystemErrorOnFatalError= %x\n", i, PcieConfig->RootPort[i].SystemErrorOnFatalError));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SystemErrorOnNonFatalError= %x\n", i, PcieConfig->RootPort[i].SystemErrorOnNonFatalError));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SystemErrorOnCorrectableError= %x\n", i, PcieConfig->RootPort[i].SystemErrorOnCorrectableError));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] MaxPayload= %x\n", i, PcieConfig->RootPort[i].MaxPayload));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] AcsEnabled= %x\n", i, PcieConfig->RootPort[i].AcsEnabled));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] AdvancedErrorReporting= %x\n", i, PcieConfig->RootPort[i].AdvancedErrorReporting));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] TransmitterHalfSwing= %x\n", i, PcieConfig->RootPort[i].TransmitterHalfSwing));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] PcieSpeed= %x\n", i, PcieConfig->RootPort[i].PcieSpeed));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] Gen3EqPh3Method= %x\n", i, PcieConfig->RootPort[i].Gen3EqPh3Method));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] PhysicalSlotNumber= %x\n", i, PcieConfig->RootPort[i].PhysicalSlotNumber));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] CompletionTimeout= %x\n", i, PcieConfig->RootPort[i].CompletionTimeout));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] Aspm= %x\n", i, PcieConfig->RootPort[i].Aspm));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] L1Substates= %x\n", i, PcieConfig->RootPort[i].L1Substates));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] LtrEnable= %x\n", i, PcieConfig->RootPort[i].LtrEnable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] LtrConfigLock= %x\n", i, PcieConfig->RootPort[i].LtrConfigLock));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] LtrMaxSnoopLatency= %x\n", i, PcieConfig->RootPort[i].LtrMaxSnoopLatency));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] LtrMaxNoSnoopLatency= %x\n", i, PcieConfig->RootPort[i].LtrMaxNoSnoopLatency));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SnoopLatencyOverrideMode= %x\n", i, PcieConfig->RootPort[i].SnoopLatencyOverrideMode));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SnoopLatencyOverrideMultiplier= %x\n", i, PcieConfig->RootPort[i].SnoopLatencyOverrideMultiplier));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SnoopLatencyOverrideValue= %x\n", i, PcieConfig->RootPort[i].SnoopLatencyOverrideValue));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] NonSnoopLatencyOverrideMode= %x\n", i, PcieConfig->RootPort[i].NonSnoopLatencyOverrideMode));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] NonSnoopLatencyOverrideMultiplier= %x\n", i, PcieConfig->RootPort[i].NonSnoopLatencyOverrideMultiplier));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] NonSnoopLatencyOverrideValue= %x\n", i, PcieConfig->RootPort[i].NonSnoopLatencyOverrideValue));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SlotPowerLimitScale= %x\n", i, PcieConfig->RootPort[i].SlotPowerLimitScale));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] SlotPowerLimitValue= %x\n", i, PcieConfig->RootPort[i].SlotPowerLimitValue));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] Uptp= %x\n", i, PcieConfig->RootPort[i].Uptp));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] Dptp= %x\n", i, PcieConfig->RootPort[i].Dptp));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioRxSetCtleEnable= %x\n", i, HsioPcieConfig->Lane[i].HsioRxSetCtleEnable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioRxSetCtle= %x\n", i, HsioPcieConfig->Lane[i].HsioRxSetCtle));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen1DownscaleAmpEnable= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen1DownscaleAmpEnable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen1DownscaleAmp= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen1DownscaleAmp));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen2DownscaleAmpEnable= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen2DownscaleAmpEnable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen2DownscaleAmp= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen2DownscaleAmp));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen3DownscaleAmpEnable= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen3DownscaleAmpEnable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen3DownscaleAmp= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen3DownscaleAmp));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen1DeEmphEnable= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen1DeEmphEnable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen1DeEmph= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen1DeEmph));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen2DeEmph3p5Enable= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen2DeEmph3p5Enable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen2DeEmph3p5= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen2DeEmph3p5));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen2DeEmph6p0Enable= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen2DeEmph6p0Enable));
+    DEBUG ((DEBUG_INFO, " RootPort[%d] HsioTxGen2DeEmph6p0= %x\n", i, HsioPcieConfig->Lane[i].HsioTxGen2DeEmph6p0));
+
+  }
+  DEBUG ((DEBUG_INFO, " EnablePort8xhDecode= %x\n", PcieConfig->EnablePort8xhDecode));
+  DEBUG ((DEBUG_INFO, " PchPciePort8xhDecodePortIndex= %x\n", PcieConfig->PchPciePort8xhDecodePortIndex));
+  DEBUG ((DEBUG_INFO, " DisableRootPortClockGating= %x\n", PcieConfig->DisableRootPortClockGating));
+  DEBUG ((DEBUG_INFO, " EnablePeerMemoryWrite= %x\n", PcieConfig->EnablePeerMemoryWrite));
+  DEBUG ((DEBUG_INFO, " AllowNoLtrIccPllShutdown= %x\n", PcieConfig->AllowNoLtrIccPllShutdown));
+  DEBUG ((DEBUG_INFO, " ComplianceTestMode= %x\n", PcieConfig->ComplianceTestMode));
+  DEBUG ((DEBUG_INFO, " RpFunctionSwap= %x\n", PcieConfig->RpFunctionSwap));
+}
+
+/**
+  Print PCH_PCIE_CONFIG2 and serial out.
+
+  @param[in] PcieConfig2        Pointer to a PCH_PCIE_CONFIG2 that provides the platform setting
+
+**/
+VOID
+PchPrintPcieConfig2 (
+  IN CONST PCH_PCIE_CONFIG2  *PcieConfig2
+  )
+{
+  UINT32 Index;
+
+  DEBUG ((DEBUG_INFO, "------------------ PCH PCIE Config2 -----------------\n"));
+  for (Index = 0; Index < PCH_PCIE_SWEQ_COEFFS_MAX; Index++) {
+    DEBUG ((DEBUG_INFO, " SwEqCoeffCm[%d] = %x\n", Index, PcieConfig2->SwEqCoeffList[Index].Cm));
+    DEBUG ((DEBUG_INFO, " SwEqCoeffCp[%d] = %x\n", Index, PcieConfig2->SwEqCoeffList[Index].Cp));
+  }
+}
+
+/**
+  Print PCH_SATA_CONFIG and serial out.
+
+  @param[in] SataConfig         Pointer to a PCH_SATA_CONFIG that provides the platform setting
+  @param[in] HsioSataConfig     Pointer to a PCH_HSIO_SATA_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintSataConfig (
+    IN CONST PCH_SATA_CONFIG      *SataConfig,
+    IN VOID                       *HsioSataConfigPtr,
+    IN UINT8                       SataControllerNo
+  )
+{
+  UINT32 i;
+
+  UINT32 MaxSataPortNum;
+  PCH_HSIO_SATA_CONFIG  *HsioSataConfig;
+
+  HsioSataConfig = HsioSataConfigPtr;
+
+  if (SataControllerNo == PCH_SATA_FIRST_CONTROLLER) {
+    DEBUG ((DEBUG_INFO, "------------------- PCH Primary SATA Config ------------------\n"));
+    MaxSataPortNum = GetPchMaxSataPortNum ();
+  } else {
+    DEBUG ((DEBUG_INFO, "------------------ PCH Secondary SATA Config ------------------\n"));
+    MaxSataPortNum  = GetPchMaxsSataPortNum ();
+  }
+  DEBUG ((DEBUG_INFO, " Enable= %x\n", SataConfig->Enable));
+  DEBUG ((DEBUG_INFO, " SataMode= %x\n", SataConfig->SataMode));
+
+
+  for (i = 0; i < MaxSataPortNum; i++) {
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] Enabled= %x\n", i, SataConfig->PortSettings[i].Enable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HotPlug= %x\n", i, SataConfig->PortSettings[i].HotPlug));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] InterlockSw= %x\n", i, SataConfig->PortSettings[i].InterlockSw));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] External= %x\n", i, SataConfig->PortSettings[i].External));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] SpinUp= %x\n", i, SataConfig->PortSettings[i].SpinUp));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] SolidStateDrive= %x\n", i, SataConfig->PortSettings[i].SolidStateDrive));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] DevSlp= %x\n", i, SataConfig->PortSettings[i].DevSlp));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] EnableDitoConfig= %x\n", i, SataConfig->PortSettings[i].EnableDitoConfig));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] DmVal= %x\n", i, SataConfig->PortSettings[i].DmVal));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] DitoVal= %x\n", i, SataConfig->PortSettings[i].DitoVal));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] ZpOdd= %x\n", i, SataConfig->PortSettings[i].ZpOdd));
+
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioRxGen1EqBoostMagEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioRxGen1EqBoostMagEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioRxGen1EqBoostMag= %x\n", i, HsioSataConfig->PortLane[i].HsioRxGen1EqBoostMag));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioRxGen2EqBoostMagEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioRxGen2EqBoostMagEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioRxGen2EqBoostMag= %x\n", i, HsioSataConfig->PortLane[i].HsioRxGen2EqBoostMag));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioRxGen3EqBoostMagEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioRxGen3EqBoostMagEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioRxGen3EqBoostMag= %x\n", i, HsioSataConfig->PortLane[i].HsioRxGen3EqBoostMag));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen1DownscaleAmpEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen1DownscaleAmpEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen1DownscaleAmp= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen1DownscaleAmp));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen2DownscaleAmpEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen2DownscaleAmpEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen2DownscaleAmp= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen2DownscaleAmp));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen3DownscaleAmpEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen3DownscaleAmpEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen3DownscaleAmp= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen3DownscaleAmp));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen1DeEmphEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen1DeEmphEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen1DeEmph= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen1DeEmph));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen2DeEmphEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen2DeEmphEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen2DeEmph= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen2DeEmph));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen3DeEmphEnable= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen3DeEmphEnable));
+    DEBUG ((DEBUG_INFO, " PortSettings[%d] HsioTxGen3DeEmph= %x\n", i, HsioSataConfig->PortLane[i].HsioTxGen3DeEmph));
+  }
+
+  DEBUG ((DEBUG_INFO, " RaidAlternateId= %x\n", SataConfig->Rst.RaidAlternateId));
+  DEBUG ((DEBUG_INFO, " Raid0= %x\n", SataConfig->Rst.Raid0));
+  DEBUG ((DEBUG_INFO, " Raid1= %x\n", SataConfig->Rst.Raid1));
+  DEBUG ((DEBUG_INFO, " Raid10= %x\n", SataConfig->Rst.Raid10));
+  DEBUG ((DEBUG_INFO, " Raid5= %x\n", SataConfig->Rst.Raid5));
+  DEBUG ((DEBUG_INFO, " Irrt= %x\n", SataConfig->Rst.Irrt));
+  DEBUG ((DEBUG_INFO, " OromUiBanner= %x\n", SataConfig->Rst.OromUiBanner));
+  DEBUG ((DEBUG_INFO, " OromUiDelay= %x\n", SataConfig->Rst.OromUiDelay));
+  DEBUG ((DEBUG_INFO, " HddUnlock= %x\n", SataConfig->Rst.HddUnlock));
+  DEBUG ((DEBUG_INFO, " LedLocate= %x\n", SataConfig->Rst.LedLocate));
+  DEBUG ((DEBUG_INFO, " IrrtOnly= %x\n", SataConfig->Rst.IrrtOnly));
+  DEBUG ((DEBUG_INFO, " SmartStorage= %x\n", SataConfig->Rst.SmartStorage));
+
+  DEBUG ((DEBUG_INFO, " SpeedSupport= %x\n", SataConfig->SpeedLimit));
+  DEBUG ((DEBUG_INFO, " eSATASpeedLimit= %x\n", SataConfig->eSATASpeedLimit));
+  DEBUG ((DEBUG_INFO, " TestMode= %x\n", SataConfig->TestMode));
+  DEBUG ((DEBUG_INFO, " SalpSupport= %x\n", SataConfig->SalpSupport));
+  DEBUG ((DEBUG_INFO, " PwrOptEnable= %x\n", SataConfig->PwrOptEnable));
+
+  for (i = 0; i < PCH_MAX_RST_PCIE_STORAGE_CR; i++) {
+    DEBUG ((DEBUG_INFO, " RstPcieStorageRemap[%d].Enable                  = %x\n", i, SataConfig->RstPcieStorageRemap[i].Enable));
+    DEBUG ((DEBUG_INFO, " RstPcieStorageRemap[%d].RstPcieStoragePort      = %x\n", i, SataConfig->RstPcieStorageRemap[i].RstPcieStoragePort));
+    DEBUG ((DEBUG_INFO, " RstPcieStorageRemap[%d].DeviceResetDelay        = %x\n", i, SataConfig->RstPcieStorageRemap[i].DeviceResetDelay));
+  }
+}
+
+/**
+  Print PCH_IOAPIC_CONFIG and serial out.
+
+  @param[in] IoApicConfig         Pointer to a PCH_IOAPIC_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintIoApicConfig (
+  IN CONST PCH_IOAPIC_CONFIG   *IoApicConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH IOAPIC Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " BdfValid= %x\n", IoApicConfig->BdfValid));
+  DEBUG ((DEBUG_INFO, " BusNumber= %x\n", IoApicConfig->BusNumber));
+  DEBUG ((DEBUG_INFO, " DeviceNumber= %x\n", IoApicConfig->DeviceNumber));
+  DEBUG ((DEBUG_INFO, " FunctionNumber= %x\n", IoApicConfig->FunctionNumber));
+  DEBUG ((DEBUG_INFO, " IoApicId= %x\n", IoApicConfig->IoApicId));
+  DEBUG ((DEBUG_INFO, " ApicRangeSelect= %x\n", IoApicConfig->ApicRangeSelect));
+  DEBUG ((DEBUG_INFO, " IoApicEntry24_119= %x\n", IoApicConfig->IoApicEntry24_119));
+}
+
+/**
+  Print PCH_HPET_CONFIG and serial out.
+
+  @param[in] HpetConfig         Pointer to a PCH_HPET_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintHpetConfig (
+  IN CONST PCH_HPET_CONFIG   *HpetConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH HPET Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " Enable %x\n", HpetConfig->Enable));
+  DEBUG ((DEBUG_INFO, " BdfValid %x\n", HpetConfig->BdfValid));
+  DEBUG ((DEBUG_INFO, " BusNumber %x\n",  HpetConfig->BusNumber));
+  DEBUG ((DEBUG_INFO, " DeviceNumber %x\n", HpetConfig->DeviceNumber));
+  DEBUG ((DEBUG_INFO, " FunctionNumber %x\n", HpetConfig->FunctionNumber));
+  DEBUG ((DEBUG_INFO, " Base %x\n", HpetConfig->Base));
+}
+
+/**
+  Print PCH_LOCK_DOWN_CONFIG and serial out.
+
+  @param[in] LockDownConfig         Pointer to a PCH_LOCK_DOWN_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintLockDownConfig (
+  IN CONST PCH_LOCK_DOWN_CONFIG   *LockDownConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH Lock Down Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " GlobalSmi= %x\n", LockDownConfig->GlobalSmi));
+  DEBUG ((DEBUG_INFO, " BiosInterface= %x\n", LockDownConfig->BiosInterface));
+  DEBUG ((DEBUG_INFO, " RtcLock= %x\n", LockDownConfig->RtcLock));
+  DEBUG ((DEBUG_INFO, " BiosLock= %x\n", LockDownConfig->BiosLock));
+  DEBUG ((DEBUG_INFO, " SpiEiss= %x\n", LockDownConfig->SpiEiss));
+}
+
+/**
+  Print PCH_SMBUS_CONFIG and serial out.
+
+  @param[in] SmbusConfig         Pointer to a PCH_SMBUS_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintSmbusConfig (
+  IN CONST PCH_SMBUS_CONFIG   *SmbusConfig
+  )
+{
+  UINT32 i;
+
+  DEBUG ((DEBUG_INFO, "------------------ PCH SMBUS Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " Enable= %x\n", SmbusConfig->Enable));
+  DEBUG ((DEBUG_INFO, " ArpEnable= %x\n", SmbusConfig->ArpEnable));
+  DEBUG ((DEBUG_INFO, " DynamicPowerGating= %x\n", SmbusConfig->DynamicPowerGating));
+  DEBUG ((DEBUG_INFO, " SmbusIoBase= %x\n", SmbusConfig->SmbusIoBase));
+  DEBUG ((DEBUG_INFO, " NumRsvdSmbusAddresses= %x\n", SmbusConfig->NumRsvdSmbusAddresses));
+  DEBUG ((DEBUG_INFO, " RsvdSmbusAddressTable= {"));
+  for (i = 0; i < SmbusConfig->NumRsvdSmbusAddresses; ++i) {
+    DEBUG ((DEBUG_INFO, " %02xh", SmbusConfig->RsvdSmbusAddressTable[i]));
+  }
+  DEBUG ((DEBUG_INFO, " }\n"));
+}
+
+/**
+  Print PCH_HDAUDIO_CONFIG and serial out.
+
+  @param[in] HdaConfig         Pointer to a PCH_HDAUDIO_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintHdAudioConfig (
+  IN CONST PCH_HDAUDIO_CONFIG   *HdaConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH HD-Audio Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " HDA Enable             = %x\n", HdaConfig->Enable));
+  DEBUG ((DEBUG_INFO, " DSP Enable             = %x\n", HdaConfig->DspEnable));
+  DEBUG ((DEBUG_INFO, " DSP UAA Compliance     = %x\n", HdaConfig->DspUaaCompliance));
+  DEBUG ((DEBUG_INFO, " iDisp Codec Disconnect = %x\n", HdaConfig->IDispCodecDisconnect));
+  DEBUG ((DEBUG_INFO, " Pme                    = %x\n", HdaConfig->Pme));
+  DEBUG ((DEBUG_INFO, " I/O Buffer Ownership   = %x\n", HdaConfig->IoBufferOwnership));
+  DEBUG ((DEBUG_INFO, " I/O Buffer Voltage     = %x\n", HdaConfig->IoBufferVoltage));
+  DEBUG ((DEBUG_INFO, " VC Type                = %x\n", HdaConfig->VcType));
+  DEBUG ((DEBUG_INFO, " HD-A Link Frequency    = %x\n", HdaConfig->HdAudioLinkFrequency));
+  DEBUG ((DEBUG_INFO, " iDisp Link Frequency   = %x\n", HdaConfig->IDispLinkFrequency));
+  DEBUG ((DEBUG_INFO, " iDisp Link T-Mode      = %x\n", HdaConfig->IDispLinkTmode));
+  DEBUG ((DEBUG_INFO, " DSP Endpoint DMIC      = %x\n", HdaConfig->DspEndpointDmic));
+  DEBUG ((DEBUG_INFO, " DSP Endpoint I2S       = %x\n", HdaConfig->DspEndpointI2s));
+  DEBUG ((DEBUG_INFO, " DSP Endpoint BT        = %x\n", HdaConfig->DspEndpointBluetooth));
+  DEBUG ((DEBUG_INFO, " DSP Feature Mask       = %x\n", HdaConfig->DspFeatureMask));
+  DEBUG ((DEBUG_INFO, " DSP PP Module Mask     = %x\n", HdaConfig->DspPpModuleMask));
+  DEBUG ((DEBUG_INFO, " ResetWaitTimer         = %x\n", HdaConfig->ResetWaitTimer));
+}
+
+/**
+  Print PCH_PM_CONFIG and serial out.
+
+  @param[in] PmConfig         Pointer to a PCH_PM_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintPmConfig (
+  IN CONST PCH_PM_CONFIG   *PmConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH PM Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " PowerResetStatusClear MeWakeSts     = %x\n", PmConfig->PowerResetStatusClear.MeWakeSts));
+  DEBUG ((DEBUG_INFO, " PowerResetStatusClear MeHrstColdSts = %x\n", PmConfig->PowerResetStatusClear.MeHrstColdSts));
+  DEBUG ((DEBUG_INFO, " PowerResetStatusClear MeHrstWarmSts = %x\n", PmConfig->PowerResetStatusClear.MeHrstWarmSts));
+  DEBUG ((DEBUG_INFO, " PowerResetStatusClear MeHostPowerDn = %x\n", PmConfig->PowerResetStatusClear.MeHostPowerDn));
+  DEBUG ((DEBUG_INFO, " PowerResetStatusClear WolOvrWkSts   = %x\n", PmConfig->PowerResetStatusClear.WolOvrWkSts));
+
+  DEBUG ((DEBUG_INFO, " WakeConfig PmeB0S5Dis               = %x\n", PmConfig->WakeConfig.PmeB0S5Dis));
+  DEBUG ((DEBUG_INFO, " WakeConfig WolEnableOverride        = %x\n", PmConfig->WakeConfig.WolEnableOverride));
+  DEBUG ((DEBUG_INFO, " WakeConfig LanWakeFromDeepSx        = %x\n", PmConfig->WakeConfig.LanWakeFromDeepSx));
+  DEBUG ((DEBUG_INFO, " WakeConfig PcieWakeFromDeepSx       = %x\n", PmConfig->WakeConfig.PcieWakeFromDeepSx));
+  DEBUG ((DEBUG_INFO, " WakeConfig WoWlanEnable             = %x\n", PmConfig->WakeConfig.WoWlanEnable));
+  DEBUG ((DEBUG_INFO, " WakeConfig WoWlanDeepSxEnable       = %x\n", PmConfig->WakeConfig.WoWlanDeepSxEnable));
+
+  DEBUG ((DEBUG_INFO, " PchDeepSxPol                        = %x\n", PmConfig->PchDeepSxPol));
+  DEBUG ((DEBUG_INFO, " PchSlpS3MinAssert                   = %x\n", PmConfig->PchSlpS3MinAssert));
+  DEBUG ((DEBUG_INFO, " PchSlpS4MinAssert                   = %x\n", PmConfig->PchSlpS4MinAssert));
+  DEBUG ((DEBUG_INFO, " PchSlpSusMinAssert                  = %x\n", PmConfig->PchSlpSusMinAssert));
+  DEBUG ((DEBUG_INFO, " PchSlpAMinAssert                    = %x\n", PmConfig->PchSlpAMinAssert));
+  DEBUG ((DEBUG_INFO, " PciClockRun                         = %x\n", PmConfig->PciClockRun));
+  DEBUG ((DEBUG_INFO, " SlpStrchSusUp                       = %x\n", PmConfig->SlpStrchSusUp));
+  DEBUG ((DEBUG_INFO, " SlpLanLowDc                         = %x\n", PmConfig->SlpLanLowDc));
+  DEBUG ((DEBUG_INFO, " PwrBtnOverridePeriod                = %x\n", PmConfig->PwrBtnOverridePeriod));
+  DEBUG ((DEBUG_INFO, " DisableEnergyReport                 = %x\n", PmConfig->DisableEnergyReport));
+  DEBUG ((DEBUG_INFO, " DisableDsxAcPresentPulldown         = %x\n", PmConfig->DisableDsxAcPresentPulldown));
+  DEBUG ((DEBUG_INFO, " PmcReadDisable                      = %x\n", PmConfig->PmcReadDisable));
+  DEBUG ((DEBUG_INFO, " PchPwrCycDur                        = %x\n", PmConfig->PchPwrCycDur));
+  DEBUG ((DEBUG_INFO, " PciePllSsc                          = %x\n", PmConfig->PciePllSsc));
+  DEBUG ((DEBUG_INFO, " CapsuleResetType                    = %x\n", PmConfig->CapsuleResetType));
+  DEBUG ((DEBUG_INFO, " DisableNativePowerButton            = %x\n", PmConfig->DisableNativePowerButton));
+  DEBUG ((DEBUG_INFO, " SlpS0Enabled                        = %x\n", PmConfig->SlpS0Enable));
+}
+
+/**
+  Print PCH_DMI_CONFIG and serial out.
+
+  @param[in] DmiConfig         Pointer to a PCH_DMI_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintDmiConfig (
+  IN CONST PCH_DMI_CONFIG   *DmiConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH DMI Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " DmiAspm= %x\n", DmiConfig->DmiAspm));
+  DEBUG ((DEBUG_INFO, " PwrOptEnable= %x\n", DmiConfig->PwrOptEnable));
+
+}
+
+/**
+  Print PCH_LPC_SIRQ_CONFIG and serial out.
+
+  @param[in] SerialIrqConfig         Pointer to a PCH_LPC_SIRQ_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintSerialIrqConfig (
+  IN CONST PCH_LPC_SIRQ_CONFIG   *SerialIrqConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH LPC SIRQ Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " SirqEnable= %x\n", SerialIrqConfig->SirqEnable));
+  DEBUG ((DEBUG_INFO, " SirqMode= %x\n", SerialIrqConfig->SirqMode));
+  DEBUG ((DEBUG_INFO, " StartFramePulse= %x\n", SerialIrqConfig->StartFramePulse));
+}
+
+/**
+  Print PCH_THERMAL_CONFIG and serial out.
+
+  @param[in] ThermalConfig         Pointer to a PCH_THERMAL_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintThermalConfig (
+  IN CONST PCH_THERMAL_CONFIG   *ThermalConfig
+  )
+{
+  UINTN i;
+
+  DEBUG ((DEBUG_INFO, "------------------ PCH Thermal Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " TsmicLock= %x\n", ThermalConfig->TsmicLock));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels T0Level %x centigrade degree\n", ThermalConfig->ThermalThrottling.TTLevels.T0Level));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels T1Level %x centigrade degree\n", ThermalConfig->ThermalThrottling.TTLevels.T1Level));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels T2Level %x centigrade degree\n", ThermalConfig->ThermalThrottling.TTLevels.T2Level));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels TTEnable %x\n", ThermalConfig->ThermalThrottling.TTLevels.TTEnable));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels TTState13Enable %x\n", ThermalConfig->ThermalThrottling.TTLevels.TTState13Enable));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels TTLock %x\n", ThermalConfig->ThermalThrottling.TTLevels.TTLock));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels SuggestedSetting %x\n", ThermalConfig->ThermalThrottling.TTLevels.SuggestedSetting));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling TTLevels PchCrossThrottling %x\n", ThermalConfig->ThermalThrottling.TTLevels.PchCrossThrottling));
+
+  DEBUG ((DEBUG_INFO, " ThermalThrottling DmiHaAWC DmiTsawEn %x\n", ThermalConfig->ThermalThrottling.DmiHaAWC.DmiTsawEn));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling DmiHaAWC TS0TW %x\n", ThermalConfig->ThermalThrottling.DmiHaAWC.TS0TW));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling DmiHaAWC TS1TW %x\n", ThermalConfig->ThermalThrottling.DmiHaAWC.TS1TW));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling DmiHaAWC TS2TW %x\n", ThermalConfig->ThermalThrottling.DmiHaAWC.TS2TW));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling DmiHaAWC TS3TW %x\n", ThermalConfig->ThermalThrottling.DmiHaAWC.TS3TW));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling DmiHaAWC SuggestedSetting %x\n", ThermalConfig->ThermalThrottling.DmiHaAWC.SuggestedSetting));
+
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P0T1M %x\n", ThermalConfig->ThermalThrottling.SataTT.P0T1M));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P0T2M %x\n", ThermalConfig->ThermalThrottling.SataTT.P0T2M));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P0T3M %x\n", ThermalConfig->ThermalThrottling.SataTT.P0T3M));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P0TDisp %x\n", ThermalConfig->ThermalThrottling.SataTT.P0TDisp));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P0Tinact %x\n", ThermalConfig->ThermalThrottling.SataTT.P0Tinact));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P0TDispFinit %x\n", ThermalConfig->ThermalThrottling.SataTT.P0TDispFinit));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P1T1M %x\n", ThermalConfig->ThermalThrottling.SataTT.P1T1M));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P1T2M %x\n", ThermalConfig->ThermalThrottling.SataTT.P1T2M));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P1T3M %x\n", ThermalConfig->ThermalThrottling.SataTT.P1T3M));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P1TDisp %x\n", ThermalConfig->ThermalThrottling.SataTT.P1TDisp));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P1Tinact %x\n", ThermalConfig->ThermalThrottling.SataTT.P1Tinact));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT P1TDispFinit %x\n", ThermalConfig->ThermalThrottling.SataTT.P1TDispFinit));
+  DEBUG ((DEBUG_INFO, " ThermalThrottling SataTT SuggestedSetting %x\n", ThermalConfig->ThermalThrottling.SataTT.SuggestedSetting));
+
+  DEBUG ((DEBUG_INFO, " MemoryThrottling Enable= %x\n", ThermalConfig->MemoryThrottling.Enable));
+  for (i = 0; i < MaxTsGpioPin; i++) {
+    DEBUG ((DEBUG_INFO, " MemoryThrottling TsGpioPinSetting PmsyncEnable= %x\n", ThermalConfig->MemoryThrottling.TsGpioPinSetting[i].PmsyncEnable));
+    DEBUG ((DEBUG_INFO, " MemoryThrottling TsGpioPinSetting C0TransmitEnable= %x\n", ThermalConfig->MemoryThrottling.TsGpioPinSetting[i].C0TransmitEnable));
+    DEBUG ((DEBUG_INFO, " MemoryThrottling TsGpioPinSetting PinSelection= %x\n", ThermalConfig->MemoryThrottling.TsGpioPinSetting[i].PinSelection));
+  }
+  DEBUG ((DEBUG_INFO, " PchHotLevel = %x\n", ThermalConfig->PchHotLevel));
+  DEBUG ((DEBUG_INFO, " ThermalDeviceEnable %x\n", ThermalConfig->ThermalDeviceEnable));
+}
+
+/**
+  Print PCH_GENERAL_CONFIG and serial out.
+
+  @param[in] PchConfig         Pointer to a PCH_GENERAL_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintGeneralConfig (
+  IN CONST PCH_GENERAL_CONFIG   *PchConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH General Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " SubSystemVendorId= %x\n", PchConfig->SubSystemVendorId));
+  DEBUG ((DEBUG_INFO, " SubSystemId= %x\n", PchConfig->SubSystemId));
+  DEBUG ((DEBUG_INFO, " Crid= %x\n", PchConfig->Crid));
+}
+
+/**
+  Print PCH_LAN_CONFIG and serial out.
+
+  @param[in] LanConfig         Pointer to a PCH_LAN_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintLanConfig (
+  IN CONST PCH_LAN_CONFIG   *LanConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH LAN Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " Enable= %x\n", LanConfig->Enable));
+  DEBUG ((DEBUG_INFO, " K1OffEnable= %x\n", LanConfig->K1OffEnable));
+  DEBUG ((DEBUG_INFO, " ClkReqSupported= %d\n", LanConfig->ClkReqSupported));
+  DEBUG ((DEBUG_INFO, " ClkReqNumber= %d\n", LanConfig->ClkReqNumber));
+}
+
+
+/**
+  Print PCH_INTERRUPT_CONFIG and serial out
+
+  @param[in] InterruptConfig        Pointer to Interrupt Configuration structure
+
+**/
+VOID
+PchPrintInterruptConfig (
+  IN CONST PCH_INTERRUPT_CONFIG     *InterruptConfig
+  )
+{
+  UINTN i;
+  //
+  // Print interrupt information
+  //
+  DEBUG ((DEBUG_INFO, "------------------ PCH Interrupt Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, " Interrupt assignment:\n"));
+  DEBUG ((DEBUG_INFO, "  Dxx:Fx INTx IRQ\n"));
+  for (i = 0; i < InterruptConfig->NumOfDevIntConfig; i++) {
+    DEBUG ((DEBUG_INFO, "  D%02d:F%d    %d %03d\n",
+              InterruptConfig->DevIntConfig[i].Device,
+              InterruptConfig->DevIntConfig[i].Function,
+              InterruptConfig->DevIntConfig[i].IntX,
+              InterruptConfig->DevIntConfig[i].Irq));
+  }
+  DEBUG ((DEBUG_INFO, " Legacy PIC interrupt routing:\n"));
+  DEBUG ((DEBUG_INFO, "  PIRQx    IRQx\n"));
+  for (i = 0; i < PCH_MAX_PXRC_CONFIG; i++) {
+    DEBUG ((DEBUG_INFO, "  PIRQ%c -> IRQ%d\n", i + 65, InterruptConfig->PxRcConfig[i]));
+  }
+  DEBUG ((DEBUG_INFO, " Other interrupt configuration:\n"));
+  DEBUG ((DEBUG_INFO, "  GpioIrqRoute= %d\n", InterruptConfig->GpioIrqRoute));
+  DEBUG ((DEBUG_INFO, "  SciIrqSelect= %d\n", InterruptConfig->SciIrqSelect));
+  DEBUG ((DEBUG_INFO, "  TcoIrqEnable= %d\n", InterruptConfig->TcoIrqEnable));
+  DEBUG ((DEBUG_INFO, "  TcoIrqSelect= %d\n", InterruptConfig->TcoIrqSelect));
+}
+
+
+/**
+  Print PCH_FLASH_PROTECTION_CONFIG and serial out.
+
+  @param[in] FlashProtectConfig  Pointer to a PCH_FLASH_PROTECTION_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintFlashProtectionConfig (
+  IN CONST PCH_FLASH_PROTECTION_CONFIG   *FlashProtectConfig
+  )
+{
+  UINT32 i;
+
+  DEBUG ((DEBUG_INFO, "------------------ PCH Flash Protection Config ------------------\n"));
+  for (i = 0; i < PCH_FLASH_PROTECTED_RANGES; ++i) {
+    DEBUG ((DEBUG_INFO, " WriteProtectionEnable[%d]= %x\n", i, FlashProtectConfig->ProtectRange[i].WriteProtectionEnable));
+    DEBUG ((DEBUG_INFO, " ReadProtectionEnable[%d]= %x\n", i, FlashProtectConfig->ProtectRange[i].ReadProtectionEnable));
+    DEBUG ((DEBUG_INFO, " ProtectedRangeLimit[%d]= %x\n", i, FlashProtectConfig->ProtectRange[i].ProtectedRangeLimit));
+    DEBUG ((DEBUG_INFO, " ProtectedRangeBase[%d]= %x\n", i, FlashProtectConfig->ProtectRange[i].ProtectedRangeBase));
+  }
+}
+
+/**
+  Print PCH_WDT_CONFIG and serial out.
+
+  @param[in] WdtConfig                  Pointer to a PCH_WDT_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintWdtConfig (
+  IN CONST PCH_WDT_CONFIG               *WdtConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH WDT Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, "DisableAndLock= %x\n", WdtConfig->DisableAndLock));
+}
+
+/**
+  Print PCH_P2SB_CONFIG and serial out.
+
+  @param[in] P2sbConfig                 Pointer to a PCH_P2SB_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintP2sbConfig (
+  IN CONST PCH_P2SB_CONFIG              *P2sbConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH P2SB Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, "SbiUnlock= %x\n", P2sbConfig->SbiUnlock));
+  DEBUG ((DEBUG_INFO, "PsfUnlock= %x\n", P2sbConfig->PsfUnlock));
+}
+
+/**
+  Print PCH_DCI_CONFIG and serial out.
+
+  @param[in] DciConfig                  Pointer to a PCH_DCI_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintDciConfig (
+  IN CONST PCH_DCI_CONFIG               *DciConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH DCI Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, "DciEn= %x\n", DciConfig->DciEn));
+  DEBUG ((DEBUG_INFO, "DciAutoDetect= %x\n", DciConfig->DciAutoDetect));
+}
+
+/**
+  Print PCH_LPC_CONFIG and serial out.
+
+  @param[in] LpcConfig                  Pointer to a PCH_LPC_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintLpcConfig (
+  IN CONST PCH_LPC_CONFIG               *LpcConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH LPC Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, "EnhancePort8xhDecoding= %x\n", LpcConfig->EnhancePort8xhDecoding));
+}
+
+/**
+  Print PCH_SPI_CONFIG and serial out.
+
+  @param[in] SpiConfig                  Pointer to a PCH_SPI_CONFIG that provides the platform setting
+
+**/
+VOID
+PchPrintSpiConfig (
+  IN CONST PCH_SPI_CONFIG               *SpiConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "------------------ PCH SPI Config ------------------\n"));
+  DEBUG ((DEBUG_INFO, "ShowSpiController= %x\n", SpiConfig->ShowSpiController));
+}
+
+/**
+  Print whole PCH_POLICY_PPI and serial out.
+
+  @param[in] PchPolicyPpi    The RC Policy PPI instance
+
+**/
+VOID
+PchPrintPolicyPpi (
+  IN  PCH_POLICY_PPI     *PchPolicyPpi
+  )
+{
+DEBUG_CODE_BEGIN();
+  DEBUG ((DEBUG_INFO, "------------------------ PCH Print Platform Protocol Start ------------------------\n"));
+  DEBUG ((DEBUG_INFO, " Revision= %x\n", PchPolicyPpi->Revision));
+  DEBUG ((DEBUG_INFO, " Port80Route= %x\n", PchPolicyPpi->Port80Route));
+  DEBUG ((DEBUG_INFO, " AcpiBase= %x\n", PchPolicyPpi->AcpiBase));
+
+  PchPrintGeneralConfig (&PchPolicyPpi->PchConfig);
+
+  PchPrintPcieConfig (&PchPolicyPpi->PcieConfig, &PchPolicyPpi->HsioPcieConfig);
+
+  PchPrintPcieConfig2 (&PchPolicyPpi->PcieConfig2);
+
+  PchPrintSataConfig (&PchPolicyPpi->SataConfig,  &PchPolicyPpi->HsioSataConfig,  PCH_SATA_FIRST_CONTROLLER);
+  PchPrintSataConfig (&PchPolicyPpi->sSataConfig, &PchPolicyPpi->HsiosSataConfig, PCH_SATA_SECOND_CONTROLLER);
+  PchPrintUsbConfig (&PchPolicyPpi->UsbConfig);
+
+  PchPrintIoApicConfig (&PchPolicyPpi->IoApicConfig);
+
+  PchPrintHpetConfig (&PchPolicyPpi->HpetConfig);
+
+  PchPrintHdAudioConfig (&PchPolicyPpi->HdAudioConfig);
+
+  PchPrintLanConfig (&PchPolicyPpi->LanConfig);
+
+  PchPrintSmbusConfig (&PchPolicyPpi->SmbusConfig);
+
+  PchPrintLockDownConfig (&PchPolicyPpi->LockDownConfig);
+
+  PchPrintThermalConfig (&PchPolicyPpi->ThermalConfig);
+
+  PchPrintPmConfig (&PchPolicyPpi->PmConfig);
+
+  PchPrintDmiConfig (&PchPolicyPpi->DmiConfig);
+
+  PchPrintSerialIrqConfig (&PchPolicyPpi->SerialIrqConfig);
+
+
+  PchPrintFlashProtectionConfig (&PchPolicyPpi->FlashProtectConfig);
+
+  PchPrintWdtConfig (&PchPolicyPpi->WdtConfig);
+
+  PchPrintP2sbConfig (&PchPolicyPpi->P2sbConfig);
+
+  PchPrintDciConfig (&PchPolicyPpi->DciConfig);
+
+  PchPrintLpcConfig (&PchPolicyPpi->LpcConfig);
+
+  PchPrintSpiConfig (&PchPolicyPpi->SpiConfig);
+
+  DEBUG ((DEBUG_INFO, "------------------------ PCH Print Platform Protocol End --------------------------\n"));
+DEBUG_CODE_END();
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.c
new file mode 100644
index 0000000000..c5f9c39265
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.c
@@ -0,0 +1,581 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiPchPolicyLibrary.h"
+#include <Library/PchPmcLib.h>
+
+/**
+  mDevIntConfig[] table contains data on INTx and IRQ for each device.
+  IRQ value for devices which use ITSS INTx->PIRQx mapping need to be set in a way
+  that for each multifunctional Dxx:Fy same interrupt pins must map to the same IRQ.
+  Those IRQ values will be used to update ITSS.PIRx register.
+  In APIC relationship between PIRQs and IRQs is:
+  PIRQA -> IRQ16
+  PIRQB -> IRQ17
+  PIRQC -> IRQ18
+  PIRQD -> IRQ19
+  PIRQE -> IRQ20
+  PIRQF -> IRQ21
+  PIRQG -> IRQ22
+  PIRQH -> IRQ23
+
+  Devices which use INTx->PIRQy mapping are: cAVS(in PCI mode), SMBus, GbE, TraceHub, PCIe,
+  SATA, HECI, IDE-R, KT Redirection, xHCI, Thermal Subsystem, Camera IO Host Controller
+
+  PCI Express Root Ports mapping should be programmed only with values as in below table (D27/28/29)
+  otherwise _PRT methods in ACPI for RootPorts would require additional patching as
+  PCIe Endpoint Device Interrupt is further subjected to INTx to PIRQy Mapping
+
+  Configured IRQ values are not used if an OS chooses to be in PIC instead of APIC mode
+**/
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_DEVICE_INTERRUPT_CONFIG mDevIntConfig[] = {
+//  {31, 0, PchNoInt, 0}, // LPC/eSPI Interface, doesn't use interrupts
+//  {31, 1, PchNoInt, 0}, // P2SB, doesn't use interrupts
+//  {31, 2, PchNoInt, 0}, // PMC , doesn't use interrupts
+  {31, 3, PchIntA, 16}, // cAVS(Audio, Voice, Speach), INTA is default, programmed in PciCfgSpace 3Dh
+  {31, 4, PchIntA, 16}, // SMBus Controller, no default value, programmed in PciCfgSpace 3Dh
+//  {31, 5, PchNoInt, 0}, // SPI , doesn't use interrupts
+  {31, 6, PchIntA, 16}, // GbE Controller, INTA is default, programmed in PciCfgSpace 3Dh
+  {31, 7, PchIntA, 16}, // TraceHub, INTA is default, RO register
+  {29, 0, PchIntA, 16}, // PCI Express Port 9, INT is default, programmed in PciCfgSpace + FCh
+  {29, 1, PchIntB, 17}, // PCI Express Port 10, INT is default, programmed in PciCfgSpace + FCh
+  {29, 2, PchIntC, 18}, // PCI Express Port 11, INT is default, programmed in PciCfgSpace + FCh
+  {29, 3, PchIntD, 19}, // PCI Express Port 12, INT is default, programmed in PciCfgSpace + FCh
+  {29, 4, PchIntA, 16}, // PCI Express Port 13 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {29, 5, PchIntB, 17}, // PCI Express Port 14 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {29, 6, PchIntC, 18}, // PCI Express Port 15 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {29, 7, PchIntD, 19}, // PCI Express Port 16 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {28, 0, PchIntA, 16}, // PCI Express Port 1, INT is default, programmed in PciCfgSpace + FCh
+  {28, 1, PchIntB, 17}, // PCI Express Port 2, INT is default, programmed in PciCfgSpace + FCh
+  {28, 2, PchIntC, 18}, // PCI Express Port 3, INT is default, programmed in PciCfgSpace + FCh
+  {28, 3, PchIntD, 19}, // PCI Express Port 4, INT is default, programmed in PciCfgSpace + FCh
+  {28, 4, PchIntA, 16}, // PCI Express Port 5, INT is default, programmed in PciCfgSpace + FCh
+  {28, 5, PchIntB, 17}, // PCI Express Port 6, INT is default, programmed in PciCfgSpace + FCh
+  {28, 6, PchIntC, 18}, // PCI Express Port 7, INT is default, programmed in PciCfgSpace + FCh
+  {28, 7, PchIntD, 19}, // PCI Express Port 8, INT is default, programmed in PciCfgSpace + FCh
+  {27, 0, PchIntA, 16}, // PCI Express Port 17 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {27, 1, PchIntB, 17}, // PCI Express Port 18 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {27, 2, PchIntC, 18}, // PCI Express Port 19 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+  {27, 3, PchIntD, 19}, // PCI Express Port 20 (SKL PCH-H Only), INT is default, programmed in PciCfgSpace + FCh
+//  {24, 0, 0, 0}, // Reserved (used by RST PCIe Storage Cycle Router)
+  {23, 0, PchIntA, 16}, // SATA Controller, INTA is default, programmed in PciCfgSpace + 3Dh
+  {22, 0, PchIntA, 16}, // CSME: HECI #1
+  {22, 1, PchIntB, 17}, // CSME: HECI #2
+  {22, 2, PchIntC, 18}, // CSME: IDE-Redirection (IDE-R)
+  {22, 3, PchIntD, 19}, // CSME: Keyboard and Text (KT) Redirection
+  {22, 4, PchIntA, 16}, // CSME: HECI #3
+//  {22, 7, PchNoInt, 0}, // CSME: WLAN
+  {20, 0, PchIntA, 16}, // USB 3.0 xHCI Controller, no default value, programmed in PciCfgSpace 3Dh
+  {20, 2, PchIntC, 18}, // Thermal Subsystem
+//  {20, 4, 0, 0}, // TraceHub Phantom (ACPI) Function
+//  {18, 0, PchNoInt, 0}, // CSME: KVMcc,  doesn't use interrupts
+//  {18, 1, PchNoInt, 0}, // CSME: Clink,  doesn't use interrupts
+//  {18, 2, PchNoInt, 0}, // CSME: PMT,  doesn't use interrupts
+//  {18, 3, 0, 0}, // CSME: CSE UMA
+//  {18, 4, 0, 0}  // CSME: fTPM DMA
+  {17, 5, PchIntA, 16} // SSATA controller.
+#ifdef IE_SUPPORT
+  ,
+//  {16, 0, PchIntA, 16}, // IE: HECI #1
+//  {16, 1, PchIntB, 17}, // IE: HECI #2
+//  {16, 2, PchIntC, 18}, // IE: IDE-Redirection (IDE-R)
+  {16, 3, PchIntD, 19} // IE: Keyboard and Text (KT) Redirection
+//  {16, 4, PchIntA, 16}  // IE: HECI #3
+#endif // IE_SUPPORT
+};
+
+//
+// mLpOnlyDevIntConfig[] table contains data on INTx and IRQ for devices that exist on SPT-LP but not on SPT-H.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_DEVICE_INTERRUPT_CONFIG mLpOnlyDevIntConfig[] = {
+  {25, 1, PchIntB, 33}, // SerialIo I2C Controller #5, INTA is default, programmed in PCR[SERIALIO] + PCICFGCTRL[6]
+  {25, 2, PchIntC, 34}  // SerialIo I2C Controller #4, INTA is default, programmed in PCR[SERIALIO] + PCICFGCTRL[5]
+};
+/**
+  mPxRcConfig[] table contains data for 8259 routing (how PIRQx is mapped to IRQy).
+  This information is used by systems which choose to use legacy PIC
+  interrupt controller. Only IRQ3-7,9-12,14,15 are valid. Values from this table
+  will be programmed into ITSS.PxRC registers.
+**/
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPxRcConfig[] = {
+  11,  // PARC: PIRQA -> IRQ11
+  10,  // PBRC: PIRQB -> IRQ10
+  11,  // PCRC: PIRQC -> IRQ11
+  11,  // PDRC: PIRQD -> IRQ11
+  11,  // PERC: PIRQE -> IRQ11
+  11,  // PFRC: PIRQF -> IRQ11
+  11,  // PGRC: PIRQG -> IRQ11
+  11   // PHRC: PIRQH -> IRQ11
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSmbusRsvdAddresses[] = {
+  0xA0,
+  0xA2,
+  0xA4,
+  0xA6
+};
+
+/**
+  PchCreatePolicyDefaults creates the default setting of PCH Policy.
+  It allocates and zero out buffer, and fills in the Intel default settings.
+
+  @param[out] PchPolicyPpi      The pointer to get PCH Policy PPI instance
+
+  @retval EFI_SUCCESS                   The policy default is initialized.
+  @retval EFI_OUT_OF_RESOURCES          Insufficient resources to create buffer
+**/
+EFI_STATUS
+EFIAPI
+PchCreatePolicyDefaults (
+  OUT  PCH_POLICY_PPI                   **PchPolicyPpi
+  )
+{
+  PCH_POLICY_PPI           *PchPolicy;
+  PCH_SERIES               PchSeries;
+  UINT32                   PortIndex;
+  UINT32                   Index;
+  UINT8                    IntConfigTableEntries;
+
+  PchSeries = GetPchSeries ();
+
+  PchPolicy = (PCH_POLICY_PPI *) AllocateZeroPool (sizeof (PCH_POLICY_PPI));
+  if (PchPolicy == NULL) {
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Policy not listed here are set to 0/FALSE as default.
+  //
+
+  /********************************
+    General initialization
+  ********************************/
+  PchPolicy->Revision                = PCH_POLICY_REVISION;
+  PchPolicy->AcpiBase                = PcdGet16 (PcdPchAcpiIoPortBaseAddress);
+  PchPolicy->TempMemBaseAddr         = PCH_TEMP_BASE_ADDRESS;
+
+  /********************************
+    PCH general configuration
+  ********************************/
+  //
+  // Default Svid Sdid configuration
+  //
+  PchPolicy->PchConfig.SubSystemVendorId = V_PCH_INTEL_VENDOR_ID;
+  PchPolicy->PchConfig.SubSystemId       = V_PCH_DEFAULT_SID;
+
+  /********************************
+    PCI Express related settings
+  ********************************/
+
+  PchPolicy->TempPciBusMin = 2;
+  PchPolicy->TempPciBusMax = 10;
+
+  PchPolicy->PcieConfig.RpFunctionSwap = TRUE;
+
+  for (PortIndex = 0; PortIndex < GetPchMaxPciePortNum (); PortIndex++) {
+    PchPolicy->PcieConfig.RootPort[PortIndex].Aspm                 = PchPcieAspmAutoConfig;
+    PchPolicy->PcieConfig.RootPort[PortIndex].Enable               = TRUE;
+    PchPolicy->PcieConfig.RootPort[PortIndex].PmSci                = TRUE;
+    PchPolicy->PcieConfig.RootPort[PortIndex].AcsEnabled           = TRUE;
+
+    PchPolicy->PcieConfig.RootPort[PortIndex].MaxPayload           = PchPcieMaxPayload256;
+
+    PchPolicy->PcieConfig.RootPort[PortIndex].PhysicalSlotNumber   = (UINT8) PortIndex;
+
+    PchPolicy->PcieConfig.RootPort[PortIndex].L1Substates          = PchPcieL1SubstatesL1_1_2;
+
+    //
+    // PCIe LTR Configuration.
+    //
+    PchPolicy->PcieConfig.RootPort[PortIndex].LtrEnable             = TRUE;
+    if (PchSeries == PchLp) {
+      PchPolicy->PcieConfig.RootPort[PortIndex].LtrMaxSnoopLatency               = 0x1003;
+      PchPolicy->PcieConfig.RootPort[PortIndex].LtrMaxNoSnoopLatency             = 0x1003;
+    }
+    if (PchSeries == PchH) {
+      PchPolicy->PcieConfig.RootPort[PortIndex].LtrMaxSnoopLatency               = 0x0846;
+      PchPolicy->PcieConfig.RootPort[PortIndex].LtrMaxNoSnoopLatency             = 0x0846;
+    }
+    PchPolicy->PcieConfig.RootPort[PortIndex].SnoopLatencyOverrideMode           = 2;
+    PchPolicy->PcieConfig.RootPort[PortIndex].SnoopLatencyOverrideMultiplier     = 2;
+    PchPolicy->PcieConfig.RootPort[PortIndex].SnoopLatencyOverrideValue          = 60;
+    PchPolicy->PcieConfig.RootPort[PortIndex].NonSnoopLatencyOverrideMode        = 2;
+    PchPolicy->PcieConfig.RootPort[PortIndex].NonSnoopLatencyOverrideMultiplier  = 2;
+    PchPolicy->PcieConfig.RootPort[PortIndex].NonSnoopLatencyOverrideValue       = 60;
+
+    PchPolicy->PcieConfig.RootPort[PortIndex].Uptp                               = 5;
+    PchPolicy->PcieConfig.RootPort[PortIndex].Dptp                               = 7;
+  }
+
+  for (Index = 0; Index < GetPchMaxPciePortNum (); ++Index) {
+    PchPolicy->PcieConfig.EqPh3LaneParam[Index].Cm = 6;
+    PchPolicy->PcieConfig.EqPh3LaneParam[Index].Cp = 6;
+  }
+
+  PchPolicy->PcieConfig2.SwEqCoeffList[0].Cm = 6;
+  PchPolicy->PcieConfig2.SwEqCoeffList[0].Cp = 8;
+  PchPolicy->PcieConfig2.SwEqCoeffList[1].Cm = 8;
+  PchPolicy->PcieConfig2.SwEqCoeffList[1].Cp = 2;
+  PchPolicy->PcieConfig2.SwEqCoeffList[2].Cm = 10;
+  PchPolicy->PcieConfig2.SwEqCoeffList[2].Cp = 6;
+  PchPolicy->PcieConfig2.SwEqCoeffList[3].Cm = 12;
+  PchPolicy->PcieConfig2.SwEqCoeffList[3].Cp = 8;
+  PchPolicy->PcieConfig2.SwEqCoeffList[4].Cm = 14;
+  PchPolicy->PcieConfig2.SwEqCoeffList[4].Cp = 2;
+
+  /********************************
+    SATA related settings
+  ********************************/
+  PchPolicy->SataConfig.Enable               = TRUE;
+  PchPolicy->SataConfig.SalpSupport          = TRUE;
+  PchPolicy->SataConfig.SataMode             = PchSataModeAhci;
+
+  for (PortIndex = 0; PortIndex < GetPchMaxSataPortNum (); PortIndex++) {
+    PchPolicy->SataConfig.PortSettings[PortIndex].Enable           = TRUE;
+    PchPolicy->SataConfig.PortSettings[PortIndex].DmVal            = 15;
+    PchPolicy->SataConfig.PortSettings[PortIndex].DitoVal          = 625;
+  }
+
+  PchPolicy->SataConfig.Rst.Raid0            = TRUE;
+  PchPolicy->SataConfig.Rst.Raid1            = TRUE;
+  PchPolicy->SataConfig.Rst.Raid10           = TRUE;
+  PchPolicy->SataConfig.Rst.Raid5            = TRUE;
+  PchPolicy->SataConfig.Rst.Irrt             = TRUE;
+  PchPolicy->SataConfig.Rst.OromUiBanner     = TRUE;
+  PchPolicy->SataConfig.Rst.OromUiDelay      = PchSataOromDelay2sec;
+  PchPolicy->SataConfig.Rst.HddUnlock        = TRUE;
+  PchPolicy->SataConfig.Rst.LedLocate        = TRUE;
+  PchPolicy->SataConfig.Rst.IrrtOnly         = TRUE;
+  PchPolicy->SataConfig.Rst.SmartStorage     = TRUE;
+
+  for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {
+    PchPolicy->SataConfig.RstPcieStorageRemap[Index].DeviceResetDelay             = 100;
+  }
+  /********************************
+    sSATA related settings
+  ********************************/
+    PchPolicy->sSataConfig.Enable               = TRUE;
+  //  PchPolicy->sSataConfig.TestMode             = FALSE;
+  //  PchPolicy->sSataConfig.LegacyMode           = FALSE;
+    PchPolicy->sSataConfig.SalpSupport          = TRUE;
+  //  PchPolicy->sSataConfig.eSATASpeedLimit      = FALSE;
+    PchPolicy->sSataConfig.SataMode             = PchSataModeAhci;
+  //  PchPolicy->sSataConfig.SpeedLimit           = PchsSataSpeedDefault;
+
+  for (PortIndex = 0; PortIndex < GetPchMaxsSataPortNum (); PortIndex++) {
+      PchPolicy->sSataConfig.PortSettings[PortIndex].Enable           = TRUE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].HotPlug          = FALSE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].InterlockSw      = FALSE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].External         = FALSE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].SpinUp           = FALSE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].SolidStateDrive  = FALSE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].DevSlp           = FALSE;
+  //    PchPolicy->sSataConfig.PortSettings[PortIndex].EnableDitoConfig = FALSE;
+      PchPolicy->sSataConfig.PortSettings[PortIndex].DmVal            = 15;
+      PchPolicy->sSataConfig.PortSettings[PortIndex].DitoVal          = 625;
+  }
+
+  //  PchPolicy->sSataConfig.Rst.RaidAlternateId  = FALSE;
+    PchPolicy->sSataConfig.Rst.Raid0            = TRUE;
+    PchPolicy->sSataConfig.Rst.Raid1            = TRUE;
+    PchPolicy->sSataConfig.Rst.Raid10           = TRUE;
+    PchPolicy->sSataConfig.Rst.Raid5            = TRUE;
+    PchPolicy->sSataConfig.Rst.Irrt             = TRUE;
+    PchPolicy->sSataConfig.Rst.OromUiBanner     = TRUE;
+    PchPolicy->sSataConfig.Rst.OromUiDelay      = PchSataOromDelay2sec;
+    PchPolicy->sSataConfig.Rst.HddUnlock        = TRUE;
+    PchPolicy->sSataConfig.Rst.LedLocate        = TRUE;
+    PchPolicy->sSataConfig.Rst.IrrtOnly         = TRUE;
+    PchPolicy->sSataConfig.Rst.SmartStorage     = TRUE;
+
+    for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {
+      //PchPolicy->sSataConfig.RstPcieStorageRemap[Index].Enable                     = 0;
+      //PchPolicy->sSataConfig.RstPcieStorageRemap[Index].RstPcieStoragePort         = 0;
+      PchPolicy->sSataConfig.RstPcieStorageRemap[Index].DeviceResetDelay             = 100;
+  }
+
+  /********************************
+    USB related configuration
+  ********************************/
+  for (PortIndex = 0; PortIndex < GetPchXhciMaxUsb2PortNum (); PortIndex++) {
+    PchPolicy->UsbConfig.PortUsb20[PortIndex].Enable  = TRUE;
+  }
+
+  for (PortIndex = 0; PortIndex < GetPchXhciMaxUsb3PortNum (); PortIndex++) {
+    PchPolicy->UsbConfig.PortUsb30[PortIndex].Enable  = TRUE;
+  }
+  //
+  //XHCI Wake On USB Disabled
+  //
+  PchPolicy->UsbConfig.XhciWakeOnUsb = FALSE;
+  //
+  // USB Port Over Current Pins mapping, please set as per board layout.
+  // Default is PchUsbOverCurrentPin0(0)
+  //
+  PchPolicy->UsbConfig.PortUsb20[ 2].OverCurrentPin = PchUsbOverCurrentPin1;
+  PchPolicy->UsbConfig.PortUsb20[ 3].OverCurrentPin = PchUsbOverCurrentPin1;
+  PchPolicy->UsbConfig.PortUsb20[ 4].OverCurrentPin = PchUsbOverCurrentPin2;
+  PchPolicy->UsbConfig.PortUsb20[ 5].OverCurrentPin = PchUsbOverCurrentPin2;
+  PchPolicy->UsbConfig.PortUsb20[ 6].OverCurrentPin = PchUsbOverCurrentPin3;
+  PchPolicy->UsbConfig.PortUsb20[ 7].OverCurrentPin = PchUsbOverCurrentPin3;
+  PchPolicy->UsbConfig.PortUsb20[ 8].OverCurrentPin = PchUsbOverCurrentPin4;
+  PchPolicy->UsbConfig.PortUsb20[ 9].OverCurrentPin = PchUsbOverCurrentPin4;
+  PchPolicy->UsbConfig.PortUsb20[10].OverCurrentPin = PchUsbOverCurrentPin5;
+  PchPolicy->UsbConfig.PortUsb20[11].OverCurrentPin = PchUsbOverCurrentPin5;
+  PchPolicy->UsbConfig.PortUsb20[12].OverCurrentPin = PchUsbOverCurrentPin6;
+  PchPolicy->UsbConfig.PortUsb20[13].OverCurrentPin = PchUsbOverCurrentPin6;
+  PchPolicy->UsbConfig.PortUsb20[14].OverCurrentPin = PchUsbOverCurrentPin7;
+  PchPolicy->UsbConfig.PortUsb20[15].OverCurrentPin = PchUsbOverCurrentPin7;
+
+  PchPolicy->UsbConfig.PortUsb30[2].OverCurrentPin  = PchUsbOverCurrentPin1;
+  PchPolicy->UsbConfig.PortUsb30[3].OverCurrentPin  = PchUsbOverCurrentPin1;
+  PchPolicy->UsbConfig.PortUsb30[4].OverCurrentPin  = PchUsbOverCurrentPin2;
+  PchPolicy->UsbConfig.PortUsb30[5].OverCurrentPin  = PchUsbOverCurrentPin2;
+  PchPolicy->UsbConfig.PortUsb30[6].OverCurrentPin  = PchUsbOverCurrentPin3;
+  PchPolicy->UsbConfig.PortUsb30[7].OverCurrentPin  = PchUsbOverCurrentPin3;
+  PchPolicy->UsbConfig.PortUsb30[8].OverCurrentPin  = PchUsbOverCurrentPin4;
+  PchPolicy->UsbConfig.PortUsb30[9].OverCurrentPin  = PchUsbOverCurrentPin4;
+
+  //
+  // Default values of USB2 AFE settings.
+  //
+  for (Index = 0; Index < PCH_H_XHCI_MAX_USB2_PORTS; Index++) {
+
+    PchPolicy->UsbConfig.PortUsb20[Index].Afe.Petxiset  = 7;
+    PchPolicy->UsbConfig.PortUsb20[Index].Afe.Txiset    = 0;
+    PchPolicy->UsbConfig.PortUsb20[Index].Afe.Predeemp  = 2;
+
+	PchPolicy->UsbConfig.PortUsb20[Index].Afe.Pehalfbit = 1;
+  }
+
+  //
+  // Enable/Disable SSIC support in the setup menu
+  //
+  for (PortIndex = 0; PortIndex < PCH_XHCI_MAX_SSIC_PORT_COUNT; PortIndex++) {
+    PchPolicy->UsbConfig.SsicConfig.SsicPort[PortIndex].Enable   = FALSE;
+  }
+
+  //
+  // xDCI configuration
+  //
+  PchPolicy->UsbConfig.XdciConfig.Enable = FALSE;
+
+
+  /********************************
+    Io Apic configuration
+  ********************************/
+  PchPolicy->IoApicConfig.IoApicId           = 0x02;
+  PchPolicy->IoApicConfig.IoApicEntry24_119  = FALSE;
+
+  /********************************
+    HPET Configuration
+  ********************************/
+  PchPolicy->HpetConfig.Enable              = TRUE;
+  PchPolicy->HpetConfig.Base                = PCH_HPET_BASE_ADDRESS;
+
+  /********************************
+    HD-Audio configuration
+  ********************************/
+  PchPolicy->HdAudioConfig.Enable            = PCH_HDAUDIO_AUTO;
+  PchPolicy->HdAudioConfig.DspEnable         = TRUE;
+  PchPolicy->HdAudioConfig.HdAudioLinkFrequency = PchHdaLinkFreq24MHz;
+  PchPolicy->HdAudioConfig.IDispLinkFrequency   = PchHdaLinkFreq96MHz;
+  PchPolicy->HdAudioConfig.ResetWaitTimer       = 600; // Must be at least 521us (25 frames)
+  PchPolicy->HdAudioConfig.DspEndpointDmic      = PchHdaDmic4chArray;
+
+  /********************************
+    Lan configuration
+  ********************************/
+  PchPolicy->LanConfig.Enable               = TRUE;
+  /********************************
+    SMBus configuration
+  ********************************/
+  PchPolicy->SmbusConfig.Enable                = TRUE;
+  PchPolicy->SmbusConfig.SmbusIoBase           = PcdGet16 (PcdSmbusBaseAddress);
+  ASSERT (sizeof (mSmbusRsvdAddresses) <= PCH_MAX_SMBUS_RESERVED_ADDRESS);
+  PchPolicy->SmbusConfig.NumRsvdSmbusAddresses = sizeof (mSmbusRsvdAddresses);
+  CopyMem (
+    PchPolicy->SmbusConfig.RsvdSmbusAddressTable,
+    mSmbusRsvdAddresses,
+    sizeof (mSmbusRsvdAddresses)
+    );
+
+  /********************************
+    Lockdown configuration
+  ********************************/
+  PchPolicy->LockDownConfig.GlobalSmi       = TRUE;
+  //
+  // PCH BIOS Spec Flash Security Recommendations,
+  // Intel strongly recommends that BIOS sets the BIOS Interface Lock Down bit. Enabling this bit
+  // will mitigate malicious software attempts to replace the system BIOS option ROM with its own code.
+  // Here we always enable this as a Policy.
+  //
+  PchPolicy->LockDownConfig.BiosInterface   = TRUE;
+  PchPolicy->LockDownConfig.RtcLock         = TRUE;
+
+  /********************************
+    Thermal configuration.
+  ********************************/
+  PchPolicy->ThermalConfig.ThermalDeviceEnable                           = 0;
+  PchPolicy->ThermalConfig.TsmicLock                                     = TRUE;
+  PchPolicy->ThermalConfig.ThermalThrottling.TTLevels.SuggestedSetting   = TRUE;
+  PchPolicy->ThermalConfig.ThermalThrottling.TTLevels.PchCrossThrottling = TRUE;
+  PchPolicy->ThermalConfig.ThermalThrottling.DmiHaAWC.SuggestedSetting   = TRUE;
+  PchPolicy->ThermalConfig.ThermalThrottling.SataTT.SuggestedSetting     = TRUE;
+  PchPolicy->ThermalConfig.MemoryThrottling.TsGpioPinSetting[TsGpioC].PmsyncEnable     = TRUE;
+  PchPolicy->ThermalConfig.MemoryThrottling.TsGpioPinSetting[TsGpioC].C0TransmitEnable = TRUE;
+  PchPolicy->ThermalConfig.MemoryThrottling.TsGpioPinSetting[TsGpioD].PmsyncEnable     = TRUE;
+  PchPolicy->ThermalConfig.MemoryThrottling.TsGpioPinSetting[TsGpioD].C0TransmitEnable = TRUE;
+
+  /********************************
+    MiscPm Configuration
+  ********************************/
+  PchPolicy->PmConfig.PowerResetStatusClear.MeWakeSts      = TRUE;
+  PchPolicy->PmConfig.PowerResetStatusClear.MeHrstColdSts  = TRUE;
+  PchPolicy->PmConfig.PowerResetStatusClear.MeHrstWarmSts  = TRUE;
+  PchPolicy->PmConfig.PowerResetStatusClear.WolOvrWkSts    = TRUE;
+
+  PchPolicy->PmConfig.WakeConfig.WolEnableOverride         = TRUE;
+  PchPolicy->PmConfig.WakeConfig.LanWakeFromDeepSx         = TRUE;
+
+  PchPolicy->PmConfig.PchSlpS3MinAssert                    = PchSlpS350ms;
+  PchPolicy->PmConfig.PchSlpS4MinAssert                    = PchSlpS44s;
+  PchPolicy->PmConfig.PchSlpSusMinAssert                   = PchSlpSus4s;
+  PchPolicy->PmConfig.PchSlpAMinAssert                     = PchSlpA2s;
+
+  PchPolicy->PmConfig.PmcReadDisable                       = TRUE;
+  PchPolicy->PmConfig.SlpLanLowDc                          = TRUE;
+  PchPolicy->PmConfig.PciePllSsc                           = 0xFF;
+
+  PchPolicy->PmConfig.SlpS0Enable                          = TRUE;
+
+  PchPolicy->PmConfig.GrPfetDurOnDef                       = PchPmGrPfetDur5us;
+
+  /********************************
+    DMI related settings
+  ********************************/
+  PchPolicy->DmiConfig.DmiAspm = TRUE;
+  PchPolicy->DmiConfig.DmiStopAndScreamEnable = FALSE;
+
+  /********************************
+    Serial IRQ Configuration
+  ********************************/
+  PchPolicy->SerialIrqConfig.SirqEnable       = TRUE;
+  PchPolicy->SerialIrqConfig.SirqMode         = PchQuietMode;
+  PchPolicy->SerialIrqConfig.StartFramePulse  = PchSfpw4Clk;
+
+
+  /********************************
+    Interrupt Configuration
+  ********************************/
+  IntConfigTableEntries = sizeof (mDevIntConfig) / sizeof (PCH_DEVICE_INTERRUPT_CONFIG);
+  ASSERT (IntConfigTableEntries <= PCH_MAX_DEVICE_INTERRUPT_CONFIG);
+  PchPolicy->PchInterruptConfig.NumOfDevIntConfig = IntConfigTableEntries;
+  CopyMem (
+    PchPolicy->PchInterruptConfig.DevIntConfig,
+    mDevIntConfig,
+    sizeof (mDevIntConfig)
+    );
+  if (GetPchSeries () == PchLp) {
+    CopyMem (
+      &(PchPolicy->PchInterruptConfig.DevIntConfig[IntConfigTableEntries]),
+      mLpOnlyDevIntConfig,
+      sizeof (mLpOnlyDevIntConfig)
+      );
+    PchPolicy->PchInterruptConfig.NumOfDevIntConfig += (sizeof (mLpOnlyDevIntConfig) / sizeof (PCH_DEVICE_INTERRUPT_CONFIG));
+  }
+
+  ASSERT ((sizeof (mPxRcConfig) / sizeof (UINT8)) <= PCH_MAX_PXRC_CONFIG);
+  CopyMem (
+    PchPolicy->PchInterruptConfig.PxRcConfig,
+    mPxRcConfig,
+    sizeof (mPxRcConfig)
+    );
+
+  PchPolicy->PchInterruptConfig.GpioIrqRoute = 14;
+  PchPolicy->PchInterruptConfig.SciIrqSelect = 9;
+  PchPolicy->PchInterruptConfig.TcoIrqSelect = 9;
+
+
+  /********************************
+    Port 61h emulation
+  ********************************/
+  PchPolicy->Port61hSmmConfig.Enable   = TRUE;
+
+
+  /********************************
+    DCI Configuration
+  ********************************/
+  PchPolicy->DciConfig.DciAutoDetect     = TRUE;
+
+  /********************************
+    LPC Configuration
+  ********************************/
+  PchPolicy->LpcConfig.EnhancePort8xhDecoding     = TRUE;
+
+  /********************************
+    Power Optimizer related settings
+  ********************************/
+  PchPolicy->SataConfig.PwrOptEnable     = TRUE;
+  PchPolicy->sSataConfig.PwrOptEnable     = TRUE;
+
+
+  PchPolicy->AdrConfig.PchAdrEn = FORCE_ENABLE;
+  PchPolicy->AdrConfig.AdrGpioSel = PM_SYNC_GPIO_B;
+  PchPolicy->AdrConfig.AdrHostPartitionReset = FORCE_DISABLE;
+  PchPolicy->AdrConfig.AdrTimerEn = FORCE_ENABLE;
+  PchPolicy->AdrConfig.AdrTimerVal = V_PCH_LBG_MROM_ADRTIMERCTRL_ADR_TMR_100US;
+  PchPolicy->AdrConfig.AdrMultiplierVal = V_PCH_LBG_MROM_ADRTIMERCTRL_ADR_MULT_1;
+
+  *PchPolicyPpi = PchPolicy;
+  return EFI_SUCCESS;
+}
+
+/**
+  PchInstallPolicyPpi installs PchPolicyPpi.
+  While installed, RC assumes the Policy is ready and finalized. So please update and override
+  any setting before calling this function.
+
+  @param[in] PchPolicyPpi      The pointer to PCH Policy PPI instance
+
+  @retval EFI_SUCCESS                   The policy is installed.
+  @retval EFI_OUT_OF_RESOURCES          Insufficient resources to create buffer
+**/
+EFI_STATUS
+EFIAPI
+PchInstallPolicyPpi (
+  IN  PCH_POLICY_PPI           *PchPolicyPpi
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_PEI_PPI_DESCRIPTOR                *PchPolicyPpiDesc;
+
+  PchPolicyPpiDesc = (EFI_PEI_PPI_DESCRIPTOR *) AllocateZeroPool (sizeof (EFI_PEI_PPI_DESCRIPTOR));
+  if (PchPolicyPpiDesc == NULL) {
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PchPolicyPpiDesc->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+  PchPolicyPpiDesc->Guid  = &gPchPlatformPolicyPpiGuid;
+  PchPolicyPpiDesc->Ppi   = PchPolicyPpi;
+
+  //
+  // Print whole PCH_POLICY_PPI and serial out.
+  //
+  if (PchIsDwrFlow() == FALSE) {
+    PchPrintPolicyPpi (PchPolicyPpi);
+  }
+
+  //
+  // Install PCH Policy PPI
+  //
+  Status = PeiServicesInstallPpi (PchPolicyPpiDesc);
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.inf
new file mode 100644
index 0000000000..f11ba239b1
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLib.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION          = 0x00010017
+  BASE_NAME            = PeiPchPolicyLib
+  FILE_GUID            = BB1AC992-B2CA-4744-84B7-915C185576C5
+  VERSION_STRING       = 1.0
+  MODULE_TYPE          = PEIM
+  LIBRARY_CLASS        = PchPolicyLib
+
+
+[LibraryClasses]
+  DebugLib
+  IoLib
+  PcdLib
+  PeiServicesLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  PchInfoLib
+  PchPmcLib                                   #SERVER_BIOS
+
+
+[Packages]
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+
+[Pcd]
+  gEfiPchTokenSpaceGuid.PcdPchAcpiIoPortBaseAddress          #SERVER_BIOS
+  gEfiPchTokenSpaceGuid.PcdSmbusBaseAddress   #SERVER_BIOS
+  gEfiPchTokenSpaceGuid.PcdSerialIoUartDebugEnable
+  gEfiPchTokenSpaceGuid.PcdSerialIoUartNumber
+
+
+[Sources]
+  PeiPchPolicyLib.c
+  PeiPchPolicyLibrary.h
+  PchPrintPolicy.c
+  Rvp3PolicyLib.c
+
+
+[Ppis]
+  gPchPlatformPolicyPpiGuid            ## PRODUCES # SERVER_BIOS
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLibrary.h b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLibrary.h
new file mode 100644
index 0000000000..5a35f0ba47
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/PeiPchPolicyLibrary.h
@@ -0,0 +1,25 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_PCH_POLICY_LIBRARY_H_
+#define _PEI_PCH_POLICY_LIBRARY_H_
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PchInfoLib.h>
+#include <Ppi/PchPolicy.h>
+#include <PchAccess.h>
+#include <Library/PchSerialIoLib.h>
+#include <Library/PchPolicyLib.h>
+
+#define PCH_HPET_BASE_ADDRESS             0xFED00000
+
+
+#endif // _PEI_PCH_POLICY_LIBRARY_H_
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/Rvp3PolicyLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/Rvp3PolicyLib.c
new file mode 100644
index 0000000000..092bda717d
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/PeiPchPolicyLib/Rvp3PolicyLib.c
@@ -0,0 +1,205 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiPchPolicyLibrary.h"
+
+/*
+  Apply RVP3 PCH specific default settings
+
+  @param[in] PchPolicyPpi      The pointer to PCH Policy PPI instance
+*/
+VOID
+EFIAPI
+PchRvp3DefaultPolicy (
+  IN  PCH_POLICY_PPI           *PchPolicy
+  )
+{
+  UINTN Index;
+
+  //
+  // PCIE RP
+  //
+  for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
+    PchPolicy->PcieConfig.RootPort[Index].ClkReqDetect                   = TRUE;
+    PchPolicy->PcieConfig.RootPort[Index].AdvancedErrorReporting         = TRUE;
+  }
+
+  PchPolicy->PcieConfig.RootPort[0].ClkReqSupported = TRUE;
+  PchPolicy->PcieConfig.RootPort[0].ClkReqNumber = 2;
+  PchPolicy->HsioPcieConfig.Lane[0].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[0].HsioRxSetCtle = 6;
+
+  PchPolicy->HsioPcieConfig.Lane[1].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[1].HsioRxSetCtle = 6;
+
+  PchPolicy->HsioPcieConfig.Lane[2].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[2].HsioRxSetCtle = 6;
+
+  PchPolicy->HsioPcieConfig.Lane[3].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[3].HsioRxSetCtle = 6;
+
+  PchPolicy->PcieConfig.RootPort[4].ClkReqSupported = TRUE;
+  PchPolicy->PcieConfig.RootPort[4].ClkReqNumber = 3;
+
+  PchPolicy->PcieConfig.RootPort[5].ClkReqSupported = TRUE;
+  PchPolicy->PcieConfig.RootPort[5].ClkReqNumber = 1;
+  PchPolicy->HsioPcieConfig.Lane[5].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[5].HsioRxSetCtle = 8;
+
+  PchPolicy->HsioPcieConfig.Lane[7].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[7].HsioRxSetCtle = 8;
+
+  PchPolicy->PcieConfig.RootPort[8].ClkReqSupported = TRUE;
+  PchPolicy->PcieConfig.RootPort[8].ClkReqNumber = 5;
+  PchPolicy->HsioPcieConfig.Lane[8].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[8].HsioRxSetCtle = 8;
+
+  PchPolicy->PcieConfig.RootPort[9].ClkReqSupported = TRUE;
+  PchPolicy->PcieConfig.RootPort[9].ClkReqNumber = 4;
+  PchPolicy->HsioPcieConfig.Lane[9].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[9].HsioRxSetCtle = 8;
+
+  PchPolicy->HsioPcieConfig.Lane[10].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[10].HsioRxSetCtle = 8;
+
+  PchPolicy->HsioPcieConfig.Lane[11].HsioRxSetCtleEnable = TRUE;
+  PchPolicy->HsioPcieConfig.Lane[11].HsioRxSetCtle = 8;
+
+  //
+  // SATA
+  //
+  PchPolicy->HsioSataConfig.PortLane[0].HsioRxGen3EqBoostMagEnable = TRUE;
+  PchPolicy->HsioSataConfig.PortLane[0].HsioRxGen3EqBoostMag = 4;
+  PchPolicy->HsioSataConfig.PortLane[0].HsioTxGen1DownscaleAmpEnable = TRUE;
+  PchPolicy->HsioSataConfig.PortLane[0].HsioTxGen1DownscaleAmp = 0x2C;
+  PchPolicy->HsioSataConfig.PortLane[0].HsioTxGen2DownscaleAmpEnable = 0;
+  PchPolicy->HsioSataConfig.PortLane[0].HsioTxGen2DownscaleAmp = 0;
+
+  //
+  // USB
+  //
+  PchPolicy->UsbConfig.PortUsb20[0].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[0].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[0].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[0].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[1].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[1].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[1].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[1].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[2].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[2].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[2].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[2].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[3].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[3].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[3].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[3].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[4].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[4].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[4].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[4].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[5].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[5].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[5].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[5].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[6].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[6].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[6].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[6].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[7].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[7].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[7].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[7].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[8].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[8].Afe.Txiset       = 5;
+  PchPolicy->UsbConfig.PortUsb20[8].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[8].Afe.Pehalfbit    = 1;
+
+  PchPolicy->UsbConfig.PortUsb20[9].Afe.Petxiset     = 7;
+  PchPolicy->UsbConfig.PortUsb20[9].Afe.Txiset       = 0;
+  PchPolicy->UsbConfig.PortUsb20[9].Afe.Predeemp     = 2;
+  PchPolicy->UsbConfig.PortUsb20[9].Afe.Pehalfbit    = 1;
+
+  // OC Map for USB2 Ports
+  PchPolicy->UsbConfig.PortUsb20[ 0].OverCurrentPin = PchUsbOverCurrentPin0;
+  PchPolicy->UsbConfig.PortUsb20[ 1].OverCurrentPin = PchUsbOverCurrentPin2;
+  PchPolicy->UsbConfig.PortUsb20[ 2].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[ 3].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[ 4].OverCurrentPin = PchUsbOverCurrentPin2;
+  PchPolicy->UsbConfig.PortUsb20[ 5].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[ 6].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[ 7].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[ 8].OverCurrentPin = PchUsbOverCurrentPin1;
+  PchPolicy->UsbConfig.PortUsb20[ 9].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[10].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[11].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[12].OverCurrentPin = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb20[13].OverCurrentPin = PchUsbOverCurrentPinSkip;
+
+  // OC Map for USB3 Ports
+  PchPolicy->UsbConfig.PortUsb30[0].OverCurrentPin  = PchUsbOverCurrentPin0;
+  PchPolicy->UsbConfig.PortUsb30[1].OverCurrentPin  = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb30[2].OverCurrentPin  = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb30[3].OverCurrentPin  = PchUsbOverCurrentPin1;
+  PchPolicy->UsbConfig.PortUsb30[4].OverCurrentPin  = PchUsbOverCurrentPinSkip;
+  PchPolicy->UsbConfig.PortUsb30[5].OverCurrentPin  = PchUsbOverCurrentPinSkip;
+
+  PchPolicy->UsbConfig.SsicConfig.SsicPort[0].Enable = TRUE;
+  PchPolicy->UsbConfig.SsicConfig.SsicPort[1].Enable = TRUE;
+
+  //
+  // IOAPIC
+  //
+  PchPolicy->IoApicConfig.BdfValid          = 1;
+  PchPolicy->IoApicConfig.BusNumber         = 0xF0;
+  PchPolicy->IoApicConfig.DeviceNumber      = 0x1F;
+  PchPolicy->IoApicConfig.FunctionNumber    = 0;
+
+  //
+  // LAN
+  //
+  PchPolicy->LanConfig.K1OffEnable     = TRUE;
+  PchPolicy->LanConfig.ClkReqSupported = TRUE;
+  PchPolicy->LanConfig.ClkReqNumber    = 3;
+
+  //
+  // LOCK DOWN
+  //
+  PchPolicy->LockDownConfig.SpiEiss     = TRUE;
+  PchPolicy->LockDownConfig.BiosLock    = TRUE;
+
+  //
+  // THERMAL
+  //
+  PchPolicy->ThermalConfig.ThermalThrottling.TTLevels.PchCrossThrottling = FALSE;
+
+  //
+  // PM CONFIG
+  //
+  PchPolicy->PmConfig.PciClockRun       = TRUE;
+
+  //
+  // DMI
+  //
+  PchPolicy->DmiConfig.PwrOptEnable     = TRUE;
+
+
+  //
+  // TRACEHUB
+  //
+  PchPolicy->PchTraceHubConfig.MemReg0Size = 0x100000;  // 1MB
+  PchPolicy->PchTraceHubConfig.MemReg1Size = 0x100000;  // 1MB
+
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf
new file mode 100644
index 0000000000..00f5e92189
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SmmSpiFlashCommonLib.inf
@@ -0,0 +1,50 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = SmmSpiFlashCommonLib
+  FILE_GUID                      = 9632D96E-E849-4217-9217-DC500B8AAE47
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  LIBRARY_CLASS                  = SpiFlashCommonLib|DXE_SMM_DRIVER
+  CONSTRUCTOR                    = SmmSpiFlashCommonLibConstructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[LibraryClasses]
+  PciLib
+  IoLib
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  SmmServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  MmPciLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[Pcd]
+  gEfiPchTokenSpaceGuid.PcdFlashAreaBaseAddress  ## CONSUMES
+  gEfiPchTokenSpaceGuid.PcdFlashAreaSize         ## CONSUMES
+
+[Sources]
+  SpiFlashCommonSmmLib.c
+  SpiFlashCommon.c
+
+[Protocols]
+  gEfiSmmSpiProtocolGuid                        ## CONSUMES
+
+[Depex.X64.DXE_SMM_DRIVER]
+  gEfiSmmSpiProtocolGuid
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c
new file mode 100644
index 0000000000..a079e471bb
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommon.c
@@ -0,0 +1,192 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/SpiFlashCommonLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Protocol/Spi.h>
+
+
+EFI_SPI_PROTOCOL       *mSpiProtocol;
+
+//
+// FlashAreaBaseAddress and Size for boottime and runtime usage.
+//
+UINTN mFlashAreaBaseAddress = 0;
+UINTN mFlashAreaSize        = 0;
+
+/**
+  Enable block protection on the Serial Flash device.
+
+  @retval     EFI_SUCCESS       Opertion is successful.
+  @retval     EFI_DEVICE_ERROR  If there is any device errors.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiFlashLock (
+  VOID
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Read NumBytes bytes of data from the address specified by
+  PAddress into Buffer.
+
+  @param[in]      Address       The starting physical address of the read.
+  @param[in,out]  NumBytes      On input, the number of bytes to read. On output, the number
+                                of bytes actually read.
+  @param[out]     Buffer        The destination data buffer for the read.
+
+  @retval         EFI_SUCCESS       Opertion is successful.
+  @retval         EFI_DEVICE_ERROR  If there is any device errors.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiFlashRead (
+  IN     UINTN                        Address,
+  IN OUT UINT32                       *NumBytes,
+     OUT UINT8                        *Buffer
+  )
+{
+  ASSERT ((NumBytes != NULL) && (Buffer != NULL));
+  if ((NumBytes == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // This function is implemented specifically for those platforms
+  // at which the SPI device is memory mapped for read. So this
+  // function just do a memory copy for Spi Flash Read.
+  //
+  CopyMem (Buffer, (VOID *) Address, *NumBytes);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Write NumBytes bytes of data from Buffer to the address specified by
+  PAddresss.
+
+  @param[in]      Address         The starting physical address of the write.
+  @param[in,out]  NumBytes        On input, the number of bytes to write. On output,
+                                  the actual number of bytes written.
+  @param[in]      Buffer          The source data buffer for the write.
+
+  @retval         EFI_SUCCESS       Opertion is successful.
+  @retval         EFI_DEVICE_ERROR  If there is any device errors.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiFlashWrite (
+  IN     UINTN                      Address,
+  IN OUT UINT32                     *NumBytes,
+  IN     UINT8                      *Buffer
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     Offset;
+  UINT32                    Length;
+  UINT32                    RemainingBytes;
+
+  ASSERT ((NumBytes != NULL) && (Buffer != NULL));
+  if ((NumBytes == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (Address >= mFlashAreaBaseAddress);
+
+  Offset = Address - mFlashAreaBaseAddress;
+
+  ASSERT ((*NumBytes + Offset) <= mFlashAreaSize);
+
+  Status = EFI_SUCCESS;
+  RemainingBytes = *NumBytes;
+
+
+  while (RemainingBytes > 0) {
+    if (RemainingBytes > SECTOR_SIZE_4KB) {
+      Length = SECTOR_SIZE_4KB;
+    } else {
+      Length = RemainingBytes;
+    }
+    Status = mSpiProtocol->FlashWrite (
+                             mSpiProtocol,
+                             FlashRegionBios,
+                             (UINT32) Offset,
+                             Length,
+                             Buffer
+                             );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+    RemainingBytes -= Length;
+    Offset += Length;
+    Buffer += Length;
+  }
+
+  //
+  // Actual number of bytes written
+  //
+  *NumBytes -= RemainingBytes;
+
+  return Status;
+}
+
+/**
+  Erase the block starting at Address.
+
+  @param[in]  Address         The starting physical address of the block to be erased.
+                              This library assume that caller garantee that the PAddress
+                              is at the starting address of this block.
+  @param[in]  NumBytes        On input, the number of bytes of the logical block to be erased.
+                              On output, the actual number of bytes erased.
+
+  @retval     EFI_SUCCESS.      Opertion is successful.
+  @retval     EFI_DEVICE_ERROR  If there is any device errors.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiFlashBlockErase (
+  IN    UINTN                     Address,
+  IN    UINTN                     *NumBytes
+  )
+{
+  EFI_STATUS          Status;
+  UINTN               Offset;
+  UINTN               RemainingBytes;
+
+  ASSERT (NumBytes != NULL);
+  if (NumBytes == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (Address >= mFlashAreaBaseAddress);
+
+  Offset = Address - mFlashAreaBaseAddress;
+
+  ASSERT ((*NumBytes % SECTOR_SIZE_4KB) == 0);
+  ASSERT ((*NumBytes + Offset) <= mFlashAreaSize);
+
+  Status = EFI_SUCCESS;
+  RemainingBytes = *NumBytes;
+
+
+  Status = mSpiProtocol->FlashErase (
+                           mSpiProtocol,
+                           FlashRegionBios,
+                           (UINT32) Offset,
+                           (UINT32) RemainingBytes
+                           );
+  return Status;
+}
+
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c
new file mode 100644
index 0000000000..81cb0a16e8
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/Library/SmmSpiFlashCommonLib/SpiFlashCommonSmmLib.c
@@ -0,0 +1,53 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/SpiFlashCommonLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Protocol/Spi.h>
+
+extern EFI_SPI_PROTOCOL   *mSpiProtocol;
+
+extern UINTN mFlashAreaBaseAddress;
+extern UINTN mFlashAreaSize;
+
+/**
+  The library constructuor.
+
+  The function does the necessary initialization work for this library
+  instance.
+
+  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
+  @param[in]  SystemTable       A pointer to the EFI system table.
+
+  @retval     EFI_SUCCESS       The function always return EFI_SUCCESS for now.
+                                It will ASSERT on error for debug version.
+  @retval     EFI_ERROR         Please reference LocateProtocol for error code details.
+**/
+EFI_STATUS
+EFIAPI
+SmmSpiFlashCommonLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  mFlashAreaBaseAddress = (UINTN)PcdGet32 (PcdFlashAreaBaseAddress);
+  mFlashAreaSize        = (UINTN)PcdGet32 (PcdFlashAreaSize);
+
+  //
+  // Locate the SMM SPI protocol.
+  //
+  Status = gSmst->SmmLocateProtocol (
+                    &gEfiSmmSpiProtocolGuid,
+                    NULL,
+                    (VOID **) &mSpiProtocol
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/BasePchResetCommonLib.inf b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/BasePchResetCommonLib.inf
new file mode 100644
index 0000000000..9fcd02243b
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/BasePchResetCommonLib.inf
@@ -0,0 +1,27 @@
+## @file
+#
+# Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = BasePchResetCommonLib
+  FILE_GUID                      = 1E6151B2-6306-4C9C-B9AC-794A13BEBC3F
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PchResetCommonLib
+
+[Sources]
+  PchResetCommon.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  PurleyRefreshSiliconPkg/SiPkg.dec
+
+[LibraryClasses]
+  IoLib
+  DebugLib
+  PchCycleDecodingLib
diff --git a/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/PchResetCommon.c b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/PchResetCommon.c
new file mode 100644
index 0000000000..0c33e9a9d9
--- /dev/null
+++ b/Silicon/Intel/PurleyRefreshSiliconPkg/Pch/LibraryPrivate/BasePchResetCommonLib/PchResetCommon.c
@@ -0,0 +1,168 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <PchAccess.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <IncludePrivate/Library/PchResetCommonLib.h>
+
+
+EFI_STATUS
+EFIAPI
+PchResetCallback (
+  IN     PCH_RESET_TYPE           PchResetType
+  );
+
+/**
+  Initialize an Pch Reset ppi/protocol instance.
+
+  @param[in] PchResetInstance     Pointer to PchResetInstance to initialize
+
+  @retval EFI_SUCCESS             The protocol instance was properly initialized
+  @exception EFI_UNSUPPORTED      The PCH is not supported by this module
+**/
+EFI_STATUS
+PchResetConstructor (
+  PCH_RESET_INSTANCE          *PchResetInstance
+  )
+{
+  UINTN   PmcBaseAddress;
+
+  ///
+  /// Initialize the Reset protocol instance
+  ///
+  PchResetInstance->Signature               = PCH_RESET_SIGNATURE;
+  PchResetInstance->Handle                  = NULL;
+
+  ///
+  /// Sanity check to ensure PMC ACPI/PM BASE initialization has occurred previously.
+  ///
+  PmcBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_PCH,
+                     PCI_DEVICE_NUMBER_PCH_PMC,
+                     PCI_FUNCTION_NUMBER_PCH_PMC
+                     );
+  PchResetInstance->PchPmcBase = PmcBaseAddress;
+  PchPwrmBaseGet (&(PchResetInstance->PchPwrmBase));
+  ASSERT (PchResetInstance->PchPwrmBase != 0);
+  PchAcpiBaseGet (&(PchResetInstance->PchAcpiBase));
+  ASSERT (PchResetInstance->PchAcpiBase != 0);
+
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Execute Pch Reset from the host controller.
+  @param[in] PchResetInstance     Pointer to PchResetInstance to initialize
+  @param[in] PchResetType         Pch Reset Types which includes ColdReset, WarmReset, ShutdownReset,
+                                  PowerCycleReset, GlobalReset, GlobalResetWithEc
+
+  @retval EFI_SUCCESS             Successfully completed.
+  @retval EFI_INVALID_PARAMETER   If ResetType is invalid.
+**/
+EFI_STATUS
+PchReset (
+  IN  PCH_RESET_INSTANCE *PchResetInstance,
+  IN  PCH_RESET_TYPE     PchResetType
+  )
+{
+  UINTN      PmcBaseAddress;
+  UINT16     ABase;
+  UINT8      OutputData;
+  UINT32     Data32;
+  UINT16     Data16;
+  EFI_STATUS Status;
+
+  PmcBaseAddress = PchResetInstance->PchPmcBase;
+  ABase          = PchResetInstance->PchAcpiBase;
+  switch (PchResetType) {
+    case ColdReset:
+      IoWrite8 ((UINTN) R_PCH_RST_CNT, (UINT8) V_PCH_RST_CNT_HARDSTARTSTATE);
+      OutputData = V_PCH_RST_CNT_FULLRESET;
+      break;
+
+    case WarmReset:
+      IoWrite8 ((UINTN) R_PCH_RST_CNT, (UINT8) V_PCH_RST_CNT_SOFTSTARTSTATE);
+      OutputData = V_PCH_RST_CNT_HARDRESET;
+      break;
+
+    case ShutdownReset:
+      ///
+      /// Firstly, ACPI decode must be enabled
+      ///
+      MmioOr8 (
+        PmcBaseAddress + R_PCH_PMC_ACPI_CNT,
+        (UINT8) (B_PCH_PMC_ACPI_CNT_ACPI_EN)
+        );
+
+      ///
+      /// Then, GPE0_EN should be disabled to avoid any GPI waking up the system from S5
+      ///
+      IoWrite32 ((UINTN) (ABase + R_PCH_ACPI_GPE0_EN_127_96), 0);
+
+      ///
+      /// Secondly, PwrSts register must be cleared
+      ///
+      /// Write a "1" to bit[8] of power button status register at
+      /// (PM_BASE + PM1_STS_OFFSET) to clear this bit
+      ///
+      Data16 = B_PCH_SMI_STS_PM1_STS_REG;
+      IoWrite16 ((UINTN) (ABase + R_PCH_SMI_STS), Data16);
+
+      ///
+      /// Finally, transform system into S5 sleep state
+      ///
+      Data32  = IoRead32 ((UINTN) (ABase + R_PCH_ACPI_PM1_CNT));
+
+      Data32  = (UINT32) ((Data32 &~(B_PCH_ACPI_PM1_CNT_SLP_TYP + B_PCH_ACPI_PM1_CNT_SLP_EN)) | V_PCH_ACPI_PM1_CNT_S5);
+
+      IoWrite32 ((UINTN) (ABase + R_PCH_ACPI_PM1_CNT), Data32);
+
+      Data32 = Data32 | B_PCH_ACPI_PM1_CNT_SLP_EN;
+
+      IoWrite32 ((UINTN) (ABase + R_PCH_ACPI_PM1_CNT), Data32);
+      return EFI_SUCCESS;
+
+    case PowerCycleReset:
+    case GlobalReset:
+    case GlobalResetWithEc:
+      ///
+      /// PCH BIOS Spec Section 4.6 GPIO Reset Requirement
+      ///
+
+      if ((PchResetType == GlobalReset) || (PchResetType == GlobalResetWithEc)) {
+        MmioOr32 (
+          PmcBaseAddress + R_PCH_PMC_ETR3,
+          (UINT32) (B_PCH_PMC_ETR3_CF9GR)
+          );
+      }
+      OutputData = V_PCH_RST_CNT_FULLRESET;
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_ERROR, "Resetting the platform (%02x)...\n", OutputData));
+
+  Status = PchResetCallback (PchResetType);
+
+  if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {
+    IoWrite8 ((UINTN) R_PCH_RST_CNT, OutputData);
+    ///
+    /// Waiting for system reset
+    ///
+    CpuDeadLoop ();
+  }
+
+  return Status;
+}
-- 
2.27.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#74973): https://edk2.groups.io/g/devel/message/74973
Mute This Topic: https://groups.io/mt/82742431/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list