summaryrefslogtreecommitdiff
path: root/Core/EM/UsbRecovery/XhciPEI
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/UsbRecovery/XhciPEI')
-rw-r--r--Core/EM/UsbRecovery/XhciPEI/XhciPei.c2314
-rw-r--r--Core/EM/UsbRecovery/XhciPEI/XhciPei.cif9
-rw-r--r--Core/EM/UsbRecovery/XhciPEI/XhciPei.h1245
3 files changed, 3568 insertions, 0 deletions
diff --git a/Core/EM/UsbRecovery/XhciPEI/XhciPei.c b/Core/EM/UsbRecovery/XhciPEI/XhciPei.c
new file mode 100644
index 0000000..ae926ca
--- /dev/null
+++ b/Core/EM/UsbRecovery/XhciPEI/XhciPei.c
@@ -0,0 +1,2314 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2010, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//**********************************************************************
+//
+// $Header: /Alaska/SOURCE/Modules/USBRecovery/XhciPei.c 10 11/24/12 5:45a Ryanchou $
+//
+// $Revision: 10 $
+//
+// $Date: 11/24/12 5:45a $
+//
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/USBRecovery/XhciPei.c $
+//
+// 10 11/24/12 5:45a Ryanchou
+// [TAG] EIP103990
+// [Category] Improvement
+// [Description] Synchronized with USB PEI module 4.6.3_USB_08.10.24.
+// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c,
+// BotPeim.c, BotPeim.h, PeiAtapi.c, UsbBotPeim.c, UsbBotPeim.h,
+// HubPeim.c, UsbPeim.c, XhciPei.c, XhciPei.h, HubPeim.h, PeiUsbLib.c,
+// PeiUsbLib.h, UsbPeim.h
+//
+// 9 4/24/12 10:16p Wilsonlee
+// [TAG] EIP75547
+// [Category] Bug Fix
+// [Severity] Normal
+// [Symptom] Xhci recovery funtion failed when SS devices on USB 3.0
+// port.
+// [RootCause] The SS device connected to USB2 port.
+// [Solution] Reset the USB2 port when initial xhci controller, then the
+// SS device reconnect to USB3 port.
+// [Files] XhciPei.c, XhciPei.h
+//
+// 8 4/12/11 12:00a Rameshr
+// [TAG]- EIP 57444
+// [Category]-IMPROVEMENT
+// [Description]- PI1.1 Support.
+// [Files]- OhciPeiboard.c,Xhcipei.c, Peiusblib.c
+//
+// 7 1/18/11 1:08a Ryanchou
+// [TAG] EIP47931
+// [Category] Improvement
+// [Description] Added USB 3.0 hub support.
+// [Files] EhciPei.c, EhciPei.h, HubPeim.c, HubPeim.h, OhciPei.c,
+// OhciPei.h, UhcPeim.c, UhcPeim.h, usb.h, UsbHostController.h,
+// UsbIoPeim.c, UsbPeim.c, UsbPeim.h, XhciPei.c, XhciPei.h
+//
+// 6 1/17/11 7:08a Ryanchou
+// [TAG] EIP48013
+// [Category] Improvement
+// [Description] Use 32 or 64 byte Context data structures dynamically.
+// [Files] XhciPei.c, XhciPei.h
+//
+// 5 10/27/10 11:27a Olegi
+// [TAG] EIP46147
+// [Category] Bug Fix
+//
+// 4 10/20/10 10:44a Olegi
+// [TAG] EIP46492
+// [Category] Bug Fix
+// [Severity] Important
+// [Symptom] TdSize variable should be declared as a 32bit integer
+// instead of a 8bit one.
+//
+// 3 10/14/10 3:57p Olegi
+// Added code that check for PCI device presence.
+//
+// 2 10/12/10 5:57p Olegi
+// Added (UINTN) typecast when converting pointers to UINT64. Without it
+// pointers that have BIT31 will have bits 32..63 set.
+//
+// 1 10/11/10 4:53p Olegi
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------------
+//
+// Name: XhciPei.c
+//
+// Description:
+// This file is the main source file for the xHCI PEI USB recovery module.
+// Its entry point at XhciPeiUsbEntryPoint will be executed from the
+// UsbRecoveryInitialize INIT_LIST.
+//
+//----------------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#include <AmiPeiLib.h>
+#include "XhciPei.h"
+#include <PPI\stall.h>
+#include "token.h"
+#include "pci.h"
+#include "usbpeim.h"
+
+PCI_BUS_DEV_FUNCTION gXhciControllerPciTable[] = {PEI_XHCI_CONTROLLER_PCI_ADDRESS {0,0,0}};
+UINT16 gXhciControllerCount = \
+ sizeof(gXhciControllerPciTable) / sizeof(PCI_BUS_DEV_FUNCTION) - 1;
+
+PCI_DEV_REGISTER_VALUE gPeiXhciInitPciTable[] = {PEI_XHCI_CONTROLLER_PCI_REGISTER_VALUES {0,0,0,0,0,0,0}};
+UINT16 gPeiXhciInitPciTableCount = \
+ sizeof(gPeiXhciInitPciTable) / sizeof(PCI_DEV_REGISTER_VALUE) - 1;
+
+UINT8 gSlotBeingConfigured;
+
+#ifndef PI_SPECIFICATION_VERSION //old Core
+extern EFI_STATUS PciCfgModify(
+IN CONST EFI_PEI_SERVICES **PeiServices,
+IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
+IN UINT64 Address,
+IN UINTN SetBits,
+IN UINTN ClearBits
+);
+#endif
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: XhciPeiUsbEntryPoint
+//
+// Description:
+// This is the entry point into the XHCI initialization.
+//
+// Input:
+// IN EFI_FFS_FILE_HEADER *FfsHeader
+// -- EFI_FFS_FILE_HEADER pointer
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciPeiUsbEntryPoint (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_PEI_SERVICES **PeiServices )
+{
+
+ EFI_STATUS Status;
+ EFI_PEI_STALL_PPI *StallPpi;
+ UINT32 XhciBaseAddress = PEI_XHCI_MMIOBASE;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ USB3_CONTROLLER *Usb3Hc;
+ UINTN MemPages;
+ UINT8 ControllerIndex;
+ UINT8 PciDevIndex;
+ UINT8 CmdRegisterValue = 6;
+
+ //-------------------------------------------
+ // Initialize the EFI_PEI_STALL_PPI interface
+ //-------------------------------------------
+ Status = (**PeiServices).LocatePpi( PeiServices, &gPeiStallPpiGuid,
+ 0, NULL, &StallPpi );
+ if ( EFI_ERROR( Status ) ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ // Program PCI registers of the host controller and other relevant PCI
+ // devices (e.g. bridges that enable this host).
+
+ for (PciDevIndex = 0; PciDevIndex < gPeiXhciInitPciTableCount; PciDevIndex++) {
+
+ EFI_PEI_PCI_CFG_PPI_WIDTH Width;
+
+ switch (gPeiXhciInitPciTable[PciDevIndex].Size) {
+ case 8: Width = EfiPeiPciCfgWidthUint8; break;
+ case 16: Width = EfiPeiPciCfgWidthUint16; break;
+ case 32: Width = EfiPeiPciCfgWidthUint32; break;
+ case 64: Width = EfiPeiPciCfgWidthUint64; break;
+ default: continue;
+ }
+
+ Status = PciCfgModify(
+ PeiServices,
+ Width,
+ PEI_PCI_CFG_ADDRESS(
+ gPeiXhciInitPciTable[PciDevIndex].Bus,
+ gPeiXhciInitPciTable[PciDevIndex].Device,
+ gPeiXhciInitPciTable[PciDevIndex].Function,
+ gPeiXhciInitPciTable[PciDevIndex].Register
+ ),
+ gPeiXhciInitPciTable[PciDevIndex].SetBits,
+ gPeiXhciInitPciTable[PciDevIndex].ClearBits);
+ }
+
+ for (ControllerIndex = 0; ControllerIndex < gXhciControllerCount;
+ ControllerIndex++, XhciBaseAddress+=0x10000)
+ {
+ UINT16 Vid;
+ UINT16 Did;
+
+ // Get VID/DID, see if controller is visible on PCI
+ (*PeiServices)->PciCfg->Read(PeiServices,(*PeiServices)->PciCfg,
+ EfiPeiPciCfgWidthUint16, XHCI_PCI_ADDRESS( ControllerIndex, PCI_VID ),&Vid);
+ if (Vid == 0xffff) continue; // Controller not present
+
+ (*PeiServices)->PciCfg->Read(PeiServices,(*PeiServices)->PciCfg,
+ EfiPeiPciCfgWidthUint16, XHCI_PCI_ADDRESS( ControllerIndex, PCI_DID ), &Did);
+
+ //----------------------------------------------------------
+ // Allocate USB3_CONTROLLER object that holds all necessary
+ // information for the Host Controller operational registers
+ // for each controller. Initialze the controller and setup
+ // data structures, get it ready for operation.
+ //----------------------------------------------------------
+ MemPages = sizeof(USB3_CONTROLLER) / 0x1000 + 1;
+ Status = (**PeiServices).AllocatePages(PeiServices,
+ EfiConventionalMemory,
+ MemPages,
+ &TempPtr);
+ if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;
+
+ (**PeiServices).SetMem((VOID*)TempPtr, MemPages*4096, 0); // Clear allocated memory
+
+ Usb3Hc = (USB3_CONTROLLER*)(UINTN)TempPtr;
+
+ //----------------------------------------------------------
+ // USB3 controller data area is allocated, start stuff it in
+ // with the useful filling in with the useful data.
+ //----------------------------------------------------------
+
+ // Program BAR
+ (*PeiServices)->PciCfg->Write(PeiServices,(*PeiServices)->PciCfg,
+ EfiPeiPciCfgWidthUint32,
+ XHCI_PCI_ADDRESS( ControllerIndex, PCI_BAR0 ),
+ &XhciBaseAddress
+ );
+ Usb3Hc->CapRegs = (XHCI_HC_CAP_REGS*)(UINTN)XhciBaseAddress;
+
+ // Enable MMIO access and BM
+ (*PeiServices)->PciCfg->Write(PeiServices,(*PeiServices)->PciCfg,
+ EfiPeiPciCfgWidthUint8,
+ XHCI_PCI_ADDRESS( ControllerIndex, PCI_CMD ),
+ &CmdRegisterValue
+ );
+
+ (UINT8)(UINTN)Usb3Hc->CapRegs &= ~(0x7F); // Clear attributes
+
+ Usb3Hc->Did = Did;
+ Usb3Hc->Vid = Vid;
+ Usb3Hc->Access64 = Usb3Hc->CapRegs->HcParams.Ac64;
+ Usb3Hc->HciVersion = Usb3Hc->CapRegs->HciVersion;
+ Usb3Hc->MaxPorts = Usb3Hc->CapRegs->HcParams1.MaxPorts;
+ Usb3Hc->OpRegs = (XHCI_HC_OP_REGS*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->CapRegs->CapLength);
+ Usb3Hc->PageSize4K = Usb3Hc->OpRegs->PageSize;
+ Usb3Hc->ContextSize = 0x20 << Usb3Hc->CapRegs->HcParams.Csz;
+ Usb3Hc->MaxIntrs = Usb3Hc->CapRegs->HcParams1.MaxIntrs; // Get maximum number of interrupters
+ Usb3Hc->DbOffset = Usb3Hc->CapRegs->DbOff; // Doorbell offset
+ Usb3Hc->MaxSlots = PEI_XHCI_MAX_SLOTS;
+
+ Usb3Hc->InputContext = (VOID*)&Usb3Hc->InpCtx;
+ Usb3Hc->XfrRings = Usb3Hc->XfrRing;
+ Usb3Hc->XfrTrbs = (UINTN)Usb3Hc->XfrTrb;
+ Usb3Hc->DeviceContext = (VOID*)Usb3Hc->DevCtx;
+
+ XhciExtCapParser(PeiServices, Usb3Hc); //(EIP75547+)
+
+ PEI_TRACE ((-1, PeiServices, "USB recovery xHCI[%d] controller initialization details:\n", ControllerIndex));
+ PEI_TRACE ((-1, PeiServices, " PCI location: B%x/D%x/F%x, VID:DID = %x:%x, BAR0 = %x\n",
+ gXhciControllerPciTable[ControllerIndex].Bus,
+ gXhciControllerPciTable[ControllerIndex].Device,
+ gXhciControllerPciTable[ControllerIndex].Function,
+ Usb3Hc->Vid,
+ Usb3Hc->Did,
+ Usb3Hc->CapRegs
+ ));
+ PEI_TRACE((-1, PeiServices, " MaxSlots = %x, InputCtx %x, Device Ctx %x\n",
+ Usb3Hc->MaxSlots, (UINT8*)Usb3Hc->InputContext, (UINT8*)Usb3Hc->DeviceContext));
+
+ Usb3Hc->PeiServices = PeiServices;
+ Usb3Hc->CpuIoPpi = (*PeiServices)->CpuIo;
+ Usb3Hc->StallPpi = StallPpi;
+ Usb3Hc->PciCfgPpi = (*PeiServices)->PciCfg;
+
+ // Initialize the xHCI Controller for operation
+ Status = XhciInitHC(PeiServices, Usb3Hc, ControllerIndex);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+ if (EFI_ERROR(Status)) return Status;
+
+ // Setup PPI entry point
+ Usb3Hc->UsbHostControllerPpi.ControlTransfer = XhciHcControlTransfer;
+ Usb3Hc->UsbHostControllerPpi.BulkTransfer = XhciHcBulkTransfer;
+ Usb3Hc->UsbHostControllerPpi.GetRootHubPortNumber = XhciHcGetRootHubPortNumber;
+ Usb3Hc->UsbHostControllerPpi.GetRootHubPortStatus = XhciHcGetRootHubPortStatus;
+ Usb3Hc->UsbHostControllerPpi.SetRootHubPortFeature = XhciHcSetRootHubPortFeature;
+ Usb3Hc->UsbHostControllerPpi.ClearRootHubPortFeature = XhciHcClearRootHubPortFeature;
+ Usb3Hc->UsbHostControllerPpi.PreConfigureDevice = XhciHcPreConfigureDevice;
+ Usb3Hc->UsbHostControllerPpi.EnableEndpoints = XhciEnableEndpoints;
+
+ Usb3Hc->PpiDescriptor.Flags =(EFI_PEI_PPI_DESCRIPTOR_PPI |EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ Usb3Hc->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;
+ Usb3Hc->PpiDescriptor.Ppi = &Usb3Hc->UsbHostControllerPpi;
+
+ Status = (**PeiServices).InstallPpi(PeiServices, &Usb3Hc->PpiDescriptor);
+ if (EFI_ERROR(Status)) return EFI_NOT_FOUND;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: XhciInitHC
+//
+// Description:
+// This function initializes xHCI controller registers and starts it.
+//
+// Input:
+// EFI_PEI_SERVICES **PeiServices
+// -- PEI_SERVICES pointer
+// USB3_CONTROLLER *Usb3Hc
+// -- XHCI controller data structure pointer
+// UINT8 ControllerIndex
+// -- 0-based index of the controller to be initialized
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful initialization completion
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciInitHC(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 ControllerIndex
+)
+{
+ XHCI_INTERRUPTER_REGS *Interrupter;
+ XHCI_ER_SEGMENT_ENTRY *Erst0Entry;
+ BOOLEAN PpSet = FALSE;
+ UINT8 PortNumber;
+ volatile XHCI_PORTSC *PortSC;
+ UINT32 CurrentPortOffset = 0;
+ UINT32 i;
+
+ // Wait controller ready
+ for (i = 0; i < 100; i++) {
+ if (Usb3Hc->OpRegs->UsbSts.Field.Cnr == 0) break;
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 1);
+ }
+ PEI_ASSERT(PeiServices, Usb3Hc->OpRegs->UsbSts.Field.Cnr == 0);
+ if (Usb3Hc->OpRegs->UsbSts.Field.Cnr) return EFI_DEVICE_ERROR;
+
+ // Check if the xHC is halted
+ if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0)
+ {
+ Usb3Hc->OpRegs->UsbCmd.RunStop = 0;
+ // The xHC should halt within 16 ms. Section 5.4.1.1
+ for (i = 0; i < 16; i++) {
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 1);
+ if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) break;
+ }
+ PEI_ASSERT(PeiServices, Usb3Hc->OpRegs->UsbSts.Field.HcHalted);
+ if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0) return EFI_DEVICE_ERROR;
+ }
+
+ // Reset controller
+ Usb3Hc->OpRegs->UsbCmd.HcRst = 1;
+ for (i = 0; i < 400; i++) {
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 1);
+ if (Usb3Hc->OpRegs->UsbCmd.HcRst == 0) break;
+ }
+
+ PEI_ASSERT(PeiServices, Usb3Hc->OpRegs->UsbCmd.HcRst == 0);
+ if (Usb3Hc->OpRegs->UsbCmd.HcRst) return EFI_DEVICE_ERROR; // Controller can not be reset
+
+ // Wait controller ready
+ for (i = 0; i < 100; i++) {
+ if (Usb3Hc->OpRegs->UsbSts.Field.Cnr == 0) break;
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 1);
+ }
+ PEI_ASSERT(PeiServices, Usb3Hc->OpRegs->UsbSts.Field.Cnr == 0);
+ if (Usb3Hc->OpRegs->UsbSts.Field.Cnr) return EFI_DEVICE_ERROR;
+
+ Usb3Hc->RtRegs = (XHCI_HC_RT_REGS*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->CapRegs->RtsOff);
+ PEI_TRACE ((-1, PeiServices, "PEI_XHCI: RT registers are at %x\n", Usb3Hc->RtRegs));
+
+ Usb3Hc->OpRegs->Config = Usb3Hc->MaxSlots; // Max device slots enabled
+ Usb3Hc->DcbaaPtr = (XHCI_DCBAA*)Usb3Hc->Dcbaa;
+
+ XhciMmio64Write(Usb3Hc, (UINTN)&Usb3Hc->OpRegs->DcbAap, (UINT64)(UINTN)Usb3Hc->DcbaaPtr);
+
+ // Define the Command Ring Dequeue Pointer by programming the Command Ring
+ // Control Register (5.4.5) with a 64-bit address pointing to the starting
+ // address of the first TRB of the Command Ring.
+
+ // Initialize Command Ring Segment: Size TRBS_PER_SEGMENT*16, 64 Bytes aligned
+ XhciInitRing(&Usb3Hc->CmdRing, (UINTN)Usb3Hc->CommandRing, TRBS_PER_SEGMENT, TRUE);
+ PEI_TRACE ((-1, PeiServices, "CMD Ring is at %x\n", (UINTN)&Usb3Hc->CmdRing));
+
+ // Write CRCR HC register with the allocated address. Set Ring Cycle State to 1.
+ XhciMmio64Write(Usb3Hc, (UINTN)&Usb3Hc->OpRegs->Crcr,
+ (UINT64)(UINTN)Usb3Hc->CmdRing.Base + CRCR_RING_CYCLE_STATE);
+
+ // Initialize and assign Event Ring
+ XhciInitRing(&Usb3Hc->EvtRing, (UINTN)Usb3Hc->EventRing, TRBS_PER_SEGMENT, FALSE);
+ PEI_TRACE ((-1, PeiServices, "EVT Ring is at %x\n", (UINTN)&Usb3Hc->EvtRing));
+
+ // NOTE: This driver supports one Interrupter, hence it uses
+ // one Event Ring segment with TRBS_PER_SEGMENT TRBs in it.
+
+ // Initialize ERST[0]
+ Erst0Entry = &Usb3Hc->Erst;
+ Erst0Entry->RsBase = (UINT64)(UINTN)Usb3Hc->EvtRing.Base;
+ Erst0Entry->RsSize = TRBS_PER_SEGMENT;
+
+ Interrupter = Usb3Hc->RtRegs->IntRegs;
+
+ // Initialize Interrupter fields
+ Interrupter->Erstz = 1; // # of segments
+ // ER dequeue pointer
+ XhciMmio64Write(Usb3Hc, (UINTN)&Interrupter->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr);
+ // Seg Table location
+ XhciMmio64Write(Usb3Hc, (UINTN)&Interrupter->Erstba, (UINT64)(UINTN)Erst0Entry);
+ Interrupter->IMod = XHCI_IMODI; // Max interrupt rate
+ Interrupter->IMan |= 2; // Enable interrupt
+
+ PEI_TRACE((-1, PeiServices, "Transfer Rings structures start at %x\n", Usb3Hc->XfrRings));
+
+ // Set PortPower unless PowerPortControl indicates otherwise
+ if (Usb3Hc->CapRegs->HcParams.Ppc != 0) {
+ for (PortNumber = 0; PortNumber<Usb3Hc->MaxPorts;
+ PortNumber++, CurrentPortOffset+=0x10) {
+ PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs +
+ XHCI_PORTSC_OFFSET + CurrentPortOffset);
+ if (PortSC->Field.Pp == 0) {
+ PortSC->Field.Pp = 1; // Set port power
+ PpSet = TRUE;
+ }
+ }
+ if (PpSet) XHCI_FIXED_DELAY_MS(Usb3Hc, 20); // Wait for 20 ms, Section 5.4.8
+ }
+
+ Usb3Hc->OpRegs->UsbCmd.Inte = 1;
+ Usb3Hc->OpRegs->UsbCmd.RunStop = 1;
+
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 100);
+
+ XhciResetUsb2Port(PeiServices, Usb3Hc); //(EIP75547+)
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: XhciHcPreConfigureDevice
+//
+// Description:
+// This function does preliminary device initialization: enables slot and
+// sets the address.
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful pre-configuration completion
+// = EFI_DEVICE_ERROR on error
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciHcPreConfigureDevice(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 Port,
+ IN UINT8 DeviceSpeed,
+ IN UINT16 TransactionTranslator
+)
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ UINT8 *Device;
+ UINT8 *ParentHubDevice;
+ TRB_RING *XfrRing;
+ UINT8 Speed;
+ static UINT16 aMaxPacketSize[5] = {0, 8, 8, 64, 512};
+ EFI_STATUS Status;
+ UINT8 SlotId;
+ XHCI_INPUT_CONTROL_CONTEXT *CtlCtx;
+ XHCI_SLOT_CONTEXT *SlotCtx;
+ XHCI_SLOT_CONTEXT *ParentHubSlotCtx;
+ XHCI_EP_CONTEXT *Ep0Ctx;
+ UINT8 ParentHubSlotId;
+ UINT8 i;
+
+// XHCI_FIXED_DELAY_MS(Usb3Hc, 1000);
+
+ // Obtain device slot using Enable Slot command, 4.3.2, 4.6.3
+ Status = XhciExecuteCommand(PeiServices, Usb3Hc, XhciTEnableSlotCmd, &SlotId);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+ PEI_ASSERT(PeiServices, SlotId != 0);
+ if (Status != EFI_SUCCESS) return Status;
+
+ Device = (UINT8*)XhciGetDeviceContext(Usb3Hc, SlotId);
+
+ // Update DCBAA with the new device pointer (index = SlotId)
+ Usb3Hc->DcbaaPtr->DevCntxtAddr[SlotId-1] = (UINT64)(UINTN)Device;
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Slot[%d] enabled, device context at %x\n", SlotId, Device));
+
+ // Initialize data structures associated with the slot 4.3.3
+
+ // Zero the InputContext and DeviceContext
+ (**PeiServices).SetMem((UINT8*)Usb3Hc->InputContext, XHCI_INPUT_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0);
+ (**PeiServices).SetMem(Device, XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0);
+
+ // Initialize the Input Control Context of the Input Context
+ // by setting the A0 and A1 flags to 1
+
+ CtlCtx = (XHCI_INPUT_CONTROL_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 0);
+ CtlCtx->AddContextFlags = BIT0 + BIT1;
+
+ // Initialize the Input Slot Context data structure
+ SlotCtx = (XHCI_SLOT_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 1);
+ SlotCtx->RouteString = 0;
+ SlotCtx->ContextEntries = 1;
+ if (TransactionTranslator == 0) {
+ SlotCtx->RootHubPort = Port;
+ } else {
+ Status = GetSlotId(Usb3Hc->DeviceMap, &ParentHubSlotId, (UINT8)(TransactionTranslator & 0xF));
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+ ParentHubDevice = (UINT8*)XhciGetDeviceContext(Usb3Hc, ParentHubSlotId);
+ ParentHubSlotCtx = (XHCI_SLOT_CONTEXT*)XhciGetContextEntry(Usb3Hc, ParentHubDevice, 0);
+ SlotCtx->RootHubPort = ParentHubSlotCtx->RootHubPort;
+ }
+
+ switch (DeviceSpeed) {
+ case USB_HIGH_SPEED_DEVICE: Speed = XHCI_DEVSPEED_HIGH; break;
+ case USB_SLOW_SPEED_DEVICE: Speed = XHCI_DEVSPEED_LOW; break;
+ case USB_FULL_SPEED_DEVICE: Speed = XHCI_DEVSPEED_FULL; break;
+ case USB_SUPER_SPEED_DEVICE: Speed = XHCI_DEVSPEED_SUPER;
+ }
+
+ SlotCtx->Speed = Speed;
+
+ XfrRing = XhciInitXfrRing(Usb3Hc, SlotId, 0);
+
+ // Initialize the Input default control Endpoint 0 Context
+ Ep0Ctx = (XHCI_EP_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 2);
+ Ep0Ctx->EpType = XHCI_EPTYPE_CTL;
+ Ep0Ctx->MaxPacketSize = aMaxPacketSize[Speed];
+ Ep0Ctx->TrDequeuePtr = (UINT64)(UINTN)XfrRing->Base + 1;
+ Ep0Ctx->AvgTrbLength = 8;
+ Ep0Ctx->ErrorCount = 3;
+
+ // Initialize Route String and TT fields
+ if (TransactionTranslator != 0) {
+ if (ParentHubSlotCtx->Speed == XHCI_DEVSPEED_SUPER) {
+ for (i = 0; i < 5; i++) {
+ if (((ParentHubSlotCtx->RouteString >> (i << 2)) & 0xF) == 0) {
+ break;
+ }
+ }
+ SlotCtx->RouteString = ParentHubSlotCtx->RouteString | (Port << (i << 2));
+ } else {
+ // Update TT fields in the Slot context for LS/FS device connected to HS hub
+ if (SlotCtx->Speed == XHCI_DEVSPEED_FULL || SlotCtx->Speed == XHCI_DEVSPEED_LOW) {
+ if(ParentHubSlotCtx->Speed == XHCI_DEVSPEED_HIGH) {
+ SlotCtx->TtHubSlotId = ParentHubSlotId;
+ SlotCtx->TtPortNumber = (UINT8)(TransactionTranslator >> 7);
+ SlotCtx->MultiTT = ParentHubSlotCtx->MultiTT;
+ } else {
+ SlotCtx->TtHubSlotId = ParentHubSlotCtx->TtHubSlotId;
+ SlotCtx->TtPortNumber = ParentHubSlotCtx->TtPortNumber;
+ SlotCtx->MultiTT = ParentHubSlotCtx->MultiTT;
+ }
+ }
+ }
+ }
+
+ // Assign a new address 4.3.4, 4.6.5
+ Status = XhciExecuteCommand(PeiServices, Usb3Hc, XhciTAddressDeviceCmd, &SlotId);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+ if (Status != EFI_SUCCESS) {
+ XhciExecuteCommand(PeiServices, Usb3Hc, XhciTDisableSlotCmd, &SlotId);
+ Usb3Hc->DcbaaPtr->DevCntxtAddr[SlotId-1] = 0;
+ return Status;
+ }
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: new device address %d\n", ((XHCI_SLOT_CONTEXT*)Device)->DevAddr));
+
+ gSlotBeingConfigured = SlotId; // Valid from now til SetAddress
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: UpdateDeviceMap
+//
+// Description:
+// This function updates SlotId<->Address mapping table.
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS if update is successful
+// = EFI_NOT_FOUND if there is no room for a new entry in the map
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UpdateDeviceMap(
+ PEI_XHCI_SLOTADDR_MAP *DeviceMap,
+ UINT8 SlotId,
+ UINT8 DevAddr
+)
+{
+ UINT8 i;
+ PEI_XHCI_SLOTADDR_MAP *Map = DeviceMap;
+
+ for (i = 0; i < PEI_XHCI_MAX_SLOTS; i++, Map++) {
+ if (Map->SlotId == 0) {
+ Map->SlotId = SlotId;
+ Map->DevAddr = DevAddr;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: GetSlotId
+//
+// Description:
+// This function retrieves SlotId from the Slot<->Address mapping table.
+//
+// Output:
+// SlotId variable is updated
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS if update is successful
+// = EFI_NOT_FOUND if the requested Slot is not found in the mapping table
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetSlotId(
+ PEI_XHCI_SLOTADDR_MAP *DeviceMap,
+ UINT8 *SlotId,
+ UINT8 DevAddr
+)
+{
+ UINT8 i;
+ PEI_XHCI_SLOTADDR_MAP *Map = DeviceMap;
+
+ for (i = 0; i < PEI_XHCI_MAX_SLOTS; i++, Map++) {
+ if (Map->DevAddr == DevAddr) {
+ *SlotId = Map->SlotId;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciClearStalledEp
+//
+// Description:
+// This function is called to restart endpoint. After Endpoint STALLs, it
+// transitions from Halted to Stopped state. It is restored back to Running
+// state by moving the endpoint ring dequeue pointer past the failed control
+// transfer with a Set TR Dequeue Pointer. Then it is restarted by ringing the
+// doorbell. Alternatively endpint is restarted using Configure Endpoint command.
+//
+// Input:
+// Stalled EP data - SlotId and DCI
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciClearStalledEp(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 SlotId,
+ UINT8 Dci
+)
+{
+ UINT16 EpInfo;
+ TRB_RING *XfrRing;
+ EFI_STATUS Status;
+ XHCI_SET_TRPTR_CMD_TRB Trb;
+
+ // Reset stalled endpoint
+ EpInfo = (Dci << 8) + SlotId;
+ Status = XhciExecuteCommand(PeiServices, Usb3Hc, XhciTResetEndpointCmd, &EpInfo);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+
+ XfrRing = XhciGetXfrRing(Usb3Hc, SlotId, Dci-1);
+
+ Trb.TrPointer = (UINT64)((UINTN)XfrRing->QueuePtr + XfrRing->CycleBit); // Set up DCS
+ Trb.EndpointId = Dci;
+ Trb.SlotId = SlotId;
+
+ Status = XhciExecuteCommand(PeiServices, Usb3Hc, XhciTSetTRDequeuePointerCmd, &Trb);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciUpdateEp0MaxPacket
+//
+// Description:
+// This function verifies the MaxPacket size of the control pipe. If it does
+// not match the one received as a part of GET_DESCRIPTOR, then this function
+// updates the MaxPacket data in DeviceContext and HC is notified via
+// EvaluateContext command.
+//
+// Input:
+// Usb3Hc Pointer to the HC structure
+// Device Evaluated device context pointer
+// SlotId Device context index in DCBAA
+// Endp0MaxPacket Max packet size obtained from the device
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+XhciUpdateEp0MaxPacket(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 SlotId,
+ UINT8 Endp0MaxPacket
+)
+{
+ UINT8 Status;
+ UINT8 *DevCtx;
+ XHCI_INPUT_CONTROL_CONTEXT *CtlCtx;
+ XHCI_SLOT_CONTEXT *SlotCtx;
+ XHCI_EP_CONTEXT *EpCtx;
+
+ DevCtx = (UINT8*)XhciGetDeviceContext(Usb3Hc, SlotId);
+
+ SlotCtx = (XHCI_SLOT_CONTEXT*)XhciGetContextEntry(Usb3Hc, DevCtx, 0);
+ if (SlotCtx->Speed != XHCI_DEVSPEED_FULL) return;
+
+ EpCtx = (XHCI_EP_CONTEXT*)XhciGetContextEntry(Usb3Hc, DevCtx, 1);
+ if (EpCtx->MaxPacketSize == Endp0MaxPacket) return;
+
+ // Prepare input context for EvaluateContext comand
+ (**PeiServices).SetMem((UINT8*)Usb3Hc->InputContext, XHCI_INPUT_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0);
+
+ CtlCtx = (XHCI_INPUT_CONTROL_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 0);
+ CtlCtx->AddContextFlags = BIT1;
+
+ EpCtx = (XHCI_EP_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 2);
+ EpCtx->MaxPacketSize = Endp0MaxPacket;
+
+ Status = XhciExecuteCommand(PeiServices, Usb3Hc, XhciTEvaluateContextCmd, &SlotId);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: XhciHcControlTransfer
+//
+// Description:
+// This function intiates a USB control transfer and waits on it to
+// complete.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 bDeviceAddress
+// -- USB address of the device for which the control
+// transfer is to be issued
+// IN UINT8 DeviceType
+// -- Not used
+// IN UINT8 MaximumPacketLength
+// -- Maximum number of bytes that can be sent to or
+// received from the endpoint in a single data packet
+// IN EFI_USB_DEVICE_REQUEST *Request
+// -- EFI_USB_DEVICE_REQUEST pointer
+// IN EFI_USB_DATA_DIRECTION TransferDirection
+// -- Direction of transfer
+// OPTIONAL IN OUT VOID *DataBuffer
+// -- Pointer to source or destination buffer
+// OPTIONAL IN OUT UINTN *DataLength
+// -- Length of buffer
+// IN UINTN TimeOut
+// -- Not used
+// OUT UINT32 *TransferResult
+// -- Not used
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciHcControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaximumPacketLength,
+ IN UINT16 TransactionTranslator OPTIONAL,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult )
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ XHCI_TRB *Trb;
+ volatile UINT32 *Doorbell;
+ UINT8 SlotId;
+ UINT8 CompletionCode;
+ UINT8 Status;
+ TRB_RING *XfrRing;
+ UINT16 Rq = ((UINT16)Request->Request << 8) + Request->RequestType;
+
+ // Skip SET_ADDRESS request
+ if (Request->RequestType == USB_DEV_SET_ADDRESS_REQ_TYPE &&
+ Request->Request == USB_DEV_SET_ADDRESS)
+ {
+ Status = UpdateDeviceMap(Usb3Hc->DeviceMap, gSlotBeingConfigured, (UINT8)Request->Value);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+ return EFI_SUCCESS;
+ }
+
+ if (DeviceAddress == 0) {
+ SlotId = gSlotBeingConfigured;
+ } else {
+ Status = GetSlotId(Usb3Hc->DeviceMap, &SlotId, DeviceAddress);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+ }
+
+ // Insert Setup, Data(if needed), and Status TRBs into the transfer ring
+ XfrRing = XhciGetXfrRing(Usb3Hc, SlotId, 0);
+
+ // Setup TRB
+ Trb = XhciAdvanceEnqueuePtr(XfrRing);
+ Trb->TrbType = XhciTSetupStage;
+ ((XHCI_SETUP_XFR_TRB*)Trb)->Idt = 1;
+ *(UINT16*)&((XHCI_SETUP_XFR_TRB*)Trb)->bmRequestType = Rq;
+ ((XHCI_SETUP_XFR_TRB*)Trb)->wValue = Request->Value;
+ ((XHCI_SETUP_XFR_TRB*)Trb)->wIndex = Request->Index;
+ ((XHCI_SETUP_XFR_TRB*)Trb)->wLength = (UINT16)(*DataLength);
+ ((XHCI_SETUP_XFR_TRB*)Trb)->XferLength = 8;
+
+ if (Usb3Hc->HciVersion == 0x100) {
+ if (*DataLength != 0) {
+ if ((Rq & BIT7) != 0) {
+ ((XHCI_SETUP_XFR_TRB*)Trb)->Trt = XHCI_XFER_TYPE_DATA_IN;
+ } else {
+ ((XHCI_SETUP_XFR_TRB*)Trb)->Trt = XHCI_XFER_TYPE_DATA_OUT;
+ }
+ } else {
+ ((XHCI_SETUP_XFR_TRB*)Trb)->Trt = XHCI_XFER_TYPE_NO_DATA;
+ }
+ }
+
+ // Data TRB
+ if (*DataLength != 0) {
+ Trb = XhciAdvanceEnqueuePtr(XfrRing);
+ Trb->TrbType = XhciTDataStage;
+ ((XHCI_DATA_XFR_TRB*)Trb)->Dir = ((Rq & BIT7) != 0)? 1 : 0;
+ ((XHCI_DATA_XFR_TRB*)Trb)->XferLength = *DataLength;
+ ((XHCI_DATA_XFR_TRB*)Trb)->DataBuffer = (UINT64)(UINTN)Data;
+ }
+
+ // Status TRB
+ Trb = XhciAdvanceEnqueuePtr(XfrRing);
+ Trb->TrbType = XhciTStatusStage;
+ ((XHCI_STATUS_XFR_TRB*)Trb)->Ioc = 1;
+ if ((Rq & BIT7) == 0) {
+ ((XHCI_STATUS_XFR_TRB*)Trb)->Dir = 1; // Status is IN
+ }
+
+ // Ring the doorbell and see Event Ring update
+ Doorbell = XhciGetTheDoorbell(Usb3Hc, SlotId);
+ *Doorbell = 1; // Control EP0 Enqueue Pointer Update
+
+ Status = XhciWaitForEvent(
+ PeiServices, Usb3Hc, Trb, XhciTTransferEvt,
+ &CompletionCode, XHCI_CTL_COMPLETE_TIMEOUT_MS, NULL);
+
+
+ if (CompletionCode == XHCI_TRB_STALL_ERROR) {
+ Status = XhciClearStalledEp(PeiServices,
+ Usb3Hc, SlotId, 1); // Dci = 1 for control endpoint
+ return 0;
+ }
+
+ if (Request->Request == USB_DEV_GET_DESCRIPTOR && *DataLength == 8) {
+ // Full speed device requires the update of MaxPacket size
+ XhciUpdateEp0MaxPacket(PeiServices, Usb3Hc, SlotId,
+ ((EFI_USB_DEVICE_DESCRIPTOR*)Data)->MaxPacketSize0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: XhciHcBulkTransfer
+//
+// Description:
+// This function intiates a USB bulk transfer and waits on it to
+// complete.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 DeviceAddress
+// -- USB address of the device for which the control
+// transfer is to be issued
+// IN UINT8 EndPointAddress
+// -- Particular endpoint for the device
+// IN UINT8 MaximumPacketLength
+// -- Maximum number of bytes that can be sent to or
+// received from the endpoint in a single data packet
+// OPTIONAL IN OUT VOID *DataBuffer
+// -- Pointer to source or destination buffer
+// OPTIONAL IN OUT UINTN *DataLength
+// -- Length of buffer
+// IN OUT UINT8 *DataToggle
+// -- Used to update the control/status DataToggle field
+// of the Transfer Descriptor
+// IN UINTN TimeOut
+// -- Not used
+// OUT UINT32 *TransferResult
+// -- Not used
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciHcBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT16 MaximumPacketLength,
+ IN UINT16 TransactionTranslator OPTIONAL,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult )
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ XHCI_TRB *Trb;
+ UINTN FirstTrb;
+ volatile UINT32 *Doorbell;
+ UINT8 SlotId;
+ UINT8 CompletionCode;
+ EFI_STATUS Status;
+ TRB_RING *XfrRing;
+ UINT8 Endpoint;
+ UINT8 Dci;
+ UINT64 DataPointer;
+ UINT32 ResidualData; // Transferred amount return by Transfer Event
+ UINT32 TransferredSize; // Total transfer amount
+ UINT32 RingDataSize; // One TRB ring transfer amount
+ UINT32 RemainingXfrSize;
+ UINT32 RemainingDataSize;
+ UINT32 XfrSize;
+ UINT32 XfrTdSize;
+ UINT32 TdPktCnt;
+ UINT32 TdSize;
+
+ Endpoint = EndPointAddress;
+ Dci = (Endpoint & 0xf)* 2;
+ if (Endpoint & BIT7) Dci++;
+
+ GetSlotId(Usb3Hc->DeviceMap, &SlotId, DeviceAddress);
+
+ Doorbell = XhciGetTheDoorbell(Usb3Hc, SlotId);
+
+ XfrRing = XhciGetXfrRing(Usb3Hc, SlotId, Dci-1);
+
+ // Make a chain of TDs to transfer the requested amount of data. If necessary,
+ // make multiple transfers in a loop.
+
+ DataPointer = (UINTN)Data;
+ RemainingDataSize = *DataLength;
+
+ // Two loops are executing the transfer:
+ // The inner loop creates a transfer ring of chained TDs, XHCI_BOT_TD_MAXSIZE
+ // bytes each. This makes a ring capable of transferring
+ // XHCI_BOT_TD_MAXSIZE * (TRBS_PER_SEGMENT-1) bytes.
+ // The outter loop repeats the transfer if the requested transfer size exceeds
+ // XHCI_BOT_TD_MAXSIZE * (TRBS_PER_SEGMENT-1).
+
+ for (TransferredSize = 0; TransferredSize < *DataLength;) {
+ // Calculate the amount of data to transfer in the ring
+ RingDataSize = (RemainingDataSize > XHCI_BOT_MAX_XFR_SIZE)?
+ XHCI_BOT_MAX_XFR_SIZE : RemainingDataSize;
+
+ RemainingXfrSize = RingDataSize;
+ TdPktCnt = RingDataSize / MaximumPacketLength;
+
+ for (Trb = NULL, XfrSize = 0, FirstTrb = 0; XfrSize < RingDataSize;)
+ {
+ Trb = XhciAdvanceEnqueuePtr(XfrRing);
+ if (FirstTrb == 0) FirstTrb = (UINTN)Trb;
+
+ Trb->TrbType = XhciTNormal;
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->Isp = 1;
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->DataBuffer = DataPointer;
+
+ // See if we need a TD chain. Note that we do not need to
+ // place the chained TRB into Event Ring, since we will not be
+ // looking for it anyway. Set IOC only for the last-in-chain TRB.
+ if (RemainingXfrSize > XHCI_BOT_TD_MAXSIZE) {
+ XfrTdSize = XHCI_BOT_TD_MAXSIZE;
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->Chain = 1;
+ } else {
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->Ioc = 1;
+ XfrTdSize = RemainingXfrSize;
+ }
+ // Data buffers referenced by Transfer TRBs shall not span 64KB boundaries.
+ // If a physical data buffer spans a 64KB boundary, software shall chain
+ // multiple TRBs to describe the buffer.
+ if (XfrTdSize > (UINT32)(0x10000 - (DataPointer & (0x10000 - 1))))
+ {
+ XfrTdSize = (UINT32)(0x10000 - (DataPointer & (0x10000 - 1)));
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->Chain = 1;
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->Ioc = 0;
+ }
+
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->XferLength = XfrTdSize;
+ if(Usb3Hc->HciVersion == 0x100) {
+ TdSize = TdPktCnt - ((XfrSize + XfrTdSize)/MaximumPacketLength);
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->TdSize = (TdSize > 31)? 31 : TdSize;
+ } else {
+ TdSize = RemainingXfrSize - XfrTdSize;
+ ((XHCI_NORMAL_XFR_TRB*)Trb)->TdSize = (TdSize < 32768)? (TdSize >> 10) : 31;
+ }
+
+ XfrSize += XfrTdSize;
+ DataPointer += XfrTdSize;
+ RemainingXfrSize -= XfrTdSize;
+ }
+
+ // If transfer ring crossed Link TRB, set its Chain flag
+ if ((UINTN)Trb < FirstTrb) {
+ ((XHCI_NORMAL_XFR_TRB*)XfrRing->LastTrb)->Chain = 1;
+ }
+
+ // Ring the door bell and see Event Ring update
+ *Doorbell = Dci;
+
+ Status = XhciWaitForEvent(
+ PeiServices, Usb3Hc, Trb, XhciTTransferEvt,
+ &CompletionCode, XHCI_BULK_COMPLETE_TIMEOUT_MS, &ResidualData);
+
+ // Clear Link TRB chain flag
+ ((XHCI_NORMAL_XFR_TRB*)XfrRing->LastTrb)->Chain = 0;
+
+ if (CompletionCode == XHCI_TRB_STALL_ERROR) {
+ XhciClearStalledEp(PeiServices, Usb3Hc, SlotId, Dci);
+ break;
+ }
+ TransferredSize += (RingDataSize - ResidualData);
+ if (ResidualData != 0) break; // Short packet detected, no more transfers
+ RemainingDataSize -= RingDataSize;
+ }
+
+ *DataLength = TransferredSize;
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciHcGetRootHubPortNumber
+//
+// Description:
+// This function returns number of root ports supported by the controller.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciHcGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber )
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+
+ *PortNumber = Usb3Hc->MaxPorts;
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: UpdatePortStatusSpeed
+//
+// Description:
+// This function converts XHCI speed definition into the terms
+// of PEI_USB_HOST_CONTROLLER_PPI (namely XHCI_DEVSPEED_xyz is converted
+// into USB_PORT_STAT_xyz).
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+UpdatePortStatusSpeed(
+ EFI_PEI_SERVICES **PeiServices,
+ UINT8 Speed,
+ UINT16 *PortStatus
+)
+{
+ switch (Speed) {
+ case XHCI_DEVSPEED_UNDEFINED:
+ case XHCI_DEVSPEED_FULL:
+ break;
+ case XHCI_DEVSPEED_LOW:
+ *PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ break;
+ case XHCI_DEVSPEED_HIGH:
+ *PortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ break;
+ case XHCI_DEVSPEED_SUPER:
+ *PortStatus |= USB_PORT_STAT_SUPER_SPEED;
+ break;
+ default:
+ PEI_TRACE((-1, PeiServices, "XHCI ERROR: unknown device speed.\n"));
+ }
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciHcGetRootHubPortStatus
+//
+// Description:
+// Host controller API function; returns root hub port status in terms of
+// PEI_USB_HOST_CONTROLLER_PPI definition.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciHcGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus )
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ volatile XHCI_PORTSC *PortSC;
+
+ // Find the proper MMIO access offset for a given port
+ PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs +
+ XHCI_PORTSC_OFFSET + (0x10 * (PortNumber - 1)));
+
+ PEI_TRACE((-1, PeiServices, "XHCI port[%d] status: %08x\n", PortNumber, PortSC->AllBits));
+
+ *(UINT32*)PortStatus = 0;
+
+ if (PortSC->Field.Ccs != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+ if (PortSC->Field.Ped != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+ if (PortSC->Field.Oca != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;
+ }
+ if (PortSC->Field.Pr != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+ if (PortSC->Field.Pp != 0) {
+ PortStatus->PortStatus |= USB_PORT_STAT_POWER;
+ }
+ if (PortSC->Field.Csc != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+ if (PortSC->Field.Pec != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+ if (PortSC->Field.Occ != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;
+ }
+ if (PortSC->Field.Prc != 0) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;
+ }
+
+ UpdatePortStatusSpeed(PeiServices, PortSC->Field.PortSpeed, &PortStatus->PortStatus);
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciHcSetRootHubPortFeature
+//
+// Description:
+// Host controller PEI_USB_HOST_CONTROLLER_PPI API function; sets a requested
+// feature of a root hub port.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciHcSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature )
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ volatile XHCI_PORTSC *PortSC;
+
+ if (PortNumber > Usb3Hc->MaxPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs +
+ XHCI_PORTSC_OFFSET + (0x10 * (PortNumber - 1)));
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ case EfiUsbPortSuspend:
+ break;
+
+ case EfiUsbPortReset:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) | XHCI_PCS_PR;
+ break;
+
+ case EfiUsbPortPower:
+ PortSC->AllBits = XHCI_PCS_PP;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciHcClearRootHubPortFeature
+//
+// Description:
+// Host controller PEI_USB_HOST_CONTROLLER_PPI API function; clears a requested
+// feature of a root hub port.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS XhciHcClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature )
+{
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ volatile XHCI_PORTSC *PortSC;
+
+ if (PortNumber > Usb3Hc->MaxPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs +
+ XHCI_PORTSC_OFFSET + (0x10 * (PortNumber - 1)));
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) | XHCI_PCS_PED;
+ break;
+
+ case EfiUsbPortSuspend:
+ case EfiUsbPortReset:
+ break;
+
+ case EfiUsbPortPower:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) & ~(XHCI_PCS_PP);
+ break;
+
+ case EfiUsbPortOwner:
+ break;
+
+ case EfiUsbPortConnectChange:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) | XHCI_PCS_CSC;
+ break;
+
+ case EfiUsbPortEnableChange:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) | XHCI_PCS_PEC;
+ break;
+
+ case EfiUsbPortSuspendChange:
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) | XHCI_PCS_OCC;
+ break;
+
+ case EfiUsbPortResetChange:
+ PortSC->AllBits = (PortSC->AllBits & XHCI_PCS_PP) | XHCI_PCS_PRC;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciMmio64Write
+//
+// Description:
+// MMIO write; depending on 64-bit access availability executes either one
+// 64-bit write or two 32-bit writes.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+XhciMmio64Write(
+ USB3_CONTROLLER *Usb3Hc,
+ UINTN Address,
+ UINT64 Data
+)
+{
+ if (Usb3Hc->Access64) {
+ *(UINT64*)Address = Data;
+ }
+ else {
+ *(UINT32*)Address = (UINT32)Data;
+ *(UINT32*)(Address + sizeof(UINT32)) = (UINT32)(Shr64(Data, 32));
+ }
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciInitRing
+//
+// Description:
+// Transfer ring initialization. There is an option to create a Link TRB in
+// the end of the ring.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciInitRing (
+ IN OUT TRB_RING *Ring,
+ IN UINTN RingBase,
+ IN UINT32 RingSize,
+ IN BOOLEAN PlaceLinkTrb
+)
+{
+ XHCI_LINK_TRB *LinkTrb;
+
+ Ring->Base = (XHCI_TRB*)RingBase;
+ Ring->Size = RingSize;
+ Ring->LastTrb = Ring->Base + RingSize - 1;
+ Ring->CycleBit = 1;
+ Ring->QueuePtr = (XHCI_TRB*)RingBase;
+
+ // Initialize ring with zeroes
+ {
+ UINT8 *p = (UINT8*)RingBase;
+ UINTN i;
+ for (i = 0; i < RingSize*sizeof(XHCI_TRB); i++, p++) *p = 0;
+ }
+
+ if (PlaceLinkTrb) {
+ // Place a Link TRB in the end of the ring pointing to the beginning
+ LinkTrb = (XHCI_LINK_TRB*)Ring->LastTrb;
+ LinkTrb->NextSegPtr = (UINT64)(UINTN)RingBase;
+ LinkTrb->ToggleCycle = 1;
+ LinkTrb->TrbType = XhciTLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: XhciAdvanceEnqueuePtr
+//
+// Description:
+// This function advances returns the pointer to the current TRB and anvances
+// dequeue pointer. If the advance pointer is Link TRB, then it: 1) activates
+// Link TRB by updating its cycle bit, 2) updates dequeue pointer to the value
+// pointed by Link TRB.
+//
+// Input:
+// Ring - TRB ring to be updated
+//
+// Output:
+// TRB that can be used for command, transfer, etc.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+XHCI_TRB*
+XhciAdvanceEnqueuePtr(
+ TRB_RING *Ring
+)
+{
+ XHCI_TRB* Trb = Ring->QueuePtr;
+
+ if (Trb->TrbType == XhciTLink) {
+ Trb->CycleBit = Ring->CycleBit;
+ Ring->CycleBit ^= 1;
+ Ring->QueuePtr = Ring->Base;
+
+ Trb = Ring->QueuePtr;
+ }
+ // Clear the TRB
+ {
+ UINT32 *p = (UINT32*)Trb;
+ UINT8 i = 0;
+ for (i=0; i<(sizeof(XHCI_TRB)/sizeof(UINT32)); i++) {
+ *p++ = 0;
+ }
+ }
+
+ Trb->CycleBit = Ring->CycleBit;
+ Ring->QueuePtr++;
+
+ return Trb;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: XHCI_ProcessInterrupt
+//
+// Description: This is the XHCI controller event handler. It walks through
+// the Event Ring and executes the event associated code if needed. Updates
+// the Event Ring Data Pointer in the xHC to let it know which events are
+// completed.
+//
+// Output:
+// EFI_NOT_READY - Need more Interrupt processing
+// EFI_SUCCESS - No interrupts pending
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciProcessInterrupt(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc
+)
+{
+ XHCI_TRB *Trb;
+ XHCI_EVENT_TRB *EvTrb;
+
+ if ((UINT32)Usb3Hc->OpRegs->DcbAap != (UINT32)Usb3Hc->DcbaaPtr) return EFI_SUCCESS;
+/*
+ if (Usb3Hc->OpRegs->UsbSts.Field.Pcd) {
+ XHCI_EnumeratePorts(HcStruc);
+ Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_PCD; // Clear PortChangeDetect
+ }
+*/
+ if (Usb3Hc->OpRegs->UsbSts.Field.Eint)
+ {
+ Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_EVT_INTERRUPT;
+ Usb3Hc->RtRegs->IntRegs[0].IMan |= BIT0;
+ }
+
+ // Check for pending interrupts:
+ // check the USBSTS[3] and IMAN [0] to determine if any interrupt generated
+ if (Usb3Hc->EvtRing.QueuePtr->CycleBit != Usb3Hc->EvtRing.CycleBit) return EFI_SUCCESS;
+
+ // See if there are any TRBs waiting in the event ring
+ //for (Count = 0; Count < Usb3Hc->EvtRing.Size; Count++) {
+ for (;;) {
+ Trb = Usb3Hc->EvtRing.QueuePtr;
+
+ if (Trb->CycleBit != Usb3Hc->EvtRing.CycleBit) break; // past the last
+
+ if (Usb3Hc->EvtRing.QueuePtr == Usb3Hc->EvtRing.LastTrb) {
+ // Reached the end of the ring, wrap around
+ Usb3Hc->EvtRing.QueuePtr = Usb3Hc->EvtRing.Base;
+ Usb3Hc->EvtRing.CycleBit ^= 1;
+ } else {
+ Usb3Hc->EvtRing.QueuePtr++;
+ }
+ // TODO:: error manager
+ if (Trb->CompletionCode == XHCI_TRB_SHORTPACKET) {
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: short packet detected."));
+ }
+
+ if (Trb->CompletionCode == XHCI_TRB_STALL_ERROR) {
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: device STALLs."));
+ }
+
+ if (Trb->CompletionCode != XHCI_TRB_SUCCESS
+ && Trb->CompletionCode != XHCI_TRB_STALL_ERROR
+ && Trb->CompletionCode != XHCI_TRB_SHORTPACKET) {
+ PEI_TRACE((-1, PeiServices, "Trb completion code: %d\n", Trb->CompletionCode));
+ PEI_ASSERT(PeiServices, FALSE);
+ }
+
+ // Process TRB pointed by Usb3Hc->EvtRing->QueuePtr
+ EvTrb = (XHCI_EVENT_TRB*)Trb;
+
+ switch (Trb->TrbType) {
+ case XhciTTransferEvt:
+// very frequent, debug message here might affect timings,
+// uncomment only when needed
+// PEI_TRACE((-1, PeiServices, "TransferEvt\n"));
+
+// DEBUG
+/* XhciProcessXferEvt(
+ PeiServices,
+ Usb3Hc,
+ EvTrb->TransferEvt.TrbPtr,
+ EvTrb->TransferEvt.SlotId,
+ EvTrb->TransferEvt.EndpointId);*/
+ break;
+ case XhciTCmdCompleteEvt:
+ PEI_TRACE((-1, PeiServices, "CmdCompleteEvt\n"));
+ break;
+ case XhciTPortStatusChgEvt:
+ PEI_TRACE((-1, PeiServices, "PortStatusChgEvt, port #%d\n", EvTrb->PortStsChgEvt.PortId));
+ break;
+ case XhciTDoorbellEvt:
+ PEI_TRACE((-1, PeiServices, "DoorbellEvt\n"));
+ break;
+ case XhciTHostControllerEvt:
+ PEI_TRACE((-1, PeiServices, "HostControllerEvt\n"));
+ break;
+ case XhciTDevNotificationEvt:
+ PEI_TRACE((-1, PeiServices, "DevNotificationEvt\n"));
+ break;
+ case XhciTMfIndexWrapEvt:
+ PEI_TRACE((-1, PeiServices, "MfIndexWrapEvt\n"));
+ break;
+ default:
+ PEI_TRACE((-1, PeiServices, "UNKNOWN EVENT\n"));
+ }
+ }
+ //PEI_ASSERT(PeiServices, Count<Usb3Hc->EvtRing.Size); // Event ring is full
+
+ // Update ERDP to inform xHC that we have processed another TRB
+ XhciMmio64Write(Usb3Hc,
+ (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr | BIT3);
+
+ return EFI_SUCCESS; // Set as interrupt processed
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: XhciWaitForEvent
+//
+// Description:
+// This function walks through the active TRBs in the event ring and looks for
+// the command TRB to be complete. If found, returns SlotId and CompletionCode
+// from the completed event TRB. In the end it processes the event ring,
+// adjusting its Dequeue Pointer.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciWaitForEvent(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ XHCI_TRB *TrbToCheck,
+ TRB_TYPE EventType,
+ UINT8 *CompletionCode,
+ UINT16 TimeOutMs,
+ VOID *Data
+)
+{
+ XHCI_TRB *Trb;
+ UINT32 TimeOut;
+ EFI_STATUS Status;
+ UINT8 CycleBit;
+// UINT32 TimeOutValue = TimeOutMs << 6; // *64, 15 us unit
+ UINT32 TimeOutValue = TimeOutMs + 1;
+
+ for (TimeOut = 0; TimeOut < TimeOutValue; TimeOut++) {
+ for (Trb = Usb3Hc->EvtRing.QueuePtr,
+ CycleBit = Usb3Hc->EvtRing.CycleBit;;) {
+ if (Trb->CycleBit != CycleBit) {
+ // Command is not complete, break and retry
+ break;
+ }
+
+ *CompletionCode = Trb->CompletionCode;
+ if (Trb->CompletionCode == XHCI_TRB_STALL_ERROR ||
+ Trb->CompletionCode == XHCI_TRB_TRANSACTION_ERROR) {
+ Status = EFI_DEVICE_ERROR;
+ goto DoneWaiting;
+ }
+
+ // Active TRB found
+ if (Trb->TrbType == EventType) {
+ if ((*(UINTN*)&Trb->Param1) == (UINTN)TrbToCheck) {
+
+ if (Trb->CompletionCode != XHCI_TRB_SUCCESS && Trb->CompletionCode != XHCI_TRB_SHORTPACKET) {
+ PEI_TRACE((-1, PeiServices, "TRB Completion Error: %d\n", Trb->CompletionCode));
+ PEI_ASSERT(PeiServices, FALSE);
+ }
+
+ if (EventType == XhciTCmdCompleteEvt) {
+ *(UINT8*)Data = ((XHCI_CMDCOMPLETE_EVT_TRB*)Trb)->SlotId;
+ }
+ if (EventType == XhciTTransferEvt) {
+ if (Data != NULL) {
+ *(UINT32*)Data = ((XHCI_TRANSFER_EVT_TRB*)Trb)->TransferLength;
+ }
+ }
+
+ Status = (Trb->CompletionCode == XHCI_TRB_SUCCESS ||
+ Trb->CompletionCode == XHCI_TRB_SHORTPACKET)? EFI_SUCCESS:EFI_DEVICE_ERROR;
+ goto DoneWaiting;
+ }
+ }
+ // Advance TRB pointer
+ if (Trb == Usb3Hc->EvtRing.LastTrb) {
+ Trb = Usb3Hc->EvtRing.Base;
+ CycleBit ^= 1;
+ } else {
+ Trb++;
+ }
+ if (Trb == Usb3Hc->EvtRing.QueuePtr) {
+ // Event ring is full, return error
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Event Ring is full...\n"));
+ PEI_ASSERT(PeiServices, FALSE);
+ *CompletionCode = XHCI_TRB_EVENTRINGFULL_ERROR;
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ }
+// XHCI_FIXED_DELAY_15MCS(Usb3Hc, 1); // 15 us out of TimeOutMs
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 1); // 1 ms out of TimeOutMs
+ }
+
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: execution time-out.\n"));
+
+ *CompletionCode = XHCI_TRB_EXECUTION_TIMEOUT_ERROR;
+ Status = EFI_DEVICE_ERROR;
+
+DoneWaiting:
+ XhciProcessInterrupt(PeiServices, Usb3Hc);
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: XhciExecuteCommand
+//
+// Description:
+// This function places a given command in the Command Ring, rings HC doorbell,
+// and waits for the command completion.
+//
+// Output:
+// EFI_DEVICE_ERROR on execution failure, otherwise EFI_SUCCESS
+// Params - pointer to the command specific data.
+//
+// Notes:
+// Caller is responsible for a data placeholder.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciExecuteCommand(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ TRB_TYPE Cmd,
+ VOID *Params
+)
+{
+ volatile UINT32 *Doorbell;
+ UINT8 CompletionCode;
+ UINT8 SlotId;
+ EFI_STATUS Status;
+ XHCI_TRB *Trb = XhciAdvanceEnqueuePtr(&Usb3Hc->CmdRing);
+
+ Trb->TrbType = Cmd; // Set TRB type
+
+ // Fill in the command TRB fields
+ switch (Cmd) {
+ case XhciTAddressDeviceCmd:
+ case XhciTEvaluateContextCmd:
+ case XhciTConfigureEndpointCmd:
+ ((XHCI_ADDRESSDEV_CMD_TRB*)Trb)->InpCtxAddress = (UINT64)(UINTN)Usb3Hc->InputContext;
+ ((XHCI_ADDRESSDEV_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params);
+ ((XHCI_ADDRESSDEV_CMD_TRB*)Trb)->Bsr = 0;
+ break;
+ case XhciTResetEndpointCmd:
+ ((XHCI_RESET_EP_CMD_TRB*)Trb)->Tsp = 0;
+ ((XHCI_RESET_EP_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params);
+ ((XHCI_RESET_EP_CMD_TRB*)Trb)->EndpointId = *((UINT8*)Params+1);
+ break;
+ case XhciTSetTRDequeuePointerCmd:
+ ((XHCI_SET_TRPTR_CMD_TRB*)Trb)->TrPointer = ((XHCI_SET_TRPTR_CMD_TRB*)Params)->TrPointer;
+ ((XHCI_SET_TRPTR_CMD_TRB*)Trb)->EndpointId = ((XHCI_SET_TRPTR_CMD_TRB*)Params)->EndpointId;
+ ((XHCI_SET_TRPTR_CMD_TRB*)Trb)->SlotId = ((XHCI_SET_TRPTR_CMD_TRB*)Params)->SlotId;
+ break;
+ case XhciTDisableSlotCmd:
+ ((XHCI_DISABLESLOT_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params);
+ break;
+ }
+
+ // Ring the door bell and see Event Ring update
+ Doorbell = (UINT32*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->DbOffset);
+ *Doorbell = 0; // HC doorbell is #0
+
+ Status = XhciWaitForEvent(
+ PeiServices, Usb3Hc, Trb, XhciTCmdCompleteEvt,
+ &CompletionCode, XHCI_CMD_COMPLETE_TIMEOUT_MS, &SlotId);
+
+ if (Status == EFI_DEVICE_ERROR) {
+ PEI_TRACE((-1, PeiServices, "XHCI command completion error code: %d\n", CompletionCode));
+ PEI_ASSERT(PeiServices, Status != EFI_DEVICE_ERROR);
+ return Status;
+ }
+
+ switch (Cmd) {
+ case XhciTEnableSlotCmd:
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Enable Slot command complete, SlotID %d\n", SlotId));
+ *((UINT8*)Params) = SlotId;
+ break;
+ case XhciTEvaluateContextCmd:
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Evaluate Context command complete.\n"));
+ break;
+ case XhciTConfigureEndpointCmd:
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Configure Endpoint command complete.\n"));
+ break;
+ case XhciTResetEndpointCmd:
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Reset Endpoint command complete (slot#%x dci#%x).\n",
+ *((UINT8*)Params), *((UINT8*)Params+1)));
+ break;
+ case XhciTSetTRDequeuePointerCmd:
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: Set TR pointer command complete.\n"));
+ break;
+ case XhciTDisableSlotCmd:
+ PEI_TRACE((-1, PeiServices, "PEI_XHCI: DisableSlot command complete.\n"));
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciInitXfrRing
+//
+// Description:
+// This function initializes transfer ring of given endpoint
+//
+// Output:
+// Pointer to the transfer ring
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+TRB_RING*
+XhciInitXfrRing(
+ USB3_CONTROLLER* Usb3Hc,
+ UINT8 Slot,
+ UINT8 Ep
+)
+{
+ TRB_RING *XfrRing = Usb3Hc->XfrRings + (Slot-1)*32 + Ep;
+ UINTN Base = Usb3Hc->XfrTrbs + ((Slot-1)*32+Ep)*RING_SIZE;
+
+ XhciInitRing(XfrRing, Base, TRBS_PER_SEGMENT, TRUE);
+
+ return XfrRing;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciTranslateInterval
+//
+// Description:
+// This routine calculates the Interval field to be used in device's endpoint
+// context. Interval is calculated using the following rules (Section 6.2.3.6):
+//
+// For SuperSpeed bulk and control endpoints, the Interval field shall not be
+// used by the xHC. For all other endpoint types and speeds, system software
+// shall translate the bInterval field in the USB Endpoint Descriptor to the
+// appropriate value for this field.
+//
+// For high-speed and SuperSpeed Interrupt and Isoch endpoints the bInterval
+// field the Endpoint Descriptor is computed as 125æs * 2^(bInterval-1), where
+// bInterval = 1 to 16, therefore Interval = bInterval - 1.
+//
+// For low-speed Interrupt and full-speed Interrupt and Isoch endpoints the
+// bInterval field declared by a Full or Low-speed device is computed as
+// bInterval * 1ms., where bInterval = 1 to 255.
+//
+// For Full- and Low-speed devices software shall round the value of Endpoint
+// Context Interval field down to the nearest base 2 multiple of bInterval * 8.
+//
+// Input:
+// EpType Endpoint type, see XHCI_EP_CONTEXT.DW1.EpType field definitions
+// Speed Endpoint speed, 1..4 for XHCI_DEVSPEED_FULL, _LOW, _HIGH, _SUPER
+// Interval Poll interval value from endpoint descriptor
+//
+// Output:
+// Interval value to be written to the endpoint context
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+XhciTranslateInterval(
+ UINT8 EpType,
+ UINT8 Speed,
+ UINT8 Interval
+)
+{
+ UINT8 TempData;
+ UINT8 BitCount;
+
+ if (EpType == XHCI_EPTYPE_CTL ||
+ EpType == XHCI_EPTYPE_BULK_OUT ||
+ EpType == XHCI_EPTYPE_BULK_IN) {
+
+ if (Speed == XHCI_DEVSPEED_HIGH) {
+ return Interval;
+ } else {
+ return 0; // Interval field will not be used for LS, FS and SS
+ }
+ }
+
+ // Control and Bulk endpoints are processed; translate intervals for Isoc and Interrupt
+ // endpoints
+
+ // Translate SS and HS endpoints
+ if (Speed == XHCI_DEVSPEED_SUPER || Speed == XHCI_DEVSPEED_HIGH) {
+ return (Interval - 1);
+ }
+
+ for (TempData = Interval, BitCount = 0; TempData != 0; BitCount++) {
+ TempData >>= 1;
+ }
+ return (BitCount + 2); // return value, where Interval = 0.125*2^value
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciEnableEndpoints
+//
+// Description:
+// This function parses the device descriptor data and enables the endpoints
+// by 1)assigning the Transfer TRB and 2)executing ConfigureEndpoint command
+// for the slot. Section 4.3.5.
+//
+// Input:
+// Desc - Device Configuration Descriptor data pointer
+//
+// Output:
+// EFI_DEVICE_ERROR on error, EFI_SUCCESS on success
+//
+// Notes:
+// 1) This call is executed before SET_CONFIGURATION control transfer
+// 2) Device slot is addressed by gSlotBeingConfigured
+// 3) EP0 information is valid in the Device
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciEnableEndpoints (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 *Desc
+)
+{
+ UINT16 TotalLength;
+ UINT16 CurPos;
+ UINT8 Dci;
+ EFI_USB_INTERFACE_DESCRIPTOR *IntrfDesc;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ TRB_RING *XfrRing;
+ UINT8 EpType;
+ UINT8 Status;
+ UINT8 IsHub;
+ UINT8 DevSpeed;
+ XHCI_INPUT_CONTROL_CONTEXT *CtlCtx;
+ XHCI_SLOT_CONTEXT *SlotCtx;
+ XHCI_EP_CONTEXT *EpCtx;
+
+ USB3_CONTROLLER *Usb3Hc = PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS(This);
+ UINT8 SlotId = gSlotBeingConfigured;
+ UINT8 *DevCtx = (UINT8*)XhciGetDeviceContext(Usb3Hc, SlotId);
+
+ if (((EFI_USB_CONFIG_DESCRIPTOR*)Desc)->DescriptorType != USB_DT_CONFIG) return EFI_DEVICE_ERROR;
+
+ SlotCtx = (XHCI_SLOT_CONTEXT*)XhciGetContextEntry(Usb3Hc, DevCtx, 0);
+ DevSpeed = SlotCtx->Speed;
+
+ // Note (From 4.6.6): The Add Context flag A1 and Drop Context flags D0 and D1
+ // of the Input Control Context (in the Input Context) shall be cleared to 0.
+ // Endpoint 0 Context does not apply to the Configure Endpoint Command and
+ // shall be ignored by the xHC. A0 shall be set to 1.
+
+ // Note (From 6.2.2.2): If Hub = 1 and Speed = High-Speed (3), then the
+ // TT Think Time and Multi-TT (MTT) fields shall be initialized.
+ // If Hub = 1, then the Number of Ports field shall be initialized, else
+ // Number of Ports = 0.
+
+ // Prepare input context for EvaluateContext comand
+ (**PeiServices).SetMem((UINT8*)Usb3Hc->InputContext, XHCI_INPUT_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0);
+
+ CtlCtx = (XHCI_INPUT_CONTROL_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 0);
+ CtlCtx->AddContextFlags = BIT0; // EP0
+
+ SlotCtx = (XHCI_SLOT_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 1);
+
+ // Collect the endpoint information and update the Device Input Context
+ TotalLength = ((EFI_USB_CONFIG_DESCRIPTOR*)Desc)->TotalLength;
+
+ if (TotalLength > (MAX_CONTROL_DATA_SIZE - 1)) {
+ TotalLength = MAX_CONTROL_DATA_SIZE - 1;
+ }
+
+ for (CurPos = 0; CurPos < TotalLength; CurPos += EpDesc->Length) {
+ EpDesc = (EFI_USB_ENDPOINT_DESCRIPTOR*)(IntrfDesc = (EFI_USB_INTERFACE_DESCRIPTOR*)(Desc + CurPos));
+
+ if (IntrfDesc->DescriptorType == USB_DT_INTERFACE) {
+ IsHub = IntrfDesc->InterfaceClass == BASE_CLASS_HUB;
+ continue;
+ }
+
+ if (EpDesc->DescriptorType != USB_DT_ENDPOINT) continue;
+
+ // Found Endpoint, fill up the information in the InputContext
+
+ // Calculate Device Context Index (DCI), Section 4.5.1.
+ // 1) For Isoch, Interrupt, or Bulk type endpoints the DCI is calculated
+ // from the Endpoint Number and Direction with the following formula:
+ // DCI = (Endpoint Number * 2) + Direction, where Direction = 0 for OUT
+ // endpoints and 1 for IN endpoints.
+ // 2) For Control type endpoints:
+ // DCI = (Endpoint Number * 2) + 1
+ //
+ // Also calculate XHCI EP type out of EpDesc->bEndpointFlags
+
+ if ((EpDesc->Attributes & EP_DESC_FLAG_TYPE_BITS) == EP_DESC_FLAG_TYPE_CONT) {
+ Dci = (EpDesc->EndpointAddress & 0xf) * 2 + 1;
+ EpType = XHCI_EPTYPE_CTL;
+ } else {
+ // Isoc, Bulk or Interrupt endpoint
+ Dci = (EpDesc->EndpointAddress & 0xf) * 2;
+ EpType = EpDesc->Attributes & EP_DESC_FLAG_TYPE_BITS; // 1, 2, or 3
+
+ if (EpDesc->EndpointAddress & BIT7) {
+ Dci++; // IN
+ EpType += 4; // 5, 6, or 7
+ }
+ }
+
+ // Update ContextEntries in the Slot context
+ if (Dci > SlotCtx->ContextEntries) {
+ SlotCtx->ContextEntries = Dci;
+ }
+
+ EpCtx = (XHCI_EP_CONTEXT*)XhciGetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, Dci + 1);
+
+ EpCtx->EpType = EpType;
+ EpCtx->MaxPacketSize = EpDesc->MaxPacketSize;
+ EpCtx->ErrorCount = 3;
+
+ // Set Interval
+ EpCtx->Interval = XhciTranslateInterval(EpType, DevSpeed, EpDesc->Interval);
+
+ XfrRing = XhciInitXfrRing(Usb3Hc, SlotId, Dci - 1);
+ EpCtx->TrDequeuePtr = (UINT64)(UINTN)XfrRing->Base + 1;
+
+ CtlCtx->AddContextFlags |= (1 << Dci);
+ }
+
+ // For a HUB update NumberOfPorts and TTT fields in the Slot context. For that get hub descriptor
+ // and use bNbrPorts and TT Think time fields (11.23.2.1 of USB2 specification)
+ // Notes:
+ // - Slot.Hub field is already updated
+ // - Do not set NumberOfPorts and TTT fields for 0.95 controllers
+
+ if (IsHub) {
+
+ EFI_STATUS Status;
+ EFI_USB_HUB_DESCRIPTOR HubDesc;
+ UINT8 Speed;
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT32 Timeout;
+ UINTN DataLength = sizeof(EFI_USB_HUB_DESCRIPTOR);
+ UINT32 TransferResult;
+
+ //
+ // Fill Device request packet
+ //
+ (**PeiServices).SetMem((VOID*)&DevReq, sizeof(EFI_USB_DEVICE_REQUEST), 0);
+ DevReq.RequestType = USB_RT_HUB | 0x80;
+ DevReq.Request = USB_DEV_GET_DESCRIPTOR;
+ DevReq.Value = DevSpeed == XHCI_DEVSPEED_SUPER ? USB_DT_SS_HUB << 8 : USB_DT_HUB << 8;
+ DevReq.Index = 0;
+ DevReq.Length = sizeof(EFI_USB_HUB_DESCRIPTOR);
+
+ Timeout = 3000;
+
+ switch (DevSpeed) {
+ case XHCI_DEVSPEED_HIGH: Speed = USB_HIGH_SPEED_DEVICE; break;
+ case XHCI_DEVSPEED_LOW: Speed = USB_SLOW_SPEED_DEVICE; break;
+ case XHCI_DEVSPEED_FULL: Speed = USB_FULL_SPEED_DEVICE; break;
+ case XHCI_DEVSPEED_SUPER: Speed = USB_SUPER_SPEED_DEVICE;
+ }
+
+ EpCtx = (XHCI_EP_CONTEXT*)XhciGetContextEntry(Usb3Hc, DevCtx, 1);
+
+ Status = XhciHcControlTransfer(PeiServices, This,
+ 0, // Current address
+ Speed,
+ EpCtx->MaxPacketSize,
+ 0, // Transaction translator
+ &DevReq,
+ EfiUsbDataIn,
+ &HubDesc,
+ &DataLength,
+ Timeout,
+ &TransferResult);
+
+ if (!EFI_ERROR(Status)) {
+ SlotCtx->Hub = 1;
+ SlotCtx->PortsNum = HubDesc.NbrPorts;
+
+ if (DevSpeed == XHCI_DEVSPEED_HIGH) {
+ SlotCtx->TThinkTime = (HubDesc.HubCharacteristics[0] >> 5) & 0x3;
+ }
+ }
+ }
+
+// check route string here
+ // Input context is updated with the endpoint information. Execute ConfigureEndpoint command.
+ Status = XhciExecuteCommand(PeiServices, Usb3Hc, XhciTConfigureEndpointCmd, &SlotId);
+ PEI_ASSERT(PeiServices, Status == EFI_SUCCESS);
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciGetXfrRing
+//
+// Description:
+// This routine calculates the address of the address ring of a particular
+// Slot/Endpoint.
+//
+// Output:
+// Pointer to the transfer ring
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+TRB_RING*
+XhciGetXfrRing(
+ USB3_CONTROLLER* Usb3Hc,
+ UINT8 Slot,
+ UINT8 Ep
+)
+{
+ return Usb3Hc->XfrRings + (Slot-1)*32 + Ep;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: XhciGetTheDoorbell
+//
+// Description:
+// This function calculates and returns the pointer to a doorbell for a
+// given Slot.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32*
+XhciGetTheDoorbell(
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 SlotId
+)
+{
+ return (UINT32*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->DbOffset + sizeof(UINT32)*SlotId);
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: XhciGetDeviceContext
+//
+// Description:
+// This function calculates and returns the pointer to a device context for
+// a given Slot.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8*
+XhciGetDeviceContext(
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 SlotId
+)
+{
+ UINT32 DevCtxSize = XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize;
+ return (UINT8*)((UINTN)Usb3Hc->DeviceContext + (SlotId - 1) * DevCtxSize);
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: XhciGetContextEntry
+//
+// Description:
+// This function calculates and returns the pointer to a context entry for
+// a given index.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8*
+XhciGetContextEntry(
+ USB3_CONTROLLER *Usb3Hc,
+ VOID *Context,
+ UINT8 Index
+)
+{
+ return (UINT8*)((UINTN)Context + Index * Usb3Hc->ContextSize);
+}
+ //(EIP75547+)>
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciEnableUsb2Port
+//
+// Description:
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+XhciResetUsb2Port(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc
+)
+{
+ UINT8 Count;
+ UINT8 PortNumber;
+ volatile XHCI_PORTSC *PortSC;
+ UINT32 i;
+
+ if (Usb3Hc->Usb2Protocol) {
+ for(Count = 0; Count < Usb3Hc->Usb2Protocol->PortCount; Count++) {
+ PortNumber = Count + Usb3Hc->Usb2Protocol->PortOffset;
+ PortSC =(XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs +
+ XHCI_PORTSC_OFFSET + (0x10 * (PortNumber - 1)));
+ if (PortSC->Field.Ccs) {
+ if(!(PortSC->Field.Ped)) {
+ PortSC->AllBits = XHCI_PCS_PR | XHCI_PCS_PP;
+ for (i = 0; i < 200; i++) {
+ XHCI_FIXED_DELAY_MS(Usb3Hc, 1);
+ if (PortSC->Field.Prc) break;
+ }
+ PortSC->AllBits = XHCI_PCS_WRC | XHCI_PCS_PRC | XHCI_PCS_PP;
+ }
+ }
+ }
+ }
+
+ }
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Name: XhciExtCapParser
+//
+// Description:
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+XhciExtCapParser(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc
+)
+{
+ XHCI_EXT_CAP *CurPtr;
+
+ if (Usb3Hc->CapRegs->HcParams.Xecp == 0) return EFI_SUCCESS;
+
+ // Starts from first capability
+ CurPtr = (XHCI_EXT_CAP *)((UINTN)Usb3Hc->CapRegs + (Usb3Hc->CapRegs->HcParams.Xecp << 2));
+
+ // Traverse all capability structures
+ for(;;) {
+ switch (CurPtr->CapId) {
+ case XHCI_EXT_CAP_USB_LEGACY:
+ break;
+ case XHCI_EXT_CAP_SUPPORTED_PROTOCOL:
+ if (((XHCI_EXT_PROTOCOL*)CurPtr)->MajorRev == 0x02) {
+ Usb3Hc->Usb2Protocol = (XHCI_EXT_PROTOCOL*)CurPtr;
+ PEI_TRACE((-1, PeiServices, "XHCI: USB2 Support Protocol %x, PortOffset %x PortCount %x\n",
+ Usb3Hc->Usb2Protocol, Usb3Hc->Usb2Protocol->PortOffset, Usb3Hc->Usb2Protocol->PortCount));
+ } else if (((XHCI_EXT_PROTOCOL*)CurPtr)->MajorRev == 0x03) {
+ Usb3Hc->Usb3Protocol = (XHCI_EXT_PROTOCOL*)CurPtr;
+ PEI_TRACE((-1, PeiServices, "XHCI: USB3 Support Protocol %x, PortOffset %x PortCount %x\n",
+ Usb3Hc->Usb3Protocol, Usb3Hc->Usb3Protocol->PortOffset, Usb3Hc->Usb3Protocol->PortCount));
+ }
+ break;
+
+ case XHCI_EXT_CAP_POWERMANAGEMENT:
+ case XHCI_EXT_CAP_IO_VIRTUALIZATION:
+ case XHCI_EXT_CAP_USB_DEBUG_PORT:
+ break;
+ }
+ if(CurPtr->NextCapPtr == 0) break;
+ // Point to next capability
+ CurPtr=(XHCI_EXT_CAP *)((UINTN)CurPtr+ (((UINTN)CurPtr->NextCapPtr) << 2));
+ }
+
+ return EFI_SUCCESS;
+}
+ //(EIP75547+)
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2010, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/UsbRecovery/XhciPEI/XhciPei.cif b/Core/EM/UsbRecovery/XhciPEI/XhciPei.cif
new file mode 100644
index 0000000..918bf2a
--- /dev/null
+++ b/Core/EM/UsbRecovery/XhciPEI/XhciPei.cif
@@ -0,0 +1,9 @@
+<component>
+ name = "XhciPei"
+ category = ModulePart
+ LocalRoot = "core\em\UsbRecovery\XhciPEI\"
+ RefName = "XhciPei"
+[files]
+"XhciPei.c"
+"XhciPei.h"
+<endComponent>
diff --git a/Core/EM/UsbRecovery/XhciPEI/XhciPei.h b/Core/EM/UsbRecovery/XhciPEI/XhciPei.h
new file mode 100644
index 0000000..bb9f667
--- /dev/null
+++ b/Core/EM/UsbRecovery/XhciPEI/XhciPei.h
@@ -0,0 +1,1245 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2010, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//**********************************************************************
+//
+// $Header: /Alaska/SOURCE/Modules/USBRecovery/XhciPei.h 5 11/24/12 5:45a Ryanchou $
+//
+// $Revision: 5 $
+//
+// $Date: 11/24/12 5:45a $
+//
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/USBRecovery/XhciPei.h $
+//
+// 5 11/24/12 5:45a Ryanchou
+// [TAG] EIP103990
+// [Category] Improvement
+// [Description] Synchronized with USB PEI module 4.6.3_USB_08.10.24.
+// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c,
+// BotPeim.c, BotPeim.h, PeiAtapi.c, UsbBotPeim.c, UsbBotPeim.h,
+// HubPeim.c, UsbPeim.c, XhciPei.c, XhciPei.h, HubPeim.h, PeiUsbLib.c,
+// PeiUsbLib.h, UsbPeim.h
+//
+// 4 4/24/12 10:19p Wilsonlee
+// [TAG] EIP75547
+// [Category] Bug Fix
+// [Severity] Normal
+// [Symptom] Xhci recovery funtion failed when SS devices on USB 3.0
+// port.
+// [RootCause] The SS device connected to USB2 port.
+// [Solution] Reset the USB2 port when initial xhci controller, then the
+// SS device reconnect to USB3 port.
+// [Files] XhciPei.c, XhciPei.h
+//
+// 3 1/18/11 1:09a Ryanchou
+// [TAG] EIP47931
+// [Category] Improvement
+// [Description] Added USB 3.0 hub support.
+// [Files] EhciPei.c, EhciPei.h, HubPeim.c, HubPeim.h, OhciPei.c,
+// OhciPei.h, UhcPeim.c, UhcPeim.h, usb.h, UsbHostController.h,
+// UsbIoPeim.c, UsbPeim.c, UsbPeim.h, XhciPei.c, XhciPei.h
+//
+// 2 1/17/11 7:09a Ryanchou
+// [TAG] EIP48013
+// [Category] Improvement
+// [Description] Use 32 or 64 byte Context data structures dynamically.
+// [Files] XhciPei.c, XhciPei.h
+//
+// 1 10/11/10 4:53p Olegi
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------------
+//
+// Name: XhciPei.h
+//
+// Description:
+// This file is the main header file for the EHCI PEI USB recovery module. It
+// contains generic constant and type declarations/definitions.
+//
+//----------------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#ifndef _XHCIPEI_H
+#define _XHCIPEI_H
+
+#include <PEI.h>
+#include "PPI\UsbHostController.h"
+#include "PPI\Stall.h"
+
+//----------------------------------------------------------------------------
+// XHCI_PCI_ADDRESS( ControllerIndex, Register )
+//
+// allows easy generation of a valid PCI address using an index into the
+// gXhciControllerPciTable and a register number
+#define XHCI_PCI_ADDRESS( ControllerIndex, Register ) PEI_PCI_CFG_ADDRESS( \
+ gXhciControllerPciTable[ControllerIndex].Bus, \
+ gXhciControllerPciTable[ControllerIndex].Device, \
+ gXhciControllerPciTable[ControllerIndex].Function, \
+ Register )
+
+#define XHCI_FIXED_DELAY_MS( Usb3Hc, milliseconds ) \
+ Usb3Hc->StallPpi->Stall( Usb3Hc->PeiServices, Usb3Hc->StallPpi, milliseconds * 1000 );
+
+#define XHCI_FIXED_DELAY_15MCS( Usb3Hc, units ) \
+ Usb3Hc->StallPpi->Stall( Usb3Hc->PeiServices, Usb3Hc->StallPpi, units * 15 );
+
+// CountTime(milliseconds * 1000, PM_BASE_ADDRESS);
+
+#define XHCI_SWITCH2SS_DELAY_MS 5
+#define MAX_CONTROL_DATA_SIZE 0x200
+
+#define EP_DESC_FLAG_TYPE_BITS 0x03 //Bit 1-0: Indicate type of transfer on endpoint
+#define EP_DESC_FLAG_TYPE_CONT 0x00 //Bit 1-0: 00 = Endpoint does control transfers
+#define EP_DESC_FLAG_TYPE_ISOC 0x01 //Bit 1-0: 01 = Endpoint does isochronous transfers
+#define EP_DESC_FLAG_TYPE_BULK 0x02 //Bit 1-0: 10 = Endpoint does bulk transfers
+#define EP_DESC_FLAG_TYPE_INT 0x03 //Bit 1-0: 11 = Endpoint does interrupt transfers
+
+#pragma pack(push,1)
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+} PCI_BUS_DEV_FUNCTION;
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT32 Register;
+ UINT8 Size;
+ UINT32 SetBits;
+ UINT32 ClearBits;
+} PCI_DEV_REGISTER_VALUE;
+/*
+typedef struct {
+ UINT8 bDescLength;
+ UINT8 bDescType;
+ UINT16 wUsbSpecVersion;
+ UINT8 bBaseClass;
+ UINT8 bSubClass;
+ UINT8 bProtocol;
+ UINT8 bEndp0MaxPacket;
+ UINT16 wVendorId;
+ UINT16 wDeviceId;
+ UINT16 wDeviceRev;
+ UINT8 bMfgStr;
+ UINT8 bProductStr;
+ UINT8 bSerialStr;
+ UINT8 bNumConfigs;
+} DEV_DESC;
+
+typedef struct {
+ UINT8 bDescLength;
+ UINT8 bDescType;
+ UINT16 wTotalLength;
+ UINT8 bNumInterfaces;
+ UINT8 bConfigValue;
+ UINT8 bConfigString;
+ UINT8 bConfigFlags;
+ UINT8 bConfigPower;
+} CNFG_DESC;
+
+typedef struct {
+ UINT8 bDescLength;
+ UINT8 bDescType;
+ UINT8 bInterfaceNum;
+ UINT8 bAltSettingNum;
+ UINT8 bNumEndpoints;
+ UINT8 bBaseClass;
+ UINT8 bSubClass;
+ UINT8 bProtocol;
+ UINT8 bInterfaceString;
+}INTRF_DESC;
+
+typedef struct {
+ UINT8 bDescLength;
+ UINT8 bDescType;
+ UINT8 bNumPorts; // Number of downstream ports on hub
+ UINT16 wHubFlags; // See HUB_FLAG_xxx bit definitions below
+ UINT8 bPowerOnDelay; // Time to delay after turning on power to port (in 2ms units)
+ UINT8 bHubControlAmps; // Milliamps of current needed by hub controller
+
+ UINT8 bDeviceRemovable; // Variable size array of bits (one for each port)
+} HUB_DESC;
+
+typedef struct {
+ UINT8 bDescLength;
+ UINT8 bDescType;
+ UINT8 bEndpointAddr;
+ UINT8 bEndpointFlags;
+ UINT16 wMaxPacketSize;
+ UINT8 bPollInterval;
+} ENDP_DESC;
+*/
+// XHCI_EP_CONTEXT.DW0.State definitions
+#define XHCI_EP_STATE_DISABLED 0
+#define XHCI_EP_STATE_RUNNING 1
+#define XHCI_EP_STATE_HALTED 2
+#define XHCI_EP_STATE_STOPPED 3
+#define XHCI_EP_STATE_ERROR 4
+
+// XHCI_EP_CONTEXT.DW1.EpType definitions
+#define XHCI_EP_TYPE_NOTVALID 0
+#define XHCI_EP_TYPE_ISO_OUT 1
+#define XHCI_EP_TYPE_BLK_OUT 2
+#define XHCI_EP_TYPE_INT_OUT 3
+#define XHCI_EP_TYPE_CONTROL 4
+#define XHCI_EP_TYPE_ISO_IN 5
+#define XHCI_EP_TYPE_BLK_IN 6
+#define XHCI_EP_TYPE_INT_IN 7
+
+//---------------------------------------------------------
+// Device context definition
+//---------------------------------------------------------
+
+// TRB completion codes Table 130
+#define XHCI_TRB_INVALID 0
+#define XHCI_TRB_SUCCESS 1
+#define XHCI_TRB_DATABUF_ERROR 2
+#define XHCI_TRB_BABBLE_ERROR 3
+#define XHCI_TRB_TRANSACTION_ERROR 4
+#define XHCI_TRB_TRB_ERROR 5
+#define XHCI_TRB_STALL_ERROR 6
+#define XHCI_TRB_RESOURCE_ERROR 7
+#define XHCI_TRB_BANDWIDTH_ERROR 8
+#define XHCI_TRB_OUTOFSLOTS_ERROR 9
+#define XHCI_TRB_INVALIDSTREAMTYPE_ERROR 10
+#define XHCI_TRB_SLOTNOTENABLED_ERROR 11
+#define XHCI_TRB_ENDPOINTNOTENABLED_ERROR 12
+#define XHCI_TRB_SHORTPACKET 13
+#define XHCI_TRB_RINGUNDERRUN 14
+#define XHCI_TRB_RINGOVERRUN 15
+#define XHCI_TRB_VFRINGFULL_ERROR 16
+#define XHCI_TRB_PARAMETER_ERROR 17
+#define XHCI_TRB_BANDWIDTHOVERRUN_ERROR 18
+#define XHCI_TRB_CONTEXTSTATE_ERROR 19
+#define XHCI_TRB_NOPINGRESPONSE_ERROR 20
+#define XHCI_TRB_EVENTRINGFULL_ERROR 21
+#define XHCI_TRB_MISSEDSERVICE_ERROR 23
+#define XHCI_TRB_CMDRINGSTOPPED 24
+#define XHCI_TRB_COMMANDABORTED 25
+#define XHCI_TRB_STOPPED 26
+#define XHCI_TRB_STOPPEDLENGTHINVALID 27
+#define XHCI_TRB_CONTROLABORT_ERROR 28
+#define XHCI_TRB_ISOCHBUFOVERRUN 31
+#define XHCI_TRB_EVENTLOST_ERROR 32
+#define XHCI_TRB_UNDEFINED_ERROR 33
+#define XHCI_TRB_INVALIDSTREAMID_ERROR 34
+#define XHCI_TRB_SECONDARYBANDWIDTH_ERROR 35
+#define XHCI_TRB_SPLITTRANSACTION_ERROR 36
+
+#define XHCI_TRB_EXECUTION_TIMEOUT_ERROR 255
+
+//---------------------------------------------------------
+// Transfer Descriptor Block (TRB) definitions, section 4.11
+//---------------------------------------------------------
+// TRB Template
+typedef struct {
+ UINT32 Param1;
+ UINT32 Param2;
+
+ UINT32 RsvdZ1 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ3 : 16;
+} XHCI_TRB;
+
+// Event TRB types, Section 6.4.2
+typedef struct {
+ UINT64 TrbPtr;
+
+ UINT32 TransferLength : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ1 : 1;
+ UINT32 EventData : 1;
+ UINT32 RsvdZ2 : 7;
+ UINT32 TrbType : 6;
+ UINT32 EndpointId : 5;
+ UINT32 RzvdZ3 : 3;
+ UINT32 SlotId : 8;
+} XHCI_TRANSFER_EVT_TRB;
+
+typedef struct {
+ UINT64 CmdTrbPtr;
+
+ UINT32 RsvdZ1 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 9;
+ UINT32 TrbType : 6;
+ UINT32 VfId : 8;
+ UINT32 SlotId : 8;
+} XHCI_CMDCOMPLETE_EVT_TRB;
+
+typedef struct {
+ UINT32 RsvdZ1 : 24;
+ UINT32 PortId : 8;
+
+ UINT32 RsvdZ2;
+
+ UINT32 RsvdZ3 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ4 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ5 : 16;
+} XHCI_PORTSTSCHG_EVT_TRB;
+
+typedef struct {
+ UINT32 RsvdZ1[2];
+
+ UINT32 RsvdZ2 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ3 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ4 : 8;
+ UINT32 SlotId : 8;
+} XHCI_BANDWIDTHRQ_EVT_TRB;
+
+typedef struct {
+ UINT32 DbReason : 5;
+ UINT32 RsvdZ1 : 27;
+
+ UINT32 Rsvd2;
+
+ UINT32 RsvdZ3 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ4 : 9;
+ UINT32 TrbType : 6;
+ UINT32 VfId : 8;
+ UINT32 SlotId : 8;
+} XHCI_DORBELL_EVT_TRB;
+
+typedef struct {
+ UINT32 RsvdZ1[2];
+
+ UINT32 RsvdZ2 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ3 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ4 : 16;
+} XHCI_HC_EVT_TRB;
+
+typedef struct {
+ UINT8 RsvdZ1 : 4;
+ UINT8 NtfType : 4;
+
+ UINT8 DevNtfData[7];
+
+ UINT32 RsvdZ2 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ3 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ4 : 8;
+ UINT32 SlotId : 8;
+} XHCI_DEVNOTIFY_EVT_TRB;
+
+typedef struct {
+ UINT32 RsvdZ[2];
+
+ UINT32 RsvdZ2 : 24;
+ UINT32 CompletionCode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ3 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ4 : 16;
+} XHCI_MFINDXWRAP_EVT_TRB;
+
+typedef union {
+ XHCI_TRANSFER_EVT_TRB TransferEvt;
+ XHCI_CMDCOMPLETE_EVT_TRB CmdEvt;
+ XHCI_PORTSTSCHG_EVT_TRB PortStsChgEvt;
+ XHCI_BANDWIDTHRQ_EVT_TRB BandwidthRqEvt;
+ XHCI_DORBELL_EVT_TRB DoorbellEvt;
+ XHCI_HC_EVT_TRB HcEvt;
+ XHCI_DEVNOTIFY_EVT_TRB DevNotificationEvt;
+ XHCI_MFINDXWRAP_EVT_TRB MicroframeIndxWrapEvt;
+} XHCI_EVENT_TRB;
+
+// Command TRB types, Section 6.4.3
+typedef struct {
+ UINT32 RsvdZ1[3];
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ3 : 16;
+} XHCI_COMMON_CMD_TRB;
+
+typedef struct {
+ UINT32 RsvdZ1[3];
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 9;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ3 : 8;
+ UINT32 SlotId : 8;
+} XHCI_DISABLESLOT_CMD_TRB;
+
+typedef struct {
+ UINT64 InpCtxAddress;
+ UINT32 RsvdZ1;
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 8;
+ UINT32 Bsr : 1;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ3 : 8;
+ UINT32 SlotId : 8;
+} XHCI_ADDRESSDEV_CMD_TRB;
+
+typedef struct {
+ UINT32 RsvdZ1[3];
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 8;
+ UINT32 Tsp : 1;
+ UINT32 TrbType : 6;
+ UINT32 EndpointId : 5;
+ UINT32 RsvdZ3 : 3;
+ UINT32 SlotId : 8;
+} XHCI_RESET_EP_CMD_TRB;
+
+typedef struct {
+ UINT64 TrPointer;
+
+ UINT32 RsvdZ1 :16;
+ UINT32 StreamId :16;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 9;
+ UINT32 TrbType : 6;
+ UINT32 EndpointId : 5;
+ UINT32 RsvdZ3 : 3;
+ UINT32 SlotId : 8;
+} XHCI_SET_TRPTR_CMD_TRB;
+
+typedef union {
+ XHCI_COMMON_CMD_TRB GenericCmdTrb;
+ XHCI_COMMON_CMD_TRB NoOpCmdTrb;
+ XHCI_COMMON_CMD_TRB EnableSlotCmdTrb;
+ XHCI_DISABLESLOT_CMD_TRB DisableSlotCmdTrb;
+ XHCI_ADDRESSDEV_CMD_TRB AddressDevCmdTrb;
+ XHCI_SET_TRPTR_CMD_TRB SetTrPtrCmdTrb;
+} XHCI_CMD_TRB;
+
+// Transfer TRB types, Section 6.4.1
+
+typedef struct {
+ UINT64 DataBuffer;
+
+ UINT32 XferLength : 17;
+ UINT32 TdSize : 5;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 EvalNext : 1;
+ UINT32 Isp : 1;
+ UINT32 NoSnoop : 1;
+ UINT32 Chain : 1;
+ UINT32 Ioc : 1;
+ UINT32 Idt : 1;
+ UINT32 RsvdZ1 : 2;
+ UINT32 Bei : 1;
+ UINT32 TrbType : 6;
+ UINT32 Rsvd2 : 16;
+} XHCI_NORMAL_XFR_TRB;
+
+#define XHCI_XFER_TYPE_NO_DATA 0
+#define XHCI_XFER_TYPE_DATA_OUT 2
+#define XHCI_XFER_TYPE_DATA_IN 3
+
+typedef struct {
+ UINT8 bmRequestType;
+ UINT8 bRequest;
+ UINT16 wValue;
+ UINT16 wIndex;
+ UINT16 wLength;
+
+ UINT32 XferLength : 17;
+ UINT32 RsvdZ1 : 5;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ2 : 4;
+ UINT32 Ioc : 1;
+ UINT32 Idt : 1;
+ UINT32 RsvdZ3 : 3;
+ UINT32 TrbType : 6;
+ UINT32 Trt : 2;
+ UINT32 RsvdZ4 : 14;
+} XHCI_SETUP_XFR_TRB;
+
+typedef struct {
+ UINT64 DataBuffer;
+
+ UINT32 XferLength : 17;
+ UINT32 TdLength : 5;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 EvalNext : 1;
+ UINT32 Isp : 1;
+ UINT32 NoSnoop : 1;
+ UINT32 Chain : 1;
+ UINT32 Ioc : 1;
+ UINT32 Idt : 1;
+ UINT32 RsvdZ1 : 3;
+ UINT32 TrbType : 6;
+ UINT32 Dir : 1;
+ UINT32 Rsvd2 : 15;
+} XHCI_DATA_XFR_TRB;
+
+typedef struct {
+ UINT64 RsvdZ1;
+
+ UINT32 RsvdZ2 : 22;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 EvalNext : 1;
+ UINT32 RsvdZ3 : 2;
+ UINT32 Chain : 1;
+ UINT32 Ioc : 1;
+ UINT32 RsvdZ4 : 4;
+ UINT32 TrbType : 6;
+ UINT32 Dir : 1;
+ UINT32 Rsvd2 : 15;
+} XHCI_STATUS_XFR_TRB;
+
+typedef struct {
+ UINT64 DataBuffer;
+
+ UINT32 XferLength : 17;
+ UINT32 TdLength : 5;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 EvalNext : 1;
+ UINT32 Isp : 1;
+ UINT32 NoSnoop : 1;
+ UINT32 Chain : 1;
+ UINT32 Ioc : 1;
+ UINT32 Idt : 1;
+ UINT32 RsvdZ1 : 3;
+ UINT32 TrbType : 6;
+ UINT32 Rsvd2 : 4;
+ UINT32 FrameId : 11;
+ UINT32 Sia : 1;
+} XHCI_ISOCH_XFR_TRB;
+
+typedef struct {
+ UINT64 RsvdZ1;
+
+ UINT32 RsvdZ2 : 22;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 EvalNext : 1;
+ UINT32 RsvdZ3 : 2;
+ UINT32 Chain : 1;
+ UINT32 Ioc : 1;
+ UINT32 RsvdZ4 : 4;
+ UINT32 TrbType : 6;
+ UINT32 Rsvd2 : 16;
+} XHCI_NOOP_XFR_TRB;
+
+typedef union {
+ XHCI_NORMAL_XFR_TRB NormalXfrTrb;
+ XHCI_SETUP_XFR_TRB SetupXfrTrb;
+ XHCI_DATA_XFR_TRB DataXfrTrb;
+ XHCI_STATUS_XFR_TRB StatusXfrTrb;
+ XHCI_ISOCH_XFR_TRB IsockXfrTrb;
+ XHCI_NOOP_XFR_TRB NoopXfrTrb;
+} XHCI_XFR_TRB;
+
+
+// Other TRB types
+typedef struct {
+ UINT64 NextSegPtr;
+
+ UINT32 RsvdZ1 : 22;
+ UINT32 Interrupter : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 ToggleCycle : 1;
+ UINT32 RsvdZ2 : 2;
+ UINT32 Chain : 1;
+ UINT32 Ioc : 1;
+ UINT32 RsvdZ3 : 4;
+ UINT32 TrbType : 6;
+ UINT32 RsvdZ4 : 16;
+} XHCI_LINK_TRB;
+
+typedef struct {
+ XHCI_TRB *Base;
+ UINT32 Size; // #of TRBs in the ring
+ XHCI_TRB* LastTrb;
+ XHCI_TRB* QueuePtr;
+ UINT8 CycleBit;
+ UINT8 Pad[27-3*sizeof(VOID*)]; // Make size 32 Bytes
+} TRB_RING;
+
+// The following definition fixes the size of ring
+// segment to TRBS_PER_SEGMENT * sizeof(XHCI_TRB)
+#define TRBS_PER_SEGMENT 64
+#define RING_SIZE TRBS_PER_SEGMENT*sizeof(XHCI_TRB)
+
+// Default timeouts
+#define XHCI_CMD_COMPLETE_TIMEOUT_MS 500
+#define XHCI_CTL_COMPLETE_TIMEOUT_MS 2000
+#define XHCI_BULK_COMPLETE_TIMEOUT_MS 10000
+#define XHCI_INT_COMPLETE_TIMEOUT_MS 1500
+
+//#define XHCI_BOT_TD_MAXSIZE 512
+#define XHCI_BOT_TD_MAXSIZE 0x10000
+#define XHCI_BOT_MAX_XFR_SIZE XHCI_BOT_TD_MAXSIZE*8
+
+typedef struct {
+ UINT32 RouteString : 20;
+ UINT32 Speed : 4;
+ UINT32 RsvdZ1 : 1;
+ UINT32 MultiTT : 1;
+ UINT32 Hub : 1;
+ UINT32 ContextEntries : 5;
+
+ UINT32 MaxExitLatency : 16;
+ UINT32 RootHubPort : 8;
+ UINT32 PortsNum : 8;
+
+ UINT32 TtHubSlotId : 8;
+ UINT32 TtPortNumber : 8;
+ UINT32 TThinkTime : 2;
+ UINT32 RsvdZ3 : 4;
+ UINT32 Interrupter : 10;
+
+ UINT32 DevAddr : 8;
+ UINT32 RsvdZ4 : 19;
+ UINT32 SlotState : 5;
+
+ UINT32 RsvdO[4];
+} XHCI_SLOT_CONTEXT;
+
+// XHCI_SLOT_CONTEXT.DW3.SlotState definitions
+#define XHCI_SLOT_STATE_DISABLED 0
+#define XHCI_SLOT_STATE_DEFAULT 1
+#define XHCI_SLOT_STATE_ADDRESSED 2
+#define XHCI_SLOT_STATE_CONFIGURED 3
+
+// Endpoint types, Table 57
+#define XHCI_EPTYPE_NOT_VALID 0
+#define XHCI_EPTYPE_ISOCH_OUT 1
+#define XHCI_EPTYPE_BULK_OUT 2
+#define XHCI_EPTYPE_INT_OUT 3
+#define XHCI_EPTYPE_CTL 4
+#define XHCI_EPTYPE_ISOCH_IN 5
+#define XHCI_EPTYPE_BULK_IN 6
+#define XHCI_EPTYPE_INT_IN 7
+
+typedef struct {
+ UINT32 EpState : 3;
+ UINT32 RsvdZ1 : 5;
+ UINT32 Mult : 2;
+ UINT32 MaxPStreams : 5;
+ UINT32 Lsa : 1;
+ UINT32 Interval : 8;
+ UINT32 RzvdZ2 : 8;
+
+ UINT32 ForceEvent : 1;
+ UINT32 ErrorCount : 2;
+ UINT32 EpType : 3;
+ UINT32 RsvdZ : 1;
+ UINT32 Hid : 1;
+ UINT32 MaxBurstSize : 8;
+ UINT32 MaxPacketSize : 16;
+
+ UINT64 TrDequeuePtr; // BIT0 of this field is DCS (Dequeue Cycle State)
+ UINT16 AvgTrbLength;
+ UINT16 MaxEsitPayload;
+ UINT32 RsvdO[3];
+} XHCI_EP_CONTEXT;
+
+typedef struct {
+ UINT32 DropContextFlags;
+ UINT32 AddContextFlags;
+ UINT32 RzvdZ[6];
+} XHCI_INPUT_CONTROL_CONTEXT;
+
+typedef struct {
+ XHCI_SLOT_CONTEXT Slot;
+ XHCI_EP_CONTEXT Ep[31];
+} XHCI_DEVICE_CONTEXT;
+
+#define XHCI_DEVICE_CONTEXT_ENTRIES 32
+
+typedef struct {
+ XHCI_INPUT_CONTROL_CONTEXT CtlCtx;
+ XHCI_DEVICE_CONTEXT DevCtx;
+} XHCI_INPUT_CONTEXT;
+
+#define XHCI_INPUT_CONTEXT_ENTRIES 33
+
+ //(EIP75547+)>
+//---------------------------------------------------------
+// Extended Capabilities
+//---------------------------------------------------------
+#define XHCI_EXT_CAP_USB_LEGACY 1
+#define XHCI_EXT_CAP_SUPPORTED_PROTOCOL 2
+#define XHCI_EXT_CAP_POWERMANAGEMENT 3
+#define XHCI_EXT_CAP_IO_VIRTUALIZATION 4
+#define XHCI_EXT_CAP_USB_DEBUG_PORT 10
+
+typedef struct {
+ UINT32 CapId:8; // Capability ID
+ UINT32 NextCapPtr:8; // Next xHCI Extended Capability Pointer
+ UINT32 Cap:16; // Capability Specific
+} XHCI_EXT_CAP;
+ //<(EIP75547+)
+
+typedef struct {
+ UINT64 ScratchpadBufArrayPtr;
+ UINT64 DevCntxtAddr[255];
+} XHCI_DCBAA; // Total size is 256 64-bit entries, or 2K Bytes (section 6.1)
+// XHCI PCI Configuration Registers
+//---------------------------------------------------------------------------
+
+// Serial Bus Release Number Register
+#define XHCI_PCI_SBRN 0x60
+
+// Frame Length Adjustment Register
+#define XHCI_PCI_FLADJ 0x61
+
+// Host Controller Capability Registers
+//---------------------------------------------------------------------------
+
+typedef struct {
+ UINT32 MaxSlots : 8; // Number of Device Slots
+ UINT32 MaxIntrs : 11; // Number of Interrupters
+ UINT32 Rsvd : 5; // Reserved
+ UINT32 MaxPorts : 8; // Number of ports
+} HCPARAMS1;
+
+typedef struct {
+ UINT32 Ist : 4; // Isochronous Scheduling Threshold
+ UINT32 ErstMax : 4; // Event Ring Segment Table Max
+ UINT32 Rsvd : 18;
+ UINT32 Spr : 1; // Scratchpad restore
+ UINT32 MaxScratchPadBufs : 5; // Number of scratchpad buffers
+} HCPARAMS2;
+
+typedef struct {
+ UINT32 U1DevExitLatency : 8; // Worst case latency of U1->U0, mks
+ UINT32 Rsvd : 8;
+ UINT32 U2DevExitLatency : 16; // Worst case latency of U2->U0, mks
+} HCPARAMS3;
+
+typedef struct {
+ UINT32 Ac64 : 1; // 64-bit Addressing Capability
+ UINT32 Bnc : 1; // Bandwidth Negotiation Capability
+ UINT32 Csz : 1; // Context data structures width (32 or 64 bit)
+ UINT32 Ppc : 1; // Power Port Control
+ UINT32 Pind : 1; // Port Indicators
+ UINT32 Lhrc : 1; // Light HC Reset Capability
+ UINT32 Ltc : 1; // Latency Tolerance Capability
+ UINT32 Nss : 1; // No Secondary SID Support
+ UINT32 Rsvd : 4;
+ UINT32 MaxPsaSize : 4; // Maximum Primary Stream Array Size
+ UINT32 Xecp : 16; // xHCI Extended Capabilities Pointer
+} HCPARAMS;
+
+typedef struct {
+ UINT8 CapLength; // 00
+ UINT8 Rsvd; // 01
+ UINT16 HciVersion; // 02
+ HCPARAMS1 HcParams1; // 04
+ HCPARAMS2 HcParams2; // 08
+ HCPARAMS3 HcParams3; // 0C
+ HCPARAMS HcParams; // 10
+ UINT32 DbOff; // 14
+ UINT32 RtsOff; // 18
+} XHCI_HC_CAP_REGS;
+
+//-----------------------------------------------------------
+// Host Controller Operational Registers
+//-----------------------------------------------------------
+typedef struct {
+ UINT32 RunStop : 1;
+ UINT32 HcRst : 1; // HC Reset
+ UINT32 Inte : 1; // Interrupter Enable
+ UINT32 HsEe : 1; // Host System Error Enable
+ UINT32 Rsvd : 3;
+ UINT32 LhcRst : 1; // Light Host Controller Reset
+ UINT32 Css : 1; // Controller Save State
+ UINT32 Crs : 1; // Controller Restore State
+ UINT32 Ewe : 1; // Enable Wrap Event
+ UINT32 Eu3S : 1; // Enable U3 MFINDEX Stop
+ UINT32 Rsvd1 : 20;
+} XHCI_USBCMD;
+
+typedef struct {
+ union {
+ UINT32 AllBits; // can be used for clearing status
+ #define XHCI_STS_HALTED BIT0
+ #define XHCI_STS_HOSTSYSTEM_ERROR BIT2
+ #define XHCI_STS_EVT_INTERRUPT BIT3
+ #define XHCI_STS_PCD BIT4
+ struct {
+ UINT32 HcHalted : 1;
+ UINT32 Rsvd1 : 1;
+ UINT32 Hse : 1; // Host System Error
+ UINT32 Eint : 1; // Event Interrupt
+ UINT32 Pcd : 1; // Port Change Detect
+ UINT32 Rsvd2 : 3;
+ UINT32 Sss : 1; // Save State Status
+ UINT32 Rss : 1; // Restore State Status
+ UINT32 Sre : 1; // Save/Restore Error
+ UINT32 Cnr : 1; // Controller Not Ready
+ UINT32 Hce : 1; // Host Controller Error
+ UINT32 Rsvd3 : 19;
+ } Field;
+ };
+} XHCI_USBSTS;
+
+typedef struct {
+ UINT32 Rcs : 1; // Ring Cycle State
+ UINT32 Cs : 1; // Command Stop
+ UINT32 Ca : 1; // Command Abort
+ UINT32 Crr : 1; // Command Ring Running
+ UINT32 Rsvd : 2;
+ UINT32 CrPointer : 26; // Command Ring Pointer
+} XHCI_CRCR;
+
+#define XHCI_PORT_CONNECT BIT0
+#define XHCI_PORT_ENABLE BIT1
+#define XHCI_PORT_RESET BIT4
+#define XHCI_PORT_RESET_CHG BIT21
+
+#define XHCI_PORTSC_OFFSET 0x400
+
+// Port speed definitions as read from PortSpeed field of PORTSC
+#define XHCI_DEVSPEED_UNDEFINED 0
+#define XHCI_DEVSPEED_FULL 1
+#define XHCI_DEVSPEED_LOW 2
+#define XHCI_DEVSPEED_HIGH 3
+#define XHCI_DEVSPEED_SUPER 4
+
+typedef struct {
+ union {
+ UINT32 AllBits; // can be used for clearing status
+ #define XHCI_PCS_CCS BIT0
+ #define XHCI_PCS_PED BIT1
+ #define XHCI_PCS_OCA BIT3
+ #define XHCI_PCS_PR BIT4
+ #define XHCI_PCS_PP BIT9
+ #define XHCI_PCS_CSC BIT17
+ #define XHCI_PCS_PEC BIT18
+ #define XHCI_PCS_WRC BIT19 //(EIP75547+)
+ #define XHCI_PCS_OCC BIT20
+ #define XHCI_PCS_PRC BIT21
+ #define XHCI_PCS_WPR BIT31 //(EIP75547+)
+ struct {
+ UINT32 Ccs : 1; // 0 Current Connect Status - RO
+ UINT32 Ped : 1; // 1 Port Enabled/Disabled - RW1CS
+ UINT32 RsvdZ1 : 1; // 2
+ UINT32 Oca : 1; // 3 Over-current Active - RO
+ UINT32 Pr : 1; // 4 Port Reset - RW1S
+ UINT32 Pls : 4; // 5..8 Port Link State - RWS
+ UINT32 Pp : 1; // 9 Port Power - RWS
+ UINT32 PortSpeed : 4; // 10..13 Port Speed - RO
+ UINT32 Pic : 2; // 14..15 Port Indicator Ctl - RWS
+ UINT32 Lws : 1; // 16 Port Link State Write Strobe - RW
+ UINT32 Csc : 1; // 17 Connect Status Change - RW1CS
+ UINT32 Pec : 1; // 18 Port Enabled/Disabled Change - RW1CS
+ UINT32 Wrc : 1; // 19 Warm Port Reset Change - RW1CS/RsvdZ
+ UINT32 Occ : 1; // 20 Over-current Change - RW1CS
+ UINT32 Prc : 1; // 21 Port Reset Change - RW1CS
+ UINT32 Plc : 1; // 22 Port Link State Change - RW1CS
+ UINT32 Cec : 1; // 23 Port Config Error Change - RW1CS/RsvdZ
+ UINT32 Cas : 1; // 24 Cold Attach Status - RO //(EIP75547)
+ UINT32 Wce : 1; // 25 Wake on Connect Enable - RWS
+ UINT32 Wde : 1; // 26 Wake on Disconnect Enable - RWS
+ UINT32 Woe : 1; // 27 Wake on Over-current Enable - RWS
+ UINT32 RsvdZ2 : 2; // 28..29 //(EIP75547)
+ UINT32 Dr : 1; // 30 Device Removable (0 removable) - RO
+ UINT32 Wpr : 1; // 31 Warm Port Reset - RW1S/RsvdZ
+ } Field;
+ };
+} XHCI_PORTSC;
+
+typedef struct {
+ XHCI_USBCMD UsbCmd; // 00
+ XHCI_USBSTS UsbSts; // 04
+ UINT32 PageSize; // 08
+ UINT8 Rsvd1[8]; // 0C
+ UINT32 DnCtrl; // 14 Device Notification Control
+ UINT64 Crcr; // 18 Command Ring Control
+ UINT8 Rsvd2[16]; // 20
+ UINT64 DcbAap; // 30 Device Context Base Address Array Pointer
+ UINT32 Config; // 38 Max Device Slots Enabled
+} XHCI_HC_OP_REGS;
+
+// Minimum inter-interrupt interval, in 250ns units. The value of 4000 makes 1ms interval.
+#define XHCI_IMODI 4000
+
+// Note: the following structure defines 32-bit and 64-bits fields
+// without detailing; this MMIO data must be accessed using Dword
+// access for 32-bit fields and Qword access for 64-bit, Section 5.5.
+typedef struct {
+ UINT32 IMan; // Interrupter Management
+ UINT32 IMod; // Interrupter Moderation
+ UINT32 Erstz; // Event Ring Segment Table Size
+ UINT32 RsrvP;
+ UINT64 Erstba; // Event Ring Segment Table Base Address
+ UINT64 Erdp; // Event Ring Dequeue Pointer
+} XHCI_INTERRUPTER_REGS;
+
+typedef struct {
+ UINT32 MfIndex;
+ UINT32 Reserved[7];
+ XHCI_INTERRUPTER_REGS IntRegs[1024];
+} XHCI_HC_RT_REGS;
+
+typedef enum {
+ XhciTNormal = 1,
+ XhciTSetupStage, // 2
+ XhciTDataStage, // 3
+ XhciTStatusStage,// 4
+ XhciTIsoch, // 5
+ XhciTLink, // 6
+ XhciTEventData, // 7
+ XhciTNoOp, // 8
+ XhciTEnableSlotCmd, // 9
+ XhciTDisableSlotCmd, // 10
+ XhciTAddressDeviceCmd, // 11
+ XhciTConfigureEndpointCmd, //12
+ XhciTEvaluateContextCmd, //13
+ XhciTResetEndpointCmd, //14
+ XhciTStopEndpointCmd, // 15
+ XhciTSetTRDequeuePointerCmd, //16
+ XhciTResetDeviceCmd, // 17
+ XhciTForceEventCmd, // 18
+ XhciTNegotiateBandwidthCmd, // 19
+ XhciTSetLatencyToleranceCmd, // 20
+ XhciTGetPortBandwidthCmd, // 21
+ XhciTForceHeaderCmd, // 22
+ XhciTNoOpCmd, // 23
+// 24..31 reserved
+ XhciTTransferEvt = 32,
+ XhciTCmdCompleteEvt, // 33
+ XhciTPortStatusChgEvt, // 34
+ XhciTBandwidthRequestEvt, // 35
+ XhciTDoorbellEvt, // 36
+ XhciTHostControllerEvt, // 37
+ XhciTDevNotificationEvt, // 38
+ XhciTMfIndexWrapEvt // 39
+} TRB_TYPE;
+
+typedef struct {
+ UINT64 RsBase;
+ UINT16 RsSize;
+ UINT16 Rsvd1;
+ UINT32 Rsvd2;
+} XHCI_ER_SEGMENT_ENTRY;
+
+#define CRCR_RING_CYCLE_STATE BIT0
+
+#define TRBS_PER_SEGMENT 64
+#define RING_SIZE TRBS_PER_SEGMENT*sizeof(XHCI_TRB)
+
+typedef struct {
+ UINT8 SlotId;
+ UINT8 DevAddr;
+} PEI_XHCI_SLOTADDR_MAP;
+
+// Note that MaxSlots affects the size of USB3_CONTROLLER structure as
+// well as its data boundaries and alignment. Default value is 32; if a
+// different value needs to be assigned, make sure that boundaries and
+// alignment meets the requirements; do the padding as needed.
+// See XHCI specification Chapter 6 for the details.
+
+#define PEI_XHCI_MAX_SLOTS 32
+
+ //(EIP75547+)>
+typedef struct {
+ struct {
+ UINT32 CapId:8;
+ UINT32 NextCapPtr:8;
+ UINT32 MinorRev:8;
+ UINT32 MajorRev:8;
+ };
+
+ UINT32 NameString;
+
+ struct {
+ UINT32 PortOffset:8;
+ UINT32 PortCount:8;
+ UINT32 L1c:1; // L1 Capability
+ UINT32 Hso:1; // High-speed Only
+ UINT32 Ihi:1; // Integrated Hub Implemented
+ UINT32 RsvdZ:13;
+ };
+} XHCI_EXT_PROTOCOL;
+ //<(EIP75547+)
+
+typedef struct _USB3_CONTROLLER {
+ UINTN Dcbaa[PEI_XHCI_MAX_SLOTS]; // 32*4 = 128
+ UINT8 XfrTrb[RING_SIZE*PEI_XHCI_MAX_SLOTS*32];
+ UINT8 CommandRing[RING_SIZE];
+ UINT8 EventRing[RING_SIZE];
+
+ UINT8 DevCtx[PEI_XHCI_MAX_SLOTS * 0x800];
+ UINT8 InpCtx[0x840];
+ XHCI_ER_SEGMENT_ENTRY Erst;
+
+ UINT16 Vid;
+ UINT16 Did;
+ BOOLEAN Access64;
+ UINT16 HciVersion;
+ UINT8 MaxPorts;
+ UINT32 PageSize4K;
+ UINT8 ContextSize;
+ UINT16 MaxIntrs;
+ UINT32 DbOffset;
+ UINT8 MaxSlots;
+ VOID *InputContext;
+ TRB_RING CmdRing;
+ TRB_RING EvtRing;
+ TRB_RING XfrRing[PEI_XHCI_MAX_SLOTS*32]; // 32 endpoints per device
+ TRB_RING *XfrRings;
+ UINTN XfrTrbs;
+ VOID *DeviceContext;
+ XHCI_DCBAA *DcbaaPtr;
+ XHCI_HC_CAP_REGS *CapRegs;
+ XHCI_HC_OP_REGS *OpRegs;
+ XHCI_HC_RT_REGS *RtRegs;
+ XHCI_EXT_PROTOCOL *Usb2Protocol; //(EIP75547+)
+ XHCI_EXT_PROTOCOL *Usb3Protocol; //(EIP75547+)
+
+ PEI_XHCI_SLOTADDR_MAP DeviceMap[PEI_XHCI_MAX_SLOTS];
+
+ EFI_PEI_SERVICES **PeiServices;
+ PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ EFI_PEI_CPU_IO_PPI *CpuIoPpi;
+ EFI_PEI_STALL_PPI *StallPpi;
+ EFI_PEI_PCI_CFG_PPI *PciCfgPpi;
+
+} USB3_CONTROLLER;
+
+#pragma pack(pop)
+
+//----------------------------------------------------------------------------
+// Function prototypes
+//----------------------------------------------------------------------------
+EFI_STATUS XhciHcControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaximumPacketLength,
+ IN UINT16 TransactionTranslator OPTIONAL,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult );
+
+EFI_STATUS XhciHcBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT16 MaximumPacketLength,
+ IN UINT16 TransactionTranslator OPTIONAL,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult );
+
+EFI_STATUS XhciHcGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber );
+
+EFI_STATUS XhciHcGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus );
+
+EFI_STATUS XhciHcSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature );
+
+EFI_STATUS XhciHcClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature );
+
+EFI_STATUS XhciInitHC(
+ EFI_PEI_SERVICES **PeiServices,
+ struct _USB3_CONTROLLER *Usb3Hc,
+ UINT8 ControllerIndex);
+
+EFI_STATUS XhciHcPreConfigureDevice(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 Port,
+ IN UINT8 Speed,
+ IN UINT16 TransactionTranslator);
+
+EFI_STATUS XhciEnableEndpoints (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 *Desc);
+
+VOID
+XhciMmio64Write(
+ USB3_CONTROLLER *Usb3Hc,
+ UINTN Address,
+ UINT64 Data);
+
+EFI_STATUS XhciInitRing(TRB_RING*, UINTN, UINT32, BOOLEAN);
+EFI_STATUS XhciExecuteCommand(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ TRB_TYPE Cmd,
+ VOID *Params
+);
+
+TRB_RING*
+XhciInitXfrRing(
+ USB3_CONTROLLER* Usb3Hc,
+ UINT8 Slot,
+ UINT8 Ep);
+
+EFI_STATUS
+UpdateDeviceMap(
+ PEI_XHCI_SLOTADDR_MAP *DeviceMap,
+ UINT8 SlotId,
+ UINT8 DevAddr);
+
+EFI_STATUS
+GetSlotId(
+ PEI_XHCI_SLOTADDR_MAP *DeviceMap,
+ UINT8 *SlotId,
+ UINT8 DevAddr);
+
+EFI_STATUS Stall(EFI_PEI_SERVICES**, EFI_PEI_STALL_PPI*, UINTN);
+EFI_STATUS CountTime(UINT, UINT16);
+EFI_STATUS XhciInitDeviceData (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This
+// HC_STRUC *HcStruc,
+// DEV_INFO *DevInfo,
+// UINT8 PortStatus,
+// UINT8 **DeviceData
+);
+
+TRB_RING* XhciGetXfrRing(
+ USB3_CONTROLLER* Usb3Hc,
+ UINT8 Slot,
+ UINT8 Ep);
+
+UINT32* XhciGetTheDoorbell(
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 SlotId);
+
+XHCI_TRB* XhciAdvanceEnqueuePtr(
+ TRB_RING *Ring);
+
+EFI_STATUS XhciWaitForEvent(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc,
+ XHCI_TRB *TrbToCheck,
+ TRB_TYPE EventType,
+ UINT8 *CompletionCode,
+ UINT16 TimeOutMs,
+ VOID *Data
+);
+
+UINT8*
+XhciGetDeviceContext(
+ USB3_CONTROLLER *Usb3Hc,
+ UINT8 SlotId
+);
+
+UINT8*
+XhciGetContextEntry(
+ USB3_CONTROLLER *Usb3Hc,
+ VOID *Context,
+ UINT8 Index
+);
+
+ //(EIP75547+)>
+VOID
+XhciResetUsb2Port(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc
+);
+
+EFI_STATUS
+XhciExtCapParser(
+ EFI_PEI_SERVICES **PeiServices,
+ USB3_CONTROLLER *Usb3Hc
+);
+ //<(EIP75547+)
+
+#define _CR( Record, TYPE, Field ) \
+ ( (TYPE *) ( (CHAR8 *) (Record) - (CHAR8 *) &( ( (TYPE *) 0 )->Field ) ) )
+#define PEI_RECOVERY_USB_XHCI_DEV_FROM_THIS( a ) \
+ _CR( a, USB3_CONTROLLER, UsbHostControllerPpi )
+
+#endif // _XHCIPEI_H
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2010, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//********************************************************************** \ No newline at end of file