• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
PcieStall(IN UINTN Microseconds)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
PcieFindCapId(UINT8 Bus,UINT8 Device,UINT8 Function,UINT8 CapId)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
PcieFindExtendedCapId(UINT8 Bus,UINT8 Device,UINT8 Function,UINT16 CapId)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
PcieInitTcxVc0(IN UINT8 Bus1,IN UINT8 Device1,IN UINT8 Function1,IN UINT8 Bus2,IN UINT8 Device2,IN UINT8 Function2)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
PcieMapTcxVc0(IN UINT8 Bus1,IN UINT8 Device1,IN UINT8 Function1,IN UINT8 Bus2,IN UINT8 Device2,IN UINT8 Function2,IN UINT8 TCx)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
PcieSetCommonClock(IN UINT8 Bus1,IN UINT8 Device1,IN UINT8 Function1,IN UINT8 Bus2,IN UINT8 Device2)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
PcieSetClkreq(IN UINT8 Bus,IN UINT8 Device)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
PcieSetAspmAuto(IN UINT8 RootBus,IN UINT8 RootDevice,IN UINT8 RootFunction,IN UINT8 EndpointBus,IN UINT8 EndpointDevice,IN UINT8 EndpointFunction,OUT UINT16 * LinkAspmVal)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
PcieSetAspmManual(IN UINT8 Bus,IN UINT8 Device,IN UINT8 Function,IN UINT8 AspmSetting,OUT UINT16 * LinkAspmVal)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
QNCRootPortInit(IN UINT32 RootPortIndex,IN PCIEXP_ROOT_PORT_CONFIGURATION * RootPortConfig,IN UINT64 PciExpressBar,IN UINT32 QNCRootComplexBar,IN UINT32 QNCPmioBase,IN UINT32 QNCGpeBase)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
QNCDownStreamPortsInit(IN PCIEXP_ROOT_PORT_CONFIGURATION * RootPortConfig,IN QNC_DEVICE_ENABLES * QNCDeviceEnables,IN UINT64 PciExpressBar,IN UINT32 QNCRootComplexBar,IN UINT32 QNCPmioBase,IN UINT32 QNCGpeBase,OUT UINTN * RpEnableMask)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
PciExpressEarlyInit(VOID)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
PciExpressInit()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