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