/** @file
The XHCI register operation routines.
(C) Copyright 2023 Hewlett Packard Enterprise Development LP
Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Xhci.h"
/**
Read 1-byte width XHCI capability register.
@param Xhc The XHCI Instance.
@param Offset The offset of the 1-byte width capability register.
@return The register content read.
@retval If err, return 0xFF.
**/
UINT8
XhcReadCapReg8 (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset
)
{
UINT8 Data;
EFI_STATUS Status;
Status = Xhc->PciIo->Mem.Read (
Xhc->PciIo,
EfiPciIoWidthUint8,
XHC_BAR_INDEX,
(UINT64)Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
Data = 0xFF;
}
return Data;
}
/**
Read 4-bytes width XHCI capability register.
@param Xhc The XHCI Instance.
@param Offset The offset of the 4-bytes width capability register.
@return The register content read.
@retval If err, return 0xFFFFFFFF.
**/
UINT32
XhcReadCapReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset
)
{
UINT32 Data;
EFI_STATUS Status;
Status = Xhc->PciIo->Mem.Read (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
(UINT64)Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));
Data = 0xFFFFFFFF;
}
return Data;
}
/**
Read 4-bytes width XHCI Operational register.
@param Xhc The XHCI Instance.
@param Offset The offset of the 4-bytes width operational register.
@return The register content read.
@retval If err, return 0xFFFFFFFF.
**/
UINT32
XhcReadOpReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset
)
{
UINT32 Data;
EFI_STATUS Status;
ASSERT (Xhc->CapLength != 0);
Status = Xhc->PciIo->Mem.Read (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->CapLength + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
Data = 0xFFFFFFFF;
}
return Data;
}
/**
Write the data to the 4-bytes width XHCI operational register.
@param Xhc The XHCI Instance.
@param Offset The offset of the 4-bytes width operational register.
@param Data The data to write.
**/
VOID
XhcWriteOpReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Data
)
{
EFI_STATUS Status;
ASSERT (Xhc->CapLength != 0);
Status = Xhc->PciIo->Mem.Write (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->CapLength + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
}
}
/**
Write the data to the XHCI door bell register.
@param Xhc The XHCI Instance.
@param Offset The offset of the door bell register.
@param Data The data to write.
**/
VOID
XhcWriteDoorBellReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Data
)
{
EFI_STATUS Status;
ASSERT (Xhc->DBOff != 0);
Status = Xhc->PciIo->Mem.Write (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->DBOff + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
}
}
/**
Read XHCI runtime register.
@param Xhc The XHCI Instance.
@param Offset The offset of the runtime register.
@return The register content read
**/
UINT32
XhcReadRuntimeReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset
)
{
UINT32 Data;
EFI_STATUS Status;
ASSERT (Xhc->RTSOff != 0);
Status = Xhc->PciIo->Mem.Read (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->RTSOff + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset));
Data = 0xFFFFFFFF;
}
return Data;
}
/**
Write the data to the XHCI runtime register.
@param Xhc The XHCI Instance.
@param Offset The offset of the runtime register.
@param Data The data to write.
**/
VOID
XhcWriteRuntimeReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Data
)
{
EFI_STATUS Status;
ASSERT (Xhc->RTSOff != 0);
Status = Xhc->PciIo->Mem.Write (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->RTSOff + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset));
}
}
/**
Read XHCI extended capability register.
@param Xhc The XHCI Instance.
@param Offset The offset of the extended capability register.
@return The register content read
**/
UINT32
XhcReadExtCapReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset
)
{
UINT32 Data;
EFI_STATUS Status;
ASSERT (Xhc->ExtCapRegBase != 0);
Status = Xhc->PciIo->Mem.Read (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->ExtCapRegBase + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset));
Data = 0xFFFFFFFF;
}
return Data;
}
/**
Write the data to the XHCI extended capability register.
@param Xhc The XHCI Instance.
@param Offset The offset of the extended capability register.
@param Data The data to write.
**/
VOID
XhcWriteExtCapReg (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Data
)
{
EFI_STATUS Status;
ASSERT (Xhc->ExtCapRegBase != 0);
Status = Xhc->PciIo->Mem.Write (
Xhc->PciIo,
EfiPciIoWidthUint32,
XHC_BAR_INDEX,
Xhc->ExtCapRegBase + Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset));
}
}
/**
Set one bit of the runtime register while keeping other bits.
@param Xhc The XHCI Instance.
@param Offset The offset of the runtime register.
@param Bit The bit mask of the register to set.
**/
VOID
XhcSetRuntimeRegBit (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
)
{
UINT32 Data;
Data = XhcReadRuntimeReg (Xhc, Offset);
Data |= Bit;
XhcWriteRuntimeReg (Xhc, Offset, Data);
}
/**
Clear one bit of the runtime register while keeping other bits.
@param Xhc The XHCI Instance.
@param Offset The offset of the runtime register.
@param Bit The bit mask of the register to set.
**/
VOID
XhcClearRuntimeRegBit (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
)
{
UINT32 Data;
Data = XhcReadRuntimeReg (Xhc, Offset);
Data &= ~Bit;
XhcWriteRuntimeReg (Xhc, Offset, Data);
}
/**
Set one bit of the operational register while keeping other bits.
@param Xhc The XHCI Instance.
@param Offset The offset of the operational register.
@param Bit The bit mask of the register to set.
**/
VOID
XhcSetOpRegBit (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
)
{
UINT32 Data;
Data = XhcReadOpReg (Xhc, Offset);
Data |= Bit;
XhcWriteOpReg (Xhc, Offset, Data);
}
/**
Clear one bit of the operational register while keeping other bits.
@param Xhc The XHCI Instance.
@param Offset The offset of the operational register.
@param Bit The bit mask of the register to clear.
**/
VOID
XhcClearOpRegBit (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
)
{
UINT32 Data;
Data = XhcReadOpReg (Xhc, Offset);
Data &= ~Bit;
XhcWriteOpReg (Xhc, Offset, Data);
}
/**
Wait the operation register's bit as specified by Bit
to become set (or clear).
@param Xhc The XHCI Instance.
@param Offset The offset of the operation register.
@param Bit The bit of the register to wait for.
@param WaitToSet Wait the bit to set or clear.
@param Timeout The time to wait before abort (in millisecond, ms).
@retval EFI_SUCCESS The bit successfully changed by host controller.
@retval EFI_TIMEOUT The time out occurred.
**/
EFI_STATUS
XhcWaitOpRegBit (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Offset,
IN UINT32 Bit,
IN BOOLEAN WaitToSet,
IN UINT32 Timeout
)
{
UINT64 TimeoutTicks;
UINT64 ElapsedTicks;
UINT64 TicksDelta;
UINT64 CurrentTick;
if (Timeout == 0) {
return EFI_TIMEOUT;
}
TimeoutTicks = XhcConvertTimeToTicks (XHC_MICROSECOND_TO_NANOSECOND (Timeout * XHC_1_MILLISECOND));
ElapsedTicks = 0;
CurrentTick = GetPerformanceCounter ();
do {
if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
return EFI_SUCCESS;
}
gBS->Stall (XHC_1_MICROSECOND);
TicksDelta = XhcGetElapsedTicks (&CurrentTick);
// Ensure that ElapsedTicks is always incremented to avoid indefinite hangs
if (TicksDelta == 0) {
TicksDelta = XhcConvertTimeToTicks (XHC_MICROSECOND_TO_NANOSECOND (XHC_1_MICROSECOND));
}
ElapsedTicks += TicksDelta;
} while (ElapsedTicks < TimeoutTicks);
return EFI_TIMEOUT;
}
/**
Set Bios Ownership
@param Xhc The XHCI Instance.
**/
VOID
XhcSetBiosOwnership (
IN USB_XHCI_INSTANCE *Xhc
)
{
UINT32 Buffer;
if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
return;
}
DEBUG ((DEBUG_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);
XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
}
/**
Clear Bios Ownership
@param Xhc The XHCI Instance.
**/
VOID
XhcClearBiosOwnership (
IN USB_XHCI_INSTANCE *Xhc
)
{
UINT32 Buffer;
if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {
return;
}
DEBUG ((DEBUG_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);
Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);
XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);
}
/**
Calculate the offset of the XHCI capability.
@param Xhc The XHCI Instance.
@param CapId The XHCI Capability ID.
@return The offset of XHCI legacy support capability register.
**/
UINT32
XhcGetCapabilityAddr (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT8 CapId
)
{
UINT32 ExtCapOffset;
UINT8 NextExtCapReg;
UINT32 Data;
ExtCapOffset = 0;
do {
//
// Check if the extended capability register's capability id is USB Legacy Support.
//
Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
if ((Data & 0xFF) == CapId) {
return ExtCapOffset;
}
//
// If not, then traverse all of the ext capability registers till finding out it.
//
NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
ExtCapOffset += (NextExtCapReg << 2);
} while (NextExtCapReg != 0);
return 0xFFFFFFFF;
}
/**
Calculate the offset of the xHCI Supported Protocol Capability.
@param Xhc The XHCI Instance.
@param MajorVersion The USB Major Version in xHCI Support Protocol Capability Field
@return The offset of xHCI Supported Protocol capability register.
**/
UINT32
XhcGetSupportedProtocolCapabilityAddr (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT8 MajorVersion
)
{
UINT32 ExtCapOffset;
UINT8 NextExtCapReg;
UINT32 Data;
UINT32 NameString;
XHC_SUPPORTED_PROTOCOL_DW0 UsbSupportDw0;
if (Xhc == NULL) {
return 0;
}
ExtCapOffset = 0;
do {
//
// Check if the extended capability register's capability id is USB Legacy Support.
//
Data = XhcReadExtCapReg (Xhc, ExtCapOffset);
UsbSupportDw0.Dword = Data;
if ((Data & 0xFF) == XHC_CAP_USB_SUPPORTED_PROTOCOL) {
if (UsbSupportDw0.Data.RevMajor == MajorVersion) {
NameString = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_NAME_STRING_OFFSET);
if (NameString == XHC_SUPPORTED_PROTOCOL_NAME_STRING_VALUE) {
//
// Ensure Name String field is xHCI supported protocols in xHCI Supported Protocol Capability Offset 04h
//
return ExtCapOffset;
}
}
}
//
// If not, then traverse all of the ext capability registers till finding out it.
//
NextExtCapReg = (UINT8)((Data >> 8) & 0xFF);
ExtCapOffset += (NextExtCapReg << 2);
} while (NextExtCapReg != 0);
return 0xFFFFFFFF;
}
/**
Find PortSpeed value match Protocol Speed ID Value (PSIV).
@param Xhc The XHCI Instance.
@param ExtCapOffset The USB Major Version in xHCI Support Protocol Capability Field
@param PortSpeed The Port Speed Field in USB PortSc register
@param PortNumber The Port Number (0-indexed)
@return The Protocol Speed ID (PSI) from xHCI Supported Protocol capability register.
**/
UINT32
XhciPsivGetPsid (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 ExtCapOffset,
IN UINT8 PortSpeed,
IN UINT8 PortNumber
)
{
XHC_SUPPORTED_PROTOCOL_DW2 PortId;
XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID Reg;
UINT32 Count;
UINT32 MinPortIndex;
UINT32 MaxPortIndex;
if ((Xhc == NULL) || (ExtCapOffset == 0xFFFFFFFF)) {
return 0;
}
//
// According to XHCI 1.1 spec November 2017,
// Section 7.2 xHCI Supported Protocol Capability
// 1. Get the PSIC(Protocol Speed ID Count) value.
// 2. The PSID register boundary should be Base address + PSIC * 0x04
//
PortId.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_DW2_OFFSET);
//
// According to XHCI 1.1 spec November 2017, valid values
// for CompPortOffset are 1 to CompPortCount - 1.
//
// PortNumber is zero-indexed, so subtract 1.
//
if ((PortId.Data.CompPortOffset == 0) || (PortId.Data.CompPortCount == 0)) {
return 0;
}
MinPortIndex = PortId.Data.CompPortOffset - 1;
MaxPortIndex = MinPortIndex + PortId.Data.CompPortCount - 1;
if ((PortNumber < MinPortIndex) || (PortNumber > MaxPortIndex)) {
return 0;
}
for (Count = 0; Count < PortId.Data.Psic; Count++) {
Reg.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_PSI_OFFSET + (Count << 2));
if (Reg.Data.Psiv == PortSpeed) {
return Reg.Dword;
}
}
return 0;
}
/**
Find PortSpeed value match case in XHCI Supported Protocol Capability
@param Xhc The XHCI Instance.
@param PortSpeed The Port Speed Field in USB PortSc register
@param PortNumber The Port Number (0-indexed)
@return The USB Port Speed.
**/
UINT16
XhcCheckUsbPortSpeedUsedPsic (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT8 PortSpeed,
IN UINT8 PortNumber
)
{
XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID SpField;
UINT16 UsbSpeedIdMap;
if (Xhc == NULL) {
return 0;
}
SpField.Dword = 0;
UsbSpeedIdMap = 0;
//
// Check xHCI Supported Protocol Capability, find the PSIV field to match
// PortSpeed definition when the Major Revision is 03h.
//
if (Xhc->Usb3SupOffset != 0xFFFFFFFF) {
SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb3SupOffset, PortSpeed, PortNumber);
if (SpField.Dword != 0) {
//
// Found the corresponding PORTSC value in PSIV field of USB3 offset.
//
UsbSpeedIdMap = USB_PORT_STAT_SUPER_SPEED;
}
}
//
// Check xHCI Supported Protocol Capability, find the PSIV field to match
// PortSpeed definition when the Major Revision is 02h.
//
if ((UsbSpeedIdMap == 0) && (Xhc->Usb2SupOffset != 0xFFFFFFFF)) {
SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb2SupOffset, PortSpeed, PortNumber);
if (SpField.Dword != 0) {
//
// Found the corresponding PORTSC value in PSIV field of USB2 offset.
//
if (SpField.Data.Psie == 2) {
//
// According to XHCI 1.1 spec November 2017,
// Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition,
// PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 2 shall represent bit rate in Mb/s
//
if (SpField.Data.Psim == XHC_SUPPORTED_PROTOCOL_USB2_HIGH_SPEED_PSIM) {
//
// PSIM shows as default High-speed protocol, apply to High-speed mapping
//
UsbSpeedIdMap = USB_PORT_STAT_HIGH_SPEED;
}
} else if (SpField.Data.Psie == 1) {
//
// According to XHCI 1.1 spec November 2017,
// Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition,
// PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 1 shall represent bit rate in Kb/s
//
if (SpField.Data.Psim == XHC_SUPPORTED_PROTOCOL_USB2_LOW_SPEED_PSIM) {
//
// PSIM shows as default Low-speed protocol, apply to Low-speed mapping
//
UsbSpeedIdMap = USB_PORT_STAT_LOW_SPEED;
}
}
}
}
return UsbSpeedIdMap;
}
/**
Whether the XHCI host controller is halted.
@param Xhc The XHCI Instance.
@retval TRUE The controller is halted.
@retval FALSE It isn't halted.
**/
BOOLEAN
XhcIsHalt (
IN USB_XHCI_INSTANCE *Xhc
)
{
return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);
}
/**
Whether system error occurred.
@param Xhc The XHCI Instance.
@retval TRUE System error happened.
@retval FALSE No system error.
**/
BOOLEAN
XhcIsSysError (
IN USB_XHCI_INSTANCE *Xhc
)
{
return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);
}
/**
Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
@param Xhc The XHCI Instance.
**/
VOID
XhcSetHsee (
IN USB_XHCI_INSTANCE *Xhc
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT16 XhciCmd;
PciIo = Xhc->PciIo;
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint16,
PCI_COMMAND_OFFSET,
sizeof (XhciCmd) / sizeof (UINT16),
&XhciCmd
);
if (!EFI_ERROR (Status)) {
if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {
XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);
}
}
}
/**
Reset the XHCI host controller.
@param Xhc The XHCI Instance.
@param Timeout Time to wait before abort (in millisecond, ms).
@retval EFI_SUCCESS The XHCI host controller is reset.
@return Others Failed to reset the XHCI before Timeout.
**/
EFI_STATUS
XhcResetHC (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Timeout
)
{
EFI_STATUS Status;
Status = EFI_SUCCESS;
DEBUG ((DEBUG_INFO, "XhcResetHC!\n"));
//
// Host can only be reset when it is halt. If not so, halt it
//
if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
Status = XhcHaltHC (Xhc, Timeout);
if (EFI_ERROR (Status)) {
return Status;
}
}
if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||
((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0))
{
XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
//
// Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
// Otherwise there may have the timeout case happened.
// The below is a workaround to solve such problem.
//
gBS->Stall (PcdGet16 (PcdDelayXhciHCReset));
Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
if (!EFI_ERROR (Status)) {
//
// The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
// Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
//
XhcSetHsee (Xhc);
}
}
return Status;
}
/**
Halt the XHCI host controller.
@param Xhc The XHCI Instance.
@param Timeout Time to wait before abort (in millisecond, ms).
@return EFI_SUCCESS The XHCI host controller is halt.
@return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
**/
EFI_STATUS
XhcHaltHC (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Timeout
)
{
EFI_STATUS Status;
XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);
return Status;
}
/**
Set the XHCI host controller to run.
@param Xhc The XHCI Instance.
@param Timeout Time to wait before abort (in millisecond, ms).
@return EFI_SUCCESS The XHCI host controller is running.
@return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
**/
EFI_STATUS
XhcRunHC (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 Timeout
)
{
EFI_STATUS Status;
XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);
return Status;
}