summaryrefslogtreecommitdiff
path: root/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm')
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c130
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchGpioSxIsolationSmm.c48
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c308
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h344
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf107
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c415
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c464
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPort61hSmm.c160
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c74
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchXhciSxSmm.c73
10 files changed, 2123 insertions, 0 deletions
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
new file mode 100644
index 0000000000..cfaf0d57bd
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
@@ -0,0 +1,130 @@
+/** @file
+ PCH BIOS Write Protect Driver.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "PchInitSmm.h"
+
+///
+/// Global variables
+///
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_TCO_SMI_DISPATCH_PROTOCOL *mPchTcoSmiDispatchProtocol;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSpiRegBase;
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_ESPI_SMI_DISPATCH_PROTOCOL *mEspiSmmDispatchProtocol;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN 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
+ )
+{
+ //
+ // Disable BIOSWE bit to protect BIOS
+ //
+ MmioAnd8 ((UINTN) (mSpiRegBase + R_PCH_SPI_BC), (UINT8) ~B_PCH_SPI_BC_WPD);
+}
+
+/**
+ 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
+ //
+ MmioAnd8 ((UINTN) (mLpcRegBase + R_PCH_LPC_BC), (UINT8) ~B_PCH_LPC_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;
+ }
+
+ mSpiRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SPI,
+ PCI_FUNCTION_NUMBER_PCH_SPI
+ );
+
+ mLpcRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+
+ 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);
+
+ //
+ // 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/KabylakeSiliconPkg/Pch/PchInit/Smm/PchGpioSxIsolationSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchGpioSxIsolationSmm.c
new file mode 100644
index 0000000000..4c3dd6cf11
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchGpioSxIsolationSmm.c
@@ -0,0 +1,48 @@
+/** @file
+ PCH GPIO Sx Isolation Driver Entry
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "PchInitSmm.h"
+#include <Library/GpioLib.h>
+#include <Library/GpioNativeLib.h>
+
+/**
+ This function performs GPIO Sx Isolation for DevSlp pins.
+**/
+VOID
+PchGpioSxIsolationCallback (
+ VOID
+ )
+{
+ UINT32 SataPortsMax;
+ UINT32 SataPort;
+ GPIO_PAD DevSlpGpioPad;
+
+ SataPortsMax = GetPchMaxSataPortNum ();
+
+ //
+ // If DevSlp pad is used in its native mode then
+ // set PadRstCfg to 10'b (GPIO Reset)
+ //
+ for (SataPort = 0; SataPort < SataPortsMax; SataPort++) {
+ //
+ // Check if DevSlp pad is in native mode
+ //
+ if (GpioIsSataDevSlpPinEnabled (SataPort, &DevSlpGpioPad)) {
+ //
+ // Program PADCFG_DW0.PadRstCfg
+ //
+ GpioSetPadResetConfig (DevSlpGpioPad, GpioResetNormal);
+ }
+ }
+}
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
new file mode 100644
index 0000000000..c6e1809946
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
@@ -0,0 +1,308 @@
+/** @file
+ PCH Init Smm module for PCH specific SMI handlers.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "PchInitSmm.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;
+
+//
+// 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;
+GLOBAL_REMOVE_IF_UNREFERENCED SI_CONFIG_HOB *mSiConfigHob;
+
+//
+// The reserved MMIO range to be used in Sx handler
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mResvMmioSize;
+//
+// The reserved MMIO range to be used by xHCI ASL code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mXhciMmioBaseAddr;
+
+/**
+ SMBUS Sx entry SMI handler.
+**/
+VOID
+SmbusSxCallback (
+ VOID
+ )
+{
+ UINTN SmbusRegBase;
+ UINT16 SmbusIoBase;
+
+ SmbusRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SMBUS,
+ PCI_FUNCTION_NUMBER_PCH_SMBUS
+ );
+
+ if (MmioRead32 (SmbusRegBase) == 0xFFFFFFFF) {
+ return;
+ }
+
+ SmbusIoBase = MmioRead16 (SmbusRegBase + R_PCH_SMBUS_BASE) & B_PCH_SMBUS_BASE_BAR;
+ if (SmbusIoBase == 0) {
+ return;
+ }
+
+ MmioOr8 (SmbusRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_IO_SPACE);
+ //
+ // Clear SMBUS status and SMB_WAK_STS of GPE0
+ //
+ IoWrite8 (SmbusIoBase + R_PCH_SMBUS_HSTS, B_PCH_SMBUS_SMBALERT_STS);
+ IoWrite32 (mAcpiBaseAddr + R_PCH_ACPI_GPE0_STS_127_96, B_PCH_ACPI_GPE0_STS_127_96_SMB_WAK);
+}
+
+/**
+ 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
+ )
+{
+ PchGpioSxIsolationCallback ();
+ PchLanSxCallback ();
+
+ if (((EFI_SMM_SX_REGISTER_CONTEXT*)Context)->Type == SxS3) {
+ PchXhciS3Callback ();
+ }
+
+ 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.
+
+ This function is only called from entry point therefore DXE/boot Services can be used here.
+ Updates ACPI NVS location to reserve allocated MMIO range as system resource.
+**/
+VOID
+AllocateReservedMmio (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol;
+ EFI_STATUS Status;
+
+ mResvMmioSize = 1 << N_PCH_LAN_MBARA_ALIGN;
+
+ if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
+ mResvMmioBaseAddr = 0xFFFFFFFF;
+ }
+ Status = gDS->AllocateMemorySpace (
+ PcdGet8 (PcdEfiGcdAllocateType),
+ EfiGcdMemoryTypeMemoryMappedIo,
+ N_PCH_LAN_MBARA_ALIGN,
+ mResvMmioSize,
+ &mResvMmioBaseAddr,
+ ImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "mResvMmioBaseAddr %x\n", mResvMmioBaseAddr));
+
+ //
+ // Locate the PCH shared data area and update reserved memory base address
+ //
+ Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **) &PchNvsAreaProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ PchNvsAreaProtocol->Area->SxMemSize = (UINT32) mResvMmioSize;
+ PchNvsAreaProtocol->Area->SxMemBase = (UINT32) mResvMmioBaseAddr;
+
+ //
+ // Install and initialize all the needed protocols
+ //
+ if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
+ mXhciMmioBaseAddr = 0xFFFFFFFF;
+ }
+ Status = gDS->AllocateMemorySpace (
+ PcdGet8 (PcdEfiGcdAllocateType),
+ EfiGcdMemoryTypeMemoryMappedIo,
+ N_PCH_XHCI_MEM_ALIGN,
+ V_PCH_XHCI_MEM_LENGTH,
+ &mXhciMmioBaseAddr,
+ ImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "mXhciMmioBaseAddr %x\n", mXhciMmioBaseAddr));
+
+ //
+ // Update XWMB, XHCI memory base address
+ //
+ PchNvsAreaProtocol->Area->XhciRsvdMemBase = (UINT32) mXhciMmioBaseAddr;
+}
+
+/**
+ 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);
+
+ HobPtr.Guid = GetFirstGuidHob (&gSiConfigHobGuid);
+ ASSERT (HobPtr.Guid != NULL);
+ mSiConfigHob = (SI_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);
+
+ PchAcpiBaseGet (&mAcpiBaseAddr);
+
+ AllocateReservedMmio (ImageHandle);
+
+ InitializeSxHandler (ImageHandle);
+
+ Status = InitializePchPcieSmm (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = InstallIoTrapPort61h (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = InstallPchBiosWriteProtect (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = InstallPchSpiAsyncSmiHandler ();
+ ASSERT_EFI_ERROR (Status);
+
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
new file mode 100644
index 0000000000..58ef567cc0
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
@@ -0,0 +1,344 @@
+/** @file
+ Header file for PCH Init SMM Handler
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _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 <IndustryStandard/Pci30.h>
+#include <PchAccess.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PchPcieRpLib.h>
+#include <Library/PchInfoLib.h>
+#include <Library/GpioLib.h>
+#include <Library/GpioNativeLib.h>
+#include <Library/PchEspiLib.h>
+#include <Library/MmPciLib.h>
+#include <Library/ConfigBlockLib.h>
+#include <Library/PchPciExpressHelpersLib.h>
+#include <Protocol/PchPcieSmiDispatch.h>
+#include <Protocol/PchTcoSmiDispatch.h>
+#include <Protocol/PchSmiDispatch.h>
+#include <Protocol/PchEspiSmiDispatch.h>
+#include <Protocol/PchSmmIoTrapControl.h>
+#include <Protocol/PchNvs.h>
+#include <Protocol/PcieIoTrap.h>
+#include <SiConfigHob.h>
+#include <PchConfigHob.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 EFI_PHYSICAL_ADDRESS mXhciMmioBaseAddr;
+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 *mSiConfigHob;
+
+#define EFI_PCI_CAPABILITY_ID_PCIPM 0x01
+
+#define DeviceD0 0x00
+#define DeviceD3 0x03
+
+typedef enum {
+ PciCfg,
+ PciMmr
+} PCH_PCI_ACCESS_TYPE;
+
+typedef enum {
+ Acpi,
+ Rcrb,
+ Tco
+} PCH_ACCESS_TYPE;
+
+typedef struct {
+ PCH_ACCESS_TYPE AccessType;
+ UINT32 Address;
+ UINT32 Data;
+ UINT32 Mask;
+ UINT8 Width;
+} PCH_SAVE_RESTORE_REG;
+
+typedef struct {
+ PCH_SAVE_RESTORE_REG* PchSaveRestoreReg;
+ UINT8 size;
+ PCH_SERIES PchSeries;
+} PCH_SAVE_RESTORE_REG_WRAP;
+
+struct _PCH_SAVE_RESTORE_PCI;
+
+typedef struct _PCH_SAVE_RESTORE_PCI{
+ PCH_PCI_ACCESS_TYPE AccessType;
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 BarOffset;
+ UINT16 Offset;
+ UINT32 Data;
+ UINT32 Mask;
+ UINT8 Width;
+ VOID (*RestoreFunction)(struct _PCH_SAVE_RESTORE_PCI *PchSaveRestorePci);
+} PCH_SAVE_RESTORE_PCI;
+
+typedef struct {
+ PCH_SAVE_RESTORE_PCI* PchSaveRestorePci;
+ UINT8 size;
+ PCH_SERIES PchSeries;
+} PCH_SAVE_RESTORE_PCI_WRAP;
+
+typedef struct {
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 PowerState;
+} DEVICE_POWER_STATE;
+
+VOID
+RestorePxDevSlp(
+ IN PCH_SAVE_RESTORE_PCI *PchSaveRestorePci
+ );
+
+/**
+ 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
+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
+ );
+
+/**
+ Locate required protocol and register the 61h IO trap
+
+ @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
+InstallIoTrapPort61h (
+ 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
+ );
+
+/**
+ xHCI S3 entry handler
+**/
+VOID
+PchXhciS3Callback (
+ VOID
+ );
+
+/**
+ GbE Sx entry handler
+**/
+VOID
+PchLanSxCallback (
+ VOID
+ );
+
+/**
+ This function performs GPIO Sx Isolation for DevSlp pins.
+**/
+VOID
+PchGpioSxIsolationCallback (
+ 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/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
new file mode 100644
index 0000000000..458eac090e
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
@@ -0,0 +1,107 @@
+## @file
+# Component description file for PchInitSmm driver
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License which accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+INF_VERSION = 0x00010017
+BASE_NAME = 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
+PchPciExpressHelpersLib
+SmmServicesTableLib
+MmPciLib
+HobLib
+GpioLib
+GpioPrivateLib
+ReportStatusCodeLib
+DevicePathLib
+PchCycleDecodingLib
+PchPcieRpLib
+PchInfoLib
+TimerLib
+ConfigBlockLib
+
+
+[Packages]
+MdePkg/MdePkg.dec
+KabylakeSiliconPkg/SiPkg.dec
+KabylakeSiliconPkg/KabylakeSiliconPrivate.dec
+
+
+[Pcd]
+gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType
+
+
+[Sources]
+PchInitSmm.c
+PchPcieSmm.c
+PchPort61hSmm.c
+PchGpioSxIsolationSmm.c
+PchLanSxSmm.c
+PchInitSmm.h
+PchBiosWriteProtect.c
+PchSpiAsync.c
+PchXhciSxSmm.c
+
+
+[Protocols]
+gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES
+gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES
+gPchSmmIoTrapControlGuid ## CONSUMES
+gEfiSmmCpuProtocolGuid ## CONSUMES
+gPchNvsAreaProtocolGuid ## CONSUMES
+gPchPcieSmiDispatchProtocolGuid ## CONSUMES
+gPchTcoSmiDispatchProtocolGuid ## CONSUMES
+gPchSmiDispatchProtocolGuid ## CONSUMES
+gPchEspiSmiDispatchProtocolGuid ## CONSUMES
+gPchPcieIoTrapProtocolGuid ## PRODUCES
+
+
+[Guids]
+gSiConfigHobGuid ## CONSUMES
+gPchConfigHobGuid ## CONSUMES
+gPchDeviceTableHobGuid
+
+
+[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 # This is for SmmServicesTableLib
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c
new file mode 100644
index 0000000000..d05cb61bbc
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c
@@ -0,0 +1,415 @@
+/** @file
+ PCH LAN Sx handler implementation.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/TimerLib.h>
+#include "PchInitSmm.h"
+
+//
+// Maximum loop time for GbE status check
+//
+#define GBE_MAX_LOOP_TIME 4000
+
+/**
+ Checks if Lan is Enabled or Disabled
+
+ @retval BOOLEAN TRUE if device is enabled, FALSE otherwise.
+**/
+BOOLEAN
+IsGbeEnabled (
+ VOID
+ )
+{
+ UINTN GbePciBase;
+
+ GbePciBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LAN,
+ PCI_FUNCTION_NUMBER_PCH_LAN
+ );
+
+ if (MmioRead32 (GbePciBase) != 0xFFFFFFFF) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+/**
+ Test for MDIO operation complete.
+
+ @param [in] GbeBar GbE MMIO space
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+**/
+EFI_STATUS
+GbeMdiWaitReady (
+ UINT32 GbeBar
+ )
+{
+ UINT32 Count;
+
+ for (Count = 0; Count < GBE_MAX_LOOP_TIME; ++Count) {
+ if (MmioRead32 (GbeBar + R_PCH_LAN_CSR_MDIC) & B_PCH_LAN_CSR_MDIC_RB) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (50);
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Acquire MDIO software semaphore.
+
+ 1. Ensure that MBARA offset F00h [5] = 1b
+ 2. Poll MBARA offset F00h [5] up to 200ms
+
+ @param [in] GbeBar GbE MMIO space
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+**/
+EFI_STATUS
+GbeAcquireMdio (
+ IN UINT32 GbeBar
+ )
+{
+ UINT32 ExtCnfCtrl;
+ UINT32 Count;
+
+ MmioOr32 (GbeBar + R_PCH_LAN_CSR_EXTCNF_CTRL, B_PCH_LAN_CSR_EXTCNF_CTRL_SWFLAG);
+ for (Count = 0; Count < GBE_MAX_LOOP_TIME; ++Count) {
+ ExtCnfCtrl = MmioRead32 (GbeBar + R_PCH_LAN_CSR_EXTCNF_CTRL);
+ if (ExtCnfCtrl & B_PCH_LAN_CSR_EXTCNF_CTRL_SWFLAG) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (50);
+ }
+ ASSERT (FALSE);
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ Release MDIO software semaphore by clearing MBARA offset F00h [5]
+
+ @param [in] GbeBar GbE MMIO space
+**/
+VOID
+GbeReleaseMdio (
+ IN UINT32 GbeBar
+ )
+{
+ ASSERT (MmioRead32 (GbeBar + R_PCH_LAN_CSR_EXTCNF_CTRL) & B_PCH_LAN_CSR_EXTCNF_CTRL_SWFLAG);
+ MmioAnd32 (GbeBar + R_PCH_LAN_CSR_EXTCNF_CTRL, (UINT32) ~B_PCH_LAN_CSR_EXTCNF_CTRL_SWFLAG);
+ ASSERT ((MmioRead32 (GbeBar + R_PCH_LAN_CSR_EXTCNF_CTRL) & B_PCH_LAN_CSR_EXTCNF_CTRL_SWFLAG) == 0);
+}
+
+/**
+ Perform MDI write.
+
+ @param [in] GbeBar GbE MMIO space
+ @param [in] Data Value to write in lower 16bits, upper 16bit may contain opcode.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+GbeMdiWrite (
+ IN UINT32 GbeBar,
+ IN UINT32 Data
+ )
+{
+ MmioWrite32 (GbeBar + R_PCH_LAN_CSR_MDIC, Data | 0x04000000);
+ return GbeMdiWaitReady (GbeBar);
+}
+
+/**
+ Perform MDI read.
+
+ @param [in] GbeBar GbE MMIO space
+ @param [in] Command MDI command
+ @param [out] Data Value read
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+GbeMdiRead (
+ IN UINT32 GbeBar,
+ IN UINT32 Command,
+ OUT UINT16 *Data
+ )
+{
+ EFI_STATUS Status;
+ MmioWrite32 (GbeBar + R_PCH_LAN_CSR_MDIC, Command | 0x08000000);
+ Status = GbeMdiWaitReady (GbeBar);
+ *Data = (UINT16) MmioRead32 (GbeBar + R_PCH_LAN_CSR_MDIC);
+ return Status;
+}
+
+/**
+ Configure WOL during Sx entry.
+
+ @param [in] GbeBar GbE MMIO space
+**/
+VOID
+GbeWolWorkaround (
+ IN UINT32 GbeBar
+ )
+{
+ UINT32 RAL0;
+ UINT32 RAH0;
+ EFI_STATUS Status;
+ UINT16 Data16;
+
+ //
+ // System BIOS performs read from MBARA offset 5400h [31:0] and MBARA offset 5404h [31:0]
+ //
+ RAL0 = MmioRead32 (GbeBar + R_PCH_LAN_CSR_RAL);
+ RAH0 = MmioRead32 (GbeBar + R_PCH_LAN_CSR_RAH);
+
+ //
+ // Set MBARA offset 20h = 0x043f6400
+ //
+ Status = GbeMdiWrite (GbeBar, 0x043f6400);
+
+ //
+ // If timeout is reached, force MAC to SMB and try again
+ // Assert if failed on second attempt
+ //
+ if (Status == EFI_TIMEOUT) {
+ //
+ // Change Extended Device Control Register BIT 11 to 1 which
+ // forces the interface between the MAC and the Phy to be on SMBus.
+ // Cleared on the assertion of PCI reset.
+ //
+ MmioOr32 (GbeBar + R_PCH_LAN_CSR_CTRL_EXT, B_PCH_LAN_CSR_CTRL_EXT_FORCE_SMB);
+ Status = GbeMdiWrite (GbeBar, 0x043f6400);
+ }
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Wait 4 mSec
+ //
+ MicroSecondDelay (4000);
+
+ //
+ // Set MBARA offset 20h = 0x4310010
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04310010);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4320000 or with
+ // the least significant word of MBARA offset 5400
+ //
+ Status = GbeMdiWrite (GbeBar, (0x04320000 | (RAL0 & 0xFFFF)));
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4310011
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04310011);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4320000 or with
+ // the most significant word of MBARA offset 5400
+ //
+ Status = GbeMdiWrite (GbeBar, (0x04320000 | (RAL0 >> 16)));
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4310012
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04310012);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4320000 or with
+ // the least significant word of MBARA offset 5404
+ //
+ Status = GbeMdiWrite (GbeBar, (0x04320000 | (RAH0 & B_PCH_LAN_CSR_RAH_RAH)));
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4310013
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04310013);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4328000
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04328000);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4310001
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04310001);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x8320000
+ //
+ Status = GbeMdiRead (GbeBar, 0x08320000, &Data16);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x4320000 OR TEMP[15:0] OR 1
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04320000 | Data16 | BIT0);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x43f6460
+ //
+ Status = GbeMdiWrite (GbeBar, 0x043f6460);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Wait 4 mSec
+ //
+ MicroSecondDelay (4000);
+
+ //
+ // Set MBARA offset 20h = 0x4310042
+ //
+ Status = GbeMdiWrite (GbeBar, 0x04310042);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA offset 20h = 0x43F6020
+ //
+ Status = GbeMdiWrite (GbeBar, 0x043F6020);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Wait 4 mSec
+ //
+ MicroSecondDelay (4000);
+
+ //
+ // Set MBARA offset 20h = 0x8310000
+ // TEMP[15:0] = MBARA + 20[15:0]
+ //
+ Status = GbeMdiRead (GbeBar, 0x08310000, &Data16);
+ if (EFI_ERROR (Status)) return;
+
+ //
+ // Set MBARA + 20h = 4310000h or with the TEMP[15:0] OR 10h
+ //
+ GbeMdiWrite (GbeBar, 0x04310000 | Data16 | BIT4);
+}
+
+/**
+ 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
+ )
+{
+ UINTN LanRegBase;
+ UINT32 GbeBar;
+ EFI_STATUS Status;
+
+ LanRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LAN,
+ PCI_FUNCTION_NUMBER_PCH_LAN
+ );
+
+ if (MmioRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+ return;
+ }
+
+ //
+ // Check if GbE device is in D0
+ //
+ if ((MmioRead16 (LanRegBase + R_PCH_LAN_PMCS) & B_PCH_LAN_PMCS_PS) != V_PCH_LAN_PMCS_PS0) {
+ return;
+ }
+
+ ASSERT (mResvMmioSize >= (1 << N_PCH_LAN_MBARA_ALIGN));
+ GbeBar = (UINT32) mResvMmioBaseAddr;
+ if (GbeBar == 0) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Enable MMIO decode using reserved range.
+ //
+ MmioAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+ MmioWrite32 (LanRegBase + R_PCH_LAN_MBARA, GbeBar);
+ MmioOr16 (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_PCH_LAN_CSR_WUC) & B_PCH_LAN_CSR_WUC_APME) {
+ Status = GbeAcquireMdio (GbeBar);
+ ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ GbeWolWorkaround (GbeBar);
+ GbeReleaseMdio (GbeBar);
+ }
+ }
+
+ //
+ // Disable MMIO decode.
+ //
+ MmioAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+ MmioWrite32 (LanRegBase + R_PCH_LAN_MBARA, 0);
+}
+
+/**
+ Enable platform wake from LAN when in DeepSx if platform supports it.
+ Called upon Sx entry.
+**/
+VOID
+GbeConfigureDeepSxWake (
+ VOID
+ )
+{
+ UINT32 PchPwrmBase;
+
+ PchPwrmBaseGet (&PchPwrmBase);
+
+ if ((MmioRead32 (PchPwrmBase + R_PCH_PWRM_DSX_CFG) & (UINT32) B_PCH_PWRM_DSX_CFG_LAN_WAKE_EN) != 0) {
+ IoOr32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0_EN_127_96), (UINT32) B_PCH_ACPI_GPE0_EN_127_96_LAN_WAKE);
+ }
+}
+
+/**
+ GbE Sx entry handler
+**/
+VOID
+PchLanSxCallback (
+ VOID
+ )
+{
+ if (IsGbeEnabled ()) {
+ GbeSxWorkaround ();
+ GbeConfigureDeepSxWake ();
+
+ }
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
new file mode 100644
index 0000000000..b4234f649c
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
@@ -0,0 +1,464 @@
+/** @file
+ PCH Pcie SMM Driver Entry
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "PchInitSmm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE *mDevAspmOverride;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfDevAspmOverride;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPolicyRevision;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPchBusNumber;
+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 UINT32 mLtrNonSupportRpBitMap;
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mPciePmTrapExecuted = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAllowNoLtrIccPllShutdownPolicy = 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;
+ EFI_HANDLE Handle;
+ UINT32 PwrmBase;
+ UINTN RpBase;
+ BOOLEAN LtrSupported;
+ BOOLEAN DownstreamDevicePresent;
+
+ Handle = NULL;
+ LtrSupported = TRUE;
+
+ RpBase = MmPciBase (
+ mPchBusNumber,
+ (UINT32) RpDevice,
+ (UINT32) RpFunction
+ );
+
+ if (MmioRead16 (RpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check for presence detect state
+ //
+ DownstreamDevicePresent = !!(MmioRead16 (RpBase + R_PCH_PCIE_SLSTS) & B_PCIE_SLSTS_PDS);
+
+ mLtrNonSupportRpBitMap &= ~(1 << PortIndex);
+
+ if (DownstreamDevicePresent) {
+ SecBus = MmioRead8 (RpBase + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ SubBus = MmioRead8 (RpBase + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ ASSERT (SecBus != 0 && SubBus != 0);
+ PchPcieInitRootPortDownstreamDevices (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ RpDevice,
+ RpFunction,
+ mTempRootPortBusNumMin,
+ mTempRootPortBusNumMax,
+ (BOOLEAN)mPcieRootPortConfig[PortIndex].EnableCpm
+ );
+ if (!LtrSupported) {
+ mLtrNonSupportRpBitMap |= 1 << PortIndex;
+ }
+
+ //
+ // Perform Equalization
+ //
+ MmioOr32 (RpBase + R_PCH_PCIE_EX_LCTL3, B_PCIE_EX_LCTL3_PE);
+ MmioOr32 (RpBase + R_PCH_PCIE_LCTL, B_PCIE_LCTL_RL);
+ }
+
+ //
+ // If not all devices support LTR, set PWRMBASE + 0x3EC [24,16] = 0, 1
+ // This will disable ICC PLL shutdown
+ //
+ if (!mAllowNoLtrIccPllShutdownPolicy) {
+ PchPwrmBaseGet (&PwrmBase);
+ if (mLtrNonSupportRpBitMap != 0) {
+ MmioAndThenOr32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~BIT24, BIT16);
+ } else {
+ MmioAnd32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~(BIT24 | BIT16));
+ }
+ }
+
+ 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 PwrmBase;
+ UINT32 PortIndex;
+ UINTN RpBase;
+ BOOLEAN L1SubstatesSupportedPerPort;
+ UINT8 MaxPciePortNum;
+ UINTN RpDevice;
+ UINTN RpFunction;
+ PCH_GENERATION PchGen;
+ PCH_SERIES PchSeries;
+ PCH_STEPPING PchStep;
+
+ PchGen = GetPchGeneration ();
+ PchSeries = GetPchSeries ();
+ PchStep = PchStepping ();
+ L1SubstatesSupportedPerPort = FALSE;
+ MaxPciePortNum = GetPchMaxPciePortNum ();
+
+ //
+ // Step 4a
+ // In case not all devices support LTR, disable ICC PLL shutdown
+ // set PWRMBASE + 0x3EC [24,16] = 0, 1
+ // (Note this register should be saved and restored during S3 transitions)
+ //
+ if (!mAllowNoLtrIccPllShutdownPolicy) {
+ PchPwrmBaseGet (&PwrmBase);
+ MmioAndThenOr32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~BIT24, BIT16);
+ }
+
+ for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
+ GetPchPcieRpDevFun (PortIndex, &RpDevice, &RpFunction);
+ RpBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDevice, (UINT32) RpFunction);
+ }
+ //
+ // Step 4b
+ // By this time, LTR support map is known.
+ // If all devices support LTR, allow ICC PLL shutdown
+ // (Note this register should be saved and restored during S3 transitions)
+ //
+ if (!mAllowNoLtrIccPllShutdownPolicy) {
+ if (mLtrNonSupportRpBitMap == 0) {
+ PchPwrmBaseGet (&PwrmBase);
+ MmioAnd32 (PwrmBase + R_PCH_PWRM_CS_SD_CTL2, (UINT32) ~(BIT24 | BIT16));
+ }
+ }
+
+ //
+ // Program the remapped root port's ASPM based on endpoint's ASPM
+ //
+ if ((PchGen == SklPch) &&
+ (((PchSeries == PchLp) && (PchStep < PchLpC0)) ||
+ ((PchSeries == PchH) && (PchStep < PchHD0)))) {
+ return;
+ }
+}
+
+/**
+ 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
+PchPcieIoTrapSmiCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ if (CallbackContext->WriteData == PciePmTrap) {
+ if (mPciePmTrapExecuted == FALSE) {
+ PchPciePmIoTrapSmiCallback ();
+ mPciePmTrapExecuted = 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
+ )
+{
+ mPciePmTrapExecuted = 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;
+ UINTN RpBase;
+ UINTN RpDevice;
+ UINTN RpFunction;
+ EFI_HANDLE PcieHandle;
+ PCH_PCIE_SMI_DISPATCH_PROTOCOL *PchPcieSmiDispatchProtocol;
+ EFI_HOB_GUID_TYPE* Hob;
+ UINT32 DevTableSize;
+ 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;
+
+ 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);
+
+ mPolicyRevision = mSiConfigHob->Header.Revision;
+ mPchBusNumber = DEFAULT_PCI_BUS_NUMBER_PCH;
+ mTempRootPortBusNumMin = mSiConfigHob->TempPciBusMin;
+ mTempRootPortBusNumMax = mSiConfigHob->TempPciBusMax;
+ mAllowNoLtrIccPllShutdownPolicy = (BOOLEAN) mPchConfigHob->PcieRp.AllowNoLtrIccPllShutdown;
+
+ ASSERT (sizeof mPcieRootPortConfig == sizeof mPchConfigHob->PcieRp.RootPort);
+ CopyMem (
+ mPcieRootPortConfig,
+ &(mPchConfigHob->PcieRp.RootPort),
+ sizeof (mPcieRootPortConfig)
+ );
+
+ mDevAspmOverride = NULL;
+ mNumOfDevAspmOverride = 0;
+ mLtrNonSupportRpBitMap = 0;
+
+ Hob = GetFirstGuidHob (&gPchDeviceTableHobGuid);
+ if (Hob != NULL) {
+ DevTableSize = GET_GUID_HOB_DATA_SIZE (Hob);
+ ASSERT ((DevTableSize % sizeof (PCH_PCIE_DEVICE_OVERRIDE)) == 0);
+ mNumOfDevAspmOverride = DevTableSize / sizeof (PCH_PCIE_DEVICE_OVERRIDE);
+ DEBUG ((DEBUG_INFO, "Found PcieDeviceTable HOB (%d entries)\n", mNumOfDevAspmOverride));
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ DevTableSize,
+ (VOID **) &mDevAspmOverride
+ );
+ CopyMem (mDevAspmOverride, GET_GUID_HOB_DATA (Hob), DevTableSize);
+ }
+
+ //
+ // Throught all PCIE root port function and register the SMI Handler for enabled ports.
+ //
+ for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
+ GetPchPcieRpDevFun (PortIndex, &RpDevice, &RpFunction);
+ RpBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDevice, (UINT32) RpFunction);
+ //
+ // Skip the root port function which is not enabled
+ //
+ if (MmioRead32 (RpBase) == 0xFFFFFFFF) {
+ continue;
+ }
+
+ if (!mPcieRootPortConfig[PortIndex].EnableHotplugSmi) {
+ continue;
+ }
+ //
+ // Register SMI Handlers for Hot Plug and Link Active State Change
+ //
+ Data8 = MmioRead8 (RpBase + R_PCH_PCIE_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_MPC_HPME;
+ Data32And = (UINT32) ~B_PCH_PCIE_MPC_HPME;
+ S3BootScriptSaveMemReadWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (RpBase + R_PCH_PCIE_MPC),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+
+ //
+ // Register SMI Handler for Link Equalization Request from Gen 3 Devices.
+ //
+ Data8 = MmioRead8 (RpBase + R_PCH_PCIE_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 () End\n"));
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPort61hSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPort61hSmm.c
new file mode 100644
index 0000000000..0717f38291
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchPort61hSmm.c
@@ -0,0 +1,160 @@
+/** @file
+ PCH Port 61h bit-4 toggling in SMM IO Trap
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchInitSmm.h"
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpu; ///< To read and write save state
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mPchIoTrapHandle; ///< Pause and resume via EFI_HANDLE
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *mPchSmmIoTrapControl; ///< To pause and resume IO trap
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mInternalState = 0; ///< To store the toggle value for each CPU threads
+
+/**
+ This SMI handle will pause the IO trap in the beginning
+
+ @param[in] DispatchHandle - The handle of this callback, obtained when registering
+ @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
+
+ @retval None
+**/
+VOID
+PchIoTrapPort61hSmiCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *CallbackContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN CpuIndex;
+ UINTN Mask;
+ UINT8 ReadValue, WriteValue;
+ EFI_SMM_SAVE_STATE_IO_INFO IoInfo;
+ //
+ // Disabling the IO Trap, prevent SMI re-enter because of reading port 61h in handler itself
+ //
+ Status = mPchSmmIoTrapControl->Pause (
+ mPchSmmIoTrapControl,
+ mPchIoTrapHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Detects the CPU which causes the IO Trap
+ //
+ for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
+ Status = mSmmCpu->ReadSaveState (
+ mSmmCpu,
+ sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
+ EFI_SMM_SAVE_STATE_REGISTER_IO,
+ CpuIndex,
+ &IoInfo
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Make sure the IO trap is byte read, port input only, and it is port 0x61
+ //
+ if ((IoInfo.IoWidth == EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8) &&
+ (IoInfo.IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT) &&
+ (IoInfo.IoPort == 0x61)) {
+ //
+ // Read from Port 61h, toggle bit4 based on the internal state
+ //
+ ReadValue = IoRead8 (0x61);
+ Mask = (UINTN) (1 << CpuIndex);
+ mInternalState ^= Mask;
+ WriteValue = (mInternalState & Mask) ? (ReadValue | 0x10) : (ReadValue & ~0x10);
+ Status = mSmmCpu->WriteSaveState (
+ mSmmCpu,
+ sizeof (UINT8),
+ EFI_SMM_SAVE_STATE_REGISTER_RAX,
+ CpuIndex,
+ &WriteValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ } //if the iotrap is the one we want
+ } //if iotrap happens for this thread
+ } //for (iterate for all threads)
+
+ //
+ // Resume the IO Trap
+ // Port 61h bit-4 emulation will be disabled after exit boot service
+ // The disabling mechanism is actually to not resume the trap.
+ // This means, even after exit boot service, this handler will be called once
+ // before it is disabled
+ //
+ if (mPchNvsArea->ExitBootServicesFlag == 0) {
+ Status = mPchSmmIoTrapControl->Resume (
+ mPchSmmIoTrapControl,
+ mPchIoTrapHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ DEBUG ((DEBUG_INFO, "Port61H trap has been disabled. \n"));
+ }
+}
+
+
+/**
+ Locate required protocol and register the IO trap in this entry point
+
+ @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
+InstallIoTrapPort61h (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext;
+
+ DEBUG ((DEBUG_INFO, "InstallIoTrapPort61h()\n"));
+
+ if (mPchConfigHob->Port61hSmm.Enable == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Locate the protocol to read and write save state
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate the protocol for pause and resume
+ //
+ Status = gSmst->SmmLocateProtocol (&gPchSmmIoTrapControlGuid, NULL, (VOID **) &mPchSmmIoTrapControl);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Configure trap type, in ECP, MergeDisable should be TRUE for pause and resume to work
+ //
+ PchIoTrapContext.Type = ReadTrap;
+ PchIoTrapContext.Length = 1;
+ PchIoTrapContext.Address = 0x61;
+ Status = mPchIoTrap->Register (
+ mPchIoTrap,
+ (EFI_SMM_HANDLER_ENTRY_POINT2) PchIoTrapPort61hSmiCallback,
+ &PchIoTrapContext,
+ &mPchIoTrapHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
new file mode 100644
index 0000000000..463de1dba8
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
@@ -0,0 +1,74 @@
+/** @file
+ PCH SPI Async SMI handler.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "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/KabylakeSiliconPkg/Pch/PchInit/Smm/PchXhciSxSmm.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchXhciSxSmm.c
new file mode 100644
index 0000000000..f17b125d4f
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Smm/PchXhciSxSmm.c
@@ -0,0 +1,73 @@
+/** @file
+ PCH xHCI Sx handler implementation.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/TimerLib.h>
+#include "PchInitSmm.h"
+
+/**
+ xHCI Controller Configurations Prior to Entering S3
+**/
+VOID
+PchXhciS3Callback (
+ VOID
+ )
+{
+ UINTN XhciPciMmBase;
+ UINT8 OrgCmdByte;
+ UINT16 OrgPmcs;
+ UINT32 OrgMmioAddr;
+ UINT32 OrgMmioHAddr;
+ UINT32 XhciMmioBase;
+
+ XhciPciMmBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI
+ );
+
+ ///
+ /// Save Cmd and XhciBar and Pmcs registers
+ ///
+ OrgCmdByte = MmioRead8 (XhciPciMmBase + PCI_COMMAND_OFFSET);
+ OrgPmcs = MmioRead16 (XhciPciMmBase + R_PCH_XHCI_PWR_CNTL_STS);
+ OrgMmioAddr = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE) & 0xFFFF0000;
+ OrgMmioHAddr = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE + 4);
+
+ ///
+ /// Use the reserved MMIO
+ /// Clear MSE before changing MMIO address
+ ///
+ MmioAnd8 (XhciPciMmBase + PCI_COMMAND_OFFSET, (UINT8)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE, (UINT32) mXhciMmioBaseAddr);
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE + 4, 0);
+
+ ///
+ /// Set MSE
+ ///
+ MmioOr8 (XhciPciMmBase + PCI_COMMAND_OFFSET, (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
+
+ XhciMmioBase = (UINT32) mXhciMmioBaseAddr;
+
+ ///
+ /// Restore Cmd and XhciBar and Pmcs registers
+ ///
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE + 4, OrgMmioHAddr);
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE, OrgMmioAddr);
+ MmioWrite8 (XhciPciMmBase + PCI_COMMAND_OFFSET, OrgCmdByte);
+ ///
+ /// Bring device to D3
+ ///
+ MmioOr8 (XhciPciMmBase + R_PCH_XHCI_PWR_CNTL_STS, (UINT8)(V_PCH_XHCI_PWR_CNTL_STS_PWR_STS_D3));
+
+} \ No newline at end of file