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