summaryrefslogtreecommitdiff
path: root/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit')
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c465
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchCio2Acpi.c57
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c247
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c504
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h320
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c699
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.inf101
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFsp.inf80
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c169
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchRstPcieStorage.c286
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c125
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchScs.c1869
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c49
-rw-r--r--Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c112
-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
24 files changed, 7206 insertions, 0 deletions
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
new file mode 100644
index 0000000000..789b61170d
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
@@ -0,0 +1,465 @@
+/** @file
+ This is the driver that initializes the Intel PCH.
+
+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 "PchInit.h"
+#include <Library/PchSerialIoLib.h>
+
+//
+// Module variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol;
+
+extern PCH_RST_PCIE_STORAGE_DETECTION mRstPcieStorageDetection[];
+
+/**
+ Retrieve interrupt information about a PCH device from policy
+
+ @param[in] Device PCI device number
+
+ @retval PCH_DEVICE_INTERRUPT_CONFIG structure with device's interrupt information
+**/
+PCH_DEVICE_INTERRUPT_CONFIG
+GetInterruptPolicy (
+ IN PCH_SERIAL_IO_CONTROLLER Device
+ )
+{
+ PCH_DEVICE_INTERRUPT_CONFIG EmptyRecord;
+ UINT8 DevNum;
+ UINT8 FuncNum;
+ UINT8 Index;
+
+ ZeroMem (&EmptyRecord, sizeof (PCH_DEVICE_INTERRUPT_CONFIG));
+ DevNum = GetSerialIoDeviceNumber (Device);
+ FuncNum = GetSerialIoFunctionNumber (Device);
+
+ 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.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+UpdateSerialIoAcpiData (
+ VOID
+ )
+{
+ PCH_SERIAL_IO_CONTROLLER Index;
+
+ for (Index = 0; Index < PCH_SERIALIO_MAX_CONTROLLERS; Index++) {
+ mPchNvsAreaProtocol.Area->SMD[Index] = mPchConfigHob->SerialIo.DevMode[Index];
+ mPchNvsAreaProtocol.Area->SIR[Index] = (GetInterruptPolicy (Index)).Irq;
+ mPchNvsAreaProtocol.Area->SB0[Index] = FindSerialIoBar (Index, 0);
+ mPchNvsAreaProtocol.Area->SB1[Index] = FindSerialIoBar (Index, 1);
+ }
+ if (GetPchSeries () == PchH) {
+ mPchNvsAreaProtocol.Area->SMD[PchSerialIoIndexI2C4] = PchSerialIoDisabled;
+ mPchNvsAreaProtocol.Area->SMD[PchSerialIoIndexI2C5] = PchSerialIoDisabled;
+ }
+
+ //
+ // Update GPIO device ACPI variables
+ //
+ mPchNvsAreaProtocol.Area->GPEN = mPchConfigHob->SerialIo.Gpio;
+ mPchNvsAreaProtocol.Area->SGIR = mPchConfigHob->Interrupt.GpioIrqRoute;
+
+
+ DEBUG ((DEBUG_INFO, "UpdateSerialIoAcpiData() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update NVS Area after RST PCIe Storage Remapping and before Boot
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+PchUpdateNvsAreaAfterRemapping (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {
+ mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index] = mRstPcieStorageDetection[Index].DeviceInterface;
+ mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PmCapPtr;
+ mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PcieCapPtr;
+ mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.L1ssCapPtr;
+ mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl2;
+ mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl1;
+ mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.LtrCapPtr;
+ mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLtrData;
+ mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLctlData16;
+ mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctlData16;
+ mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctl2Data16;
+ mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.RootPortDctl2Data16;
+ mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBar;
+ mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBarValue[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBarValue;
+ mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBar;
+ mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBarValue;
+ mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index] = mRstPcieStorageDetection[Index].RootPortNum;
+ }
+ 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
+ )
+{
+
+ PCH_SERIES PchSeries;
+
+ DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n"));
+
+ PchSeries = GetPchSeries ();
+
+ ///
+ /// 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 ();
+ //
+ // Define and update ASL definitions for Cio2 device (only on PCH-LP).
+ //
+ if (PchSeries >= PchLp) {
+ UpdateCio2AcpiData ();
+ }
+
+ //
+ // Update Pch Nvs Area
+ //
+ PchUpdateNvsArea ();
+
+ //
+ // Patch PchNvsArea Address
+ //
+ PatchPchNvsAreaAddress ();
+
+ 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 ();
+ //
+ // 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;
+}
+
+
+/**
+ PCH Update NvsArea ExitBootServicesFlag on ExitBootService. This event is used if only ExitBootService is used
+ and not in legacy boot
+
+ @retval None
+**/
+VOID
+EFIAPI
+PchUpdateNvsOnExitBootServices (
+ VOID
+ )
+{
+ mPchNvsAreaProtocol.Area->ExitBootServicesFlag = 1;
+
+ return;
+}
+
+/**
+ 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;
+ PCH_SERIES PchSeries;
+ UINTN Index;
+ UINT32 HpetBaseAdress;
+ GPIO_GROUP GroupToGpeDw0;
+ GPIO_GROUP GroupToGpeDw1;
+ GPIO_GROUP GroupToGpeDw2;
+ GPIO_GROUP Group;
+ UINT32 PadNumber;
+ GPIO_PAD GpioPad;
+ GPIO_PAD_OWN PadOwnVal;
+ GPIO_CONFIG GpioData;
+ UINTN RpDev;
+ UINTN RpFun;
+ UINT32 Data32;
+ UINT16 Data16;
+
+ Status = EFI_SUCCESS;
+ PchSeries = GetPchSeries ();
+
+ //
+ // Update ASL PCIE port address according to root port device and function
+ //
+ for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
+ Status = GetPchPcieRpDevFun (Index, &RpDev, &RpFun);
+ ASSERT_EFI_ERROR (Status);
+
+ 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].LtrMaxSnoopLatency;
+ mPchNvsAreaProtocol.Area->PcieLtrMaxNoSnoopLatency[Index] = mPchConfigHob->PcieRp.RootPort[Index].LtrMaxNoSnoopLatency;
+ }
+
+ //
+ // Update PCHS.
+ //
+ mPchNvsAreaProtocol.Area->PchSeries = (UINT16) PchSeries;
+ //
+ // Update PCHG.
+ //
+ mPchNvsAreaProtocol.Area->PchGeneration = (UINT16) GetPchGeneration ();
+ //
+ // 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 PMC ACPIBASE and PWRMBASE
+ //
+ PchAcpiBaseGet (&Data16);
+ mPchNvsAreaProtocol.Area->PMBS = Data16;
+
+ PchPwrmBaseGet (&Data32);
+ mPchNvsAreaProtocol.Area->PWRM = Data32;
+
+ //
+ // Update GPP_X to GPE_DWX mapping.
+ //
+ GpioGetGroupToGpeDwX (&GroupToGpeDw0, &GroupToGpeDw1, &GroupToGpeDw2);
+
+ //
+ // GPEM is an object for informing how GPIO groups are mapped to GPE.
+ // Mapping for GPP_x is evaluated from (GPEM >> (GroupNumber*2)) & 0x3
+ // Here GroupNumber does not match xxx_GPIO_GROUP type and is always
+ // 0 based (GPP_A = 0, both for LP and H)
+ // Possible values for each group:
+ // 00b - 2-tier
+ // 01b - 1-tier, GPE_DW0
+ // 10b - 1-tier, GPE_DW1
+ // 11b - 1-tier, GPE_DW2
+ //
+ mPchNvsAreaProtocol.Area->GPEM = (0x1 << (GpioGetGroupIndexFromGroup (GroupToGpeDw0) * 2)) |
+ (0x2 << (GpioGetGroupIndexFromGroup (GroupToGpeDw1) * 2)) |
+ (0x3 << (GpioGetGroupIndexFromGroup (GroupToGpeDw2) * 2));
+
+ //
+ // GP2T[GroupIndex] is an object for storing information about GPIO pads which are
+ // enabled for 2-tier GPE event and their interrupt is configured for level
+ // 0b - Gpio Pad which is not 2-tier event or hasn't got level interrupt
+ // 1b - Gpio Pad enabled for 2-tier event and having level interrupt
+ //
+ for (Group = GpioGetLowestGroup (); Group <= GpioGetHighestGroup (); Group++) {
+ Index = GpioGetGroupIndexFromGroup (Group);
+ if (Index >= sizeof (mPchNvsAreaProtocol.Area->GP2T) / sizeof (mPchNvsAreaProtocol.Area->GP2T[0])) {
+ DEBUG ((DEBUG_ERROR, "GpioGetGroupIndexFromGroup (%x) = %x out of GP2T table range\n", Group, GpioGetGroupIndexFromGroup (Group)));
+ continue;
+ }
+ mPchNvsAreaProtocol.Area->GP2T[Index] = 0x0;
+
+ if ((Group == GroupToGpeDw0) ||
+ (Group == GroupToGpeDw1) ||
+ (Group == GroupToGpeDw2)) {
+ //
+ // not 2-tier GPE
+ //
+ continue;
+ }
+
+ for (PadNumber = 0; PadNumber < GpioGetPadPerGroup (Group); PadNumber++) {
+
+ GpioPad = GpioGetGpioPadFromGroupAndPadNumber (Group, PadNumber);
+
+ GpioGetPadOwnership (GpioPad, &PadOwnVal);
+ if (PadOwnVal != GpioPadOwnHost) {
+ continue;
+ }
+
+ GpioGetPadConfig (GpioPad, &GpioData);
+
+ if (((GpioData.InterruptConfig & B_GPIO_INT_CONFIG_INT_SOURCE_MASK) == GpioIntSci) &&
+ ((GpioData.InterruptConfig & B_GPIO_INT_CONFIG_INT_TYPE_MASK) == GpioIntLevel)) {
+ //
+ // This pad is enabled for GPE and has level interrupt
+ //
+ mPchNvsAreaProtocol.Area->GP2T[Index] |= 1 << PadNumber;
+ }
+ }
+ }
+
+ //
+ // Thermal device in ACPI mode
+ //
+ mPchNvsAreaProtocol.Area->ThermalDeviceAcpiEnabled = mPchConfigHob->Thermal.ThermalDeviceEnable == 2 ? 1 : 0;
+ //
+ // Get Thermal Device interrupt line number
+ //
+ for (Index = 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; Index++) {
+ if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device == PCI_DEVICE_NUMBER_PCH_THERMAL) &&
+ (mPchConfigHob->Interrupt.DevIntConfig[Index].Function == PCI_FUNCTION_NUMBER_PCH_THERMAL)) {
+ mPchNvsAreaProtocol.Area->ThermalDeviceInterruptLine = mPchConfigHob->Interrupt.DevIntConfig[Index].Irq;
+ }
+ }
+
+ //
+ // SCS Configuration
+ //
+ // Update eMMC HS400 mode enablement
+ //
+ mPchNvsAreaProtocol.Area->EMH4 = (UINT8) mPchConfigHob->Scs.ScsEmmcHs400Enabled;
+
+ //
+ // Update eMMC Driver Strength
+ // Per eMMC 5.01 JEDEC Specification (JESD84-B50.1, Table 186)
+ // Nominal Impedance - Driver Type Values:
+ // 50 Ohm 0x0
+ // 33 Ohm 0x1
+ // 40 Ohm 0x4
+ //
+ switch (mPchConfigHob->Scs.ScsEmmcHs400DriverStrength) {
+ case DriverStrength33Ohm:
+ mPchNvsAreaProtocol.Area->EMDS = 0x1;
+ break;
+ case DriverStrength40Ohm:
+ mPchNvsAreaProtocol.Area->EMDS = 0x4;
+ break;
+ case DriverStrength50Ohm:
+ default:
+ mPchNvsAreaProtocol.Area->EMDS = 0x0;
+ }
+
+ //
+ // CPU SKU
+ //
+ mPchNvsAreaProtocol.Area->CpuSku = GetCpuSku ();
+
+ return Status;
+}
+
+/**
+ Initialize PCH Nvs Area opeartion region.
+
+ @retval EFI_SUCCESS initialized successfully
+ @retval EFI_NOT_FOUND Nvs Area operation region is not found
+**/
+EFI_STATUS
+PatchPchNvsAreaAddress (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Address;
+ UINT16 Length;
+
+ Status = InitializeAslUpdateLib ();
+ ASSERT_EFI_ERROR (Status);
+
+ Address = (UINT32) (UINTN) mPchNvsAreaProtocol.Area;
+ Length = (UINT16) sizeof (PCH_NVS_AREA);
+ DEBUG ((DEBUG_INFO, "PatchPchNvsAreaAddress: PCH NVS Address %x Length %x\n", Address, Length));
+ Status = UpdateNameAslCode (SIGNATURE_32 ('P','N','V','B'), &Address, sizeof (Address));
+ ASSERT_EFI_ERROR (Status);
+ Status = UpdateNameAslCode (SIGNATURE_32 ('P','N','V','L'), &Length, sizeof (Length));
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchCio2Acpi.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchCio2Acpi.c
new file mode 100644
index 0000000000..f0abea1323
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchCio2Acpi.c
@@ -0,0 +1,57 @@
+/** @file
+ Initializes PCH CIO2 device ACPI data.
+
+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 <PchInit.h>
+
+/**
+ Update ASL definitions for CIO2 device.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+UpdateCio2AcpiData (
+ VOID
+ )
+{
+ UINT32 Index;
+ PCH_STEPPING PchStep;
+
+ DEBUG ((DEBUG_INFO, "UpdateCio2AcpiData() Start\n"));
+ PchStep = PchStepping ();
+
+ //if CIO2 is enabled as ACPI device then update its ACPI data
+ if (PchStep >= PchLpC0) {
+ mPchNvsAreaProtocol.Area->Cio2EnabledAsAcpiDevice = 0;
+ DEBUG ((DEBUG_INFO, "UpdateCio2AcpiData() Cio2 has not been enabled as ACPI device\n"));
+ } else {
+ mPchNvsAreaProtocol.Area->Cio2EnabledAsAcpiDevice = 0;
+ if (mPchConfigHob->Cio2.DeviceEnable == 1) {
+ mPchNvsAreaProtocol.Area->Cio2EnabledAsAcpiDevice = 1;
+ for (Index = 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; Index++) {
+ if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device == PCI_DEVICE_NUMBER_PCH_CIO2) &&
+ (mPchConfigHob->Interrupt.DevIntConfig[Index].Function == PCI_FUNCTION_NUMBER_PCH_CIO2)) {
+ mPchNvsAreaProtocol.Area->Cio2IrqNumber = mPchConfigHob->Interrupt.DevIntConfig[Index].Irq;
+ DEBUG ((DEBUG_INFO, "UpdateCio2AcpiData() Cio2 has been enabled as ACPI device. Irq number = 0x%x\n", mPchConfigHob->Interrupt.DevIntConfig[Index].Irq));
+ break;
+ }
+ }
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "UpdateCio2AcpiData() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
new file mode 100644
index 0000000000..732dc8905d
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
@@ -0,0 +1,247 @@
+/** @file
+ Initializes the PCH HD Audio ACPI Tables.
+
+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 <PchInit.h>
+#include <Guid/Acpi.h>
+#include <Library/PcdLib.h>
+#include <Library/PchHdaLib.h>
+
+PCH_HDA_NHLT_ENDPOINTS mPchHdaNhltEndpoints[HdaEndpointMax] =
+{
+ {HdaDmicX1, B_HDA_DMIC_1CH_48KHZ_16BIT_FORMAT, FALSE},
+ {HdaDmicX2, (B_HDA_DMIC_2CH_48KHZ_16BIT_FORMAT | B_HDA_DMIC_2CH_48KHZ_32BIT_FORMAT), FALSE},
+ {HdaDmicX4, (B_HDA_DMIC_4CH_48KHZ_16BIT_FORMAT | B_HDA_DMIC_4CH_48KHZ_32BIT_FORMAT), FALSE},
+ {HdaBtRender, (B_HDA_BT_NARROWBAND_FORMAT | B_HDA_BT_WIDEBAND_FORMAT | B_HDA_BT_A2DP_FORMAT), FALSE},
+ {HdaBtCapture, (B_HDA_BT_NARROWBAND_FORMAT | B_HDA_BT_WIDEBAND_FORMAT), FALSE},
+ {HdaI2sRender1, (B_HDA_I2S_RTK298_RENDER_4CH_48KHZ_24BIT_FORMAT), FALSE},
+ {HdaI2sRender2, (B_HDA_I2S_RTK298_RENDER_4CH_48KHZ_24BIT_FORMAT), FALSE},
+ {HdaI2sCapture, (B_HDA_I2S_RTK298_CAPTURE_4CH_48KHZ_24BIT_FORMAT), FALSE}
+};
+
+/**
+ 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->Header.Signature == NHLT_ACPI_TABLE_SIGNATURE) {
+ break;
+ }
+ }
+
+ 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;
+}
+
+/**
+ Constructs and installs NHLT table.
+
+ @retval EFI_SUCCESS ACPI Table installed successfully
+ @retval EFI_UNSUPPORTED ACPI Table protocol not found
+**/
+EFI_STATUS
+PublishNhltAcpiTable (
+ VOID
+ )
+{
+ UINTN AcpiTableKey;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ NHLT_ACPI_TABLE *NhltTable;
+ UINT32 TableLength;
+ EFI_STATUS Status;
+
+ AcpiTable = NULL;
+ NhltTable = NULL;
+ AcpiTableKey = 0;
+
+ DEBUG ((DEBUG_INFO, "PublishNhltAcpiTable() Start\n"));
+
+ //
+ // Locate ACPI support protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+ if ( EFI_ERROR (Status) || AcpiTable == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ NhltConstructor (mPchHdaNhltEndpoints, &NhltTable, &TableLength);
+ NhltAcpiHeaderConstructor (NhltTable, TableLength);
+
+ Status = AcpiTable->InstallAcpiTable (AcpiTable, NhltTable, NhltTable->Header.Length, &AcpiTableKey);
+
+ DEBUG ((DEBUG_INFO, "PublishNhltAcpiTable() End\n"));
+ return Status;
+}
+
+/**
+ Sets NVS ACPI variables for _DSM accordingly to policy.
+
+ @param[in] NhltAcpiTableAddress
+ @param[in] NhltAcpiTableLength
+ @param[in] DspFeatureMask
+**/
+VOID
+UpdateHdaAcpiData (
+ IN UINT64 NhltAcpiTableAddress,
+ IN UINT32 NhltAcpiTableLength,
+ IN UINT32 DspFeatureMask
+ )
+{
+ DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address = 0x%016x, Length = 0x%08x\n", NhltAcpiTableAddress, NhltAcpiTableLength));
+ DEBUG ((DEBUG_INFO, " FeatureMask = 0x%08x\n", DspFeatureMask));
+
+ mPchNvsAreaProtocol.Area->NHLA = NhltAcpiTableAddress;
+ mPchNvsAreaProtocol.Area->NHLL = NhltAcpiTableLength;
+ mPchNvsAreaProtocol.Area->ADFM = DspFeatureMask;
+}
+
+/**
+ Initialize and publish NHLT (Non-HDA Link Table), update NVS variables.
+
+ @param[in] *HdaConfig
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SetHdaAcpiTable (
+ IN CONST HDAUDIO_HOB *HdaConfig
+ )
+{
+ NHLT_ACPI_TABLE *NhltTable;
+ EFI_STATUS Status;
+ NhltTable = NULL;
+
+
+ switch (HdaConfig->DspEndpointDmic) {
+ case PchHdaDmic1chArray:
+ mPchHdaNhltEndpoints[HdaDmicX1].Enable = TRUE;
+ break;
+ case PchHdaDmic2chArray:
+ mPchHdaNhltEndpoints[HdaDmicX2].Enable = TRUE;
+ break;
+ case PchHdaDmic4chArray:
+ mPchHdaNhltEndpoints[HdaDmicX4].Enable = TRUE;
+ break;
+ case PchHdaDmicDisabled:
+ default:
+ mPchHdaNhltEndpoints[HdaDmicX2].Enable = FALSE;
+ mPchHdaNhltEndpoints[HdaDmicX4].Enable = FALSE;
+ }
+
+ if (HdaConfig->DspEndpointBluetooth) {
+ mPchHdaNhltEndpoints[HdaBtRender].Enable = TRUE;
+ mPchHdaNhltEndpoints[HdaBtCapture].Enable = TRUE;
+ }
+
+ if (HdaConfig->DspEndpointI2s) {
+ mPchHdaNhltEndpoints[HdaI2sRender1].Enable = TRUE;
+ mPchHdaNhltEndpoints[HdaI2sRender2].Enable = TRUE;
+ mPchHdaNhltEndpoints[HdaI2sCapture].Enable = TRUE;
+ }
+
+ Status = PublishNhltAcpiTable ();
+ NhltTable = LocateNhltAcpiTable ();
+ if (NhltTable == NULL) {
+ return EFI_LOAD_ERROR;
+ }
+
+ UpdateHdaAcpiData ((UINT64) (UINTN) NhltTable, (UINT32) (NhltTable->Header.Length), HdaConfig->DspFeatureMask);
+
+ DEBUG_CODE ( NhltAcpiTableDump (NhltTable); );
+ return Status;
+}
+
+/**
+ 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;
+ CONST HDAUDIO_HOB *HdaConfig;
+ UINTN HdaPciBase;
+
+ DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n"));
+
+ HdaConfig = &mPchConfigHob->HdAudio;
+
+ HdaPciBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_HDA,
+ PCI_FUNCTION_NUMBER_PCH_HDA
+ );
+
+ if ((MmioRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) || (HdaConfig->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;
+ }
+
+ Status = SetHdaAcpiTable (HdaConfig);
+
+ DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status = %r\n", Status));
+ return Status;
+}
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
new file mode 100644
index 0000000000..0428479b50
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
@@ -0,0 +1,504 @@
+/** @file
+ This is the Common driver that initializes the Intel PCH.
+
+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 "PchInit.h"
+
+//
+// Module variables
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *mPchConfigHob;
+GLOBAL_REMOVE_IF_UNREFERENCED SI_CONFIG_HOB *mSiConfigHob;
+
+/**
+ 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);
+
+ //
+ // Get Silicon Config data HOB
+ //
+ HobPtr.Guid = GetFirstGuidHob (&gSiConfigHobGuid);
+ ASSERT (HobPtr.Guid != NULL);
+ mSiConfigHob = (SI_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);
+
+ DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n"));
+
+ return;
+}
+
+/**
+ Lock USB registers before boot
+
+ @param[in] PchConfigHob The PCH Config HOB
+**/
+VOID
+LockXhciConfiguration (
+ IN CONST PCH_CONFIG_HOB *PchConfigHob
+ )
+{
+ UINTN XhciPciMmBase;
+ UINT32 XhccCfg;
+
+ DEBUG ((DEBUG_INFO, "LockXhciConfiguration () - Start\n"));
+
+ XhciPciMmBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI
+ );
+
+ ///
+ /// PCH BIOS Spec Section 13.2.4 Locking xHCI Register Settings
+ /// PCH BIOS Spec Locking xHCI Register settings
+ /// After xHCI is initialized, BIOS should lock the xHCI configuration registers to RO.
+ /// This prevent any unintended changes. There is also a lockdown feature for OverCurrent
+ /// registers. BIOS should set these bits to lock down the settings prior to end of POST.
+ /// 1. Set Access Control bit at XHCI PCI offset 40h[31] to 1b to lock xHCI register settings.
+ /// 2. Set OC Configuration Done bit at XHCI PCI offset 44h[31] to lock overcurrent mappings from
+ /// further changes.
+ ///
+ MmioOr32 (XhciPciMmBase + R_PCH_XHCI_XHCC2, (UINT32) (BIT31));
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC2),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC2)
+ );
+
+ ///
+ /// PCH BIOS Spec xHCI controller setup
+ /// Note:
+ /// XHCI PCI offset 40h is write once register.
+ /// Unsupported Request Detected bit is write clear
+ ///
+ XhccCfg = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_XHCC1);
+ XhccCfg &= (UINT32) ~(B_PCH_XHCI_XHCC1_URD);
+ XhccCfg |= (UINT32) (B_PCH_XHCI_XHCC1_ACCTRL);
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_XHCC1, XhccCfg);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC1),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_XHCC1)
+ );
+
+ DEBUG ((DEBUG_INFO, "LockXhciConfiguration () - End\n"));
+}
+
+/**
+ Process all the lock downs
+**/
+VOID
+ProcessAllLocks (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT8 Data8;
+ UINT16 Data16And;
+ UINT16 Data16Or;
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 DlockValue;
+ UINTN PciLpcRegBase;
+ UINTN PciSpiRegBase;
+ UINTN PciPmcRegBase;
+ UINT16 TcoBase;
+ UINT32 PchPwrmBase;
+ UINTN PchSpiBar0;
+
+ PciLpcRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ PciPmcRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_PMC,
+ PCI_FUNCTION_NUMBER_PCH_PMC
+ );
+ PciSpiRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SPI,
+ PCI_FUNCTION_NUMBER_PCH_SPI
+ );
+ PchSpiBar0 = MmioRead32 (PciSpiRegBase + R_PCH_SPI_BAR0) &~(B_PCH_SPI_BAR0_MASK);
+
+ PchTcoBaseGet (&TcoBase);
+
+ //
+ // Lock XHCI configuration
+ //
+ LockXhciConfiguration (mPchConfigHob);
+
+ ///
+ /// Set PWRMBASE + 620h [31] to lock the ST and NST PG register fields.
+ ///
+ ConfigurePmcStaticFunctionDisableLock ();
+
+ ///
+ /// SKL PCH BWG 7.2.4 Additional PCH DMI and OP-DMI Programming Steps
+ /// Step 9.2
+ /// Set PCR[DMI] + 2234h [31] = 1b.
+ /// Leave this in DXE since setting it in PEI would break the ActiveBIOS module.
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = B_PCH_PCR_DMI_DMIC_SRL;
+ PchPcrAndThenOr32 (
+ PID_DMI, R_PCH_PCR_DMI_DMIC,
+ Data32And,
+ Data32Or
+ );
+ PCH_PCR_BOOT_SCRIPT_READ_WRITE (
+ S3BootScriptWidthUint32,
+ PID_DMI, R_PCH_PCR_DMI_DMIC,
+ &Data32Or,
+ &Data32And
+ );
+
+
+ ///
+ /// Program the Flash Protection Range Register based on policy
+ ///
+ DlockValue = MmioRead32 (PchSpiBar0 + R_PCH_SPI_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_PCH_SPI_PRX_WPE : 0;
+ Data32 |= (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable == TRUE) ? B_PCH_SPI_PRX_RPE : 0;
+ Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeLimit << N_PCH_SPI_PRX_PRL) & B_PCH_SPI_PRX_PRL_MASK;
+ Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeBase << N_PCH_SPI_PRX_PRB) & B_PCH_SPI_PRX_PRB_MASK;
+ DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, Data32));
+
+ DlockValue |= (UINT32) (B_PCH_SPI_DLOCK_PR0LOCKDN << Index);
+ MmioWrite32 ((UINTN) (PchSpiBar0 + (R_PCH_SPI_PR0 + (Index * S_PCH_SPI_PRX))), Data32);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PchSpiBar0 + (R_PCH_SPI_PR0 + (Index * S_PCH_SPI_PRX))),
+ 1,
+ (VOID *) (UINTN) (PchSpiBar0 + (R_PCH_SPI_PR0 + (Index * S_PCH_SPI_PRX)))
+ );
+ }
+ //
+ // Program DLOCK register
+ //
+ MmioWrite32 ((UINTN) (PchSpiBar0 + R_PCH_SPI_DLOCK), DlockValue);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PchSpiBar0 + R_PCH_SPI_DLOCK),
+ 1,
+ (VOID *) (UINTN) (PchSpiBar0 + R_PCH_SPI_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.
+ ///
+ MmioOr32 ((UINTN) (PchSpiBar0 + R_PCH_SPI_HSFSC), (UINT32) (B_PCH_SPI_HSFSC_FLOCKDN));
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PchSpiBar0 + R_PCH_SPI_HSFSC),
+ 1,
+ (VOID *) (UINTN) (PchSpiBar0 + R_PCH_SPI_HSFSC)
+ );
+
+ ///
+ /// 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_PCH_SPI_SFDP0_VSCC0), B_PCH_SPI_SFDP0_VSCC0_VCL);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PchSpiBar0 + R_PCH_SPI_SFDP0_VSCC0),
+ 1,
+ (VOID *) (UINTN) (PchSpiBar0 + R_PCH_SPI_SFDP0_VSCC0)
+ );
+
+ ///
+ /// Additional Power Management Programming
+ /// Step 3
+ /// Set GEN_PMCON_LOCK register, PMC PCI offset A6h = 06h, after stretch and ACPI base programming completed.
+ ///
+ MmioOr8 (
+ (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_B + 2),
+ (UINT8) ((B_PCH_PMC_GEN_PMCON_B_SLPSX_STR_POL_LOCK | B_PCH_PMC_GEN_PMCON_B_ACPI_BASE_LOCK) >> 16)
+ );
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_B + 2),
+ 1,
+ (VOID *) (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_B + 2)
+ );
+
+ ///
+ /// PCH BIOS Spec Section 3.6 Flash Security Recommendation
+ /// BIOS needs to enable the BIOS Lock Enable (BLE) feature of the PCH by setting
+ /// SPI/eSPI/LPC PCI offset DCh[1] = 1b.
+ /// When this bit is set, attempts to write the BIOS Write Enable (BIOSWE) bit
+ /// in PCH will cause a SMI which will allow the BIOS to verify that the write is
+ /// from a valid source.
+ /// Remember that BIOS needs to set SPI/LPC/eSPI PCI Offset DC [0] = 0b to enable
+ /// BIOS region protection before exiting the SMI handler.
+ /// Also, TCO_EN bit needs to be set (SMI_EN Register, ABASE + 30h[13] = 1b) to keep
+ /// BLE feature enabled after booting to the OS.
+ /// Intel requires that BIOS enables the Lock Enable (LE) feature of the PCH to
+ /// ensure SMM protection of flash.
+ /// Left to platform code to register a callback function to handle BiosWp SMI
+ ///
+ if (mPchConfigHob->LockDown.BiosLock == TRUE) {
+ //
+ // eSPI/LPC
+ //
+ if (! (MmioRead8 (PciLpcRegBase + R_PCH_LPC_BC) & B_PCH_LPC_BC_LE)) {
+ DEBUG ((DEBUG_INFO, "Set LPC bios lock\n"));
+ MmioOr8 ((UINTN) (PciLpcRegBase + R_PCH_LPC_BC), B_PCH_LPC_BC_LE);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciLpcRegBase + R_PCH_LPC_BC),
+ 1,
+ (VOID *) (UINTN) (PciLpcRegBase + R_PCH_LPC_BC)
+ );
+ }
+ //
+ // SPI
+ //
+ if (! (MmioRead8 (PciSpiRegBase + R_PCH_SPI_BC) & B_PCH_SPI_BC_LE)) {
+ DEBUG ((DEBUG_INFO, "Set SPI bios lock\n"));
+ MmioOr8 ((UINTN) (PciSpiRegBase + R_PCH_SPI_BC), (UINT8) B_PCH_SPI_BC_LE);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciSpiRegBase + R_PCH_SPI_BC),
+ 1,
+ (VOID *) (UINTN) (PciSpiRegBase + R_PCH_SPI_BC)
+ );
+ }
+ }
+
+ ///
+ /// PCH BIOS Spec Section 3.6 Flash Security Recommendation
+ /// BIOS also needs to set the BIOS Interface Lock Down bit in multiple locations
+ /// (PCR[DMI] + 274Ch[0], LPC/eSPI PCI offset DCh[7] and SPI PCI offset DCh[7]).
+ /// Setting these bits will prevent writes to the Top Swap bit (under their respective locations)
+ /// and the Boot BIOS Straps. Enabling this bit will mitigate malicious software
+ /// attempts to replace the system BIOS option ROM with its own code.
+ ///
+ if (mPchConfigHob->LockDown.BiosInterface == TRUE) {
+ ///
+ /// LPC
+ ///
+ MmioOr8 ((UINTN) (PciLpcRegBase + R_PCH_LPC_BC), (UINT32) B_PCH_LPC_BC_BILD);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciLpcRegBase + R_PCH_LPC_BC),
+ 1,
+ (VOID *) (UINTN) (PciLpcRegBase + R_PCH_LPC_BC)
+ );
+
+ ///
+ /// Reads back for posted write to take effect
+ ///
+ Data8 = MmioRead8 ((UINTN) (PciLpcRegBase + R_PCH_LPC_BC));
+ S3BootScriptSaveMemPoll (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciLpcRegBase + R_PCH_LPC_BC),
+ &Data8, // BitMask
+ &Data8, // BitValue
+ 1, // Duration
+ 1 // LoopTimes
+ );
+
+ ///
+ /// SPI
+ ///
+ MmioOr8 ((UINTN) (PciSpiRegBase + R_PCH_SPI_BC), (UINT32) B_PCH_SPI_BC_BILD);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciSpiRegBase + R_PCH_SPI_BC),
+ 1,
+ (VOID *) (UINTN) (PciSpiRegBase + R_PCH_SPI_BC)
+ );
+
+ ///
+ /// Reads back for posted write to take effect
+ ///
+ Data8 = MmioRead8 ((UINTN) (PciSpiRegBase + R_PCH_SPI_BC));
+ S3BootScriptSaveMemPoll (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciSpiRegBase + R_PCH_SPI_BC),
+ &Data8, // BitMask
+ &Data8, // BitValue
+ 1, // Duration
+ 1 // LoopTimes
+ );
+
+ ///
+ /// Set PCR[DMI] + 274C[0] = 1b
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = B_PCH_PCR_DMI_BILD;
+ PchPcrAndThenOr32 (PID_DMI, R_PCH_PCR_DMI_GCS, Data32And, Data32Or);
+ PCH_PCR_BOOT_SCRIPT_READ_WRITE (
+ S3BootScriptWidthUint32,
+ PID_DMI, R_PCH_PCR_DMI_GCS,
+ &Data32Or,
+ &Data32And
+ );
+ }
+
+ ///
+ /// PCH BIOS Spec Section 5.13 BIOS guide on using RTC RAM
+ /// For Data integrity protection, set RTC Memory locks (Upper 128 Byte Lock and
+ /// Lower 128 Byte Lock) at SBCR[RTC] + 3400h[4] and SBCR[RTC] + 3400h[3]. Note once locked
+ /// bytes 0x38 - 0x3F in each of the Upper and Lower Byte blocks, respectively,
+ /// cannot be unlocked until next reset.
+ ///
+ if (mPchConfigHob->LockDown.RtcLock == TRUE) {
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (B_PCH_PCR_RTC_CONF_UCMOS_LOCK | B_PCH_PCR_RTC_CONF_LCMOS_LOCK | B_PCH_PCR_RTC_CONF_RESERVED);
+ PchPcrAndThenOr32 (
+ PID_RTC, R_PCH_PCR_RTC_CONF,
+ Data32And,
+ Data32Or
+ );
+ PCH_PCR_BOOT_SCRIPT_READ_WRITE (
+ S3BootScriptWidthUint32,
+ PID_RTC, R_PCH_PCR_RTC_CONF,
+ &Data32Or,
+ &Data32And
+ );
+ }
+
+ ///
+ /// Lock Down TCO
+ ///
+ Data16And = 0xFFFF;
+ Data16Or = B_PCH_TCO_CNT_LOCK;
+ IoOr16 (TcoBase + R_PCH_TCO1_CNT, Data16Or);
+ S3BootScriptSaveIoReadWrite (
+ S3BootScriptWidthUint16,
+ (UINTN) (TcoBase + R_PCH_TCO1_CNT),
+ &Data16Or, // Data to be ORed
+ &Data16And // Data to be ANDed
+ );
+
+ ///
+ /// PCH BIOS Spec Section 5.15.1 Additional Chipset Initialization
+ /// Step 1
+ /// Set SPIBAR0 + F0h [0] to 1b
+ ///
+ MmioOr8 ((UINTN) (PchSpiBar0 + R_PCH_SPI_SSML), B_PCH_SPI_SSML_SSL);
+
+ //
+ // Lock Down PMC
+ // Set PWRM + 0x18 [27, 22] prior to OS.
+ //
+ PchPwrmBaseGet (&PchPwrmBase);
+ Data32Or = BIT27;
+ if (mPchConfigHob->Pm.PmcReadDisable) {
+ Data32Or |= BIT22;
+ }
+ MmioOr32 (PchPwrmBase + R_PCH_PWRM_CFG, Data32Or);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PchPwrmBase + R_PCH_PWRM_CFG),
+ 1,
+ (VOID *) (UINTN) (PchPwrmBase + R_PCH_PWRM_CFG)
+ );
+}
+
+/**
+ Set eSPI BME bit
+**/
+VOID
+ConfigureEspiBme (
+ VOID
+ )
+{
+}
+
+/**
+ Common PCH initialization before Boot Sript Table is closed
+
+**/
+VOID
+PchOnPciEnumCompleteCommon (
+ VOID
+ )
+{
+ UINT32 Data32Or;
+ UINT32 Data32And;
+
+ DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() Start\n"));
+
+ ProcessAllLocks ();
+
+ ///
+ /// Perform remaining configuration for PCH SATA on End of DXE
+ ///
+ ConfigurePchSataOnEndOfDxe ();
+
+ ///
+ /// PSTHCTL (0xD00h[2]) = 1, PSTH IOSF Primary Trunk Clock Gating Enable (PSTHIOSFPTCGE)
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = B_PCH_PCR_PSTH_PSTHIOSFPTCGE;
+ PchPcrAndThenOr32 (PID_PSTH, R_PCH_PCR_PSTH_PSTHCTL, Data32And, Data32Or);
+ PCH_PCR_BOOT_SCRIPT_READ_WRITE (
+ S3BootScriptWidthUint32,
+ PID_PSTH, R_PCH_PCR_PSTH_PSTHCTL,
+ &Data32Or,
+ &Data32And
+ );
+
+ //
+ // Set eSPI BME after PCI enumeration
+ //
+ ConfigureEspiBme ();
+
+ //
+ // This function process P2SB configuration
+ // This MUST be executed in very end of End Of Dxe
+ // All PSF access after this function will not acceptable
+ //
+ ConfigureP2sbSbiLock ((BOOLEAN) mPchConfigHob->P2sb.SbiUnlock);
+
+ DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() End\n"));
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
new file mode 100644
index 0000000000..a05697d337
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
@@ -0,0 +1,320 @@
+/** @file
+ Header file for PCH Initialization 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.
+
+**/
+#ifndef _PCH_INITIALIZATION_DRIVER_H_
+#define _PCH_INITIALIZATION_DRIVER_H_
+
+typedef UINT16 STRING_REF;
+#ifdef FSP_FLAG
+#include <Library/PeiServicesLib.h>
+#include <Uefi/UefiSpec.h>
+#endif
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/ConfigBlockLib.h>
+#include <Protocol/DriverSupportedEfiVersion.h>
+#include <Library/PchCycleDecodingLib.h>
+#include <Library/PchPcieRpLib.h>
+#include <Library/PchP2sbLib.h>
+#include <Library/PchPcrLib.h>
+#include <Library/PchEspiLib.h>
+#include <Library/PchInfoLib.h>
+#include <Library/TraceHubInitLib.h>
+#include <Guid/EventGroup.h>
+#include <Library/S3BootScriptLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciPlatform.h>
+#include <Protocol/PciEnumerationComplete.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#ifndef FSP_FLAG
+#include <Library/DxeServicesTableLib.h>
+#endif
+
+#include <PchAccess.h>
+#include <SiConfigHob.h>
+#include <Protocol/PchInfo.h>
+#include <IndustryStandard/Pci30.h>
+#include <Library/AslUpdateLib.h>
+#include <Library/MmPciLib.h>
+#include <Library/CpuPlatformLib.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/PchEmmcTuning.h>
+#include <Library/GpioLib.h>
+#include <Library/GpioNativeLib.h>
+#include <Protocol/PchNvs.h>
+#include <Protocol/PcieIoTrap.h>
+#include <Library/PchInitCommonLib.h>
+#include <Library/PchPciExpressHelpersLib.h>
+#include <Library/PchPsfLib.h>
+#include <Library/PchPsfPrivateLib.h>
+#include <PchConfigHob.h>
+
+typedef struct {
+ PCH_INFO_PROTOCOL PchInfo;
+} PCH_INSTANCE_PRIVATE_DATA;
+
+//
+// This struct is used to record the fields that is required to be saved and restored during RST PCIe Storage Remapping Configuration
+//
+typedef struct {
+ UINT8 PmCapPtr;
+ UINT8 PcieCapPtr;
+ UINT16 L1ssCapPtr;
+ UINT8 EndpointL1ssControl2;
+ UINT32 EndpointL1ssControl1;
+ UINT16 LtrCapPtr;
+ UINT32 EndpointLtrData;
+ UINT16 EndpointLctlData16;
+ UINT16 EndpointDctlData16;
+ UINT16 EndpointDctl2Data16;
+ UINT16 RootPortDctl2Data16;
+} PCH_RST_PCIE_STORAGE_SAVE_RESTORE;
+
+//
+// This struct is used to record the result of RST PCIe Storage detection for each RST PCIe Storage Cycle Router supported on the platform
+//
+typedef struct {
+ BOOLEAN SupportRstPcieStoragRemapping; // Indicates if RST PCIe Storage Remapping is supported and PCIe storage device is found under a Cycle Router
+ UINT8 RootPortNum; // Indicates the root port number with RST PCIe Storage Remapping remapping supported and PCIe storage device plugged on, numbering is 0-based
+ UINT8 RootPortLane; // Indicates the root port lanes occupied by the PCIe storage device with 4-bit mask
+ UINT8 DeviceInterface; // Indicates the interface of the PCIe storage device (AHCI or NVMe)
+ UINT8 IsMsixSupported; // Indicates if the PCIe storage device support MSI-X cap
+ UINT16 MsixStartingVector; // Records the starting vector of PCIe storage device's MSI-X (if supported)
+ UINT16 MsixEndingVector; // Records the ending vector of PCIe storage device's MSI-X (if supported)
+ UINT32 EndPointBarSize; // Records the PCIe storage device's BAR size
+ UINT32 EndPointUniqueMsixTableBar; // Records the PCIe storage device's MSI-X Table BAR if it supports unique MSI-X Table BAR
+ UINT32 EndPointUniqueMsixTableBarValue; // Records the PCIe storage device's MSI-X Table BAR value if it supports unique MSI-X Table BAR
+ UINT32 EndPointUniqueMsixPbaBar; // Records the PCIe storage device's MSI-X PBA BAR if it supports unique MSI-X PBA BAR
+ UINT32 EndPointUniqueMsixPbaBarValue; // Records the PCIe storage device's MSI-X PBA BAR value if it supports unique MSI-X PBA BAR
+ UINT8 EndPointBcc; // Records the PCIe storage device's Base Class Code
+ UINT8 EndPointScc; // Records the PCIe storage device's Sub Class Code
+ UINT8 EndPointPi; // Records the PCIe storage device's Programming Interface
+ PCH_RST_PCIE_STORAGE_SAVE_RESTORE PchRstPcieStorageSaveRestore; // Records the fields that is required to be saved and restored
+} PCH_RST_PCIE_STORAGE_DETECTION;
+
+//
+// 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 *mSiConfigHob;
+
+//
+// Function Prototype
+//
+
+//
+// Local function prototypes
+//
+/**
+ Initialize the PCH device according to the PCH Policy HOB
+ and install PCH info instance.
+
+**/
+VOID
+InitializePchDevice (
+ VOID
+ );
+
+/**
+ Common PchInit Module Entry Point
+**/
+VOID
+PchInitEntryPointCommon (
+ VOID
+ );
+
+/**
+ Common PCH initialization on PCI enumeration complete.
+**/
+VOID
+PchOnPciEnumCompleteCommon (
+ VOID
+ );
+
+/**
+ Configures Serial IO Controllers
+
+**/
+EFI_STATUS
+ConfigureSerialIoAtBoot (
+ VOID
+ );
+
+/**
+ Creates device handles for SerialIo devices in ACPI mode
+
+**/
+VOID
+CreateSerialIoHandles (
+ VOID
+ );
+
+/**
+ Mark memory used by SerialIo devices in ACPI mode as allocated
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+AllocateSerialIoMemory (
+ VOID
+ );
+
+/**
+ Update ASL definitions for SerialIo devices.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+UpdateSerialIoAcpiData (
+ VOID
+ );
+
+/**
+ Initialize PCIE SRC clocks in ICC subsystem
+
+ @param[in] GbePortNumber Number of PCIE rootport assigned to GbE adapter
+
+**/
+VOID
+ConfigurePchPcieClocks (
+ IN UINTN GbePortNumber
+ );
+
+/**
+ 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
+ );
+
+/**
+ Configure eMMC in HS400 Mode
+
+ @param[in] This A pointer to PCH_EMMC_TUNING_PROTOCOL structure
+ @param[in] Revision Revision parameter used to verify the layout of EMMC_INFO and TUNINGDATA.
+ @param[in] EmmcInfo A pointer to EMMC_INFO structure
+ @param[out] EmmcTuningData A pointer to EMMC_TUNING_DATA structure
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_NOT_FOUND The item was not found
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+ @retval EFI_CRC_ERROR Command or Data CRC Error
+**/
+EFI_STATUS
+EFIAPI
+ConfigureEmmcHs400Mode (
+ IN PCH_EMMC_TUNING_PROTOCOL *This,
+ IN UINT8 Revision,
+ IN EMMC_INFO *EmmcInfo,
+ OUT EMMC_TUNING_DATA *EmmcTuningData
+ );
+
+/**
+ Install PCH EMMC TUNING PROTOCOL
+
+**/
+VOID
+InstallPchEmmcTuningProtocol (
+ VOID
+ );
+
+/**
+ Perform the remaining configuration on PCH SATA to perform device detection,
+ then set the SATA SPD and PxE corresponding, and set the Register Lock on PCH SATA
+
+ @retval None
+**/
+VOID
+ConfigurePchSataOnEndOfDxe (
+ VOID
+ );
+
+/**
+ Update ASL data for CIO2 Device.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+UpdateCio2AcpiData (
+ 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
+ );
+
+/**
+ Initialize PCH Nvs Area opeartion region.
+
+ @retval EFI_SUCCESS initialized successfully
+ @retval EFI_NOT_FOUND Nvs Area operation region is not found
+**/
+EFI_STATUS
+PatchPchNvsAreaAddress (
+ VOID
+ );
+
+/**
+ PCH Update NvsArea ExitBootServicesFlag on ExitBootService. This event is used if only ExitBootService is used
+ and not in legacy boot
+
+ @retval None
+**/
+VOID
+EFIAPI
+PchUpdateNvsOnExitBootServices (
+ VOID
+ );
+#endif // _PCH_INITIALIZATION_DRIVER_H_
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
new file mode 100644
index 0000000000..1857b7f3c5
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
@@ -0,0 +1,699 @@
+/** @file
+ This is the Uefi driver that initializes the Intel PCH.
+
+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 "PchInit.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
+ );
+
+
+/**
+ BIOS W/A for Si bug on PCH stepping LpA0, LpA1, LpA2, LpB0:
+ allocates 1MB memory space for ISH BAR,
+ overrides 4KB memory allocation done by standard PCI enumarator.
+
+ @retval EFI_STATUS
+ @retval EFI_SUCCESS Allocation successful or stepping other that A0/A1/A2 (W/A not required)
+ @retval EFI_OUT_OF_RESOURCES Memory could not be allocated.
+**/
+EFI_STATUS
+AllocateIshMemorySpace (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN PciIshRegBase;
+ EFI_PHYSICAL_ADDRESS IshMemBaseAddress;
+
+ PciIshRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_ISH,
+ PCI_FUNCTION_NUMBER_PCH_ISH
+ );
+
+ if ((MmioRead16 (PciIshRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) ||
+ (GetPchSeries () == PchH) ||
+ (PchStepping () > PchLpB1)) {
+ return EFI_SUCCESS;
+ }
+
+ if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
+ IshMemBaseAddress = 0xffffffff;
+ }
+ Status = gDS->AllocateMemorySpace (
+ PcdGet8 (PcdEfiGcdAllocateType),
+ EfiGcdMemoryTypeMemoryMappedIo,
+ N_PCH_ISH_BAR0_ALIGNMENT,
+ V_PCH_ISH_BAR0_SIZE,
+ &IshMemBaseAddress,
+ mImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MmioAnd16 (PciIshRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+ MmioWrite32 (PciIshRegBase + R_PCH_ISH_BAR0_LOW, (UINT32) IshMemBaseAddress);
+ MmioWrite32 (PciIshRegBase + R_PCH_ISH_BAR0_HIGH, 0);
+ MmioOr16 (PciIshRegBase + PCI_COMMAND_OFFSET, (UINT16) EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ DEBUG ((DEBUG_INFO, "ISH W/A: Allocated 1MB MMIO, BAR0 = 0x%08x\n", (UINT32) IshMemBaseAddress));
+ return Status;
+}
+
+
+/**
+ Process all the lock downs
+**/
+VOID
+ProcessSmiLocks (
+ VOID
+ )
+{
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT16 ABase;
+ UINTN PciPmcRegBase;
+
+ PciPmcRegBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_PMC,
+ PCI_FUNCTION_NUMBER_PCH_PMC
+ );
+
+ ///
+ /// 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) {
+ PchAcpiBaseGet (&ABase);
+ ///
+ /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK during S3 resume
+ ///
+ Data32Or = IoRead32 ((UINTN) (ABase + R_PCH_SMI_EN));
+ if ((Data32Or & B_PCH_SMI_EN_GBL_SMI) != 0) {
+ Data32And = 0xFFFFFFFF;
+ Data32Or |= B_PCH_SMI_EN_GBL_SMI;
+ S3BootScriptSaveIoReadWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (ABase + R_PCH_SMI_EN),
+ &Data32Or, // Data to be ORed
+ &Data32And // Data to be ANDed
+ );
+ }
+ MmioOr8 ((UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_A), B_PCH_PMC_GEN_PMCON_A_SMI_LOCK);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint8,
+ (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_A),
+ 1,
+ (VOID *) (UINTN) (PciPmcRegBase + R_PCH_PMC_GEN_PMCON_A)
+ );
+ }
+}
+
+/**
+ 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);
+ ASSERT_EFI_ERROR (Status);
+ 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 = PciePmTrap;
+ 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;
+ UINTN ThermalPciBase;
+ UINT32 PchPwrmBase;
+
+ ///
+ /// 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);
+
+
+ PchPwrmBaseGet (&PchPwrmBase);
+
+ //
+ // Allocate BAR for ISH - workaround for Si bug on stepping LpA0/A1/A2
+ //
+ AllocateIshMemorySpace ();
+
+ //
+ // Enable Thermal MSE
+ //
+ ThermalPciBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_THERMAL,
+ PCI_FUNCTION_NUMBER_PCH_THERMAL
+ );
+ if (MmioRead16 (ThermalPciBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF) {
+ if (((MmioRead32 (ThermalPciBase + R_PCH_THERMAL_TBAR) & B_PCH_THERMAL_TBAR_MASK) != 0) ||
+ ((MmioRead32 (ThermalPciBase + R_PCH_THERMAL_TBARH) != 0))) {
+ MmioOr8 (ThermalPciBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+ }
+ }
+
+ ReconfigurePciePowerManagementForS3 ();
+ ProcessSmiLocks ();
+#ifndef FSP_WRAPPER_FLAG
+ PchOnPciEnumCompleteCommon ();
+#endif
+}
+
+/**
+ 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);
+}
+
+/**
+ Updates PCIe configuration in PCH Info Protocol.
+
+ @param[in,out] PchInfo Pointer to PCH info protocol instance to be updated
+**/
+VOID
+UpdatePcieConfigInfo (
+ IN OUT PCH_INFO_PROTOCOL *PchInfo
+ )
+{
+ EFI_STATUS Status;
+ PCH_SERIES PchSeries;
+ UINT32 StrapFuseCfg1;
+ UINT32 StrapFuseCfg5;
+ UINT32 StrapFuseCfg9;
+ UINT32 StrapFuseCfg13;
+ UINT32 StrapFuseCfg17;
+ UINT32 StrapFuseCfg21;
+
+ PchSeries = GetPchSeries ();
+
+ Status = PchSbiRpPciRead32 (
+ 0,
+ R_PCH_PCIE_STRPFUSECFG,
+ &StrapFuseCfg1
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PchSbiRpPciRead32 (
+ 4,
+ R_PCH_PCIE_STRPFUSECFG,
+ &StrapFuseCfg5
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PchSbiRpPciRead32 (
+ 8,
+ R_PCH_PCIE_STRPFUSECFG,
+ &StrapFuseCfg9
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PchInfo->PcieControllerCfg1 = (UINT8) ((StrapFuseCfg1 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC);
+ PchInfo->PcieControllerCfg2 = (UINT8) ((StrapFuseCfg5 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC);
+ PchInfo->PcieControllerCfg3 = (UINT8) ((StrapFuseCfg9 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC);
+
+ if (PchSeries == PchH) {
+ Status = PchSbiRpPciRead32 (
+ 12,
+ R_PCH_PCIE_STRPFUSECFG,
+ &StrapFuseCfg13
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PchSbiRpPciRead32 (
+ 16,
+ R_PCH_PCIE_STRPFUSECFG,
+ &StrapFuseCfg17
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PchInfo->PcieControllerCfg4 = (UINT8) ((StrapFuseCfg13 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC);
+ PchInfo->PcieControllerCfg5 = (UINT8) ((StrapFuseCfg17 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC);
+
+ if (GetPchGeneration () == KblPch) {
+ Status = PchSbiRpPciRead32 (
+ 20,
+ R_PCH_PCIE_STRPFUSECFG,
+ &StrapFuseCfg21
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PchInfo->PcieControllerCfg6 = (UINT8) ((StrapFuseCfg21 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC);
+ }
+
+ }
+}
+
+/**
+ Stores PCIE Gen3 software equalization settings in bootscript to accelerate S3 resume
+**/
+VOID
+SavePcieGen3Eq (
+ VOID
+ )
+{
+ UINT8 RpIndex;
+ UINTN RpBase;
+ UINT8 EqMethod;
+ UINT32 Data32;
+ UINT32 Data32Or;
+ UINT32 Data32And;
+
+ for (RpIndex = 0; RpIndex < GetPchMaxPciePortNum (); ++RpIndex) {
+ RpBase = PchPcieBase (RpIndex);
+ //
+ // Before trying to save it, make sure software gen3 equalization did actually happen
+ //
+ if (MmioRead32 (RpBase) == 0xFFFFFFFF) {
+ continue;
+ }
+ if (GetMaxLinkSpeed (RpBase) < 3) {
+ continue;
+ }
+ EqMethod = mPchConfigHob->PcieRp.RootPort[RpIndex].Gen3EqPh3Method;
+ if (EqMethod != PchPcieEqDefault && EqMethod != PchPcieEqSoftware) {
+ continue;
+ }
+ //
+ // Can't check current link speed due to some nonconformant devices
+ // Instead we verify B_PCH_PCIE_EQCFG1_RTLEPCEB bit which together with policy check above
+ // guarantees that software gen3 eq was performed
+ //
+ if (!(MmioRead32 (RpBase + R_PCH_PCIE_EQCFG1) & B_PCH_PCIE_EQCFG1_RTLEPCEB)) {
+ continue;
+ }
+
+ //
+ // Restore PCIE Gen3 equalization coefficients
+ //
+ Data32 = MmioRead32 (RpBase + R_PCH_PCIE_RTPCL1);
+ S3BootScriptSaveMemWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_RTPCL1, 1, &Data32);
+ Data32 = MmioRead32 (RpBase + R_PCH_PCIE_RTPCL2);
+ S3BootScriptSaveMemWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_RTPCL2, 1, &Data32);
+ Data32And = 0xFFFFFFFF;
+ Data32Or = B_PCH_PCIE_EQCFG1_RTLEPCEB | B_PCH_PCIE_EQCFG1_RTPCOE;
+ S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_EQCFG1, &Data32Or, &Data32And);
+
+ //
+ // Perform link retrain.
+ //
+ Data32And = (UINT32) (~B_PCIE_LCTL2_TLS);
+ Data32Or = V_PCIE_LCTL2_TLS_GEN3;
+ S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_LCTL2, &Data32Or, &Data32And);
+ Data32And = 0xFFFFFFFF;
+ Data32Or = B_PCIE_EX_LCTL3_PE;
+ S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_EX_LCTL3, &Data32Or, &Data32And);
+ Data32Or = B_PCIE_LCTL_RL;
+ S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_LCTL, &Data32Or, &Data32And);
+ /// PCH BIOS Spec Section 8.15 Additional PCI Express* Programming Steps
+ /// Set "Link Speed Training Policy", Dxx:Fn + D4h[6] to 1.
+ /// Make sure this is after mod-PHY related programming is completed.
+ Data32Or = B_PCH_PCIE_MPC2_LSTP;
+ DEBUG ((DEBUG_WARN, "Gen3Eq S3MmioOr32 0x%08x\n", RpBase + R_PCH_PCIE_MPC2));
+ S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, RpBase + R_PCH_PCIE_MPC2, &Data32Or, &Data32And);
+ }
+}
+
+/**
+ Initialize the PCH device according to the PCH Policy HOB
+ and install PCH info instance.
+**/
+VOID
+InitializePchDevice (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ PCH_INFO_PROTOCOL *PchInfo;
+ EFI_STATUS Status;
+ UINT32 PchPwrmBase;
+
+ Handle = NULL;
+
+ DEBUG ((DEBUG_INFO, "InitializePchDevice() Start\n"));
+
+ PchPwrmBaseGet (&PchPwrmBase);
+
+ //
+ // Create the PCH Info protocol instance
+ //
+ PchInfo = AllocateZeroPool (sizeof (PCH_INFO_PROTOCOL));
+ if (PchInfo == NULL) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ PchInfo->Revision = PCH_INFO_PROTOCOL_REVISION;
+
+ UpdatePcieConfigInfo (PchInfo);
+
+ //
+ // Store PCIE Gen3 software equalization settings in bootscripts to save time on S3 resume
+ // This must happen before some rootports get hidden by RST remapping
+ //
+ SavePcieGen3Eq ();
+
+
+ //
+ // Configure root port function number mapping
+ // For UEFI bios, execute RPFN mapping after RST configuraion and before PCI enumeration.
+ //
+ Status = PchConfigureRpfnMapping ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Pch Emmc Tuning Protocol
+ //
+ if ((mPchConfigHob->Scs.ScsEmmcEnabled == TRUE) && (mPchConfigHob->Scs.ScsEmmcHs400Enabled == TRUE)) {
+ InstallPchEmmcTuningProtocol ();
+ }
+
+ //
+ // Install PCH info protocol on new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gPchInfoProtocolGuid,
+ PchInfo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "InitializePchDevice() End\n"));
+}
+/**
+ <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 ();
+
+ InitializePchDevice ();
+
+ Status = PchAcpiInit (ImageHandle);
+
+ CreateSerialIoHandles ();
+
+ PchRegisterNotifications ();
+
+ 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);
+
+ PchUpdateNvsOnExitBootServices ();
+
+ 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
+ )
+{
+#ifndef FSP_WRAPPER_FLAG
+ UINTN XhciMmioBase;
+ UINTN XhciPciMmBase;
+ UINT8 XhciPciCommand;
+ BOOLEAN XhciPdoRestartNeeded;
+#endif // FSP_WRAPPER_FLAG
+
+ DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() Start\n"));
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+#ifndef FSP_WRAPPER_FLAG
+ if (mPchConfigHob->Usb.DelayPdoProgramming == TRUE) {
+ XhciPciMmBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI
+ );
+
+ // Check if xHCI has memory access
+ XhciPciCommand = MmioRead8 (XhciPciMmBase + PCI_COMMAND_OFFSET);
+
+ if ((XhciPciCommand & EFI_PCI_COMMAND_MEMORY_SPACE) == 0x0) {
+ DEBUG ((DEBUG_ERROR, "xHCI Controller isn't configured properly for PDO setting\n"));
+ } else {
+ // Getting base MMIO address for xHCI
+ XhciMmioBase = (
+ MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE) |
+ ((UINTN) MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE_2) << N_PCH_XHCI_MEM_SHIFT)
+ ) & ((UINTN)~(B_PCH_XHCI_MEM_ALIGN_MASK));
+
+ XhciPdoRestartNeeded = UsbPdoProgramming (
+ XhciMmioBase,
+ mPchConfigHob->Usb.Usb2DisabledPorts,
+ mPchConfigHob->Usb.Usb3DisabledPorts
+ );
+ // If PDO registers are locked, reset platform to unlock them
+ if (XhciPdoRestartNeeded) {
+ gST->RuntimeServices->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "PDO register already programmed\n"));
+ }
+#endif // FSP_WRAPPER_FLAG
+
+ //
+ // Trigger an Iotrap SMI to config PCIE power management setting after PCI enumrate is done
+ //
+ if (mPcieIoTrapAddress != 0) {
+ IoWrite32 ((UINTN) mPcieIoTrapAddress, PciePmTrap);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() End\n"));
+}
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.inf b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.inf
new file mode 100644
index 0000000000..0242dcbe9a
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.inf
@@ -0,0 +1,101 @@
+## @file
+# Component description file for Pch Initialization 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 = PchInitDxe
+FILE_GUID = DE23ACEE-CF55-4fb6-AA77-984AB53DE823
+VERSION_STRING = 1.0
+MODULE_TYPE = DXE_DRIVER
+ENTRY_POINT = PchInitEntryPointDxe
+
+
+[LibraryClasses]
+S3BootScriptLib
+PchCycleDecodingLib
+PchPcieRpLib
+PchP2sbLib
+PchPcrLib
+PchInfoLib
+PchPciExpressHelpersLib
+UefiBootServicesTableLib
+DebugLib
+IoLib
+TimerLib
+HobLib
+BaseMemoryLib
+MemoryAllocationLib
+UefiLib
+DxeServicesTableLib
+UefiDriverEntryPoint
+UefiRuntimeServicesTableLib
+AslUpdateLib
+CpuPlatformLib
+GpioLib
+PchSerialIoLib
+PchHdaLib
+PchInitCommonLib
+ConfigBlockLib
+PchPsfLib
+PchPsfPrivateLib
+RstPrivateLib
+
+[Packages]
+MdePkg/MdePkg.dec
+KabylakeSiliconPkg/SiPkg.dec
+KabylakeSiliconPkg/KabylakeSiliconPrivate.dec
+
+
+[Pcd]
+gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType
+
+
+[Sources]
+PchInitDxe.c
+PchInit.h
+PchInit.c
+PchSata.c
+PchRstPcieStorage.c
+PchSerialIo.c
+PchSerialIoDxe.c
+PchHdaAcpi.c
+PchScs.c
+PchCio2Acpi.c
+PchAcpi.c
+
+
+[Protocols]
+gPchInfoProtocolGuid ## PRODUCES
+gPchNvsAreaProtocolGuid ## PRODUCES
+gPchEmmcTuningProtocolGuid ## PRODUCES
+gEfiPciIoProtocolGuid ## CONSUMES
+gEfiAcpiTableProtocolGuid ## CONSUMES
+gEfiBlockIoProtocolGuid ## CONSUMES
+gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES
+gPchPcieIoTrapProtocolGuid ## CONSUMES
+
+
+[Guids]
+gEfiEndOfDxeEventGroupGuid
+gEfiAcpiTableGuid
+gSiConfigHobGuid ## CONSUMES
+gPchConfigHobGuid ## CONSUMES
+gPchPcieStorageDetectHobGuid ## 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/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFsp.inf b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFsp.inf
new file mode 100644
index 0000000000..18feffd894
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFsp.inf
@@ -0,0 +1,80 @@
+## @file
+# Component description file for Pch Initialization driver for FSP package
+#
+# 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 = 0x00010005
+BASE_NAME = PchInitDxe
+FILE_GUID = 5AA5031E-4CB6-43D4-B219-FE50FF5D116C
+MODULE_TYPE = PEIM
+VERSION_STRING = 1.0
+ENTRY_POINT = PchInitEntryPointFsp
+
+
+[LibraryClasses]
+PeimEntryPoint
+PchCycleDecodingLib
+PchPcieRpLib
+PchP2sbLib
+PchPcrLib
+PchInfoLib
+PchEspiLib
+PchPciExpressHelpersLib
+DebugLib
+IoLib
+TimerLib
+HobLib
+BaseMemoryLib
+MemoryAllocationLib
+CpuPlatformLib
+GpioLib
+PchSerialIoLib
+PchInitCommonLib
+S3BootScriptLib # NULL library
+ConfigBlockLib
+PchPsfLib
+PchPsfPrivateLib
+
+[Packages]
+MdePkg/MdePkg.dec
+KabylakeSiliconPkg/SiPkg.dec
+KabylakeSiliconPkg/KabylakeSiliconPrivate.dec
+
+
+[Pcd]
+gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType
+
+
+[Sources]
+PchInitFsp.c
+PchInit.h
+PchInit.c
+PchSata.c
+PchSerialIo.c
+
+
+[Protocols]
+gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES
+
+
+[Guids]
+gEfiEventReadyToBootGuid
+gSiConfigHobGuid ## CONSUMES
+gPchConfigHobGuid ## CONSUMES
+
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c
new file mode 100644
index 0000000000..9307b8fc4c
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c
@@ -0,0 +1,169 @@
+/** @file
+ This is the FSP driver that initializes the Intel PCH.
+
+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 "PchInit.h"
+
+EFI_STATUS
+EFIAPI
+PchOnPciEnumCompleteFsp (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+STATIC
+EFI_PEI_NOTIFY_DESCRIPTOR mPchOnPciEnumCompleteNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPciEnumerationCompleteProtocolGuid,
+ PchOnPciEnumCompleteFsp
+ }
+};
+
+EFI_STATUS
+EFIAPI
+PchReadyToBootEventFsp (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mReadyToBootNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEventReadyToBootGuid,
+ PchReadyToBootEventFsp
+ }
+};
+
+
+/**
+ <b>FSP PchInit Module Entry Point for FSP</b>\n
+
+ @param[in] FileHandle PEIM's file handle
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver
+**/
+EFI_STATUS
+EFIAPI
+PchInitEntryPointFsp (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "PchInitEntryPointFsp() Start\n"));
+
+ PchInitEntryPointCommon ();
+
+ Status = PeiServicesNotifyPpi (mPchOnPciEnumCompleteNotifyList);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiServicesNotifyPpi (mReadyToBootNotifyList);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "PchInitEntryPointFsp() End\n"));
+
+ return Status;
+}
+
+/**
+ Fsp PCH initialization on PCI enumeration complete
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver
+**/
+EFI_STATUS
+EFIAPI
+PchOnPciEnumCompleteFsp (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteFsp() Start\n"));
+
+ PchOnPciEnumCompleteCommon ();
+
+ DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteFsp() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ FSP PCH Ready to boot event handler
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver
+**/
+EFI_STATUS
+EFIAPI
+PchReadyToBootEventFsp (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ UINTN XhciMmioBase;
+ UINTN XhciPciMmBase;
+ UINT16 XhciPciCommand;
+ BOOLEAN XhciPdoRestartNeeded;
+
+ DEBUG ((DEBUG_INFO, "PchReadyToBootEventFsp() Start\n"));
+
+ // Check if USB PDO programming was skipped during PEI phase
+ if (mPchConfigHob->Usb.DelayPdoProgramming == TRUE) {
+ XhciPciMmBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI
+ );
+
+ // Check if xHCI has memory access
+ XhciPciCommand = MmioRead16 (XhciPciMmBase + PCI_COMMAND_OFFSET);
+ if ((XhciPciCommand & EFI_PCI_COMMAND_MEMORY_SPACE) == 0x0) {
+ DEBUG ((DEBUG_ERROR, "xHCI Controller isn't configured properly\n"));
+ } else {
+ // Getting base MMIO address for xHCI
+ XhciMmioBase = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE) & (B_PCH_XHCI_MEM_ALIGN_MASK << N_PCH_XHCI_MEM_ALIGN);
+
+ XhciPdoRestartNeeded = UsbPdoProgramming (
+ XhciMmioBase,
+ mPchConfigHob->Usb.Usb2DisabledPorts,
+ mPchConfigHob->Usb.Usb3DisabledPorts
+ );
+ // If PDO registers are locked, reset platform to unlock them
+ if (XhciPdoRestartNeeded) {
+ (*PeiServices)->ResetSystem2 (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "PDO register already programmed\n"));
+ }
+
+ DEBUG ((DEBUG_INFO, "PchReadyToBootEventFsp() End\n"));
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchRstPcieStorage.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchRstPcieStorage.c
new file mode 100644
index 0000000000..801abf2602
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchRstPcieStorage.c
@@ -0,0 +1,286 @@
+/** @file
+ Configures the remapping for PCH Intel RST PCie Storage
+ In order to use this feature, Intel RST Driver is required
+
+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 "PchInit.h"
+#include <Library/RstPrivateLib.h>
+#include <PchPcieStorageDetectHob.h>
+
+//
+// Variables below indicate the memory range to be allocated to the PCIe storage device BAR usage when it is HIDDEN,
+// thus it does not overlapped with the SGREG_BAR from the host perspective
+//
+#define RST_PCIE_STORAGE_MEMORY_START_RANGE PCH_PCR_BASE_ADDRESS
+#define RST_PCIE_STORAGE_MEMORY_END_RANGE (PCH_PCR_BASE_ADDRESS + PCH_PCR_MMIO_SIZE - 1)
+
+#define PCI_CARD_PM_CAP_ID 0x01
+#define PCI_CARD_MSIX_CAP_ID 0x11
+#define PCI_CARD_SATA_CAP_ID 0x12
+#define PCI_CARD_BAR_TOTAL 6
+#define PCI_CARD_LINK_SPEED_GEN1_GEN2 0
+#define PCI_CARD_LINK_SPEED_GEN3 1
+#define PCI_CARD_LINK_WIDTH_1 0
+#define PCI_CARD_LINK_WIDTH_2 1
+#define PCI_CARD_LINK_WIDTH_4 2
+#define PCI_CARD_REVISION 0x08
+#define PCI_CARD_BASE_ADDR0 0x10
+#define PCI_CARD_BASE_ADDR1 0x14
+#define PCI_CARD_BASE_ADDR5 0x24
+
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_RST_PCIE_STORAGE_DETECTION mRstPcieStorageDetection [PCH_MAX_RST_PCIE_STORAGE_CR];
+
+UINT32 PchRstPcieStorageCurrentMemoryRange = RST_PCIE_STORAGE_MEMORY_START_RANGE;
+
+
+/**
+ Function to perform dump for PCH_RST_PCIE_STORAGE_DETECTION
+
+ @param[in] Index Index for RST PCIe Storage Cycle Router Instance
+
+ @retval None
+**/
+VOID
+PchRstPcieStorageRemappingDump (
+ IN UINTN Index
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((DEBUG_INFO, "PchRstPcieStorageRemappingDump() Started\n"));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].SupportRstPcieStoragRemapping = %x\n", Index, mRstPcieStorageDetection[Index].SupportRstPcieStoragRemapping));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].RootPortNum = %x\n", Index, mRstPcieStorageDetection[Index].RootPortNum));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].RootPortLane = %x\n", Index, mRstPcieStorageDetection[Index].RootPortLane));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].DeviceInterface = %x\n", Index, mRstPcieStorageDetection[Index].DeviceInterface));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].IsMsixSupported = %x\n", Index, mRstPcieStorageDetection[Index].IsMsixSupported));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].MsixStartingVector = %x\n", Index, mRstPcieStorageDetection[Index].MsixStartingVector));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].MsixEndingVector = %x\n", Index, mRstPcieStorageDetection[Index].MsixEndingVector));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointBarSize = %x\n", Index, mRstPcieStorageDetection[Index].EndPointBarSize));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixTableBar = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBar));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixTableBarValue = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBarValue));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixPbaBar = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBar));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixPbaBarValue = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBarValue));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointBcc = %x\n", Index, mRstPcieStorageDetection[Index].EndPointBcc));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointScc = %x\n", Index, mRstPcieStorageDetection[Index].EndPointScc));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointPi = %x\n", Index, mRstPcieStorageDetection[Index].EndPointPi));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.PmCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PmCapPtr));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.PcieCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PcieCapPtr));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.L1ssCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.L1ssCapPtr));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointL1ssControl2 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl2));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointL1ssControl1 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl1));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.LtrCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.LtrCapPtr));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointLtrData = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLtrData));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointLctlData16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLctlData16));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointDctlData16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctlData16));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointDctl2Data16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctl2Data16));
+ DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.RootPortDctl2Data16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.RootPortDctl2Data16));
+ DEBUG ((DEBUG_INFO, "PchRstPcieStorageRemappingDump() Ended\n"));
+ DEBUG_CODE_END ();
+}
+
+/**
+ Perform memory space allocation or free memory pool for AHCI BAR
+
+ @param[in] Operation True: Perform memory space allocation for AHCI BAR
+ False: Perform memory pool free for AHCI BAR
+ @param[in,out] MemBaseAddress The base memory address used by AHCI BAR
+**/
+VOID
+AbarMemorySpaceOperation (
+ IN BOOLEAN Operation,
+ IN OUT EFI_PHYSICAL_ADDRESS *MemBaseAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN AhciBarAlignment;
+ UINTN AhciBarLength;
+
+ //
+ // Assign a 512k size memory space to the ABAR when NVM Remapping is enabled
+ //
+ AhciBarAlignment = N_PCH_SATA_AHCI_BAR_ALIGNMENT_512K; // 2^19: 512K Alignment
+ AhciBarLength = V_PCH_SATA_AHCI_BAR_LENGTH_512K; // 512K Length
+
+
+ if (Operation == TRUE) {
+ ///
+ /// If MemBaseAddress is not allocated yet, allocate the AHCI BAR
+ ///
+ if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
+ BaseAddress = 0x0ffffffff;
+ }
+ Status = gDS->AllocateMemorySpace (
+ PcdGet8 (PcdEfiGcdAllocateType),
+ EfiGcdMemoryTypeMemoryMappedIo,
+ AhciBarAlignment,
+ AhciBarLength,
+ &BaseAddress,
+ mImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ *MemBaseAddress = BaseAddress;
+ } else {
+ ///
+ /// Else, free the GCD pool
+ ///
+ gDS->FreeMemorySpace (
+ *MemBaseAddress,
+ AhciBarLength
+ );
+ }
+}
+
+/**
+ Function to perform memory allocation for PCIe storage device that support unique BAR
+
+ @param[in] BarSize The BAR size required for memory allocation
+ @param[in,out] AllocAddr The Address that been allocated by this function
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES Memory or storage is not enough
+**/
+EFI_STATUS
+PchRstPcieStorageMemAllocation (
+ IN UINT32 BarSize,
+ IN OUT UINT32 *AllocAddr
+ )
+{
+ if ((PchRstPcieStorageCurrentMemoryRange + BarSize) > RST_PCIE_STORAGE_MEMORY_END_RANGE) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((PchRstPcieStorageCurrentMemoryRange & (BarSize - 1)) != 0) {
+ *AllocAddr = (PchRstPcieStorageCurrentMemoryRange + BarSize) & ~(BarSize-1);
+ } else {
+ *AllocAddr = PchRstPcieStorageCurrentMemoryRange;
+ }
+
+ PchRstPcieStorageCurrentMemoryRange = *AllocAddr + BarSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Check and detect PCIe storage device per policies, and if existed, indicate if it should be subjected for remapping
+ Populate the mRstPcieStorageDetection structure along with it for later usages
+
+ @param[in, out] RemappingRequired Boolean value with TRUE indicates that RST PCIe Storage Remapping is required
+ @param[in] TempPciBusMin The temporary minimum Bus number for root port initialization
+ @param[in] SataRegBase SATA Register Base
+
+ @retval None
+**/
+VOID
+DetectPcieStorageDevices (
+ IN OUT BOOLEAN *RemappingRequired,
+ IN UINT8 TempPciBusMin,
+ IN UINTN SataRegBase
+ )
+{
+ EFI_STATUS Status;
+ PCH_SERIES PchSeries;
+ UINT8 DeviceInterface;
+ UINT32 PortNum;
+ UINTN PciRootPortRegBase;
+ UINTN RpDev;
+ UINTN RpFunc;
+ UINT8 RootPortLane;
+ PCIE_STORAGE_INFO_HOB *PcieStorageInfoHob;
+ VOID *Hob;
+ UINT32 CycleRouterNum;
+
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: DetectPcieStorageDevices Started\n"));
+
+ Hob = NULL;
+ Hob = GetFirstGuidHob (&gPchPcieStorageDetectHobGuid);
+ if (Hob != NULL) {
+ PcieStorageInfoHob = (PCIE_STORAGE_INFO_HOB *) GET_GUID_HOB_DATA (Hob);
+ } else {
+ return;
+ }
+
+ PchSeries = GetPchSeries ();
+
+ for (PortNum = 0; PortNum < GetPchMaxPciePortNum (); PortNum++) {
+
+ //
+ // Check Info hob for Cycle Router avaliable
+ // skip to next root port if Cr is not avaliable
+ //
+ CycleRouterNum = PcieStorageInfoHob->RstCycleRouterMap[PortNum / 4];
+ if (CycleRouterNum == RST_PCIE_STORAGE_CR_INVALID) {
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: cycle router not avaliable on Rp = %d\n", PortNum));
+ continue;
+ }
+
+ Status = GetPchPcieRpDevFun (PortNum, &RpDev, &RpFunc);
+ ASSERT_EFI_ERROR (Status);
+
+ PciRootPortRegBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDev, (UINT32) RpFunc);
+ RootPortLane = RstGetRpLaneOccupyMask (PortNum);
+
+
+ if (RootPortLane == 0) {
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: root port lane is not occupied\n"));
+ continue;
+ }
+
+ ///
+ /// Check if the RST PCIe Storage Cycle Router is enabled, continue to the next root port in the next x4 lane if it is disabled
+ ///
+ if (mPchConfigHob->Sata.RstPcieStorageRemap[CycleRouterNum].Enable == 0) {
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: RST PCIe Storage Cycle Router %d is disabled\n", CycleRouterNum));
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: Proceed to root port in the next x4 lane (@ port %d)\n", PortNum + 1));
+ PortNum += 3 - (PortNum % 4);
+ continue;
+ }
+
+ ///
+ /// Check if the current root port is matching selected root port from policy, continue to next port if they are not matched
+ ///
+ if ((mPchConfigHob->Sata.RstPcieStorageRemap[CycleRouterNum].RstPcieStoragePort != 0) &&
+ (mPchConfigHob->Sata.RstPcieStorageRemap[CycleRouterNum].RstPcieStoragePort != PortNum + 1)) {
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: root port %d not matched with selected root port, proceed to next port\n", PortNum + 1));
+ continue;
+ }
+
+
+ // Read device programming interface from info hob
+ // if no device is present continue
+ if (PcieStorageInfoHob->PcieStorageLinkWidth[PortNum]) {
+ DeviceInterface = PcieStorageInfoHob->PcieStorageProgrammingInterface[PortNum];
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: Device present on RP# %d, PiInterface = %d\n", PortNum + 1, DeviceInterface));
+ } else {
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: RP# %d no device present\n", PortNum + 1));
+ continue;
+ }
+
+
+ ///
+ /// Update the remapping detail for detected PCIe storage device, and move to the root port in the next x4 lane
+ ///
+ if ((DeviceInterface != RST_PCIE_STORAGE_INTERFACE_NONE)) {
+ mRstPcieStorageDetection[CycleRouterNum].SupportRstPcieStoragRemapping = TRUE;
+ mRstPcieStorageDetection[CycleRouterNum].RootPortNum = (UINT8) PortNum;
+ mRstPcieStorageDetection[CycleRouterNum].RootPortLane = RootPortLane;
+ mRstPcieStorageDetection[CycleRouterNum].DeviceInterface = DeviceInterface;
+ PortNum += 3 - (PortNum % 4);
+ *RemappingRequired = TRUE;
+ } else {
+ continue;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: DetectPcieStorageDevices() Ended\n"));
+}
+
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
new file mode 100644
index 0000000000..d1f2948de6
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
@@ -0,0 +1,125 @@
+/** @file
+ Perform related functions for PCH Sata in DXE phase
+
+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 <PchInit.h>
+
+/**
+ Perform the remaining configuration on PCH SATA to perform device detection,
+ then set the SATA SPD and PxE corresponding, and set the Register Lock on PCH SATA
+
+ @retval None
+**/
+VOID
+ConfigurePchSataOnEndOfDxe (
+ VOID
+ )
+{
+ UINTN PciSataRegBase;
+ UINT16 SataPortsEnabled;
+ PCH_SERIES PchSeries;
+ UINT16 WordReg;
+ UINT32 DwordReg;
+ UINTN Index;
+
+ ///
+ /// 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 = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_SATA, PCI_FUNCTION_NUMBER_PCH_SATA);
+ PchSeries = GetPchSeries ();
+ SataPortsEnabled = 0;
+
+ if (MmioRead16 (PciSataRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+ return;
+ }
+ if (PchSeries == PchLp) {
+ WordReg = MmioRead16 (PciSataRegBase + R_PCH_LP_SATA_PCS);
+ for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) {
+ if ((mPchConfigHob->Sata.PortSettings[Index].HotPlug == TRUE) ||
+ (WordReg & (B_PCH_LP_SATA_PCS_P0P << Index)) ||
+ (mPchConfigHob->Sata.TestMode == TRUE) ||
+ (mPchConfigHob->Sata.PortSettings[Index].External == TRUE)) {
+ SataPortsEnabled |= (mPchConfigHob->Sata.PortSettings[Index].Enable << Index);
+ }
+ }
+
+ ///
+ /// Set MAP."Sata PortX Disable", SATA PCI offset 90h[10:8] to 1b if SATA Port 0/1/2 is disabled
+ ///
+ MmioOr16 (PciSataRegBase + R_PCH_LP_SATA_MAP, ((~SataPortsEnabled << N_PCH_LP_SATA_MAP_SPD) & (UINT16) B_PCH_LP_SATA_MAP_SPD));
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint16,
+ (UINTN) (PciSataRegBase + R_PCH_LP_SATA_MAP),
+ 1,
+ (VOID *) (UINTN) (PciSataRegBase + R_PCH_LP_SATA_MAP)
+ );
+
+ ///
+ /// Program PCS "Port X Enabled", SATA PCI offset 92h[2:0] = Port 0~2 Enabled bit as per SataPortsEnabled value.
+ ///
+ MmioOr16 (PciSataRegBase + R_PCH_LP_SATA_PCS, SataPortsEnabled);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint16,
+ (UINTN) (PciSataRegBase + R_PCH_LP_SATA_PCS),
+ 1,
+ (VOID *) (UINTN) (PciSataRegBase + R_PCH_LP_SATA_PCS)
+ );
+ } else {
+ DwordReg = MmioRead32 (PciSataRegBase + R_PCH_H_SATA_PCS);
+ for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) {
+ if ((mPchConfigHob->Sata.PortSettings[Index].HotPlug == TRUE) ||
+ (DwordReg & (B_PCH_H_SATA_PCS_P0P << Index)) ||
+ (mPchConfigHob->Sata.TestMode == TRUE) ||
+ (mPchConfigHob->Sata.PortSettings[Index].External == TRUE)) {
+ SataPortsEnabled |= (mPchConfigHob->Sata.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
+ ///
+ MmioOr32 (PciSataRegBase + R_PCH_H_SATA_MAP, ((~SataPortsEnabled << N_PCH_H_SATA_MAP_SPD) & (UINT32) B_PCH_H_SATA_MAP_SPD));
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PciSataRegBase + R_PCH_H_SATA_MAP),
+ 1,
+ (VOID *) (UINTN) (PciSataRegBase + R_PCH_H_SATA_MAP)
+ );
+
+ ///
+ /// Program PCS "Port X Enabled", SATA PCI offset 94h[7:0] = Port 0~7 Enabled bit as per SataPortsEnabled value.
+ ///
+ MmioOr16 (PciSataRegBase + R_PCH_H_SATA_PCS, SataPortsEnabled);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint16,
+ (UINTN) (PciSataRegBase + R_PCH_H_SATA_PCS),
+ 1,
+ (VOID *) (UINTN) (PciSataRegBase + R_PCH_H_SATA_PCS)
+ );
+ }
+
+ ///
+ /// Step 14
+ /// Program SATA PCI offset 9Ch [31] to 1b
+ ///
+ MmioOr32 ((UINTN) (PciSataRegBase + R_PCH_SATA_SATAGC), BIT31);
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (PciSataRegBase + R_PCH_SATA_SATAGC),
+ 1,
+ (VOID *) (UINTN) (PciSataRegBase + R_PCH_SATA_SATAGC)
+ );
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchScs.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchScs.c
new file mode 100644
index 0000000000..34227826b4
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchScs.c
@@ -0,0 +1,1869 @@
+/** @file
+ Initializes PCH Storage and Communications Subsystem Controllers.
+
+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 <PchInit.h>
+
+//
+// HS400 Tuning Definitions
+//
+#define RX_STROBE_DLL1_TAP_MAX_RANGE 39
+#define RX_STROBE_DLL1_TAP_MIN_RANGE 0
+#define RX_STROBE_DLL1_TAP_MIN_MEPT 5
+#define RX_STROBE_DLL1_TAP_MAX_MEPT 16
+#define TX_DATA_DLL_TAP_MAX_RANGE 79
+#define TX_DATA_DLL_TAP_MIN_RANGE 0
+#define TX_DATA_DLL_TAP_MIN_MEPT 4
+#define TX_DATA_DLL_TAP_MAX_MEPT 22
+
+//
+// Command Definitions
+//
+#define CMD6 6
+#define CMD8 8
+#define CMD13 13
+#define CMD31 31
+#define SWITCH CMD6
+#define SEND_EXT_CSD CMD8
+#define SEND_STATUS CMD13
+#define SEND_WRITE_PROT_TYPE CMD31
+#define WRITE_BYTE_MODE 3
+#define BLOCK_LENGTH 512
+#define TIMEOUT_COMMAND 100
+#define TIMEOUT_DATA 5000
+#define HS_TIMING_INDEX 185
+#define BUS_WIDTH_INDEX 183
+
+//
+// Card Status Definitions
+//
+#define SWITCH_ERROR BIT7
+#define ERASE_RESET BIT13
+#define WP_ERASE_SKIP BIT15
+#define CID_CSD_OVERWRITE BIT16
+#define ERROR BIT19
+#define CC_ERROR BIT20
+#define CARD_ECC_FAILED BIT21
+#define ILLEGAL_COMMAND BIT22
+#define COM_CRC_ERROR BIT23
+#define LOCK_UNLOCK_FAILED BIT24
+#define CARD_IS_LOCKED BIT25
+#define WP_VIOLATION BIT26
+#define ERASE_PARAM BIT27
+#define ERASE_SEQ_ERROR BIT28
+#define BLOCK_LEN_ERROR BIT29
+#define ADDRESS_MISALIGN BIT30
+#define ADDRESS_OUT_OF_RANGE BIT31
+
+typedef enum {
+ Hs200 = 0,
+ Hs400,
+ DDR50,
+ SDR25
+} EMMC_MODE;
+
+typedef enum {
+ RxDll1 = 0,
+ RxDll2
+} RX_STROBE_DLL_REG;
+
+typedef enum {
+ NotAvailable = 0,
+ Passed,
+ Failed
+} BLOCK_READ_WRITE_STATUS;
+
+typedef enum {
+ ResponseNo = 0,
+ ResponseR1,
+ ResponseR1b,
+ ResponseR2,
+ ResponseR3,
+ ResponseR4,
+ ResponseR5,
+ ResponseR5b,
+ ResponseR6,
+ ResponseR7
+} RESPONSE_TYPE;
+
+typedef enum {
+ NoData = 0,
+ InData,
+ OutData
+} TRANSFER_TYPE;
+
+typedef struct {
+ UINT32 CmdSet: 3;
+ UINT32 Reserved0: 5;
+ UINT32 Value: 8;
+ UINT32 Index: 8;
+ UINT32 Access: 2;
+ UINT32 Reserved1: 6;
+} SWITCH_ARGUMENT;
+
+//
+// PCH_EMMC_TUNING PROTOCOL Global Variable
+//
+GLOBAL_REMOVE_IF_UNREFERENCED PCH_EMMC_TUNING_PROTOCOL PchEmmcTuningProtocol = {
+ ConfigureEmmcHs400Mode
+};
+
+#define EMMC_HS400_TUNING_PATTERN_BLOCKS_NUMBER 5
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CONST UINT32 EmmcWorstCasePattern[] =
+{
+0x60FEFE00, 0xEDFF10FE, 0x60FEFE00, 0xEDFF10FE, 0xDE08216A, 0xE25F20DF, 0xDE08216A, 0xE25F20DF, // spt_a0_sandisk_50ohm
+0xFF00CFFF, 0x1014B5CF, 0xFF00CFFF, 0x1014B5CF, 0x225F25DF, 0x20DFDE61, 0x225F25DF, 0x20DFDE61, // spt_a0_sandisk_40ohm
+0xEFE770BD, 0x4AFF0000, 0xEFE770BD, 0x4AFF0000, 0x7B84FF5B, 0x5B655B0E, 0x7B84FF5B, 0x5B655B0E, // spt_a0_hynix_50ohm
+0x7B93D620, 0xDFFF00E8, 0x7B93D620, 0xDFFF00E8, 0x3DC2FF3D, 0x38EA7DF3, 0x3DC2FF3D, 0x38EA7DF3, // spt_a0_hynix_40ohm
+0x50127FAC, 0x4400FD00, 0x50127FAC, 0x4400FD00, 0x7887FF78, 0x109A394F, 0x7887FF78, 0x109A394F, // spt_a0_hynix_33ohm
+0x50F20DBF, 0x3832CDFD, 0x50F20DBF, 0x3832CDFD, 0xFB04D720, 0xE69DC704, 0xFB04D720, 0xE69DC704, // spt_a0_samsung19nm_33ohm
+0x40EFFF00, 0x40FFFF00, 0x40EFFF00, 0x40FFFF00, 0xE85F20DF, 0x20DF003F, 0xE85F20DF, 0x20DF003F, // spt_a0_toshiba_50ohm
+0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0x20DFA0FF, 0x58DB20DF, 0x20DFA0FF, 0x58DB20DF, // spt_a0_toshiba_40ohm
+0x50FF0008, 0x7E10FFFF, 0x50FF0008, 0x7E10FFFF, 0x3B8F7A85, 0xFF7A5AFF, 0x3B8F7A85, 0xFF7A5AFF, // spt_b0_hynix_40ohm
+0x8A7575FF, 0x9ACA7F54, 0x8A7575FF, 0x9ACA7F54, 0xDF649B92, 0x7B24AFA0, 0xDF649B92, 0x7B24AFA0, // spt_b0_samsung16nm_50ohm
+0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xDAD6EF50, 0x6B1C6B25, 0xDAD6EF50, 0x6B1C6B25, // spt_b0_samsung16nm_40ohm
+0x7f52ff02, 0xff02ff02, 0x7f52ff02, 0xff02ff02, 0x72bc63a5, 0x679afa9d, 0x72bc63a5, 0x679afa9d, // spt_b0_samsung16nm_33ohm
+
+0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, // baseline_pattern_8
+0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
+0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
+0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CONST UINT32 EmmcWorstCasePatternSize = sizeof (EmmcWorstCasePattern);
+
+
+
+/**
+ Set max clock frequency of the host, the actual frequency may not be the same
+ as MaxFrequency. It depends on the max frequency the host can support, divider,
+ and host speed mode.
+
+ @param[in] This Pointer to EFI_SD_HOST_IO_PROTOCOL
+ @param[in] MaxFrequency Max frequency in HZ
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_TIMEOUT The timeout time expired.
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+ IN UINTN EmmcBaseAddress,
+ IN UINT32 MaxFrequency
+ )
+{
+ UINT16 Data16;
+ UINT32 Frequency;
+ UINT32 Divider = 0;
+ UINT32 TimeOutCount;
+ UINT32 CurrentClockInKHz;
+
+ DEBUG ((DEBUG_INFO, "SetClockFrequency: BaseClockInMHz = %d \n", 200));
+
+ Frequency = (200 * 1000 * 1000) / MaxFrequency;
+ DEBUG ((DEBUG_INFO, "SetClockFrequency: FrequencyInHz = %d \n", Frequency));
+
+ if ((200 * 1000 * 1000 % MaxFrequency) != 0) {
+ Frequency += 1;
+ }
+
+ Divider = 1;
+ while (Frequency > Divider) {
+ Divider = Divider * 2;
+ }
+ if (Divider >= 0x400) {
+ Divider = 0x200;
+ }
+ Divider = Divider >> 1;
+
+ DEBUG ((DEBUG_INFO, "SetClockFrequency: after shift: Base Clock Divider = 0x%x \n", Divider));
+
+ CurrentClockInKHz = (200 * 1000);
+ if (Divider != 0) {
+ CurrentClockInKHz = CurrentClockInKHz / (Divider * 2);
+ }
+ //
+ //Set frequency
+ // Bit[15:8] SDCLK Frequency Select at offset 2Ch
+ // 80h - base clock divided by 256
+ // 40h - base clock divided by 128
+ // 20h - base clock divided by 64
+ // 10h - base clock divided by 32
+ // 08h - base clock divided by 16
+ // 04h - base clock divided by 8
+ // 02h - base clock divided by 4
+ // 01h - base clock divided by 2
+ // 00h - Highest Frequency the target support (10MHz-63MHz)
+ //
+ // Bit [07:06] are assigned to bit 09-08 of clock divider in SDCLK Frequency Select on SD controller 3.0
+ //
+
+ Data16 = (UINT16) ((Divider & 0xFF) << 8 | (((Divider & 0xFF00) >> 8) << 6));
+
+ DEBUG ((DEBUG_INFO,
+ "SetClockFrequency: base=%dMHz, clkctl=0x%04x, f=%dKHz\n",
+ 200,
+ Data16,
+ CurrentClockInKHz
+ ));
+ DEBUG ((DEBUG_INFO, "SetClockFrequency: set MMIO_CLKCTL value = 0x%x \n", Data16));
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL, Data16);
+ Data16 |= BIT0;
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL, Data16);
+ TimeOutCount = 1000;
+ do {
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL);
+ MicroSecondDelay (100);
+ TimeOutCount--;
+ if (TimeOutCount == 0) {
+ DEBUG ((DEBUG_INFO, "SetClockFrequency: Timeout\n"));
+ return EFI_TIMEOUT;
+ }
+ } while ((Data16 & BIT1) != BIT1);
+
+ Data16 |= BIT2;
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL, Data16);
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Error Reason from Host
+
+ @param[in] CommandIndex Command Index which return error
+ @param[in] ErrorCode Command Error Code
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_TIMEOUT Command Timeout Error
+ @retval EFI_TIMEOUT Data Timeout Error
+ @retval EFI_CRC_ERROR Command or Data CRC Error
+ @retval EFI_DEVICE_ERROR Command End Bit Error
+ Command Index Error
+ Data End Bit Error
+ Current Limit Error
+ Auto CMD12 Error
+ ADMA Error
+**/
+STATIC
+EFI_STATUS
+EmmcGetErrorReason (
+ IN UINT16 CommandIndex,
+ IN UINT16 ErrorCode
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_DEVICE_ERROR;
+
+ DEBUG ((DEBUG_ERROR, "[%2d] -- ", CommandIndex));
+
+ if (ErrorCode & BIT0) {
+ Status = EFI_TIMEOUT;
+ DEBUG ((DEBUG_ERROR, "Command Timeout Error\n"));
+ }
+
+ if (ErrorCode & BIT1) {
+ Status = EFI_CRC_ERROR;
+ DEBUG ((DEBUG_ERROR, "Command CRC Error\n"));
+ }
+
+ if (ErrorCode & BIT2) {
+ DEBUG ((DEBUG_ERROR, "Command End Bit Error\n"));
+ }
+
+ if (ErrorCode & BIT3) {
+ DEBUG ((DEBUG_ERROR, "Command Index Error\n"));
+ }
+
+ return Status;
+}
+
+/**
+ Reset the host CMD and DATA Line
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_TIMEOUT The timeout time expired.
+**/
+EFI_STATUS
+EmmcReset (
+ IN UINTN EmmcBaseAddress
+ )
+{
+ UINT8 Data8;
+ UINT8 ResetType;
+ UINT16 SaveClkCtl;
+ UINT32 Data;
+ UINT32 TimeOutCount;
+
+ ResetType = (B_PCH_SCS_DEV_MEM_SWRST_CMDLINE | B_PCH_SCS_DEV_MEM_SWRST_DATALINE);
+
+ //
+ // To improve eMMC stability, we zero the R_PCH_SCS_DEV_MEM_CLKCTL register and
+ // stall for 50 microsecond before reseting the controller. We
+ // restore the register setting following the reset operation.
+ //
+ SaveClkCtl = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL);
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL, 0);
+ MicroSecondDelay (50);
+ //
+ // Reset the SD host controller
+ //
+ MmioWrite8 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_SWRST, ResetType);
+
+ Data = 0;
+ TimeOutCount = 1000; // 1 second timeout
+ do {
+ MicroSecondDelay (1 * 1000);
+
+ TimeOutCount --;
+
+ Data8 = MmioRead8 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_SWRST);
+ if ((Data8 & ResetType) == 0) {
+ break;
+ }
+ } while (TimeOutCount > 0);
+
+ //
+ // We now restore the R_PCH_SCS_DEV_MEM_CLKCTL register which we set to 0 above.
+ //
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CLKCTL, SaveClkCtl);
+
+ if (TimeOutCount == 0) {
+ DEBUG ((DEBUG_ERROR, "EmmcReset: Time out \n"));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check card status, print the DEBUG info and check the error
+
+ @param[in] CardStatus Status got from card status register
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.
+ @retval EFI_DEVICE_ERROR Device failed during operation
+**/
+EFI_STATUS
+EmmcCheckCardStatus (
+ IN UINT32 CardStatus
+ )
+{
+
+ EFI_STATUS Status;
+ Status = EFI_SUCCESS;
+ DEBUG ((DEBUG_ERROR, "CardStatus:"));
+
+ if (CardStatus & ADDRESS_OUT_OF_RANGE) {
+ DEBUG ((DEBUG_ERROR, " ADDRESS_OUT_OF_RANGE"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & ADDRESS_MISALIGN) {
+ DEBUG ((DEBUG_ERROR, " ADDRESS_MISALIGN"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & BLOCK_LEN_ERROR) {
+ DEBUG ((DEBUG_ERROR, " BLOCK_LEN_ERROR"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & ERASE_SEQ_ERROR) {
+ DEBUG ((DEBUG_ERROR, " ERASE_SEQ_ERROR"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & ERASE_PARAM) {
+ DEBUG ((DEBUG_ERROR, " ERASE_PARAM"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & WP_VIOLATION) {
+ DEBUG ((DEBUG_ERROR, " WP_VIOLATION"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & CARD_IS_LOCKED) {
+ DEBUG ((DEBUG_ERROR, " CARD_IS_LOCKED"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & LOCK_UNLOCK_FAILED) {
+ DEBUG ((DEBUG_ERROR, " LOCK_UNLOCK_FAILED"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & COM_CRC_ERROR) {
+ DEBUG ((DEBUG_ERROR, " COM_CRC_ERROR"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & ILLEGAL_COMMAND) {
+ DEBUG ((DEBUG_ERROR, " ILLEGAL_COMMAND"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & CARD_ECC_FAILED) {
+ DEBUG ((DEBUG_ERROR, " CARD_ECC_FAILED"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & CC_ERROR) {
+ DEBUG ((DEBUG_ERROR, " CC_ERROR"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & ERROR) {
+ DEBUG ((DEBUG_ERROR, " ERROR"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & CID_CSD_OVERWRITE) {
+ DEBUG ((DEBUG_ERROR, " CID_CSD_OVERWRITE"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & WP_ERASE_SKIP) {
+ DEBUG ((DEBUG_ERROR, " WP_ERASE_SKIP"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & ERASE_RESET) {
+ DEBUG ((DEBUG_ERROR, " ERASE_RESET"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (CardStatus & SWITCH_ERROR) {
+ DEBUG ((DEBUG_ERROR, " SWITCH_ERROR"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_ERROR, " \n"));
+
+ return Status;
+}
+/**
+ The main function used to send the command to the card inserted into the SD/MMC host
+ slot. It will assemble the arguments to set the command register and wait for the command
+ and transfer completed until timeout. Then it will read the response register to fill
+ the ResponseData.
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] CommandIndex The command index to set the command index field of command register
+ @param[in] Argument Command argument to set the argument field of command register
+ @param[in] DataType TRANSFER_TYPE, indicates no data, data in or data out
+ @param[in] Buffer Contains the data read from / write to the device
+ @param[in] BufferSize The size of the buffer
+ @param[in] ResponseType RESPONSE_TYPE
+ @param[in] TimeOut Time out value in 1 ms unit
+ @param[out] ResponseData Depending on the ResponseType, such as CSD or card status
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_OUT_OF_RESOURCES A resource has run out.
+ @retval EFI_TIMEOUT The timeout time expired.
+ @retval EFI_DEVICE_ERROR The physical device reported an error while attempting the operation
+**/
+EFI_STATUS
+SendCommand (
+ IN UINTN EmmcBaseAddress,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ResponseDataCount;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+ UINT32 BlockLength;
+ UINT32 Index;
+ BOOLEAN CommandCompleted;
+ BOOLEAN BufferReadReady;
+ INT32 Timeout;
+
+ Status = EFI_SUCCESS;
+ BlockLength = BLOCK_LENGTH;
+
+ if (Buffer != NULL && DataType == NoData) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+
+ //
+ // Check CMD INHIBIT and DATA INHIBIT before send command
+ //
+ Timeout = 1000;
+ do {
+ Data32 = MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_PSTATE);
+ MicroSecondDelay (100);
+ } while ((Timeout-- > 0) && (Data32 & BIT0));
+
+ Timeout = 1000;
+ do {
+ Data32 = MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_PSTATE);
+ MicroSecondDelay (100);
+ } while ((Timeout-- > 0) && (Data32 & BIT1));
+
+
+ //
+ // Enable Interrupts
+ //
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTEN, B_PCH_SCS_DEV_MEM_NINTEN_MASK);
+
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_ERINTEN, B_PCH_SCS_DEV_MEM_ERINTEN_MASK);
+
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSIGNEN, B_PCH_SCS_DEV_MEM_NINTSIGNEN_MASK);
+
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_ERINTSIGNEN, B_PCH_SCS_DEV_MEM_ERINTSIGNEN_MASK);
+
+ //
+ // Clear status bits
+ //
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS, B_PCH_SCS_DEV_MEM_NINTSTS_CLEAR_MASK);
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_ERINTSTS, B_PCH_SCS_DEV_MEM_ERINTSTS_CLEAR_MASK);
+
+ if (Buffer != NULL) {
+ Data16 = 0;
+ if (BufferSize <= BlockLength) {
+ Data16 |= BufferSize;
+ } else {
+ Data16 |= BlockLength;
+ }
+ } else {
+ Data16 = 0;
+ }
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_BLKSZ, Data16);
+
+ if (Buffer != NULL) {
+ if (BufferSize <= BlockLength) {
+ Data16 = 1;
+ } else {
+ Data16 = (UINT16) (BufferSize / BlockLength);
+ }
+ } else {
+ Data16 = 0;
+ }
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_BLKCNT, Data16);
+
+ //
+ // Argument
+ //
+ MmioWrite32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CMDARG, Argument);
+
+ //
+ // Transfer Mode
+ //
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_XFRMODE);
+
+ //
+ // Data Transfer Direction Select
+ //
+ Data16 = 0;
+ if (DataType == InData) {
+ Data16 |= B_PCH_SCS_DEV_MEM_XFRMODE_DATA_TRANS_DIR;
+ }
+
+ if (CommandIndex == SEND_EXT_CSD) {
+ Data16 |= B_PCH_SCS_DEV_MEM_XFRMODE_BLKCNT_EN;
+ }
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_XFRMODE, Data16);
+ //
+ //Command
+ //
+ //ResponseTypeSelect IndexCheck CRCCheck ResponseType
+ // 00 0 0 NoResponse
+ // 01 0 1 R2
+ // 10 0 0 R3, R4
+ // 10 1 1 R1, R5, R6, R7
+ // 11 1 1 R1b, R5b
+ //
+ switch (ResponseType) {
+ case ResponseNo:
+ Data16 = (CommandIndex << 8);
+ ResponseDataCount = 0;
+ break;
+
+ case ResponseR1:
+ case ResponseR5:
+ case ResponseR6:
+ case ResponseR7:
+ Data16 = (CommandIndex << 8) | V_PCH_SCS_DEV_MEM_SDCMD_RESP_TYPE_SEL_RESP48 |
+ B_PCH_SCS_DEV_MEM_SDCMD_CMD_INDEX_CHECK_EN | B_PCH_SCS_DEV_MEM_SDCMD_CMD_CRC_CHECK_EN;
+ ResponseDataCount = 1;
+ break;
+
+ case ResponseR1b:
+ case ResponseR5b:
+ Data16 = (CommandIndex << 8) | V_PCH_SCS_DEV_MEM_SDCMD_RESP_TYPE_SEL_RESP48_CHK |
+ B_PCH_SCS_DEV_MEM_SDCMD_CMD_INDEX_CHECK_EN | B_PCH_SCS_DEV_MEM_SDCMD_CMD_CRC_CHECK_EN;
+ ResponseDataCount = 1;
+ break;
+
+ case ResponseR2:
+ Data16 = (CommandIndex << 8) | V_PCH_SCS_DEV_MEM_SDCMD_RESP_TYPE_SEL_RESP136 |
+ B_PCH_SCS_DEV_MEM_SDCMD_CMD_CRC_CHECK_EN;
+ ResponseDataCount = 4;
+ break;
+
+ case ResponseR3:
+ case ResponseR4:
+ Data16 = (CommandIndex << 8) | V_PCH_SCS_DEV_MEM_SDCMD_RESP_TYPE_SEL_RESP48;
+ ResponseDataCount = 1;
+ break;
+
+ default:
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+
+ if (DataType != NoData) {
+ Data16 |= B_PCH_SCS_DEV_MEM_SDCMD_DATA_PRESENT_SEL;
+ }
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_SDCMD, Data16);
+ CommandCompleted = FALSE;
+ BufferReadReady = FALSE;
+ TimeOut = 1000;
+ do {
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_ERINTSTS);
+ if ((Data16 & B_PCH_SCS_DEV_MEM_ERINTSTS_MASK) != 0) {
+ Status = EmmcGetErrorReason (CommandIndex, Data16);
+ return Status;
+ }
+
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS) & 0x1ff;
+ if (Data16 & B_PCH_SCS_DEV_MEM_NINTSTS_CMD_COMPLETE) {
+ //
+ // Command completed
+ //
+ CommandCompleted = TRUE;
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS, B_PCH_SCS_DEV_MEM_NINTSTS_CMD_COMPLETE);
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS);
+ if ((DataType == NoData) & (ResponseType != ResponseR1b)) {
+ break;
+ }
+ }
+
+ if ((CommandCompleted) && (ResponseType == ResponseR1b)) {
+ Data32 = MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_PSTATE);
+ if (Data32 & B_PCH_SCS_DEV_MEM_PSTATE_DAT0) {
+ break;
+ }
+ }
+
+ if ((CommandCompleted) && (Buffer!= NULL)) {
+ if (!(Data16 & B_PCH_SCS_DEV_MEM_NINTSTS_CMD_COMPLETE)) {
+
+ if (Data16 & B_PCH_SCS_DEV_MEM_NINTSTS_BUF_READ_READY_INTR) {
+ BufferReadReady = TRUE;
+ MmioOr16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS, B_PCH_SCS_DEV_MEM_NINTSTS_BUF_READ_READY_INTR);
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS);
+ }
+
+ if (BufferReadReady) {
+ if (!(Data16 & B_PCH_SCS_DEV_MEM_NINTSTS_BUF_READ_READY_INTR)) {
+ for (Index = 0; Index < BufferSize; Index = Index + 4) {
+ Data32 = MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_BUFDATAPORT);
+ if ((Index + 4) < BufferSize) {
+ CopyMem ((Buffer + Index), &Data32, 4);
+ } else {
+ CopyMem ((Buffer + Index), &Data32, (BufferSize - Index));
+ }
+ }
+ }
+ Data16 = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS);
+ }
+
+ if (Data16 & B_PCH_SCS_DEV_MEM_NINTSTS_TRANSFER_COMPLETE) {
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_NINTSTS, B_PCH_SCS_DEV_MEM_NINTSTS_TRANSFER_COMPLETE);
+ break;
+ }
+ }
+ }
+ MicroSecondDelay (1*1000);
+
+ TimeOut --;
+
+ } while (TimeOut > 0);
+
+ if (TimeOut == 0) {
+ Status = EFI_TIMEOUT;
+ return Status;
+ }
+
+ if (ResponseData != NULL) {
+ UINT32 *ResDataPtr = NULL;
+
+ ResDataPtr = ResponseData;
+ for (Index = 0; Index < ResponseDataCount; Index++) {
+ *ResDataPtr = MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_RESP + Index * 4);
+ ResDataPtr++;
+ }
+
+ if (ResponseType == ResponseR2) {
+ //
+ // Adjustment for R2 response
+ //
+ Data32 = 1;
+ for (Index = 0; Index < ResponseDataCount; Index++) {
+ Data64 = LShiftU64 (*ResponseData, 8);
+ *ResponseData = (UINT32) ((Data64 & 0xFFFFFFFF) | Data32);
+ Data32 = (UINT32) RShiftU64 (Data64, 32);
+ ResponseData++;
+ }
+ }
+ }
+ return Status;
+}
+
+/**
+ This main function is to send command to Emmc
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] CommandIndex The command index to set the command index field of command register
+ @param[in] Argument Command argument to set the argument field of command register
+ @param[in] DataType TRANSFER_TYPE, indicates no data, data in or data out
+ @param[in] Buffer Contains the data read from / write to the device
+ @param[in] BufferSize The size of the buffer
+ @param[in] ResponseType RESPONSE_TYPE
+ @param[in] TimeOut Time out value in 1 ms unit
+ @param[out] ResponseData Depending on the ResponseType, such as CSD or card status
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_OUT_OF_RESOURCES A resource has run out.
+ @retval EFI_TIMEOUT The timeout time expired.
+ @retval EFI_DEVICE_ERROR The physical device reported an error while attempting the operation
+**/
+EFI_STATUS
+EmmcSendCommand (
+ IN UINTN EmmcBaseAddress,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SendCommand (
+ EmmcBaseAddress,
+ CommandIndex,
+ Argument,
+ DataType,
+ Buffer,
+ BufferSize,
+ ResponseType,
+ TimeOut,
+ ResponseData
+ );
+
+ if (!EFI_ERROR (Status)) {
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+ ASSERT (ResponseData != NULL);
+ Status = EmmcCheckCardStatus (*ResponseData);
+ if (EFI_ERROR (Status)) {
+ EmmcReset (EmmcBaseAddress);
+ }
+ }
+ } else {
+ //
+ // Reset Host Controller CMD and DATA
+ //
+ EmmcReset (EmmcBaseAddress);
+ }
+
+ return Status;
+}
+/**
+ Set Tx Data Delay Control 1
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] Value Value (0 - 79)
+
+ @retval VOID
+**/
+VOID
+EmmcSetTxDllCtrl1 (
+ IN UINTN EmmcBaseAddress,
+ IN UINT8 Value
+ )
+{
+ MmioAndThenOr8 (EmmcBaseAddress + (R_PCH_SCS_DEV_MEM_TX_DATA_DLL_CNTL1 + 1), 0, Value);
+}
+
+/**
+ Set Rx Strobe Delay Control DLL1 for HS400
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] RxDll To program RxDll1 or RxDll2 register
+ @param[in] Value Value (0 - 39)
+
+ @retval VOID
+**/
+VOID
+EmmcSetRxDllCtrl (
+ IN UINTN EmmcBaseAddress,
+ IN UINT8 RxDll,
+ IN UINT8 Value
+ )
+{
+ if (RxDll == RxDll1) {
+ MmioAndThenOr8 (EmmcBaseAddress + (R_PCH_SCS_DEV_MEM_RX_STROBE_DLL_CNTL + 1), 0, Value);
+ } else {
+ MmioAndThenOr8 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_RX_STROBE_DLL_CNTL, 0, Value);
+ }
+}
+
+/**
+ Disable eMMC Host HS400 Support
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+
+ @retval N/A
+**/
+VOID
+EmmcHostHs400Disabled (
+ IN UINTN EmmcBaseAddress
+ )
+{
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode()::EmmcHostHs400Disabled()\n"));
+ MmioAnd32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CAP_BYPASS_REG1, (UINT32) ~B_PCH_SCS_DEV_MEM_CAP_BYPASS_REG1_HS400);
+}
+/**
+ Set Host Mode
+
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] Mode Set Host Mode, 0: HS200, 1: HS400
+
+ @retval N/A
+**/
+VOID
+EmmcSetHostMode (
+ IN UINTN EmmcBaseAddress,
+ IN UINT32 Mode
+ )
+{
+ UINT16 ModeSet;
+ UINT32 HostCapabilities;
+
+ ModeSet = MmioRead16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_HOST_CTL2);
+ HostCapabilities = MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_CAP2);
+
+ ModeSet &= ~B_PCH_SCS_DEV_MEM_HOST_CTL2_MODE_MASK;
+ if ((Mode == Hs200) && (HostCapabilities & B_PCH_SCS_DEV_MEM_CAP2_SDR104_SUPPORT)) {
+ ModeSet |= V_PCH_SCS_DEV_MEM_HOST_CTL2_MODE_SDR104;
+ } else if ((Mode == Hs400) && (HostCapabilities & B_PCH_SCS_DEV_MEM_CAP2_HS400_SUPPORT)) {
+ ModeSet |= V_PCH_SCS_DEV_MEM_HOST_CTL2_MODE_HS400;
+ } else if (Mode == DDR50) {
+ ModeSet |= V_PCH_SCS_DEV_MEM_HOST_CTL2_MODE_DDR50;
+ } else if (Mode == SDR25) {
+ ModeSet |= V_PCH_SCS_DEV_MEM_HOST_CTL2_MODE_SDR25;
+ }
+
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode(): SetHostDdrMode = 0x%x\n", ModeSet));
+
+ MmioWrite16 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_HOST_CTL2, ModeSet);
+}
+
+/**
+ To select eMMC card operating mode HS200/HS400
+
+ @param[in] EmmcInfo A pointer to EMMC_INFO structure
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] EmmcMode To select HS200 or HS400 mode
+
+ @retval EFI_SUCCESS Emmc Mode Select successful.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+**/
+EFI_STATUS
+EmmcModeSelection (
+ IN EMMC_INFO *EmmcInfo,
+ IN UINTN EmmcBaseAddress,
+ IN EMMC_MODE EmmcMode
+ )
+{
+ SWITCH_ARGUMENT SwitchArgument;
+ UINT32 CardStatus;
+ UINT32 HsTimingValue;
+ UINT32 BusWidthValue;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode()::EmmcModeSelection() Start\n"));
+
+ if (EmmcMode == Hs200) {
+ HsTimingValue = 0x02;
+ BusWidthValue = EmmcInfo->HS200BusWidth;
+ DEBUG ((DEBUG_INFO, "HS200 Driver Strength: 50 Ohm\n"));
+ } else {
+ DEBUG ((DEBUG_INFO, "HS400 Driver Strength: "));
+ switch (mPchConfigHob->Scs.ScsEmmcHs400DriverStrength) {
+ case DriverStrength33Ohm:
+ HsTimingValue = 0x13;
+ DEBUG ((DEBUG_INFO, "33 Ohm\n"));
+ break;
+ case DriverStrength40Ohm:
+ HsTimingValue = 0x43;
+ DEBUG ((DEBUG_INFO, "40 Ohm\n"));
+ break;
+ case DriverStrength50Ohm:
+ HsTimingValue = 0x03;
+ DEBUG ((DEBUG_INFO, "50 Ohm\n"));
+ break;
+ default:
+ HsTimingValue = 0x13;
+ DEBUG ((DEBUG_INFO, "default - 33 Ohm\n"));
+ }
+
+ BusWidthValue = 6;
+ }
+ SetClockFrequency (EmmcBaseAddress, (50 * 1000 * 1000)); // Set 50MHz
+ //
+ // 1. Set HS_TIMING to 0x01 for High Speed interface timing. This is required prior DDR 8 bit bus width setting (CMD6)
+ //
+ ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = 1;
+ SwitchArgument.Index = HS_TIMING_INDEX;
+ SwitchArgument.Access = WRITE_BYTE_MODE;
+ Status = EmmcSendCommand (
+ EmmcBaseAddress,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ &CardStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EmmcSetHostMode (EmmcBaseAddress, SDR25);
+
+ //
+ // 2. Set desired bus width to DDR 8 bit CMD6
+ //
+ ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = BusWidthValue;
+ SwitchArgument.Index = BUS_WIDTH_INDEX;
+ SwitchArgument.Access = WRITE_BYTE_MODE;
+ Status = EmmcSendCommand (
+ EmmcBaseAddress,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ &CardStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EmmcSetHostMode (EmmcBaseAddress, DDR50);
+
+ //
+ // 3. Set HS400 bit and Driver Strentgh value in HS_TIMING (CMD6)
+ //
+ ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = HsTimingValue;
+ SwitchArgument.Index = HS_TIMING_INDEX;
+ SwitchArgument.Access = WRITE_BYTE_MODE;
+ Status = EmmcSendCommand (
+ EmmcBaseAddress,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ &CardStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (EmmcMode == Hs200) {
+ DEBUG ((DEBUG_INFO, "Set eMMC Mode: HS200\n"));
+ EmmcSetHostMode (EmmcBaseAddress, Hs200);
+ } else {
+ DEBUG ((DEBUG_INFO, "Set eMMC Mode: HS400\n"));
+ EmmcSetHostMode (EmmcBaseAddress, Hs400);
+ }
+ SetClockFrequency (EmmcBaseAddress, (200 * 1000 * 1000)); // Set 200MHz
+
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode()::EmmcModeSelection() End\n"));
+ return EFI_SUCCESS;
+}
+
+/**
+ Prints worst case pattern used for HS400 taining
+
+ @param[in] BlockIo A pointer to EFI_BLOCK_IO_PROTOCOL structure
+ @param[in] TuningPattern Data buffer containg pattern for training
+ @param[in] TuningPatternSize Size of the buffer with pattern
+
+ @retval N/A
+**/
+VOID
+EmmcPrintHs400TuningPattern (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UINT8 *TuningPattern,
+ IN UINT32 TuningPatternSize
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ UINT32 Index;
+
+ DEBUG ((DEBUG_VERBOSE, "--------------- TUNING PATTERN ----------------\n"));
+ DEBUG ((DEBUG_VERBOSE, "BlockIo->Media->MediaId = 0x%08x\n", BlockIo->Media->MediaId));
+ DEBUG ((DEBUG_VERBOSE, "BlockIo->Media->BlockSize = 0x%08x\n", BlockIo->Media->BlockSize));
+ DEBUG ((DEBUG_VERBOSE, "Tuning Pattern Size = 0x%08x\n", TuningPatternSize));
+ for (Index = 0; Index < TuningPatternSize; Index++) {
+ if (Index % 16 == 0) {
+ DEBUG ((DEBUG_VERBOSE, "\n"));
+ }
+ if (Index % (BlockIo->Media->BlockSize) == 0) {
+ DEBUG ((DEBUG_VERBOSE, "-------------------- BLOCK --------------------\n"));
+ }
+ DEBUG ((DEBUG_VERBOSE, "%02x ", TuningPattern[Index]));
+ }
+ DEBUG ((DEBUG_VERBOSE, "\n-----------------------------------------------\n"));
+ DEBUG_CODE_END ();
+}
+
+/**
+ Writes worst case pattern used for HS400 taining
+
+ @param[in] BlockIo A pointer to EFI_BLOCK_IO_PROTOCOL structure
+ @param[in] TuningPattern Data buffer containg pattern for training
+ @param[in] TuningPatternSize Size of the buffer with pattern
+
+ @retval EFI_SUCCESS HS400 Rx Data Path Training is successful.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+**/
+EFI_STATUS
+EmmcWriteHs400TuningPattern (
+ IN EMMC_INFO *EmmcInfo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UINTN EmmcBaseAddress,
+ IN UINT8 *TuningPattern
+ )
+{
+ UINT8 *Buffer;
+ UINT32 Index;
+ UINT32 TuningPatternSize;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ TuningPatternSize = BlockIo->Media->BlockSize * EMMC_HS400_TUNING_PATTERN_BLOCKS_NUMBER;
+
+ DEBUG ((DEBUG_INFO, "EmmcWriteHs400TuningPattern() Start\n"));
+
+ Buffer = (VOID *) AllocateZeroPool (TuningPatternSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ for (Index = 0; Index < EMMC_HS400_TUNING_PATTERN_BLOCKS_NUMBER; Index++){
+ CopyMem (Buffer + (Index * BlockIo->Media->BlockSize), TuningPattern, BlockIo->Media->BlockSize);
+ }
+
+ Status = BlockIo->WriteBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ TuningPatternSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcWriteHs400TuningPattern: Multiple Blocks Write at HS200 Mode Failed!\n"));
+ goto Exit;
+ }
+
+Exit:
+ FreePool (Buffer);
+ DEBUG ((DEBUG_INFO, "EmmcWriteHs400TuningPattern() End, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ To perform HS400 Rx Data Path Training
+
+ @param[in] EmmcInfo A pointer to EMMC_INFO structure
+ @param[in] BlockIo A pointer to EFI_BLOCK_IO_PROTOCOL structure
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in/out] EmmcTuningData A pointer to EMMC_TUNING_DATA structure
+
+ @retval EFI_SUCCESS HS400 Rx Data Path Training is successful.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+ @retval EFI_CRC_ERROR Command or Data CRC Error
+**/
+EFI_STATUS
+EmmcRxHs400Tuning (
+ IN EMMC_INFO *EmmcInfo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UINTN EmmcBaseAddress,
+ IN OUT EMMC_TUNING_DATA *EmmcTuningData
+ )
+{
+ UINT8 *Buffer;
+ UINT8 DllCount;
+ UINT8 DllMax;
+ UINT8 DllMin;
+ UINT8 Smin;
+ UINT8 Smax;
+ UINT8 Sopt;
+ EFI_STATUS Status;
+ EFI_STATUS ModeStatus;
+ BLOCK_READ_WRITE_STATUS FirstRead;
+ UINT32 TuningPatternSize;
+
+ DEBUG ((DEBUG_INFO, "EmmcRxHs400Tuning() Start\n"));
+
+ Status = EFI_SUCCESS;
+ ModeStatus = EFI_SUCCESS;
+
+ Smin = RX_STROBE_DLL1_TAP_MIN_MEPT;
+ Smax = RX_STROBE_DLL1_TAP_MAX_MEPT;
+ TuningPatternSize = BlockIo->Media->BlockSize * EMMC_HS400_TUNING_PATTERN_BLOCKS_NUMBER;
+
+ Buffer = (VOID *) AllocateZeroPool (TuningPatternSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // 1. Read Tuning Block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ TuningPatternSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcRxHs400Tuning: Tuning Blocks Read at HS200 Mode Failed!\n"));
+ goto Exit;
+ }
+
+ DEBUG_CODE ( EmmcPrintHs400TuningPattern (BlockIo, Buffer, TuningPatternSize); );
+
+ //
+ // 2. Move to HS400 Mode
+ //
+ Status = EmmcModeSelection (EmmcInfo, EmmcBaseAddress, Hs400);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcRxHs400Tuning: eMMC HS400 Mode Selection Failed!\n"));
+ goto Exit;
+ }
+ //
+ // 3. Set Rx Strobe DLL1 to the Minimal Expected Passing Tap (Smin)
+ // Offset 830h: Rx Strobe Delay DLL 1(HS400 Mode), bits [14:8]
+ // Set Rx Data Strobe DLL2 to middle point 0x13
+ // Offset 830h: Rx Strobe Delay DLL 2(HS400 Mode), bits [6:0]
+ DEBUG ((DEBUG_INFO, "EmmcRxHs400Tuning: Set Rx Data DLL1 to the Minimal Expected Passing Tap (Smin = 0x%x)\n", Smin));
+ DllCount = RX_STROBE_DLL1_TAP_MIN_MEPT;
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll1, DllCount);
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll2, DllCount);
+
+ //
+ // 4. Read the block that was stored
+ // 5. If CRC fails on first read, increase the DLL Step and repeat block read until passed
+ // Else if CRC passed on first read, decrease the DLL Step and repeat block read until failed
+ // 6. Store the Rx Path min DLL passing step number
+ //
+ FirstRead = NotAvailable;
+ DllMax = RX_STROBE_DLL1_TAP_MAX_RANGE;
+ DllMin = RX_STROBE_DLL1_TAP_MIN_RANGE;
+
+ while ((DllCount <= DllMax) && (DllCount >= DllMin)) {
+ DEBUG ((DEBUG_INFO, "[ EmmcRxHs400Tuning: Rx Min DLL1 (DllCount) = 0x%x ]\n", DllCount));
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ TuningPatternSize,
+ Buffer
+ );
+ if (Status == EFI_SUCCESS) {
+ if (FirstRead == NotAvailable) {
+ FirstRead = Passed;
+ } else if (FirstRead == Failed) {
+ Smin = DllCount;
+ break;
+ }
+ if (DllCount == RX_STROBE_DLL1_TAP_MIN_RANGE) {
+ Smin = RX_STROBE_DLL1_TAP_MIN_RANGE;
+ break;
+ }
+ } else if (Status == EFI_CRC_ERROR) { // Rely on the driver to return ReadBlocks status on CRC error
+ if (FirstRead == NotAvailable) {
+ FirstRead = Failed;
+ } else if (FirstRead == Passed) {
+ Smin = DllCount + 1;
+ break;
+ }
+ if (DllCount == RX_STROBE_DLL1_TAP_MAX_RANGE) {
+ Status = EFI_CRC_ERROR;
+ DEBUG ((DEBUG_ERROR, "[Rx DLL Tuning Failed] DllCount == TAP_MAX_RANGE\n"));
+ goto Exit;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "[Rx DLL Tuning Failed] Smin - Tuning Blocks Read Error!\n"));
+ goto Exit;
+ }
+
+ if (FirstRead == Failed) {
+ DllCount++;
+ } else {
+ DllCount--;
+ }
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll1, DllCount);
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll2, DllCount);
+ }
+
+ DEBUG ((DEBUG_INFO, "[Rx DLL Tuning] Found Minimal Passing Tap = 0x%x\n", Smin));
+
+ //
+ // 7. Set the Rx Strobe DLL1 to the Maximal Expected Passing Tap (Smax)
+ // Offset 830h: Rx Strobe Delay DLL 1(HS400 Mode), bits [14:8]
+ // 8. Read the block that was stored
+ // 9. If CRC fails on first read, decrease the DLL Step and repeat step 8 until pass
+ // Else if CRC passed on first read, increase the DLL Step and repeat step 8 until failed
+ //
+ DEBUG ((DEBUG_INFO, "EmmcRxHs400Tuning: Set Rx Data DLL1 to the Maximal Expected Passing Tap (Smax = 0x%x)\n", Smax));
+ DllCount = RX_STROBE_DLL1_TAP_MAX_MEPT;
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll1, DllCount);
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll2, DllCount);
+
+ FirstRead = NotAvailable;
+ DllMax = RX_STROBE_DLL1_TAP_MAX_RANGE;
+ DllMin = RX_STROBE_DLL1_TAP_MIN_RANGE;
+ while ((DllCount <= DllMax) && (DllCount >= DllMin)) {
+ DEBUG ((DEBUG_INFO, "[ EmmcRxHs400Tuning: Rx Max DLL1 (DllCount) = 0x%x ]\n", DllCount));
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ TuningPatternSize,
+ Buffer
+ );
+ if (Status == EFI_SUCCESS) {
+ if (FirstRead == NotAvailable) {
+ FirstRead = Passed;
+ } else if (FirstRead == Failed) {
+ Smax = DllCount;
+ break;
+ }
+ if (DllCount == RX_STROBE_DLL1_TAP_MAX_RANGE) {
+ Smax = DllCount;
+ break;
+ }
+ } else if (Status == EFI_CRC_ERROR) { // Rely on the driver to return ReadBlocks status on CRC error
+ if (FirstRead == NotAvailable) {
+ FirstRead = Failed;
+ } else if (FirstRead == Passed) {
+ Smax = DllCount - 1;
+ break;
+ }
+ if (DllCount == RX_STROBE_DLL1_TAP_MIN_RANGE) {
+ Status = EFI_CRC_ERROR;
+ goto Exit;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "[Rx DLL Tuning Failed] Smax - Tuning Blocks Read Error!\n"));
+ goto Exit;
+ }
+ if (FirstRead == Failed) {
+ DllCount--;
+ } else {
+ DllCount++;
+ }
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll1, DllCount);
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll2, DllCount);
+ }
+ //
+ // 10. Store the Rx Path max DLL Passing Step number
+ //
+
+ //
+ // 11. Compute the Rx DLL Optimal Point (Sopt) = (Smax - Smin)/2 + Smin
+ //
+ Sopt = (Smax - Smin) / 2 + Smin;
+ DEBUG ((DEBUG_INFO, "[Rx DLL Tuning] Optimal Point (Sopt = (Smax[0x%x] - Smin[0x%x]) / 2 + Smin[0x%x]) = 0x%x\n", Smax, Smin, Smin, Sopt));
+ //
+ // 12. Store the Rx DLL optimal value (Sopt)
+ //
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll1, Sopt);
+ EmmcSetRxDllCtrl (EmmcBaseAddress, RxDll2, Sopt);
+
+ DEBUG ((DEBUG_INFO, "[Rx HS400 Tuning Success] Rx Strobe Delay Control (830h) = 0x%08x\n",
+ MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_RX_STROBE_DLL_CNTL)));
+
+ Status = EFI_SUCCESS;
+ EmmcTuningData->Hs400RxStrobe1Dll = Sopt;
+
+Exit:
+ FreePool (Buffer);
+ DEBUG ((DEBUG_INFO, "EmmcRxHs400Tuning() End, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ To perform HS400 Tx Data Path Training
+
+ @param[in] EmmcInfo A pointer to EMMC_INFO structure
+ @param[in] EmmcBaseAddress Base address of MMIO register
+ @param[in] BlockIo A pointer to EFI_BLOCK_IO_PROTOCOL structure
+ @param[in/out] EmmcTuningData A pointer to EMMC_TUNING_DATA structure
+
+ @retval EFI_SUCCESS HS400 Rx Data Path Training is successful.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+ @retval EFI_CRC_ERROR Command or Data CRC Error
+**/
+EFI_STATUS
+EmmcTxHs400Tuning (
+ IN EMMC_INFO *EmmcInfo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UINTN EmmcBaseAddress,
+ IN OUT EMMC_TUNING_DATA *EmmcTuningData
+ )
+{
+ UINT8 *Buffer;
+ UINT8 DllCount;
+ UINT8 DllMax;
+ UINT8 DllMin;
+ UINT8 Smin;
+ UINT8 Smax;
+ UINT8 Sopt;
+ UINT8 N;
+ EFI_STATUS Status;
+ EFI_STATUS ModeStatus;
+ BLOCK_READ_WRITE_STATUS FirstWrite;
+
+ DEBUG ((DEBUG_INFO, "EmmcTxHs400Tuning() Start\n"));
+ Status = EFI_SUCCESS;
+ ModeStatus = EFI_SUCCESS;
+
+ Smin = TX_DATA_DLL_TAP_MIN_MEPT;
+ Smax = TX_DATA_DLL_TAP_MAX_MEPT;
+ N = 0;
+
+ Buffer = (VOID *) AllocateZeroPool (BlockIo->Media->BlockSize);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ //
+ // 1. Read Tuning Block that used at Rx HS400 Tuning
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcTxHs400Tuning: Tuning Block Read at HS400 Mode Failed!\n"));
+ goto Exit;
+ }
+ DEBUG_CODE ( EmmcPrintHs400TuningPattern (BlockIo, Buffer, BlockIo->Media->BlockSize); );
+
+ //
+ // 2. Set Tx Data DLL1 to the Minimal Expected Passing Tap (Smin)
+ // Offset 824h: Tx Data Delay Control 1
+ // Tx Data Delay (HS400 Mode), BIT[14:8]
+ //
+ DEBUG ((DEBUG_INFO, "EmmcTxHs400Tuning: Set Tx Data DLL to the Minimal Expected Passing Tap (Smin = 0x%x)\n", Smin));
+
+ DllCount = TX_DATA_DLL_TAP_MIN_MEPT;
+ EmmcSetTxDllCtrl1 (EmmcBaseAddress, DllCount);
+
+ //
+ // 2. Write Single Block
+ //
+ FirstWrite = NotAvailable;
+ DllMax = TX_DATA_DLL_TAP_MAX_RANGE;
+ DllMin = TX_DATA_DLL_TAP_MIN_RANGE;
+
+ while ((DllCount <= DllMax) && (DllCount >= DllMin)) {
+ DEBUG ((DEBUG_INFO, "[ EmmcTxHs400Tuning: Tx Min DLL (DllCount) = 0x%x ]\n", DllCount));
+ Status = BlockIo->WriteBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ if (Status == EFI_SUCCESS) {
+ if (FirstWrite == NotAvailable) {
+ FirstWrite = Passed;
+ } else if (FirstWrite == Failed) {
+ Smin = DllCount;
+ break;
+ }
+ if (DllCount == TX_DATA_DLL_TAP_MIN_RANGE) {
+ Smin = TX_DATA_DLL_TAP_MIN_RANGE;
+ break;
+ }
+ //
+ // 3. If CRC fails increment DLL Step and repeat step 2
+ //
+ } else if (Status == EFI_CRC_ERROR) { // Rely on the driver to return ReadBlocks status on CRC error
+ if (FirstWrite == NotAvailable) {
+ FirstWrite = Failed;
+ } else if (FirstWrite == Passed) {
+ Smin = DllCount + 1;
+ break;
+ }
+ if (DllCount == TX_DATA_DLL_TAP_MAX_RANGE) {
+ DEBUG ((DEBUG_ERROR, "[Tx DLL Tuning Failed] DllCount == TAP_MAX_RANGE\n"));
+ goto Exit;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "[Tx DLL Tuning Failed] Smin - Tuning Block Write Error!\n"));
+ goto Exit;
+ }
+ if (FirstWrite == Failed) {
+ DllCount++;
+ } else {
+ DllCount--;
+ }
+ EmmcSetTxDllCtrl1 (EmmcBaseAddress, DllCount);
+ }
+ //
+ // 4. Store the Tx Path min DLL passing step number
+ //
+ DEBUG ((DEBUG_INFO, "[Tx DLL Tuning] Found Minimal Passing Tap = 0x%x\n", Smin));
+
+ //
+ // 5. Set the DLL to max expected passing step (Smax)
+ //
+ DEBUG ((DEBUG_INFO, "EmmcTxHs400Tuning: Set Tx Data DLL to the Maximal Expected Passing Tap (Smax = 0x%x)\n", Smax));
+ DllCount = TX_DATA_DLL_TAP_MAX_MEPT;
+ EmmcSetTxDllCtrl1 (EmmcBaseAddress, DllCount);
+ //
+ // 6. Write Single Block
+ //
+ FirstWrite = NotAvailable;
+ DllMax = TX_DATA_DLL_TAP_MAX_RANGE;
+ DllMin = TX_DATA_DLL_TAP_MIN_RANGE;
+
+ while ((DllCount <= DllMax) && (DllCount >= DllMin)) {
+ DEBUG ((DEBUG_INFO, "[ EmmcTxHs400Tuning: Tx Max DLL1 (DllCount) = 0x%x ]\n", DllCount));
+ Status = BlockIo->WriteBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ EmmcInfo->Lba,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+
+ if (Status == EFI_SUCCESS) {
+ if (FirstWrite == NotAvailable) {
+ FirstWrite = Passed;
+ } else if (FirstWrite == Failed) {
+ Smax = DllCount;
+ break;
+ }
+ if (DllCount == TX_DATA_DLL_TAP_MAX_RANGE) {
+ Smax = TX_DATA_DLL_TAP_MAX_RANGE;
+ break;
+ }
+ //
+ // 7. If CRC fails decrement DLL Step and repeat step 6
+ //
+ } else if (Status == EFI_CRC_ERROR) { // Rely on the driver to return ReadBlocks status on CRC error
+ if (FirstWrite == NotAvailable) {
+ FirstWrite = Failed;
+ } else if (FirstWrite == Passed) {
+ Smax = DllCount - 1;
+ break;
+ }
+ if (DllCount == TX_DATA_DLL_TAP_MIN_RANGE) {
+ DEBUG ((DEBUG_ERROR, "[Tx DLL Tuning Failed] DllCount == TAP_MIN_RANGE\n"));
+ goto Exit;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "[Tx DLL Tuning Failed] Smax - Tuning Block Write Error!\n"));
+ goto Exit;
+ }
+ if (FirstWrite == Failed) {
+ DllCount--;
+ } else {
+ DllCount++;
+ }
+ EmmcSetTxDllCtrl1 (EmmcBaseAddress, DllCount);
+ }
+ //
+ // 8. Store the DLL passing step number (Smax)
+ //
+ DEBUG ((DEBUG_INFO, "[Tx DLL Tuning] Found Maximal Passing Tap = 0x%x\n", Smax));
+
+ N = Smax - Smin;
+ if (N <= 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 9. Compute the Tx DLL Optimal point (Sopt) = (Smax - Smin) / 2 + Smin
+ //
+ Sopt = (Smax - Smin) / 2 + Smin;
+ DEBUG ((DEBUG_INFO, "[Tx DLL Tuning] Optimal Point (Sopt = (Smax[0x%x] - Smin[0x%x]) / 2 + Smin[0x%x]) = 0x%x\n", Smax, Smin, Smin, Sopt));
+
+ //
+ // 10. Store the Tx Strobe DLL Optimal point value
+ //
+ EmmcSetTxDllCtrl1 (EmmcBaseAddress, Sopt);
+
+ DEBUG ((DEBUG_INFO, "[Tx HS400 Tuning Success] Tx Data Delay Control 1 (824h) = 0x%08x\n",
+ MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_TX_DATA_DLL_CNTL1)));
+
+ Status = EFI_SUCCESS;
+ EmmcTuningData->Hs400TxDataDll = Sopt;
+
+Exit:
+ FreePool (Buffer);
+ DEBUG ((DEBUG_INFO, "EmmcTxHs400Tuning() End, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ To perform write protection checking on the address to write
+
+ @param[in] EmmcInfo A pointer to EMMC_INFO structure
+ @param[in] BlockIo A pointer to EFI_BLOCK_IO_PROTOCOL structure
+ @param[in] EmmcBaseAddress Base address of MMIO register
+
+ @retval EFI_SUCCESS HS400 Rx Data Path Training is successful.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+ @retval EFI_CRC_ERROR Command or Data CRC Error
+**/
+EFI_STATUS
+EmmcWriteProtectCheck (
+ IN EMMC_INFO *EmmcInfo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UINTN EmmcBaseAddress
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DataSize;
+ UINT32 CardStatus;
+ UINT32 Address;
+ UINT32 Timeout;
+ UINT16 CommandIndex;
+ UINT8 *Buffer;
+
+ Status = EFI_SUCCESS;
+ DataSize = 8;
+ CommandIndex = SEND_WRITE_PROT_TYPE;
+ Timeout = TIMEOUT_DATA;
+
+ Buffer = (VOID *) AllocateZeroPool (DataSize);
+ Address = (UINT32) DivU64x32 (MultU64x32 (EmmcInfo->Lba, BlockIo->Media->BlockSize), 512);
+
+ DEBUG ((DEBUG_INFO, "EmmcWriteProtectCheck() Start\n"));
+
+ if (BlockIo->Media->ReadOnly == TRUE) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Exit;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ Status = EmmcSendCommand (
+ EmmcBaseAddress,
+ CommandIndex,
+ Address,
+ InData,
+ Buffer,
+ DataSize,
+ ResponseR1,
+ Timeout,
+ &CardStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((Buffer[7] & (BIT0 | BIT1)) !=0) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Exit;
+ }
+
+Exit:
+ FreePool (Buffer);
+ DEBUG ((DEBUG_INFO, "EmmcWriteProtectCheck End, Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ Configure eMMC in HS400 Mode
+
+ @param[in] This A pointer to PCH_EMMC_TUNING_PROTOCOL structure
+ @param[in] Revision Revision parameter used to verify the layout of EMMC_INFO and TUNINGDATA.
+ @param[in] EmmcInfo A pointer to EMMC_INFO structure
+ @param[out] EmmcTuningData A pointer to EMMC_TUNING_DATA structure
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_NOT_FOUND The item was not found
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER A parameter was incorrect.
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+ @retval EFI_CRC_ERROR Command or Data CRC Error
+**/
+EFI_STATUS
+EFIAPI
+ConfigureEmmcHs400Mode (
+ IN PCH_EMMC_TUNING_PROTOCOL *This,
+ IN UINT8 Revision,
+ IN EMMC_INFO *EmmcInfo,
+ OUT EMMC_TUNING_DATA *EmmcTuningData
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_STATUS Status;
+ EFI_STATUS ModeStatus;
+ UINTN EmmcBaseAddress;
+ UINTN EmmcPciBaseAddress;
+ ModeStatus = EFI_SUCCESS;
+
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode() Start\n"));
+ EmmcTuningData->Hs400DataValid = FALSE;
+ //
+ // Check PCH_EMMC_TUNING_PROTOCOL_REVISION
+ //
+ if (Revision != PCH_EMMC_TUNING_PROTOCOL_REVISION) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: PCH eMMC Tuning Protocol Revision Not Match! Tuning Aborted\n"));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get eMMC Host Controller Mmio base register
+ //
+ EmmcPciBaseAddress = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SCS_EMMC,
+ PCI_FUNCTION_NUMBER_PCH_SCS_EMMC
+ );
+
+ if (MmioRead16 (EmmcPciBaseAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: eMMC Host Controller Unavailable!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Assume BAR is ready since it's executed after blockio ready, handling 64bit BAR in DXE is not required
+ //
+ EmmcBaseAddress = MmioRead32 (EmmcPciBaseAddress + PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFF000;
+ //
+ // Enable Memory Decode
+ //
+ if ((MmioRead8 (EmmcPciBaseAddress + PCI_COMMAND_OFFSET) & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
+ MmioOr8 (EmmcPciBaseAddress + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+ }
+
+ DEBUG ((DEBUG_INFO, "Initial HS400 DLL values (set in PEI):\n"));
+ DEBUG ((DEBUG_INFO, "Tx Data Delay Control 1 (824h) = 0x%08x\n", MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_TX_DATA_DLL_CNTL1)));
+ DEBUG ((DEBUG_INFO, "Rx Strobe Delay Control (830h) = 0x%08x\n", MmioRead32 (EmmcBaseAddress + R_PCH_SCS_DEV_MEM_RX_STROBE_DLL_CNTL)));
+
+ if (mPchConfigHob->Scs.ScsEmmcHs400TuningRequired == FALSE) {
+ if (mPchConfigHob->Scs.ScsEmmcHs400DllDataValid == TRUE) {
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode: SCS eMMC 5.0 HS400 Tuning Not Required, set device to HS400 mode\n"));
+ Status = EmmcModeSelection (EmmcInfo, EmmcBaseAddress, Hs400);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: eMMC HS400 Mode Selection Failed!\n"));
+ }
+ return Status;
+ } else {
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode: SCS eMMC 5.0 HS400 Mode Selection Not Required.\n"));
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Handle Platform Emmc Info Protocol for Efi Block Io Protocol
+ //
+ Status = gBS->HandleProtocol (
+ EmmcInfo->PartitionHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID**) &BlockIo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: BlockIo: Platform Emmc Info Protocol Handle Not Found!\n"));
+ EmmcHostHs400Disabled (EmmcBaseAddress);
+ return Status;
+ }
+
+ //
+ // Write Protection checking on the region
+ //
+ Status = EmmcWriteProtectCheck (EmmcInfo, BlockIo, EmmcBaseAddress);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: Region is write protected! HS400 Tuning Abort!\n"));
+ EmmcHostHs400Disabled (EmmcBaseAddress);
+ return Status;
+ }
+
+ Status = EmmcWriteHs400TuningPattern (EmmcInfo, BlockIo, EmmcBaseAddress, (UINT8*)EmmcWorstCasePattern);
+
+ //
+ // Rx HS400 Auto Tuning
+ //
+ Status = EmmcRxHs400Tuning (EmmcInfo, BlockIo, EmmcBaseAddress, EmmcTuningData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: Rx HS400 Auto Tuning Failed!\n"));
+ ModeStatus = EmmcModeSelection (EmmcInfo, EmmcBaseAddress, Hs200);
+ if (EFI_ERROR (ModeStatus)) {
+ DEBUG ((DEBUG_ERROR, "EmmcTxHs400Tuning: eMMC HS200 Mode Selection Failed!\n"));
+ }
+ EmmcTuningData->Hs400DataValid = FALSE;
+ return Status;
+ }
+
+ //
+ // Tx HS400 Auto Tuning
+ //
+ Status = EmmcTxHs400Tuning (EmmcInfo, BlockIo, EmmcBaseAddress, EmmcTuningData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ConfigureEmmcHs400Mode: Tx HS400 Auto Tuning Failed!\n"));
+ ModeStatus = EmmcModeSelection (EmmcInfo, EmmcBaseAddress, Hs200);
+ if (EFI_ERROR (ModeStatus)) {
+ DEBUG ((DEBUG_ERROR, "EmmcTxHs400Tuning: eMMC HS200 Mode Selection Failed!\n"));
+ }
+ EmmcTuningData->Hs400DataValid = FALSE;
+ return Status;
+ }
+
+ //
+ // Set current HS400 Driver Strength in tuning data structre
+ // Set HS400 Data Valid Tuning Bit to TRUE
+ //
+ EmmcTuningData->Hs400DriverStrength = (UINT8) mPchConfigHob->Scs.ScsEmmcHs400DriverStrength;
+ EmmcTuningData->Hs400DataValid = TRUE;
+
+ DEBUG ((DEBUG_INFO, "ConfigureEmmcHs400Mode() End\n"));
+ return Status;
+}
+
+/**
+ Install PCH EMMC TUNING PROTOCOL
+
+**/
+VOID
+InstallPchEmmcTuningProtocol (
+ VOID
+ )
+{
+
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ Handle = NULL;
+
+ ///
+ /// For normal boot flow
+ /// 1. If ScsEmmcEnabled and ScsEmmcHs400Enabled policy set,
+ /// a) Set ScsEmmcHs400TuningRequired policy to state tuning required in PEI,
+ /// - if RTC_PWR_STS bit is set which indicates a new coin-cell battery insertion, a battery failure or CMOS clear.(Boot with default settings)
+ /// - if non-volatile variable 'Hs400TuningData' does not exist
+ /// b) RC installed Pch Emmc Tuning Protocol regardless of ScsEmmcHs400TuningRequired policy setting.in DXE
+ /// c) If boot with default settings after CMOS cleared, platform delete variable 'Hs400TuningData' in DXE
+ /// 2. Once RC successfully installed Pch Emmc Tuning Protocol, it will be used to perform EmmcTune for Hs400.
+ /// 3. Then, platform must set the variable with returned EmmcTuningData no matter tuning pass of fail
+ /// 4. Platform shall set variable 'Hs400TuningData' for one time only or after CMOS clear
+ ///
+ /// For fast boot flow
+ /// 1. If ScsEmmcEnabled and ScsEmmcHs400Enabled policy set,
+ /// a) Set ScsEmmcHs400TuningRequired policy to state tuning not required, if non-volatile variable 'Hs400TuningData' exist
+ /// b) RC installed Pch Emmc Tuning Protocol regardless of ScsEmmcHs400TuningRequired policy setting in DXE
+ /// 2. Once RC successfully installed Pch Emmc Tuning Protocol, it will be used to perform EmmcTune
+ /// 3. Since ScsEmmcHs400TuningRequired state tuning not required, RC will not perform Emmc Hs400 Tuning but just set the device to operate in HS400 mode if data is valid
+ /// 4. Platform shall not set variable 'Hs400TuningData'
+ ///
+ //
+ // Install PchEmmcTuningProtocol Protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gPchEmmcTuningProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &PchEmmcTuningProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
new file mode 100644
index 0000000000..013c729ddf
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
@@ -0,0 +1,49 @@
+/** @file
+ Initializes Serial IO Controllers.
+
+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 <PchInit.h>
+#include <Library/PchSerialIoLib.h>
+
+
+/**
+ Puts all SerialIo controllers (except UARTs in debug mode) in D3
+ Clears MemoryEnable for all PCI-mode controllers
+**/
+EFI_STATUS
+ConfigureSerialIoAtBoot (
+ VOID
+ )
+{
+ PCH_SERIAL_IO_CONTROLLER Index;
+ UINTN PciCfgBase;
+
+ for (Index = 0; Index < PchSerialIoIndexMax; Index++) {
+ if ((mPchConfigHob->SerialIo.DevMode[Index] == PchSerialIoDisabled) ||
+ (mPchConfigHob->SerialIo.DevMode[Index] == PchSerialIoSkipInit) ) {
+ continue;
+ }
+ if ((Index >= PchSerialIoIndexUart0) &&
+ (mPchConfigHob->SerialIo.EnableDebugUartAfterPost) &&
+ (mPchConfigHob->SerialIo.DebugUartNumber == (UINT32) (Index - PchSerialIoIndexUart0))) {
+ continue;
+ }
+ PciCfgBase = FindSerialIoBar (Index,1);
+ MmioOr32 (PciCfgBase + R_PCH_SERIAL_IO_PME_CTRL_STS, B_PCH_SERIAL_IO_PME_CTRL_STS_PWR_ST);
+ MmioRead32 (PciCfgBase + R_PCH_SERIAL_IO_PME_CTRL_STS);
+ if (mPchConfigHob->SerialIo.DevMode[Index] == PchSerialIoPci) {
+ MmioAnd32 (PciCfgBase + PCI_COMMAND_OFFSET, (UINT32)~(EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER) );
+ }
+ }
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
new file mode 100644
index 0000000000..3b951092b5
--- /dev/null
+++ b/Silicon/Intel/KabylakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
@@ -0,0 +1,112 @@
+/** @file
+ Initializes Serial IO Controllers.
+
+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 <PchInit.h>
+#include <Library/PchSerialIoLib.h>
+#include <Library/DevicePathLib.h>
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH RootPort;
+ ACPI_EXTENDED_HID_DEVICE_PATH AcpiDev;
+ CHAR8 HidString[8];
+ CHAR8 UidString;
+ CHAR8 CidString;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} SERIALIO_DEVICE_PATH;
+
+#define gPciRootBridge {{ACPI_DEVICE_PATH, ACPI_DP, {(UINT8)(sizeof(ACPI_HID_DEVICE_PATH)), 0}}, EISA_PNP_ID (0x0A03), 0}
+#define gAcpiDev {{ACPI_DEVICE_PATH,ACPI_EXTENDED_DP,{(UINT8)(sizeof(ACPI_EXTENDED_HID_DEVICE_PATH)+SERIALIO_TOTAL_ID_LENGTH),0}},0,0,0}
+#define gEndEntire {END_DEVICE_PATH_TYPE,END_ENTIRE_DEVICE_PATH_SUBTYPE,{END_DEVICE_PATH_LENGTH,0}}
+
+GLOBAL_REMOVE_IF_UNREFERENCED SERIALIO_DEVICE_PATH gSerialIoPath = {
+ gPciRootBridge,
+ gAcpiDev,
+ "\0\0\0\0\0\0\0",
+ '\0',
+ '\0',
+ gEndEntire
+};
+
+/**
+Mark memory used by SerialIo devices in ACPI mode as allocated
+
+@retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+AllocateSerialIoMemory (
+ VOID
+ )
+{
+ PCH_SERIAL_IO_CONTROLLER i;
+ UINT8 BarNumber;
+ UINTN Bar;
+ EFI_STATUS Status;
+
+ for (i=0; i<PchSerialIoIndexMax; i++) {
+ if (mPchConfigHob->SerialIo.DevMode[i] == PchSerialIoAcpiHidden ||
+ mPchConfigHob->SerialIo.DevMode[i] == PchSerialIoLegacyUart ||
+ mPchConfigHob->SerialIo.DevMode[i] == PchSerialIoAcpi) {
+ for (BarNumber = 0; BarNumber<=1; BarNumber++) {
+ Bar = FindSerialIoBar (i,BarNumber);
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeReserved,
+ Bar,
+ V_PCH_SERIAL_IO_BAR_SIZE,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeReserved,
+ N_PCH_SERIAL_IO_BAR_ALIGNMENT,
+ V_PCH_SERIAL_IO_BAR_SIZE,
+ &Bar,
+ mImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+VOID
+CreateSerialIoHandles (
+ VOID
+ )
+{
+ EFI_HANDLE NewHandle;
+ EFI_DEVICE_PATH_PROTOCOL *NewPath;
+ EFI_STATUS Status;
+ UINT32 Controller;
+
+ for (Controller = 0; Controller < PchSerialIoIndexMax; Controller++) {
+ if (mPchConfigHob->SerialIo.DevMode[Controller] == PchSerialIoAcpi) {
+ NewHandle = NULL;
+ CopyMem (gSerialIoPath.HidString, GetSerialIoAcpiHID (Controller), SERIALIO_HID_LENGTH);
+ NewPath = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&gSerialIoPath);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &NewHandle,
+ &gEfiDevicePathProtocolGuid,
+ NewPath,
+ NULL );
+ }
+ }
+}
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