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