/** @file
Usb3 Debug Port initialization
Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "Usb3DebugPortLibInternal.h"
UINT16 mString0Desc[] = {
// String Descriptor Type + Length
( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,
0x0409
};
UINT16 mManufacturerStrDesc[] = {
// String Descriptor Type + Length
( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,
'I', 'n', 't', 'e', 'l'
};
//USB 3.0 Debug Cable
UINT16 mProductStrDesc[] = {
// String Descriptor Type + Length
( USB_DESC_TYPE_STRING << 8 ) + PRODUCT_DESC_LEN,
'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
};
UINT16 mSerialNumberStrDesc[] = {
// String Descriptor Type + Length
( USB_DESC_TYPE_STRING << 8 ) + SERIAL_DESC_LEN,
'1'
};
XHC_DC_CONTEXT DebugCapabilityContextTemplate = {
{
0,
0,
0,
0,
STRING0_DESC_LEN,
MANU_DESC_LEN,
PRODUCT_DESC_LEN,
SERIAL_DESC_LEN,
0,
0,
0,
0
},
{
0, // EPState
0, // RsvdZ1
0, // Mult
0, // MaxPStreams
0, // LSA
0, // Interval
0, // RsvdZ2
0, // RsvdZ3
3, // CERR
ED_BULK_OUT, // EPType
0, // RsvdZ4
0, // HID
0, // MaxBurstSize
1024, // MaxPacketSize
0, // PtrLo
0, // PtrHi
0x1000, // AverageTRBLength
0, // MaxESITPayload
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
},
{
0,
0,
0,
0,
0,
0,
0,
0,
3, //CERR
ED_BULK_IN,
0,
0,
0,
1024, //MaxPacketSize
0,
0,
0x1000,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
}
};
/**
Return command register value in XHCI controller.
**/
UINT16
GetXhciPciCommand (
VOID
)
{
UINT8 Bus;
UINT8 Device;
UINT8 Function;
UINT16 Command;
USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
UsbDebugPort.Controller = GetUsb3DebugPortController();
Bus = UsbDebugPort.PciAddress.Bus;
Device = UsbDebugPort.PciAddress.Device;
Function = UsbDebugPort.PciAddress.Function;
Command = PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
return Command;
}
/**
Discover the USB3 debug device.
@param[in] Instance Pointer to USB3 debug port object instance.
@retval RETURN_SUCCESS The USB3 debug device was found.
@retval RETURN_DEVICE_ERROR The USB3 debug device was not found.
**/
RETURN_STATUS
DiscoverUsb3DebugPort(
IN USB3_DEBUG_PORT_INSTANCE *Instance
)
{
UINT8 Bus;
UINT8 Device;
UINT8 Function;
UINT16 Command;
EFI_PHYSICAL_ADDRESS UsbBase;
USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
EFI_PHYSICAL_ADDRESS CapabilityPointer;
UINT32 Capability;
BOOLEAN Flag;
UINT8 CapLength;
UsbDebugPort.Controller = GetUsb3DebugPortController();
Bus = UsbDebugPort.PciAddress.Bus;
Device = UsbDebugPort.PciAddress.Device;
Function = UsbDebugPort.PciAddress.Function;
if ((PciRead8(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)) != PCI_CLASS_SERIAL) ||
(PciRead8(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)) != PCI_CLASS_SERIAL_USB) ||
(PciRead8(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET)) != 0x30)) {
//
// The device is not XHCI controller
//
return RETURN_NOT_FOUND;
}
//
// USBBASE is at 10-13h, i.e. the first BAR, clear the low bits which is not part of base address
//
UsbBase = GetXhciBaseAddress ();
//
// Set XHCI MMIO base address if necessary
//
if ((UsbBase == 0) || (UsbBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
UsbBase = PcdGet32 (PcdXhciDefaultBaseAddress);
PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)UsbBase);
PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0x0);
UsbBase = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET)) & XHCI_BASE_ADDRESS_32_BIT_MASK;
if (UsbBase == 0 || UsbBase == XHCI_BASE_ADDRESS_32_BIT_MASK) {
return RETURN_DEVICE_ERROR;
}
}
//
// Set MSE and BME bit - enable the address space
//
Command = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
}
CapLength = MmioRead8 ((UINTN) UsbBase);
//
// Get capability pointer from HCCPARAMS at offset 0x10
//
CapabilityPointer = UsbBase + (MmioRead32 ((UINTN)(UsbBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
//
// Search XHCI debug capability
//
Flag = FALSE;
Capability = MmioRead32 ((UINTN)CapabilityPointer);
while (TRUE) {
if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
Flag = TRUE;
break;
}
if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
//
// Reach the end of capability list, quit
//
break;
}
CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
Capability = MmioRead32 ((UINTN)CapabilityPointer);
}
Instance->Signature = USB3_DEBUG_PORT_INSTANCE_SIGNATURE;
if (Flag) {
Instance->DebugSupport = TRUE;
Instance->DebugCapabilityBase = CapabilityPointer;
Instance->DebugCapabilityOffset = CapabilityPointer - UsbBase;
Instance->XhciOpRegister = UsbBase + CapLength;
Instance->XhcMmioBase = UsbBase;
Instance->PciBusNumber = Bus;
Instance->PciDeviceNumber = Device;
Instance->PciFunctionNumber = Function;
}
//
// Restore Command Register
//
PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
return RETURN_SUCCESS;
}
/**
Create XHCI event ring.
@param Xhc The XHCI Instance.
@param EventRing The created event ring.
**/
EFI_STATUS
CreateEventRing (
IN USB3_DEBUG_PORT_INSTANCE *Xhc,
OUT EVENT_RING *EventRing
)
{
VOID *Buf;
EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
ASSERT (EventRing != NULL);
//
// Allocate Event Ring
//
Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
ASSERT (Buf != NULL);
ASSERT (((UINTN) Buf & 0x3F) == 0);
ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
//
// Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
// and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
//
EventRing->EventRingCCS = 1;
//
// Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
//
Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
ASSERT (Buf != NULL);
ASSERT (((UINTN) Buf & 0x3F) == 0);
ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;
//
// Fill Event Segment address
//
ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
//
// Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
//
XhcWriteDebugReg (
Xhc,
XHC_DC_DCERDP,
XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
);
XhcWriteDebugReg (
Xhc,
XHC_DC_DCERDP + 4,
XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
);
//
// Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
//
XhcWriteDebugReg (
Xhc,
XHC_DC_DCERSTBA,
XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)
);
XhcWriteDebugReg (
Xhc,
XHC_DC_DCERSTBA + 4,
XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)
);
//
// Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
//
XhcWriteDebugReg (
Xhc,
XHC_DC_DCERSTSZ,
ERST_NUMBER
);
return EFI_SUCCESS;
}
/**
Create XHCI transfer ring.
@param Xhc The XHCI Instance.
@param TrbNum The number of TRB in the ring.
@param TransferRing The created transfer ring.
**/
VOID
CreateTransferRing (
IN USB3_DEBUG_PORT_INSTANCE *Xhc,
IN UINT32 TrbNum,
OUT TRANSFER_RING *TransferRing
)
{
VOID *Buf;
LINK_TRB *EndTrb;
Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
ASSERT (Buf != NULL);
ASSERT (((UINTN) Buf & 0xF) == 0);
ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
TransferRing->TrbNumber = TrbNum;
TransferRing->RingEnqueue = TransferRing->RingSeg0;
TransferRing->RingDequeue = TransferRing->RingSeg0;
TransferRing->RingPCS = 1;
//
// 4.9.2 Transfer Ring Management
// To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
// point to the first TRB in the ring.
//
EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
EndTrb->Type = TRB_TYPE_LINK;
EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
//
// Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
//
EndTrb->TC = 1;
//
// Set Cycle bit as other TRB PCS init value
//
EndTrb->CycleBit = 0;
}
/**
Create debug capability context for XHC debug device.
@param Xhc The XHCI Instance.
@retval EFI_SUCCESS The bit successfully changed by host controller.
@retval EFI_TIMEOUT The time out occurred.
**/
EFI_STATUS
CreateDebugCapabilityContext (
IN USB3_DEBUG_PORT_INSTANCE *Xhc
)
{
VOID *Buf;
XHC_DC_CONTEXT *DebugCapabilityContext;
UINT8 *String0Desc;
UINT8 *ManufacturerStrDesc;
UINT8 *ProductStrDesc;
UINT8 *SerialNumberStrDesc;
//
// Allocate debug device context
//
Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
ASSERT (Buf != NULL);
ASSERT (((UINTN) Buf & 0xF) == 0);
ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;
Xhc->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;
CopyMem (DebugCapabilityContext, &DebugCapabilityContextTemplate, sizeof (XHC_DC_CONTEXT));
//
// Update string descriptor address
//
String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
ASSERT (String0Desc != NULL);
ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
//
// Allocate and initialize the Transfer Ring for the Input Endpoint Context.
//
ZeroMem (&Xhc->TransferRingIn, sizeof (TRANSFER_RING));
CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, &Xhc->TransferRingIn);
//
// Can not set BIT0, otherwise there is no transfer ring detected.
//
DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Xhc->TransferRingIn.RingSeg0) | BIT0;
DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Xhc->TransferRingIn.RingSeg0);
//
// Allocate and initialize the Transfer Ring for the Output Endpoint Context.
//
ZeroMem (&Xhc->TransferRingOut, sizeof (TRANSFER_RING));
CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, &Xhc->TransferRingOut);
//
// Can not set BIT0, otherwise there is no transfer ring detected.
//
DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Xhc->TransferRingOut.RingSeg0) | BIT0;
DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Xhc->TransferRingOut.RingSeg0);
//
// Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
//
XhcWriteDebugReg (
Xhc,
XHC_DC_DCCP,
XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)
);
XhcWriteDebugReg (
Xhc,
XHC_DC_DCCP + 4,
XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)
);
return EFI_SUCCESS;
}
/**
Initialize the USB3 debug Device hardware.
@param[in] Instance Pointer to USB3 debug port object instance.
@retval RETURN_SUCCESS The USB3 debug device was initialized successfully.
@retval !RETURN_SUCCESS Error.
**/
RETURN_STATUS
InitializeUsb3DebugPort (
IN USB3_DEBUG_PORT_INSTANCE *Instance
)
{
RETURN_STATUS Status;
UINT64 XhciOpRegister;
volatile UINT32 Dcctrl;
UINT8 Bus;
UINT8 Device;
UINT8 Function;
UINT16 Command;
EFI_BOOT_MODE BootMode;
UINT64 TimeOut;
CHAR8 *TestString;
UINTN Length;
UINT32 TransferResult;
Bus = Instance->PciBusNumber;
Device = Instance->PciDeviceNumber;
Function = Instance->PciFunctionNumber;
Command = GetXhciPciCommand ();
//
// Save and set Command Register
//
if (((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((Command & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
}
//
// Clear DCE bit and LSE bit in DCCTRL
//
if ((XhcReadDebugReg (Instance, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
XhcClearDebugRegBit (Instance, XHC_DC_DCCTRL, BIT1|BIT31);
}
XhciOpRegister = Instance->XhciOpRegister;
//
// Get current Boot Mode
//
BootMode = GetBootModeHob ();
if (BootMode != BOOT_ON_S3_RESUME) {
if (!XhcIsBitSet((UINTN)(XhciOpRegister + XHC_USBSTS_OFFSET), XHC_USBSTS_HALT)) {
XhcClrR32Bit((UINTN) XhciOpRegister + XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
while (!XhcIsBitSet((UINTN)(XhciOpRegister + XHC_USBSTS_OFFSET), XHC_USBSTS_HALT)) {
MicroSecondDelay (10);
}
}
//
// Reset host controller
//
XhcSetR32Bit((UINTN)XhciOpRegister + XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
//
// Ensure that the host controller is reset (RESET bit must be cleared after reset)
//
while (XhcIsBitSet((UINTN)XhciOpRegister + XHC_USBCMD_OFFSET, XHC_USBCMD_RESET)) {
MicroSecondDelay (10);
}
}
//
// Initialize event ring
//
ZeroMem (&Instance->EventRing, sizeof (EVENT_RING));
Status = CreateEventRing (Instance, &Instance->EventRing);
ASSERT_EFI_ERROR (Status);
//
// Init IN and OUT endpoint context
//
Status = CreateDebugCapabilityContext (Instance);
ASSERT_EFI_ERROR (Status);
//
// Init data buffer used to transfer
//
Instance->Urb.Data = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAlignBuffer (XHC_DEBUG_PORT_DATA_LENGTH);
//
// Init DCDDI1 and DCDDI2
//
XhcWriteDebugReg (
Instance,
XHC_DC_DCDDI1,
(UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
);
XhcWriteDebugReg (
Instance,
XHC_DC_DCDDI2,
(UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
);
//
// Set DCE bit and LSE bit to "1" in DCCTRL
//
XhcSetDebugRegBit (Instance, XHC_DC_DCCTRL, BIT1|BIT31);
TimeOut = DivU64x32 (PcdGet64 (PcdXhciHostWaitTimeout), XHC_POLL_DELAY) + 1;
while (TimeOut != 0) {
//
// Check if debug device is in configured state
//
Dcctrl = XhcReadDebugReg (Instance, XHC_DC_DCCTRL);
if ((Dcctrl & BIT0) != 0) {
//
// Set the flag to indicate debug device is ready
//
Instance->Ready = TRUE;
break;
}
MicroSecondDelay (XHC_POLL_DELAY);
TimeOut--;
}
if (!Instance->Ready) {
XhcClearDebugRegBit (Instance, XHC_DC_DCCTRL, BIT1|BIT31);
} else {
TestString = "Usb 3.0 Debug Message Start\n";
Length = AsciiStrLen (TestString);
XhcDataTransfer (
Instance,
EfiUsbDataOut,
TestString,
&Length,
0,
&TransferResult
);
}
//
// Restore Command Register
//
PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
return EFI_SUCCESS;
}
/**
Update XHC hardware address when MMIO base is changed.
@param Instance The XHCI Instance.
@param XhcMmioBase XHCI MMIO base address.
**/
VOID
FixUsb3InstanceResource (
IN OUT USB3_DEBUG_PORT_INSTANCE *Instance,
IN EFI_PHYSICAL_ADDRESS XhcMmioBase
)
{
if ((Instance == NULL) || (Instance->XhcMmioBase == XhcMmioBase)) {
return;
}
//
// Need fix Instance data according to PCI resource
//
Instance->XhcMmioBase = XhcMmioBase;
Instance->DebugCapabilityBase = XhcMmioBase + Instance->DebugCapabilityOffset;
Instance->XhciOpRegister = XhcMmioBase + MmioRead8 ((UINTN)XhcMmioBase);
}
/**
Save USB3 instance address.
@param[in] Instance The XHCI Instance.
**/
VOID
SaveUsb3InstanceAddress (
IN USB3_DEBUG_PORT_INSTANCE *Instance
)
{
UINT16 Command;
USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
UINT8 Bus;
UINT8 Device;
UINT8 Function;
Command = GetXhciPciCommand ();
UsbDebugPort.Controller = GetUsb3DebugPortController();
Bus = UsbDebugPort.PciAddress.Bus;
Device = UsbDebugPort.PciAddress.Device;
Function = UsbDebugPort.PciAddress.Function;
//
// Set Command Register
//
if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
}
//
// After debug device is finished to enumerate, use DCDDI2 register to store instance address
//
XhcWriteDebugReg (
Instance,
XHC_DC_DCDDI2,
(UINT32)(UINTN)Instance
);
//
// Restore Command Register
//
PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
}