XhciReg.c revision 74b04490da9dcb90de61e31db51b8e137f9e6e3d
1/** @file 2 3 The XHCI register operation routines. 4 5Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> 6This program and the accompanying materials 7are licensed and made available under the terms and conditions of the BSD License 8which accompanies this distribution. The full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT 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**/ 28UINT8 29XhcReadCapReg8 ( 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**/ 64UINT32 65XhcReadCapReg ( 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**/ 100UINT32 101XhcReadOpReg ( 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**/ 136VOID 137XhcWriteOpReg ( 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**/ 169VOID 170XhcWriteOpReg16 ( 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**/ 203UINT32 204XhcReadDoorBellReg ( 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**/ 239VOID 240XhcWriteDoorBellReg ( 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**/ 273UINT32 274XhcReadRuntimeReg ( 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**/ 309VOID 310XhcWriteRuntimeReg ( 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**/ 343UINT32 344XhcReadExtCapReg ( 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**/ 379VOID 380XhcWriteExtCapReg ( 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**/ 413VOID 414XhcSetRuntimeRegBit ( 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**/ 435VOID 436XhcClearRuntimeRegBit ( 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**/ 457VOID 458XhcSetOpRegBit ( 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**/ 480VOID 481XhcClearOpRegBit ( 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**/ 508EFI_STATUS 509XhcWaitOpRegBit ( 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 UINTN Loop; 519 520 Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1; 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_POLL_DELAY); 528 } 529 530 return EFI_TIMEOUT; 531} 532 533/** 534 Set Bios Ownership 535 536 @param Xhc The XHCI Instance. 537 538**/ 539VOID 540XhcSetBiosOwnership ( 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**/ 563VOID 564XhcClearBiosOwnership ( 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**/ 590UINT32 591XhcGetCapabilityAddr ( 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**/ 629BOOLEAN 630XhcIsHalt ( 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**/ 647BOOLEAN 648XhcIsSysError ( 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**/ 665EFI_STATUS 666XhcResetHC ( 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**/ 707EFI_STATUS 708XhcHaltHC ( 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**/ 731EFI_STATUS 732XhcRunHC ( 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