2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
14 // Two arrays used to translate the XHCI port state (change)
15 // to the UEFI protocol's port state (change).
17 USB_PORT_STATE_MAP mUsbPortStateMap
[] = {
18 { XHC_PORTSC_CCS
, USB_PORT_STAT_CONNECTION
},
19 { XHC_PORTSC_PED
, USB_PORT_STAT_ENABLE
},
20 { XHC_PORTSC_OCA
, USB_PORT_STAT_OVERCURRENT
},
21 { XHC_PORTSC_PP
, USB_PORT_STAT_POWER
},
22 { XHC_PORTSC_RESET
, USB_PORT_STAT_RESET
}
25 USB_PORT_STATE_MAP mUsbPortChangeMap
[] = {
26 { XHC_PORTSC_CSC
, USB_PORT_STAT_C_CONNECTION
},
27 { XHC_PORTSC_PEC
, USB_PORT_STAT_C_ENABLE
},
28 { XHC_PORTSC_OCC
, USB_PORT_STAT_C_OVERCURRENT
},
29 { XHC_PORTSC_PRC
, USB_PORT_STAT_C_RESET
}
32 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap
[] = {
33 { XHC_PORTSC_CSC
, EfiUsbPortConnectChange
},
34 { XHC_PORTSC_PEC
, EfiUsbPortEnableChange
},
35 { XHC_PORTSC_OCC
, EfiUsbPortOverCurrentChange
},
36 { XHC_PORTSC_PRC
, EfiUsbPortResetChange
}
39 USB_PORT_STATE_MAP mUsbHubPortStateMap
[] = {
40 { XHC_HUB_PORTSC_CCS
, USB_PORT_STAT_CONNECTION
},
41 { XHC_HUB_PORTSC_PED
, USB_PORT_STAT_ENABLE
},
42 { XHC_HUB_PORTSC_OCA
, USB_PORT_STAT_OVERCURRENT
},
43 { XHC_HUB_PORTSC_PP
, USB_PORT_STAT_POWER
},
44 { XHC_HUB_PORTSC_RESET
, USB_PORT_STAT_RESET
}
47 USB_PORT_STATE_MAP mUsbHubPortChangeMap
[] = {
48 { XHC_HUB_PORTSC_CSC
, USB_PORT_STAT_C_CONNECTION
},
49 { XHC_HUB_PORTSC_PEC
, USB_PORT_STAT_C_ENABLE
},
50 { XHC_HUB_PORTSC_OCC
, USB_PORT_STAT_C_OVERCURRENT
},
51 { XHC_HUB_PORTSC_PRC
, USB_PORT_STAT_C_RESET
}
54 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap
[] = {
55 { XHC_HUB_PORTSC_CSC
, EfiUsbPortConnectChange
},
56 { XHC_HUB_PORTSC_PEC
, EfiUsbPortEnableChange
},
57 { XHC_HUB_PORTSC_OCC
, EfiUsbPortOverCurrentChange
},
58 { XHC_HUB_PORTSC_PRC
, EfiUsbPortResetChange
},
59 { XHC_HUB_PORTSC_BHRC
, Usb3PortBHPortResetChange
}
63 Read XHCI Operation register.
65 @param Xhc The XHCI device.
66 @param Offset The operation register offset.
68 @retval the register content read.
79 ASSERT (Xhc
->CapLength
!= 0);
81 Data
= MmioRead32 (Xhc
->UsbHostControllerBaseAddress
+ Xhc
->CapLength
+ Offset
);
86 Write the data to the XHCI operation register.
88 @param Xhc The XHCI device.
89 @param Offset The operation register offset.
90 @param Data The data to write.
100 ASSERT (Xhc
->CapLength
!= 0);
102 MmioWrite32 (Xhc
->UsbHostControllerBaseAddress
+ Xhc
->CapLength
+ Offset
, Data
);
106 Set one bit of the operational register while keeping other bits.
108 @param Xhc The XHCI device.
109 @param Offset The offset of the operational register.
110 @param Bit The bit mask of the register to set.
122 Data
= XhcPeiReadOpReg (Xhc
, Offset
);
124 XhcPeiWriteOpReg (Xhc
, Offset
, Data
);
128 Clear one bit of the operational register while keeping other bits.
130 @param Xhc The XHCI device.
131 @param Offset The offset of the operational register.
132 @param Bit The bit mask of the register to clear.
136 XhcPeiClearOpRegBit (
144 Data
= XhcPeiReadOpReg (Xhc
, Offset
);
146 XhcPeiWriteOpReg (Xhc
, Offset
, Data
);
150 Wait the operation register's bit as specified by Bit
151 to become set (or clear).
153 @param Xhc The XHCI device.
154 @param Offset The offset of the operational register.
155 @param Bit The bit mask of the register to wait for.
156 @param WaitToSet Wait the bit to set or clear.
157 @param Timeout The time to wait before abort (in millisecond, ms).
159 @retval EFI_SUCCESS The bit successfully changed by host controller.
160 @retval EFI_TIMEOUT The time out occurred.
168 IN BOOLEAN WaitToSet
,
174 for (Index
= 0; Index
< Timeout
* XHC_1_MILLISECOND
; Index
++) {
175 if (XHC_REG_BIT_IS_SET (Xhc
, Offset
, Bit
) == WaitToSet
) {
179 MicroSecondDelay (XHC_1_MICROSECOND
);
186 Read XHCI capability register.
188 @param Xhc The XHCI device.
189 @param Offset Capability register address.
191 @retval the register content read.
195 XhcPeiReadCapRegister (
202 Data
= MmioRead32 (Xhc
->UsbHostControllerBaseAddress
+ Offset
);
208 Write the data to the XHCI door bell register.
210 @param Xhc The XHCI device.
211 @param Offset The offset of the door bell register.
212 @param Data The data to write.
216 XhcPeiWriteDoorBellReg (
222 ASSERT (Xhc
->DBOff
!= 0);
224 MmioWrite32 (Xhc
->UsbHostControllerBaseAddress
+ Xhc
->DBOff
+ Offset
, Data
);
228 Read XHCI runtime register.
230 @param Xhc The XHCI device.
231 @param Offset The offset of the runtime register.
233 @return The register content read
237 XhcPeiReadRuntimeReg (
244 ASSERT (Xhc
->RTSOff
!= 0);
246 Data
= MmioRead32 (Xhc
->UsbHostControllerBaseAddress
+ Xhc
->RTSOff
+ Offset
);
252 Write the data to the XHCI runtime register.
254 @param Xhc The XHCI device.
255 @param Offset The offset of the runtime register.
256 @param Data The data to write.
260 XhcPeiWriteRuntimeReg (
266 ASSERT (Xhc
->RTSOff
!= 0);
268 MmioWrite32 (Xhc
->UsbHostControllerBaseAddress
+ Xhc
->RTSOff
+ Offset
, Data
);
272 Set one bit of the runtime register while keeping other bits.
274 @param Xhc The XHCI device.
275 @param Offset The offset of the runtime register.
276 @param Bit The bit mask of the register to set.
280 XhcPeiSetRuntimeRegBit (
288 Data
= XhcPeiReadRuntimeReg (Xhc
, Offset
);
290 XhcPeiWriteRuntimeReg (Xhc
, Offset
, Data
);
294 Clear one bit of the runtime register while keeping other bits.
296 @param Xhc The XHCI device.
297 @param Offset The offset of the runtime register.
298 @param Bit The bit mask of the register to set.
302 XhcPeiClearRuntimeRegBit (
310 Data
= XhcPeiReadRuntimeReg (Xhc
, Offset
);
312 XhcPeiWriteRuntimeReg (Xhc
, Offset
, Data
);
316 Check whether Xhc is halted.
318 @param Xhc The XHCI device.
320 @retval TRUE The controller is halted.
321 @retval FALSE The controller isn't halted.
329 return XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
);
333 Check whether system error occurred.
335 @param Xhc The XHCI device.
337 @retval TRUE System error happened.
338 @retval FALSE No system error.
346 return XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HSE
);
350 Reset the host controller.
352 @param Xhc The XHCI device.
353 @param Timeout Time to wait before abort (in millisecond, ms).
355 @retval EFI_TIMEOUT The transfer failed due to time out.
356 @retval Others Failed to reset the host.
368 // Host can only be reset when it is halt. If not so, halt it
370 if (!XhcPeiIsHalt (Xhc
)) {
371 Status
= XhcPeiHaltHC (Xhc
, Timeout
);
373 if (EFI_ERROR (Status
)) {
378 XhcPeiSetOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RESET
);
380 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
381 // Otherwise there may have the timeout case happened.
382 // The below is a workaround to solve such problem.
384 MicroSecondDelay (1000);
385 Status
= XhcPeiWaitOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RESET
, FALSE
, Timeout
);
387 DEBUG ((DEBUG_INFO
, "XhcPeiResetHC: %r\n", Status
));
392 Halt the host controller.
394 @param Xhc The XHCI device.
395 @param Timeout Time to wait before abort.
397 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.
398 @retval EFI_SUCCESS The XHCI is halt.
409 XhcPeiClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RUN
);
410 Status
= XhcPeiWaitOpRegBit (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
, TRUE
, Timeout
);
411 DEBUG ((DEBUG_INFO
, "XhcPeiHaltHC: %r\n", Status
));
418 @param Xhc The XHCI device.
419 @param Timeout Time to wait before abort.
421 @retval EFI_SUCCESS The XHCI is running.
422 @retval Others Failed to set the XHCI to run.
433 XhcPeiSetOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RUN
);
434 Status
= XhcPeiWaitOpRegBit (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
, FALSE
, Timeout
);
435 DEBUG ((DEBUG_INFO
, "XhcPeiRunHC: %r\n", Status
));
440 Submits control transfer to a target USB device.
442 @param PeiServices The pointer of EFI_PEI_SERVICES.
443 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
444 @param DeviceAddress The target device address.
445 @param DeviceSpeed Target device speed.
446 @param MaximumPacketLength Maximum packet size the default control transfer
447 endpoint is capable of sending or receiving.
448 @param Request USB device request to send.
449 @param TransferDirection Specifies the data direction for the data stage.
450 @param Data Data buffer to be transmitted or received from USB device.
451 @param DataLength The size (in bytes) of the data buffer.
452 @param TimeOut Indicates the maximum timeout, in millisecond.
453 If Timeout is 0, then the caller must wait for the function
454 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
455 @param Translator Transaction translator to be used by this device.
456 @param TransferResult Return the result of this control transfer.
458 @retval EFI_SUCCESS Transfer was completed successfully.
459 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
460 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
461 @retval EFI_TIMEOUT Transfer failed due to timeout.
462 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
467 XhcPeiControlTransfer (
468 IN EFI_PEI_SERVICES
**PeiServices
,
469 IN PEI_USB2_HOST_CONTROLLER_PPI
*This
,
470 IN UINT8 DeviceAddress
,
471 IN UINT8 DeviceSpeed
,
472 IN UINTN MaximumPacketLength
,
473 IN EFI_USB_DEVICE_REQUEST
*Request
,
474 IN EFI_USB_DATA_DIRECTION TransferDirection
,
476 IN OUT UINTN
*DataLength
,
478 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
479 OUT UINT32
*TransferResult
486 UINT8 DescriptorType
;
491 EFI_USB_HUB_DESCRIPTOR
*HubDesc
;
493 EFI_STATUS RecoveryStatus
;
495 EFI_USB_PORT_STATUS PortStatus
;
497 EFI_USB_DEVICE_REQUEST ClearPortRequest
;
501 // Validate parameters
503 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
504 return EFI_INVALID_PARAMETER
;
507 if ((TransferDirection
!= EfiUsbDataIn
) &&
508 (TransferDirection
!= EfiUsbDataOut
) &&
509 (TransferDirection
!= EfiUsbNoData
))
511 return EFI_INVALID_PARAMETER
;
514 if ((TransferDirection
== EfiUsbNoData
) &&
515 ((Data
!= NULL
) || (*DataLength
!= 0)))
517 return EFI_INVALID_PARAMETER
;
520 if ((TransferDirection
!= EfiUsbNoData
) &&
521 ((Data
== NULL
) || (*DataLength
== 0)))
523 return EFI_INVALID_PARAMETER
;
526 if ((MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16) &&
527 (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64) &&
528 (MaximumPacketLength
!= 512)
531 return EFI_INVALID_PARAMETER
;
534 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) {
535 return EFI_INVALID_PARAMETER
;
538 if ((DeviceSpeed
== EFI_USB_SPEED_SUPER
) && (MaximumPacketLength
!= 512)) {
539 return EFI_INVALID_PARAMETER
;
542 Xhc
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This
);
544 Status
= EFI_DEVICE_ERROR
;
545 *TransferResult
= EFI_USB_ERR_SYSTEM
;
548 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
549 DEBUG ((DEBUG_ERROR
, "XhcPeiControlTransfer: HC is halted or has system error\n"));
554 // Check if the device is still enabled before every transaction.
556 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, DeviceAddress
);
562 // Hook the Set_Address request from UsbBus.
563 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
565 if ((Request
->Request
== USB_REQ_SET_ADDRESS
) &&
566 (Request
->RequestType
== USB_REQUEST_TYPE (EfiUsbNoData
, USB_REQ_TYPE_STANDARD
, USB_TARGET_DEVICE
)))
569 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
570 // This way is used to clean the history to avoid using wrong device address afterwards.
572 for (Index
= 0; Index
< 255; Index
++) {
573 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
574 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) &&
575 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== (UINT8
)Request
->Value
))
577 Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
= 0;
581 if (Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
== 0) {
586 // The actual device address has been assigned by XHCI during initializing the device slot.
587 // So we just need establish the mapping relationship between the device address requested from UsbBus
588 // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface
589 // can find out the actual device address by it.
591 Xhc
->UsbDevContext
[SlotId
].BusDevAddr
= (UINT8
)Request
->Value
;
592 Status
= EFI_SUCCESS
;
597 // Create a new URB, insert it into the asynchronous
598 // schedule list, then poll the execution status.
599 // Note that we encode the direction in address although default control
600 // endpoint is bidirectional. XhcPeiCreateUrb expects this
601 // combination of Ep addr and its direction.
603 Endpoint
= (UINT8
)(0 | ((TransferDirection
== EfiUsbDataIn
) ? 0x80 : 0));
604 Urb
= XhcPeiCreateUrb (
619 DEBUG ((DEBUG_ERROR
, "XhcPeiControlTransfer: failed to create URB"));
620 Status
= EFI_OUT_OF_RESOURCES
;
624 Status
= XhcPeiExecTransfer (Xhc
, FALSE
, Urb
, TimeOut
);
627 // Get the status from URB. The result is updated in XhcPeiCheckUrbResult
628 // which is called by XhcPeiExecTransfer
630 *TransferResult
= Urb
->Result
;
631 *DataLength
= Urb
->Completed
;
633 if (Status
== EFI_TIMEOUT
) {
635 // The transfer timed out. Abort the transfer by dequeueing of the TD.
637 RecoveryStatus
= XhcPeiDequeueTrbFromEndpoint (Xhc
, Urb
);
638 if (EFI_ERROR (RecoveryStatus
)) {
639 DEBUG ((DEBUG_ERROR
, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
642 XhcPeiFreeUrb (Xhc
, Urb
);
645 if (*TransferResult
== EFI_USB_NOERROR
) {
646 Status
= EFI_SUCCESS
;
647 } else if ((*TransferResult
== EFI_USB_ERR_STALL
) || (*TransferResult
== EFI_USB_ERR_BABBLE
)) {
648 RecoveryStatus
= XhcPeiRecoverHaltedEndpoint (Xhc
, Urb
);
649 if (EFI_ERROR (RecoveryStatus
)) {
650 DEBUG ((DEBUG_ERROR
, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
653 Status
= EFI_DEVICE_ERROR
;
654 XhcPeiFreeUrb (Xhc
, Urb
);
657 XhcPeiFreeUrb (Xhc
, Urb
);
663 // Unmap data before consume.
665 XhcPeiFreeUrb (Xhc
, Urb
);
668 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
669 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
670 // Hook Set_Config request from UsbBus as we need configure device endpoint.
672 if ((Request
->Request
== USB_REQ_GET_DESCRIPTOR
) &&
673 ((Request
->RequestType
== USB_REQUEST_TYPE (EfiUsbDataIn
, USB_REQ_TYPE_STANDARD
, USB_TARGET_DEVICE
)) ||
674 ((Request
->RequestType
== USB_REQUEST_TYPE (EfiUsbDataIn
, USB_REQ_TYPE_CLASS
, USB_TARGET_DEVICE
)))))
676 DescriptorType
= (UINT8
)(Request
->Value
>> 8);
677 if ((DescriptorType
== USB_DESC_TYPE_DEVICE
) && ((*DataLength
== sizeof (EFI_USB_DEVICE_DESCRIPTOR
)) || ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (*DataLength
== 8)))) {
678 ASSERT (Data
!= NULL
);
680 // Store a copy of device scriptor as hub device need this info to configure endpoint.
682 CopyMem (&Xhc
->UsbDevContext
[SlotId
].DevDesc
, Data
, *DataLength
);
683 if (Xhc
->UsbDevContext
[SlotId
].DevDesc
.BcdUSB
>= 0x0300) {
685 // If it's a usb3.0 device, then its max packet size is a 2^n.
687 MaxPacket0
= 1 << Xhc
->UsbDevContext
[SlotId
].DevDesc
.MaxPacketSize0
;
689 MaxPacket0
= Xhc
->UsbDevContext
[SlotId
].DevDesc
.MaxPacketSize0
;
692 Xhc
->UsbDevContext
[SlotId
].ConfDesc
= AllocateZeroPool (Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
* sizeof (EFI_USB_CONFIG_DESCRIPTOR
*));
693 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
== NULL
) {
694 Status
= EFI_OUT_OF_RESOURCES
;
698 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
699 Status
= XhcPeiEvaluateContext (Xhc
, SlotId
, MaxPacket0
);
701 Status
= XhcPeiEvaluateContext64 (Xhc
, SlotId
, MaxPacket0
);
703 } else if (DescriptorType
== USB_DESC_TYPE_CONFIG
) {
704 ASSERT (Data
!= NULL
);
705 if (*DataLength
== ((UINT16
*)Data
)[1]) {
707 // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.
709 Index
= (UINT8
)Request
->Value
;
710 ASSERT (Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
);
711 Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] = AllocateZeroPool (*DataLength
);
712 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] == NULL
) {
713 Status
= EFI_OUT_OF_RESOURCES
;
717 CopyMem (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
], Data
, *DataLength
);
719 } else if (((DescriptorType
== USB_DESC_TYPE_HUB
) ||
720 (DescriptorType
== USB_DESC_TYPE_HUB_SUPER_SPEED
)) && (*DataLength
> 2))
722 ASSERT (Data
!= NULL
);
723 HubDesc
= (EFI_USB_HUB_DESCRIPTOR
*)Data
;
724 ASSERT (HubDesc
->NumPorts
<= 15);
726 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
728 TTT
= (UINT8
)((HubDesc
->HubCharacter
& (BIT5
| BIT6
)) >> 5);
729 if (Xhc
->UsbDevContext
[SlotId
].DevDesc
.DeviceProtocol
== 2) {
731 // Don't support multi-TT feature for super speed hub now.
734 DEBUG ((DEBUG_ERROR
, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
739 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
740 Status
= XhcPeiConfigHubContext (Xhc
, SlotId
, HubDesc
->NumPorts
, TTT
, MTT
);
742 Status
= XhcPeiConfigHubContext64 (Xhc
, SlotId
, HubDesc
->NumPorts
, TTT
, MTT
);
745 } else if ((Request
->Request
== USB_REQ_SET_CONFIG
) &&
746 (Request
->RequestType
== USB_REQUEST_TYPE (EfiUsbNoData
, USB_REQ_TYPE_STANDARD
, USB_TARGET_DEVICE
)))
749 // Hook Set_Config request from UsbBus as we need configure device endpoint.
751 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
752 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]->ConfigurationValue
== (UINT8
)Request
->Value
) {
753 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
754 Status
= XhcPeiSetConfigCmd (Xhc
, SlotId
, DeviceSpeed
, Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
756 Status
= XhcPeiSetConfigCmd64 (Xhc
, SlotId
, DeviceSpeed
, Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
762 } else if ((Request
->Request
== USB_REQ_GET_STATUS
) &&
763 (Request
->RequestType
== USB_REQUEST_TYPE (EfiUsbDataIn
, USB_REQ_TYPE_CLASS
, USB_TARGET_OTHER
)))
765 ASSERT (Data
!= NULL
);
767 // Hook Get_Status request from UsbBus to keep track of the port status change.
769 State
= *(UINT32
*)Data
;
770 PortStatus
.PortStatus
= 0;
771 PortStatus
.PortChangeStatus
= 0;
773 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
775 // For super speed hub, its bit10~12 presents the attached device speed.
777 if ((State
& XHC_PORTSC_PS
) >> 10 == 0) {
778 PortStatus
.PortStatus
|= USB_PORT_STAT_SUPER_SPEED
;
782 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
784 if (XHC_BIT_IS_SET (State
, BIT9
)) {
785 PortStatus
.PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
786 } else if (XHC_BIT_IS_SET (State
, BIT10
)) {
787 PortStatus
.PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
792 // Convert the XHCI port/port change state to UEFI status
794 MapSize
= sizeof (mUsbHubPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
795 for (Index
= 0; Index
< MapSize
; Index
++) {
796 if (XHC_BIT_IS_SET (State
, mUsbHubPortStateMap
[Index
].HwState
)) {
797 PortStatus
.PortStatus
= (UINT16
)(PortStatus
.PortStatus
| mUsbHubPortStateMap
[Index
].UefiState
);
801 MapSize
= sizeof (mUsbHubPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
802 for (Index
= 0; Index
< MapSize
; Index
++) {
803 if (XHC_BIT_IS_SET (State
, mUsbHubPortChangeMap
[Index
].HwState
)) {
804 PortStatus
.PortChangeStatus
= (UINT16
)(PortStatus
.PortChangeStatus
| mUsbHubPortChangeMap
[Index
].UefiState
);
808 MapSize
= sizeof (mUsbHubClearPortChangeMap
) / sizeof (USB_CLEAR_PORT_MAP
);
810 for (Index
= 0; Index
< MapSize
; Index
++) {
811 if (XHC_BIT_IS_SET (State
, mUsbHubClearPortChangeMap
[Index
].HwState
)) {
812 ZeroMem (&ClearPortRequest
, sizeof (EFI_USB_DEVICE_REQUEST
));
813 ClearPortRequest
.RequestType
= USB_REQUEST_TYPE (EfiUsbNoData
, USB_REQ_TYPE_CLASS
, USB_TARGET_OTHER
);
814 ClearPortRequest
.Request
= (UINT8
)USB_REQ_CLEAR_FEATURE
;
815 ClearPortRequest
.Value
= mUsbHubClearPortChangeMap
[Index
].Selector
;
816 ClearPortRequest
.Index
= Request
->Index
;
817 ClearPortRequest
.Length
= 0;
819 XhcPeiControlTransfer (
836 XhcPeiPollPortStatusChange (Xhc
, Xhc
->UsbDevContext
[SlotId
].RouteString
, (UINT8
)Request
->Index
, &PortStatus
);
838 *(UINT32
*)Data
= *(UINT32
*)&PortStatus
;
843 if (EFI_ERROR (Status
)) {
844 DEBUG ((DEBUG_ERROR
, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
851 Submits bulk transfer to a bulk endpoint of a USB device.
853 @param PeiServices The pointer of EFI_PEI_SERVICES.
854 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
855 @param DeviceAddress Target device address.
856 @param EndPointAddress Endpoint number and its direction in bit 7.
857 @param DeviceSpeed Device speed, Low speed device doesn't support
859 @param MaximumPacketLength Maximum packet size the endpoint is capable of
860 sending or receiving.
861 @param Data Array of pointers to the buffers of data to transmit
862 from or receive into.
863 @param DataLength The lenght of the data buffer.
864 @param DataToggle On input, the initial data toggle for the transfer;
865 On output, it is updated to to next data toggle to use of
866 the subsequent bulk transfer.
867 @param TimeOut Indicates the maximum time, in millisecond, which the
868 transfer is allowed to complete.
869 If Timeout is 0, then the caller must wait for the function
870 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
871 @param Translator A pointr to the transaction translator data.
872 @param TransferResult A pointer to the detailed result information of the
875 @retval EFI_SUCCESS The transfer was completed successfully.
876 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
877 @retval EFI_INVALID_PARAMETER Parameters are invalid.
878 @retval EFI_TIMEOUT The transfer failed due to timeout.
879 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
885 IN EFI_PEI_SERVICES
**PeiServices
,
886 IN PEI_USB2_HOST_CONTROLLER_PPI
*This
,
887 IN UINT8 DeviceAddress
,
888 IN UINT8 EndPointAddress
,
889 IN UINT8 DeviceSpeed
,
890 IN UINTN MaximumPacketLength
,
891 IN OUT VOID
*Data
[EFI_USB_MAX_BULK_BUFFER_NUM
],
892 IN OUT UINTN
*DataLength
,
893 IN OUT UINT8
*DataToggle
,
895 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
896 OUT UINT32
*TransferResult
903 EFI_STATUS RecoveryStatus
;
906 // Validate the parameters
908 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
909 (Data
== NULL
) || (Data
[0] == NULL
) || (TransferResult
== NULL
))
911 return EFI_INVALID_PARAMETER
;
914 if ((*DataToggle
!= 0) && (*DataToggle
!= 1)) {
915 return EFI_INVALID_PARAMETER
;
918 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) ||
919 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
920 ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) && (MaximumPacketLength
> 512)) ||
921 ((DeviceSpeed
== EFI_USB_SPEED_SUPER
) && (MaximumPacketLength
> 1024)))
923 return EFI_INVALID_PARAMETER
;
926 Xhc
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This
);
928 *TransferResult
= EFI_USB_ERR_SYSTEM
;
929 Status
= EFI_DEVICE_ERROR
;
931 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
932 DEBUG ((DEBUG_ERROR
, "XhcPeiBulkTransfer: HC is halted or has system error\n"));
937 // Check if the device is still enabled before every transaction.
939 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, DeviceAddress
);
945 // Create a new URB, insert it into the asynchronous
946 // schedule list, then poll the execution status.
948 Urb
= XhcPeiCreateUrb (
963 DEBUG ((DEBUG_ERROR
, "XhcPeiBulkTransfer: failed to create URB\n"));
964 Status
= EFI_OUT_OF_RESOURCES
;
968 Status
= XhcPeiExecTransfer (Xhc
, FALSE
, Urb
, TimeOut
);
970 *TransferResult
= Urb
->Result
;
971 *DataLength
= Urb
->Completed
;
973 if (Status
== EFI_TIMEOUT
) {
975 // The transfer timed out. Abort the transfer by dequeueing of the TD.
977 RecoveryStatus
= XhcPeiDequeueTrbFromEndpoint (Xhc
, Urb
);
978 if (EFI_ERROR (RecoveryStatus
)) {
979 DEBUG ((DEBUG_ERROR
, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
982 if (*TransferResult
== EFI_USB_NOERROR
) {
983 Status
= EFI_SUCCESS
;
984 } else if ((*TransferResult
== EFI_USB_ERR_STALL
) || (*TransferResult
== EFI_USB_ERR_BABBLE
)) {
985 RecoveryStatus
= XhcPeiRecoverHaltedEndpoint (Xhc
, Urb
);
986 if (EFI_ERROR (RecoveryStatus
)) {
987 DEBUG ((DEBUG_ERROR
, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
990 Status
= EFI_DEVICE_ERROR
;
994 XhcPeiFreeUrb (Xhc
, Urb
);
998 if (EFI_ERROR (Status
)) {
999 DEBUG ((DEBUG_ERROR
, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1006 Retrieves the number of root hub ports.
1008 @param[in] PeiServices The pointer to the PEI Services Table.
1009 @param[in] This The pointer to this instance of the
1010 PEI_USB2_HOST_CONTROLLER_PPI.
1011 @param[out] PortNumber The pointer to the number of the root hub ports.
1013 @retval EFI_SUCCESS The port number was retrieved successfully.
1014 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
1019 XhcPeiGetRootHubPortNumber (
1020 IN EFI_PEI_SERVICES
**PeiServices
,
1021 IN PEI_USB2_HOST_CONTROLLER_PPI
*This
,
1022 OUT UINT8
*PortNumber
1025 PEI_XHC_DEV
*XhcDev
;
1027 XhcDev
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This
);
1029 if (PortNumber
== NULL
) {
1030 return EFI_INVALID_PARAMETER
;
1033 *PortNumber
= XhcDev
->HcSParams1
.Data
.MaxPorts
;
1034 DEBUG ((DEBUG_INFO
, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber
));
1039 Clears a feature for the specified root hub port.
1041 @param PeiServices The pointer of EFI_PEI_SERVICES.
1042 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1043 @param PortNumber Specifies the root hub port whose feature
1044 is requested to be cleared.
1045 @param PortFeature Indicates the feature selector associated with the
1046 feature clear request.
1048 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
1049 for the USB root hub port specified by PortNumber.
1050 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1055 XhcPeiClearRootHubPortFeature (
1056 IN EFI_PEI_SERVICES
**PeiServices
,
1057 IN PEI_USB2_HOST_CONTROLLER_PPI
*This
,
1058 IN UINT8 PortNumber
,
1059 IN EFI_USB_PORT_FEATURE PortFeature
1067 Xhc
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This
);
1068 Status
= EFI_SUCCESS
;
1070 if (PortNumber
>= Xhc
->HcSParams1
.Data
.MaxPorts
) {
1071 Status
= EFI_INVALID_PARAMETER
;
1075 Offset
= (UINT32
)(XHC_PORTSC_OFFSET
+ (0x10 * PortNumber
));
1076 State
= XhcPeiReadOpReg (Xhc
, Offset
);
1077 DEBUG ((DEBUG_INFO
, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber
, State
));
1080 // Mask off the port status change bits, these bits are
1083 State
&= ~(BIT1
| BIT17
| BIT18
| BIT19
| BIT20
| BIT21
| BIT22
| BIT23
);
1085 switch (PortFeature
) {
1086 case EfiUsbPortEnable
:
1088 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1089 // A port may be disabled by software writing a '1' to this flag.
1091 State
|= XHC_PORTSC_PED
;
1092 State
&= ~XHC_PORTSC_RESET
;
1093 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1096 case EfiUsbPortSuspend
:
1097 State
|= XHC_PORTSC_LWS
;
1098 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1099 State
&= ~XHC_PORTSC_PLS
;
1100 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1103 case EfiUsbPortReset
:
1105 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
1106 // Register bits indicate status when read, a clear bit may be set by
1107 // writing a '1'. Writing a '0' to RW1S bits has no effect.
1111 case EfiUsbPortPower
:
1112 if (Xhc
->HcCParams
.Data
.Ppc
) {
1114 // Port Power Control supported
1116 State
&= ~XHC_PORTSC_PP
;
1117 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1122 case EfiUsbPortOwner
:
1124 // XHCI root hub port don't has the owner bit, ignore the operation
1128 case EfiUsbPortConnectChange
:
1130 // Clear connect status change
1132 State
|= XHC_PORTSC_CSC
;
1133 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1136 case EfiUsbPortEnableChange
:
1138 // Clear enable status change
1140 State
|= XHC_PORTSC_PEC
;
1141 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1144 case EfiUsbPortOverCurrentChange
:
1146 // Clear PortOverCurrent change
1148 State
|= XHC_PORTSC_OCC
;
1149 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1152 case EfiUsbPortResetChange
:
1154 // Clear Port Reset change
1156 State
|= XHC_PORTSC_PRC
;
1157 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1160 case EfiUsbPortSuspendChange
:
1162 // Not supported or not related operation
1167 Status
= EFI_INVALID_PARAMETER
;
1172 DEBUG ((DEBUG_INFO
, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature
, Status
));
1177 Sets a feature for the specified root hub port.
1179 @param PeiServices The pointer of EFI_PEI_SERVICES
1180 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI
1181 @param PortNumber Root hub port to set.
1182 @param PortFeature Feature to set.
1184 @retval EFI_SUCCESS The feature specified by PortFeature was set.
1185 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1186 @retval EFI_TIMEOUT The time out occurred.
1191 XhcPeiSetRootHubPortFeature (
1192 IN EFI_PEI_SERVICES
**PeiServices
,
1193 IN PEI_USB2_HOST_CONTROLLER_PPI
*This
,
1194 IN UINT8 PortNumber
,
1195 IN EFI_USB_PORT_FEATURE PortFeature
1203 Xhc
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This
);
1204 Status
= EFI_SUCCESS
;
1206 if (PortNumber
>= Xhc
->HcSParams1
.Data
.MaxPorts
) {
1207 Status
= EFI_INVALID_PARAMETER
;
1211 Offset
= (UINT32
)(XHC_PORTSC_OFFSET
+ (0x10 * PortNumber
));
1212 State
= XhcPeiReadOpReg (Xhc
, Offset
);
1213 DEBUG ((DEBUG_INFO
, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber
, State
));
1216 // Mask off the port status change bits, these bits are
1219 State
&= ~(BIT1
| BIT17
| BIT18
| BIT19
| BIT20
| BIT21
| BIT22
| BIT23
);
1221 switch (PortFeature
) {
1222 case EfiUsbPortEnable
:
1224 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
1225 // A port may be disabled by software writing a '1' to this flag.
1229 case EfiUsbPortSuspend
:
1230 State
|= XHC_PORTSC_LWS
;
1231 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1232 State
&= ~XHC_PORTSC_PLS
;
1234 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1237 case EfiUsbPortReset
:
1239 // Make sure Host Controller not halt before reset it
1241 if (XhcPeiIsHalt (Xhc
)) {
1242 Status
= XhcPeiRunHC (Xhc
, XHC_GENERIC_TIMEOUT
);
1243 if (EFI_ERROR (Status
)) {
1249 // 4.3.1 Resetting a Root Hub Port
1250 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
1251 // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)
1252 // bit in the PORTSC field is set to '1'.
1254 State
|= XHC_PORTSC_RESET
;
1255 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1256 XhcPeiWaitOpRegBit (Xhc
, Offset
, XHC_PORTSC_PRC
, TRUE
, XHC_GENERIC_TIMEOUT
);
1259 case EfiUsbPortPower
:
1260 if (Xhc
->HcCParams
.Data
.Ppc
) {
1262 // Port Power Control supported
1264 State
|= XHC_PORTSC_PP
;
1265 XhcPeiWriteOpReg (Xhc
, Offset
, State
);
1270 case EfiUsbPortOwner
:
1272 // XHCI root hub port don't has the owner bit, ignore the operation
1277 Status
= EFI_INVALID_PARAMETER
;
1281 DEBUG ((DEBUG_INFO
, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature
, Status
));
1286 Retrieves the current status of a USB root hub port.
1288 @param PeiServices The pointer of EFI_PEI_SERVICES.
1289 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
1290 @param PortNumber The root hub port to retrieve the state from.
1291 @param PortStatus Variable to receive the port state.
1293 @retval EFI_SUCCESS The status of the USB root hub port specified.
1294 by PortNumber was returned in PortStatus.
1295 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
1300 XhcPeiGetRootHubPortStatus (
1301 IN EFI_PEI_SERVICES
**PeiServices
,
1302 IN PEI_USB2_HOST_CONTROLLER_PPI
*This
,
1303 IN UINT8 PortNumber
,
1304 OUT EFI_USB_PORT_STATUS
*PortStatus
1312 USB_DEV_ROUTE ParentRouteChart
;
1314 if (PortStatus
== NULL
) {
1315 return EFI_INVALID_PARAMETER
;
1318 Xhc
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This
);
1320 if (PortNumber
>= Xhc
->HcSParams1
.Data
.MaxPorts
) {
1321 return EFI_INVALID_PARAMETER
;
1325 // Clear port status.
1327 PortStatus
->PortStatus
= 0;
1328 PortStatus
->PortChangeStatus
= 0;
1330 Offset
= (UINT32
)(XHC_PORTSC_OFFSET
+ (0x10 * PortNumber
));
1331 State
= XhcPeiReadOpReg (Xhc
, Offset
);
1332 DEBUG ((DEBUG_INFO
, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber
, State
));
1335 // According to XHCI 1.1 spec November 2017,
1336 // bit 10~13 of the root port status register identifies the speed of the attached device.
1338 switch ((State
& XHC_PORTSC_PS
) >> 10) {
1340 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
1344 PortStatus
->PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
1349 PortStatus
->PortStatus
|= USB_PORT_STAT_SUPER_SPEED
;
1357 // Convert the XHCI port/port change state to UEFI status
1359 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
1361 for (Index
= 0; Index
< MapSize
; Index
++) {
1362 if (XHC_BIT_IS_SET (State
, mUsbPortStateMap
[Index
].HwState
)) {
1363 PortStatus
->PortStatus
= (UINT16
)(PortStatus
->PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
1368 // Bit5~8 reflects its current link state.
1370 if ((State
& XHC_PORTSC_PLS
) >> 5 == 3) {
1371 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
1374 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
1376 for (Index
= 0; Index
< MapSize
; Index
++) {
1377 if (XHC_BIT_IS_SET (State
, mUsbPortChangeMap
[Index
].HwState
)) {
1378 PortStatus
->PortChangeStatus
= (UINT16
)(PortStatus
->PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
1382 MapSize
= sizeof (mUsbClearPortChangeMap
) / sizeof (USB_CLEAR_PORT_MAP
);
1384 for (Index
= 0; Index
< MapSize
; Index
++) {
1385 if (XHC_BIT_IS_SET (State
, mUsbClearPortChangeMap
[Index
].HwState
)) {
1386 XhcPeiClearRootHubPortFeature (PeiServices
, This
, PortNumber
, (EFI_USB_PORT_FEATURE
)mUsbClearPortChangeMap
[Index
].Selector
);
1391 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
1392 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
1394 ParentRouteChart
.Dword
= 0;
1395 XhcPeiPollPortStatusChange (Xhc
, ParentRouteChart
, PortNumber
, PortStatus
);
1397 DEBUG ((DEBUG_INFO
, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus
->PortChangeStatus
, PortStatus
->PortStatus
));
1402 One notified function to stop the Host Controller at the end of PEI
1404 @param[in] PeiServices Pointer to PEI Services Table.
1405 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
1406 caused this function to execute.
1407 @param[in] Ppi Pointer to the PPI data associated with this function.
1409 @retval EFI_SUCCESS The function completes successfully
1415 IN EFI_PEI_SERVICES
**PeiServices
,
1416 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
1422 Xhc
= PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor
);
1424 XhcPeiHaltHC (Xhc
, XHC_GENERIC_TIMEOUT
);
1426 XhcPeiFreeSched (Xhc
);
1432 @param FileHandle Handle of the file being invoked.
1433 @param PeiServices Describes the list of possible PEI Services.
1435 @retval EFI_SUCCESS PPI successfully installed.
1441 IN EFI_PEI_FILE_HANDLE FileHandle
,
1442 IN CONST EFI_PEI_SERVICES
**PeiServices
1445 PEI_USB_CONTROLLER_PPI
*UsbControllerPpi
;
1448 UINTN ControllerType
;
1451 PEI_XHC_DEV
*XhcDev
;
1452 EFI_PHYSICAL_ADDRESS TempPtr
;
1456 // Shadow this PEIM to run from memory.
1458 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
1462 Status
= PeiServicesLocatePpi (
1463 &gPeiUsbControllerPpiGuid
,
1466 (VOID
**)&UsbControllerPpi
1468 if (EFI_ERROR (Status
)) {
1469 return EFI_UNSUPPORTED
;
1476 Status
= UsbControllerPpi
->GetUsbController (
1477 (EFI_PEI_SERVICES
**)PeiServices
,
1484 // When status is error, it means no controller is found.
1486 if (EFI_ERROR (Status
)) {
1491 // This PEIM is for XHC type controller.
1493 if (ControllerType
!= PEI_XHCI_CONTROLLER
) {
1498 MemPages
= EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV
));
1499 Status
= PeiServicesAllocatePages (
1500 EfiBootServicesData
,
1504 if (EFI_ERROR (Status
)) {
1505 return EFI_OUT_OF_RESOURCES
;
1508 ZeroMem ((VOID
*)(UINTN
)TempPtr
, EFI_PAGES_TO_SIZE (MemPages
));
1509 XhcDev
= (PEI_XHC_DEV
*)((UINTN
)TempPtr
);
1511 XhcDev
->Signature
= USB_XHC_DEV_SIGNATURE
;
1512 XhcDev
->UsbHostControllerBaseAddress
= (UINT32
)BaseAddress
;
1513 XhcDev
->CapLength
= (UINT8
)(XhcPeiReadCapRegister (XhcDev
, XHC_CAPLENGTH_OFFSET
) & 0x0FF);
1514 XhcDev
->HcSParams1
.Dword
= XhcPeiReadCapRegister (XhcDev
, XHC_HCSPARAMS1_OFFSET
);
1515 XhcDev
->HcSParams2
.Dword
= XhcPeiReadCapRegister (XhcDev
, XHC_HCSPARAMS2_OFFSET
);
1516 XhcDev
->HcCParams
.Dword
= XhcPeiReadCapRegister (XhcDev
, XHC_HCCPARAMS_OFFSET
);
1517 XhcDev
->DBOff
= XhcPeiReadCapRegister (XhcDev
, XHC_DBOFF_OFFSET
);
1518 XhcDev
->RTSOff
= XhcPeiReadCapRegister (XhcDev
, XHC_RTSOFF_OFFSET
);
1521 // This PageSize field defines the page size supported by the xHC implementation.
1522 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1523 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1525 PageSize
= XhcPeiReadOpReg (XhcDev
, XHC_PAGESIZE_OFFSET
) & XHC_PAGESIZE_MASK
;
1526 XhcDev
->PageSize
= 1 << (HighBitSet32 (PageSize
) + 12);
1528 DEBUG ((DEBUG_INFO
, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev
->UsbHostControllerBaseAddress
));
1529 DEBUG ((DEBUG_INFO
, "XhciPei: CapLength: %x\n", XhcDev
->CapLength
));
1530 DEBUG ((DEBUG_INFO
, "XhciPei: HcSParams1: %x\n", XhcDev
->HcSParams1
.Dword
));
1531 DEBUG ((DEBUG_INFO
, "XhciPei: HcSParams2: %x\n", XhcDev
->HcSParams2
.Dword
));
1532 DEBUG ((DEBUG_INFO
, "XhciPei: HcCParams: %x\n", XhcDev
->HcCParams
.Dword
));
1533 DEBUG ((DEBUG_INFO
, "XhciPei: DBOff: %x\n", XhcDev
->DBOff
));
1534 DEBUG ((DEBUG_INFO
, "XhciPei: RTSOff: %x\n", XhcDev
->RTSOff
));
1535 DEBUG ((DEBUG_INFO
, "XhciPei: PageSize: %x\n", XhcDev
->PageSize
));
1537 XhcPeiResetHC (XhcDev
, XHC_RESET_TIMEOUT
);
1538 ASSERT (XhcPeiIsHalt (XhcDev
));
1541 // Initialize the schedule
1543 XhcPeiInitSched (XhcDev
);
1546 // Start the Host Controller
1548 XhcPeiRunHC (XhcDev
, XHC_GENERIC_TIMEOUT
);
1551 // Wait for root port state stable
1553 MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE
);
1555 XhcDev
->Usb2HostControllerPpi
.ControlTransfer
= XhcPeiControlTransfer
;
1556 XhcDev
->Usb2HostControllerPpi
.BulkTransfer
= XhcPeiBulkTransfer
;
1557 XhcDev
->Usb2HostControllerPpi
.GetRootHubPortNumber
= XhcPeiGetRootHubPortNumber
;
1558 XhcDev
->Usb2HostControllerPpi
.GetRootHubPortStatus
= XhcPeiGetRootHubPortStatus
;
1559 XhcDev
->Usb2HostControllerPpi
.SetRootHubPortFeature
= XhcPeiSetRootHubPortFeature
;
1560 XhcDev
->Usb2HostControllerPpi
.ClearRootHubPortFeature
= XhcPeiClearRootHubPortFeature
;
1562 XhcDev
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
1563 XhcDev
->PpiDescriptor
.Guid
= &gPeiUsb2HostControllerPpiGuid
;
1564 XhcDev
->PpiDescriptor
.Ppi
= &XhcDev
->Usb2HostControllerPpi
;
1566 XhcDev
->EndOfPeiNotifyList
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
1567 XhcDev
->EndOfPeiNotifyList
.Guid
= &gEfiEndOfPeiSignalPpiGuid
;
1568 XhcDev
->EndOfPeiNotifyList
.Notify
= XhcEndOfPei
;
1570 PeiServicesInstallPpi (&XhcDev
->PpiDescriptor
);
1571 PeiServicesNotifyPpi (&XhcDev
->EndOfPeiNotifyList
);