Home | History | Annotate | Download | only in IntelQNCLib
      1 /** @file
      2 QNC PCI Express initialization entry
      3 
      4 Copyright (c) 2013-2015 Intel Corporation.
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "CommonHeader.h"
     17 
     18 #define PCIEXP_ROOT_PORT_URE_ENABLE    BIT0   //  unsupported request reporting enable
     19 #define PCIEXP_ROOT_PORT_FEE_ENABLE    BIT1   //  Fatal Error Reporting Enable
     20 #define PCIEXP_ROOT_PORT_NFE_ENABLE    BIT2   //  Non-Fatal Error Reporting Enable
     21 #define PCIEXP_ROOT_PORT_CEE_ENABLE    BIT3   //  Correctable Error Reporting Enable
     22 #define PCIEXP_ROOT_PORT_SFE_ENABLE    BIT4   //  System Error on Fatal Error Enable
     23 #define PCIEXP_ROOT_PORT_SNE_ENABLE    BIT5   //  System Error on Non-Fatal Error Enable
     24 #define PCIEXP_ROOT_PORT_SCE_ENABLE    BIT6   //  System Error on Correctable Error Enable
     25 
     26 EFI_STATUS
     27 PcieStall (
     28   IN UINTN              Microseconds
     29   )
     30 {
     31   MicroSecondDelay (Microseconds);
     32   return EFI_SUCCESS;
     33 }
     34 
     35 /**
     36 
     37   Find the Offset to a given Capabilities ID
     38     CAPID list:
     39       0x01 = PCI Power Management Interface
     40       0x04 = Slot Identification
     41       0x05 = MSI Capability
     42       0x10 = PCI Express Capability
     43 
     44   @param[in]  Bus                     Bus number of the interested device
     45   @param[in]  Device                  Device number of the interested device
     46   @param[in]  Function                Function number of the interested device
     47   @param[in]  CapId                   Capability ID to be scanned
     48 
     49   @retval Offset of desired CAPID
     50 
     51 **/
     52 UINT32
     53 PcieFindCapId (
     54   UINT8   Bus,
     55   UINT8   Device,
     56   UINT8   Function,
     57   UINT8   CapId
     58   )
     59 {
     60   UINT8    CapHeader;
     61 
     62   //
     63   // Always start at Offset 0x34
     64   //
     65   CapHeader = QNCMmPci8 (0, Bus, Device, Function, R_QNC_PCIE_CAP_PTR);
     66 
     67   if (CapHeader == 0xFF) {
     68      return 0;
     69   }
     70 
     71   while (CapHeader != 0) {
     72     if (QNCMmPci8 (0, Bus, Device, Function, CapHeader) == CapId) {
     73       return CapHeader;
     74     }
     75     CapHeader = QNCMmPci8 (0, Bus, Device, Function, CapHeader + 1);
     76   }
     77   return 0;
     78 }
     79 
     80 /**
     81 
     82   Search and return the offset of desired Pci Express Capability ID
     83     CAPID list:
     84       0x0001 = Advanced Error Rreporting Capability
     85       0x0002 = Virtual Channel Capability
     86       0x0003 = Device Serial Number Capability
     87       0x0004 = Power Budgeting Capability
     88 
     89   @param[in]  Bus                     Bus number of the interested device
     90   @param[in]  Device                  Device number of the interested device
     91   @param[in]  Function                Function number of the interested device
     92   @param[in]  CapId                   Capability ID to be scanned
     93 
     94   @retval Offset of desired CAPID
     95 
     96 **/
     97 UINT32
     98 PcieFindExtendedCapId (
     99   UINT8   Bus,
    100   UINT8   Device,
    101   UINT8   Function,
    102   UINT16  CapId
    103   )
    104 {
    105   UINT16    CapHeaderOffset;
    106   UINT16    CapHeaderId;
    107 
    108   // Start to search at Offset 0x100
    109   // Get Capability Header
    110   CapHeaderId = 0;
    111   CapHeaderOffset = PCIE_CAP_EXT_HEARDER_OFFSET;
    112 
    113   while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {
    114     CapHeaderId = QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset);
    115     if (CapHeaderId == CapId) {
    116       return CapHeaderOffset;
    117     }
    118     CapHeaderOffset = (QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4);
    119   }
    120   return 0;
    121 }
    122 
    123 /**
    124 
    125   Map Vc on both root port and downstream device
    126 
    127   @param[in]  Bus1                    Bus number of the root port
    128   @param[in]  Device1                 Device number of the root port
    129   @param[in]  Function1               Function number of the root port
    130   @param[in]  Bus2                    Bus number of the downstream device
    131   @param[in]  Device2                 Device number of the downstream device
    132   @param[in]  Function2               Function number of the downstream device
    133 
    134   @retval EFI_SUCCESS    Map Vc successful
    135 
    136 **/
    137 EFI_STATUS
    138 PcieInitTcxVc0 (
    139   IN UINT8   Bus1,
    140   IN UINT8   Device1,
    141   IN UINT8   Function1,
    142   IN UINT8   Bus2,
    143   IN UINT8   Device2,
    144   IN UINT8   Function2
    145   )
    146 {
    147   UINT32  Offset;
    148 
    149   //
    150   // Initialize TCx-VC0 value on the port to only use TC0
    151   //
    152   Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);
    153   if (Offset == 0) {
    154     return EFI_UNSUPPORTED;
    155   }
    156   QNCMmPci8AndThenOr (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);
    157 
    158   // Set TCx-VC0 value on the Endpoint
    159 
    160   Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);
    161   if (Offset == 0) {
    162     return EFI_UNSUPPORTED;
    163   }
    164   QNCMmPci8AndThenOr (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);
    165 
    166   return EFI_SUCCESS;
    167 }
    168 
    169 /**
    170 
    171   Map Traffic Class x to Vc0 on both root port and downstream device
    172 
    173   @param[in]  Bus1                    Bus number of the root port
    174   @param[in]  Device1                 Device number of the root port
    175   @param[in]  Function1               Function number of the root port
    176   @param[in]  Bus2                    Bus number of the downstream device
    177   @param[in]  Device2                 Device number of the downstream device
    178   @param[in]  Function2               Function number of the downstream device
    179   @param[in]  TCx                     Traffic Class to be mapped to vc0
    180 
    181   @retval EFI_SUCCESS    Map Tcx to Vc0 successful
    182 
    183 **/
    184 EFI_STATUS
    185 PcieMapTcxVc0 (
    186   IN UINT8   Bus1,
    187   IN UINT8   Device1,
    188   IN UINT8   Function1,
    189   IN UINT8   Bus2,
    190   IN UINT8   Device2,
    191   IN UINT8   Function2,
    192   IN UINT8   TCx
    193   )
    194 {
    195   UINT32  Offset;
    196 
    197   //
    198   // Set TCx-VC0 value on the port
    199   //
    200 
    201   Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);
    202   if (Offset == 0) {
    203     return EFI_UNSUPPORTED;
    204   }
    205   QNCMmPci8 (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);
    206 
    207   // Set TCx-VC0 value on the Endpoint
    208 
    209   Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);
    210   if (Offset == 0) {
    211     return EFI_UNSUPPORTED;
    212   }
    213   QNCMmPci8 (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);
    214 
    215   return EFI_SUCCESS;
    216 }
    217 
    218 /**
    219 
    220   Set common clock for both root port and downstream device.
    221 
    222   @param[in]  Bus1                    Bus number of the root port
    223   @param[in]  Device1                 Device number of the root port
    224   @param[in]  Function1               Function number of the root port
    225   @param[in]  Bus2                    Device number of the downstream device
    226   @param[in]  Device2                 Function number of the downstream device
    227 
    228   @retval EFI_SUCCESS    Set common clock successful
    229 
    230 **/
    231 EFI_STATUS
    232 PcieSetCommonClock (
    233   IN UINT8   Bus1,
    234   IN UINT8   Device1,
    235   IN UINT8   Function1,
    236   IN UINT8   Bus2,
    237   IN UINT8   Device2
    238  )
    239 {
    240   UINT32      CapOffset1;
    241   UINT32      CapOffset2;
    242   UINT8       Function2;
    243   UINT8       CommonClock;
    244   EFI_STATUS  Status;
    245 
    246   //
    247   // Get the pointer to the Port PCI Express Capability Structure.
    248   //
    249   CommonClock = 0;
    250   CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, PCIE_CAPID);
    251   if (CapOffset1 == 0) {
    252     return EFI_UNSUPPORTED;
    253   }
    254 
    255   //
    256   // Step 1
    257   // Read the Slot Clock Configuration bit of the Link status register of the root port and the endpoint device connected to the port
    258   // If both components have this bit set to 1, then System BIOS should set the "Common Clock Configuration" bit in the Link Control Registers
    259   // for both components at both sides of the link to indicate that components at both ends
    260   // of the link use a common clock source
    261   //
    262 
    263   //
    264   // Check the Port Slot Clock Configuration Bit.
    265   //
    266   if ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) == 0) {
    267     return EFI_UNSUPPORTED;
    268   }
    269 
    270   for (Function2 = 0; Function2 < 8; Function2++) {
    271     //
    272     // Check the Endpoint Slot Clock Configuration Bit.
    273     //
    274     CapOffset2 = PcieFindCapId (Bus2, Device2, Function2, PCIE_CAPID);
    275     if ((CapOffset2 != 0) &&
    276        ((QNCMmPci16 (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) != 0)) {
    277 
    278       //
    279       // Common clock is supported, set common clock bit on root port
    280       // and the endpoint
    281       //
    282       if (CommonClock == 0) {
    283         QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);
    284         CommonClock++;
    285       }
    286       QNCMmPci8Or (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);
    287     }
    288   }
    289 
    290   //
    291   // Step 2   If the Common Clock Configuration bit was changed by BIOS in step 1,
    292   // System BIOS should initiate a link training by setting the Retrain Link bit
    293   // in the Link Control register of the root port (D28:F0/F1 offset
    294   // 50h [5]) to "1b" and then poll the Link Training bit in the Link Status
    295   // register of the root port (D28:F0/F1/F2/F3/F4/F5 offset 52h [11]) until it is
    296   // "0b".
    297   //
    298   if (CommonClock == 0) {
    299     Status = EFI_UNSUPPORTED;
    300   } else {
    301     //
    302     // Retrain the Link per PCI Express Specification.
    303     //
    304     QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_RL);
    305 
    306     //
    307     // Wait until Re-Training has completed.
    308     //
    309     while ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_LT) != 0);
    310     Status = EFI_SUCCESS;
    311   }
    312 
    313   return Status;
    314 }
    315 
    316 /**
    317 
    318   Enables the CLKREQ# PM on all the end point functions
    319 
    320   @param[in]  Bus                Bus number of the downstream device
    321   @param[in]  Device             Device number of the downstream device
    322 
    323   @retval None
    324 
    325 **/
    326 VOID
    327 PcieSetClkreq (
    328   IN  UINT8   Bus,
    329   IN  UINT8   Device
    330  )
    331 {
    332   UINT8  Function;
    333   UINT32 CapOffset;
    334 
    335   //
    336   // Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if
    337   // exists then enable the CLKREQ# bit (BIT8) on that function
    338   //
    339   for (Function = 0; Function < 8; Function++) {
    340     //
    341     // Find the PCIe Cap Id (offset 10h)
    342     //
    343     CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
    344     if (CapOffset == 0) {
    345        continue;
    346     }
    347 
    348     //
    349     // Check if CLKREQ# is supported by the endpoints
    350     //
    351     if ((QNCMmPci32 (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CAP_OFFSET))
    352       & B_QNC_PCIE_LCAP_CPM) != B_QNC_PCIE_LCAP_CPM) {
    353       //
    354       // CLKREQ# is not supported so dont do anything
    355       //
    356       return;
    357     }
    358   }
    359 
    360   //
    361   // Now enable the CLKREQ#
    362   //
    363   for (Function = 0; Function < 8; Function++) {
    364     //
    365     // Find the PCIe Cap Id (offset 10h)
    366     //
    367     CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
    368     if (CapOffset == 0) {
    369        continue;
    370     }
    371 
    372     QNCMmPci16Or (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CNT_OFFSET), BIT8);
    373   }
    374 }
    375 
    376 /**
    377 
    378   Configure ASPM automatically for both root port and downstream device.
    379 
    380   @param[in]  RootBus                    Bus number of the root port
    381   @param[in]  RootDevice                 Device number of the root port
    382   @param[in]  RootFunction               Function number of the root port
    383   @param[in]  EndpointBus                Bus number of the downstream device
    384   @param[in]  EndpointDevice             Device number of the downstream device
    385   @param[in]  EndpointFunction           Function number of the downstream device
    386   @param[in]  LinkAspmVal                Currently used ASPM setting
    387 
    388   @retval EFI_SUCCESS    Configure ASPM successful
    389 
    390 **/
    391 EFI_STATUS
    392 PcieSetAspmAuto (
    393   IN  UINT8   RootBus,
    394   IN  UINT8   RootDevice,
    395   IN  UINT8   RootFunction,
    396   IN  UINT8   EndpointBus,
    397   IN  UINT8   EndpointDevice,
    398   IN  UINT8   EndpointFunction,
    399   OUT UINT16  *LinkAspmVal
    400  )
    401 {
    402   UINT32    RootPcieCapOffset;
    403   UINT32    EndpointPcieCapOffset;
    404   UINT16    RootPortAspm;
    405   UINT16    EndPointAspm;
    406   UINT16    AspmVal;
    407   UINT32    PortLxLat;
    408   UINT32    EndPointLxLat;
    409   UINT32    LxLat;
    410 
    411   //
    412   // Get the pointer to the Port PCI Express Capability Structure.
    413   //
    414   RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID);
    415   if (RootPcieCapOffset == 0) {
    416     return EFI_UNSUPPORTED;
    417   }
    418 
    419   //
    420   // Get the pointer to the Endpoint PCI Express Capability Structure.
    421   //
    422   EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID);
    423   if (EndpointPcieCapOffset == 0) {
    424     return EFI_UNSUPPORTED;
    425   }
    426 
    427   //
    428   // Obtain initial ASPM settings from respective port capability registers.
    429   //
    430   RootPortAspm  = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
    431 
    432   //
    433   // Configure downstream device if present.
    434   //
    435   EndPointAspm  = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
    436 
    437   //
    438   // TODO: Mask APMC with values from lookup table.
    439   // RevID of 0xFF applies to all steppings.
    440   //
    441 
    442   // TODO: Mask with latency/acceptable latency comparison results.
    443 
    444   AspmVal = RootPortAspm;
    445   if (RootPortAspm > EndPointAspm) {
    446     AspmVal = EndPointAspm;
    447   }
    448 
    449   //
    450   // Check if L1 should be enabled based on port and endpoint L1 exit latency.
    451   //
    452   if(AspmVal & BIT1) {
    453     PortLxLat      = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
    454     EndPointLxLat  = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
    455 
    456     LxLat = PortLxLat;
    457     if(PortLxLat < EndPointLxLat) {
    458       LxLat = EndPointLxLat;
    459     }
    460 
    461     //
    462     // check if the value is bigger than endpoint L1 acceptable exit latency, if it is
    463     // larger than accepted value, then we should disable L1
    464     //
    465     LxLat >>= 6;
    466     if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) {
    467       AspmVal &= ~BIT1;
    468     }
    469   }
    470 
    471   //
    472   // Check if L0s should be enabled based on port and endpoint L0s exit latency.
    473   //
    474   if(AspmVal & BIT0) {
    475     PortLxLat      = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
    476     EndPointLxLat  = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
    477 
    478     LxLat = PortLxLat;
    479     if(PortLxLat < EndPointLxLat) {
    480       LxLat = EndPointLxLat;
    481     }
    482 
    483     //
    484     // check if the value is bigger than endpoint L0s acceptable exit latency, if it is
    485     // larger than accepted value, then we should disable L0s
    486     //
    487     LxLat >>= 6;
    488     if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) {
    489       AspmVal &= ~BIT0;
    490     }
    491   }
    492 
    493   RootPortAspm = AspmVal;
    494 
    495   *LinkAspmVal = AspmVal;
    496   //
    497   // Set Endpoint Aspm
    498   //
    499   QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal);
    500 
    501 
    502   //
    503   // Set Root Port Aspm
    504   //
    505   QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm);
    506 
    507   return EFI_SUCCESS;
    508 }
    509 
    510 /**
    511 
    512   Configure ASPM based on the given setting for the interested device.
    513 
    514   @param[in]  Bus                    Bus number of the interested device
    515   @param[in]  Device                 Device number of the interested device
    516   @param[in]  Function               Function number of the interested device
    517   @param[in]  AspmSetting            Aspm setting
    518   @param[in]  LinkAspmVal            Currently used ASPM setting
    519 
    520   @retval EFI_SUCCESS    Configure ASPM successful
    521 
    522 **/
    523 EFI_STATUS
    524 PcieSetAspmManual (
    525   IN  UINT8   Bus,
    526   IN  UINT8   Device,
    527   IN  UINT8   Function,
    528   IN  UINT8   AspmSetting,
    529   OUT UINT16  *LinkAspmVal
    530  )
    531 {
    532   UINT32    PcieCapOffset;
    533   UINT16    PortAspm;
    534 
    535   //
    536   // Get the pointer to the Port PCI Express Capability Structure.
    537   //
    538   PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
    539   if (PcieCapOffset == 0) {
    540     return EFI_UNSUPPORTED;
    541   }
    542 
    543   // Read the Link Capability register's ASPM setting
    544   PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
    545   // Mask it with the Setup selection
    546   PortAspm &= AspmSetting;
    547 
    548   *LinkAspmVal = PortAspm;
    549   // Write it to the Link Control register
    550   QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm);
    551 
    552   return EFI_SUCCESS;
    553 }
    554 
    555 /**
    556 
    557   Perform Initialization on one PCI Express root port.
    558 
    559   @param[in]  RootPortIndex          Index of PCI Express root port
    560   @param[in]  RootPortConfig         Pointer to the given pcie root port configuration
    561   @param[in]  PciExpressBar          Base address of pcie space
    562   @param[in]  QNCRootComplexBar       Base address of root complex
    563   @param[in]  QNCPmioBase             Base address of PM IO space
    564   @param[in]  QNCGpeBase              Base address of gpe IO space
    565 
    566   @retval EFI_SUCCESS    Initialization successful
    567 
    568 **/
    569 EFI_STATUS
    570 QNCRootPortInit (
    571   IN UINT32                                    RootPortIndex,
    572   IN PCIEXP_ROOT_PORT_CONFIGURATION            *RootPortConfig,
    573   IN UINT64                                    PciExpressBar,
    574   IN UINT32                                    QNCRootComplexBar,
    575   IN UINT32                                    QNCPmioBase,
    576   IN UINT32                                    QNCGpeBase
    577   )
    578 {
    579   UINT64            RPBase;
    580   UINT64            EndPointBase;
    581   UINT16            AspmVal;
    582   UINT16            SlotStatus;
    583   UINTN             Index;
    584   UINT32            CapOffset;
    585   UINT32            DwordReg;
    586 
    587   RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12);
    588   CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID);
    589 
    590   if (CapOffset == 0) {
    591     return EFI_UNSUPPORTED;
    592   }
    593 
    594   //
    595   // Initialize "Slot Implmemented Bit" for this root port
    596   //
    597   if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) {
    598     QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI);
    599   }
    600 
    601   //
    602   // For Root Port Slots Numbering on the CRBs.
    603   //  Root Port 0 = Slot 1
    604   //  Root Port 1 = Slot 2
    605   //  Root Port 2 = Slot 3
    606   //  Root Port 3 = Slot 4
    607   //
    608   DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP);
    609   DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE;
    610   DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET);
    611   DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ;
    612   QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg;
    613 
    614   //
    615   // Check for a Presence Detect Change.
    616   //
    617   SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS);
    618   if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) {
    619     return EFI_NOT_FOUND;
    620   }
    621 
    622   //
    623   // Temporarily Hardcode the Root Port Bridge Number to 2.
    624   //
    625   // This Endpoint check should immediately pass.  Howerver, a 900ms delay
    626   // has been added to match the timing requirements of the PCI Express Base
    627   // Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s
    628   // after a reset of a device, before it may determine that a device which
    629   // fails to return a Successful Completion status for a valid Configuration
    630   // Request is a broken device").  Note that a 100ms delay was already added
    631   // after the Root Ports were first taken out of reset.
    632   //
    633   QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200);
    634   //
    635   // Only do this when a downstream device is present
    636   //
    637   EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12);
    638   if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
    639     for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){
    640       if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) {
    641         break;
    642       }
    643       PcieStall (15);
    644     }
    645     if (Index >= V_PCIE_MAX_TRY_TIMES) {
    646       //
    647       // Clear Bus Numbers.
    648       //
    649       QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
    650       return EFI_NOT_FOUND;
    651     }
    652   }
    653 
    654   //
    655   // PCI Express* Virtual Channels
    656   // Clear TC1-7 Traffic classes.
    657   // Map TC0-VC0
    658   //
    659   PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0);
    660   PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0);
    661 
    662   //
    663   // Set Common Clock for inserted cards
    664   //
    665   if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
    666     PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0);
    667   }
    668 
    669   //
    670   // Flow for Enabling ASPM
    671   //
    672   if (RootPortConfig[RootPortIndex].Bits.AspmEnable) {
    673     if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) {
    674       PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal);
    675     } else {
    676       //
    677       // Set ASPM values according to setup selections, masked by capabilities
    678       //
    679       PcieSetAspmManual (
    680         PCI_BUS_NUMBER_QNC,
    681         (UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT),
    682         (UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex),
    683         (UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)),
    684         &AspmVal
    685         );
    686     }
    687   }
    688 
    689   //
    690   // Enable the PCIe CLKREQ#
    691   //
    692   if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
    693     PcieSetClkreq (2, 0);
    694   }
    695 
    696   //
    697   // Clear Bus Numbers
    698   //
    699   QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
    700 
    701   //
    702   // Additional configurations
    703   //
    704 
    705   //
    706   // PCI-E Unsupported Request Reporting Enable
    707   //
    708   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) {
    709     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE);
    710   }
    711 
    712   //
    713   // Device Fatal Error Reporting Enable
    714   //
    715   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) {
    716     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE);
    717   }
    718 
    719   //
    720   // Device Non Fatal Error Reporting Enable
    721   //
    722   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) {
    723     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE);
    724   }
    725 
    726   //
    727   // Device Correctable Error Reporting Enable
    728   //
    729   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) {
    730     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE);
    731   }
    732   //
    733   // Root PCI-E PME Interrupt Enable
    734   //
    735   if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) {
    736     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE);
    737   }
    738   //
    739   // Root PCI-E System Error on Fatal Error Enable
    740   //
    741   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) {
    742     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE);
    743   }
    744 
    745   //
    746   // Root PCI-E System Error on Non-Fatal Error Enable
    747   //
    748   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) {
    749     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE);
    750   }
    751 
    752   //
    753   // Root PCI-E System Error on Correctable Error Enable
    754   //
    755   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) {
    756     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE);
    757   }
    758 
    759   //
    760   // Root PCI-E Powermanagement SCI Enabled
    761   //
    762   if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) {
    763     //
    764     // Make sure that PME Interrupt Enable bit of Root Control register
    765     // of PCI Express Capability struceture is cleared
    766     //
    767     QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE));
    768     QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE);
    769 
    770     //
    771     // Make sure GPE0 Stutus RW1C Bit is clear.
    772     //
    773     DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S);
    774     if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) {
    775       IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE);
    776     }
    777   }
    778 
    779   //
    780   // PCIe Hot Plug SCI Enable
    781   //
    782   if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) {
    783     //
    784     // Write clear for :
    785     // Attention Button Pressed (bit0)
    786     // Presence Detect Changed (bit3)
    787     //
    788     QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP));
    789 
    790     //
    791     // Sequence 2: Program the following bits in Slot Control register at offset 18h
    792     // of PCI Express* Capability structure:
    793     // Attention Button Pressed Enable (bit0) = 1b
    794     // Presence Detect Changed Enable (bit3) = 1b
    795     // Hot Plug Interrupt Enable (bit5) = 0b
    796     //
    797     QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE));
    798 
    799     //
    800     // Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset
    801     // D8h as follows:
    802     // Hot Plug SCI Enable (HPCE, bit30) = 1b
    803     // Hot Plug SMI Enable (HPME, bit1) = 0b
    804     //
    805     QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE);
    806   }
    807 
    808 
    809   return EFI_SUCCESS;
    810 }
    811 
    812 
    813 /**
    814   Perform Initialization of the Downstream Root Ports
    815 **/
    816 VOID
    817 QNCDownStreamPortsInit (
    818   IN PCIEXP_ROOT_PORT_CONFIGURATION             *RootPortConfig,
    819   IN QNC_DEVICE_ENABLES                      *QNCDeviceEnables,
    820   IN UINT64                                     PciExpressBar,
    821   IN UINT32                                     QNCRootComplexBar,
    822   IN UINT32                                     QNCPmioBase,
    823   IN UINT32                                     QNCGpeBase,
    824   OUT UINTN                                     *RpEnableMask
    825   )
    826 {
    827   EFI_STATUS     Status;
    828   UINT32         Index;
    829 
    830   //
    831   // Initialize every root port and downstream device
    832   //
    833   for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) {
    834     if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) {
    835       Status = QNCRootPortInit (
    836                Index,
    837                RootPortConfig,
    838                PciExpressBar,
    839                QNCRootComplexBar,
    840                QNCPmioBase,
    841                QNCGpeBase
    842                );
    843 
    844       if (!EFI_ERROR (Status)) {
    845         (*RpEnableMask) |= LShiftU64(1, Index);
    846         DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask));
    847       }
    848     }
    849   }
    850 }
    851 
    852 /**
    853   Do early init of pci express rootports on Soc.
    854 
    855 **/
    856 
    857 VOID
    858 EFIAPI
    859 PciExpressEarlyInit (
    860   VOID
    861   )
    862 {
    863   //
    864   // Setup Message Bus Idle Counter (SBIC) values.
    865   //
    866   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);
    867   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);
    868 
    869   //
    870   // Program SVID/SID the same as VID/DID for Root ports.
    871   //
    872   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);
    873   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);
    874 
    875   //
    876   // Set the IPF bit in MCR2
    877   //
    878   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);
    879   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);
    880 
    881   //
    882   // Set up the Posted and Non Posted Request sizes for PCIe
    883   //
    884   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));
    885 
    886   return;
    887 }
    888 
    889 
    890 /**
    891   Complete initialization all the pci express rootports on Soc.
    892 **/
    893 EFI_STATUS
    894 EFIAPI
    895 PciExpressInit (
    896   )
    897 {
    898   UINT64                            PciExpressBar;
    899   UINT32                            QNCRootComplexBar;
    900   UINT32                            QNCPmioBase;
    901   UINT32                            QNCGpeBase;
    902   UINTN                             RpEnableMask;
    903   PCIEXP_ROOT_PORT_CONFIGURATION    *mRootPortConfig;
    904   QNC_DEVICE_ENABLES                mQNCDeviceEnables;
    905 
    906   //
    907   // Get BAR registers
    908   //
    909   QNCRootComplexBar  = QNC_RCRB_BASE;
    910   QNCPmioBase        = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;
    911   QNCGpeBase         = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK;
    912   RpEnableMask = 0;                 // assume all root ports are disabled
    913 
    914   PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress);
    915 
    916   //
    917   // Get platform information from PCD entries
    918   //
    919   mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
    920   mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration);
    921 
    922   DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x,  value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n",
    923           mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32,
    924           mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32));
    925 
    926   QNCDownStreamPortsInit (
    927                          mRootPortConfig,
    928                          &mQNCDeviceEnables,
    929                          PciExpressBar,
    930                          QNCRootComplexBar,
    931                          QNCPmioBase,
    932                          QNCGpeBase,
    933                          &RpEnableMask
    934                          );
    935 
    936   return EFI_SUCCESS;
    937 }
    938 
    939