/** @file\r
Usb Hub Request Support In PEI Phase\r
\r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
}\r
\r
/**\r
- Get a given hub descriptor.\r
+ Get a given (SuperSpeed) hub descriptor.\r
\r
@param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicates the hub controller device.\r
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
@param DescriptorSize The length of Hub Descriptor buffer.\r
@param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
EFI_STATUS\r
PeiGetHubDescriptor (\r
IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
IN PEI_USB_IO_PPI *UsbIoPpi,\r
IN UINTN DescriptorSize,\r
OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
)\r
{\r
EFI_USB_DEVICE_REQUEST DevReq;\r
+ UINT8 DescType;\r
+\r
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
\r
+ DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?\r
+ USB_DT_SUPERSPEED_HUB :\r
+ USB_DT_HUB;\r
+\r
//\r
// Fill Device request packet\r
//\r
DevReq.RequestType = USB_RT_HUB | 0x80;\r
DevReq.Request = USB_HUB_GET_DESCRIPTOR;\r
- DevReq.Value = USB_DT_HUB << 8;\r
- DevReq.Length = (UINT16)DescriptorSize;\r
+ DevReq.Value = (UINT16) (DescType << 8);\r
+ DevReq.Length = (UINT16) DescriptorSize;\r
\r
return UsbIoPpi->UsbControlTransfer (\r
PeiServices,\r
);\r
}\r
\r
+/**\r
+ Read the whole usb hub descriptor. It is necessary\r
+ to do it in two steps because hub descriptor is of\r
+ variable length.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicates the hub controller device.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
+ successfully returned.\r
+\r
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubReadDesc (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // First get the hub descriptor length\r
+ //\r
+ Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the whole hub descriptor\r
+ //\r
+ return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);\r
+}\r
+\r
+/**\r
+ USB hub control transfer to set the hub depth.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicates the hub controller device.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Depth of the hub is set.\r
+ @retval Others Failed to set the depth.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubCtrlSetHubDepth (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DevReq.RequestType = USB_RT_HUB;\r
+ DevReq.Request = USB_HUB_REQ_SET_DEPTH;\r
+ DevReq.Value = PeiUsbDevice->Tier;\r
+ DevReq.Length = 0;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
/**\r
Configure a given hub.\r
\r
IN PEI_USB_DEVICE *PeiUsbDevice\r
)\r
{\r
- EFI_USB_HUB_DESCRIPTOR HubDescriptor;\r
+ UINT8 HubDescBuffer[256];\r
+ EFI_USB_HUB_DESCRIPTOR *HubDescriptor;\r
EFI_STATUS Status;\r
EFI_USB_HUB_STATUS HubStatus;\r
UINTN Index;\r
- UINT32 PortStatus;\r
PEI_USB_IO_PPI *UsbIoPpi;\r
\r
- ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
\r
//\r
- // First get the hub descriptor length\r
+ // The length field of descriptor is UINT8 type, so the buffer\r
+ // with 256 bytes is enough to hold the descriptor data.\r
//\r
- Status = PeiGetHubDescriptor (\r
- PeiServices,\r
- UsbIoPpi,\r
- 2,\r
- &HubDescriptor\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;\r
+\r
//\r
- // First get the whole descriptor, then\r
- // get the number of hub ports\r
+ // Get the hub descriptor \r
//\r
- Status = PeiGetHubDescriptor (\r
+ Status = PeiUsbHubReadDesc (\r
PeiServices,\r
+ PeiUsbDevice,\r
UsbIoPpi,\r
- HubDescriptor.Length,\r
- &HubDescriptor\r
+ HubDescriptor\r
);\r
if (EFI_ERROR (Status)) {\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
+ PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;\r
\r
- Status = PeiHubGetHubStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT32 *) &HubStatus\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Get all hub ports status\r
- //\r
- for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-\r
- Status = PeiHubGetPortStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- &PortStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- }\r
- //\r
- // Power all the hub ports\r
- //\r
- for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
- Status = PeiHubSetPortFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT8) (Index + 1),\r
- EfiUsbPortPower\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- }\r
- //\r
- // Clear Hub Status Change\r
- //\r
- Status = PeiHubGetHubStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- (UINT32 *) &HubStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+ DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));\r
+ PeiUsbHubCtrlSetHubDepth (\r
+ PeiServices,\r
+ PeiUsbDevice,\r
+ UsbIoPpi\r
+ );\r
} else {\r
//\r
- // Hub power supply change happens\r
+ // Power all the hub ports\r
//\r
- if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
- PeiHubClearHubFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- C_HUB_LOCAL_POWER\r
- );\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+ Status = PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortPower\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));\r
+ continue;\r
+ }\r
+ }\r
+\r
+ DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));\r
+ if (HubDescriptor->PwrOn2PwrGood > 0) {\r
+ MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
}\r
+\r
//\r
- // Hub change overcurrent happens\r
+ // Clear Hub Status Change\r
//\r
- if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
- PeiHubClearHubFeature (\r
- PeiServices,\r
- UsbIoPpi,\r
- C_HUB_OVER_CURRENT\r
- );\r
+ Status = PeiHubGetHubStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT32 *) &HubStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // Hub power supply change happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_LOCAL_POWER\r
+ );\r
+ }\r
+ //\r
+ // Hub change overcurrent happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_OVER_CURRENT\r
+ );\r
+ }\r
}\r
}\r
\r
IN UINT8 PortNum\r
)\r
{\r
- UINT8 Try;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
EFI_USB_PORT_STATUS HubPortStatus;\r
\r
-\r
MicroSecondDelay (100 * 1000);\r
\r
//\r
EfiUsbPortReset\r
);\r
\r
- Try = 10;\r
- do {\r
- PeiHubGetPortStatus (\r
- PeiServices,\r
- UsbIoPpi,\r
- PortNum,\r
- (UINT32 *) &HubPortStatus\r
- );\r
+ //\r
+ // Drive the reset signal for worst 20ms. Check USB 2.0 Spec\r
+ // section 7.1.7.5 for timing requirements.\r
+ //\r
+ MicroSecondDelay (USB_SET_PORT_RESET_STALL);\r
\r
- MicroSecondDelay (2 * 1000);\r
- Try -= 1;\r
- } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+ //\r
+ // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.\r
+ //\r
+ ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+ for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+ Status = PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ (UINT32 *) &HubPortStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+ }\r
+\r
+ if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+ DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));\r
+ return;\r
+ }\r
\r
//\r
- // clear reset root port\r
+ // clear reset change root port\r
//\r
PeiHubClearPortFeature (\r
PeiServices,\r
UsbIoPpi,\r
PortNum,\r
- EfiUsbPortReset\r
+ EfiUsbPortResetChange\r
);\r
\r
MicroSecondDelay (1 * 1000);\r