diff options
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib')
6 files changed, 2492 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.cif b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.cif new file mode 100644 index 0000000..bffca56 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.cif @@ -0,0 +1,12 @@ +<component> + name = "PchPciExpressHelpersLib" + category = ModulePart + LocalRoot = "ReferenceCode\Chipset\LynxPoint\Library\PchPciExpressHelpersLib" + RefName = "PchPciExpressHelpersLib" +[files] +"PchPciExpressHelpersLib.sdl" +"PchPciExpressHelpersLib.mak" +"PchPciExpressHelpersLibrary.c" +"PchPciExpressHelpersLibrary.h" +"PchPciExpressHelpersLib.inf" +<endComponent> diff --git a/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.inf b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.inf new file mode 100644 index 0000000..aa731f8 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.inf @@ -0,0 +1,66 @@ +## @file +# Component description file for the PchPciExpressHelpersLib +# +#@copyright +# Copyright (c) 2008 - 2012 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# This file contains a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = PchPciExpressHelpersLib +COMPONENT_TYPE = LIBRARY + +[sources.common] + PchPciExpressHelpersLibrary.c + +[sources.ia32] + + +[sources.x64] + + +[sources.ipf] + + +[sources.ebc] + + +[includes.common] + . + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT) + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Protocol/PchPlatformPolicy + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework/Include + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + +[libraries.common] + PchPlatformLib + +[libraries.ia32] + + +[libraries.x64] + + +[nmake.common]
\ No newline at end of file diff --git a/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.mak b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.mak new file mode 100644 index 0000000..e8ce73e --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.mak @@ -0,0 +1,88 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchLib/PchPciExpressHelpersLib/PchPciExpressHelpersLib.mak 2 10/16/12 4:57a Scottyang $ +# +# $Revision: 2 $ +# +# $Date: 10/16/12 4:57a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchLib/PchPciExpressHelpersLib/PchPciExpressHelpersLib.mak $ +# +# 2 10/16/12 4:57a Scottyang +# [TAG] EIP84720 +# [Category] Improvement +# [Description] Support Hot-Plug in Shark Bay +# [Files] PchRootPort.c, PchPcie.asl, PchPciExpressHelpersLib.mak, +# PchPciExpressHlpersLibrary.c, SB.sdl +# +# 1 2/08/12 8:47a Yurenlai +# Intel Lynx Point/SB eChipset initially releases. +# +#************************************************************************* +all : PchPciExpressHelpersLib + +PchPciExpressHelpersLib : PchPciExpressHelpersDxeLib PchPciExpressHelpersPeiLib + +$(PchPciExpressHelpersDxeLib_LIB) : PchPciExpressHelpersDxeLib +$(PchPciExpressHelpersPeiLib_LIB) : PchPciExpressHelpersPeiLib + +PchPciExpressHelpersDxeLib : $(BUILD_DIR)\PchPciExpressHelpersLib.mak PchPciExpressHelpersLibDxeBin +PchPciExpressHelpersPeiLib : $(BUILD_DIR)\PchPciExpressHelpersLib.mak PchPciExpressHelpersLibPeiBin + +$(BUILD_DIR)\PchPciExpressHelpersLib.mak : $(PchPciExpressHelpersLib_DIR)\$(@B).cif $(PchPciExpressHelpersLib_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(PchPciExpressHelpersLib_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +PchPciExpressHelpersLib_INCLUDES=\ + $(EDK_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + $(INTEL_PCH_INCLUDES)\ + +PchPciExpressHelpersLib_DEFINES=\ + $(CFLAGS)\ + +PchPciExpressHelpersLibDxeBin: + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\PchPciExpressHelpersLib.mak all \ + "MY_INCLUDES=$(PchPciExpressHelpersLib_INCLUDES)" \ + TYPE=LIBRARY LIBRARIES= \ + LIBRARY_NAME=$(PchPciExpressHelpersDxeLib_LIB) + +PchPciExpressHelpersLibPeiBin: +!IF "$(x64_BUILD)"=="1" + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS) BUILD_DIR=$(BUILD_DIR)\IA32\ +!ELSE + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ +!ENDIF + /f $(BUILD_DIR)\PchPciExpressHelpersLib.mak all \ + "MY_INCLUDES=$(PchPciExpressHelpersLib_INCLUDES)" \ + "MY_DEFINES=$(PchPciExpressHelpersLib_DEFINES)" \ + LIBRARIES= \ + TYPE=PEI_LIBRARY LIBRARY_NAME=$(PchPciExpressHelpersPeiLib_LIB) +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.sdl b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.sdl new file mode 100644 index 0000000..1bb4ebc --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLib.sdl @@ -0,0 +1,83 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchLib/PchPciExpressHelpersLib/PchPciExpressHelpersLib.sdl 1 2/08/12 8:47a Yurenlai $ +# +# $Revision: 1 $ +# +# $Date: 2/08/12 8:47a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchLib/PchPciExpressHelpersLib/PchPciExpressHelpersLib.sdl $ +# +# 1 2/08/12 8:47a Yurenlai +# Intel Lynx Point/SB eChipset initially releases. +# +#************************************************************************* +TOKEN + Name = "PchPciExpressHelpersLib_SUPPORT" + Value = "1" + Help = "Main switch to enable PchPciExpressHelpersLib support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Master = Yes +End + +PATH + Name = "PchPciExpressHelpersLib_DIR" +End + +MODULE + File = "PchPciExpressHelpersLib.mak" + Help = "Includes PchPciExpressHelpersLib.mak to Project" +End + +ELINK + Name = "PchPciExpressHelpersDxeLib_LIB" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "$(BUILD_DIR)\PchPciExpressHelpersDxeLib_Lib.lib" + Parent = "PchPciExpressHelpersDxeLib_LIB" + InvokeOrder = AfterParent +End + +ELINK + Name = "PchPciExpressHelpersPeiLib_LIB" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "$(BUILD_DIR)\PchPciExpressHelpersPeiLib_Lib.lib" + Parent = "PchPciExpressHelpersPeiLib_LIB" + InvokeOrder = AfterParent +End +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLibrary.c b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLibrary.c new file mode 100644 index 0000000..7d622b3 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLibrary.c @@ -0,0 +1,2201 @@ +/** @file + This file contains routines that support PCI Express initialization + +@copyright + Copyright (c) 1999 - 2013 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchPciExpressHelpersLibrary.h" +// AMI_OVERRIDE, [EIP84720]> +#include "Token.h" +// AMI_OVERRIDE, [EIP84720]< + +/** + Find the Offset to a given Capabilities ID + CAPID list: + 0x01 = PCI Power Management Interface + 0x04 = Slot Identification + 0x05 = MSI Capability + 0x10 = PCI Express Capability + + @param[in] Bus Pci Bus Number + @param[in] Device Pci Device Number + @param[in] Function Pci Function Number + @param[in] CapId CAPID to search for + + @retval 0 CAPID not found + @retval Other CAPID found, Offset of desired CAPID +**/ +UINT8 +PcieFindCapId ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Function, + IN UINT8 CapId + ) +{ + UINT8 CapHeaderOffset; + UINT8 CapHeaderId; + UINTN DeviceBase; + + DeviceBase = MmPciAddress (0, Bus, Device, Function, 0); + + /// + /// Check the header layout to determine the Offset of Capabilities Pointer Register + /// + if ((MmioRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) & HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE)) { + /// + /// If CardBus bridge, start at Offset 0x14 + /// + CapHeaderOffset = 0x14; + } else { + /// + /// Otherwise, start at Offset 0x34 + /// + CapHeaderOffset = 0x34; + } + /// + /// Get Capability Header, A pointer value of 00h is used to indicate the last capability in the list. + /// + CapHeaderId = 0; + CapHeaderOffset = MmioRead8 (DeviceBase + CapHeaderOffset) & ((UINT8) ~(BIT0 | BIT1)); + while (CapHeaderOffset != 0 && CapHeaderId != 0xFF) { + CapHeaderId = MmioRead8 (DeviceBase + CapHeaderOffset); + if (CapHeaderId == CapId) { + return CapHeaderOffset; + } + /// + /// Each capability must be DWORD aligned. + /// The bottom two bits of all pointers (including the initial pointer at 34h) are reserved + /// and must be implemented as 00b although software must mask them to allow for future uses of these bits. + /// + CapHeaderOffset = MmioRead8 (DeviceBase + CapHeaderOffset + 1) & ((UINT8) ~(BIT0 | BIT1)); + } + + return 0; +} + +/** + Search and return the offset of desired Pci Express Capability ID + CAPID list: + 0x0001 = Advanced Error Rreporting Capability + 0x0002 = Virtual Channel Capability + 0x0003 = Device Serial Number Capability + 0x0004 = Power Budgeting Capability + + @param[in] Bus Pci Bus Number + @param[in] Device Pci Device Number + @param[in] Function Pci Function Number + @param[in] CapId Extended CAPID to search for + + @retval 0 CAPID not found + @retval Other CAPID found, Offset of desired CAPID +**/ +UINT16 +PcieFindExtendedCapId ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Function, + IN UINT16 CapId + ) +{ + UINT16 CapHeaderOffset; + UINT16 CapHeaderId; + UINTN DeviceBase; + + DeviceBase = MmPciAddress (0, Bus, Device, Function, 0); + + /// + /// Start to search at Offset 0x100 + /// Get Capability Header, A pointer value of 00h is used to indicate the last capability in the list. + /// + CapHeaderId = 0; + CapHeaderOffset = 0x100; + while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) { + CapHeaderId = MmioRead16 (DeviceBase + CapHeaderOffset); + if (CapHeaderId == CapId) { + return CapHeaderOffset; + } + /// + /// Each capability must be DWORD aligned. + /// The bottom two bits of all pointers are reserved and must be implemented as 00b + /// although software must mask them to allow for future uses of these bits. + /// + CapHeaderOffset = (MmioRead16 (DeviceBase + CapHeaderOffset + 2) >> 4) & ((UINT16) ~(BIT0 | BIT1)); + } + + return 0; +} + +/** + Map a TC to VC0 for port and endpoint + + @param[in] Bus1 The bus number of the port + @param[in] Device1 The device number of the port + @param[in] Function1 The function number of the port + @param[in] Bus2 The bus number of the endpoint + @param[in] Device2 The device number of the endpoint + @param[in] TCx The TC number + + @exception EFI_UNSUPPORTED Unsupported operation. + @retval EFI_SUCCESS Successfully completed. +**/ +EFI_STATUS +PcieMapTcxVc0 ( + IN UINT8 Bus1, + IN UINT8 Device1, + IN UINT8 Function1, + IN UINT8 Bus2, + IN UINT8 Device2, + IN UINT8 TCx + ) +{ + UINT16 Offset; + UINTN DeviceBase1; + UINTN DeviceBase2; + UINT8 DeviceIndex; + UINT8 FunctionIndex; + UINT8 Function2; + + DeviceBase1 = MmPciAddress (0, Bus1, Device1, Function1, 0); + + /// + /// Set TCx-VC0 value on the port + /// + Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2); + if (Offset == 0) { + return EFI_UNSUPPORTED; + } + + MmioAndThenOr8 (DeviceBase1 + Offset + 0x014, (UINT8) (~0xF), 1); + MmioWrite8 (DeviceBase1 + Offset + 0x014, (UINT8) (1 << TCx)); + + /// + /// Set TCx-VC0 value on the Endpoint + /// + for (DeviceIndex = 0; DeviceIndex <= Device2; DeviceIndex++) { + DeviceBase2 = MmPciAddress (0, Bus2, DeviceIndex, 0, 0); + if (MmioRead16 (DeviceBase2 + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + continue; + } + /// + /// Check if EndPoint device is Multi-Function Device + /// + if (MmioRead8 (DeviceBase2 + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) { + /// + /// If multi-function Device, check function 0-7 + /// + Function2 = PCI_MAX_FUNC; + } else { + /// + /// Otherwise, check function 0 only + /// + Function2 = 0; + } + + for (FunctionIndex = 0; FunctionIndex <= Function2; FunctionIndex++) { + DeviceBase2 = MmPciAddress (0, Bus2, DeviceIndex, FunctionIndex, 0); + + Offset = PcieFindExtendedCapId (Bus2, DeviceIndex, FunctionIndex, 2); + if (Offset == 0) { + continue; + } + + MmioAndThenOr8 (DeviceBase2 + Offset + 0x014, (UINT8) (~0xF), 1); + MmioWrite8 (DeviceBase2 + Offset + 0x014, (UINT8) (1 << TCx)); + } + } + + return EFI_SUCCESS; +} + +/** + Set Common clock to Root port and Endpoint PCI device + + @param[in] Bus1 Root port Pci Bus Number + @param[in] Device1 Root port Pci Device Number + @param[in] Function1 Root port Pci Function Number + @param[in] Bus2 Endpoint Pci Bus Number + @param[in] Device2 Endpoint Pci Device Number + + @exception EFI_UNSUPPORTED Unsupported operation. + @retval EFI_SUCCESS VC mapping correctly initialized +**/ +EFI_STATUS +PcieSetCommonClock ( + IN UINT8 Bus1, + IN UINT8 Device1, + IN UINT8 Function1, + IN UINT8 Bus2, + IN UINT8 Device2 + ) +{ + UINT8 CapOffset1; + UINT8 CapOffset2; + BOOLEAN CommonClockSupport; + EFI_STATUS Status; + UINTN DeviceBase1; + UINTN DeviceBase2; + UINT16 RegData16; + UINT8 DeviceIndex; + UINT8 FunctionIndex; + UINT8 Function2; + + DeviceBase1 = MmPciAddress (0, Bus1, Device1, Function1, 0); + + /// + /// Get the pointer to the Port PCI Express Capability Structure. + /// + CommonClockSupport = FALSE; + CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (CapOffset1 == 0) { + return EFI_UNSUPPORTED; + } + /// + /// Check the Port Slot Clock Configuration Bit. + /// + if ((MmioRead16 (DeviceBase1 + CapOffset1 + 0x012) & BIT12) == 0) { + return EFI_UNSUPPORTED; + } + + for (DeviceIndex = 0; DeviceIndex <= Device2; DeviceIndex++) { + DeviceBase2 = MmPciAddress (0, Bus2, DeviceIndex, 0, 0); + if (MmioRead16 (DeviceBase2 + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + continue; + } + /// + /// Check if EndPoint device is Multi-Function Device + /// + if (MmioRead8 (DeviceBase2 + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) { + /// + /// If multi-function Device, check function 0-7 + /// + Function2 = PCI_MAX_FUNC; + } else { + /// + /// Otherwise, check function 0 only + /// + Function2 = 0; + } + + for (FunctionIndex = 0; FunctionIndex <= Function2; FunctionIndex++) { + DeviceBase2 = MmPciAddress (0, Bus2, DeviceIndex, FunctionIndex, 0); + /// + /// Check the Endpoint Slot Clock Configuration Bit. + /// + CapOffset2 = PcieFindCapId (Bus2, DeviceIndex, FunctionIndex, EFI_PCI_CAPABILITY_ID_PCIEXP); + if ((CapOffset2 != 0) && ((MmioRead16 (DeviceBase2 + CapOffset2 + 0x012) & BIT12) != 0)) { + /// + /// Common clock is supported, set common clock bit on root port + /// and the endpoint + /// + if (CommonClockSupport == FALSE) { + MmioOr8 (DeviceBase1 + CapOffset1 + 0x010, BIT6); + CommonClockSupport = TRUE; + } + + MmioOr8 (DeviceBase2 + CapOffset2 + 0x010, BIT6); + } + } + } + /// + /// If common clock not supported on root port and endpoint, return EFI_UNSUPPORTED + /// + if (CommonClockSupport == FALSE) { + Status = EFI_UNSUPPORTED; + } else { + Status = EFI_SUCCESS; + } + /// + /// Set Pci + D4h Bit 6 and Bit 12 to 1 for root port only + /// + if (Bus1 == 0) { + MmioOr32 (DeviceBase1 + 0xD4, ((UINT32)(BIT6 | BIT12))); + } + /// + /// Retrain the Link per PCI Express Specification. + /// + MmioOr8 (DeviceBase1 + CapOffset1 + 0x010, BIT5); + +// AMI_OVERRIDE >>> +#ifdef PCIE_CLEAR_RETRAIN_BIT_SUPPORT_FLAG + PchPmTimerStall (1); + + if((MmioRead8 (DeviceBase1 + CapOffset1 + 0x010) & BIT5) == 1){ + MmioAnd8 (DeviceBase1 + CapOffset1 + 0x010, BIT5); + } +#endif +// AMI_OVERRIDE <<< + + /// + /// Wait until Re-Training has completed. + /// + do { + RegData16 = MmioRead16 (DeviceBase1 + CapOffset1 + 0x012) & BIT11; + } while (RegData16 != 0); + + return Status; +} + +/** + This function enables the CLKREQ# PM on all the end point functions + + @param[in] Bus Pci Bus Number + @param[in] Device Pci Device Number + @param[in] RootFunction Rootport Function Number + + @retval None +**/ +VOID +PcieSetClkreq ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 RootFunction + ) +{ + UINT8 CapOffset; + UINTN DeviceBase; + UINT8 DeviceIndex; + UINT8 FunctionIndex; + UINT8 Function; + UINT32 Data32; + UINT16 GpioBase; + BOOLEAN ClkreqPerPortSupported; + PCH_SERIES PchSeries; + UINT8 RootPortNumber; + UINT32 RootComplexBar; + + + PchSeries = GetPchSeries(); + + if (PchSeries == PchLp) { + GpioBase = MmioRead16 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_GPIO_BASE) + ) & B_PCH_LPC_GPIO_BASE_BAR; + + RootComplexBar = PCH_RCRB_BASE; + RootPortNumber = GetPchPcieRpNumber(RootComplexBar, RootFunction); + Data32 = (IoRead32 ((UINTN) (GpioBase + R_PCH_GP_X_CONFIG0(18 + RootPortNumber))) & B_PCH_GPIO_OWN0_GPIO_USE_SEL); + + if (Data32 != 0) { + /// + /// CLKREQ not supported on root port + /// + return; + } + } + + for (DeviceIndex = 0; DeviceIndex <= Device; DeviceIndex++) { + DeviceBase = MmPciAddress (0, Bus, DeviceIndex, 0, 0); + if (MmioRead16 (DeviceBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + continue; + } + + ClkreqPerPortSupported = TRUE; + + /// + /// Check if EndPoint device is Multi-Function Device + /// + if (MmioRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) { + /// + /// If multi-function Device, check function 0-7 + /// + Function = PCI_MAX_FUNC; + } else { + /// + /// Otherwise, check function 0 only + /// + Function = 0; + } + /// + /// Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if + /// exists then enable the CLKREQ# bit (BIT8) on that function + /// + for (FunctionIndex = 0; FunctionIndex <= Function; FunctionIndex++) { + /// + /// Find the PCIe Cap Id (offset 10h) + /// + CapOffset = PcieFindCapId (Bus, DeviceIndex, FunctionIndex, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (CapOffset == 0) { + continue; + } + + DeviceBase = MmPciAddress (0, Bus, DeviceIndex, FunctionIndex, 0); + /// + /// Check if CLKREQ# is supported by the endpoints + /// + if ((MmioRead32 (DeviceBase + CapOffset + 0x0C) & BIT18) == 0) { + /// + /// CLKREQ# is not supported so dont do anything + /// + ClkreqPerPortSupported = FALSE; + break; + } + } + + if (ClkreqPerPortSupported == FALSE) { + continue; + } + /// + /// Now enable the CLKREQ# + /// + for (FunctionIndex = 0; FunctionIndex <= Function; FunctionIndex++) { + /// + /// Find the PCIe Cap Id (offset 10h) + /// + CapOffset = PcieFindCapId (Bus, DeviceIndex, FunctionIndex, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (CapOffset == 0) { + continue; + } + + DeviceBase = MmPciAddress (0, Bus, DeviceIndex, FunctionIndex, 0); + MmioOr16 (DeviceBase + CapOffset + 0x010, BIT8); + } + } +} + +/** + This function get or set the Max Payload Size on all the end point functions + + @param[in] EndPointBus The Bus Number of the Endpoint + @param[in] EndPointDevice The Device Number of the Endpoint + @param[in, out] MaxPayload The Max Payolad Size of the root port + @param[in] Operation True: Set the Max Payload Size on all the end point functions + False: Get the Max Payload Size on all the end point functions + + @retval EFI_SUCCESS Successfully completed. +**/ +EFI_STATUS +PcieMaxPayloadSize ( + IN UINT8 EndPointBus, + IN UINT8 EndPointDevice, + IN OUT UINT16 *MaxPayload, + IN BOOLEAN Operation + ) +{ + UINTN DeviceBase; + UINT8 PcieCapOffset; + UINT16 EndPointMaxPayload; + UINT8 DeviceIndex; + UINT8 FunctionIndex; + UINT8 EndPointFunction; + + /// + /// Obtain the Max Payload Size for all the end point functions + /// + for (DeviceIndex = 0; DeviceIndex <= EndPointDevice; DeviceIndex++) { + DeviceBase = MmPciAddress (0, EndPointBus, DeviceIndex, 0, 0); + if (MmioRead16 (DeviceBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + continue; + } + /// + /// Check if EndPoint device is Multi-Function Device + /// + if (MmioRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) { + /// + /// If multi-function Device, check function 0-7 + /// + EndPointFunction = PCI_MAX_FUNC; + } else { + /// + /// Otherwise, check function 0 only + /// + EndPointFunction = 0; + } + + for (FunctionIndex = 0; FunctionIndex <= EndPointFunction; FunctionIndex++) { + DeviceBase = MmPciAddress (0, EndPointBus, DeviceIndex, FunctionIndex, 0); + if (MmioRead16 (DeviceBase + 0x0) != 0xFFFF) { + /// + /// Get the pointer to the Endpoint PCI Express Capability Structure. + /// + PcieCapOffset = PcieFindCapId (EndPointBus, DeviceIndex, FunctionIndex, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (PcieCapOffset == 0) { + continue; + } + + if (Operation == TRUE) { + /// + /// Set the Max Payload Size of the end point function + /// + MmioAndThenOr16 ( + DeviceBase + PcieCapOffset + 0x08, + (UINT16)~(BIT7 | BIT6 | BIT5), + *MaxPayload << 5 + ); + } else { + /// + /// Get the end point function Max Payload Size support + /// + EndPointMaxPayload = MmioRead16 (DeviceBase + PcieCapOffset + 0x04) & (BIT2 | BIT1 | BIT0); + /// + /// Obtain the minimum Max Payload Size between the PCIE root Port and the end point functions + /// + if (*MaxPayload > EndPointMaxPayload) { + *MaxPayload = EndPointMaxPayload; + } + } + } + } + } + + return EFI_SUCCESS; +} + +/** + This function disable the forwarding of EOI messages unless it discovers + an IOAPIC behind this root port. + + @param[in] RootBus The Bus Number of the root port + @param[in] RootDevice The Device Number of the root port + @param[in] RootFunction The Function Number of the root port + @param[in] EndPointBus The Bus Number of the Endpoint + @param[in] EndPointDevice The Device Number of the Endpoint + + @exception EFI_UNSUPPORTED Unsupported operation. + @retval EFI_SUCCESS Successfully completed. +**/ +EFI_STATUS +PcieSetEoiFwdDisable ( + IN UINT8 RootBus, + IN UINT8 RootDevice, + IN UINT8 RootFunction, + IN UINT8 EndPointBus, + IN UINT8 EndPointDevice + ) +{ + BOOLEAN IoApicBehind; + UINTN RootDeviceBase; + UINTN DeviceBase; + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseClassCode; + UINT8 DeviceIndex; + UINT8 FunctionIndex; + UINT8 EndPointFunction; + + IoApicBehind = FALSE; + RootDeviceBase = MmPciAddress (0, RootBus, RootDevice, RootFunction, 0); + + /// + /// Check if an IOAPIC behind the root port + /// + for (DeviceIndex = 0; DeviceIndex <= EndPointDevice; DeviceIndex++) { + DeviceBase = MmPciAddress (0, EndPointBus, DeviceIndex, 0, 0); + if (MmioRead16 (DeviceBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + continue; + } + /// + /// Check if EndPoint device is Multi-Function Device + /// + if (MmioRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) { + /// + /// If multi-function Device, check function 0-7 + /// + EndPointFunction = PCI_MAX_FUNC; + } else { + /// + /// Otherwise, check function 0 only + /// + EndPointFunction = 0; + } + + for (FunctionIndex = 0; FunctionIndex <= EndPointFunction; FunctionIndex++) { + DeviceBase = MmPciAddress (0, EndPointBus, DeviceIndex, FunctionIndex, 0); + BaseClassCode = MmioRead8 (DeviceBase + PCI_CLASSCODE_OFFSET + 2); + SubClassCode = MmioRead8 (DeviceBase + PCI_CLASSCODE_OFFSET + 1); + ProgInterface = MmioRead8 (DeviceBase + PCI_CLASSCODE_OFFSET); + + if ((BaseClassCode == PCI_CLASS_SYSTEM_PERIPHERAL) && + (SubClassCode == PCI_SUBCLASS_PIC) && + ((ProgInterface == PCI_IF_APIC_CONTROLLER) || + (ProgInterface == PCI_IF_APIC_CONTROLLER2))) { + IoApicBehind = TRUE; + } + } + } + /// + /// PCH BIOS Spec Rev 0.5.0, Section 8.14 Additional PCI Express* Programming Steps + /// Step 20 + /// If there is no IOAPIC behind the root port, set EOI Forwarding Disable bit (B0:D28:F0-F7:D4h[1]) to 1b. + /// + if (IoApicBehind == FALSE) { + #ifdef HOTPLUG_EOI_FLAG // AMI_OVERRIDE, [EIP84720]> + MmioOr8 (RootDeviceBase + 0xD4, (UINT8) (BIT1)); + #else + //Supporting _RMV method in asl code, and reading hotplug capability register of root port + //if hotplug disable, then set EOI Forwarding Disable bit + #ifdef TBT_UP_PORT_FUNC_FLAG + if((TBT_UP_PORT_FUNC == RootFunction) || (!(MmioRead8 (DeviceBase + 0x54) & 0x40))){ + #else + if(!(MmioRead8 (DeviceBase + 0x54) & 0x40)){ + #endif + MmioOr8 (RootDeviceBase + 0xD4, (UINT8) (BIT1)); + } + #endif // AMI_OVERRIDE, [EIP84720]< + } + + return EFI_SUCCESS; +} + +typedef enum { + CalculateAspm, + ManualAspm, + SetAspm +} OPERATION; + +/** + This function compares the actual latency in LatencyValue1 + with actual latency in LatencyValue2 and stores the minimum + back to LatencyValue1, in the required format. + If this is the first call, then LatencyValue1 will be replaced by LatencyValue2. + + @param[in, out] LatencyValue1 - Current latency value + @param[in] LatencyValue2 - Latency value from the Table + + @retval None +**/ +VOID +DetermineLatencyValue ( + IN OUT UINT16 *LatencyValue1, + IN UINT16 *LatencyValue2 + ) +{ + ASSERT (LTR_SCALE_VALUE (*LatencyValue1) < 6); + ASSERT (LTR_SCALE_VALUE (*LatencyValue2) < 6); + /// + /// If there are more than one device behind a bridge that are part of the override table, + /// store the lower latency value and corresponding scale bits back to LatencyValue1 + /// + if ((LTR_LATENCY_NS(*LatencyValue1) == 0) || (LTR_LATENCY_NS(*LatencyValue1) > LTR_LATENCY_NS(*LatencyValue2))) { + *LatencyValue1 = *LatencyValue2; + } +} + +/** + Calculate/Set EndPoint device Power management settings + + @param[in] RootDeviceBase The Root Port PCI Express address + @param[in] RootPcieCapOffset The pointer to the Root Port PCI Express Capability Structure + @param[in] EndPointBus The Bus Number of the Endpoint + @param[in] NumOfDevAspmOverride Number of Device specific ASPM policy override items + @param[in] DevAspmOverride Pointer to array of Device specific ASPM policy override items + @param[in, out] LinkAspmVal Resulting Link ASPM value programmed + @param[in] Operation Operation Types + @param[in] NumOfDevLtrOverride Number of Device specific LTR override items + @param[in] DevLtrOverride Pointer to array of Device specific LTR policy override items + @param[in, out] LtrOverrideVal Resulting LTR override value to be programmed + @param[in] RootL1SubstateExtCapOffset The register offset of Root Port L1 Substates + @param[in, out] L1SubstatesSupported Input and return the result of L1 Substates support + @param[in] L1SubstatesConfig L1 Substates configurations + @param[in, out] PortCommonModeRestoreTime Input and return common mode restore time of L1 Substate setting + @param[in, out] PortTpowerOnValue Input and return power on value of L1 Substate setting + @param[in, out] PortTpowerOnScale Input and return power on scale of L1 Substate setting + @param[in] PchPwrOptPcie Pcie Power Optimizer Configuration + @param[in, out] AspmOverride Input and return the Aspm Override enable for pre-1.1 devices + @param[in, out] ClkreqPerPortSupported Input to check if clkreq per port is supportted + @param[in, out] RpAndEndPointsLtrSupported Return to check if all endpoints support LTR + @param[in] PolicyRevision Policy revision for codes compatibility + + @retval EFI_SUCCESS Successfully completed + @retval EFI_NOT_FOUND Can not find device + @retval EFI_OUT_OF_RESOURCES The endpoint device is a bridge, but the Subordinate Bus Number of + the root port is not greater than its Secondary Bus Number. You may + get this error if PCI emulation is not done before this function gets + called and the platform policy settings of "TempRootPortBusNumMax" and + "TempRootPortBusNumMin" do not provide enough resource for temp bus + number usage. +**/ +EFI_STATUS +PcieEndPointPm ( + IN UINTN RootDeviceBase, + IN UINT32 RootPcieCapOffset, + IN UINT8 EndPointBus, + IN UINT8 NumOfDevAspmOverride, + IN PCH_PCIE_DEVICE_ASPM_OVERRIDE *DevAspmOverride, + IN OUT UINT16 *LinkAspmVal, + IN OPERATION Operation, + IN UINT8 NumOfDevLtrOverride, + IN PCH_PCIE_DEVICE_LTR_OVERRIDE *DevLtrOverride, + IN OUT UINT32 *LtrOverrideVal, + IN UINT16 RootL1SubstateExtCapOffset, + IN OUT BOOLEAN *L1SubstatesSupported, + IN PCH_PCIE_EXPRESS_L1SUBSTATES_CONTROL L1SubstatesConfig, + IN OUT UINT32 *PortCommonModeRestoreTime, + IN OUT UINT32 *PortTpowerOnValue, + IN OUT UINT32 *PortTpowerOnScale, + IN PCH_PCIE_PWR_OPT *PchPwrOptPcie, + IN OUT BOOLEAN *AspmOverride, + IN BOOLEAN *ClkreqPerPortSupported, + IN OUT BOOLEAN *RpAndEndPointsLtrSupported, + IN UINT8 PolicyRevision + ) +{ + EFI_STATUS Status; + UINTN EndPointBase; + UINT8 EndPointFunction; + UINT8 EndPointPcieCapOffset; + UINT8 PcieDeviceIndex; + UINT16 EndPointAspm; + UINT16 EndPointVendorId; + UINT16 EndPointDeviceId; + UINT8 EndPointRevId; + UINT8 EndPointBaseClassCode; + UINT8 EndPointSubClassCode; + UINT32 PortLxLat; + UINT32 EndPointLxLat; + UINT32 LxLat; + UINT8 DownStreamBusMin; + UINT8 ClassCode; + UINT8 RootDevSubBusNum; + BOOLEAN BusAssign; + UINT8 DeviceIndex; + UINT8 FunctionIndex; + UINT16 LtrExtendedCapOffset; + UINT32 DeviceCapabilities2; + UINT16 DefaultMaxLatency; + UINT16 Data16; + UINT32 Data32; + UINT16 EndPointL1SubStateCapOffset; + UINT32 RootDeviceL1Substates; + UINT32 EndPointL1Substates; + UINT8 EndPointPortCommonModeRestoreTime; + UINT8 EndPointTpowerOnScale; + UINT8 EndPointTpowerOnValue; + UINT32 Multiplier[4] = {2, 10, 100, 0}; + UINT32 EndPointL1SubstCapMask; + PCH_SERIES PchSeries; + + DefaultMaxLatency = 0; + PchSeries = GetPchSeries(); + for (DeviceIndex = 0; DeviceIndex <= PCI_MAX_DEVICE; DeviceIndex++) { + EndPointBase = MmPciAddress (0, EndPointBus, DeviceIndex, 0, 0); + if (MmioRead16 (EndPointBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + continue; + } + /// + /// Check if EndPoint device is Multi-Function Device + /// + if (MmioRead8 (EndPointBase + PCI_HEADER_TYPE_OFFSET) & HEADER_TYPE_MULTI_FUNCTION) { + /// + /// If multi-function Device, check function 0-7 + /// + EndPointFunction = PCI_MAX_FUNC; + } else { + /// + /// Otherwise, check function 0 only + /// + EndPointFunction = 0; + } + + for (FunctionIndex = 0; FunctionIndex <= EndPointFunction; FunctionIndex++) { + /// + /// Get the pointer to the Endpoint PCI Express Capability Structure. + /// + EndPointPcieCapOffset = PcieFindCapId (EndPointBus, DeviceIndex, FunctionIndex, EFI_PCI_CAPABILITY_ID_PCIEXP); + + if (EndPointPcieCapOffset == 0) { + if (FunctionIndex < EndPointFunction) { + continue; + } else { + return EFI_NOT_FOUND; + } + } + EndPointBase = MmPciAddress (0, EndPointBus, DeviceIndex, FunctionIndex, 0); + EndPointVendorId = MmioRead16 (EndPointBase + R_PCH_PCIE_VENDOR_ID); + EndPointDeviceId = MmioRead16 (EndPointBase + R_PCH_PCIE_DEVICE_ID); + EndPointRevId = MmioRead8 (EndPointBase + R_PCH_PCIE_RID); + EndPointL1SubStateCapOffset = 0; + RootDeviceL1Substates = 0; + EndPointL1Substates = 0; + EndPointL1SubstCapMask = 0x0000001F; + if (PchSeries == PchLp) { + /// + /// Get the endpoint supports L1 Substates Capabilities + /// + for (PcieDeviceIndex = 0; PcieDeviceIndex < NumOfDevAspmOverride; PcieDeviceIndex++) { + if ((PolicyRevision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_2) && + ((DevAspmOverride[PcieDeviceIndex].OverrideConfig & PchPcieL1SubstatesOverride) == PchPcieL1SubstatesOverride) && + (EndPointVendorId == DevAspmOverride[PcieDeviceIndex].VendorId) && + (EndPointDeviceId == DevAspmOverride[PcieDeviceIndex].DeviceId) && + ((EndPointRevId == DevAspmOverride[PcieDeviceIndex].RevId) || + (DevAspmOverride[PcieDeviceIndex].RevId == 0xFF))) { + if ((EndPointVendorId == 0x8086) && + ((EndPointDeviceId == 0x08B1) || (EndPointDeviceId == 0x08B2) || + (EndPointDeviceId == 0x08B3) || (EndPointDeviceId == 0x08B4))) { + if ((MmioRead32 (EndPointBase + DevAspmOverride[PcieDeviceIndex].L1SubstatesCapOffset) & 0xFFFF) == 0xCAFE) { + EndPointL1SubStateCapOffset = DevAspmOverride[PcieDeviceIndex].L1SubstatesCapOffset; + EndPointL1SubstCapMask = DevAspmOverride[PcieDeviceIndex].L1SubstatesCapMask; + } + } else { + EndPointL1SubStateCapOffset = DevAspmOverride[PcieDeviceIndex].L1SubstatesCapOffset; + EndPointL1SubstCapMask = DevAspmOverride[PcieDeviceIndex].L1SubstatesCapMask; + } + } + } + if (EndPointL1SubStateCapOffset == 0) { + EndPointL1SubStateCapOffset = PcieFindExtendedCapId ( + EndPointBus, + DeviceIndex, + FunctionIndex, + 0x1E); + } + if (EndPointL1SubStateCapOffset != 0) { + RootDeviceL1Substates = MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04); + EndPointL1Substates = MmioRead32 (EndPointBase + EndPointL1SubStateCapOffset + 0x04); + } + } + DeviceCapabilities2 = MmioRead32 (EndPointBase + EndPointPcieCapOffset + 0x24); + if (((DeviceCapabilities2 & BIT11) == 0) || (PchPwrOptPcie->LtrEnable != TRUE)) { + *RpAndEndPointsLtrSupported = FALSE; + } + /// + /// Configure downstream device if present. + /// + + if (Operation == CalculateAspm || Operation == ManualAspm) { + if ((MmioRead32 (EndPointBase + EndPointPcieCapOffset + 0x00C) & BIT18) != BIT18) { + *ClkreqPerPortSupported = FALSE; + } + EndPointAspm = (MmioRead16 (EndPointBase + EndPointPcieCapOffset + 0x00C) >> 10) & 3; + DEBUG ((EFI_D_INFO, "Endpoint Device %0x Capability ASPM: %0x\n", DeviceIndex, EndPointAspm)); + if (Operation == CalculateAspm) { + /// + /// Check endpoint for pre-1.1 devices based on the Role based Error Reporting Capability bit + /// and enable Aspm Override + /// + if (!(MmioRead16 (EndPointBase + EndPointPcieCapOffset + 0x4) & BIT15)) { + DEBUG ((EFI_D_INFO, "Override root port ASPM to L1 for pre-1.1 devices\n")); + *AspmOverride = TRUE; + } + /// + /// Mask APMC with values from lookup table. + /// RevID of 0xFF applies to all steppings. + /// + EndPointBaseClassCode = MmioRead8 (EndPointBase + R_PCH_PCIE_BCC); + EndPointSubClassCode = MmioRead8 (EndPointBase + R_PCH_PCIE_SCC); + + for (PcieDeviceIndex = 0; PcieDeviceIndex < NumOfDevAspmOverride; PcieDeviceIndex++) { + if ((PolicyRevision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_2) && + ((DevAspmOverride[PcieDeviceIndex].OverrideConfig & PchPcieL1L2Override) == PchPcieL1L2Override) && + ((DevAspmOverride[PcieDeviceIndex].VendorId == EndPointVendorId) || + (DevAspmOverride[PcieDeviceIndex].VendorId == 0xFFFF)) && + ((DevAspmOverride[PcieDeviceIndex].DeviceId == EndPointDeviceId) || + (DevAspmOverride[PcieDeviceIndex].DeviceId == 0xFFFF)) && + ((DevAspmOverride[PcieDeviceIndex].RevId == EndPointRevId) || + (DevAspmOverride[PcieDeviceIndex].RevId == 0xFF)) && + ((DevAspmOverride[PcieDeviceIndex].BaseClassCode == EndPointBaseClassCode) || + (DevAspmOverride[PcieDeviceIndex].BaseClassCode == 0xFF)) && + ((DevAspmOverride[PcieDeviceIndex].SubClassCode == EndPointSubClassCode) || + (DevAspmOverride[PcieDeviceIndex].SubClassCode == 0xFF))) { + /// + /// Override value of 0xFF applies to all. + /// + EndPointAspm = DevAspmOverride[PcieDeviceIndex].EndPointAspm; + break; + } + } + /// + /// Check if L1 should be enabled based on port and endpoint L1 exit latency. + /// + if (EndPointAspm & BIT1) { + PortLxLat = MmioRead32 (RootDeviceBase + RootPcieCapOffset + 0x00C) & (BIT17 + BIT16 + BIT15); + EndPointLxLat = MmioRead32 (EndPointBase + EndPointPcieCapOffset + 0x00C) & (BIT17 + BIT16 + BIT15); + + LxLat = PortLxLat; + if (PortLxLat < EndPointLxLat) { + LxLat = EndPointLxLat; + } + /// + /// check if the value is bigger than endpoint L1 acceptable exit latency, if it is + /// larger than accepted value, then we should disable L1 + /// + LxLat >>= 6; + if (LxLat > (MmioRead32 (EndPointBase + EndPointPcieCapOffset + 0x004) & (BIT11 + BIT10 + BIT9))) { + EndPointAspm &= ~BIT1; + } + } + /// + /// Check if L0s should be enabled based on port and endpoint L0s exit latency. + /// + if (EndPointAspm & BIT0) { + PortLxLat = MmioRead32 (RootDeviceBase + RootPcieCapOffset + 0x00C) & (BIT14 + BIT13 + BIT12); + EndPointLxLat = MmioRead32 (EndPointBase + EndPointPcieCapOffset + 0x00C) & (BIT14 + BIT13 + BIT12); + + LxLat = PortLxLat; + if (PortLxLat < EndPointLxLat) { + LxLat = EndPointLxLat; + } + /// + /// check if the value is bigger than endpoint L0s acceptable exit latency, if it is + /// larger than accepted value, then we should disable L0s + /// + LxLat >>= 6; + if (LxLat > (MmioRead32 (EndPointBase + EndPointPcieCapOffset + 0x004) & (BIT8 + BIT7 + BIT6))) { + EndPointAspm &= ~BIT0; + } + } + } + + *LinkAspmVal &= EndPointAspm; + DEBUG ((EFI_D_INFO, "Calculate Endpoint Device %0x Aspm Value: %0x\n", DeviceIndex, EndPointAspm)); + if (PchSeries == PchLp) { + /// + /// Check if the endpoint supports L1 Substates Capabilities + /// + if ((EndPointL1SubStateCapOffset != 0) && (RootL1SubstateExtCapOffset != 0)) { + /// + /// If both Root and endpoint's L1 Sub-States Extended Capability Offset + 0x04[4:0] are 11111b, + /// a. Read L1 Sub-States Extended Capability Offset + 0x04[15:8], and program the highest value advertised + /// between PCIe rootport and device to L1 Sub-States Extended Capability Offset + 0x08[15:8] on + /// Pcie root port. + /// b. Read L1 Sub-States Extended Capability Offset + 0x04[23:19] and [17:16], and program the highest value + /// advertised between PCIe root port and device.to L1 Sub-States Extended Capability Offset + 0x08 [7:0] on + /// both Pcie root port and device. + /// c. Program L1 Sub-States Extended Capability Offset + 0x08[31:29] to 010b for both Pcie root port and device + /// d. Program L1 Sub-States Extended Capability Offset + 0x08[25:16] to 0010100000b for both Pcie root port and device + /// e. Program L1 Sub-States Extended Capability Offset + 0x08[4:0] to 01111b for both Pcie root port and device + /// + if (((RootDeviceL1Substates & 0x1F) == 0x1F) && + ((EndPointL1Substates & EndPointL1SubstCapMask) == EndPointL1SubstCapMask) && + (L1SubstatesConfig != PchPcieL1SubstatesDisabled)) { + *L1SubstatesSupported = TRUE; + EndPointPortCommonModeRestoreTime = (EndPointL1Substates >> 8) & 0xFF; + EndPointTpowerOnScale = (EndPointL1Substates >> 16) & 0x3; + EndPointTpowerOnValue = (EndPointL1Substates >> 19) & 0x1F; + + if (EndPointPortCommonModeRestoreTime > *PortCommonModeRestoreTime) { + *PortCommonModeRestoreTime = EndPointPortCommonModeRestoreTime; + } + + if ((EndPointTpowerOnValue * Multiplier[EndPointTpowerOnScale]) > + (*PortTpowerOnValue * Multiplier[*PortTpowerOnScale])) { + *PortTpowerOnValue = EndPointTpowerOnValue; + *PortTpowerOnScale = EndPointTpowerOnScale; + } + } + } + } + /// + /// For each device detected, scan the LTR override table + /// If there are endpoints connected directly to the rootport then + /// LtrOverrideVal will be replaced by the value from the table for that endpoint + /// If there are endpoints that are behind a bridge and that are also part of the table then + /// LtrOverrideVal will maintain the minimum of all such values. + /// A non zero value of LtrOverrideVal will indicate: + /// i):That there is atleast one entry in the LTR override Table + /// ii):The final value to be programmed in offset 0x400. This value will be applied for all the devices + /// connected to this root port + /// + Data32 = *LtrOverrideVal; + if (DevLtrOverride != NULL) { + for (PcieDeviceIndex = 0; PcieDeviceIndex < NumOfDevLtrOverride; PcieDeviceIndex++) { + if ((DevLtrOverride[PcieDeviceIndex].VendorId == EndPointVendorId) && + ((DevLtrOverride[PcieDeviceIndex].DeviceId == EndPointDeviceId) || + (DevLtrOverride[PcieDeviceIndex].DeviceId == 0xFFFF)) && + ((DevLtrOverride[PcieDeviceIndex].RevId == EndPointRevId) || + (DevLtrOverride[PcieDeviceIndex].RevId == 0xFF))) { + + /// + /// Get the Non-Snoop latency value from the table, compare and store the minimum + /// + if (DevLtrOverride[PcieDeviceIndex].NonSnoopLatency & BIT15) { + Data16 = (UINT16)((Data32 & 0xFFFF0000) >> 16); + DetermineLatencyValue(&Data16, &DevLtrOverride[PcieDeviceIndex].NonSnoopLatency); + Data32 = (Data32 & 0xFFFF) | ((UINT32)(Data16 << 16)); + } + + /// + /// Get the Snoop latency value from the table, compare and store the minimum + /// + if (DevLtrOverride[PcieDeviceIndex].SnoopLatency & BIT15) { + Data16 = (UINT16)(Data32 & 0xFFFF); + DetermineLatencyValue(&Data16, &DevLtrOverride[PcieDeviceIndex].SnoopLatency); + Data32 = (Data32 & 0xFFFF0000) | (UINT32)Data16; + } + *LtrOverrideVal = Data32; + break; + } + } + } + } else if (Operation == SetAspm) { + if (PchSeries == PchLp) { + if ((EndPointL1SubStateCapOffset != 0) && (*L1SubstatesSupported)) { + if (((RootDeviceL1Substates & 0x1F) == 0x1F) && + ((EndPointL1Substates & EndPointL1SubstCapMask) == EndPointL1SubstCapMask)) { + MmioAndThenOr32 ( + EndPointBase + EndPointL1SubStateCapOffset + 0x0C, + (UINT32) ~(0xF8), + (*PortTpowerOnValue << 3) + ); + MmioAndThenOr32 ( + EndPointBase + EndPointL1SubStateCapOffset + 0x0C, + (UINT32) ~(0x03), + *PortTpowerOnScale); + MmioAndThenOr32 ( + EndPointBase + EndPointL1SubStateCapOffset + 0x08, + (UINT32) ~(0xE3FF0000), + (UINT32) (BIT30 | BIT23 | BIT21) + ); + Data32 = (BIT3 | BIT2 | BIT1 | BIT0); + if (L1SubstatesConfig == PchPcieL1SubstatesL1_1) { + Data32 &= (UINT32)~(BIT0); + } + if (L1SubstatesConfig == PchPcieL1SubstatesL1_2) { + Data32 &= (UINT32)~(BIT1); + } + MmioAndThenOr32 ( + EndPointBase + EndPointL1SubStateCapOffset + 0x08, + (UINT32) ~(0x1F), + Data32 + ); + } + } + } + /// + /// Write it to the Link Control register + /// + DEBUG ((EFI_D_INFO, "Program Endpoint Device %0x Aspm Value: %0x\n", DeviceIndex, *LinkAspmVal)); + MmioAndThenOr16 (EndPointBase + EndPointPcieCapOffset + 0x10, 0xFFFC, *LinkAspmVal); + /// + /// PCH BIOS Spec Rev 0.5.5, Section 8.14.1 Power Optimizer Configuration + /// Step 3 + /// For PCIe Endpoint, + /// If Endpoint device supported LTR, Device Capabilities 2 Register Offset 24h [11] = 1b, + /// + if ((DeviceCapabilities2 & BIT11) && (PchPwrOptPcie->LtrEnable == TRUE)) { + /// + /// Step 3.1 + /// Program Endpoint LTR Mechanism Enable, Device Control 2 Register Offset 28h [10] = 1b + /// when device supports LTR but is not found in override table (table listing correct + /// latency requirements for devices that supports LTR and also for devices that do not + /// support LTR) + /// + if (DevLtrOverride != NULL) { + for (PcieDeviceIndex = 0; PcieDeviceIndex < NumOfDevLtrOverride; PcieDeviceIndex++) { + if ((DevLtrOverride[PcieDeviceIndex].VendorId != EndPointVendorId) || + ((DevLtrOverride[PcieDeviceIndex].DeviceId != EndPointDeviceId) && + (DevLtrOverride[PcieDeviceIndex].DeviceId != 0xFFFF)) || + ((DevLtrOverride[PcieDeviceIndex].RevId != EndPointRevId) && + (DevLtrOverride[PcieDeviceIndex].RevId != 0xFF))) { + MmioOr16 (EndPointBase + EndPointPcieCapOffset + 0x28, BIT10); + break; + } + } + } else { + MmioOr16 (EndPointBase + EndPointPcieCapOffset + 0x28, BIT10); + } + } + /// + /// Get the pointer to the Endpoint PCI Express Extended Capability Structure + /// and configure the Max Snoop and Max No-Snoop Latency for the endpoint + /// + LtrExtendedCapOffset = PcieFindExtendedCapId (EndPointBus, DeviceIndex, FunctionIndex, 0x18); + if (LtrExtendedCapOffset != 0) { + Data32 = *LtrOverrideVal; + if (PchSeries == PchH) { + DefaultMaxLatency = 0x0846; + } + if (PchSeries == PchLp) { + DefaultMaxLatency = 0x1003; + } + /// + /// PCH BIOS Spec Rev 0.5.6, Section 8.14.1 Power Optimizer Configuration + /// Step 3.2 + /// Program Endpoint Max Snoop Latency Register, Latency Tolerance Reporting(LTR) + /// Capability Offset 04h [15:0] with Intel recommended default value for max snoop + /// latency if there is no snoop latency override value getting programmed in the + /// override register else program the endpoint Max Snoop Latency Register with the + /// minimum of snoop latency override value for that root port and Intel recommended + /// default value for max snoop latency + /// Intel recommended default value for max snoop latency for LPT-H = 0x0846 + /// Intel recommended default value for max snoop latency for LPT-LP = 0x1003 + /// + if (PolicyRevision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_7) { + DefaultMaxLatency = PchPwrOptPcie->LtrMaxSnoopLatency; + } + + Data16 = (UINT16)(Data32 & 0xFFFF); + /// + /// Set the max snoop latency to either the default max snoop latency or to the snoop latency override value + /// that is being programmed for this root port + /// + DetermineLatencyValue(&Data16, &DefaultMaxLatency); + MmioAndThenOr16 ( + EndPointBase + LtrExtendedCapOffset + 4, + (UINT16) (~0x1FFF), + Data16 + ); + /// + /// PCH BIOS Spec Rev 0.5.6, Section 8.14.1 Power Optimizer Configuration + /// Step 3.3 + /// Program Endpoint Max No-Snoop Latency Register, Latency Tolerance Reporting(LTR) + /// Capability Offset 06h [15:0] with Intel recommended default value for max no-snoop + /// latency if there is no No-snoop latency override value getting programmed in the + /// override register else program the endpoint Max No-Snoop Latency Register with the + /// minimum of No-snoop latency override value for that root port and Intel recommended + /// default value for max no-snoop latency + /// Intel recommended default value for max no-snoop latency for LPT-H = 0x0846 + /// Intel recommended default value for max no-snoop latency for LPT-LP = 0x1003 + /// + if (PolicyRevision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_7) { + DefaultMaxLatency = PchPwrOptPcie->LtrMaxNoSnoopLatency; + } + Data16 = (UINT16)((Data32 & 0xFFFF0000) >> 16); + DetermineLatencyValue(&Data16, &DefaultMaxLatency); + MmioAndThenOr16 ( + EndPointBase + LtrExtendedCapOffset + 6, + (UINT16) (~0x1FFF), + Data16 + ); + } + /// + /// Step 4 + /// For PCIe Endpoint, + /// If Endpoint device supported OBFF, Device Capabilities 2 Register Offset 24h [19:18] = 2h, + /// + if ((DeviceCapabilities2 & BIT19) && (PchPwrOptPcie->ObffEnable == PCH_DEVICE_ENABLE)) { + /// + /// Step 4.1 + /// Program Endpoint OBFF Mechanism Enable, Device Control 2 Register Offset 28h [14:13] = 3h + /// + MmioOr16 (EndPointBase + EndPointPcieCapOffset + 0x28, (BIT14 + BIT13)); + } + } + /// + /// Check if this device is a bridge + /// + ClassCode = MmioRead8 (EndPointBase + R_PCH_PCIE_BCC); + + if (ClassCode == PCI_CLASS_BRIDGE) { + /// + /// Get the downstream Bus number + /// + DownStreamBusMin = (UINT8) (MmioRead32 (EndPointBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) >> 8); + /// + /// If the Secondary Bus Number of endpoint device is not assigned + /// + if (DownStreamBusMin == 0) { + RootDevSubBusNum = (UINT8) (MmioRead32 (RootDeviceBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) >> 16); + /// + /// If the endpoint device is a bridge, the Subordinate Bus Number of the root port will need to be greater + /// than the Secondary Bus Number of the root port (the Bus Number of endpoint device). + /// + if (RootDevSubBusNum > EndPointBus) { + /// + /// Assign the Primary, Secondary and Subordinate Bus Number to endpoint device + /// + MmioAndThenOr32 ( + EndPointBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, + 0xFF000000, + EndPointBus | (((UINT32) (EndPointBus + 1) << 8)) | ((UINT32) (RootDevSubBusNum << 16)) + ); + DownStreamBusMin = EndPointBus + 1; + } else { + return EFI_OUT_OF_RESOURCES; + } + + BusAssign = FALSE; + } else { + BusAssign = TRUE; + } + + if (DownStreamBusMin > EndPointBus) { + Status = PcieEndPointPm ( + RootDeviceBase, + RootPcieCapOffset, + DownStreamBusMin, + NumOfDevAspmOverride, + DevAspmOverride, + LinkAspmVal, + Operation, + NumOfDevLtrOverride, + DevLtrOverride, + LtrOverrideVal, + RootL1SubstateExtCapOffset, + L1SubstatesSupported, + L1SubstatesConfig, + PortCommonModeRestoreTime, + PortTpowerOnValue, + PortTpowerOnScale, + PchPwrOptPcie, + AspmOverride, + ClkreqPerPortSupported, + RpAndEndPointsLtrSupported, + PolicyRevision + ); + if (Status == EFI_NOT_FOUND) { + DEBUG ((EFI_D_INFO, "Check DownStreamBus:%d and no device found!\n", DownStreamBusMin)); + } + + if (BusAssign == FALSE) { + /// + /// Clear Bus Numbers. + /// + MmioAnd32 (EndPointBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0xFF000000); + } + } + } + } + } + + return EFI_SUCCESS; +} + +/** + This function checks if the root port and downstream device support Clkreq per port, ASPM L1 and L1 substates + + @param[in] RootBus Pci Bus Number of the root port + @param[in] RootDevice Pci Device Number of the root port + @param[in] RootFunction Pci Function Number of the root port + @param[in] RootPortAspm Root port Aspm configuration + @param[in] NumOfDevAspmOverride Number of Device specific ASPM policy override items + @param[in] DevAspmOverride Pointer to array of Device specific ASPM policy override items + @param[in] TempBusNumberMin Minimal temp bus number that can be assigned to the root port (as secondary + bus number) and its down stream switches + @param[in] TempBusNumberMax Maximal temp bus number that can be assigned to the root port (as subordinate + bus number) and its down stream switches + @param[in] NumOfDevLtrOverride Number of Device specific LTR override items + @param[in] DevLtrOverride Pointer to array of Device specific LTR policy override items + @param[in] PchPwrOptPcie Pcie Power Optimizer Configuration + @param[in, out] L1SubstatesSupported Flag to indicate if L1 Substates are supported + @param[in] L1SubstatesConfig L1 Substates configuration + @param[in] PolicyRevision Revision of the policy + @param[in, out] AspmVal Aspm value for both rootport and end point devices + @param[in, out] ClkreqPerPortSupported Clkreq support for both rootport and endpoint devices + @param[out] LtrSupported Check and return if all endpoints support LTR + + @retval EFI_SUCCESS The function completed successfully + @exception EFI_UNSUPPORTED The pointer to the Port PCI Express Capability Structure is not found +**/ +EFI_STATUS +PcieCheckPmConfig ( + IN UINT8 RootBus, + IN UINT8 RootDevice, + IN UINT8 RootFunction, + IN PCH_PCI_EXPRESS_ASPM_CONTROL RootPortAspm, + IN UINT8 NumOfDevAspmOverride, + IN PCH_PCIE_DEVICE_ASPM_OVERRIDE *DevAspmOverride, + IN UINT8 TempBusNumberMin, + IN UINT8 TempBusNumberMax, + IN UINT8 NumOfDevLtrOverride, + IN PCH_PCIE_DEVICE_LTR_OVERRIDE *DevLtrOverride, + IN PCH_PCIE_PWR_OPT *PchPwrOptPcie, + IN OUT BOOLEAN *L1SubstatesSupported, + IN PCH_PCIE_EXPRESS_L1SUBSTATES_CONTROL L1SubstatesConfig, + IN UINT8 PolicyRevision, + IN OUT UINT16 *AspmVal, + IN OUT BOOLEAN *ClkreqPerPortSupported, + OUT BOOLEAN *LtrSupported + ) +{ + EFI_STATUS Status; + UINTN RootDeviceBase; + UINT32 RootPcieCapOffset; + UINT8 EndPointBus; + OPERATION Operation; + UINT16 SlotStatus; + BOOLEAN BusAssign; + UINT32 DeviceCapabilities2; + UINT32 LtrOvrVal; + UINT32 Data32Or; + UINT16 GpioBase; + UINT32 RootComplexBar; + UINT16 RootL1SubstateExtCapOffset; + UINT32 PortCommonModeRestoreTime; + UINT32 PortTpowerOnValue; + UINT32 PortTpowerOnScale; + BOOLEAN AspmOverride; + PCH_SERIES PchSeries; + UINT8 RootPortNumber; + + PchSeries = GetPchSeries(); + Status = EFI_SUCCESS; + RootDeviceBase = MmPciAddress (0, RootBus, RootDevice, RootFunction, 0); + RootComplexBar = PCH_RCRB_BASE; + PortCommonModeRestoreTime = 0; + PortTpowerOnValue = 0; + PortTpowerOnScale = 0; + *L1SubstatesSupported = FALSE; + AspmOverride = FALSE; + *ClkreqPerPortSupported = FALSE; + GpioBase = 0; + + if (MmioRead16 (RootDeviceBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + return EFI_NOT_FOUND; + } + if (PchSeries == PchLp) { + GpioBase = MmioRead16 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_GPIO_BASE) + ) & B_PCH_LPC_GPIO_BASE_BAR; + + RootPortNumber = GetPchPcieRpNumber(RootComplexBar, RootFunction); + Data32Or = (IoRead32 ((UINTN) (GpioBase + R_PCH_GP_X_CONFIG0(18 + RootPortNumber))) & B_PCH_GPIO_OWN0_GPIO_USE_SEL); + + if (Data32Or == 0) { + *ClkreqPerPortSupported = TRUE; + } + } + + /// + /// Get the pointer to the Port PCI Express Capability Structure. + /// + RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (RootPcieCapOffset == 0) { + return EFI_UNSUPPORTED; + } + DeviceCapabilities2 = MmioRead32 (RootDeviceBase + RootPcieCapOffset + 0x24); + + *AspmVal = (MmioRead16 (RootDeviceBase + RootPcieCapOffset + 0x00C) >> 10) & 3; + if (RootPortAspm == PchPcieAspmAutoConfig) { + Operation = CalculateAspm; + } else { + Operation = ManualAspm; + *AspmVal &= RootPortAspm; + } + /// + /// Get the downstream Bus number + /// + EndPointBus = (UINT8) (MmioRead32 (RootDeviceBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) >> 8); + /// + /// If the Secondary Bus Number of the root port is not assigned + /// Note: + /// It will be better that PCI emulation has been done before PcieSetPm(). Or, you will need to assign + /// a larger number to TempRootPortBusNumMax to support the specific card which has many bridges behind. + /// If it is not, the platform policy settings of "TempRootPortBusNumMax" and "TempRootPortBusNumMin" + /// will be assigned to the Subordinate and Secondary Bus Number of the root ports. + /// The assigned bus number will be cleared in the end of PcieSetPm(). + /// + if (EndPointBus == 0) { + MmioAndThenOr32 ( + RootDeviceBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, + 0xFF0000FF, + ((UINT32) (TempBusNumberMin << 8)) | ((UINT32) (TempBusNumberMax << 16)) + ); + EndPointBus = TempBusNumberMin; + BusAssign = FALSE; + } else { + BusAssign = TRUE; + } + /// + /// Check whether the slot has a device connected + /// + SlotStatus = MmioRead16 (RootDeviceBase + RootPcieCapOffset + 0x1A); + LtrOvrVal = 0; + + RootL1SubstateExtCapOffset = 0; + if (PchSeries == PchLp) { + RootL1SubstateExtCapOffset = PcieFindExtendedCapId (RootBus, RootDevice, RootFunction, 0x1E); + if (RootL1SubstateExtCapOffset != 0) { + PortCommonModeRestoreTime = (MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04) >> 8) & 0xFF; + PortTpowerOnScale = (MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04) >> 16) & 0x3; + PortTpowerOnValue = (MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04) >> 19) & 0x1F; + } + } + /// + /// Obtain initial ASPM settings from respective port capability registers. + /// Scan LTR override table for device match and calculate the lowest override + /// value to be programmed into B0:D28:F0~F7 + 400h + /// + if (EndPointBus != 0 && (SlotStatus & BIT6) != 0) { + Status = PcieEndPointPm ( + RootDeviceBase, + RootPcieCapOffset, + EndPointBus, + NumOfDevAspmOverride, + DevAspmOverride, + AspmVal, + Operation, + NumOfDevLtrOverride, + DevLtrOverride, + &LtrOvrVal, + RootL1SubstateExtCapOffset, + L1SubstatesSupported, + L1SubstatesConfig, + &PortCommonModeRestoreTime, + &PortTpowerOnValue, + &PortTpowerOnScale, + PchPwrOptPcie, + &AspmOverride, + ClkreqPerPortSupported, + LtrSupported, + PolicyRevision + ); + } + + if (BusAssign == FALSE) { + /// + /// Clear Bus Numbers. + /// + MmioAnd32 (RootDeviceBase + 0x018, 0xFF0000FF); + } + + return Status; +} +/** + This function performs the Power Management settings for root port and downstream device + + @param[in] RootBus Pci Bus Number of the root port + @param[in] RootDevice Pci Device Number of the root port + @param[in] RootFunction Pci Function Number of the root port + @param[in] RootPortAspm Root port Aspm configuration + @param[in] NumOfDevAspmOverride Number of Device specific ASPM policy override items + @param[in] DevAspmOverride Pointer to array of Device specific ASPM policy override items + @param[in] TempBusNumberMin Minimal temp bus number that can be assigned to the root port (as secondary + bus number) and its down stream switches + @param[in] TempBusNumberMax Maximal temp bus number that can be assigned to the root port (as subordinate + bus number) and its down stream switches + @param[in] NumOfDevLtrOverride Number of Device specific LTR override items + @param[in] DevLtrOverride Pointer to array of Device specific LTR policy override items + @param[in] PchPwrOptPcie Pcie Power Optimizer Configuration + @param[in, out] L1SubstatesSupported Flag to indicate if L1 Substates are supported + @param[in] L1SubstatesConfig L1 Substates configuration + @param[in] PolicyRevision Policy revision for codes compatibility + @param[in] FirstRpToSetPm Indicates if this is the first root port to be set + @param[in] L1SupportedInAllEnabledPorts Check if L1 is supported in all enabled ports + @param[in] ClkreqSupportedInAllEnabledPorts Check if clkreq is supported in all enabled ports + @param[out] LtrSupported Check and return if all endpoints support LTR + + @retval EFI_SUCCESS The function completed successfully + @exception EFI_UNSUPPORTED The pointer to the Port PCI Express Capability Structure is not found +**/ +EFI_STATUS +PcieSetPm ( + IN UINT8 RootBus, + IN UINT8 RootDevice, + IN UINT8 RootFunction, + IN PCH_PCI_EXPRESS_ASPM_CONTROL RootPortAspm, + IN UINT8 NumOfDevAspmOverride, + IN PCH_PCIE_DEVICE_ASPM_OVERRIDE *DevAspmOverride, + IN UINT8 TempBusNumberMin, + IN UINT8 TempBusNumberMax, + IN UINT8 NumOfDevLtrOverride, + IN PCH_PCIE_DEVICE_LTR_OVERRIDE *DevLtrOverride, + IN PCH_PCIE_PWR_OPT *PchPwrOptPcie, + IN OUT BOOLEAN *L1SubstatesSupported, + IN PCH_PCIE_EXPRESS_L1SUBSTATES_CONTROL L1SubstatesConfig, + IN UINT8 PolicyRevision, + IN BOOLEAN FirstRPToSetPm, + IN BOOLEAN L1SupportedInAllEnabledPorts, + IN BOOLEAN ClkreqSupportedInAllEnabledPorts, + OUT BOOLEAN *LtrSupported + ) +{ + /// + /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 ASPM on DMI and the PCI Express* Root Ports + /// + /// When enabling L0s / L1 support, BIOS should enable upstream device before downstream + /// device. When disabling ASPM, BIOS should make sure downstream device is disabled + /// before upstream device. + /// The System BIOS must perform the following steps to enable + /// L0s/L1 on the root ports: + /// + /// 1. Determine whether the endpoint supports L1 by checking the Active State Link PM + /// Support field of the endpoint Link Capability Register. If the endpoint does not + /// support L1, the System BIOS can skip the L1 calculations below. Likewise, System + /// BIOS should not enable L1 on the root port or the endpoint if the endpoint does not + /// support L1. + /// 2. Calculate the total L0s and L1 exit latency. A description of this calculation + /// is provided in Section 8.3.1.1. + /// 3. Compare the calculated total exit latency with Endpoint L0s/L1 Acceptable Latency + /// read from the Device Capabilities Register of the Endpoint to determine if L0s or + /// L1 can be enabled for all or some of the links on the entire path to satisfy the + /// Acceptable Latency reported by the Endpoint. The Exit Latency fields reported by + /// the registers are given as a range. It is recommended that System BIOS uses the + /// high end of the range for the latency calculation and comparison. For example, if + /// the latency field reports "2 us to less than 4 us", then 4 us should be used for + /// the calculation. + /// 4. If the comparison in step 3 indicates L0s and L1 can be enabled on a root port and + /// the endpoints attached to the root port, then set the root port register + /// D28:F0~F7:Reg E8h[1], then set the APMC field, D28:F0~F7:Reg 50h[1:0] to 11b and write + /// the same value to the APMC field of the endpoint Link Control register. If the + /// comparison in step 1 indicates only L0s can be enabled on a root port and the + /// endpoints attached to the root port, then set the APMC field, D28:F0~F7:Reg 50h[1:0] + /// to 01b and write the same value to the APMC field of the endpoint Link Control + /// register. + /// + /// NOTE: current implementation does not support full length exit latency calculation + /// + UINT16 AspmVal; + EFI_STATUS Status; + UINTN RootDeviceBase; + UINT32 RootPcieCapOffset; + UINT8 EndPointBus; + OPERATION Operation; + UINT16 SlotStatus; + BOOLEAN BusAssign; + UINT32 DeviceCapabilities2; + UINT32 LtrOvrVal; + UINT32 Data32Or; + UINT8 Data8And; + UINT8 Data8Or; + UINT16 GpioBase; + BOOLEAN ClkreqPerPortSupported; + UINT32 RootComplexBar; + UINT16 RootL1SubstateExtCapOffset; + UINT32 PortCommonModeRestoreTime; + UINT32 PortTpowerOnValue; + UINT32 PortTpowerOnScale; + BOOLEAN AspmOverride; + PCH_SERIES PchSeries; + UINT8 RootPortNumber; +#ifdef ULT_FLAG + UINT32 Data32; + UINT8 Response; +#endif // ULT_FLAG + + PchSeries = GetPchSeries(); + Status = EFI_SUCCESS; + RootDeviceBase = MmPciAddress (0, RootBus, RootDevice, RootFunction, 0); + RootComplexBar = PCH_RCRB_BASE; + PortCommonModeRestoreTime = 0; + PortTpowerOnValue = 0; + PortTpowerOnScale = 0; + *L1SubstatesSupported = FALSE; + AspmOverride = FALSE; + ClkreqPerPortSupported = FALSE; + GpioBase = 0; + + if (MmioRead16 (RootDeviceBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) { + return EFI_NOT_FOUND; + } + if (PchSeries == PchLp) { + GpioBase = MmioRead16 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_GPIO_BASE) + ) & B_PCH_LPC_GPIO_BASE_BAR; + + RootPortNumber = GetPchPcieRpNumber(RootComplexBar, RootFunction); + Data32Or = (IoRead32 ((UINTN) (GpioBase + R_PCH_GP_X_CONFIG0(18 + RootPortNumber))) & B_PCH_GPIO_OWN0_GPIO_USE_SEL); + + if (Data32Or == 0) { + ClkreqPerPortSupported = TRUE; + } + } + + /// + /// Get the pointer to the Port PCI Express Capability Structure. + /// + RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, EFI_PCI_CAPABILITY_ID_PCIEXP); + if (RootPcieCapOffset == 0) { + return EFI_UNSUPPORTED; + } + DeviceCapabilities2 = MmioRead32 (RootDeviceBase + RootPcieCapOffset + 0x24); + + /// + /// Enable LTR mechanism for this root port if it is capable + /// + if ((DeviceCapabilities2 & BIT11) && (PchPwrOptPcie->LtrEnable == TRUE)) { + MmioOr16 (RootDeviceBase + RootPcieCapOffset + 0x28, BIT10); + } + + /// + /// Enable OBFF using WAKE# signaling for this root port if it is capable + /// + if ((DeviceCapabilities2 & BIT19) && (PchPwrOptPcie->ObffEnable == TRUE)) { + MmioOr16 (RootDeviceBase + RootPcieCapOffset + 0x28, (BIT14 + BIT13)); + } + AspmVal = (MmioRead16 (RootDeviceBase + RootPcieCapOffset + 0x00C) >> 10) & 3; + if (RootPortAspm == PchPcieAspmAutoConfig) { + Operation = CalculateAspm; + } else { + Operation = ManualAspm; + AspmVal &= RootPortAspm; + } + /// + /// Get the downstream Bus number + /// + EndPointBus = (UINT8) (MmioRead32 (RootDeviceBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) >> 8); + /// + /// If the Secondary Bus Number of the root port is not assigned + /// Note: + /// It will be better that PCI emulation has been done before PcieSetPm(). Or, you will need to assign + /// a larger number to TempRootPortBusNumMax to support the specific card which has many bridges behind. + /// If it is not, the platform policy settings of "TempRootPortBusNumMax" and "TempRootPortBusNumMin" + /// will be assigned to the Subordinate and Secondary Bus Number of the root ports. + /// The assigned bus number will be cleared in the end of PcieSetPm(). + /// + if (EndPointBus == 0) { + MmioAndThenOr32 ( + RootDeviceBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, + 0xFF0000FF, + ((UINT32) (TempBusNumberMin << 8)) | ((UINT32) (TempBusNumberMax << 16)) + ); + EndPointBus = TempBusNumberMin; + BusAssign = FALSE; + } else { + BusAssign = TRUE; + } + /// + /// Check whether the slot has a device connected + /// + SlotStatus = MmioRead16 (RootDeviceBase + RootPcieCapOffset + 0x1A); + LtrOvrVal = 0; + + RootL1SubstateExtCapOffset = 0; + if (PchSeries == PchLp) { + RootL1SubstateExtCapOffset = PcieFindExtendedCapId (RootBus, RootDevice, RootFunction, 0x1E); + if (RootL1SubstateExtCapOffset != 0) { + PortCommonModeRestoreTime = (MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04) >> 8) & 0xFF; + PortTpowerOnScale = (MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04) >> 16) & 0x3; + PortTpowerOnValue = (MmioRead32 (RootDeviceBase + RootL1SubstateExtCapOffset + 0x04) >> 19) & 0x1F; + } + } + /// + /// Obtain initial ASPM settings from respective port capability registers. + /// Scan LTR override table for device match and calculate the lowest override + /// value to be programmed into B0:D28:F0~F7 + 400h + /// + if (EndPointBus != 0 && (SlotStatus & BIT6) != 0) { + Status = PcieEndPointPm ( + RootDeviceBase, + RootPcieCapOffset, + EndPointBus, + NumOfDevAspmOverride, + DevAspmOverride, + &AspmVal, + Operation, + NumOfDevLtrOverride, + DevLtrOverride, + &LtrOvrVal, + RootL1SubstateExtCapOffset, + L1SubstatesSupported, + L1SubstatesConfig, + &PortCommonModeRestoreTime, + &PortTpowerOnValue, + &PortTpowerOnScale, + PchPwrOptPcie, + &AspmOverride, + &ClkreqPerPortSupported, + LtrSupported, + PolicyRevision + ); + if (PchPwrOptPcie->LtrEnable == PCH_DEVICE_ENABLE) { + if (PolicyRevision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_7) { + if (PchPwrOptPcie->SnoopLatencyOverrideMode == 1) { + LtrOvrVal &= 0xFFFF0000; + LtrOvrVal |= (UINT32) BIT15 | + (UINT32) (PchPwrOptPcie->SnoopLatencyOverrideMultiplier << 10) | + (UINT32) (PchPwrOptPcie->SnoopLatencyOverrideValue); + } + + if (PchPwrOptPcie->NonSnoopLatencyOverrideMode == 1) { + LtrOvrVal &= 0x0000FFFF; + LtrOvrVal |= (UINT32) BIT31 | + (UINT32) (PchPwrOptPcie->NonSnoopLatencyOverrideMultiplier << 26) | + (UINT32) (PchPwrOptPcie->NonSnoopLatencyOverrideValue << 16); + } + } + if (LtrOvrVal != 0) { + /// + /// Program B0:D28:F0~F7 + 400h only if we find a device in the LTR override table + /// + MmioWrite32 (RootDeviceBase + R_PCH_PCIE_LTROVR, LtrOvrVal); + /// + /// Step 1.2 + /// Program B0:D28:F0~F7 + 404h [1:0] = 11b for ports which has a PCIe device + /// device attached to it. + /// + Data32Or = BIT1 | BIT0; + if (PolicyRevision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_7) { + if (PchPwrOptPcie->SnoopLatencyOverrideMode == 0) { + Data32Or &= (UINT32) ~BIT0; + } + if (PchPwrOptPcie->NonSnoopLatencyOverrideMode == 0) { + Data32Or &= (UINT32) ~BIT1; + } + if (PchPwrOptPcie->LtrConfigLock == PCH_DEVICE_ENABLE) { + /// + /// Set the lock bit + /// + Data32Or |= BIT2; + } + } + MmioWrite32 (RootDeviceBase + R_PCH_PCIE_LTROVR2, Data32Or); + } + } + } +#ifdef ULT_FLAG + if (PchSeries == PchLp) { + /// + /// If both Root and endpoint's L1 Sub-States Extended Capability Offset + 0x04[4:0] are 11111b, + /// + if (*L1SubstatesSupported) { + /// + /// a. Read L1 Sub-States Extended Capability Offset + 0x04[15:8], and Set the highest value advertised + /// between PCIe rootport and device to L1 Sub-States Extended Capability Offset + 0x08[15:8] on both + /// Pcie root port and device. + /// + MmioAndThenOr32 ( + RootDeviceBase + RootL1SubstateExtCapOffset + 0x08, + (UINT32) ~(0xFF00), + (UINT32) PortCommonModeRestoreTime << 8 + ); + + /// + /// b. Read L1 Sub-States Extended Capability Offset + 0x04[23:19] and [17:16], and Set the highest value + /// advertised between PCIe root port and device to L1 Sub-States Extended Capability Offset + 0x0C [7:0] on + /// both Pcie root port and device. + MmioAndThenOr32 ( + RootDeviceBase + RootL1SubstateExtCapOffset + 0x0C, + 0xFFFFFF04, + (UINT32) ((PortTpowerOnValue << 3) | PortTpowerOnScale) + ); + + /// + /// c. Set L1 Sub-States Extended Capability Offset + 0x08[31:29] to 010b for both Pcie root port and device + /// d. Set L1 Sub-States Extended Capability Offset + 0x08[25:16] to 0010100000b for both Pcie root port and device + /// + MmioAndThenOr32 ( + RootDeviceBase + RootL1SubstateExtCapOffset + 0x08, + (UINT32) ~(0xE3FF0000), + (UINT32) (BIT30 | BIT23 | BIT21) + ); + + /// + /// e. If clkreq per port is suported, set D28:F0~F5:420h[0] to 1b prior to L1 enabling + /// + if (((AspmVal & V_PCH_PCIE_LCTL_APMC_L1) == V_PCH_PCIE_LCTL_APMC_L1) && ClkreqPerPortSupported) { + MmioOr32 (RootDeviceBase + R_PCH_PCIE_PCIEPMECTL, BIT0); + } + + /// + /// f. Set L1 Sub-States Extended Capability Offset + 0x08[4:0] to 01111b for both Pcie root port and device + /// + Data32Or = (BIT3 | BIT2 | BIT1 | BIT0); + if (L1SubstatesConfig == PchPcieL1SubstatesL1_1) { + Data32Or &= (UINT32)~(BIT0); + } + if (L1SubstatesConfig == PchPcieL1SubstatesL1_2) { + Data32Or &= (UINT32)~(BIT1); + } + MmioAndThenOr32 ( + RootDeviceBase + RootL1SubstateExtCapOffset + 0x08, + (UINT32) ~(BIT4 | BIT3 | BIT2 | BIT1 | BIT0), + Data32Or + ); + } + + + if ((AspmVal & V_PCH_PCIE_LCTL_APMC_L1) == V_PCH_PCIE_LCTL_APMC_L1) { + /// + /// Program D28:F0~F5:E2h[5:4] to 11b prior to enabling ASPM L1, + /// if all enabled ports support ASPM L1 + /// + if (FirstRPToSetPm && L1SupportedInAllEnabledPorts) { + Status = PchIobpExecution ( + RootComplexBar, + 0xE00000E0, + PciConfigRead, + 0xE0 + GetPchPcieRpfn( RootComplexBar, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1), + &Data32, + &Response + ); + ASSERT_EFI_ERROR (Status); + Data32 |= ((B_PCH_PCIE_RPPGEN_LMSDOCGE | B_PCH_PCIE_RPPGEN_SEOCGE) << 16); + Status = PchIobpExecution ( + RootComplexBar, + 0xE00000E0, + PciConfigWrite, + 0xE0 + GetPchPcieRpfn( RootComplexBar, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1), + &Data32, + &Response + ); + ASSERT_EFI_ERROR (Status); + } + + if (ClkreqPerPortSupported) { + /// + /// Program D28:F0~F5:420h[17] to 0b prior to enabling ASPM L1 + /// + if (*L1SubstatesSupported) { + MmioAnd32 (RootDeviceBase + R_PCH_PCIE_PCIEPMECTL, (UINT32)~B_PCH_PCIE_PCIEPMECTL_L1LE); + } + + /// + /// Program D28:F0~F5:420h[29] to 1b, when D28:F0:E1h[6] is set to 1b + /// + Data32Or = B_PCH_PCIE_PCIEPMECTL_DLSULDLSD; + MmioOr32 ( + RootDeviceBase + R_PCH_PCIE_PCIEPMECTL, + Data32Or + ); + + /// + /// If dedicated CLKREQ# per-port is supported on all enabled ports, set D28:F0:E1h[6] to 1b prior to enabling ASPM L1 + /// + if (FirstRPToSetPm && ClkreqSupportedInAllEnabledPorts) { + Status = PchIobpExecution ( + RootComplexBar, + 0xE00000E0, + PciConfigRead, + 0xE0 + GetPchPcieRpfn( RootComplexBar, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1), + &Data32, + &Response + ); + ASSERT_EFI_ERROR (Status); + Data32 |= (B_PCH_PCIE_RPDCGEN_POCGE << 8); + Status = PchIobpExecution ( + RootComplexBar, + 0xE00000E0, + PciConfigWrite, + 0xE0 + GetPchPcieRpfn( RootComplexBar, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1), + &Data32, + &Response + ); + ASSERT_EFI_ERROR (Status); + } + } + } + } +#endif // ULT_FLAG + /// + /// Set Root Port Aspm and enable LTR capability of the device + /// + MmioAndThenOr16 (RootDeviceBase + RootPcieCapOffset + 0x010, 0xFFFC, AspmVal); + /// + /// Based on the Role based Error Reporting Capability bit, for pre-1.1 devices, + /// program root port 0xD4[4] to 1 and 0xD4[3:2] to 10. + /// + if (AspmOverride) { + MmioAndThenOr8 (RootDeviceBase + R_PCH_PCIE_MPC2, + (UINT8)~(B_PCH_PCIE_MPC2_ASPMCOEN | B_PCH_PCIE_MPC2_ASPMCO), + (B_PCH_PCIE_MPC2_ASPMCOEN | V_PCH_PCIE_MPC2_ASPMCO_L1) + ); + } else { + MmioAnd8 (RootDeviceBase + R_PCH_PCIE_MPC2, (UINT8)~(B_PCH_PCIE_MPC2_ASPMCOEN | B_PCH_PCIE_MPC2_ASPMCO)); + } + /// + /// PCH BIOS Spec Rev 0.5.5, Section 8.14.1 Power Optimizer Configuration + /// Step 1 + /// Enable support Latency Tolerance Reporting (LTR) + /// + + if (EndPointBus != 0 && (SlotStatus & BIT6) != 0) { + /// + /// Set Endpoint Aspm and LTR capabilities + /// + Status = PcieEndPointPm ( + RootDeviceBase, + RootPcieCapOffset, + EndPointBus, + NumOfDevAspmOverride, + DevAspmOverride, + &AspmVal, + SetAspm, + NumOfDevLtrOverride, + DevLtrOverride, + &LtrOvrVal, + RootL1SubstateExtCapOffset, + L1SubstatesSupported, + L1SubstatesConfig, + &PortCommonModeRestoreTime, + &PortTpowerOnValue, + &PortTpowerOnScale, + PchPwrOptPcie, + &AspmOverride, + &ClkreqPerPortSupported, + LtrSupported, + PolicyRevision + ); + } + + if (BusAssign == FALSE) { + /// + /// Clear Bus Numbers. + /// + MmioAnd32 (RootDeviceBase + 0x018, 0xFF0000FF); + } + + if (!EFI_ERROR (Status)) { + /// + /// If L0s and L1 can be enabled on a root port and the endpoints attached to the root port, + /// then set the root port register D28:Fx:Reg E8h[1] + /// + if (AspmVal == V_PCH_PCIE_LCTL_APMC_L0S_L1) { + if (PchSeries == PchLp) { + /// + /// Set the root port register D28:Fx:REG E8h[3:2] to 10b before setting D28:Fx:Reg E8h[0] or E8h[1] + /// + Data8Or = BIT3; + Data8And = (UINT8) ~(V_PCH_PCIE_PECR1_FIELD_3); + MmioAndThenOr8 ( + RootDeviceBase + R_PCH_PCIE_PECR1, + Data8And, + Data8Or + ); + } + MmioOr8 (RootDeviceBase + R_PCH_PCIE_PECR1, B_PCH_PCIE_PECR1_FIELD_2); + } + } + + return Status; +} + +/** + Initializes the root port and its down stream devices + + @param[in] RootPortBus Pci Bus Number of the root port + @param[in] RootPortDevice Pci Device Number of the root port + @param[in] RootPortFunc Pci Function Number of the root port + @param[in] TempBusNumberMin Minimal temp bus number that can be assigned to the root port (as secondary + bus number) and its down stream switches + @param[in] TempBusNumberMax Maximal temp bus number that can be assigned to the root port (as subordinate + bus number) and its down stream switches + @param[in, out] MaxPayload The Max Payolad Size of the root port + @param[out] DeviceClassDword Get the downstream device code dword for unstream RootPort reference + + @retval EFI_SUCCESS Successfully completed + @retval EFI_NOT_FOUND Can not find device. +**/ +EFI_STATUS +PchPcieInitDownstreamDevices ( + IN UINT8 RootPortBus, + IN UINT8 RootPortDevice, + IN UINT8 RootPortFunc, + IN UINT8 TempBusNumberMin, + IN UINT8 TempBusNumberMax, + IN OUT UINT16 *MaxPayload, + OUT UINT32 *DeviceClassDword + ) +{ + EFI_STATUS Status; + UINT32 Index; + UINTN RPBase; + UINTN EndPointBase; + + RPBase = MmPciAddress (0, RootPortBus, RootPortDevice, RootPortFunc, 0); + /// + /// Temporarily Hardcode the Root Port Bridge Number to TempBusNumberMin + /// + MmioAndThenOr32 ( + RPBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, + 0xFF000000, + RootPortBus | ((UINT32) (TempBusNumberMin << 8)) | ((UINT32) (TempBusNumberMax << 16)) + ); + /// + /// This Endpoint check should immediately pass. Howerver, a 1.0s delay + /// has been added to match the timing requirements of the PCI Express Base + /// Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s + /// after a reset of a device, before it may determine that a device which + /// fails to return a Successful Completion status for a valid Configuration + /// Request is a broken device"). + /// + EndPointBase = MmPciAddress (0, TempBusNumberMin, 0, 0, 0); + /// + /// A config write is required in order for the device to re-capture the Bus number, + /// according to PCI Express Base Specification, 2.2.6.2 ("Note that the Bus Number + /// and Device Number may be changed at run time, and so it is necessary to re-capture + /// this information with each and every Configuration Write Request") + /// + MmioWrite8 (EndPointBase + 0x0, 0); + for (Index = 0; Index < 100000; Index++) { + if (MmioRead16 (EndPointBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF) { + break; + } + + PchPmTimerStall (10); + } + + if (Index >= 100000) { + /// + /// Clear Bus Numbers. + /// + MmioAnd32 (RPBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0xFF000000); + return EFI_NOT_FOUND; + } + /// + /// Get the device class code dword for upstream RootPort reference + /// + if (DeviceClassDword != NULL) { + *DeviceClassDword = MmioRead32 (EndPointBase + R_PCH_PCIE_RID); + } + /// + /// Get the Max Payload Size on all the end point functions + /// + PcieMaxPayloadSize (TempBusNumberMin, PCI_MAX_DEVICE, MaxPayload, FALSE); + /// + /// Check if this device is a bridge + /// + if (MmioRead8 (EndPointBase + R_PCH_PCIE_BCC) == PCI_CLASS_BRIDGE) { + /// + /// Initialize downstream devices + /// + if (TempBusNumberMax > TempBusNumberMin) { + Status = PchPcieInitDownstreamDevices ( + TempBusNumberMin, + 0, + 0, + TempBusNumberMin + 1, + TempBusNumberMax, + MaxPayload, + NULL + ); + } + } + /// + /// Complete Common Port and Endpoint Configuration. + /// + /// + /// Map TC0-VC0 + /// + PcieMapTcxVc0 (RootPortBus, RootPortDevice, (UINT8) RootPortFunc, TempBusNumberMin, PCI_MAX_DEVICE, 0x0); + + /// + /// Set Common Clock for inserted cards + /// + /// + /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 ASPM on DMI and the PCI Express* Root Ports + /// Before determining whether ASPM can be enabled or not, + /// the System BIOS must perform the following steps: + /// + /// For PCH H + /// 1. Update the Link Capabilities of the DMI to indicate L1 is + /// supported on the interface by setting the LCAP Register + /// RCBA + 21A4h [11:10] = 11b + /// (Done in PchPm.c) + /// + /// 2. Enable L0s on DMI for Desktop platforms by setting the APMC field, + /// RCBA + offset 21A8h[1:0] to 01b. + /// Enable L0s/L1 on DMI by setting RCBA + offset 21A8h[1:0] to 11b. + /// (Done in PchPm.c) + /// + /// 3. For each root port, read the Slot Clock Configuration bit, D28:F0~F7:Reg 52h[12], + /// of the root port and the endpoint device connected to the port (i.e., D0:F0 on the + /// secondary bus behind the root port). If both components have this bit set, then the + /// System BIOS should set the Common Clock Configuration (CCC) bit, D28:F0~F7:Reg 50h[6], + /// for both components at both sides of the link to indicate that components at both ends + /// of the link use a common clock source. + /// + /// 4. If the CCC bit was changed by the System BIOS in step 3, System BIOS should initiate + /// a link training by setting the Retrain Link (RL) bit, D28:F0~F7:Reg 50h[5], and then poll the Link + /// Training (LT) bit, D28:F0~F7:Reg 52h[11], until it is clear. + /// Note that System BIOS should save and restore CCC bit on S3. + /// + PcieSetCommonClock (RootPortBus, RootPortDevice, (UINT8) RootPortFunc, TempBusNumberMin, PCI_MAX_DEVICE); + + /// + /// Enable the PCIe CLKREQ# + /// + PcieSetClkreq (TempBusNumberMin, PCI_MAX_DEVICE, (UINT8) RootPortFunc); + + /// + /// Set the Max Payload Size on all the end point functions + /// + PcieMaxPayloadSize (TempBusNumberMin, PCI_MAX_DEVICE, MaxPayload, TRUE); + + /// + /// Disable the forwarding of EOI messages unless it discovers an IOAPIC behind this root port + /// + PcieSetEoiFwdDisable (RootPortBus, RootPortDevice, RootPortFunc, TempBusNumberMin, PCI_MAX_DEVICE); + /// + /// Clear Bus Numbers + /// + MmioAnd32 (RPBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0xFF000000); + + return EFI_SUCCESS; +} + +/** + Initializes the root port and its down stream devices + + @param[in] RootPortBus Pci Bus Number of the root port + @param[in] RootPortDevice Pci Device Number of the root port + @param[in] RootPortFunc Pci Function Number of the root port + @param[in] TempBusNumberMin Minimal temp bus number that can be assigned to the root port (as secondary + bus number) and its down stream switches + @param[in] TempBusNumberMax Maximal temp bus number that can be assigned to the root port (as subordinate + bus number) and its down stream switches + @param[out] DeviceClassDword Get the downstream device code dword for unstream RootPort reference + + @retval EFI_SUCCESS Successfully completed + @retval EFI_NOT_FOUND Can not find device. +**/ +EFI_STATUS +PchPcieInitRootPortDownstreamDevices ( + IN UINT8 RootPortBus, + IN UINT8 RootPortDevice, + IN UINT8 RootPortFunc, + IN UINT8 TempBusNumberMin, + IN UINT8 TempBusNumberMax, + OUT UINT32 *DeviceClassDword + ) +{ + UINT16 SlotStatus; + UINTN RPBase; + UINT16 RootPortMaxPayload; + UINT8 PcieCapOffset; + EFI_STATUS Status; + + RPBase = MmPciAddress (0, RootPortBus, RootPortDevice, RootPortFunc, 0); + /// + /// Check for a Presence Detect Change. + /// + SlotStatus = MmioRead16 (RPBase + R_PCH_PCIE_SLSTS); + + /// + /// Check whether the slot has a device connected + /// + if ((SlotStatus & BIT6) == 0) { + return EFI_NOT_FOUND; + } + /// + /// Get the pointer to the Endpoint PCI Express Capability Structure. + /// + PcieCapOffset = PcieFindCapId ( + RootPortBus, + RootPortDevice, + RootPortFunc, + EFI_PCI_CAPABILITY_ID_PCIEXP + ); + + /// + /// Get the root port Max Payload Size support + /// + RootPortMaxPayload = MmioRead16 (RPBase + PcieCapOffset + 0x04) & (BIT2 | BIT1 | BIT0); + + /// + /// Initialize downstream devices + /// + Status = PchPcieInitDownstreamDevices ( + RootPortBus, + RootPortDevice, + RootPortFunc, + TempBusNumberMin, + TempBusNumberMax, + &RootPortMaxPayload, + DeviceClassDword + ); + + /// + /// Set the PCIE root Port Max Payload Size + /// + MmioAndThenOr16 (RPBase + PcieCapOffset + 0x08, (UINT16)~(BIT7 | BIT6 | BIT5), RootPortMaxPayload << 5); + + return Status; +} diff --git a/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLibrary.h b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLibrary.h new file mode 100644 index 0000000..7f32fe0 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Library/PchPciExpressHelpersLib/PchPciExpressHelpersLibrary.h @@ -0,0 +1,42 @@ +/** @file + Header file for PCH Pci Express helps library implementation. + +@copyright + Copyright (c) 2008 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement +**/ +#ifndef _PCH_PCI_EXPRESS_HELPERS_LIBRARY_H_ +#define _PCH_PCI_EXPRESS_HELPERS_LIBRARY_H_ + +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueBase.h" +#include "PchPlatformPolicy.h" +#include "PchAccess.h" +#include "PchPlatformLib.h" +#include "PchPciExpressHelperslib.h" +#include "pci23.h" +#include "pci22.h" +#endif + +#define LTR_VALUE_MASK (BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7 + BIT8 + BIT9) +#define LTR_SCALE_MASK (BIT10 + BIT11 + BIT12) + +// +// LTR related macros +// +#define LTR_LATENCY_VALUE(x) ((x) & LTR_VALUE_MASK) +#define LTR_SCALE_VALUE(x) (((x) & LTR_SCALE_MASK) >> 10) +#define LTR_LATENCY_NS(x) (LTR_LATENCY_VALUE(x) * (1 << (5 * LTR_SCALE_VALUE(x)))) + +#endif |