MdeModulePkg XhciPei/UsbBusPei: Add XHCI recovery support.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15611 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
Usb Hub Request Support In PEI Phase
|
||||
|
||||
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions
|
||||
@@ -319,6 +319,139 @@ PeiGetHubDescriptor (
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Get a given SuperSpeed hub descriptor.
|
||||
|
||||
@param PeiServices General-purpose services that are available to every PEIM.
|
||||
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
|
||||
@param HubDescriptor Caller allocated buffer to store the hub descriptor if
|
||||
successfully returned.
|
||||
|
||||
@retval EFI_SUCCESS Hub descriptor is obtained successfully.
|
||||
@retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
|
||||
@retval Others Other failure occurs.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
PeiGetSuperSpeedHubDesc (
|
||||
IN EFI_PEI_SERVICES **PeiServices,
|
||||
IN PEI_USB_IO_PPI *UsbIoPpi,
|
||||
OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
|
||||
)
|
||||
{
|
||||
EFI_USB_DEVICE_REQUEST DevReq;
|
||||
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
|
||||
|
||||
//
|
||||
// Fill Device request packet
|
||||
//
|
||||
DevReq.RequestType = USB_RT_HUB | 0x80;
|
||||
DevReq.Request = USB_HUB_GET_DESCRIPTOR;
|
||||
DevReq.Value = USB_DT_SUPERSPEED_HUB << 8;
|
||||
DevReq.Length = 12;
|
||||
|
||||
return UsbIoPpi->UsbControlTransfer (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
&DevReq,
|
||||
EfiUsbDataIn,
|
||||
PcdGet32 (PcdUsbTransferTimeoutValue),
|
||||
HubDescriptor,
|
||||
12
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Read the whole usb hub descriptor. It is necessary
|
||||
to do it in two steps because hub descriptor is of
|
||||
variable length.
|
||||
|
||||
@param PeiServices General-purpose services that are available to every PEIM.
|
||||
@param PeiUsbDevice Indicates the hub controller device.
|
||||
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
|
||||
@param HubDescriptor Caller allocated buffer to store the hub descriptor if
|
||||
successfully returned.
|
||||
|
||||
@retval EFI_SUCCESS Hub descriptor is obtained successfully.
|
||||
@retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
|
||||
@retval Others Other failure occurs.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
PeiUsbHubReadDesc (
|
||||
IN EFI_PEI_SERVICES **PeiServices,
|
||||
IN PEI_USB_DEVICE *PeiUsbDevice,
|
||||
IN PEI_USB_IO_PPI *UsbIoPpi,
|
||||
OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
|
||||
//
|
||||
// Get the super speed hub descriptor
|
||||
//
|
||||
Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor);
|
||||
} else {
|
||||
|
||||
//
|
||||
// First get the hub descriptor length
|
||||
//
|
||||
Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the whole hub descriptor
|
||||
//
|
||||
Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
USB hub control transfer to set the hub depth.
|
||||
|
||||
@param PeiServices General-purpose services that are available to every PEIM.
|
||||
@param PeiUsbDevice Indicates the hub controller device.
|
||||
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
|
||||
|
||||
@retval EFI_SUCCESS Depth of the hub is set.
|
||||
@retval Others Failed to set the depth.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
PeiUsbHubCtrlSetHubDepth (
|
||||
IN EFI_PEI_SERVICES **PeiServices,
|
||||
IN PEI_USB_DEVICE *PeiUsbDevice,
|
||||
IN PEI_USB_IO_PPI *UsbIoPpi
|
||||
)
|
||||
{
|
||||
EFI_USB_DEVICE_REQUEST DevReq;
|
||||
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
|
||||
|
||||
//
|
||||
// Fill Device request packet
|
||||
//
|
||||
DevReq.RequestType = USB_RT_HUB;
|
||||
DevReq.Request = USB_HUB_REQ_SET_DEPTH;
|
||||
DevReq.Value = PeiUsbDevice->Tier;
|
||||
DevReq.Length = 0;
|
||||
|
||||
return UsbIoPpi->UsbControlTransfer (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
&DevReq,
|
||||
EfiUsbNoData,
|
||||
PcdGet32 (PcdUsbTransferTimeoutValue),
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Configure a given hub.
|
||||
|
||||
@@ -339,32 +472,18 @@ PeiDoHubConfig (
|
||||
EFI_STATUS Status;
|
||||
EFI_USB_HUB_STATUS HubStatus;
|
||||
UINTN Index;
|
||||
UINT32 PortStatus;
|
||||
PEI_USB_IO_PPI *UsbIoPpi;
|
||||
|
||||
ZeroMem (&HubDescriptor, sizeof (HubDescriptor));
|
||||
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
|
||||
|
||||
//
|
||||
// First get the hub descriptor length
|
||||
// Get the hub descriptor
|
||||
//
|
||||
Status = PeiGetHubDescriptor (
|
||||
Status = PeiUsbHubReadDesc (
|
||||
PeiServices,
|
||||
PeiUsbDevice,
|
||||
UsbIoPpi,
|
||||
2,
|
||||
&HubDescriptor
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
//
|
||||
// First get the whole descriptor, then
|
||||
// get the number of hub ports
|
||||
//
|
||||
Status = PeiGetHubDescriptor (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
HubDescriptor.Length,
|
||||
&HubDescriptor
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
@@ -373,74 +492,66 @@ PeiDoHubConfig (
|
||||
|
||||
PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;
|
||||
|
||||
Status = PeiHubGetHubStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT32 *) &HubStatus
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
//
|
||||
// Get all hub ports status
|
||||
//
|
||||
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
|
||||
|
||||
Status = PeiHubGetPortStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
&PortStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Power all the hub ports
|
||||
//
|
||||
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
|
||||
Status = PeiHubSetPortFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
EfiUsbPortPower
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Clear Hub Status Change
|
||||
//
|
||||
Status = PeiHubGetHubStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT32 *) &HubStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
|
||||
DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
|
||||
PeiUsbHubCtrlSetHubDepth (
|
||||
PeiServices,
|
||||
PeiUsbDevice,
|
||||
UsbIoPpi
|
||||
);
|
||||
} else {
|
||||
//
|
||||
// Hub power supply change happens
|
||||
// Power all the hub ports
|
||||
//
|
||||
if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
|
||||
PeiHubClearHubFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
C_HUB_LOCAL_POWER
|
||||
);
|
||||
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
|
||||
Status = PeiHubSetPortFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
EfiUsbPortPower
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor.PwrOn2PwrGood));
|
||||
if (HubDescriptor.PwrOn2PwrGood > 0) {
|
||||
MicroSecondDelay (HubDescriptor.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
|
||||
}
|
||||
|
||||
//
|
||||
// Hub change overcurrent happens
|
||||
// Clear Hub Status Change
|
||||
//
|
||||
if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
|
||||
PeiHubClearHubFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
C_HUB_OVER_CURRENT
|
||||
);
|
||||
Status = PeiHubGetHubStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT32 *) &HubStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
} else {
|
||||
//
|
||||
// Hub power supply change happens
|
||||
//
|
||||
if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
|
||||
PeiHubClearHubFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
C_HUB_LOCAL_POWER
|
||||
);
|
||||
}
|
||||
//
|
||||
// Hub change overcurrent happens
|
||||
//
|
||||
if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
|
||||
PeiHubClearHubFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
C_HUB_OVER_CURRENT
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,10 +573,10 @@ PeiResetHubPort (
|
||||
IN UINT8 PortNum
|
||||
)
|
||||
{
|
||||
UINT8 Try;
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
EFI_USB_PORT_STATUS HubPortStatus;
|
||||
|
||||
|
||||
MicroSecondDelay (100 * 1000);
|
||||
|
||||
//
|
||||
@@ -478,27 +589,49 @@ PeiResetHubPort (
|
||||
EfiUsbPortReset
|
||||
);
|
||||
|
||||
Try = 10;
|
||||
do {
|
||||
PeiHubGetPortStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
PortNum,
|
||||
(UINT32 *) &HubPortStatus
|
||||
);
|
||||
|
||||
MicroSecondDelay (2 * 1000);
|
||||
Try -= 1;
|
||||
} while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);
|
||||
//
|
||||
// Drive the reset signal for worst 20ms. Check USB 2.0 Spec
|
||||
// section 7.1.7.5 for timing requirements.
|
||||
//
|
||||
MicroSecondDelay (USB_SET_PORT_RESET_STALL);
|
||||
|
||||
//
|
||||
// clear reset root port
|
||||
// Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
|
||||
//
|
||||
ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
|
||||
|
||||
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
|
||||
Status = PeiHubGetPortStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
PortNum,
|
||||
(UINT32 *) &HubPortStatus
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
|
||||
}
|
||||
|
||||
if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
|
||||
DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// clear reset change root port
|
||||
//
|
||||
PeiHubClearPortFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
PortNum,
|
||||
EfiUsbPortReset
|
||||
EfiUsbPortResetChange
|
||||
);
|
||||
|
||||
MicroSecondDelay (1 * 1000);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
Constants definitions for Usb Hub Peim
|
||||
|
||||
Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions
|
||||
@@ -80,6 +80,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
|
||||
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
|
||||
|
||||
#define USB_HUB_REQ_SET_DEPTH 12
|
||||
|
||||
#define MAXBYTES 8
|
||||
#pragma pack(1)
|
||||
//
|
||||
|
@@ -221,26 +221,24 @@ IsPortConnect (
|
||||
}
|
||||
|
||||
/**
|
||||
Judge if the port is connected with a low-speed usb device or not.
|
||||
Get device speed according to port status.
|
||||
|
||||
@param PortStatus The usb port status gotten.
|
||||
@param PortStatus The usb port status gotten.
|
||||
|
||||
@retval TRUE A low-speed usb device is connected with the port.
|
||||
@retval FALSE No low-speed usb device is connected with the port.
|
||||
@return Device speed value.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
IsPortLowSpeedDeviceAttached (
|
||||
IN UINT16 PortStatus
|
||||
PeiUsbGetDeviceSpeed (
|
||||
IN UINT16 PortStatus
|
||||
)
|
||||
{
|
||||
//
|
||||
// return the bit 9 value of PortStatus
|
||||
//
|
||||
if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
|
||||
return EFI_USB_SPEED_LOW;
|
||||
} else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){
|
||||
return EFI_USB_SPEED_HIGH;
|
||||
} else if ((PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
|
||||
return EFI_USB_SPEED_SUPER;
|
||||
} else {
|
||||
return EFI_USB_SPEED_FULL;
|
||||
}
|
||||
|
@@ -70,6 +70,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
#define USB_DT_HUB 0x29
|
||||
#define USB_DT_SUPERSPEED_HUB 0x2A
|
||||
#define USB_DT_HID 0x21
|
||||
|
||||
//
|
||||
@@ -202,17 +203,16 @@ IsPortConnect (
|
||||
);
|
||||
|
||||
/**
|
||||
Judge if the port is connected with a low-speed usb device or not.
|
||||
Get device speed according to port status.
|
||||
|
||||
@param PortStatus The usb port status gotten.
|
||||
@param PortStatus The usb port status gotten.
|
||||
|
||||
@retval TRUE A low-speed usb device is connected with the port.
|
||||
@retval FALSE No low-speed usb device is connected with the port.
|
||||
@return Device speed value.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
IsPortLowSpeedDeviceAttached (
|
||||
IN UINT16 PortStatus
|
||||
PeiUsbGetDeviceSpeed (
|
||||
IN UINT16 PortStatus
|
||||
);
|
||||
|
||||
/**
|
||||
|
@@ -105,7 +105,7 @@ PeiUsbControlTransfer (
|
||||
PeiUsbDev->UsbHcPpi,
|
||||
PeiUsbDev->DeviceAddress,
|
||||
PeiUsbDev->DeviceSpeed,
|
||||
PeiUsbDev->MaxPacketSize0,
|
||||
(UINT8) PeiUsbDev->MaxPacketSize0,
|
||||
Request,
|
||||
Direction,
|
||||
Data,
|
||||
@@ -126,6 +126,7 @@ PeiUsbControlTransfer (
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
@@ -238,6 +239,7 @@ PeiUsbBulkTransfer (
|
||||
PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
|
||||
}
|
||||
|
||||
DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@@ -228,6 +228,8 @@ PeiHubEnumeration (
|
||||
|
||||
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
|
||||
|
||||
DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));
|
||||
|
||||
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
|
||||
|
||||
Status = PeiHubGetPortStatus (
|
||||
@@ -241,25 +243,14 @@ PeiHubEnumeration (
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsPortConnectChange (PortStatus.PortChangeStatus)) {
|
||||
PeiHubClearPortFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
EfiUsbPortConnectChange
|
||||
);
|
||||
|
||||
MicroSecondDelay (100 * 1000);
|
||||
|
||||
DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
|
||||
//
|
||||
// Only handle connection/enable/overcurrent/reset change.
|
||||
//
|
||||
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
|
||||
continue;
|
||||
} else {
|
||||
if (IsPortConnect (PortStatus.PortStatus)) {
|
||||
|
||||
PeiHubGetPortStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
(UINT32 *) &PortStatus
|
||||
);
|
||||
|
||||
//
|
||||
// Begin to deal with the new device
|
||||
//
|
||||
@@ -294,19 +285,44 @@ PeiHubEnumeration (
|
||||
NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
|
||||
NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;
|
||||
NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;
|
||||
NewPeiUsbDevice->Tier = (UINT8) (PeiUsbDevice->Tier + 1);
|
||||
NewPeiUsbDevice->IsHub = 0x0;
|
||||
NewPeiUsbDevice->DownStreamPortNo = 0x0;
|
||||
|
||||
PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
|
||||
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
|
||||
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
|
||||
//
|
||||
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
|
||||
//
|
||||
PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
|
||||
|
||||
PeiHubGetPortStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
(UINT32 *) &PortStatus
|
||||
);
|
||||
} else {
|
||||
PeiHubClearPortFeature (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
EfiUsbPortResetChange
|
||||
);
|
||||
}
|
||||
|
||||
PeiHubGetPortStatus (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
(UINT8) (Index + 1),
|
||||
(UINT32 *) &PortStatus
|
||||
);
|
||||
NewPeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
|
||||
DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
|
||||
|
||||
NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);
|
||||
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
|
||||
NewPeiUsbDevice->MaxPacketSize0 = 512;
|
||||
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
|
||||
NewPeiUsbDevice->MaxPacketSize0 = 64;
|
||||
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
|
||||
NewPeiUsbDevice->MaxPacketSize0 = 8;
|
||||
} else {
|
||||
NewPeiUsbDevice->MaxPacketSize0 = 8;
|
||||
}
|
||||
|
||||
if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
|
||||
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {
|
||||
@@ -330,6 +346,7 @@ PeiHubEnumeration (
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));
|
||||
|
||||
Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
|
||||
|
||||
@@ -435,6 +452,8 @@ PeiUsbEnumeration (
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
|
||||
|
||||
for (Index = 0; Index < NumOfRootPort; Index++) {
|
||||
//
|
||||
// First get root port status to detect changes happen
|
||||
@@ -454,48 +473,14 @@ PeiUsbEnumeration (
|
||||
&PortStatus
|
||||
);
|
||||
}
|
||||
DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));
|
||||
if (IsPortConnectChange (PortStatus.PortChangeStatus)) {
|
||||
//
|
||||
// Changes happen, first clear this change status
|
||||
//
|
||||
if (Usb2HcPpi != NULL) {
|
||||
Usb2HcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
(UINT8) Index,
|
||||
EfiUsbPortConnectChange
|
||||
);
|
||||
} else {
|
||||
UsbHcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
(UINT8) Index,
|
||||
EfiUsbPortConnectChange
|
||||
);
|
||||
}
|
||||
MicroSecondDelay (100 * 1000);
|
||||
|
||||
DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
|
||||
//
|
||||
// Only handle connection/enable/overcurrent/reset change.
|
||||
//
|
||||
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
|
||||
continue;
|
||||
} else {
|
||||
if (IsPortConnect (PortStatus.PortStatus)) {
|
||||
if (Usb2HcPpi != NULL) {
|
||||
Usb2HcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
(UINT8) Index,
|
||||
&PortStatus
|
||||
);
|
||||
} else {
|
||||
UsbHcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
(UINT8) Index,
|
||||
&PortStatus
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Connect change happen
|
||||
//
|
||||
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
|
||||
Status = PeiServicesAllocatePages (
|
||||
EfiBootServicesCode,
|
||||
@@ -530,33 +515,65 @@ PeiUsbEnumeration (
|
||||
PeiUsbDevice->IsHub = 0x0;
|
||||
PeiUsbDevice->DownStreamPortNo = 0x0;
|
||||
|
||||
ResetRootPort (
|
||||
PeiServices,
|
||||
PeiUsbDevice->UsbHcPpi,
|
||||
PeiUsbDevice->Usb2HcPpi,
|
||||
Index,
|
||||
0
|
||||
);
|
||||
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
|
||||
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
|
||||
//
|
||||
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
|
||||
//
|
||||
ResetRootPort (
|
||||
PeiServices,
|
||||
PeiUsbDevice->UsbHcPpi,
|
||||
PeiUsbDevice->Usb2HcPpi,
|
||||
Index,
|
||||
0
|
||||
);
|
||||
|
||||
if (Usb2HcPpi != NULL) {
|
||||
Usb2HcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
(UINT8) Index,
|
||||
&PortStatus
|
||||
);
|
||||
if (Usb2HcPpi != NULL) {
|
||||
Usb2HcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
(UINT8) Index,
|
||||
&PortStatus
|
||||
);
|
||||
} else {
|
||||
UsbHcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
(UINT8) Index,
|
||||
&PortStatus
|
||||
);
|
||||
}
|
||||
} else {
|
||||
UsbHcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
(UINT8) Index,
|
||||
&PortStatus
|
||||
);
|
||||
if (Usb2HcPpi != NULL) {
|
||||
Usb2HcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
(UINT8) Index,
|
||||
EfiUsbPortResetChange
|
||||
);
|
||||
} else {
|
||||
UsbHcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
(UINT8) Index,
|
||||
EfiUsbPortResetChange
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);
|
||||
PeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
|
||||
DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
|
||||
|
||||
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
|
||||
PeiUsbDevice->MaxPacketSize0 = 512;
|
||||
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
|
||||
PeiUsbDevice->MaxPacketSize0 = 64;
|
||||
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
|
||||
PeiUsbDevice->MaxPacketSize0 = 8;
|
||||
} else {
|
||||
PeiUsbDevice->MaxPacketSize0 = 8;
|
||||
}
|
||||
|
||||
//
|
||||
// Configure that Usb Device
|
||||
//
|
||||
@@ -570,7 +587,7 @@ PeiUsbEnumeration (
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));
|
||||
DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
|
||||
|
||||
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
|
||||
|
||||
@@ -665,9 +682,6 @@ PeiConfigureUsbDevice (
|
||||
//
|
||||
|
||||
for (Retry = 0; Retry < 3; Retry ++) {
|
||||
|
||||
PeiUsbDevice->MaxPacketSize0 = 8;
|
||||
|
||||
Status = PeiUsbGetDescriptor (
|
||||
PeiServices,
|
||||
UsbIoPpi,
|
||||
@@ -678,17 +692,21 @@ PeiConfigureUsbDevice (
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));
|
||||
DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Retry == 3) {
|
||||
DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));
|
||||
DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
|
||||
if ((DeviceDescriptor.BcdUSB == 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {
|
||||
PeiUsbDevice->MaxPacketSize0 = 1 << 9;
|
||||
} else {
|
||||
PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
|
||||
}
|
||||
|
||||
(*DeviceAddress) ++;
|
||||
|
||||
@@ -699,7 +717,7 @@ PeiConfigureUsbDevice (
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));
|
||||
DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
@@ -995,6 +1013,8 @@ ResetRootPort (
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
EFI_USB_PORT_STATUS PortStatus;
|
||||
|
||||
|
||||
if (Usb2HcPpi != NULL) {
|
||||
@@ -1015,8 +1035,12 @@ ResetRootPort (
|
||||
return;
|
||||
}
|
||||
|
||||
MicroSecondDelay (200 * 1000);
|
||||
|
||||
//
|
||||
// Drive the reset signal for at least 50ms. Check USB 2.0 Spec
|
||||
// section 7.1.7.5 for timing requirements.
|
||||
//
|
||||
MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
|
||||
|
||||
//
|
||||
// clear reset root port
|
||||
//
|
||||
@@ -1031,9 +1055,45 @@ ResetRootPort (
|
||||
DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
MicroSecondDelay (1 * 1000);
|
||||
|
||||
|
||||
MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
|
||||
|
||||
//
|
||||
// USB host controller won't clear the RESET bit until
|
||||
// reset is actually finished.
|
||||
//
|
||||
ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
|
||||
|
||||
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
|
||||
Status = Usb2HcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
PortNum,
|
||||
&PortStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
|
||||
}
|
||||
|
||||
if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
|
||||
DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
|
||||
return;
|
||||
}
|
||||
|
||||
Usb2HcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
PortNum,
|
||||
EfiUsbPortResetChange
|
||||
);
|
||||
|
||||
Usb2HcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
Usb2HcPpi,
|
||||
@@ -1077,7 +1137,11 @@ ResetRootPort (
|
||||
return;
|
||||
}
|
||||
|
||||
MicroSecondDelay (200 * 1000);
|
||||
//
|
||||
// Drive the reset signal for at least 50ms. Check USB 2.0 Spec
|
||||
// section 7.1.7.5 for timing requirements.
|
||||
//
|
||||
MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
|
||||
|
||||
//
|
||||
// clear reset root port
|
||||
@@ -1094,8 +1158,44 @@ ResetRootPort (
|
||||
return;
|
||||
}
|
||||
|
||||
MicroSecondDelay (1 * 1000);
|
||||
|
||||
MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
|
||||
|
||||
//
|
||||
// USB host controller won't clear the RESET bit until
|
||||
// reset is actually finished.
|
||||
//
|
||||
ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
|
||||
|
||||
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
|
||||
Status = UsbHcPpi->GetRootHubPortStatus (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
PortNum,
|
||||
&PortStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
|
||||
}
|
||||
|
||||
if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
|
||||
DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
|
||||
return;
|
||||
}
|
||||
|
||||
UsbHcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
PortNum,
|
||||
EfiUsbPortResetChange
|
||||
);
|
||||
|
||||
UsbHcPpi->ClearRootHubPortFeature (
|
||||
PeiServices,
|
||||
UsbHcPpi,
|
||||
|
@@ -33,25 +33,20 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
#include <IndustryStandard/Usb.h>
|
||||
|
||||
#define MAX_ROOT_PORT 2
|
||||
#define MAX_INTERFACE 8
|
||||
#define MAX_ENDPOINT 16
|
||||
|
||||
#define USB_SLOW_SPEED_DEVICE 0x01
|
||||
#define USB_FULL_SPEED_DEVICE 0x02
|
||||
|
||||
#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D')
|
||||
typedef struct {
|
||||
UINTN Signature;
|
||||
PEI_USB_IO_PPI UsbIoPpi;
|
||||
EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList;
|
||||
UINT16 MaxPacketSize0;
|
||||
UINT16 DataToggle;
|
||||
UINT8 DeviceAddress;
|
||||
UINT8 MaxPacketSize0;
|
||||
UINT8 DeviceSpeed;
|
||||
UINT8 IsHub;
|
||||
UINT16 DataToggle;
|
||||
UINT8 DownStreamPortNo;
|
||||
UINT8 Reserved; // Padding for IPF
|
||||
UINTN AllocateAddress;
|
||||
PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;
|
||||
PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;
|
||||
@@ -61,11 +56,48 @@ typedef struct {
|
||||
EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescList[MAX_INTERFACE];
|
||||
EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT];
|
||||
EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescList[MAX_INTERFACE][MAX_ENDPOINT];
|
||||
EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
|
||||
EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
|
||||
UINT8 Tier;
|
||||
} PEI_USB_DEVICE;
|
||||
|
||||
#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)
|
||||
|
||||
#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
|
||||
|
||||
#define USB_BUS_1_MILLISECOND 1000
|
||||
|
||||
//
|
||||
// Wait for port reset, refers to specification
|
||||
// [USB20-7.1.7.5, it says 10ms for hub and 50ms for
|
||||
// root hub]
|
||||
//
|
||||
// According to USB2.0, Chapter 11.5.1.5 Resetting,
|
||||
// the worst case for TDRST is 20ms
|
||||
//
|
||||
#define USB_SET_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
|
||||
#define USB_SET_ROOT_PORT_RESET_STALL (50 * USB_BUS_1_MILLISECOND)
|
||||
|
||||
//
|
||||
// Wait for clear roothub port reset, set by experience
|
||||
//
|
||||
#define USB_CLR_ROOT_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
|
||||
|
||||
//
|
||||
// Wait for port statue reg change, set by experience
|
||||
//
|
||||
#define USB_WAIT_PORT_STS_CHANGE_STALL (100)
|
||||
|
||||
//
|
||||
// Host software return timeout if port status doesn't change
|
||||
// after 500ms(LOOP * STALL = 5000 * 0.1ms), set by experience
|
||||
//
|
||||
#define USB_WAIT_PORT_STS_CHANGE_LOOP 5000
|
||||
|
||||
//
|
||||
// Wait for hub port power-on, refers to specification
|
||||
// [USB20-11.23.2]
|
||||
//
|
||||
#define USB_SET_PORT_POWER_STALL (2 * USB_BUS_1_MILLISECOND)
|
||||
|
||||
/**
|
||||
Submits control transfer to a target USB device.
|
||||
|
Reference in New Issue
Block a user