1 /** @file 2 3 The XHCI register operation routines. 4 5 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> 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 "Xhci.h" 17 18 /** 19 Read 1-byte width XHCI capability register. 20 21 @param Xhc The XHCI Instance. 22 @param Offset The offset of the 1-byte width capability register. 23 24 @return The register content read. 25 @retval If err, return 0xFF. 26 27 **/ 28 UINT8 29 XhcReadCapReg8 ( 30 IN USB_XHCI_INSTANCE *Xhc, 31 IN UINT32 Offset 32 ) 33 { 34 UINT8 Data; 35 EFI_STATUS Status; 36 37 Status = Xhc->PciIo->Mem.Read ( 38 Xhc->PciIo, 39 EfiPciIoWidthUint8, 40 XHC_BAR_INDEX, 41 (UINT64) Offset, 42 1, 43 &Data 44 ); 45 46 if (EFI_ERROR (Status)) { 47 DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset)); 48 Data = 0xFF; 49 } 50 51 return Data; 52 } 53 54 /** 55 Read 4-bytes width XHCI capability register. 56 57 @param Xhc The XHCI Instance. 58 @param Offset The offset of the 4-bytes width capability register. 59 60 @return The register content read. 61 @retval If err, return 0xFFFFFFFF. 62 63 **/ 64 UINT32 65 XhcReadCapReg ( 66 IN USB_XHCI_INSTANCE *Xhc, 67 IN UINT32 Offset 68 ) 69 { 70 UINT32 Data; 71 EFI_STATUS Status; 72 73 Status = Xhc->PciIo->Mem.Read ( 74 Xhc->PciIo, 75 EfiPciIoWidthUint32, 76 XHC_BAR_INDEX, 77 (UINT64) Offset, 78 1, 79 &Data 80 ); 81 82 if (EFI_ERROR (Status)) { 83 DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset)); 84 Data = 0xFFFFFFFF; 85 } 86 87 return Data; 88 } 89 90 /** 91 Read 4-bytes width XHCI Operational register. 92 93 @param Xhc The XHCI Instance. 94 @param Offset The offset of the 4-bytes width operational register. 95 96 @return The register content read. 97 @retval If err, return 0xFFFFFFFF. 98 99 **/ 100 UINT32 101 XhcReadOpReg ( 102 IN USB_XHCI_INSTANCE *Xhc, 103 IN UINT32 Offset 104 ) 105 { 106 UINT32 Data; 107 EFI_STATUS Status; 108 109 ASSERT (Xhc->CapLength != 0); 110 111 Status = Xhc->PciIo->Mem.Read ( 112 Xhc->PciIo, 113 EfiPciIoWidthUint32, 114 XHC_BAR_INDEX, 115 (UINT64) (Xhc->CapLength + Offset), 116 1, 117 &Data 118 ); 119 120 if (EFI_ERROR (Status)) { 121 DEBUG ((EFI_D_ERROR, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset)); 122 Data = 0xFFFFFFFF; 123 } 124 125 return Data; 126 } 127 128 /** 129 Write the data to the 4-bytes width XHCI operational register. 130 131 @param Xhc The XHCI Instance. 132 @param Offset The offset of the 4-bytes width operational register. 133 @param Data The data to write. 134 135 **/ 136 VOID 137 XhcWriteOpReg ( 138 IN USB_XHCI_INSTANCE *Xhc, 139 IN UINT32 Offset, 140 IN UINT32 Data 141 ) 142 { 143 EFI_STATUS Status; 144 145 ASSERT (Xhc->CapLength != 0); 146 147 Status = Xhc->PciIo->Mem.Write ( 148 Xhc->PciIo, 149 EfiPciIoWidthUint32, 150 XHC_BAR_INDEX, 151 (UINT64) (Xhc->CapLength + Offset), 152 1, 153 &Data 154 ); 155 156 if (EFI_ERROR (Status)) { 157 DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset)); 158 } 159 } 160 161 /** 162 Write the data to the 2-bytes width XHCI operational register. 163 164 @param Xhc The XHCI Instance. 165 @param Offset The offset of the 2-bytes width operational register. 166 @param Data The data to write. 167 168 **/ 169 VOID 170 XhcWriteOpReg16 ( 171 IN USB_XHCI_INSTANCE *Xhc, 172 IN UINT32 Offset, 173 IN UINT16 Data 174 ) 175 { 176 EFI_STATUS Status; 177 178 ASSERT (Xhc->CapLength != 0); 179 180 Status = Xhc->PciIo->Mem.Write ( 181 Xhc->PciIo, 182 EfiPciIoWidthUint16, 183 XHC_BAR_INDEX, 184 (UINT64) (Xhc->CapLength + Offset), 185 1, 186 &Data 187 ); 188 189 if (EFI_ERROR (Status)) { 190 DEBUG ((EFI_D_ERROR, "XhcWriteOpReg16: Pci Io Write error: %r at %d\n", Status, Offset)); 191 } 192 } 193 194 /** 195 Read XHCI door bell register. 196 197 @param Xhc The XHCI Instance. 198 @param Offset The offset of the door bell register. 199 200 @return The register content read 201 202 **/ 203 UINT32 204 XhcReadDoorBellReg ( 205 IN USB_XHCI_INSTANCE *Xhc, 206 IN UINT32 Offset 207 ) 208 { 209 UINT32 Data; 210 EFI_STATUS Status; 211 212 ASSERT (Xhc->DBOff != 0); 213 214 Status = Xhc->PciIo->Mem.Read ( 215 Xhc->PciIo, 216 EfiPciIoWidthUint32, 217 XHC_BAR_INDEX, 218 (UINT64) (Xhc->DBOff + Offset), 219 1, 220 &Data 221 ); 222 223 if (EFI_ERROR (Status)) { 224 DEBUG ((EFI_D_ERROR, "XhcReadDoorBellReg: Pci Io Read error - %r at %d\n", Status, Offset)); 225 Data = 0xFFFFFFFF; 226 } 227 228 return Data; 229 } 230 231 /** 232 Write the data to the XHCI door bell register. 233 234 @param Xhc The XHCI Instance. 235 @param Offset The offset of the door bell register. 236 @param Data The data to write. 237 238 **/ 239 VOID 240 XhcWriteDoorBellReg ( 241 IN USB_XHCI_INSTANCE *Xhc, 242 IN UINT32 Offset, 243 IN UINT32 Data 244 ) 245 { 246 EFI_STATUS Status; 247 248 ASSERT (Xhc->DBOff != 0); 249 250 Status = Xhc->PciIo->Mem.Write ( 251 Xhc->PciIo, 252 EfiPciIoWidthUint32, 253 XHC_BAR_INDEX, 254 (UINT64) (Xhc->DBOff + Offset), 255 1, 256 &Data 257 ); 258 259 if (EFI_ERROR (Status)) { 260 DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset)); 261 } 262 } 263 264 /** 265 Read XHCI runtime register. 266 267 @param Xhc The XHCI Instance. 268 @param Offset The offset of the runtime register. 269 270 @return The register content read 271 272 **/ 273 UINT32 274 XhcReadRuntimeReg ( 275 IN USB_XHCI_INSTANCE *Xhc, 276 IN UINT32 Offset 277 ) 278 { 279 UINT32 Data; 280 EFI_STATUS Status; 281 282 ASSERT (Xhc->RTSOff != 0); 283 284 Status = Xhc->PciIo->Mem.Read ( 285 Xhc->PciIo, 286 EfiPciIoWidthUint32, 287 XHC_BAR_INDEX, 288 (UINT64) (Xhc->RTSOff + Offset), 289 1, 290 &Data 291 ); 292 293 if (EFI_ERROR (Status)) { 294 DEBUG ((EFI_D_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset)); 295 Data = 0xFFFFFFFF; 296 } 297 298 return Data; 299 } 300 301 /** 302 Write the data to the XHCI runtime register. 303 304 @param Xhc The XHCI Instance. 305 @param Offset The offset of the runtime register. 306 @param Data The data to write. 307 308 **/ 309 VOID 310 XhcWriteRuntimeReg ( 311 IN USB_XHCI_INSTANCE *Xhc, 312 IN UINT32 Offset, 313 IN UINT32 Data 314 ) 315 { 316 EFI_STATUS Status; 317 318 ASSERT (Xhc->RTSOff != 0); 319 320 Status = Xhc->PciIo->Mem.Write ( 321 Xhc->PciIo, 322 EfiPciIoWidthUint32, 323 XHC_BAR_INDEX, 324 (UINT64) (Xhc->RTSOff + Offset), 325 1, 326 &Data 327 ); 328 329 if (EFI_ERROR (Status)) { 330 DEBUG ((EFI_D_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset)); 331 } 332 } 333 334 /** 335 Read XHCI extended capability register. 336 337 @param Xhc The XHCI Instance. 338 @param Offset The offset of the extended capability register. 339 340 @return The register content read 341 342 **/ 343 UINT32 344 XhcReadExtCapReg ( 345 IN USB_XHCI_INSTANCE *Xhc, 346 IN UINT32 Offset 347 ) 348 { 349 UINT32 Data; 350 EFI_STATUS Status; 351 352 ASSERT (Xhc->ExtCapRegBase != 0); 353 354 Status = Xhc->PciIo->Mem.Read ( 355 Xhc->PciIo, 356 EfiPciIoWidthUint32, 357 XHC_BAR_INDEX, 358 (UINT64) (Xhc->ExtCapRegBase + Offset), 359 1, 360 &Data 361 ); 362 363 if (EFI_ERROR (Status)) { 364 DEBUG ((EFI_D_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset)); 365 Data = 0xFFFFFFFF; 366 } 367 368 return Data; 369 } 370 371 /** 372 Write the data to the XHCI extended capability register. 373 374 @param Xhc The XHCI Instance. 375 @param Offset The offset of the extended capability register. 376 @param Data The data to write. 377 378 **/ 379 VOID 380 XhcWriteExtCapReg ( 381 IN USB_XHCI_INSTANCE *Xhc, 382 IN UINT32 Offset, 383 IN UINT32 Data 384 ) 385 { 386 EFI_STATUS Status; 387 388 ASSERT (Xhc->ExtCapRegBase != 0); 389 390 Status = Xhc->PciIo->Mem.Write ( 391 Xhc->PciIo, 392 EfiPciIoWidthUint32, 393 XHC_BAR_INDEX, 394 (UINT64) (Xhc->ExtCapRegBase + Offset), 395 1, 396 &Data 397 ); 398 399 if (EFI_ERROR (Status)) { 400 DEBUG ((EFI_D_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset)); 401 } 402 } 403 404 405 /** 406 Set one bit of the runtime register while keeping other bits. 407 408 @param Xhc The XHCI Instance. 409 @param Offset The offset of the runtime register. 410 @param Bit The bit mask of the register to set. 411 412 **/ 413 VOID 414 XhcSetRuntimeRegBit ( 415 IN USB_XHCI_INSTANCE *Xhc, 416 IN UINT32 Offset, 417 IN UINT32 Bit 418 ) 419 { 420 UINT32 Data; 421 422 Data = XhcReadRuntimeReg (Xhc, Offset); 423 Data |= Bit; 424 XhcWriteRuntimeReg (Xhc, Offset, Data); 425 } 426 427 /** 428 Clear one bit of the runtime register while keeping other bits. 429 430 @param Xhc The XHCI Instance. 431 @param Offset The offset of the runtime register. 432 @param Bit The bit mask of the register to set. 433 434 **/ 435 VOID 436 XhcClearRuntimeRegBit ( 437 IN USB_XHCI_INSTANCE *Xhc, 438 IN UINT32 Offset, 439 IN UINT32 Bit 440 ) 441 { 442 UINT32 Data; 443 444 Data = XhcReadRuntimeReg (Xhc, Offset); 445 Data &= ~Bit; 446 XhcWriteRuntimeReg (Xhc, Offset, Data); 447 } 448 449 /** 450 Set one bit of the operational register while keeping other bits. 451 452 @param Xhc The XHCI Instance. 453 @param Offset The offset of the operational register. 454 @param Bit The bit mask of the register to set. 455 456 **/ 457 VOID 458 XhcSetOpRegBit ( 459 IN USB_XHCI_INSTANCE *Xhc, 460 IN UINT32 Offset, 461 IN UINT32 Bit 462 ) 463 { 464 UINT32 Data; 465 466 Data = XhcReadOpReg (Xhc, Offset); 467 Data |= Bit; 468 XhcWriteOpReg (Xhc, Offset, Data); 469 } 470 471 472 /** 473 Clear one bit of the operational register while keeping other bits. 474 475 @param Xhc The XHCI Instance. 476 @param Offset The offset of the operational register. 477 @param Bit The bit mask of the register to clear. 478 479 **/ 480 VOID 481 XhcClearOpRegBit ( 482 IN USB_XHCI_INSTANCE *Xhc, 483 IN UINT32 Offset, 484 IN UINT32 Bit 485 ) 486 { 487 UINT32 Data; 488 489 Data = XhcReadOpReg (Xhc, Offset); 490 Data &= ~Bit; 491 XhcWriteOpReg (Xhc, Offset, Data); 492 } 493 494 /** 495 Wait the operation register's bit as specified by Bit 496 to become set (or clear). 497 498 @param Xhc The XHCI Instance. 499 @param Offset The offset of the operation register. 500 @param Bit The bit of the register to wait for. 501 @param WaitToSet Wait the bit to set or clear. 502 @param Timeout The time to wait before abort (in millisecond, ms). 503 504 @retval EFI_SUCCESS The bit successfully changed by host controller. 505 @retval EFI_TIMEOUT The time out occurred. 506 507 **/ 508 EFI_STATUS 509 XhcWaitOpRegBit ( 510 IN USB_XHCI_INSTANCE *Xhc, 511 IN UINT32 Offset, 512 IN UINT32 Bit, 513 IN BOOLEAN WaitToSet, 514 IN UINT32 Timeout 515 ) 516 { 517 UINT32 Index; 518 UINT64 Loop; 519 520 Loop = Timeout * XHC_1_MILLISECOND; 521 522 for (Index = 0; Index < Loop; Index++) { 523 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) { 524 return EFI_SUCCESS; 525 } 526 527 gBS->Stall (XHC_1_MICROSECOND); 528 } 529 530 return EFI_TIMEOUT; 531 } 532 533 /** 534 Set Bios Ownership 535 536 @param Xhc The XHCI Instance. 537 538 **/ 539 VOID 540 XhcSetBiosOwnership ( 541 IN USB_XHCI_INSTANCE *Xhc 542 ) 543 { 544 UINT32 Buffer; 545 546 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) { 547 return; 548 } 549 550 DEBUG ((EFI_D_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n")); 551 552 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset); 553 Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE); 554 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer); 555 } 556 557 /** 558 Clear Bios Ownership 559 560 @param Xhc The XHCI Instance. 561 562 **/ 563 VOID 564 XhcClearBiosOwnership ( 565 IN USB_XHCI_INSTANCE *Xhc 566 ) 567 { 568 UINT32 Buffer; 569 570 if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) { 571 return; 572 } 573 574 DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n")); 575 576 Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset); 577 Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE); 578 XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer); 579 } 580 581 /** 582 Calculate the offset of the XHCI capability. 583 584 @param Xhc The XHCI Instance. 585 @param CapId The XHCI Capability ID. 586 587 @return The offset of XHCI legacy support capability register. 588 589 **/ 590 UINT32 591 XhcGetCapabilityAddr ( 592 IN USB_XHCI_INSTANCE *Xhc, 593 IN UINT8 CapId 594 ) 595 { 596 UINT32 ExtCapOffset; 597 UINT8 NextExtCapReg; 598 UINT32 Data; 599 600 ExtCapOffset = 0; 601 602 do { 603 // 604 // Check if the extended capability register's capability id is USB Legacy Support. 605 // 606 Data = XhcReadExtCapReg (Xhc, ExtCapOffset); 607 if ((Data & 0xFF) == CapId) { 608 return ExtCapOffset; 609 } 610 // 611 // If not, then traverse all of the ext capability registers till finding out it. 612 // 613 NextExtCapReg = (UINT8)((Data >> 8) & 0xFF); 614 ExtCapOffset += (NextExtCapReg << 2); 615 } while (NextExtCapReg != 0); 616 617 return 0xFFFFFFFF; 618 } 619 620 /** 621 Whether the XHCI host controller is halted. 622 623 @param Xhc The XHCI Instance. 624 625 @retval TRUE The controller is halted. 626 @retval FALSE It isn't halted. 627 628 **/ 629 BOOLEAN 630 XhcIsHalt ( 631 IN USB_XHCI_INSTANCE *Xhc 632 ) 633 { 634 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT); 635 } 636 637 638 /** 639 Whether system error occurred. 640 641 @param Xhc The XHCI Instance. 642 643 @retval TRUE System error happened. 644 @retval FALSE No system error. 645 646 **/ 647 BOOLEAN 648 XhcIsSysError ( 649 IN USB_XHCI_INSTANCE *Xhc 650 ) 651 { 652 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE); 653 } 654 655 /** 656 Reset the XHCI host controller. 657 658 @param Xhc The XHCI Instance. 659 @param Timeout Time to wait before abort (in millisecond, ms). 660 661 @retval EFI_SUCCESS The XHCI host controller is reset. 662 @return Others Failed to reset the XHCI before Timeout. 663 664 **/ 665 EFI_STATUS 666 XhcResetHC ( 667 IN USB_XHCI_INSTANCE *Xhc, 668 IN UINT32 Timeout 669 ) 670 { 671 EFI_STATUS Status; 672 673 Status = EFI_SUCCESS; 674 675 DEBUG ((EFI_D_INFO, "XhcResetHC!\n")); 676 // 677 // Host can only be reset when it is halt. If not so, halt it 678 // 679 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) { 680 Status = XhcHaltHC (Xhc, Timeout); 681 682 if (EFI_ERROR (Status)) { 683 return Status; 684 } 685 } 686 687 if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) || 688 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) { 689 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET); 690 Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout); 691 } 692 693 return Status; 694 } 695 696 697 /** 698 Halt the XHCI host controller. 699 700 @param Xhc The XHCI Instance. 701 @param Timeout Time to wait before abort (in millisecond, ms). 702 703 @return EFI_SUCCESS The XHCI host controller is halt. 704 @return EFI_TIMEOUT Failed to halt the XHCI before Timeout. 705 706 **/ 707 EFI_STATUS 708 XhcHaltHC ( 709 IN USB_XHCI_INSTANCE *Xhc, 710 IN UINT32 Timeout 711 ) 712 { 713 EFI_STATUS Status; 714 715 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN); 716 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout); 717 return Status; 718 } 719 720 721 /** 722 Set the XHCI host controller to run. 723 724 @param Xhc The XHCI Instance. 725 @param Timeout Time to wait before abort (in millisecond, ms). 726 727 @return EFI_SUCCESS The XHCI host controller is running. 728 @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout. 729 730 **/ 731 EFI_STATUS 732 XhcRunHC ( 733 IN USB_XHCI_INSTANCE *Xhc, 734 IN UINT32 Timeout 735 ) 736 { 737 EFI_STATUS Status; 738 739 XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN); 740 Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout); 741 return Status; 742 } 743 744