[edk2-devel] [Patch V2 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules

Heng Luo heng.luo at intel.com
Thu Feb 4 08:49:15 UTC 2021


REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3171

Adds the following files:
  * Pch/PchInit/Dxe
  * Pch/PchInit/Smm
  * Pch/PchSmiDispatcher/Smm
  * Pch/SmmControl/RuntimeDxe

Cc: Sai Chaganty <rangasai.v.chaganty at intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone at intel.com>
Signed-off-by: Heng Luo <heng.luo at intel.com>
---
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c                      |  494 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c                  |   41 ++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c                   |  201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c                      |  314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h                      |  122 ++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c                   |  354 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf              |   96 ++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c                      |   89 ++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c                  |   33 +++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c               |  134 ++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c                     |  266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c          |  137 +++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c                  |   33 +++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c                   |  285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h                   |  254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf                 |  110 +++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c                   |  451 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c                  |   67 +++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c              | 1284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h              |  226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c      | 2442 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf  |  116 ++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h        |   40 +++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelperClient.c  |   57 ++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h              | 1043 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c          |  926 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c          | 1588 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h          |  341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c           |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c       |  332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h       |  155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c |  667 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c   |   81 +++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c            |  381 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c            |  224 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c           |  230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c      |  778 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h      |  107 ++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf       |   54 +++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c   |  394 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h   |  130 +++++++++++++++++++++++++++++++++++++++++++++++++
 41 files changed, 15340 insertions(+)

diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
new file mode 100644
index 0000000000..e88afa5ded
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
@@ -0,0 +1,494 @@
+/** @file
+  This is the driver that initializes the Intel PCH.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "PchInit.h"
+#include <Protocol/PchPolicy.h>
+#include <GpioDevConfig.h>
+#include <ScsConfig.h>
+#include <Library/PchInfoLib.h>
+#include <Library/GpioLib.h>
+#include <Library/GpioNativeLib.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PmcLib.h>
+#include <Library/SerialIoAccessLib.h>
+#include <Library/GbeLib.h>
+#include <PchRstHob.h>
+#include <Library/PchPcieRpLib.h>
+#include <TraceHubConfig.h>
+#include <PchReservedResources.h>
+#include <Library/PciSegmentLib.h>
+#include <Register/PchRegs.h>
+#include <Library/BaseLib.h>
+#include <Register/UsbRegs.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+#include <PcieRegs.h>
+#include <Library/PchPcrLib.h>
+#include <Library/PchPciBdfLib.h>
+#include <PchHybridStorageHob.h>
+#include <Library/SataLib.h>
+
+//
+// Module variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL    mPchNvsAreaProtocol;
+
+/**
+  Retrieve interrupt information about a PCH device from policy
+
+  @param[in] UartNumber                 Uart number
+
+  @retval PCH_DEVICE_INTERRUPT_CONFIG   structure with device's interrupt information
+**/
+PCH_DEVICE_INTERRUPT_CONFIG
+GetUartInterrupt (
+  IN UINT8  UartNumber
+  )
+{
+  PCH_DEVICE_INTERRUPT_CONFIG EmptyRecord;
+  UINT8                       DevNum;
+  UINT8                       FuncNum;
+  UINT8                       Index;
+
+  ZeroMem (&EmptyRecord, sizeof (PCH_DEVICE_INTERRUPT_CONFIG));
+  DevNum  = SerialIoUartDevNumber (UartNumber);
+  FuncNum = SerialIoUartFuncNumber (UartNumber);
+
+  for (Index = 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; Index++) {
+    if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device == DevNum) &&
+        (mPchConfigHob->Interrupt.DevIntConfig[Index].Function == FuncNum)) {
+      return mPchConfigHob->Interrupt.DevIntConfig[Index];
+    }
+  }
+  return EmptyRecord;
+}
+
+/**
+  Update ASL definitions for SerialIo devices.
+
+**/
+VOID
+UpdateSerialIoAcpiData (
+  VOID
+  )
+{
+  UINT8        Index;
+
+  for (Index = 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++) {
+    mPchNvsAreaProtocol.Area->SM0[Index] = mPchConfigHob->SerialIo.SpiDeviceConfig[Index].Mode;
+    mPchNvsAreaProtocol.Area->SC0[Index] = GetSerialIoSpiPciCfg (Index);
+  }
+  for (Index = 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++) {
+    mPchNvsAreaProtocol.Area->IM0[Index] = mPchConfigHob->SerialIo.I2cDeviceConfig[Index].Mode;
+    mPchNvsAreaProtocol.Area->IC0[Index] = GetSerialIoI2cPciCfg (Index);
+  }
+  for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++) {
+    mPchNvsAreaProtocol.Area->UM0[Index] = mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode;
+    mPchNvsAreaProtocol.Area->UC0[Index] = GetSerialIoUartPciCfg (Index);
+    mPchNvsAreaProtocol.Area->UD0[Index] = mPchConfigHob->SerialIo.UartDeviceConfig[Index].DmaEnable;
+    mPchNvsAreaProtocol.Area->UP0[Index] = mPchConfigHob->SerialIo.UartDeviceConfig[Index].PowerGating;
+    mPchNvsAreaProtocol.Area->UI0[Index] = (GetUartInterrupt (Index)).Irq;
+  }
+}
+
+#if FixedPcdGet8(PcdEmbeddedEnable) == 0x1
+/**
+  Update NVS Area for Timed GPIO devices.
+**/
+VOID
+UpdateTimedGpioSetup (
+  VOID
+  )
+{
+  mPchNvsAreaProtocol.Area->EnableTimedGpio0 = (UINT8)mPchConfigHob->Pm.EnableTimedGpio0;
+  mPchNvsAreaProtocol.Area->EnableTimedGpio1 = (UINT8)mPchConfigHob->Pm.EnableTimedGpio1;
+}
+#endif
+
+/**
+  Update NVS Area after RST PCIe Storage Remapping and before Boot
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_NOT_FOUND           Couldn't fetch RstHob
+**/
+EFI_STATUS
+PchUpdateNvsAreaAfterRemapping (
+  VOID
+  )
+{
+  UINTN                 Index;
+  VOID                  *Hob;
+  PCH_RST_HOB           *RstHob;
+
+  Hob = GetFirstGuidHob (&gPchRstHobGuid);
+  if (Hob == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  RstHob = (PCH_RST_HOB *) GET_GUID_HOB_DATA (Hob);
+
+  for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {
+    mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index]        = RstHob->RstCrConfiguration[Index].DeviceInterface;
+    mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index]             = RstHob->SavedRemapedDeviceConfigSpace[Index].PmCapPtr;
+    mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index]           = RstHob->SavedRemapedDeviceConfigSpace[Index].PcieCapPtr;
+    mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index]           = RstHob->SavedRemapedDeviceConfigSpace[Index].L1ssCapPtr;
+    mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index]       = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl2;
+    mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index]       = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl1;
+    mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index]            = RstHob->SavedRemapedDeviceConfigSpace[Index].LtrCapPtr;
+    mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index]            = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLtrData;
+    mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index]         = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLctlData16;
+    mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index]         = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctlData16;
+    mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index]        = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctl2Data16;
+    mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index]        = RstHob->SavedRemapedDeviceConfigSpace[Index].RootPortDctl2Data16;
+    mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index]       = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBar;
+    mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBarValue[Index]  = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBarValue;
+    mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index]         = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBar;
+    mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index]    = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBarValue;
+    mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index]          = RstHob->RstCrConfiguration[Index].RootPortNum;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Update the Hybrid storage location NVS Area if Hybrid Storage device is present
+**/
+EFI_STATUS
+UpdateHybridStorageLocation (
+  VOID
+  )
+{
+  VOID                               *Hob;
+  PCH_HYBRIDSTORAGE_HOB              *HybridStorageHob;
+
+  Hob = GetFirstGuidHob (&gHybridStorageHobGuid);
+  if (Hob == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  HybridStorageHob = (PCH_HYBRIDSTORAGE_HOB *) GET_GUID_HOB_DATA (Hob);
+  mPchNvsAreaProtocol.Area->HybridStorageLocation = HybridStorageHob->HybridStorageLocation;
+  return EFI_SUCCESS;
+}
+
+/**
+  PCH ACPI initialization before Boot Sript Table is closed
+  It update ACPI table and ACPI NVS area.
+
+  @param[in] Event                A pointer to the Event that triggered the callback.
+  @param[in] Context              A pointer to private data registered with the callback function.
+**/
+VOID
+EFIAPI
+PchAcpiOnEndOfDxe (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n"));
+
+  ///
+  /// Closed the event to avoid call twice when launch shell
+  ///
+  gBS->CloseEvent (Event);
+
+  //
+  // Init HDA Audio ACPI tables
+  //
+  PchHdAudioAcpiInit ();
+  //
+  // Update ASL definitions for SerialIo devices.
+  //
+  UpdateSerialIoAcpiData ();
+  UpdateCnviAcpiData ();
+#if FixedPcdGet8(PcdEmbeddedEnable) == 0x1
+  UpdateTimedGpioSetup();
+#endif
+
+  //
+  // Update Pch Nvs Area
+  //
+  PchUpdateNvsArea ();
+
+  DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() End\n"));
+
+  return;
+}
+
+/**
+  Initialize Pch acpi
+  @param[in] ImageHandle          Handle for the image of this driver
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_OUT_OF_RESOURCES    Do not have enough resources to initialize the driver
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiInit (
+  IN EFI_HANDLE         ImageHandle
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   EndOfDxeEvent;
+
+  DEBUG ((DEBUG_INFO, "Install PCH NVS protocol\n"));
+
+  Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (PCH_NVS_AREA), (VOID **) &mPchNvsAreaProtocol.Area);
+  ASSERT_EFI_ERROR (Status);
+
+  ZeroMem ((VOID *) mPchNvsAreaProtocol.Area, sizeof (PCH_NVS_AREA));
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gPchNvsAreaProtocolGuid,
+                  &mPchNvsAreaProtocol,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Update the NVS Area after RST PCIe Storage Remapping
+  ///
+  PchUpdateNvsAreaAfterRemapping ();
+
+  UpdateHybridStorageLocation ();
+  //
+  // Register an end of DXE event for PCH ACPI to do tasks before invoking any UEFI drivers,
+  // applications, or connecting consoles,...
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  PchAcpiOnEndOfDxe,
+                  NULL,
+                  &gEfiEndOfDxeEventGroupGuid,
+                  &EndOfDxeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+
+/**
+  Update NVS area for PCIe root ports.
+**/
+STATIC
+VOID
+PcieRpUpdateNvsArea (
+  VOID
+  )
+{
+  UINT32  Index;
+
+  for (Index = 0; Index < PCH_MAX_PCIE_CLOCKS; Index++) {
+    mPchNvsAreaProtocol.Area->ClockToRootPortMap[Index] = mPchConfigHob->PcieRp.PcieClock[Index].Usage;
+  }
+}
+
+/**
+  Update ASL object before Boot
+
+  @retval EFI_STATUS
+  @retval EFI_NOT_READY         The Acpi protocols are not ready.
+**/
+EFI_STATUS
+PchUpdateNvsArea (
+  VOID
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 Index;
+  UINT32                HpetBaseAdress;
+  GPIO_GROUP            GroupToGpeDwX[3];
+  UINT32                GroupDw[3];
+  UINTN                 RpDev;
+  UINTN                 RpFun;
+  UINT32                Data32;
+  PCH_POLICY_PROTOCOL   *PchPolicy;
+  GPIO_DXE_CONFIG       *GpioDxeConfig;
+  UINT64                XdciPciBase;
+  UINT64                XdciBar;
+  UINT16                PciMemConfig;
+  UINT16                TcoBase;
+  UINT8                 ClearXdciBar = FALSE;
+
+  ///
+  /// Get PCH Policy Protocol
+  ///
+  Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)&PchPolicy);
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Get GPIO DXE Config Block
+  ///
+  Status = GetConfigBlock ((VOID *)PchPolicy, &gGpioDxeConfigGuid, (VOID *)&GpioDxeConfig);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Update ASL PCIE port address according to root port device and function
+  //
+  for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
+    RpDev = PchPcieRpDevNumber (Index);
+    RpFun = PchPcieRpFuncNumber (Index);
+    Data32 = ((UINT8) RpDev << 16) | (UINT8) RpFun;
+    mPchNvsAreaProtocol.Area->RpAddress[Index] = Data32;
+
+    //
+    // Update Maximum Snoop Latency and Maximum No-Snoop Latency values for PCIE
+    //
+    mPchNvsAreaProtocol.Area->PcieLtrMaxSnoopLatency[Index]   = mPchConfigHob->PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxSnoopLatency;
+    mPchNvsAreaProtocol.Area->PcieLtrMaxNoSnoopLatency[Index] = mPchConfigHob->PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxNoSnoopLatency;
+  }
+
+  //
+  // Update PCHS.
+  //
+  mPchNvsAreaProtocol.Area->PchSeries     = PchSeries ();
+  //
+  // Update PCHG.
+  //
+  mPchNvsAreaProtocol.Area->PchGeneration = (UINT16) PchGeneration ();
+  //
+  // Update PSTP.
+  //
+  mPchNvsAreaProtocol.Area->PchStepping = (UINT16) PchStepping ();
+  //
+  // Update HPET base address.
+  //
+  PchHpetBaseGet (&HpetBaseAdress);
+  mPchNvsAreaProtocol.Area->HPTE          = TRUE;  // @todo remove the NVS, since it's always enabled.
+  mPchNvsAreaProtocol.Area->HPTB          = HpetBaseAdress;
+  //
+  // Update SBREG_BAR.
+  //
+  mPchNvsAreaProtocol.Area->SBRG          = PCH_PCR_BASE_ADDRESS;
+
+  //
+  // Update base address
+  //
+  mPchNvsAreaProtocol.Area->PMBS = PmcGetAcpiBase ();
+  mPchNvsAreaProtocol.Area->PWRM = PmcGetPwrmBase ();
+  PchTcoBaseGet (&TcoBase);
+  mPchNvsAreaProtocol.Area->TcoBase = TcoBase;
+
+  //
+  // Update PCH PID info
+  //
+  mPchNvsAreaProtocol.Area->IclkPid = PchPcrGetPid (PchIpIclk);
+
+  //
+  // Update GPIO device ACPI variables
+  //
+  mPchNvsAreaProtocol.Area->SGIR = mPchConfigHob->Interrupt.GpioIrqRoute;
+  mPchNvsAreaProtocol.Area->GPHD = (UINT8)GpioDxeConfig->HideGpioAcpiDevice;
+
+  //
+  // Update GPP_X to GPE_DWX mapping.
+  //
+  GpioGetGroupDwToGpeDwX (
+    &GroupToGpeDwX[0], &GroupDw[0],
+    &GroupToGpeDwX[1], &GroupDw[1],
+    &GroupToGpeDwX[2], &GroupDw[2]
+    );
+
+  //
+  // GEI0/1/2 and GED0/1/2 are objects for informing how GPIO groups are mapped to GPE0.
+  // If Group is mapped to 1-Tier GPE information is also stored on what Group DW
+  // is mapped to GPE_DWx. Because GPE_DWx register is 32 bits large if groups have more than
+  // 32 pads only part of it can be mapped.
+  //
+  //  GEIx - GroupIndex mapped to GPE0_DWx
+  //  GEDx - DoubleWorld part of Group: 0 - pins 31-0, 1 - pins 63-32, ...
+  //
+  mPchNvsAreaProtocol.Area->GEI0 = (UINT8) GpioGetGroupIndexFromGroup (GroupToGpeDwX[0]);
+  mPchNvsAreaProtocol.Area->GEI1 = (UINT8) GpioGetGroupIndexFromGroup (GroupToGpeDwX[1]);
+  mPchNvsAreaProtocol.Area->GEI2 = (UINT8) GpioGetGroupIndexFromGroup (GroupToGpeDwX[2]);
+  mPchNvsAreaProtocol.Area->GED0 = (UINT8) GroupDw[0];
+  mPchNvsAreaProtocol.Area->GED1 = (UINT8) GroupDw[1];
+  mPchNvsAreaProtocol.Area->GED2 = (UINT8) GroupDw[2];
+
+  //
+  // SCS Configuration
+  //
+
+  PcieRpUpdateNvsArea ();
+
+  //
+  // SATA configuration.
+  //
+  mPchNvsAreaProtocol.Area->SataPortPresence = GetSataPortPresentStatus (0);
+  DEBUG ((DEBUG_INFO, "SataPortPresence: 0x%x\n", mPchNvsAreaProtocol.Area->SataPortPresence));
+
+  //
+  // CPU SKU
+  //
+  mPchNvsAreaProtocol.Area->CpuSku = 0;
+  mPchNvsAreaProtocol.Area->PsOnEnable            = (UINT8)mPchConfigHob->Pm.PsOnEnable;
+
+  for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
+    mPchNvsAreaProtocol.Area->LtrEnable[Index]  = (UINT8)mPchConfigHob->PcieRp.RootPort[Index].PcieRpCommonConfig.LtrEnable;
+  }
+
+  mPchNvsAreaProtocol.Area->GBES = IsGbePresent ();
+
+  //
+  // Update PCH Trace Hub Mode
+  //
+  mPchNvsAreaProtocol.Area->PchTraceHubMode     = (UINT8) mPchConfigHob->PchTraceHub.PchTraceHubMode;
+
+  //
+  // Saving GCTL value into PCH NVS area
+  //
+
+  XdciPciBase = PchXdciPciCfgBase ();
+
+  //
+  // Determine Base address for Base address register (Offset 0x10)
+  //
+  if (PciSegmentRead32 (XdciPciBase) != 0xFFFFFFFF) {
+
+    XdciBar = PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFFFF0;
+
+    if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & B_PCI_BAR_MEMORY_TYPE_MASK) == B_PCI_BAR_MEMORY_TYPE_64) {
+      XdciBar += (UINT64)PciSegmentRead32 (XdciPciBase + (PCI_BASE_ADDRESSREG_OFFSET + 4)) << 32;
+    }
+
+    if (XdciBar == 0x0) {
+      ClearXdciBar = TRUE;
+      PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET), PcdGet32 (PcdSiliconInitTempMemBaseAddr));
+      XdciBar = PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFFFF0;
+
+      if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & B_PCI_BAR_MEMORY_TYPE_MASK) == B_PCI_BAR_MEMORY_TYPE_64) {
+        XdciBar += (UINT64)PciSegmentRead32 (XdciPciBase + (PCI_BASE_ADDRESSREG_OFFSET + 4)) << 32;
+      }
+    }
+
+    //
+    // Enable Pci Memconfig to read the correct value for GCTL register
+    //
+    PciMemConfig = PciSegmentRead16 (XdciPciBase + PCI_COMMAND_OFFSET);
+    PciSegmentWrite16 (XdciPciBase + PCI_COMMAND_OFFSET, PciMemConfig | (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+
+    mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale = MmioRead32(XdciBar + R_XDCI_MEM_GCTL);
+    DEBUG ((DEBUG_INFO, "PchxDCIPwrDnScale  0x%x\n", (UINT64)mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale));
+    //
+    // Disable Pci Memconfig & clear Base address
+    //
+    PciSegmentWrite16(XdciPciBase + PCI_COMMAND_OFFSET, PciMemConfig);
+
+    if (ClearXdciBar == TRUE) {
+      PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET), 0x0);
+      PciSegmentWrite32 ((XdciPciBase + (PCI_BASE_ADDRESSREG_OFFSET + 4)), 0x0);
+    }
+  }
+
+  return Status;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c
new file mode 100644
index 0000000000..5c8e1ce5b4
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c
@@ -0,0 +1,41 @@
+/** @file
+  Initializes PCH CNVi device ACPI data.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <CnviConfigHob.h>
+#include "PchInit.h"
+#include <Register/PchPcrRegs.h>
+
+/**
+  Update ASL definitions for CNVi device.
+
+  @retval EFI_SUCCESS         The function completed successfully
+**/
+EFI_STATUS
+UpdateCnviAcpiData (
+  VOID
+  )
+{
+  EFI_PEI_HOB_POINTERS HobPtr;
+  CNVI_CONFIG_HOB      *CnviConfigHob;
+
+  DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() Start\n"));
+
+  // Get CNVi Config HOB.
+  HobPtr.Guid = GetFirstGuidHob (&gCnviConfigHobGuid);
+  if (HobPtr.Guid != NULL) {
+    CnviConfigHob = (CNVI_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);
+    mPchNvsAreaProtocol.Area->CnviMode           = (UINT8)CnviConfigHob->Mode;
+    mPchNvsAreaProtocol.Area->CnviBtCore         = (UINT8)CnviConfigHob->BtCore;
+    mPchNvsAreaProtocol.Area->CnviBtAudioOffload = (UINT8)CnviConfigHob->BtAudioOffload;
+  }
+  mPchNvsAreaProtocol.Area->CnviPortId = PID_CNVI;
+  DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() End\n"));
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
new file mode 100644
index 0000000000..dbdb028483
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
@@ -0,0 +1,201 @@
+
+/** @file
+  Initializes the PCH HD Audio ACPI Tables.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/AcpiTable.h>
+#include <DxeHdaNhlt.h>
+#include <Library/DxeHdaNhltLib.h>
+#include "PchInit.h"
+#include <HdAudioConfig.h>
+#include <PchConfigHob.h>
+#include <Library/PcdLib.h>
+#include <Protocol/PchPolicy.h>
+#include <HdAudioConfig.h>
+#include <IndustryStandard/Pci30.h>
+#include <Register/PchRegs.h>
+#include <Library/PchPciBdfLib.h>
+#include <Library/PchInfoLib.h>
+
+#define XTAL_FREQ_38P4MHZ    1
+
+/**
+  Retrieves address of NHLT table from XSDT/RSDT.
+
+  @retval NHLT_ACPI_TABLE*  Pointer to NHLT table if found
+  @retval NULL              NHLT could not be found
+**/
+NHLT_ACPI_TABLE *
+LocateNhltAcpiTable (
+  VOID
+  )
+{
+  EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;
+  EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;
+  NHLT_ACPI_TABLE                               *Nhlt;
+  UINTN                                         Index;
+  UINT64                                        Data64;
+  EFI_STATUS                                    Status;
+  Rsdp  = NULL;
+  Xsdt  = NULL;
+  Nhlt  = NULL;
+
+  ///
+  /// Find the AcpiSupport protocol returns RSDP (or RSD PTR) address.
+  ///
+  DEBUG ((DEBUG_INFO, "LocateNhltAcpiTable() Start\n"));
+
+  Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID *) &Rsdp);
+  if (EFI_ERROR (Status) || (Rsdp == NULL)) {
+    DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp == NULL\n"));
+    return NULL;
+  }
+
+  Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
+  if (Xsdt == NULL || Xsdt->Signature != EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
+    // If XSDT has not been found, check RSDT
+    Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
+    if (Xsdt == NULL || Xsdt->Signature != EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
+      DEBUG ((DEBUG_ERROR, "XSDT/RSDT == NULL or wrong signature\n"));
+      return NULL;
+    }
+  }
+
+  for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Xsdt->Length; Index = Index + sizeof (UINT64)) {
+    Data64  = *(UINT64 *) ((UINT8 *) Xsdt + Index);
+    Nhlt    = (NHLT_ACPI_TABLE *) (UINTN) Data64;
+    if (Nhlt != NULL && Nhlt->Header.Signature == NHLT_ACPI_TABLE_SIGNATURE) {
+      break;
+    }
+    Nhlt = NULL;
+  }
+
+  if (Nhlt == NULL || Nhlt->Header.Signature != NHLT_ACPI_TABLE_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "Nhlt == NULL or wrong signature\n"));
+    return NULL;
+  }
+
+  DEBUG ((DEBUG_INFO, "Found NhltTable, Address = 0x%016x\n", Nhlt));
+
+  return Nhlt;
+}
+
+/**
+  Sets NVS ACPI variables for HDAS._DSM and SNDW._DSD accordingly to policy.
+
+  @param[in]                NhltAcpiTableAddress
+  @param[in]                NhltAcpiTableLength
+  @param[in]                *HdAudioConfigHob
+  @param[in]                *HdAudioDxeConfig
+**/
+VOID
+UpdateHdaAcpiData (
+  IN       UINT64                 NhltAcpiTableAddress,
+  IN       UINT32                 NhltAcpiTableLength,
+  IN CONST HDAUDIO_HOB            *HdAudioConfigHob,
+  IN CONST HDAUDIO_DXE_CONFIG     *HdAudioDxeConfig
+  )
+{
+  DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address = 0x%016x, Length = 0x%08x\n", NhltAcpiTableAddress, NhltAcpiTableLength));
+  DEBUG ((DEBUG_INFO, " FeatureMask = 0x%08x\n", HdAudioDxeConfig->DspFeatureMask));
+
+  mPchNvsAreaProtocol.Area->XTAL = XTAL_FREQ_38P4MHZ;
+  mPchNvsAreaProtocol.Area->NHLA = NhltAcpiTableAddress;
+  mPchNvsAreaProtocol.Area->NHLL = NhltAcpiTableLength;
+  mPchNvsAreaProtocol.Area->ADFM = HdAudioDxeConfig->DspFeatureMask;
+
+  if (HdAudioConfigHob->DspEnable || HdAudioConfigHob->DspUaaCompliance == FALSE) {
+    mPchNvsAreaProtocol.Area->SWQ0 = HdAudioConfigHob->AudioLinkSndw1 ? 0 : BIT1;
+    mPchNvsAreaProtocol.Area->SWQ1 = HdAudioConfigHob->AudioLinkSndw2 ? 0 : BIT1;
+    mPchNvsAreaProtocol.Area->SWQ2 = HdAudioConfigHob->AudioLinkSndw3 ? 0 : BIT1;
+    mPchNvsAreaProtocol.Area->SWQ3 = HdAudioConfigHob->AudioLinkSndw4 ? 0 : BIT1;
+  } else {
+    mPchNvsAreaProtocol.Area->SWQ0 = BIT1;
+    mPchNvsAreaProtocol.Area->SWQ1 = BIT1;
+    mPchNvsAreaProtocol.Area->SWQ2 = BIT1;
+    mPchNvsAreaProtocol.Area->SWQ3 = BIT1;
+  }
+
+  mPchNvsAreaProtocol.Area->SWMC = GetPchHdaMaxSndwLinkNum ();
+
+  mPchNvsAreaProtocol.Area->ACS0 = (UINT8)HdAudioDxeConfig->SndwConfig[0].AutonomousClockStop;
+  mPchNvsAreaProtocol.Area->ACS1 = (UINT8)HdAudioDxeConfig->SndwConfig[1].AutonomousClockStop;
+  mPchNvsAreaProtocol.Area->ACS2 = (UINT8)HdAudioDxeConfig->SndwConfig[2].AutonomousClockStop;
+  mPchNvsAreaProtocol.Area->ACS3 = (UINT8)HdAudioDxeConfig->SndwConfig[3].AutonomousClockStop;
+
+  mPchNvsAreaProtocol.Area->DAI0 = (UINT8)HdAudioDxeConfig->SndwConfig[0].DataOnActiveIntervalSelect;
+  mPchNvsAreaProtocol.Area->DAI1 = (UINT8)HdAudioDxeConfig->SndwConfig[1].DataOnActiveIntervalSelect;
+  mPchNvsAreaProtocol.Area->DAI2 = (UINT8)HdAudioDxeConfig->SndwConfig[2].DataOnActiveIntervalSelect;
+  mPchNvsAreaProtocol.Area->DAI3 = (UINT8)HdAudioDxeConfig->SndwConfig[3].DataOnActiveIntervalSelect;
+
+  mPchNvsAreaProtocol.Area->DOD0 = (UINT8)HdAudioDxeConfig->SndwConfig[0].DataOnDelaySelect;
+  mPchNvsAreaProtocol.Area->DOD1 = (UINT8)HdAudioDxeConfig->SndwConfig[1].DataOnDelaySelect;
+  mPchNvsAreaProtocol.Area->DOD2 = (UINT8)HdAudioDxeConfig->SndwConfig[2].DataOnDelaySelect;
+  mPchNvsAreaProtocol.Area->DOD3 = (UINT8)HdAudioDxeConfig->SndwConfig[3].DataOnDelaySelect;
+}
+
+/**
+  Initialize Intel High Definition Audio ACPI Tables
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_LOAD_ERROR          ACPI table cannot be installed
+  @retval EFI_UNSUPPORTED         ACPI table not set because DSP is disabled
+**/
+EFI_STATUS
+PchHdAudioAcpiInit (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  UINT64                        HdaPciBase;
+  CONST HDAUDIO_HOB             *HdAudioConfigHob;
+  PCH_POLICY_PROTOCOL           *PchPolicy;
+  HDAUDIO_DXE_CONFIG            *HdAudioDxeConfig;
+  NHLT_ACPI_TABLE               *NhltTable;
+
+
+  DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n"));
+
+  HdAudioConfigHob = &mPchConfigHob->HdAudio;
+
+  ///
+  /// Get PCH Policy Protocol
+  ///
+  Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)&PchPolicy);
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Get HD Audio DXE Config Block
+  ///
+  Status = GetConfigBlock ((VOID *)PchPolicy, &gHdAudioDxeConfigGuid, (VOID *)&HdAudioDxeConfig);
+  ASSERT_EFI_ERROR (Status);
+
+  HdaPciBase = HdaPciCfgBase ();
+
+  if ((PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) || (HdAudioConfigHob->DspEnable == FALSE)) {
+    // Do not set ACPI tables if HDAudio is Function disabled or DSP is disabled
+    DEBUG ((DEBUG_INFO, "AudioDSP: Non-HDAudio ACPI Table (NHLT) not set!\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  NhltTable = LocateNhltAcpiTable ();
+  if (NhltTable == NULL) {
+    return EFI_LOAD_ERROR;
+  }
+
+  UpdateHdaAcpiData ((UINT64) (UINTN) NhltTable, (UINT32) (NhltTable->Header.Length), HdAudioConfigHob, HdAudioDxeConfig);
+  DEBUG_CODE ( NhltAcpiTableDump (NhltTable); );
+
+  DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status = %r\n", Status));
+  return Status;
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
new file mode 100644
index 0000000000..734d4e295a
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
@@ -0,0 +1,314 @@
+/** @file
+  This is the Common driver that initializes the Intel PCH.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/TimerLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/HobLib.h>
+
+#include "PchInit.h"
+#include <PchPolicyCommon.h>
+#include <Library/SpiCommonLib.h>
+#include <Library/PmcPrivateLib.h>
+#include <Library/PchDmiLib.h>
+#include <Library/SiScheduleResetLib.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PchPcrLib.h>
+#include <IndustryStandard/Pci30.h>
+#include <Library/SpiAccessPrivateLib.h>
+#include <Register/PchRegs.h>
+#include <Register/PchPcrRegs.h>
+#include <Register/PchRegsLpc.h>
+#include <Register/SpiRegs.h>
+#include <Register/PchRegsPsth.h>
+#include <Register/PmcRegs.h>
+#include <Register/HdaRegs.h>
+#include <Library/GpioCheckConflictLib.h>
+#include <Library/PchPciBdfLib.h>
+#include <Library/PchInfoLib.h>
+
+//
+// Module variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB           *mPchConfigHob;
+
+//
+// EFI_EVENT
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT mHeciEvent;
+
+/**
+  Common PchInit Module Entry Point
+**/
+VOID
+PchInitEntryPointCommon (
+  VOID
+  )
+{
+  EFI_PEI_HOB_POINTERS  HobPtr;
+
+  DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n"));
+
+  //
+  // Get PCH Config HOB.
+  //
+  HobPtr.Guid   = GetFirstGuidHob (&gPchConfigHobGuid);
+  ASSERT (HobPtr.Guid != NULL);
+  mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);
+
+  DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n"));
+
+  return;
+}
+
+/**
+  Lock SPI register before boot
+**/
+VOID
+LockSpiConfiguration (
+  VOID
+  )
+{
+  UINTN         Index;
+  UINT16        Data16;
+  UINT16        Data16And;
+  UINT16        Data16Or;
+  UINT32        Data32;
+  UINT32        DlockValue;
+  UINT64        PciSpiRegBase;
+  UINT32        PchSpiBar0;
+  UINT32        Timer;
+
+  PciSpiRegBase = SpiPciCfgBase ();
+
+  //
+  // Check for SPI controller presence before programming
+  //
+  if (PciSegmentRead16 (PciSpiRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return;
+  }
+
+  //
+  // Make sure SPI BAR0 has fixed address before writing to boot script.
+  // The same base address is set in PEI and will be used during resume.
+  //
+  PchSpiBar0 = PCH_SPI_BASE_ADDRESS;
+
+  PciSegmentAnd8    (PciSpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+  PciSegmentWrite32 (PciSpiRegBase + R_SPI_CFG_BAR0, PchSpiBar0);
+  PciSegmentOr8     (PciSpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+  //
+  // Locking for security reasons only if Extended BIOS Range Decode is supported
+  //
+  if (IsExtendedBiosRangeDecodeSupported ()) {
+    //
+    // Before setting FLOCKDN lock Extended BIOS Range configuration
+    // All configuration of this feature shall be done already at this moment
+    //
+    PciSegmentOr32 (PciSpiRegBase + R_SPI_CFG_BC, BIT28);
+    S3BootScriptSavePciCfgWrite (
+      S3BootScriptWidthUint32,
+      (UINTN) PciSpiRegBase + R_SPI_CFG_BC,
+      1,
+      (VOID *) (UINTN) (PciSpiRegBase + R_SPI_CFG_BC)
+      );
+  }
+
+  //
+  // Program the Flash Protection Range Register based on policy
+  //
+  DlockValue = MmioRead32 (PchSpiBar0 + R_SPI_MEM_DLOCK);
+  for (Index = 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) {
+    if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable ||
+         mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) != TRUE) {
+      continue;
+    }
+
+    //
+    // Proceed to program the register after ensure it is enabled
+    //
+    Data32 = 0;
+    Data32 |= (mPchConfigHob->ProtectRange[Index].WriteProtectionEnable == TRUE) ? B_SPI_MEM_PRX_WPE : 0;
+    Data32 |= (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable == TRUE) ? B_SPI_MEM_PRX_RPE : 0;
+    Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeLimit << N_SPI_MEM_PRX_PRL) & B_SPI_MEM_PRX_PRL_MASK;
+    Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeBase << N_SPI_MEM_PRX_PRB) & B_SPI_MEM_PRX_PRB_MASK;
+    DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, Data32));
+
+    DlockValue |= (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index);
+    MmioWrite32 ((UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))), Data32);
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint32,
+      (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))),
+      1,
+      (VOID *) (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX)))
+      );
+  }
+  //
+  // Program DLOCK register
+  //
+  MmioWrite32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), DlockValue);
+  S3BootScriptSaveMemWrite (
+    S3BootScriptWidthUint32,
+    (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK),
+    1,
+    (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK)
+    );
+
+  ///
+  /// PCH BIOS Spec Section 3.6 Flash Security Recommendation
+  /// In PCH SPI controller the BIOS should set the Flash Configuration Lock-Down bit
+  /// (SPI_BAR0 + 04[15]) at end of post.  When set to 1, those Flash Program Registers
+  /// that are locked down by this FLOCKDN bit cannot be written.
+  /// Please refer to the EDS for which program registers are impacted.
+  /// Additionally BIOS must program SPI_BAR0 + 0x04 BIT11 (WRSDIS) to disable Write Status in HW sequencing
+  ///
+
+  //
+  // Ensure there is no pending SPI trasaction before setting lock bits
+  //
+  Timer = 0;
+  while (MmioRead16 (PchSpiBar0 + R_SPI_MEM_HSFSC) & B_SPI_MEM_HSFSC_SCIP) {
+    if (Timer > SPI_WAIT_TIME) {
+      //
+      // SPI transaction is pending too long at this point, exit with error.
+      //
+      DEBUG ((DEBUG_ERROR, "SPI Cycle timeout\n"));
+      ASSERT (FALSE);
+      break;
+    }
+    MicroSecondDelay (SPI_WAIT_PERIOD);
+    Timer += SPI_WAIT_PERIOD;
+  }
+
+  Data16And = B_SPI_MEM_HSFSC_SCIP;
+  Data16    = 0;
+  S3BootScriptSaveMemPoll (
+    S3BootScriptWidthUint16,
+    PchSpiBar0 + R_SPI_MEM_HSFSC,
+    &Data16And,
+    &Data16,
+    SPI_WAIT_PERIOD,
+    SPI_WAIT_TIME / SPI_WAIT_PERIOD
+    );
+
+  //
+  // Clear any outstanding status
+  //
+  Data16Or  = B_SPI_MEM_HSFSC_SAF_DLE
+            | B_SPI_MEM_HSFSC_SAF_ERROR
+            | B_SPI_MEM_HSFSC_AEL
+            | B_SPI_MEM_HSFSC_FCERR
+            | B_SPI_MEM_HSFSC_FDONE;
+  Data16And = 0xFFFF;
+  MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);
+  S3BootScriptSaveMemReadWrite (
+    S3BootScriptWidthUint16,
+    PchSpiBar0 + R_SPI_MEM_HSFSC,
+    &Data16Or,
+    &Data16And
+    );
+
+  //
+  // Set WRSDIS
+  //
+  Data16Or  = B_SPI_MEM_HSFSC_WRSDIS;
+  Data16And = 0xFFFF;
+  MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);
+  S3BootScriptSaveMemReadWrite (
+    S3BootScriptWidthUint16,
+    PchSpiBar0 + R_SPI_MEM_HSFSC,
+    &Data16Or,
+    &Data16And
+    );
+
+  //
+  // Set FLOCKDN
+  //
+  Data16Or  = B_SPI_MEM_HSFSC_FLOCKDN;
+  Data16And = 0xFFFF;
+  MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);
+  S3BootScriptSaveMemReadWrite (
+    S3BootScriptWidthUint16,
+    PchSpiBar0 + R_SPI_MEM_HSFSC,
+    &Data16Or,
+    &Data16And
+    );
+
+  ///
+  /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock
+  /// It is strongly recommended that BIOS sets the Vendor Component Lock (VCL) bits. VCL applies
+  /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without the VCL bits set, it is
+  /// possible to make Host/GbE VSCC register(s) changes in that can cause undesired host and
+  /// integrated GbE Serial Flash functionality.
+  ///
+  MmioOr32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), B_SPI_MEM_SFDP0_VSCC0_VCL);
+  S3BootScriptSaveMemWrite (
+    S3BootScriptWidthUint32,
+    (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0),
+    1,
+    (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0)
+    );
+}
+
+/**
+  Set HD Audio PME bit
+**/
+VOID
+ConfigureHdAudioPme (
+  VOID
+  )
+{
+  UINT64 HdaPciBase;
+
+  HdaPciBase = HdaPciCfgBase ();
+
+  if (PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return;
+  }
+
+  ///
+  /// PME Enable for Audio controller
+  ///
+  if (mPchConfigHob->HdAudio.Pme == TRUE) {
+    PciSegmentOr32 (HdaPciBase + R_HDA_CFG_PCS, (UINT32) B_HDA_CFG_PCS_PMEE);
+  }
+}
+
+/**
+  Set eSPI BME bit
+**/
+VOID
+ConfigureEspiBme (
+  VOID
+  )
+{
+  UINT64 EspiPciBase;
+
+  EspiPciBase = EspiPciCfgBase ();
+
+  if (PciSegmentRead16 (EspiPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return;
+  }
+  if ((PciSegmentRead32 (EspiPciBase + R_ESPI_CFG_PCBC) & B_ESPI_CFG_PCBC_ESPI_EN) == 0) {
+    return;
+  }
+
+  //
+  // Refer to PCH BWG.
+  // To enable eSPI bus mastering BIOS must enable BME in eSPI controller
+  // and also set BME bit in the respective slave devices through Configuration
+  // and Capabilities register of each slave using Get_Configuration and Set_Configuration functionality.
+  //
+  // NOTE: The setting is also done in PEI, but might be cleared by PCI bus during PCI enumeration.
+  //       Therefore, reeable it after PCI enumeration done.
+  //
+  if (mPchConfigHob->Espi.BmeMasterSlaveEnabled == TRUE) {
+    PciSegmentOr8 (EspiPciBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_BUS_MASTER);
+  }
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
new file mode 100644
index 0000000000..0d6647e3f3
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
@@ -0,0 +1,122 @@
+/** @file
+  Header file for PCH Initialization Driver.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _PCH_INIT_DXE_H_
+#define _PCH_INIT_DXE_H_
+
+#include <SiConfigHob.h>
+#include <PchConfigHob.h>
+#include <Protocol/PchNvsArea.h>
+
+//
+// Data definitions
+//
+extern EFI_HANDLE               mImageHandle;
+
+//
+// Pch NVS area definition
+//
+extern PCH_NVS_AREA_PROTOCOL    mPchNvsAreaProtocol;
+
+extern PCH_CONFIG_HOB           *mPchConfigHob;
+extern SI_CONFIG_HOB_DATA       *mSiConfigHobData;
+
+//
+// Function Prototype
+//
+
+//
+// Local function prototypes
+//
+/**
+  Common PchInit Module Entry Point
+**/
+VOID
+PchInitEntryPointCommon (
+  VOID
+  );
+
+/**
+  Calls Boot Os Hand off routine for each Serial IO Controller
+**/
+VOID
+ConfigureSerialIoAtBoot (
+  VOID
+  );
+
+/**
+  Puts all SerialIo controllers (except UARTs in debug mode) in D3.
+  Clears MemoryEnable for all PCI-mode controllers on S3 resume
+**/
+VOID
+ConfigureSerialIoAtS3Resume (
+  VOID
+  );
+
+/**
+  Add Serial Io UART Hidden Handles
+**/
+VOID
+CreateSerialIoUartHiddenHandle (
+  VOID
+  );
+
+/**
+  Initialize Intel High Definition Audio ACPI Tables
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_LOAD_ERROR          ACPI table cannot be installed
+  @retval EFI_UNSUPPORTED         ACPI table not set because DSP is disabled
+**/
+EFI_STATUS
+PchHdAudioAcpiInit (
+  VOID
+  );
+
+/**
+  Perform the remaining configuration on SATA to perform device detection,
+  then set the SATA SPD and PxE corresponding, and set the Register Lock on PCH SATA
+**/
+VOID
+ConfigureSataOnEndOfDxe (
+  VOID
+  );
+
+/**
+  Update ASL data for CNVI Device.
+
+  @retval EFI_SUCCESS             The function completed successfully
+**/
+EFI_STATUS
+UpdateCnviAcpiData (
+   VOID
+   );
+
+/**
+  Initialize Pch acpi
+  @param[in] ImageHandle          Handle for the image of this driver
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_OUT_OF_RESOURCES    Do not have enough resources to initialize the driver
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiInit (
+  IN EFI_HANDLE         ImageHandle
+  );
+
+/**
+  Update ASL object before Boot
+
+  @retval EFI_STATUS
+  @retval EFI_NOT_READY         The Acpi protocols are not ready.
+**/
+EFI_STATUS
+PchUpdateNvsArea (
+  VOID
+  );
+
+#endif // _PCH_INIT_DXE_H_
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
new file mode 100644
index 0000000000..1d4f08a86c
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
@@ -0,0 +1,354 @@
+/** @file
+  This is the Uefi driver that initializes the Intel PCH.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "PchInit.h"
+#include <PchPolicyCommon.h>
+#include <Protocol/PcieIoTrap.h>
+#include <Library/PchInfoLib.h>
+#include <Library/PmcLib.h>
+#include <Library/PchPcieRpLib.h>
+#include <Library/PmcPrivateLib.h>
+#include <Library/PciExpressHelpersLib.h>
+#include <PcieRegs.h>
+#include <Register/PchPcieRpRegs.h>
+#include <Register/PmcRegs.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE               mImageHandle;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16                   mPcieIoTrapAddress;
+
+VOID
+EFIAPI
+PchOnBootToOs (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  );
+
+
+VOID
+EFIAPI
+PchOnExitBootServices (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  );
+
+
+VOID
+EFIAPI
+PchOnReadyToBoot (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  );
+
+/**
+  Process all the lock downs
+**/
+VOID
+ProcessSmiLocks (
+  VOID
+  )
+{
+  UINT32        Data32And;
+  UINT32        Data32Or;
+  UINT16        ABase;
+
+  ///
+  /// PCH BIOS Spec Section 3.6 Flash Security Recommendation
+  /// BIOS needs to enables SMI_LOCK (PMC PCI offset A0h[4] = 1b) which prevent writes
+  /// to the Global SMI Enable bit (GLB_SMI_EN ABASE + 30h[0]). Enabling this bit will
+  /// mitigate malicious software attempts to gain system management mode privileges.
+  ///
+  if (mPchConfigHob->LockDown.GlobalSmi == TRUE) {
+    ///
+    /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK during S3 resume
+    ///
+    ABase = PmcGetAcpiBase ();
+    Data32Or = IoRead32 ((UINTN) (ABase + R_ACPI_IO_SMI_EN));
+    if ((Data32Or & B_ACPI_IO_SMI_EN_GBL_SMI) != 0) {
+      Data32And = 0xFFFFFFFF;
+      Data32Or |= B_ACPI_IO_SMI_EN_GBL_SMI;
+      S3BootScriptSaveIoReadWrite (
+        S3BootScriptWidthUint32,
+        (UINTN) (ABase + R_ACPI_IO_SMI_EN),
+        &Data32Or,  // Data to be ORed
+        &Data32And  // Data to be ANDed
+        );
+    }
+      PmcLockSmiWithS3BootScript ();
+  }
+}
+
+/**
+  Do PCIE power management while resume from S3
+**/
+VOID
+ReconfigurePciePowerManagementForS3 (
+  VOID
+  )
+{
+  EFI_STATUS                            Status;
+  UINT32                                Data32;
+  PCH_PCIE_IOTRAP_PROTOCOL              *PchPcieIoTrapProtocol;
+
+  Status = gBS->LocateProtocol (&gPchPcieIoTrapProtocolGuid, NULL, (VOID **) &PchPcieIoTrapProtocol);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  mPcieIoTrapAddress = PchPcieIoTrapProtocol->PcieTrapAddress;
+  DEBUG ((DEBUG_INFO, "PcieIoTrapAddress: %0x\n", mPcieIoTrapAddress));
+
+  if (mPcieIoTrapAddress != 0) {
+    //
+    // Save PCH PCIE IoTrap address to re-config PCIE power management setting after resume from S3
+    //
+    Data32 = PchPciePmTrap;
+    S3BootScriptSaveIoWrite (
+      S3BootScriptWidthUint32,
+      (UINTN) (mPcieIoTrapAddress),
+      1,
+      &Data32
+      );
+  } else {
+    ASSERT (FALSE);
+  }
+}
+
+/**
+  This is the callback function for PCI ENUMERATION COMPLETE.
+**/
+VOID
+EFIAPI
+PchOnPciEnumComplete (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  EFI_STATUS          Status;
+  VOID                *ProtocolPointer;
+
+  ///
+  /// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
+  /// if it is, we will skip it until real event is triggered
+  ///
+  Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) &ProtocolPointer);
+  if (EFI_SUCCESS != Status) {
+    return;
+  }
+  gBS->CloseEvent (Event);
+
+  ReconfigurePciePowerManagementForS3 ();
+  ProcessSmiLocks ();
+  ConfigureSerialIoAtS3Resume ();
+}
+
+/**
+  Register callback functions for PCH DXE.
+**/
+VOID
+PchRegisterNotifications (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   ReadyToBoot;
+  EFI_EVENT   LegacyBootEvent;
+  EFI_EVENT   ExitBootServicesEvent;
+  VOID        *Registration;
+
+  ///
+  /// Create PCI Enumeration Completed callback for PCH
+  ///
+  EfiCreateProtocolNotifyEvent (
+    &gEfiPciEnumerationCompleteProtocolGuid,
+    TPL_CALLBACK,
+    PchOnPciEnumComplete,
+    NULL,
+    &Registration
+    );
+
+  //
+  // Register a Ready to boot event to config PCIE power management setting after OPROM executed
+  //
+  Status = EfiCreateEventReadyToBootEx (
+             TPL_CALLBACK,
+             PchOnReadyToBoot,
+             NULL,
+             &ReadyToBoot
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Create events for PCH to do the task before ExitBootServices/LegacyBoot.
+  // It is guaranteed that only one of two events below will be signalled
+  //
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
+                  TPL_CALLBACK,
+                  PchOnExitBootServices,
+                  NULL,
+                  &ExitBootServicesEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = EfiCreateEventLegacyBootEx (
+             TPL_CALLBACK,
+             PchOnBootToOs,
+             NULL,
+             &LegacyBootEvent
+             );
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  <b>PchInit DXE Module Entry Point</b>\n
+  - <b>Introduction</b>\n
+      The PchInit module is a DXE driver that initializes the Intel Platform Controller Hub
+      following the PCH BIOS specification and EDS requirements and recommendations. It consumes
+      the PCH_POLICY_HOB SI_POLICY_HOB for expected configurations per policy.
+      This is the standard EFI driver point that detects whether there is an supported PCH in
+      the system and if so, initializes the chipset.
+
+  - <b>Details</b>\n
+    This module is required for initializing the Intel Platform Controller Hub to
+    follow the PCH BIOS specification and EDS.
+    This includes some initialization sequences, enabling and disabling PCH devices,
+    configuring clock gating, RST PCIe Storage Remapping, SATA controller, ASPM of PCIE devices. Right before end of DXE,
+    it's responsible to lock down registers for security requirement.
+
+  - @pre
+    - PCH PCR base address configured
+    - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+      - This is to ensure that PCI MMIO and IO resource has been prepared and available for this driver to allocate.
+
+  - @result
+    - Publishes the @link _PCH_INFO_PROTOCOL PCH_INFO_PROTOCOL @endlink
+    - Publishes the @link _PCH_EMMC_TUNING_PROTOCOL PCH_EMMC_TUNING_PROTOCOL @endlink
+
+  - <b>References</b>\n
+    - @link _PCH_POLICY PCH_POLICY_HOB @endlink.
+    - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink.
+
+  - <b>Integration Checklists</b>\n
+    - Verify prerequisites are met. Porting Recommendations.
+    - No modification of this module should be necessary
+    - Any modification of this module should follow the PCH BIOS Specification and EDS
+
+  @param[in] ImageHandle          Handle for the image of this driver
+  @param[in] SystemTable          Pointer to the EFI System Table
+
+  @retval EFI_SUCCESS             The function completed successfully
+  @retval EFI_OUT_OF_RESOURCES    Do not have enough resources to initialize the driver
+**/
+EFI_STATUS
+EFIAPI
+PchInitEntryPointDxe (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS            Status;
+
+  DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() Start\n"));
+
+  mImageHandle = ImageHandle;
+
+  PchInitEntryPointCommon ();
+
+  Status = PchAcpiInit (ImageHandle);
+
+  PchRegisterNotifications ();
+
+  CreateSerialIoUartHiddenHandle ();
+
+  DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() End\n"));
+
+  return Status;
+}
+
+/**
+  PCH initialization before ExitBootServices / LegacyBoot events
+  Useful for operations which must happen later than at EndOfPost event
+
+  @param[in] Event                A pointer to the Event that triggered the callback.
+  @param[in] Context              A pointer to private data registered with the callback function.
+**/
+VOID
+EFIAPI
+PchOnBootToOs (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  ///
+  /// Closed the event to avoid call twice
+  ///
+  if (Event != NULL) {
+    gBS->CloseEvent (Event);
+  }
+
+  ConfigureSerialIoAtBoot ();
+
+  return;
+}
+
+/**
+  PCH initialization on ExitBootService. This event is used if only ExitBootService is used
+  and not in legacy boot
+
+  @param[in] Event                A pointer to the Event that triggered the callback.
+  @param[in] Context              A pointer to private data registered with the callback function.
+
+  @retval None
+**/
+VOID
+EFIAPI
+PchOnExitBootServices (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  PchOnBootToOs (NULL, NULL);
+
+  return;
+}
+
+/**
+  PCH initialization before boot to OS
+
+  @param[in] Event                A pointer to the Event that triggered the callback.
+  @param[in] Context              A pointer to private data registered with the callback function.
+**/
+VOID
+EFIAPI
+PchOnReadyToBoot (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() Start\n"));
+
+  if (Event != NULL) {
+    gBS->CloseEvent (Event);
+  }
+
+  //
+  // Trigger an Iotrap SMI to config PCIE power management setting after PCI enumrate is done
+  //
+  if (mPcieIoTrapAddress != 0) {
+    IoWrite32 ((UINTN) mPcieIoTrapAddress, PchPciePmTrap);
+  } else {
+    ASSERT (FALSE);
+  }
+
+  DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() End\n"));
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf
new file mode 100644
index 0000000000..4941ff0f49
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf
@@ -0,0 +1,96 @@
+## @file
+# Component description file for Pch Initialization driver
+#
+#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+INF_VERSION = 0x00010017
+BASE_NAME = PchInitDxeTgl
+FILE_GUID = 4BD0EB2F-3A2D-442E-822D-753516F75424
+VERSION_STRING = 1.0
+MODULE_TYPE = DXE_DRIVER
+ENTRY_POINT = PchInitEntryPointDxe
+
+
+[LibraryClasses]
+S3BootScriptLib
+PchCycleDecodingLib
+PchPcieRpLib
+PchPcrLib
+PchInfoLib
+PciExpressHelpersLib
+UefiBootServicesTableLib
+DebugLib
+IoLib
+TimerLib
+HobLib
+BaseMemoryLib
+MemoryAllocationLib
+UefiLib
+DxeServicesTableLib
+UefiDriverEntryPoint
+UefiRuntimeServicesTableLib
+GpioLib
+SerialIoAccessLib
+ConfigBlockLib
+PmcLib
+PmcPrivateLibWithS3
+SataLib
+PchDmiWithS3Lib
+GbeLib
+SiScheduleResetLib
+DxeHdaNhltLib
+SpiAccessPrivateLib
+PchPciBdfLib
+
+[Packages]
+MdePkg/MdePkg.dec
+TigerlakeSiliconPkg/SiPkg.dec
+
+
+[Pcd]
+gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress
+gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr ## CONSUMES
+gSiPkgTokenSpaceGuid.PcdEmbeddedEnable             ## CONSUMES
+
+[Sources]
+PchInitDxe.c
+PchInit.h
+PchInit.c
+PchSata.c
+PchSerialIo.c
+PchSerialIoDxe.c
+PchHdaAcpi.c
+PchCnviAcpi.c
+PchAcpi.c
+
+
+[Protocols]
+gPchNvsAreaProtocolGuid ## PRODUCES
+gEfiPciIoProtocolGuid ## CONSUMES
+gEfiAcpiTableProtocolGuid ## CONSUMES
+gEfiBlockIoProtocolGuid ## CONSUMES
+gHeciProtocolGuid
+gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES
+gPchPcieIoTrapProtocolGuid ## CONSUMES
+gPchPolicyProtocolGuid ## CONSUMES
+
+
+[Guids]
+gEfiEndOfDxeEventGroupGuid
+gEfiAcpiTableGuid
+gEmmcDxeConfigGuid               ## CONSUMES
+gSiConfigHobGuid                 ## CONSUMES
+gPchConfigHobGuid                ## CONSUMES
+gPchRstHobGuid                   ## CONSUMES
+gHdAudioDxeConfigGuid            ## CONSUMES
+gGpioDxeConfigGuid               ## CONSUMES
+gCnviConfigHobGuid               ## CONSUMES
+gHybridStorageHobGuid            ## CONSUMES
+
+[Depex]
+gEfiPciHostBridgeResourceAllocationProtocolGuid ## This is to ensure that PCI MMIO and IO resource has been prepared and available for this driver to allocate.
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
new file mode 100644
index 0000000000..886f3b4bc0
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
@@ -0,0 +1,89 @@
+/** @file
+  Perform related functions for PCH Sata in DXE phase
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/S3BootScriptLib.h>
+
+#include "PchInit.h"
+#include <Library/SataLib.h>
+#include <Library/PchPciBdfLib.h>
+#include <Register/SataRegs.h>
+
+/**
+  Perform the remaining configuration on SATA to perform device detection,
+  then set the SATA SPD and PxE corresponding, and set the Register Lock on PCH SATA
+
+  @retval None
+**/
+VOID
+ConfigureSataOnEndOfDxe (
+  VOID
+  )
+{
+  UINT64        PciSataRegBase;
+  UINT16        SataPortsEnabled;
+  UINT32        DwordReg;
+  UINTN         Index;
+  UINT32        SataCtrlIndex;
+
+  for (SataCtrlIndex = 0; SataCtrlIndex < MaxSataControllerNum (); SataCtrlIndex++) {
+    ///
+    /// SATA PCS: Enable the port in any of below condition:
+    /// i.)   Hot plug is enabled
+    /// ii.)  A device is attached
+    /// iii.) Test mode is enabled
+    /// iv.)  Configured as eSATA port
+    ///
+    PciSataRegBase    = SataPciCfgBase (SataCtrlIndex);
+    SataPortsEnabled  = 0;
+
+    DwordReg = PciSegmentRead32 (PciSataRegBase + R_SATA_CFG_PCS);
+    for (Index = 0; Index < MaxSataPortNum (SataCtrlIndex); Index++) {
+      if ((mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].HotPlug == TRUE) ||
+          (DwordReg & (B_SATA_CFG_PCS_P0P << Index)) ||
+            (mPchConfigHob->Sata[SataCtrlIndex].TestMode == TRUE) ||
+            (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].External == TRUE)) {
+          SataPortsEnabled |= (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].Enable << Index);
+      }
+    }
+
+    ///
+    /// Set MAP."Sata PortX Disable", SATA PCI offset 90h[23:16] to 1b if SATA Port 0/1/2/3/4/5/6/7 is disabled
+    ///
+    PciSegmentOr32 (PciSataRegBase + R_SATA_CFG_MAP, (~SataPortsEnabled << N_SATA_CFG_MAP_SPD));
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint32,
+      PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_MAP,
+      1,
+      (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_MAP)
+      );
+
+    ///
+    /// Program PCS "Port X Enabled", SATA PCI offset 94h[7:0] = Port 0~7 Enabled bit as per SataPortsEnabled value.
+    ///
+    PciSegmentOr16 (PciSataRegBase + R_SATA_CFG_PCS, SataPortsEnabled);
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint16,
+      PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_PCS,
+      1,
+      (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_PCS)
+      );
+
+    ///
+    /// Step 14
+    /// Program SATA PCI offset 9Ch [31] to 1b
+    ///
+    PciSegmentOr32 ((UINTN) (PciSataRegBase + R_SATA_CFG_SATAGC), BIT31);
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint32,
+      PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_SATAGC,
+      1,
+      (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_SATAGC)
+      );
+  }
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
new file mode 100644
index 0000000000..9409a9a387
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
@@ -0,0 +1,33 @@
+/** @file
+  Initializes Serial IO Controllers.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchInit.h"
+#include <Library/SerialIoPrivateLib.h>
+#include <Library/PchInfoLib.h>
+
+/**
+  Calls Boot Os Hand off routine for each Serial IO Controller
+**/
+VOID
+ConfigureSerialIoAtBoot (
+  VOID
+  )
+{
+  UINT8  Index;
+
+  for (Index = 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++) {
+    SerialIoSpiBootHandler (Index, &mPchConfigHob->SerialIo.SpiDeviceConfig[Index]);
+  }
+
+  for (Index = 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++) {
+    SerialIoI2cBootHandler (Index, &mPchConfigHob->SerialIo.I2cDeviceConfig[Index]);
+  }
+
+  for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++) {
+    SerialIoUartBootHandler (Index, &mPchConfigHob->SerialIo.UartDeviceConfig[Index]);
+  }
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
new file mode 100644
index 0000000000..fde7da6b96
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
@@ -0,0 +1,134 @@
+/** @file
+  Initializes Serial IO Controllers.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/SerialIoPrivateLib.h>
+#include <Library/PchInfoLib.h>
+#include <IndustryStandard/Pci30.h>
+#include <Register/SerialIoRegs.h>
+#include <PchInit.h>
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH          RootPort;
+  ACPI_EXTENDED_HID_DEVICE_PATH AcpiDev;
+  CHAR8                         HidString[8];
+  UINT16                        DeviceId;
+  UINT8                         UartIndex;
+  EFI_DEVICE_PATH_PROTOCOL      End;
+} SERIALIO_UART_DEVICE_PATH;
+
+#define mPciRootBridge {{ACPI_DEVICE_PATH, ACPI_DP, {(UINT8)(sizeof (ACPI_HID_DEVICE_PATH)), 0}}, EISA_PNP_ID (0x0A03), 0}
+#define mAcpiDev {{ACPI_DEVICE_PATH, ACPI_EXTENDED_DP, {(UINT8)(sizeof (ACPI_EXTENDED_HID_DEVICE_PATH) + (sizeof(CHAR8) * 8) + sizeof (UINT16) + sizeof (UINT8)), 0}},0,0,0}
+#define mEndEntire {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
+
+GLOBAL_REMOVE_IF_UNREFERENCED SERIALIO_UART_DEVICE_PATH mSerialIoUartPath = {
+  mPciRootBridge,
+  mAcpiDev,
+  "UART\0\0\0",
+  0xFFFF,
+  0xFF,
+  mEndEntire
+};
+
+/**
+  Add Serial Io UART Hidden Handles
+**/
+VOID
+CreateSerialIoUartHiddenHandle (
+  VOID
+  )
+{
+  EFI_HANDLE               NewHandle;
+  EFI_DEVICE_PATH_PROTOCOL *NewPath;
+  EFI_STATUS               Status;
+  UINT8                    Index;
+  UINT16                   DeviceId;
+
+  DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle\n"));
+
+  for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++) {
+    DEBUG ((DEBUG_INFO, "UART Index: %d Mode: %d\n", Index, mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode));
+    if (mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode == SerialIoUartHidden) {
+      NewHandle = NULL;
+      DeviceId = MmioRead16 (GetSerialIoUartFixedPciCfgAddress (Index) + PCI_DEVICE_ID_OFFSET);
+      DEBUG ((DEBUG_INFO, "Creating Handle for UART DEVICE_ID: 0x%X \n", DeviceId));
+      mSerialIoUartPath.AcpiDev.HID  = 0x5432 + (Index << 16); //UAR
+      mSerialIoUartPath.HidString[4] = (CHAR8)('0' + Index);
+      mSerialIoUartPath.DeviceId     = DeviceId;
+      mSerialIoUartPath.UartIndex    = Index;
+      NewPath = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*) &mSerialIoUartPath);
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &NewHandle,
+                      &gEfiDevicePathProtocolGuid,
+                      NewPath,
+                      NULL
+                      );
+      DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle Status: %r\n", Status));
+    }
+  }
+}
+
+/**
+  Stores Pme Control Status and Command register values in S3 Boot Script
+
+  @param[in] S3PciCfgBase      S3 Boot Script Pci Config Base
+  @param[in] Command           Pci Command register data to save
+  @param[in] Pme               Pci Pme Control register data to save
+
+**/
+VOID
+STATIC
+SerialIoS3Save (
+  IN UINTN   S3PciCfgBase,
+  IN UINTN   Command,
+  IN UINTN   Pme
+  )
+{
+  if (S3PciCfgBase != 0) {
+    S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS, 1, &Pme);
+    S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase + PCI_COMMAND_OFFSET, 1, &Command);
+  }
+}
+
+/**
+  Puts all SerialIo controllers (except UARTs in debug mode) in D3.
+  Clears MemoryEnable for all PCI-mode controllers on S3 resume
+**/
+VOID
+ConfigureSerialIoAtS3Resume (
+  VOID
+  )
+{
+  UINT8     Index;
+  UINTN     S3PciCfgBase;
+  UINT32    Command;
+  UINT32    Pme;
+
+  S3PciCfgBase = 0;
+  for (Index = 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++) {
+    SerialIoSpiS3Handler (Index, &mPchConfigHob->SerialIo.SpiDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme);
+    SerialIoS3Save (S3PciCfgBase, Command, Pme);
+  }
+
+  S3PciCfgBase = 0;
+  for (Index = 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++) {
+    SerialIoI2cS3Handler (Index, &mPchConfigHob->SerialIo.I2cDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme);
+    SerialIoS3Save (S3PciCfgBase, Command, Pme);
+  }
+
+  S3PciCfgBase = 0;
+  for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++) {
+    SerialIoUartS3Handler (Index, &mPchConfigHob->SerialIo.UartDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme);
+    SerialIoS3Save (S3PciCfgBase, Command, Pme);
+  }
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c
new file mode 100644
index 0000000000..786ce13915
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c
@@ -0,0 +1,266 @@
+/** @file
+  Gbe Sx handler implementation.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/TimerLib.h>
+#include "PchInitSmm.h"
+#include <Library/PmcPrivateLib.h>
+#include <Library/GbeMdiLib.h>
+#include <Library/GbeLib.h>
+#include <Register/PchRegs.h>
+#include <Register/GbeRegs.h>
+#include <Library/PchPciBdfLib.h>
+
+
+/**
+  Configure WOL during Sx entry.
+
+  @param [in]  GbeBar   GbE MMIO space
+**/
+VOID
+GbeWolWorkaround (
+  IN      UINT32  GbeBar
+  )
+{
+  UINT32      RAL0;
+  UINT32      RAH0;
+  UINT16      WUC;
+  EFI_STATUS  Status;
+  UINT16      Data16;
+
+  //
+  // 1. Set page to 769 Port Control Registers
+  // 2. Wait 4 mSec
+  //
+  Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 3. Set registry to 17 Port General Configuration
+  // 4. Copy all settings from Port General Configuration
+  //
+  Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 5. Modify BIT 4 and BIT 2 to disable host wake up and set MACPD
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP));
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 6. Read Receive Address Low and Receive Address High from MMIO
+  //
+  RAL0 = MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAL);
+  RAH0 = MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAH);
+
+  //
+  // 7. Set page to 800 Wake Up Registers
+  // 8. Wait 4 mSec
+  //
+  Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_800_WAKE_UP_REGISTERS);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 9. Set registry to 16 Receive Address Low 1/2
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_16_RAL0);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 10. Program first 16 bits [0:15] out of 48 in Receive Address Low 1/2
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 & 0xFFFF));
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 11. Set registry to 17 Receive Address Low 2/2
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_17_RAL1);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 12. Program second 16 bits [16:31] out of 48 in Receive Address Low 2/2
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 >> 16));
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 13. Set registry to 18 Receive Address High 1/2
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_18_RAH0);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 14. Program last 16 bits [32:47] out of 48
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAH0 & B_GBE_MEM_CSR_RAH_RAH));
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 15. Set registry to 19 Receive Address High 2/2
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_19_RAH1);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 16. Set Address Valid
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, B_PHY_MDI_PAGE_800_REGISETER_19_RAH1_ADDRESS_VALID);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 17. Set Wake Up Control Register 1
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_1_WUC);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 18. Copy WakeUp Control from MAC MMIO
+  //
+  WUC = (UINT16) MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC);
+
+  //
+  // 19. Store WakeUp Contorl into LCD
+  // Modify APME bit to enable APM wake up
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (WUC & 0xFFFF));
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 20. Set page to 803 Host Wol Packet
+  // 21. Wait 4 mSec
+  //
+  Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_803_HOST_WOL_PACKET);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 22. Set registry to 66 Host WoL Packet Clear
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_803_REGISETER_66_HWPC);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 23. Clear WOL Packet
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, 0);
+  if (EFI_ERROR (Status)) return;
+  //
+  // 24. Set page to 769 Port Control Registers
+  // 25. Wait 4 mSec
+  //
+  Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 26. Set registry to 17 Port General Configuration
+  //
+  Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_769_REGISETER_17_PGC);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 27. Copy all settings from Port General Configuration
+  //
+  Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);
+  if (EFI_ERROR (Status)) return;
+
+  //
+  // 28. Modify BIT 4 and BIT 2 to enable host wake up and clear MACPD
+  //
+  Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE));
+  if (EFI_ERROR (Status)) return;
+}
+
+/**
+  Additional Internal GbE Controller special cases WOL Support.
+
+  System BIOS is required perform additional steps upon S0 to S3,4,5 transition
+  when ME is off and GbE device in D0. This is needed to enable LAN wake
+  in particular when platform is shut-down from EFI.
+**/
+VOID
+GbeSxWorkaround (
+  VOID
+  )
+{
+  UINT64      LanRegBase;
+  UINT32      GbeBar;
+  EFI_STATUS  Status;
+
+  LanRegBase = GbePciCfgBase ();
+
+  if (PciSegmentRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return;
+  }
+
+  //
+  // Check if GbE device is in D0
+  //
+  if ((PciSegmentRead16 (LanRegBase + R_GBE_CFG_PMCS) & B_GBE_CFG_PMCS_PS) != V_GBE_CFG_PMCS_PS0) {
+    return;
+  }
+
+  ASSERT (mResvMmioSize >= (1 << N_GBE_CFG_MBARA_ALIGN));
+  GbeBar = (UINT32) mResvMmioBaseAddr;
+  if (GbeBar == 0) {
+    ASSERT (FALSE);
+    return;
+  }
+
+  //
+  // Enable MMIO decode using reserved range.
+  //
+  PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+  PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, GbeBar);
+  PciSegmentOr16 (LanRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+  //
+  // If MBARA offset 5800h [0] = 1b then proceed with the w/a
+  //
+  if (MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC) & B_GBE_MEM_CSR_WUC_APME) {
+    Status = GbeMdiAcquireMdio (GbeBar);
+    ASSERT_EFI_ERROR (Status);
+    if (!EFI_ERROR (Status)) {
+      GbeWolWorkaround (GbeBar);
+      GbeMdiReleaseMdio (GbeBar);
+    }
+  }
+
+  //
+  // Disable MMIO decode.
+  //
+  PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+  PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, 0);
+}
+
+/**
+  Enable platform wake from LAN when in DeepSx if platform supports it.
+  Called upon Sx entry.
+**/
+VOID
+GbeConfigureDeepSxWake (
+  VOID
+  )
+{
+  if (PmcIsLanDeepSxWakeEnabled ()) {
+    IoOr32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96), (UINT32) B_ACPI_IO_GPE0_EN_127_96_LAN_WAKE);
+  }
+}
+
+/**
+  GbE Sx entry handler
+**/
+VOID
+PchLanSxCallback (
+  VOID
+  )
+{
+  if (IsGbeEnabled ()) {
+    GbeSxWorkaround ();
+    GbeConfigureDeepSxWake ();
+
+  }
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
new file mode 100644
index 0000000000..f435af434a
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
@@ -0,0 +1,137 @@
+/** @file
+  PCH BIOS Write Protect Driver.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchInitSmm.h"
+#include <Register/PchRegs.h>
+#include <Register/PchRegsLpc.h>
+#include <Register/SpiRegs.h>
+#include <Library/SpiAccessPrivateLib.h>
+#include <Library/PchPciBdfLib.h>
+
+//
+// Global variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_TCO_SMI_DISPATCH_PROTOCOL     *mPchTcoSmiDispatchProtocol;
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_ESPI_SMI_DISPATCH_PROTOCOL    *mEspiSmmDispatchProtocol;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64                            mLpcRegBase;
+
+/**
+  This hardware SMI handler will be run every time the BIOS Write Enable bit is set.
+
+  @param[in] DispatchHandle       Not used
+**/
+VOID
+EFIAPI
+PchSpiBiosWpCallback (
+  IN  EFI_HANDLE                              DispatchHandle
+  )
+{
+  SpiClearBiosWriteProtectDisable ();
+}
+
+/**
+  This hardware SMI handler will be run every time the BIOS Write Enable bit is set.
+
+  @param[in] DispatchHandle       Not used
+
+**/
+VOID
+EFIAPI
+PchLpcBiosWpCallback (
+  IN  EFI_HANDLE                              DispatchHandle
+  )
+{
+  //
+  // Disable BIOSWE bit to protect BIOS
+  //
+  PciSegmentAnd8 ((UINTN) (mLpcRegBase + R_LPC_CFG_BC), (UINT8) ~B_LPC_CFG_BC_WPD);
+}
+
+/**
+  Entry point for Pch Bios Write Protect driver.
+
+  @param[in] ImageHandle          Image handle of this driver.
+  @param[in] SystemTable          Global system service table.
+
+  @retval EFI_SUCCESS             Initialization complete.
+**/
+EFI_STATUS
+EFIAPI
+InstallPchBiosWriteProtect (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+  EFI_HANDLE              Handle;
+
+  DEBUG ((DEBUG_INFO, "InstallPchBiosWriteProtect()\n"));
+
+  if (mPchConfigHob->LockDown.BiosLock != TRUE) {
+    return EFI_SUCCESS;
+  }
+
+  mLpcRegBase = LpcPciCfgBase ();
+
+  DEBUG ((DEBUG_INFO, "Installing BIOS Write Protect SMI handler\n"));
+  //
+  // Get the PCH TCO SMM dispatch protocol
+  //
+  mPchTcoSmiDispatchProtocol = NULL;
+  Status = gSmst->SmmLocateProtocol (&gPchTcoSmiDispatchProtocolGuid, NULL, (VOID **) &mPchTcoSmiDispatchProtocol);
+  ASSERT_EFI_ERROR (Status);
+  //
+  // Always register an SPI BiosWp callback function to handle TCO BIOSWR SMI
+  // NOTE: No matter the BIOS resides behind SPI or not, it needs to handle the SPI BIOS WP SMI
+  //       to avoid SMI deadloop on SPI WPD write.
+  //
+  Handle = NULL;
+  Status = mPchTcoSmiDispatchProtocol->SpiBiosWpRegister (
+                                         mPchTcoSmiDispatchProtocol,
+                                         PchSpiBiosWpCallback,
+                                         &Handle
+                                         );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Always register an LPC/eSPI BiosWp callback function to handle TCO BIOSWR SMI
+  // NOTE: No matter the BIOS resides behind LPC/eSPI or not, it needs to handle the BIOS WP SMI
+  //       to avoid SMI deadloop on LPC/eSPI WPD write.
+  //
+  if (IsEspiEnabled ()) {
+    //
+    // Get the PCH ESPI SMM dispatch protocol
+    //
+    mEspiSmmDispatchProtocol = NULL;
+    Status = gSmst->SmmLocateProtocol (&gPchEspiSmiDispatchProtocolGuid, NULL, (VOID **) &mEspiSmmDispatchProtocol);
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // Register an ESpiBiosWp callback function to handle BIOSWR SMI
+    //
+    Handle = NULL;
+    Status = mEspiSmmDispatchProtocol->BiosWrProtectRegister (
+                                         mEspiSmmDispatchProtocol,
+                                         PchLpcBiosWpCallback,
+                                         &Handle
+                                         );
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    //
+    // Register an LPC BiosWp callback function to handle TCO BIOSWR SMI
+    //
+    Handle = NULL;
+    Status = mPchTcoSmiDispatchProtocol->LpcBiosWpRegister (
+                                           mPchTcoSmiDispatchProtocol,
+                                           PchLpcBiosWpCallback,
+                                           &Handle
+                                           );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c
new file mode 100644
index 0000000000..f3d11ab204
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c
@@ -0,0 +1,33 @@
+/** @file
+  PCH HD Audio Sx handler implementation.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PchInitSmm.h"
+#include <Register/PchRegs.h>
+#include <Register/HdaRegs.h>
+#include <Library/PchPciBdfLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64  mHdaPciBase;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mHdaCodecSxWakeCapability = FALSE;
+
+/**
+  Updates Codec Sx Wake Capability setting: disabled/enabled
+**/
+VOID
+UpdateHdaCodecSxWakeCapabilitySetting (
+  VOID
+  )
+{
+  mHdaPciBase = HdaPciCfgBase ();
+
+  if ((mPchConfigHob->HdAudio.CodecSxWakeCapability == FALSE) ||
+      (PciSegmentRead16 (mHdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF)) {
+    mHdaCodecSxWakeCapability = FALSE;
+  } else {
+    mHdaCodecSxWakeCapability = TRUE;
+  }
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
new file mode 100644
index 0000000000..9c2475e3a1
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
@@ -0,0 +1,285 @@
+/** @file
+  PCH Init Smm module for PCH specific SMI handlers.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchInitSmm.h"
+#include <Register/PchRegs.h>
+#include <Register/UsbRegs.h>
+#include <Register/SmbusRegs.h>
+#include <Library/PchPciBdfLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL        *mPchIoTrap;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_SX_DISPATCH2_PROTOCOL             *mSxDispatch;
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA                              *mPchNvsArea;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16                                    mAcpiBaseAddr;
+
+GLOBAL_REMOVE_IF_UNREFERENCED FIVR_EXT_RAIL_CONFIG                      mFivrExtVnnRailSxConfig;
+
+//
+// NOTE: The module variables of policy here are only valid in post time, but not runtime time.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB                            *mPchConfigHob;
+
+//
+// The reserved MMIO range to be used in Sx handler
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS                      mResvMmioBaseAddr;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN                                     mResvMmioSize;
+
+/**
+  SMBUS Sx entry SMI handler.
+**/
+VOID
+SmbusSxCallback (
+  VOID
+  )
+{
+  UINT64                      SmbusRegBase;
+  UINT16                      SmbusIoBase;
+
+  SmbusRegBase = SmbusPciCfgBase ();
+
+  if (PciSegmentRead32 (SmbusRegBase) == 0xFFFFFFFF) {
+    return;
+  }
+
+  SmbusIoBase = PciSegmentRead16 (SmbusRegBase + R_SMBUS_CFG_BASE) & B_SMBUS_CFG_BASE_BAR;
+  if (SmbusIoBase == 0) {
+    return;
+  }
+
+  PciSegmentOr8 (SmbusRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_IO_SPACE);
+  //
+  // Clear SMBUS status and SMB_WAK_STS of GPE0
+  //
+  IoWrite8 (SmbusIoBase + R_SMBUS_IO_HSTS, B_SMBUS_IO_SMBALERT_STS);
+  IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0_STS_127_96_SMB_WAK);
+}
+
+/*
+  PCH xHCI Sx entry SMI handler
+*/
+VOID
+PchXhciSxCallback (
+  VOID
+  )
+{
+  UINTN      XhciPciBase;
+
+  XhciPciBase = PchXhciPciCfgBase ();
+
+  //
+  // Safety check for xHCI existense
+  //
+  if (PciSegmentRead32 (XhciPciBase) == 0xFFFFFFFF) {
+    return;
+  }
+
+  //
+  // If xHCI is in D0 that means OS didn't put it to D3 during Sx entry i.e. USB kernel debug is enabled.
+  // Unless it is put manually to D3, USB wake functionality will not work.
+  //
+  if ((PciSegmentRead8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS) & V_XHCI_CFG_PWR_CNTL_STS_PWR_STS_D3) == 0) {
+    //
+    // Put device to D3 to enable wake functionality for USB devices
+    //
+    PciSegmentOr8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS, (UINT8)(B_XHCI_CFG_PWR_CNTL_STS_PWR_STS));
+  }
+}
+
+/**
+  Cache PCH FIVR policy.
+**/
+VOID
+UpdatePchFivrSettings (
+  VOID
+  )
+{
+  CopyMem (
+    &mFivrExtVnnRailSxConfig,
+    &mPchConfigHob->Fivr.ExtVnnRailSx,
+    sizeof (mFivrExtVnnRailSxConfig)
+    );
+}
+
+/**
+  PCH Sx entry SMI handler.
+
+  @param[in]     Handle          Handle of the callback
+  @param[in]     Context         The dispatch context
+  @param[in,out] CommBuffer      A pointer to a collection of data in memory that will
+                                 be conveyed from a non-SMM environment into an SMM environment.
+  @param[in,out] CommBufferSize  The size of the CommBuffer.
+
+  @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+PchSxHandler (
+  IN  EFI_HANDLE                   Handle,
+  IN CONST VOID                    *Context OPTIONAL,
+  IN OUT VOID                      *CommBuffer OPTIONAL,
+  IN OUT UINTN                     *CommBufferSize OPTIONAL
+  )
+{
+  PchLanSxCallback ();
+  PchXhciSxCallback ();
+
+  SmbusSxCallback ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize PCH Sx entry SMI handler.
+
+  @param[in] ImageHandle - Handle for the image of this driver
+**/
+VOID
+InitializeSxHandler (
+  IN EFI_HANDLE        ImageHandle
+  )
+{
+  EFI_SMM_SX_REGISTER_CONTEXT               SxDispatchContext;
+  EFI_HANDLE                                SxDispatchHandle;
+  EFI_SLEEP_TYPE                            SxType;
+  EFI_STATUS                                Status;
+
+  DEBUG ((DEBUG_INFO, "InitializeSxHandler() Start\n"));
+
+  //
+  // Register the callback for S3/S4/S5 entry
+  //
+  SxDispatchContext.Phase = SxEntry;
+  for (SxType = SxS3; SxType <= SxS5; SxType++) {
+    SxDispatchContext.Type  = SxType;
+    Status = mSxDispatch->Register (
+                            mSxDispatch,
+                            PchSxHandler,
+                            &SxDispatchContext,
+                            &SxDispatchHandle
+                            );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  DEBUG ((DEBUG_INFO, "InitializeSxHandler() End\n"));
+}
+
+/**
+  Allocates reserved MMIO for Sx SMI handler use.
+**/
+VOID
+AllocateReservedMmio (
+  VOID
+  )
+{
+  mResvMmioBaseAddr = PcdGet32 (PcdSiliconInitTempMemBaseAddr);
+  mResvMmioSize     = PcdGet32 (PcdSiliconInitTempMemSize);
+  DEBUG ((DEBUG_INFO, "mResvMmioBaseAddr %x, mResvMmioSize %x\n", mResvMmioBaseAddr, mResvMmioSize));
+}
+
+/**
+  Initializes the PCH SMM handler for for PCIE hot plug support
+  <b>PchInit SMM Module Entry Point</b>\n
+  - <b>Introduction</b>\n
+      The PchInitSmm module is a SMM driver that initializes the Intel Platform Controller Hub
+      SMM requirements and services. It consumes the PCH_POLICY_HOB and SI_POLICY_HOB for expected
+      configurations per policy.
+
+  - <b>Details</b>\n
+    This module provides SMI handlers to services PCIE HotPlug SMI, LinkActive SMI, and LinkEq SMI.
+    And also provides port 0x61 emulation support, registers BIOS WP handler to process BIOSWP status,
+    and registers SPI Async SMI handler to handler SPI Async SMI.
+    This module also registers Sx SMI callback function to detail with GPIO Sx Isolation and LAN requirement.
+
+  - @pre
+    - PCH PCR base address configured
+    - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+      - This is to ensure that PCI MMIO and IO resource has been prepared and available for this driver to allocate.
+    - EFI_SMM_BASE2_PROTOCOL
+    - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL
+    - EFI_SMM_SX_DISPATCH2_PROTOCOL
+    - EFI_SMM_CPU_PROTOCOL
+    - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink
+    - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink
+
+  - <b>References</b>\n
+    - @link _PCH_POLICY PCH_POLICY_HOB @endlink.
+    - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink.
+
+  - <b>Integration Checklists</b>\n
+    - Verify prerequisites are met. Porting Recommendations.
+    - No modification of this module should be necessary
+    - Any modification of this module should follow the PCH BIOS Specification and EDS
+
+  @param[in] ImageHandle - Handle for the image of this driver
+  @param[in] SystemTable - Pointer to the EFI System Table
+
+  @retval EFI_SUCCESS    - PCH SMM handler was installed
+**/
+EFI_STATUS
+EFIAPI
+PchInitSmmEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                                Status;
+  PCH_NVS_AREA_PROTOCOL                     *PchNvsAreaProtocol;
+  EFI_PEI_HOB_POINTERS                      HobPtr;
+
+  DEBUG ((DEBUG_INFO, "PchInitSmmEntryPoint()\n"));
+
+  Status = gSmst->SmmLocateProtocol (
+                    &gEfiSmmIoTrapDispatch2ProtocolGuid,
+                    NULL,
+                    (VOID **) &mPchIoTrap
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gSmst->SmmLocateProtocol (
+                    &gEfiSmmSxDispatch2ProtocolGuid,
+                    NULL,
+                    (VOID**) &mSxDispatch
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **) &PchNvsAreaProtocol);
+  ASSERT_EFI_ERROR (Status);
+  mPchNvsArea = PchNvsAreaProtocol->Area;
+
+  //
+  // Get PCH Data HOB.
+  //
+  HobPtr.Guid   = GetFirstGuidHob (&gPchConfigHobGuid);
+  ASSERT (HobPtr.Guid != NULL);
+  mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);
+
+  mAcpiBaseAddr = PmcGetAcpiBase ();
+
+  AllocateReservedMmio ();
+
+  InitializeSxHandler (ImageHandle);
+
+  Status = InitializePchPcieSmm (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = InstallPchBiosWriteProtect (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = InstallPchSpiAsyncSmiHandler ();
+  ASSERT_EFI_ERROR (Status);
+
+  UpdateHdaCodecSxWakeCapabilitySetting ();
+
+  UpdatePchFivrSettings ();
+
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
new file mode 100644
index 0000000000..c2a09acd11
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
@@ -0,0 +1,254 @@
+/** @file
+  Header file for PCH Init SMM Handler
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCH_INIT_SMM_H_
+#define _PCH_INIT_SMM_H_
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmIoTrapDispatch2.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/SmmCpu.h>
+#include <Library/TimerLib.h>
+
+#include <IndustryStandard/Pci30.h>
+#include <Library/PmcLib.h>
+#include <Library/PchPcieRpLib.h>
+#include <Library/PchInfoLib.h>
+#include <Library/SataLib.h>
+#include <Library/GpioLib.h>
+#include <Library/GpioNativeLib.h>
+#include <Library/EspiLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/ConfigBlockLib.h>
+#include <Library/PciExpressHelpersLib.h>
+#include <Protocol/PchPcieSmiDispatch.h>
+#include <Protocol/PchTcoSmiDispatch.h>
+#include <Protocol/PchSmiDispatch.h>
+#include <Protocol/PchEspiSmiDispatch.h>
+#include <Protocol/PchSmmIoTrapControl.h>
+#include <Protocol/PchNvsArea.h>
+#include <Protocol/PcieIoTrap.h>
+#include <SiConfigHob.h>
+#include <PchConfigHob.h>
+#include <Library/PmcPrivateLib.h>
+
+extern EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL        *mPchIoTrap;
+extern EFI_SMM_SX_DISPATCH2_PROTOCOL             *mSxDispatch;
+
+extern PCH_NVS_AREA                              *mPchNvsArea;
+extern UINT16                                    mAcpiBaseAddr;
+
+extern EFI_PHYSICAL_ADDRESS                      mResvMmioBaseAddr;
+extern UINTN                                     mResvMmioSize;
+
+//
+// NOTE: The module variables of policy here are only valid in post time, but not runtime time.
+//
+extern PCH_CONFIG_HOB                            *mPchConfigHob;
+extern SI_CONFIG_HOB_DATA                        *mSiConfigHobData;
+
+/**
+  Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling
+
+  @param[in] ImageHandle          The image handle of this module
+  @param[in] SystemTable          The EFI System Table
+
+  @retval EFI_SUCCESS             The function completes successfully
+**/
+EFI_STATUS
+EFIAPI
+InitializePchPcieSmm (
+  IN      EFI_HANDLE            ImageHandle,
+  IN      EFI_SYSTEM_TABLE      *SystemTable
+  );
+
+/**
+  Program Common Clock and ASPM of Downstream Devices
+
+  @param[in] PortIndex                  Pcie Root Port Number
+  @param[in] RpDevice                   Pcie Root Pci Device Number
+  @param[in] RpFunction                 Pcie Root Pci Function Number
+
+  @retval EFI_SUCCESS                   Root port complete successfully
+  @retval EFI_UNSUPPORTED               PMC has invalid vendor ID
+**/
+EFI_STATUS
+PchPcieSmi (
+  IN  UINT8                             PortIndex,
+  IN  UINT8                             RpDevice,
+  IN  UINT8                             RpFunction
+  );
+
+/**
+  PCIE Hotplug SMI call back function for each Root port
+
+  @param[in] DispatchHandle             Handle of this dispatch function
+  @param[in] RpContext                  Rootport context, which contains RootPort Index,
+                                        and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieSmiRpHandlerFunction (
+  IN  EFI_HANDLE                        DispatchHandle,
+  IN  PCH_PCIE_SMI_RP_CONTEXT           *RpContext
+  );
+
+/**
+  PCIE Link Active State Change Hotplug SMI call back function for all Root ports
+
+  @param[in] DispatchHandle             Handle of this dispatch function
+  @param[in] RpContext                  Rootport context, which contains RootPort Index,
+                                        and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieLinkActiveStateChange (
+  IN  EFI_HANDLE                        DispatchHandle,
+  IN  PCH_PCIE_SMI_RP_CONTEXT           *RpContext
+  );
+
+/**
+  PCIE Link Equalization Request SMI call back function for all Root ports
+
+  @param[in] DispatchHandle             Handle of this dispatch function
+  @param[in] RpContext                  Rootport context, which contains RootPort Index,
+                                        and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieLinkEqHandlerFunction (
+  IN  EFI_HANDLE                        DispatchHandle,
+  IN  PCH_PCIE_SMI_RP_CONTEXT           *RpContext
+  );
+
+/**
+  An IoTrap callback to config PCIE power management settings
+
+  @param[in] DispatchHandle  - The handle of this callback, obtained when registering
+  @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
+
+**/
+VOID
+EFIAPI
+PchPcieIoTrapSmiCallback (
+  IN     EFI_HANDLE                     DispatchHandle,
+  IN     EFI_SMM_IO_TRAP_CONTEXT        *CallbackContext,
+  IN OUT VOID                           *CommBuffer,
+  IN OUT UINTN                          *CommBufferSize
+  );
+
+/**
+  Initializes the PCH SMM handler for PCH save and restore
+
+  @param[in] ImageHandle - Handle for the image of this driver
+  @param[in] SystemTable - Pointer to the EFI System Table
+
+  @retval EFI_SUCCESS    - PCH SMM handler was installed
+**/
+EFI_STATUS
+EFIAPI
+PchInitLateSmm (
+  IN      EFI_HANDLE            ImageHandle,
+  IN      EFI_SYSTEM_TABLE      *SystemTable
+  );
+
+/**
+  Initialize PCH Sx entry SMI handler.
+
+  @param[in] ImageHandle - Handle for the image of this driver
+**/
+VOID
+InitializeSxHandler (
+  IN EFI_HANDLE        ImageHandle
+  );
+
+/**
+  PCH Sx entry SMI handler.
+
+  @param[in]     Handle          Handle of the callback
+  @param[in]     Context         The dispatch context
+  @param[in,out] CommBuffer      A pointer to a collection of data in memory that will
+                                 be conveyed from a non-SMM environment into an SMM environment.
+  @param[in,out] CommBufferSize  The size of the CommBuffer.
+
+  @retval EFI_SUCCESS
+**/
+
+EFI_STATUS
+EFIAPI
+PchSxHandler (
+  IN  EFI_HANDLE                   Handle,
+  IN CONST VOID                    *Context OPTIONAL,
+  IN OUT VOID                      *CommBuffer OPTIONAL,
+  IN OUT UINTN                     *CommBufferSize OPTIONAL
+  );
+
+/**
+  GbE Sx entry handler
+**/
+VOID
+PchLanSxCallback (
+  VOID
+  );
+
+/**
+  Updates Codec Sx Wake Capability setting: disabled/enabled
+**/
+VOID
+UpdateHdaCodecSxWakeCapabilitySetting (
+  VOID
+  );
+
+/**
+  Register dispatch function to handle GPIO pads Sx isolation
+**/
+VOID
+InitializeGpioSxIsolationSmm (
+  VOID
+  );
+
+/**
+  Entry point for Pch Bios Write Protect driver.
+
+  @param[in] ImageHandle          Image handle of this driver.
+  @param[in] SystemTable          Global system service table.
+
+  @retval EFI_SUCCESS             Initialization complete.
+**/
+EFI_STATUS
+EFIAPI
+InstallPchBiosWriteProtect (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  );
+
+/**
+  This fuction install SPI ASYNC SMI handler.
+
+  @retval EFI_SUCCESS             Initialization complete.
+**/
+EFI_STATUS
+EFIAPI
+InstallPchSpiAsyncSmiHandler (
+  VOID
+  );
+
+
+
+
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
new file mode 100644
index 0000000000..aaf36a7b2a
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
@@ -0,0 +1,110 @@
+## @file
+# Component description file for PchInitSmm driver
+#
+#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+INF_VERSION = 0x00010017
+BASE_NAME = PchInitSmm
+FILE_GUID = D7B10D4E-67E6-4C74-83E9-F9AF0ACC33CC
+VERSION_STRING = 1.0
+MODULE_TYPE = DXE_SMM_DRIVER
+PI_SPECIFICATION_VERSION = 1.10
+ENTRY_POINT = PchInitSmmEntryPoint
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+
+[LibraryClasses]
+UefiBootServicesTableLib
+UefiDriverEntryPoint
+DxeServicesTableLib
+IoLib
+DebugLib
+BaseLib
+BaseMemoryLib
+S3BootScriptLib
+PciExpressHelpersLib
+SmmServicesTableLib
+PciSegmentLib
+HobLib
+GpioLib
+GpioPrivateLib
+ReportStatusCodeLib
+DevicePathLib
+PmcLib
+PchPcieRpLib
+PchInfoLib
+EspiLib
+TimerLib
+ConfigBlockLib
+PmcPrivateLib
+SataLib
+GbeLib
+GbeMdiLib
+SpiAccessPrivateLib
+PchPciBdfLib
+
+[Packages]
+MdePkg/MdePkg.dec
+TigerlakeSiliconPkg/SiPkg.dec
+
+
+[Pcd]
+gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress
+gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMin
+gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMax
+gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr
+gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemSize
+
+
+[Sources]
+PchInitSmm.c
+PchPcieSmm.c
+GbeSxSmm.c
+PchInitSmm.h
+PchBiosWriteProtect.c
+PchSpiAsync.c
+PchHdaSxSmm.c
+
+
+[Protocols]
+gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES
+gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES
+gPchSmmIoTrapControlGuid ## CONSUMES
+gEfiSmmCpuProtocolGuid ## CONSUMES
+gPchNvsAreaProtocolGuid ## CONSUMES
+gPchPcieSmiDispatchProtocolGuid ## CONSUMES
+gPchTcoSmiDispatchProtocolGuid ## CONSUMES
+gPchSmiDispatchProtocolGuid ## CONSUMES
+gPchEspiSmiDispatchProtocolGuid ## CONSUMES
+gPchPcieIoTrapProtocolGuid ## PRODUCES
+gPchPolicyProtocolGuid ##CONSUMES
+
+
+[Guids]
+gSiConfigHobGuid             ## CONSUMES
+gPchConfigHobGuid            ## CONSUMES
+gPchDeviceTableHobGuid
+gPchPcieRpDxeConfigGuid         ## CONSUMES
+
+
+[Depex]
+gEfiSmmIoTrapDispatch2ProtocolGuid AND
+gEfiSmmSxDispatch2ProtocolGuid AND
+gPchSmmIoTrapControlGuid AND
+gPchPcieSmiDispatchProtocolGuid AND
+gPchTcoSmiDispatchProtocolGuid AND
+gEfiSmmCpuProtocolGuid AND
+gPchNvsAreaProtocolGuid AND
+gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure that PCI MMIO resource has been prepared and available for this driver to allocate.
+gEfiSmmBase2ProtocolGuid AND # This is for SmmServicesTableLib
+gPchPolicyProtocolGuid
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
new file mode 100644
index 0000000000..e885a342a7
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
@@ -0,0 +1,451 @@
+/** @file
+  PCH Pcie SMM Driver Entry
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchInitSmm.h"
+#include <PcieRegs.h>
+#include <Register/PchRegs.h>
+#include <Register/PchPcieRpRegs.h>
+#include <Library/PcieHelperLib.h>
+#include <Library/PchPciBdfLib.h>
+#include <Protocol/PchPolicy.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE      *mDevAspmOverride;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32                        mNumOfDevAspmOverride;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8                         mPchBusNumber;
+//
+// @note:
+// These temp bus numbers cannot be used in runtime (hot-plug).
+// These can be used only during boot.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8                         mTempRootPortBusNumMin;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8                         mTempRootPortBusNumMax;
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_ROOT_PORT_CONFIG     mPcieRootPortConfig[PCH_MAX_PCIE_ROOT_PORTS];
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN                       mPchPciePmTrapExecuted = FALSE;
+
+extern EFI_GUID gPchDeviceTableHobGuid;
+
+/**
+  Program Common Clock and ASPM of Downstream Devices
+
+  @param[in] PortIndex                  Pcie Root Port Number
+  @param[in] RpDevice                   Pcie Root Pci Device Number
+  @param[in] RpFunction                 Pcie Root Pci Function Number
+
+  @retval EFI_SUCCESS                   Root port complete successfully
+  @retval EFI_UNSUPPORTED               PMC has invalid vendor ID
+**/
+EFI_STATUS
+PchPcieSmi (
+  IN  UINT8                             PortIndex,
+  IN  UINT8                             RpDevice,
+  IN  UINT8                             RpFunction
+  )
+{
+  UINT8                 SecBus;
+  UINT8                 SubBus;
+  UINT64                RpBase;
+  UINT64                EpBase;
+  UINT8                 EpPcieCapPtr;
+  UINT8                 EpMaxSpeed;
+  BOOLEAN               DownstreamDevicePresent;
+  UINT32                Timeout;
+
+  RpBase   = PCI_SEGMENT_LIB_ADDRESS (
+               DEFAULT_PCI_SEGMENT_NUMBER_PCH,
+               mPchBusNumber,
+               (UINT32) RpDevice,
+               (UINT32) RpFunction,
+               0
+               );
+
+  if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+    return EFI_SUCCESS;
+  }
+  //
+  // Check presence detect state. Here the endpoint must be detected using PDS rather than
+  // the usual LinkActive check, because PDS changes immediately and LA takes a few milliseconds to stabilize
+  //
+  DownstreamDevicePresent = !!(PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_SLSTS) & B_PCIE_SLSTS_PDS);
+
+  if (DownstreamDevicePresent) {
+    ///
+    /// Make sure the link is active before trying to talk to device behind it
+    /// Wait up to 100ms, according to PCIE spec chapter 6.7.3.3
+    ///
+    Timeout = 100 * 1000;
+    while ((PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_LSTS) & B_PCIE_LSTS_LA) == 0 ) {
+      MicroSecondDelay (10);
+      Timeout-=10;
+      if (Timeout == 0) {
+        return EFI_NOT_FOUND;
+      }
+    }
+    SecBus  = PciSegmentRead8 (RpBase + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+    SubBus  = PciSegmentRead8 (RpBase + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+    ASSERT (SecBus != 0 && SubBus != 0);
+    RootportDownstreamConfiguration (
+      DEFAULT_PCI_SEGMENT_NUMBER_PCH,
+      DEFAULT_PCI_BUS_NUMBER_PCH,
+      RpDevice,
+      RpFunction,
+      mTempRootPortBusNumMin,
+      mTempRootPortBusNumMax,
+      EnumPchPcie
+      );
+    RootportDownstreamPmConfiguration (
+      DEFAULT_PCI_SEGMENT_NUMBER_PCH,
+      DEFAULT_PCI_BUS_NUMBER_PCH,
+      RpDevice,
+      RpFunction,
+      mTempRootPortBusNumMin,
+      mTempRootPortBusNumMax,
+      &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig,
+      mNumOfDevAspmOverride,
+      mDevAspmOverride
+    );
+    //
+    // Perform Equalization
+    //
+    EpBase = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus, 0, 0, 0);
+    EpPcieCapPtr = PcieFindCapId (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP);
+    EpMaxSpeed = PciSegmentRead8 (EpBase + EpPcieCapPtr + R_PCIE_LCAP_OFFSET) & B_PCIE_LCAP_MLS;
+    if (EpMaxSpeed >= 3) {
+      PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_EX_LCTL3, B_PCIE_EX_LCTL3_PE);
+      PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_LCTL, B_PCIE_LCTL_RL);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  PCIE Hotplug SMI call back function for each Root port
+
+  @param[in] DispatchHandle             Handle of this dispatch function
+  @param[in] RpContext                  Rootport context, which contains RootPort Index,
+                                        and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieSmiRpHandlerFunction (
+  IN  EFI_HANDLE                        DispatchHandle,
+  IN  PCH_PCIE_SMI_RP_CONTEXT           *RpContext
+  )
+{
+  PchPcieSmi (RpContext->RpIndex, RpContext->DevNum, RpContext->FuncNum);
+}
+
+/**
+  PCIE Link Active State Change Hotplug SMI call back function for all Root ports
+
+  @param[in] DispatchHandle             Handle of this dispatch function
+  @param[in] RpContext                  Rootport context, which contains RootPort Index,
+                                        and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieLinkActiveStateChange (
+  IN  EFI_HANDLE                        DispatchHandle,
+  IN  PCH_PCIE_SMI_RP_CONTEXT           *RpContext
+  )
+{
+  return;
+}
+
+/**
+  PCIE Link Equalization Request SMI call back function for all Root ports
+
+  @param[in] DispatchHandle             Handle of this dispatch function
+  @param[in] RpContext                  Rootport context, which contains RootPort Index,
+                                        and RootPort PCI BDF.
+**/
+VOID
+EFIAPI
+PchPcieLinkEqHandlerFunction (
+  IN  EFI_HANDLE                        DispatchHandle,
+  IN  PCH_PCIE_SMI_RP_CONTEXT           *RpContext
+  )
+{
+  ///
+  /// From PCI Express specification, the PCIe device can request for Link Equalization. When the
+  /// Link Equalization is requested by the device, an SMI will be generated  by PCIe RP when
+  /// enabled and the SMI subroutine would invoke the Software Preset/Coefficient Search
+  /// software to re-equalize the link.
+  ///
+
+  return;
+
+}
+
+/**
+  An IoTrap callback to config PCIE power management settings
+**/
+VOID
+PchPciePmIoTrapSmiCallback (
+  VOID
+  )
+{
+  UINT32                                    PortIndex;
+  UINT64                                    RpBase;
+  UINT8                                     MaxPciePortNum;
+
+  MaxPciePortNum                   = GetPchMaxPciePortNum ();
+
+  for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
+    RpBase = PchPcieRpPciCfgBase (PortIndex);
+
+    if (PciSegmentRead16 (RpBase) != 0xFFFF) {
+      RootportDownstreamPmConfiguration (
+        DEFAULT_PCI_SEGMENT_NUMBER_PCH,
+        DEFAULT_PCI_BUS_NUMBER_PCH,
+        PchPcieRpDevNumber (PortIndex),
+        PchPcieRpFuncNumber (PortIndex),
+        mTempRootPortBusNumMin,
+        mTempRootPortBusNumMax,
+        &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig,
+        mNumOfDevAspmOverride,
+        mDevAspmOverride
+      );
+
+    }
+  }
+}
+
+/**
+  An IoTrap callback to config PCIE power management settings
+
+  @param[in] DispatchHandle  - The handle of this callback, obtained when registering
+  @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
+
+**/
+VOID
+EFIAPI
+PchPcieIoTrapSmiCallback (
+  IN  EFI_HANDLE                            DispatchHandle,
+  IN  EFI_SMM_IO_TRAP_CONTEXT                *CallbackContext,
+  IN OUT VOID                               *CommBuffer,
+  IN OUT UINTN                              *CommBufferSize
+  )
+{
+  if (CallbackContext->WriteData == PchPciePmTrap) {
+    if (mPchPciePmTrapExecuted == FALSE) {
+      PchPciePmIoTrapSmiCallback ();
+      mPchPciePmTrapExecuted = TRUE;
+    }
+  } else {
+    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+  }
+}
+
+/**
+  This function clear the Io trap executed flag before enter S3
+
+  @param[in] Handle    Handle of the callback
+  @param[in] Context   The dispatch context
+
+  @retval EFI_SUCCESS  PCH register saved
+**/
+EFI_STATUS
+EFIAPI
+PchPcieS3EntryCallBack (
+  IN  EFI_HANDLE                        Handle,
+  IN CONST VOID                    *Context OPTIONAL,
+  IN OUT VOID                      *CommBuffer OPTIONAL,
+  IN OUT UINTN                     *CommBufferSize OPTIONAL
+  )
+{
+  mPchPciePmTrapExecuted = FALSE;
+  return EFI_SUCCESS;
+}
+/**
+  Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling
+
+  @param[in] ImageHandle          The image handle of this module
+  @param[in] SystemTable          The EFI System Table
+
+  @retval EFI_SUCCESS             The function completes successfully
+**/
+EFI_STATUS
+EFIAPI
+InitializePchPcieSmm (
+  IN      EFI_HANDLE            ImageHandle,
+  IN      EFI_SYSTEM_TABLE      *SystemTable
+  )
+{
+  EFI_STATUS                            Status;
+  UINT8                                 PortIndex;
+  UINT8                                 Data8;
+  UINT32                                Data32Or;
+  UINT32                                Data32And;
+  UINT64                                RpBase;
+  EFI_HANDLE                            PcieHandle;
+  PCH_PCIE_SMI_DISPATCH_PROTOCOL        *PchPcieSmiDispatchProtocol;
+  EFI_HANDLE                            PchIoTrapHandle;
+  EFI_SMM_IO_TRAP_REGISTER_CONTEXT      PchIoTrapContext;
+  EFI_SMM_SX_REGISTER_CONTEXT           SxDispatchContext;
+  PCH_PCIE_IOTRAP_PROTOCOL              *PchPcieIoTrapProtocol;
+  EFI_HANDLE                            SxDispatchHandle;
+  UINT8                                 MaxPciePortNum;
+  PCH_POLICY_PROTOCOL                   *PchPolicy;
+  PCIE_RP_DXE_CONFIG                    *PchPcieRpDxeConfig;
+  UINTN                                 PcieDeviceTableSize;
+  PCH_PCIE_DEVICE_OVERRIDE              *DevAspmOverride;
+  UINTN                                 Count;
+
+  DEBUG ((DEBUG_INFO, "InitializePchPcieSmm () Start\n"));
+
+  MaxPciePortNum    = GetPchMaxPciePortNum ();
+
+  //
+  // Locate Pch Pcie Smi Dispatch Protocol
+  //
+  Status = gSmst->SmmLocateProtocol (&gPchPcieSmiDispatchProtocolGuid, NULL, (VOID**) &PchPcieSmiDispatchProtocol);
+  ASSERT_EFI_ERROR (Status);
+
+  mPchBusNumber = DEFAULT_PCI_BUS_NUMBER_PCH;
+  mTempRootPortBusNumMin = PcdGet8 (PcdSiliconInitTempPciBusMin);
+  mTempRootPortBusNumMax = PcdGet8 (PcdSiliconInitTempPciBusMax);
+
+  ASSERT (sizeof mPcieRootPortConfig == sizeof mPchConfigHob->PcieRp.RootPort);
+  CopyMem (
+    mPcieRootPortConfig,
+    &(mPchConfigHob->PcieRp.RootPort),
+    sizeof (mPcieRootPortConfig)
+    );
+
+  DevAspmOverride                   = NULL;
+  mDevAspmOverride                  = NULL;
+  mNumOfDevAspmOverride             = 0;
+
+  Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **) &PchPolicy);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = GetConfigBlock ((VOID*) PchPolicy, &gPchPcieRpDxeConfigGuid, (VOID*) &PchPcieRpDxeConfig);
+  ASSERT_EFI_ERROR (Status);
+
+  DevAspmOverride = PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr;
+
+  Count = 0;
+  if (DevAspmOverride != NULL) {
+    for (Count = 0; DevAspmOverride[Count].DeviceId != 0; Count++) {}
+  }
+
+  if (Count !=0) {
+    PcieDeviceTableSize = Count * sizeof (PCH_PCIE_DEVICE_OVERRIDE);
+    Status = gSmst->SmmAllocatePool (
+                      EfiRuntimeServicesData,
+                      PcieDeviceTableSize,
+                      (VOID **) &mDevAspmOverride
+                      );
+    ASSERT_EFI_ERROR (Status);
+    CopyMem (mDevAspmOverride, DevAspmOverride, PcieDeviceTableSize);
+    mNumOfDevAspmOverride = (UINT32) Count;
+  }
+  //
+  // Throught all PCIE root port function and register the SMI Handler for enabled ports.
+  //
+  for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
+    RpBase = PchPcieRpPciCfgBase (PortIndex);
+    //
+    // Skip the root port function which is not enabled
+    //
+    if (PciSegmentRead32 (RpBase) == 0xFFFFFFFF) {
+      continue;
+    }
+
+    //
+    // Register SMI Handlers for Hot Plug and Link Active State Change
+    //
+    Data8 = PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_SLCAP);
+    if (Data8 & B_PCIE_SLCAP_HPC) {
+      PcieHandle = NULL;
+      Status = PchPcieSmiDispatchProtocol->HotPlugRegister (
+                                             PchPcieSmiDispatchProtocol,
+                                             PchPcieSmiRpHandlerFunction,
+                                             PortIndex,
+                                             &PcieHandle
+                                             );
+      ASSERT_EFI_ERROR (Status);
+
+      Status = PchPcieSmiDispatchProtocol->LinkActiveRegister (
+                                             PchPcieSmiDispatchProtocol,
+                                             PchPcieLinkActiveStateChange,
+                                             PortIndex,
+                                             &PcieHandle
+                                             );
+      ASSERT_EFI_ERROR (Status);
+
+      Data32Or  = B_PCH_PCIE_CFG_MPC_HPME;
+      Data32And = (UINT32) ~B_PCH_PCIE_CFG_MPC_HPME;
+      PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC, Data32Or);
+      S3BootScriptSaveMemReadWrite (
+        S3BootScriptWidthUint32,
+        PcdGet64 (PcdSiPciExpressBaseAddress) + RpBase + R_PCH_PCIE_CFG_MPC,
+        &Data32Or,  /// Data to be ORed
+        &Data32And  /// Data to be ANDed
+        );
+    }
+
+    //
+    // Register SMI Handler for Link Equalization Request from Gen 3 Devices.
+    //
+    Data8 = PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_LCAP);
+    if ((Data8 & B_PCIE_LCAP_MLS) == V_PCIE_LCAP_MLS_GEN3) {
+      Status = PchPcieSmiDispatchProtocol->LinkEqRegister (
+                                             PchPcieSmiDispatchProtocol,
+                                             PchPcieLinkEqHandlerFunction,
+                                             PortIndex,
+                                             &PcieHandle
+                                             );
+      ASSERT_EFI_ERROR (Status);
+    }
+  }
+
+  ASSERT_EFI_ERROR (Status);
+
+  PchIoTrapContext.Type     = WriteTrap;
+  PchIoTrapContext.Length   = 4;
+  PchIoTrapContext.Address  = 0;
+  Status = mPchIoTrap->Register (
+                         mPchIoTrap,
+                         (EFI_SMM_HANDLER_ENTRY_POINT2) PchPcieIoTrapSmiCallback,
+                         &PchIoTrapContext,
+                         &PchIoTrapHandle
+                         );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Install the PCH Pcie IoTrap protocol
+  //
+  (gBS->AllocatePool) (EfiBootServicesData, sizeof (PCH_PCIE_IOTRAP_PROTOCOL), (VOID **)&PchPcieIoTrapProtocol);
+  PchPcieIoTrapProtocol->PcieTrapAddress = PchIoTrapContext.Address;
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gPchPcieIoTrapProtocolGuid,
+                  PchPcieIoTrapProtocol,
+                  NULL
+                  );
+
+  //
+  // Register the callback for S3 entry
+  //
+  SxDispatchContext.Type  = SxS3;
+  SxDispatchContext.Phase = SxEntry;
+  Status = mSxDispatch->Register (
+                          mSxDispatch,
+                          PchPcieS3EntryCallBack,
+                          &SxDispatchContext,
+                          &SxDispatchHandle
+                          );
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INFO, "InitializePchPcieSmm, IoTrap @ %x () End\n", PchIoTrapContext.Address));
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
new file mode 100644
index 0000000000..bdae6fe918
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
@@ -0,0 +1,67 @@
+/** @file
+  PCH SPI Async SMI handler.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchInitSmm.h"
+
+///
+/// Global variables
+///
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMI_DISPATCH_PROTOCOL     *mPchSmiDispatchProtocol;
+
+/**
+  This hardware SMI handler will be run every time the flash write/earse happens.
+
+  @param[in] DispatchHandle       Not used
+
+**/
+VOID
+EFIAPI
+PchSpiAsyncCallback (
+  IN  EFI_HANDLE                              DispatchHandle
+  )
+{
+  //
+  // Dummy SMI handler
+  //
+}
+
+/**
+  This fuction install SPI ASYNC SMI handler.
+
+  @retval EFI_SUCCESS             Initialization complete.
+**/
+EFI_STATUS
+EFIAPI
+InstallPchSpiAsyncSmiHandler (
+  VOID
+  )
+{
+  EFI_STATUS              Status;
+  EFI_HANDLE              Handle;
+
+  DEBUG ((DEBUG_INFO, "InstallPchSpiAsyncSmiHandler()\n"));
+
+  ///
+  /// Get the PCH SMM dispatch protocol
+  ///
+  mPchSmiDispatchProtocol = NULL;
+  Status = gSmst->SmmLocateProtocol (&gPchSmiDispatchProtocolGuid, NULL, (VOID **) &mPchSmiDispatchProtocol);
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Register an SpiAsync callback function
+  ///
+  Handle = NULL;
+  Status = mPchSmiDispatchProtocol->SpiAsyncRegister (
+                                      mPchSmiDispatchProtocol,
+                                      PchSpiAsyncCallback,
+                                      &Handle
+                                      );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
new file mode 100644
index 0000000000..54a1575f2c
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
@@ -0,0 +1,1284 @@
+/** @file
+  Main implementation source file for the Io Trap SMM driver
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Protocol/PchNvsArea.h>
+#include <Library/SmiHandlerProfileLib.h>
+#include <Register/PchPcrRegs.h>
+#include <Register/PchRegsPsth.h>
+#include <Register/PchDmiRegs.h>
+
+#define GENERIC_IOTRAP_SIZE 0x100
+
+//
+// Module global variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE                      mDriverImageHandle;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE                      mIoTrapHandle;
+
+GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_INSTANCE                mIoTrapData;
+GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_RECORD                  *mIoTrapRecord;
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA                    *mPchNvsArea;
+
+
+static CONST UINT16             mLengthTable[10] = { 1, 2, 3, 4, 8, 16, 32, 64, 128, 256 };
+
+/**
+  Helper function that encapsulates IoTrap register access.
+  IO trap related register updates must be made in 2 registers, IOTRAP and DMI source decode.
+
+  @param[in] TrapHandlerNum    trap number (0-3)
+  @param[in] Value             value to be written in both registers
+  @param[in] SaveToBootscript  if true, this register write will be saved to bootscript
+
+**/
+VOID
+SetIoTrapLowDword (
+  IN UINT8   TrapHandlerNum,
+  IN UINT32  Value,
+  IN BOOLEAN SaveToBootscript
+  )
+{
+  UINT32  BitMask;
+  UINT32  BitValue;
+  //
+  // To provide sequentially consistent programming model for IO trap
+  // all pending IO cycles must be flushed before enabling and before disabling a trap.
+  // Without this the trap may trigger due to IO cycle issued before the trap is enabled or a cycle issued before the trap is disabled might be missed.
+  // a. Issues a MemRd to PSTH IO Trap Enable bit -> This serves to flush all previous IO cycles.
+  // b. Then only issues a MemWr to PSTH IO Trap Enable == Value
+  // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves to push the MemWr to PSTH and confirmed that IO Trap is in fact enabled
+  //
+  PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
+  PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, Value);
+  PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
+
+  PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, Value);
+  //
+  // Read back DMI IOTRAP register to enforce ordering so DMI write is completed before any IO reads
+  // from other threads which may occur after this point (after SMI exit).
+  //
+  PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8);
+  if (SaveToBootscript) {
+    //
+    // Ignore the value check of PCH_PCR_BOOT_SCRIPT_READ
+    //
+    BitMask  = 0;
+    BitValue = 0;
+
+    PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);
+    PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, 1, &Value);
+    PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);
+    PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, 1, &Value);
+  }
+}
+
+/**
+  Helper function that encapsulates IoTrap register access.
+  IO trap related register updates must be made in 2 registers, IOTRAP and DMI source decode.
+
+  @param[in] TrapHandlerNum    trap number (0-3)
+  @param[in] Value             value to be written in both registers
+  @param[in] SaveToBootscript  if true, this register write will be saved to bootscript
+
+**/
+VOID
+SetIoTrapHighDword (
+  IN UINT8   TrapHandlerNum,
+  IN UINT32  Value,
+  IN BOOLEAN SaveToBootscript
+  )
+{
+  PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, Value);
+  PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, Value);
+  if (SaveToBootscript) {
+    PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, 1, &Value);
+    PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, 1, &Value);
+  }
+}
+
+/**
+  Clear pending IOTRAP status.
+  If IOTRAP status is pending and IOTRAP is disabled, then BIOS will not find a match SMI source
+  and will not dispatch any SMI handler for it. The pending status will lead to SMI storm.
+  This prevents that IOTRAP gets triggered by pending IO cycles even after it's disabled.
+
+  @param[in] TrapHandlerNum    trap number (0-3)
+
+**/
+VOID
+ClearPendingIoTrapStatus (
+  IN UINT8   TrapHandlerNum
+  )
+{
+  PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPST, (UINT32)(1 << TrapHandlerNum));
+}
+
+/**
+  IO resources allocated to IO traps need to be reported to OS so that they don't get reused.
+  This function makes IO trap allocation data available to ACPI
+
+  @param[in] TrapHandlerNum  trap number (0-3)
+  @param[in] BaseAddress     address of allocated IO resource
+  @param[in] Track           TRUE = resource allocated, FALSE = resource freed
+
+**/
+VOID
+UpdateIoTrapAcpiResources (
+  IN UINT8                TrapHandlerNum,
+  IN EFI_PHYSICAL_ADDRESS BaseAddress,
+  IN BOOLEAN              Track
+  )
+{
+
+  if (Track == TRUE) {
+    mPchNvsArea->IoTrapAddress[TrapHandlerNum] = (UINT16) BaseAddress;
+    mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 1;
+  } else {
+    mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 0;
+  }
+}
+
+/**
+  Get address from IOTRAP low dword.
+
+  @param[in] IoTrapRegLowDword    IOTRAP register low dword
+
+  @retval                         Address of IOTRAP setting.
+**/
+STATIC
+UINT16
+AddressFromLowDword (
+  UINT32  IoTrapRegLowDword
+  )
+{
+  return (UINT16) (IoTrapRegLowDword & B_PSTH_PCR_TRPREG_AD);
+}
+
+/**
+  Get length from IOTRAP low dword.
+
+  @param[in] IoTrapRegLowDword    IOTRAP register low dword
+
+  @retval                         Length of IOTRAP setting.
+**/
+STATIC
+UINT16
+LengthFromLowDword (
+  UINT32  IoTrapRegLowDword
+  )
+{
+  return (UINT16) (((IoTrapRegLowDword >> 16) & 0xFC) + 4);
+}
+
+/**
+  Get ByteEnable from IOTRAP high dword.
+
+  @param[in] IoTrapRegHighDword   IOTRAP register high dword
+
+  @retval                         ByteEnable of IOTRAP setting.
+**/
+STATIC
+UINT8
+ByteEnableFromHighDword (
+  UINT32  IoTrapRegHighDword
+  )
+{
+  return (UINT8) (IoTrapRegHighDword & 0x0F);
+}
+
+/**
+  Get ByteEnableMask from IOTRAP high dword.
+
+  @param[in] IoTrapRegHighDword   IOTRAP register high dword
+
+  @retval                         ByteEnableMask of IOTRAP setting.
+**/
+STATIC
+UINT8
+ByteEnableMaskFromHighDword (
+  UINT32  IoTrapRegHighDword
+  )
+{
+  return (UINT8) ((IoTrapRegHighDword & 0xF0) >> 4);
+}
+
+/**
+  Check the IoTrap register matches the IOTRAP EX content.
+
+  @param[in] IoTrapRecord         IOTRAP registration record structure
+  @param[in] IoTrapRegLowDword    IOTRAP register low dword
+  @param[in] IoTrapRegHighDword   IOTRAP register high dword
+
+  @retval    TRUE                 Content matched
+             FALSE                Content mismatched
+**/
+STATIC
+BOOLEAN
+IsIoTrapExContentMatched (
+  IO_TRAP_RECORD  *IoTrapRecord,
+  UINT32          IoTrapRegLowDword,
+  UINT32          IoTrapRegHighDword
+  )
+{
+  if ((IoTrapRecord->Context.Address == AddressFromLowDword (IoTrapRegLowDword))          &&
+      (IoTrapRecord->Context.Length == LengthFromLowDword (IoTrapRegLowDword))            &&
+      (IoTrapRecord->Context.ByteEnable == ByteEnableFromHighDword (IoTrapRegHighDword))  &&
+      (IoTrapRecord->Context.ByteEnableMask == ByteEnableMaskFromHighDword (IoTrapRegHighDword)))
+  {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+
+/**
+  The helper function for IoTrap callback dispacther
+
+  @param[in] TrapHandlerNum  trap number (0-3)
+**/
+VOID
+IoTrapDispatcherHelper (
+  UINTN                                     TrapHandlerNum
+  )
+{
+  IO_TRAP_RECORD                            *RecordInDb;
+  LIST_ENTRY                                *LinkInDb;
+  EFI_SMM_IO_TRAP_REGISTER_CONTEXT          CurrentIoTrapRegisterData;
+  EFI_SMM_IO_TRAP_CONTEXT                   CurrentIoTrapContextData;
+  UINT16                                    BaseAddress;
+  UINT16                                    StartAddress;
+  UINT16                                    EndAddress;
+  UINT32                                    Data32;
+  UINT8                                     ActiveHighByteEnable;
+  BOOLEAN                                   ReadCycle;
+  UINT32                                    WriteData;
+
+  if (!IsListEmpty (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase))) {
+    Data32 = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC);
+    WriteData = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD);
+
+    BaseAddress           = (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA);
+    ActiveHighByteEnable  = (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >> 16);
+    ReadCycle             = (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) == B_PSTH_PCR_TRPC_RW);
+    //
+    // StartAddress and EndAddress will be equal if it's byte access
+    //
+    EndAddress    = (UINT16) (HighBitSet32 ((UINT32) (ActiveHighByteEnable))) + BaseAddress;
+    StartAddress  = (UINT16) (LowBitSet32 ((UINT32) (ActiveHighByteEnable))) + BaseAddress;
+
+    CurrentIoTrapRegisterData.Type = (EFI_SMM_IO_TRAP_DISPATCH_TYPE)ReadCycle;
+    CurrentIoTrapContextData.WriteData = WriteData;
+
+    LinkInDb = GetFirstNode (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
+
+    while (!IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) {
+      RecordInDb = IO_TRAP_RECORD_FROM_LINK (LinkInDb);
+
+      //
+      // If MergeDisable is TRUE, no need to check the address range, dispatch the callback function directly.
+      //
+      if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
+        if (RecordInDb->IoTrapCallback != NULL) {
+          RecordInDb->IoTrapCallback (&RecordInDb->Link, &CurrentIoTrapContextData, NULL, NULL);
+        }
+        if (RecordInDb->IoTrapExCallback != NULL) {
+          RecordInDb->IoTrapExCallback (BaseAddress, ActiveHighByteEnable, !ReadCycle, WriteData);
+        }
+        //
+        // Expect only one callback available. So break immediately.
+        //
+        break;
+      //
+      // If MergeDisable is FALSE, check the address range and trap type.
+      //
+      } else {
+        if ((RecordInDb->Context.Address <= StartAddress) &&
+            (RecordInDb->Context.Address + RecordInDb->Context.Length > EndAddress)) {
+          if ((RecordInDb->Context.Type == IoTrapExTypeReadWrite) || (RecordInDb->Context.Type == (IO_TRAP_EX_DISPATCH_TYPE) CurrentIoTrapRegisterData.Type)) {
+            //
+            // Pass the IO trap context information
+            //
+            RecordInDb->IoTrapCallback (&RecordInDb->Link, &CurrentIoTrapContextData, NULL, NULL);
+          }
+          //
+          // Break if the address is match
+          //
+          break;
+        } else {
+          LinkInDb = GetNextNode (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &RecordInDb->Link);
+          if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) {
+            //
+            // An IO access was trapped that does not have a handler registered.
+            // This indicates an error condition.
+            //
+            ASSERT (FALSE);
+          }
+        }
+      } // end of if else block
+    } // end of while loop
+  } // end of if else block
+}
+
+/**
+  IoTrap dispatcher for IoTrap register 0.
+
+  @param[in] DispatchHandle             Handle of dispatch function
+**/
+VOID
+EFIAPI
+IoTrapDispatcher0 (
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  IoTrapDispatcherHelper (0);
+}
+
+/**
+  IoTrap dispatcher for IoTrap register 1.
+
+  @param[in] DispatchHandle             Handle of dispatch function
+**/
+VOID
+EFIAPI
+IoTrapDispatcher1 (
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  IoTrapDispatcherHelper (1);
+}
+
+/**
+  IoTrap dispatcher for IoTrap register 2.
+
+  @param[in] DispatchHandle             Handle of dispatch function
+**/
+VOID
+EFIAPI
+IoTrapDispatcher2 (
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  IoTrapDispatcherHelper (2);
+}
+
+/**
+  IoTrap dispatcher for IoTrap register 3.
+
+  @param[in] DispatchHandle             Handle of dispatch function
+**/
+VOID
+EFIAPI
+IoTrapDispatcher3 (
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  IoTrapDispatcherHelper (3);
+}
+
+/**
+  IoTrap registratrion helper fucntion.
+
+  @param[in] DispatchHandle             Handle of dispatch function
+  @param[in] IoTrapDispatchFunction     Dispatch function of IoTrapDispatch2Protocol.
+                                        This could be NULL if it's not from IoTrapDispatch2Protocol.
+  @param[in] IoTrapExDispatchFunction   Dispatch function of IoTrapExDispatchProtocol.
+                                        This could be NULL if it's not from IoTrapExDispatchProtocol.
+  @param[in out] Address                The pointer of IO Address.
+                                        If the input Addres is 0, it will return the address assigned
+                                        by registration to this caller.
+  @param[in] Length                     Length of IO address range.
+  @param[in] Type                       Read/Write type of IO trap.
+  @param[in] ByteEnable                 Bitmap to enable trap for each byte of every dword alignment address.
+  @param[in] ByteEnableMask             ByteEnableMask bitwise to ignore the ByteEnable setting.
+
+  @retval    EFI_INVALID_PARAMETER      If Type is invalid,
+                                        If Length is invalid,
+                                        If Address is invalid,
+             EFI_ACCESS_DENIED          If the SmmReadyToLock event has been triggered,
+             EFI_OUT_OF_RESOURCES       If run out of IoTrap register resource,
+                                        If run out of SMM memory pool,
+             EFI_SUCCESS                IoTrap register successfully.
+**/
+EFI_STATUS
+IoTrapRegisterHelper (
+  OUT       EFI_HANDLE                             *DispatchHandle,
+  IN        EFI_SMM_HANDLER_ENTRY_POINT2           IoTrapDispatchFunction,
+  IN        IO_TRAP_EX_DISPATCH_CALLBACK           IoTrapExDispatchFunction,
+  IN OUT    UINT16                                 *Address,
+  IN        UINT16                                 Length,
+  IN        IO_TRAP_EX_DISPATCH_TYPE               Type,
+  IN        UINT8                                  ByteEnable,
+  IN        UINT8                                  ByteEnableMask
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  BaseAddress;
+  UINT32                UsedLength;
+  UINT8                 TrapHandlerNum;
+  UINT32                IoTrapRegLowDword;
+  UINT32                IoTrapRegHighDword;
+  BOOLEAN               TempMergeDisable;
+
+  DEBUG ((DEBUG_INFO, "IoTrapRegisterHelper\n"));
+  DEBUG ((DEBUG_INFO, "Address:%x \n", *Address));
+  DEBUG ((DEBUG_INFO, "Length:%x \n", Length));
+  DEBUG ((DEBUG_INFO, "Type:%x \n", Type));
+  DEBUG ((DEBUG_INFO, "ByteEnable:%x \n", ByteEnable));
+  DEBUG ((DEBUG_INFO, "ByteEnableMask:%x \n", ByteEnableMask));
+
+  //
+  // Return error if the type is invalid
+  //
+  if (Type >= IoTrapExTypeMaximum) {
+    DEBUG ((DEBUG_ERROR, "The Dispatch Type %0X is invalid! \n", Type));
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Return error if the Length is invalid
+  //
+  if (Length < 1 || Length > GENERIC_IOTRAP_SIZE) {
+    DEBUG ((DEBUG_ERROR, "The Dispatch Length %0X is invalid! \n", Length));
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Return error if the address is invalid
+  // PCH supports non-aligned address but (Address % 4 + Length) must not be more than 4
+  //
+  if (((Length & (Length - 1)) != 0) && (Length != 3)) {
+    DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (((Length >= 4) && (*Address & 0x3)) ||
+      ((Length < 4) && (((*Address & 0x3) + Length) > 4))) {
+    DEBUG ((DEBUG_ERROR, "PCH does not support Dispatch Address %0X and Length %0X combination \n", *Address, Length));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Length >= 4) && ((*Address & (Length - 1)) != 0)) {
+    DEBUG ((DEBUG_ERROR, "Dispatch Address %0X is not aligned to the Length %0X \n", *Address, Length));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  if (*Address) {
+    TempMergeDisable = TRUE;
+  }else {
+    TempMergeDisable = FALSE;
+  }
+  //
+  // Loop through the first IO Trap handler, looking for the suitable handler
+  //
+  for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+    //
+    // Get information from Io Trap handler register
+    //
+    IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
+
+    //
+    // Check if the IO Trap handler is not used
+    //
+    if (AddressFromLowDword (IoTrapRegLowDword) == 0) {
+      //
+      //  Search available IO address and allocate it if the IO address is 0
+      //
+      BaseAddress = *Address;
+      if (BaseAddress == 0) {
+        //
+        // Allocate 256 byte range from GCD for common pool usage
+        //
+        if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
+          BaseAddress = 0xFFFF;
+        }
+        Status = gDS->AllocateIoSpace (
+                        PcdGet8 (PcdEfiGcdAllocateType),
+                        EfiGcdIoTypeIo,
+                        8,
+                        GENERIC_IOTRAP_SIZE,
+                        &BaseAddress,
+                        mDriverImageHandle,
+                        NULL
+                        );
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "Can't find any available IO address! \n"));
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        *Address   = (UINT16) BaseAddress;
+        UsedLength = GENERIC_IOTRAP_SIZE;
+        mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength = Length;
+        mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = TRUE;
+        UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE);
+      } else {
+        BaseAddress &= B_PSTH_PCR_TRPREG_AD;
+        UsedLength = Length;
+      }
+
+      Status = PchInternalIoTrapSmiRegister (
+                 mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher,
+                 TrapHandlerNum,
+                 &mIoTrapHandle
+                 );
+
+      ASSERT_EFI_ERROR (Status);
+      mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = mIoTrapHandle;
+
+      //
+      // Fill in the Length, address and Enable the IO Trap SMI
+      //
+      IoTrapRegLowDword = (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)) << 16) |
+        (UINT16) BaseAddress |
+        B_PSTH_PCR_TRPREG_TSE;
+
+      if (UsedLength < 4) {
+        //
+        // The 4 bits is the Byte Enable Mask bits to indicate which byte that are trapped.
+        // The input ByteEnable and ByteEnableMask are ignored in this case.
+        //
+        IoTrapRegHighDword  = (((1 << UsedLength) - 1) << ((*Address & 0x3) + (N_PSTH_PCR_TRPREG_BEM - 32))) |
+          (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);
+      } else {
+        //
+        // Fill in the ByteEnable, ByteEnableMask, and Type of Io Trap register
+        //
+        IoTrapRegHighDword  = ((ByteEnableMask & 0xF) << (N_PSTH_PCR_TRPREG_BEM - 32)) |
+          ((ByteEnable & 0xF) << (N_PSTH_PCR_TRPREG_BE - 32)) |
+          (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);
+      }
+      SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
+      SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
+      //
+      // Set MergeDisable flag of the registered IoTrap
+      //
+      mIoTrapData.Entry[TrapHandlerNum].MergeDisable = TempMergeDisable;
+    } else {
+      //
+      // Check next handler if MergeDisable is TRUE or the registered IoTrap if MergeDisable is TRUE
+      // If the Io Trap register is used by IoTrapEx protocol, then the MergeDisable will be FALSE.
+      //
+      if ((TempMergeDisable == TRUE) || (mIoTrapData.Entry[TrapHandlerNum].MergeDisable == TRUE)) {
+        continue;
+      }
+      //
+      // The IO Trap handler is used, calculate the Length
+      //
+      UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
+      BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
+      //
+      //  Assign an addfress from common pool if the caller's address is 0
+      //
+      if (*Address == 0) {
+        //
+        //  Check next handler if it's fully used
+        //
+        if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >= GENERIC_IOTRAP_SIZE) {
+          continue;
+        }
+        //
+        // Check next handler if it's not for a common pool
+        //
+        if (UsedLength < GENERIC_IOTRAP_SIZE) {
+          continue;
+        }
+        //
+        // Check next handler if the size is too big
+        //
+        if (Length >= (UINT16) GENERIC_IOTRAP_SIZE - mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength) {
+          continue;
+        }
+        //
+        // For common pool, we don't need to change the BaseAddress and UsedLength
+        //
+        *Address = (UINT16) (BaseAddress + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength);
+        mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength += Length;
+      }
+      //
+      // Only set RWM bit when we need both read and write cycles.
+      //
+      IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
+      if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) == 0 &&
+          (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >> N_PSTH_PCR_TRPREG_RWIO) !=
+          (UINT32) Type) {
+        IoTrapRegHighDword = ((IoTrapRegHighDword | B_PSTH_PCR_TRPREG_RWM) & ~B_PSTH_PCR_TRPREG_RWIO);
+        SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
+      }
+    }
+    break;
+  }
+
+  if (TrapHandlerNum >= IO_TRAP_HANDLER_NUM) {
+    DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO Trap handler! \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Create database record and add to database
+  //
+  Status = gSmst->SmmAllocatePool (
+                    EfiRuntimeServicesData,
+                    sizeof (IO_TRAP_RECORD),
+                    (VOID **) &mIoTrapRecord
+                    );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate memory for mIoTrapRecord! \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Gather information about the registration request
+  //
+  mIoTrapRecord->Signature               = IO_TRAP_RECORD_SIGNATURE;
+  mIoTrapRecord->Context.Address         = *Address;
+  mIoTrapRecord->Context.Length          = Length;
+  mIoTrapRecord->Context.Type            = Type;
+  mIoTrapRecord->Context.ByteEnable      = ByteEnable;
+  mIoTrapRecord->Context.ByteEnableMask  = ByteEnableMask;
+  mIoTrapRecord->IoTrapCallback          = IoTrapDispatchFunction;
+  mIoTrapRecord->IoTrapExCallback        = IoTrapExDispatchFunction;
+  mIoTrapRecord->IoTrapNumber            = TrapHandlerNum;
+
+  InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &mIoTrapRecord->Link);
+
+  //
+  // Child's handle will be the address linked list link in the record
+  //
+  *DispatchHandle = (EFI_HANDLE) (&mIoTrapRecord->Link);
+
+  DEBUG ((DEBUG_INFO, "Result Address:%x \n", *Address));
+  DEBUG ((DEBUG_INFO, "Result Length:%x \n", Length));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  IoTrap unregistratrion helper fucntion.
+
+  @param[in] DispatchHandle             Handle of dispatch function
+
+  @retval    EFI_INVALID_PARAMETER      If DispatchHandle is invalid,
+             EFI_ACCESS_DENIED          If the SmmReadyToLock event has been triggered,
+             EFI_SUCCESS                IoTrap unregister successfully.
+**/
+EFI_STATUS
+IoTrapUnRegisterHelper (
+  IN EFI_HANDLE                                  DispatchHandle
+  )
+{
+  EFI_STATUS            Status;
+  IO_TRAP_RECORD        *RecordToDelete;
+  UINT32                IoTrapRegLowDword;
+  EFI_PHYSICAL_ADDRESS  BaseAddress;
+  UINT32                UsedLength;
+  UINT8                 TrapHandlerNum;
+  UINT8                 LengthIndex;
+  BOOLEAN               RequireToDisableIoTrapHandler;
+
+  if (DispatchHandle == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+  //
+  // Take the entry out of the linked list
+  //
+  if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RequireToDisableIoTrapHandler = FALSE;
+  //
+  // Loop through the first IO Trap handler, looking for the suitable handler
+  //
+  TrapHandlerNum = RecordToDelete->IoTrapNumber;
+
+  if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
+    //
+    // Disable the IO Trap handler if it's the only child of the Trap handler
+    //
+    RequireToDisableIoTrapHandler = TRUE;
+  } else {
+    //
+    // Get information from Io Trap handler register
+    //
+    IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
+
+    //
+    // Check next Io Trap handler if the IO Trap handler is not used
+    //
+    if (AddressFromLowDword (IoTrapRegLowDword) != 0) {
+
+      UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
+      BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
+
+      //
+      // Check if it's the maximum address of the Io Trap handler
+      //
+      if ((UINTN)(BaseAddress + UsedLength) == (UINTN)(RecordToDelete->Context.Address + RecordToDelete->Context.Length)) {
+
+        if (BaseAddress == RecordToDelete->Context.Address) {
+          //
+          // Disable the IO Trap handler if it's the only child of the Trap handler
+          //
+          RequireToDisableIoTrapHandler = TRUE;
+        } else {
+          //
+          // Calculate the new IO Trap handler Length
+          //
+          UsedLength = UsedLength - RecordToDelete->Context.Length;
+          //
+          // Check the alignment is dword * power of 2 or not
+          //
+          for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof (UINT16); LengthIndex++) {
+            if (UsedLength == mLengthTable[LengthIndex]) {
+              break;
+            }
+          }
+          //
+          // Do not decrease the length if the alignment is not dword * power of 2
+          //
+          if (LengthIndex < sizeof (mLengthTable) / sizeof (UINT16)) {
+            //
+            // Decrease the length to prevent the IO trap SMI
+            //
+            IoTrapRegLowDword = (UINT32) ((((UsedLength - 1) &~(BIT1 + BIT0)) << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE);
+          }
+          SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
+        }
+      }
+    }
+  }
+
+  if (RequireToDisableIoTrapHandler) {
+    mIoTrapHandle = mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle;
+    Status        = PchInternalIoTrapSmiUnRegister (mIoTrapHandle);
+    ASSERT_EFI_ERROR (Status);
+
+    SetIoTrapLowDword (TrapHandlerNum, 0, TRUE);
+    SetIoTrapHighDword (TrapHandlerNum, 0, TRUE);
+    //
+    // Also clear pending IOTRAP status.
+    //
+    ClearPendingIoTrapStatus (TrapHandlerNum);
+
+    mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = 0;
+    mIoTrapData.Entry[TrapHandlerNum].MergeDisable = FALSE;
+    if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource == TRUE) {
+      mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = FALSE;
+      UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE);
+    }
+  }
+
+  RemoveEntryList (&RecordToDelete->Link);
+  Status = gSmst->SmmFreePool (RecordToDelete);
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Register a new IO Trap SMI dispatch function with a parent SMM driver.
+  The caller will provide information about the IO trap characteristics via
+  the context.  This includes base address, length, read vs. r/w, etc.
+  This function will autoallocate IO base address from a common pool if the base address is 0,
+  and the RegisterContext Address field will be updated.
+  The service will not perform GCD allocation if the base address is non-zero.
+  In this case, the caller is responsible for the existence and allocation of the
+  specific IO range.
+  This function looks for the suitable handler and Register a new IoTrap handler
+  if the IO Trap handler is not used. It also enable the IO Trap Range to generate
+  SMI.
+
+  @param[in] This                 Pointer to the EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchFunction     Pointer to dispatch function to be invoked for
+                                  this SMI source.
+  @param[in, out] RegisterContext Pointer to the dispatch function's context.
+                                  The caller fills this context in before calling
+                                  the register function to indicate to the register
+                                  function the IO trap SMI source for which the dispatch
+                                  function should be invoked.  This may not be NULL.
+                                  If the registration address is not 0, it's caller's responsibility
+                                  to reserve the IO resource in ACPI.
+  @param[out] DispatchHandle      Handle of dispatch function, for when interfacing
+                                  with the parent SMM driver, will be the address of linked
+                                  list link in the call back record.  This may not be NULL.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  registered and the SMI source has been enabled.
+  @retval EFI_DEVICE_ERROR        The driver was unable to enable the SMI source.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available
+  @retval EFI_INVALID_PARAMETER   Address requested is already in use.
+  @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+IoTrapRegister (
+  IN CONST  EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL     *This,
+  IN        EFI_SMM_HANDLER_ENTRY_POINT2           DispatchFunction,
+  IN OUT    EFI_SMM_IO_TRAP_REGISTER_CONTEXT       *RegisterContext,
+  OUT       EFI_HANDLE                             *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  DEBUG ((DEBUG_INFO, "IoTrapRegister\n"));
+  Status = IoTrapRegisterHelper (
+             DispatchHandle,
+             DispatchFunction,
+             NULL,
+             &(RegisterContext->Address),
+             RegisterContext->Length,
+             (IO_TRAP_EX_DISPATCH_TYPE) RegisterContext->Type,
+             0x00,
+             0x0F);
+
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (
+      &gEfiSmmIoTrapDispatch2ProtocolGuid,
+      DispatchFunction,
+      (UINTN)RETURN_ADDRESS (0),
+      RegisterContext,
+      sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)
+      );
+  }
+  return Status;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver.
+
+  @param[in] This                 Pointer to the EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  unregistered and the SMI source has been disabled
+                                  if there are no other registered child dispatch
+                                  functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER   Handle is invalid.
+  @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+IoTrapUnRegister (
+  IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL    *This,
+  IN EFI_HANDLE                                  DispatchHandle
+  )
+{
+  IO_TRAP_RECORD *RecordToDelete;
+
+  RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+  SmiHandlerProfileUnregisterHandler (
+    &gIoTrapExDispatchProtocolGuid,
+    RecordToDelete->IoTrapCallback,
+    &RecordToDelete->Context,
+    sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)
+    );
+  return IoTrapUnRegisterHelper (DispatchHandle);
+}
+
+/**
+  Register a new IO Trap Ex SMI dispatch function.
+
+  @param[in] This                 Pointer to the IO_TRAP_EX_DISPATCH_PROTOCOL instance.
+  @param[in] DispatchFunction     Pointer to dispatch function to be invoked for
+                                  this SMI source.
+  @param[in] RegisterContext      Pointer to the dispatch function's context.
+                                  The caller fills this context in before calling
+                                  the register function to indicate to the register
+                                  function the IO trap Ex SMI source for which the dispatch
+                                  function should be invoked.  This MUST not be NULL.
+  @param[out] DispatchHandle      Handle of dispatch function.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  registered and the SMI source has been enabled.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available
+  @retval EFI_INVALID_PARAMETER   Address requested is already in use.
+  @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+IoTrapExRegister (
+  IN  IO_TRAP_EX_DISPATCH_PROTOCOL  *This,
+  IN  IO_TRAP_EX_DISPATCH_CALLBACK  DispatchFunction,
+  IN  IO_TRAP_EX_REGISTER_CONTEXT   *RegisterContext,
+  OUT EFI_HANDLE                    *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  DEBUG ((DEBUG_INFO, "PchSmmIoTrapExRegister\n"));
+  //
+  // Return error if length is less than 4 and not power of 2.
+  //
+  if ((RegisterContext->Length < 4) || ((RegisterContext->Length & (RegisterContext->Length - 1)) != 0)) {
+    DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = IoTrapRegisterHelper (
+             DispatchHandle,
+             NULL,
+             DispatchFunction,
+             &(RegisterContext->Address),
+             RegisterContext->Length,
+             RegisterContext->Type,
+             RegisterContext->ByteEnable,
+             RegisterContext->ByteEnableMask);
+
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (
+      &gIoTrapExDispatchProtocolGuid,
+      (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
+      (UINTN)RETURN_ADDRESS (0),
+      RegisterContext,
+      sizeof (*RegisterContext)
+      );
+  }
+  return Status;
+}
+
+/**
+  Unregister a SMI source dispatch function.
+  This function is unsupported.
+
+  @param[in] This                 Pointer to the IO_TRAP_EX_DISPATCH_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_UNSUPPORTED         The function is unsupported.
+**/
+EFI_STATUS
+EFIAPI
+IoTrapExUnRegister (
+  IN IO_TRAP_EX_DISPATCH_PROTOCOL   *This,
+  IN EFI_HANDLE                     DispatchHandle
+  )
+{
+  IO_TRAP_RECORD *RecordToDelete;
+
+  RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+  SmiHandlerProfileUnregisterHandler (
+    &gIoTrapExDispatchProtocolGuid,
+    RecordToDelete->IoTrapCallback,
+    &RecordToDelete->Context,
+    sizeof (RecordToDelete->Context)
+    );
+  return IoTrapUnRegisterHelper (DispatchHandle);
+}
+
+/**
+  Pause IoTrap callback function.
+
+  This function disables the SMI enable of IoTrap according to the DispatchHandle,
+  which is returned by IoTrap callback registration. It only supports the DispatchHandle
+  with MergeDisable TRUE and address not zero.
+
+  NOTE: This call does not guarantee all pending IO cycles to be synchronized
+        and pending IO cycles issued before this call might not be trapped.
+
+  @param[in] This                 Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of the child service to change state.
+
+  @retval EFI_SUCCESS             This operation is complete.
+  @retval EFI_INVALID_PARAMETER   The DispatchHandle is invalid.
+  @retval EFI_ACCESS_DENIED       The SMI status is alrady PAUSED.
+**/
+EFI_STATUS
+EFIAPI
+IoTrapControlPause (
+  IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL   *This,
+  IN EFI_HANDLE                         DispatchHandle
+  )
+{
+  IO_TRAP_RECORD                        *IoTrapRecord;
+  UINT32                                IoTrapRegLowDword;
+  UINT32                                IoTrapRegHighDword;
+  EFI_PHYSICAL_ADDRESS                  BaseAddress;
+  UINT32                                UsedLength;
+  UINT8                                 TrapHandlerNum;
+  BOOLEAN                               TempMergeDisable;
+  BOOLEAN                               DisableIoTrap;
+
+  if (DispatchHandle == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+
+  if (IoTrapRecord->Context.Address) {
+    TempMergeDisable =TRUE;
+  }else {
+    TempMergeDisable = FALSE;
+  }
+
+  if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
+      (TempMergeDisable != TRUE)                            ||
+      (IoTrapRecord->Context.Address == 0)                  ||
+      (IoTrapRecord->Context.Length == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+    //
+    // This IoTrap register should be merge disabled.
+    //
+    if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
+      continue;
+    }
+    IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
+    IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
+    //
+    // Depending on the usage, we will obtain the UsedLength and BaseAddress differently
+    // If the registered trap length is less than 4, we obtain the length from Byte Enable Mask
+    // In the other hand, we obtain the length from Address Mask
+    //
+    if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
+      UsedLength = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) - LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
+      BaseAddress = AddressFromLowDword (IoTrapRegLowDword) + LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
+    } else {
+      UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
+      BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
+    }
+
+    //
+    // The address and length of record matches the IoTrap register's.
+    //
+    DisableIoTrap = FALSE;
+    if ((IoTrapRecord->IoTrapExCallback != NULL) &&
+        IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, IoTrapRegHighDword)) {
+      DisableIoTrap = TRUE;
+    } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
+               (UsedLength  == IoTrapRecord->Context.Length )) {
+      DisableIoTrap = TRUE;
+    }
+
+    if (DisableIoTrap) {
+      //
+      // Check if status matched.
+      // If this is already Paused, return warning status.
+      //
+      if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) == 0) {
+        return EFI_ACCESS_DENIED;
+      }
+      //
+      // Clear IoTrap register SMI enable bit
+      //
+      IoTrapRegLowDword &= (~B_PSTH_PCR_TRPREG_TSE);
+      SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);
+      //
+      // Also clear pending IOTRAP status.
+      //
+      ClearPendingIoTrapStatus (TrapHandlerNum);
+      return EFI_SUCCESS;
+    }
+  }
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
+  Resume IoTrap callback function.
+
+  This function enables the SMI enable of IoTrap according to the DispatchHandle,
+  which is returned by IoTrap callback registration. It only supports the DispatchHandle
+  with MergeDisable TRUE and address not zero.
+
+  @param[in] This                 Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of the child service to change state.
+
+  @retval EFI_SUCCESS             This operation is complete.
+  @retval EFI_INVALID_PARAMETER   The DispatchHandle is invalid.
+  @retval EFI_ACCESS_DENIED       The SMI status is alrady RESUMED.
+**/
+EFI_STATUS
+EFIAPI
+IoTrapControlResume (
+  IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL   *This,
+  IN EFI_HANDLE                         DispatchHandle
+  )
+{
+  IO_TRAP_RECORD                        *IoTrapRecord;
+  UINT32                                IoTrapRegLowDword;
+  UINT32                                IoTrapRegHighDword;
+  EFI_PHYSICAL_ADDRESS                  BaseAddress;
+  UINT32                                UsedLength;
+  UINT8                                 TrapHandlerNum;
+  BOOLEAN                               TempMergeDisable;
+  BOOLEAN                               EnableIoTrap;
+
+  if (DispatchHandle == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+  IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+
+  if (IoTrapRecord->Context.Address) {
+    TempMergeDisable = TRUE;
+  }else {
+    TempMergeDisable = FALSE;
+  }
+
+  if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
+      (TempMergeDisable != TRUE)          ||
+      (IoTrapRecord->Context.Address == 0)                  ||
+      (IoTrapRecord->Context.Length == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+    //
+    // This IoTrap register should be merge disabled.
+    //
+    if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
+      continue;
+    }
+    IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
+    IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
+    //
+    // Depending on the usage, we will obtain the UsedLength and BaseAddress differently
+    // If the registered trap length is less than 4, we obtain the length from Byte Enable Mask
+    // In the other hand, we obtain the length from Address Mask
+    //
+    if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
+      UsedLength  = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) - LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
+      BaseAddress = AddressFromLowDword (IoTrapRegLowDword) + LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
+    } else {
+      UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
+      BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
+    }
+
+    //
+    // The address and length of record matches the IoTrap register's.
+    //
+    EnableIoTrap = FALSE;
+    if ((IoTrapRecord->IoTrapExCallback != NULL) &&
+        IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, IoTrapRegHighDword)) {
+      EnableIoTrap = TRUE;
+    } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
+               (UsedLength  == IoTrapRecord->Context.Length )) {
+      EnableIoTrap = TRUE;
+    }
+
+    if (EnableIoTrap) {
+      //
+      // Check if status matched.
+      // If this is already Resume, return warning status.
+      //
+      if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) != 0) {
+        return EFI_ACCESS_DENIED;
+      }
+      //
+      // Set IoTrap register SMI enable bit
+      //
+      IoTrapRegLowDword |= (B_PSTH_PCR_TRPREG_TSE);
+      SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);
+      return EFI_SUCCESS;
+    }
+  }
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
+  The IoTrap module abstracts PCH I/O trapping capabilities for other drivers.
+  This driver manages the limited I/O trap resources.
+
+  @param[in] ImageHandle                Image handle for this driver image
+
+  @retval EFI_SUCCESS                   Driver initialization completed successfully
+**/
+EFI_STATUS
+EFIAPI
+InstallIoTrap (
+  IN EFI_HANDLE                         ImageHandle
+  )
+{
+  EFI_STATUS             Status;
+  PCH_NVS_AREA_PROTOCOL  *PchNvsAreaProtocol;
+  UINTN                  TrapHandlerNum;
+
+  //
+  // Initialize the EFI SMM driver library
+  //
+  mDriverImageHandle = ImageHandle;
+
+  //
+  // Initialize the IO TRAP protocol we produce
+  //
+  mIoTrapData.Signature = IO_TRAP_INSTANCE_SIGNATURE;
+  mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register   = IoTrapRegister;
+  mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister = IoTrapUnRegister;
+
+  //
+  // Initialize the IO TRAP EX protocol
+  //
+  mIoTrapData.IoTrapExDispatchProtocol.Register       = IoTrapExRegister;
+  mIoTrapData.IoTrapExDispatchProtocol.UnRegister     = IoTrapExUnRegister;
+
+  //
+  // Initialize the IO TRAP control protocol.
+  //
+  mIoTrapData.PchSmmIoTrapControlProtocol.Pause       = IoTrapControlPause;
+  mIoTrapData.PchSmmIoTrapControlProtocol.Resume      = IoTrapControlResume;
+
+  for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+    //
+    // Initialize IO TRAP Callback DataBase
+    //
+    InitializeListHead (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
+  }
+  mIoTrapData.Entry[0].CallbackDispatcher = IoTrapDispatcher0;
+  mIoTrapData.Entry[1].CallbackDispatcher = IoTrapDispatcher1;
+  mIoTrapData.Entry[2].CallbackDispatcher = IoTrapDispatcher2;
+  mIoTrapData.Entry[3].CallbackDispatcher = IoTrapDispatcher3;
+
+  //
+  // Get address of PchNvs structure for later use
+  //
+  Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **) &PchNvsAreaProtocol);
+  ASSERT_EFI_ERROR (Status);
+  mPchNvsArea = PchNvsAreaProtocol->Area;
+
+  //
+  // Install protocol interface
+  //
+  mIoTrapData.Handle = NULL;
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &mIoTrapData.Handle,
+                    &gEfiSmmIoTrapDispatch2ProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mIoTrapData.EfiSmmIoTrapDispatchProtocol
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &mIoTrapData.Handle,
+                    &gIoTrapExDispatchProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mIoTrapData.IoTrapExDispatchProtocol
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &mIoTrapData.Handle,
+                    &gPchSmmIoTrapControlGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mIoTrapData.PchSmmIoTrapControlProtocol
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h
new file mode 100644
index 0000000000..e69d2e2d4d
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h
@@ -0,0 +1,226 @@
+/** @file
+  Defines and prototypes for the IoTrap SMM driver
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _IO_TRAP_H_
+#define _IO_TRAP_H_
+
+//
+// Include files
+//
+#include <Library/S3BootScriptLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Protocol/SmmIoTrapDispatch2.h>
+#include <Protocol/PchSmmIoTrapControl.h>
+#include <Protocol/IoTrapExDispatch.h>
+
+#define IO_TRAP_HANDLER_NUM 4
+
+//
+// Driver private data
+//
+#define IO_TRAP_INSTANCE_SIGNATURE  SIGNATURE_32 ('I', 'O', 'T', 'P')
+
+typedef struct {
+  EFI_HANDLE                            IoTrapHandle;
+  /**
+    The callback linked list for all "merged" IoTrap callbacks.
+  **/
+  LIST_ENTRY                            CallbackDataBase;
+  /**
+    The IoTrap IO range used length tracking for "merged" IoTrap register.
+  **/
+  UINT32                                TrapUsedLength;
+  /**
+    Determine if IoTrap can be merged with other IoTrap callbacks.
+    If MergeDisable is TRUE, then there is only one callback function for one IoTrap register.
+    If MergeDisable is FALSE, then there are multiple callbacks in the "CallbackDataBase" for one IoTrap register.
+  **/
+  BOOLEAN                               MergeDisable;
+  /**
+    Indicator of the resource tracking in ACPI.
+    If the registration address is not 0, it's caller's responsibility to reserve the IO resource in ACPI.
+  **/
+  BOOLEAN                               ReservedAcpiIoResource;
+  /**
+    Dispatcher for each IoTrap register.
+  **/
+  PCH_SMI_DISPATCH_CALLBACK             CallbackDispatcher;
+} IO_TRAP_ENTRY_ATTRIBUTES;
+
+typedef struct {
+  UINT32                                Signature;
+  EFI_HANDLE                            Handle;
+  EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL    EfiSmmIoTrapDispatchProtocol;
+  PCH_SMM_IO_TRAP_CONTROL_PROTOCOL      PchSmmIoTrapControlProtocol;        ///< Protocol for runtime control the IoTrap state
+  IO_TRAP_EX_DISPATCH_PROTOCOL          IoTrapExDispatchProtocol;           ///< Protocol for IoTrap Extension
+  IO_TRAP_ENTRY_ATTRIBUTES              Entry[IO_TRAP_HANDLER_NUM];
+} IO_TRAP_INSTANCE;
+
+#define IO_TRAP_INSTANCE_FROM_THIS(a) CR (a, IO_TRAP_INSTANCE, EfiSmmIoTrapDispatchProtocol, IO_TRAP_INSTANCE_SIGNATURE)
+
+///
+/// "IOTRAP" RECORD
+/// Linked list data structures
+///
+#define IO_TRAP_RECORD_SIGNATURE  SIGNATURE_32 ('I', 'T', 'R', 'C')
+
+typedef struct _IO_TRAP_RECORD {
+  UINT32                                    Signature;
+  LIST_ENTRY                                Link;
+  IO_TRAP_EX_REGISTER_CONTEXT               Context;
+  /**
+    The callback function of IoTrap protocol.
+    This also indicate it's the record for IoTrapProtocol.
+    Only one of IoTrapCallback or IoTrapExCallback is valid at a time.
+  **/
+  EFI_SMM_HANDLER_ENTRY_POINT2              IoTrapCallback;
+  /**
+    The callback function of IoTrapEx protocol
+    This also indicate it's the record for IoTrapExProtocol.
+    Only one of IoTrapCallback or IoTrapExCallback is valid at a time.
+  **/
+  IO_TRAP_EX_DISPATCH_CALLBACK              IoTrapExCallback;
+  UINT8                                     IoTrapNumber;
+} IO_TRAP_RECORD;
+
+#define IO_TRAP_RECORD_FROM_LINK(_record) CR (_record, IO_TRAP_RECORD, Link, IO_TRAP_RECORD_SIGNATURE)
+
+//
+// Prototypes
+//
+/**
+  The IoTrap module abstracts PCH I/O trapping capabilities for other drivers.
+  This driver manages the limited I/O trap resources.
+
+  @param[in] ImageHandle                Image handle for this driver image
+
+  @retval EFI_SUCCESS                   Driver initialization completed successfully
+**/
+EFI_STATUS
+EFIAPI
+InstallIoTrap (
+  IN EFI_HANDLE                     ImageHandle
+  );
+
+/**
+  Register a new IO Trap SMI dispatch function with a parent SMM driver.
+  The caller will provide information about the IO trap characteristics via
+  the context.  This includes base address, length, read vs. r/w, etc.
+  This function will autoallocate IO base address from a common pool if the base address is 0,
+  and the RegisterContext Address field will be updated.
+  The service will not perform GCD allocation if the base address is non-zero.
+  In this case, the caller is responsible for the existence and allocation of the
+  specific IO range.
+  This function looks for the suitable handler and Register a new IoTrap handler
+  if the IO Trap handler is not used. It also enable the IO Trap Range to generate
+  SMI.
+
+  @param[in] This                 Pointer to the  EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchFunction     Pointer to dispatch function to be invoked for
+                                  this SMI source.
+  @param[in, out] RegisterContext Pointer to the dispatch function's context.
+                                  The caller fills this context in before calling
+                                  the register function to indicate to the register
+                                  function the IO trap SMI source for which the dispatch
+                                  function should be invoked.  This may not be NULL.
+                                  If the registration address is not 0, it's caller's responsibility
+                                  to reserve the IO resource in ACPI.
+  @param[out] DispatchHandle      Handle of dispatch function, for when interfacing
+                                  with the parent SMM driver, will be the address of linked
+                                  list link in the call back record.  This may not be NULL.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  registered and the SMI source has been enabled.
+  @retval EFI_DEVICE_ERROR        The driver was unable to enable the SMI source.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available
+  @retval EFI_INVALID_PARAMETER   Address requested is already in use.
+  @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+IoTrapRegister (
+  IN  CONST   EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL     *This,
+  IN          EFI_SMM_HANDLER_ENTRY_POINT2           DispatchFunction,
+  IN OUT      EFI_SMM_IO_TRAP_REGISTER_CONTEXT       *RegisterContext,
+  OUT EFI_HANDLE                                      *DispatchHandle
+  );
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver.
+
+  @param[in] This                 Pointer to the  EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  unregistered and the SMI source has been disabled
+                                  if there are no other registered child dispatch
+                                  functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER   Handle is invalid.
+  @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+IoTrapUnRegister (
+  IN CONST  EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL    *This,
+  IN EFI_HANDLE                                   DispatchHandle
+  );
+
+/**
+  This I/O Trap SMI handler invokes the ACPI reference code to handle the SMI.
+  It currently assumes it owns all of the IO trap SMI.
+
+  @param[in] DispatchHandle           Not used
+
+**/
+VOID
+EFIAPI
+IoTrapCallback (
+  IN  EFI_HANDLE                      DispatchHandle
+  );
+
+/**
+  Pause IoTrap callback function.
+
+  This function disables the SMI enable of IoTrap according to the DispatchHandle,
+  which is returned by IoTrap callback registration. It only supports the DispatchHandle
+  with MergeDisable TRUE and address not zero.
+
+  @param[in] This                 Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of the child service to change state.
+
+  @retval EFI_SUCCESS             This operation is complete.
+  @retval EFI_INVALID_PARAMETER   The DispatchHandle is invalid.
+  @retval EFI_ACCESS_DENIED       The SMI status is alrady PAUSED.
+**/
+EFI_STATUS
+EFIAPI
+IoTrapControlPause (
+  IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,
+  IN EFI_HANDLE                       DispatchHandle
+  );
+
+/**
+  Resume IoTrap callback function.
+
+  This function enables the SMI enable of IoTrap according to the DispatchHandle,
+  which is returned by IoTrap callback registration. It only supports the DispatchHandle
+  with MergeDisable TRUE and address not zero.
+
+  @param[in] This                 Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of the child service to change state.
+
+  @retval EFI_SUCCESS             This operation is complete.
+  @retval EFI_INVALID_PARAMETER   The DispatchHandle is invalid.
+  @retval EFI_ACCESS_DENIED       The SMI status is alrady RESUMED.
+**/
+EFI_STATUS
+EFIAPI
+IoTrapControlResume (
+  IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,
+  IN EFI_HANDLE                       DispatchHandle
+  );
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c
new file mode 100644
index 0000000000..affbe94eb7
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatch.c
@@ -0,0 +1,2442 @@
+/** @file
+  This function handle the register/unregister of PCH specific SMI events.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Library/SmiHandlerProfileLib.h>
+#include <Register/PchRegs.h>
+#include <Register/PchPcrRegs.h>
+#include <Register/PmcRegs.h>
+#include <Register/PchRegsLpc.h>
+#include <Register/SpiRegs.h>
+#include <Register/PchPcieRpRegs.h>
+#include <Register/PchRegsPsth.h>
+#include <Library/PchPciBdfLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <PchBdfAssignment.h>
+#include "PchSmiHelper.h"
+
+/**
+  The internal function used to create and insert a database record
+  for SMI record of Pch Smi types.
+
+  @param[in]  SrcDesc                   The pointer to the SMI source description
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  PchSmiType                Specific SMI type of PCH SMI
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+**/
+EFI_STATUS
+PchSmiRecordInsert (
+  IN  CONST PCH_SMM_SOURCE_DESC         *SrcDesc,
+  IN  PCH_SMI_CALLBACK_FUNCTIONS        DispatchFunction,
+  IN  PCH_SMI_TYPES                     PchSmiType,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       Record;
+
+  if (SrcDesc == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Record, sizeof (DATABASE_RECORD));
+  //
+  // Gather information about the registration request
+  //
+  Record.Signature                      = DATABASE_RECORD_SIGNATURE;
+  Record.PchSmiCallback                 = DispatchFunction;
+  Record.ProtocolType                   = PchSmiDispatchType;
+  Record.PchSmiType                     = PchSmiType;
+
+  CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));
+  Status = SmmCoreInsertRecord (
+             &Record,
+             DispatchHandle
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+
+//
+// TCO_STS bit that needs to be cleared
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mDescSrcTcoSts = {
+  PCH_SMM_NO_FLAGS,
+  {
+    NULL_BIT_DESC_INITIALIZER,
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_TCO
+    }
+  },
+  NULL_BIT_DESC_INITIALIZER
+};
+
+/**
+  Clear the TCO SMI status bit and block after the SMI handling is done
+
+  @param[in] SrcDesc                    Pointer to the PCH SMI source description table
+
+**/
+VOID
+EFIAPI
+PchTcoSmiClearSourceAndBlock (
+  CONST PCH_SMM_SOURCE_DESC             *SrcDesc
+  )
+{
+  PchSmmClearSourceAndBlock (SrcDesc);
+  //
+  // Any TCO-based status bits require special handling.
+  // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers
+  //
+  PchSmmClearSource (&mDescSrcTcoSts);
+}
+
+/**
+  Clear the TCO SMI status bit after the SMI handling is done
+
+  @param[in] SrcDesc                    Pointer to the PCH SMI source description table
+
+**/
+VOID
+EFIAPI
+PchTcoSmiClearSource (
+  CONST PCH_SMM_SOURCE_DESC             *SrcDesc
+  )
+{
+  PchSmmClearSource (SrcDesc);
+  //
+  // Any TCO-based status bits require special handling.
+  // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers
+  //
+  PchSmmClearSource (&mDescSrcTcoSts);
+}
+
+/**
+  Initialize Source descriptor structure
+
+   @param[in] SrcDesc                    Pointer to the PCH SMI source description table
+
+**/
+VOID
+EFIAPI
+NullInitSourceDesc (
+   PCH_SMM_SOURCE_DESC                   *SrcDesc
+   )
+{
+  ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));
+  SrcDesc->En[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
+  SrcDesc->En[1].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
+  SrcDesc->Sts[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
+  SrcDesc->PmcSmiSts.Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
+}
+
+//
+// Mch srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMch = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_STS}
+      },
+      S_TCO_IO_TCO1_STS,
+      N_TCO_IO_TCO1_STS_DMISMI
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  The register function used to register SMI handler of MCH event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiMchRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescMch,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiMchType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSource;
+    PchSmmClearSource (&Record->SrcDesc);
+    PchSmmEnableSource (&Record->SrcDesc);
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// TcoTimeout srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTcoTimeout = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_STS}
+      },
+      S_TCO_IO_TCO1_STS,
+      N_TCO_IO_TCO1_STS_TIMEOUT
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  The register function used to register SMI handler of TcoTimeout event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiTcoTimeoutRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescTcoTimeout,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiTcoTimeoutType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSource;
+    PchSmmClearSource (&Record->SrcDesc);
+    PchSmmEnableSource (&Record->SrcDesc);
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// OsTco srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescOsTco = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_STS}
+      },
+      S_TCO_IO_TCO1_STS,
+      N_TCO_IO_TCO1_STS_SW_TCO_SMI
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  The register function used to register SMI handler of OS TCO event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiOsTcoRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescOsTco,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiOsTcoType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSource;
+    PchSmmClearSource (&Record->SrcDesc);
+    PchSmmEnableSource (&Record->SrcDesc);
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// Nmi
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNmi = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_CNT}
+      },
+      S_TCO_IO_TCO1_CNT,
+      N_TCO_IO_TCO1_CNT_NMI2SMI_EN
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_STS}
+      },
+      S_TCO_IO_TCO1_STS,
+      N_TCO_IO_TCO1_STS_NMI2SMI
+    }
+  },
+  //
+  // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS.
+  //       So skip the top level status check and check the TCO1_STS directly.
+  //
+  NULL_BIT_DESC_INITIALIZER
+};
+
+/**
+  The register function used to register SMI handler of NMI event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiNmiRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescNmi,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiNmiType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSource;
+    PchSmmClearSource (&Record->SrcDesc);
+    PchSmmEnableSource (&Record->SrcDesc);
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// IntruderDetect srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIntruderDet = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO2_CNT}
+      },
+      S_TCO_IO_TCO2_CNT,
+      N_TCO_IO_TCO2_CNT_INTRD_SEL
+    }
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO2_STS}
+      },
+      S_TCO_IO_TCO2_STS,
+      N_TCO_IO_TCO2_STS_INTRD_DET
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  The register function used to register SMI handler of Intruder Detect event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiIntruderDetRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescIntruderDet,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiIntruderDetectType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSourceAndBlock;
+    PchSmmClearSource (&Record->SrcDesc);
+    PchSmmEnableSource (&Record->SrcDesc);
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// SpiBiosWp srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSpiBiosWp = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
+          R_SPI_CFG_BC
+        ) }
+      },
+      S_SPI_CFG_BC,
+      N_SPI_CFG_BC_BLE
+    },
+  },
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
+          R_SPI_CFG_BC
+        ) }
+      },
+      S_SPI_CFG_BC,
+      N_SPI_CFG_BC_SYNC_SS
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  Special handling for SPI Write Protect
+
+  @param[in]  SrcDesc   Not used
+**/
+VOID
+EFIAPI
+PchTcoSpiWpClearSource (
+  CONST PCH_SMM_SOURCE_DESC             *SrcDesc
+  )
+{
+  UINT64 SpiRegBase;
+  UINT32 BiosControl;
+  UINT32 Timeout;
+
+  SpiRegBase = SpiPciCfgBase ();
+  PciSegmentAndThenOr32 (
+    SpiRegBase + R_SPI_CFG_BC,
+    (UINT32) ~B_SPI_CFG_BC_ASYNC_SS,
+    B_SPI_CFG_BC_SYNC_SS
+    );
+  //
+  // Ensure the SYNC is cleared
+  //
+  Timeout = 1000;
+  do {
+    BiosControl = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC);
+    Timeout--;
+  } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0));
+
+  //
+  // Any TCO-based status bits require special handling.
+  // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers
+  //
+  PchSmmClearSource (&mDescSrcTcoSts);
+}
+
+/**
+  Set SMI_EN_TCO to enable TCO SMI.
+**/
+STATIC
+VOID
+PchSetSmiEnTco (
+  VOID
+  )
+{
+  IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, B_ACPI_IO_SMI_EN_TCO);
+}
+
+/**
+  The register function used to register SMI handler of BIOS write protect event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiSpiBiosWpRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescSpiBiosWp,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiSpiBiosWpType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSpiWpClearSource;
+    PchTcoSpiWpClearSource (NULL);
+    //
+    // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
+    // Only enable SMI_EN_TCO.
+    //
+    PchSetSmiEnTco ();
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// LpcBiosWp srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
+          R_LPC_CFG_BC
+        ) }
+      },
+      S_LPC_CFG_BC,
+      N_LPC_CFG_BC_LE
+    }
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_STS}
+      },
+      S_TCO_IO_TCO1_STS,
+      N_TCO_IO_TCO1_STS_BIOSWR
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  The register function used to register SMI handler of LPC BIOS write protect event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiLpcBiosWpRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  if (IsEspiEnabled ()) {
+    //
+    // Status is D31F0's PCBC.BWPDS
+    //
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescLpcBiosWp,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiLpcBiosWpType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSource;
+    PchSmmClearSource (&Record->SrcDesc);
+    //
+    // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
+    // Only enable SMI_EN_TCO.
+    //
+    PchSetSmiEnTco ();
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// NEWCENTURY_STS bit that needs to be cleared
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        TCO_ADDR_TYPE,
+        {R_TCO_IO_TCO1_STS}
+      },
+      S_TCO_IO_TCO1_STS,
+      N_TCO_IO_TCO1_STS_NEWCENTURY
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  The register function used to register SMI handler of NEW CENTURY event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiNewCenturyRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescNewCentury,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchTcoSmiNewCenturyType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchTcoSmiClearSourceAndBlock;
+    PchSmmClearSource (&Record->SrcDesc);
+    PchSmmEnableSource (&Record->SrcDesc);
+    SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                       Protocol instance pointer.
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchTcoSmiUnRegister (
+  IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  DATABASE_RECORD                       *Record;
+  EFI_STATUS                            Status;
+
+  Record = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
+      (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev == SpiDevNumber ()) &&
+      (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ()) &&
+      (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
+      (Record->SrcDesc.En[1].Bit == N_SPI_CFG_BC_BLE)) {
+    //
+    // SPI Write Protect cannot be disabled
+    //
+    return EFI_ACCESS_DENIED;
+  } else if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
+             (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev == LpcDevNumber ()) &&
+             (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc == LpcFuncNumber ()) &&
+             (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_LPC_CFG_BC) &&
+             (Record->SrcDesc.En[1].Bit == N_LPC_CFG_BC_LE)) {
+    //
+    // eSPI/LPC Write Protect cannot be disabled
+    //
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileUnregisterHandler (&gPchTcoSmiDispatchProtocolGuid, Record->Callback, NULL, 0);
+  }
+  return Status;
+}
+
+
+//
+// PcieRpHotPlug srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpHotPlugTemplate = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        {R_PCH_PCIE_CFG_MPC}
+      },
+      S_PCH_PCIE_CFG_MPC,
+      N_PCH_PCIE_CFG_MPC_HPME
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        {R_PCH_PCIE_CFG_SMSCS}
+      },
+      S_PCH_PCIE_CFG_SMSCS,
+      N_PCH_PCIE_CFG_SMSCS_HPPDM
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_PCI_EXP
+  }
+};
+
+/**
+  The register function used to register SMI handler of PCIE RP hotplug event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  RpIndex                   Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index.
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchPcieSmiHotPlugRegister (
+  IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
+  IN  UINTN                             RpIndex,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  UINTN                                 RpDev;
+  UINTN                                 RpFun;
+  PCH_SMM_PCIE_REGISTER_CONTEXT         Context;
+  DATABASE_RECORD                       *Record;
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+  GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
+
+  PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
+  PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
+  PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
+  PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
+
+  Status = PchSmiRecordInsert (
+             &PchPcieSmiRpHotPlugTemplate,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchPcieSmiRpHotplugType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpHotplugType;
+    Record->ChildContext.Pcie.RpIndex = RpIndex;
+    Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
+    SmiHandlerProfileRegisterHandler (
+      &gPchPcieSmiDispatchProtocolGuid,
+      (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
+      (UINTN)RETURN_ADDRESS (0),
+      &Context,
+      sizeof (Context)
+      );
+  }
+  PchSmmClearSource (&PchPcieSmiRpHotPlugTemplate);
+  PchSmmEnableSource (&PchPcieSmiRpHotPlugTemplate);
+
+  return Status;
+}
+
+//
+// PcieRpLinkActive srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpLinkActiveTemplate = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        {R_PCH_PCIE_CFG_MPC}
+      },
+      S_PCH_PCIE_CFG_MPC,
+      N_PCH_PCIE_CFG_MPC_HPME
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        {R_PCH_PCIE_CFG_SMSCS}
+      },
+      S_PCH_PCIE_CFG_SMSCS,
+      N_PCH_PCIE_CFG_SMSCS_HPLAS
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_PCI_EXP
+  }
+};
+
+/**
+  The register function used to register SMI handler of PCIE RP link active event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  RpIndex                   Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index.
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchPcieSmiLinkActiveRegister (
+  IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
+  IN  UINTN                             RpIndex,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  UINTN                                 RpDev;
+  UINTN                                 RpFun;
+  PCH_SMM_PCIE_REGISTER_CONTEXT         Context;
+  DATABASE_RECORD                       *Record;
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
+
+
+  PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
+  PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
+  PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
+  PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
+
+  Status = PchSmiRecordInsert (
+             &PchPcieSmiRpLinkActiveTemplate,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchPcieSmiRpLinkActiveType,
+             DispatchHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpLinkActiveType;
+    Record->ChildContext.Pcie.RpIndex = RpIndex;
+    Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
+    SmiHandlerProfileRegisterHandler (
+      &gPchPcieSmiDispatchProtocolGuid,
+      (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
+      (UINTN)RETURN_ADDRESS (0),
+      &Context,
+      sizeof (Context)
+      );
+  }
+  PchSmmClearSource (&PchPcieSmiRpLinkActiveTemplate);
+  PchSmmEnableSource (&PchPcieSmiRpLinkActiveTemplate);
+
+  return Status;
+}
+
+//
+// PcieRpLinkEq srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpLinkEqTemplate = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        {R_PCH_PCIE_CFG_EQCFG1}
+      },
+      S_PCH_PCIE_CFG_EQCFG1,
+      N_PCH_PCIE_CFG_EQCFG1_LERSMIE
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        {R_PCH_PCIE_CFG_SMSCS}
+      },
+      S_PCH_PCIE_CFG_SMSCS,
+      N_PCH_PCIE_CFG_SMSCS_LERSMIS
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_PCI_EXP
+  }
+};
+/**
+  The register function used to register SMI handler of PCIE RP Link Equalization Request event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  RpIndex                   Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index.
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchPcieSmiLinkEqRegister (
+  IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
+  IN  UINTN                             RpIndex,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  UINTN                                 RpDev;
+  UINTN                                 RpFun;
+  EFI_STATUS                            Status;
+  PCH_SMM_PCIE_REGISTER_CONTEXT         Context;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
+
+  //
+  // Patch the RP device number and function number of srcdesc.
+  //
+  PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
+  PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
+  PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
+  PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
+
+  Status = PchSmiRecordInsert (
+           &PchPcieSmiRpLinkEqTemplate,
+           (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+           PchPcieSmiRpLinkEqType,
+           DispatchHandle
+           );
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpLinkEqType;
+    Record->ChildContext.Pcie.RpIndex = RpIndex;
+    Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
+    SmiHandlerProfileRegisterHandler (
+      &gPchPcieSmiDispatchProtocolGuid,
+      (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,
+      (UINTN)RETURN_ADDRESS (0),
+      &Context,
+      sizeof (Context)
+      );
+  }
+  return Status;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                       Protocol instance pointer.
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchPcieSmiUnRegister (
+  IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  DATABASE_RECORD                       *RecordToDelete;
+  EFI_STATUS                            Status;
+
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+      SmiHandlerProfileUnregisterHandler (
+        &gPchPcieSmiDispatchProtocolGuid,
+        RecordToDelete->Callback,
+        &RecordToDelete->ChildContext,
+        sizeof (RecordToDelete->ContextSize)
+        );
+  }
+  return Status;
+}
+
+//
+// Pme srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPme = {
+  PCH_SMM_SCI_EN_DEPENDENT,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_GPE0_EN_127_96}
+      },
+      S_ACPI_IO_GPE0_EN_127_96,
+      N_ACPI_IO_GPE0_EN_127_96_PME
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_GPE0_STS_127_96}
+      },
+      S_ACPI_IO_GPE0_STS_127_96,
+      N_ACPI_IO_GPE0_STS_127_96_PME
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_GPE0
+  }
+};
+
+/**
+  The register function used to register SMI handler of PME event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiSmiPmeRegister (
+  IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescPme,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchAcpiSmiPmeType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescPme);
+  PchSmmEnableSource (&mSrcDescPme);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// PmeB0 srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPmeB0 = {
+  PCH_SMM_SCI_EN_DEPENDENT,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_GPE0_EN_127_96}
+      },
+      S_ACPI_IO_GPE0_EN_127_96,
+      N_ACPI_IO_GPE0_EN_127_96_PME_B0
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_GPE0_STS_127_96}
+      },
+      S_ACPI_IO_GPE0_STS_127_96,
+      N_ACPI_IO_GPE0_STS_127_96_PME_B0
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_GPE0
+  }
+};
+/**
+  The register function used to register SMI handler of PME B0 event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiSmiPmeB0Register (
+  IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescPmeB0,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchAcpiSmiPmeB0Type,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescPmeB0);
+  PchSmmEnableSource (&mSrcDescPmeB0);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// RtcAlarm srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescRtcAlarm = {
+  PCH_SMM_SCI_EN_DEPENDENT,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_PM1_EN}
+      },
+      S_ACPI_IO_PM1_EN,
+      N_ACPI_IO_PM1_EN_RTC
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_PM1_STS}
+      },
+      S_ACPI_IO_PM1_STS,
+      N_ACPI_IO_PM1_STS_RTC
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_PM1_STS_REG
+  }
+};
+
+/**
+  The register function used to register SMI handler of RTC alarm event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiSmiRtcAlarmRegister (
+  IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescRtcAlarm,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchAcpiSmiRtcAlarmType,
+             DispatchHandle
+             );
+
+  PchSmmClearSource (&mSrcDescRtcAlarm);
+  PchSmmEnableSource (&mSrcDescRtcAlarm);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// TmrOverflow srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTmrOverflow = {
+  PCH_SMM_SCI_EN_DEPENDENT,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_PM1_EN}
+      },
+      S_ACPI_IO_PM1_EN,
+      N_ACPI_IO_PM1_EN_TMROF
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_PM1_STS}
+      },
+      S_ACPI_IO_PM1_STS,
+      N_ACPI_IO_PM1_STS_TMROF
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_PM1_STS_REG
+  }
+};
+
+/**
+  The register function used to register SMI handler of Timer Overflow event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiSmiTmrOverflowRegister (
+  IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescTmrOverflow,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchAcpiSmiTmrOverflowType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescTmrOverflow);
+  PchSmmEnableSource (&mSrcDescTmrOverflow);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+
+  return Status;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                       Protocol instance pointer.
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiSmiUnRegister (
+  IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  DATABASE_RECORD                   *RecordToDelete;
+  EFI_STATUS                        Status;
+
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileUnregisterHandler (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0);
+  }
+  return Status;
+}
+
+//
+// SerialIrq srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq = {
+  PCH_SMM_NO_FLAGS,
+  {
+    NULL_BIT_DESC_INITIALIZER,
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_SERIRQ
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_SERIRQ
+  }
+};
+
+/**
+  The register function used to register SMI handler of Serial IRQ event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchSmiSerialIrqRegister (
+  IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescSerialIrq,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchSmiSerialIrqType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescSerialIrq);
+  PchSmmEnableSource (&mSrcDescSerialIrq);
+  if (!EFI_ERROR (Status)) {
+     SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// McSmi srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMcSmi = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_MCSMI
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_MCSMI
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_MCSMI
+  }
+};
+
+/**
+  The register function used to register SMI handler of MCSMI event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchSmiMcSmiRegister (
+  IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescMcSmi,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchSmiMcSmiType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescMcSmi);
+  PchSmmEnableSource (&mSrcDescMcSmi);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// SmBus srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSmbus = {
+  PCH_SMM_NO_FLAGS,
+  {
+    NULL_BIT_DESC_INITIALIZER,
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_SMBUS
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_SMBUS
+  }
+};
+
+/**
+  The register function used to register SMI handler of SMBUS event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchSmiSmbusRegister (
+  IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescSmbus,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchSmiSmBusType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescSmbus);
+  PchSmmEnableSource (&mSrcDescSmbus);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// SpiAsyncSmi srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSpiAsyncSmi = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
+          R_SPI_CFG_BC
+        ) }
+      },
+      S_SPI_CFG_BC,
+      N_SPI_CFG_BC_ASE_BWP
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
+          R_SPI_CFG_BC
+        ) }
+      },
+      S_SPI_CFG_BC,
+      N_SPI_CFG_BC_ASYNC_SS
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_SPI
+  }
+};
+
+/**
+  Special handling for SPI Asynchronous SMI.
+  If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done
+  transitions from 1 to 0 or when the SMI enable becomes false.
+
+  @param[in]  SrcDesc   Not used
+**/
+VOID
+EFIAPI
+PchSmiSpiAsyncClearSource (
+  CONST PCH_SMM_SOURCE_DESC             *SrcDesc
+  )
+{
+  UINT64                                SpiRegBase;
+  UINT32                                SpiBar0;
+
+  SpiRegBase = SpiPciCfgBase ();
+  SpiBar0 = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG_BAR0_MASK);
+  if (SpiBar0 != PCH_SPI_BASE_ADDRESS) {
+    //
+    // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE.
+    //
+    SpiBar0 = PCH_SPI_BASE_ADDRESS;
+    PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+    PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0);
+    PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+  }
+
+  MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE);
+}
+
+/**
+  Special handling to enable SPI Asynchronous SMI
+**/
+VOID
+PchSmiSpiAsyncEnableSource (
+  VOID
+  )
+{
+  UINT64 SpiRegBase;
+  UINT32 Data32And;
+  UINT32 Data32Or;
+
+  SpiRegBase = SpiPciCfgBase ();
+  Data32And = (UINT32) ~B_SPI_CFG_BC_SYNC_SS;
+  Data32Or = B_SPI_CFG_BC_ASE_BWP;
+
+  PciSegmentAndThenOr32 (
+    SpiRegBase + R_SPI_CFG_BC,
+    Data32And,
+    Data32Or
+    );
+  S3BootScriptSavePciCfgReadWrite (
+    S3BootScriptWidthUint32,
+    SpiRegBase + R_SPI_CFG_BC,
+    (VOID*) &Data32Or,
+    (VOID*) &Data32And
+    );
+
+  //
+  // Clear the source
+  //
+  PchSmiSpiAsyncClearSource (NULL);
+}
+
+/**
+  The register function used to register SMI handler of SPI Asynchronous event.
+
+  @param[in]  This                      The pointer to the protocol itself
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchSmiSpiAsyncRegister (
+  IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescSpiAsyncSmi,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchSmiSpiAsyncType,
+             DispatchHandle
+             );
+
+  if (!EFI_ERROR (Status)) {
+    Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
+    Record->ClearSource = PchSmiSpiAsyncClearSource;
+    PchSmiSpiAsyncClearSource (NULL);
+    PchSmiSpiAsyncEnableSource ();
+    SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                       Protocol instance pointer.
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+  @retval EFI_ACCESS_DENIED             Return access denied since SPI aync SMI handler is not able to disabled.
+**/
+EFI_STATUS
+EFIAPI
+PchSmiUnRegister (
+  IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  DATABASE_RECORD                       *Record;
+  UINT64                                SpiRegBase;
+  EFI_STATUS                            Status;
+
+  Record = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  if ((Record->SrcDesc.En[0].Reg.Type == PCIE_ADDR_TYPE) &&
+      (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev == SpiDevNumber ()) &&
+      (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ()) &&
+      (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
+      (Record->SrcDesc.En[0].Bit == N_SPI_CFG_BC_ASE_BWP)) {
+    SpiRegBase = SpiPciCfgBase ();
+    if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) {
+      //
+      // SPI Asynchronous SMI cannot be disabled
+      //
+      return EFI_ACCESS_DENIED;
+    }
+  }
+  Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, Record->Callback, NULL, 0);
+  }
+  return Status;
+}
+
+
+/**
+  Declaration of PCH TCO SMI DISPATCH PROTOCOL instance
+**/
+PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol = {
+  PCH_TCO_SMI_DISPATCH_REVISION,        // Revision
+  PchTcoSmiUnRegister,                  // Unregister
+  PchTcoSmiMchRegister,                 // Mch
+  PchTcoSmiTcoTimeoutRegister,          // TcoTimeout
+  PchTcoSmiOsTcoRegister,               // OsTco
+  PchTcoSmiNmiRegister,                 // Nmi
+  PchTcoSmiIntruderDetRegister,         // IntruderDectect
+  PchTcoSmiSpiBiosWpRegister,           // SpiBiosWp
+  PchTcoSmiLpcBiosWpRegister,           // LpcBiosWp
+  PchTcoSmiNewCenturyRegister           // NewCentury
+};
+
+/**
+  Declaration of PCH PCIE SMI DISPATCH PROTOCOL instance
+**/
+PCH_PCIE_SMI_DISPATCH_PROTOCOL mPchPcieSmiDispatchProtocol = {
+  PCH_PCIE_SMI_DISPATCH_REVISION,       // Revision
+  PchPcieSmiUnRegister,                 // Unregister
+  PchPcieSmiHotPlugRegister,            // PcieRpXHotPlug
+  PchPcieSmiLinkActiveRegister,         // PcieRpXLinkActive
+  PchPcieSmiLinkEqRegister              // PcieRpXLinkEq
+};
+
+/**
+  Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance
+**/
+PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol = {
+  PCH_ACPI_SMI_DISPATCH_REVISION,       // Revision
+  PchAcpiSmiUnRegister,                 // Unregister
+  PchAcpiSmiPmeRegister,                // Pme
+  PchAcpiSmiPmeB0Register,              // PmeB0
+  PchAcpiSmiRtcAlarmRegister,           // RtcAlarm
+  PchAcpiSmiTmrOverflowRegister         // TmrOverflow
+};
+
+/**
+  Declaration of MISC PCH SMI DISPATCH PROTOCOL instance
+**/
+PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol = {
+  PCH_SMI_DISPATCH_REVISION,            // Revision
+  PchSmiUnRegister,                     // Unregister
+  PchSmiSerialIrqRegister,              // SerialIrq
+  PchSmiMcSmiRegister,                  // McSmi
+  PchSmiSmbusRegister,                  // SmBus
+  PchSmiSpiAsyncRegister                // SpiAsync
+};
+
+/**
+  Install protocols of PCH specifics SMI types, including
+  PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types.
+
+  @retval                               the result of protocol installation
+**/
+EFI_STATUS
+InstallPchSmiDispatchProtocols (
+  VOID
+  )
+{
+  EFI_HANDLE                            Handle;
+  EFI_STATUS                            Status;
+
+  Handle = NULL;
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &Handle,
+                    &gPchTcoSmiDispatchProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mPchTcoSmiDispatchProtocol
+                    );
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &Handle,
+                    &gPchPcieSmiDispatchProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mPchPcieSmiDispatchProtocol
+                    );
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &Handle,
+                    &gPchAcpiSmiDispatchProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mPchAcpiSmiDispatchProtocol
+                    );
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &Handle,
+                    &gPchSmiDispatchProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mPchSmiDispatchProtocol
+                    );
+
+  return Status;
+}
+
+/**
+  The function to dispatch all callback function of PCH SMI types.
+
+  @retval EFI_SUCCESS                   Function successfully completed
+  @retval EFI_UNSUPPORTED               no
+**/
+EFI_STATUS
+PchSmiTypeCallbackDispatcher (
+  IN  DATABASE_RECORD                   *Record
+  )
+{
+  EFI_STATUS                            Status;
+  PCH_SMI_TYPES                         PchSmiType;
+  UINTN                                 RpIndex;
+  PCH_PCIE_SMI_RP_CONTEXT               RpContext;
+
+  PchSmiType = Record->PchSmiType;
+  Status     = EFI_SUCCESS;
+
+  switch (PchSmiType) {
+    case PchTcoSmiMchType:
+    case PchTcoSmiTcoTimeoutType:
+    case PchTcoSmiOsTcoType:
+    case PchTcoSmiNmiType:
+    case PchTcoSmiIntruderDetectType:
+    case PchTcoSmiSpiBiosWpType:
+    case PchTcoSmiLpcBiosWpType:
+    case PchTcoSmiNewCenturyType:
+      ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
+      break;
+    case PchPcieSmiRpHotplugType:
+    case PchPcieSmiRpLinkActiveType:
+    case PchPcieSmiRpLinkEqType:
+      RpContext.BusNum  = DEFAULT_PCI_BUS_NUMBER_PCH;
+      RpContext.DevNum  = (UINT8) Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev;
+      RpContext.FuncNum = (UINT8) Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc;
+      GetPcieRpNumber (RpContext.DevNum, RpContext.FuncNum, &RpIndex);
+      RpContext.RpIndex = (UINT8) RpIndex;
+      ((PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link, &RpContext);
+      break;
+    case PchAcpiSmiPmeType:
+    case PchAcpiSmiPmeB0Type:
+    case PchAcpiSmiRtcAlarmType:
+    case PchAcpiSmiTmrOverflowType:
+      ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
+      break;
+    case PchEspiSmiEspiSlaveType:
+      ((PCH_ESPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
+      break;
+    case PchSmiSerialIrqType:
+    case PchSmiMcSmiType:
+    case PchSmiSmBusType:
+    case PchSmiSpiAsyncType:
+    case PchIoTrapSmiType:                ///< internal type for IoTrap
+      ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
+      break;
+    default:
+      Status = EFI_UNSUPPORTED;
+      break;
+  }
+
+  return Status;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIoTrap[4] = {
+  //
+  // PCH I/O Trap register 0 monitor
+  //
+  {
+    PCH_SMM_NO_FLAGS,
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG0) }
+        },
+        4,
+        0
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
+        },
+        1,
+        0
+      }
+    },
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_MONITOR
+    }
+  },
+  //
+  // PCH I/O Trap register 1 monitor
+  //
+  {
+    PCH_SMM_NO_FLAGS,
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG1) }
+        },
+        4,
+        0
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
+        },
+        1,
+        1
+      }
+    },
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_MONITOR
+    }
+  },
+  //
+  // PCH I/O Trap register 2 monitor
+  //
+  {
+    PCH_SMM_NO_FLAGS,
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG2) }
+        },
+        4,
+        0
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
+        },
+        1,
+        2
+      }
+    },
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_MONITOR
+    }
+  },
+  //
+  // PCH I/O Trap register 3 monitor,
+  //
+  {
+    PCH_SMM_NO_FLAGS,
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG3) }
+        },
+        4,
+        0
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          PCR_ADDR_TYPE,
+          {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
+        },
+        1,
+        3
+      }
+    },
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_MONITOR
+    }
+  }
+};
+
+/**
+  The register function used to register SMI handler of IoTrap event.
+  This is internal function and only used by Iotrap module.
+
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  IoTrapIndex               Index number of IOTRAP register
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+**/
+EFI_STATUS
+PchInternalIoTrapSmiRegister (
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  IN  UINTN                             IoTrapIndex,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  Status = PchSmiRecordInsert (
+             &mSrcDescIoTrap[IoTrapIndex],
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchIoTrapSmiType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescIoTrap[IoTrapIndex]);
+  PchSmmEnableSource (&mSrcDescIoTrap[IoTrapIndex]);
+  return Status;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+**/
+EFI_STATUS
+PchInternalIoTrapSmiUnRegister (
+  IN  EFI_HANDLE                        DispatchHandle
+  )
+{
+  return PchSmmCoreUnRegister (NULL, DispatchHandle);
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf
new file mode 100644
index 0000000000..97ad2f457e
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatcher.inf
@@ -0,0 +1,116 @@
+## @file
+# Component description file for the Pch SMI Dispatch Handlers module
+#
+#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+INF_VERSION = 0x00010017
+BASE_NAME = PchSmiDispatcher
+FILE_GUID = B0D6ED53-B844-43f5-BD2F-61095264E77E
+VERSION_STRING = 1.0
+MODULE_TYPE = DXE_SMM_DRIVER
+PI_SPECIFICATION_VERSION = 1.10
+ENTRY_POINT = InitializePchSmmDispatcher
+
+
+[LibraryClasses]
+UefiBootServicesTableLib
+UefiDriverEntryPoint
+IoLib
+DebugLib
+PcdLib
+BaseLib
+BaseMemoryLib
+HobLib
+DevicePathLib
+PchCycleDecodingLib
+PchPcieRpLib
+PchPcrLib
+SmmServicesTableLib
+ReportStatusCodeLib
+PerformanceLib
+DxeServicesTableLib
+GpioLib
+GpioPrivateLib
+EspiLib
+S3BootScriptLib
+ConfigBlockLib
+PmcPrivateLib
+PmcLib
+SmiHandlerProfileLib
+CpuPcieRpLib
+PchPciBdfLib
+PmcPrivateLibWithS3
+CpuPcieInfoFruLib
+
+[Packages]
+MdePkg/MdePkg.dec
+TigerlakeSiliconPkg/SiPkg.dec
+
+
+[Pcd]
+# Progress Code for S3 Suspend start.
+# PROGRESS_CODE_S3_SUSPEND_START = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000000))    = 0x03078000
+gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart
+# Progress Code for S3 Suspend end.
+# PROGRESS_CODE_S3_SUSPEND_END   = (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001))    = 0x03078001
+gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd
+gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType
+
+
+[Sources]
+PchSmm.h
+PchSmmCore.c
+PchSmmHelpers.h
+PchSmmHelpers.c
+PchxSmmHelpers.h
+PchxSmmHelpers.c
+PchSmmUsb.c
+PchSmmGpi.c
+PchSmmPowerButton.c
+PchSmmSw.c
+PchSmmSx.c
+PchSmmPeriodicTimer.c
+IoTrap.c
+PchSmiDispatch.c
+PchSmmEspi.c
+PchSmiHelperClient.c
+
+
+[Protocols]
+gEfiPciRootBridgeIoProtocolGuid ## CONSUMES
+gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES
+gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES
+gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES
+gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES
+gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES
+gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES
+gEfiSmmBase2ProtocolGuid ## CONSUMES
+gEfiSmmCpuProtocolGuid ## CONSUMES
+gEfiSmmReadyToLockProtocolGuid ## CONSUMES
+gEfiSmmIoTrapDispatch2ProtocolGuid ## PRODUCES
+gPchSmmIoTrapControlGuid ## PRODUCES
+gPchTcoSmiDispatchProtocolGuid ## PRODUCES
+gPchPcieSmiDispatchProtocolGuid ## PRODUCES
+gPchAcpiSmiDispatchProtocolGuid ## PRODUCES
+gPchSmiDispatchProtocolGuid ## PRODUCES
+gPchEspiSmiDispatchProtocolGuid ## PRODUCES
+gPchSmmPeriodicTimerControlGuid ## PRODUCES
+gIoTrapExDispatchProtocolGuid ## PRODUCES
+gPchNvsAreaProtocolGuid ## CONSUMES
+
+
+[Guids]
+
+
+[Depex]
+gEfiPciRootBridgeIoProtocolGuid AND
+gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure that PCI MMIO resource has been prepared and available for this driver to allocate.
+gEfiSmmCpuProtocolGuid AND
+gEfiSmmBase2ProtocolGuid AND ## This is for SmmServicesTableLib
+gPchNvsAreaProtocolGuid
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h
new file mode 100644
index 0000000000..b224ee650c
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.h
@@ -0,0 +1,40 @@
+/** @file
+  PCH SMI Helper Header
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCH_SMI_HELPER_H_
+#define _PCH_SMI_HELPER_H_
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Get Root Port physical Number by CPU or PCH Pcie Root Port Device and Function Number
+
+  @param[in]  RpDev                 Root port device number.
+  @param[in]  RpFun                 Root port function number.
+  @param[out] RpNumber              Return corresponding physical Root Port index (0-based)
+**/
+VOID
+GetPcieRpNumber (
+  IN  UINTN   RpDev,
+  IN  UINTN   RpFun,
+  OUT UINTN   *RpNumber
+  );
+
+/**
+  Get CPU or PCH Pcie Root Port Device and Function Number by Root Port physical Number
+
+  @param[in]  RpNumber              Root port physical number. (0-based)
+  @param[out] RpDev                 Return corresponding root port device number.
+  @param[out] RpFun                 Return corresponding root port function number.
+**/
+VOID
+GetPcieRpDevFun (
+  IN  UINTN   RpIndex,
+  OUT UINTN   *RpDev,
+  OUT UINTN   *RpFun
+  );
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelperClient.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelperClient.c
new file mode 100644
index 0000000000..7693e76683
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelperClient.c
@@ -0,0 +1,57 @@
+/** @file
+  This file provides function to handle client-server differences.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Register/PmcRegs.h>
+#include <Register/PchPcieRpRegs.h>
+#include <Register/CpuPcieRegs.h>
+#include <Library/CpuPcieInfoFruLib.h>
+#include <Library/CpuPcieRpLib.h>
+#include <CpuPcieInfo.h>
+#include <Library/PchPcieRpLib.h>
+#include <Library/PchInfoLib.h>
+#include <Library/PchPciBdfLib.h>
+
+/**
+  Get Root Port physical Number by CPU or PCH Pcie Root Port Device and Function Number
+
+  @param[in]  RpDev                 Root port device number.
+  @param[in]  RpFun                 Root port function number.
+  @param[out] RpNumber              Return corresponding physical Root Port index (0-based)
+**/
+VOID
+GetPcieRpNumber (
+  IN  UINTN   RpDev,
+  IN  UINTN   RpFun,
+  OUT UINTN   *RpNumber
+  )
+{
+  UINT64  RpBase;
+  RpBase = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, RpDev, RpFun, 0);
+  GetPchPcieRpNumber (RpDev, RpFun, RpNumber);
+}
+
+/**
+  Get CPU or PCH Pcie Root Port Device and Function Number by Root Port physical Number
+
+  @param[in]  RpNumber              Root port physical number. (0-based)
+  @param[out] RpDev                 Return corresponding root port device number.
+  @param[out] RpFun                 Return corresponding root port function number.
+**/
+VOID
+GetPcieRpDevFun (
+  IN  UINTN   RpIndex,
+  OUT UINTN   *RpDev,
+  OUT UINTN   *RpFun
+  )
+{
+  if (RpIndex >= CpuRpIndex0 && RpIndex <= CpuRpIndex3) {
+    GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun);
+  } else {
+    *RpDev = PchPcieRpDevNumber (RpIndex);
+    *RpFun = PchPcieRpFuncNumber (RpIndex);
+  }
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h
new file mode 100644
index 0000000000..6a23de2bc9
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h
@@ -0,0 +1,1043 @@
+/** @file
+  Prototypes and defines for the PCH SMM Dispatcher.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _PCH_SMM_H_
+#define _PCH_SMM_H_
+
+#include <Uefi.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SmmControl2.h>
+#include <Protocol/SmmUsbDispatch2.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmGpiDispatch2.h>
+#include <Protocol/SmmPowerButtonDispatch2.h>
+#include <Protocol/SmmPeriodicTimerDispatch2.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PerformanceLib.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <IndustryStandard/Pci30.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PchPcieRpLib.h>
+#include <Library/PchPcrLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/GpioLib.h>
+#include <Library/PchInfoLib.h>
+#include <Library/EspiLib.h>
+#include <Library/GpioPrivateLib.h>
+#include <Protocol/PchTcoSmiDispatch.h>
+#include <Protocol/PchPcieSmiDispatch.h>
+#include <Protocol/PchAcpiSmiDispatch.h>
+#include <Protocol/PchSmiDispatch.h>
+#include <Protocol/PchEspiSmiDispatch.h>
+#include <Protocol/IoTrapExDispatch.h>
+#include <Library/PmcLib.h>
+#include "IoTrap.h"
+
+#define EFI_BAD_POINTER          0xAFAFAFAFAFAFAFAFULL
+
+extern BOOLEAN                   mReadyToLock;
+
+///
+/// Define an enumeration for all the supported protocols
+///
+#define PCH_SMM_PROTOCOL_TYPE_MAX       6
+
+typedef enum {
+  UsbType,
+  SxType,
+  SwType,
+  GpiType,
+  PowerButtonType,
+  PeriodicTimerType,
+  PchSmiDispatchType,
+  PchSmmProtocolTypeMax
+} PCH_SMM_PROTOCOL_TYPE;
+
+///
+/// Define all the supported types of PCH SMI
+///
+typedef enum {
+  PchTcoSmiMchType,
+  PchTcoSmiTcoTimeoutType,
+  PchTcoSmiOsTcoType,
+  PchTcoSmiNmiType,
+  PchTcoSmiIntruderDetectType,
+  PchTcoSmiSpiBiosWpType,
+  PchTcoSmiLpcBiosWpType,
+  PchTcoSmiNewCenturyType,
+  PchPcieSmiRpHotplugType,
+  PchPcieSmiRpLinkActiveType,
+  PchPcieSmiRpLinkEqType,
+  PchAcpiSmiPmeType,
+  PchAcpiSmiPmeB0Type,
+  PchAcpiSmiRtcAlarmType,
+  PchAcpiSmiTmrOverflowType,
+  PchEspiSmiEspiSlaveType,
+  PchSmiSerialIrqType,
+  PchSmiMcSmiType,
+  PchSmiSmBusType,
+  PchSmiSpiAsyncType,
+  PchIoTrapSmiType                      ///< internal SMI type
+} PCH_SMI_TYPES;
+
+///
+/// Generic funciton pointer to cover all Pch SMI function pointer types
+///
+typedef
+VOID
+(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) (
+  IN EFI_HANDLE                         DispatchHandle,
+  ...
+  );
+
+
+///
+/// SPECIFYING A REGISTER
+/// We want a general way of referring to addresses.  For this case, we'll only
+/// need addresses in the ACPI table (and the TCO entries within the ACPI table).
+/// However, it's interesting to consider what it would take to support other types
+/// of addresses.  To address Will's concern, I think it prudent to accommodate it
+/// early on in the design.
+///
+/// Addresses we need to consider:
+///
+///  Type:                           Required:
+///  I/O                             Yes
+///    ACPI (special case of I/O)    Only if we want to
+///    TCO  (special case of I/O)    Only if we want to
+///  GPIO  (special case of MMIO)    Only if we want to
+///  Memory (or Memory Mapped I/O)   Only if we want to
+///  PCIE                            Yes, for BiosWp
+///
+typedef enum {
+  ///
+  ///  IO_ADDR_TYPE, /// unimplemented
+  ///
+  ACPI_ADDR_TYPE,
+  TCO_ADDR_TYPE,
+  ///
+  ///  MEMORY_ADDR_TYPE, /// unimplemented
+  ///
+  GPIO_ADDR_TYPE,
+  MEMORY_MAPPED_IO_ADDRESS_TYPE,
+  PCIE_ADDR_TYPE,
+  PCR_ADDR_TYPE,
+  NUM_ADDR_TYPES,                     ///< count of items in this enum
+  PCH_SMM_ADDR_TYPE_NULL        = -1  ///< sentinel to indicate NULL or to signal end of arrays
+} ADDR_TYPE;
+
+//
+// Assumption: 32-bits -- enum's evaluate to integer
+// Assumption: This code will only run on IA-32.  Justification: IA-64 doesn't have SMIs.
+// We don't have to worry about 64-bit addresses.
+// Typedef the size of addresses in case the numbers I'm using are wrong or in case
+// this changes.  This is a good idea because PCI_ADDR will change, for example, when
+// we add support for PciExpress.
+//
+typedef UINT16 IO_ADDR;
+typedef IO_ADDR ACPI_ADDR;  ///< can omit
+typedef IO_ADDR TCO_ADDR;   ///< can omit
+typedef UINTN MEM_ADDR;
+typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS;
+typedef MEM_ADDR *GPIO_ADDR;
+typedef union {
+  UINT32  Raw;
+  struct {
+    UINT32 Reg: 16;
+    UINT32 Fnc: 3;
+    UINT32 Dev: 5;
+    UINT32 Bus: 8;
+  } Fields;
+} PCIE_ADDR;
+
+typedef union {
+  UINT32  Raw;
+  struct {
+    UINT16 Offset;
+    UINT8  Pid;
+    UINT8  Base;
+  } Fields;
+} PCR_ADDR;
+
+typedef struct {
+  ADDR_TYPE Type;
+  union {
+    ///
+    /// used to initialize during declaration/definition
+    ///
+    UINT32                    raw;
+
+    ///
+    /// used to access useful data
+    ///
+    IO_ADDR                   io;
+    ACPI_ADDR                 acpi;
+    TCO_ADDR                  tco;
+    GPIO_ADDR                 gpio;
+    MEM_ADDR                  mem;
+    MEMORY_MAPPED_IO_ADDRESS  Mmio;
+    PCIE_ADDR                 pcie;
+    PCR_ADDR                  Pcr;
+
+  } Data;
+
+} PCH_SMM_ADDRESS;
+
+///
+/// SPECIFYING BITS WITHIN A REGISTER
+/// Here's a struct that helps us specify a source or enable bit.
+///
+typedef struct {
+  PCH_SMM_ADDRESS Reg;
+  UINT8           SizeInBytes;  ///< of the register
+  UINT8           Bit;
+} PCH_SMM_BIT_DESC;
+
+//
+// Sometimes, we'll have bit descriptions that are unused.  It'd be great to have a
+// way to easily identify them:
+//
+#define IS_BIT_DESC_NULL(BitDesc)   ((BitDesc).Reg.Type == PCH_SMM_ADDR_TYPE_NULL)  ///< "returns" true when BitDesc is NULL
+#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = PCH_SMM_ADDR_TYPE_NULL)   ///< will "return" an integer w/ value of 0
+#define NULL_BIT_DESC_INITIALIZER \
+  { \
+    { \
+      PCH_SMM_ADDR_TYPE_NULL, \
+      { \
+        0 \
+      } \
+    }, \
+    0, 0 \
+  }
+//
+// I'd like a type to specify the callback's Sts & En bits because they'll
+// be commonly used together:
+//
+#define NUM_EN_BITS   2
+#define NUM_STS_BITS  1
+
+//
+// Flags
+//
+typedef UINT8 PCH_SMM_SOURCE_FLAGS;
+
+//
+// Flags required to describe the event source
+//
+#define PCH_SMM_NO_FLAGS          0
+#define PCH_SMM_SCI_EN_DEPENDENT  1
+
+typedef struct {
+  PCH_SMM_SOURCE_FLAGS  Flags;
+  PCH_SMM_BIT_DESC      En[NUM_EN_BITS];    ///< Describes the enable bit(s) for the SMI event
+  PCH_SMM_BIT_DESC      Sts[NUM_STS_BITS];  ///< Describes the secondary status bit for the SMI event. Might be the same as TopLevelSmi
+  PCH_SMM_BIT_DESC      PmcSmiSts;          ///< Refereing to the top level status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS
+} PCH_SMM_SOURCE_DESC;
+
+///
+/// Used to initialize null source descriptor
+///
+#define NULL_SOURCE_DESC_INITIALIZER \
+  { \
+    PCH_SMM_NO_FLAGS, \
+    { \
+      NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \
+    }, \
+    { \
+      NULL_BIT_DESC_INITIALIZER \
+    }, \
+    NULL_BIT_DESC_INITIALIZER \
+  }
+
+///
+/// Define a PCIE RP event context for SmiProfileHandlerInfo tool
+///
+typedef struct {
+  PCH_SMI_TYPES               PchSmiType;
+  UINTN                       RpIndex;
+} PCH_SMM_PCIE_REGISTER_CONTEXT;
+
+///
+/// CHILD CONTEXTS
+/// To keep consistent w/ the architecture, we'll need to provide the context
+/// to the child when we call its callback function.  After talking with Will,
+/// we agreed that we'll need functions to "dig" the context out of the hardware
+/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those
+/// contexts to prevent unnecessary dispatches.  I'd like a general type for these
+/// "GetContext" functions, so I'll need a union of all the protocol contexts for
+/// our internal use:
+///
+typedef union {
+  //
+  // (in no particular order)
+  //
+  EFI_SMM_SX_REGISTER_CONTEXT             Sx;
+  EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
+  EFI_SMM_SW_REGISTER_CONTEXT             Sw;
+  EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT   PowerButton;
+  EFI_SMM_USB_REGISTER_CONTEXT            Usb;
+  EFI_SMM_GPI_REGISTER_CONTEXT            Gpi;
+  PCH_SMM_PCIE_REGISTER_CONTEXT           Pcie;
+} PCH_SMM_CONTEXT;
+
+///
+/// Misc data for PchDispatcher usage.
+/// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII,
+/// and PchDispatcher needs it for every record. Thus move it here to support ElapsedTime.
+///
+typedef struct {
+  UINTN    ElapsedTime;
+  ///
+  /// A switch to control periodic timer SMI enabling
+  ///
+  BOOLEAN  TimerSmiEnabled;
+} PCH_SMM_MISC_DATA;
+
+//
+// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes
+//
+typedef struct _DATABASE_RECORD DATABASE_RECORD;
+
+///
+/// Assumption: the GET_CONTEXT function will be as small and simple as possible.
+/// Assumption: We don't need to pass in an enumeration for the protocol because each
+///    GET_CONTEXT function is written for only one protocol.
+/// We also need a function to compare contexts to see if the child should be dispatched
+/// In addition, we need a function to acquire CommBuffer and CommBufferSize for
+///    dispatch callback function of EDKII native support.
+///
+typedef
+VOID
+(EFIAPI *GET_CONTEXT) (
+  IN  DATABASE_RECORD    * Record,
+  OUT PCH_SMM_CONTEXT    * Context
+  );
+
+typedef
+BOOLEAN
+(EFIAPI *CMP_CONTEXT) (
+  IN PCH_SMM_CONTEXT     * Context1,
+  IN PCH_SMM_CONTEXT     * Context2
+  );
+
+typedef
+VOID
+(EFIAPI *GET_COMMBUFFER) (
+  IN  DATABASE_RECORD    * Record,
+  OUT VOID               **CommBuffer,
+  OUT UINTN              * CommBufferSize
+  );
+
+///
+/// Finally, every protocol will require a "Get Context" and "Compare Context" call, so
+/// we may as well wrap that up in a table, too.
+///
+typedef struct {
+  GET_CONTEXT     GetContext;
+  CMP_CONTEXT     CmpContext;
+  GET_COMMBUFFER  GetCommBuffer;
+} CONTEXT_FUNCTIONS;
+
+extern CONTEXT_FUNCTIONS          ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX];
+
+///
+/// MAPPING CONTEXT TO BIT DESCRIPTIONS
+/// I'd like to have a general approach to mapping contexts to bit descriptions.
+/// Sometimes, we'll find that we can use table lookups or constant assignments;
+/// other times, we'll find that we'll need to use a function to perform the mapping.
+/// If we define a macro to mask that process, we'll never have to change the code.
+/// I don't know if this is desirable or not -- if it isn't, then we can get rid
+/// of the macros and just use function calls or variable assignments.  Doesn't matter
+/// to me.
+/// Mapping complex contexts requires a function
+///
+
+/**
+  Maps a USB context to a source description.
+
+  @param[in] Context              The context we need to map.  Type must be USB.
+  @param[out] SrcDesc             The source description that corresponds to the given context.
+
+**/
+VOID
+MapUsbToSrcDesc (
+  IN  PCH_SMM_CONTEXT         *Context,
+  OUT PCH_SMM_SOURCE_DESC     *SrcDesc
+  );
+
+/**
+  Figure out which timer the child is requesting and
+  send back the source description
+
+  @param[in] DispatchContext      The pointer to the Dispatch Context instances
+  @param[out] SrcDesc             The pointer to the source description
+
+**/
+VOID
+MapPeriodicTimerToSrcDesc (
+  IN  PCH_SMM_CONTEXT                                         *DispatchContext,
+  OUT PCH_SMM_SOURCE_DESC                                     *SrcDesc
+  );
+
+//
+// Mapping simple contexts can be done by assignment or lookup table
+//
+extern CONST PCH_SMM_SOURCE_DESC  mSxSourceDesc;
+extern CONST PCH_SMM_SOURCE_DESC  mPowerButtonSourceDesc;
+extern CONST PCH_SMM_SOURCE_DESC  mSrcDescNewCentury;
+extern CONST PCH_SMM_SOURCE_DESC  mGpiSourceDescTemplate;
+
+///
+/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
+///
+#define MAXIMUM_SWI_VALUE 0xFF
+///
+/// Open: Need to make sure this kind of type cast will actually work.
+///   May need an intermediate form w/ two VOID* arguments.  I'll figure
+///   that out when I start compiling.
+///
+typedef
+VOID
+(EFIAPI *PCH_SMM_CLEAR_SOURCE) (
+  CONST PCH_SMM_SOURCE_DESC * SrcDesc
+  );
+
+///
+/// "DATABASE" RECORD
+/// Linked list data structures
+///
+#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
+
+struct _DATABASE_RECORD {
+  UINT32                        Signature;
+  LIST_ENTRY                    Link;
+  BOOLEAN                       Processed;
+  ///
+  /// Status and Enable bit description
+  ///
+  PCH_SMM_SOURCE_DESC           SrcDesc;
+
+  ///
+  /// Callback function
+  ///
+  EFI_SMM_HANDLER_ENTRY_POINT2  Callback;
+  PCH_SMM_CONTEXT               ChildContext;
+  UINTN                         ContextSize;
+
+  ///
+  /// Special handling hooks -- init them to NULL if unused/unneeded
+  ///
+  PCH_SMM_CLEAR_SOURCE          ClearSource;
+
+  ///
+  /// Functions required to make callback code general
+  ///
+  CONTEXT_FUNCTIONS             ContextFunctions;
+
+  ///
+  /// The protocol that this record dispatches
+  ///
+  PCH_SMM_PROTOCOL_TYPE         ProtocolType;
+
+  ///
+  /// Misc data for private usage
+  ///
+  PCH_SMM_MISC_DATA             MiscData;
+
+  ///
+  /// PCH SMI callback function
+  ///
+  PCH_SMI_CALLBACK_FUNCTIONS    PchSmiCallback;
+  ///
+  /// Indicate the PCH SMI types.
+  ///
+  PCH_SMI_TYPES                 PchSmiType;
+};
+
+#define DATABASE_RECORD_FROM_LINK(_record)  CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
+#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record)  CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)
+
+///
+/// HOOKING INTO THE ARCHITECTURE
+///
+typedef
+EFI_STATUS
+(EFIAPI *PCH_SMM_GENERIC_REGISTER) (
+  IN  VOID                                    **This,
+  IN  VOID                                    *DispatchFunction,
+  IN  VOID                                    *DispatchContext,
+  OUT EFI_HANDLE                              *DispatchHandle
+  );
+typedef
+EFI_STATUS
+(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) (
+  IN  VOID                                    **This,
+  IN  EFI_HANDLE                              DispatchHandle
+  );
+
+///
+/// Define a memory "stamp" equivalent in size and function to most of the protocols
+///
+typedef struct {
+  PCH_SMM_GENERIC_REGISTER    Register;
+  PCH_SMM_GENERIC_UNREGISTER  Unregister;
+  UINTN                       Extra1;
+  UINTN                       Extra2; ///< may not need this one
+} PCH_SMM_GENERIC_PROTOCOL;
+
+/**
+  Register a child SMI dispatch function with a parent SMM driver.
+
+  @param[in] This                 Pointer to the PCH_SMM_GENERIC_PROTOCOL instance.
+  @param[in] DispatchFunction     Pointer to dispatch function to be invoked for this SMI source.
+  @param[in] DispatchContext      Pointer to the dispatch function's context.
+  @param[out] DispatchHandle      Handle of dispatch function, for when interfacing
+                                  with the parent SMM driver, will be the address of linked
+                                  list link in the call back record.
+
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to create database record
+  @retval EFI_INVALID_PARAMETER   The input parameter is invalid
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  registered and the SMI source has been enabled.
+**/
+EFI_STATUS
+EFIAPI
+PchPiSmmCoreRegister (
+  IN  PCH_SMM_GENERIC_PROTOCOL                          *This,
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2                      DispatchFunction,
+  IN  PCH_SMM_CONTEXT                                   *DispatchContext,
+  OUT EFI_HANDLE                                        *DispatchHandle
+  );
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                       Protocol instance pointer.
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchPiSmmCoreUnRegister (
+  IN PCH_SMM_GENERIC_PROTOCOL                           *This,
+  IN EFI_HANDLE                                         *DispatchHandle
+  );
+
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver.
+
+  @param[in] This                 Pointer to the PCH_SMM_GENERIC_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  unregistered and the SMI source has been disabled
+                                  if there are no other registered child dispatch
+                                  functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER   Handle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+PchSmmCoreUnRegister (
+  IN  PCH_SMM_GENERIC_PROTOCOL                         *This,
+  IN  EFI_HANDLE                                       *DispatchHandle
+  );
+
+typedef union {
+  PCH_SMM_GENERIC_PROTOCOL                    Generic;
+  EFI_SMM_USB_DISPATCH2_PROTOCOL              Usb;
+  EFI_SMM_SX_DISPATCH2_PROTOCOL               Sx;
+  EFI_SMM_SW_DISPATCH2_PROTOCOL               Sw;
+  EFI_SMM_GPI_DISPATCH2_PROTOCOL              Gpi;
+  EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL     PowerButton;
+  EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL   PeriodicTimer;
+} PCH_SMM_PROTOCOL;
+
+///
+/// Define a structure to help us identify the generic protocol
+///
+#define PROTOCOL_SIGNATURE  SIGNATURE_32 ('P', 'R', 'O', 'T')
+
+typedef struct {
+  UINTN                 Signature;
+
+  PCH_SMM_PROTOCOL_TYPE Type;
+  EFI_GUID              *Guid;
+  PCH_SMM_PROTOCOL      Protocols;
+} PCH_SMM_QUALIFIED_PROTOCOL;
+
+#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
+  CR ( \
+  _generic, \
+  PCH_SMM_QUALIFIED_PROTOCOL, \
+  Protocols, \
+  PROTOCOL_SIGNATURE \
+  )
+
+///
+/// Create private data for the protocols that we'll publish
+///
+typedef struct {
+  LIST_ENTRY                  CallbackDataBase;
+  EFI_HANDLE                  SmiHandle;
+  EFI_HANDLE                  InstallMultProtHandle;
+  PCH_SMM_QUALIFIED_PROTOCOL  Protocols[PCH_SMM_PROTOCOL_TYPE_MAX];
+} PRIVATE_DATA;
+
+extern PRIVATE_DATA           mPrivateData;
+extern UINT16                 mAcpiBaseAddr;
+extern UINT16                 mTcoBaseAddr;
+
+/**
+  The internal function used to create and insert a database record
+
+  @param[in]  InsertRecord              Record to insert to database.
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+**/
+EFI_STATUS
+SmmCoreInsertRecord (
+  IN  DATABASE_RECORD                   *NewRecord,
+  OUT EFI_HANDLE                        *DispatchHandle
+  );
+
+/**
+  Get the Sleep type
+
+  @param[in] Record               No use
+  @param[out] Context             The context that includes SLP_TYP bits to be filled
+**/
+VOID
+EFIAPI
+SxGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT PCH_SMM_CONTEXT    *Context
+  );
+
+/**
+  Register a child SMI source dispatch function for the specified software SMI.
+
+  This service registers a function (DispatchFunction) which will be called when the software
+  SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return,
+  DispatchHandle contains a unique handle which may be used later to unregister the function
+  using UnRegister().
+
+  @param[in]  This                 Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
+  @param[in]  DispatchFunction     Function to register for handler when the specified software
+                                   SMI is generated.
+  @param[in, out] RegisterContext  Pointer to the dispatch function's context.
+                                   The caller fills this context in before calling
+                                   the register function to indicate to the register
+                                   function which Software SMI input value the
+                                   dispatch function should be invoked for.
+  @param[out] DispatchHandle       Handle generated by the dispatcher to track the
+                                   function instance.
+
+  @retval EFI_SUCCESS            The dispatch function has been successfully
+                                 registered and the SMI source has been enabled.
+  @retval EFI_DEVICE_ERROR       The SW driver was unable to enable the SMI source.
+  @retval EFI_INVALID_PARAMETER  RegisterContext is invalid. The SW SMI input value
+                                 is not within a valid range or is already in use.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough memory (system or SMM) to manage this
+                                 child.
+  @retval EFI_OUT_OF_RESOURCES   A unique software SMI value could not be assigned
+                                 for this dispatch.
+**/
+EFI_STATUS
+EFIAPI
+PchSwSmiRegister (
+  IN  EFI_SMM_SW_DISPATCH2_PROTOCOL       *This,
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2        DispatchFunction,
+  IN  EFI_SMM_SW_REGISTER_CONTEXT         *DispatchContext,
+  OUT EFI_HANDLE                          *DispatchHandle
+  );
+
+/**
+  Unregister a child SMI source dispatch function for the specified software SMI.
+
+  This service removes the handler associated with DispatchHandle so that it will no longer be
+  called in response to a software SMI.
+
+  @param[in] This                Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchHandle      Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS            The dispatch function has been successfully unregistered.
+  @retval EFI_INVALID_PARAMETER  The DispatchHandle was not valid.
+**/
+EFI_STATUS
+EFIAPI
+PchSwSmiUnRegister (
+  IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL  *This,
+  IN       EFI_HANDLE                     DispatchHandle
+  );
+
+/**
+  Init required protocol for Pch Sw Dispatch protocol.
+**/
+VOID
+PchSwDispatchInit (
+  VOID
+  );
+
+/**
+  Check whether sleep type of two contexts match
+
+  @param[in] Context1             Context 1 that includes sleep type 1
+  @param[in] Context2             Context 2 that includes sleep type 2
+
+  @retval FALSE                   Sleep types match
+  @retval TRUE                    Sleep types don't match
+**/
+BOOLEAN
+EFIAPI
+SxCmpContext (
+  IN PCH_SMM_CONTEXT     *Context1,
+  IN PCH_SMM_CONTEXT     *Context2
+  );
+
+/**
+  Update the elapsed time from the Interval data of DATABASE_RECORD
+
+  @param[in] Record               The pointer to the DATABASE_RECORD.
+  @param[out] HwContext           The Context to be updated.
+**/
+VOID
+EFIAPI
+PeriodicTimerGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT PCH_SMM_CONTEXT    *Context
+  );
+
+/**
+  Check whether Periodic Timer of two contexts match
+
+  @param[in] Context1             Context 1 that includes Periodic Timer  1
+  @param[in] Context2             Context 2 that includes Periodic Timer  2
+
+  @retval FALSE                   Periodic Timer match
+  @retval TRUE                    Periodic Timer don't match
+**/
+BOOLEAN
+EFIAPI
+PeriodicTimerCmpContext (
+  IN PCH_SMM_CONTEXT     *Context1,
+  IN PCH_SMM_CONTEXT     *Context2
+  );
+
+/**
+  Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
+
+  @param[in]  Record              No use
+  @param[out] CommBuffer          Point to the CommBuffer structure
+  @param[out] CommBufferSize      Point to the Size of CommBuffer structure
+**/
+VOID
+EFIAPI
+PeriodicTimerGetCommBuffer (
+  IN  DATABASE_RECORD    *Record,
+  OUT VOID               **CommBuffer,
+  OUT UINTN              *CommBufferSize
+  );
+
+/**
+  Get the power button status.
+
+  @param[in] Record               The pointer to the DATABASE_RECORD.
+  @param[out] Context             Calling context from the hardware, will be updated with the current power button status.
+**/
+VOID
+EFIAPI
+PowerButtonGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT PCH_SMM_CONTEXT    *Context
+  );
+
+/**
+  Check whether Power Button status of two contexts match
+
+  @param[in] Context1             Context 1 that includes Power Button status 1
+  @param[in] Context2             Context 2 that includes Power Button status 2
+
+  @retval FALSE                   Power Button status match
+  @retval TRUE                    Power Button status don't match
+**/
+BOOLEAN
+EFIAPI
+PowerButtonCmpContext (
+  IN PCH_SMM_CONTEXT     *Context1,
+  IN PCH_SMM_CONTEXT     *Context2
+  );
+
+/**
+  This function is responsible for calculating and enabling any timers that are required
+  to dispatch messages to children. The SrcDesc argument isn't acutally used.
+
+  @param[in] SrcDesc              Pointer to the PCH_SMM_SOURCE_DESC instance.
+**/
+VOID
+EFIAPI
+PchSmmPeriodicTimerClearSource (
+  IN CONST PCH_SMM_SOURCE_DESC    *SrcDesc
+  );
+
+/**
+  This services returns the next SMI tick period that is supported by the chipset.
+  The order returned is from longest to shortest interval period.
+
+  @param[in] This                 Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
+  @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child.
+
+  @retval EFI_SUCCESS             The service returned successfully.
+  @retval EFI_INVALID_PARAMETER   The parameter SmiTickInterval is invalid.
+**/
+EFI_STATUS
+PchSmmPeriodicTimerDispatchGetNextShorterInterval (
+  IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL    *This,
+  IN OUT UINT64                                         **SmiTickInterval
+  );
+
+/**
+  Install PCH SMM periodic timer control protocol
+
+  @param[in] Handle                     handle for this driver
+
+  @retval EFI_SUCCESS                   Driver initialization completed successfully
+**/
+EFI_STATUS
+EFIAPI
+InstallPchSmmPeriodicTimerControlProtocol (
+  IN EFI_HANDLE                         Handle
+  );
+
+/**
+  When we get an SMI that indicates that we are transitioning to a sleep state,
+  we need to actually transition to that state.  We do this by disabling the
+  "SMI on sleep enable" feature, which generates an SMI when the operating system
+  tries to put the system to sleep, and then physically putting the system to sleep.
+**/
+VOID
+PchSmmSxGoToSleep (
+  VOID
+  );
+
+/**
+  Install protocols of PCH specifics SMI types, including
+  PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types.
+
+  @retval                               the result of protocol installation
+**/
+EFI_STATUS
+InstallPchSmiDispatchProtocols (
+  VOID
+  );
+
+/**
+  The function to dispatch all callback function of PCH SMI types.
+
+  @retval EFI_SUCCESS                   Function successfully completed
+  @retval EFI_UNSUPPORTED               no
+**/
+EFI_STATUS
+PchSmiTypeCallbackDispatcher (
+  IN  DATABASE_RECORD                   *Record
+  );
+
+/**
+  The register function used to register SMI handler of IoTrap event.
+  This is internal function and only used by Iotrap module.
+
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  IoTrapIndex               Index number of IOTRAP register
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+**/
+EFI_STATUS
+PchInternalIoTrapSmiRegister (
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  IN  UINTN                             IoTrapIndex,
+  OUT EFI_HANDLE                        *DispatchHandle
+  );
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+**/
+EFI_STATUS
+PchInternalIoTrapSmiUnRegister (
+  IN  EFI_HANDLE                        DispatchHandle
+  );
+
+/**
+  Register an eSPI SMI handler based on the type
+
+  @param[in]  DispatchFunction        Callback in an event of eSPI SMI
+  @param[in]  PchSmiTypes             The eSPI type published by PchSmiDispatch
+  @param[out] DispatchHandle          The callback handle
+
+  @retval     EFI_INVALID_PARAMETER   Error with NULL SMI source description
+  @retval     EFI_OUT_OF_RESOURCES    Fail to allocate pool for database record
+  @retval     EFI_SUCCESS             Registration is successful.
+**/
+EFI_STATUS
+PchInternalEspiSmiRegister (
+  IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
+  IN  PCH_SMI_TYPES                     PchSmiTypes,
+  OUT EFI_HANDLE                        *DispatchHandle
+  );
+
+/**
+  Unregister an eSPI SMI handler
+
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+**/
+EFI_STATUS
+PchInternalEspiSmiUnRegister (
+  IN  EFI_HANDLE                        DispatchHandle
+  );
+
+/**
+  The internal function used to create and insert a database record
+  for SMI record of Pch Smi types.
+
+  @param[in]  SrcDesc                   The pointer to the SMI source description
+  @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
+  @param[in]  PchSmiType                Specific SMI type of PCH SMI
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+**/
+EFI_STATUS
+PchSmiRecordInsert (
+  IN  CONST PCH_SMM_SOURCE_DESC         *SrcDesc,
+  IN  PCH_SMI_CALLBACK_FUNCTIONS        DispatchFunction,
+  IN  PCH_SMI_TYPES                     PchSmiType,
+  OUT EFI_HANDLE                        *DispatchHandle
+  );
+
+extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq;
+extern CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp;
+
+/**
+  Clear the TCO SMI status bit and block after the SMI handling is done
+
+  @param[in] SrcDesc                    Pointer to the PCH SMI source description table
+
+**/
+VOID
+EFIAPI
+PchTcoSmiClearSourceAndBlock (
+  CONST PCH_SMM_SOURCE_DESC             *SrcDesc
+  );
+
+/**
+  Clear the TCO SMI status bit after the SMI handling is done
+
+  @param[in] SrcDesc                    Pointer to the PCH SMI source description table
+
+**/
+VOID
+EFIAPI
+PchTcoSmiClearSource (
+  CONST PCH_SMM_SOURCE_DESC             *SrcDesc
+  );
+
+/**
+  Initialize Source descriptor structure
+
+  @param[in] SrcDesc                    Pointer to the PCH SMI source description table
+**/
+VOID
+EFIAPI
+NullInitSourceDesc (
+  PCH_SMM_SOURCE_DESC                   *SrcDesc
+  );
+
+/**
+  The register function used to register SMI handler of GPI SMI event.
+
+  @param[in]  This               Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
+  @param[in]  DispatchFunction   Function to register for handler when the specified GPI causes an SMI.
+  @param[in]  RegisterContext    Pointer to the dispatch function's context.
+                                 The caller fills this context in before calling
+                                 the register function to indicate to the register
+                                 function the GPI(s) for which the dispatch function
+                                 should be invoked.
+  @param[out] DispatchHandle     Handle generated by the dispatcher to track the
+                                 function instance.
+
+  @retval EFI_SUCCESS            The dispatch function has been successfully
+                                 registered and the SMI source has been enabled.
+  @retval EFI_ACCESS_DENIED      Register is not allowed
+  @retval EFI_INVALID_PARAMETER  RegisterContext is invalid. The GPI input value
+                                 is not within valid range.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough memory (system or SMM) to manage this child.
+**/
+EFI_STATUS
+EFIAPI
+PchGpiSmiRegister (
+  IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL  *This,
+  IN       EFI_SMM_HANDLER_ENTRY_POINT2    DispatchFunction,
+  IN       EFI_SMM_GPI_REGISTER_CONTEXT    *RegisterContext,
+  OUT      EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  Unregister a GPI SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                 Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  unregistered and the SMI source has been disabled
+                                  if there are no other registered child dispatch
+                                  functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER   Handle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+PchGpiSmiUnRegister (
+  IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL  *This,
+  IN       EFI_HANDLE                      DispatchHandle
+  );
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c
new file mode 100644
index 0000000000..b2e76a8b72
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.c
@@ -0,0 +1,926 @@
+/** @file
+  This driver is responsible for the registration of child drivers
+  and the abstraction of the PCH SMI sources.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmm.h"
+#include "PchSmmHelpers.h"
+#include "PchSmmEspi.h"
+#include <Library/SmiHandlerProfileLib.h>
+#include <Register/GpioRegs.h>
+#include <Register/PmcRegs.h>
+#include <Register/RtcRegs.h>
+
+#define PROGRESS_CODE_S3_SUSPEND_START  PcdGet32 (PcdProgressCodeS3SuspendStart)
+//
+// MODULE / GLOBAL DATA
+//
+// Module variables used by the both the main dispatcher and the source dispatchers
+// Declared in PchSmm.h
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16                mAcpiBaseAddr;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16                mTcoBaseAddr;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN               mReadyToLock;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN               mS3SusStart;
+
+GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA          mPrivateData = {
+  {
+    NULL,
+    NULL
+  },                                    // CallbackDataBase linked list head
+  NULL,                                 // EFI handle returned when calling InstallMultipleProtocolInterfaces
+  NULL,                                 //
+  {                                     // protocol arrays
+    //
+    // elements within the array
+    //
+    {
+      PROTOCOL_SIGNATURE,
+      UsbType,
+      &gEfiSmmUsbDispatch2ProtocolGuid,
+      {{
+        (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
+        (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister
+      }}
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      SxType,
+      &gEfiSmmSxDispatch2ProtocolGuid,
+      {{
+        (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
+        (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister
+      }}
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      SwType,
+      &gEfiSmmSwDispatch2ProtocolGuid,
+      {{
+        (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister,
+        (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister,
+        (UINTN) MAXIMUM_SWI_VALUE
+      }}
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      GpiType,
+      &gEfiSmmGpiDispatch2ProtocolGuid,
+      {{
+        (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister,
+        (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister,
+        (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS
+      }}
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      PowerButtonType,
+      &gEfiSmmPowerButtonDispatch2ProtocolGuid,
+      {{
+        (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
+        (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister
+      }}
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      PeriodicTimerType,
+      &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
+      {{
+        (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
+        (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister,
+        (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval
+      }}
+    },
+  }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS     mContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX] = {
+  {
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    SxGetContext,
+    SxCmpContext,
+    NULL
+  },
+  {
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    PowerButtonGetContext,
+    PowerButtonCmpContext,
+    NULL
+  },
+  {
+    PeriodicTimerGetContext,
+    PeriodicTimerCmpContext,
+    PeriodicTimerGetCommBuffer
+  },
+};
+
+//
+// PROTOTYPES
+//
+// Functions use only in this file
+//
+EFI_STATUS
+EFIAPI
+PchSmmCoreDispatcher (
+  IN       EFI_HANDLE         SmmImageHandle,
+  IN CONST VOID               *PchSmmCore,     OPTIONAL
+  IN OUT   VOID               *CommunicationBuffer,
+  IN OUT   UINTN              *SourceSize
+  );
+
+//
+// FUNCTIONS
+//
+/**
+  SMM ready to lock notification event handler.
+
+  @param  Protocol   Points to the protocol's unique identifier
+  @param  Interface  Points to the interface instance
+  @param  Handle     The handle on which the interface was installed
+
+  @retval EFI_SUCCESS   SmmReadyToLockCallback runs successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockCallback (
+  IN CONST EFI_GUID                       *Protocol,
+  IN VOID                                 *Interface,
+  IN EFI_HANDLE                           Handle
+  )
+{
+  mReadyToLock = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  <b>PchSmiDispatcher SMM Module Entry Point</b>\n
+  - <b>Introduction</b>\n
+    The PchSmiDispatcher module is an SMM driver which  provides SMI handler registration
+    services for PCH generated SMIs.
+
+  - <b>Details</b>\n
+    This module provides SMI handler registration servicies for PCH SMIs.
+    NOTE: All the register/unregister functions will be locked after SMM ready to boot signal event.
+    Please make sure no handler is installed after that.
+
+  - @pre
+    - EFI_SMM_BASE2_PROTOCOL
+      - Documented in the System Management Mode Core Interface Specification
+    - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+      - Documented in the UEFI 2.0 Specification and above
+    - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+      - This is to ensure that PCI MMIO and IO resource has been prepared and available for this driver to allocate.
+    - EFI_SMM_CPU_PROTOCOL
+
+  - @result
+    The PchSmiDispatcher driver produces:
+    - EFI_SMM_USB_DISPATCH2_PROTOCOL
+    - EFI_SMM_SX_DISPATCH2_PROTOCOL
+    - EFI_SMM_SW_DISPATCH2_PROTOCOL
+    - EFI_SMM_GPI_DISPATCH2_PROTOCOL
+    - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL
+    - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL
+    - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL
+    - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink
+    - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL PCH_ACPI_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_SMI_DISPATCH_PROTOCOL PCH_SMI_DISPATCH_PROTOCOL @endlink
+    - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink
+
+  @param[in] ImageHandle          Pointer to the loaded image protocol for this driver
+  @param[in] SystemTable          Pointer to the EFI System Table
+
+  @retval EFI_SUCCESS             PchSmmDispatcher Initialization completed.
+**/
+EFI_STATUS
+EFIAPI
+InitializePchSmmDispatcher (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS           Status;
+  VOID                 *SmmReadyToLockRegistration;
+
+  mS3SusStart = FALSE;
+  //
+  // Access ACPI Base Addresses Register
+  //
+
+  mAcpiBaseAddr = PmcGetAcpiBase ();
+  ASSERT (mAcpiBaseAddr != 0);
+
+  //
+  // Access TCO Base Addresses Register
+  //
+  PchTcoBaseGet (&mTcoBaseAddr);
+  ASSERT (mTcoBaseAddr != 0);
+
+  //
+  // Register a callback function to handle subsequent SMIs.  This callback
+  // will be called by SmmCoreDispatcher.
+  //
+  Status = gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);
+  ASSERT_EFI_ERROR (Status);
+  //
+  // Initialize Callback DataBase
+  //
+  InitializeListHead (&mPrivateData.CallbackDataBase);
+
+  //
+  // Enable SMIs on the PCH now that we have a callback
+  //
+  PchSmmInitHardware ();
+
+  //
+  // Install and initialize all the needed protocols
+  //
+  PchSwDispatchInit ();
+  PchSmmPublishDispatchProtocols ();
+  InstallPchSmiDispatchProtocols ();
+  InstallIoTrap (ImageHandle);
+  InstallEspiSmi (ImageHandle);
+  InstallPchSmmPeriodicTimerControlProtocol (mPrivateData.InstallMultProtHandle);
+
+  //
+  // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function.
+  //
+  Status = gSmst->SmmRegisterProtocolNotify (
+                    &gEfiSmmReadyToLockProtocolGuid,
+                    SmmReadyToLockCallback,
+                    &SmmReadyToLockRegistration
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The internal function used to create and insert a database record
+
+  @param[in]  InsertRecord              Record to insert to database.
+  @param[out] DispatchHandle            Handle of dispatch function to register.
+
+  @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
+  @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
+  @retval EFI_SUCCESS                   The database record is created successfully.
+**/
+EFI_STATUS
+SmmCoreInsertRecord (
+  IN  DATABASE_RECORD                   *NewRecord,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+  DATABASE_RECORD                       *Record;
+
+  if ((NewRecord == NULL) ||
+      (NewRecord->Signature != DATABASE_RECORD_SIGNATURE))
+  {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (DATABASE_RECORD), (VOID **) &Record);
+  if (EFI_ERROR (Status)) {
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD));
+
+  //
+  // After ensuring the source of event is not null, we will insert the record into the database
+  //
+  InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+
+  //
+  // Child's handle will be the address linked list link in the record
+  //
+  *DispatchHandle = (EFI_HANDLE) (&Record->Link);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                       Protocol instance pointer.
+  @param[in] DispatchHandle             Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS                   The dispatch function has been successfully
+                                        unregistered and the SMI source has been disabled
+                                        if there are no other registered child dispatch
+                                        functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER         Handle is invalid.
+  @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
+**/
+EFI_STATUS
+EFIAPI
+PchPiSmmCoreUnRegister (
+  IN PCH_SMM_GENERIC_PROTOCOL                           *This,
+  IN EFI_HANDLE                                         *DispatchHandle
+  )
+{
+  DATABASE_RECORD                   *RecordToDelete;
+  EFI_STATUS                        Status;
+  PCH_SMM_QUALIFIED_PROTOCOL        *Qualified;
+
+  Qualified      = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  Status         = PchSmmCoreUnRegister (NULL, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileUnregisterHandler (
+      Qualified->Guid,
+      RecordToDelete->Callback,
+      &RecordToDelete->ChildContext,
+      RecordToDelete->ContextSize
+      );
+  }
+  return Status;
+}
+
+/**
+  Register a child SMI dispatch function with a parent SMM driver.
+
+  @param[in] This                 Pointer to the PCH_SMM_GENERIC_PROTOCOL instance.
+  @param[in] DispatchFunction     Pointer to dispatch function to be invoked for this SMI source.
+  @param[in] DispatchContext      Pointer to the dispatch function's context.
+  @param[out] DispatchHandle      Handle of dispatch function, for when interfacing
+                                  with the parent SMM driver, will be the address of linked
+                                  list link in the call back record.
+
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to create database record
+  @retval EFI_INVALID_PARAMETER   The input parameter is invalid
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  registered and the SMI source has been enabled.
+**/
+EFI_STATUS
+EFIAPI
+PchPiSmmCoreRegister (
+  IN  PCH_SMM_GENERIC_PROTOCOL                          *This,
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2                      DispatchFunction,
+  IN  PCH_SMM_CONTEXT                                   *DispatchContext,
+  OUT EFI_HANDLE                                        *DispatchHandle
+  )
+{
+  EFI_STATUS                  Status;
+  DATABASE_RECORD             Record;
+  PCH_SMM_QUALIFIED_PROTOCOL  *Qualified;
+  PCH_SMM_SOURCE_DESC         NullSourceDesc;
+
+  //
+  // Initialize NullSourceDesc
+  //
+  NullInitSourceDesc (&NullSourceDesc);
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  ZeroMem (&Record, sizeof (DATABASE_RECORD));
+
+  //
+  // Gather information about the registration request
+  //
+  Record.Callback          = DispatchFunction;
+
+  Qualified                = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
+
+  Record.ProtocolType      = Qualified->Type;
+
+  Record.ContextFunctions  = mContextFunctions[Qualified->Type];
+  //
+  // Perform linked list housekeeping
+  //
+  Record.Signature         = DATABASE_RECORD_SIGNATURE;
+
+  switch (Qualified->Type) {
+    //
+    // By the end of this switch statement, we'll know the
+    // source description the child is registering for
+    //
+    case UsbType:
+      Record.ContextSize = sizeof (EFI_SMM_USB_REGISTER_CONTEXT);
+      CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);
+      //
+      // Check the validity of Context Type
+      //
+      if ((Record.ChildContext.Usb.Type < UsbLegacy) || (Record.ChildContext.Usb.Type > UsbWake)) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc);
+      Record.ClearSource = NULL;
+      //
+      // use default clear source function
+      //
+      break;
+
+    case SxType:
+      Record.ContextSize = sizeof (EFI_SMM_SX_REGISTER_CONTEXT);
+      CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);
+      //
+      // Check the validity of Context Type and Phase
+      //
+      if ((Record.ChildContext.Sx.Type < SxS0) ||
+          (Record.ChildContext.Sx.Type >= EfiMaximumSleepType) ||
+          (Record.ChildContext.Sx.Phase < SxEntry) ||
+          (Record.ChildContext.Sx.Phase >= EfiMaximumPhase)
+          ) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof (PCH_SMM_SOURCE_DESC));
+      Record.ClearSource = NULL;
+      //
+      // use default clear source function
+      //
+      break;
+
+    case PowerButtonType:
+      Record.ContextSize = sizeof (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT);
+      CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);
+      //
+      // Check the validity of Context Phase
+      //
+      if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) ||
+          (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit))
+      {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof (PCH_SMM_SOURCE_DESC));
+      Record.ClearSource = NULL;
+      //
+      // use default clear source function
+      //
+      break;
+
+    case PeriodicTimerType:
+      Record.ContextSize = sizeof (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT);
+      CopyMem (&Record.ChildContext, DispatchContext, Record.ContextSize);
+      //
+      // Check the validity of timer value
+      //
+      if (DispatchContext->PeriodicTimer.SmiTickInterval <= 0) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc);
+      Record.MiscData.TimerSmiEnabled = TRUE;
+      Record.ClearSource = PchSmmPeriodicTimerClearSource;
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+      break;
+  }
+
+  if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // After ensuring the source of event is not null, we will insert the record into the database
+  // Child's handle will be the address linked list link in the record
+  //
+  Status = SmmCoreInsertRecord (
+             &Record,
+             DispatchHandle
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  if (Record.ClearSource == NULL) {
+    //
+    // Clear the SMI associated w/ the source using the default function
+    //
+    PchSmmClearSource (&Record.SrcDesc);
+  } else {
+    //
+    // This source requires special handling to clear
+    //
+    Record.ClearSource (&Record.SrcDesc);
+  }
+
+  PchSmmEnableSource (&Record.SrcDesc);
+  SmiHandlerProfileRegisterHandler (
+    Qualified->Guid,
+    DispatchFunction,
+    (UINTN)RETURN_ADDRESS (0),
+    DispatchContext,
+    Record.ContextSize
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver.
+
+  @param[in] This                 Pointer to the PCH_SMM_GENERIC_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  unregistered and the SMI source has been disabled
+                                  if there are no other registered child dispatch
+                                  functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER   Handle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+PchSmmCoreUnRegister (
+  IN PCH_SMM_GENERIC_PROTOCOL                           *This,
+  IN EFI_HANDLE                                         *DispatchHandle
+  )
+{
+  EFI_STATUS                   Status;
+  BOOLEAN                      NeedClearEnable;
+  UINTN                        DescIndex;
+  DATABASE_RECORD              *RecordToDelete;
+  DATABASE_RECORD              *RecordInDb;
+  LIST_ENTRY                   *LinkInDb;
+
+  if (DispatchHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+
+  //
+  // Take the entry out of the linked list
+  //
+  if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RemoveEntryList (&RecordToDelete->Link);
+
+  //
+  // Loop through all the souces in record linked list to see if any source enable is equal.
+  // If any source enable is equal, we do not want to disable it.
+  //
+  for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
+    if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) {
+      continue;
+    }
+    NeedClearEnable = TRUE;
+    LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+    while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+      RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+      if (IsBitEqualToAnySourceEn (&RecordToDelete->SrcDesc.En[DescIndex], &RecordInDb->SrcDesc)) {
+        NeedClearEnable = FALSE;
+        break;
+      }
+      LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+    }
+    if (NeedClearEnable == FALSE) {
+      continue;
+    }
+    WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE);
+  }
+  Status = gSmst->SmmFreePool (RecordToDelete);
+  if (EFI_ERROR (Status)) {
+    ASSERT (FALSE);
+    return Status;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This function clears the pending SMI status before set EOS.
+  NOTE: This only clears the pending SMI with known reason.
+        Please do not clear unknown pending SMI status since that will hide potential issues.
+
+  @param[in] SmiStsValue                SMI status
+  @param[in] SciEn                      Sci Enable status
+**/
+STATIC
+VOID
+ClearPendingSmiStatus (
+  UINT32  SmiStsValue,
+  BOOLEAN SciEn
+  )
+{
+  //
+  // Clear NewCentury status if it's not handled.
+  //
+  if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) {
+    if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & B_TCO_IO_TCO1_STS_NEWCENTURY) {
+      PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury);
+    }
+  }
+  // Clear PWRBTNOR_STS if it's not handled.
+  //
+  if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & B_ACPI_IO_PM1_STS_PRBTNOR) {
+    IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PRBTNOR);
+  }
+  //
+  // Clear WADT_STS if this is triggered by WADT timer.
+  //
+  if (!SciEn) {
+    if (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & B_ACPI_IO_GPE0_STS_127_96_WADT) {
+      IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0_STS_127_96_WADT);
+    }
+  }
+  //
+  // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is not supported
+  //
+  if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) {
+    IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, B_ACPI_IO_SMI_STS_GPIO_UNLOCK);
+  }
+}
+
+/**
+  The callback function to handle subsequent SMIs.  This callback will be called by SmmCoreDispatcher.
+
+  @param[in] SmmImageHandle             Not used
+  @param[in] PchSmmCore                 Not used
+  @param[in, out] CommunicationBuffer   Not used
+  @param[in, out] SourceSize            Not used
+
+  @retval EFI_SUCCESS                   Function successfully completed
+**/
+EFI_STATUS
+EFIAPI
+PchSmmCoreDispatcher (
+  IN       EFI_HANDLE         SmmImageHandle,
+  IN CONST VOID               *PchSmmCore,
+  IN OUT   VOID               *CommunicationBuffer,
+  IN OUT   UINTN              *SourceSize
+  )
+{
+  //
+  // Used to prevent infinite loops
+  //
+  UINTN               EscapeCount;
+
+  BOOLEAN             ContextsMatch;
+  BOOLEAN             EosSet;
+  BOOLEAN             SxChildWasDispatched;
+
+  DATABASE_RECORD     *RecordInDb;
+  LIST_ENTRY          *LinkInDb;
+  DATABASE_RECORD     *RecordToExhaust;
+  LIST_ENTRY          *LinkToExhaust;
+
+  PCH_SMM_CONTEXT     Context;
+  VOID                *CommBuffer;
+  UINTN               CommBufferSize;
+
+  EFI_STATUS          Status;
+  BOOLEAN             SciEn;
+  UINT32              SmiEnValue;
+  UINT32              SmiStsValue;
+  UINT8               Port74Save;
+  UINT8               Port76Save;
+
+  PCH_SMM_SOURCE_DESC ActiveSource;
+
+  //
+  // Initialize ActiveSource
+  //
+  NullInitSourceDesc (&ActiveSource);
+
+  EscapeCount           = 3;
+  ContextsMatch         = FALSE;
+  EosSet                = FALSE;
+  SxChildWasDispatched  = FALSE;
+  Status                = EFI_SUCCESS;
+
+  //
+  // Save IO index registers
+  // @note: Save/Restore port 70h directly might break NMI_EN# setting,
+  //       then save/restore 74h/76h instead.
+  // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF8
+  //
+  Port76Save = IoRead8 (R_RTC_IO_EXT_INDEX_ALT);
+  Port74Save = IoRead8 (R_RTC_IO_INDEX_ALT);
+
+  if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
+    //
+    // We have children registered w/ us -- continue
+    //
+    while ((!EosSet) && (EscapeCount > 0)) {
+      EscapeCount--;
+
+      LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+
+      //
+      // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is active
+      //
+      SciEn       = PchSmmGetSciEn ();
+      SmiEnValue  = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
+      SmiStsValue = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS));
+
+      while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+        RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+
+        //
+        // look for the first active source
+        //
+        if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, SmiStsValue)) {
+          //
+          // Didn't find the source yet, keep looking
+          //
+          LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+
+          //
+          // if it's the last one, try to clear EOS
+          //
+          if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+            //
+            // Clear pending SMI status before EOS
+            //
+            ClearPendingSmiStatus (SmiStsValue, SciEn);
+            EosSet = PchSmmSetAndCheckEos ();
+          }
+        } else {
+          //
+          // We found a source. If this is a sleep type, we have to go to
+          // appropriate sleep state anyway.No matter there is sleep child or not
+          //
+          if (RecordInDb->ProtocolType == SxType) {
+            SxChildWasDispatched = TRUE;
+          }
+          //
+          // "cache" the source description and don't query I/O anymore
+          //
+          CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc), sizeof (PCH_SMM_SOURCE_DESC));
+          LinkToExhaust = LinkInDb;
+
+          //
+          // exhaust the rest of the queue looking for the same source
+          //
+          while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
+            RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
+            //
+            // RecordToExhaust->Link might be removed (unregistered) by Callback function, and then the
+            // system will hang in ASSERT() while calling GetNextNode().
+            // To prevent the issue, we need to get next record in DB here (before Callback function).
+            //
+            LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link);
+
+            if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
+              //
+              // These source descriptions are equal, so this callback should be
+              // dispatched.
+              //
+              if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
+                //
+                // This child requires that we get a calling context from
+                // hardware and compare that context to the one supplied
+                // by the child.
+                //
+                ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);
+
+                //
+                // Make sure contexts match before dispatching event to child
+                //
+                RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
+                ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);
+
+              } else {
+                //
+                // This child doesn't require any more calling context beyond what
+                // it supplied in registration.  Simply pass back what it gave us.
+                //
+                Context       = RecordToExhaust->ChildContext;
+                ContextsMatch = TRUE;
+              }
+
+              if (ContextsMatch) {
+                if (RecordToExhaust->ProtocolType == PchSmiDispatchType) {
+                  //
+                  // For PCH SMI dispatch protocols
+                  //
+                  PchSmiTypeCallbackDispatcher (RecordToExhaust);
+                } else {
+                  if ((RecordToExhaust->ProtocolType == SxType) && (Context.Sx.Type == SxS3) && (Context.Sx.Phase == SxEntry) && !mS3SusStart) {
+                    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_START);
+                    mS3SusStart = TRUE;
+                  }
+                  //
+                  // For EFI standard SMI dispatch protocols
+                  //
+                  if (RecordToExhaust->Callback != NULL) {
+                    if (RecordToExhaust->ContextFunctions.GetCommBuffer != NULL) {
+                      //
+                      // This callback function needs CommBuffer and CommBufferSize.
+                      // Get those from child and then pass to callback function.
+                      //
+                      RecordToExhaust->ContextFunctions.GetCommBuffer (RecordToExhaust, &CommBuffer, &CommBufferSize);
+                    } else {
+                      //
+                      // Child doesn't support the CommBuffer and CommBufferSize.
+                      // Just pass NULL value to callback function.
+                      //
+                      CommBuffer     = NULL;
+                      CommBufferSize = 0;
+                    }
+
+                    PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc (), RecordToExhaust->ProtocolType);
+                    RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExhaust->Link, &Context, CommBuffer, &CommBufferSize);
+                    PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (), RecordToExhaust->ProtocolType);
+                    if (RecordToExhaust->ProtocolType == SxType) {
+                      SxChildWasDispatched = TRUE;
+                    }
+                  } else {
+                    ASSERT (FALSE);
+                  }
+                }
+              }
+            }
+          }
+
+          if (RecordInDb->ClearSource == NULL) {
+            //
+            // Clear the SMI associated w/ the source using the default function
+            //
+            PchSmmClearSource (&ActiveSource);
+          } else {
+            //
+            // This source requires special handling to clear
+            //
+            RecordInDb->ClearSource (&ActiveSource);
+          }
+          //
+          // Clear pending SMI status before EOS
+          //
+          ClearPendingSmiStatus (SmiStsValue, SciEn);
+          //
+          // Also, try to clear EOS
+          //
+          EosSet = PchSmmSetAndCheckEos ();
+          //
+          // Queue is empty, reset the search
+          //
+          break;
+        }
+      }
+    }
+  }
+  //
+  // If you arrive here, there are two possible reasons:
+  // (1) you've got problems with clearing the SMI status bits in the
+  // ACPI table.  If you don't properly clear the SMI bits, then you won't be able to set the
+  // EOS bit.  If this happens too many times, the loop exits.
+  // (2) there was a SMM communicate for callback messages that was received prior
+  // to this driver.
+  // If there is an asynchronous SMI that occurs while processing the Callback, let
+  // all of the drivers (including this one) have an opportunity to scan for the SMI
+  // and handle it.
+  // If not, we don't want to exit and have the foreground app. clear EOS without letting
+  // these other sources get serviced.
+  //
+  // This assert is not valid with CSM legacy solution because it generates software SMI
+  // to test for legacy USB support presence.
+  // This may not be illegal, so we cannot assert at this time.
+  //
+  //  ASSERT (EscapeCount > 0);
+  //
+  if (SxChildWasDispatched) {
+    //
+    // A child of the SmmSxDispatch protocol was dispatched during this call;
+    // put the system to sleep.
+    //
+    PchSmmSxGoToSleep ();
+  }
+  //
+  // Restore IO index registers
+  // @note: Save/Restore port 70h directly might break NMI_EN# setting,
+  //       then save/restore 74h/76h instead.
+  //
+  IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save);
+  IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save);
+
+  return Status;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c
new file mode 100644
index 0000000000..9ce4072e37
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c
@@ -0,0 +1,1588 @@
+/** @file
+  eSPI SMI implementation
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PchSmmEspi.h"
+#include <Library/PmcPrivateLib.h>
+#include <Library/EspiLib.h>
+#include <Library/SmiHandlerProfileLib.h>
+#include <Register/PchRegs.h>
+#include <Register/PchPcrRegs.h>
+#include <Register/PchRegsLpc.h>
+#include <Library/PchPciBdfLib.h>
+#include <PchBdfAssignment.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE mEspiSmiInstance = {
+  //
+  // Signature
+  //
+  ESPI_SMI_INSTANCE_SIGNATURE,
+  //
+  // Handle
+  //
+  NULL,
+  //
+  // PchEspiSmiDispatchProtocol
+  //
+  {
+    PCH_ESPI_SMI_DISPATCH_REVISION,
+    EspiSmiUnRegister,
+    BiosWrProtectRegister,
+    BiosWrReportRegister,
+    PcNonFatalErrRegister,
+    PcFatalErrRegister,
+    VwNonFatalErrRegister,
+    VwFatalErrRegister,
+    FlashNonFatalErrRegister,
+    FlashFatalErrRegister,
+    LnkType1ErrRegister,
+    EspiSlaveSmiRegister
+  },
+  //
+  // PchSmiEspiHandle[EspiTopLevelTypeMax]
+  //
+  {
+    NULL, NULL, NULL
+  },
+  //
+  // CallbackDataBase[EspiSmiTypeMax]
+  //
+  {
+    {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL},
+    {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}
+  },
+  //
+  // EspiSmiEventCounter[EspiSmiTypeMax]
+  //
+  {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+  },
+  //
+  // Barrier[EspiTopLevelTypeMax]
+  //
+  {
+    {
+      BiosWrProtect,
+      BiosWrProtect
+    },
+    {
+      BiosWrReport,
+      LnkType1Err
+    },
+    {
+      EspiSlaveSmi,
+      EspiSlaveSmi
+    }
+  }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST ESPI_DESCRIPTOR mEspiDescriptor[EspiSmiTypeMax] = {
+  //
+  // BiosWrProtect
+  //
+  {
+    {
+      PCIE_ADDR_TYPE,
+      { (
+        (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+        (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
+        (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
+        R_ESPI_CFG_PCBC
+      ) }
+    },
+    //
+    // SourceIsActiveAndMask and SourceIsActiveValue
+    //
+    B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,
+    B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,
+    //
+    // ClearStatusAndMask and ClearStatusOrMask
+    //
+    (UINT32) ~B_ESPI_CFG_PCBC_BWRS,
+    B_ESPI_CFG_PCBC_BWPDS
+  },
+  //
+  // BiosWrReport
+  //
+  {
+    {
+      PCIE_ADDR_TYPE,
+      { (
+        (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+        (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
+        (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
+        R_ESPI_CFG_PCBC
+      ) }
+    },
+    B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,
+    B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,
+    (UINT32) ~B_ESPI_CFG_PCBC_BWPDS,
+    B_ESPI_CFG_PCBC_BWRS
+  },
+  //
+  // PcNonFatalErr
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }
+    },
+    (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
+    (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR_XNFEE)),
+    (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XFES),
+    B_ESPI_PCR_XERR_XNFES
+  },
+  //
+  // PcFatalErr
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }
+    },
+    (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
+    (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_XFEE)),
+    (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES),
+    B_ESPI_PCR_XERR_XFES
+  },
+  //
+  // VwNonFatalErr
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }
+    },
+    (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
+    (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR_XNFEE)),
+    (UINT32) ~B_ESPI_PCR_XERR_XFES,
+    B_ESPI_PCR_XERR_XNFES
+  },
+  //
+  // VwFatalErr
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }
+    },
+    (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
+    (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_XFEE)),
+    (UINT32) ~B_ESPI_PCR_XERR_XNFES,
+    B_ESPI_PCR_XERR_XFES
+  },
+  //
+  // FlashNonFatalErr
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }
+    },
+    (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
+    (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << N_ESPI_PCR_XERR_XNFEE)),
+    (UINT32) ~B_ESPI_PCR_XERR_XFES,
+    B_ESPI_PCR_XERR_XNFES
+  },
+  //
+  // FlashFatalErr
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }
+    },
+    (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
+    (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << N_ESPI_PCR_XERR_XFEE)),
+    (UINT32) ~B_ESPI_PCR_XERR_XNFES,
+    B_ESPI_PCR_XERR_XFES
+  },
+  //
+  // LnkType1Err
+  //
+  {
+    {
+      PCR_ADDR_TYPE,
+      {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_LNKERR_SLV0) }
+    },
+    B_ESPI_PCR_LNKERR_SLV0_LFET1S | B_ESPI_PCR_LNKERR_SLV0_LFET1E,
+    B_ESPI_PCR_LNKERR_SLV0_LFET1S | (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_SLV0_LFET1E),
+    (UINT32) ~B_ESPI_PCR_LNKERR_SLV0_SLCRR,
+    B_ESPI_PCR_LNKERR_SLV0_LFET1S
+  },
+};
+
+/**
+  Enable eSPI SMI source
+
+  @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
+**/
+STATIC
+VOID
+EspiSmiEnableSource (
+  IN CONST  ESPI_SMI_TYPE EspiSmiType
+  )
+{
+  UINT64      PciBaseAddress;
+
+  switch (EspiSmiType) {
+    case BiosWrProtect:
+      //
+      // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
+      //
+      break;
+    case BiosWrReport:
+      PciBaseAddress = EspiPciCfgBase ();
+      PciSegmentAndThenOr32 (
+        PciBaseAddress + R_ESPI_CFG_PCBC,
+        (UINT32) ~(B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWPDS),
+        B_ESPI_CFG_PCBC_BWRE
+        );
+      break;
+    case PcNonFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_PCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
+        B_ESPI_PCR_XERR_XNFEE
+        );
+      break;
+
+    case PcFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_PCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
+        B_ESPI_PCR_XERR_XFEE
+        );
+      break;
+
+    case VwNonFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_VWERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
+        B_ESPI_PCR_XERR_XNFEE
+        );
+      break;
+
+    case VwFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_VWERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
+        B_ESPI_PCR_XERR_XFEE
+        );
+      break;
+
+    case FlashNonFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_FCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
+        B_ESPI_PCR_XERR_XNFEE
+        );
+      break;
+
+    case FlashFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_FCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
+        B_ESPI_PCR_XERR_XFEE
+        );
+      break;
+
+    case LnkType1Err:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_LNKERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
+        (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_SLV0_LFET1E)
+        );
+
+      if (IsEspiSecondSlaveSupported ()) {
+        PchPcrAndThenOr32 (
+          PID_ESPISPI,
+          (UINT16) R_ESPI_PCR_LNKERR_SLV1,
+          (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
+          (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << N_ESPI_PCR_LNKERR_SLV0_LFET1E)
+          );
+      }
+      break;
+
+    default:
+      DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));
+      ASSERT (FALSE);
+      break;
+  }
+}
+
+
+/**
+  Disable eSPI SMI source
+
+  @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
+**/
+STATIC
+VOID
+EspiSmiDisableSource (
+  IN CONST  ESPI_SMI_TYPE EspiSmiType
+  )
+{
+
+  switch (EspiSmiType) {
+    case BiosWrProtect:
+    case BiosWrReport:
+      DEBUG ((DEBUG_ERROR, "Bit is write lock, thus BWRE/BWPDS source cannot be disabled \n"));
+      ASSERT (FALSE);
+      break;
+    case PcNonFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_PCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),
+        0
+        );
+      break;
+
+    case PcFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_PCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
+        0
+        );
+      break;
+
+    case VwNonFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_VWERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),
+        0
+        );
+      break;
+
+    case VwFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_VWERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
+        0
+        );
+      break;
+
+    case FlashNonFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_FCERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XNFEE),
+        0
+        );
+      break;
+
+    case FlashFatalErr:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+       (UINT16) R_ESPI_PCR_FCERR_SLV0,
+       (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
+       0
+       );
+      break;
+
+    case LnkType1Err:
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) R_ESPI_PCR_LNKERR_SLV0,
+        (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
+        0
+        );
+
+      if (IsEspiSecondSlaveSupported ()) {
+        PchPcrAndThenOr32 (
+          PID_ESPISPI,
+          (UINT16) R_ESPI_PCR_LNKERR_SLV1,
+          (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | B_ESPI_PCR_LNKERR_SLV0_LFET1S),
+          0
+          );
+      }
+      break;
+
+    default:
+      DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));
+      ASSERT (FALSE);
+      break;
+  }
+}
+
+/**
+  Clear a status for the SMI event
+
+  @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
+**/
+STATIC
+VOID
+EspiSmiClearStatus (
+  IN CONST  ESPI_SMI_TYPE EspiSmiType
+  )
+{
+  UINT32                  PciBus;
+  UINT32                  PciDev;
+  UINT32                  PciFun;
+  UINT32                  PciReg;
+  UINT64                  PciBaseAddress;
+  CONST ESPI_DESCRIPTOR   *Desc;
+
+  Desc = &mEspiDescriptor[EspiSmiType];
+
+  switch (Desc->Address.Type) {
+    case PCIE_ADDR_TYPE:
+      PciBus  = Desc->Address.Data.pcie.Fields.Bus;
+      PciDev  = Desc->Address.Data.pcie.Fields.Dev;
+      PciFun  = Desc->Address.Data.pcie.Fields.Fnc;
+      PciReg  = Desc->Address.Data.pcie.Fields.Reg;
+      PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
+      PciSegmentAndThenOr32 (PciBaseAddress + PciReg, Desc->ClearStatusAndMask, Desc->ClearStatusOrMask);
+      break;
+    case PCR_ADDR_TYPE:
+      PchPcrAndThenOr32 (
+        Desc->Address.Data.Pcr.Fields.Pid,
+        Desc->Address.Data.Pcr.Fields.Offset,
+        Desc->ClearStatusAndMask,
+        Desc->ClearStatusOrMask
+        );
+      break;
+    default:
+      DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
+      ASSERT (FALSE);
+      break;
+  }
+}
+
+/**
+  Checks if a source is active by looking at the enable and status bits
+
+  @param[in]  EspiSmiType  Type based on ESPI_SMI_TYPE
+**/
+STATIC
+BOOLEAN
+EspiSmiSourceIsActive (
+  IN CONST  ESPI_SMI_TYPE EspiSmiType
+  )
+{
+  BOOLEAN                 Active;
+  UINT32                  PciBus;
+  UINT32                  PciDev;
+  UINT32                  PciFun;
+  UINT32                  PciReg;
+  UINT64                  PciBaseAddress;
+  UINT32                  Data32;
+  CONST ESPI_DESCRIPTOR   *Desc;
+
+  Desc = &mEspiDescriptor[EspiSmiType];
+
+  Active = FALSE;
+  switch (Desc->Address.Type) {
+    case PCIE_ADDR_TYPE:
+      PciBus  = Desc->Address.Data.pcie.Fields.Bus;
+      PciDev  = Desc->Address.Data.pcie.Fields.Dev;
+      PciFun  = Desc->Address.Data.pcie.Fields.Fnc;
+      PciReg  = Desc->Address.Data.pcie.Fields.Reg;
+      PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
+      Data32 = PciSegmentRead32 (PciBaseAddress + PciReg);
+      break;
+
+    case PCR_ADDR_TYPE:
+      Data32 = PchPcrRead32 (
+                 Desc->Address.Data.Pcr.Fields.Pid,
+                 Desc->Address.Data.Pcr.Fields.Offset
+                 );
+      break;
+
+    default:
+      Data32 = 0;
+      DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
+      ASSERT (FALSE);
+      break;
+  }
+
+  if ((Data32 & Desc->SourceIsActiveAndMask) == Desc->SourceIsActiveValue) {
+    Active = TRUE;
+  }
+
+  return Active;
+}
+
+/**
+  Insert a handler into the corresponding linked list based on EspiSmiType
+
+  @param[in]  DispatchFunction      The callback to execute
+  @param[in]  EspiSmiType           Type based on ESPI_SMI_TYPE to determine which linked list to use
+  @param[out] DispatchHandle        The link to the record in the database
+
+  @retval     EFI_SUCCESS           Record was successfully inserted into master database
+  @retval     EFI_OUT_OF_RESOURCES  Cannot allocate pool to insert record
+**/
+STATIC
+EFI_STATUS
+InsertEspiRecord (
+  IN        PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  IN        ESPI_SMI_TYPE                   EspiSmiType,
+  OUT       EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS      Status;
+  ESPI_SMI_RECORD *Record;
+
+  Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (ESPI_SMI_RECORD), (VOID **) &Record);
+  if (EFI_ERROR (Status)) {
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  SetMem (Record, sizeof (ESPI_SMI_RECORD), 0);
+
+  Record->Callback  = DispatchFunction;
+  Record->Signature = ESPI_SMI_RECORD_SIGNATURE;
+
+  InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &Record->Link);
+  EspiSmiClearStatus (EspiSmiType);
+  EspiSmiEnableSource (EspiSmiType);
+
+  ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType];
+
+  *DispatchHandle = (EFI_HANDLE) (&Record->Link);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This callback is registered to PchSmiDispatch
+
+  @param[in]  DispatchHandle  Used to determine which source have been triggered
+**/
+VOID
+EspiSmiCallback (
+  IN  EFI_HANDLE                      DispatchHandle
+  )
+{
+  DATABASE_RECORD     *PchSmiRecord;
+  ESPI_TOP_LEVEL_TYPE EspiTopLevelType;
+  ESPI_SMI_TYPE       EspiSmiType;
+  ESPI_SMI_RECORD     *RecordInDb;
+  LIST_ENTRY          *LinkInDb;
+
+  PchSmiRecord = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+
+  if (PchSmiRecord->PchSmiType == PchTcoSmiLpcBiosWpType) {
+    EspiTopLevelType = EspiBiosWrProtect;
+  } else if (PchSmiRecord->PchSmiType == PchSmiSerialIrqType) {
+    EspiTopLevelType = EspiSerialIrq;
+  } else {
+    DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong DispatchHandle"));
+    ASSERT (FALSE);
+    return;
+  }
+
+  for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start; EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End; ++EspiSmiType) {
+    if (!EspiSmiSourceIsActive (EspiSmiType)) {
+      continue;
+    }
+    //
+    // The source is active, so walk the callback database and dispatch
+    //
+    if (!IsListEmpty (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])) {
+      //
+      // We have children registered w/ us -- continue
+      //
+      LinkInDb = GetFirstNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
+
+      while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb)) {
+        RecordInDb = ESPI_RECORD_FROM_LINK (LinkInDb);
+
+        //
+        // RecordInDb->Link might be removed (unregistered) by Callback function, and then the
+        // system will hang in ASSERT() while calling GetNextNode().
+        // To prevent the issue, we need to get next record in DB here (before Callback function).
+        //
+        LinkInDb = GetNextNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &RecordInDb->Link);
+
+        //
+        // Callback
+        //
+        if (RecordInDb->Callback != NULL) {
+          RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link);
+        } else {
+          ASSERT (FALSE);
+        }
+      }
+    } else if (EspiSmiType == LnkType1Err) {
+      //
+      // If no proper handler registered for Link Type 1 Error
+      // Call default SMI handler recover otherwise
+      //
+      EspiDefaultFatalErrorHandler ();
+    }
+
+    //
+    // Finish walking the linked list for the EspiSmiType, so clear status
+    //
+    EspiSmiClearStatus (EspiSmiType);
+  }
+}
+
+//
+// EspiBiosWp srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescEspiBiosWp = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_TCO
+    },
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
+          R_ESPI_CFG_PCBC
+        ) }
+      },
+      S_ESPI_CFG_PCBC,
+      N_ESPI_CFG_PCBC_LE
+    }
+  },
+  {
+    {
+      {
+        PCIE_ADDR_TYPE,
+        { (
+          (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
+          (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
+          (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
+          R_ESPI_CFG_PCBC
+        ) }
+      },
+      S_ESPI_CFG_PCBC,
+      N_ESPI_CFG_PCBC_BWPDS
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_TCO
+  }
+};
+
+/**
+  This function will register EspiSmiCallback with mSrcDescEspiBiosWp source decriptor
+  This function make sure there is only one BIOS WP SMI handler is registered.
+  While any ESPI sub BIOS WP SMI type is registered, all the BIOS WP SMI
+  will go to callback function EspiSmiCallback first, and then dispatchs the callbacks
+  recorded in mEspiSmiInstance.
+
+  @retval EFI_SUCCESS Registration succeed
+  @retval others      Registration failed
+**/
+STATIC
+EFI_STATUS
+RegisterBiosWrProtectIfNull (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  DATABASE_RECORD *Record;
+
+  if (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] == NULL) {
+    Status = PchSmiRecordInsert (
+               &mSrcDescEspiBiosWp,
+               (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,
+               PchTcoSmiLpcBiosWpType,
+               &mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Fail to register BIOS WP SMI handler \n"));
+      return Status;
+    }
+    Record = DATABASE_RECORD_FROM_LINK (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]);
+    Record->ClearSource = PchTcoSmiClearSource;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function will register EspiSmiCallback with mSrcDescSerialIrq source decriptor
+  This function make sure there is only one Serial IRQ SMI handler is registered.
+  While any ESPI sub Serial IRQ SMI type is registered, all the Serial IRQ SMI
+  will go to callback function EspiSmiCallback first, and then dispatchs the callbacks
+  recorded in mEspiSmiInstance.
+
+  @retval EFI_SUCCESS Registration succeed
+  @retval others      Registration failed
+**/
+STATIC
+EFI_STATUS
+RegisterSerialIrqIfNull (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  if (mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] == NULL) {
+    Status = PchSmiRecordInsert (
+               &mSrcDescSerialIrq,
+               (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,
+               PchSmiSerialIrqType,
+               &mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq]
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Fail to register Serial IRQ SMI handler \n"));
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Installs and initialize this protocol
+
+  @param[in]  ImageHandle   Not used
+
+  @retval     EFI_SUCCESS   Installation succeed
+  @retval     others        Installation failed
+**/
+EFI_STATUS
+EFIAPI
+InstallEspiSmi (
+  IN EFI_HANDLE           ImageHandle
+  )
+{
+  EFI_STATUS    Status;
+  ESPI_SMI_TYPE EspiSmiType;
+
+  DEBUG ((DEBUG_INFO, "[InstallEspiSmi] Enter\n"));
+
+  //
+  // InitializeListHead for mEspiSmiInstance.CallBackDataBase[EspiTopLevelTypeMax]
+  //
+  for (EspiSmiType = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
+    InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
+  }
+
+  //
+  // Install EfiEspiSmiDispatchProtocol
+  //
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &mEspiSmiInstance.Handle,
+                    &gPchEspiSmiDispatchProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mEspiSmiInstance.PchEspiSmiDispatchProtocol
+                    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to install eSPI SMI Dispatch Protocol\n"));
+    ASSERT (FALSE);
+    return Status;
+  }
+
+  // Register eSPI SMM callback to enable Fatal Error handling by default handler
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Enable LnkType1Err SMI generation for default handler
+  EspiSmiClearStatus (LnkType1Err);
+  EspiSmiEnableSource (LnkType1Err);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+BiosWrProtectRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterBiosWrProtectIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, BiosWrProtect, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a BIOS Write Report event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+BiosWrReportRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, BiosWrReport, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+PcNonFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, PcNonFatalErr, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+PcFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, PcFatalErr, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+VwNonFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, VwNonFatalErr, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+VwFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, VwFatalErr, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+FlashNonFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, FlashNonFatalErr, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+FlashFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, FlashFatalErr, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Link Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+LnkType1ErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = RegisterSerialIrqIfNull ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Insert a record
+  //
+  Status = InsertEspiRecord (DispatchFunction, LnkType1Err, DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+  return Status;
+}
+
+//
+// EspiSlave srcdesc
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescEspiSlave = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_ESPI
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_ESPI
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_ESPI
+  }
+};
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI
+  This routine will also lock down ESPI_SMI_LOCK bit after registration and prevent
+  this handler from unregistration.
+  On platform that supports more than 1 device through another chip select (SPT-H),
+  the SMI handler itself needs to inspect both the eSPI devices' interrupt status registers
+  (implementation specific for each Slave) in order to identify and service the cause.
+  After servicing it, it has to clear the Slaves' internal SMI# status registers
+
+  @param[in]  This                      Not used
+  @param[in]  DispatchFunction          The callback to execute
+  @param[out] DispatchHandle            The handle for this callback registration
+
+  @retval     EFI_SUCCESS               Registration succeed
+  @retval     EFI_ACCESS_DENIED         Return access denied if the SmmReadyToLock event has been triggered
+  @retval     EFI_ACCESS_DENIED         The ESPI_SMI_LOCK is set and register is blocked.
+  @retval     others                    Registration failed
+**/
+EFI_STATUS
+EFIAPI
+EspiSlaveSmiRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // If ESPI_SMI_LOCK is set, the register is blocked.
+  //
+  if (PmcIsEspiSmiLockSet ()) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // @note: This service doesn't utilize the data base of mEspiSmiInstance.
+  //        While SMI is triggered it directly goes to the registing DispatchFunction
+  //        instead of EspiSmiCallback.
+  //
+  Status = PchSmiRecordInsert (
+             &mSrcDescEspiSlave,
+             (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
+             PchEspiSmiEspiSlaveType,
+             DispatchHandle
+             );
+  PchSmmClearSource (&mSrcDescEspiSlave);
+  PchSmmEnableSource (&mSrcDescEspiSlave);
+
+  //
+  // Lock down the ESPI_SMI_LOCK after ESPI SMI is enabled.
+  //
+  PmcLockEspiSmiWithS3BootScript ();
+  //
+  // Keep the DispatchHandle which will be used for unregister function.
+  //
+  mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] = *DispatchHandle;
+
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
+  }
+
+  return Status;
+}
+
+/**
+  eSPI SMI Dispatch Protocol instance to unregister a callback based on handle
+
+  @param[in]  This                    Not used
+  @param[in]  DispatchHandle          Handle acquired during registration
+
+  @retval     EFI_SUCCESS             Unregister successful
+  @retval     EFI_INVALID_PARAMETER   DispatchHandle is null
+  @retval     EFI_INVALID_PARAMETER   DispatchHandle's forward link has bad pointer
+  @retval     EFI_INVALID_PARAMETER   DispatchHandle does not exist in database
+  @retval     EFI_ACCESS_DENIED       Unregistration is done after end of DXE
+  @retval     EFI_ACCESS_DENIED       DispatchHandle is not allowed to unregistered
+**/
+EFI_STATUS
+EFIAPI
+EspiSmiUnRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  EFI_HANDLE                      DispatchHandle
+  )
+{
+  EFI_STATUS          Status;
+  ESPI_TOP_LEVEL_TYPE EspiTopLevelType;
+  ESPI_SMI_TYPE       EspiSmiType;
+  BOOLEAN             SafeToDisable;
+  LIST_ENTRY          *LinkInDb;
+  ESPI_SMI_RECORD     *RecordPointer;
+  DATABASE_RECORD    *RecordToDelete;
+
+  if (DispatchHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  if (((LIST_ENTRY *) DispatchHandle)->ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // For DispatchHandle belongs to Espi Slave SMI, refuses the request of unregistration.
+  //
+  if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] == DispatchHandle) {
+    DEBUG ((DEBUG_ERROR, "UnRegister is not allowed for ESPI Slave SMI handle! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Iterate through all the database to find the record
+  //
+  for (EspiSmiType = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
+    LinkInDb = GetFirstNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
+
+    while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb)) {
+      if (LinkInDb != (LIST_ENTRY *) DispatchHandle) {
+        LinkInDb = GetNextNode (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb);
+
+      } else {
+        //
+        // Found the source to be from this list
+        //
+        RemoveEntryList (LinkInDb);
+        RecordPointer = (ESPI_RECORD_FROM_LINK (LinkInDb));
+
+        if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
+          if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] == 0) {
+            EspiSmiDisableSource (EspiSmiType);
+          }
+        }
+
+        Status = gSmst->SmmFreePool (RecordPointer);
+        if (EFI_ERROR (Status)) {
+          ASSERT (FALSE);
+        }
+
+        goto EspiSmiUnRegisterEnd;
+      }
+    }
+  }
+  //
+  // If the code reach here, the handle passed in cannot be found
+  //
+  DEBUG ((DEBUG_ERROR, "eSPI SMI handle is not in record database \n"));
+  ASSERT (FALSE);
+  return EFI_INVALID_PARAMETER;
+
+EspiSmiUnRegisterEnd:
+
+  //
+  // Unregister and clear the handle from PchSmiDispatch
+  //
+  for (EspiTopLevelType = 0; EspiTopLevelType < EspiTopLevelTypeMax; ++EspiTopLevelType) {
+    SafeToDisable = TRUE;
+    //
+    // Checks all the child events that belongs to a top level status in PMC
+    //
+    for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start; EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End; ++EspiSmiType) {
+      if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
+        SafeToDisable = FALSE;
+      }
+    }
+    //
+    // Finally, disable the top level event in PMC
+    //
+    if (SafeToDisable) {
+      if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] != NULL) {
+        Status = PchSmmCoreUnRegister (NULL, mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType]);
+        ASSERT_EFI_ERROR (Status);
+        mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] = NULL;
+      }
+    }
+  }
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  if (!EFI_ERROR (Status)) {
+    SmiHandlerProfileUnregisterHandler (&gPchEspiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns AND maks for clearing eSPI channel registers errors statuses
+  In addition to common status bit we add channel specific erro bits to avoid clearing them
+
+  @param[in]  ChannelNumber           Channel number (0 for PC, 1 for VW, 2 for OOB, 3 for FA)
+
+  @retval     UINT32                  AND mask with all the status bit masked to not clear them by mistake
+**/
+UINT32
+GetEspiChannelStatusClearMask (
+  UINT8       ChannelNumber
+  )
+{
+  UINT32    Data32;
+
+  // Common error status bits for all channel registers
+  Data32 = B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES;
+
+  // Check channels for channel specific status bits
+  switch(ChannelNumber) {
+    case 0:   // Peripheral Channel specific status bits
+      Data32 |= B_ESPI_PCR_PCERR_PCURD;
+      break;
+    case 3:   // Flash Access Channel specific status bits
+      Data32 |= B_ESPI_PCR_FCERR_SAFBLK;
+      break;
+  }
+
+  // Return the expected AND mask
+  return (UINT32)~(Data32);
+}
+
+/**
+  Checks if channel error register data has Fatal Error bit set
+  If yes then reset the channel on slave
+
+  @param[in]  ChannelBaseAddress      Base address
+  @param[in]  ChannelNumber           Channel number (0 for PC, 1 for VW, 2 for OOB, 3 for FA)
+  @param[in]  SlaveId                 Slave ID of which channel is to be reset
+**/
+VOID
+CheckSlaveChannelErrorAndReset (
+  UINT16      ChannelBaseAddress,
+  UINT8       ChannelNumber,
+  UINT8       SlaveId
+  )
+{
+  UINT32      Data32;
+  UINT16      ChannelAddress;
+  EFI_STATUS  Status;
+
+  if (ChannelNumber == 2) {
+    DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function due to lack of error register\n", ChannelNumber));
+    return;
+  }
+
+  if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) {
+    DEBUG ((DEBUG_WARN, "Channel %d is not supported by slave device\n", ChannelNumber));
+    return;
+  }
+
+  // Calculate channel address based on slave id
+  ChannelAddress = (UINT16) (ChannelBaseAddress + (SlaveId * S_ESPI_PCR_XERR));
+
+  // Reading channel error register data
+  Data32 = PchPcrRead32 (PID_ESPISPI, ChannelAddress);
+
+  DEBUG ((DEBUG_INFO, "eSPI channel error register (0x%4X) has value 0x%8X\n", ChannelAddress, Data32));
+
+  // Check Fatal Error status bit in channel error register data
+  if ((Data32 & B_ESPI_PCR_XERR_XFES) != 0) {
+    Status = PchEspiSlaveChannelReset (SlaveId, ChannelNumber);
+
+    if (EFI_ERROR (Status)) {
+      switch (Status) {
+        case EFI_UNSUPPORTED:
+          DEBUG ((DEBUG_ERROR, "Slave doesn't support channel %d\n", ChannelNumber));
+          break;
+        case EFI_TIMEOUT:
+          DEBUG ((DEBUG_ERROR, "Timeout occured during channel %d reset on slave %d\n", ChannelNumber, SlaveId));
+          break;
+        default:
+          DEBUG ((DEBUG_ERROR, "Error occured during channel %d reset\n", ChannelNumber));
+          break;
+      }
+    } else {
+      DEBUG ((DEBUG_INFO, "eSPI Slave %d channel %d reset ended successfully\n", SlaveId, ChannelNumber));
+      // If channel reset was successfull clear the fatal error flag by writing one
+      // we should be aware not to clear other status bits by mistake and mask them
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        ChannelAddress,
+        GetEspiChannelStatusClearMask (ChannelNumber),
+        B_ESPI_PCR_XERR_XFES
+        );
+    }
+  }
+}
+
+/**
+  eSPI SMI handler for Fatal Error recovery flow
+**/
+VOID
+EspiDefaultFatalErrorHandler (
+  VOID
+  )
+{
+  UINT32      Data32;
+  UINT8       SlaveId;
+  UINT8       MaxSlavesCount;
+
+  DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Enter\n"));
+
+  MaxSlavesCount = IsEspiSecondSlaveSupported () ? 2 : 1;
+
+  DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount %d\n", MaxSlavesCount));
+
+  for (SlaveId = 0; SlaveId < MaxSlavesCount; ++SlaveId) {
+    //
+    // Check if slave has SLCRR bit set. If it does it means it needs recovery.
+    //
+    Data32 = PchPcrRead32 (PID_ESPISPI, (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)));
+
+    DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Slave %d LNKERR reg 0x%8X\n", SlaveId, Data32));
+    //
+    // If SLCRR[31] bit is set we need to recover that slave
+    //
+    if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) != 0) {
+      // 1. Perform in-band reset
+      PchEspiSlaveInBandReset (SlaveId);
+
+      // 2. Channels reset
+      CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 0, SlaveId); // Peripheral channel reset
+      CheckSlaveChannelErrorAndReset (R_ESPI_PCR_VWERR_SLV0, 1, SlaveId); // Virtual Wire channel reset
+
+      // Flash Access channel is not supported for CS1#
+      if (SlaveId == 0) {
+        CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 3, SlaveId); // Flash Access channel reset
+      }
+
+      // Clear SLCRR bit of slave after all channels recovery was done
+      PchPcrAndThenOr32 (
+        PID_ESPISPI,
+        (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)),
+        (UINT32)~(B_ESPI_PCR_LNKERR_SLV0_LFET1S),
+        (UINT32) (B_ESPI_PCR_LNKERR_SLV0_SLCRR)
+        );
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Exit\n"));
+}
+
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h
new file mode 100644
index 0000000000..4903464fae
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h
@@ -0,0 +1,341 @@
+/** @file
+  eSPI SMI Dispatch header
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCH_SMM_ESPI_H_
+#define _PCH_SMM_ESPI_H_
+
+#include "PchSmmHelpers.h"
+
+#define ESPI_SMI_INSTANCE_SIGNATURE       SIGNATURE_32 ('E', 'S', 'P', 'I')
+#define ESPI_SMI_RECORD_SIGNATURE         SIGNATURE_32 ('E', 'S', 'R', 'C')
+
+#define ESPI_INSTANCE_FROM_THIS(_this)      CR (_this, ESPI_SMI_INSTANCE, EfiEspiSmiDispatchProtocol, ESPI_SMI_INSTANCE_SIGNATURE)
+#define ESPI_RECORD_FROM_LINK(_link)        CR (_link, ESPI_SMI_RECORD, Link, ESPI_SMI_RECORD_SIGNATURE)
+
+typedef enum {
+  EspiBiosWrProtect,    ///< BIOS Write Protect
+  EspiSerialIrq,        ///< eSPI Master Asserted SMI
+  EspiPmc,              ///< eSPI PMC SMI
+  EspiTopLevelTypeMax
+} ESPI_TOP_LEVEL_TYPE;
+
+typedef enum {
+  BiosWrProtect,        ///< BIOS Write Protect
+  BiosWrReport,         ///< Peripheral Channel BIOS Write Protect
+  PcNonFatalErr,        ///< Peripheral Channel Non Fatal Error
+  PcFatalErr,           ///< Peripheral Channel Fatal Error
+  VwNonFatalErr,        ///< Virtual Wire Non Fatal Error
+  VwFatalErr,           ///< Virtual Wire Fatal Error
+  FlashNonFatalErr,     ///< Flash Channel Non Fatal Error
+  FlashFatalErr,        ///< Flash Channel Fatal Error
+  LnkType1Err,          ///< Link Error
+  EspiSlaveSmi,         ///< Espi Slave SMI
+  EspiSmiTypeMax
+} ESPI_SMI_TYPE;
+
+///
+/// This is used to classify ESPI_SMI_TYPE to ESPI_TOP_LEVEL_TYPE.
+/// Used during dispatching and unregistering
+///
+typedef struct {
+  ESPI_SMI_TYPE Start;
+  ESPI_SMI_TYPE End;
+} ESPI_SMI_TYPE_BARRIER;
+
+typedef struct _ESPI_SMI_INSTANCE {
+  ///
+  /// Signature associated with this instance
+  ///
+  UINT32                          Signature;
+  ///
+  /// EFI_HANDLE acquired when installing PchEspiSmiDispatchProtocol
+  ///
+  EFI_HANDLE                      Handle;
+  ///
+  /// The protocol to register or unregister eSPI SMI callbacks
+  ///
+  PCH_ESPI_SMI_DISPATCH_PROTOCOL  PchEspiSmiDispatchProtocol;
+  ///
+  /// The handle acquired when registering eSPI SMI callback to PchSmiDispatch
+  ///
+  EFI_HANDLE                      PchSmiEspiHandle[EspiTopLevelTypeMax];
+  ///
+  /// The linked list for record database.
+  ///
+  LIST_ENTRY                      CallbackDataBase[EspiSmiTypeMax];
+  ///
+  /// This is an internal counter to track the number of eSPI master events have been registered.
+  /// When unregistering, we can disable the SMI if the counter is zero
+  ///
+  UINTN                           EspiSmiEventCounter[EspiSmiTypeMax];
+  ///
+  /// Instance of barrier
+  ///
+  CONST ESPI_SMI_TYPE_BARRIER     Barrier[EspiTopLevelTypeMax];
+} ESPI_SMI_INSTANCE;
+
+typedef struct _ESPI_DESCRIPTOR {
+  PCH_SMM_ADDRESS   Address;
+  UINT32            SourceIsActiveAndMask;
+  UINT32            SourceIsActiveValue;
+  UINT32            ClearStatusAndMask;
+  UINT32            ClearStatusOrMask;
+} ESPI_DESCRIPTOR;
+
+///
+/// A simple record to store the callbacks associated with an eSPI SMI source
+///
+typedef struct _ESPI_SMI_RECORD {
+  UINT32                          Signature;
+  LIST_ENTRY                      Link;
+  PCH_ESPI_SMI_DISPATCH_CALLBACK  Callback;
+} ESPI_SMI_RECORD;
+
+/**
+  Installs and initialize this protocol
+
+  @param[in]  ImageHandle   Not used
+
+  @retval     EFI_SUCCESS   Installation succeed
+  @retval     others        Installation failed
+**/
+EFI_STATUS
+EFIAPI
+InstallEspiSmi (
+  IN EFI_HANDLE           ImageHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+BiosWrProtectRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a BIOS Write Report event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+BiosWrReportRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+PcNonFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+PcFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+VwNonFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+VwFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+FlashNonFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+FlashFatalErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a Link Error event
+
+  @param[in]  This              Not used
+  @param[in]  DispatchFunction  The callback to execute
+  @param[out] DispatchHandle    The handle for this callback registration
+
+  @retval     EFI_SUCCESS       Registration succeed
+  @retval     EFI_ACCESS_DENIED Return access denied if the SmmReadyToLock event has been triggered
+  @retval     others            Registration failed
+**/
+EFI_STATUS
+EFIAPI
+LnkType1ErrRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK  DispatchFunction,
+  OUT EFI_HANDLE                      *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI
+  NOTE: The register function is not available when the ESPI_SMI_LOCK bit is set.
+        This runtine will also lock donw ESPI_SMI_LOCK bit after registration and
+        prevent this handler from unregistration.
+  On platform that supports more than 1 device through another chip select (SPT-H),
+  the SMI handler itself needs to inspect both the eSPI devices' interrupt status registers
+  (implementation specific for each Slave) in order to identify and service the cause.
+  After servicing it, it has to clear the Slaves' internal SMI# status registers
+
+  @param[in]  This                      Not used
+  @param[in]  DispatchFunction          The callback to execute
+  @param[out] DispatchHandle            The handle for this callback registration
+
+  @retval     EFI_SUCCESS               Registration succeed
+  @retval     EFI_ACCESS_DENIED         Return access denied if the SmmReadyToLock event has been triggered
+  @retval     EFI_ACCESS_DENIED         The ESPI_SMI_LOCK is set and register is blocked.
+  @retval     others                    Registration failed
+**/
+EFI_STATUS
+EFIAPI
+EspiSlaveSmiRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL    *This,
+  IN  PCH_ESPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
+  OUT EFI_HANDLE                        *DispatchHandle
+  );
+
+/**
+  eSPI SMI Dispatch Protocol instance to unregister a callback based on handle
+
+  @param[in]  This                    Not used
+  @param[in]  DispatchHandle          Handle acquired during registration
+
+  @retval     EFI_SUCCESS             Unregister successful
+  @retval     EFI_INVALID_PARAMETER   DispatchHandle is null
+  @retval     EFI_INVALID_PARAMETER   DispatchHandle's forward link has bad pointer
+  @retval     EFI_INVALID_PARAMETER   DispatchHandle does not exist in database
+  @retval     EFI_ACCESS_DENIED       Unregistration is done after end of DXE
+  @retval     EFI_ACCESS_DENIED       DispatchHandle is not allowed to unregistered
+**/
+EFI_STATUS
+EFIAPI
+EspiSmiUnRegister (
+  IN  PCH_ESPI_SMI_DISPATCH_PROTOCOL  *This,
+  IN  EFI_HANDLE                      DispatchHandle
+  );
+
+/**
+  eSPI SMI handler for Fatal Error recovery flow
+
+  @param[in]  DispatchHandle          Handle acquired during registration
+**/
+VOID
+EspiDefaultFatalErrorHandler (
+  VOID
+  );
+
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c
new file mode 100644
index 0000000000..61f925c860
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c
@@ -0,0 +1,263 @@
+/** @file
+  File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmm.h"
+#include "PchSmmHelpers.h"
+#include <Library/SmiHandlerProfileLib.h>
+#include <Register/GpioRegs.h>
+#include <Register/PmcRegs.h>
+
+//
+// Structure for GPI SMI is a template which needs to have
+// GPI Smi bit offset and Smi Status & Enable registers updated (accordingly
+// to choosen group and pad number) after adding it to SMM Callback database
+//
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPchGpiSourceDescTemplate = {
+  PCH_SMM_NO_FLAGS,
+  {
+    NULL_BIT_DESC_INITIALIZER,
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        GPIO_ADDR_TYPE, {0x0}
+      },
+      S_GPIO_PCR_GP_SMI_STS, 0x0,
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_GPIO_SMI
+  }
+};
+
+/**
+  The register function used to register SMI handler of GPI SMI event.
+
+  @param[in]  This               Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
+  @param[in]  DispatchFunction   Function to register for handler when the specified GPI causes an SMI.
+  @param[in]  RegisterContext    Pointer to the dispatch function's context.
+                                 The caller fills this context in before calling
+                                 the register function to indicate to the register
+                                 function the GPI(s) for which the dispatch function
+                                 should be invoked.
+  @param[out] DispatchHandle     Handle generated by the dispatcher to track the
+                                 function instance.
+
+  @retval EFI_SUCCESS            The dispatch function has been successfully
+                                 registered and the SMI source has been enabled.
+  @retval EFI_ACCESS_DENIED      Register is not allowed
+  @retval EFI_INVALID_PARAMETER  RegisterContext is invalid. The GPI input value
+                                 is not within valid range.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough memory (system or SMM) to manage this child.
+**/
+EFI_STATUS
+EFIAPI
+PchGpiSmiRegister (
+  IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL  *This,
+  IN       EFI_SMM_HANDLER_ENTRY_POINT2    DispatchFunction,
+  IN       EFI_SMM_GPI_REGISTER_CONTEXT    *RegisterContext,
+  OUT      EFI_HANDLE                      *DispatchHandle
+  )
+{
+  EFI_STATUS                  Status;
+  DATABASE_RECORD             Record;
+  GPIO_PAD                    GpioPad;
+  UINT8                       GpiSmiBitOffset;
+  UINT32                      GpiHostSwOwnRegAddress;
+  UINT32                      GpiSmiStsRegAddress;
+  UINT32                      Data32Or;
+  UINT32                      Data32And;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  Status = GpioGetPadAndSmiRegs (
+             (UINT32) RegisterContext->GpiNum,
+             &GpioPad,
+             &GpiSmiBitOffset,
+             &GpiHostSwOwnRegAddress,
+             &GpiSmiStsRegAddress
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ZeroMem (&Record, sizeof (DATABASE_RECORD));
+
+  //
+  // Gather information about the registration request
+  //
+  Record.Callback          = DispatchFunction;
+  Record.ChildContext.Gpi  = *RegisterContext;
+  Record.ProtocolType      = GpiType;
+  Record.Signature         = DATABASE_RECORD_SIGNATURE;
+
+  CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof (PCH_SMM_SOURCE_DESC) );
+
+  Record.SrcDesc.Sts[0].Reg.Data.raw = GpiSmiStsRegAddress;  // GPI SMI Status register
+  Record.SrcDesc.Sts[0].Bit = GpiSmiBitOffset;               // Bit position for selected pad
+
+  //
+  // Insert GpiSmi handler to PchSmmCore database
+  //
+  *DispatchHandle = NULL;
+
+  Status = SmmCoreInsertRecord (
+             &Record,
+             DispatchHandle
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  SmiHandlerProfileRegisterHandler (
+    &gEfiSmmGpiDispatch2ProtocolGuid,
+    (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,
+    (UINTN)RETURN_ADDRESS (0),
+    RegisterContext,
+    sizeof(*RegisterContext)
+    );
+
+  //
+  // Enable GPI SMI
+  // HOSTSW_OWN with respect to generating GPI SMI has negative logic:
+  //  - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/SCI
+  //  - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI
+  //
+  Data32And  = (UINT32)~(1u << GpiSmiBitOffset);
+  MmioAnd32 (GpiHostSwOwnRegAddress, Data32And);
+
+  //
+  // Add HOSTSW_OWN programming into S3 boot script
+  //
+  Data32Or = 0;
+  S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, GpiHostSwOwnRegAddress, &Data32Or, &Data32And);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unregister a GPI SMI source dispatch function with a parent SMM driver
+
+  @param[in] This                 Pointer to the EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchHandle       Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS             The dispatch function has been successfully
+                                  unregistered and the SMI source has been disabled
+                                  if there are no other registered child dispatch
+                                  functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER   Handle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+PchGpiSmiUnRegister (
+  IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL  *This,
+  IN       EFI_HANDLE                      DispatchHandle
+  )
+{
+  EFI_STATUS      Status;
+  DATABASE_RECORD *RecordToDelete;
+  DATABASE_RECORD *RecordInDb;
+  LIST_ENTRY      *LinkInDb;
+  GPIO_PAD        GpioPad;
+  UINT8           GpiSmiBitOffset;
+  UINT32          GpiHostSwOwnRegAddress;
+  UINT32          GpiSmiStsRegAddress;
+  UINT32          Data32Or;
+  UINT32          Data32And;
+  BOOLEAN         DisableGpiSmiSource;
+
+
+  if (DispatchHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  if ((RecordToDelete->Signature != DATABASE_RECORD_SIGNATURE) ||
+      (RecordToDelete->ProtocolType != GpiType)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  DisableGpiSmiSource = TRUE;
+  //
+  // Loop through all sources in record linked list to see if any other GPI SMI
+  // is installed on the same pin. If no then disable GPI SMI capability on this pad
+  //
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+    //
+    // If this is the record to delete skip it
+    //
+    if (RecordInDb == RecordToDelete) {
+      continue;
+    }
+    //
+    // Check if record is GPI SMI type
+    //
+    if (RecordInDb->ProtocolType == GpiType) {
+      //
+      // Check if same GPIO pad is the source of this SMI
+      //
+      if (RecordInDb->ChildContext.Gpi.GpiNum == RecordToDelete->ChildContext.Gpi.GpiNum) {
+        DisableGpiSmiSource = FALSE;
+        break;
+      }
+    }
+  }
+
+  if (DisableGpiSmiSource) {
+    GpioGetPadAndSmiRegs (
+      (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum,
+      &GpioPad,
+      &GpiSmiBitOffset,
+      &GpiHostSwOwnRegAddress,
+      &GpiSmiStsRegAddress
+      );
+
+    Data32Or = 1u << GpiSmiBitOffset;
+    Data32And = 0xFFFFFFFF;
+    MmioOr32 (GpiHostSwOwnRegAddress, Data32Or);
+    S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, GpiHostSwOwnRegAddress, &Data32Or, &Data32And);
+  }
+
+
+  RemoveEntryList (&RecordToDelete->Link);
+  ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD));
+  Status = gSmst->SmmFreePool (RecordToDelete);
+
+  if (EFI_ERROR (Status)) {
+    ASSERT (FALSE);
+    return Status;
+  }
+  SmiHandlerProfileUnregisterHandler (
+    &gEfiSmmGpiDispatch2ProtocolGuid,
+    RecordToDelete->Callback,
+    &RecordToDelete->ChildContext,
+    RecordToDelete->ContextSize
+    );
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c
new file mode 100644
index 0000000000..6bbf9ea8e8
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.c
@@ -0,0 +1,332 @@
+/** @file
+  Helper functions for PCH SMM dispatcher.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Register/PmcRegs.h>
+
+///
+/// #define BIT_ZERO 0x00000001
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32  BIT_ZERO = 0x00000001;
+
+///
+/// SUPPORT / HELPER FUNCTIONS (PCH version-independent)
+///
+
+/**
+  Compare 2 SMM source descriptors' enable settings.
+
+  @param[in] Src1                 Pointer to the PCH SMI source description table 1
+  @param[in] Src2                 Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The enable settings of the 2 SMM source descriptors are identical.
+  @retval FALSE                   The enable settings of the 2 SMM source descriptors are not identical.
+**/
+BOOLEAN
+CompareEnables (
+  CONST IN PCH_SMM_SOURCE_DESC *Src1,
+  CONST IN PCH_SMM_SOURCE_DESC *Src2
+  )
+{
+  BOOLEAN IsEqual;
+  UINTN   DescIndex;
+
+  IsEqual = TRUE;
+  for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+    ///
+    /// It's okay to compare a NULL bit description to a non-NULL bit description.
+    /// They are unequal and these tests will generate the correct result.
+    ///
+    if (Src1->En[DescIndex].Bit != Src2->En[DescIndex].Bit ||
+        Src1->En[DescIndex].Reg.Type != Src2->En[DescIndex].Reg.Type ||
+        Src1->En[DescIndex].Reg.Data.raw != Src2->En[DescIndex].Reg.Data.raw
+        ) {
+      IsEqual = FALSE;
+      break;
+      ///
+      /// out of for loop
+      ///
+    }
+  }
+
+  return IsEqual;
+}
+
+/**
+  Compare a bit descriptor to the enables of source descriptor. Includes null address type.
+
+  @param[in] BitDesc              Pointer to the PCH SMI bit descriptor
+  @param[in] Src                  Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The bit desc is equal to any of the enables in source descriptor
+  @retval FALSE                   The bid desc is not equal to all of the enables in source descriptor
+**/
+BOOLEAN
+IsBitEqualToAnySourceEn (
+  CONST IN PCH_SMM_BIT_DESC    *BitDesc,
+  CONST IN PCH_SMM_SOURCE_DESC *Src
+  )
+{
+  BOOLEAN IsEqual;
+  UINTN   DescIndex;
+
+  IsEqual = FALSE;
+
+  for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
+    if ((BitDesc->Reg.Type == Src->En[DescIndex].Reg.Type) &&
+        (BitDesc->Reg.Data.raw == Src->En[DescIndex].Reg.Data.raw) &&
+        (BitDesc->Bit == Src->En[DescIndex].Bit)) {
+      IsEqual = TRUE;
+      break;
+    }
+  }
+  return IsEqual;
+}
+
+/**
+  Compare 2 SMM source descriptors' statuses.
+
+  @param[in] Src1                 Pointer to the PCH SMI source description table 1
+  @param[in] Src2                 Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The statuses of the 2 SMM source descriptors are identical.
+  @retval FALSE                   The statuses of the 2 SMM source descriptors are not identical.
+**/
+BOOLEAN
+CompareStatuses (
+  CONST IN PCH_SMM_SOURCE_DESC *Src1,
+  CONST IN PCH_SMM_SOURCE_DESC *Src2
+  )
+{
+  BOOLEAN IsEqual;
+  UINTN   DescIndex;
+
+  IsEqual = TRUE;
+
+  for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+    ///
+    /// It's okay to compare a NULL bit description to a non-NULL bit description.
+    /// They are unequal and these tests will generate the correct result.
+    ///
+    if (Src1->Sts[DescIndex].Bit != Src2->Sts[DescIndex].Bit ||
+        Src1->Sts[DescIndex].Reg.Type != Src2->Sts[DescIndex].Reg.Type ||
+        Src1->Sts[DescIndex].Reg.Data.raw != Src2->Sts[DescIndex].Reg.Data.raw
+        ) {
+      IsEqual = FALSE;
+      break;
+      ///
+      /// out of for loop
+      ///
+    }
+  }
+
+  return IsEqual;
+}
+
+/**
+  Compare 2 SMM source descriptors, based on Enable settings and Status settings of them.
+
+  @param[in] Src1                 Pointer to the PCH SMI source description table 1
+  @param[in] Src2                 Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The 2 SMM source descriptors are identical.
+  @retval FALSE                   The 2 SMM source descriptors are not identical.
+**/
+BOOLEAN
+CompareSources (
+  CONST IN PCH_SMM_SOURCE_DESC *Src1,
+  CONST IN PCH_SMM_SOURCE_DESC *Src2
+  )
+{
+  return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2));
+}
+
+/**
+  Check if an SMM source is active.
+
+  @param[in] Src                  Pointer to the PCH SMI source description table
+  @param[in] SciEn                Indicate if SCI is enabled or not
+  @param[in] SmiEnValue           Value from R_ACPI_IO_SMI_EN
+  @param[in] SmiStsValue          Value from R_ACPI_IO_SMI_STS
+
+  @retval TRUE                    It is active.
+  @retval FALSE                   It is inactive.
+**/
+BOOLEAN
+SourceIsActive (
+  CONST IN PCH_SMM_SOURCE_DESC  *Src,
+  CONST IN BOOLEAN              SciEn,
+  CONST IN UINT32               SmiEnValue,
+  CONST IN UINT32               SmiStsValue
+  )
+{
+  UINTN   DescIndex;
+
+  ///
+  /// This source is dependent on SciEn, and SciEn == 1.  An ACPI OS is present,
+  /// so we shouldn't do anything w/ this source until SciEn == 0.
+  ///
+  if ((Src->Flags == PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) {
+    return FALSE;
+  }
+
+  ///
+  /// Checking top level SMI status. If the status is not active, return false immediately
+  ///
+  if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) {
+    if ((Src->PmcSmiSts.Reg.Type == ACPI_ADDR_TYPE) &&
+        (Src->PmcSmiSts.Reg.Data.acpi == R_ACPI_IO_SMI_STS) &&
+        ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) == 0)) {
+      return FALSE;
+    }
+  }
+
+  ///
+  /// Read each bit desc from hardware and make sure it's a one
+  ///
+  for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+    if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) {
+      if ((Src->En[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
+          (Src->En[DescIndex].Reg.Data.acpi == R_ACPI_IO_SMI_EN) &&
+          ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) == 0)) {
+        return FALSE;
+      } else if (ReadBitDesc (&Src->En[DescIndex]) == 0) {
+        return FALSE;
+      }
+    }
+  }
+
+  ///
+  /// Read each bit desc from hardware and make sure it's a one
+  ///
+  for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+    if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) {
+      if ((Src->Sts[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
+          (Src->Sts[DescIndex].Reg.Data.acpi == R_ACPI_IO_SMI_STS) &&
+          ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) == 0)) {
+        return FALSE;
+      } else if (ReadBitDesc (&Src->Sts[DescIndex]) == 0) {
+        return FALSE;
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+  Enable the SMI source event by set the SMI enable bit, this function would also clear SMI
+  status bit to make initial state is correct
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmEnableSource (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  )
+{
+  UINTN DescIndex;
+
+  ///
+  /// Set enables to 1 by writing a 1
+  ///
+  for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
+      WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE);
+    }
+  }
+  ///
+  /// Clear statuses to 0 by writing a 1
+  ///
+  for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
+      WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
+    }
+  }
+}
+
+/**
+  Disable the SMI source event by clear the SMI enable bit
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmDisableSource (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  )
+{
+  UINTN DescIndex;
+
+  for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
+      WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE);
+    }
+  }
+}
+
+/**
+  Clear the SMI status bit by set the source bit of SMI status register
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmClearSource (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  )
+{
+  UINTN DescIndex;
+
+  for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
+      WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
+    }
+  }
+}
+
+/**
+  Sets the source to a 1 and then waits for it to clear.
+  Be very careful when calling this function -- it will not
+  ASSERT.  An acceptable case to call the function is when
+  waiting for the NEWCENTURY_STS bit to clear (which takes
+  3 RTCCLKs).
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmClearSourceAndBlock (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  )
+{
+  UINTN   DescIndex;
+  BOOLEAN IsSet;
+
+  for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+
+    if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
+      ///
+      /// Write the bit
+      ///
+      WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
+
+      ///
+      /// Don't return until the bit actually clears.
+      ///
+      IsSet = TRUE;
+      while (IsSet) {
+        IsSet = ReadBitDesc (&SrcDesc->Sts[DescIndex]);
+        ///
+        /// IsSet will eventually clear -- or else we'll have
+        /// an infinite loop.
+        ///
+      }
+    }
+  }
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h
new file mode 100644
index 0000000000..db7713fa02
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpers.h
@@ -0,0 +1,155 @@
+/** @file
+  Helper functions for PCH SMM
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef PCH_SMM_HELPERS_H
+#define PCH_SMM_HELPERS_H
+
+#include "PchSmm.h"
+#include "PchxSmmHelpers.h"
+//
+// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SUPPORT / HELPER FUNCTIONS (PCH version-independent)
+//
+
+/**
+  Publish SMI Dispatch protocols.
+
+
+**/
+VOID
+PchSmmPublishDispatchProtocols (
+  VOID
+  );
+
+/**
+  Compare 2 SMM source descriptors' enable settings.
+
+  @param[in] Src1                 Pointer to the PCH SMI source description table 1
+  @param[in] Src2                 Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The enable settings of the 2 SMM source descriptors are identical.
+  @retval FALSE                   The enable settings of the 2 SMM source descriptors are not identical.
+**/
+BOOLEAN
+CompareEnables (
+  CONST IN PCH_SMM_SOURCE_DESC *Src1,
+  CONST IN PCH_SMM_SOURCE_DESC *Src2
+  );
+
+/**
+  Compare a bit descriptor to the enables of source descriptor. Includes null address type.
+
+  @param[in] BitDesc              Pointer to the PCH SMI bit descriptor
+  @param[in] Src                  Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The bit desc is equal to any of the enables in source descriptor
+  @retval FALSE                   The bid desc is not equal to all of the enables in source descriptor
+**/
+BOOLEAN
+IsBitEqualToAnySourceEn (
+  CONST IN PCH_SMM_BIT_DESC    *BitDesc,
+  CONST IN PCH_SMM_SOURCE_DESC *Src
+  );
+
+/**
+  Compare 2 SMM source descriptors' statuses.
+
+  @param[in] Src1                 Pointer to the PCH SMI source description table 1
+  @param[in] Src2                 Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The statuses of the 2 SMM source descriptors are identical.
+  @retval FALSE                   The statuses of the 2 SMM source descriptors are not identical.
+**/
+BOOLEAN
+CompareStatuses (
+  CONST IN PCH_SMM_SOURCE_DESC *Src1,
+  CONST IN PCH_SMM_SOURCE_DESC *Src2
+  );
+
+/**
+  Compare 2 SMM source descriptors, based on Enable settings and Status settings of them.
+
+  @param[in] Src1                 Pointer to the PCH SMI source description table 1
+  @param[in] Src2                 Pointer to the PCH SMI source description table 2
+
+  @retval TRUE                    The 2 SMM source descriptors are identical.
+  @retval FALSE                   The 2 SMM source descriptors are not identical.
+**/
+BOOLEAN
+CompareSources (
+  CONST IN PCH_SMM_SOURCE_DESC *Src1,
+  CONST IN PCH_SMM_SOURCE_DESC *Src2
+  );
+
+/**
+  Check if an SMM source is active.
+
+  @param[in] Src                  Pointer to the PCH SMI source description table
+  @param[in] SciEn                Indicate if SCI is enabled or not
+  @param[in] SmiEnValue           Value from R_PCH_SMI_EN
+  @param[in] SmiStsValue          Value from R_PCH_SMI_STS
+
+  @retval TRUE                    It is active.
+  @retval FALSE                   It is inactive.
+**/
+BOOLEAN
+SourceIsActive (
+  CONST IN PCH_SMM_SOURCE_DESC  *Src,
+  CONST IN BOOLEAN              SciEn,
+  CONST IN UINT32               SmiEnValue,
+  CONST IN UINT32               SmiStsValue
+  );
+
+/**
+  Enable the SMI source event by set the SMI enable bit, this function would also clear SMI
+  status bit to make initial state is correct
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmEnableSource (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  );
+
+/**
+  Disable the SMI source event by clear the SMI enable bit
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmDisableSource (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  );
+
+/**
+  Clear the SMI status bit by set the source bit of SMI status register
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmClearSource (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  );
+
+/**
+  Sets the source to a 1 and then waits for it to clear.
+  Be very careful when calling this function -- it will not
+  ASSERT.  An acceptable case to call the function is when
+  waiting for the NEWCENTURY_STS bit to clear (which takes
+  3 RTCCLKs).
+
+  @param[in] SrcDesc              Pointer to the PCH SMI source description table
+
+**/
+VOID
+PchSmmClearSourceAndBlock (
+  CONST PCH_SMM_SOURCE_DESC *SrcDesc
+  );
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c
new file mode 100644
index 0000000000..3c3e638cbf
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c
@@ -0,0 +1,667 @@
+/** @file
+  File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Protocol/PchSmmPeriodicTimerControl.h>
+#include <Library/PmcPrivateLib.h>
+
+//
+// There is only one instance for PeriodicTimerCommBuffer.
+// It's safe in SMM since there is no re-entry for the function.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_PERIODIC_TIMER_CONTEXT          mPchPeriodicTimerCommBuffer;
+
+typedef enum {
+  PERIODIC_TIMER= 0,
+  SWSMI_TIMER,
+  NUM_TIMERS
+} SUPPORTED_TIMER;
+
+typedef struct _TIMER_INTERVAL {
+  UINT64  Interval;
+  UINT8   AssociatedTimer;
+} TIMER_INTERVAL;
+
+#define NUM_INTERVALS 8
+
+//
+// Time constants, in 100 nano-second units
+//
+#define TIME_64s    640000000 ///< 64   s
+#define TIME_32s    320000000 ///< 32   s
+#define TIME_16s    160000000 ///< 16   s
+#define TIME_8s     80000000  ///<  8   s
+#define TIME_64ms   640000    ///< 64   ms
+#define TIME_32ms   320000    ///< 32   ms
+#define TIME_16ms   160000    ///< 16   ms
+#define TIME_1_5ms  15000     ///< 1.5  ms
+
+typedef enum {
+  INDEX_TIME_64s  = 0,
+  INDEX_TIME_32s,
+  INDEX_TIME_16s,
+  INDEX_TIME_8s,
+  INDEX_TIME_64ms,
+  INDEX_TIME_32ms,
+  INDEX_TIME_16ms,
+  INDEX_TIME_1_5ms,
+  INDEX_TIME_MAX
+} TIMER_INTERVAL_INDEX;
+
+static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] = {
+  {
+    TIME_64s,
+    PERIODIC_TIMER
+  },
+  {
+    TIME_32s,
+    PERIODIC_TIMER
+  },
+  {
+    TIME_16s,
+    PERIODIC_TIMER
+  },
+  {
+    TIME_8s,
+    PERIODIC_TIMER
+  },
+  {
+    TIME_64ms,
+    SWSMI_TIMER
+  },
+  {
+    TIME_32ms,
+    SWSMI_TIMER
+  },
+  {
+    TIME_16ms,
+    SWSMI_TIMER
+  },
+  {
+    TIME_1_5ms,
+    SWSMI_TIMER
+  },
+};
+
+typedef struct _TIMER_INFO {
+  UINTN   NumChildren;        ///< number of children using this timer
+  UINT64  MinReqInterval;     ///< minimum interval required by children
+  UINTN   CurrentSetting;     ///< interval this timer is set at right now (index into interval table)
+} TIMER_INFO;
+
+GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO          mTimers[NUM_TIMERS];
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mTimerSourceDesc[NUM_TIMERS] = {
+  {
+    PCH_SMM_NO_FLAGS,
+    {
+      {
+        {
+          ACPI_ADDR_TYPE,
+          {R_ACPI_IO_SMI_EN}
+        },
+        S_ACPI_IO_SMI_EN,
+        N_ACPI_IO_SMI_EN_PERIODIC
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          ACPI_ADDR_TYPE,
+          {R_ACPI_IO_SMI_STS}
+        },
+        S_ACPI_IO_SMI_STS,
+        N_ACPI_IO_SMI_STS_PERIODIC
+      }
+    },
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_PERIODIC
+    }
+  },
+  {
+    PCH_SMM_NO_FLAGS,
+    {
+      {
+        {
+          ACPI_ADDR_TYPE,
+          {R_ACPI_IO_SMI_EN}
+        },
+        S_ACPI_IO_SMI_EN,
+        N_ACPI_IO_SMI_EN_SWSMI_TMR
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          ACPI_ADDR_TYPE,
+          {R_ACPI_IO_SMI_STS}
+        },
+        S_ACPI_IO_SMI_STS,
+        N_ACPI_IO_SMI_STS_SWSMI_TMR
+      }
+    },
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_SWSMI_TMR
+    }
+  }
+};
+
+/**
+  Program Smm Periodic Timer
+
+  @param[in] SrcDesc              Pointer to the PCH_SMM_SOURCE_DESC instance.
+**/
+VOID
+PchSmmPeriodicTimerProgramTimers (
+  IN CONST PCH_SMM_SOURCE_DESC    *SrcDesc
+  );
+
+/**
+  Convert the dispatch context to the timer interval, this function will assert if then either:
+  (1) The context contains an invalid interval
+  (2) The timer interval table is corrupt
+
+  @param[in] DispatchContext      The pointer to the Dispatch Context
+
+  @retval TIMER_INTERVAL          The timer interval of input dispatch context
+**/
+TIMER_INTERVAL *
+ContextToTimerInterval (
+  IN  PCH_SMM_CONTEXT     *DispatchContext
+  )
+{
+  UINTN loopvar;
+
+  ///
+  /// Determine which timer this child is using
+  ///
+  for (loopvar = 0; loopvar < NUM_INTERVALS; loopvar++) {
+    if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) &&
+         (DispatchContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
+        (DispatchContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)) {
+      return &mSmmPeriodicTimerIntervals[loopvar];
+    }
+  }
+  ///
+  /// If this assertion fires, then either:
+  ///    (1) the context contains an invalid interval
+  ///    (2) the timer interval table is corrupt
+  ///
+  ASSERT (FALSE);
+
+  return NULL;
+}
+
+/**
+  Figure out which timer the child is requesting and
+  send back the source description
+
+  @param[in] DispatchContext      The pointer to the Dispatch Context instances
+  @param[out] SrcDesc             The pointer to the source description
+
+**/
+VOID
+MapPeriodicTimerToSrcDesc (
+  IN  PCH_SMM_CONTEXT             *DispatchContext,
+  OUT PCH_SMM_SOURCE_DESC         *SrcDesc
+  )
+{
+  TIMER_INTERVAL  *TimerInterval;
+
+  ///
+  /// Figure out which timer the child is requesting and
+  /// send back the source description
+  ///
+  TimerInterval = ContextToTimerInterval (DispatchContext);
+  if (TimerInterval == NULL) {
+    return;
+  }
+
+  CopyMem (
+    (VOID *) SrcDesc,
+    (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]),
+    sizeof (PCH_SMM_SOURCE_DESC)
+    );
+
+  ///
+  /// Program the value of the interval into hardware
+  ///
+  PchSmmPeriodicTimerProgramTimers (SrcDesc);
+}
+
+/**
+  Update the elapsed time from the Interval data of DATABASE_RECORD
+
+  @param[in] Record               The pointer to the DATABASE_RECORD.
+  @param[out] HwContext           The Context to be updated.
+
+**/
+VOID
+EFIAPI
+PeriodicTimerGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT PCH_SMM_CONTEXT    *HwContext
+  )
+{
+  TIMER_INTERVAL  *TimerInterval;
+
+  ASSERT (Record->ProtocolType == PeriodicTimerType);
+
+  TimerInterval = ContextToTimerInterval (&Record->ChildContext);
+  if (TimerInterval == NULL) {
+    return;
+  }
+  ///
+  /// Ignore the hardware context. It's not required for this protocol.
+  /// Instead, just increment the child's context.
+  /// Update the elapsed time w/ the data from our tables
+  ///
+  Record->MiscData.ElapsedTime += mTimers[TimerInterval->AssociatedTimer].MinReqInterval;
+  *HwContext = Record->ChildContext;
+}
+
+/**
+  Check whether Periodic Timer of two contexts match
+
+  @param[in] Context1             Context 1 that includes Periodic Timer  1
+  @param[in] Context2             Context 2 that includes Periodic Timer  2
+
+  @retval FALSE                   Periodic Timer match
+  @retval TRUE                    Periodic Timer don't match
+**/
+BOOLEAN
+EFIAPI
+PeriodicTimerCmpContext (
+  IN PCH_SMM_CONTEXT     *HwContext,
+  IN PCH_SMM_CONTEXT     *ChildContext
+  )
+{
+  DATABASE_RECORD        *Record;
+  Record = DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext);
+
+  if (!Record->MiscData.TimerSmiEnabled) {
+    return FALSE;
+  }
+  if (Record->MiscData.ElapsedTime >= ChildContext->PeriodicTimer.Period) {
+    ///
+    /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffer
+    ///
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
+
+  @param[in]  Record              No use
+  @param[out] CommBuffer          Point to the CommBuffer structure
+  @param[out] CommBufferSize      Point to the Size of CommBuffer structure
+
+**/
+VOID
+EFIAPI
+PeriodicTimerGetCommBuffer (
+  IN  DATABASE_RECORD    *Record,
+  OUT VOID               **CommBuffer,
+  OUT UINTN              *CommBufferSize
+  )
+{
+  ASSERT (Record->ProtocolType == PeriodicTimerType);
+
+  mPchPeriodicTimerCommBuffer.ElapsedTime = Record->MiscData.ElapsedTime;
+
+  ///
+  /// For EDKII, the ElapsedTime is reset here
+  ///
+  Record->MiscData.ElapsedTime = 0;
+
+  ///
+  /// Return the CommBuffer
+  ///
+  *CommBuffer = (VOID *) &mPchPeriodicTimerCommBuffer;
+  *CommBufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
+}
+
+/**
+  Program Smm Periodic Timer
+
+  @param[in] SrcDesc              Pointer to the PCH_SMM_SOURCE_DESC instance.
+**/
+VOID
+PchSmmPeriodicTimerProgramTimers (
+  IN CONST PCH_SMM_SOURCE_DESC    *SrcDesc
+  )
+{
+  SUPPORTED_TIMER Timer;
+  DATABASE_RECORD *RecordInDb;
+  LIST_ENTRY      *LinkInDb;
+  TIMER_INTERVAL  *TimerInterval;
+
+  ///
+  /// Find the minimum required interval for each timer
+  ///
+  for (Timer = 0; Timer < NUM_TIMERS; Timer++) {
+    mTimers[Timer].MinReqInterval = ~ (UINT64) 0x0;
+    mTimers[Timer].NumChildren    = 0;
+  }
+
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+    if (RecordInDb->ProtocolType == PeriodicTimerType) {
+      if (RecordInDb->MiscData.TimerSmiEnabled) {
+        ///
+        /// This child is registerd with the PeriodicTimer protocol
+        ///
+        TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
+        if (TimerInterval == NULL) {
+          return;
+        }
+
+        Timer = TimerInterval->AssociatedTimer;
+        if (Timer < 0 || Timer >= NUM_TIMERS) {
+          ASSERT (FALSE);
+          CpuDeadLoop ();
+          return;
+        }
+        if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {
+          mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;
+        }
+        mTimers[Timer].NumChildren++;
+      }
+    }
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+  }
+  ///
+  /// Program the hardware
+  ///
+  if (mTimers[PERIODIC_TIMER].NumChildren > 0) {
+    switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
+      case TIME_64s:
+        PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s);
+        mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
+        break;
+
+      case TIME_32s:
+        PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s);
+        mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
+        break;
+
+      case TIME_16s:
+        PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s);
+        mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
+        break;
+
+      case TIME_8s:
+        PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s);
+        mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
+        break;
+
+      default:
+        ASSERT (FALSE);
+        break;
+    }
+
+    ///
+    /// Restart the timer here, just need to clear the SMI
+    ///
+    if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_PERIODIC) {
+      PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]);
+    }
+  } else {
+    PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]);
+  }
+
+  if (mTimers[SWSMI_TIMER].NumChildren > 0) {
+    switch (mTimers[SWSMI_TIMER].MinReqInterval) {
+      case TIME_64ms:
+        PmcSetSwSmiRate (PmcSwSmiRate64ms);
+        mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms;
+        break;
+
+      case TIME_32ms:
+        PmcSetSwSmiRate (PmcSwSmiRate32ms);
+        mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms;
+        break;
+
+      case TIME_16ms:
+        PmcSetSwSmiRate (PmcSwSmiRate16ms);
+        mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms;
+        break;
+
+      case TIME_1_5ms:
+        PmcSetSwSmiRate (PmcSwSmiRate1p5ms);
+        mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
+        break;
+
+      default:
+        ASSERT (FALSE);
+        break;
+    }
+
+    ///
+    /// Restart the timer here, need to disable, clear, then enable to restart this timer
+    ///
+    if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_SWSMI_TMR) {
+      PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]);
+      PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]);
+      PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]);
+    }
+  } else {
+    PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]);
+  }
+}
+
+/**
+  This services returns the next SMI tick period that is supported by the chipset.
+  The order returned is from longest to shortest interval period.
+
+  @param[in] This                 Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
+  @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child.
+
+  @retval EFI_SUCCESS             The service returned successfully.
+  @retval EFI_INVALID_PARAMETER   The parameter SmiTickInterval is invalid.
+**/
+EFI_STATUS
+PchSmmPeriodicTimerDispatchGetNextShorterInterval (
+  IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL  *This,
+  IN OUT   UINT64                                     **SmiTickInterval
+  )
+{
+  TIMER_INTERVAL  *IntervalPointer;
+
+  ASSERT (SmiTickInterval != NULL);
+
+  IntervalPointer = (TIMER_INTERVAL *) *SmiTickInterval;
+
+  if (IntervalPointer == NULL) {
+    ///
+    /// The first time child requesting an interval
+    ///
+    IntervalPointer = &mSmmPeriodicTimerIntervals[0];
+  } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) {
+    ///
+    /// At end of the list
+    ///
+    IntervalPointer = NULL;
+  } else {
+    if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&
+        (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1])
+        ) {
+      ///
+      /// Get the next interval in the list
+      ///
+      IntervalPointer++;
+    } else {
+      ///
+      /// Input is out of range
+      ///
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  if (IntervalPointer != NULL) {
+    *SmiTickInterval = &IntervalPointer->Interval;
+  } else {
+    *SmiTickInterval = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is responsible for calculating and enabling any timers that are required
+  to dispatch messages to children. The SrcDesc argument isn't acutally used.
+
+  @param[in] SrcDesc              Pointer to the PCH_SMM_SOURCE_DESC instance.
+
+**/
+VOID
+EFIAPI
+PchSmmPeriodicTimerClearSource (
+  IN CONST PCH_SMM_SOURCE_DESC    *SrcDesc
+  )
+{
+  PchSmmPeriodicTimerProgramTimers (SrcDesc);
+}
+
+
+/**
+  Check if the handle is in type of PeriodicTimer
+
+  @retval TRUE                          The handle is in type of PeriodicTimer.
+  @retval FALSE                         The handle is not in type of PeriodicTimer.
+**/
+BOOLEAN
+IsSmmPeriodicTimerHandle (
+  IN EFI_HANDLE                         DispatchHandle
+  )
+{
+  DATABASE_RECORD                       *RecordInDb;
+  LIST_ENTRY                            *LinkInDb;
+
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    if (DispatchHandle == (EFI_HANDLE) LinkInDb) {
+      RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+      if (RecordInDb->ProtocolType == PeriodicTimerType) {
+        return TRUE;
+      }
+    }
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);
+  }
+  return FALSE;
+}
+
+/**
+  Pause SMM periodic timer callback function.
+
+  This function disable the SMI enable of SMI timer according to the DispatchHandle,
+  which is returned by SMM periodic timer callback registration.
+
+  @retval EFI_SUCCESS                   This operation is complete.
+  @retval EFI_INVALID_PARAMETER         The DispatchHandle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+PchSmmPeriodicTimerControlPause (
+  IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL      *This,
+  IN EFI_HANDLE                                   DispatchHandle
+  )
+{
+  DATABASE_RECORD                       *RecordInDb;
+
+  if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  RecordInDb->MiscData.TimerSmiEnabled = FALSE;
+  //
+  // reset the timer interval per SMI trigger due to stop a periodic timer SMI
+  //
+  PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc);
+  return EFI_SUCCESS;
+}
+
+/**
+  Resume SMM periodic timer callback function.
+
+  This function enable the SMI enable of SMI timer according to the DispatchHandle,
+  which is returned by SMM periodic timer callback registration.
+
+  @retval EFI_SUCCESS                   This operation is complete.
+  @retval EFI_INVALID_PARAMETER         The DispatchHandle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+PchSmmPeriodicTimerControlResume (
+  IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL      *This,
+  IN EFI_HANDLE                                   DispatchHandle
+  )
+{
+  DATABASE_RECORD                       *RecordInDb;
+
+  if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) {
+    return EFI_INVALID_PARAMETER;
+  }
+  RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+  RecordInDb->MiscData.TimerSmiEnabled = TRUE;
+  //
+  // reset the timer interval per SMI trigger due to resume a periodic timer SMI
+  //
+  PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc);
+  return EFI_SUCCESS;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL mPchSmmPeriodicTimerControlProtocol = {
+  PchSmmPeriodicTimerControlPause,
+  PchSmmPeriodicTimerControlResume
+};
+
+/**
+  Install PCH SMM periodic timer control protocol
+
+  @param[in] Handle                     handle for this driver
+
+  @retval EFI_SUCCESS                   Driver initialization completed successfully
+**/
+EFI_STATUS
+EFIAPI
+InstallPchSmmPeriodicTimerControlProtocol (
+  IN EFI_HANDLE                         Handle
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Install protocol interface
+  //
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &Handle,
+                    &gPchSmmPeriodicTimerControlGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mPchSmmPeriodicTimerControlProtocol
+                    );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c
new file mode 100644
index 0000000000..bfed944848
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowerButton.c
@@ -0,0 +1,81 @@
+/** @file
+  File to contain all the hardware specific stuff for the Smm Power Button dispatch protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <PchSmmHelpers.h>
+#include <Library/PmcPrivateLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc = {
+  PCH_SMM_SCI_EN_DEPENDENT,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_PM1_EN}
+      },
+      S_ACPI_IO_PM1_EN,
+      N_ACPI_IO_PM1_EN_PWRBTN
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_PM1_STS}
+      },
+      S_ACPI_IO_PM1_STS,
+      N_ACPI_IO_PM1_STS_PWRBTN
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_PM1_STS_REG
+  }
+};
+
+/**
+  Get the power button status.
+
+  @param[in] Record               The pointer to the DATABASE_RECORD.
+  @param[out] Context             Calling context from the hardware, will be updated with the current power button status.
+
+**/
+VOID
+EFIAPI
+PowerButtonGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT PCH_SMM_CONTEXT    *Context
+  )
+{
+  if (PmcGetPwrBtnLevel ()) {
+    Context->PowerButton.Phase = EfiPowerButtonExit;
+  } else {
+    Context->PowerButton.Phase = EfiPowerButtonEntry;
+  }
+}
+
+/**
+  Check whether Power Button status of two contexts match
+
+  @param[in] Context1             Context 1 that includes Power Button status 1
+  @param[in] Context2             Context 2 that includes Power Button status 2
+
+  @retval FALSE                   Power Button status match
+  @retval TRUE                    Power Button status don't match
+**/
+BOOLEAN
+EFIAPI
+PowerButtonCmpContext (
+  IN PCH_SMM_CONTEXT     *Context1,
+  IN PCH_SMM_CONTEXT     *Context2
+  )
+{
+  return (BOOLEAN) (Context1->PowerButton.Phase == Context2->PowerButton.Phase);
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c
new file mode 100644
index 0000000000..9b13bf6308
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c
@@ -0,0 +1,381 @@
+/** @file
+  File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Protocol/SmmCpu.h>
+#include <Register/PchRegsLpc.h>
+#include <Register/PmcRegs.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL          *mSmmCpuProtocol;
+
+STATIC LIST_ENTRY                       mSwSmiCallbackDataBase;
+
+//
+// "SWSMI" RECORD
+// Linked list data structures
+//
+#define SW_SMI_RECORD_SIGNATURE         SIGNATURE_32 ('S', 'W', 'S', 'M')
+
+#define SW_SMI_RECORD_FROM_LINK(_record)  CR (_record, SW_SMI_RECORD, Link, SW_SMI_RECORD_SIGNATURE)
+
+typedef struct {
+  UINT32                                Signature;
+  LIST_ENTRY                            Link;
+  EFI_SMM_SW_REGISTER_CONTEXT           Context;
+  EFI_SMM_HANDLER_ENTRY_POINT2          Callback;
+} SW_SMI_RECORD;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSwSourceDesc = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_APMC
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_APM
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_APM
+  }
+};
+
+/**
+  Check the SwSmiInputValue to see if there is a duplicated one in the database
+
+  @param[in] SwSmiInputValue      SwSmiInputValue
+
+  @retval EFI_SUCCESS             There is no duplicated SwSmiInputValue
+  @retval EFI_INVALID_PARAMETER   There is a duplicated SwSmiInputValue
+**/
+EFI_STATUS
+SmiInputValueDuplicateCheck (
+  IN UINTN  SwSmiInputValue
+  )
+{
+  SW_SMI_RECORD   *SwSmiRecord;
+  LIST_ENTRY      *LinkInDb;
+
+  LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase);
+  while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {
+    SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb);
+    if (SwSmiRecord->Context.SwSmiInputValue == SwSmiInputValue) {
+      return EFI_INVALID_PARAMETER;
+    }
+    LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Register a child SMI source dispatch function for the specified software SMI.
+
+  This service registers a function (DispatchFunction) which will be called when the software
+  SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On return,
+  DispatchHandle contains a unique handle which may be used later to unregister the function
+  using UnRegister().
+
+  @param[in]  This                 Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
+  @param[in]  DispatchFunction     Function to register for handler when the specified software
+                                   SMI is generated.
+  @param[in, out] RegisterContext  Pointer to the dispatch function's context.
+                                   The caller fills this context in before calling
+                                   the register function to indicate to the register
+                                   function which Software SMI input value the
+                                   dispatch function should be invoked for.
+  @param[out] DispatchHandle       Handle generated by the dispatcher to track the
+                                   function instance.
+
+  @retval EFI_SUCCESS            The dispatch function has been successfully
+                                 registered and the SMI source has been enabled.
+  @retval EFI_DEVICE_ERROR       The SW driver was unable to enable the SMI source.
+  @retval EFI_INVALID_PARAMETER  RegisterContext is invalid. The SW SMI input value
+                                 is not within a valid range or is already in use.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough memory (system or SMM) to manage this
+                                 child.
+  @retval EFI_OUT_OF_RESOURCES   A unique software SMI value could not be assigned
+                                 for this dispatch.
+**/
+EFI_STATUS
+EFIAPI
+PchSwSmiRegister (
+  IN  EFI_SMM_SW_DISPATCH2_PROTOCOL       *This,
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2        DispatchFunction,
+  IN  EFI_SMM_SW_REGISTER_CONTEXT         *DispatchContext,
+  OUT EFI_HANDLE                          *DispatchHandle
+  )
+{
+  EFI_STATUS       Status;
+  SW_SMI_RECORD    *SwSmiRecord;
+  UINTN            Index;
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Find available SW SMI value if the input is -1
+  //
+  if (DispatchContext->SwSmiInputValue == (UINTN) -1) {
+    for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
+      if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) {
+        DispatchContext->SwSmiInputValue = Index;
+        break;
+      }
+    }
+    if (DispatchContext->SwSmiInputValue == (UINTN) -1) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+  //
+  // Check if it's a valid SW SMI value.
+  // The value must not bigger than 0xFF.
+  // And the value must not be 0xFF sincie it's used for SmmControll protocol.
+  //
+  if (DispatchContext->SwSmiInputValue >= MAXIMUM_SWI_VALUE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext->SwSmiInputValue))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create database record and add to database
+  //
+  Status = gSmst->SmmAllocatePool (
+                    EfiRuntimeServicesData,
+                    sizeof (SW_SMI_RECORD),
+                    (VOID **) &SwSmiRecord
+                    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Gather information about the registration request
+  //
+  SwSmiRecord->Signature               = SW_SMI_RECORD_SIGNATURE;
+  SwSmiRecord->Context.SwSmiInputValue = DispatchContext->SwSmiInputValue;
+  SwSmiRecord->Callback                = DispatchFunction;
+  //
+  // Publish the S/W SMI numbers in Serial logs used for Debug build.
+  //
+  DEBUG ((DEBUG_INFO, "SW SMI NUM %x  Sw Record at Address 0x%X\n", SwSmiRecord->Context.SwSmiInputValue, SwSmiRecord));
+
+  InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link);
+
+  //
+  // Child's handle will be the address linked list link in the record
+  //
+  *DispatchHandle = (EFI_HANDLE) (&SwSmiRecord->Link);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unregister a child SMI source dispatch function for the specified software SMI.
+
+  This service removes the handler associated with DispatchHandle so that it will no longer be
+  called in response to a software SMI.
+
+  @param[in] This                Pointer to the EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
+  @param[in] DispatchHandle      Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS            The dispatch function has been successfully unregistered.
+  @retval EFI_INVALID_PARAMETER  The DispatchHandle was not valid.
+**/
+EFI_STATUS
+EFIAPI
+PchSwSmiUnRegister (
+  IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL  *This,
+  IN       EFI_HANDLE                     DispatchHandle
+  )
+{
+  EFI_STATUS            Status;
+  SW_SMI_RECORD         *RecordToDelete;
+
+  if (DispatchHandle == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Return access denied if the SmmReadyToLock event has been triggered
+  //
+  if (mReadyToLock == TRUE) {
+    DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  RecordToDelete = SW_SMI_RECORD_FROM_LINK (DispatchHandle);
+  //
+  // Take the entry out of the linked list
+  //
+  if (RecordToDelete->Signature != SW_SMI_RECORD_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RemoveEntryList (&RecordToDelete->Link);
+  ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD));
+  Status = gSmst->SmmFreePool (RecordToDelete);
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Main entry point for an SMM handler dispatch or communicate-based callback.
+
+  @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
+  @param[in]     Context         Points to an optional handler context which was specified when the
+                                 handler was registered.
+  @param[in,out] CommBuffer      A pointer to a collection of data in memory that will
+                                 be conveyed from a non-SMM environment into an SMM environment.
+  @param[in,out] CommBufferSize  The size of the CommBuffer.
+
+  @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers
+                                              should still be called.
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should
+                                              still be called.
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still
+                                              be called.
+  @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+PchSwSmiDispatcher (
+  IN       EFI_HANDLE         DispatchHandle,
+  IN CONST VOID               *Context,
+  IN OUT   VOID               *CommBuffer,
+  IN OUT   UINTN              *CommBufferSize
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_SMM_SAVE_STATE_IO_INFO            SmiIoInfo;
+  UINTN                                 CpuIndex;
+  SW_SMI_RECORD                         *SwSmiRecord;
+  LIST_ENTRY                            *LinkInDb;
+  EFI_SMM_SW_CONTEXT                    SwSmiCommBuffer;
+  UINTN                                 SwSmiCommBufferSize;
+
+  SwSmiCommBufferSize      = sizeof (EFI_SMM_SW_CONTEXT);
+  //
+  // The value in DataPort might not be accurate in multiple thread environment.
+  // There might be racing condition for R_PCH_IO_APM_STS port.
+  // Therefor, this is just for reference.
+  //
+  SwSmiCommBuffer.DataPort = IoRead8 (R_PCH_IO_APM_STS);
+
+  for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
+    Status = mSmmCpuProtocol->ReadSaveState (
+                                mSmmCpuProtocol,
+                                sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
+                                EFI_SMM_SAVE_STATE_REGISTER_IO,
+                                CpuIndex,
+                                &SmiIoInfo
+                                );
+    //
+    // If this is not the SMI source, skip it.
+    //
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+    //
+    // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT (0xB2)", skip it.
+    //
+    if ((SmiIoInfo.IoPort != R_PCH_IO_APM_CNT) ||
+        (SmiIoInfo.IoType != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) ||
+        (SmiIoInfo.IoWidth != EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8))
+    {
+      continue;
+    }
+    //
+    // If the IO data is used for SmmControl protocol, skip it.
+    //
+    if (SmiIoInfo.IoData == 0xFF) {
+      continue;
+    }
+
+    SwSmiCommBuffer.SwSmiCpuIndex = CpuIndex;
+    SwSmiCommBuffer.CommandPort   = (UINT8) SmiIoInfo.IoData;
+
+    LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase);
+    while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {
+      SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb);
+      if (SwSmiRecord->Context.SwSmiInputValue == SmiIoInfo.IoData) {
+        SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize);
+      }
+      LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord->Link);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Init required protocol for Pch Sw Dispatch protocol.
+**/
+VOID
+PchSwDispatchInit (
+  VOID
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_HANDLE                            DispatchHandle;
+  DATABASE_RECORD                       Record;
+
+  //
+  // Locate PI SMM CPU protocol
+  //
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpuProtocol);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Initialize SW SMI Callback DataBase
+  //
+  InitializeListHead (&mSwSmiCallbackDataBase);
+
+  //
+  // Insert SwSmi handler to PchSmmCore database
+  // There will always be one SwType record in PchSmmCore database
+  //
+  ZeroMem (&Record, sizeof (DATABASE_RECORD));
+  Record.Signature    = DATABASE_RECORD_SIGNATURE;
+  Record.Callback     = PchSwSmiDispatcher;
+  Record.ProtocolType = SwType;
+
+  CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof (PCH_SMM_SOURCE_DESC));
+
+  DispatchHandle      = NULL;
+  Status = SmmCoreInsertRecord (
+             &Record,
+             &DispatchHandle
+             );
+  ASSERT_EFI_ERROR (Status);
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c
new file mode 100644
index 0000000000..7d79f21dbd
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c
@@ -0,0 +1,224 @@
+/** @file
+  File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Register/PmcRegs.h>
+#include <Register/PchPcieRpRegs.h>
+#include <Library/PchPciBdfLib.h>
+#include "PchSmiHelper.h"
+
+extern BOOLEAN               mS3SusStart;
+#define PROGRESS_CODE_S3_SUSPEND_END  PcdGet32 (PcdProgressCodeS3SuspendEnd)
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSxSourceDesc = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_ON_SLP_EN
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_ON_SLP_EN
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_ON_SLP_EN
+  }
+};
+
+/**
+  Get the Sleep type
+
+  @param[in] Record               No use
+  @param[out] Context             The context that includes SLP_TYP bits to be filled
+
+**/
+VOID
+EFIAPI
+SxGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT PCH_SMM_CONTEXT    *Context
+  )
+{
+  UINT32  Pm1Cnt;
+
+  Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
+
+  ///
+  /// By design, the context phase will always be ENTRY
+  ///
+  Context->Sx.Phase = SxEntry;
+
+  ///
+  /// Map the PM1_CNT register's SLP_TYP bits to the context type
+  ///
+  switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) {
+    case V_ACPI_IO_PM1_CNT_S0:
+      Context->Sx.Type = SxS0;
+      break;
+
+    case V_ACPI_IO_PM1_CNT_S1:
+      Context->Sx.Type = SxS1;
+      break;
+
+    case V_ACPI_IO_PM1_CNT_S3:
+      Context->Sx.Type = SxS3;
+      break;
+
+    case V_ACPI_IO_PM1_CNT_S4:
+      Context->Sx.Type = SxS4;
+      break;
+
+    case V_ACPI_IO_PM1_CNT_S5:
+      Context->Sx.Type = SxS5;
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+}
+
+/**
+  Check whether sleep type of two contexts match
+
+  @param[in] Context1             Context 1 that includes sleep type 1
+  @param[in] Context2             Context 2 that includes sleep type 2
+
+  @retval FALSE                   Sleep types match
+  @retval TRUE                    Sleep types don't match
+**/
+BOOLEAN
+EFIAPI
+SxCmpContext (
+  IN PCH_SMM_CONTEXT     *Context1,
+  IN PCH_SMM_CONTEXT     *Context2
+  )
+{
+  return (BOOLEAN) (Context1->Sx.Type == Context2->Sx.Type);
+}
+
+/**
+  For each PCIE RP clear PME SCI status and disable SCI, then PCIEXP_WAKE_STS from PMC.
+  This prevents platform from waking more than one time due to a single PCIE wake event.
+  Normally it's up to OS to clear SCI statuses. But in a scenario where platform wakes
+  and goes to S5 instead of booting to OS, the SCI status would remain set and would trigger another wake.
+**/
+VOID
+ClearPcieSci (
+  VOID
+  )
+{
+  UINT32 MaxPorts;
+  UINT32 RpIndex;
+  UINT64 RpBase;
+
+  MaxPorts = GetPchMaxPciePortNum ();
+  for (RpIndex = 0; RpIndex < MaxPorts; RpIndex++) {
+    RpBase = PchPcieRpPciCfgBase (RpIndex);
+  if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF) {
+      PciSegmentAnd8 ((RpBase + R_PCH_PCIE_CFG_MPC + 3), (UINT8)~((UINT8)(B_PCH_PCIE_CFG_MPC_PMCE >> 24)));
+      PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_SMSCS, B_PCH_PCIE_CFG_SMSCS_PMCS);
+    }
+  }
+  IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, B_ACPI_IO_PM1_STS_PCIEXP_WAKE_STS);
+}
+
+
+/**
+  When we get an SMI that indicates that we are transitioning to a sleep state,
+  we need to actually transition to that state.  We do this by disabling the
+  "SMI on sleep enable" feature, which generates an SMI when the operating system
+  tries to put the system to sleep, and then physically putting the system to sleep.
+
+
+**/
+VOID
+PchSmmSxGoToSleep (
+  VOID
+  )
+{
+  UINT32      Pm1Cnt;
+
+  ClearPcieSci ();
+
+  ///
+  /// Disable SMIs
+  ///
+  PchSmmClearSource (&mSxSourceDesc);
+  PchSmmDisableSource (&mSxSourceDesc);
+
+  ///
+  /// Get Power Management 1 Control Register Value
+  ///
+  Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
+
+  ///
+  /// Record S3 suspend performance data
+  ///
+  if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) == V_ACPI_IO_PM1_CNT_S3) {
+    ///
+    /// Report status code before goto S3 sleep
+    ///
+    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_END);
+    mS3SusStart = FALSE;
+    ///
+    /// Write back cache into memory and invalidate cache before going to sleep.
+    ///
+    AsmWbinvd ();
+  }
+
+  ///
+  /// Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep
+  ///
+  Pm1Cnt |= B_ACPI_IO_PM1_CNT_SLP_EN;
+
+  IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt);
+
+  ///
+  /// Should only proceed if wake event is generated.
+  ///
+  if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) == V_ACPI_IO_PM1_CNT_S1) {
+    while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS))) & B_ACPI_IO_PM1_STS_WAK) == 0x0);
+  } else {
+    CpuDeadLoop ();
+  }
+  ///
+  /// The system just went to sleep. If the sleep state was S1, then code execution will resume
+  /// here when the system wakes up.
+  ///
+  Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
+
+  if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == 0) {
+    ///
+    /// An ACPI OS isn't present, clear the sleep information
+    ///
+    Pm1Cnt &= ~B_ACPI_IO_PM1_CNT_SLP_TYP;
+    Pm1Cnt |= V_ACPI_IO_PM1_CNT_S0;
+
+    IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt);
+  }
+
+  PchSmmClearSource (&mSxSourceDesc);
+  PchSmmEnableSource (&mSxSourceDesc);
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c
new file mode 100644
index 0000000000..a0c67bd959
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c
@@ -0,0 +1,230 @@
+/** @file
+  File to contain all the hardware specific stuff for the Smm USB dispatch protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Register/UsbRegs.h>
+#include <Register/PchRegsLpc.h>
+#include <Register/PmcRegs.h>
+#include <Library/PchPciBdfLib.h>
+#include <PchBdfAssignment.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb1Legacy = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_LEGACY_USB
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_LEGACY_USB
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_LEGACY_USB
+  }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mUsb3Legacy = {
+  PCH_SMM_NO_FLAGS,
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_EN}
+      },
+      S_ACPI_IO_SMI_EN,
+      N_ACPI_IO_SMI_EN_LEGACY_USB3
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {
+        ACPI_ADDR_TYPE,
+        {R_ACPI_IO_SMI_STS}
+      },
+      S_ACPI_IO_SMI_STS,
+      N_ACPI_IO_SMI_STS_LEGACY_USB3
+    }
+  },
+  {
+    {
+      ACPI_ADDR_TYPE,
+      {R_ACPI_IO_SMI_STS}
+    },
+    S_ACPI_IO_SMI_STS,
+    N_ACPI_IO_SMI_STS_LEGACY_USB3
+  }
+};
+
+typedef enum {
+  PchUsbControllerLpc0    = 0,
+  PchUsbControllerXhci,
+  PchUsbControllerTypeMax
+} PCH_USB_CONTROLLER_TYPE;
+
+typedef struct {
+  UINT8                   Function;
+  UINT8                   Device;
+  PCH_USB_CONTROLLER_TYPE UsbConType;
+} USB_CONTROLLER;
+
+GLOBAL_REMOVE_IF_UNREFERENCED USB_CONTROLLER  mUsbControllersMap[] = {
+  {
+    PCI_FUNCTION_NUMBER_PCH_LPC,
+    PCI_DEVICE_NUMBER_PCH_LPC,
+    PchUsbControllerLpc0
+  },
+  {
+    PCI_FUNCTION_NUMBER_PCH_XHCI,
+    PCI_DEVICE_NUMBER_PCH_XHCI,
+    PchUsbControllerXhci
+  }
+};
+
+/**
+  Find the handle that best matches the input Device Path and return the USB controller type
+
+  @param[in] DevicePath           Pointer to the device Path table
+  @param[out] Controller          Returned with the USB controller type of the input device path
+
+  @retval EFI_SUCCESS             Find the handle that best matches the input Device Path
+  @exception EFI_UNSUPPORTED      Invalid device Path table or can't find any match USB device path
+                                  PCH_USB_CONTROLLER_TYPE The USB controller type of the input
+                                  device path
+**/
+EFI_STATUS
+DevicePathToSupportedController (
+  IN  EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
+  OUT PCH_USB_CONTROLLER_TYPE    *Controller
+  )
+{
+  EFI_STATUS                Status;
+  EFI_HANDLE                DeviceHandle;
+  ACPI_HID_DEVICE_PATH      *AcpiNode;
+  PCI_DEVICE_PATH           *PciNode;
+  EFI_DEVICE_PATH_PROTOCOL  *RemaingDevicePath;
+  UINT8                     UsbIndex;
+  ///
+  /// Find the handle that best matches the Device Path. If it is only a
+  /// partial match the remaining part of the device path is returned in
+  /// RemainingDevicePath.
+  ///
+  RemaingDevicePath = DevicePath;
+  Status = gBS->LocateDevicePath (
+                  &gEfiPciRootBridgeIoProtocolGuid,
+                  &DevicePath,
+                  &DeviceHandle
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  DevicePath = RemaingDevicePath;
+
+  ///
+  /// Get first node: Acpi Node
+  ///
+  AcpiNode = (ACPI_HID_DEVICE_PATH *) RemaingDevicePath;
+
+  if (AcpiNode->Header.Type != ACPI_DEVICE_PATH ||
+      AcpiNode->Header.SubType != ACPI_DP ||
+      DevicePathNodeLength (&AcpiNode->Header) != sizeof (ACPI_HID_DEVICE_PATH) ||
+      AcpiNode->HID != EISA_PNP_ID (0x0A03) ||
+      AcpiNode->UID != 0
+      ) {
+    return EFI_UNSUPPORTED;
+  } else {
+    ///
+    /// Get the next node: Pci Node
+    ///
+    RemaingDevicePath = NextDevicePathNode (RemaingDevicePath);
+    PciNode           = (PCI_DEVICE_PATH *) RemaingDevicePath;
+    if (PciNode->Header.Type != HARDWARE_DEVICE_PATH ||
+        PciNode->Header.SubType != HW_PCI_DP ||
+        DevicePathNodeLength (&PciNode->Header) != sizeof (PCI_DEVICE_PATH)
+        ) {
+      return EFI_UNSUPPORTED;
+    }
+
+    for (UsbIndex = 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof (USB_CONTROLLER); UsbIndex++) {
+      if ((PciNode->Device == mUsbControllersMap[UsbIndex].Device) &&
+          (PciNode->Function == mUsbControllersMap[UsbIndex].Function)) {
+        *Controller = mUsbControllersMap[UsbIndex].UsbConType;
+        return EFI_SUCCESS;
+      }
+    }
+
+    return EFI_UNSUPPORTED;
+  }
+}
+
+/**
+  Maps a USB context to a source description.
+
+  @param[in] Context              The context we need to map.  Type must be USB.
+  @param[in] SrcDesc              The source description that corresponds to the given context.
+
+**/
+VOID
+MapUsbToSrcDesc (
+  IN  PCH_SMM_CONTEXT         *Context,
+  OUT PCH_SMM_SOURCE_DESC     *SrcDesc
+  )
+{
+  PCH_USB_CONTROLLER_TYPE Controller;
+  EFI_STATUS              Status;
+
+  Status = DevicePathToSupportedController (Context->Usb.Device, &Controller);
+  ///
+  /// Either the device path passed in by the child is incorrect or
+  /// the ones stored here internally are incorrect.
+  ///
+  ASSERT_EFI_ERROR (Status);
+
+  switch (Context->Usb.Type) {
+    case UsbLegacy:
+      switch (Controller) {
+        case PchUsbControllerLpc0:
+          CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof (PCH_SMM_SOURCE_DESC));
+          break;
+
+        case PchUsbControllerXhci:
+          CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof (PCH_SMM_SOURCE_DESC));
+          break;
+
+        default:
+          ASSERT (FALSE);
+          break;
+      }
+      break;
+
+    case UsbWake:
+      ASSERT (FALSE);
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c
new file mode 100644
index 0000000000..a0b7e37d46
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.c
@@ -0,0 +1,778 @@
+/** @file
+  This driver is responsible for the registration of child drivers
+  and the abstraction of the PCH SMI sources.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "PchSmmHelpers.h"
+#include <Register/PchRegs.h>
+#include <Register/PmcRegs.h>
+
+//
+// Help handle porting bit shifts to IA-64.
+//
+#define BIT_ZERO  0x00000001
+
+/**
+  Publish SMI Dispatch protocols.
+
+
+**/
+VOID
+PchSmmPublishDispatchProtocols (
+  VOID
+  )
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+  UINTN      Index;
+  //
+  // Install protocol interfaces.
+  //
+  for (Index = 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) {
+    Status = gSmst->SmmInstallProtocolInterface (
+                      &mPrivateData.InstallMultProtHandle,
+                      mPrivateData.Protocols[Index].Guid,
+                      EFI_NATIVE_INTERFACE,
+                      &mPrivateData.Protocols[Index].Protocols.Generic
+                      );
+  }
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  Initialize bits that aren't necessarily related to an SMI source.
+
+
+  @retval EFI_SUCCESS             SMI source initialization completed.
+  @retval Asserts                 Global Smi Bit is not enabled successfully.
+**/
+EFI_STATUS
+PchSmmInitHardware (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Clear all SMIs
+  //
+  PchSmmClearSmi ();
+
+  Status = PchSmmEnableGlobalSmiBit ();
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Be *really* sure to clear all SMIs
+  //
+  PchSmmClearSmi ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enables the PCH to generate SMIs. Note that no SMIs will be generated
+  if no SMI sources are enabled. Conversely, no enabled SMI source will
+  generate SMIs if SMIs are not globally enabled. This is the main
+  switchbox for SMI generation.
+
+
+  @retval EFI_SUCCESS             Enable Global Smi Bit completed
+**/
+EFI_STATUS
+PchSmmEnableGlobalSmiBit (
+  VOID
+  )
+{
+  UINT32  SmiEn;
+
+  SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
+
+  //
+  // Set the "global smi enable" bit
+  //
+  SmiEn |= B_ACPI_IO_SMI_EN_GBL_SMI;
+
+  IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Clears the SMI after all SMI source have been processed.
+  Note that this function will not work correctly (as it is
+  written) unless all SMI sources have been processed.
+  A revision of this function could manually clear all SMI
+  status bits to guarantee success.
+
+
+  @retval EFI_SUCCESS             Clears the SMIs completed
+  @retval Asserts                 EOS was not set to a 1
+**/
+EFI_STATUS
+PchSmmClearSmi (
+  VOID
+  )
+{
+  BOOLEAN     EosSet;
+  BOOLEAN     SciEn;
+  UINT32      Pm1Cnt;
+  UINT16      Pm1Sts;
+  UINT32      Gpe0Sts;
+  UINT32      SmiSts;
+  UINT16      DevActSts;
+  UINT16      Tco1Sts;
+
+  Gpe0Sts      = 0;
+  //
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)
+  //
+  Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
+  SciEn  = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == B_ACPI_IO_PM1_CNT_SCI_EN);
+  if (!SciEn) {
+    //
+    // Clear any SMIs that double as SCIs (when SCI_EN==0)
+    //
+    Pm1Sts   = IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS));
+    Gpe0Sts  = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96));
+
+    Pm1Sts |=
+    (
+      B_ACPI_IO_PM1_STS_WAK |
+      B_ACPI_IO_PM1_STS_PRBTNOR |
+      B_ACPI_IO_PM1_STS_RTC |
+      B_ACPI_IO_PM1_STS_PWRBTN |
+      B_ACPI_IO_PM1_STS_GBL |
+      B_ACPI_IO_PM1_STS_TMROF
+      );
+
+    Gpe0Sts |=
+    (
+      B_ACPI_IO_GPE0_STS_127_96_WADT |
+      B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS |
+      B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE |
+      B_ACPI_IO_GPE0_STS_127_96_PME_B0 |
+      B_ACPI_IO_GPE0_STS_127_96_PME |
+      B_ACPI_IO_GPE0_STS_127_96_BATLOW |
+      B_ACPI_IO_GPE0_STS_127_96_RI |
+      B_ACPI_IO_GPE0_STS_127_96_SWGPE
+      );
+
+    IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS), (UINT16) Pm1Sts);
+    IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96), (UINT32) Gpe0Sts);
+  }
+  //
+  // Clear all SMIs that are unaffected by SCI_EN
+  //
+  SmiSts        = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS));
+  DevActSts     = IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_STS));
+  Tco1Sts       = IoRead16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS));
+
+  SmiSts |=
+  (
+    B_ACPI_IO_SMI_STS_SMBUS |
+    B_ACPI_IO_SMI_STS_PERIODIC |
+    B_ACPI_IO_SMI_STS_TCO |
+    B_ACPI_IO_SMI_STS_MCSMI |
+    B_ACPI_IO_SMI_STS_SWSMI_TMR |
+    B_ACPI_IO_SMI_STS_APM |
+    B_ACPI_IO_SMI_STS_ON_SLP_EN |
+    B_ACPI_IO_SMI_STS_BIOS
+    );
+  DevActSts |=
+  (
+    B_ACPI_IO_DEVACT_STS_KBC |
+    B_ACPI_IO_DEVACT_STS_PIRQDH |
+    B_ACPI_IO_DEVACT_STS_PIRQCG |
+    B_ACPI_IO_DEVACT_STS_PIRQBF |
+    B_ACPI_IO_DEVACT_STS_PIRQAE
+    );
+  Tco1Sts |=
+  (
+    B_TCO_IO_TCO1_STS_DMISERR |
+    B_TCO_IO_TCO1_STS_DMISMI |
+    B_TCO_IO_TCO1_STS_DMISCI |
+    B_TCO_IO_TCO1_STS_BIOSWR |
+    B_TCO_IO_TCO1_STS_NEWCENTURY |
+    B_TCO_IO_TCO1_STS_TIMEOUT |
+    B_TCO_IO_TCO1_STS_TCO_INT |
+    B_TCO_IO_TCO1_STS_SW_TCO_SMI
+    );
+
+  GpioClearAllGpiSmiSts ();
+
+  IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS), Tco1Sts);
+
+  //
+  // We do not want to write 1 to clear INTRD_DET bit.
+  //
+  IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO2_STS), (UINT16) ~B_TCO_IO_TCO2_STS_INTRD_DET);
+
+  IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS), SmiSts);
+
+  IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_STS), DevActSts);
+
+  //
+  // Try to clear the EOS bit. ASSERT on an error
+  //
+  EosSet = PchSmmSetAndCheckEos ();
+  ASSERT (EosSet);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set the SMI EOS bit after all SMI source have been processed.
+
+
+  @retval FALSE                   EOS was not set to a 1; this is an error
+  @retval TRUE                    EOS was correctly set to a 1
+**/
+BOOLEAN
+PchSmmSetAndCheckEos (
+  VOID
+  )
+{
+  UINT32  SmiEn;
+
+  SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
+
+  //
+  // Reset the PCH to generate subsequent SMIs
+  //
+  SmiEn |= B_ACPI_IO_SMI_EN_EOS;
+
+  IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);
+
+  //
+  // Double check that the assert worked
+  //
+  SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
+
+  //
+  // Return TRUE if EOS is set correctly
+  //
+  if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) == 0) {
+    //
+    // EOS was not set to a 1; this is an error
+    //
+    return FALSE;
+  } else {
+    //
+    // EOS was correctly set to a 1
+    //
+    return TRUE;
+  }
+}
+
+/**
+  Determine whether an ACPI OS is present (via the SCI_EN bit)
+
+
+  @retval TRUE                    ACPI OS is present
+  @retval FALSE                   ACPI OS is not present
+**/
+BOOLEAN
+PchSmmGetSciEn (
+  VOID
+  )
+{
+  BOOLEAN SciEn;
+  UINT32  Pm1Cnt;
+
+  //
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)
+  //
+  Pm1Cnt  = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
+  SciEn   = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == B_ACPI_IO_PM1_CNT_SCI_EN);
+
+  return SciEn;
+}
+
+/**
+  Read a specifying bit with the register
+  These may or may not need to change w/ the PCH version; they're highly IA-32 dependent, though.
+
+  @param[in] BitDesc              The struct that includes register address, size in byte and bit number
+
+  @retval TRUE                    The bit is enabled
+  @retval FALSE                   The bit is disabled
+**/
+BOOLEAN
+ReadBitDesc (
+  CONST PCH_SMM_BIT_DESC  *BitDesc
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      Register;
+  UINT32      PciBus;
+  UINT32      PciDev;
+  UINT32      PciFun;
+  UINT32      PciReg;
+  UINTN       RegSize;
+  BOOLEAN     BitWasOne;
+  UINTN       ShiftCount;
+  UINTN       RegisterOffset;
+  UINT32      BaseAddr;
+  UINT64      PciBaseAddress;
+
+  ASSERT (BitDesc != NULL);
+  ASSERT (!IS_BIT_DESC_NULL (*BitDesc));
+
+  RegSize     = 0;
+  Register    = 0;
+  ShiftCount  = 0;
+  BitWasOne   = FALSE;
+
+  switch (BitDesc->Reg.Type) {
+
+    case ACPI_ADDR_TYPE:
+    case TCO_ADDR_TYPE:
+      if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) {
+        RegisterOffset  = BitDesc->Reg.Data.acpi;
+        BaseAddr        = mAcpiBaseAddr;
+      } else {
+        RegisterOffset  = BitDesc->Reg.Data.tco;
+        BaseAddr        = mTcoBaseAddr;
+      }
+      switch (BitDesc->SizeInBytes) {
+
+        case 0:
+          //
+          // Chances are that this field didn't get initialized.
+          // Check your assignments to bit descriptions.
+          //
+          ASSERT (FALSE);
+          break;
+
+        case 1:
+          RegSize = SMM_IO_UINT8;
+          break;
+
+        case 2:
+          RegSize = SMM_IO_UINT16;
+          break;
+
+        case 4:
+          RegSize = SMM_IO_UINT32;
+          break;
+
+        case 8:
+          RegSize = SMM_IO_UINT64;
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+      //
+      // Double check that we correctly read in the acpi base address
+      //
+      ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1));
+
+      ShiftCount      = BitDesc->Bit;
+      //
+      // As current CPU Smm Io can only support at most
+      // 32-bit read/write,if Operation is 64 bit,
+      // we do a 32 bit operation according to BitDesc->Bit
+      //
+      if (RegSize == SMM_IO_UINT64) {
+        RegSize = SMM_IO_UINT32;
+        //
+        // If the operation is for high 32 bits
+        //
+        if (BitDesc->Bit >= 32) {
+          RegisterOffset += 4;
+          ShiftCount -= 32;
+        }
+      }
+
+      Status = gSmst->SmmIo.Io.Read (
+                                 &gSmst->SmmIo,
+                                 RegSize,
+                                 BaseAddr + RegisterOffset,
+                                 1,
+                                 &Register
+                                 );
+      ASSERT_EFI_ERROR (Status);
+
+      if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) != 0) {
+        BitWasOne = TRUE;
+      } else {
+        BitWasOne = FALSE;
+      }
+      break;
+
+    case GPIO_ADDR_TYPE:
+    case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+      //
+      // Read the register, and it with the bit to read
+      //
+      switch (BitDesc->SizeInBytes) {
+        case 1:
+          Register = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio);
+          break;
+
+        case 2:
+          Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio);
+          break;
+
+        case 4:
+          Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio);
+          break;
+
+        case 8:
+          Register                      = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio);
+          *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4);
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+
+      Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
+      if (Register) {
+        BitWasOne = TRUE;
+      } else {
+        BitWasOne = FALSE;
+      }
+      break;
+
+    case PCIE_ADDR_TYPE:
+      PciBus  = BitDesc->Reg.Data.pcie.Fields.Bus;
+      PciDev  = BitDesc->Reg.Data.pcie.Fields.Dev;
+      PciFun  = BitDesc->Reg.Data.pcie.Fields.Fnc;
+      PciReg  = BitDesc->Reg.Data.pcie.Fields.Reg;
+      PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
+      switch (BitDesc->SizeInBytes) {
+
+        case 0:
+          //
+          // Chances are that this field didn't get initialized.
+          // Check your assignments to bit descriptions.
+          //
+          ASSERT (FALSE);
+          break;
+
+        case 1:
+          Register = (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg);
+          break;
+
+        case 2:
+          Register = (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg);
+          break;
+
+        case 4:
+          Register = (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg);
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+
+      if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) != 0) {
+        BitWasOne = TRUE;
+      } else {
+        BitWasOne = FALSE;
+      }
+      break;
+
+    case PCR_ADDR_TYPE:
+      //
+      // Read the register, and it with the bit to read
+      //
+      switch (BitDesc->SizeInBytes) {
+        case 1:
+          Register = PchPcrRead8  (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset);
+          break;
+
+        case 2:
+          Register = PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset);
+          break;
+
+        case 4:
+          Register = PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset);
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+
+      Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
+      if (Register) {
+        BitWasOne = TRUE;
+      } else {
+        BitWasOne = FALSE;
+      }
+      break;
+
+    default:
+      //
+      // This address type is not yet implemented
+      //
+      ASSERT (FALSE);
+      break;
+  }
+
+  return BitWasOne;
+}
+
+/**
+  Write a specifying bit with the register
+
+  @param[in] BitDesc              The struct that includes register address, size in byte and bit number
+  @param[in] ValueToWrite         The value to be wrote
+  @param[in] WriteClear           If the rest bits of the register is write clear
+
+**/
+VOID
+WriteBitDesc (
+  CONST PCH_SMM_BIT_DESC  *BitDesc,
+  CONST BOOLEAN           ValueToWrite,
+  CONST BOOLEAN           WriteClear
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      Register;
+  UINT64      AndVal;
+  UINT64      OrVal;
+  UINT32      RegSize;
+  UINT32      PciBus;
+  UINT32      PciDev;
+  UINT32      PciFun;
+  UINT32      PciReg;
+  UINTN       RegisterOffset;
+  UINT32      BaseAddr;
+  UINT64      PciBaseAddress;
+
+  ASSERT (BitDesc != NULL);
+  ASSERT (!IS_BIT_DESC_NULL (*BitDesc));
+
+  RegSize   = 0;
+  Register  = 0;
+
+  if (WriteClear) {
+    AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit);
+  } else {
+    AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit));
+  }
+
+  OrVal = (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit));
+
+  switch (BitDesc->Reg.Type) {
+
+    case ACPI_ADDR_TYPE:
+    case TCO_ADDR_TYPE:
+      if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) {
+        RegisterOffset  = BitDesc->Reg.Data.acpi;
+        BaseAddr        = mAcpiBaseAddr;
+      } else {
+        RegisterOffset  = BitDesc->Reg.Data.tco;
+        BaseAddr        = mTcoBaseAddr;
+      }
+
+      switch (BitDesc->SizeInBytes) {
+
+        case 0:
+          //
+          // Chances are that this field didn't get initialized.
+          // Check your assignments to bit descriptions.
+          //
+          ASSERT (FALSE);
+          break;
+
+        case 1:
+          RegSize = SMM_IO_UINT8;
+          break;
+
+        case 2:
+          RegSize = SMM_IO_UINT16;
+          break;
+
+        case 4:
+          RegSize = SMM_IO_UINT32;
+          break;
+
+        case 8:
+          RegSize = SMM_IO_UINT64;
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+      //
+      // Double check that we correctly read in the acpi base address
+      //
+      ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1));
+
+      //
+      // As current CPU Smm Io can only support at most
+      // 32-bit read/write,if Operation is 64 bit,
+      // we do a 32 bit operation according to BitDesc->Bit
+      //
+      if (RegSize == SMM_IO_UINT64) {
+        RegSize = SMM_IO_UINT32;
+        //
+        // If the operation is for high 32 bits
+        //
+        if (BitDesc->Bit >= 32) {
+          RegisterOffset += 4;
+
+          if (WriteClear) {
+            AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit - 32);
+          } else {
+            AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32));
+          }
+
+          OrVal = LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32);
+        }
+      }
+
+      Status = gSmst->SmmIo.Io.Read (
+                                 &gSmst->SmmIo,
+                                 RegSize,
+                                 BaseAddr + RegisterOffset,
+                                 1,
+                                 &Register
+                                 );
+      ASSERT_EFI_ERROR (Status);
+
+      Register &= AndVal;
+      Register |= OrVal;
+
+      Status = gSmst->SmmIo.Io.Write (
+                                 &gSmst->SmmIo,
+                                 RegSize,
+                                 BaseAddr + RegisterOffset,
+                                 1,
+                                 &Register
+                                 );
+      ASSERT_EFI_ERROR (Status);
+      break;
+
+    case GPIO_ADDR_TYPE:
+    case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+      //
+      // Read the register, or it with the bit to set, then write it back.
+      //
+      switch (BitDesc->SizeInBytes) {
+        case 1:
+          MmioAndThenOr8  ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8)  AndVal, (UINT8)  OrVal);
+          break;
+
+        case 2:
+          MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) AndVal, (UINT16) OrVal);
+          break;
+
+        case 4:
+          MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) AndVal, (UINT32) OrVal);
+          break;
+
+        case 8:
+          Register                      = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio);
+          *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4);
+          Register &= AndVal;
+          Register |= OrVal;
+          MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register);
+          MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) (&Register) + 1));
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+      break;
+
+    case PCIE_ADDR_TYPE:
+      PciBus  = BitDesc->Reg.Data.pcie.Fields.Bus;
+      PciDev  = BitDesc->Reg.Data.pcie.Fields.Dev;
+      PciFun  = BitDesc->Reg.Data.pcie.Fields.Fnc;
+      PciReg  = BitDesc->Reg.Data.pcie.Fields.Reg;
+      PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
+      switch (BitDesc->SizeInBytes) {
+
+        case 0:
+          //
+          // Chances are that this field didn't get initialized -- check your assignments
+          // to bit descriptions.
+          //
+          ASSERT (FALSE);
+          break;
+
+        case 1:
+          PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, (UINT8) OrVal);
+          break;
+
+        case 2:
+          PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVal, (UINT16) OrVal);
+          break;
+
+        case 4:
+          PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal, (UINT32) OrVal);
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+      break;
+
+    case PCR_ADDR_TYPE:
+      //
+      // Read the register, or it with the bit to set, then write it back.
+      //
+      switch (BitDesc->SizeInBytes) {
+        case 1:
+          PchPcrAndThenOr8  ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8)  AndVal, (UINT8)  OrVal);
+          break;
+
+        case 2:
+          PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) OrVal);
+          break;
+
+        case 4:
+          PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) OrVal);
+          break;
+
+        default:
+          //
+          // Unsupported or invalid register size
+          //
+          ASSERT (FALSE);
+          break;
+      }
+      break;
+
+    default:
+      //
+      // This address type is not yet implemented
+      //
+      ASSERT (FALSE);
+      break;
+  }
+}
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h
new file mode 100644
index 0000000000..6dd6f2027d
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelpers.h
@@ -0,0 +1,107 @@
+/** @file
+  This driver is responsible for the registration of child drivers
+  and the abstraction of the PCH SMI sources.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _PCHX_SMM_HELPERS_H_
+#define _PCHX_SMM_HELPERS_H_
+
+#include "PchSmm.h"
+
+/**
+  Initialize bits that aren't necessarily related to an SMI source.
+
+
+  @retval EFI_SUCCESS             SMI source initialization completed.
+  @retval Asserts                 Global Smi Bit is not enabled successfully.
+**/
+EFI_STATUS
+PchSmmInitHardware (
+  VOID
+  );
+
+/**
+  Enables the PCH to generate SMIs. Note that no SMIs will be generated
+  if no SMI sources are enabled. Conversely, no enabled SMI source will
+  generate SMIs if SMIs are not globally enabled. This is the main
+  switchbox for SMI generation.
+
+
+  @retval EFI_SUCCESS             Enable Global Smi Bit completed
+**/
+EFI_STATUS
+PchSmmEnableGlobalSmiBit (
+  VOID
+  );
+
+/**
+  Clears the SMI after all SMI source have been processed.
+  Note that this function will not work correctly (as it is
+  written) unless all SMI sources have been processed.
+  A revision of this function could manually clear all SMI
+  status bits to guarantee success.
+
+
+  @retval EFI_SUCCESS             Clears the SMIs completed
+  @retval Asserts                 EOS was not set to a 1
+**/
+EFI_STATUS
+PchSmmClearSmi (
+  VOID
+  );
+
+/**
+  Set the SMI EOS bit after all SMI source have been processed.
+
+
+  @retval FALSE                   EOS was not set to a 1; this is an error
+  @retval TRUE                    EOS was correctly set to a 1
+**/
+BOOLEAN
+PchSmmSetAndCheckEos (
+  VOID
+  );
+
+/**
+  Determine whether an ACPI OS is present (via the SCI_EN bit)
+
+
+  @retval TRUE                    ACPI OS is present
+  @retval FALSE                   ACPI OS is not present
+**/
+BOOLEAN
+PchSmmGetSciEn (
+  VOID
+  );
+
+/**
+  Read a specifying bit with the register
+
+  @param[in] BitDesc              The struct that includes register address, size in byte and bit number
+
+  @retval TRUE                    The bit is enabled
+  @retval FALSE                   The bit is disabled
+**/
+BOOLEAN
+ReadBitDesc (
+  CONST PCH_SMM_BIT_DESC *BitDesc
+  );
+
+/**
+  Write a specifying bit with the register
+
+  @param[in] BitDesc              The struct that includes register address, size in byte and bit number
+  @param[in] ValueToWrite         The value to be wrote
+  @param[in] WriteClear           If the rest bits of the register is write clear
+
+**/
+VOID
+WriteBitDesc (
+  CONST PCH_SMM_BIT_DESC  *BitDesc,
+  CONST BOOLEAN           ValueToWrite,
+  CONST BOOLEAN           WriteClear
+  );
+
+#endif
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf
new file mode 100644
index 0000000000..a142cfa95a
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf
@@ -0,0 +1,54 @@
+## @file
+# Component description file for SmmControl module
+#
+#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+INF_VERSION = 0x00010017
+BASE_NAME = SmmControl
+FILE_GUID = A0BAD9F7-AB78-491b-B583-C52B7F84B9E0
+VERSION_STRING = 1.0
+MODULE_TYPE = DXE_RUNTIME_DRIVER
+ENTRY_POINT = SmmControlDriverEntryInit
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+
+
+[LibraryClasses]
+IoLib
+UefiDriverEntryPoint
+DebugLib
+UefiBootServicesTableLib
+UefiRuntimeServicesTableLib
+PmcLib
+GpioLib
+
+
+[Packages]
+MdePkg/MdePkg.dec
+TigerlakeSiliconPkg/SiPkg.dec
+
+
+[Sources]
+SmmControlDriver.h
+SmmControlDriver.c
+
+
+[Protocols]
+gEfiSmmControl2ProtocolGuid ## PRODUCES
+
+
+[Guids]
+gEfiEventVirtualAddressChangeGuid
+
+
+[Depex]
+TRUE
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c
new file mode 100644
index 0000000000..5822f42165
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c
@@ -0,0 +1,394 @@
+/** @file
+  This is the driver that publishes the SMM Control Protocol.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Guid/EventGroup.h>
+#include <Library/PmcLib.h>
+#include <Library/GpioLib.h>
+#include <IndustryStandard/Pci30.h>
+#include <Register/PchRegsLpc.h>
+#include <Register/SpiRegs.h>
+#include <Register/PmcRegs.h>
+#include "SmmControlDriver.h"
+
+STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16                          mABase;
+
+VOID
+EFIAPI
+DisablePendingSmis (
+  VOID
+  );
+
+/**
+  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.
+
+**/
+VOID
+EFIAPI
+SmmControlVirtualAddressChangeEvent (
+  IN EFI_EVENT                  Event,
+  IN VOID                       *Context
+  )
+{
+  gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger));
+  gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear));
+}
+
+/**
+  <b>SmmControl DXE RUNTIME Module Entry Point</b>\n
+  - <b>Introduction</b>\n
+    The SmmControl module is a DXE RUNTIME driver that provides a standard way
+    for other drivers to trigger software SMIs.
+
+  - @pre
+    - PCH Power Management I/O space base address has already been programmed.
+      If SmmControl 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.
+    - EFI_SMM_BASE2_PROTOCOL
+      - Documented in the System Management Mode Core Interface Specification.
+
+  - @result
+    The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in
+    System Management Mode Core Interface Specification.
+
+  @param[in] ImageHandle          Handle for the image of this driver
+  @param[in] SystemTable          Pointer to the EFI System Table
+
+  @retval EFI_STATUS              Results of the installation of the SMM Control Protocol
+**/
+EFI_STATUS
+EFIAPI
+SmmControlDriverEntryInit (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   Event;
+
+  DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n"));
+
+  //
+  // Get the Power Management I/O space base address. We assume that
+  // this base address has already been programmed if this driver is
+  // being run.
+  //
+  mABase = PmcGetAcpiBase ();
+
+  Status = EFI_SUCCESS;
+  if (mABase != 0) {
+    //
+    // Install the instance of the protocol
+    //
+    mSmmControl.Signature                       = SMM_CONTROL_PRIVATE_DATA_SIGNATURE;
+    mSmmControl.Handle                          = ImageHandle;
+
+    mSmmControl.SmmControl.Trigger              = Activate;
+    mSmmControl.SmmControl.Clear                = Deactivate;
+    mSmmControl.SmmControl.MinimumTriggerPeriod = 0;
+
+    //
+    // Install our protocol interfaces on the device's handle
+    //
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &mSmmControl.Handle,
+                    &gEfiSmmControl2ProtocolGuid,
+                    &mSmmControl.SmmControl,
+                    NULL
+                    );
+  } else {
+    Status = EFI_DEVICE_ERROR;
+    return Status;
+  }
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  SmmControlVirtualAddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &Event
+                  );
+  //
+  // Disable any PCH SMIs that, for whatever reason, are asserted after the boot.
+  //
+  DisablePendingSmis ();
+
+  DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n"));
+
+  return Status;
+}
+
+/**
+  Trigger the software SMI
+
+  @param[in] Data                 The value to be set on the software SMI data port
+
+  @retval EFI_SUCCESS             Function completes successfully
+**/
+EFI_STATUS
+EFIAPI
+SmmTrigger (
+  IN UINT8   Data
+  )
+{
+  UINT32  OutputData;
+  UINT32  OutputPort;
+
+  //
+  // Enable the APMC SMI
+  //
+  OutputPort  = mABase + R_ACPI_IO_SMI_EN;
+  OutputData  = IoRead32 ((UINTN) OutputPort);
+  OutputData |= (B_ACPI_IO_SMI_EN_APMC | B_ACPI_IO_SMI_EN_GBL_SMI);
+  DEBUG (
+    (DEBUG_VERBOSE,
+     "The SMI Control Port at address %x will be written to %x.\n",
+     OutputPort,
+     OutputData)
+    );
+  IoWrite32 (
+    (UINTN) OutputPort,
+    (UINT32) (OutputData)
+    );
+
+  OutputPort  = R_PCH_IO_APM_CNT;
+  OutputData  = Data;
+
+  //
+  // Generate the APMC SMI
+  //
+  IoWrite8 (
+    (UINTN) OutputPort,
+    (UINT8) (OutputData)
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Clear the SMI status
+
+
+  @retval EFI_SUCCESS             The function completes successfully
+  @retval EFI_DEVICE_ERROR        Something error occurred
+**/
+EFI_STATUS
+EFIAPI
+SmmClear (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      OutputData;
+  UINT32      OutputPort;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Clear the Power Button Override Status Bit, it gates EOS from being set.
+  //
+  OutputPort  = mABase + R_ACPI_IO_PM1_STS;
+  OutputData  = B_ACPI_IO_PM1_STS_PRBTNOR;
+  DEBUG (
+    (DEBUG_VERBOSE,
+     "The PM1 Status Port at address %x will be written to %x.\n",
+     OutputPort,
+     OutputData)
+    );
+  IoWrite16 (
+    (UINTN) OutputPort,
+    (UINT16) (OutputData)
+    );
+
+  //
+  // Clear the APM SMI Status Bit
+  //
+  OutputPort  = mABase + R_ACPI_IO_SMI_STS;
+  OutputData  = B_ACPI_IO_SMI_STS_APM;
+  DEBUG (
+    (DEBUG_VERBOSE,
+     "The SMI Status Port at address %x will be written to %x.\n",
+     OutputPort,
+     OutputData)
+    );
+  IoWrite32 (
+    (UINTN) OutputPort,
+    (UINT32) (OutputData)
+    );
+
+  //
+  // Set the EOS Bit
+  //
+  OutputPort  = mABase + R_ACPI_IO_SMI_EN;
+  OutputData  = IoRead32 ((UINTN) OutputPort);
+  OutputData |= B_ACPI_IO_SMI_EN_EOS;
+  DEBUG (
+    (DEBUG_VERBOSE,
+     "The SMI Control Port at address %x will be written to %x.\n",
+     OutputPort,
+     OutputData)
+    );
+  IoWrite32 (
+    (UINTN) OutputPort,
+    (UINT32) (OutputData)
+    );
+
+  //
+  // There is no need to read EOS back and check if it is set.
+  // This can lead to a reading of zero if an SMI occurs right after the SMI_EN port read
+  // but before the data is returned to the CPU.
+  // SMM Dispatcher should make sure that EOS is set after all SMI sources are processed.
+  //
+  return Status;
+}
+
+/**
+  This routine generates an SMI
+
+  @param[in] This                       The EFI SMM Control protocol instance
+  @param[in, out] CommandPort           The buffer contains data to the command port
+  @param[in, out] DataPort              The buffer contains data to the data port
+  @param[in] Periodic                   Periodic or not
+  @param[in] ActivationInterval         Interval of periodic SMI
+
+  @retval EFI Status                    Describing the result of the operation
+  @retval EFI_INVALID_PARAMETER         Some parameter value passed is not supported
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL                    * This,
+  IN OUT  UINT8                                         *CommandPort       OPTIONAL,
+  IN OUT  UINT8                                         *DataPort          OPTIONAL,
+  IN      BOOLEAN                                       Periodic           OPTIONAL,
+  IN      UINTN                                         ActivationInterval OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       Data;
+
+  if (Periodic) {
+    DEBUG ((DEBUG_WARN, "Invalid parameter\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (CommandPort == NULL) {
+    Data = 0xFF;
+  } else {
+    Data = *CommandPort;
+  }
+  //
+  // Clear any pending the APM SMI
+  //
+  Status = SmmClear ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return SmmTrigger (Data);
+}
+
+/**
+  This routine clears an SMI
+
+  @param[in] This                 The EFI SMM Control protocol instance
+  @param[in] Periodic             Periodic or not
+
+  @retval EFI Status              Describing the result of the operation
+  @retval EFI_INVALID_PARAMETER   Some parameter value passed is not supported
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL       *This,
+  IN  BOOLEAN                              Periodic OPTIONAL
+  )
+{
+  if (Periodic) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return SmmClear ();
+}
+/**
+  Disable all pending SMIs
+
+**/
+VOID
+EFIAPI
+DisablePendingSmis (
+  VOID
+  )
+{
+  UINT32               Data;
+  BOOLEAN              SciEn;
+
+  //
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)
+  //
+  Data      = IoRead16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT);
+  SciEn     = (BOOLEAN) ((Data & B_ACPI_IO_PM1_CNT_SCI_EN) == B_ACPI_IO_PM1_CNT_SCI_EN);
+
+  if (!SciEn) {
+    //
+    // Clear any SMIs that double as SCIs (when SCI_EN==0)
+    //
+    IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_STS, 0xFFFF);
+    IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_EN, 0);
+    IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT, 0);
+    IoWrite32 (
+      (UINTN) mABase + R_ACPI_IO_GPE0_STS_127_96,
+      (UINT32)( B_ACPI_IO_GPE0_STS_127_96_WADT |
+                B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS |
+                B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE |
+                B_ACPI_IO_GPE0_STS_127_96_PME_B0 |
+                B_ACPI_IO_GPE0_STS_127_96_PME |
+                B_ACPI_IO_GPE0_STS_127_96_BATLOW |
+                B_ACPI_IO_GPE0_STS_127_96_RI |
+                B_ACPI_IO_GPE0_STS_127_96_SWGPE)
+      );
+    IoWrite32 ((UINTN) mABase + R_ACPI_IO_GPE0_EN_127_96, (UINT32) B_ACPI_IO_GPE0_EN_127_96_WADT);
+  }
+  //
+  // Clear and disable all SMIs that are unaffected by SCI_EN
+  //
+  GpioDisableAllGpiSmi ();
+
+  GpioClearAllGpiSmiSts ();
+
+  IoWrite32 ((UINTN) mABase + R_ACPI_IO_DEVACT_STS, 0x0000FFFF);
+
+  IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_STS, ~0u);
+
+  //
+  // (Make sure to write this register last -- EOS re-enables SMIs for the PCH)
+  //
+  Data  = IoRead32 ((UINTN) mABase + R_ACPI_IO_SMI_EN);
+  //
+  // clear all bits except those tied to SCI_EN
+  //
+  Data &= B_ACPI_IO_SMI_EN_BIOS_RLS;
+  //
+  // enable SMIs and specifically enable writes to APM_CNT.
+  //
+  Data |= B_ACPI_IO_SMI_EN_GBL_SMI | B_ACPI_IO_SMI_EN_APMC;
+  //
+  //  NOTE: Default value of EOS is set in PCH, it will be automatically cleared Once the PCH asserts SMI# low,
+  //  we don't need to do anything to clear it
+  //
+  IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_EN, Data);
+}
+
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h
new file mode 100644
index 0000000000..af368e6945
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h
@@ -0,0 +1,130 @@
+/** @file
+  Header file for SMM Control Driver.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _SMM_CONTROL_DRIVER_H_
+#define _SMM_CONTROL_DRIVER_H_
+
+#include <Protocol/SmmControl2.h>
+
+
+#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('i', '4', 's', 'c')
+
+typedef struct {
+  UINTN                           Signature;
+  EFI_HANDLE                      Handle;
+  EFI_SMM_CONTROL2_PROTOCOL       SmmControl;
+} SMM_CONTROL_PRIVATE_DATA;
+
+#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, SMM_CONTROL_PRIVATE_DATA, SmmControl, SMM_CONTROL_DEV_SIGNATURE)
+
+//
+// Prototypes
+//
+
+/**
+  <b>SmmControl DXE RUNTIME Module Entry Point</b>\n
+  - <b>Introduction</b>\n
+    The SmmControl module is a DXE RUNTIME driver that provides a standard way
+    for other drivers to trigger software SMIs.
+
+  - @pre
+    - PCH Power Management I/O space base address has already been programmed.
+      If SmmControl 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.
+    - EFI_SMM_BASE2_PROTOCOL
+      - Documented in the System Management Mode Core Interface Specification.
+
+  - @result
+    The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in
+    System Management Mode Core Interface Specification.
+
+  @param[in] ImageHandle          Handle for the image of this driver
+  @param[in] SystemTable          Pointer to the EFI System Table
+
+  @retval EFI_STATUS              Results of the installation of the SMM Control Protocol
+**/
+EFI_STATUS
+EFIAPI
+SmmControlDriverEntryInit (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  );
+
+/**
+  Trigger the software SMI
+
+  @param[in] Data                 The value to be set on the software SMI data port
+
+  @retval EFI_SUCCESS             Function completes successfully
+**/
+EFI_STATUS
+EFIAPI
+SmmTrigger (
+  UINT8   Data
+  );
+
+/**
+  Clear the SMI status
+
+
+  @retval EFI_SUCCESS             The function completes successfully
+  @retval EFI_DEVICE_ERROR        Something error occurred
+**/
+EFI_STATUS
+EFIAPI
+SmmClear (
+  VOID
+  );
+
+/**
+  This routine generates an SMI
+
+  @param[in] This                       The EFI SMM Control protocol instance
+  @param[in, out] ArgumentBuffer        The buffer of argument
+  @param[in, out] ArgumentBufferSize    The size of the argument buffer
+  @param[in] Periodic                   Periodic or not
+  @param[in] ActivationInterval         Interval of periodic SMI
+
+  @retval EFI Status                    Describing the result of the operation
+  @retval EFI_INVALID_PARAMETER         Some parameter value passed is not supported
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL    *This,
+  IN OUT  UINT8                         *ArgumentBuffer OPTIONAL,
+  IN OUT  UINT8                         *ArgumentBufferSize OPTIONAL,
+  IN      BOOLEAN                       Periodic OPTIONAL,
+  IN      UINTN                         ActivationInterval OPTIONAL
+  );
+
+/**
+  This routine clears an SMI
+
+  @param[in] This                 The EFI SMM Control protocol instance
+  @param[in] Periodic             Periodic or not
+
+  @retval EFI Status              Describing the result of the operation
+  @retval EFI_INVALID_PARAMETER   Some parameter value passed is not supported
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL    *This,
+  IN       BOOLEAN                      Periodic OPTIONAL
+  );
+/**
+  Disable all pending SMIs
+
+**/
+VOID
+EFIAPI
+DisablePendingSmis (
+  VOID
+  );
+
+#endif
-- 
2.24.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#71224): https://edk2.groups.io/g/devel/message/71224
Mute This Topic: https://groups.io/mt/80375683/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