alder_lake_bios/Insyde/InsydeModulePkg/Bus/Usb/UsbBusPei/Hub.c

659 lines
16 KiB
C

/** @file
Usb Hub Request Support In PEI Phase
;******************************************************************************
;* Copyright (c) 2012 - 2019, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "UsbBus.h"
#include "Hub.h"
#include "UsbHelper.h"
/**
Get a given hub port status
@param PeiServices EFI_PEI_SERVICES
@param UsbIoPpi PEI_USB3_IO_PPI instance
@param Port Usb hub port number (starting from 1).
@param PortStatus Current Hub port status and change status.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
@retval EFI_INVALID_PARAMETER
**/
EFI_STATUS
PeiHubGetPortStatus (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINT8 Port,
OUT UINT32 *PortStatus
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
EFI_STATUS Status;
PEI_USB_DEVICE *PeiUsbDev;
UINT32 HubPortStatus;
PeiUsbDev = PEI_USB3_DEVICE_FROM_THIS (UsbIoPpi);
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_GET_PORT_STATUS_REQ_TYPE;
DeviceRequest.Request = HUB_GET_PORT_STATUS;
DeviceRequest.Index = Port;
DeviceRequest.Length = sizeof (UINT32);
Status = UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbDataIn,
TIMEOUT_VALUE,
PortStatus,
sizeof (UINT32)
);
if (!EFI_ERROR (Status)) {
//
// SuperSpeed Hub Status Conversion
//
if (PeiUsbDev->DeviceSpeed == EFI_USB_SPEED_SUPER) {
HubPortStatus = *PortStatus;
(*PortStatus) &= ~0x0000FFE0;
if (HubPortStatus & USB_PORT_STAT_SUPER_SPEED_POWER) {
//
// Convert Port Power Status
//
(*PortStatus) |= USB_PORT_STAT_POWER;
}
if (((HubPortStatus & USB_PORT_STAT_SUPER_SPEED_MASK) == 0) ||
((HubPortStatus & USB_PORT_STAT_SUPER_SPEED_MASK) == 0x800)) {
//
// Convert Port Speed Status
//
(*PortStatus) |= USB_PORT_STAT_SUPER_SPEED;
}
}
}
return Status;
}
/**
Set specified feature to a give hub port
@param PeiServices EFI_PEI_SERVICES
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param Port Usb hub port number (starting from 1).
@param Value New feature value.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
@retval EFI_INVALID_PARAMETER
**/
EFI_STATUS
PeiHubSetPortFeature (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINT8 Port,
IN UINT8 Value
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_SET_PORT_FEATURE_REQ_TYPE;
DeviceRequest.Request = HUB_SET_PORT_FEATURE;
DeviceRequest.Value = Value;
DeviceRequest.Index = Port;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbNoData,
TIMEOUT_VALUE,
NULL,
0
);
}
/**
Clear a specified feature of a given hub port
@param PeiServices EFI_PEI_SERVICES
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param Port Usb hub port number (starting from 1).
@param Value Feature value that will be cleared from
that hub port.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
@retval EFI_INVALID_PARAMETER
**/
EFI_STATUS
PeiHubClearPortFeature (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINT8 Port,
IN UINT8 Value
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_CLEAR_FEATURE_PORT_REQ_TYPE;
DeviceRequest.Request = HUB_CLEAR_FEATURE_PORT;
DeviceRequest.Value = Value;
DeviceRequest.Index = Port;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbNoData,
TIMEOUT_VALUE,
NULL,
0
);
}
/*++
Get Hub Status
@param PeiServices EFI_PEI_SERVICES
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param HubStatus Current Hub status and change status.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
--*/
EFI_STATUS
PeiHubGetHubStatus (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
OUT UINT32 *HubStatus
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_GET_HUB_STATUS_REQ_TYPE;
DeviceRequest.Request = HUB_GET_HUB_STATUS;
DeviceRequest.Length = sizeof (UINT32);
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbDataIn,
TIMEOUT_VALUE,
HubStatus,
sizeof (UINT32)
);
}
/**
Set a specified feature to the hub
@param PeiServices EFI_PEI_SERVICES
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param Value Feature value that will be set to the hub.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
**/
EFI_STATUS
PeiHubSetHubFeature (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINT8 Value
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_SET_HUB_FEATURE_REQ_TYPE;
DeviceRequest.Request = HUB_SET_HUB_FEATURE;
DeviceRequest.Value = Value;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbNoData,
TIMEOUT_VALUE,
NULL,
0
);
}
/**
Set a specified feature to the hub
@param PeiServices EFI_PEI_SERVICES
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param Value Feature value that will be cleared from the hub.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
**/
EFI_STATUS
PeiHubClearHubFeature (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINT8 Value
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_CLEAR_FEATURE_REQ_TYPE;
DeviceRequest.Request = HUB_CLEAR_FEATURE;
DeviceRequest.Value = Value;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbNoData,
TIMEOUT_VALUE,
NULL,
0
);
}
/**
Get the hub descriptor
@param PeiServices PeiGetHubDescriptor
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param DescriptorSize The length of Hub Descriptor buffer.
@param HubDescriptor Caller allocated buffer to store the hub descriptor
if successfully returned.
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
@retval EFI_TIME_OUT
**/
EFI_STATUS
PeiGetHubDescriptor (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINTN DescriptorSize,
OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
)
{
EFI_USB_DEVICE_REQUEST DevReq;
PEI_USB_DEVICE *PeiUsbDev;
PeiUsbDev = PEI_USB3_DEVICE_FROM_THIS (UsbIoPpi);
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_DEVICE | USB_ENDPOINT_DIR_IN;
DevReq.Request = HUB_GET_DESCRIPTOR;
DevReq.Value = ((PeiUsbDev->DeviceSpeed == EFI_USB_SPEED_SUPER) ? USB_DESC_TYPE_SSHUB : USB_DESC_TYPE_HUB) << 8;
DevReq.Length = (UINT16)DescriptorSize;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DevReq,
EfiUsbDataIn,
TIMEOUT_VALUE,
HubDescriptor,
(UINT16)DescriptorSize
);
}
/**
Set the hub depth for super speed hub
@param PeiServices PeiGetHubDescriptor
@param UsbIoPpi EFI_USB_IO_PROTOCOL instance
@param Depth The depth of hub
@retval EFI_SUCCESS
@retval EFI_DEVICE
@retval EFI_TIME_OUT
**/
STATIC
EFI_STATUS
SetHubDepth (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB3_IO_PPI *UsbIoPpi,
IN UINT8 Depth
)
{
EFI_USB_DEVICE_REQUEST DeviceRequest;
ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DeviceRequest.RequestType = HUB_SET_HUB_DEPTH_REQ_TYPE;
DeviceRequest.Request = HUB_SET_HUB_DEPTH;
DeviceRequest.Value = Depth;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DeviceRequest,
EfiUsbNoData,
TIMEOUT_VALUE,
NULL,
0
);
}
/**
Configure the hub
@param PeiUsbDevice Indicating the hub controller device that
will be configured
@retval EFI_SUCCESS
@retval EFI_DEVICE_ERROR
**/
EFI_STATUS
DoHubConfig (
IN PEI_USB_DEVICE *PeiUsbDevice
)
{
EFI_PEI_SERVICES **PeiServices;
EFI_USB_HUB_DESCRIPTOR HubDescriptor;
EFI_STATUS Status;
EFI_USB_HUB_STATUS HubStatus;
UINTN i;
UINT32 PortStatus;
PEI_USB3_IO_PPI *UsbIoPpi;
ZeroMem (&HubDescriptor, sizeof (HubDescriptor));
PeiServices = PeiUsbDevice->PeiServices;
UsbIoPpi = &PeiUsbDevice->Usb3IoPpi;
//
// 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
//
Status = PeiGetHubDescriptor (
PeiServices,
UsbIoPpi,
HubDescriptor.Length,
&HubDescriptor
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;
Status = PeiHubGetHubStatus (
PeiServices,
UsbIoPpi,
(UINT32 *) &HubStatus
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
//
// Get all hub ports status
//
for (i = 0; i < PeiUsbDevice->DownStreamPortNo; i++) {
Status = PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
(UINT8) (i + 1),
&PortStatus
);
if (EFI_ERROR (Status)) {
continue;
}
}
//
// Power all the hub ports
//
for (i = 0; i < PeiUsbDevice->DownStreamPortNo; i++) {
Status = PeiHubSetPortFeature (
PeiServices,
UsbIoPpi,
(UINT8) (i + 1),
EfiUsbPortPower
);
if (EFI_ERROR (Status)) {
continue;
}
}
//
// Stall HubDescriptor.PwrOn2PwrGood plus 200 millisecond for hub ports power on
//
PeiUsbDevice->StallPpi->Stall (
(CONST EFI_PEI_SERVICES **)PeiServices,
PeiUsbDevice->StallPpi,
(HubDescriptor.PwrOn2PwrGood + 200) * 1000
);
//
// Clear Hub Status Change
//
Status = PeiHubGetHubStatus (
PeiServices,
UsbIoPpi,
(UINT32 *) &HubStatus
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
} else {
//
// Hub power supply change happens
//
if (HubStatus.HubChange & HUB_CHANGE_LOCAL_POWER) {
PeiHubClearHubFeature (
PeiServices,
UsbIoPpi,
C_HUB_LOCAL_POWER
);
}
//
// Hub change overcurrent happens
//
if (HubStatus.HubChange & HUB_CHANGE_OVERCURRENT) {
PeiHubClearHubFeature (
PeiServices,
UsbIoPpi,
C_HUB_OVER_CURRENT
);
}
}
//
// Set Hub Depth for Super Speed Hub
//
if (HubDescriptor.DescriptorType == USB_DESC_TYPE_SSHUB) {
Status = SetHubDepth (
PeiServices,
UsbIoPpi,
PeiUsbDevice->HubDepth
);
if (EFI_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
Reset Hub Port
@param PeiUsbDevice Indicating the hub controller device that
will be configured
**/
VOID
ResetHubPort (
IN PEI_USB_DEVICE *PeiUsbDevice,
IN UINT8 PortNum
)
{
EFI_PEI_SERVICES **PeiServices;
EFI_USB_PORT_STATUS HubPortStatus;
PEI_USB3_IO_PPI *UsbIoPpi;
UINT8 n;
PeiServices = PeiUsbDevice->PeiServices;
UsbIoPpi = &PeiUsbDevice->Usb3IoPpi;
PeiUsbDevice->StallPpi->Stall (
(CONST EFI_PEI_SERVICES **)PeiServices,
PeiUsbDevice->StallPpi,
100 * 1000
);
//
// reset root port
//
PeiHubSetPortFeature (
PeiServices,
UsbIoPpi,
PortNum,
EfiUsbPortReset
);
//
// Drive the reset signal for at least 10ms. Check USB 2.0 Spec
// section 7.1.7.5 for timing requirements.
//
PeiUsbDevice->StallPpi->Stall (
(CONST EFI_PEI_SERVICES **)PeiServices,
PeiUsbDevice->StallPpi,
10 * 1000
);
n = 10;
do {
PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
PortNum,
(UINT32 *) &HubPortStatus
);
PeiUsbDevice->StallPpi->Stall (
(CONST EFI_PEI_SERVICES **)PeiServices,
PeiUsbDevice->StallPpi,
2 * 1000
);
n -= 1;
} while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && n > 0);
//
// USB hub will clear RESET bit if reset is actually finished.
//
PeiHubClearPortFeature (
PeiServices,
UsbIoPpi,
PortNum,
EfiUsbPortResetChange
);
PeiHubClearPortFeature (
PeiServices,
UsbIoPpi,
PortNum,
EfiUsbPortConnectChange
);
n = 10;
do {
PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
PortNum,
(UINT32 *) &HubPortStatus
);
PeiUsbDevice->StallPpi->Stall (
(CONST EFI_PEI_SERVICES **)PeiServices,
PeiUsbDevice->StallPpi,
2 * 1000
);
n -= 1;
} while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) != 0 && n > 0);
}