From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.100, mailfrom: michael.a.kubacki@intel.com) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by groups.io with SMTP; Fri, 16 Aug 2019 17:17:09 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Aug 2019 17:16:56 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,395,1559545200"; d="scan'208";a="182319315" Received: from makuback-desk1.amr.corp.intel.com ([10.7.159.162]) by orsmga006.jf.intel.com with ESMTP; 16 Aug 2019 17:16:55 -0700 From: "Kubacki, Michael A" To: devel@edk2.groups.io Cc: Sai Chaganty , Chasel Chiu , Nate DeSimone , Liming Gao , Michael D Kinney , Ankit Sinha Subject: [edk2-platforms][PATCH V1 26/37] CoffeelakeSiliconPkg/Pch: Add modules Date: Fri, 16 Aug 2019 17:15:52 -0700 Message-Id: <20190817001603.30632-27-michael.a.kubacki@intel.com> X-Mailer: git-send-email 2.16.2.windows.1 In-Reply-To: <20190817001603.30632-1-michael.a.kubacki@intel.com> References: <20190817001603.30632-1-michael.a.kubacki@intel.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2082 * PchInitDxeCnl - Generic DXE PCH initialization. * PchInitDxeFspCnl - Generic DXE PCH FSP initialization. * PchInitSmm - Generic SMM PCH initialization. * SmmControl - Produces an instance of EFI_SMM_CONTROL2_PROTOCOL. Cc: Sai Chaganty Cc: Chasel Chiu Cc: Nate DeSimone Cc: Liming Gao Cc: Michael D Kinney Cc: Ankit Sinha Signed-off-by: Michael Kubacki --- Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeCnl.inf | 99 ++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFspCnl.inf | 77 +++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf | 101 ++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf | 54 ++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpiSmm.inf | 45 ++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h | 223 ++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h | 187 +++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h | 132 +++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c | 451 ++++++++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c | 33 ++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c | 323 ++++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c | 554 ++++++++++++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c | 382 ++++++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c | 85 +++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c | 89 ++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c | 57 ++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c | 156 ++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c | 156 ++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c | 179 +++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c | 298 +++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c | 436 +++++++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c | 69 +++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c | 399 ++++++++++++++ Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpi.c | 310 +++++++++++ 24 files changed, 4895 insertions(+) diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeCnl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeCnl.inf new file mode 100644 index 0000000000..5e0cf06cb6 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeCnl.inf @@ -0,0 +1,99 @@ +## @file +# Component description file for Pch Initialization driver +# +# Copyright (c) 2019 Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 +PchPcrLib +PchInfoLib +PchPciExpressHelpersLib +UefiBootServicesTableLib +DebugLib +IoLib +TimerLib +HobLib +BaseMemoryLib +MemoryAllocationLib +UefiLib +DxeServicesTableLib +UefiDriverEntryPoint +UefiRuntimeServicesTableLib +AslUpdateLib +CpuPlatformLib +GpioLib +PchSerialIoLib +PchHdaLib +PchInitCommonLib +ConfigBlockLib +PmcLib +PmcPrivateLib +PmcPrivateLibWithS3 +SataLib +PchDmiWithS3Lib +PchGbeLib +SiScheduleResetLib +BiosLockLib +DxeSaPolicyLib + + +[Packages] +MdePkg/MdePkg.dec +CoffeelakeSiliconPkg/SiPkg.dec + + +[Pcd] +gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr + + +[Sources] +PchInitDxe.c +PchInit.h +PchInit.c +PchSata.c +PchSerialIo.c +PchSerialIoDxe.c +PchHdaAcpi.c +PchCnviAcpi.c +PchAcpi.c + +[Protocols] +gPchNvsAreaProtocolGuid ## PRODUCES +gPchEmmcTuningProtocolGuid ## PRODUCES +gEfiPciIoProtocolGuid ## CONSUMES +gEfiAcpiTableProtocolGuid ## CONSUMES +gEfiBlockIoProtocolGuid ## CONSUMES +gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES +gPchPcieIoTrapProtocolGuid ## CONSUMES +gPchPolicyProtocolGuid ## CONSUMES + + +[Guids] +gEfiEndOfDxeEventGroupGuid +gEfiAcpiTableGuid +gSiConfigHobGuid ## CONSUMES +gPchConfigHobGuid ## CONSUMES +gPchRstHobGuid ## CONSUMES +gHdAudioDxeConfigGuid ## CONSUMES +gGpioDxeConfigGuid ## 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/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFspCnl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFspCnl.inf new file mode 100644 index 0000000000..528cfd0296 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeFspCnl.inf @@ -0,0 +1,77 @@ +## @file +# Component description file for Pch Initialization driver for FSP package +# +# Copyright (c) 2019 Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 +PchPcrLib +PchInfoLib +PchPciExpressHelpersLib +DebugLib +IoLib +TimerLib +HobLib +BaseMemoryLib +MemoryAllocationLib +CpuPlatformLib +GpioLib +PchSerialIoLib +PchInitCommonLib +S3BootScriptLib # NULL library +ConfigBlockLib +PmcLib +PmcPrivateLib +PmcPrivateLibWithS3 +UsbInitLib +PchDmiWithS3Lib +PchGbeLib +SiScheduleResetLib +BiosLockLib + + +[Packages] +MdePkg/MdePkg.dec +CoffeelakeSiliconPkg/SiPkg.dec + + +[Pcd] +gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + + +[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/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf new file mode 100644 index 0000000000..308da65385 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf @@ -0,0 +1,101 @@ +## @file +# Component description file for PchInitSmm driver +# +# Copyright (c) 2019 Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PchInitSmm +FILE_GUID = D7B10D4E-67E6-4C74-83E9-F9AF0ACC33CC +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_SMM_DRIVER +PI_SPECIFICATION_VERSION = 1.10 +ENTRY_POINT = PchInitSmmEntryPoint +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + + +[LibraryClasses] +UefiBootServicesTableLib +UefiDriverEntryPoint +DxeServicesTableLib +IoLib +DebugLib +BaseLib +BaseMemoryLib +S3BootScriptLib +PchPciExpressHelpersLib +SmmServicesTableLib +PciSegmentLib +HobLib +GpioLib +GpioPrivateLib +ReportStatusCodeLib +DevicePathLib +PmcLib +PchPcieRpLib +PchInfoLib +TimerLib +ConfigBlockLib +PmcPrivateLib +SataLib + +[Packages] +MdePkg/MdePkg.dec +CoffeelakeSiliconPkg/SiPkg.dec + + +[Pcd] +gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMin +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMax +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemSize + + +[Sources] +PchInitSmm.c +PchPcieSmm.c +PchLanSxSmm.c +PchInitSmm.h +PchBiosWriteProtect.c +PchSpiAsync.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/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf new file mode 100644 index 0000000000..ff712f8635 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl.inf @@ -0,0 +1,54 @@ +## @file +# Component description file for SmmControl module +# +# Copyright (c) 2019 Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = SmmControl +FILE_GUID = A0BAD9F7-AB78-491b-B583-C52B7F84B9E0 +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_RUNTIME_DRIVER +ENTRY_POINT = SmmControlDriverEntryInit +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + + + +[LibraryClasses] +IoLib +UefiDriverEntryPoint +DebugLib +UefiBootServicesTableLib +UefiRuntimeServicesTableLib +PmcLib +GpioLib + + +[Packages] +MdePkg/MdePkg.dec +CoffeelakeSiliconPkg/SiPkg.dec + + +[Sources] +SmmControlDriver.h +SmmControlDriver.c + + +[Protocols] +gEfiSmmControl2ProtocolGuid ## PRODUCES + + +[Guids] +gEfiEventVirtualAddressChangeGuid + + +[Depex] +TRUE diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpiSmm.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpiSmm.inf new file mode 100644 index 0000000000..77bd3ad72b --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpiSmm.inf @@ -0,0 +1,45 @@ +## @file +# Component description file for the SPI SMM driver. +# +# Copyright (c) 2019 Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] +INF_VERSION = 0x00010017 +BASE_NAME = PchSpiSmm +FILE_GUID = 27F4917B-A707-4aad-9676-26DF168CBF0D +VERSION_STRING = 1.0 +MODULE_TYPE = DXE_SMM_DRIVER +PI_SPECIFICATION_VERSION = 1.10 +ENTRY_POINT = InstallPchSpi + + +[LibraryClasses] +DebugLib +IoLib +UefiDriverEntryPoint +UefiBootServicesTableLib +BaseLib +SmmServicesTableLib +PchSpiCommonLib +SmmPchPrivateLib + +[Packages] +MdePkg/MdePkg.dec +CoffeelakeSiliconPkg/SiPkg.dec + + +[Sources] +PchSpi.c + + +[Protocols] +gPchSmmSpiProtocolGuid ## PRODUCES +gEfiSmmCpuProtocolGuid ## CONSUMES + +[Depex] +gEfiSmmBase2ProtocolGuid AND # This is for SmmServicesTableLib +gEfiSmmCpuProtocolGuid # This is for CpuSmmDisableBiosWriteProtect() diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h new file mode 100644 index 0000000000..b84c574a2e --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h @@ -0,0 +1,223 @@ +/** @file + Header file for PCH Initialization Driver. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCH_INIT_DXE_H_ +#define _PCH_INIT_DXE_H_ + +#include +#include +#include +#include + +// +// Data definitions +// +extern EFI_HANDLE mImageHandle; + +// +// Pch NVS area definition +// +extern PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol; + +extern PCH_CONFIG_HOB *mPchConfigHob; +extern SI_CONFIG_HOB_DATA *mSiConfigHobData; + +// +// Function Prototype +// + +// +// Local function prototypes +// +/** + 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 + ); + +/** + Puts all SerialIo controllers (except UARTs in debug mode) in D3. + Clears MemoryEnable for all PCI-mode controllers on S3 resume +**/ +VOID +ConfigureSerialIoAtS3Resume ( + 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 + ); + +/** + Get eMMC PCI cfg space address + + @return UINT64 PCI base address +**/ +UINT64 +ScsGetEmmcBaseAddress ( + 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 CNVI Device. + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +UpdateCnviAcpiData ( + VOID + ); + +/** + Initialize Pch acpi + @param[in] ImageHandle Handle for the image of this driver + + @retval EFI_SUCCESS The function completed successfully + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver +**/ +EFI_STATUS +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. + +**/ +VOID +PatchPchNvsAreaAddress ( + VOID + ); + +#endif // _PCH_INIT_DXE_H_ diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h new file mode 100644 index 0000000000..693c5d3f50 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h @@ -0,0 +1,187 @@ +/** @file + Header file for PCH Init SMM Handler + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCH_INIT_SMM_H_ +#define _PCH_INIT_SMM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap; +extern EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch; + +extern PCH_NVS_AREA *mPchNvsArea; +extern UINT16 mAcpiBaseAddr; + +extern EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr; +extern UINTN mResvMmioSize; + +// +// NOTE: The module variables of policy here are only valid in post time, but not runtime time. +// +extern PCH_CONFIG_HOB *mPchConfigHob; +extern SI_CONFIG_HOB_DATA *mSiConfigHobData; + +/** + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling + + @param[in] ImageHandle The image handle of this module + @param[in] SystemTable The EFI System Table + + @retval EFI_SUCCESS The function completes successfully +**/ +EFI_STATUS +EFIAPI +InitializePchPcieSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + PCIE Hotplug SMI call back function for each Root port + + @param[in] DispatchHandle Handle of this dispatch function + @param[in] RpContext Rootport context, which contains RootPort Index, + and RootPort PCI BDF. +**/ +VOID +EFIAPI +PchPcieSmiRpHandlerFunction ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ); + +/** + PCIE Link Active State Change Hotplug SMI call back function for all Root ports + + @param[in] DispatchHandle Handle of this dispatch function + @param[in] RpContext Rootport context, which contains RootPort Index, + and RootPort PCI BDF. +**/ +VOID +EFIAPI +PchPcieLinkActiveStateChange ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ); + +/** + PCIE Link Equalization Request SMI call back function for all Root ports + + @param[in] DispatchHandle Handle of this dispatch function + @param[in] RpContext Rootport context, which contains RootPort Index, + and RootPort PCI BDF. +**/ +VOID +EFIAPI +PchPcieLinkEqHandlerFunction ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ); + +/** + An IoTrap callback to config PCIE power management settings + + @param[in] DispatchHandle - The handle of this callback, obtained when registering + @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT + +**/ +VOID +EFIAPI +PchPcieIoTrapSmiCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ); + +/** + Initializes the PCH SMM handler for PCH save and restore + + @param[in] ImageHandle - Handle for the image of this driver + @param[in] SystemTable - Pointer to the EFI System Table + + @retval EFI_SUCCESS - PCH SMM handler was installed +**/ +EFI_STATUS +EFIAPI +PchInitLateSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + 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/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h new file mode 100644 index 0000000000..08e64fa5a7 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.h @@ -0,0 +1,132 @@ +/** @file + Header file for SMM Control Driver. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _SMM_CONTROL_DRIVER_H_ +#define _SMM_CONTROL_DRIVER_H_ + +#include + + +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', '4', 's', 'c') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SMM_CONTROL2_PROTOCOL SmmControl; +} SMM_CONTROL_PRIVATE_DATA; + +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, SMM_CONTROL_PRIVATE_DATA, SmmControl, SMM_CONTROL_DEV_SIGNATURE) + +// +// Prototypes +// + +/** + SmmControl DXE RUNTIME Module Entry Point\n + - Introduction\n + The SmmControl module is a DXE RUNTIME driver that provides a standard way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been programmed. + If SmmControl Runtime DXE driver is run before Status Code Runtime Protocol + is installed and there is the need to use Status code in the driver, it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM Control Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Trigger the software SMI + + @param[in] Data The value to be set on the software SMI data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + UINT8 Data + ); + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ); + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in, out] ArgumentBuffer The buffer of argument + @param[in, out] ArgumentBufferSize The size of the argument buffer + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN OUT UINT8 *ArgumentBuffer OPTIONAL, + IN OUT UINT8 *ArgumentBufferSize OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ); + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ); +/** + Disable all pending SMIs + +**/ +VOID +EFIAPI +DisablePendingSmis ( + VOID + ); + +#endif diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c new file mode 100644 index 0000000000..bcbdb12dc3 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c @@ -0,0 +1,451 @@ +/** @file + This is the driver that initializes the Intel PCH. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include "PchInit.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Module variables +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol; + +/** + 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 < GetPchMaxSerialIoControllersNum (); Index++) { + mPchNvsAreaProtocol.Area->SMD[Index] = mPchConfigHob->SerialIo.DevMode[Index]; + mPchNvsAreaProtocol.Area->SIR[Index] = (GetInterruptPolicy (Index)).Irq; + mPchNvsAreaProtocol.Area->SB0[Index] = (UINT32) FindSerialIoBar (Index, 0); + mPchNvsAreaProtocol.Area->SB1[Index] = (UINT32) FindSerialIoBar (Index, 1); + } + if (IsPchH ()) { + mPchNvsAreaProtocol.Area->SMD[PchSerialIoIndexI2C4] = PchSerialIoDisabled; + mPchNvsAreaProtocol.Area->SMD[PchSerialIoIndexI2C5] = PchSerialIoDisabled; + } + + return EFI_SUCCESS; +} + +/** + Update NVS Area after RST PCIe Storage Remapping and before Boot +**/ +VOID +PchUpdateNvsAreaAfterRemapping ( + VOID + ) +{ + UINTN Index; + VOID *Hob; + PCH_RST_HOB *RstHob; + + Hob = GetFirstGuidHob (&gPchRstHobGuid); + if (Hob == NULL) { + DEBUG (( DEBUG_INFO , "PchUpdateNvsAreaAfterRemapping: cannot fetch RstHob" )); + return; + } + + RstHob = (PCH_RST_HOB *) GET_GUID_HOB_DATA (Hob); + + for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) { + mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index] = RstHob->RstCrConfiguration[Index].DeviceInterface; + mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].PmCapPtr; + mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].PcieCapPtr; + mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].L1ssCapPtr; + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl2; + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl1; + mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].LtrCapPtr; + mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLtrData; + mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLctlData16; + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctlData16; + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctl2Data16; + mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index] = RstHob->SavedRemapedDeviceConfigSpace[Index].RootPortDctl2Data16; + mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index] = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBar; + mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBarValue[Index] = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBarValue; + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index] = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBar; + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index] = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBarValue; + mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index] = RstHob->RstCrConfiguration[Index].RootPortNum; + } +} + +/** + 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 + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n")); + + /// + /// Closed the event to avoid call twice when launch shell + /// + gBS->CloseEvent (Event); + + // + // Init HDA Audio ACPI tables + // + PchHdAudioAcpiInit (); + + // + // Update ASL definitions for SerialIo devices. + // + UpdateSerialIoAcpiData (); + UpdateCnviAcpiData (); + + // + // Update Pch Nvs Area + // + Status = PchUpdateNvsArea (); + if (EFI_ERROR (Status)) { + return; + } + + 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 +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; +} + +/** + Update ASL object before Boot + + @retval EFI_STATUS + @retval EFI_NOT_READY The Acpi protocols are not ready. +**/ +EFI_STATUS +PchUpdateNvsArea ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT32 HpetBaseAdress; + GPIO_GROUP GroupToGpeDwX[3]; + UINT32 GroupDw[3]; + UINTN RpDev; + UINTN RpFun; + UINT32 Data32; + PCH_POLICY_PROTOCOL *PchPolicy; + PCH_GPIO_DXE_CONFIG *GpioDxeConfig; + + /// + /// Get PCH Policy Protocol + /// + Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)&PchPolicy); + ASSERT_EFI_ERROR (Status); + + /// + /// Get GPIO DXE Config Block + /// + Status = GetConfigBlock ((VOID *)PchPolicy, &gGpioDxeConfigGuid, (VOID *)&GpioDxeConfig); + ASSERT_EFI_ERROR (Status); + + // + // Update ASL PCIE port address according to root port device and function + // + for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) { + 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 = PchSeries (); + // + // Update PCHG. + // + mPchNvsAreaProtocol.Area->PchGeneration = (UINT16) PchGeneration (); + // + // Update PSTP. + // + mPchNvsAreaProtocol.Area->PchStepping = (UINT16) PchStepping (); + // + // Update HPET base address. + // + PchHpetBaseGet (&HpetBaseAdress); + mPchNvsAreaProtocol.Area->HPTE = TRUE; // @todo remove the NVS, since it's always enabled. + mPchNvsAreaProtocol.Area->HPTB = HpetBaseAdress; + // + // Update SBREG_BAR. + // + mPchNvsAreaProtocol.Area->SBRG = PCH_PCR_BASE_ADDRESS; + + // + // Update PMC ACPIBASE and PWRMBASE + // + mPchNvsAreaProtocol.Area->PMBS = PmcGetAcpiBase (); + + mPchNvsAreaProtocol.Area->PWRM = PmcGetPwrmBase (); + + // + // Update GPIO device ACPI variables + // + mPchNvsAreaProtocol.Area->SGIR = mPchConfigHob->Interrupt.GpioIrqRoute; + mPchNvsAreaProtocol.Area->GPHD = (UINT8)GpioDxeConfig->HideGpioAcpiDevice; + + // + // Update GPP_X to GPE_DWX mapping. + // + GpioGetGroupDwToGpeDwX ( + &GroupToGpeDwX[0], &GroupDw[0], + &GroupToGpeDwX[1], &GroupDw[1], + &GroupToGpeDwX[2], &GroupDw[2] + ); + + // + // GEI0/1/2 and GED0/1/2 are objects for informing how GPIO groups are mapped to GPE0. + // If Group is mapped to 1-Tier GPE information is also stored on what Group DW + // is mapped to GPE_DWx. Because GPE_DWx register is 32 bits large if groups have more than + // 32 pads only part of it can be mapped. + // + // GEIx - GroupIndex mapped to GPE0_DWx + // GEDx - DoubleWorld part of Group: 0 - pins 31-0, 1 - pins 63-32, ... + // + mPchNvsAreaProtocol.Area->GEI0 = (UINT8) GpioGetGroupIndexFromGroup (GroupToGpeDwX[0]); + mPchNvsAreaProtocol.Area->GEI1 = (UINT8) GpioGetGroupIndexFromGroup (GroupToGpeDwX[1]); + mPchNvsAreaProtocol.Area->GEI2 = (UINT8) GpioGetGroupIndexFromGroup (GroupToGpeDwX[2]); + mPchNvsAreaProtocol.Area->GED0 = (UINT8) GroupDw[0]; + mPchNvsAreaProtocol.Area->GED1 = (UINT8) GroupDw[1]; + mPchNvsAreaProtocol.Area->GED2 = (UINT8) GroupDw[2]; + + // + // SCS Configuration + // + // Update eMMC HS400 mode enablement + // + mPchNvsAreaProtocol.Area->EMH4 = (UINT8) mPchConfigHob->Scs.ScsEmmcHs400Enabled; + mPchNvsAreaProtocol.Area->EmmcEnabled = (UINT8) mPchConfigHob->Scs.ScsEmmcEnabled; + + // + // 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; + } + + mPchNvsAreaProtocol.Area->SdPowerEnableActiveHigh = (UINT8) mPchConfigHob->Scs.ScsSdPowerEnableActiveHigh; + mPchNvsAreaProtocol.Area->SdCardEnabled = (UINT8) mPchConfigHob->Scs.ScsSdCardEnabled; + + // + // SATA configuration. + // + if (PciSegmentRead16 (GetSataRegBase (SATA_1_CONTROLLER_INDEX) + PCI_DEVICE_ID_OFFSET) == 0xFFFF) { + mPchNvsAreaProtocol.Area->SataPortPresence = 0; + } else { + mPchNvsAreaProtocol.Area->SataPortPresence = PciSegmentRead8 (GetSataRegBase (SATA_1_CONTROLLER_INDEX) + R_SATA_CFG_PCS + 2); + } + + // + // CPU SKU + // + mPchNvsAreaProtocol.Area->CpuSku = GetCpuSku (); + + mPchNvsAreaProtocol.Area->SlpS0VmRuntimeControl = (UINT8)mPchConfigHob->Pm.SlpS0VmRuntimeControl; + mPchNvsAreaProtocol.Area->SlpS0Vm070VSupport = (UINT8)mPchConfigHob->Pm.SlpS0Vm070VSupport; + mPchNvsAreaProtocol.Area->SlpS0Vm075VSupport = (UINT8)mPchConfigHob->Pm.SlpS0Vm075VSupport; + mPchNvsAreaProtocol.Area->PsOnEnable = (UINT8)mPchConfigHob->Pm.PsOnEnable; + + for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) { + mPchNvsAreaProtocol.Area->LtrEnable[Index] = (UINT8)mPchConfigHob->PcieRp.RootPort[Index].LtrEnable; + } + + mPchNvsAreaProtocol.Area->GBES = PchIsGbePresent (); + + // + // Update PCH Trace Hub Mode + // + mPchNvsAreaProtocol.Area->PchTraceHubMode = (UINT8) mPchConfigHob->PchTraceHub.PchTraceHubMode; + // + // if SCRPD0[24] is set, force TH to be host debugger mode. + // + if (MmioRead32 (PCH_TRACE_HUB_MTB_BASE_ADDRESS) != 0xFFFFFFFF) { + if (MmioRead32 (PCH_TRACE_HUB_MTB_BASE_ADDRESS + R_TRACE_HUB_MEM_CSR_MTB_SCRATCHPAD0) & BIT24) { + mPchNvsAreaProtocol.Area->PchTraceHubMode = TraceHubModeHostDebugger; + } + } + + // + // Update TWMB, Temp memory base address + // + mPchNvsAreaProtocol.Area->TempRsvdMemBase = (UINT32) PcdGet32 (PcdSiliconInitTempMemBaseAddr); + + return Status; +} + +/** + Initialize PCH Nvs Area opeartion region. + +**/ +VOID +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); +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c new file mode 100644 index 0000000000..4e38db1027 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c @@ -0,0 +1,33 @@ +/** @file + Initializes PCH CNVi device ACPI data. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include "PchInit.h" +#include + +/** + Update ASL definitions for CNVi device. + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +UpdateCnviAcpiData ( + VOID + ) +{ + + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() Start\n")); + + mPchNvsAreaProtocol.Area->CnviMode = (UINT8) mPchConfigHob->Cnvi.Mode; + + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() End\n")); + + return EFI_SUCCESS; +} + + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c new file mode 100644 index 0000000000..57f2e1dca0 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c @@ -0,0 +1,323 @@ +/** @file + Initializes the PCH HD Audio ACPI Tables. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include "PchInit.h" +#include +#include +#include +#include +#include +#include +#include +#include + +PCH_HDA_NHLT_ENDPOINTS mPchHdaNhltEndpoints[HdaEndpointMax] = +{ + {HdaDmicX1, B_HDA_DMIC_1CH_48KHZ_16BIT_FORMAT, 0, FALSE}, + {HdaDmicX2, (B_HDA_DMIC_2CH_48KHZ_16BIT_FORMAT | B_HDA_DMIC_2CH_48KHZ_32BIT_FORMAT), 0, FALSE}, + {HdaDmicX4, (B_HDA_DMIC_4CH_48KHZ_16BIT_FORMAT | B_HDA_DMIC_4CH_48KHZ_32BIT_FORMAT), 0, FALSE}, + {HdaBtRender, (B_HDA_BT_NARROWBAND_FORMAT | B_HDA_BT_WIDEBAND_FORMAT | B_HDA_BT_A2DP_FORMAT), 0, FALSE}, + {HdaBtCapture, (B_HDA_BT_NARROWBAND_FORMAT | B_HDA_BT_WIDEBAND_FORMAT), 0, FALSE}, + {HdaI2sRender1, B_HDA_I2S_RTK274_RENDER_4CH_48KHZ_24BIT_FORMAT, B_HDA_I2S_RENDER_DEVICE_INFO, FALSE}, + {HdaI2sRender2, B_HDA_I2S_RTK274_RENDER_4CH_48KHZ_24BIT_FORMAT, B_HDA_I2S_RENDER_DEVICE_INFO, FALSE}, + {HdaI2sCapture, B_HDA_I2S_RTK274_CAPTURE_4CH_48KHZ_24BIT_FORMAT, B_HDA_I2S_CAPTURE_DEVICE_INFO, FALSE} +}; + +#define DSP_FW_STOLEN_MEMORY_SIZE 0x400000 //4MB +/** + Allocates 4MB of memory for DSP FW usage. + + @retval EFI_PHYSICAL_ADDRESS Allocated memory address +**/ +EFI_PHYSICAL_ADDRESS +AllocateAudioDspStolenMemory ( + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS DspStolenMemBaseAddress; + + DspStolenMemBaseAddress = 0; + + DEBUG ((DEBUG_INFO, "AllocateAudioDspStolenMemory()\n")); + + // + // Reserve memory to store Acpi Debug data. + // + DspStolenMemBaseAddress = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (DSP_FW_STOLEN_MEMORY_SIZE), + &DspStolenMemBaseAddress + ); + ASSERT_EFI_ERROR(Status); + + ZeroMem ((VOID *) (UINTN) DspStolenMemBaseAddress, DSP_FW_STOLEN_MEMORY_SIZE); + + mPchNvsAreaProtocol.Area->DSPM = (UINT32) DspStolenMemBaseAddress; + DEBUG ((DEBUG_INFO, "mPchNvsAreaProtocol.Area->DSPM = 0x%016x\n", mPchNvsAreaProtocol.Area->DSPM)); + + return DspStolenMemBaseAddress; +} + +/** + 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 HDAS._DSM and SNDW._DSD accordingly to policy. + + @param[in] NhltAcpiTableAddress + @param[in] NhltAcpiTableLength + @param[in] *HdAudioConfigHob + @param[in] *HdAudioDxeConfig +**/ +VOID +UpdateHdaAcpiData ( + IN UINT64 NhltAcpiTableAddress, + IN UINT32 NhltAcpiTableLength, + IN CONST HDAUDIO_HOB *HdAudioConfigHob, + IN CONST PCH_HDAUDIO_DXE_CONFIG *HdAudioDxeConfig + ) +{ + DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address = 0x%016x, Length = 0x%08x\n", NhltAcpiTableAddress, NhltAcpiTableLength)); + DEBUG ((DEBUG_INFO, " FeatureMask = 0x%08x\n", HdAudioDxeConfig->DspFeatureMask)); + + mPchNvsAreaProtocol.Area->NHLA = NhltAcpiTableAddress; + mPchNvsAreaProtocol.Area->NHLL = NhltAcpiTableLength; + mPchNvsAreaProtocol.Area->ADFM = HdAudioDxeConfig->DspFeatureMask; + mPchNvsAreaProtocol.Area->SWQ0 = HdAudioConfigHob->AudioLinkSndw1 ? 0 : BIT1; + mPchNvsAreaProtocol.Area->SWQ1 = HdAudioConfigHob->AudioLinkSndw2 ? 0 : BIT1; + mPchNvsAreaProtocol.Area->SWQ2 = HdAudioConfigHob->AudioLinkSndw3 ? 0 : BIT1; + mPchNvsAreaProtocol.Area->SWQ3 = HdAudioConfigHob->AudioLinkSndw4 ? 0 : BIT1; +} + +/** + Initialize and publish NHLT (Non-HDA Link Table), update NVS variables. + + @param[in] *HdAudioConfigHob + @param[in] *HdAudioDxeConfig + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +SetHdaAcpiTable ( + IN CONST HDAUDIO_HOB *HdAudioConfigHob, + IN CONST PCH_HDAUDIO_DXE_CONFIG *HdAudioDxeConfig + ) +{ + NHLT_ACPI_TABLE *NhltTable; + EFI_STATUS Status; + NhltTable = NULL; + + Status = EFI_SUCCESS; + + if (HdAudioDxeConfig->NhltDefaultFlow == TRUE) { + switch (HdAudioDxeConfig->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 (HdAudioDxeConfig->DspEndpointBluetooth) { + mPchHdaNhltEndpoints[HdaBtRender].Enable = TRUE; + mPchHdaNhltEndpoints[HdaBtCapture].Enable = TRUE; + } + + if (HdAudioDxeConfig->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), HdAudioConfigHob, HdAudioDxeConfig); + + if (IsPchLp () && (PchStepping () < PCH_B0)) { + AllocateAudioDspStolenMemory (); + } + + 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; + UINT64 HdaPciBase; + CONST HDAUDIO_HOB *HdAudioConfigHob; + PCH_POLICY_PROTOCOL *PchPolicy; + PCH_HDAUDIO_DXE_CONFIG *HdAudioDxeConfig; + + + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n")); + + HdAudioConfigHob = &mPchConfigHob->HdAudio; + + /// + /// Get PCH Policy Protocol + /// + Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)&PchPolicy); + ASSERT_EFI_ERROR (Status); + + /// + /// Get HD Audio DXE Config Block + /// + Status = GetConfigBlock ((VOID *)PchPolicy, &gHdAudioDxeConfigGuid, (VOID *)&HdAudioDxeConfig); + ASSERT_EFI_ERROR (Status); + + HdaPciBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_HDA, + PCI_FUNCTION_NUMBER_PCH_HDA, + 0 + ); + + if ((PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) || (HdAudioConfigHob->DspEnable == FALSE)) { + // Do not set ACPI tables if HDAudio is Function disabled or DSP is disabled + DEBUG ((DEBUG_INFO, "AudioDSP: Non-HDAudio ACPI Table (NHLT) not set!\n")); + return EFI_UNSUPPORTED; + } + + Status = SetHdaAcpiTable (HdAudioConfigHob, HdAudioDxeConfig); + + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status = %r\n", Status)); + return Status; +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c new file mode 100644 index 0000000000..55f1e086fb --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c @@ -0,0 +1,554 @@ +/** @file + This is the Common driver that initializes the Intel PCH. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include "PchInit.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Module variables +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *mPchConfigHob; +GLOBAL_REMOVE_IF_UNREFERENCED SI_CONFIG_HOB_DATA *mSiConfigHobData; + +// +// EFI_EVENT +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT mHeciEvent; + +/** + Common PchInit Module Entry Point +**/ +VOID +PchInitEntryPointCommon ( + VOID + ) +{ + EFI_PEI_HOB_POINTERS HobPtr; + + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n")); + + // + // Get PCH Config HOB. + // + HobPtr.Guid = GetFirstGuidHob (&gPchConfigHobGuid); + ASSERT (HobPtr.Guid != NULL); + mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid); + + // + // Get Silicon Config data HOB + // + HobPtr.Guid = GetFirstGuidHob (&gSiConfigHobGuid); + ASSERT (HobPtr.Guid != NULL); + mSiConfigHobData = (SI_CONFIG_HOB_DATA *) GET_GUID_HOB_DATA (HobPtr.Guid); + + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n")); + + return; +} + +/** + Lock SPI register before boot +**/ +VOID +LockSpiConfiguration ( + VOID + ) +{ + UINTN Index; + UINT16 Data16; + UINT16 Data16And; + UINT16 Data16Or; + UINT32 Data32; + UINT32 DlockValue; + UINT64 PciSpiRegBase; + UINT32 PchSpiBar0; + UINT32 Timer; + + PciSpiRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SPI, + PCI_FUNCTION_NUMBER_PCH_SPI, + 0 + ); + + // + // Check for SPI controller presence before programming + // + if (PciSegmentRead32 (PciSpiRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + return; + } + + // + // Make sure SPI BAR0 has fixed address before writing to boot script. + // The same base address is set in PEI and will be used during resume. + // + PchSpiBar0 = PCH_SPI_BASE_ADDRESS; + + PciSegmentAnd8 (PciSpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE); + PciSegmentWrite32 (PciSpiRegBase + R_SPI_CFG_BAR0, PchSpiBar0); + PciSegmentOr8 (PciSpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + + // + // Program the Flash Protection Range Register based on policy + // + DlockValue = MmioRead32 (PchSpiBar0 + R_SPI_MEM_DLOCK); + for (Index = 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) { + if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable || + mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) != TRUE) { + continue; + } + + // + // Proceed to program the register after ensure it is enabled + // + Data32 = 0; + Data32 |= (mPchConfigHob->ProtectRange[Index].WriteProtectionEnable == TRUE) ? B_SPI_MEM_PRX_WPE : 0; + Data32 |= (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable == TRUE) ? B_SPI_MEM_PRX_RPE : 0; + Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeLimit << N_SPI_MEM_PRX_PRL) & B_SPI_MEM_PRX_PRL_MASK; + Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeBase << N_SPI_MEM_PRX_PRB) & B_SPI_MEM_PRX_PRB_MASK; + DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, Data32)); + + DlockValue |= (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index); + MmioWrite32 ((UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))), Data32); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))), + 1, + (VOID *) (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))) + ); + } + // + // Program DLOCK register + // + MmioWrite32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), DlockValue); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), + 1, + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK) + ); + + /// + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation + /// In PCH SPI controller the BIOS should set the Flash Configuration Lock-Down bit + /// (SPI_BAR0 + 04[15]) at end of post. When set to 1, those Flash Program Registers + /// that are locked down by this FLOCKDN bit cannot be written. + /// Please refer to the EDS for which program registers are impacted. + /// Additionally BIOS must program SPI_BAR0 + 0x04 BIT11 (WRSDIS) to disable Write Status in HW sequencing + /// + + // + // Ensure there is no pending SPI trasaction before setting lock bits + // + Timer = 0; + while (MmioRead16 (PchSpiBar0 + R_SPI_MEM_HSFSC) & B_SPI_MEM_HSFSC_SCIP) { + if (Timer > SPI_WAIT_TIME) { + // + // SPI transaction is pending too long at this point, exit with error. + // + DEBUG ((DEBUG_ERROR, "SPI Cycle timeout\n")); + ASSERT (FALSE); + break; + } + MicroSecondDelay (SPI_WAIT_PERIOD); + Timer += SPI_WAIT_PERIOD; + } + + Data16And = B_SPI_MEM_HSFSC_SCIP; + Data16 = 0; + S3BootScriptSaveMemPoll ( + S3BootScriptWidthUint16, + PchSpiBar0 + R_SPI_MEM_HSFSC, + &Data16And, + &Data16, + SPI_WAIT_PERIOD, + SPI_WAIT_TIME / SPI_WAIT_PERIOD + ); + + // + // Clear any outstanding status + // + Data16Or = B_SPI_MEM_HSFSC_SAF_DLE + | B_SPI_MEM_HSFSC_SAF_ERROR + | B_SPI_MEM_HSFSC_AEL + | B_SPI_MEM_HSFSC_FCERR + | B_SPI_MEM_HSFSC_FDONE; + Data16And = 0xFFFF; + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or); + S3BootScriptSaveMemReadWrite ( + S3BootScriptWidthUint16, + PchSpiBar0 + R_SPI_MEM_HSFSC, + &Data16Or, + &Data16And + ); + + // + // Set WRSDIS + // + Data16Or = B_SPI_MEM_HSFSC_WRSDIS; + Data16And = 0xFFFF; + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or); + S3BootScriptSaveMemReadWrite ( + S3BootScriptWidthUint16, + PchSpiBar0 + R_SPI_MEM_HSFSC, + &Data16Or, + &Data16And + ); + + // + // Set FLOCKDN + // + Data16Or = B_SPI_MEM_HSFSC_FLOCKDN; + Data16And = 0xFFFF; + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or); + S3BootScriptSaveMemReadWrite ( + S3BootScriptWidthUint16, + PchSpiBar0 + R_SPI_MEM_HSFSC, + &Data16Or, + &Data16And + ); + + /// + /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock + /// It is strongly recommended that BIOS sets the Vendor Component Lock (VCL) bits. VCL applies + /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without the VCL bits set, it is + /// possible to make Host/GbE VSCC register(s) changes in that can cause undesired host and + /// integrated GbE Serial Flash functionality. + /// + MmioOr32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), B_SPI_MEM_SFDP0_VSCC0_VCL); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), + 1, + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0) + ); +} + +/** + Process all the lock downs +**/ +VOID +ProcessAllLocks ( + VOID + ) +{ + UINT8 Data8; + UINT16 Data16And; + UINT16 Data16Or; + UINT32 Data32And; + UINT32 Data32Or; + UINT64 PciLpcRegBase; + UINT16 TcoBase; + UINT64 PciSpiRegBase; + + PciLpcRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + 0 + ); + PciSpiRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SPI, + PCI_FUNCTION_NUMBER_PCH_SPI, + 0 + ); + + PchTcoBaseGet (&TcoBase); + + // + // Lock function disable (ST and NST PG) register fields. + // + PmcLockFunctionDisableConfigWithS3BootScript (); + + /// + /// PCH BWG Additional PCH DMI and OP-DMI Programming Steps + /// Lock DMI. + /// + PchDmiSetLockWithS3BootScript (); + + // + // Lock SPI register before boot. + // + LockSpiConfiguration (); + + /// + /// Additional Power Management Programming + /// Step 3 + /// Lock configuration after stretch and ACPI base programming completed. + /// + PmcLockSlpSxStretchingPolicyWithS3BootScript (); + + // + // Set BiosLock. + // + if (mPchConfigHob->LockDown.BiosLock == TRUE) { + BiosLockEnable (); + } + + /// + /// 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 + // + PciSegmentOr8 ((UINT64) (PciLpcRegBase + R_LPC_CFG_BC), (UINT32) B_LPC_CFG_BC_BILD); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint8, + PcdGet64 (PcdPciExpressBaseAddress) + PciLpcRegBase + R_LPC_CFG_BC, + 1, + (VOID *) (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) + PciLpcRegBase + R_LPC_CFG_BC) + ); + + // + // Reads back for posted write to take effect + // + Data8 = PciSegmentRead8 ((UINTN) (PciLpcRegBase + R_LPC_CFG_BC)); + S3BootScriptSaveMemPoll ( + S3BootScriptWidthUint8, + PcdGet64 (PcdPciExpressBaseAddress) + PciLpcRegBase + R_LPC_CFG_BC, + &Data8, // BitMask + &Data8, // BitValue + 1, // Duration + 1 // LoopTimes + ); + + // + // SPI + // + PciSegmentOr8 ((UINT64) (PciSpiRegBase + R_SPI_CFG_BC), (UINT32) B_SPI_CFG_BC_BILD); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint8, + PcdGet64 (PcdPciExpressBaseAddress) + PciSpiRegBase + R_SPI_CFG_BC, + 1, + (VOID *) (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) + PciSpiRegBase + R_SPI_CFG_BC) + ); + + // + // Reads back for posted write to take effect + // + Data8 = PciSegmentRead8 ((UINT64) (PciSpiRegBase + R_SPI_CFG_BC)); + S3BootScriptSaveMemPoll ( + S3BootScriptWidthUint8, + PcdGet64 (PcdPciExpressBaseAddress) + PciSpiRegBase + R_SPI_CFG_BC, + &Data8, // BitMask + &Data8, // BitValue + 1, // Duration + 1 // LoopTimes + ); + + /// + /// Set BIOS interface Lock-Down + /// + PchDmiSetBiosLockDownWithS3BootScript (); + } + + /// + /// PCH BIOS Spec on using RTC RAM + /// Regardless of BUC.TS being updated or not, BIOS must set RC.BILD bit PCR[RTC] + 3400h[31] before exit + /// For Data integrity protection, set RTC Memory locks (Upper 128 Byte Lock and + /// Lower 128 Byte Lock) at PCR[RTC] + 3400h[4] and PCR[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. + /// + Data32And = 0xFFFFFFFF; + Data32Or = 0x0; + + if (mPchConfigHob->LockDown.BiosInterface == TRUE) { + Data32Or = B_RTC_PCR_CONF_BILD; + } + if (mPchConfigHob->LockDown.RtcMemoryLock == TRUE) { + Data32Or |= (B_RTC_PCR_CONF_UCMOS_LOCK | B_RTC_PCR_CONF_LCMOS_LOCK); + } + PchPcrAndThenOr32 ( + PID_RTC_HOST, R_RTC_PCR_CONF, + Data32And, + Data32Or + ); + PCH_PCR_BOOT_SCRIPT_READ_WRITE ( + S3BootScriptWidthUint32, + PID_RTC_HOST, R_RTC_PCR_CONF, + &Data32Or, + &Data32And + ); + + /// + /// Remove access to RTC PCRs + /// + Data32And = (UINT32)~(BIT0); + Data32Or = 0; + PchPcrAndThenOr32 ( + PID_RTC_HOST, R_RTC_PCR_PG1_AC_LO, + Data32And, + Data32Or + ); + PCH_PCR_BOOT_SCRIPT_READ_WRITE ( + S3BootScriptWidthUint32, + PID_RTC_HOST, R_RTC_PCR_PG1_AC_LO, + &Data32Or, + &Data32And + ); + PchPcrAndThenOr32 ( + PID_RTC_HOST, R_RTC_PCR_PG1_CP_LO, + Data32And, + Data32Or + ); + PCH_PCR_BOOT_SCRIPT_READ_WRITE ( + S3BootScriptWidthUint32, + PID_RTC_HOST, R_RTC_PCR_PG1_CP_LO, + &Data32Or, + &Data32And + ); + + // + // Lock Down TCO + // + Data16And = 0xFFFF; + Data16Or = B_TCO_IO_TCO1_CNT_LOCK; + IoOr16 (TcoBase + R_TCO_IO_TCO1_CNT, Data16Or); + S3BootScriptSaveIoReadWrite ( + S3BootScriptWidthUint16, + (UINTN) (TcoBase + R_TCO_IO_TCO1_CNT), + &Data16Or, // Data to be ORed + &Data16And // Data to be ANDed + ); + + /// + /// PCH BIOS Spec Section 5.15.1 Additional Chipset Initialization + /// Step 1 + /// Lock PMC Set Strap Message Interface + /// + PmcLockSetStrapMsgInterfaceWithS3BootScript (); + // + // Lock Down PMC + // + PmcLockWithS3BootScript (); +} + +/** + Set eSPI BME bit +**/ +VOID +ConfigureEspiBme ( + VOID + ) +{ + UINT64 EspiPciBase; + + EspiPciBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + 0 + ); + + if (PciSegmentRead16 (EspiPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + return; + } + if ((PciSegmentRead32 (EspiPciBase + R_ESPI_CFG_PCBC) & B_ESPI_CFG_PCBC_ESPI_EN) == 0) { + return; + } + + // + // Refer to PCH BWG. + // To enable eSPI bus mastering BIOS must enable BME in eSPI controller + // and also set BME bit in the respective slave devices through Configuration + // and Capabilities register of each slave using Get_Configuration and Set_Configuration functionality. + // + // NOTE: The setting is also done in PEI, but might be cleared by PCI bus during PCI enumeration. + // Therefore, reeable it after PCI enumeration done. + // + if (mPchConfigHob->Espi.BmeMasterSlaveEnabled == TRUE) { + PciSegmentOr8 (EspiPciBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_BUS_MASTER); + } +} + +/** + Common PCH initialization before Boot Sript Table is closed + +**/ +VOID +PchOnPciEnumCompleteCommon ( + VOID + ) +{ + UINT32 Data32Or; + UINT32 Data32And; + BOOLEAN ResetStatus; + + DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() Start\n")); + + if (SiScheduleResetIsRequired ()) { + ResetStatus = SiScheduleResetPerformReset (); + ASSERT (!ResetStatus); + } + + 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_PSTH_PCR_PSTHIOSFPTCGE; + PchPcrAndThenOr32 (PID_PSTH, R_PSTH_PCR_PSTHCTL, Data32And, Data32Or); + PCH_PCR_BOOT_SCRIPT_READ_WRITE ( + S3BootScriptWidthUint32, + PID_PSTH, R_PSTH_PCR_PSTHCTL, + &Data32Or, + &Data32And + ); + + // + // Set eSPI BME after PCI enumeration + // + ConfigureEspiBme (); + + /// + /// Clear Global Reset Status, Power Failure and Host Reset Status bits + /// + PmcClearGlobalResetStatus (); + PmcClearPowerFailureStatus (); + PmcClearHostResetStatus (); + + DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() End\n")); +} diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c new file mode 100644 index 0000000000..b106c849e9 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c @@ -0,0 +1,382 @@ +/** @file + This is the Uefi driver that initializes the Intel PCH. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include "PchInit.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mImageHandle; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress; + +VOID +EFIAPI +PchOnBootToOs ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +VOID +EFIAPI +PchOnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +VOID +EFIAPI +PchOnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Process all the lock downs +**/ +VOID +ProcessSmiLocks ( + VOID + ) +{ + UINT32 Data32And; + UINT32 Data32Or; + UINT16 ABase; + + /// + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation + /// BIOS needs to enables SMI_LOCK (PMC PCI offset A0h[4] = 1b) which prevent writes + /// to the Global SMI Enable bit (GLB_SMI_EN ABASE + 30h[0]). Enabling this bit will + /// mitigate malicious software attempts to gain system management mode privileges. + /// + if (mPchConfigHob->LockDown.GlobalSmi == TRUE) { + /// + /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK during S3 resume + /// + ABase = PmcGetAcpiBase (); + Data32Or = IoRead32 ((UINTN) (ABase + R_ACPI_IO_SMI_EN)); + if ((Data32Or & B_ACPI_IO_SMI_EN_GBL_SMI) != 0) { + Data32And = 0xFFFFFFFF; + Data32Or |= B_ACPI_IO_SMI_EN_GBL_SMI; + S3BootScriptSaveIoReadWrite ( + S3BootScriptWidthUint32, + (UINTN) (ABase + R_ACPI_IO_SMI_EN), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + } + PmcLockSmiWithS3BootScript (); + } +} + +/** + Do PCIE power management while resume from S3 +**/ +VOID +ReconfigurePciePowerManagementForS3 ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 Data32; + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol; + + Status = gBS->LocateProtocol (&gPchPcieIoTrapProtocolGuid, NULL, (VOID **) &PchPcieIoTrapProtocol); + if (EFI_ERROR (Status)) { + return; + } + mPcieIoTrapAddress = PchPcieIoTrapProtocol->PcieTrapAddress; + DEBUG ((DEBUG_INFO, "PcieIoTrapAddress: %0x\n", mPcieIoTrapAddress)); + + if (mPcieIoTrapAddress != 0) { + // + // Save PCH PCIE IoTrap address to re-config PCIE power management setting after resume from S3 + // + Data32 = 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; + UINT64 ThermalPciBase; + + /// + /// 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); + + // + // Enable Thermal MSE + // + ThermalPciBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_THERMAL, + PCI_FUNCTION_NUMBER_PCH_THERMAL, + 0 + ); + if (PciSegmentRead16 (ThermalPciBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF) { + if (((PciSegmentRead32 (ThermalPciBase + R_THERMAL_CFG_MEM_TBAR) & B_THERMAL_CFG_MEM_TBAR_MASK) != 0) || + ((PciSegmentRead32 (ThermalPciBase + R_THERMAL_CFG_MEM_TBARH) != 0))) { + PciSegmentOr8 (ThermalPciBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + } + } + + ReconfigurePciePowerManagementForS3 (); + ProcessSmiLocks (); +#ifndef FSP_WRAPPER_FLAG + PchOnPciEnumCompleteCommon (); +#endif + ConfigureSerialIoAtS3Resume (); +} + +/** + Register callback functions for PCH DXE. +**/ +VOID +PchRegisterNotifications ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT LegacyBootEvent; + EFI_EVENT ExitBootServicesEvent; + VOID *Registration; + + /// + /// Create PCI Enumeration Completed callback for PCH + /// + EfiCreateProtocolNotifyEvent ( + &gEfiPciEnumerationCompleteProtocolGuid, + TPL_CALLBACK, + PchOnPciEnumComplete, + NULL, + &Registration + ); + + // + // 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); +} + +/** + Initialize the PCH device according to the PCH Policy HOB + and install PCH info instance. +**/ +VOID +InitializePchDevice ( + VOID + ) +{ + DEBUG ((DEBUG_INFO, "InitializePchDevice() Start\n")); + + DEBUG ((DEBUG_INFO, "InitializePchDevice() End\n")); +} +/** + PchInit DXE Module Entry Point\n + - Introduction\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. + + - Details\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 + + - References\n + - @link _PCH_POLICY PCH_POLICY_HOB @endlink. + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink. + + - Integration Checklists\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); + + return; +} + +/** + PCH initialization before boot to OS + + @param[in] Event A pointer to the Event that triggered the callback. + @param[in] Context A pointer to private data registered with the callback function. +**/ +VOID +EFIAPI +PchOnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() Start\n")); + + if (Event != NULL) { + gBS->CloseEvent (Event); + } + + // + // Trigger an Iotrap SMI to config PCIE power management setting after PCI enumrate is done + // + if (mPcieIoTrapAddress != 0) { + IoWrite32 ((UINTN) mPcieIoTrapAddress, PciePmTrap); + } else { + ASSERT (FALSE); + } + + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() End\n")); +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c new file mode 100644 index 0000000000..15fe4628fb --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchInitFsp.c @@ -0,0 +1,85 @@ +/** @file + This is the FSP driver that initializes the Intel PCH. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#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 + } +}; + +/** + FSP PchInit Module Entry Point for FSP\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); + + 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; +} diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c new file mode 100644 index 0000000000..6e30280fa7 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c @@ -0,0 +1,89 @@ +/** @file + Perform related functions for PCH Sata in DXE phase + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +#include "PchInit.h" +#include +#include + +/** + 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 + ) +{ + UINT64 PciSataRegBase; + UINT16 SataPortsEnabled; + UINT32 DwordReg; + UINTN Index; + UINT32 SataCtrlIndex; + + for (SataCtrlIndex = 0; SataCtrlIndex < GetPchMaxSataControllerNum (); SataCtrlIndex++) { + /// + /// SATA PCS: Enable the port in any of below condition: + /// i.) Hot plug is enabled + /// ii.) A device is attached + /// iii.) Test mode is enabled + /// iv.) Configured as eSATA port + /// + PciSataRegBase = GetSataRegBase (SataCtrlIndex); + SataPortsEnabled = 0; + + DwordReg = PciSegmentRead32 (PciSataRegBase + R_SATA_CFG_PCS); + for (Index = 0; Index < GetPchMaxSataPortNum (SataCtrlIndex); Index++) { + if ((mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].HotPlug == TRUE) || + (DwordReg & (B_SATA_CFG_PCS_P0P << Index)) || + (mPchConfigHob->Sata[SataCtrlIndex].TestMode == TRUE) || + (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].External == TRUE)) { + SataPortsEnabled |= (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].Enable << Index); + } + } + + /// + /// Set MAP."Sata PortX Disable", SATA PCI offset 90h[23:16] to 1b if SATA Port 0/1/2/3/4/5/6/7 is disabled + /// + PciSegmentOr32 (PciSataRegBase + R_SATA_CFG_MAP, (~SataPortsEnabled << N_SATA_CFG_MAP_SPD)); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + PcdGet64 (PcdPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_MAP, + 1, + (VOID *) (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_MAP) + ); + + /// + /// Program PCS "Port X Enabled", SATA PCI offset 94h[7:0] = Port 0~7 Enabled bit as per SataPortsEnabled value. + /// + PciSegmentOr16 (PciSataRegBase + R_SATA_CFG_PCS, SataPortsEnabled); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint16, + PcdGet64 (PcdPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_PCS, + 1, + (VOID *) (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_PCS) + ); + + /// + /// Step 14 + /// Program SATA PCI offset 9Ch [31] to 1b + /// + PciSegmentOr32 ((UINTN) (PciSataRegBase + R_SATA_CFG_SATAGC), BIT31); + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + PcdGet64 (PcdPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_SATAGC, + 1, + (VOID *) (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) + PciSataRegBase + R_SATA_CFG_SATAGC) + ); + } +} diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c new file mode 100644 index 0000000000..d0f4b4fa56 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c @@ -0,0 +1,57 @@ +/** @file + Initializes Serial IO Controllers. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include "PchInit.h" +#include +#include +#include + +/** + 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) { + if (IsSerialIoFunctionZero (Index)) { + if (IsSerialIoDeviceEnabled (GetSerialIoDeviceNumber (Index), GetSerialIoFunctionNumber (Index))) { + PciCfgBase = FindSerialIoBar (Index,1); + MmioOr32 (PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS, B_SERIAL_IO_CFG_PME_CTRL_STS_PWR_ST); + } + } + continue; + } + if ((Index >= PchSerialIoIndexUart0) && + (mPchConfigHob->SerialIo.EnableDebugUartAfterPost) && + (mPchConfigHob->SerialIo.DebugUartNumber == (UINT32) (Index - PchSerialIoIndexUart0))) { + continue; + } + PciCfgBase = FindSerialIoBar (Index,1); + MmioOr32 (PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS, B_SERIAL_IO_CFG_PME_CTRL_STS_PWR_ST); + MmioRead32 (PciCfgBase + R_SERIAL_IO_CFG_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) ); + if (mPchConfigHob->SerialIo.DebugUartNumber == (UINT32) (Index - PchSerialIoIndexUart0)) { + continue; + } + MmioWrite32 (PciCfgBase + R_SERIAL_IO_CFG_BAR0_LOW, 0); + MmioWrite32 (PciCfgBase + R_SERIAL_IO_CFG_BAR0_HIGH, 0); + } + } + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c new file mode 100644 index 0000000000..5563d82076 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c @@ -0,0 +1,156 @@ +/** @file + Initializes Serial IO Controllers. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include "PchInit.h" +#include +#include +#include +#include + +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; iSerialIo.DevMode[i] == PchSerialIoHidden || + mPchConfigHob->SerialIo.DevMode[i] == PchSerialIoAcpi) { + for (BarNumber = 0; BarNumber<=1; BarNumber++) { + Bar = FindSerialIoBar (i,BarNumber); + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeReserved, + Bar, + V_SERIAL_IO_CFG_BAR_SIZE, + 0 + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeReserved, + N_SERIAL_IO_CFG_BAR_ALIGNMENT, + V_SERIAL_IO_CFG_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; + 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); + gBS->InstallMultipleProtocolInterfaces ( + &NewHandle, + &gEfiDevicePathProtocolGuid, + NewPath, + NULL ); + } + } +} + +/** + Puts all SerialIo controllers (except UARTs in debug mode) in D3. + Clears MemoryEnable for all PCI-mode controllers on S3 resume +**/ +VOID +ConfigureSerialIoAtS3Resume ( + VOID + ) +{ + PCH_SERIAL_IO_CONTROLLER Index; + UINTN PciCfgBase; + UINT32 Data32; + + for (Index = 0; Index < PchSerialIoIndexMax; Index++) { + if (mPchConfigHob->SerialIo.DevMode[Index] == PchSerialIoDisabled) { + if (IsSerialIoFunctionZero (Index)) { + if (IsSerialIoDeviceEnabled (GetSerialIoDeviceNumber (Index), GetSerialIoFunctionNumber (Index))) { + PciCfgBase = FindSerialIoBar (Index,1); + Data32 = MmioRead32 (PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS); + Data32 |= B_SERIAL_IO_CFG_PME_CTRL_STS_PWR_ST; + S3BootScriptSaveMemWrite (S3BootScriptWidthUint32, PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS, 1, &Data32); + } + } + continue; + } + if ((Index >= PchSerialIoIndexUart0) && + (mPchConfigHob->SerialIo.EnableDebugUartAfterPost) && + (mPchConfigHob->SerialIo.DebugUartNumber == (UINT32) (Index - PchSerialIoIndexUart0))) { + continue; + } + PciCfgBase = FindSerialIoBar (Index,1); + Data32 = MmioRead32 (PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS); + Data32 |= B_SERIAL_IO_CFG_PME_CTRL_STS_PWR_ST; + S3BootScriptSaveMemWrite (S3BootScriptWidthUint32, PciCfgBase + R_SERIAL_IO_CFG_PME_CTRL_STS, 1, &Data32); + if (mPchConfigHob->SerialIo.DevMode[Index] == PchSerialIoPci) { + Data32 = MmioRead32 (PciCfgBase + PCI_COMMAND_OFFSET); + Data32 &= (UINT32)~(EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER); + S3BootScriptSaveMemWrite (S3BootScriptWidthUint32, PciCfgBase + PCI_COMMAND_OFFSET, 1, &Data32); + } + } +} diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c new file mode 100644 index 0000000000..7fe1567c9f --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c @@ -0,0 +1,156 @@ +/** @file + PCH BIOS Write Protect Driver. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PchInitSmm.h" +#include +#include +#include + +// +// Global variables +// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_TCO_SMI_DISPATCH_PROTOCOL *mPchTcoSmiDispatchProtocol; +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mSpiRegBase; +GLOBAL_REMOVE_IF_UNREFERENCED PCH_ESPI_SMI_DISPATCH_PROTOCOL *mEspiSmmDispatchProtocol; +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mLpcRegBase; + +/** + This hardware SMI handler will be run every time the BIOS Write Enable bit is set. + + @param[in] DispatchHandle Not used + +**/ +VOID +EFIAPI +PchSpiBiosWpCallback ( + IN EFI_HANDLE DispatchHandle + ) +{ + // + // Disable BIOSWE bit to protect BIOS + // + PciSegmentAnd8 ((UINTN) (mSpiRegBase + R_SPI_CFG_BC), (UINT8) ~B_SPI_CFG_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 + // + PciSegmentAnd8 ((UINTN) (mLpcRegBase + R_LPC_CFG_BC), (UINT8) ~B_LPC_CFG_BC_WPD); +} + +/** + Entry point for Pch Bios Write Protect driver. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable Global system service table. + + @retval EFI_SUCCESS Initialization complete. +**/ +EFI_STATUS +EFIAPI +InstallPchBiosWriteProtect ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + DEBUG ((DEBUG_INFO, "InstallPchBiosWriteProtect()\n")); + + if (mPchConfigHob->LockDown.BiosLock != TRUE) { + return EFI_SUCCESS; + } + + mSpiRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SPI, + PCI_FUNCTION_NUMBER_PCH_SPI, + 0 + ); + + mLpcRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + 0 + ); + + DEBUG ((DEBUG_INFO, "Installing BIOS Write Protect SMI handler\n")); + // + // Get the PCH TCO SMM dispatch protocol + // + mPchTcoSmiDispatchProtocol = NULL; + Status = gSmst->SmmLocateProtocol (&gPchTcoSmiDispatchProtocolGuid, NULL, (VOID **) &mPchTcoSmiDispatchProtocol); + ASSERT_EFI_ERROR (Status); + // + // Always register an SPI BiosWp callback function to handle TCO BIOSWR SMI + // NOTE: No matter the BIOS resides behind SPI or not, it needs to handle the SPI BIOS WP SMI + // to avoid SMI deadloop on SPI WPD write. + // + Handle = NULL; + Status = mPchTcoSmiDispatchProtocol->SpiBiosWpRegister ( + mPchTcoSmiDispatchProtocol, + PchSpiBiosWpCallback, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + // + // Always register an LPC/eSPI BiosWp callback function to handle TCO BIOSWR SMI + // NOTE: No matter the BIOS resides behind LPC/eSPI or not, it needs to handle the BIOS WP SMI + // to avoid SMI deadloop on LPC/eSPI WPD write. + // + if (IsEspiEnabled ()) { + // + // Get the PCH ESPI SMM dispatch protocol + // + mEspiSmmDispatchProtocol = NULL; + Status = gSmst->SmmLocateProtocol (&gPchEspiSmiDispatchProtocolGuid, NULL, (VOID **) &mEspiSmmDispatchProtocol); + ASSERT_EFI_ERROR (Status); + + // + // Register an ESpiBiosWp callback function to handle BIOSWR SMI + // + Handle = NULL; + Status = mEspiSmmDispatchProtocol->BiosWrProtectRegister ( + mEspiSmmDispatchProtocol, + PchLpcBiosWpCallback, + &Handle + ); + ASSERT_EFI_ERROR (Status); + } else { + // + // Register an LPC BiosWp callback function to handle TCO BIOSWR SMI + // + Handle = NULL; + Status = mPchTcoSmiDispatchProtocol->LpcBiosWpRegister ( + mPchTcoSmiDispatchProtocol, + PchLpcBiosWpCallback, + &Handle + ); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c new file mode 100644 index 0000000000..e9f4c91ed4 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c @@ -0,0 +1,179 @@ +/** @file + PCH Init Smm module for PCH specific SMI handlers. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PchInitSmm.h" +#include +#include +#include + +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_DATA *mSiConfigHobData; + +// +// The reserved MMIO range to be used in Sx handler +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mResvMmioSize; + +/** + SMBUS Sx entry SMI handler. +**/ +VOID +SmbusSxCallback ( + VOID + ) +{ + UINT64 SmbusRegBase; + UINT16 SmbusIoBase; + + SmbusRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SMBUS, + PCI_FUNCTION_NUMBER_PCH_SMBUS, + 0 + ); + + if (PciSegmentRead32 (SmbusRegBase) == 0xFFFFFFFF) { + return; + } + + SmbusIoBase = PciSegmentRead16 (SmbusRegBase + R_SMBUS_CFG_BASE) & B_SMBUS_CFG_BASE_BAR; + if (SmbusIoBase == 0) { + return; + } + + PciSegmentOr8 (SmbusRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_IO_SPACE); + // + // Clear SMBUS status and SMB_WAK_STS of GPE0 + // + IoWrite8 (SmbusIoBase + R_SMBUS_IO_HSTS, B_SMBUS_IO_SMBALERT_STS); + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, B_ACPI_IO_GPE0_STS_127_96_SMB_WAK); +} + +/** + Allocates reserved MMIO for Sx SMI handler use. +**/ +VOID +AllocateReservedMmio ( + VOID + ) +{ + mResvMmioBaseAddr = PcdGet32 (PcdSiliconInitTempMemBaseAddr); + mResvMmioSize = PcdGet32 (PcdSiliconInitTempMemSize); + DEBUG ((DEBUG_INFO, "mResvMmioBaseAddr %x, mResvMmioSize %x\n", mResvMmioBaseAddr, mResvMmioSize)); +} + +/** + Initializes the PCH SMM handler for for PCIE hot plug support + PchInit SMM Module Entry Point\n + - Introduction\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. + + - Details\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 + + - References\n + - @link _PCH_POLICY PCH_POLICY_HOB @endlink. + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink. + + - Integration Checklists\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); + mSiConfigHobData = (SI_CONFIG_HOB_DATA *) GET_GUID_HOB_DATA (HobPtr.Guid); + + mAcpiBaseAddr = PmcGetAcpiBase (); + + AllocateReservedMmio (); + + Status = InitializePchPcieSmm (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/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c new file mode 100644 index 0000000000..4a2d1f9cea --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchLanSxSmm.c @@ -0,0 +1,298 @@ +/** @file + PCH LAN Sx handler implementation. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include "PchInitSmm.h" +#include +#include +#include +#include + +/** + Checks if Lan is Enabled or Disabled + + @retval BOOLEAN TRUE if device is enabled, FALSE otherwise. +**/ +BOOLEAN +IsGbeEnabled ( + VOID + ) +{ + UINT64 GbePciBase; + + GbePciBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LAN, + PCI_FUNCTION_NUMBER_PCH_LAN, + 0 + ); + + if (PciSegmentRead32 (GbePciBase) != 0xFFFFFFFF) { + return TRUE; + } + + return FALSE; +} + + +/** + Configure WOL during Sx entry. + + @param [in] GbeBar GbE MMIO space +**/ +VOID +GbeWolWorkaround ( + IN UINT32 GbeBar + ) +{ + UINT32 RAL0; + UINT32 RAH0; + UINT16 WUC; + EFI_STATUS Status; + UINT16 Data16; + + // + // 1. Set page to 769 Port Control Registers + // 2. Wait 4 mSec + // + Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS); + if (EFI_ERROR (Status)) return; + + // + // 3. Set registry to 17 Port General Configuration + // 4. Copy all settings from Port General Configuration + // + Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16); + if (EFI_ERROR (Status)) return; + + // + // 5. Modify BIT 4 and BIT 2 to disable host wake up and set MACPD + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP)); + if (EFI_ERROR (Status)) return; + + // + // 6. Read Receive Address Low and Receive Address High from MMIO + // + RAL0 = MmioRead32 (GbeBar + R_LAN_MEM_CSR_RAL); + RAH0 = MmioRead32 (GbeBar + R_LAN_MEM_CSR_RAH); + + // + // 7. Set page to 800 Wake Up Registers + // 8. Wait 4 mSec + // + Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_800_WAKE_UP_REGISTERS); + if (EFI_ERROR (Status)) return; + + // + // 9. Set registry to 16 Receive Address Low 1/2 + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_16_RAL0); + if (EFI_ERROR (Status)) return; + + // + // 10. Program first 16 bits [0:15] out of 48 in Receive Address Low 1/2 + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 & 0xFFFF)); + if (EFI_ERROR (Status)) return; + + // + // 11. Set registry to 17 Receive Address Low 2/2 + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_17_RAL1); + if (EFI_ERROR (Status)) return; + + // + // 12. Program second 16 bits [16:31] out of 48 in Receive Address Low 2/2 + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 >> 16)); + if (EFI_ERROR (Status)) return; + + // + // 13. Set registry to 18 Receive Address High 1/2 + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_18_RAH0); + if (EFI_ERROR (Status)) return; + + // + // 14. Program last 16 bits [32:47] out of 48 + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAH0 & B_LAN_MEM_CSR_RAH_RAH)); + if (EFI_ERROR (Status)) return; + + // + // 15. Set registry to 19 Receive Address High 2/2 + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_19_RAH1); + if (EFI_ERROR (Status)) return; + + // + // 16. Set Address Valid + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, B_PHY_MDI_PAGE_800_REGISETER_19_RAH1_ADDRESS_VALID); + if (EFI_ERROR (Status)) return; + + // + // 17. Set Wake Up Control Register 1 + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_1_WUC); + if (EFI_ERROR (Status)) return; + + // + // 18. Copy WakeUp Control from MAC MMIO + // + WUC = (UINT16) MmioRead32 (GbeBar + R_LAN_MEM_CSR_WUC); + + // + // 19. Store WakeUp Contorl into LCD + // Modify APME bit to enable APM wake up + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (WUC & 0xFFFF)); + if (EFI_ERROR (Status)) return; + + // + // 20. Set page to 803 Host Wol Packet + // 21. Wait 4 mSec + // + Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_803_HOST_WOL_PACKET); + if (EFI_ERROR (Status)) return; + + // + // 22. Set registry to 66 Host WoL Packet Clear + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_803_REGISETER_66_HWPC); + if (EFI_ERROR (Status)) return; + + // + // 23. Clear WOL Packet + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, 0); + if (EFI_ERROR (Status)) return; + // + // 24. Set page to 769 Port Control Registers + // 25. Wait 4 mSec + // + Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS); + if (EFI_ERROR (Status)) return; + + // + // 26. Set registry to 17 Port General Configuration + // + Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_769_REGISETER_17_PGC); + if (EFI_ERROR (Status)) return; + + // + // 27. Copy all settings from Port General Configuration + // + Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16); + if (EFI_ERROR (Status)) return; + + // + // 28. Modify BIT 4 and BIT 2 to enable host wake up and clear MACPD + // + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE)); + if (EFI_ERROR (Status)) return; +} + +/** + Additional Internal GbE Controller special cases WOL Support. + + System BIOS is required perform additional steps upon S0 to S3,4,5 transition + when ME is off and GbE device in D0. This is needed to enable LAN wake + in particular when platform is shut-down from EFI. +**/ +VOID +GbeSxWorkaround ( + VOID + ) +{ + UINT64 LanRegBase; + UINT32 GbeBar; + EFI_STATUS Status; + + LanRegBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LAN, + PCI_FUNCTION_NUMBER_PCH_LAN, + 0 + ); + + if (PciSegmentRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + return; + } + + // + // Check if GbE device is in D0 + // + if ((PciSegmentRead16 (LanRegBase + R_LAN_CFG_PMCS) & B_LAN_CFG_PMCS_PS) != V_LAN_CFG_PMCS_PS0) { + return; + } + + ASSERT (mResvMmioSize >= (1 << N_LAN_CFG_MBARA_ALIGN)); + GbeBar = (UINT32) mResvMmioBaseAddr; + if (GbeBar == 0) { + ASSERT (FALSE); + return; + } + + // + // Enable MMIO decode using reserved range. + // + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE); + PciSegmentWrite32 (LanRegBase + R_LAN_CFG_MBARA, GbeBar); + PciSegmentOr16 (LanRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + + // + // If MBARA offset 5800h [0] = 1b then proceed with the w/a + // + if (MmioRead32 (GbeBar + R_LAN_MEM_CSR_WUC) & B_LAN_MEM_CSR_WUC_APME) { + Status = GbeMdiAcquireMdio (GbeBar); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + GbeWolWorkaround (GbeBar); + GbeMdiReleaseMdio (GbeBar); + } + } + + // + // Disable MMIO decode. + // + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE); + PciSegmentWrite32 (LanRegBase + R_LAN_CFG_MBARA, 0); +} + +/** + Enable platform wake from LAN when in DeepSx if platform supports it. + Called upon Sx entry. +**/ +VOID +GbeConfigureDeepSxWake ( + VOID + ) +{ + if (PmcIsLanDeepSxWakeEnabled ()) { + IoOr32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96), (UINT32) B_ACPI_IO_GPE0_EN_127_96_LAN_WAKE); + } +} + +/** + GbE Sx entry handler +**/ +VOID +PchLanSxCallback ( + VOID + ) +{ + if (IsGbeEnabled ()) { + GbeSxWorkaround (); + GbeConfigureDeepSxWake (); + + } +} diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c new file mode 100644 index 0000000000..eac2e1c3ec --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c @@ -0,0 +1,436 @@ +/** @file + PCH Pcie SMM Driver Entry + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PchInitSmm.h" +#include +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE *mDevAspmOverride; +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNumOfDevAspmOverride; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPchBusNumber; +// +// @note: +// These temp bus numbers cannot be used in runtime (hot-plug). +// These can be used only during boot. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTempRootPortBusNumMin; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mTempRootPortBusNumMax; + +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_ROOT_PORT_CONFIG mPcieRootPortConfig[PCH_MAX_PCIE_ROOT_PORTS]; + +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mPciePmTrapExecuted = 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 +**/ +STATIC +VOID +PchPcieSmi ( + IN UINT8 PortIndex, + IN UINT8 RpDevice, + IN UINT8 RpFunction + ) +{ + UINT8 SecBus; + UINT8 SubBus; + UINT64 RpBase; + UINT64 EpBase; + UINT8 EpPcieCapPtr; + UINT8 EpMaxSpeed; + BOOLEAN DownstreamDevicePresent; + UINT32 Timeout; + + RpBase = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + mPchBusNumber, + (UINT32) RpDevice, + (UINT32) RpFunction, + 0 + ); + + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + return; + } + // + // Check presence detect state. Here the endpoint must be detected using PDS rather than + // the usual LinkActive check, because PDS changes immediately and LA takes a few milliseconds to stabilize + // + DownstreamDevicePresent = !!(PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_SLSTS) & B_PCIE_SLSTS_PDS); + + if (DownstreamDevicePresent) { + /// + /// Make sure the link is active before trying to talk to device behind it + /// Wait up to 100ms, according to PCIE spec chapter 6.7.3.3 + /// + Timeout = 100 * 1000; + while ((PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_LSTS) & B_PCIE_LSTS_LA) == 0 ) { + MicroSecondDelay (10); + Timeout-=10; + if (Timeout == 0) { + return; + } + } + SecBus = PciSegmentRead8 (RpBase + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET); + SubBus = PciSegmentRead8 (RpBase + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET); + ASSERT (SecBus != 0 && SubBus != 0); + RootportDownstreamConfiguration ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + RpDevice, + RpFunction, + mTempRootPortBusNumMin, + mTempRootPortBusNumMax + ); + RootportDownstreamPmConfiguration ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + RpDevice, + RpFunction, + mTempRootPortBusNumMin, + mTempRootPortBusNumMax, + &mPcieRootPortConfig[PortIndex], + mNumOfDevAspmOverride, + mDevAspmOverride + ); + // + // Perform Equalization + // + EpBase = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus, 0, 0, 0); + EpPcieCapPtr = PcieFindCapId (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP); + EpMaxSpeed = PciSegmentRead8 (EpBase + EpPcieCapPtr + R_PCIE_LCAP_OFFSET) & B_PCIE_LCAP_MLS; + if (EpMaxSpeed >= 3) { + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_EX_LCTL3, B_PCIE_EX_LCTL3_PE); + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_LCTL, B_PCIE_LCTL_RL); + } + } +} + +/** + PCIE Hotplug SMI call back function for each Root port + + @param[in] DispatchHandle Handle of this dispatch function + @param[in] RpContext Rootport context, which contains RootPort Index, + and RootPort PCI BDF. +**/ +VOID +EFIAPI +PchPcieSmiRpHandlerFunction ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ) +{ + PchPcieSmi (RpContext->RpIndex, RpContext->DevNum, RpContext->FuncNum); +} + +/** + PCIE Link Active State Change Hotplug SMI call back function for all Root ports + + @param[in] DispatchHandle Handle of this dispatch function + @param[in] RpContext Rootport context, which contains RootPort Index, + and RootPort PCI BDF. +**/ +VOID +EFIAPI +PchPcieLinkActiveStateChange ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ) +{ + return; +} + +/** + PCIE Link Equalization Request SMI call back function for all Root ports + + @param[in] DispatchHandle Handle of this dispatch function + @param[in] RpContext Rootport context, which contains RootPort Index, + and RootPort PCI BDF. +**/ +VOID +EFIAPI +PchPcieLinkEqHandlerFunction ( + IN EFI_HANDLE DispatchHandle, + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext + ) +{ + /// + /// From PCI Express specification, the PCIe device can request for Link Equalization. When the + /// Link Equalization is requested by the device, an SMI will be generated by PCIe RP when + /// enabled and the SMI subroutine would invoke the Software Preset/Coefficient Search + /// software to re-equalize the link. + /// + + return; + +} + +/** + An IoTrap callback to config PCIE power management settings +**/ +VOID +PchPciePmIoTrapSmiCallback ( + VOID + ) +{ + UINT32 PortIndex; + UINT64 RpBase; + UINT8 MaxPciePortNum; + UINTN RpDevice; + UINTN RpFunction; + + MaxPciePortNum = GetPchMaxPciePortNum (); + + for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) { + GetPchPcieRpDevFun (PortIndex, &RpDevice, &RpFunction); + RpBase = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDevice, (UINT32) RpFunction, 0); + + if (PciSegmentRead16 (RpBase) != 0xFFFF) { + RootportDownstreamPmConfiguration ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + (UINT8)RpDevice, + (UINT8)RpFunction, + mTempRootPortBusNumMin, + mTempRootPortBusNumMax, + &mPcieRootPortConfig[PortIndex], + mNumOfDevAspmOverride, + mDevAspmOverride + ); + + } + } +} + +/** + An IoTrap callback to config PCIE power management settings + + @param[in] DispatchHandle - The handle of this callback, obtained when registering + @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT + +**/ +VOID +EFIAPI +PchPcieIoTrapSmiCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + if (CallbackContext->WriteData == 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; + UINT64 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); + + mPchBusNumber = DEFAULT_PCI_BUS_NUMBER_PCH; + mTempRootPortBusNumMin = PcdGet8 (PcdSiliconInitTempPciBusMin); + mTempRootPortBusNumMax = PcdGet8 (PcdSiliconInitTempPciBusMax); + + ASSERT (sizeof mPcieRootPortConfig == sizeof mPchConfigHob->PcieRp.RootPort); + CopyMem ( + mPcieRootPortConfig, + &(mPchConfigHob->PcieRp.RootPort), + sizeof (mPcieRootPortConfig) + ); + + mDevAspmOverride = NULL; + mNumOfDevAspmOverride = 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 = PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDevice, (UINT32) RpFunction, 0); + // + // Skip the root port function which is not enabled + // + if (PciSegmentRead32 (RpBase) == 0xFFFFFFFF) { + continue; + } + + // + // Register SMI Handlers for Hot Plug and Link Active State Change + // + Data8 = PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_SLCAP); + if (Data8 & B_PCIE_SLCAP_HPC) { + PcieHandle = NULL; + Status = PchPcieSmiDispatchProtocol->HotPlugRegister ( + PchPcieSmiDispatchProtocol, + PchPcieSmiRpHandlerFunction, + PortIndex, + &PcieHandle + ); + ASSERT_EFI_ERROR (Status); + + Status = PchPcieSmiDispatchProtocol->LinkActiveRegister ( + PchPcieSmiDispatchProtocol, + PchPcieLinkActiveStateChange, + PortIndex, + &PcieHandle + ); + ASSERT_EFI_ERROR (Status); + + Data32Or = B_PCH_PCIE_CFG_MPC_HPME; + Data32And = (UINT32) ~B_PCH_PCIE_CFG_MPC_HPME; + S3BootScriptSaveMemReadWrite ( + S3BootScriptWidthUint32, + PcdGet64 (PcdPciExpressBaseAddress) + RpBase + R_PCH_PCIE_CFG_MPC, + &Data32Or, /// Data to be ORed + &Data32And /// Data to be ANDed + ); + } + + // + // Register SMI Handler for Link Equalization Request from Gen 3 Devices. + // + Data8 = PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_LCAP); + if ((Data8 & B_PCIE_LCAP_MLS) == V_PCIE_LCAP_MLS_GEN3) { + Status = PchPcieSmiDispatchProtocol->LinkEqRegister ( + PchPcieSmiDispatchProtocol, + PchPcieLinkEqHandlerFunction, + PortIndex, + &PcieHandle + ); + ASSERT_EFI_ERROR (Status); + } + } + + ASSERT_EFI_ERROR (Status); + + PchIoTrapContext.Type = WriteTrap; + PchIoTrapContext.Length = 4; + PchIoTrapContext.Address = 0; + Status = mPchIoTrap->Register ( + mPchIoTrap, + (EFI_SMM_HANDLER_ENTRY_POINT2) PchPcieIoTrapSmiCallback, + &PchIoTrapContext, + &PchIoTrapHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Install the PCH Pcie IoTrap protocol + // + (gBS->AllocatePool) (EfiBootServicesData, sizeof (PCH_PCIE_IOTRAP_PROTOCOL), (VOID **)&PchPcieIoTrapProtocol); + PchPcieIoTrapProtocol->PcieTrapAddress = PchIoTrapContext.Address; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gPchPcieIoTrapProtocolGuid, + PchPcieIoTrapProtocol, + NULL + ); + + // + // Register the callback for S3 entry + // + SxDispatchContext.Type = SxS3; + SxDispatchContext.Phase = SxEntry; + Status = mSxDispatch->Register ( + mSxDispatch, + PchPcieS3EntryCallBack, + &SxDispatchContext, + &SxDispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm, IoTrap @ %x () End\n", PchIoTrapContext.Address)); + + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c new file mode 100644 index 0000000000..3c843616e4 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c @@ -0,0 +1,69 @@ +/** @file + PCH SPI Async SMI handler. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PchInitSmm.h" + +/// +/// Global variables +/// +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMI_DISPATCH_PROTOCOL *mPchSmiDispatchProtocol; + +/** + This hardware SMI handler will be run every time the flash write/earse happens. + + @param[in] DispatchHandle Not used + +**/ +VOID +EFIAPI +PchSpiAsyncCallback ( + IN EFI_HANDLE DispatchHandle + ) +{ + // + // Dummy SMI handler + // +} + +/** + This fuction install SPI ASYNC SMI handler. + + @retval EFI_SUCCESS Initialization complete. +**/ +EFI_STATUS +EFIAPI +InstallPchSpiAsyncSmiHandler ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + DEBUG ((DEBUG_INFO, "InstallPchSpiAsyncSmiHandler()\n")); + + /// + /// Get the PCH SMM dispatch protocol + /// + mPchSmiDispatchProtocol = NULL; + Status = gSmst->SmmLocateProtocol (&gPchSmiDispatchProtocolGuid, NULL, (VOID **) &mPchSmiDispatchProtocol); + ASSERT_EFI_ERROR (Status); + + /// + /// Register an SpiAsync callback function + /// + Handle = NULL; + Status = mPchSmiDispatchProtocol->SpiAsyncRegister ( + mPchSmiDispatchProtocol, + PchSpiAsyncCallback, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c new file mode 100644 index 0000000000..d843de3ad8 --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControlDriver.c @@ -0,0 +1,399 @@ +/** @file + This is the driver that publishes the SMM Control Protocol. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SmmControlDriver.h" + +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl; +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase; + +VOID +EFIAPI +DisablePendingSmis ( + VOID + ); + +/** + Fixup internal data pointers so that the services can be called in virtual mode. + + @param[in] Event The event registered. + @param[in] Context Event context. + +**/ +VOID +EFIAPI +SmmControlVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger)); + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear)); +} + +/** + SmmControl DXE RUNTIME Module Entry Point\n + - Introduction\n + The SmmControl module is a DXE RUNTIME driver that provides a standard way + for other drivers to trigger software SMIs. + + - @pre + - PCH Power Management I/O space base address has already been programmed. + If SmmControl Runtime DXE driver is run before Status Code Runtime Protocol + is installed and there is the need to use Status code in the driver, it will + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file. + - EFI_SMM_BASE2_PROTOCOL + - Documented in the System Management Mode Core Interface Specification. + + - @result + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL documented in + System Management Mode Core Interface Specification. + + @param[in] ImageHandle Handle for the image of this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_STATUS Results of the installation of the SMM Control Protocol +**/ +EFI_STATUS +EFIAPI +SmmControlDriverEntryInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n")); + + // + // Get the Power Management I/O space base address. We assume that + // this base address has already been programmed if this driver is + // being run. + // + mABase = PmcGetAcpiBase (); + + Status = EFI_SUCCESS; + if (mABase != 0) { + // + // Install the instance of the protocol + // + mSmmControl.Signature = SMM_CONTROL_PRIVATE_DATA_SIGNATURE; + mSmmControl.Handle = ImageHandle; + + mSmmControl.SmmControl.Trigger = Activate; + mSmmControl.SmmControl.Clear = Deactivate; + mSmmControl.SmmControl.MinimumTriggerPeriod = 0; + + // + // Install our protocol interfaces on the device's handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmmControl.Handle, + &gEfiSmmControl2ProtocolGuid, + &mSmmControl.SmmControl, + NULL + ); + } else { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SmmControlVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + // + // Disable any PCH SMIs that, for whatever reason, are asserted after the boot. + // + DisablePendingSmis (); + + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n")); + + return Status; +} + +/** + Trigger the software SMI + + @param[in] Data The value to be set on the software SMI data port + + @retval EFI_SUCCESS Function completes successfully +**/ +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Data + ) +{ + UINT32 OutputData; + UINT32 OutputPort; + + // + // Enable the APMC SMI + // + OutputPort = mABase + R_ACPI_IO_SMI_EN; + OutputData = IoRead32 ((UINTN) OutputPort); + OutputData |= (B_ACPI_IO_SMI_EN_APMC | B_ACPI_IO_SMI_EN_GBL_SMI); + DEBUG ( + (DEBUG_EVENT, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + OutputPort = R_PCH_IO_APM_CNT; + OutputData = Data; + + // + // Generate the APMC SMI + // + IoWrite8 ( + (UINTN) OutputPort, + (UINT8) (OutputData) + ); + + return EFI_SUCCESS; +} + +/** + Clear the SMI status + + + @retval EFI_SUCCESS The function completes successfully + @retval EFI_DEVICE_ERROR Something error occurred +**/ +EFI_STATUS +EFIAPI +SmmClear ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 OutputData; + UINT32 OutputPort; + + Status = EFI_SUCCESS; + + // + // Clear the Power Button Override Status Bit, it gates EOS from being set. + // + OutputPort = mABase + R_ACPI_IO_PM1_STS; + OutputData = B_ACPI_IO_PM1_STS_PRBTNOR; + DEBUG ( + (DEBUG_EVENT, + "The PM1 Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite16 ( + (UINTN) OutputPort, + (UINT16) (OutputData) + ); + + // + // Clear the APM SMI Status Bit + // + OutputPort = mABase + R_ACPI_IO_SMI_STS; + OutputData = B_ACPI_IO_SMI_STS_APM; + DEBUG ( + (DEBUG_EVENT, + "The SMI Status Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // Set the EOS Bit + // + OutputPort = mABase + R_ACPI_IO_SMI_EN; + OutputData = IoRead32 ((UINTN) OutputPort); + OutputData |= B_ACPI_IO_SMI_EN_EOS; + DEBUG ( + (DEBUG_EVENT, + "The SMI Control Port at address %x will be written to %x.\n", + OutputPort, + OutputData) + ); + IoWrite32 ( + (UINTN) OutputPort, + (UINT32) (OutputData) + ); + + // + // There is no need to read EOS back and check if it is set. + // This can lead to a reading of zero if an SMI occurs right after the SMI_EN port read + // but before the data is returned to the CPU. + // SMM Dispatcher should make sure that EOS is set after all SMI sources are processed. + // + return Status; +} + +/** + This routine generates an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in, out] CommandPort The buffer contains data to the command port + @param[in, out] DataPort The buffer contains data to the data port + @param[in] Periodic Periodic or not + @param[in] ActivationInterval Interval of periodic SMI + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This, + IN OUT UINT8 *CommandPort OPTIONAL, + IN OUT UINT8 *DataPort OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ) +{ + EFI_STATUS Status; + UINT8 Data; + + if (Periodic) { + DEBUG ((DEBUG_WARN, "Invalid parameter\n")); + return EFI_INVALID_PARAMETER; + } + + if (CommandPort == NULL) { + Data = 0xFF; + } else { + Data = *CommandPort; + } + // + // Clear any pending the APM SMI + // + Status = SmmClear (); + if (EFI_ERROR (Status)) { + return Status; + } + + return SmmTrigger (Data); +} + +/** + This routine clears an SMI + + @param[in] This The EFI SMM Control protocol instance + @param[in] Periodic Periodic or not + + @retval EFI Status Describing the result of the operation + @retval EFI_INVALID_PARAMETER Some parameter value passed is not supported +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic OPTIONAL + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + return SmmClear (); +} +/** + Disable all pending SMIs + +**/ +VOID +EFIAPI +DisablePendingSmis ( + VOID + ) +{ + UINT32 Data; + BOOLEAN SciEn; + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + Data = IoRead16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT); + SciEn = (BOOLEAN) ((Data & B_ACPI_IO_PM1_CNT_SCI_EN) == B_ACPI_IO_PM1_CNT_SCI_EN); + + if (!SciEn) { + // + // Clear any SMIs that double as SCIs (when SCI_EN==0) + // + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_STS, 0xFFFF); + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_EN, 0); + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT, 0); + IoWrite32 ( + (UINTN) mABase + R_ACPI_IO_GPE0_STS_127_96, + (UINT32)( B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS | + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE | + B_ACPI_IO_GPE0_STS_127_96_PME_B0 | + B_ACPI_IO_GPE0_STS_127_96_PME | + B_ACPI_IO_GPE0_STS_127_96_BATLOW | + B_ACPI_IO_GPE0_STS_127_96_RI | + B_ACPI_IO_GPE0_STS_127_96_SWGPE) + ); + // + // Disable WADT_EN by default can avoid the WADT SMI during POST time when the WADT_STS is set as a wake source. + // BIOS disable WADT_EN and keep WADT_STS into OS so OS can be aware of the wake source. + // + IoAnd32 ((UINTN) mABase + R_ACPI_IO_GPE0_EN_127_96, (UINT32) ~B_ACPI_IO_GPE0_EN_127_96_WADT); + } + // + // Clear and disable all SMIs that are unaffected by SCI_EN + // + GpioDisableAllGpiSmi (); + + GpioClearAllGpiSmiSts (); + + IoWrite32 ((UINTN) mABase + R_ACPI_IO_DEVACT_STS, 0x0000FFFF); + + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_STS, ~0u); + + // + // (Make sure to write this register last -- EOS re-enables SMIs for the PCH) + // + Data = IoRead32 ((UINTN) mABase + R_ACPI_IO_SMI_EN); + // + // clear all bits except those tied to SCI_EN + // + Data &= B_ACPI_IO_SMI_EN_BIOS_RLS; + // + // enable SMIs and specifically enable writes to APM_CNT. + // + Data |= B_ACPI_IO_SMI_EN_GBL_SMI | B_ACPI_IO_SMI_EN_APMC; + // + // NOTE: Default value of EOS is set in PCH, it will be automatically cleared Once the PCH asserts SMI# low, + // we don't need to do anything to clear it + // + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_EN, Data); +} + diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpi.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpi.c new file mode 100644 index 0000000000..458d137e4f --- /dev/null +++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Spi/Smm/PchSpi.c @@ -0,0 +1,310 @@ +/** @file + PCH SPI SMM Driver implements the SPI Host Controller Compatibility Interface. + + Copyright (c) 2019 Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Global variables +// +GLOBAL_REMOVE_IF_UNREFERENCED SPI_INSTANCE *mSpiInstance; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol; +// +// mPchSpiResvMmioAddr keeps the reserved MMIO range assiged to SPI. +// In SMM it always set back the reserved MMIO address to SPI BAR0 to ensure the MMIO range +// won't overlap with SMRAM range, and trusted. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSpiResvMmioAddr; + +/** + SPI Runtime SMM Module Entry Point\n + - Introduction\n + The SPI SMM module provide a standard way for other modules to use the PCH SPI Interface in SMM. + + - @pre + - EFI_SMM_BASE2_PROTOCOL + - Documented in System Management Mode Core Interface Specification . + + - @result + The SPI SMM driver produces @link _PCH_SPI_PROTOCOL PCH_SPI_PROTOCOL @endlink with GUID + gPchSmmSpiProtocolGuid which is different from SPI RUNTIME driver. + + - Integration Check List\n + - This driver supports Descriptor Mode only. + - This driver supports Hardware Sequence only. + - When using SMM SPI Protocol to perform flash access in an SMI handler, + and the SMI occurrence is asynchronous to normal mode code execution, + proper synchronization mechanism must be applied, e.g. disable SMI before + the normal mode SendSpiCmd() starts and re-enable SMI after + the normal mode SendSpiCmd() completes. + @note The implementation of SendSpiCmd() uses GBL_SMI_EN in + SMI_EN register (ABase + 30h) to disable and enable SMIs. But this may + not be effective as platform may well set the SMI_LOCK bit (i.e., PMC PCI Offset A0h [4]). + So the synchronization at caller level is likely needed. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable Global system service table. + + @retval EFI_SUCCESS Initialization complete. + @exception EFI_UNSUPPORTED The chipset is unsupported by this driver. + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver. + @retval EFI_DEVICE_ERROR Device error, driver exits abnormally. +**/ +EFI_STATUS +EFIAPI +InstallPchSpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Init PCH spi reserved MMIO address. + // + mSpiResvMmioAddr = PCH_SPI_BASE_ADDRESS; + + /// + /// Allocate pool for SPI protocol instance + /// + Status = gSmst->SmmAllocatePool ( + EfiRuntimeServicesData, /// MemoryType don't care + sizeof (SPI_INSTANCE), + (VOID **) &mSpiInstance + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mSpiInstance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem ((VOID *) mSpiInstance, sizeof (SPI_INSTANCE)); + /// + /// Initialize the SPI protocol instance + /// + Status = SpiProtocolConstructor (mSpiInstance); + if (EFI_ERROR (Status)) { + return Status; + } + /// + /// Install the SMM PCH_SPI_PROTOCOL interface + /// + Status = gSmst->SmmInstallProtocolInterface ( + &(mSpiInstance->Handle), + &gPchSmmSpiProtocolGuid, + EFI_NATIVE_INTERFACE, + &(mSpiInstance->SpiProtocol) + ); + if (EFI_ERROR (Status)) { + gSmst->SmmFreePool (mSpiInstance); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Acquire PCH spi mmio address. + If it is ever different from the preallocated address, reassign it back. + In SMM, it always override the BAR0 and returns the reserved MMIO range for SPI. + + @param[in] SpiInstance Pointer to SpiInstance to initialize + + @retval PchSpiBar0 return SPI MMIO address +**/ +UINTN +AcquireSpiBar0 ( + IN SPI_INSTANCE *SpiInstance + ) +{ + UINT32 SpiBar0; + // + // Save original SPI physical MMIO address + // + SpiBar0 = PciSegmentRead32 (SpiInstance->PchSpiBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG_BAR0_MASK); + + if (SpiBar0 != mSpiResvMmioAddr) { + // + // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE. + // + PciSegmentAnd8 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE); + PciSegmentWrite32 (SpiInstance->PchSpiBase + R_SPI_CFG_BAR0, mSpiResvMmioAddr); + PciSegmentOr8 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + } + // + // SPIBAR0 will be different before and after PCI enum so need to get it from SPI BAR0 reg. + // + return mSpiResvMmioAddr; +} + +/** + Release pch spi mmio address. Do nothing. + + @param[in] SpiInstance Pointer to SpiInstance to initialize + + @retval None +**/ +VOID +ReleaseSpiBar0 ( + IN SPI_INSTANCE *SpiInstance + ) +{ +} + +/** + This function is a hook for Spi to disable BIOS Write Protect + + @retval EFI_SUCCESS The protocol instance was properly initialized + @retval EFI_ACCESS_DENIED The BIOS Region can only be updated in SMM phase + +**/ +EFI_STATUS +EFIAPI +DisableBiosWriteProtect ( + VOID + ) +{ + UINT64 SpiBaseAddress; + + SpiBaseAddress = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SPI, + PCI_FUNCTION_NUMBER_PCH_SPI, + 0 + ); + // Write clear BC_SYNC_SS prior to change WPD from 0 to 1. + // + PciSegmentOr8 ( + SpiBaseAddress + R_SPI_CFG_BC + 1, + (B_SPI_CFG_BC_SYNC_SS >> 8) + ); + /// + /// Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b + /// Enable the access to the BIOS space for both read and write cycles + /// + PciSegmentOr8 ( + SpiBaseAddress + R_SPI_CFG_BC, + B_SPI_CFG_BC_WPD + ); + + /// + /// PCH BIOS Spec Section 3.7 BIOS Region SMM Protection Enabling + /// If the following steps are implemented: + /// - Set the EISS bit (SPI PCI Offset DCh [5]) = 1b + /// - Follow the 1st recommendation in section 3.6 + /// the BIOS Region can only be updated by following the steps bellow: + /// - Once all threads enter SMM + /// - Read memory location FED30880h OR with 00000001h, place the result in EAX, + /// and write data to lower 32 bits of MSR 1FEh (sample code available) + /// - Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b + /// - Modify BIOS Region + /// - Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b + /// + if ((PciSegmentRead8 (SpiBaseAddress + R_SPI_CFG_BC) & B_SPI_CFG_BC_EISS) != 0) { + PchSetInSmmSts (); + } + + return EFI_SUCCESS; +} + +/** + This function is a hook for Spi to enable BIOS Write Protect + + +**/ +VOID +EFIAPI +EnableBiosWriteProtect ( + VOID + ) +{ + UINT64 SpiBaseAddress; + + SpiBaseAddress = PCI_SEGMENT_LIB_ADDRESS ( + DEFAULT_PCI_SEGMENT_NUMBER_PCH, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_SPI, + PCI_FUNCTION_NUMBER_PCH_SPI, + 0 + ); + /// + /// Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b + /// Disable the access to the BIOS space for write cycles + /// + PciSegmentAnd8 ( + SpiBaseAddress + R_SPI_CFG_BC, + (UINT8) (~B_SPI_CFG_BC_WPD) + ); + + /// + /// Check if EISS bit is set + /// + if (((PciSegmentRead8 (SpiBaseAddress + R_SPI_CFG_BC)) & B_SPI_CFG_BC_EISS) == B_SPI_CFG_BC_EISS) { + PchClearInSmmSts (); + } +} + +/** + Check if it's granted to do flash write. + + @retval TRUE It's secure to do flash write. + @retval FALSE It's not secure to do flash write. +**/ +BOOLEAN +IsSpiFlashWriteGranted ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 CpuIndex; + UINT64 ProcessorId; + + if (mSmmCpuProtocol == NULL) { + Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpuProtocol); + ASSERT_EFI_ERROR (Status); + if (mSmmCpuProtocol == NULL) { + return TRUE; + } + } + + for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) { + Status = mSmmCpuProtocol->ReadSaveState ( + mSmmCpuProtocol, + sizeof (ProcessorId), + EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID, + CpuIndex, + &ProcessorId + ); + // + // If the processor is in SMM at the time the SMI occurred, + // it will return success. Otherwise, EFI_NOT_FOUND is returned. + // + if (EFI_ERROR (Status)) { + return FALSE; + } + } + + return TRUE; +} -- 2.16.2.windows.1