1 /** @file 2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid 3 which is used to enable recovery function from USB Drivers. 4 5 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions 9 of the BSD License which accompanies this distribution. The 10 full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include "EhcPeim.h" 19 20 // 21 // Two arrays used to translate the EHCI port state (change) 22 // to the UEFI protocol's port state (change). 23 // 24 USB_PORT_STATE_MAP mUsbPortStateMap[] = { 25 {PORTSC_CONN, USB_PORT_STAT_CONNECTION}, 26 {PORTSC_ENABLED, USB_PORT_STAT_ENABLE}, 27 {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND}, 28 {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT}, 29 {PORTSC_RESET, USB_PORT_STAT_RESET}, 30 {PORTSC_POWER, USB_PORT_STAT_POWER}, 31 {PORTSC_OWNER, USB_PORT_STAT_OWNER} 32 }; 33 34 USB_PORT_STATE_MAP mUsbPortChangeMap[] = { 35 {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION}, 36 {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE}, 37 {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT} 38 }; 39 40 /** 41 Read Ehc Operation register. 42 43 @param Ehc The EHCI device. 44 @param Offset The operation register offset. 45 46 @retval the register content read. 47 48 **/ 49 UINT32 50 EhcReadOpReg ( 51 IN PEI_USB2_HC_DEV *Ehc, 52 IN UINT32 Offset 53 ) 54 { 55 UINT32 Data; 56 57 ASSERT (Ehc->CapLen != 0); 58 59 Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset); 60 61 return Data; 62 } 63 64 /** 65 Write the data to the EHCI operation register. 66 67 @param Ehc The EHCI device. 68 @param Offset EHCI operation register offset. 69 @param Data The data to write. 70 71 **/ 72 VOID 73 EhcWriteOpReg ( 74 IN PEI_USB2_HC_DEV *Ehc, 75 IN UINT32 Offset, 76 IN UINT32 Data 77 ) 78 { 79 80 ASSERT (Ehc->CapLen != 0); 81 82 MmioWrite32(Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data); 83 84 } 85 86 /** 87 Set one bit of the operational register while keeping other bits. 88 89 @param Ehc The EHCI device. 90 @param Offset The offset of the operational register. 91 @param Bit The bit mask of the register to set. 92 93 **/ 94 VOID 95 EhcSetOpRegBit ( 96 IN PEI_USB2_HC_DEV *Ehc, 97 IN UINT32 Offset, 98 IN UINT32 Bit 99 ) 100 { 101 UINT32 Data; 102 103 Data = EhcReadOpReg (Ehc, Offset); 104 Data |= Bit; 105 EhcWriteOpReg (Ehc, Offset, Data); 106 } 107 108 /** 109 Clear one bit of the operational register while keeping other bits. 110 111 @param Ehc The EHCI device. 112 @param Offset The offset of the operational register. 113 @param Bit The bit mask of the register to clear. 114 115 **/ 116 VOID 117 EhcClearOpRegBit ( 118 IN PEI_USB2_HC_DEV *Ehc, 119 IN UINT32 Offset, 120 IN UINT32 Bit 121 ) 122 { 123 UINT32 Data; 124 125 Data = EhcReadOpReg (Ehc, Offset); 126 Data &= ~Bit; 127 EhcWriteOpReg (Ehc, Offset, Data); 128 } 129 130 /** 131 Wait the operation register's bit as specified by Bit 132 to become set (or clear). 133 134 @param Ehc The EHCI device. 135 @param Offset The offset of the operational register. 136 @param Bit The bit mask of the register to wait for. 137 @param WaitToSet Wait the bit to set or clear. 138 @param Timeout The time to wait before abort (in millisecond). 139 140 @retval EFI_SUCCESS The bit successfully changed by host controller. 141 @retval EFI_TIMEOUT The time out occurred. 142 143 **/ 144 EFI_STATUS 145 EhcWaitOpRegBit ( 146 IN PEI_USB2_HC_DEV *Ehc, 147 IN UINT32 Offset, 148 IN UINT32 Bit, 149 IN BOOLEAN WaitToSet, 150 IN UINT32 Timeout 151 ) 152 { 153 UINT32 Index; 154 155 for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) { 156 if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) { 157 return EFI_SUCCESS; 158 } 159 160 MicroSecondDelay (EHC_SYNC_POLL_INTERVAL); 161 } 162 163 return EFI_TIMEOUT; 164 } 165 166 /** 167 Read EHCI capability register. 168 169 @param Ehc The EHCI device. 170 @param Offset Capability register address. 171 172 @retval the register content read. 173 174 **/ 175 UINT32 176 EhcReadCapRegister ( 177 IN PEI_USB2_HC_DEV *Ehc, 178 IN UINT32 Offset 179 ) 180 { 181 UINT32 Data; 182 183 Data = MmioRead32(Ehc->UsbHostControllerBaseAddress + Offset); 184 185 return Data; 186 } 187 188 /** 189 Set door bell and wait it to be ACKed by host controller. 190 This function is used to synchronize with the hardware. 191 192 @param Ehc The EHCI device. 193 @param Timeout The time to wait before abort (in millisecond, ms). 194 195 @retval EFI_TIMEOUT Time out happened while waiting door bell to set. 196 @retval EFI_SUCCESS Synchronized with the hardware. 197 198 **/ 199 EFI_STATUS 200 EhcSetAndWaitDoorBell ( 201 IN PEI_USB2_HC_DEV *Ehc, 202 IN UINT32 Timeout 203 ) 204 { 205 EFI_STATUS Status; 206 UINT32 Data; 207 208 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD); 209 210 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout); 211 212 // 213 // ACK the IAA bit in USBSTS register. Make sure other 214 // interrupt bits are not ACKed. These bits are WC (Write Clean). 215 // 216 Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET); 217 Data &= ~USBSTS_INTACK_MASK; 218 Data |= USBSTS_IAA; 219 220 EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data); 221 222 return Status; 223 } 224 225 /** 226 Clear all the interrutp status bits, these bits 227 are Write-Clean. 228 229 @param Ehc The EHCI device. 230 231 **/ 232 VOID 233 EhcAckAllInterrupt ( 234 IN PEI_USB2_HC_DEV *Ehc 235 ) 236 { 237 EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK); 238 } 239 240 /** 241 Enable the periodic schedule then wait EHC to 242 actually enable it. 243 244 @param Ehc The EHCI device. 245 @param Timeout The time to wait before abort (in millisecond, ms). 246 247 @retval EFI_TIMEOUT Time out happened while enabling periodic schedule. 248 @retval EFI_SUCCESS The periodical schedule is enabled. 249 250 **/ 251 EFI_STATUS 252 EhcEnablePeriodSchd ( 253 IN PEI_USB2_HC_DEV *Ehc, 254 IN UINT32 Timeout 255 ) 256 { 257 EFI_STATUS Status; 258 259 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD); 260 261 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout); 262 return Status; 263 } 264 265 /** 266 Enable asynchrounous schedule. 267 268 @param Ehc The EHCI device. 269 @param Timeout Time to wait before abort. 270 271 @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled. 272 @retval Others Failed to enable the asynchronous scheudle. 273 274 **/ 275 EFI_STATUS 276 EhcEnableAsyncSchd ( 277 IN PEI_USB2_HC_DEV *Ehc, 278 IN UINT32 Timeout 279 ) 280 { 281 EFI_STATUS Status; 282 283 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC); 284 285 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout); 286 return Status; 287 } 288 289 /** 290 Check whether Ehc is halted. 291 292 @param Ehc The EHCI device. 293 294 @retval TRUE The controller is halted. 295 @retval FALSE The controller isn't halted. 296 297 **/ 298 BOOLEAN 299 EhcIsHalt ( 300 IN PEI_USB2_HC_DEV *Ehc 301 ) 302 { 303 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT); 304 } 305 306 /** 307 Check whether system error occurred. 308 309 @param Ehc The EHCI device. 310 311 @retval TRUE System error happened. 312 @retval FALSE No system error. 313 314 **/ 315 BOOLEAN 316 EhcIsSysError ( 317 IN PEI_USB2_HC_DEV *Ehc 318 ) 319 { 320 return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR); 321 } 322 323 /** 324 Reset the host controller. 325 326 @param Ehc The EHCI device. 327 @param Timeout Time to wait before abort (in millisecond, ms). 328 329 @retval EFI_TIMEOUT The transfer failed due to time out. 330 @retval Others Failed to reset the host. 331 332 **/ 333 EFI_STATUS 334 EhcResetHC ( 335 IN PEI_USB2_HC_DEV *Ehc, 336 IN UINT32 Timeout 337 ) 338 { 339 EFI_STATUS Status; 340 341 // 342 // Host can only be reset when it is halt. If not so, halt it 343 // 344 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) { 345 Status = EhcHaltHC (Ehc, Timeout); 346 347 if (EFI_ERROR (Status)) { 348 return Status; 349 } 350 } 351 352 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET); 353 Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout); 354 return Status; 355 } 356 357 /** 358 Halt the host controller. 359 360 @param Ehc The EHCI device. 361 @param Timeout Time to wait before abort. 362 363 @retval EFI_TIMEOUT Failed to halt the controller before Timeout. 364 @retval EFI_SUCCESS The EHCI is halt. 365 366 **/ 367 EFI_STATUS 368 EhcHaltHC ( 369 IN PEI_USB2_HC_DEV *Ehc, 370 IN UINT32 Timeout 371 ) 372 { 373 EFI_STATUS Status; 374 375 EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN); 376 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout); 377 return Status; 378 } 379 380 /** 381 Set the EHCI to run. 382 383 @param Ehc The EHCI device. 384 @param Timeout Time to wait before abort. 385 386 @retval EFI_SUCCESS The EHCI is running. 387 @retval Others Failed to set the EHCI to run. 388 389 **/ 390 EFI_STATUS 391 EhcRunHC ( 392 IN PEI_USB2_HC_DEV *Ehc, 393 IN UINT32 Timeout 394 ) 395 { 396 EFI_STATUS Status; 397 398 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN); 399 Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout); 400 return Status; 401 } 402 403 /** 404 Power On All EHCI Ports. 405 406 @param Ehc The EHCI device. 407 408 **/ 409 VOID 410 EhcPowerOnAllPorts ( 411 IN PEI_USB2_HC_DEV *Ehc 412 ) 413 { 414 UINT8 PortNumber; 415 UINT8 Index; 416 UINT32 RegVal; 417 418 PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS); 419 for (Index = 0; Index < PortNumber; Index++) { 420 // 421 // Do not clear port status bits on initialization. Otherwise devices will 422 // not enumerate properly at startup. 423 // 424 RegVal = EhcReadOpReg(Ehc, EHC_PORT_STAT_OFFSET + 4 * Index); 425 RegVal &= ~PORTSC_CHANGE_MASK; 426 RegVal |= PORTSC_POWER; 427 EhcWriteOpReg (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index, RegVal); 428 } 429 } 430 431 /** 432 Initialize the HC hardware. 433 EHCI spec lists the five things to do to initialize the hardware. 434 1. Program CTRLDSSEGMENT. 435 2. Set USBINTR to enable interrupts. 436 3. Set periodic list base. 437 4. Set USBCMD, interrupt threshold, frame list size etc. 438 5. Write 1 to CONFIGFLAG to route all ports to EHCI. 439 440 @param Ehc The EHCI device. 441 442 @retval EFI_SUCCESS The EHCI has come out of halt state. 443 @retval EFI_TIMEOUT Time out happened. 444 445 **/ 446 EFI_STATUS 447 EhcInitHC ( 448 IN PEI_USB2_HC_DEV *Ehc 449 ) 450 { 451 EFI_STATUS Status; 452 EFI_PHYSICAL_ADDRESS TempPtr; 453 UINTN PageNumber; 454 455 ASSERT (EhcIsHalt (Ehc)); 456 457 // 458 // Allocate the periodic frame and associated memeory 459 // management facilities if not already done. 460 // 461 if (Ehc->PeriodFrame != NULL) { 462 EhcFreeSched (Ehc); 463 } 464 PageNumber = sizeof(PEI_URB)/PAGESIZE +1; 465 Status = PeiServicesAllocatePages ( 466 EfiBootServicesCode, 467 PageNumber, 468 &TempPtr 469 ); 470 Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr); 471 if (Ehc->Urb == NULL) { 472 return Status; 473 } 474 475 EhcPowerOnAllPorts (Ehc); 476 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL); 477 478 Status = EhcInitSched (Ehc); 479 480 if (EFI_ERROR (Status)) { 481 return Status; 482 } 483 // 484 // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr 485 // 486 EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr); 487 488 // 489 // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling 490 // 491 EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0); 492 493 // 494 // 3. Program periodic frame list, already done in EhcInitSched 495 // 4. Start the Host Controller 496 // 497 EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN); 498 499 // 500 // 5. Set all ports routing to EHC 501 // 502 EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC); 503 504 // 505 // Wait roothub port power stable 506 // 507 MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL); 508 509 Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT); 510 511 if (EFI_ERROR (Status)) { 512 return Status; 513 } 514 515 Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT); 516 517 if (EFI_ERROR (Status)) { 518 return Status; 519 } 520 521 return EFI_SUCCESS; 522 } 523 524 /** 525 Submits bulk transfer to a bulk endpoint of a USB device. 526 527 @param PeiServices The pointer of EFI_PEI_SERVICES. 528 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI. 529 @param DeviceAddress Target device address. 530 @param EndPointAddress Endpoint number and its direction in bit 7. 531 @param DeviceSpeed Device speed, Low speed device doesn't support 532 bulk transfer. 533 @param MaximumPacketLength Maximum packet size the endpoint is capable of 534 sending or receiving. 535 @param Data Array of pointers to the buffers of data to transmit 536 from or receive into. 537 @param DataLength The lenght of the data buffer. 538 @param DataToggle On input, the initial data toggle for the transfer; 539 On output, it is updated to to next data toggle to use of 540 the subsequent bulk transfer. 541 @param TimeOut Indicates the maximum time, in millisecond, which the 542 transfer is allowed to complete. 543 If Timeout is 0, then the caller must wait for the function 544 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. 545 @param Translator A pointr to the transaction translator data. 546 @param TransferResult A pointer to the detailed result information of the 547 bulk transfer. 548 549 @retval EFI_SUCCESS The transfer was completed successfully. 550 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. 551 @retval EFI_INVALID_PARAMETER Parameters are invalid. 552 @retval EFI_TIMEOUT The transfer failed due to timeout. 553 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. 554 555 **/ 556 EFI_STATUS 557 EFIAPI 558 EhcBulkTransfer ( 559 IN EFI_PEI_SERVICES **PeiServices, 560 IN PEI_USB2_HOST_CONTROLLER_PPI *This, 561 IN UINT8 DeviceAddress, 562 IN UINT8 EndPointAddress, 563 IN UINT8 DeviceSpeed, 564 IN UINTN MaximumPacketLength, 565 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM], 566 IN OUT UINTN *DataLength, 567 IN OUT UINT8 *DataToggle, 568 IN UINTN TimeOut, 569 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 570 OUT UINT32 *TransferResult 571 ) 572 { 573 PEI_USB2_HC_DEV *Ehc; 574 PEI_URB *Urb; 575 EFI_STATUS Status; 576 577 // 578 // Validate the parameters 579 // 580 if ((DataLength == NULL) || (*DataLength == 0) || 581 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) { 582 return EFI_INVALID_PARAMETER; 583 } 584 585 if ((*DataToggle != 0) && (*DataToggle != 1)) { 586 return EFI_INVALID_PARAMETER; 587 } 588 589 if ((DeviceSpeed == EFI_USB_SPEED_LOW) || 590 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || 591 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) { 592 return EFI_INVALID_PARAMETER; 593 } 594 595 Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This); 596 *TransferResult = EFI_USB_ERR_SYSTEM; 597 Status = EFI_DEVICE_ERROR; 598 599 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { 600 EhcAckAllInterrupt (Ehc); 601 goto ON_EXIT; 602 } 603 604 EhcAckAllInterrupt (Ehc); 605 606 // 607 // Create a new URB, insert it into the asynchronous 608 // schedule list, then poll the execution status. 609 // 610 Urb = EhcCreateUrb ( 611 Ehc, 612 DeviceAddress, 613 EndPointAddress, 614 DeviceSpeed, 615 *DataToggle, 616 MaximumPacketLength, 617 Translator, 618 EHC_BULK_TRANSFER, 619 NULL, 620 Data[0], 621 *DataLength, 622 NULL, 623 NULL, 624 1 625 ); 626 627 if (Urb == NULL) { 628 Status = EFI_OUT_OF_RESOURCES; 629 goto ON_EXIT; 630 } 631 632 EhcLinkQhToAsync (Ehc, Urb->Qh); 633 Status = EhcExecTransfer (Ehc, Urb, TimeOut); 634 EhcUnlinkQhFromAsync (Ehc, Urb->Qh); 635 636 *TransferResult = Urb->Result; 637 *DataLength = Urb->Completed; 638 *DataToggle = Urb->DataToggle; 639 640 if (*TransferResult == EFI_USB_NOERROR) { 641 Status = EFI_SUCCESS; 642 } 643 644 EhcAckAllInterrupt (Ehc); 645 EhcFreeUrb (Ehc, Urb); 646 647 ON_EXIT: 648 return Status; 649 } 650 651 /** 652 Retrieves the number of root hub ports. 653 654 @param[in] PeiServices The pointer to the PEI Services Table. 655 @param[in] This The pointer to this instance of the 656 PEI_USB2_HOST_CONTROLLER_PPI. 657 @param[out] PortNumber The pointer to the number of the root hub ports. 658 659 @retval EFI_SUCCESS The port number was retrieved successfully. 660 @retval EFI_INVALID_PARAMETER PortNumber is NULL. 661 662 **/ 663 EFI_STATUS 664 EFIAPI 665 EhcGetRootHubPortNumber ( 666 IN EFI_PEI_SERVICES **PeiServices, 667 IN PEI_USB2_HOST_CONTROLLER_PPI *This, 668 OUT UINT8 *PortNumber 669 ) 670 { 671 672 PEI_USB2_HC_DEV *EhcDev; 673 EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This); 674 675 if (PortNumber == NULL) { 676 return EFI_INVALID_PARAMETER; 677 } 678 679 *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS); 680 return EFI_SUCCESS; 681 682 } 683 684 /** 685 Clears a feature for the specified root hub port. 686 687 @param PeiServices The pointer of EFI_PEI_SERVICES. 688 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI. 689 @param PortNumber Specifies the root hub port whose feature 690 is requested to be cleared. 691 @param PortFeature Indicates the feature selector associated with the 692 feature clear request. 693 694 @retval EFI_SUCCESS The feature specified by PortFeature was cleared 695 for the USB root hub port specified by PortNumber. 696 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 697 698 **/ 699 EFI_STATUS 700 EFIAPI 701 EhcClearRootHubPortFeature ( 702 IN EFI_PEI_SERVICES **PeiServices, 703 IN PEI_USB2_HOST_CONTROLLER_PPI *This, 704 IN UINT8 PortNumber, 705 IN EFI_USB_PORT_FEATURE PortFeature 706 ) 707 { 708 PEI_USB2_HC_DEV *Ehc; 709 UINT32 Offset; 710 UINT32 State; 711 UINT32 TotalPort; 712 EFI_STATUS Status; 713 714 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This); 715 Status = EFI_SUCCESS; 716 717 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS); 718 719 if (PortNumber >= TotalPort) { 720 Status = EFI_INVALID_PARAMETER; 721 goto ON_EXIT; 722 } 723 724 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber); 725 State = EhcReadOpReg (Ehc, Offset); 726 State &= ~PORTSC_CHANGE_MASK; 727 728 switch (PortFeature) { 729 case EfiUsbPortEnable: 730 // 731 // Clear PORT_ENABLE feature means disable port. 732 // 733 State &= ~PORTSC_ENABLED; 734 EhcWriteOpReg (Ehc, Offset, State); 735 break; 736 737 case EfiUsbPortSuspend: 738 // 739 // A write of zero to this bit is ignored by the host 740 // controller. The host controller will unconditionally 741 // set this bit to a zero when: 742 // 1. software sets the Forct Port Resume bit to a zero from a one. 743 // 2. software sets the Port Reset bit to a one frome a zero. 744 // 745 State &= ~PORSTSC_RESUME; 746 EhcWriteOpReg (Ehc, Offset, State); 747 break; 748 749 case EfiUsbPortReset: 750 // 751 // Clear PORT_RESET means clear the reset signal. 752 // 753 State &= ~PORTSC_RESET; 754 EhcWriteOpReg (Ehc, Offset, State); 755 break; 756 757 case EfiUsbPortOwner: 758 // 759 // Clear port owner means this port owned by EHC 760 // 761 State &= ~PORTSC_OWNER; 762 EhcWriteOpReg (Ehc, Offset, State); 763 break; 764 765 case EfiUsbPortConnectChange: 766 // 767 // Clear connect status change 768 // 769 State |= PORTSC_CONN_CHANGE; 770 EhcWriteOpReg (Ehc, Offset, State); 771 break; 772 773 case EfiUsbPortEnableChange: 774 // 775 // Clear enable status change 776 // 777 State |= PORTSC_ENABLE_CHANGE; 778 EhcWriteOpReg (Ehc, Offset, State); 779 break; 780 781 case EfiUsbPortOverCurrentChange: 782 // 783 // Clear PortOverCurrent change 784 // 785 State |= PORTSC_OVERCUR_CHANGE; 786 EhcWriteOpReg (Ehc, Offset, State); 787 break; 788 789 case EfiUsbPortPower: 790 case EfiUsbPortSuspendChange: 791 case EfiUsbPortResetChange: 792 // 793 // Not supported or not related operation 794 // 795 break; 796 797 default: 798 Status = EFI_INVALID_PARAMETER; 799 break; 800 } 801 802 ON_EXIT: 803 return Status; 804 } 805 806 /** 807 Sets a feature for the specified root hub port. 808 809 @param PeiServices The pointer of EFI_PEI_SERVICES 810 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI 811 @param PortNumber Root hub port to set. 812 @param PortFeature Feature to set. 813 814 @retval EFI_SUCCESS The feature specified by PortFeature was set. 815 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. 816 @retval EFI_TIMEOUT The time out occurred. 817 818 **/ 819 EFI_STATUS 820 EFIAPI 821 EhcSetRootHubPortFeature ( 822 IN EFI_PEI_SERVICES **PeiServices, 823 IN PEI_USB2_HOST_CONTROLLER_PPI *This, 824 IN UINT8 PortNumber, 825 IN EFI_USB_PORT_FEATURE PortFeature 826 ) 827 { 828 PEI_USB2_HC_DEV *Ehc; 829 UINT32 Offset; 830 UINT32 State; 831 UINT32 TotalPort; 832 EFI_STATUS Status; 833 834 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This); 835 Status = EFI_SUCCESS; 836 837 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS); 838 839 if (PortNumber >= TotalPort) { 840 Status = EFI_INVALID_PARAMETER; 841 goto ON_EXIT; 842 } 843 844 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber)); 845 State = EhcReadOpReg (Ehc, Offset); 846 847 // 848 // Mask off the port status change bits, these bits are 849 // write clean bit 850 // 851 State &= ~PORTSC_CHANGE_MASK; 852 853 switch (PortFeature) { 854 case EfiUsbPortEnable: 855 // 856 // Sofeware can't set this bit, Port can only be enable by 857 // EHCI as a part of the reset and enable 858 // 859 State |= PORTSC_ENABLED; 860 EhcWriteOpReg (Ehc, Offset, State); 861 break; 862 863 case EfiUsbPortSuspend: 864 State |= PORTSC_SUSPEND; 865 EhcWriteOpReg (Ehc, Offset, State); 866 break; 867 868 case EfiUsbPortReset: 869 // 870 // Make sure Host Controller not halt before reset it 871 // 872 if (EhcIsHalt (Ehc)) { 873 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT); 874 875 if (EFI_ERROR (Status)) { 876 break; 877 } 878 } 879 880 // 881 // Set one to PortReset bit must also set zero to PortEnable bit 882 // 883 State |= PORTSC_RESET; 884 State &= ~PORTSC_ENABLED; 885 EhcWriteOpReg (Ehc, Offset, State); 886 break; 887 888 case EfiUsbPortPower: 889 // 890 // Not supported, ignore the operation 891 // 892 Status = EFI_SUCCESS; 893 break; 894 895 case EfiUsbPortOwner: 896 State |= PORTSC_OWNER; 897 EhcWriteOpReg (Ehc, Offset, State); 898 break; 899 900 default: 901 Status = EFI_INVALID_PARAMETER; 902 } 903 904 ON_EXIT: 905 return Status; 906 } 907 908 /** 909 Retrieves the current status of a USB root hub port. 910 911 @param PeiServices The pointer of EFI_PEI_SERVICES. 912 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI. 913 @param PortNumber The root hub port to retrieve the state from. 914 @param PortStatus Variable to receive the port state. 915 916 @retval EFI_SUCCESS The status of the USB root hub port specified. 917 by PortNumber was returned in PortStatus. 918 @retval EFI_INVALID_PARAMETER PortNumber is invalid. 919 920 **/ 921 EFI_STATUS 922 EFIAPI 923 EhcGetRootHubPortStatus ( 924 IN EFI_PEI_SERVICES **PeiServices, 925 IN PEI_USB2_HOST_CONTROLLER_PPI *This, 926 IN UINT8 PortNumber, 927 OUT EFI_USB_PORT_STATUS *PortStatus 928 ) 929 { 930 PEI_USB2_HC_DEV *Ehc; 931 UINT32 Offset; 932 UINT32 State; 933 UINT32 TotalPort; 934 UINTN Index; 935 UINTN MapSize; 936 EFI_STATUS Status; 937 938 if (PortStatus == NULL) { 939 return EFI_INVALID_PARAMETER; 940 } 941 942 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This); 943 Status = EFI_SUCCESS; 944 945 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS); 946 947 if (PortNumber >= TotalPort) { 948 Status = EFI_INVALID_PARAMETER; 949 goto ON_EXIT; 950 } 951 952 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber)); 953 PortStatus->PortStatus = 0; 954 PortStatus->PortChangeStatus = 0; 955 956 State = EhcReadOpReg (Ehc, Offset); 957 958 // 959 // Identify device speed. If in K state, it is low speed. 960 // If the port is enabled after reset, the device is of 961 // high speed. The USB bus driver should retrieve the actual 962 // port speed after reset. 963 // 964 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) { 965 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; 966 967 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) { 968 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; 969 } 970 971 // 972 // Convert the EHCI port/port change state to UEFI status 973 // 974 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP); 975 976 for (Index = 0; Index < MapSize; Index++) { 977 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) { 978 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState); 979 } 980 } 981 982 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP); 983 984 for (Index = 0; Index < MapSize; Index++) { 985 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) { 986 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState); 987 } 988 } 989 990 ON_EXIT: 991 return Status; 992 } 993 994 /** 995 Submits control transfer to a target USB device. 996 997 @param PeiServices The pointer of EFI_PEI_SERVICES. 998 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI. 999 @param DeviceAddress The target device address. 1000 @param DeviceSpeed Target device speed. 1001 @param MaximumPacketLength Maximum packet size the default control transfer 1002 endpoint is capable of sending or receiving. 1003 @param Request USB device request to send. 1004 @param TransferDirection Specifies the data direction for the data stage. 1005 @param Data Data buffer to be transmitted or received from USB device. 1006 @param DataLength The size (in bytes) of the data buffer. 1007 @param TimeOut Indicates the maximum timeout, in millisecond. 1008 If Timeout is 0, then the caller must wait for the function 1009 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. 1010 @param Translator Transaction translator to be used by this device. 1011 @param TransferResult Return the result of this control transfer. 1012 1013 @retval EFI_SUCCESS Transfer was completed successfully. 1014 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. 1015 @retval EFI_INVALID_PARAMETER Some parameters are invalid. 1016 @retval EFI_TIMEOUT Transfer failed due to timeout. 1017 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. 1018 1019 **/ 1020 EFI_STATUS 1021 EFIAPI 1022 EhcControlTransfer ( 1023 IN EFI_PEI_SERVICES **PeiServices, 1024 IN PEI_USB2_HOST_CONTROLLER_PPI *This, 1025 IN UINT8 DeviceAddress, 1026 IN UINT8 DeviceSpeed, 1027 IN UINTN MaximumPacketLength, 1028 IN EFI_USB_DEVICE_REQUEST *Request, 1029 IN EFI_USB_DATA_DIRECTION TransferDirection, 1030 IN OUT VOID *Data, 1031 IN OUT UINTN *DataLength, 1032 IN UINTN TimeOut, 1033 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, 1034 OUT UINT32 *TransferResult 1035 ) 1036 { 1037 PEI_USB2_HC_DEV *Ehc; 1038 PEI_URB *Urb; 1039 UINT8 Endpoint; 1040 EFI_STATUS Status; 1041 1042 // 1043 // Validate parameters 1044 // 1045 if ((Request == NULL) || (TransferResult == NULL)) { 1046 return EFI_INVALID_PARAMETER; 1047 } 1048 1049 if ((TransferDirection != EfiUsbDataIn) && 1050 (TransferDirection != EfiUsbDataOut) && 1051 (TransferDirection != EfiUsbNoData)) { 1052 return EFI_INVALID_PARAMETER; 1053 } 1054 1055 if ((TransferDirection == EfiUsbNoData) && 1056 ((Data != NULL) || (*DataLength != 0))) { 1057 return EFI_INVALID_PARAMETER; 1058 } 1059 1060 if ((TransferDirection != EfiUsbNoData) && 1061 ((Data == NULL) || (*DataLength == 0))) { 1062 return EFI_INVALID_PARAMETER; 1063 } 1064 1065 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) && 1066 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) { 1067 return EFI_INVALID_PARAMETER; 1068 } 1069 1070 1071 if ((DeviceSpeed == EFI_USB_SPEED_LOW) || 1072 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || 1073 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) { 1074 return EFI_INVALID_PARAMETER; 1075 } 1076 1077 Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This); 1078 1079 Status = EFI_DEVICE_ERROR; 1080 *TransferResult = EFI_USB_ERR_SYSTEM; 1081 1082 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { 1083 EhcAckAllInterrupt (Ehc); 1084 goto ON_EXIT; 1085 } 1086 1087 EhcAckAllInterrupt (Ehc); 1088 1089 // 1090 // Create a new URB, insert it into the asynchronous 1091 // schedule list, then poll the execution status. 1092 // 1093 // 1094 // Encode the direction in address, although default control 1095 // endpoint is bidirectional. EhcCreateUrb expects this 1096 // combination of Ep addr and its direction. 1097 // 1098 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0)); 1099 Urb = EhcCreateUrb ( 1100 Ehc, 1101 DeviceAddress, 1102 Endpoint, 1103 DeviceSpeed, 1104 0, 1105 MaximumPacketLength, 1106 Translator, 1107 EHC_CTRL_TRANSFER, 1108 Request, 1109 Data, 1110 *DataLength, 1111 NULL, 1112 NULL, 1113 1 1114 ); 1115 1116 if (Urb == NULL) { 1117 Status = EFI_OUT_OF_RESOURCES; 1118 goto ON_EXIT; 1119 } 1120 1121 EhcLinkQhToAsync (Ehc, Urb->Qh); 1122 Status = EhcExecTransfer (Ehc, Urb, TimeOut); 1123 EhcUnlinkQhFromAsync (Ehc, Urb->Qh); 1124 1125 // 1126 // Get the status from URB. The result is updated in EhcCheckUrbResult 1127 // which is called by EhcExecTransfer 1128 // 1129 *TransferResult = Urb->Result; 1130 *DataLength = Urb->Completed; 1131 1132 if (*TransferResult == EFI_USB_NOERROR) { 1133 Status = EFI_SUCCESS; 1134 } 1135 1136 EhcAckAllInterrupt (Ehc); 1137 EhcFreeUrb (Ehc, Urb); 1138 1139 ON_EXIT: 1140 return Status; 1141 } 1142 1143 /** 1144 @param FileHandle Handle of the file being invoked. 1145 @param PeiServices Describes the list of possible PEI Services. 1146 1147 @retval EFI_SUCCESS PPI successfully installed. 1148 1149 **/ 1150 EFI_STATUS 1151 EFIAPI 1152 EhcPeimEntry ( 1153 IN EFI_PEI_FILE_HANDLE FileHandle, 1154 IN CONST EFI_PEI_SERVICES **PeiServices 1155 ) 1156 { 1157 PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi; 1158 EFI_STATUS Status; 1159 UINT8 Index; 1160 UINTN ControllerType; 1161 UINTN BaseAddress; 1162 UINTN MemPages; 1163 PEI_USB2_HC_DEV *EhcDev; 1164 EFI_PHYSICAL_ADDRESS TempPtr; 1165 1166 // 1167 // Shadow this PEIM to run from memory 1168 // 1169 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { 1170 return EFI_SUCCESS; 1171 } 1172 1173 Status = PeiServicesLocatePpi ( 1174 &gPeiUsbControllerPpiGuid, 1175 0, 1176 NULL, 1177 (VOID **) &ChipSetUsbControllerPpi 1178 ); 1179 if (EFI_ERROR (Status)) { 1180 return EFI_UNSUPPORTED; 1181 } 1182 1183 Index = 0; 1184 while (TRUE) { 1185 Status = ChipSetUsbControllerPpi->GetUsbController ( 1186 (EFI_PEI_SERVICES **) PeiServices, 1187 ChipSetUsbControllerPpi, 1188 Index, 1189 &ControllerType, 1190 &BaseAddress 1191 ); 1192 // 1193 // When status is error, meant no controller is found 1194 // 1195 if (EFI_ERROR (Status)) { 1196 break; 1197 } 1198 1199 // 1200 // This PEIM is for UHC type controller. 1201 // 1202 if (ControllerType != PEI_EHCI_CONTROLLER) { 1203 Index++; 1204 continue; 1205 } 1206 1207 MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1; 1208 Status = PeiServicesAllocatePages ( 1209 EfiBootServicesCode, 1210 MemPages, 1211 &TempPtr 1212 ); 1213 if (EFI_ERROR (Status)) { 1214 return EFI_OUT_OF_RESOURCES; 1215 } 1216 1217 ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE); 1218 EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr); 1219 1220 EhcDev->Signature = USB2_HC_DEV_SIGNATURE; 1221 1222 EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress; 1223 1224 1225 EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET); 1226 EhcDev->HcCapParams = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET); 1227 EhcDev->CapLen = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF; 1228 // 1229 // Initialize Uhc's hardware 1230 // 1231 Status = InitializeUsbHC (EhcDev); 1232 if (EFI_ERROR (Status)) { 1233 return Status; 1234 } 1235 1236 EhcDev->Usb2HostControllerPpi.ControlTransfer = EhcControlTransfer; 1237 EhcDev->Usb2HostControllerPpi.BulkTransfer = EhcBulkTransfer; 1238 EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = EhcGetRootHubPortNumber; 1239 EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = EhcGetRootHubPortStatus; 1240 EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = EhcSetRootHubPortFeature; 1241 EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = EhcClearRootHubPortFeature; 1242 1243 EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); 1244 EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid; 1245 EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi; 1246 1247 Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor); 1248 if (EFI_ERROR (Status)) { 1249 Index++; 1250 continue; 1251 } 1252 1253 Index++; 1254 } 1255 1256 return EFI_SUCCESS; 1257 } 1258 1259 /** 1260 @param EhcDev EHCI Device. 1261 1262 @retval EFI_SUCCESS EHCI successfully initialized. 1263 @retval EFI_ABORTED EHCI was failed to be initialized. 1264 1265 **/ 1266 EFI_STATUS 1267 InitializeUsbHC ( 1268 IN PEI_USB2_HC_DEV *EhcDev 1269 ) 1270 { 1271 EFI_STATUS Status; 1272 1273 1274 EhcResetHC (EhcDev, EHC_RESET_TIMEOUT); 1275 1276 Status = EhcInitHC (EhcDev); 1277 1278 if (EFI_ERROR (Status)) { 1279 return EFI_ABORTED; 1280 } 1281 1282 return EFI_SUCCESS; 1283 } 1284