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    EndPointVendorId;
407   UINT16    EndPointDeviceId;
408   UINT8     EndPointRevId;
409   UINT16    AspmVal;
410   UINT32    PortLxLat;
411   UINT32    EndPointLxLat;
412   UINT32    LxLat;
413 
414   //
415   // Get the pointer to the Port PCI Express Capability Structure.
416   //
417   RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID);
418   if (RootPcieCapOffset == 0) {
419     return EFI_UNSUPPORTED;
420   }
421 
422   //
423   // Get the pointer to the Endpoint PCI Express Capability Structure.
424   //
425   EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID);
426   if (EndpointPcieCapOffset == 0) {
427     return EFI_UNSUPPORTED;
428   }
429 
430   //
431   // Obtain initial ASPM settings from respective port capability registers.
432   //
433   RootPortAspm  = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
434 
435   //
436   // Configure downstream device if present.
437   //
438   EndPointAspm  = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
439 
440   //
441   // Mask APMC with values from lookup table.
442   // RevID of 0xFF applies to all steppings.
443   //
444 
445   EndPointVendorId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 0);
446   EndPointDeviceId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 2);
447   EndPointRevId    = QNCMmPci8 (0, EndpointBus, EndpointDevice, EndpointFunction, 8);
448 
449   // TODO: Mask with latency/acceptable latency comparison results.
450 
451   AspmVal = RootPortAspm;
452   if (RootPortAspm > EndPointAspm) {
453     AspmVal = EndPointAspm;
454   }
455 
456   //
457   // Check if L1 should be enabled based on port and endpoint L1 exit latency.
458   //
459   if(AspmVal & BIT1) {
460     PortLxLat      = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
461     EndPointLxLat  = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
462 
463     LxLat = PortLxLat;
464     if(PortLxLat < EndPointLxLat) {
465       LxLat = EndPointLxLat;
466     }
467 
468     //
469     // check if the value is bigger than endpoint L1 acceptable exit latency, if it is
470     // larger than accepted value, then we should disable L1
471     //
472     LxLat >>= 6;
473     if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) {
474       AspmVal &= ~BIT1;
475     }
476   }
477 
478   //
479   // Check if L0s should be enabled based on port and endpoint L0s exit latency.
480   //
481   if(AspmVal & BIT0) {
482     PortLxLat      = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
483     EndPointLxLat  = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
484 
485     LxLat = PortLxLat;
486     if(PortLxLat < EndPointLxLat) {
487       LxLat = EndPointLxLat;
488     }
489 
490     //
491     // check if the value is bigger than endpoint L0s acceptable exit latency, if it is
492     // larger than accepted value, then we should disable L0s
493     //
494     LxLat >>= 6;
495     if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) {
496       AspmVal &= ~BIT0;
497     }
498   }
499 
500   RootPortAspm = AspmVal;
501 
502   *LinkAspmVal = AspmVal;
503   //
504   // Set Endpoint Aspm
505   //
506   QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal);
507 
508 
509   //
510   // Set Root Port Aspm
511   //
512   QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm);
513 
514   return EFI_SUCCESS;
515 }
516 
517 /**
518 
519   Configure ASPM based on the given setting for the interested device.
520 
521   @param[in]  Bus                    Bus number of the interested device
522   @param[in]  Device                 Device number of the interested device
523   @param[in]  Function               Function number of the interested device
524   @param[in]  AspmSetting            Aspm setting
525   @param[in]  LinkAspmVal            Currently used ASPM setting
526 
527   @retval EFI_SUCCESS    Configure ASPM successful
528 
529 **/
530 EFI_STATUS
PcieSetAspmManual(IN UINT8 Bus,IN UINT8 Device,IN UINT8 Function,IN UINT8 AspmSetting,OUT UINT16 * LinkAspmVal)531 PcieSetAspmManual (
532   IN  UINT8   Bus,
533   IN  UINT8   Device,
534   IN  UINT8   Function,
535   IN  UINT8   AspmSetting,
536   OUT UINT16  *LinkAspmVal
537  )
538 {
539   UINT32    PcieCapOffset;
540   UINT16    PortAspm;
541 
542   //
543   // Get the pointer to the Port PCI Express Capability Structure.
544   //
545   PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
546   if (PcieCapOffset == 0) {
547     return EFI_UNSUPPORTED;
548   }
549 
550   // Read the Link Capability register's ASPM setting
551   PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
552   // Mask it with the Setup selection
553   PortAspm &= AspmSetting;
554 
555   *LinkAspmVal = PortAspm;
556   // Write it to the Link Control register
557   QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm);
558 
559   return EFI_SUCCESS;
560 }
561 
562 /**
563 
564   Perform Initialization on one PCI Express root port.
565 
566   @param[in]  RootPortIndex          Index of PCI Express root port
567   @param[in]  RootPortConfig         Pointer to the given pcie root port configuration
568   @param[in]  PciExpressBar          Base address of pcie space
569   @param[in]  QNCRootComplexBar       Base address of root complex
570   @param[in]  QNCPmioBase             Base address of PM IO space
571   @param[in]  QNCGpeBase              Base address of gpe IO space
572 
573   @retval EFI_SUCCESS    Initialization successful
574 
575 **/
576 EFI_STATUS
QNCRootPortInit(IN UINT32 RootPortIndex,IN PCIEXP_ROOT_PORT_CONFIGURATION * RootPortConfig,IN UINT64 PciExpressBar,IN UINT32 QNCRootComplexBar,IN UINT32 QNCPmioBase,IN UINT32 QNCGpeBase)577 QNCRootPortInit (
578   IN UINT32                                    RootPortIndex,
579   IN PCIEXP_ROOT_PORT_CONFIGURATION            *RootPortConfig,
580   IN UINT64                                    PciExpressBar,
581   IN UINT32                                    QNCRootComplexBar,
582   IN UINT32                                    QNCPmioBase,
583   IN UINT32                                    QNCGpeBase
584   )
585 {
586   UINT64            RPBase;
587   UINT64            EndPointBase;
588   UINT64            LpcBase;
589   UINT16            AspmVal;
590   UINT16            SlotStatus;
591   UINTN             Index;
592   UINT32            CapOffset;
593   UINT32            DwordReg;
594 
595   RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12);
596   LpcBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + (31 << 3) + (0 << 0)) << 12);
597   CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID);
598 
599   if (CapOffset == 0) {
600     return EFI_UNSUPPORTED;
601   }
602 
603   //
604   // Initialize "Slot Implmemented Bit" for this root port
605   //
606   if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) {
607     QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI);
608   }
609 
610   //
611   // For Root Port Slots Numbering on the CRBs.
612   //  Root Port 0 = Slot 1
613   //  Root Port 1 = Slot 2
614   //  Root Port 2 = Slot 3
615   //  Root Port 3 = Slot 4
616   //
617   DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP);
618   DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE;
619   DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET);
620   DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ;
621   QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg;
622 
623   //
624   // Check for a Presence Detect Change.
625   //
626   SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS);
627   if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) {
628     return EFI_NOT_FOUND;
629   }
630 
631   //
632   // Temporarily Hardcode the Root Port Bridge Number to 2.
633   //
634   // This Endpoint check should immediately pass.  Howerver, a 900ms delay
635   // has been added to match the timing requirements of the PCI Express Base
636   // Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s
637   // after a reset of a device, before it may determine that a device which
638   // fails to return a Successful Completion status for a valid Configuration
639   // Request is a broken device").  Note that a 100ms delay was already added
640   // after the Root Ports were first taken out of reset.
641   //
642   QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200);
643   //
644   // Only do this when a downstream device is present
645   //
646   EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12);
647   if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
648     for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){
649       if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) {
650         break;
651       }
652       PcieStall (15);
653     }
654     if (Index >= V_PCIE_MAX_TRY_TIMES) {
655       //
656       // Clear Bus Numbers.
657       //
658       QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
659       return EFI_NOT_FOUND;
660     }
661   }
662 
663   //
664   // PCI Express* Virtual Channels
665   // Clear TC1-7 Traffic classes.
666   // Map TC0-VC0
667   //
668   PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0);
669   PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0);
670 
671   //
672   // Set Common Clock for inserted cards
673   //
674   if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
675     PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0);
676   }
677 
678   //
679   // Flow for Enabling ASPM
680   //
681   if (RootPortConfig[RootPortIndex].Bits.AspmEnable) {
682     if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) {
683       PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal);
684     } else {
685       //
686       // Set ASPM values according to setup selections, masked by capabilities
687       //
688       PcieSetAspmManual (
689         PCI_BUS_NUMBER_QNC,
690         (UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT),
691         (UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex),
692         (UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)),
693         &AspmVal
694         );
695     }
696   }
697 
698   //
699   // Enable the PCIe CLKREQ#
700   //
701   if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
702     PcieSetClkreq (2, 0);
703   }
704 
705   //
706   // Clear Bus Numbers
707   //
708   QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
709 
710   //
711   // Additional configurations
712   //
713 
714   //
715   // PCI-E Unsupported Request Reporting Enable
716   //
717   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) {
718     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE);
719   }
720 
721   //
722   // Device Fatal Error Reporting Enable
723   //
724   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) {
725     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE);
726   }
727 
728   //
729   // Device Non Fatal Error Reporting Enable
730   //
731   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) {
732     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE);
733   }
734 
735   //
736   // Device Correctable Error Reporting Enable
737   //
738   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) {
739     QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE);
740   }
741   //
742   // Root PCI-E PME Interrupt Enable
743   //
744   if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) {
745     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE);
746   }
747   //
748   // Root PCI-E System Error on Fatal Error Enable
749   //
750   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) {
751     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE);
752   }
753 
754   //
755   // Root PCI-E System Error on Non-Fatal Error Enable
756   //
757   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) {
758     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE);
759   }
760 
761   //
762   // Root PCI-E System Error on Correctable Error Enable
763   //
764   if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) {
765     QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE);
766   }
767 
768   //
769   // Root PCI-E Powermanagement SCI Enabled
770   //
771   if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) {
772     //
773     // Make sure that PME Interrupt Enable bit of Root Control register
774     // of PCI Express Capability struceture is cleared
775     //
776     QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE));
777     QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE);
778 
779     //
780     // Make sure GPE0 Stutus RW1C Bit is clear.
781     //
782     DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S);
783     if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) {
784       IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE);
785     }
786   }
787 
788   //
789   // PCIe Hot Plug SCI Enable
790   //
791   if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) {
792     //
793     // Write clear for :
794     // Attention Button Pressed (bit0)
795     // Presence Detect Changed (bit3)
796     //
797     QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP));
798 
799     //
800     // Sequence 2: Program the following bits in Slot Control register at offset 18h
801     // of PCI Express* Capability structure:
802     // Attention Button Pressed Enable (bit0) = 1b
803     // Presence Detect Changed Enable (bit3) = 1b
804     // Hot Plug Interrupt Enable (bit5) = 0b
805     //
806     QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE));
807 
808     //
809     // Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset
810     // D8h as follows:
811     // Hot Plug SCI Enable (HPCE, bit30) = 1b
812     // Hot Plug SMI Enable (HPME, bit1) = 0b
813     //
814     QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE);
815   }
816 
817 
818   return EFI_SUCCESS;
819 }
820 
821 
822 /**
823   Perform Initialization of the Downstream Root Ports
824 **/
825 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)826 QNCDownStreamPortsInit (
827   IN PCIEXP_ROOT_PORT_CONFIGURATION             *RootPortConfig,
828   IN QNC_DEVICE_ENABLES                      *QNCDeviceEnables,
829   IN UINT64                                     PciExpressBar,
830   IN UINT32                                     QNCRootComplexBar,
831   IN UINT32                                     QNCPmioBase,
832   IN UINT32                                     QNCGpeBase,
833   OUT UINTN                                     *RpEnableMask
834   )
835 {
836   EFI_STATUS     Status;
837   UINT32         Index;
838 
839   //
840   // Initialize every root port and downstream device
841   //
842   for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) {
843     if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) {
844       Status = QNCRootPortInit (
845                Index,
846                RootPortConfig,
847                PciExpressBar,
848                QNCRootComplexBar,
849                QNCPmioBase,
850                QNCGpeBase
851                );
852 
853       if (!EFI_ERROR (Status)) {
854         (*RpEnableMask) |= LShiftU64(1, Index);
855         DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask));
856       }
857     }
858   }
859 }
860 
861 /**
862   Do early init of pci express rootports on Soc.
863 
864 **/
865 
866 VOID
867 EFIAPI
PciExpressEarlyInit(VOID)868 PciExpressEarlyInit (
869   VOID
870   )
871 {
872   //
873   // Setup Message Bus Idle Counter (SBIC) values.
874   //
875   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);
876   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);
877 
878   //
879   // Program SVID/SID the same as VID/DID for Root ports.
880   //
881   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);
882   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);
883 
884   //
885   // Set the IPF bit in MCR2
886   //
887   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);
888   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);
889 
890   //
891   // Set up the Posted and Non Posted Request sizes for PCIe
892   //
893   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));
894 
895   return;
896 }
897 
898 
899 /**
900   Complete initialization all the pci express rootports on Soc.
901 **/
902 EFI_STATUS
903 EFIAPI
PciExpressInit()904 PciExpressInit (
905   )
906 {
907   UINT64                            PciExpressBar;
908   UINT32                            QNCRootComplexBar;
909   UINT32                            QNCGpioBase;
910   UINT32                            QNCPmioBase;
911   UINT32                            QNCGpeBase;
912   UINTN                             RpEnableMask;
913   PCIEXP_ROOT_PORT_CONFIGURATION    *mRootPortConfig;
914   QNC_DEVICE_ENABLES                mQNCDeviceEnables;
915 
916   //
917   // Get BAR registers
918   //
919   QNCRootComplexBar  = QNC_RCRB_BASE;
920   QNCGpioBase        = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
921   QNCPmioBase        = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;
922   QNCGpeBase         = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK;
923   RpEnableMask = 0;                 // assume all root ports are disabled
924 
925   PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress);
926 
927   //
928   // Get platform information from PCD entries
929   //
930   mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
931   mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration);
932 
933   DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x,  value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n",
934           mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32,
935           mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32));
936 
937   QNCDownStreamPortsInit (
938                          mRootPortConfig,
939                          &mQNCDeviceEnables,
940                          PciExpressBar,
941                          QNCRootComplexBar,
942                          QNCPmioBase,
943                          QNCGpeBase,
944                          &RpEnableMask
945                          );
946 
947   return EFI_SUCCESS;
948 }
949 
950