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