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