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