summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Usb
diff options
context:
space:
mode:
authorStar Zeng <star.zeng@intel.com>2014-07-02 03:20:49 +0000
committerlzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524>2014-07-02 03:20:49 +0000
commitd987459f8e0b78831c95188b5b0d712ed6a54c88 (patch)
tree7a64d52560565b17395737a92e1edf2576442a89 /MdeModulePkg/Bus/Usb
parentef96ba3cbe6f9f3658f19407d4c2150dcd6eb457 (diff)
downloadedk2-platforms-d987459f8e0b78831c95188b5b0d712ed6a54c88.tar.xz
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
Diffstat (limited to 'MdeModulePkg/Bus/Usb')
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c323
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h4
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c16
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h12
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c4
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c308
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h48
7 files changed, 491 insertions, 224 deletions
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
index 5b7ebfad90..16a7b589c1 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
@@ -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
@@ -320,6 +320,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.
@param PeiServices General-purpose services that are available to every PEIM.
@@ -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
- //
- Status = PeiGetHubDescriptor (
- PeiServices,
- UsbIoPpi,
- 2,
- &HubDescriptor
- );
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- //
- // First get the whole descriptor, then
- // get the number of hub ports
+ // Get the hub descriptor
//
- Status = PeiGetHubDescriptor (
+ Status = PeiUsbHubReadDesc (
PeiServices,
+ PeiUsbDevice,
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
- );
+ //
+ // 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);
- MicroSecondDelay (2 * 1000);
- Try -= 1;
- } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);
+ //
+ // 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 root port
+ // clear reset change root port
//
PeiHubClearPortFeature (
PeiServices,
UsbIoPpi,
PortNum,
- EfiUsbPortReset
+ EfiUsbPortResetChange
);
MicroSecondDelay (1 * 1000);
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
index 273a26c1ae..f50bc63501 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
@@ -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)
//
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
index 6fef61e565..42be13ac3b 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
@@ -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;
}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
index e0557f8eea..1ace89fbc3 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
@@ -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
);
/**
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
index 492f124296..d13a7ee0a3 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
@@ -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;
}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
index 23090f68f3..947864bd27 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
@@ -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,
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
index 4685034a5c..df459e7a6e 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
@@ -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.