--- /dev/null
+/** @file\r
+QNC PCI Express initialization entry\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+\r
+#define PCIEXP_ROOT_PORT_URE_ENABLE BIT0 // unsupported request reporting enable\r
+#define PCIEXP_ROOT_PORT_FEE_ENABLE BIT1 // Fatal Error Reporting Enable\r
+#define PCIEXP_ROOT_PORT_NFE_ENABLE BIT2 // Non-Fatal Error Reporting Enable\r
+#define PCIEXP_ROOT_PORT_CEE_ENABLE BIT3 // Correctable Error Reporting Enable\r
+#define PCIEXP_ROOT_PORT_SFE_ENABLE BIT4 // System Error on Fatal Error Enable\r
+#define PCIEXP_ROOT_PORT_SNE_ENABLE BIT5 // System Error on Non-Fatal Error Enable\r
+#define PCIEXP_ROOT_PORT_SCE_ENABLE BIT6 // System Error on Correctable Error Enable\r
+\r
+EFI_STATUS\r
+PcieStall (\r
+ IN UINTN Microseconds\r
+ )\r
+{\r
+ MicroSecondDelay (Microseconds);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Find the Offset to a given Capabilities ID\r
+ CAPID list:\r
+ 0x01 = PCI Power Management Interface\r
+ 0x04 = Slot Identification\r
+ 0x05 = MSI Capability\r
+ 0x10 = PCI Express Capability\r
+\r
+ @param[in] Bus Bus number of the interested device\r
+ @param[in] Device Device number of the interested device\r
+ @param[in] Function Function number of the interested device\r
+ @param[in] CapId Capability ID to be scanned\r
+\r
+ @retval Offset of desired CAPID\r
+\r
+**/\r
+UINT32\r
+PcieFindCapId (\r
+ UINT8 Bus,\r
+ UINT8 Device,\r
+ UINT8 Function,\r
+ UINT8 CapId\r
+ )\r
+{\r
+ UINT8 CapHeader;\r
+\r
+ //\r
+ // Always start at Offset 0x34\r
+ //\r
+ CapHeader = QNCMmPci8 (0, Bus, Device, Function, R_QNC_PCIE_CAP_PTR);\r
+\r
+ if (CapHeader == 0xFF) {\r
+ return 0;\r
+ }\r
+\r
+ while (CapHeader != 0) {\r
+ if (QNCMmPci8 (0, Bus, Device, Function, CapHeader) == CapId) {\r
+ return CapHeader;\r
+ }\r
+ CapHeader = QNCMmPci8 (0, Bus, Device, Function, CapHeader + 1);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Search and return the offset of desired Pci Express Capability ID\r
+ CAPID list:\r
+ 0x0001 = Advanced Error Rreporting Capability\r
+ 0x0002 = Virtual Channel Capability\r
+ 0x0003 = Device Serial Number Capability\r
+ 0x0004 = Power Budgeting Capability\r
+\r
+ @param[in] Bus Bus number of the interested device\r
+ @param[in] Device Device number of the interested device\r
+ @param[in] Function Function number of the interested device\r
+ @param[in] CapId Capability ID to be scanned\r
+\r
+ @retval Offset of desired CAPID\r
+\r
+**/\r
+UINT32\r
+PcieFindExtendedCapId (\r
+ UINT8 Bus,\r
+ UINT8 Device,\r
+ UINT8 Function,\r
+ UINT16 CapId\r
+ )\r
+{\r
+ UINT16 CapHeaderOffset;\r
+ UINT16 CapHeaderId;\r
+\r
+ // Start to search at Offset 0x100\r
+ // Get Capability Header\r
+ CapHeaderId = 0;\r
+ CapHeaderOffset = PCIE_CAP_EXT_HEARDER_OFFSET;\r
+\r
+ while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {\r
+ CapHeaderId = QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset);\r
+ if (CapHeaderId == CapId) {\r
+ return CapHeaderOffset;\r
+ }\r
+ CapHeaderOffset = (QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Map Vc on both root port and downstream device\r
+\r
+ @param[in] Bus1 Bus number of the root port\r
+ @param[in] Device1 Device number of the root port\r
+ @param[in] Function1 Function number of the root port\r
+ @param[in] Bus2 Bus number of the downstream device\r
+ @param[in] Device2 Device number of the downstream device\r
+ @param[in] Function2 Function number of the downstream device\r
+\r
+ @retval EFI_SUCCESS Map Vc successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieInitTcxVc0 (\r
+ IN UINT8 Bus1,\r
+ IN UINT8 Device1,\r
+ IN UINT8 Function1,\r
+ IN UINT8 Bus2,\r
+ IN UINT8 Device2,\r
+ IN UINT8 Function2\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ //\r
+ // Initialize TCx-VC0 value on the port to only use TC0\r
+ //\r
+ Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8AndThenOr (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);\r
+\r
+ // Set TCx-VC0 value on the Endpoint\r
+\r
+ Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8AndThenOr (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Map Traffic Class x to Vc0 on both root port and downstream device\r
+\r
+ @param[in] Bus1 Bus number of the root port\r
+ @param[in] Device1 Device number of the root port\r
+ @param[in] Function1 Function number of the root port\r
+ @param[in] Bus2 Bus number of the downstream device\r
+ @param[in] Device2 Device number of the downstream device\r
+ @param[in] Function2 Function number of the downstream device\r
+ @param[in] TCx Traffic Class to be mapped to vc0\r
+\r
+ @retval EFI_SUCCESS Map Tcx to Vc0 successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieMapTcxVc0 (\r
+ IN UINT8 Bus1,\r
+ IN UINT8 Device1,\r
+ IN UINT8 Function1,\r
+ IN UINT8 Bus2,\r
+ IN UINT8 Device2,\r
+ IN UINT8 Function2,\r
+ IN UINT8 TCx\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ //\r
+ // Set TCx-VC0 value on the port\r
+ //\r
+\r
+ Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8 (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);\r
+\r
+ // Set TCx-VC0 value on the Endpoint\r
+\r
+ Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8 (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Set common clock for both root port and downstream device.\r
+\r
+ @param[in] Bus1 Bus number of the root port\r
+ @param[in] Device1 Device number of the root port\r
+ @param[in] Function1 Function number of the root port\r
+ @param[in] Bus2 Device number of the downstream device\r
+ @param[in] Device2 Function number of the downstream device\r
+\r
+ @retval EFI_SUCCESS Set common clock successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieSetCommonClock (\r
+ IN UINT8 Bus1,\r
+ IN UINT8 Device1,\r
+ IN UINT8 Function1,\r
+ IN UINT8 Bus2,\r
+ IN UINT8 Device2\r
+ )\r
+{\r
+ UINT32 CapOffset1;\r
+ UINT32 CapOffset2;\r
+ UINT8 Function2;\r
+ UINT8 CommonClock;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get the pointer to the Port PCI Express Capability Structure.\r
+ //\r
+ CommonClock = 0;\r
+ CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, PCIE_CAPID);\r
+ if (CapOffset1 == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Step 1\r
+ // Read the Slot Clock Configuration bit of the Link status register of the root port and the endpoint device connected to the port\r
+ // If both components have this bit set to 1, then System BIOS should set the "Common Clock Configuration" bit in the Link Control Registers\r
+ // for both components at both sides of the link to indicate that components at both ends\r
+ // of the link use a common clock source\r
+ //\r
+\r
+ //\r
+ // Check the Port Slot Clock Configuration Bit.\r
+ //\r
+ if ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ for (Function2 = 0; Function2 < 8; Function2++) {\r
+ //\r
+ // Check the Endpoint Slot Clock Configuration Bit.\r
+ //\r
+ CapOffset2 = PcieFindCapId (Bus2, Device2, Function2, PCIE_CAPID);\r
+ if ((CapOffset2 != 0) &&\r
+ ((QNCMmPci16 (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) != 0)) {\r
+\r
+ //\r
+ // Common clock is supported, set common clock bit on root port\r
+ // and the endpoint\r
+ //\r
+ if (CommonClock == 0) {\r
+ QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);\r
+ CommonClock++;\r
+ }\r
+ QNCMmPci8Or (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Step 2 If the Common Clock Configuration bit was changed by BIOS in step 1,\r
+ // System BIOS should initiate a link training by setting the Retrain Link bit\r
+ // in the Link Control register of the root port (D28:F0/F1 offset\r
+ // 50h [5]) to "1b" and then poll the Link Training bit in the Link Status\r
+ // register of the root port (D28:F0/F1/F2/F3/F4/F5 offset 52h [11]) until it is\r
+ // "0b".\r
+ //\r
+ if (CommonClock == 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ //\r
+ // Retrain the Link per PCI Express Specification.\r
+ //\r
+ QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_RL);\r
+\r
+ //\r
+ // Wait until Re-Training has completed.\r
+ //\r
+ while ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_LT) != 0);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Enables the CLKREQ# PM on all the end point functions\r
+\r
+ @param[in] Bus Bus number of the downstream device\r
+ @param[in] Device Device number of the downstream device\r
+\r
+ @retval None\r
+\r
+**/\r
+VOID\r
+PcieSetClkreq (\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device\r
+ )\r
+{\r
+ UINT8 Function;\r
+ UINT32 CapOffset;\r
+\r
+ //\r
+ // Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if\r
+ // exists then enable the CLKREQ# bit (BIT8) on that function\r
+ //\r
+ for (Function = 0; Function < 8; Function++) {\r
+ //\r
+ // Find the PCIe Cap Id (offset 10h)\r
+ //\r
+ CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);\r
+ if (CapOffset == 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check if CLKREQ# is supported by the endpoints\r
+ //\r
+ if ((QNCMmPci32 (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CAP_OFFSET))\r
+ & B_QNC_PCIE_LCAP_CPM) != B_QNC_PCIE_LCAP_CPM) {\r
+ //\r
+ // CLKREQ# is not supported so dont do anything\r
+ //\r
+ return;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Now enable the CLKREQ#\r
+ //\r
+ for (Function = 0; Function < 8; Function++) {\r
+ //\r
+ // Find the PCIe Cap Id (offset 10h)\r
+ //\r
+ CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);\r
+ if (CapOffset == 0) {\r
+ continue;\r
+ }\r
+\r
+ QNCMmPci16Or (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CNT_OFFSET), BIT8);\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Configure ASPM automatically for both root port and downstream device.\r
+\r
+ @param[in] RootBus Bus number of the root port\r
+ @param[in] RootDevice Device number of the root port\r
+ @param[in] RootFunction Function number of the root port\r
+ @param[in] EndpointBus Bus number of the downstream device\r
+ @param[in] EndpointDevice Device number of the downstream device\r
+ @param[in] EndpointFunction Function number of the downstream device\r
+ @param[in] LinkAspmVal Currently used ASPM setting\r
+\r
+ @retval EFI_SUCCESS Configure ASPM successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieSetAspmAuto (\r
+ IN UINT8 RootBus,\r
+ IN UINT8 RootDevice,\r
+ IN UINT8 RootFunction,\r
+ IN UINT8 EndpointBus,\r
+ IN UINT8 EndpointDevice,\r
+ IN UINT8 EndpointFunction,\r
+ OUT UINT16 *LinkAspmVal\r
+ )\r
+{\r
+ UINT32 RootPcieCapOffset;\r
+ UINT32 EndpointPcieCapOffset;\r
+ UINT16 RootPortAspm;\r
+ UINT16 EndPointAspm;\r
+ UINT16 EndPointVendorId;\r
+ UINT16 EndPointDeviceId;\r
+ UINT8 EndPointRevId;\r
+ UINT16 AspmVal;\r
+ UINT32 PortLxLat;\r
+ UINT32 EndPointLxLat;\r
+ UINT32 LxLat;\r
+\r
+ //\r
+ // Get the pointer to the Port PCI Express Capability Structure.\r
+ //\r
+ RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID);\r
+ if (RootPcieCapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Get the pointer to the Endpoint PCI Express Capability Structure.\r
+ //\r
+ EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID);\r
+ if (EndpointPcieCapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Obtain initial ASPM settings from respective port capability registers.\r
+ //\r
+ RootPortAspm = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;\r
+\r
+ //\r
+ // Configure downstream device if present.\r
+ //\r
+ EndPointAspm = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;\r
+\r
+ //\r
+ // Mask APMC with values from lookup table.\r
+ // RevID of 0xFF applies to all steppings.\r
+ //\r
+\r
+ EndPointVendorId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 0);\r
+ EndPointDeviceId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 2);\r
+ EndPointRevId = QNCMmPci8 (0, EndpointBus, EndpointDevice, EndpointFunction, 8);\r
+\r
+ // TODO: Mask with latency/acceptable latency comparison results.\r
+\r
+ AspmVal = RootPortAspm;\r
+ if (RootPortAspm > EndPointAspm) {\r
+ AspmVal = EndPointAspm;\r
+ }\r
+\r
+ //\r
+ // Check if L1 should be enabled based on port and endpoint L1 exit latency.\r
+ //\r
+ if(AspmVal & BIT1) {\r
+ PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;\r
+ EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;\r
+\r
+ LxLat = PortLxLat;\r
+ if(PortLxLat < EndPointLxLat) {\r
+ LxLat = EndPointLxLat;\r
+ }\r
+\r
+ //\r
+ // check if the value is bigger than endpoint L1 acceptable exit latency, if it is\r
+ // larger than accepted value, then we should disable L1\r
+ //\r
+ LxLat >>= 6;\r
+ if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) {\r
+ AspmVal &= ~BIT1;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check if L0s should be enabled based on port and endpoint L0s exit latency.\r
+ //\r
+ if(AspmVal & BIT0) {\r
+ PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;\r
+ EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;\r
+\r
+ LxLat = PortLxLat;\r
+ if(PortLxLat < EndPointLxLat) {\r
+ LxLat = EndPointLxLat;\r
+ }\r
+\r
+ //\r
+ // check if the value is bigger than endpoint L0s acceptable exit latency, if it is\r
+ // larger than accepted value, then we should disable L0s\r
+ //\r
+ LxLat >>= 6;\r
+ if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) {\r
+ AspmVal &= ~BIT0;\r
+ }\r
+ }\r
+\r
+ RootPortAspm = AspmVal;\r
+\r
+ *LinkAspmVal = AspmVal;\r
+ //\r
+ // Set Endpoint Aspm\r
+ //\r
+ QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal);\r
+\r
+\r
+ //\r
+ // Set Root Port Aspm\r
+ //\r
+ QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Configure ASPM based on the given setting for the interested device.\r
+\r
+ @param[in] Bus Bus number of the interested device\r
+ @param[in] Device Device number of the interested device\r
+ @param[in] Function Function number of the interested device\r
+ @param[in] AspmSetting Aspm setting\r
+ @param[in] LinkAspmVal Currently used ASPM setting\r
+\r
+ @retval EFI_SUCCESS Configure ASPM successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieSetAspmManual (\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Function,\r
+ IN UINT8 AspmSetting,\r
+ OUT UINT16 *LinkAspmVal\r
+ )\r
+{\r
+ UINT32 PcieCapOffset;\r
+ UINT16 PortAspm;\r
+\r
+ //\r
+ // Get the pointer to the Port PCI Express Capability Structure.\r
+ //\r
+ PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);\r
+ if (PcieCapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // Read the Link Capability register's ASPM setting\r
+ PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;\r
+ // Mask it with the Setup selection\r
+ PortAspm &= AspmSetting;\r
+\r
+ *LinkAspmVal = PortAspm;\r
+ // Write it to the Link Control register\r
+ QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Perform Initialization on one PCI Express root port.\r
+\r
+ @param[in] RootPortIndex Index of PCI Express root port\r
+ @param[in] RootPortConfig Pointer to the given pcie root port configuration\r
+ @param[in] PciExpressBar Base address of pcie space\r
+ @param[in] QNCRootComplexBar Base address of root complex\r
+ @param[in] QNCPmioBase Base address of PM IO space\r
+ @param[in] QNCGpeBase Base address of gpe IO space\r
+\r
+ @retval EFI_SUCCESS Initialization successful\r
+\r
+**/\r
+EFI_STATUS\r
+QNCRootPortInit (\r
+ IN UINT32 RootPortIndex,\r
+ IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig,\r
+ IN UINT64 PciExpressBar,\r
+ IN UINT32 QNCRootComplexBar,\r
+ IN UINT32 QNCPmioBase,\r
+ IN UINT32 QNCGpeBase\r
+ )\r
+{\r
+ UINT64 RPBase;\r
+ UINT64 EndPointBase;\r
+ UINT64 LpcBase;\r
+ UINT16 AspmVal;\r
+ UINT16 SlotStatus;\r
+ UINTN Index;\r
+ UINT32 CapOffset;\r
+ UINT32 DwordReg;\r
+\r
+ RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12);\r
+ LpcBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + (31 << 3) + (0 << 0)) << 12);\r
+ CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID);\r
+\r
+ if (CapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Initialize "Slot Implmemented Bit" for this root port\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI);\r
+ }\r
+\r
+ //\r
+ // For Root Port Slots Numbering on the CRBs.\r
+ // Root Port 0 = Slot 1\r
+ // Root Port 1 = Slot 2\r
+ // Root Port 2 = Slot 3\r
+ // Root Port 3 = Slot 4\r
+ //\r
+ DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP);\r
+ DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE;\r
+ DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET);\r
+ DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ;\r
+ QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg;\r
+\r
+ //\r
+ // Check for a Presence Detect Change.\r
+ //\r
+ SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS);\r
+ if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Temporarily Hardcode the Root Port Bridge Number to 2.\r
+ //\r
+ // This Endpoint check should immediately pass. Howerver, a 900ms delay\r
+ // has been added to match the timing requirements of the PCI Express Base\r
+ // Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s\r
+ // after a reset of a device, before it may determine that a device which\r
+ // fails to return a Successful Completion status for a valid Configuration\r
+ // Request is a broken device"). Note that a 100ms delay was already added\r
+ // after the Root Ports were first taken out of reset.\r
+ //\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200);\r
+ //\r
+ // Only do this when a downstream device is present\r
+ //\r
+ EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12);\r
+ if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {\r
+ for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){\r
+ if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) {\r
+ break;\r
+ }\r
+ PcieStall (15);\r
+ }\r
+ if (Index >= V_PCIE_MAX_TRY_TIMES) {\r
+ //\r
+ // Clear Bus Numbers.\r
+ //\r
+ QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ //\r
+ // PCI Express* Virtual Channels\r
+ // Clear TC1-7 Traffic classes.\r
+ // Map TC0-VC0\r
+ //\r
+ PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0);\r
+ PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0);\r
+\r
+ //\r
+ // Set Common Clock for inserted cards\r
+ //\r
+ if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {\r
+ PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0);\r
+ }\r
+\r
+ //\r
+ // Flow for Enabling ASPM\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.AspmEnable) {\r
+ if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) {\r
+ PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal);\r
+ } else {\r
+ //\r
+ // Set ASPM values according to setup selections, masked by capabilities\r
+ //\r
+ PcieSetAspmManual (\r
+ PCI_BUS_NUMBER_QNC,\r
+ (UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT),\r
+ (UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex),\r
+ (UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)),\r
+ &AspmVal\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Enable the PCIe CLKREQ#\r
+ //\r
+ if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {\r
+ PcieSetClkreq (2, 0);\r
+ }\r
+\r
+ //\r
+ // Clear Bus Numbers\r
+ //\r
+ QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);\r
+\r
+ //\r
+ // Additional configurations\r
+ //\r
+\r
+ //\r
+ // PCI-E Unsupported Request Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE);\r
+ }\r
+\r
+ //\r
+ // Device Fatal Error Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE);\r
+ }\r
+\r
+ //\r
+ // Device Non Fatal Error Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE);\r
+ }\r
+\r
+ //\r
+ // Device Correctable Error Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE);\r
+ }\r
+ //\r
+ // Root PCI-E PME Interrupt Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE);\r
+ }\r
+ //\r
+ // Root PCI-E System Error on Fatal Error Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE);\r
+ }\r
+\r
+ //\r
+ // Root PCI-E System Error on Non-Fatal Error Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE);\r
+ }\r
+\r
+ //\r
+ // Root PCI-E System Error on Correctable Error Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE);\r
+ }\r
+\r
+ //\r
+ // Root PCI-E Powermanagement SCI Enabled\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) {\r
+ //\r
+ // Make sure that PME Interrupt Enable bit of Root Control register\r
+ // of PCI Express Capability struceture is cleared\r
+ //\r
+ QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE));\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE);\r
+\r
+ //\r
+ // Make sure GPE0 Stutus RW1C Bit is clear.\r
+ //\r
+ DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S);\r
+ if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) {\r
+ IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE);\r
+ }\r
+ }\r
+\r
+ //\r
+ // PCIe Hot Plug SCI Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) {\r
+ //\r
+ // Write clear for :\r
+ // Attention Button Pressed (bit0)\r
+ // Presence Detect Changed (bit3)\r
+ //\r
+ QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP));\r
+\r
+ //\r
+ // Sequence 2: Program the following bits in Slot Control register at offset 18h\r
+ // of PCI Express* Capability structure:\r
+ // Attention Button Pressed Enable (bit0) = 1b\r
+ // Presence Detect Changed Enable (bit3) = 1b\r
+ // Hot Plug Interrupt Enable (bit5) = 0b\r
+ //\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE));\r
+\r
+ //\r
+ // Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset\r
+ // D8h as follows:\r
+ // Hot Plug SCI Enable (HPCE, bit30) = 1b\r
+ // Hot Plug SMI Enable (HPME, bit1) = 0b\r
+ //\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE);\r
+ }\r
+\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Perform Initialization of the Downstream Root Ports\r
+**/\r
+VOID\r
+QNCDownStreamPortsInit (\r
+ IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig,\r
+ IN QNC_DEVICE_ENABLES *QNCDeviceEnables,\r
+ IN UINT64 PciExpressBar,\r
+ IN UINT32 QNCRootComplexBar,\r
+ IN UINT32 QNCPmioBase,\r
+ IN UINT32 QNCGpeBase,\r
+ OUT UINTN *RpEnableMask\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+\r
+ //\r
+ // Initialize every root port and downstream device\r
+ //\r
+ for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) {\r
+ if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) {\r
+ Status = QNCRootPortInit (\r
+ Index,\r
+ RootPortConfig,\r
+ PciExpressBar,\r
+ QNCRootComplexBar,\r
+ QNCPmioBase,\r
+ QNCGpeBase\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ (*RpEnableMask) |= LShiftU64(1, Index);\r
+ DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask));\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Do early init of pci express rootports on Soc.\r
+\r
+**/\r
+\r
+VOID\r
+EFIAPI\r
+PciExpressEarlyInit (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Setup Message Bus Idle Counter (SBIC) values.\r
+ //\r
+ QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE);\r
+ QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE);\r
+\r
+ //\r
+ // Program SVID/SID the same as VID/DID for Root ports.\r
+ //\r
+ QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, PCI_VENDOR_ID_OFFSET);\r
+ QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, PCI_VENDOR_ID_OFFSET);\r
+\r
+ //\r
+ // Set the IPF bit in MCR2\r
+ //\r
+ QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF);\r
+ QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF);\r
+\r
+ //\r
+ // Set up the Posted and Non Posted Request sizes for PCIe\r
+ //\r
+ QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG) = QNCMmPci32AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG, ~B_QNC_PCIE_CCFG_UPSD, (B_QNC_PCIE_CCFG_UNRS | B_QNC_PCIE_CCFG_UPRS));\r
+\r
+ return;\r
+}\r
+\r
+\r
+/**\r
+ Complete initialization all the pci express rootports on Soc.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PciExpressInit (\r
+ )\r
+{\r
+ UINT64 PciExpressBar;\r
+ UINT32 QNCRootComplexBar;\r
+ UINT32 QNCGpioBase;\r
+ UINT32 QNCPmioBase;\r
+ UINT32 QNCGpeBase;\r
+ UINTN RpEnableMask;\r
+ PCIEXP_ROOT_PORT_CONFIGURATION *mRootPortConfig;\r
+ QNC_DEVICE_ENABLES mQNCDeviceEnables;\r
+\r
+ //\r
+ // Get BAR registers\r
+ //\r
+ QNCRootComplexBar = QNC_RCRB_BASE;\r
+ QNCGpioBase = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;\r
+ QNCPmioBase = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;\r
+ QNCGpeBase = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK;\r
+ RpEnableMask = 0; // assume all root ports are disabled\r
+\r
+ PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress);\r
+\r
+ //\r
+ // Get platform information from PCD entries\r
+ //\r
+ mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);\r
+ mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration);\r
+\r
+ DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x, value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n",\r
+ mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32,\r
+ mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32));\r
+\r
+ QNCDownStreamPortsInit (\r
+ mRootPortConfig,\r
+ &mQNCDeviceEnables,\r
+ PciExpressBar,\r
+ QNCRootComplexBar,\r
+ QNCPmioBase,\r
+ QNCGpeBase,\r
+ &RpEnableMask\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r