diff --git a/libefiusb/Android.mk b/libefiusb/Android.mk index dd197a8a..00e9bd35 100644 --- a/libefiusb/Android.mk +++ b/libefiusb/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \ usb.c ifeq ($(KERNELFLINGER_SUPPORT_SELF_USB_DEVICE_MODE_PROTOCOL),true) +LOCAL_CFLAGS += -DSUPPORT_SUPER_SPEED LOCAL_CFLAGS += -DUSE_SELF_USB_DEVICE_MODE_PROTOCOL LOCAL_SRC_FILES += \ device_mode/cpuio.c \ diff --git a/libefiusb/device_mode/UsbDeviceDxe.c b/libefiusb/device_mode/UsbDeviceDxe.c index 0ffce845..322bdd8d 100644 --- a/libefiusb/device_mode/UsbDeviceDxe.c +++ b/libefiusb/device_mode/UsbDeviceDxe.c @@ -1,282 +1,360 @@ -/** @file - Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ -#include -#include -#include -#include -#include "pci.h" -#include "UsbDeviceDxe.h" -#include "UsbDeviceMode.h" -#include "XdciDWC.h" - -static EFI_HANDLE xdci = 0; -PCI_DEVICE_PATH xhci_path = {.Device = -1, .Function = -1}; - -VOID -EFIAPI -PlatformSpecificInit ( - VOID - ) -{ - UINTN XhciPciMmBase; - EFI_PHYSICAL_ADDRESS XhciMemBaseAddress; - - XhciPciMmBase = MmPciAddress ( - 0, - 0, - xhci_path.Device, - xhci_path.Function, - 0 - ); - - - XhciMemBaseAddress = MmioRead32 ((UINTN) (XhciPciMmBase + R_XHCI_MEM_BASE)) & B_XHCI_MEM_BASE_BA; - DEBUG ((DEBUG_INFO, "XhciPciMmBase=%x, XhciMemBaseAddress=%x\n", XhciPciMmBase, XhciMemBaseAddress)); - - MmioWrite32 ((UINTN)(XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG0), 0x1310800); - - return; -} - -static -VOID -EFIAPI -UsbDeviceDxeExitBootService ( - __attribute__((unused))EFI_EVENT Event, - VOID *Context - ) -{ - USB_XDCI_DEV_CONTEXT *UsbXdciDevContext; - - UsbXdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context; - DEBUG ((EFI_D_INFO, "UsbDeviceDxeExitBootService enter\n")); - - if (UsbXdciDevContext->XdciPollTimer != NULL) { - uefi_call_wrapper(BS->SetTimer, - 3, - UsbXdciDevContext->XdciPollTimer, - TimerCancel, - 0); - - uefi_call_wrapper(BS->CloseEvent, 1, UsbXdciDevContext->XdciPollTimer); - UsbXdciDevContext->XdciPollTimer = NULL; - } - - return; -} - -static EFI_STATUS find_usb_device_controller (EFI_HANDLE Controller) -{ - EFI_STATUS status = EFI_UNSUPPORTED; - EFI_PCI_IO *pci; - USB_CLASSC class_reg; - UINTN seg; - UINTN bus; - UINTN dev; - UINTN fun; - - status = uefi_call_wrapper(BS->OpenProtocol, - 6, - Controller, - &PciIoProtocol, - (VOID **) &pci, - g_parent_image, - Controller, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - - if (EFI_ERROR (status)) - return status; - - status = uefi_call_wrapper(pci->Pci.Read, - 5, - pci, - EfiPciIoWidthUint8, - PCI_CLASSCODE_OFFSET, - sizeof (USB_CLASSC) / sizeof (UINT8), - &class_reg); - - if (EFI_ERROR (status)) - return status; - - // Test whether the controller belongs to USB device type - // 0x0C03FE / 0x0C0380 - - if ((class_reg.BaseCode == PCI_CLASS_SERIAL) && - (class_reg.SubClassCode == PCI_CLASS_SERIAL_USB) && - ((class_reg.ProgInterface == PCI_IF_USBDEV) || - (class_reg.ProgInterface == 0x80))) { - return EFI_SUCCESS; - } - - - if ((class_reg.BaseCode == PCI_CLASS_SERIAL) && - (class_reg.SubClassCode == PCI_CLASS_SERIAL_USB) && - (class_reg.ProgInterface == PCI_IF_XHCI)) { - - status = uefi_call_wrapper(pci->GetLocation, - 5, - pci, - &seg, - &bus, - &dev, - &fun); - xhci_path.Device = (UINT8)dev; - xhci_path.Function = (UINT8)fun; - } - - return EFI_UNSUPPORTED; -} - -EFI_GUID gEfiEventExitBootServicesGuid = EventExitBootServices; - -static EFI_STATUS usb_device_mode_start (EFI_HANDLE Controller, EFI_USB_DEVICE_MODE_PROTOCOL **usb_device) -{ - EFI_STATUS Status; - USB_XDCI_DEV_CONTEXT *UsbXdciDevContext = NULL; - EFI_PCI_IO *PciIo; - EFI_EVENT ExitBootServicesEvent; - - // Provide protocol interface - // Get the PCI I/O Protocol on PciHandle - Status = uefi_call_wrapper(BS->OpenProtocol, - 6, - Controller, - &PciIoProtocol, - (VOID **) &PciIo, - g_parent_image, - Controller, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR (Status)) { - goto ErrorExit; - } - - UsbXdciDevContext = AllocateZeroPool (sizeof (USB_XDCI_DEV_CONTEXT)); - if (UsbXdciDevContext == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ErrorExit; - } - - // Initialize the driver context - // - UsbXdciDevContext->StartUpController = FALSE; - UsbXdciDevContext->XdciHandle = Controller; - UsbXdciDevContext->Signature = EFI_USB_DEV_SIGNATURE; - - Status = uefi_call_wrapper(PciIo->Pci.Read, - 5, - PciIo, - EfiPciIoWidthUint32, - R_OTG_BAR0, - 1, - &UsbXdciDevContext->XdciMmioBarAddr); - UsbXdciDevContext->XdciMmioBarAddr &= B_OTG_BAR0_BA; - - UINT16 command = 0x6; - Status = uefi_call_wrapper(PciIo->Pci.Write, - 5, - PciIo, - EfiPciIoWidthUint16, - R_XDCI_CMD_OFF, - 1, - &command); - //read after write to ensure the former write take effect - command = 0; - Status = uefi_call_wrapper(PciIo->Pci.Read, - 5, - PciIo, - EfiPciIoWidthUint16, - R_XDCI_CMD_OFF, - 1, - &command); - - CopyMem (&(UsbXdciDevContext->UsbDevModeProtocol), - &mUsbDeviceModeProtocol, - sizeof (EFI_USB_DEVICE_MODE_PROTOCOL)); - - Status = uefi_call_wrapper(BS->CreateEventEx, - 6, - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - UsbDeviceDxeExitBootService, - UsbXdciDevContext, - &gEfiEventExitBootServicesGuid, - &ExitBootServicesEvent); - if (EFI_ERROR (Status)) - goto ErrorExit; - - *usb_device = &(UsbXdciDevContext->UsbDevModeProtocol); - - return Status; - -ErrorExit: - - if (UsbXdciDevContext != NULL) { - if (UsbXdciDevContext->XdciPollTimer != NULL) { - uefi_call_wrapper(BS->CloseEvent, - 1, - UsbXdciDevContext->XdciPollTimer); - UsbXdciDevContext->XdciPollTimer = NULL; - } - FreePool (UsbXdciDevContext); - } - - efi_perror(Status, L"ERROR - install driver failed - Exit\n"); - return Status; -} - -static BOOLEAN usb_xdci_enabled(void) -{ - EFI_STATUS ret; - UINTN NumberHandles, Index; - EFI_HANDLE *Handles; - - ret = LibLocateHandle(ByProtocol, - &PciIoProtocol, - NULL, - &NumberHandles, - &Handles); - if (EFI_ERROR(ret)) { - efi_perror(ret, L"LibLocateProtocol: Handle not found\n"); - return ret; - } - - for (Index=0; Index < NumberHandles; Index++) { - ret = find_usb_device_controller(Handles[Index]); - if (!EFI_ERROR(ret)) { - xdci = Handles[Index]; - break; - } - } - - if (Handles) { - FreePool (Handles); - } - - if (!EFI_ERROR(ret)) - return TRUE; - - return FALSE; -} - -EFI_STATUS init_usb_device_mode_protocol(EFI_USB_DEVICE_MODE_PROTOCOL **usb_device) -{ - EFI_STATUS ret = EFI_UNSUPPORTED; - - if (usb_xdci_enabled()) { - ret = usb_device_mode_start(xdci, usb_device); - } else { - efi_perror(ret, L"XDCI is disabled, please enable it in BIOS"); - } - - return ret; -} +/** @file + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include +#include +#include +#include +#include "pci.h" +#include "UsbDeviceDxe.h" +#include "UsbDeviceMode.h" +#include "XdciDWC.h" + +static EFI_HANDLE xdci_handle = 0, xhci_handle = 0; +PCI_DEVICE_PATH xhci_path = {.Device = -1, .Function = -1}; +UINTN XhciMmioBarAddr = 0; + +VOID +EFIAPI +PlatformSpecificInit ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 XhciMmioBarHigh = 0; + EFI_PCI_IO *PciIo; + UINT32 BitValue; + UINT32 BitMask; + UINT16 DelayTime = 10000; + UINT16 LoopTime; + + // Provide protocol interface + // Get the PCI I/O Protocol on PciHandle + Status = uefi_call_wrapper(BS->OpenProtocol, + 6, + xhci_handle, + &PciIoProtocol, + (VOID **) &PciIo, + g_parent_image, + xhci_handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + goto ErrorExit1; + } + + Status = uefi_call_wrapper(PciIo->Pci.Read, + 5, + PciIo, + EfiPciIoWidthUint32, + R_XHCI_BAR0, + 1, + &XhciMmioBarAddr); + if (EFI_ERROR (Status)) { + goto ErrorExit1; + } + if ((XhciMmioBarAddr & B_XHCI_BAR0_TYPE) == B_XHCI_BAR0_64_BIT) { + Status = uefi_call_wrapper(PciIo->Pci.Read, + 5, + PciIo, + EfiPciIoWidthUint32, + R_XHCI_BAR_HIGH, + 1, + &XhciMmioBarHigh); + } + if (EFI_ERROR (Status)) { + goto ErrorExit1; + } + XhciMmioBarAddr = ((UINT64) XhciMmioBarHigh << 32) | XhciMmioBarAddr; + XhciMmioBarAddr &= B_XHCI_MEM_BASE_BA; + + DEBUG ((DEBUG_INFO, "XhciMmioBarAddr=0x%016lx\n", XhciMmioBarAddr)); + + // + // Step 1: Enable OTG device Mode + // + MmioWrite32 ((UINTN)(XhciMmioBarAddr + R_XHCI_MEM_DUAL_ROLE_CFG0), 0x1310800); + + // + // Step 2: 0x80DC register, has a status bit to acknowledge the role change in Bit 29 + // + BitMask = (UINT32) (0x20000000); + BitValue = (UINT32) (1 << 29); + + for (LoopTime = 0; LoopTime < DelayTime; LoopTime++) { + if ((MmioRead32 ((UINTN)(XhciMmioBarAddr + R_XHCI_MEM_DUAL_ROLE_CFG1)) & BitMask) == (BitValue & BitMask)) { + break; + } else { + uefi_call_wrapper(BS->Stall, 1, 100); + } + } + +ErrorExit1: + + return; +} + +static +VOID +EFIAPI +UsbDeviceDxeExitBootService ( + __attribute__((unused))EFI_EVENT Event, + VOID *Context + ) +{ + USB_XDCI_DEV_CONTEXT *UsbXdciDevContext; + + UsbXdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context; + DEBUG ((EFI_D_INFO, "UsbDeviceDxeExitBootService enter\n")); + + if (UsbXdciDevContext->XdciPollTimer != NULL) { + uefi_call_wrapper(BS->SetTimer, + 3, + UsbXdciDevContext->XdciPollTimer, + TimerCancel, + 0); + + uefi_call_wrapper(BS->CloseEvent, 1, UsbXdciDevContext->XdciPollTimer); + UsbXdciDevContext->XdciPollTimer = NULL; + } + + return; +} + +static EFI_STATUS find_usb_device_controller (EFI_HANDLE Controller) +{ + EFI_STATUS status = EFI_UNSUPPORTED; + EFI_PCI_IO *pci; + USB_CLASSC class_reg; + UINTN seg; + UINTN bus; + UINTN dev; + UINTN fun; + + status = uefi_call_wrapper(BS->OpenProtocol, + 6, + Controller, + &PciIoProtocol, + (VOID **) &pci, + g_parent_image, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR (status)) + return status; + + status = uefi_call_wrapper(pci->Pci.Read, + 5, + pci, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &class_reg); + + if (EFI_ERROR (status)) + return status; + + // Test whether the controller belongs to USB device type + // 0x0C03FE / 0x0C0380 + + if ((class_reg.BaseCode == PCI_CLASS_SERIAL) && + (class_reg.SubClassCode == PCI_CLASS_SERIAL_USB) && + ((class_reg.ProgInterface == PCI_IF_USBDEV) || + (class_reg.ProgInterface == 0x80))) { + return EFI_SUCCESS; + } + + + if ((class_reg.BaseCode == PCI_CLASS_SERIAL) && + (class_reg.SubClassCode == PCI_CLASS_SERIAL_USB) && + (class_reg.ProgInterface == PCI_IF_XHCI)) { + + status = uefi_call_wrapper(pci->GetLocation, + 5, + pci, + &seg, + &bus, + &dev, + &fun); + xhci_path.Device = (UINT8)dev; + xhci_path.Function = (UINT8)fun; + xhci_handle = Controller; + } + + return EFI_UNSUPPORTED; +} + +EFI_GUID gEfiEventExitBootServicesGuid = EventExitBootServices; + +static EFI_STATUS usb_device_mode_start (EFI_HANDLE Controller, EFI_USB_DEVICE_MODE_PROTOCOL **usb_device) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbXdciDevContext = NULL; + EFI_PCI_IO *PciIo; + EFI_EVENT ExitBootServicesEvent; + UINT32 XdciMmioBarHigh = 0; + + // Provide protocol interface + // Get the PCI I/O Protocol on PciHandle + Status = uefi_call_wrapper(BS->OpenProtocol, + 6, + Controller, + &PciIoProtocol, + (VOID **) &PciIo, + g_parent_image, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + UsbXdciDevContext = AllocateZeroPool (sizeof (USB_XDCI_DEV_CONTEXT)); + if (UsbXdciDevContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + // Initialize the driver context + // + UsbXdciDevContext->StartUpController = FALSE; + UsbXdciDevContext->XdciHandle = Controller; + UsbXdciDevContext->Signature = EFI_USB_DEV_SIGNATURE; + + Status = uefi_call_wrapper(PciIo->Pci.Read, + 5, + PciIo, + EfiPciIoWidthUint32, + R_OTG_BAR0, + 1, + &UsbXdciDevContext->XdciMmioBarAddr); + + if ((UsbXdciDevContext->XdciMmioBarAddr & B_OTG_BAR0_TYPE) == B_OTG_BAR0_64_BIT) { + Status = uefi_call_wrapper(PciIo->Pci.Read, + 5, + PciIo, + EfiPciIoWidthUint32, + R_OTG_BAR_HIGH, + 1, + &XdciMmioBarHigh); + } + + UsbXdciDevContext->XdciMmioBarAddr = ((UINT64) XdciMmioBarHigh << 32) | (UsbXdciDevContext->XdciMmioBarAddr & B_OTG_BAR0_BA); + DEBUG ((EFI_D_INFO, "USB DEV mode IO addr 0x%016lx\n", UsbXdciDevContext->XdciMmioBarAddr)); + + UINT8 command8 = 0x6; + Status = uefi_call_wrapper(PciIo->Pci.Write, + 5, + PciIo, + EfiPciIoWidthUint8, + R_XDCI_CMD_OFF, + 1, + &command8); + //read after write to ensure the former write take effect + command8 = 0; + Status = uefi_call_wrapper(PciIo->Pci.Read, + 5, + PciIo, + EfiPciIoWidthUint8, + R_XDCI_CMD_OFF, + 1, + &command8); + + UINT32 command32 = 0; + Status = uefi_call_wrapper(PciIo->Pci.Write, + 5, + PciIo, + EfiPciIoWidthUint32, + R_XDCI_GEN_REGRW1, + 1, + &command32); + + CopyMem (&(UsbXdciDevContext->UsbDevModeProtocol), + &mUsbDeviceModeProtocol, + sizeof (EFI_USB_DEVICE_MODE_PROTOCOL)); + + Status = uefi_call_wrapper(BS->CreateEventEx, + 6, + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UsbDeviceDxeExitBootService, + UsbXdciDevContext, + &gEfiEventExitBootServicesGuid, + &ExitBootServicesEvent); + if (EFI_ERROR (Status)) + goto ErrorExit; + + *usb_device = &(UsbXdciDevContext->UsbDevModeProtocol); + + return Status; + +ErrorExit: + + if (UsbXdciDevContext != NULL) { + if (UsbXdciDevContext->XdciPollTimer != NULL) { + uefi_call_wrapper(BS->CloseEvent, + 1, + UsbXdciDevContext->XdciPollTimer); + UsbXdciDevContext->XdciPollTimer = NULL; + } + FreePool (UsbXdciDevContext); + } + + efi_perror(Status, L"ERROR - install driver failed - Exit\n"); + return Status; +} + +static BOOLEAN usb_xdci_enabled(void) +{ + EFI_STATUS ret; + UINTN NumberHandles, Index; + EFI_HANDLE *Handles; + + ret = LibLocateHandle(ByProtocol, + &PciIoProtocol, + NULL, + &NumberHandles, + &Handles); + if (EFI_ERROR(ret)) { + efi_perror(ret, L"LibLocateProtocol: Handle not found\n"); + return ret; + } + + for (Index=0; Index < NumberHandles; Index++) { + ret = find_usb_device_controller(Handles[Index]); + if (!EFI_ERROR(ret)) { + xdci_handle = Handles[Index]; + break; + } + } + + if (Handles) { + FreePool (Handles); + } + + if (!EFI_ERROR(ret)) + return TRUE; + + return FALSE; +} + +EFI_STATUS init_usb_device_mode_protocol(EFI_USB_DEVICE_MODE_PROTOCOL **usb_device) +{ + EFI_STATUS ret = EFI_UNSUPPORTED; + + if (usb_xdci_enabled()) { + ret = usb_device_mode_start(xdci_handle, usb_device); + } else { + efi_perror(ret, L"XDCI is disabled, please enable it in BIOS"); + } + + return ret; +} + diff --git a/libefiusb/device_mode/UsbDeviceDxe.h b/libefiusb/device_mode/UsbDeviceDxe.h index b9fb6595..d0242d60 100644 --- a/libefiusb/device_mode/UsbDeviceDxe.h +++ b/libefiusb/device_mode/UsbDeviceDxe.h @@ -13,7 +13,6 @@ #ifndef __USB_DEVICE_DXE_H__ #define __USB_DEVICE_DXE_H__ - #include #include "XdciDWC.h" #include "protocol/UsbDeviceLib.h" @@ -51,6 +50,7 @@ PlatformSpecificInit ( ); extern PCI_DEVICE_PATH xhci_path; +extern UINTN XhciMmioBarAddr; #pragma pack(1) typedef struct { @@ -61,35 +61,38 @@ typedef struct { #pragma pack() #define PCI_CLASSCODE_OFFSET 0x09 -#define PCI_CLASS_SERIAL 0x0C +#define PCI_CLASS_SERIAL 0x0C #define PCI_CLASS_SERIAL_USB 0x03 -#define PCI_IF_USBDEV 0xFE -#define PCI_IF_XHCI 0x30 +#define PCI_IF_USBDEV 0xFE +#define PCI_IF_XHCI 0x30 #define EventExitBootServices \ { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF } } #define R_OTG_BAR0 0x10 ///< BAR 0 -#define B_OTG_BAR0_BA 0xFFE00000 ///< Base Address -#define R_XHCI_MEM_BASE 0x10 +#define B_OTG_BAR0_BA 0xFFFFF000 ///< Base Address +#define B_OTG_BAR0_TYPE 0x00000006 // Type +#define B_OTG_BAR0_64_BIT 0x00000004 // 64 bit +#define R_OTG_BAR_HIGH 0x14 // BAR High +#define R_OTG_BAR1 0x18 // BAR 1 + + +#define R_XHCI_BAR0 0x10 // BAR 0 +#define R_XHCI_BAR_HIGH 0x14 // BAR High +#define B_XHCI_BAR0_TYPE 0x00000006 // Type +#define B_XHCI_BAR0_64_BIT 0x00000004 // 64 bit #define B_XHCI_MEM_BASE_BA 0xFFFFFFFFFFFF0000 #define R_XHCI_MEM_DUAL_ROLE_CFG0 0x80D8 #define R_XHCI_MEM_DUAL_ROLE_CFG1 0x80DC -#define R_XDCI_CMD_OFF 0x04 - -#define MmPciAddress( Segment, Bus, Device, Function, Register ) \ - ( (UINTN)0xE0000000 + \ - (UINTN)(Bus << 20) + \ - (UINTN)(Device << 15) + \ - (UINTN)(Function << 12) + \ - (UINTN)(Register) \ - ) +#define R_XDCI_CMD_OFF 0x04 +#define R_XDCI_GEN_REGRW1 0xB0 UINT32 MmioRead32(UINTN address); UINT16 MmioRead16(UINTN address); -UINT8 MmioRead8(UINTN address); +UINT8 MmioRead8(UINTN address); +UINT64 MmioWrite64(UINTN address, UINT64 value); UINT32 MmioWrite32(UINTN address, UINT32 value); UINT16 MmioWrite16(UINTN address, UINT16 value); -UINT8 MmioWrite8(UINTN address, UINT8 value); +UINT8 MmioWrite8(UINTN address, UINT8 value); EFI_STATUS install_usb_device_mode_protocol(void); #endif diff --git a/libefiusb/device_mode/UsbDeviceMode.c b/libefiusb/device_mode/UsbDeviceMode.c index ac9a6d31..44e209af 100644 --- a/libefiusb/device_mode/UsbDeviceMode.c +++ b/libefiusb/device_mode/UsbDeviceMode.c @@ -1,1488 +1,1482 @@ -/** @file - Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include "XdciUtility.h" -#include "UsbDeviceDxe.h" -#include "UsbDeviceMode.h" - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -// -// Global USBD driver object. This is the main private driver object -// that contains all data needed for this driver to operate. -// -USB_DEVICE_DRIVER_OBJ mDrvObj; - -// -// Global data IO transaction request object -// -USB_DEVICE_IO_REQ mCtrlIoReq = { - // - // IO information containing the Buffer and data size - // - { - NULL, - 0, - }, - // - // Note: This object is used for Control Ep transfers only - // therefore the endpoint info must always be NULL - // - { - NULL, - NULL, - } -}; - -// -// global flag to signal device event processing loop to run/stop -// -BOOLEAN mXdciRun = FALSE; - -VOID -XhciSwitchSwid(BOOLEAN enable) -{ - UINTN XhciPciMmBase; - EFI_PHYSICAL_ADDRESS XhciMemBaseAddress; - UINT32 DualRoleCfg0; - UINT32 DualRoleCfg1; - - XhciPciMmBase = MmPciAddress (0, 0, xhci_path.Device, xhci_path.Function, 0); - XhciMemBaseAddress = MmioRead32 ((UINTN) (XhciPciMmBase + R_XHCI_MEM_BASE)) & B_XHCI_MEM_BASE_BA; - DEBUG ((DEBUG_INFO, "XhciPciMmBase=%x, XhciMemBaseAddress=%x\n", XhciPciMmBase, XhciMemBaseAddress)); - - DualRoleCfg0 = MmioRead32 ((UINTN)(XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG0)); - if (enable) { - DualRoleCfg0 = DualRoleCfg0 | (1 << 24) | (1 << 21) | (1 << 20); - DEBUG ((DEBUG_INFO, "DualRoleCfg0 : Set SW ID : 0x%x \n", DualRoleCfg0)); - } - else { - DualRoleCfg0 = DualRoleCfg0 & ~(1 << 24) & ~(1 << 21) & ~(1 << 20); - DEBUG ((DEBUG_INFO, "DualRoleCfg0 : Clear SW ID : 0x%x \n", DualRoleCfg0)); - } - MmioWrite32 ((UINTN)(XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG0), DualRoleCfg0); - - DualRoleCfg1 = MmioRead32 ((UINTN)(XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG1)); - DEBUG ((DEBUG_INFO, "DualRoleCfg1 : 0x%x \n", DualRoleCfg1)); -} - -VOID -EFIAPI -UsbdMonitorEvents ( - IN EFI_EVENT __attribute__((unused))Event, - IN VOID *Context - ) -{ - USB_XDCI_DEV_CONTEXT *XdciDevContext; - UINT32 EventCount; - UINT32 PreEventCount; - UINT32 LoopCount; - - XdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context; - EventCount = UsbRegRead ((UINT32)XdciDevContext->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG (0)); - if (EventCount == 0) { - return; - } - - LoopCount = 0; - PreEventCount = EventCount; - while (EventCount != 0) { - if (UsbDeviceIsrRoutineTimerBased (mDrvObj.XdciDrvObj) != EFI_SUCCESS) { - DEBUG ((DEBUG_INFO, "UsbDeviceRun() - Failed to execute event ISR\n")); - } - EventCount = UsbRegRead ((UINT32)XdciDevContext->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG (0)); - if (PreEventCount == EventCount) { - LoopCount++; - if (LoopCount >= 5) { - DEBUG ((DEBUG_INFO, "USB is working on a long event...\n")); - break; - } - } else { - LoopCount = 0; - } - } - - return; -} - -/** - Initializes the XDCI core - - @param MmioBar Address of MMIO BAR - @param XdciHndl Double pointer to for XDCI layer to set as an - opaque handle to the driver to be used in subsequent - interactions with the XDCI layer. - - @return EFI_SUCCESS if successfully initialized XDCI, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdInit ( - IN UINT32 MmioBar, - IN VOID **XdciHndl - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - USB_DEV_CONFIG_PARAMS ConfigParams; - - XhciSwitchSwid(TRUE); - - DEBUG ((DEBUG_INFO, "UsbdInit start\n")); - ConfigParams.ControllerId = USB_ID_DWC_XDCI; - ConfigParams.BaseAddress = MmioBar; - ConfigParams.Role = USB_ROLE_DEVICE; - ConfigParams.Speed = USB_SPEED_SUPER; - - Status = UsbDeviceInit (&ConfigParams, XdciHndl); - - DEBUG ((DEBUG_INFO, "UsbdInit status is %x\n", Status)); - DEBUG ((DEBUG_INFO, "ConfigParams.BaseAddress 0x%x\n", ConfigParams.BaseAddress)); - - return Status; -} - - -/** - Copies relevant endpoint data from standard USB endpoint descriptors - to the usbEpInfo structure used by the XDCI - - @param EpDest destination structure - @param EpSrc source structure - - @return VOID - -**/ -VOID -UsbdSetEpInfo ( - IN USB_EP_INFO *EpDest, - IN USB_DEVICE_ENDPOINT_INFO *EpSrc - ) -{ - EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc = NULL; - EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR *EpCompDesc = NULL; - - // - // start by clearing all data in the destination - // - SetMem (EpDest, sizeof(USB_EP_INFO), 0); - EpDesc = EpSrc->EndpointDesc; - EpCompDesc = EpSrc->EndpointCompDesc; - - if (EpDesc != NULL) { - EpDest->EpNum = EpDesc->EndpointAddress & 0x0F; //Bits 0-3 are ep num - EpDest->EpDir = ((EpDesc->EndpointAddress & USB_ENDPOINT_DIR_IN) > 0) ? UsbEpDirIn : UsbEpDirOut; - EpDest->EpType = EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK; - EpDest->MaxPktSize = EpDesc->MaxPacketSize; - EpDest->Interval = EpDesc->Interval; - } - if (EpCompDesc != NULL) { - EpDest->MaxStreams = EpCompDesc->Attributes & USB_EP_BULK_BM_ATTR_MASK; - EpDest->BurstSize = EpCompDesc->MaxBurst; - EpDest->Mult = EpCompDesc->BytesPerInterval; - } - - return; -} - - -/** - Initializes the given endpoint - - @param XdciHndl Pointer (handle) to the XDCI driver object - @param DevEpInfo Pointer to endpoint info structure - for the endpoint to initialize - - @return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdInitEp ( - IN VOID *XdciHndl, - IN USB_DEVICE_ENDPOINT_INFO *DevEpInfo - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - USB_EP_INFO EpInfo; - - UsbdSetEpInfo (&EpInfo, DevEpInfo); - Status = UsbDeviceInitEp (XdciHndl, &EpInfo); - - return Status; -} - - -/** - Callback handler used when transfer operations complete. Calls - upper layer routine to handle the operation. - - @param XdciHndl Pointer (handle) to the XDCI driver object - @param XferReq Pointer to the transfer request structure - - @return VOID - -**/ -VOID -EFIAPI -UsbdXferDoneHndlr ( - IN VOID __attribute((unused))*XdciHndl, - IN USB_XFER_REQUEST *XferReq - ) -{ - EFI_USB_DEVICE_XFER_INFO XferInfo; - - DEBUG ((DEBUG_INFO, "UsbdXferDoneHndlr\n")); - - XferInfo.EndpointNum = (UINT8)XferReq->EpInfo.EpNum; - XferInfo.EndpointDir = XferReq->EpInfo.EpDir; - XferInfo.EndpointType = XferReq->EpInfo.EpType; - XferInfo.Buffer = XferReq->XferBuffer; - XferInfo.Length = XferReq->ActualXferLen; - - // - // If this is a non-control transfer complete, notify the class driver - // - if (XferInfo.EndpointNum > 0) { - if (mDrvObj.UsbdDevObj->DataCallback != NULL) { - mDrvObj.UsbdDevObj->DataCallback (&XferInfo); - } - } - - return; -} - - -/** - Queue a request to transmit data - - @param XdciHndl Pointer (handle) to the XDCI driver object - @param IoReq Pointer to IO structure containing details of the - transfer request - - @return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdEpTxData ( - IN VOID *XdciHndl, - IN USB_DEVICE_IO_REQ *IoReq - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - USB_XFER_REQUEST TxReq; - - // - //set endpoint data - // - UsbdSetEpInfo (&(TxReq.EpInfo), &(IoReq->EndpointInfo)); // set endpoint data - - // - //if this is a control endpoint, set the number and direction - // - if (IoReq->EndpointInfo.EndpointDesc == NULL) { - TxReq.EpInfo.EpNum = 0; - TxReq.EpInfo.EpDir = UsbEpDirIn; - } - - // - // setup the trasfer request - // - TxReq.XferBuffer = IoReq->IoInfo.Buffer; - TxReq.XferLen = IoReq->IoInfo.Length; - TxReq.XferDone = UsbdXferDoneHndlr; - - DEBUG ((DEBUG_INFO, "TX REQUEST: EpNum: 0x%x, epDir: 0x%x, epType: 0x%x, MaxPktSize: 0x%x\n",\ - TxReq.EpInfo.EpNum, TxReq.EpInfo.EpDir, TxReq.EpInfo.EpType, TxReq.EpInfo.MaxPktSize)); - - Status = UsbXdciDeviceEpTxData (XdciHndl, &TxReq); - - return Status; -} - - -/** - Queue a request to receive data - - @param XdciHndl Pointer (handle) to the XDCI driver object - @param IoReq Pointer to IO structure containing details of the - receive request - - @return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdEpRxData ( - IN VOID *XdciHndl, - IN USB_DEVICE_IO_REQ *IoReq - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - USB_XFER_REQUEST RxReq; - UINT32 ReqPacket; - - DEBUG ((DEBUG_INFO, "RX REQUEST in: IoReq->IoInfo.Length: 0x%x\n", IoReq->IoInfo.Length)); - DEBUG ((DEBUG_INFO, "RX REQUEST in: MaxPacketSize: 0x%x\n", IoReq->EndpointInfo.EndpointDesc->MaxPacketSize)); - - if (IoReq->EndpointInfo.EndpointDesc->MaxPacketSize == 0) { - return EFI_DEVICE_ERROR; - } - - // - // set endpoint data - // - UsbdSetEpInfo (&(RxReq.EpInfo), &(IoReq->EndpointInfo)); - - // - // setup the trasfer request - // - RxReq.XferBuffer = IoReq->IoInfo.Buffer; - - // - // Transfer length should be multiple of USB packet size. - // - ReqPacket = IoReq->IoInfo.Length / IoReq->EndpointInfo.EndpointDesc->MaxPacketSize; - ReqPacket = ((IoReq->IoInfo.Length % IoReq->EndpointInfo.EndpointDesc->MaxPacketSize) == 0)? ReqPacket : ReqPacket + 1; - RxReq.XferLen = ReqPacket * IoReq->EndpointInfo.EndpointDesc->MaxPacketSize; - - RxReq.XferDone = UsbdXferDoneHndlr; - - DEBUG ((DEBUG_INFO, "RX REQUEST: EpNum: 0x%x, epDir: 0x%x, epType: 0x%x\n",\ - RxReq.EpInfo.EpNum, RxReq.EpInfo.EpDir, RxReq.EpInfo.EpType)); - DEBUG ((DEBUG_INFO, "RX REQUEST send: XferLen: 0x%x\n", RxReq.XferLen)); - - Status = UsbXdciDeviceEpRxData (XdciHndl, &RxReq); - - return Status; -} - - -/** - Callback used to handle Reset events from the XDCI - - @param Param Pointer to a generic callback parameter structure - - @return XDCI usb status - -**/ -EFI_STATUS -EFIAPI -UsbdResetEvtHndlr ( - IN USB_DEVICE_CALLBACK_PARAM __attribute__((unused)) *Param - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbdResetEvtHndlr\n")); - - // - // reset device address to 0 - // - Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdResetHdlr() - Failed to set address in XDCI\n")); - } - - return Status; -} - - -/** - Callback used to handle Connection done events from the XDCI - - @param Param Pointer to a generic callback parameter structure - - @return XDCI usb status - -**/ -EFI_STATUS -EFIAPI -UsbdConnDoneEvtHndlr ( - IN USB_DEVICE_CALLBACK_PARAM __attribute__((unused))*Param - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbdConnDoneEvtHndlr\n")); - - // - //reset device address to 0 - // - Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr() - Failed to set address in XDCI\n")); - } - - // - // set the device state to attached/connected - // - mDrvObj.State = UsbDevStateAttached; - - return Status; -} - - -/** - Callback used to handle Control Endpoint Setup events from the XDCI - - @param Param Pointer to a generic callback parameter structure - - @return XDCI usb status - -**/ -EFI_STATUS -EFIAPI -UsbdSetupEvtHndlr ( - IN USB_DEVICE_CALLBACK_PARAM *Param - ) -{ - EFI_STATUS Status = EFI_SUCCESS; - EFI_USB_DEVICE_REQUEST Req; - - DEBUG ((DEBUG_INFO, "UsbdSetupEvtHndlr\n")); - - // - // Fill out request object from the incomming Buffer - // - CopyMem (&Req, Param->Buffer, sizeof(EFI_USB_DEVICE_REQUEST)); - - Status = UsbdSetupHdlr (&Req); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdSetupEvtHndlr: EFI_DEVICE_ERROR\n")); - } - - return Status; -} - - -/** - * Callback used to handle XferNotReady events from the XDCI - * - * @param Param Pointer to a generic callback parameter structure - * - * @return XDCI usb status - */ -EFI_STATUS -EFIAPI -UsbdNrdyEvtHndlr ( - IN USB_DEVICE_CALLBACK_PARAM __attribute((unused))*Param - ) -{ - DEBUG ((DEBUG_INFO, "UsbdNrdyEvtHndlr\n")); - return EFI_SUCCESS; -} - - -/** - Registers callbacks for event handlers with the XDCI layer. - The functions will be called as the registered events are triggered. - - @param XdciHndl to XDCI core driver - @return EFI_SUCCESS if successful, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdRegisterCallbacks ( - IN VOID *XdciHndl - ) -{ - if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_RESET_EVENT, UsbdResetEvtHndlr) != EFI_SUCCESS) { - goto UdciRegCallbackError; - } - - if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_CONNECTION_DONE, UsbdConnDoneEvtHndlr) != EFI_SUCCESS) { - goto UdciRegCallbackError; - } - - if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_SETUP_PKT_RECEIVED, UsbdSetupEvtHndlr) != EFI_SUCCESS) { - goto UdciRegCallbackError; - } - - if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_XFER_NRDY, UsbdNrdyEvtHndlr) != EFI_SUCCESS) { - goto UdciRegCallbackError; - } - - return EFI_SUCCESS; - -UdciRegCallbackError: - return EFI_DEVICE_ERROR; -} - - -/** - Returns the configuration descriptor for this device. The data - Buffer returned will also contain all downstream interface and - endpoint Buffers. - - @param Buffer Pointer to destination Buffer to copy descriptor data to - @param DescIndex the index of the descriptor to return - @param ReqLen the length in bytes of the request Buffer - @param DataLen Pointer whos value is to be filled with the byte count of - data copied to the output Buffer - - @return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdGetConfigDesc ( - IN VOID *Buffer, - IN UINT8 DescIndex, - IN UINT32 ReqLen, - IN UINT32 *DataLen - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - UINT8 NumConfigs = 0; - UINT32 ConfigLen = 0; - USB_DEVICE_CONFIG_OBJ *ConfigObj = NULL; - VOID *Descriptor = 0; - UINT32 Length = 0; - - DEBUG ((DEBUG_INFO, "UsbdGetConfigDesc()\n")); - - // - // For a CONFIGURATION request we send back all descriptors branching out - // from this descriptor including the INTERFACE and ENDPOINT descriptors - // - // - // Verify the requested configuration exists - check valid index - // - NumConfigs = mDrvObj.UsbdDevObj->DeviceDesc->NumConfigurations; - - if (DescIndex < NumConfigs) { - // - // get the configuration object using the index Offset - // - ConfigObj = (mDrvObj.UsbdDevObj->ConfigObjs + DescIndex); - // - // get the complete configuration Buffer block including Interface and Endpoint data - // - Descriptor = ConfigObj->ConfigAll; - // - // The config descriptor TotalLength has the full value for all desc Buffers - // - ConfigLen = ConfigObj->ConfigDesc->TotalLength; - // - // copy the data to the output Buffer - // - Length = MIN (ReqLen, ConfigLen); - CopyMem (Buffer, Descriptor, Length); - *DataLen = Length; - Status = EFI_SUCCESS; - } else { - DEBUG ((DEBUG_INFO, "UsbdGetConfigDesc() - Invalid Config index: %i\n", DescIndex)); - } - - if (Status == EFI_SUCCESS) { - if (ConfigObj != NULL) { - PrintConfigDescriptor (ConfigObj->ConfigDesc); - } - } - - return Status; -} - - -/** - Sets the active configuration to the selected configuration index if it exists - - @param CfgValue the configuration value to set - - @return EFI_SUCCESS if the configuration was set, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdSetConfig ( - UINT8 CfgValue - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - UINT8 numConfigs = 0; - USB_DEVICE_CONFIG_OBJ *pConfigObj = NULL; - USB_DEVICE_INTERFACE_OBJ *pIfObj = NULL; - USB_DEVICE_ENDPOINT_OBJ *pEpObj = NULL; - UINT8 cfgItr = 0; - UINT8 ifItr = 0; - UINT8 epItr = 0; - USB_DEVICE_ENDPOINT_INFO EpInfo; - USB_EP_INFO UsbEpInfo; - - DEBUG ((DEBUG_INFO, "UsbdSetConfig()\n")); - // - // Verify the requested configuration exists - check valid index - // - numConfigs = mDrvObj.UsbdDevObj->DeviceDesc->NumConfigurations; - - if (CfgValue != 0) { - // - // Search for a matching configuration - // - for (cfgItr = 0; cfgItr < numConfigs; cfgItr++) { - pConfigObj = (mDrvObj.UsbdDevObj->ConfigObjs + cfgItr); - if (pConfigObj->ConfigDesc->ConfigurationValue == CfgValue) { - - // - // Set the active configuration object - // - mDrvObj.ActiveConfigObj = pConfigObj; - // - // Find all interface objects for this configuration - // - for (ifItr = 0; ifItr < pConfigObj->ConfigDesc->NumInterfaces; ifItr++) { - pIfObj = (pConfigObj->InterfaceObjs + ifItr); - // - // Configure the Endpoints in the XDCI - // - for (epItr = 0; epItr < pIfObj->InterfaceDesc->NumEndpoints; epItr++) { - pEpObj = (pIfObj->EndpointObjs + epItr); - - EpInfo.EndpointDesc = pEpObj->EndpointDesc; - EpInfo.EndpointCompDesc = pEpObj->EndpointCompDesc; - - if (UsbdInitEp (mDrvObj.XdciDrvObj, &EpInfo) == EFI_SUCCESS) { - UsbdSetEpInfo(&UsbEpInfo, &EpInfo); - if (UsbDeviceEpEnable (mDrvObj.XdciDrvObj, &UsbEpInfo) == EFI_SUCCESS) { - Status = EFI_SUCCESS; - } else { - DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Failed to enable endpoint\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Failed to initialize endpoint\n")); - } - } - } - // - // Let the class driver know it is configured - // - if (Status == EFI_SUCCESS) { - if (mDrvObj.UsbdDevObj->ConfigCallback != NULL) { - mDrvObj.UsbdDevObj->ConfigCallback (CfgValue); - } - } - - mDrvObj.State = UsbDevStateConfigured; // we are now configured - - break; // break from config search loop - } - } - } - - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Invalid requested configuration value: %i\n", CfgValue)); - } - - return Status; -} - - -/** - Returns the currently active configuration value - - @param Buffer Pointer to destination Buffer to copy configuration value to - @param ReqLen the length in bytes of the request Buffer - @param DataLen Pointer whos value is to be filled with the byte count of - data copied to the output Buffer - - @return EFI_SUCCESS if config value is successfully copied, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdGetConfig ( - VOID *Buffer, - UINT32 ReqLen, - UINT32 *DataLen - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbdGetConfig()\n")); - - if (ReqLen >= 1) { // length of data expected must be 1 - if (mDrvObj.ActiveConfigObj != NULL) { // assure we have a config active - *DataLen = 1; // one byte for ConfigurationValue - *(UINT8*)Buffer = mDrvObj.ActiveConfigObj->ConfigDesc->ConfigurationValue; - - Status = EFI_SUCCESS; - } else { - DEBUG ((DEBUG_INFO, "UsbdGetConfig() - No active configuration available\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbdGetConfig() - Invalid data length\n")); - } - - return Status; -} - - -/** - Returns the requested string descriptor if it exists - - @param Buffer Pointer to destination Buffer to copy descriptor data to - @param DescIndex the index of the descriptor to return - @param LangId the target language ID - @param ReqLen the length in bytes of the request Buffer - @param DataLen Pointer whos value is to be filled with the byte count of - data copied to the output Buffer - - @return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdGetStringDesc ( - VOID *Buffer, - UINT8 DescIndex, - UINT16 LangId, - UINT32 ReqLen, - UINT32 *DataLen - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - UINT32 Length = 0; - USB_STRING_DESCRIPTOR *StringDesc; - UINT8 Index = 0; - UINT8 StrLangEntries = 0; - BOOLEAN StrLangFound = FALSE; - - DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Index: 0x%x, LangId: 0x%x, ReqLen: 0x%x\n", DescIndex, LangId, ReqLen)); - - // - // index zero of the string table contains the supported language codes - // - if (DescIndex == 0) { - StringDesc = (mDrvObj.UsbdDevObj->StringTable); - Length = MIN (ReqLen, StringDesc->Length); - CopyMem (Buffer, StringDesc, Length); - *DataLen = Length; - Status = EFI_SUCCESS; - } else { - - // - // Verify the requested language ID is supported. String descriptor Zero - // (First entry in the string table) is expected to contain the language list. - // The requested language ID is specified in the Index member of the request. - // - StringDesc = mDrvObj.UsbdDevObj->StringTable; // get language string descriptor - StrLangEntries = ((StringDesc->Length - 2) >> 1); - DEBUG ((DEBUG_INFO, "StrLangEntries=%x\n", StrLangEntries)); - - DEBUG ((DEBUG_INFO, "Looking LangID: \n")); - - for (Index = 0; Index < StrLangEntries; Index++) { - DEBUG ((DEBUG_INFO, "LangID [%x]= %x\n", Index, StringDesc->LangID [Index])); - - if (StringDesc->LangID [Index] == LangId) { - DEBUG ((DEBUG_INFO, "Found it\n")); - StrLangFound = TRUE; - } - } - - // - // If we found a matching language, attempt to get the string index requested - // - if (StrLangFound == TRUE) { - DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: StrLangFound=Found, DescIndex=%x, StrTblEntries=%x\n", DescIndex, mDrvObj.UsbdDevObj->StrTblEntries)); - - if (DescIndex < mDrvObj.UsbdDevObj->StrTblEntries) { - // - // get the string descriptor for the requested index - // - StringDesc = (mDrvObj.UsbdDevObj->StringTable + DescIndex); - - Length = MIN (ReqLen, StringDesc->Length); - DEBUG ((DEBUG_INFO, "ReqLen=%x, StringLength=%x, Length=%x\n", ReqLen, StringDesc->Length, Length)); - - CopyMem (Buffer, StringDesc, Length); - *DataLen = Length; - Status = EFI_SUCCESS; - } else { - DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Invalid String index in USB_REQ_GET_DESCRIPTOR request\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Unsupported String Language ID for USB_REQ_GET_DESCRIPTOR request\n")); - } - } - - if (Status == EFI_SUCCESS) { - PrintStringDescriptor (StringDesc); - } - return Status; -} - - -#ifdef SUPPORT_SUPER_SPEED -/** - Returns the configuration descriptor for this device. The data - Buffer returned will also contain all downstream interface and - endpoint Buffers. - - @param Buffer Pointer to destination Buffer to copy descriptor data to - @param ReqLen the length in bytes of the request Buffer - @param DataLen Pointer whos value is to be filled with the byte count of - data copied to the output Buffer - - @return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdGetBOSDesc ( - IN VOID *Buffer, - IN UINT32 ReqLen, - IN UINT32 *DataLen - ) -{ - EFI_USB_BOS_DESCRIPTOR *BosDesc = 0; - UINT32 Length = 0; - - DEBUG ((DEBUG_INFO, "UsbdGetBOSDesc()\n")); - - BosDesc = mDrvObj.UsbdDevObj->BosDesc; - Length = MIN (ReqLen, mDrvObj.UsbdDevObj->BosDesc->TotalLength); - - CopyMem(Buffer, BosDesc, Length); - *DataLen = Length; - - PrintBOSDescriptor (BosDesc); - - return EFI_SUCCESS; -} -#endif - -/** - Returns the current status for Device/Interface/Endpoint - - @param Buffer Pointer to destination Buffer to copy descriptor data to - @param ReqType The type of status to get - @param ReqLen the length in bytes of the request Buffer - @param DataLen Pointer whos value is to be filled with the byte count of - data copied to the output Buffer - - @return EFI_SUCCESS if status successfully copied, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdGetStatus ( - VOID *Buffer, - UINT8 ReqType, - UINT32 ReqLen, - UINT32 *DataLen - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbdGetStatus()\n")); - - if (ReqLen >= 2) { // length of data must be at least 2 bytes - switch (ReqType & USB_TARGET_MASK) { - case USB_TARGET_DEVICE: - *DataLen = 2; // two byte for status - *(UINT16*)Buffer = USB_STATUS_SELFPOWERED; - Status = EFI_SUCCESS; - break; - - case USB_TARGET_INTERFACE: - // - // No implementation needed at this time - // - break; - - case USB_TARGET_ENDPOINT: - // - // No implementation needed at this time - // Should specify if endpoint is halted. Implement as necessary. - // - break; - - case USB_TARGET_OTHER: - // - // No implementation needed at this time - // - break; - - default: - break; - } - } else { - DEBUG ((DEBUG_INFO, "UsbdGetStatus() - Invalid data length\n")); - } - - return Status; -} - - -/** - Sets the address of the device - - @param address the address value to set - - @return EFI_SUCCESS if address was set, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdSetAddress ( - UINT8 Address - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbdSetAddress: setting address: 0x%x\n", Address)); - - if (Address <= 0x7F) { // address must not be > 127 - mDrvObj.Address = Address; - - // - // Configure Address in the XDCI - // - Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, mDrvObj.Address); - if (!EFI_ERROR (Status)) { - mDrvObj.State = UsbDevStateAddress; - } else { - DEBUG ((DEBUG_INFO, "UsbdSetAddress: Failed to set address in XDCI\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbdSetAddress: Invalid address: 0x%x\n", Address)); - } - - return Status; -} - - -/** - Handles Setup device requests. Standard requests are immediately - handled here, and any Class/Vendor specific requests are forwarded - to the class driver - - @param CtrlRequest Pointer to a device request - - @return EFI_SUCCESS if request successfully handled, FALSE otherwise - -**/ -EFI_STATUS -UsbdSetupHdlr ( - IN EFI_USB_DEVICE_REQUEST *CtrlRequest - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - UINT8 DescIndex = 0; - USB_DEVICE_DESCRIPTOR *DevDesc = 0; - - // - // Initialize the IO object - // - mCtrlIoReq.IoInfo.Length = 0; - - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr start\n")); - PrintDeviceRequest (CtrlRequest); - - // - // Handle Standard Device Requests - // - if ((CtrlRequest->RequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) { - switch (CtrlRequest->Request) { - case USB_REQ_GET_DESCRIPTOR: - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Host requests get descriptor\n")); - if (CtrlRequest->RequestType == USB_RT_TX_DIR_D_TO_H) { - DescIndex = (CtrlRequest->Value & 0xff); // low byte is the index requested - switch (CtrlRequest->Value >> 8) { // high byte contains request type - case USB_DESC_TYPE_DEVICE: - DEBUG ((DEBUG_INFO, "Descriptor tyep: Device\n")); - DevDesc = mDrvObj.UsbdDevObj->DeviceDesc; - // - // copy the data to the output Buffer - // - mCtrlIoReq.IoInfo.Length = MIN (CtrlRequest->Length, DevDesc->Length); - CopyMem (mCtrlIoReq.IoInfo.Buffer, DevDesc, mCtrlIoReq.IoInfo.Length); - PrintDeviceDescriptor (DevDesc); - break; - - case USB_DESC_TYPE_CONFIG: - DEBUG ((DEBUG_INFO, "Descriptor tyep: Configuration\n")); - Status = UsbdGetConfigDesc ( - mCtrlIoReq.IoInfo.Buffer, - DescIndex, - CtrlRequest->Length, - &(mCtrlIoReq.IoInfo.Length) - ); - break; - - case USB_DESC_TYPE_STRING: - DEBUG ((DEBUG_INFO, "Descriptor tyep: String\n")); - Status = UsbdGetStringDesc ( - mCtrlIoReq.IoInfo.Buffer, - DescIndex, - CtrlRequest->Index, - CtrlRequest->Length, - &(mCtrlIoReq.IoInfo.Length) - ); - break; - -#ifdef SUPPORT_SUPER_SPEED - case USB_DESC_TYPE_BOS: - DEBUG ((DEBUG_INFO, "Descriptor tyep: BOS\n")); - Status = UsbdGetBOSDesc ( - mCtrlIoReq.IoInfo.Buffer, - CtrlRequest->Length, - &(mCtrlIoReq.IoInfo.Length) - ); - break; - - case USB_DESC_TYPE_SS_ENDPOINT_COMPANION: - DEBUG ((DEBUG_INFO, "Descriptor tyep: Endpoint Companion\n")); - break; -#endif - - default: - DEBUG ((DEBUG_INFO, "Descriptor tyep: Unsupported, USB_REQ_GET_DESCRIPTOR request: 0x%x\n", (CtrlRequest->Value >> 8))); - break; - } - } else { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr() - Invalid direction for USB_REQ_GET_DESCRIPTOR request\n")); - } - break; - - case USB_REQ_GET_CONFIG: - DEBUG ((DEBUG_INFO, "USB_REQ_GET_CONFIG\n")); - if (CtrlRequest->RequestType == USB_RT_TX_DIR_D_TO_H) { - Status = UsbdGetConfig (mCtrlIoReq.IoInfo.Buffer, CtrlRequest->Length, &(mCtrlIoReq.IoInfo.Length)); - } else { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_GET_CONFIG request\n")); - } - break; - - case USB_REQ_SET_CONFIG: - DEBUG ((DEBUG_INFO, "USB_REQ_SET_CONFIG\n")); - if (CtrlRequest->RequestType == USB_RT_TX_DIR_H_TO_D) { - Status = UsbdSetConfig ((UINT8)CtrlRequest->Value); - } else { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_SET_CONFIG request\n")); - } - break; - - case USB_REQ_SET_ADDRESS: - DEBUG ((DEBUG_INFO, "USB_REQ_SET_ADDRESS\n")); - if (CtrlRequest->RequestType == USB_RT_TX_DIR_H_TO_D) { - Status = UsbdSetAddress ((UINT8)CtrlRequest->Value); - } else { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_SET_ADDRESS request\n")); - } - break; - - case USB_REQ_GET_STATUS: - DEBUG ((DEBUG_INFO, "USB_REQ_GET_STATUS\n")); - if (CtrlRequest->RequestType & USB_RT_TX_DIR_D_TO_H) { - Status = UsbdGetStatus (mCtrlIoReq.IoInfo.Buffer, CtrlRequest->RequestType, CtrlRequest->Length, &(mCtrlIoReq.IoInfo.Length)); - } else { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_GET_STATUS request\n")); - } - break; -#ifdef SUPPORT_SUPER_SPEED - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - case USB_REQ_SET_DESCRIPTOR: - case USB_REQ_GET_INTERFACE: - case USB_REQ_SET_INTERFACE: - case USB_REQ_SYNCH_FRAME: -#endif - default: - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Unsupported Standard Request: 0x%x\n", CtrlRequest->Request)); - break; - } - } else { // This is not a Standard request, it specifies Class/Vendor handling - // - // Forward request to class driver - // - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Class/Vendor Request\n")); - if (mDrvObj.UsbdDevObj->SetupCallback != NULL) { - mDrvObj.UsbdDevObj->SetupCallback (CtrlRequest, &(mCtrlIoReq.IoInfo)); - } - } - - DEBUG ((DEBUG_INFO, "dataLen=%x\n", mCtrlIoReq.IoInfo.Length)); - // - // Transfer data according to request if necessary - // - if (mCtrlIoReq.IoInfo.Length> 0) { - Status = UsbdEpTxData (mDrvObj.XdciDrvObj, &mCtrlIoReq); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Failed to TX data\n")); - } - } else { - // - // If we are not responding with data, send control status - // - Status = UsbDeviceEp0TxStatus (mDrvObj.XdciDrvObj); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Failed to Tx Ep0 Status\n")); - } - } - - return Status; -} - - -/** - Handles Connection done events. Sets the device address to zero. - - @return EFI_SUCCESS if able to set the address, EFI_DEVICE_ERROR otherwise - -**/ -EFI_STATUS -UsbdConnDoneHdlr ( - VOID - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr()\n")); - - // - // reset device address to 0 - // - Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr() - Failed to set address in XDCI\n")); - } - - // - // set the device state to attached/connected - // - mDrvObj.State = UsbDevStateAttached; - - return Status; -} - - -/** - Handles transmit/receive completion events. Directly handles - control endpoint events and forwards class/vendor specific events - to the class drivers. - - @param XferInfo Pointer to Xfer structure - - @return - -**/ -VOID -UsbdXferDoneHdlr ( - IN EFI_USB_DEVICE_XFER_INFO *XferInfo - ) -{ - // - // If this is a non-control transfer complete, notify the class driver - // - if (XferInfo->EndpointNum > 0) { - if (mDrvObj.UsbdDevObj->DataCallback != NULL) { - mDrvObj.UsbdDevObj->DataCallback (XferInfo); - } - } - - return; -} - - -/** - Binds a USB class driver with this USB device driver core. - After calling this routine, the driver is ready to begin - USB processing. - - @param UsbdDevObj Pointer to a usbd device object which contains - all relevant information for the class driver device - - @return TRUE if binding was successful, FALSE otherwise - -**/ -EFI_STATUS -EFIAPI -UsbDeviceBind ( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute__((unused))*This, - IN USB_DEVICE_OBJ *UsbdDevObj - ) -{ - EFI_STATUS Status = EFI_SUCCESS; - - // - // allocate Tx Buffer - // - mCtrlIoReq.IoInfo.Buffer = AllocateZeroPool (USB_EPO_MAX_PKT_SIZE_ALL); - if (mCtrlIoReq.IoInfo.Buffer != NULL) { - mDrvObj.UsbdDevObj = UsbdDevObj; - mDrvObj.ActiveConfigObj = NULL; - mDrvObj.Address = 0; - mDrvObj.State = UsbDevStateInit; - } else { - DEBUG ((DEBUG_INFO, "UsbDeviceBind() - Failed to allocate IO Buffer\n")); - Status = EFI_DEVICE_ERROR; - } - - return Status; -} - - -/** - Unbinds the USB class driver from this USB device driver core. - - @return TRUE if successful, FALSE otherwise - -**/ -EFI_STATUS -EFIAPI -UsbDeviceUnbind ( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute__((unused))*This - ) -{ - mDrvObj.UsbdDevObj = NULL; - mDrvObj.ActiveConfigObj = NULL; - mDrvObj.Address = 0; - mDrvObj.State = UsbDevStateOff; - mDrvObj.XdciInitialized = FALSE; - - // - // release allocated Buffer data - // - if (mCtrlIoReq.IoInfo.Buffer) { - FreePool (mCtrlIoReq.IoInfo.Buffer); - } - - return EFI_SUCCESS; -} - - -/** - Performs continual USB device event processing until a cancel - event occurs - - @param TimeoutMs Connection timeout in ms. If 0, waits forever. - @return TRUE if run executed normally, FALSE if error ocurred - -**/ -EFI_STATUS -EFIAPI -UsbDeviceRun ( - IN EFI_USB_DEVICE_MODE_PROTOCOL *This, - IN UINT32 TimeoutMs - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - USB_XDCI_DEV_CONTEXT *XdciDevContext; - - XdciDevContext = USBUSBD_CONTEXT_FROM_PROTOCOL (This); - - // - // can only run if XDCI is initialized - // - if (mDrvObj.XdciInitialized == TRUE) { - - if ((mDrvObj.State == UsbDevStateConfigured) && (XdciDevContext->XdciPollTimer == NULL)) { - Status = uefi_call_wrapper(BS->CreateEvent, - 5, - EVT_TIMER | EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - UsbdMonitorEvents, - XdciDevContext, - &XdciDevContext->XdciPollTimer - ); - if (!EFI_ERROR (Status)) { - Status = uefi_call_wrapper(BS->SetTimer, 3, XdciDevContext->XdciPollTimer, TimerPeriodic,200000); - DEBUG ((EFI_D_ERROR, "UsbDeviceRun Create Event\n")); - } - } - - mXdciRun = TRUE; // set the run flag to active - Status = EFI_SUCCESS; - - // - // start the Event processing loop - // - while (TRUE) { - if (XdciDevContext->XdciPollTimer == NULL) { - if (UsbDeviceIsrRoutine (mDrvObj.XdciDrvObj) != EFI_SUCCESS) { - DEBUG ((DEBUG_INFO, "UsbDeviceRun() - Failed to execute event ISR\n")); - } - } - - // - // Check if a run cancel request exists, if so exit processing loop - // - if (mXdciRun == FALSE) { - if (XdciDevContext->XdciPollTimer != NULL) { - DEBUG ((EFI_D_ERROR, "UsbDeviceRun close Event\n")); - uefi_call_wrapper(BS->SetTimer, 3, XdciDevContext->XdciPollTimer, TimerCancel, 0); - uefi_call_wrapper(BS->CloseEvent, 1, XdciDevContext->XdciPollTimer); - XdciDevContext->XdciPollTimer = NULL; - } - Status = EFI_SUCCESS; - DEBUG ((DEBUG_INFO, "UsbDeviceRun() - processing was cancelled\n")); - break; - } - - // - // check for timeout - // - if (TimeoutMs == 0) - return EFI_TIMEOUT; - uefi_call_wrapper(BS->Stall, 1, 50); - TimeoutMs--; - } - } - - return Status; -} - - -/** - Sets a flag to stop the running device processing loop - - @return TRUE always - -**/ -EFI_STATUS -EFIAPI -UsbDeviceStop ( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute__((unused))*This - ) -{ - mXdciRun = FALSE; // set run flag to FALSE to stop processing - return EFI_SUCCESS; -} - - -EFI_STATUS -EFIAPI -UsbDeviceInitXdci ( - IN EFI_USB_DEVICE_MODE_PROTOCOL *This - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - USB_XDCI_DEV_CONTEXT *XdciDevContext; - - XdciDevContext = USBUSBD_CONTEXT_FROM_PROTOCOL (This); - - PlatformSpecificInit (); - - if (mDrvObj.XdciInitialized == FALSE) { - if (XdciDevContext->XdciMmioBarAddr != 0) { - - // - // Initialize device controller driver - // - DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Initializing Controller...\n")); - - // - // Initialize the device controller interface - // - if (UsbdInit ((UINT32)XdciDevContext->XdciMmioBarAddr, &mDrvObj.XdciDrvObj) == EFI_SUCCESS) { - - // - // Setup callbacks - // - if (UsbdRegisterCallbacks (mDrvObj.XdciDrvObj) == EFI_SUCCESS) { - - mDrvObj.XdciInitialized = TRUE; - Status = EFI_SUCCESS; - - DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Controller initialization complete\n")); - } else { - DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Failed to register UDCI callbacks\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Failed to initialize UDCI\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - XDCI MMIO BAR not set\n")); - } - } else { - DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - XDCI already initialized\n")); - Status = EFI_ALREADY_STARTED; - } - - return Status; -} - - -EFI_STATUS -EFIAPI -UsbDeviceConnect( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbDeviceConnect \n")); - if (UsbXdciDeviceConnect (mDrvObj.XdciDrvObj) == EFI_SUCCESS) { - Status = EFI_SUCCESS; - } - return Status; -} - - -EFI_STATUS -EFIAPI -UsbDeviceDisConnect ( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - - DEBUG ((DEBUG_INFO, "UsbDeviceDisConnect \n")); - if (UsbDeviceDisconnect (mDrvObj.XdciDrvObj) == EFI_SUCCESS) { - mDrvObj.State = UsbDevStateInit; - Status = EFI_SUCCESS; - } - - XhciSwitchSwid(FALSE); - return Status; -} - - -EFI_STATUS -EFIAPI -UsbDeviceEpTxData( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This, - IN USB_DEVICE_IO_REQ *IoRequest - ) -{ - EFI_STATUS Status; - - Status = UsbdEpTxData (mDrvObj.XdciDrvObj, IoRequest); - return Status; -} - - -EFI_STATUS -EFIAPI -UsbDeviceEpRxData( - IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This, - IN USB_DEVICE_IO_REQ *IoRequest - ) -{ - EFI_STATUS Status; - - Status = UsbdEpRxData (mDrvObj.XdciDrvObj, IoRequest); - return Status; -} - - -// -// The Runtime UsbDeviceMode Protocol instance produced by this driver -// -EFI_USB_DEVICE_MODE_PROTOCOL mUsbDeviceModeProtocol = { - UsbDeviceInitXdci, - UsbDeviceConnect, - UsbDeviceDisConnect, - UsbDeviceEpTxData, - UsbDeviceEpRxData, - UsbDeviceBind, - UsbDeviceUnbind, - UsbDeviceRun, - UsbDeviceStop -}; - +/** @file + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include "XdciUtility.h" +#include "UsbDeviceDxe.h" +#include "UsbDeviceMode.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +// +// Global USBD driver object. This is the main private driver object +// that contains all data needed for this driver to operate. +// +USB_DEVICE_DRIVER_OBJ mDrvObj; + +// +// Global data IO transaction request object +// +USB_DEVICE_IO_REQ mCtrlIoReq = { + // + // IO information containing the Buffer and data size + // + { + NULL, + 0, + }, + // + // Note: This object is used for Control Ep transfers only + // therefore the endpoint info must always be NULL + // + { + NULL, + NULL, + } +}; + +// +// global flag to signal device event processing loop to run/stop +// +BOOLEAN mXdciRun = FALSE; + +VOID +XhciSwitchSwid(BOOLEAN enable) +{ + UINT32 DualRoleCfg0; + UINT32 DualRoleCfg1; + + + DualRoleCfg0 = MmioRead32 ((UINTN)(XhciMmioBarAddr + R_XHCI_MEM_DUAL_ROLE_CFG0)); + if (enable) { + DualRoleCfg0 = DualRoleCfg0 | (1 << 24) | (1 << 21) | (1 << 20); + DEBUG ((DEBUG_INFO, "DualRoleCfg0 : Set SW ID : 0x%x \n", DualRoleCfg0)); + } + else { + DualRoleCfg0 = DualRoleCfg0 & ~(1 << 24) & ~(1 << 21) & ~(1 << 20); + DEBUG ((DEBUG_INFO, "DualRoleCfg0 : Clear SW ID : 0x%x \n", DualRoleCfg0)); + } + MmioWrite32 ((UINTN)(XhciMmioBarAddr + R_XHCI_MEM_DUAL_ROLE_CFG0), DualRoleCfg0); + + DualRoleCfg1 = MmioRead32 ((UINTN)(XhciMmioBarAddr + R_XHCI_MEM_DUAL_ROLE_CFG1)); + DEBUG ((DEBUG_INFO, "DualRoleCfg1 : 0x%x \n", DualRoleCfg1)); +} + +VOID +EFIAPI +UsbdMonitorEvents ( + IN EFI_EVENT __attribute__((unused))Event, + IN VOID *Context + ) +{ + USB_XDCI_DEV_CONTEXT *XdciDevContext; + UINT32 EventCount; + UINT32 PreEventCount; + UINT32 LoopCount; + + XdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context; + EventCount = UsbRegRead ((UINT32)XdciDevContext->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG (0)); + if (EventCount == 0) { + return; + } + + LoopCount = 0; + PreEventCount = EventCount; + while (EventCount != 0) { + if (UsbDeviceIsrRoutineTimerBased (mDrvObj.XdciDrvObj) != EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "UsbDeviceRun() - Failed to execute event ISR\n")); + } + EventCount = UsbRegRead ((UINT32)XdciDevContext->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG (0)); + if (PreEventCount == EventCount) { + LoopCount++; + if (LoopCount >= 5) { + DEBUG ((DEBUG_INFO, "USB is working on a long event...\n")); + break; + } + } else { + LoopCount = 0; + } + } + + return; +} + +/** + Initializes the XDCI core + + @param MmioBar Address of MMIO BAR + @param XdciHndl Double pointer to for XDCI layer to set as an + opaque handle to the driver to be used in subsequent + interactions with the XDCI layer. + + @return EFI_SUCCESS if successfully initialized XDCI, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdInit ( + IN UINTN MmioBar, + IN VOID **XdciHndl + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_DEV_CONFIG_PARAMS ConfigParams; + +// XhciSwitchSwid(TRUE); + + DEBUG ((DEBUG_INFO, "UsbdInit start\n")); + ConfigParams.ControllerId = USB_ID_DWC_XDCI; + ConfigParams.BaseAddress = MmioBar; + ConfigParams.Role = USB_ROLE_DEVICE; + ConfigParams.Speed = USB_SPEED_SUPER; + + Status = UsbDeviceInit (&ConfigParams, XdciHndl); + + DEBUG ((DEBUG_INFO, "UsbdInit status is %x\n", Status)); + DEBUG ((DEBUG_INFO, "ConfigParams.BaseAddress 0x%016lx\n", ConfigParams.BaseAddress)); + + return Status; +} + + +/** + Copies relevant endpoint data from standard USB endpoint descriptors + to the usbEpInfo structure used by the XDCI + + @param EpDest destination structure + @param EpSrc source structure + + @return VOID + +**/ +VOID +UsbdSetEpInfo ( + IN USB_EP_INFO *EpDest, + IN USB_DEVICE_ENDPOINT_INFO *EpSrc + ) +{ + EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc = NULL; + EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR *EpCompDesc = NULL; + + // + // start by clearing all data in the destination + // + SetMem (EpDest, sizeof(USB_EP_INFO), 0); + EpDesc = EpSrc->EndpointDesc; + EpCompDesc = EpSrc->EndpointCompDesc; + + if (EpDesc != NULL) { + EpDest->EpNum = EpDesc->EndpointAddress & 0x0F; //Bits 0-3 are ep num + EpDest->EpDir = ((EpDesc->EndpointAddress & USB_ENDPOINT_DIR_IN) > 0) ? UsbEpDirIn : UsbEpDirOut; + EpDest->EpType = EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK; + EpDest->MaxPktSize = EpDesc->MaxPacketSize; + EpDest->Interval = EpDesc->Interval; + } + if (EpCompDesc != NULL) { + EpDest->MaxStreams = EpCompDesc->Attributes & USB_EP_BULK_BM_ATTR_MASK; + EpDest->BurstSize = EpCompDesc->MaxBurst; + EpDest->Mult = EpCompDesc->BytesPerInterval; + } + + return; +} + + +/** + Initializes the given endpoint + + @param XdciHndl Pointer (handle) to the XDCI driver object + @param DevEpInfo Pointer to endpoint info structure + for the endpoint to initialize + + @return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdInitEp ( + IN VOID *XdciHndl, + IN USB_DEVICE_ENDPOINT_INFO *DevEpInfo + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_EP_INFO EpInfo; + + UsbdSetEpInfo (&EpInfo, DevEpInfo); + Status = UsbDeviceInitEp (XdciHndl, &EpInfo); + + return Status; +} + + +/** + Callback handler used when transfer operations complete. Calls + upper layer routine to handle the operation. + + @param XdciHndl Pointer (handle) to the XDCI driver object + @param XferReq Pointer to the transfer request structure + + @return VOID + +**/ +VOID +EFIAPI +UsbdXferDoneHndlr ( + IN VOID __attribute((unused))*XdciHndl, + IN USB_XFER_REQUEST *XferReq + ) +{ + EFI_USB_DEVICE_XFER_INFO XferInfo; + + DEBUG ((DEBUG_INFO, "UsbdXferDoneHndlr\n")); + + XferInfo.EndpointNum = (UINT8)XferReq->EpInfo.EpNum; + XferInfo.EndpointDir = XferReq->EpInfo.EpDir; + XferInfo.EndpointType = XferReq->EpInfo.EpType; + XferInfo.Buffer = XferReq->XferBuffer; + XferInfo.Length = XferReq->ActualXferLen; + + // + // If this is a non-control transfer complete, notify the class driver + // + if (XferInfo.EndpointNum > 0) { + if (mDrvObj.UsbdDevObj->DataCallback != NULL) { + mDrvObj.UsbdDevObj->DataCallback (&XferInfo); + } + } + + return; +} + + +/** + Queue a request to transmit data + + @param XdciHndl Pointer (handle) to the XDCI driver object + @param IoReq Pointer to IO structure containing details of the + transfer request + + @return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdEpTxData ( + IN VOID *XdciHndl, + IN USB_DEVICE_IO_REQ *IoReq + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_XFER_REQUEST TxReq; + + // + //set endpoint data + // + UsbdSetEpInfo (&(TxReq.EpInfo), &(IoReq->EndpointInfo)); // set endpoint data + + // + //if this is a control endpoint, set the number and direction + // + if (IoReq->EndpointInfo.EndpointDesc == NULL) { + TxReq.EpInfo.EpNum = 0; + TxReq.EpInfo.EpDir = UsbEpDirIn; + } + + // + // setup the trasfer request + // + TxReq.XferBuffer = IoReq->IoInfo.Buffer; + TxReq.XferLen = IoReq->IoInfo.Length; + TxReq.XferDone = UsbdXferDoneHndlr; + + DEBUG ((DEBUG_INFO, "TX REQUEST: EpNum: 0x%x, epDir: 0x%x, epType: 0x%x, MaxPktSize: 0x%x\n",\ + TxReq.EpInfo.EpNum, TxReq.EpInfo.EpDir, TxReq.EpInfo.EpType, TxReq.EpInfo.MaxPktSize)); + + Status = UsbXdciDeviceEpTxData (XdciHndl, &TxReq); + + return Status; +} + + +/** + Queue a request to receive data + + @param XdciHndl Pointer (handle) to the XDCI driver object + @param IoReq Pointer to IO structure containing details of the + receive request + + @return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdEpRxData ( + IN VOID *XdciHndl, + IN USB_DEVICE_IO_REQ *IoReq + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_XFER_REQUEST RxReq; + UINT32 ReqPacket; + + DEBUG ((DEBUG_INFO, "RX REQUEST in: IoReq->IoInfo.Length: 0x%x\n", IoReq->IoInfo.Length)); + DEBUG ((DEBUG_INFO, "RX REQUEST in: MaxPacketSize: 0x%x\n", IoReq->EndpointInfo.EndpointDesc->MaxPacketSize)); + + if (IoReq->EndpointInfo.EndpointDesc->MaxPacketSize == 0) { + return EFI_DEVICE_ERROR; + } + + // + // set endpoint data + // + UsbdSetEpInfo (&(RxReq.EpInfo), &(IoReq->EndpointInfo)); + + // + // setup the trasfer request + // + RxReq.XferBuffer = IoReq->IoInfo.Buffer; + + // + // Transfer length should be multiple of USB packet size. + // + ReqPacket = IoReq->IoInfo.Length / IoReq->EndpointInfo.EndpointDesc->MaxPacketSize; + ReqPacket = ((IoReq->IoInfo.Length % IoReq->EndpointInfo.EndpointDesc->MaxPacketSize) == 0)? ReqPacket : ReqPacket + 1; + RxReq.XferLen = ReqPacket * IoReq->EndpointInfo.EndpointDesc->MaxPacketSize; + + RxReq.XferDone = UsbdXferDoneHndlr; + + DEBUG ((DEBUG_INFO, "RX REQUEST: EpNum: 0x%x, epDir: 0x%x, epType: 0x%x\n",\ + RxReq.EpInfo.EpNum, RxReq.EpInfo.EpDir, RxReq.EpInfo.EpType)); + DEBUG ((DEBUG_INFO, "RX REQUEST send: XferLen: 0x%x\n", RxReq.XferLen)); + + Status = UsbXdciDeviceEpRxData (XdciHndl, &RxReq); + + return Status; +} + + +/** + Callback used to handle Reset events from the XDCI + + @param Param Pointer to a generic callback parameter structure + + @return XDCI usb status + +**/ +EFI_STATUS +EFIAPI +UsbdResetEvtHndlr ( + IN USB_DEVICE_CALLBACK_PARAM __attribute__((unused)) *Param + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbdResetEvtHndlr\n")); + + // + // reset device address to 0 + // + Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdResetHdlr() - Failed to set address in XDCI\n")); + } + + return Status; +} + + +/** + Callback used to handle Connection done events from the XDCI + + @param Param Pointer to a generic callback parameter structure + + @return XDCI usb status + +**/ +EFI_STATUS +EFIAPI +UsbdConnDoneEvtHndlr ( + IN USB_DEVICE_CALLBACK_PARAM __attribute__((unused))*Param + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbdConnDoneEvtHndlr\n")); + // + //reset device address to 0 + // + Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr() - Failed to set address in XDCI\n")); + } + + // + // set the device state to attached/connected + // + mDrvObj.State = UsbDevStateAttached; + + return Status; +} + + +/** + Callback used to handle Control Endpoint Setup events from the XDCI + + @param Param Pointer to a generic callback parameter structure + + @return XDCI usb status + +**/ +EFI_STATUS +EFIAPI +UsbdSetupEvtHndlr ( + IN USB_DEVICE_CALLBACK_PARAM *Param + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_USB_DEVICE_REQUEST Req; + + DEBUG ((DEBUG_INFO, "UsbdSetupEvtHndlr\n")); + + // + // Fill out request object from the incomming Buffer + // + CopyMem (&Req, Param->Buffer, sizeof(EFI_USB_DEVICE_REQUEST)); + + Status = UsbdSetupHdlr (&Req); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdSetupEvtHndlr: EFI_DEVICE_ERROR\n")); + } + + return Status; +} + + +/** + * Callback used to handle XferNotReady events from the XDCI + * + * @param Param Pointer to a generic callback parameter structure + * + * @return XDCI usb status + */ +EFI_STATUS +EFIAPI +UsbdNrdyEvtHndlr ( + IN USB_DEVICE_CALLBACK_PARAM __attribute((unused))*Param + ) +{ + DEBUG ((DEBUG_INFO, "UsbdNrdyEvtHndlr\n")); + return EFI_SUCCESS; +} + + +/** + Registers callbacks for event handlers with the XDCI layer. + The functions will be called as the registered events are triggered. + + @param XdciHndl to XDCI core driver + @return EFI_SUCCESS if successful, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdRegisterCallbacks ( + IN VOID *XdciHndl + ) +{ + if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_RESET_EVENT, UsbdResetEvtHndlr) != EFI_SUCCESS) { + goto UdciRegCallbackError; + } + + if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_CONNECTION_DONE, UsbdConnDoneEvtHndlr) != EFI_SUCCESS) { + goto UdciRegCallbackError; + } + + if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_SETUP_PKT_RECEIVED, UsbdSetupEvtHndlr) != EFI_SUCCESS) { + goto UdciRegCallbackError; + } + + if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_XFER_NRDY, UsbdNrdyEvtHndlr) != EFI_SUCCESS) { + goto UdciRegCallbackError; + } + + return EFI_SUCCESS; + +UdciRegCallbackError: + return EFI_DEVICE_ERROR; +} + + +/** + Returns the configuration descriptor for this device. The data + Buffer returned will also contain all downstream interface and + endpoint Buffers. + + @param Buffer Pointer to destination Buffer to copy descriptor data to + @param DescIndex the index of the descriptor to return + @param ReqLen the length in bytes of the request Buffer + @param DataLen Pointer whos value is to be filled with the byte count of + data copied to the output Buffer + + @return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdGetConfigDesc ( + IN VOID *Buffer, + IN UINT8 DescIndex, + IN UINT32 ReqLen, + IN UINT32 *DataLen + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINT8 NumConfigs = 0; + UINT32 ConfigLen = 0; + USB_DEVICE_CONFIG_OBJ *ConfigObj = NULL; + VOID *Descriptor = 0; + UINT32 Length = 0; + + DEBUG ((DEBUG_INFO, "UsbdGetConfigDesc()\n")); + + // + // For a CONFIGURATION request we send back all descriptors branching out + // from this descriptor including the INTERFACE and ENDPOINT descriptors + // + // + // Verify the requested configuration exists - check valid index + // + NumConfigs = mDrvObj.UsbdDevObj->DeviceDesc->NumConfigurations; + + if (DescIndex < NumConfigs) { + // + // get the configuration object using the index Offset + // + ConfigObj = (mDrvObj.UsbdDevObj->ConfigObjs + DescIndex); + // + // get the complete configuration Buffer block including Interface and Endpoint data + // + Descriptor = ConfigObj->ConfigAll; + // + // The config descriptor TotalLength has the full value for all desc Buffers + // + ConfigLen = ConfigObj->ConfigDesc->TotalLength; + // + // copy the data to the output Buffer + // + Length = MIN (ReqLen, ConfigLen); + CopyMem (Buffer, Descriptor, Length); + *DataLen = Length; + Status = EFI_SUCCESS; + } else { + DEBUG ((DEBUG_INFO, "UsbdGetConfigDesc() - Invalid Config index: %i\n", DescIndex)); + } + + if (Status == EFI_SUCCESS) { + if (ConfigObj != NULL) { + PrintConfigDescriptor (ConfigObj->ConfigDesc); + } + } + + return Status; +} + + +/** + Sets the active configuration to the selected configuration index if it exists + + @param CfgValue the configuration value to set + + @return EFI_SUCCESS if the configuration was set, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdSetConfig ( + UINT8 CfgValue + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINT8 numConfigs = 0; + USB_DEVICE_CONFIG_OBJ *pConfigObj = NULL; + USB_DEVICE_INTERFACE_OBJ *pIfObj = NULL; + USB_DEVICE_ENDPOINT_OBJ *pEpObj = NULL; + UINT8 cfgItr = 0; + UINT8 ifItr = 0; + UINT8 epItr = 0; + USB_DEVICE_ENDPOINT_INFO EpInfo; + USB_EP_INFO UsbEpInfo; + + DEBUG ((DEBUG_INFO, "UsbdSetConfig()\n")); + // + // Verify the requested configuration exists - check valid index + // + numConfigs = mDrvObj.UsbdDevObj->DeviceDesc->NumConfigurations; + + if (CfgValue != 0) { + // + // Search for a matching configuration + // + for (cfgItr = 0; cfgItr < numConfigs; cfgItr++) { + pConfigObj = (mDrvObj.UsbdDevObj->ConfigObjs + cfgItr); + if (pConfigObj->ConfigDesc->ConfigurationValue == CfgValue) { + + // + // Set the active configuration object + // + mDrvObj.ActiveConfigObj = pConfigObj; + // + // Find all interface objects for this configuration + // + for (ifItr = 0; ifItr < pConfigObj->ConfigDesc->NumInterfaces; ifItr++) { + pIfObj = (pConfigObj->InterfaceObjs + ifItr); + // + // Configure the Endpoints in the XDCI + // + for (epItr = 0; epItr < pIfObj->InterfaceDesc->NumEndpoints; epItr++) { + pEpObj = (pIfObj->EndpointObjs + epItr); + + EpInfo.EndpointDesc = pEpObj->EndpointDesc; + EpInfo.EndpointCompDesc = pEpObj->EndpointCompDesc; + + if (UsbdInitEp (mDrvObj.XdciDrvObj, &EpInfo) == EFI_SUCCESS) { + UsbdSetEpInfo(&UsbEpInfo, &EpInfo); + if (UsbDeviceEpEnable (mDrvObj.XdciDrvObj, &UsbEpInfo) == EFI_SUCCESS) { + Status = EFI_SUCCESS; + } else { + DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Failed to enable endpoint\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Failed to initialize endpoint\n")); + } + } + } + // + // Let the class driver know it is configured + // + if (Status == EFI_SUCCESS) { + if (mDrvObj.UsbdDevObj->ConfigCallback != NULL) { + mDrvObj.UsbdDevObj->ConfigCallback (CfgValue); + } + } + + mDrvObj.State = UsbDevStateConfigured; // we are now configured + + break; // break from config search loop + } + } + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Invalid requested configuration value: %i\n", CfgValue)); + } + + return Status; +} + + +/** + Returns the currently active configuration value + + @param Buffer Pointer to destination Buffer to copy configuration value to + @param ReqLen the length in bytes of the request Buffer + @param DataLen Pointer whos value is to be filled with the byte count of + data copied to the output Buffer + + @return EFI_SUCCESS if config value is successfully copied, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdGetConfig ( + VOID *Buffer, + UINT32 ReqLen, + UINT32 *DataLen + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbdGetConfig()\n")); + + if (ReqLen >= 1) { // length of data expected must be 1 + if (mDrvObj.ActiveConfigObj != NULL) { // assure we have a config active + *DataLen = 1; // one byte for ConfigurationValue + *(UINT8*)Buffer = mDrvObj.ActiveConfigObj->ConfigDesc->ConfigurationValue; + + Status = EFI_SUCCESS; + } else { + DEBUG ((DEBUG_INFO, "UsbdGetConfig() - No active configuration available\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbdGetConfig() - Invalid data length\n")); + } + + return Status; +} + + +/** + Returns the requested string descriptor if it exists + + @param Buffer Pointer to destination Buffer to copy descriptor data to + @param DescIndex the index of the descriptor to return + @param LangId the target language ID + @param ReqLen the length in bytes of the request Buffer + @param DataLen Pointer whos value is to be filled with the byte count of + data copied to the output Buffer + + @return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdGetStringDesc ( + VOID *Buffer, + UINT8 DescIndex, + UINT16 LangId, + UINT32 ReqLen, + UINT32 *DataLen + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINT32 Length = 0; + USB_STRING_DESCRIPTOR *StringDesc; + UINT8 Index = 0; + UINT8 StrLangEntries = 0; + BOOLEAN StrLangFound = FALSE; + + DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Index: 0x%x, LangId: 0x%x, ReqLen: 0x%x\n", DescIndex, LangId, ReqLen)); + + // + // index zero of the string table contains the supported language codes + // + if (DescIndex == 0) { + StringDesc = (mDrvObj.UsbdDevObj->StringTable); + Length = MIN (ReqLen, StringDesc->Length); + CopyMem (Buffer, StringDesc, Length); + *DataLen = Length; + Status = EFI_SUCCESS; + } else { + + // + // Verify the requested language ID is supported. String descriptor Zero + // (First entry in the string table) is expected to contain the language list. + // The requested language ID is specified in the Index member of the request. + // + StringDesc = mDrvObj.UsbdDevObj->StringTable; // get language string descriptor + StrLangEntries = ((StringDesc->Length - 2) >> 1); + DEBUG ((DEBUG_INFO, "StrLangEntries=%x\n", StrLangEntries)); + + DEBUG ((DEBUG_INFO, "Looking LangID: \n")); + + for (Index = 0; Index < StrLangEntries; Index++) { + DEBUG ((DEBUG_INFO, "LangID [%x]= %x\n", Index, StringDesc->LangID [Index])); + + if (StringDesc->LangID [Index] == LangId) { + DEBUG ((DEBUG_INFO, "Found it\n")); + StrLangFound = TRUE; + } + } + + // + // If we found a matching language, attempt to get the string index requested + // + if (StrLangFound == TRUE) { + DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: StrLangFound=Found, DescIndex=%x, StrTblEntries=%x\n", DescIndex, mDrvObj.UsbdDevObj->StrTblEntries)); + + if (DescIndex < mDrvObj.UsbdDevObj->StrTblEntries) { + // + // get the string descriptor for the requested index + // + StringDesc = (mDrvObj.UsbdDevObj->StringTable + DescIndex); + + Length = MIN (ReqLen, StringDesc->Length); + DEBUG ((DEBUG_INFO, "ReqLen=%x, StringLength=%x, Length=%x\n", ReqLen, StringDesc->Length, Length)); + + CopyMem (Buffer, StringDesc, Length); + *DataLen = Length; + Status = EFI_SUCCESS; + } else { + DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Invalid String index in USB_REQ_GET_DESCRIPTOR request\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Unsupported String Language ID for USB_REQ_GET_DESCRIPTOR request\n")); + } + } + + if (Status == EFI_SUCCESS) { + PrintStringDescriptor (StringDesc); + } + return Status; +} + + +#ifdef SUPPORT_SUPER_SPEED +/** + Returns the configuration descriptor for this device. The data + Buffer returned will also contain all downstream interface and + endpoint Buffers. + + @param Buffer Pointer to destination Buffer to copy descriptor data to + @param ReqLen the length in bytes of the request Buffer + @param DataLen Pointer whos value is to be filled with the byte count of + data copied to the output Buffer + + @return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdGetBOSDesc ( + IN VOID *Buffer, + IN UINT32 ReqLen, + IN UINT32 *DataLen + ) +{ + EFI_USB_BOS_DESCRIPTOR *BosDesc = 0; + UINT32 Length = 0; + + DEBUG ((DEBUG_INFO, "UsbdGetBOSDesc()\n")); + + BosDesc = mDrvObj.UsbdDevObj->BosDesc; + Length = MIN (ReqLen, mDrvObj.UsbdDevObj->BosDesc->TotalLength); + + CopyMem(Buffer, BosDesc, Length); + *DataLen = Length; + + PrintBOSDescriptor (BosDesc); + + return EFI_SUCCESS; +} +#endif + +/** + Returns the current status for Device/Interface/Endpoint + + @param Buffer Pointer to destination Buffer to copy descriptor data to + @param ReqType The type of status to get + @param ReqLen the length in bytes of the request Buffer + @param DataLen Pointer whos value is to be filled with the byte count of + data copied to the output Buffer + + @return EFI_SUCCESS if status successfully copied, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdGetStatus ( + VOID *Buffer, + UINT8 ReqType, + UINT32 ReqLen, + UINT32 *DataLen + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbdGetStatus()\n")); + + if (ReqLen >= 2) { // length of data must be at least 2 bytes + switch (ReqType & USB_TARGET_MASK) { + case USB_TARGET_DEVICE: + *DataLen = 2; // two byte for status + *(UINT16*)Buffer = USB_STATUS_SELFPOWERED; + Status = EFI_SUCCESS; + break; + + case USB_TARGET_INTERFACE: + // + // No implementation needed at this time + // + break; + + case USB_TARGET_ENDPOINT: + // + // No implementation needed at this time + // Should specify if endpoint is halted. Implement as necessary. + // + break; + + case USB_TARGET_OTHER: + // + // No implementation needed at this time + // + break; + + default: + break; + } + } else { + DEBUG ((DEBUG_INFO, "UsbdGetStatus() - Invalid data length\n")); + } + + return Status; +} + + +/** + Sets the address of the device + + @param address the address value to set + + @return EFI_SUCCESS if address was set, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdSetAddress ( + UINT8 Address + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbdSetAddress: setting address: 0x%x\n", Address)); + + if (Address <= 0x7F) { // address must not be > 127 + mDrvObj.Address = Address; + + // + // Configure Address in the XDCI + // + Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, mDrvObj.Address); + if (!EFI_ERROR (Status)) { + mDrvObj.State = UsbDevStateAddress; + } else { + DEBUG ((DEBUG_INFO, "UsbdSetAddress: Failed to set address in XDCI\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbdSetAddress: Invalid address: 0x%x\n", Address)); + } + + return Status; +} + + +/** + Handles Setup device requests. Standard requests are immediately + handled here, and any Class/Vendor specific requests are forwarded + to the class driver + + @param CtrlRequest Pointer to a device request + + @return EFI_SUCCESS if request successfully handled, FALSE otherwise + +**/ +EFI_STATUS +UsbdSetupHdlr ( + IN EFI_USB_DEVICE_REQUEST *CtrlRequest + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINT8 DescIndex = 0; + USB_DEVICE_DESCRIPTOR *DevDesc = 0; + + // + // Initialize the IO object + // + mCtrlIoReq.IoInfo.Length = 0; + + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr start\n")); + PrintDeviceRequest (CtrlRequest); + + // + // Handle Standard Device Requests + // + if ((CtrlRequest->RequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) { + switch (CtrlRequest->Request) { + case USB_REQ_GET_DESCRIPTOR: + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Host requests get descriptor\n")); + if (CtrlRequest->RequestType == USB_RT_TX_DIR_D_TO_H) { + DescIndex = (CtrlRequest->Value & 0xff); // low byte is the index requested + switch (CtrlRequest->Value >> 8) { // high byte contains request type + case USB_DESC_TYPE_DEVICE: + DEBUG ((DEBUG_INFO, "Descriptor tyep: Device\n")); + DevDesc = mDrvObj.UsbdDevObj->DeviceDesc; + // + // copy the data to the output Buffer + // + mCtrlIoReq.IoInfo.Length = MIN (CtrlRequest->Length, DevDesc->Length); + CopyMem (mCtrlIoReq.IoInfo.Buffer, DevDesc, mCtrlIoReq.IoInfo.Length); + PrintDeviceDescriptor (DevDesc); + break; + + case USB_DESC_TYPE_CONFIG: + DEBUG ((DEBUG_INFO, "Descriptor tyep: Configuration\n")); + Status = UsbdGetConfigDesc ( + mCtrlIoReq.IoInfo.Buffer, + DescIndex, + CtrlRequest->Length, + &(mCtrlIoReq.IoInfo.Length) + ); + break; + + case USB_DESC_TYPE_STRING: + DEBUG ((DEBUG_INFO, "Descriptor tyep: String\n")); + Status = UsbdGetStringDesc ( + mCtrlIoReq.IoInfo.Buffer, + DescIndex, + CtrlRequest->Index, + CtrlRequest->Length, + &(mCtrlIoReq.IoInfo.Length) + ); + break; + +#ifdef SUPPORT_SUPER_SPEED + case USB_DESC_TYPE_BOS: + DEBUG ((DEBUG_INFO, "Descriptor tyep: BOS\n")); + Status = UsbdGetBOSDesc ( + mCtrlIoReq.IoInfo.Buffer, + CtrlRequest->Length, + &(mCtrlIoReq.IoInfo.Length) + ); + break; + + case USB_DESC_TYPE_SS_ENDPOINT_COMPANION: + DEBUG ((DEBUG_INFO, "Descriptor tyep: Endpoint Companion\n")); + break; +#endif + + default: + DEBUG ((DEBUG_INFO, "Descriptor tyep: Unsupported, USB_REQ_GET_DESCRIPTOR request: 0x%x\n", (CtrlRequest->Value >> 8))); + break; + } + } else { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr() - Invalid direction for USB_REQ_GET_DESCRIPTOR request\n")); + } + break; + + case USB_REQ_GET_CONFIG: + DEBUG ((DEBUG_INFO, "USB_REQ_GET_CONFIG\n")); + if (CtrlRequest->RequestType == USB_RT_TX_DIR_D_TO_H) { + Status = UsbdGetConfig (mCtrlIoReq.IoInfo.Buffer, CtrlRequest->Length, &(mCtrlIoReq.IoInfo.Length)); + } else { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_GET_CONFIG request\n")); + } + break; + + case USB_REQ_SET_CONFIG: + DEBUG ((DEBUG_INFO, "USB_REQ_SET_CONFIG\n")); + if (CtrlRequest->RequestType == USB_RT_TX_DIR_H_TO_D) { + Status = UsbdSetConfig ((UINT8)CtrlRequest->Value); + } else { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_SET_CONFIG request\n")); + } + break; + + case USB_REQ_SET_ADDRESS: + DEBUG ((DEBUG_INFO, "USB_REQ_SET_ADDRESS\n")); + if (CtrlRequest->RequestType == USB_RT_TX_DIR_H_TO_D) { + Status = UsbdSetAddress ((UINT8)CtrlRequest->Value); + } else { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_SET_ADDRESS request\n")); + } + break; + + case USB_REQ_GET_STATUS: + DEBUG ((DEBUG_INFO, "USB_REQ_GET_STATUS\n")); + if (CtrlRequest->RequestType & USB_RT_TX_DIR_D_TO_H) { + Status = UsbdGetStatus (mCtrlIoReq.IoInfo.Buffer, CtrlRequest->RequestType, CtrlRequest->Length, &(mCtrlIoReq.IoInfo.Length)); + } else { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_GET_STATUS request\n")); + } + break; +#ifdef SUPPORT_SUPER_SPEED + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + case USB_REQ_SET_DESCRIPTOR: + case USB_REQ_GET_INTERFACE: + case USB_REQ_SET_INTERFACE: + case USB_REQ_SYNCH_FRAME: +#endif + default: + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Unsupported Standard Request: 0x%x\n", CtrlRequest->Request)); + break; + } + } else { // This is not a Standard request, it specifies Class/Vendor handling + // + // Forward request to class driver + // + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Class/Vendor Request\n")); + if (mDrvObj.UsbdDevObj->SetupCallback != NULL) { + mDrvObj.UsbdDevObj->SetupCallback (CtrlRequest, &(mCtrlIoReq.IoInfo)); + } + } + + DEBUG ((DEBUG_INFO, "dataLen=%x\n", mCtrlIoReq.IoInfo.Length)); + // + // Transfer data according to request if necessary + // + if (mCtrlIoReq.IoInfo.Length> 0) { + Status = UsbdEpTxData (mDrvObj.XdciDrvObj, &mCtrlIoReq); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Failed to TX data\n")); + } + } else { + // + // If we are not responding with data, send control status + // + Status = UsbDeviceEp0TxStatus (mDrvObj.XdciDrvObj); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Failed to Tx Ep0 Status\n")); + } + } + + return Status; +} + + +/** + Handles Connection done events. Sets the device address to zero. + + @return EFI_SUCCESS if able to set the address, EFI_DEVICE_ERROR otherwise + +**/ +EFI_STATUS +UsbdConnDoneHdlr ( + VOID + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr()\n")); + + // + // reset device address to 0 + // + Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr() - Failed to set address in XDCI\n")); + } + + // + // set the device state to attached/connected + // + mDrvObj.State = UsbDevStateAttached; + + return Status; +} + + +/** + Handles transmit/receive completion events. Directly handles + control endpoint events and forwards class/vendor specific events + to the class drivers. + + @param XferInfo Pointer to Xfer structure + + @return + +**/ +VOID +UsbdXferDoneHdlr ( + IN EFI_USB_DEVICE_XFER_INFO *XferInfo + ) +{ + // + // If this is a non-control transfer complete, notify the class driver + // + if (XferInfo->EndpointNum > 0) { + if (mDrvObj.UsbdDevObj->DataCallback != NULL) { + mDrvObj.UsbdDevObj->DataCallback (XferInfo); + } + } + + return; +} + + +/** + Binds a USB class driver with this USB device driver core. + After calling this routine, the driver is ready to begin + USB processing. + + @param UsbdDevObj Pointer to a usbd device object which contains + all relevant information for the class driver device + + @return TRUE if binding was successful, FALSE otherwise + +**/ +EFI_STATUS +EFIAPI +UsbDeviceBind ( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute__((unused))*This, + IN USB_DEVICE_OBJ *UsbdDevObj + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + // + // allocate Tx Buffer + // + mCtrlIoReq.IoInfo.Buffer = AllocateZeroPool (USB_EPO_MAX_PKT_SIZE_ALL); + if (mCtrlIoReq.IoInfo.Buffer != NULL) { + mDrvObj.UsbdDevObj = UsbdDevObj; + mDrvObj.ActiveConfigObj = NULL; + mDrvObj.Address = 0; + mDrvObj.State = UsbDevStateInit; + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceBind() - Failed to allocate IO Buffer\n")); + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + + +/** + Unbinds the USB class driver from this USB device driver core. + + @return TRUE if successful, FALSE otherwise + +**/ +EFI_STATUS +EFIAPI +UsbDeviceUnbind ( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute__((unused))*This + ) +{ + mDrvObj.UsbdDevObj = NULL; + mDrvObj.ActiveConfigObj = NULL; + mDrvObj.Address = 0; + mDrvObj.State = UsbDevStateOff; + mDrvObj.XdciInitialized = FALSE; + + // + // release allocated Buffer data + // + if (mCtrlIoReq.IoInfo.Buffer) { + FreePool (mCtrlIoReq.IoInfo.Buffer); + } + + return EFI_SUCCESS; +} + + +/** + Performs continual USB device event processing until a cancel + event occurs + + @param TimeoutMs Connection timeout in ms. If 0, waits forever. + @return TRUE if run executed normally, FALSE if error ocurred + +**/ +EFI_STATUS +EFIAPI +UsbDeviceRun ( + IN EFI_USB_DEVICE_MODE_PROTOCOL *This, + IN UINT32 TimeoutMs + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_XDCI_DEV_CONTEXT *XdciDevContext; + + XdciDevContext = USBUSBD_CONTEXT_FROM_PROTOCOL (This); + + // + // can only run if XDCI is initialized + // + if (mDrvObj.XdciInitialized == TRUE) { + + if ((mDrvObj.State == UsbDevStateConfigured) && (XdciDevContext->XdciPollTimer == NULL)) { + Status = uefi_call_wrapper(BS->CreateEvent, + 5, + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UsbdMonitorEvents, + XdciDevContext, + &XdciDevContext->XdciPollTimer + ); + if (!EFI_ERROR (Status)) { + Status = uefi_call_wrapper(BS->SetTimer, 3, XdciDevContext->XdciPollTimer, TimerPeriodic,200000); + DEBUG ((EFI_D_ERROR, "UsbDeviceRun Create Event\n")); + } + } + + mXdciRun = TRUE; // set the run flag to active + Status = EFI_SUCCESS; + + // + // start the Event processing loop + // + while (TRUE) { + if (XdciDevContext->XdciPollTimer == NULL) { + if (UsbDeviceIsrRoutine (mDrvObj.XdciDrvObj) != EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "UsbDeviceRun() - Failed to execute event ISR\n")); + } + } + + // + // Check if a run cancel request exists, if so exit processing loop + // + if (mXdciRun == FALSE) { + if (XdciDevContext->XdciPollTimer != NULL) { + DEBUG ((EFI_D_ERROR, "UsbDeviceRun close Event\n")); + uefi_call_wrapper(BS->SetTimer, 3, XdciDevContext->XdciPollTimer, TimerCancel, 0); + uefi_call_wrapper(BS->CloseEvent, 1, XdciDevContext->XdciPollTimer); + XdciDevContext->XdciPollTimer = NULL; + } + Status = EFI_SUCCESS; + DEBUG ((DEBUG_INFO, "UsbDeviceRun() - processing was cancelled\n")); + break; + } + + // + // check for timeout + // + if (TimeoutMs == 0) + return EFI_TIMEOUT; + uefi_call_wrapper(BS->Stall, 1, 50); + TimeoutMs--; + } + } + + return Status; +} + + +/** + Sets a flag to stop the running device processing loop + + @return TRUE always + +**/ +EFI_STATUS +EFIAPI +UsbDeviceStop ( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute__((unused))*This + ) +{ + mXdciRun = FALSE; // set run flag to FALSE to stop processing + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +UsbDeviceInitXdci ( + IN EFI_USB_DEVICE_MODE_PROTOCOL *This + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_XDCI_DEV_CONTEXT *XdciDevContext; + + XdciDevContext = USBUSBD_CONTEXT_FROM_PROTOCOL (This); + + PlatformSpecificInit (); + + if (mDrvObj.XdciInitialized == FALSE) { + if (XdciDevContext->XdciMmioBarAddr != 0) { + + // + // Initialize device controller driver + // + DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Initializing Controller...\n")); + + // + // Initialize the device controller interface + // + if (UsbdInit (XdciDevContext->XdciMmioBarAddr, &mDrvObj.XdciDrvObj) == EFI_SUCCESS) { + + // + // Setup callbacks + // + if (UsbdRegisterCallbacks (mDrvObj.XdciDrvObj) == EFI_SUCCESS) { + + mDrvObj.XdciInitialized = TRUE; + Status = EFI_SUCCESS; + + DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Controller initialization complete\n")); + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Failed to register UDCI callbacks\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Failed to initialize UDCI\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - XDCI MMIO BAR not set\n")); + } + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - XDCI already initialized\n")); + Status = EFI_ALREADY_STARTED; + } + + return Status; +} + + +EFI_STATUS +EFIAPI +UsbDeviceConnect( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbDeviceConnect \n")); + if (UsbXdciDeviceConnect (mDrvObj.XdciDrvObj) == EFI_SUCCESS) { + Status = EFI_SUCCESS; + } + return Status; +} + + +EFI_STATUS +EFIAPI +UsbDeviceDisConnect ( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbDeviceDisConnect \n")); + if (UsbDeviceDisconnect (mDrvObj.XdciDrvObj) == EFI_SUCCESS) { + mDrvObj.State = UsbDevStateInit; + Status = EFI_SUCCESS; + } + + XhciSwitchSwid(FALSE); + return Status; +} + + +EFI_STATUS +EFIAPI +UsbDeviceEpTxData( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This, + IN USB_DEVICE_IO_REQ *IoRequest + ) +{ + EFI_STATUS Status; + + Status = UsbdEpTxData (mDrvObj.XdciDrvObj, IoRequest); + return Status; +} + + +EFI_STATUS +EFIAPI +UsbDeviceEpRxData( + IN EFI_USB_DEVICE_MODE_PROTOCOL __attribute((unused))*This, + IN USB_DEVICE_IO_REQ *IoRequest + ) +{ + EFI_STATUS Status; + + Status = UsbdEpRxData (mDrvObj.XdciDrvObj, IoRequest); + return Status; +} + + +// +// The Runtime UsbDeviceMode Protocol instance produced by this driver +// +EFI_USB_DEVICE_MODE_PROTOCOL mUsbDeviceModeProtocol = { + UsbDeviceInitXdci, + UsbDeviceConnect, + UsbDeviceDisConnect, + UsbDeviceEpTxData, + UsbDeviceEpRxData, + UsbDeviceBind, + UsbDeviceUnbind, + UsbDeviceRun, + UsbDeviceStop +}; + diff --git a/libefiusb/device_mode/UsbDeviceMode.h b/libefiusb/device_mode/UsbDeviceMode.h index 506a4c8b..a9b19a65 100644 --- a/libefiusb/device_mode/UsbDeviceMode.h +++ b/libefiusb/device_mode/UsbDeviceMode.h @@ -17,8 +17,7 @@ #include "protocol/UsbIo.h" #include "protocol/UsbDeviceModeProtocol.h" - -/// +//// /// Function declaration /// EFI_STATUS @@ -27,6 +26,5 @@ UsbdSetupHdlr ( ); extern EFI_USB_DEVICE_MODE_PROTOCOL mUsbDeviceModeProtocol; - #endif diff --git a/libefiusb/device_mode/XdciCommon.h b/libefiusb/device_mode/XdciCommon.h index 468e8a83..0d5d5d92 100644 --- a/libefiusb/device_mode/XdciCommon.h +++ b/libefiusb/device_mode/XdciCommon.h @@ -154,3 +154,6 @@ struct _USB_XFER_REQUEST { #endif +#define DEBUG_INFO EFI_SUCCESS +#define EFI_D_INFO EFI_SUCCESS +#define EFI_D_ERROR EFI_DEVICE_ERROR diff --git a/libefiusb/device_mode/XdciDWC.c b/libefiusb/device_mode/XdciDWC.c index 8b615f6c..52cd34be 100644 --- a/libefiusb/device_mode/XdciDWC.c +++ b/libefiusb/device_mode/XdciDWC.c @@ -1,4022 +1,4032 @@ -/** @file - Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ -#include -#include -#include -#include - -#include "UsbDeviceDxe.h" -#include "XdciInterface.h" -#include "XdciDWC.h" - -UINT32 -UsbRegRead ( - IN UINT32 Base, - IN UINT32 Offset - ) -{ - volatile UINT32 *addr = (volatile UINT32 *)(UINTN)(Base + Offset); - return *addr; -} - -VOID -UsbRegWrite ( - IN UINT32 Base, - IN UINT32 Offset, - IN UINT32 val - ) -{ - volatile UINT32 *addr = (volatile UINT32 *)(UINTN)(Base + Offset); - *addr = val; -} - - -/** - Internal utility function: - This function is used to obtain physical endpoint number - xDCI needs physical endpoint number for EP registers - We also use it to index into our EP array - Note: Certain data structures/commands use logical EP numbers - as opposed to physical endpoint numbers so one should be - careful when interpreting EP numbers - @EpNum: Logical endpoint number - @epDir: Direction for the endpoint - -**/ -STATIC -UINT32 -DwcXdciGetPhysicalEpNum ( - IN UINT32 EndpointNum, - IN USB_EP_DIR EndpointDir - ) -{ - return EndpointDir? ((EndpointNum << 1) | EndpointDir) : (EndpointNum << 1); -} - - -/** - Internal utility function: - This function is used to obtain the MPS for control transfers - Based on the Speed. If this is called before bus reset completes - then it returns MPS Based on desired Speed. If it is after bus - reset then MPS returned is Based on actual negotiated Speed - @CoreHandle: xDCI controller handle address - @mps: address of 32-bit variable to return the MPS - -**/ -STATIC -EFI_STATUS -DwcXdciCoreGetCtrlMps ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 *mps - ) -{ - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreGetCtrlMps: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (mps == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreGetCtrlMps: INVALID parameter\n")); - return EFI_INVALID_PARAMETER; - } - - switch (CoreHandle->ActualSpeed) { - case USB_SPEED_HIGH: - *mps = DWC_XDCI_HS_CTRL_EP_MPS; - break; - case USB_SPEED_FULL: - *mps = DWC_XDCI_FS_CTRL_EP_MPS; - break; - case USB_SPEED_LOW: - *mps = DWC_XDCI_LS_CTRL_EP_MPS; - break; - case USB_SPEED_SUPER: - *mps = DWC_XDCI_SS_CTRL_EP_MPS; - break; - default: - *mps = 0; - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreGetCtrlMps: UNKNOWN Speed\n")); - break; - } - - return EFI_SUCCESS; -} - - -/** - Internal utility function: - This function is used to initialize the parameters required - for executing endpoint command - @CoreHandle: xDCI controller handle address - @EpInfo: EP info address - @ConfigAction: Configuration action specific to EP command - @EpCmd: xDCI EP command for which parameters are initialized - @EpCmdParams: address of struct to return EP params - -**/ -STATIC -EFI_STATUS -DwcXdciCoreInitEpCmdParams ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN USB_EP_INFO *EpInfo, - IN UINT32 ConfigAction, - IN DWC_XDCI_ENDPOINT_CMD EpCmd, - IN DWC_XDCI_ENDPOINT_CMD_PARAMS *EpCmdParams - ) -{ - EFI_STATUS status = EFI_SUCCESS; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreInitEpCmdParams: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Reset params - // - EpCmdParams->Param0 = EpCmdParams->Param1 = EpCmdParams->Param2 = 0; - - switch (EpCmd) { - case EPCMD_SET_EP_CONFIG: - // - // Issue DEPCFG command for EP - // Issue a DEPCFG (Command 1) command for endpoint - // - if (EpInfo->MaxStreams) { - EpCmdParams->Param1 = DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK; - } - - if (EpInfo->Interval) { - EpCmdParams->Param1 |= ((EpInfo->Interval-1) << DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS); - } - - // - // Set EP num - // - EpCmdParams->Param1 |= (EpInfo->EpNum << DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_BIT_POS); - // - // Set EP direction - // - EpCmdParams->Param1 |= (EpInfo->EpDir << DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_BIT_POS); - // - // Set EP-specific Event enable for not ready and - // complete events - // - EpCmdParams->Param1 &= ~DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK; - // - // Setup the events we want enabled for this EP - // - EpCmdParams->Param1 |= (DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK | - DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK | - DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK); - - // - // We only have one interrupt line for this core. - // Set interrupt number to 0 - // - EpCmdParams->Param1 &= ~DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK; - - // - // Set FIFOnum = 0 for control EP0 - // - EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_MASK; - - // - // Program FIFOnum for non-EP0 EPs - // - if (EpInfo->EpNum && EpInfo->EpDir) { - EpCmdParams->Param0 |= (EpInfo->EpNum << DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_BIT_POS); - } - - // - // Program max packet size - // - EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_MPS_MASK; - EpCmdParams->Param0 |= (EpInfo->MaxPktSize << DWC_XDCI_PARAM0_SET_EP_CFG_MPS_BIT_POS); - - // - // Set Burst size. 0 means burst size of 1 - // - EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_MASK; - EpCmdParams->Param0 |= (EpInfo->BurstSize << DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_BIT_POS); - - // - // Set EP type - // - EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_MASK; - EpCmdParams->Param0 |= (EpInfo->EpType << DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_BIT_POS); - - // - // Set config action - // - EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MASK; - EpCmdParams->Param0 |= (ConfigAction << DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_BIT_POS); - break; - - case EPCMD_SET_EP_XFER_RES_CONFIG: - // Set Param0 to 1. Same for all EPs when resource - // configuration is done - // - EpCmdParams->Param0 = 1; - break; - - case EPCMD_END_XFER: - // - // Nothing to set. Already reset params for all cmds - // - break; - - case EPCMD_START_NEW_CONFIG: - // - // Nothing to set. Already reset params for all cmds - // - break; - - default: - status = EFI_INVALID_PARAMETER; - DEBUG ((DEBUG_INFO, "\nDwcXdciCoreInitEpCmdParams: INVALID Parameter")); - break; - } - - return status; -} - - -/** - Internal utility function: - This function is used to issue the xDCI endpoint command - @CoreHandle: xDCI controller handle address - @EpNum: Physical EP num - @EpCmd: xDCI EP command - @EpCmdParams: EP command parameters address - -**/ -STATIC -EFI_STATUS -DwcXdciCoreIssueEpCmd ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 EpNum, - IN UINT32 EpCmd, - IN DWC_XDCI_ENDPOINT_CMD_PARAMS *EpCmdParams - ) -{ - UINT32 BaseAddr; - UINT32 MaxDelayIter = 5000;//DWC_XDCI_MAX_DELAY_ITERATIONS; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreIssueEpCmd: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = CoreHandle->BaseAddress; - - // - // Set EP command parameter values - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EPCMD_PARAM2_REG(EpNum), - EpCmdParams->Param2 - ); - - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EPCMD_PARAM1_REG(EpNum), - EpCmdParams->Param1 - ); - - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EPCMD_PARAM0_REG(EpNum), - EpCmdParams->Param0 - ); - - // - // Set the command code and activate it - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EPCMD_REG(EpNum), - EpCmd | DWC_XDCI_EPCMD_CMD_ACTIVE_MASK - ); - - // - // Wait until command completes - // - do { - if (!(UsbRegRead (BaseAddr, DWC_XDCI_EPCMD_REG(EpNum)) & DWC_XDCI_EPCMD_CMD_ACTIVE_MASK)) - break; - else - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreIssueEpCmd. ERROR: Failed to issue Command\n")); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - - -/** - Internal utility function: - This function is used to flush all FIFOs - @CoreHandle: xDCI controller handle address - -**/ -STATIC -EFI_STATUS -DwcXdciCoreFlushAllFifos ( - IN XDCI_CORE_HANDLE *CoreHandle - ) -{ - UINT32 BaseAddr; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreFlushAllFifos: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = CoreHandle->BaseAddress; - - // - // Write the command to flush all FIFOs - // - UsbRegWrite( - BaseAddr, - DWC_XDCI_DGCMD_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_ALL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) - ); - - // - // Wait until command completes - // - do { - if (!(UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) - break; - else - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - - -/** - Internal utility function: - This function is used to flush Tx FIFO specific to an endpoint - @CoreHandle: xDCI controller handle address - @EpNum: Physical EP num - -**/ -STATIC -EFI_STATUS -DwcXdciCoreFlushEpTxFifo ( - XDCI_CORE_HANDLE *CoreHandle, - __attribute__((unused)) UINT32 EpNum - ) -{ - UINT32 BaseAddr; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreFlushEpTxFifo: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = CoreHandle->BaseAddress; - // - // TODO: Currently we are only using TxFIFO 0. Later map these - // Write the FIFO num/dir param for the generic command. - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DGCMD_PARAM_REG, - ((UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_PARAM_REG) & ~DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK) | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK) - ); - - // - // Write the command to flush all FIFOs - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DGCMD_REG, - (UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) - ); - - - // - // Wait until command completes - // - do { - if (!(UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) - break; - else - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - - - -STATIC -EFI_STATUS -DwcXdciCorePrepareOneTrb ( - IN DWC_XDCI_TRB *Trb, - IN DWC_XDCI_TRB_CONTROL TrbCtrl, - IN UINT32 LastBit, - IN UINT32 ChainBit, - IN UINT8 *BufferPtr, - IN UINT32 size - ) -{ - DEBUG ((DEBUG_INFO, "Trb is 0x%x, BufferPtr is 0x%x, size is 0x%x\n", Trb, BufferPtr, size)); - - Trb->BuffPtrLow = (UINT32)(UINTN)BufferPtr; - Trb->BuffPtrHigh = 0; - Trb->LenXferParams = size; - Trb->TrbCtrl = TrbCtrl << DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; - - if (ChainBit) - Trb->TrbCtrl |= ChainBit << DWC_XDCI_TRB_CTRL_CHAIN_BUFF_BIT_POS; - - if (LastBit) - Trb->TrbCtrl |= LastBit << DWC_XDCI_TRB_CTRL_LST_TRB_BIT_POS; - - Trb->TrbCtrl |= DWC_XDCI_TRB_CTRL_IOSP_MISOCH_MASK| DWC_XDCI_TRB_CTRL_HWO_MASK; - - DEBUG ((DEBUG_INFO, "(DwcXdciCorePrepareOneTrb) Trb->BuffPtrLow = 0x%x, Trb->LenXferParams is 0x%x, Trb->TrbCtrl is 0x%x\n", - Trb->BuffPtrLow, Trb->LenXferParams, Trb->TrbCtrl)); - return EFI_SUCCESS; -} - - -/** - Internal utility function: - This function is used to initialize transfer request block - @CoreHandle: xDCI controller handle address - @Trb: Address of TRB to initialize - @TrbCtrl: TRB control value - @buffPtr: Transfer Buffer address - @size: Size of the transfer - -**/ -STATIC -EFI_STATUS -DwcXdciCoreInitTrb ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN DWC_XDCI_TRB *Trb, - IN DWC_XDCI_TRB_CONTROL TrbCtrl, - IN UINT8 *BufferPtr, - IN UINT32 size - ) -{ -#define ONE_TRB_SIZE (DWC_XDCI_TRB_BUFF_SIZE_MASK & 0x00F00000) - UINT8 *TrbBuffer; - UINT32 TrbCtrlLast; - UINT32 TrbCtrlChain; - UINT32 TrbIndex; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreInitTrb: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (Trb == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreInitTrb: INVALID handle\n")); - return EFI_INVALID_PARAMETER; - } - - // - // Init TRB fields - // NOTE: Assuming we are only using 32-bit addresses - // TODO: update for 64-bit addresses - // - if (size <= DWC_XDCI_TRB_BUFF_SIZE_MASK) { - // - // Can transfer in one TRB - // - TrbCtrlChain = 0; - TrbCtrlLast = 1; - DwcXdciCorePrepareOneTrb (Trb, TrbCtrl, TrbCtrlLast, TrbCtrlChain, BufferPtr, size); - return EFI_SUCCESS; - } - - // - // Can't transfer in one TRB. - // Seperate it in every ONE_TRB_SIZE of TRB - // - TrbBuffer = BufferPtr; - TrbIndex = 0; - while (size > ONE_TRB_SIZE) { - TrbCtrlChain = 1; - TrbCtrlLast = 0; - DwcXdciCorePrepareOneTrb (Trb, TrbCtrl, TrbCtrlLast, TrbCtrlChain, TrbBuffer, ONE_TRB_SIZE); - TrbBuffer += ONE_TRB_SIZE; - size -= ONE_TRB_SIZE; - Trb++; - TrbIndex++; - if (TrbIndex >= DWC_XDCI_TRB_NUM) - return EFI_OUT_OF_RESOURCES; - } - TrbCtrlChain = 0; - TrbCtrlLast = 1; - DwcXdciCorePrepareOneTrb (Trb, TrbCtrl, TrbCtrlLast, TrbCtrlChain, TrbBuffer, size); - - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to start a SETUP phase on control endpoint - @CoreHandle: xDCI controller handle address - -**/ -STATIC -EFI_STATUS -DwcXdciCoreStartEp0SetupXfer ( - IN XDCI_CORE_HANDLE *CoreHandle - ) -{ - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS status = EFI_DEVICE_ERROR; - DWC_XDCI_TRB *Trb; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreStartEp0SetupXfer: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (CoreHandle->EpHandles[0].State == USB_EP_STATE_SETUP) { - DEBUG ((DEBUG_INFO, "EP0 was already in SETUP phase\n")); - return EFI_SUCCESS; - } - - CoreHandle->EpHandles[0].State = USB_EP_STATE_SETUP; - Trb = CoreHandle->Trbs; - DEBUG ((DEBUG_INFO, "(DwcXdciCoreStartEp0SetupXfer)\n")); - - status = DwcXdciCoreInitTrb ( - CoreHandle, - Trb, - TRBCTL_SETUP, - CoreHandle->AlignedSetupBuffer, - 8 - ); - - if (status) - return status; - - // - // Issue a DEPSTRTXFER for EP0 - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Init the lower re-bits for TRB address - // - EpCmdParams.Param1 = (UINT32)(UINTN)Trb; - - // - // Issue the command to start transfer on physical - // endpoint 0 - // - status = DwcXdciCoreIssueEpCmd ( - CoreHandle, - 0, - EPCMD_START_XFER, - &EpCmdParams - ); - - // - // Save new resource index for this transfer - // - CoreHandle->EpHandles[0].CurrentXferRscIdx = ((UsbRegRead ( - CoreHandle->BaseAddress, - DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS - ); - - return status; -} - - -/** - Internal function: - This function is used to process the state change event - @CoreHandle: xDCI controller handle address - @event: device event dword - -**/ -STATIC -EFI_STATUS -DwcXdciProcessDeviceStateChangeEvent ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 Event - ) -{ - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessDeviceStateChangeEvent: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - CoreHandle->HirdVal = (Event & DWC_XDCI_EVENT_BUFF_DEV_HIRD_MASK) >> DWC_XDCI_EVENT_BUFF_DEV_HIRD_BIT_POS; - - CoreHandle->LinkState = ((Event & DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_MASK) >> DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_BIT_POS); - - if (CoreHandle->EventCallbacks.DevLinkStateCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.LinkState = CoreHandle->LinkState; - CoreHandle->EventCallbacks.CbEventParams.Hird = CoreHandle->HirdVal; - CoreHandle->EventCallbacks.CbEventParams.SsEvent = (Event & DWC_XDCI_EVENT_BUFF_DEV_SS_EVENT_MASK) ? 1 : 0; - CoreHandle->EventCallbacks.DevLinkStateCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to issue a command to end transfer - @CoreHandle: xDCI controller handle address - @EpNum: Physical EP num for which transfer is to be ended - -**/ -STATIC -EFI_STATUS -DwcXdciEndXfer ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 EpNum - ) -{ - EFI_STATUS status; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - UINT32 cmdParams; - DWC_XDCI_TRB *TrbPtr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciEndXfer: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - CoreHandle->EpHandles[EpNum].CheckFlag = FALSE; - - // - // Issue a DEPENDXFER for EP - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - cmdParams = ((CoreHandle->EpHandles[EpNum].CurrentXferRscIdx << DWC_XDCI_EPCMD_RES_IDX_BIT_POS) | DWC_XDCI_EPCMD_FORCE_RM_MASK); - - if (CoreHandle->EpHandles[EpNum].CurrentXferRscIdx == 0) { - return EFI_SUCCESS; - } - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd( - CoreHandle, - EpNum, - cmdParams | DWC_XDCI_EPCMD_END_XFER, - &EpCmdParams - ); - - if (!status) { - CoreHandle->EpHandles[EpNum].CurrentXferRscIdx = 0; - TrbPtr = CoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM); - ZeroMem (TrbPtr, DWC_XDCI_TRB_NUM * sizeof (DWC_XDCI_TRB)); - } - - return status; -} - - -/** - Internal function: - This function is used to process bus reset detection event - @CoreHandle: xDCI controller handle address - -**/ -STATIC -EFI_STATUS -DwcXdciProcessDeviceResetDet ( - IN XDCI_CORE_HANDLE *CoreHandle - ) -{ - EFI_STATUS status = EFI_SUCCESS; - - if (CoreHandle == NULL) { - return EFI_DEVICE_ERROR; - } - - // - // Flush all FIFOs - // - status = DwcXdciCoreFlushAllFifos(CoreHandle); - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceResetDet: Failed to flush FIFOs\n")); - } - - // - // Start SETUP phase on EP0 - // - status = DwcXdciCoreStartEp0SetupXfer(CoreHandle); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceResetDet: Failed to start SETUP phase for EP0\n")); - return status; - } - - // - // Notify upper layer if a callback is registerd for - // this event - // - if (CoreHandle->EventCallbacks.DevBusResetCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - status = CoreHandle->EventCallbacks.DevBusResetCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - return status; -} - - -/** - Internal function: - This function is used to process connection done (means reset - complete) event - @CoreHandle: xDCI controller handle address - -**/ -STATIC -EFI_STATUS -DwcXdciProcessDeviceResetDone ( - IN XDCI_CORE_HANDLE *CoreHandle - ) -{ - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - UINT32 BaseAddr; - EFI_STATUS status = EFI_SUCCESS; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessDeviceResetDone: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = CoreHandle->BaseAddress; - CoreHandle->ActualSpeed = (UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_CONN_SPEED_MASK); - DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceResetDone CoreHandle->ActualSpeed is %x\n", CoreHandle->ActualSpeed)); - - // - // Program MPS Based on the negotiated Speed - // - DwcXdciCoreGetCtrlMps (CoreHandle, &CoreHandle->EpHandles[0].EpInfo.MaxPktSize); - DwcXdciCoreGetCtrlMps (CoreHandle, &CoreHandle->EpHandles[1].EpInfo.MaxPktSize); - - // - // Init DEPCFG cmd params for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - CoreHandle, - &CoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - CoreHandle, - 0, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - return status; - } - - // - // Init DEPCFG cmd params for EP1 - // - status = DwcXdciCoreInitEpCmdParams ( - CoreHandle, - &CoreHandle->EpHandles[1].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - CoreHandle, - 1, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - // - // Put the other PHY into suspend - // - if (CoreHandle->ActualSpeed == USB_SPEED_SUPER) { - // - // Put HS PHY to suspend - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB2PHYCFG_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) | DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) - ); - - // - // Clear SS PHY's suspend mask - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB3PIPECTL_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) - ); - - } else { - // - // Put SS PHY to suspend - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB3PIPECTL_REG(0), - (UsbRegRead(BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) | DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) - ); - - // - // Clear HS PHY's suspend mask - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB2PHYCFG_REG(0), - (UsbRegRead(BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) - ); - } - - // - // Notify upper layer if callback is registered - // - if (CoreHandle->EventCallbacks.DevResetDoneCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.Speed = CoreHandle->ActualSpeed; - CoreHandle->EventCallbacks.DevResetDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - return status; -} - - -/** - Internal function: - This function is used to process device event - @CoreHandle: xDCI controller handle address - @IntLineEventBuffer: event Buffer pointing to device event - @ProcessedEventSize: address of variable to save the size of - the event that was Processed - -**/ -STATIC -EFI_STATUS -DwcXdciProcessDeviceEvent ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN DWC_XDCI_EVENT_BUFFER *IntLineEventBuffer, - IN UINT32 *ProcessedEventSize - ) -{ - UINT32 event; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessDeviceEvent: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Extract device event - // - event = (IntLineEventBuffer->Event & DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK); - event >>= DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS; - - // - // Assume default event size. Change it in switch case if - // different - // - *ProcessedEventSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; - - switch (event) { - case DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT\n")); - DwcXdciProcessDeviceResetDet (CoreHandle); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT\n")); - DwcXdciProcessDeviceResetDone (CoreHandle); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT\n")); - DwcXdciProcessDeviceStateChangeEvent (CoreHandle, IntLineEventBuffer->Event); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT\n")); - break; - - case DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT: - DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT\n")); - *ProcessedEventSize = DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES; - break; - - default: - DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceEvent: UNHANDLED device event: %x\n", event)); - break; - } - - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to process EP not ready for - non-control endpoints - @CoreHandle: xDCI controller handle address - @EpNum: Physical endpoint number - -**/ -STATIC -EFI_STATUS -DwcXdciProcessEpXferNotReady ( - __attribute__((unused)) XDCI_CORE_HANDLE *CoreHandle, - __attribute__((unused)) UINT32 EpNum - ) -{ - // - // TODO: Not doing on-demand transfers - // Revisit if required for later use - // - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to process EP not ready for - control endpoints - @CoreHandle: xDCI controller handle address - @EpNum: Physical endpoint number - @dataStage: EP not ready when data stage token was received - @statusStage: EP not ready when status stage token was received - -**/ -STATIC -EFI_STATUS -DwcXdciProcessEp0XferNotReady ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 EpNum, - IN UINT32 epEventStatus - ) -{ - USB_EP_STATE epState = USB_EP_STATE_SETUP; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEp0XferNotReady: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - // - // Is it data stage or status stage - // - if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_DATA_REQ_MASK) { - epState = USB_EP_STATE_DATA; - } else if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK) { - epState = USB_EP_STATE_STATUS; - } - - if ((EpNum == 0) && (epState == USB_EP_STATE_STATUS)) { - if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_XFER_ACTIVE_MASK) { - DEBUG ((DEBUG_INFO, "XFER_ACTIVE\n")); - } else { - DEBUG ((DEBUG_INFO, "XFER_NOT_ACTIVE\n")); - } - DwcXdciEp0ReceiveStatusPkt (CoreHandle); - } - - // - // Notify upper layer if a callback is registered for - // this event - // - if (CoreHandle->EventCallbacks.DevXferNrdyCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.EpState = epState; - CoreHandle->EventCallbacks.DevXferNrdyCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to process transfer phone done for EP0 - @CoreHandle: xDCI controller handle address - @EpNum: Physical endpoint number (0 for OUT and 1 for IN) - -**/ -STATIC -EFI_STATUS -DwcXdciProcessEp0XferPhaseDone ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 EpNum - ) -{ - DWC_XDCI_ENDPOINT *epHandle; - DWC_XDCI_TRB *Trb; - EFI_STATUS status = EFI_SUCCESS; - UINT32 TrbSts; - UINT32 TrbCtrl; - UINT32 TrbBufsize; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEp0XferPhaseDone: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - epHandle = &CoreHandle->EpHandles[EpNum]; - Trb = CoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM); - DEBUG ((DEBUG_INFO, "(DwcXdciProcessEp0XferPhaseDone)EpNum is %d\n", EpNum)); - - if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { - DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone. HW owns TRB: %x!!!\n", (UINT32)(UINTN)Trb)); - } - - epHandle->CurrentXferRscIdx = 0; - epHandle->State = USB_EP_STATE_ENABLED; - TrbCtrl = (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_TYPE_MASK) >> DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; - TrbSts = (Trb->LenXferParams & DWC_XDCI_TRB_STATUS_MASK) >> DWC_XDCI_TRB_STATUS_BIT_POS; - TrbBufsize = Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK; - - switch (TrbCtrl) { - case DWC_XDCI_TRB_CTRL_TYPE_SETUP: - DEBUG ((DEBUG_INFO, "SETUP\n")); - if (CoreHandle->EventCallbacks.DevSetupPktReceivedCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.Buffer = CoreHandle->AlignedSetupBuffer; - status = CoreHandle->EventCallbacks.DevSetupPktReceivedCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - if (!(CoreHandle->AlignedSetupBuffer[0] & USB_SETUP_DATA_PHASE_DIRECTION_MASK)) { - // - // Keep a Buffer ready for setup phase - // - DwcXdciCoreStartEp0SetupXfer (CoreHandle); - } - - break; - - case DWC_XDCI_TRB_CTRL_TYPE_STATUS2: - DEBUG ((DEBUG_INFO, "STATUS2\n")); - break; - - case DWC_XDCI_TRB_CTRL_TYPE_STATUS3: - DEBUG ((DEBUG_INFO, "STATUS3\n")); - // - // Notify upper layer of control transfer completion - // if a callback function was registerd - // - if (CoreHandle->EventCallbacks.DevXferDoneCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.EpNum = (EpNum >> 1); - CoreHandle->EventCallbacks.CbEventParams.EpDir = (EpNum & 1); - CoreHandle->EventCallbacks.CbEventParams.Buffer = (UINT8 *)(UINTN)(Trb->BuffPtrLow); - CoreHandle->EventCallbacks.DevXferDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - // - // Status phase done. Queue next SETUP packet - // - status = DwcXdciCoreStartEp0SetupXfer(CoreHandle); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone: FAILED to queue SETUP\n")); - } - break; - - case DWC_XDCI_TRB_CTRL_TYPE_DATA: - DEBUG ((DEBUG_INFO, "DATA\n")); - if (TrbSts == DWC_XDCI_TRB_STATUS_SETUP_PENDING || TrbBufsize != 0) { - DEBUG ((DEBUG_INFO, "ERROR: Control transfert aborted by host: Setup pending\n")); - DwcXdciCoreStartEp0SetupXfer (CoreHandle); - } - - if (CoreHandle->EventCallbacks.DevXferDoneCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.EpNum = (EpNum >> 1); - CoreHandle->EventCallbacks.CbEventParams.EpDir = (EpNum & 1); - CoreHandle->EventCallbacks.CbEventParams.Buffer = (UINT8 *)(UINTN)(Trb->BuffPtrLow); - CoreHandle->EventCallbacks.DevXferDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - break; - - default: - DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone: UNHANDLED STATE in TRB\n")); - break; - } - - return status; -} - - -/** - Internal function: - This function is used to process transfer done for - non-control endpoints - @CoreHandle: xDCI controller handle address - @EpNum: Physical endpoint number - -**/ -STATIC -EFI_STATUS -DwcXdciProcessEpXferDone ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 EpNum - ) -{ - DWC_XDCI_ENDPOINT *epHandle; - DWC_XDCI_TRB *Trb; - USB_XFER_REQUEST *XferReq; - UINT32 remainingLen; - - if (EpNum > DWC_XDCI_MAX_ENDPOINTS) { - EpNum = DWC_XDCI_MAX_ENDPOINTS; - } - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpXferDone: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - epHandle = &CoreHandle->EpHandles[EpNum]; - epHandle->CurrentXferRscIdx = 0; - Trb = epHandle->Trb; - XferReq = &epHandle->XferHandle; - - // - // if transfer done, set CheckFlag to FALSE for allow next transfer request. - // - epHandle->CheckFlag = FALSE; - - if ((Trb == NULL) || (XferReq == NULL)) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpXferDone: INVALID parameter\n")); - return EFI_INVALID_PARAMETER; - } - - // - // Compute the actual transfer length - // - XferReq->ActualXferLen = XferReq->XferLen; - remainingLen = (Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK); - - if (remainingLen > XferReq->XferLen) { - // - // Buffer overrun? This should never happen - // - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpXferDone: Possible Buffer overrun\n")); - } else { - XferReq->ActualXferLen -= remainingLen; - } - - // - // Notify upper layer of request-specific transfer completion - // if there is a callback specifically for this request - // - if (XferReq->XferDone) { - XferReq->XferDone(CoreHandle->ParentHandle, XferReq); - } - - // - // Notify upper layer if a callback was registered - // - if (CoreHandle->EventCallbacks.DevXferDoneCallback) { - CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; - CoreHandle->EventCallbacks.CbEventParams.EpNum = (EpNum >> 1); - CoreHandle->EventCallbacks.CbEventParams.EpDir = (EpNum & 1); - CoreHandle->EventCallbacks.CbEventParams.EpType = epHandle->EpInfo.EpType; - CoreHandle->EventCallbacks.CbEventParams.Buffer = (UINT8 *)(UINTN)(epHandle->Trb->BuffPtrLow); - CoreHandle->EventCallbacks.DevXferDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); - } - - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to process endpoint events - @CoreHandle: xDCI controller handle address - @IntLineEventBuffer: address of Buffer containing event - to process - @ProcessedEventSize: address to save the size of event - Processed - -**/ -STATIC -EFI_STATUS -DwcXdciProcessEpEvent ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN DWC_XDCI_EVENT_BUFFER *IntLineEventBuffer, - IN UINT32 *ProcessedEventSize - ) -{ - UINT32 EpNum; - UINT32 epEvent; - UINT32 epEventStatus; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpEvent: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - epEvent = IntLineEventBuffer->Event; - - *ProcessedEventSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; - - // - // Get EP num - // - EpNum = ((epEvent & DWC_XDCI_EVENT_BUFF_EP_NUM_MASK) >> DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS); - epEventStatus = (epEvent & DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK); - - // - // Interpret event and handle transfer completion here - // - epEvent = ((epEvent & DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK) >> DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS); - - switch (epEvent) { - case DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT: - DEBUG ((DEBUG_INFO, "XFER_CMPLT ep %d\n", EpNum)); - if (EpNum > 1) { - DwcXdciProcessEpXferDone (CoreHandle, EpNum); - } else { - DwcXdciProcessEp0XferPhaseDone (CoreHandle, EpNum); - } - break; - - case DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS: - DEBUG ((DEBUG_INFO, "IN_PROGRESS\n")); - break; - - case DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY: - DEBUG ((DEBUG_INFO, "NOT_READY ep %d\n", EpNum)); - if (EpNum > 1) { - // - // Endpoint transfer is not ready - // - DwcXdciProcessEpXferNotReady (CoreHandle, EpNum); - } else { - DwcXdciProcessEp0XferNotReady (CoreHandle, EpNum, epEventStatus); - } - break; - - default: - DEBUG ((DEBUG_INFO, "DwcXdciProcessEpEvent: UNKNOWN EP event\n")); - break; - } - - return EFI_SUCCESS; -} - - -/** - Internal function: - This function is used to process events on single interrupt line - @CoreHandle: xDCI controller handle address - @eventCount: event bytes to process - @ProcessedEventCount: address to save the size - (in bytes) of event Processed - Processed - -**/ -STATIC -EFI_STATUS -DwcXdciProcessInterruptLineEvents ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 eventCount, - IN UINT32 *ProcessedEventCount - ) -{ - UINT32 ProcessedEventSize = 0; - UINT32 currentEventAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessInterruptLineEvents: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (CoreHandle->CurrentEventBuffer == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessInterruptLineEvents: INVALID event Buffer\n")); - return EFI_INVALID_PARAMETER; - } - - currentEventAddr = (UINT32)(UINTN)(CoreHandle->CurrentEventBuffer); - - // - // Process eventCount/eventSize number of events - // in this run - // - while (eventCount) { - if (CoreHandle->CurrentEventBuffer->Event & DWC_XDCI_EVENT_DEV_MASK) { - DwcXdciProcessDeviceEvent ( - CoreHandle, - CoreHandle->CurrentEventBuffer, - &ProcessedEventSize - ); - } else { - DwcXdciProcessEpEvent ( - CoreHandle, - CoreHandle->CurrentEventBuffer, - &ProcessedEventSize); - } - - eventCount -= ProcessedEventSize; - *ProcessedEventCount += ProcessedEventSize; - if ((currentEventAddr + ProcessedEventSize) >= - ((UINT32)(UINTN)(CoreHandle->AlignedEventBuffers) + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)) - ) { - currentEventAddr = (UINT32)(UINTN)(CoreHandle->AlignedEventBuffers); - DEBUG ((DEBUG_INFO, "DwcXdciProcessInterruptLineEvents: Event Buffer bound reached\n")); - } else { - currentEventAddr += ProcessedEventSize; - } - - CoreHandle->CurrentEventBuffer = (DWC_XDCI_EVENT_BUFFER *)(UINTN)currentEventAddr; - } - - return EFI_SUCCESS; -} - -// -// DWC XDCI APIs -// - -/** - Interface: - - This function is used to initialize the xDCI core - @configParams: Parameters from app to configure the core - @deviceCorePtr: HW-independent APIs handle for device core - @CoreHandle: xDCI controller handle retured - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreInit ( - IN USB_DEV_CONFIG_PARAMS *ConfigParams, - IN VOID *deviceCorePtr, - IN VOID **CoreHandle - ) -{ - EFI_STATUS status = EFI_DEVICE_ERROR; - UINT32 BaseAddr; - XDCI_CORE_HANDLE *LocalCoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - UINT8 i; - - LocalCoreHandle = (XDCI_CORE_HANDLE *)AllocateZeroPool (sizeof(XDCI_CORE_HANDLE)); - - if (CoreHandle == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (LocalCoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to allocate handle for xDCI\n")); - return EFI_OUT_OF_RESOURCES; - } - - ZeroMem (LocalCoreHandle, sizeof(XDCI_CORE_HANDLE)); - - LocalCoreHandle->ParentHandle = deviceCorePtr; - - *CoreHandle = (VOID *)LocalCoreHandle; - - LocalCoreHandle->Id = ConfigParams->ControllerId; - LocalCoreHandle->BaseAddress = BaseAddr = ConfigParams->BaseAddress; - LocalCoreHandle->Flags = ConfigParams->Flags; - LocalCoreHandle->DesiredSpeed = LocalCoreHandle->ActualSpeed = ConfigParams->Speed; - LocalCoreHandle->Role = ConfigParams->Role; - - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_CSFTRST_MASK); - - // Wait until core soft reset completes - do { - if (!(UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & DWC_XDCI_DCTL_CSFTRST_MASK)) { - break; - } else { - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - efi_perror (status, L"Failed to reset device controller 0x%x",(UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG))); - return EFI_DEVICE_ERROR; - } - - DEBUG ((DEBUG_INFO, "USB core has been reset\n")); - - // - // All FIFOs are flushed at this point - // - // - // Ensure we have EP0 Rx/Tx handles initialized - // - LocalCoreHandle->EpHandles[0].EpInfo.EpNum = 0; - LocalCoreHandle->EpHandles[0].EpInfo.EpDir = UsbEpDirOut; - LocalCoreHandle->EpHandles[0].EpInfo.EpType = USB_ENDPOINT_CONTROL; - LocalCoreHandle->EpHandles[0].EpInfo.MaxPktSize = DWC_XDCI_SS_CTRL_EP_MPS; - // - // 0 means burst size of 1 - // - LocalCoreHandle->EpHandles[0].EpInfo.BurstSize = 0; - - LocalCoreHandle->EpHandles[1].EpInfo.EpNum = 0; - LocalCoreHandle->EpHandles[1].EpInfo.EpDir = UsbEpDirIn; - LocalCoreHandle->EpHandles[1].EpInfo.EpType = USB_ENDPOINT_CONTROL; - LocalCoreHandle->EpHandles[1].EpInfo.MaxPktSize = DWC_XDCI_SS_CTRL_EP_MPS; - // - // 0 means burst size of 1 - // - LocalCoreHandle->EpHandles[1].EpInfo.BurstSize = 0; - - LocalCoreHandle->DevState = UsbDevStateDefault; - - // - // Clear KeepConnect bit so we can allow disconnect and - // re-connect. Stay in RX_DETECT state - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & - (~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & - ((~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK) | (DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS)) - ); - - DEBUG ((DEBUG_INFO, "Device controller Synopsys ID: %x\n", UsbRegRead (BaseAddr, DWC_XDCI_GSNPSID_REG))); - DEBUG ((DEBUG_INFO, "Default value of xDCI GSBUSCFG0 and GSBUSCFG1: %x, %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG0_REG), - UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG1_REG))); - - DEBUG ((DEBUG_INFO, "Default value of xDCI GTXTHRCFG and GRXTHRCFG: %x, %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GTXTHRCFG_REG), - UsbRegRead (BaseAddr, DWC_XDCI_GRXTHRCFG_REG))); - - // - // Clear ULPI auto-resume bit - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB2PHYCFG_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)) & ~DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK) - ); - - DEBUG ((DEBUG_INFO, "Default value of xDCI GUSB2PHYCFG and GUSB3PIPECTL: %x, %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)), - UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG (0)))); - // - // Only one RxFIFO - // - DEBUG ((DEBUG_INFO, "Default value of DWC_XDCI_GRXFIFOSIZ: %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GRXFIFOSIZ_REG (0)))); - - for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++) { - DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_GTXFIFOSIZ %d: %x\n", - i, UsbRegRead (BaseAddr, DWC_XDCI_GTXFIFOSIZ_REG (i)))); - } - - // - // TODO: Need to check if TxFIFO should start where RxFIFO ends - // or default is correct i.e. TxFIFO starts at 0 just like RxFIFO - // - - // - // Allocate and Initialize Event Buffers - // - LocalCoreHandle->MaxDevIntLines = ((UsbRegRead (BaseAddr, DWC_XDCI_GHWPARAMS1_REG) & - DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >> - DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS); - - DEBUG ((DEBUG_INFO, "Max dev int lines: %d\n", LocalCoreHandle->MaxDevIntLines)); - // - // One event Buffer per interrupt line. - // Need to align it to size of event Buffer - // Buffer needs to be big enough. Otherwise the core - // won't operate - // - LocalCoreHandle->AlignedEventBuffers = (DWC_XDCI_EVENT_BUFFER *) - ((UINT32)(UINTN)(LocalCoreHandle->EventBuffers) + - ((sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - - (((UINT32)(UINTN)(LocalCoreHandle->EventBuffers)) % - (sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)))); - - for (i = 0; i < LocalCoreHandle->MaxDevIntLines; i++) { - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GEVNTADR_REG (i), - (UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers + i * sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - ); - - // - // Clear High 32bit address register, GEVNTADR register is 64-bit register - // default is 0xffffffffffffffff - // - UsbRegWrite (BaseAddr, DWC_XDCI_GEVNTADR_REG (i) + 4, 0x00000000); - - LocalCoreHandle->CurrentEventBuffer = LocalCoreHandle->AlignedEventBuffers; - // - // Write size and clear the mask - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EVNTSIZ_REG (i), - sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER - ); - - // - // Write 0 to the event count register as the last step - // - // for event configuration - // - UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i), 0); - - DEBUG ((DEBUG_INFO, "Value of xDCI Event Buffer %d: %x, Size: %x, Count: %x\n", - i, - UsbRegRead (BaseAddr, DWC_XDCI_GEVNTADR_REG (i)), - UsbRegRead (BaseAddr, DWC_XDCI_EVNTSIZ_REG (i)), - UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i)))); - } - - // - // Program Global Control Register to disable scaledown, - // disable clock gating - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GCTL_REG, - ((UsbRegRead(BaseAddr, DWC_XDCI_GCTL_REG) & - ~(DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK + DWC_XDCI_GCTL_RAMCLKSEL_MASK + DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK)) | - DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK | - (DWC_XDCI_GCTL_PRT_CAP_DEVICE << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS))); - - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG))); - - // - // TODO: Program desired Speed and set LPM capable - // We will do this when SuperSpeed works. For now, - // force into High-Speed mode to aVOID anyone trying this - // on Super Speed port - // - - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCFG_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | LocalCoreHandle->DesiredSpeed - ); -#if 0 - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCFG_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | DWC_XDCI_DCFG_DESIRED_HS_SPEED - ); -#endif - - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG))); - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG))); - - // - // Enable Device Interrupt Events - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DEVTEN_REG, - DWC_XDCI_DEVTEN_DEVICE_INTS - ); - // - // Program the desired role - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GCTL_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG) & ~DWC_XDCI_GCTL_PRT_CAP_DIR_MASK) | (LocalCoreHandle->Role << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS) - ); - // - // Clear USB2 suspend for start new config command - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB2PHYCFG_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) - ); - - // - // Clear USB3 suspend for start new config command - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB3PIPECTL_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) - ); - - // - // Issue DEPSTARTCFG command for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_START_NEW_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to init params for START_NEW_CONFIG EP command on xDCI"); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_START_NEW_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to issue START_NEW_CONFIG EP command on xDCI"); - return status; - } - - // - // Issue DEPCFG command for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP0"); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_SET_EP_CONFIG, - &EpCmdParams); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP0"); - return status; - } - - // - // Issue DEPCFG command for EP1 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[1].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP1"); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 1, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP1"); - return status; - } - - // - // Issue DEPXFERCFG command for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0"); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0"); - return status; - } - - // - // Issue DEPXFERCFG command for EP1 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[1].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1"); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 1, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - efi_perror (status, L"DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1"); - return status; - } - - // - // Prepare a Buffer for SETUP packet - // - LocalCoreHandle->Trbs = (DWC_XDCI_TRB *)(UINTN)((UINT32)(UINTN) - LocalCoreHandle->UnalignedTrbs + - (DWC_XDCI_TRB_BYTE_ALIGNMENT - - ((UINT32)(UINTN)LocalCoreHandle->UnalignedTrbs % - DWC_XDCI_TRB_BYTE_ALIGNMENT))); - - DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ unalignedTrbs address is 0x%x\n", LocalCoreHandle->UnalignedTrbs)); - DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ TRB address is 0x%x\n", LocalCoreHandle->Trbs)); - // - // Allocate Setup Buffer that is 8-byte aligned - // - LocalCoreHandle->AlignedSetupBuffer = LocalCoreHandle->DefaultSetupBuffer + - (DWC_XDCI_SETUP_BUFF_SIZE - - ((UINT32)(UINTN)(LocalCoreHandle->DefaultSetupBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); - - // - // Aligned Buffer for status phase - // - LocalCoreHandle->AlignedMiscBuffer = LocalCoreHandle->MiscBuffer + - (DWC_XDCI_SETUP_BUFF_SIZE - - ((UINT32)(UINTN)(LocalCoreHandle->AlignedMiscBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); - - - // - // Enable Physical Endpoints 0 - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EP_DALEPENA_REG, - UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 0) - ); - // - // Enable Physical Endpoints 1 - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EP_DALEPENA_REG, - UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 1) - ); - - DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DEVTEN_REG))); - return status; -} - - -/** - Interface: - This function is used to de-initialize the xDCI core - @CoreHandle: xDCI controller handle - @flags: Special flags for de-initializing the core in - particular way - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreDeinit ( - VOID *CoreHandle, - __attribute__((unused)) UINT32 flags - ) -{ - FreePool (CoreHandle); - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to register event callback function - @CoreHandle: xDCI controller handle - @event: Event for which callback is to be registered - @callbackFn: Callback function to invoke after event occurs - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreRegisterCallback ( - IN VOID *CoreHandle, - IN USB_DEVICE_EVENT_ID Event, - IN USB_DEVICE_CALLBACK_FUNC CallbackFunc - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - - if (LocalCoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreRegisterCallback: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - DEBUG ((DEBUG_INFO, "DwcXdciCoreRegisterCallback: event is %d\n", Event)); - switch (Event) { - case USB_DEVICE_DISCONNECT_EVENT: - LocalCoreHandle->EventCallbacks.DevDisconnectCallback = CallbackFunc; - break; - - case USB_DEVICE_RESET_EVENT: - LocalCoreHandle->EventCallbacks.DevBusResetCallback = CallbackFunc; - break; - - case USB_DEVICE_CONNECTION_DONE: - LocalCoreHandle->EventCallbacks.DevResetDoneCallback = CallbackFunc; - break; - - case USB_DEVICE_STATE_CHANGE_EVENT: - LocalCoreHandle->EventCallbacks.DevLinkStateCallback = CallbackFunc; - break; - - case USB_DEVICE_WAKEUP_EVENT: - LocalCoreHandle->EventCallbacks.DevWakeupCallback = CallbackFunc; - break; - - case USB_DEVICE_HIBERNATION_REQ_EVENT: - LocalCoreHandle->EventCallbacks.DevHibernationCallback = CallbackFunc; - break; - - case USB_DEVICE_SOF_EVENT: - LocalCoreHandle->EventCallbacks.DevSofCallback = CallbackFunc; - break; - - case USB_DEVICE_ERRATIC_ERR_EVENT: - LocalCoreHandle->EventCallbacks.DevErraticErrCallback = CallbackFunc; - break; - - case USB_DEVICE_CMD_CMPLT_EVENT: - LocalCoreHandle->EventCallbacks.DevCmdCmpltCallback = CallbackFunc; - break; - - case USB_DEVICE_BUFF_OVERFLOW_EVENT: - LocalCoreHandle->EventCallbacks.DevBuffOvflwCallback = CallbackFunc; - break; - - case USB_DEVICE_TEST_LMP_RX_EVENT: - LocalCoreHandle->EventCallbacks.DevTestLmpRxCallback = CallbackFunc; - break; - - case USB_DEVICE_SETUP_PKT_RECEIVED: - LocalCoreHandle->EventCallbacks.DevSetupPktReceivedCallback = CallbackFunc; - break; - - case USB_DEVICE_XFER_NRDY: - LocalCoreHandle->EventCallbacks.DevXferNrdyCallback = CallbackFunc; - break; - - case USB_DEVICE_XFER_DONE: - LocalCoreHandle->EventCallbacks.DevXferDoneCallback = CallbackFunc; - break; - - default: - break; - } - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to unregister event callback function - @CoreHandle: xDCI controller handle - @event: Event for which callback function is to be unregistered - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreUnregisterCallback ( - IN VOID *CoreHandle, - IN USB_DEVICE_EVENT_ID event - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - - if (LocalCoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreUnregisterCallback: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - switch (event) { - case USB_DEVICE_DISCONNECT_EVENT: - LocalCoreHandle->EventCallbacks.DevDisconnectCallback = NULL; - break; - - case USB_DEVICE_RESET_EVENT: - LocalCoreHandle->EventCallbacks.DevBusResetCallback = NULL; - break; - - case USB_DEVICE_CONNECTION_DONE: - LocalCoreHandle->EventCallbacks.DevResetDoneCallback = NULL; - break; - - case USB_DEVICE_STATE_CHANGE_EVENT: - LocalCoreHandle->EventCallbacks.DevLinkStateCallback = NULL; - break; - - case USB_DEVICE_WAKEUP_EVENT: - LocalCoreHandle->EventCallbacks.DevWakeupCallback = NULL; - break; - - case USB_DEVICE_HIBERNATION_REQ_EVENT: - LocalCoreHandle->EventCallbacks.DevHibernationCallback = NULL; - break; - - case USB_DEVICE_SOF_EVENT: - LocalCoreHandle->EventCallbacks.DevSofCallback = NULL; - break; - - case USB_DEVICE_ERRATIC_ERR_EVENT: - LocalCoreHandle->EventCallbacks.DevErraticErrCallback = NULL; - break; - - case USB_DEVICE_CMD_CMPLT_EVENT: - LocalCoreHandle->EventCallbacks.DevCmdCmpltCallback = NULL; - break; - - case USB_DEVICE_BUFF_OVERFLOW_EVENT: - LocalCoreHandle->EventCallbacks.DevBuffOvflwCallback = NULL; - break; - - case USB_DEVICE_TEST_LMP_RX_EVENT: - LocalCoreHandle->EventCallbacks.DevTestLmpRxCallback = NULL; - break; - - case USB_DEVICE_SETUP_PKT_RECEIVED: - LocalCoreHandle->EventCallbacks.DevSetupPktReceivedCallback = NULL; - break; - - case USB_DEVICE_XFER_NRDY: - LocalCoreHandle->EventCallbacks.DevXferNrdyCallback = NULL; - break; - - case USB_DEVICE_XFER_DONE: - LocalCoreHandle->EventCallbacks.DevXferDoneCallback = NULL; - break; - - default: - break; - } - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used as an interrupt service routine - @CoreHandle: xDCI controller handle - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreIsrRoutine ( - IN VOID *CoreHandle - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 BaseAddr; - UINT32 eventCount; - UINT32 ProcessedEventCount; - UINT32 i; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreIsrRoutine: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (LocalCoreHandle->InterrupProcessing == TRUE) { - DEBUG ((DEBUG_INFO, "interrupProcessing.........\n")); - return EFI_SUCCESS; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - // - // Event Buffer corresponding to each interrupt line needs - // to be Processed - // - LocalCoreHandle->InterrupProcessing = TRUE; - for (i = 0; i < LocalCoreHandle->MaxDevIntLines; i++) { - // - // Get the number of events HW has written for this - // interrupt line - // - eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i)); - eventCount &= DWC_XDCI_EVNTCOUNT_MASK; - ProcessedEventCount = 0; - - // - // Process interrupt line Buffer only if count is non-zero - // - if (eventCount) { - // - // Process events in this Buffer - // - DwcXdciProcessInterruptLineEvents (LocalCoreHandle, eventCount, &ProcessedEventCount); - // - // Write back the Processed number of events so HW decrements it from current - // event count - // - UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i), ProcessedEventCount); - } - } - LocalCoreHandle->InterrupProcessing = FALSE; - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used as an interrupt service routine and it processes only one event at a time. - @CoreHandle: xDCI controller handle - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreIsrRoutineTimerBased ( - IN VOID *CoreHandle - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 BaseAddr; - UINT32 eventCount; - UINT32 ProcessedEventCount; - UINT32 currentEventAddr; - UINT32 ProcessedEventSize = 0; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreIsrRoutineTimerBased: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (LocalCoreHandle->CurrentEventBuffer == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreIsrRoutineTimerBased: INVALID event Buffer\n")); - return EFI_INVALID_PARAMETER; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0)) & DWC_XDCI_EVNTCOUNT_MASK; - - if (LocalCoreHandle->InterrupProcessing == TRUE) { - DEBUG ((DEBUG_INFO, "interrupProcessing.........\n")); - return EFI_SUCCESS; - } - - LocalCoreHandle->InterrupProcessing = TRUE; - - ProcessedEventCount = 0; - currentEventAddr = (UINT32)(UINTN)(LocalCoreHandle->CurrentEventBuffer); - - if (LocalCoreHandle->CurrentEventBuffer->Event & DWC_XDCI_EVENT_DEV_MASK) { - DwcXdciProcessDeviceEvent ( - LocalCoreHandle, - LocalCoreHandle->CurrentEventBuffer, - &ProcessedEventSize - ); - } else { - DwcXdciProcessEpEvent ( - LocalCoreHandle, - LocalCoreHandle->CurrentEventBuffer, - &ProcessedEventSize); - } - - eventCount -= ProcessedEventSize; - ProcessedEventCount += ProcessedEventSize; - if ((currentEventAddr + ProcessedEventSize) >= - ((UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers) + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)) - ) { - currentEventAddr = (UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers); - DEBUG ((DEBUG_INFO, "DwcXdciProcessInterruptLineEvents: Event Buffer bound reached\n")); - } else { - currentEventAddr += ProcessedEventSize; - } - - LocalCoreHandle->CurrentEventBuffer = (DWC_XDCI_EVENT_BUFFER *)(UINTN)currentEventAddr; - UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0), ProcessedEventCount); - LocalCoreHandle->InterrupProcessing = FALSE; - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to enable xDCI to connect to the host - @CoreHandle: xDCI controller handle - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreConnect ( - IN VOID *CoreHandle - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - UINT32 BaseAddr; - - EFI_STATUS ret = EFI_DEVICE_ERROR; - if (CoreHandle == NULL) { - efi_perror (ret, L"DwcXdciCoreConnect: INVALID handle\n"); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // Clear KeepConnect bit so we can allow disconnect and re-connect - // Also issue No action on state change to aVOID any link change - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - (UsbRegRead(BaseAddr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & ~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK - ); - - // - // Set Run bit to connect to the host - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_RUN_STOP_MASK - ); - - // Wait until core starts running - do { - if (!(UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK)) { - break; - } else { - efi_perror (ret, L"Stall for core run"); - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to disconnect xDCI from the host - @CoreHandle: xDCI controller handle - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreDisconnect ( - IN VOID *CoreHandle - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - UINT32 BaseAddr; - UINT32 eventCount; - UINT32 dsts; - UINT32 i; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0)); - eventCount &= DWC_XDCI_EVNTCOUNT_MASK; - - DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: eventCount=%d\n", eventCount)); - while (eventCount) { - DwcXdciCoreIsrRoutine(LocalCoreHandle); - eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0)); - eventCount &= DWC_XDCI_EVNTCOUNT_MASK; - DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: eventCount=%d\n", eventCount)); - } - - // - // Issue DEPENDXFER for active transfers - // - for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++){ - if (LocalCoreHandle->EpHandles[i].CurrentXferRscIdx){ - DwcXdciEndXfer(LocalCoreHandle, i); - } - } - // - // Clear Run bit to disconnect from host - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead(BaseAddr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_RUN_STOP_MASK); - - // - // Wait until core is halted - // - do { - dsts = UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG); - DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: waiting halt: DSTS=0x%x\n", dsts)); - if ((dsts & DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK) != 0){ - break; - } else { - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: Failed to halt the device controller\n")); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to obtain current USB bus Speed - @CoreHandle: xDCI controller handle - @Speed: Address of variable to save the Speed - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreGetSpeed ( - IN VOID *CoreHandle, - IN USB_SPEED *Speed - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreGetSpeed: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (Speed == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreGetSpeed: INVALID parameter\n")); - return EFI_INVALID_PARAMETER; - } - - *Speed = UsbRegRead (LocalCoreHandle->BaseAddress, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_CONN_SPEED_MASK; - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to obtain current USB bus Speed - @CoreHandle: xDCI controller handle - @address: USB address to set (assigned by USB host) - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreSetAddress ( - IN VOID *CoreHandle, - IN UINT32 address - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreSetAddress: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - DEBUG ((DEBUG_INFO, "DwcXdciCoreSetAddress is 0x%x \n", address)); - // - // Program USB device address - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCFG_REG, - (UsbRegRead(BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DEV_ADDRESS_MASK) | (address << DWC_XDCI_DCFG_DEV_ADDRESS_BIT_POS) - ); - - LocalCoreHandle->DevState = UsbDevStateAddress; - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG))); - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DEVTEN_REG))); - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG))); - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG))); - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to set configuration - @CoreHandle: xDCI controller handle - @ConfigNum: config num to set (assigned by USB host) - -**/ -EFI_STATUS -EFIAPI -DwcXdciCoreSetConfig ( - VOID *CoreHandle, - __attribute__((unused)) UINT32 ConfigNum - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS status; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreSetConfig: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Issue DEPSTARTCFG command on EP0 (new config for - // non-control EPs) - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_START_NEW_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreSetConfig: Failed to init params for EPCMD_START_NEW_CONFIG command\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - (EPCMD_START_NEW_CONFIG | (2 << DWC_XDCI_EPCMD_RES_IDX_BIT_POS)), - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreSetConfig: Failed to issue EPCMD_START_NEW_CONFIG command\n")); - return status; - } - - return status; -} - - -/** - Interface: - This function is used to set link state - @CoreHandle: xDCI controller handle - @state: Desired link state - -**/ -EFI_STATUS -EFIAPI -DwcXdciSetLinkState ( - IN VOID *CoreHandle, - IN USB_DEVICE_SS_LINK_STATE state - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciSetLinkState: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // Clear old mask - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK - ); - - // - // Request new state - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | (state << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS) - ); - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to initialize endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - to be initialized - -**/ -EFI_STATUS -EFIAPI -DwcXdciInitEp ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS status; - UINT32 EpNum; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciInitEp: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - - // - // Save EP properties - // - CopyMem (&(LocalCoreHandle->EpHandles[EpNum].EpInfo), EpInfo, sizeof (USB_EP_INFO)); - - // - // Init CheckFlag - // - LocalCoreHandle->EpHandles[EpNum].CheckFlag = FALSE; - - // - // Init DEPCFG cmd params for EP - // - status = DwcXdciCoreInitEpCmdParams ( - CoreHandle, - &LocalCoreHandle->EpHandles[EpNum].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to init params for EPCMD_SET_EP_CONFIG command\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - CoreHandle, - EpNum, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to issue EPCMD_SET_EP_CONFIG command\n")); - return status; - } - - // - // Issue a DEPXFERCFG command for endpoint - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[EpNum].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - EpNum, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command\n")); - } - - return status; -} - - -/** - Interface: - This function is used to enable non-Ep0 endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - to be enabled - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpEnable ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 EpNum; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpEnable: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - - // - // Enable Physical Endpoint EpNum - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EP_DALEPENA_REG, - UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << EpNum) - ); - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to disable non-Ep0 endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - to be enabled - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpDisable ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 EpNum; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpDisable: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - - // - // Disable Physical Endpoint EpNum - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EP_DALEPENA_REG, - UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) & ~(1 << EpNum) - ); - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to STALL and endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - to be enabled - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpStall ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS status; - UINT32 EpNum; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpStall: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - - // - // Set Ep State Info - // - if (LocalCoreHandle->EpHandles[EpNum].State != USB_EP_STATE_STALLED) { - LocalCoreHandle->EpHandles[EpNum].OrgState = LocalCoreHandle->EpHandles[EpNum].State; - LocalCoreHandle->EpHandles[EpNum].State = USB_EP_STATE_STALLED; - } - // - // Issue a DWC_XDCI_EPCMD_SET_STALL for EP - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - EpNum, - DWC_XDCI_EPCMD_SET_STALL, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpStall: Failed to issue EP stall command\n")); - } - - return status; -} - - -/** - Interface: - This function is used to clear endpoint STALL - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - to be enabled - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpClearStall ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS status; - UINT32 EpNum; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpClearStall: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - - // - // Set Ep State Info - // - LocalCoreHandle->EpHandles[EpNum].State = LocalCoreHandle->EpHandles[EpNum].OrgState; - - // - // Issue a DWC_XDCI_EPCMD_CLEAR_STALL for EP - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - EpNum, - DWC_XDCI_EPCMD_CLEAR_STALL, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpStall: Failed to issue EP clea stall command\n")); - } - - return status; -} - - -/** - Interface: - This function is used to set endpoint in NOT READY state - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - to be enabled - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpSetNrdy ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - UINT32 EpNum; - UINT32 BaseAddr; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpSetNrdy: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - - // - // Program the EP number in command's param reg - // - UsbRegWrite (BaseAddr, DWC_XDCI_DGCMD_PARAM_REG, EpNum); - - // - // Issue EP not ready generic device command - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DGCMD_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SET_EP_NRDY) - ); - - // - // Activate the command - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DGCMD_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) - ); - - // - // Wait until command completes - // - do { - if (!(UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) - break; - else - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - - -/** - Interface: - This function is used to queue receive SETUP packet request - @CoreHandle: xDCI controller handle - @Buffer: Address of Buffer to receive SETUP packet - -**/ -EFI_STATUS -EFIAPI -DwcXdciEp0ReceiveSetupPkt ( - IN VOID *CoreHandle, - IN UINT8 *Buffer - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS Status = EFI_DEVICE_ERROR; - DWC_XDCI_TRB *Trb; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveSetupPkt: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - LocalCoreHandle->EpHandles[0].EpInfo.EpNum = 0; - LocalCoreHandle->EpHandles[0].EpInfo.EpDir = 0; - LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_SETUP; - Trb = LocalCoreHandle->Trbs; - DEBUG ((DEBUG_INFO, "(DwcXdciEp0ReceiveSetupPkt)\n")); - - Status = DwcXdciCoreInitTrb ( - LocalCoreHandle, - Trb, - TRBCTL_SETUP, - Buffer, - 8 - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveSetupPkt: Init TRB Failed \n")); - return Status; - } - - // - // Issue a DEPSTRTXFER for EP0 - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Init the lower re-bits for TRB address - // - EpCmdParams.Param1 = (UINT32)(UINTN)Trb; - - // - // Issue the command - // - Status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_START_XFER, - &EpCmdParams - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "\nDwcXdciEp0ReceiveSetupPkt: Failed to issue Start Transfer command")); - } - - // - // Save new resource index for this transfer - // - LocalCoreHandle->EpHandles[0].CurrentXferRscIdx = ((UsbRegRead(LocalCoreHandle->BaseAddress, DWC_XDCI_EPCMD_REG(0)) & - DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS - ); - - return Status; -} - - -/** - Interface: - This function is used to queue receive status packet on EP0 - @CoreHandle: xDCI controller handle - -**/ -EFI_STATUS -EFIAPI -DwcXdciEp0ReceiveStatusPkt ( - IN VOID *CoreHandle - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_TRB *Trb; - DWC_XDCI_TRB_CONTROL TrbCtrl; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS Status; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveStatusPkt: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // We are receiving on EP0 so physical EP is 0 - // - Trb = LocalCoreHandle->Trbs; - DEBUG ((DEBUG_INFO, "(DwcXdciEp0ReceiveStatusPkt)\n")); - if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { - DEBUG ((DEBUG_INFO, "statusPkt still not transferred.\n")); - return EFI_SUCCESS; - } - - LocalCoreHandle->EpHandles[0].EpInfo.EpNum = 0; - LocalCoreHandle->EpHandles[0].EpInfo.EpDir = 0; - - // - // OUT data phase for 3-phased control transfer - // - TrbCtrl = TRBCTL_3_PHASE; - - // - // Init TRB for the transfer - // - Status = DwcXdciCoreInitTrb ( - LocalCoreHandle, - Trb, - TrbCtrl, - LocalCoreHandle->AlignedSetupBuffer, - 0 - ); - - if (!Status) { - // - // Issue a DEPSTRTXFER for EP0 - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Init the lower bits for TRB address - // - EpCmdParams.Param1 = (UINT32)(UINTN)Trb; - - // - // Issue the command - // - Status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_START_XFER, - &EpCmdParams - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveStatusPkt: Failed to issue Start Transfer command for EP0\n")); - } - // - // Save new resource index for this transfer - // - LocalCoreHandle->EpHandles[0].CurrentXferRscIdx = ((UsbRegRead(BaseAddr, DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); - - // - // TODO: We are not using the EP state for control transfers - // right now simply because we're only supporting IN - // data phase. For the current use case, we don't - // need OUT data phase. We can add that later and we will - // add some of the state and SETUP packet awareness code - // - LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_STATUS; - } - - return Status; -} - - -/** - Interface: - This function is used to send status packet on EP0 - @CoreHandle: xDCI controller handle - -**/ -EFI_STATUS -EFIAPI -DwcXdciEp0SendStatusPkt ( - IN VOID *CoreHandle - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_TRB *Trb; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - EFI_STATUS Status; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0SendStatusPkt: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // We are sending on EP0 so physical EP is 1 - // - Trb = (LocalCoreHandle->Trbs + (1 * DWC_XDCI_TRB_NUM)); - DEBUG ((DEBUG_INFO, "(DwcXdciEp0SendStatusPkt)\n")); - - LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_STATUS; - Status = DwcXdciCoreInitTrb ( - LocalCoreHandle, - Trb, - TRBCTL_2_PHASE, - LocalCoreHandle->AlignedMiscBuffer, - 0 - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0SendStatusPkt: TRB failed during status phase\n")); - return Status; - } - - // - // Issue a DEPSTRTXFER for EP1 - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Init the lower re-bits for TRB address - // - EpCmdParams.Param1 = (UINT32)(UINTN)Trb; - - // - // Issue the command - // - Status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 1, - EPCMD_START_XFER, - &EpCmdParams - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEp0SendStatusPkt: Failed to issue Start Transfer on EP0\n")); - } - - // - // Save new resource index for this transfer - // - LocalCoreHandle->EpHandles[1].CurrentXferRscIdx = ((UsbRegRead(BaseAddr, DWC_XDCI_EPCMD_REG(1)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); - LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_STATUS; - - return Status; -} - - -/** - Interface: - This function is used to send data on non-EP0 endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - @Buffer: Buffer containing data to transmit - @size: Size of transfer (in bytes) - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpTxData ( - IN VOID *CoreHandle, - IN USB_XFER_REQUEST *XferReq - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - DWC_XDCI_TRB *Trb; - DWC_XDCI_TRB_CONTROL TrbCtrl; - EFI_STATUS Status; - UINT32 EpNum; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (XferReq == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: INVALID transfer request\n")); - return EFI_INVALID_PARAMETER; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum ( - XferReq->EpInfo.EpNum, - XferReq->EpInfo.EpDir - ); - - Trb = (LocalCoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM)); - DEBUG ((DEBUG_INFO, "(DwcXdciEpTxData)EpNum is %d\n", EpNum)); - - - if (EpNum > 1) - TrbCtrl = TRBCTL_NORMAL; - else - TrbCtrl = TRBCTL_CTRL_DATA_PHASE; - - if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { - Status = DwcXdciEndXfer (LocalCoreHandle, EpNum); - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: Failed to end previous transfer\n")); - } - - Status = DwcXdciCoreFlushEpTxFifo (LocalCoreHandle, EpNum); - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: Failed to end previous transfer\n")); - } - } - - // - // Data phase - // - CopyMem (&(LocalCoreHandle->EpHandles[EpNum].XferHandle), XferReq, sizeof (USB_XFER_REQUEST)); - LocalCoreHandle->EpHandles[EpNum].State = USB_EP_STATE_DATA; - - LocalCoreHandle->EpHandles[EpNum].Trb = Trb; - - Status = DwcXdciCoreInitTrb ( - LocalCoreHandle, - Trb, - TrbCtrl, - XferReq->XferBuffer, - XferReq->XferLen - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: TRB failed\n")); - return Status; - } - - // - // Issue a DEPSTRTXFER for EP - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Init the lower re-bits for TRB address - // - EpCmdParams.Param1 = (UINT32)(UINTN)Trb; - - // - // Issue the command - // - Status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - EpNum, - EPCMD_START_XFER, - &EpCmdParams - ); - - // - // Save new resource index for this transfer - // - LocalCoreHandle->EpHandles[EpNum].CurrentXferRscIdx = ((UsbRegRead (BaseAddr, DWC_XDCI_EPCMD_REG(EpNum)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); - - return Status; -} - - -/** - Interface: - This function is used to receive data on non-EP0 endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - @Buffer: Buffer containing data to transmit - @size: Size of transfer (in bytes) - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpRxData ( - IN VOID *CoreHandle, - IN USB_XFER_REQUEST *XferReq - ) -{ - XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - DWC_XDCI_TRB *Trb; - DWC_XDCI_TRB_CONTROL TrbCtrl; - EFI_STATUS Status; - UINT32 EpNum; - UINT32 BaseAddr; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - if (XferReq == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: INVALID transfer request\n")); - return EFI_INVALID_PARAMETER; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - // - // Convert to physical endpoint - // - EpNum = DwcXdciGetPhysicalEpNum (XferReq->EpInfo.EpNum, XferReq->EpInfo.EpDir); - - Trb = (LocalCoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM)); - DEBUG ((DEBUG_INFO, "(DwcXdciEpRxData)EpNum is %d\n", EpNum)); - - if (EpNum > 1) - TrbCtrl = TRBCTL_NORMAL; - else - TrbCtrl = TRBCTL_CTRL_DATA_PHASE; - - // - // If CheckFlag didn't set to FALSE, means the previous transfer request didn't complete, - // need to wait the previous request done. - // - if (LocalCoreHandle->EpHandles[EpNum].CheckFlag == TRUE) { - return EFI_NOT_READY; - } - - LocalCoreHandle->EpHandles[EpNum].CheckFlag = TRUE; - - // - // Data phase - // - CopyMem (&(LocalCoreHandle->EpHandles[EpNum].XferHandle), XferReq, sizeof (USB_XFER_REQUEST)); - - LocalCoreHandle->EpHandles[EpNum].State = USB_EP_STATE_DATA; - - LocalCoreHandle->EpHandles[EpNum].Trb = Trb; - - DEBUG ((DEBUG_INFO, "(DwcXdciEpRxData)XferReq->XferLen is 0x%x\n", XferReq->XferLen)); - - Status = DwcXdciCoreInitTrb ( - LocalCoreHandle, - Trb, - TrbCtrl, - XferReq->XferBuffer, - XferReq->XferLen - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: TRB failed\n")); - return Status; - } - // - // Issue a DEPSTRTXFER for EP - // Reset params - // - EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; - - // - // Init the lower re-bits for TRB address - // - EpCmdParams.Param1 = (UINT32)(UINTN)Trb; - - // - // Issue the command - // - Status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - EpNum, - EPCMD_START_XFER, - &EpCmdParams - ); - - if (Status) { - DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: Failed to start transfer\n")); - } - - // - // Save new resource index for this transfer - // - LocalCoreHandle->EpHandles[EpNum].CurrentXferRscIdx = ((UsbRegRead(BaseAddr, DWC_XDCI_EPCMD_REG(EpNum)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); - - return Status; -} - - - -STATIC -EFI_STATUS -DwcXdciCoreFlushEpFifo ( - IN XDCI_CORE_HANDLE *CoreHandle, - IN UINT32 EpNum - ) -{ - UINT32 BaseAddr; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - UINT32 fifoNum; - UINT32 Param; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreFlushEpTxFifo: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - BaseAddr = CoreHandle->BaseAddress; - - // - // Translate to FIFOnum - // NOTE: Assuming this is a Tx EP - // - fifoNum = (EpNum >> 1); - - // - // TODO: Currently we are only using TxFIFO 0. Later map these - // Write the FIFO num/dir param for the generic command. - // - - Param = UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_PARAM_REG); - Param &= ~(DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK); - - if ((EpNum & 0x01) != 0) { - Param |= (fifoNum | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK); - } else { - Param |= fifoNum; - } - - DEBUG ((DEBUG_INFO, "USB FU Flash: CMD 0x%08x :: Param 0x%08x\n", - (UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK), - Param)); - - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DGCMD_PARAM_REG, - Param - ); - - // - // Write the command to flush all FIFOs - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DGCMD_REG, - (UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) - ); - - - // - // Wait until command completes - // - do { - if (!(UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) - break; - else - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - -/** - Interface: - This function is used to cancel a transfer on non-EP0 endpoint - @CoreHandle: xDCI controller handle - @EpInfo: Address of structure describing properties of EP - -**/ -EFI_STATUS -EFIAPI -DwcXdciEpCancelTransfer ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - UINT32 EpNum; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpCancelTransfer: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Get physical EP num - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - Status = DwcXdciEndXfer(CoreHandle, EpNum); - DwcXdciCoreFlushEpFifo(CoreHandle, EpNum); - - return Status; -} - - -EFI_STATUS -usbProcessDeviceResetDet ( - IN XDCI_CORE_HANDLE *CoreHandle - ) -{ - return DwcXdciProcessDeviceResetDet (CoreHandle); -} - -EFI_STATUS -usbProcessDeviceResetDone ( - IN XDCI_CORE_HANDLE *CoreHandle - ) -{ - return DwcXdciProcessDeviceResetDone (CoreHandle); -} - -UINT32 -UsbGetPhysicalEpNum ( - IN UINT32 EndpointNum, - IN USB_EP_DIR EndpointDir - ) -{ - return DwcXdciGetPhysicalEpNum( - EndpointNum, - EndpointDir - ); -} - - -EFI_STATUS -EFIAPI -UsbXdciCoreReinit ( - IN VOID *CoreHandle - ) -{ - EFI_STATUS status = EFI_DEVICE_ERROR; - UINT32 BaseAddr; - XDCI_CORE_HANDLE *LocalCoreHandle; - DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; - UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; - UINT8 i; - - LocalCoreHandle = CoreHandle; - - if (CoreHandle == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (LocalCoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to allocate handle for xDCI\n")); - return EFI_OUT_OF_RESOURCES; - } - - BaseAddr = LocalCoreHandle->BaseAddress; - - DEBUG ((DEBUG_INFO, "Resetting the USB core\n")); - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_CSFTRST_MASK - ); - - // - // Wait until core soft reset completes - // - do { - if (!(UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & DWC_XDCI_DCTL_CSFTRST_MASK)) { - break; - } else { - uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); - } - } while (--MaxDelayIter); - - if (!MaxDelayIter) { - DEBUG ((DEBUG_INFO, "Failed to reset device controller\n")); - return EFI_DEVICE_ERROR; - } - - DEBUG ((DEBUG_INFO, "USB core has been reset\n")); - - LocalCoreHandle->DevState = UsbDevStateDefault; - - // - // Clear KeepConnect bit so we can allow disconnect and - // re-connect. Stay in RX_DETECT state - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCTL_REG, - UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & - (~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & - ((~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK) | - (DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS)) - ); - - DEBUG ((DEBUG_INFO, "Device controller Synopsys ID: %x\n", UsbRegRead (BaseAddr, DWC_XDCI_GSNPSID_REG))); - DEBUG ((DEBUG_INFO, "Default value of xDCI GSBUSCFG0 and GSBUSCFG1: %x, %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG0_REG), - UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG1_REG))); - - DEBUG ((DEBUG_INFO, "Default value of xDCI GTXTHRCFG and GRXTHRCFG: %x, %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GTXTHRCFG_REG), - UsbRegRead (BaseAddr, DWC_XDCI_GRXTHRCFG_REG))); - - // - // Clear ULPI auto-resume bit - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB2PHYCFG_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)) & ~DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK) - ); - - DEBUG ((DEBUG_INFO, "Default value of xDCI GUSB2PHYCFG and GUSB3PIPECTL: %x, %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)), - UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG (0)))); - - // - // Only one RxFIFO - // - DEBUG ((DEBUG_INFO, "Default value of DWC_XDCI_GRXFIFOSIZ: %x\n", - UsbRegRead (BaseAddr, DWC_XDCI_GRXFIFOSIZ_REG (0)))); - - for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++) { - DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_GTXFIFOSIZ %d: %x\n", - i, UsbRegRead (BaseAddr, DWC_XDCI_GTXFIFOSIZ_REG (i)))); - } - - // - // TODO: Need to check if TxFIFO should start where RxFIFO ends - // or default is correct i.e. TxFIFO starts at 0 just like RxFIFO - // - - // - // Allocate and Initialize Event Buffers - // - LocalCoreHandle->MaxDevIntLines = ((UsbRegRead (BaseAddr, DWC_XDCI_GHWPARAMS1_REG) & - DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >> - DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS); - - DEBUG ((DEBUG_INFO, "Max dev int lines: %d\n", LocalCoreHandle->MaxDevIntLines)); - // - // One event Buffer per interrupt line. - // Need to align it to size of event Buffer - // Buffer needs to be big enough. Otherwise the core - // won't operate - // - LocalCoreHandle->AlignedEventBuffers = (DWC_XDCI_EVENT_BUFFER *) - ((UINT32)(UINTN)(LocalCoreHandle->EventBuffers) + - ((sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - - (((UINT32)(UINTN)(LocalCoreHandle->EventBuffers)) % - (sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)))); - - for (i = 0; i < LocalCoreHandle->MaxDevIntLines; i++) { - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GEVNTADR_REG (i), - (UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers + i * sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - ); - - // - // Clear High 32bit address register, GEVNTADR register is 64-bit register - // default is 0xffffffffffffffff - // - UsbRegWrite (BaseAddr, DWC_XDCI_GEVNTADR_REG (i) + 4, 0x00000000); - - LocalCoreHandle->CurrentEventBuffer = LocalCoreHandle->AlignedEventBuffers; - // - // Write size and clear the mask - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EVNTSIZ_REG (i), - sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER - ); - - // - // Write 0 to the event count register as the last step - // for event configuration - // - UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i), 0); - - DEBUG ((DEBUG_INFO, "Value of xDCI Event Buffer %d: %x, Size: %x, Count: %x\n", - i, - UsbRegRead (BaseAddr, DWC_XDCI_GEVNTADR_REG (i)), - UsbRegRead (BaseAddr, DWC_XDCI_EVNTSIZ_REG (i)), - UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i)))); - } - - // - // Program Global Control Register to disable scaledown, - // disable clock gating - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GCTL_REG, - ((UsbRegRead(BaseAddr, DWC_XDCI_GCTL_REG) & - ~(DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK + DWC_XDCI_GCTL_RAMCLKSEL_MASK + DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK)) | - DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK | - (DWC_XDCI_GCTL_PRT_CAP_DEVICE << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS))); - - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG))); - - - // - // TODO: Program desired Speed and set LPM capable - // We will do this when SuperSpeed works. For now, - // force into High-Speed mode to aVOID anyone trying this - // on Super Speed port - // -#if 1 - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCFG_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | LocalCoreHandle->DesiredSpeed - ); -#else - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DCFG_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | DWC_XDCI_DCFG_DESIRED_HS_SPEED - ); -#endif - - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG))); - DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG))); - - // - // Enable Device Interrupt Events - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_DEVTEN_REG, - DWC_XDCI_DEVTEN_DEVICE_INTS - ); - - // - // Program the desired role - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GCTL_REG, - (UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG) & ~DWC_XDCI_GCTL_PRT_CAP_DIR_MASK) | (LocalCoreHandle->Role << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS) - ); - - // - // Clear USB2 suspend for start new config command - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB2PHYCFG_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) - ); - // - // Clear USB3 suspend for start new config command - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_GUSB3PIPECTL_REG (0), - (UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) - ); - // - // Issue DEPSTARTCFG command for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_START_NEW_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for START_NEW_CONFIG EP command on xDCI\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_START_NEW_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue START_NEW_CONFIG EP command on xDCI\n")); - return status; - } - - // - // Issue DEPCFG command for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP0\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_SET_EP_CONFIG, - &EpCmdParams); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP0\n")); - return status; - } - - // - // Issue DEPCFG command for EP1 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[1].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP1\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 1, - EPCMD_SET_EP_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP1\n")); - return status; - } - - // - // Issue DEPXFERCFG command for EP0 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[0].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 0, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); - return status; - } - - // - // Issue DEPXFERCFG command for EP1 - // - status = DwcXdciCoreInitEpCmdParams ( - LocalCoreHandle, - &LocalCoreHandle->EpHandles[1].EpInfo, - DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); - return status; - } - - // - // Issue the command - // - status = DwcXdciCoreIssueEpCmd ( - LocalCoreHandle, - 1, - EPCMD_SET_EP_XFER_RES_CONFIG, - &EpCmdParams - ); - - if (status) { - DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); - return status; - } - - // - // Prepare a Buffer for SETUP packet - // - LocalCoreHandle->Trbs = (DWC_XDCI_TRB *)(UINTN)((UINT32)(UINTN) - LocalCoreHandle->UnalignedTrbs + - (DWC_XDCI_TRB_BYTE_ALIGNMENT - - ((UINT32)(UINTN)LocalCoreHandle->UnalignedTrbs % - DWC_XDCI_TRB_BYTE_ALIGNMENT))); - - DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ unalignedTrbs address is 0x%x\n", LocalCoreHandle->UnalignedTrbs)); - DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ TRB address is 0x%x\n", LocalCoreHandle->Trbs)); - - // - // Allocate Setup Buffer that is 8-byte aligned - // - LocalCoreHandle->AlignedSetupBuffer = LocalCoreHandle->DefaultSetupBuffer + - (DWC_XDCI_SETUP_BUFF_SIZE - - ((UINT32)(UINTN)(LocalCoreHandle->DefaultSetupBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); - - // - // Aligned Buffer for status phase - // - LocalCoreHandle->AlignedMiscBuffer = LocalCoreHandle->MiscBuffer + - (DWC_XDCI_SETUP_BUFF_SIZE - - ((UINT32)(UINTN)(LocalCoreHandle->AlignedMiscBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); - - // - // We will queue SETUP request when we see bus reset - // - - // - // Enable Physical Endpoints 0 - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EP_DALEPENA_REG, - UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 0) - ); - - // - // Enable Physical Endpoints 1 - // - UsbRegWrite ( - BaseAddr, - DWC_XDCI_EP_DALEPENA_REG, - UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 1) - ); - - DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DEVTEN_REG))); - return status; - - -} - - -EFI_STATUS -UsbXdciCoreFlushEpFifo ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ) -{ - EFI_STATUS Status = EFI_DEVICE_ERROR; - UINT32 EpNum; - - if (CoreHandle == NULL) { - DEBUG ((DEBUG_INFO, "DwcXdciEpCancelTransfer: INVALID handle\n")); - return EFI_DEVICE_ERROR; - } - - // - // Get physical EP num - // - EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); - DwcXdciCoreFlushEpFifo(CoreHandle, EpNum); - - return Status; -} +/** @file + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include +#include +#include +#include + +#include "UsbDeviceDxe.h" +#include "XdciInterface.h" +#include "XdciDWC.h" + +UINT32 +UsbRegRead ( + IN UINTN Base, + IN UINT32 Offset + ) +{ + volatile UINT32 *addr = (volatile UINT32 *)(UINTN)(Base + Offset); + return *addr; +} + +VOID +UsbRegWrite ( + IN UINTN Base, + IN UINT32 Offset, + IN UINT32 val + ) +{ + volatile UINT32 *addr = (volatile UINT32 *)(UINTN)(Base + Offset); + *addr = val; +} + + +/** + Internal utility function: + This function is used to obtain physical endpoint number + xDCI needs physical endpoint number for EP registers + We also use it to index into our EP array + Note: Certain data structures/commands use logical EP numbers + as opposed to physical endpoint numbers so one should be + careful when interpreting EP numbers + @EpNum: Logical endpoint number + @epDir: Direction for the endpoint + +**/ +STATIC +UINT32 +DwcXdciGetPhysicalEpNum ( + IN UINT32 EndpointNum, + IN USB_EP_DIR EndpointDir + ) +{ + return EndpointDir? ((EndpointNum << 1) | EndpointDir) : (EndpointNum << 1); +} + + +/** + Internal utility function: + This function is used to obtain the MPS for control transfers + Based on the Speed. If this is called before bus reset completes + then it returns MPS Based on desired Speed. If it is after bus + reset then MPS returned is Based on actual negotiated Speed + @CoreHandle: xDCI controller handle address + @mps: address of 32-bit variable to return the MPS + +**/ +STATIC +EFI_STATUS +DwcXdciCoreGetCtrlMps ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 *mps + ) +{ + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreGetCtrlMps: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (mps == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreGetCtrlMps: INVALID parameter\n")); + return EFI_INVALID_PARAMETER; + } + + switch (CoreHandle->ActualSpeed) { + case USB_SPEED_HIGH: + *mps = DWC_XDCI_HS_CTRL_EP_MPS; + break; + case USB_SPEED_FULL: + *mps = DWC_XDCI_FS_CTRL_EP_MPS; + break; + case USB_SPEED_LOW: + *mps = DWC_XDCI_LS_CTRL_EP_MPS; + break; + case USB_SPEED_SUPER: + *mps = DWC_XDCI_SS_CTRL_EP_MPS; + break; + default: + *mps = 0; + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreGetCtrlMps: UNKNOWN Speed\n")); + break; + } + + return EFI_SUCCESS; +} + + +/** + Internal utility function: + This function is used to initialize the parameters required + for executing endpoint command + @CoreHandle: xDCI controller handle address + @EpInfo: EP info address + @ConfigAction: Configuration action specific to EP command + @EpCmd: xDCI EP command for which parameters are initialized + @EpCmdParams: address of struct to return EP params + +**/ +STATIC +EFI_STATUS +DwcXdciCoreInitEpCmdParams ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN USB_EP_INFO *EpInfo, + IN UINT32 ConfigAction, + IN DWC_XDCI_ENDPOINT_CMD EpCmd, + IN DWC_XDCI_ENDPOINT_CMD_PARAMS *EpCmdParams + ) +{ + EFI_STATUS status = EFI_SUCCESS; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreInitEpCmdParams: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Reset params + // + EpCmdParams->Param0 = EpCmdParams->Param1 = EpCmdParams->Param2 = 0; + + switch (EpCmd) { + case EPCMD_SET_EP_CONFIG: + // + // Issue DEPCFG command for EP + // Issue a DEPCFG (Command 1) command for endpoint + // + if (EpInfo->MaxStreams) { + EpCmdParams->Param1 = DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK; + } + + if (EpInfo->Interval) { + EpCmdParams->Param1 |= ((EpInfo->Interval-1) << DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS); + } + + // + // Set EP num + // + EpCmdParams->Param1 |= (EpInfo->EpNum << DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_BIT_POS); + // + // Set EP direction + // + EpCmdParams->Param1 |= (EpInfo->EpDir << DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_BIT_POS); + // + // Set EP-specific Event enable for not ready and + // complete events + // + EpCmdParams->Param1 &= ~DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK; + // + // Setup the events we want enabled for this EP + // + EpCmdParams->Param1 |= (DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK | + DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK | + DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK); + + // + // We only have one interrupt line for this core. + // Set interrupt number to 0 + // + EpCmdParams->Param1 &= ~DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK; + + // + // Set FIFOnum = 0 for control EP0 + // + EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_MASK; + + // + // Program FIFOnum for non-EP0 EPs + // + if (EpInfo->EpNum && EpInfo->EpDir) { + EpCmdParams->Param0 |= (EpInfo->EpNum << DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_BIT_POS); + } + + // + // Program max packet size + // + EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_MPS_MASK; + EpCmdParams->Param0 |= (EpInfo->MaxPktSize << DWC_XDCI_PARAM0_SET_EP_CFG_MPS_BIT_POS); + + // + // Set Burst size. 0 means burst size of 1 + // + EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_MASK; + EpCmdParams->Param0 |= (EpInfo->BurstSize << DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_BIT_POS); + + // + // Set EP type + // + EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_MASK; + EpCmdParams->Param0 |= (EpInfo->EpType << DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_BIT_POS); + + // + // Set config action + // + EpCmdParams->Param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MASK; + EpCmdParams->Param0 |= (ConfigAction << DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_BIT_POS); + break; + + case EPCMD_SET_EP_XFER_RES_CONFIG: + // Set Param0 to 1. Same for all EPs when resource + // configuration is done + // + EpCmdParams->Param0 = 1; + break; + + case EPCMD_END_XFER: + // + // Nothing to set. Already reset params for all cmds + // + break; + + case EPCMD_START_NEW_CONFIG: + // + // Nothing to set. Already reset params for all cmds + // + break; + + default: + status = EFI_INVALID_PARAMETER; + DEBUG ((DEBUG_INFO, "\nDwcXdciCoreInitEpCmdParams: INVALID Parameter")); + break; + } + + return status; +} + + +/** + Internal utility function: + This function is used to issue the xDCI endpoint command + @CoreHandle: xDCI controller handle address + @EpNum: Physical EP num + @EpCmd: xDCI EP command + @EpCmdParams: EP command parameters address + +**/ +STATIC +EFI_STATUS +DwcXdciCoreIssueEpCmd ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum, + IN UINT32 EpCmd, + IN DWC_XDCI_ENDPOINT_CMD_PARAMS *EpCmdParams + ) +{ + UINTN BaseAddr; + UINT32 MaxDelayIter = 5000;//DWC_XDCI_MAX_DELAY_ITERATIONS; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreIssueEpCmd: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = CoreHandle->BaseAddress; + + // + // Set EP command parameter values + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EPCMD_PARAM2_REG(EpNum), + EpCmdParams->Param2 + ); + + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EPCMD_PARAM1_REG(EpNum), + EpCmdParams->Param1 + ); + + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EPCMD_PARAM0_REG(EpNum), + EpCmdParams->Param0 + ); + + // + // Set the command code and activate it + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EPCMD_REG(EpNum), + EpCmd | DWC_XDCI_EPCMD_CMD_ACTIVE_MASK + ); + + // + // Wait until command completes + // + do { + if (!(UsbRegRead (BaseAddr, DWC_XDCI_EPCMD_REG(EpNum)) & DWC_XDCI_EPCMD_CMD_ACTIVE_MASK)) + break; + else + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreIssueEpCmd. ERROR: Failed to issue Command\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Internal utility function: + This function is used to flush all FIFOs + @CoreHandle: xDCI controller handle address + +**/ +STATIC +EFI_STATUS +DwcXdciCoreFlushAllFifos ( + IN XDCI_CORE_HANDLE *CoreHandle + ) +{ + UINTN BaseAddr; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreFlushAllFifos: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = CoreHandle->BaseAddress; + + // + // Write the command to flush all FIFOs + // + UsbRegWrite( + BaseAddr, + DWC_XDCI_DGCMD_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_ALL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) + ); + + // + // Wait until command completes + // + do { + if (!(UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) + break; + else + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Internal utility function: + This function is used to flush Tx FIFO specific to an endpoint + @CoreHandle: xDCI controller handle address + @EpNum: Physical EP num + +**/ +STATIC +EFI_STATUS +DwcXdciCoreFlushEpTxFifo ( + XDCI_CORE_HANDLE *CoreHandle, + __attribute__((unused)) UINT32 EpNum + ) +{ + UINTN BaseAddr; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreFlushEpTxFifo: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = CoreHandle->BaseAddress; + // + // TODO: Currently we are only using TxFIFO 0. Later map these + // Write the FIFO num/dir param for the generic command. + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DGCMD_PARAM_REG, + ((UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_PARAM_REG) & ~DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK) | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK) + ); + + // + // Write the command to flush all FIFOs + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DGCMD_REG, + (UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) + ); + + + // + // Wait until command completes + // + do { + if (!(UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) + break; + else + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + + +STATIC +EFI_STATUS +DwcXdciCorePrepareOneTrb ( + IN DWC_XDCI_TRB *Trb, + IN DWC_XDCI_TRB_CONTROL TrbCtrl, + IN UINT32 LastBit, + IN UINT32 ChainBit, + IN UINT8 *BufferPtr, + IN UINT32 size + ) +{ + DEBUG ((DEBUG_INFO, "Trb is 0x%x, BufferPtr is 0x%x, size is 0x%x\n", Trb, BufferPtr, size)); + + Trb->BuffPtrLow = (UINT32)(UINTN)BufferPtr; + Trb->BuffPtrHigh = 0; + Trb->LenXferParams = size; + Trb->TrbCtrl = TrbCtrl << DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; + + if (ChainBit) + Trb->TrbCtrl |= ChainBit << DWC_XDCI_TRB_CTRL_CHAIN_BUFF_BIT_POS; + + if (LastBit) + Trb->TrbCtrl |= LastBit << DWC_XDCI_TRB_CTRL_LST_TRB_BIT_POS; + + Trb->TrbCtrl |= DWC_XDCI_TRB_CTRL_IOSP_MISOCH_MASK| DWC_XDCI_TRB_CTRL_HWO_MASK; + + DEBUG ((DEBUG_INFO, "(DwcXdciCorePrepareOneTrb) Trb->BuffPtrLow = 0x%x, Trb->LenXferParams is 0x%x, Trb->TrbCtrl is 0x%x\n", + Trb->BuffPtrLow, Trb->LenXferParams, Trb->TrbCtrl)); + return EFI_SUCCESS; +} + + +/** + Internal utility function: + This function is used to initialize transfer request block + @CoreHandle: xDCI controller handle address + @Trb: Address of TRB to initialize + @TrbCtrl: TRB control value + @buffPtr: Transfer Buffer address + @size: Size of the transfer + +**/ +STATIC +EFI_STATUS +DwcXdciCoreInitTrb ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN DWC_XDCI_TRB *Trb, + IN DWC_XDCI_TRB_CONTROL TrbCtrl, + IN UINT8 *BufferPtr, + IN UINT32 size + ) +{ +#define ONE_TRB_SIZE (DWC_XDCI_TRB_BUFF_SIZE_MASK & 0x00F00000) + UINT8 *TrbBuffer; + UINT32 TrbCtrlLast; + UINT32 TrbCtrlChain; + UINT32 TrbIndex; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreInitTrb: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (Trb == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreInitTrb: INVALID handle\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Init TRB fields + // NOTE: Assuming we are only using 32-bit addresses + // TODO: update for 64-bit addresses + // + if (size <= DWC_XDCI_TRB_BUFF_SIZE_MASK) { + // + // Can transfer in one TRB + // + TrbCtrlChain = 0; + TrbCtrlLast = 1; + DwcXdciCorePrepareOneTrb (Trb, TrbCtrl, TrbCtrlLast, TrbCtrlChain, BufferPtr, size); + return EFI_SUCCESS; + } + + // + // Can't transfer in one TRB. + // Seperate it in every ONE_TRB_SIZE of TRB + // + TrbBuffer = BufferPtr; + TrbIndex = 0; + while (size > ONE_TRB_SIZE) { + TrbCtrlChain = 1; + TrbCtrlLast = 0; + DwcXdciCorePrepareOneTrb (Trb, TrbCtrl, TrbCtrlLast, TrbCtrlChain, TrbBuffer, ONE_TRB_SIZE); + TrbBuffer += ONE_TRB_SIZE; + size -= ONE_TRB_SIZE; + Trb++; + TrbIndex++; + if (TrbIndex >= DWC_XDCI_TRB_NUM) + return EFI_OUT_OF_RESOURCES; + } + TrbCtrlChain = 0; + TrbCtrlLast = 1; + DwcXdciCorePrepareOneTrb (Trb, TrbCtrl, TrbCtrlLast, TrbCtrlChain, TrbBuffer, size); + + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to start a SETUP phase on control endpoint + @CoreHandle: xDCI controller handle address + +**/ +STATIC +EFI_STATUS +DwcXdciCoreStartEp0SetupXfer ( + IN XDCI_CORE_HANDLE *CoreHandle + ) +{ + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS status = EFI_DEVICE_ERROR; + DWC_XDCI_TRB *Trb; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreStartEp0SetupXfer: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (CoreHandle->EpHandles[0].State == USB_EP_STATE_SETUP) { + DEBUG ((DEBUG_INFO, "EP0 was already in SETUP phase\n")); + return EFI_SUCCESS; + } + + CoreHandle->EpHandles[0].State = USB_EP_STATE_SETUP; + Trb = CoreHandle->Trbs; + DEBUG ((DEBUG_INFO, "(DwcXdciCoreStartEp0SetupXfer)\n")); + + status = DwcXdciCoreInitTrb ( + CoreHandle, + Trb, + TRBCTL_SETUP, + CoreHandle->AlignedSetupBuffer, + 8 + ); + + if (status) + return status; + + // + // Issue a DEPSTRTXFER for EP0 + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Init the lower re-bits for TRB address + // + EpCmdParams.Param1 = (UINT32)(UINTN)Trb; + + // + // Issue the command to start transfer on physical + // endpoint 0 + // + status = DwcXdciCoreIssueEpCmd ( + CoreHandle, + 0, + EPCMD_START_XFER, + &EpCmdParams + ); + + // + // Save new resource index for this transfer + // + CoreHandle->EpHandles[0].CurrentXferRscIdx = ((UsbRegRead ( + CoreHandle->BaseAddress, + DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS + ); + + return status; +} + + +/** + Internal function: + This function is used to process the state change event + @CoreHandle: xDCI controller handle address + @event: device event dword + +**/ +STATIC +EFI_STATUS +DwcXdciProcessDeviceStateChangeEvent ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 Event + ) +{ + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessDeviceStateChangeEvent: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + CoreHandle->HirdVal = (Event & DWC_XDCI_EVENT_BUFF_DEV_HIRD_MASK) >> DWC_XDCI_EVENT_BUFF_DEV_HIRD_BIT_POS; + + CoreHandle->LinkState = ((Event & DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_MASK) >> DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_BIT_POS); + + if (CoreHandle->EventCallbacks.DevLinkStateCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.LinkState = CoreHandle->LinkState; + CoreHandle->EventCallbacks.CbEventParams.Hird = CoreHandle->HirdVal; + CoreHandle->EventCallbacks.CbEventParams.SsEvent = (Event & DWC_XDCI_EVENT_BUFF_DEV_SS_EVENT_MASK) ? 1 : 0; + CoreHandle->EventCallbacks.DevLinkStateCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to issue a command to end transfer + @CoreHandle: xDCI controller handle address + @EpNum: Physical EP num for which transfer is to be ended + +**/ +STATIC +EFI_STATUS +DwcXdciEndXfer ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum + ) +{ + EFI_STATUS status; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + UINT32 cmdParams; + DWC_XDCI_TRB *TrbPtr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciEndXfer: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + CoreHandle->EpHandles[EpNum].CheckFlag = FALSE; + + // + // Issue a DEPENDXFER for EP + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + cmdParams = ((CoreHandle->EpHandles[EpNum].CurrentXferRscIdx << DWC_XDCI_EPCMD_RES_IDX_BIT_POS) | DWC_XDCI_EPCMD_FORCE_RM_MASK); + + if (CoreHandle->EpHandles[EpNum].CurrentXferRscIdx == 0) { + return EFI_SUCCESS; + } + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd( + CoreHandle, + EpNum, + cmdParams | DWC_XDCI_EPCMD_END_XFER, + &EpCmdParams + ); + + if (!status) { + CoreHandle->EpHandles[EpNum].CurrentXferRscIdx = 0; + TrbPtr = CoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM); + ZeroMem (TrbPtr, DWC_XDCI_TRB_NUM * sizeof (DWC_XDCI_TRB)); + } + + return status; +} + + +/** + Internal function: + This function is used to process bus reset detection event + @CoreHandle: xDCI controller handle address + +**/ +STATIC +EFI_STATUS +DwcXdciProcessDeviceResetDet ( + IN XDCI_CORE_HANDLE *CoreHandle + ) +{ + EFI_STATUS status = EFI_SUCCESS; + + if (CoreHandle == NULL) { + return EFI_DEVICE_ERROR; + } + + // + // Flush all FIFOs + // + status = DwcXdciCoreFlushAllFifos(CoreHandle); + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceResetDet: Failed to flush FIFOs\n")); + } + + // + // Start SETUP phase on EP0 + // + status = DwcXdciCoreStartEp0SetupXfer(CoreHandle); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceResetDet: Failed to start SETUP phase for EP0\n")); + return status; + } + + // + // Notify upper layer if a callback is registerd for + // this event + // + if (CoreHandle->EventCallbacks.DevBusResetCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + status = CoreHandle->EventCallbacks.DevBusResetCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + return status; +} + + +/** + Internal function: + This function is used to process connection done (means reset + complete) event + @CoreHandle: xDCI controller handle address + +**/ +STATIC +EFI_STATUS +DwcXdciProcessDeviceResetDone ( + IN XDCI_CORE_HANDLE *CoreHandle + ) +{ + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + UINTN BaseAddr; + EFI_STATUS status = EFI_SUCCESS; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessDeviceResetDone: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = CoreHandle->BaseAddress; + CoreHandle->ActualSpeed = (UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_CONN_SPEED_MASK); + DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceResetDone CoreHandle->ActualSpeed is %x\n", CoreHandle->ActualSpeed)); + + // + // Program MPS Based on the negotiated Speed + // + DwcXdciCoreGetCtrlMps (CoreHandle, &CoreHandle->EpHandles[0].EpInfo.MaxPktSize); + DwcXdciCoreGetCtrlMps (CoreHandle, &CoreHandle->EpHandles[1].EpInfo.MaxPktSize); + + // + // Init DEPCFG cmd params for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + CoreHandle, + &CoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + CoreHandle, + 0, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + return status; + } + + // + // Init DEPCFG cmd params for EP1 + // + status = DwcXdciCoreInitEpCmdParams ( + CoreHandle, + &CoreHandle->EpHandles[1].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + CoreHandle, + 1, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + // + // Put the other PHY into suspend + // + if (CoreHandle->ActualSpeed == USB_SPEED_SUPER) { + // + // Put HS PHY to suspend + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB2PHYCFG_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) | DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) + ); + + // + // Clear SS PHY's suspend mask + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB3PIPECTL_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) + ); + + } else { + // + // Put SS PHY to suspend + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB3PIPECTL_REG(0), + (UsbRegRead(BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) | DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) + ); + + // + // Clear HS PHY's suspend mask + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB2PHYCFG_REG(0), + (UsbRegRead(BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) + ); + } + + // + // Notify upper layer if callback is registered + // + if (CoreHandle->EventCallbacks.DevResetDoneCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.Speed = CoreHandle->ActualSpeed; + CoreHandle->EventCallbacks.DevResetDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + return status; +} + + +/** + Internal function: + This function is used to process device event + @CoreHandle: xDCI controller handle address + @IntLineEventBuffer: event Buffer pointing to device event + @ProcessedEventSize: address of variable to save the size of + the event that was Processed + +**/ +STATIC +EFI_STATUS +DwcXdciProcessDeviceEvent ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN DWC_XDCI_EVENT_BUFFER *IntLineEventBuffer, + IN UINT32 *ProcessedEventSize + ) +{ + UINT32 event; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessDeviceEvent: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Extract device event + // + event = (IntLineEventBuffer->Event & DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK); + event >>= DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS; + + // + // Assume default event size. Change it in switch case if + // different + // + *ProcessedEventSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; + + switch (event) { + case DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT\n")); + DwcXdciProcessDeviceResetDet (CoreHandle); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT\n")); + DwcXdciProcessDeviceResetDone (CoreHandle); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT\n")); + DwcXdciProcessDeviceStateChangeEvent (CoreHandle, IntLineEventBuffer->Event); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT: + DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT\n")); + *ProcessedEventSize = DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES; + break; + + default: + DEBUG ((DEBUG_INFO, "DwcXdciProcessDeviceEvent: UNHANDLED device event: %x\n", event)); + break; + } + + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to process EP not ready for + non-control endpoints + @CoreHandle: xDCI controller handle address + @EpNum: Physical endpoint number + +**/ +STATIC +EFI_STATUS +DwcXdciProcessEpXferNotReady ( + __attribute__((unused)) XDCI_CORE_HANDLE *CoreHandle, + __attribute__((unused)) UINT32 EpNum + ) +{ + // + // TODO: Not doing on-demand transfers + // Revisit if required for later use + // + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to process EP not ready for + control endpoints + @CoreHandle: xDCI controller handle address + @EpNum: Physical endpoint number + @dataStage: EP not ready when data stage token was received + @statusStage: EP not ready when status stage token was received + +**/ +STATIC +EFI_STATUS +DwcXdciProcessEp0XferNotReady ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum, + IN UINT32 epEventStatus + ) +{ + USB_EP_STATE epState = USB_EP_STATE_SETUP; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEp0XferNotReady: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + // + // Is it data stage or status stage + // + if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_DATA_REQ_MASK) { + epState = USB_EP_STATE_DATA; + } else if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK) { + epState = USB_EP_STATE_STATUS; + } + + if ((EpNum == 0) && (epState == USB_EP_STATE_STATUS)) { + if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_XFER_ACTIVE_MASK) { + DEBUG ((DEBUG_INFO, "XFER_ACTIVE\n")); + } else { + DEBUG ((DEBUG_INFO, "XFER_NOT_ACTIVE\n")); + } + DwcXdciEp0ReceiveStatusPkt (CoreHandle); + } + + // + // Notify upper layer if a callback is registered for + // this event + // + if (CoreHandle->EventCallbacks.DevXferNrdyCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.EpState = epState; + CoreHandle->EventCallbacks.DevXferNrdyCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to process transfer phone done for EP0 + @CoreHandle: xDCI controller handle address + @EpNum: Physical endpoint number (0 for OUT and 1 for IN) + +**/ +STATIC +EFI_STATUS +DwcXdciProcessEp0XferPhaseDone ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum + ) +{ + DWC_XDCI_ENDPOINT *epHandle; + DWC_XDCI_TRB *Trb; + EFI_STATUS status = EFI_SUCCESS; + UINT32 TrbSts; + UINT32 TrbCtrl; + UINT32 TrbBufsize; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEp0XferPhaseDone: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + epHandle = &CoreHandle->EpHandles[EpNum]; + Trb = CoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM); + DEBUG ((DEBUG_INFO, "(DwcXdciProcessEp0XferPhaseDone)EpNum is %d\n", EpNum)); + + if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { + DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone. HW owns TRB: %x!!!\n", (UINT32)(UINTN)Trb)); + } + + epHandle->CurrentXferRscIdx = 0; + epHandle->State = USB_EP_STATE_ENABLED; + TrbCtrl = (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_TYPE_MASK) >> DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; + TrbSts = (Trb->LenXferParams & DWC_XDCI_TRB_STATUS_MASK) >> DWC_XDCI_TRB_STATUS_BIT_POS; + TrbBufsize = Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK; + + switch (TrbCtrl) { + case DWC_XDCI_TRB_CTRL_TYPE_SETUP: + DEBUG ((DEBUG_INFO, "SETUP\n")); + if (CoreHandle->EventCallbacks.DevSetupPktReceivedCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.Buffer = CoreHandle->AlignedSetupBuffer; + status = CoreHandle->EventCallbacks.DevSetupPktReceivedCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + if (!(CoreHandle->AlignedSetupBuffer[0] & USB_SETUP_DATA_PHASE_DIRECTION_MASK)) { + // + // Keep a Buffer ready for setup phase + // + DwcXdciCoreStartEp0SetupXfer (CoreHandle); + } + + break; + + case DWC_XDCI_TRB_CTRL_TYPE_STATUS2: + DEBUG ((DEBUG_INFO, "STATUS2\n")); + break; + + case DWC_XDCI_TRB_CTRL_TYPE_STATUS3: + DEBUG ((DEBUG_INFO, "STATUS3\n")); + // + // Notify upper layer of control transfer completion + // if a callback function was registerd + // + if (CoreHandle->EventCallbacks.DevXferDoneCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.EpNum = (EpNum >> 1); + CoreHandle->EventCallbacks.CbEventParams.EpDir = (EpNum & 1); + CoreHandle->EventCallbacks.CbEventParams.Buffer = (UINT8 *)(UINTN)(Trb->BuffPtrLow); + CoreHandle->EventCallbacks.DevXferDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + // + // Status phase done. Queue next SETUP packet + // + status = DwcXdciCoreStartEp0SetupXfer(CoreHandle); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone: FAILED to queue SETUP\n")); + } + break; + + case DWC_XDCI_TRB_CTRL_TYPE_DATA: + DEBUG ((DEBUG_INFO, "DATA\n")); + if (TrbSts == DWC_XDCI_TRB_STATUS_SETUP_PENDING || TrbBufsize != 0) { + DEBUG ((DEBUG_INFO, "ERROR: Control transfert aborted by host: Setup pending\n")); + DwcXdciCoreStartEp0SetupXfer (CoreHandle); + } else { + DwcXdciEp0ReceiveStatusPkt (CoreHandle); + } + + if (CoreHandle->EventCallbacks.DevXferDoneCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.EpNum = (EpNum >> 1); + CoreHandle->EventCallbacks.CbEventParams.EpDir = (EpNum & 1); + CoreHandle->EventCallbacks.CbEventParams.Buffer = (UINT8 *)(UINTN)(Trb->BuffPtrLow); + CoreHandle->EventCallbacks.DevXferDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + break; + + default: + DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone: UNHANDLED STATE in TRB\n")); + break; + } + + return status; +} + + +/** + Internal function: + This function is used to process transfer done for + non-control endpoints + @CoreHandle: xDCI controller handle address + @EpNum: Physical endpoint number + +**/ +STATIC +EFI_STATUS +DwcXdciProcessEpXferDone ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum + ) +{ + DWC_XDCI_ENDPOINT *epHandle; + DWC_XDCI_TRB *Trb; + USB_XFER_REQUEST *XferReq; + UINT32 remainingLen; + + if (EpNum > DWC_XDCI_MAX_ENDPOINTS) { + EpNum = DWC_XDCI_MAX_ENDPOINTS; + } + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpXferDone: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + epHandle = &CoreHandle->EpHandles[EpNum]; + epHandle->CurrentXferRscIdx = 0; + Trb = epHandle->Trb; + XferReq = &epHandle->XferHandle; + + // + // if transfer done, set CheckFlag to FALSE for allow next transfer request. + // + epHandle->CheckFlag = FALSE; + + if ((Trb == NULL) || (XferReq == NULL)) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpXferDone: INVALID parameter\n")); + return EFI_INVALID_PARAMETER; + } + + // + // Compute the actual transfer length + // + XferReq->ActualXferLen = XferReq->XferLen; + remainingLen = (Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK); + + if (remainingLen > XferReq->XferLen) { + // + // Buffer overrun? This should never happen + // + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpXferDone: Possible Buffer overrun\n")); + } else { + XferReq->ActualXferLen -= remainingLen; + } + + // + // Notify upper layer of request-specific transfer completion + // if there is a callback specifically for this request + // + if (XferReq->XferDone) { + XferReq->XferDone(CoreHandle->ParentHandle, XferReq); + } + + // + // Notify upper layer if a callback was registered + // + if (CoreHandle->EventCallbacks.DevXferDoneCallback) { + CoreHandle->EventCallbacks.CbEventParams.ParentHandle = CoreHandle->ParentHandle; + CoreHandle->EventCallbacks.CbEventParams.EpNum = (EpNum >> 1); + CoreHandle->EventCallbacks.CbEventParams.EpDir = (EpNum & 1); + CoreHandle->EventCallbacks.CbEventParams.EpType = epHandle->EpInfo.EpType; + CoreHandle->EventCallbacks.CbEventParams.Buffer = (UINT8 *)(UINTN)(epHandle->Trb->BuffPtrLow); + CoreHandle->EventCallbacks.DevXferDoneCallback (&CoreHandle->EventCallbacks.CbEventParams); + } + + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to process endpoint events + @CoreHandle: xDCI controller handle address + @IntLineEventBuffer: address of Buffer containing event + to process + @ProcessedEventSize: address to save the size of event + Processed + +**/ +STATIC +EFI_STATUS +DwcXdciProcessEpEvent ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN DWC_XDCI_EVENT_BUFFER *IntLineEventBuffer, + IN UINT32 *ProcessedEventSize + ) +{ + UINT32 EpNum; + UINT32 epEvent; + UINT32 epEventStatus; + USB_EP_STATE epState = USB_EP_STATE_DATA; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessEpEvent: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + epEvent = IntLineEventBuffer->Event; + + *ProcessedEventSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; + + // + // Get EP num + // + EpNum = ((epEvent & DWC_XDCI_EVENT_BUFF_EP_NUM_MASK) >> DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS); + epEventStatus = (epEvent & DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK); + + // + // Interpret event and handle transfer completion here + // + epEvent = ((epEvent & DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK) >> DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS); + + switch (epEvent) { + case DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT: + DEBUG ((DEBUG_INFO, "XFER_CMPLT ep %d\n", EpNum)); + if (EpNum > 1) { + DwcXdciProcessEpXferDone (CoreHandle, EpNum); + } else { + DwcXdciProcessEp0XferPhaseDone (CoreHandle, EpNum); + } + break; + + case DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS: + DEBUG ((DEBUG_INFO, "IN_PROGRESS\n")); + break; + + case DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY: + DEBUG ((DEBUG_INFO, "NOT_READY ep %d\n", EpNum)); + if (EpNum > 1) { + // + // Endpoint transfer is not ready + // + DwcXdciProcessEpXferNotReady (CoreHandle, EpNum); + } else { + /* Is it data stage or status stage */ + if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_DATA_REQ_MASK) { + epState = USB_EP_STATE_DATA; + } else if (epEventStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK) { + epState = USB_EP_STATE_STATUS; + } + /* Process transfer not ready case */ + DwcXdciProcessEp0XferNotReady (CoreHandle, EpNum, epState); + } + break; + + default: + DEBUG ((DEBUG_INFO, "DwcXdciProcessEpEvent: UNKNOWN EP event\n")); + break; + } + + return EFI_SUCCESS; +} + + +/** + Internal function: + This function is used to process events on single interrupt line + @CoreHandle: xDCI controller handle address + @eventCount: event bytes to process + @ProcessedEventCount: address to save the size + (in bytes) of event Processed + Processed + +**/ +STATIC +EFI_STATUS +DwcXdciProcessInterruptLineEvents ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 eventCount, + IN UINT32 *ProcessedEventCount + ) +{ + UINT32 ProcessedEventSize = 0; + UINT32 currentEventAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessInterruptLineEvents: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (CoreHandle->CurrentEventBuffer == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciProcessInterruptLineEvents: INVALID event Buffer\n")); + return EFI_INVALID_PARAMETER; + } + + currentEventAddr = (UINT32)(UINTN)(CoreHandle->CurrentEventBuffer); + + // + // Process eventCount/eventSize number of events + // in this run + // + while (eventCount) { + if (CoreHandle->CurrentEventBuffer->Event & DWC_XDCI_EVENT_DEV_MASK) { + DwcXdciProcessDeviceEvent ( + CoreHandle, + CoreHandle->CurrentEventBuffer, + &ProcessedEventSize + ); + } else { + DwcXdciProcessEpEvent ( + CoreHandle, + CoreHandle->CurrentEventBuffer, + &ProcessedEventSize); + } + + eventCount -= ProcessedEventSize; + *ProcessedEventCount += ProcessedEventSize; + if ((currentEventAddr + ProcessedEventSize) >= + ((UINT32)(UINTN)(CoreHandle->AlignedEventBuffers) + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)) + ) { + currentEventAddr = (UINT32)(UINTN)(CoreHandle->AlignedEventBuffers); + DEBUG ((DEBUG_INFO, "DwcXdciProcessInterruptLineEvents: Event Buffer bound reached\n")); + } else { + currentEventAddr += ProcessedEventSize; + } + + CoreHandle->CurrentEventBuffer = (DWC_XDCI_EVENT_BUFFER *)(UINTN)currentEventAddr; + } + + return EFI_SUCCESS; +} + +// +// DWC XDCI APIs +// + +/** + Interface: + + This function is used to initialize the xDCI core + @configParams: Parameters from app to configure the core + @deviceCorePtr: HW-independent APIs handle for device core + @CoreHandle: xDCI controller handle retured + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreInit ( + IN USB_DEV_CONFIG_PARAMS *ConfigParams, + IN VOID *deviceCorePtr, + IN VOID **CoreHandle + ) +{ + EFI_STATUS status = EFI_DEVICE_ERROR; + UINTN BaseAddr; + XDCI_CORE_HANDLE *LocalCoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + UINT8 i; + + LocalCoreHandle = (XDCI_CORE_HANDLE *)AllocateZeroPool (sizeof(XDCI_CORE_HANDLE)); + + if (CoreHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (LocalCoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to allocate handle for xDCI\n")); + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (LocalCoreHandle, sizeof(XDCI_CORE_HANDLE)); + + LocalCoreHandle->ParentHandle = deviceCorePtr; + + *CoreHandle = (VOID *)LocalCoreHandle; + + LocalCoreHandle->Id = ConfigParams->ControllerId; + LocalCoreHandle->BaseAddress = BaseAddr = ConfigParams->BaseAddress; + LocalCoreHandle->Flags = ConfigParams->Flags; + LocalCoreHandle->DesiredSpeed = LocalCoreHandle->ActualSpeed = ConfigParams->Speed; + LocalCoreHandle->Role = ConfigParams->Role; + + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_CSFTRST_MASK); + + // Wait until core soft reset completes + do { + if (!(UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & DWC_XDCI_DCTL_CSFTRST_MASK)) { + break; + } else { + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + efi_perror (status, L"Failed to reset device controller 0x%x",(UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG))); + return EFI_DEVICE_ERROR; + } + + DEBUG ((DEBUG_INFO, "USB core has been reset\n")); + + // + // All FIFOs are flushed at this point + // + // + // Ensure we have EP0 Rx/Tx handles initialized + // + LocalCoreHandle->EpHandles[0].EpInfo.EpNum = 0; + LocalCoreHandle->EpHandles[0].EpInfo.EpDir = UsbEpDirOut; + LocalCoreHandle->EpHandles[0].EpInfo.EpType = USB_ENDPOINT_CONTROL; + LocalCoreHandle->EpHandles[0].EpInfo.MaxPktSize = DWC_XDCI_SS_CTRL_EP_MPS; + // + // 0 means burst size of 1 + // + LocalCoreHandle->EpHandles[0].EpInfo.BurstSize = 0; + + LocalCoreHandle->EpHandles[1].EpInfo.EpNum = 0; + LocalCoreHandle->EpHandles[1].EpInfo.EpDir = UsbEpDirIn; + LocalCoreHandle->EpHandles[1].EpInfo.EpType = USB_ENDPOINT_CONTROL; + LocalCoreHandle->EpHandles[1].EpInfo.MaxPktSize = DWC_XDCI_SS_CTRL_EP_MPS; + // + // 0 means burst size of 1 + // + LocalCoreHandle->EpHandles[1].EpInfo.BurstSize = 0; + + LocalCoreHandle->DevState = UsbDevStateDefault; + + // + // Clear KeepConnect bit so we can allow disconnect and + // re-connect. Stay in RX_DETECT state + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & + (~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & + ((~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK) | (DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS)) + ); + + DEBUG ((DEBUG_INFO, "Device controller Synopsys ID: %x\n", UsbRegRead (BaseAddr, DWC_XDCI_GSNPSID_REG))); + DEBUG ((DEBUG_INFO, "Default value of xDCI GSBUSCFG0 and GSBUSCFG1: %x, %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG0_REG), + UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG1_REG))); + + DEBUG ((DEBUG_INFO, "Default value of xDCI GTXTHRCFG and GRXTHRCFG: %x, %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GTXTHRCFG_REG), + UsbRegRead (BaseAddr, DWC_XDCI_GRXTHRCFG_REG))); + + // + // Clear ULPI auto-resume bit + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB2PHYCFG_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)) & ~DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK) + ); + + DEBUG ((DEBUG_INFO, "Default value of xDCI GUSB2PHYCFG and GUSB3PIPECTL: %x, %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)), + UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG (0)))); + // + // Only one RxFIFO + // + DEBUG ((DEBUG_INFO, "Default value of DWC_XDCI_GRXFIFOSIZ: %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GRXFIFOSIZ_REG (0)))); + + for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++) { + DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_GTXFIFOSIZ %d: %x\n", + i, UsbRegRead (BaseAddr, DWC_XDCI_GTXFIFOSIZ_REG (i)))); + } + + // + // TODO: Need to check if TxFIFO should start where RxFIFO ends + // or default is correct i.e. TxFIFO starts at 0 just like RxFIFO + // + + // + // Allocate and Initialize Event Buffers + // + LocalCoreHandle->MaxDevIntLines = ((UsbRegRead (BaseAddr, DWC_XDCI_GHWPARAMS1_REG) & + DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >> + DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS); + + DEBUG ((DEBUG_INFO, "Max dev int lines: %d\n", LocalCoreHandle->MaxDevIntLines)); + // + // One event Buffer per interrupt line. + // Need to align it to size of event Buffer + // Buffer needs to be big enough. Otherwise the core + // won't operate + // + LocalCoreHandle->AlignedEventBuffers = (DWC_XDCI_EVENT_BUFFER *) + ((UINT32)(UINTN)(LocalCoreHandle->EventBuffers) + + ((sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - + (((UINT32)(UINTN)(LocalCoreHandle->EventBuffers)) % + (sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)))); + + for (i = 0; i < LocalCoreHandle->MaxDevIntLines; i++) { + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GEVNTADR_REG (i), + (UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers + i * sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) + ); + + // + // Clear High 32bit address register, GEVNTADR register is 64-bit register + // default is 0xffffffffffffffff + // + UsbRegWrite (BaseAddr, DWC_XDCI_GEVNTADR_REG (i) + 4, 0x00000000); + + LocalCoreHandle->CurrentEventBuffer = LocalCoreHandle->AlignedEventBuffers; + // + // Write size and clear the mask + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EVNTSIZ_REG (i), + sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER + ); + + // + // Write 0 to the event count register as the last step + // + // for event configuration + // + UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i), 0); + + DEBUG ((DEBUG_INFO, "Value of xDCI Event Buffer %d: %x, Size: %x, Count: %x\n", + i, + UsbRegRead (BaseAddr, DWC_XDCI_GEVNTADR_REG (i)), + UsbRegRead (BaseAddr, DWC_XDCI_EVNTSIZ_REG (i)), + UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i)))); + } + + // + // Program Global Control Register to disable scaledown, + // disable clock gating + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GCTL_REG, + ((UsbRegRead(BaseAddr, DWC_XDCI_GCTL_REG) & + ~(DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK + DWC_XDCI_GCTL_RAMCLKSEL_MASK + DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK)) | + DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK | + (DWC_XDCI_GCTL_PRT_CAP_DEVICE << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS))); + + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG))); + + // + // TODO: Program desired Speed and set LPM capable + // We will do this when SuperSpeed works. For now, + // force into High-Speed mode to aVOID anyone trying this + // on Super Speed port + // +#ifdef SUPPORT_SUPER_SPEED + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCFG_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | LocalCoreHandle->DesiredSpeed + ); +#else + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCFG_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | DWC_XDCI_DCFG_DESIRED_HS_SPEED + ); +#endif + + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG))); + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG))); + + // + // Enable Device Interrupt Events + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DEVTEN_REG, + DWC_XDCI_DEVTEN_DEVICE_INTS + ); + // + // Program the desired role + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GCTL_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG) & ~DWC_XDCI_GCTL_PRT_CAP_DIR_MASK) | (LocalCoreHandle->Role << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS) + ); + // + // Clear USB2 suspend for start new config command + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB2PHYCFG_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) + ); + + // + // Clear USB3 suspend for start new config command + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB3PIPECTL_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) + ); + + // + // Issue DEPSTARTCFG command for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_START_NEW_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to init params for START_NEW_CONFIG EP command on xDCI"); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_START_NEW_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to issue START_NEW_CONFIG EP command on xDCI"); + return status; + } + + // + // Issue DEPCFG command for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP0"); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_SET_EP_CONFIG, + &EpCmdParams); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP0"); + return status; + } + + // + // Issue DEPCFG command for EP1 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[1].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP1"); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 1, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP1"); + return status; + } + + // + // Issue DEPXFERCFG command for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0"); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0"); + return status; + } + + // + // Issue DEPXFERCFG command for EP1 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[1].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1"); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 1, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + efi_perror (status, L"DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1"); + return status; + } + + // + // Prepare a Buffer for SETUP packet + // + LocalCoreHandle->Trbs = (DWC_XDCI_TRB *)(UINTN)((UINT32)(UINTN) + LocalCoreHandle->UnalignedTrbs + + (DWC_XDCI_TRB_BYTE_ALIGNMENT - + ((UINT32)(UINTN)LocalCoreHandle->UnalignedTrbs % + DWC_XDCI_TRB_BYTE_ALIGNMENT))); + + DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ unalignedTrbs address is 0x%x\n", LocalCoreHandle->UnalignedTrbs)); + DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ TRB address is 0x%x\n", LocalCoreHandle->Trbs)); + // + // Allocate Setup Buffer that is 8-byte aligned + // + LocalCoreHandle->AlignedSetupBuffer = LocalCoreHandle->DefaultSetupBuffer + + (DWC_XDCI_SETUP_BUFF_SIZE - + ((UINT32)(UINTN)(LocalCoreHandle->DefaultSetupBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); + + // + // Aligned Buffer for status phase + // + LocalCoreHandle->AlignedMiscBuffer = LocalCoreHandle->MiscBuffer + + (DWC_XDCI_SETUP_BUFF_SIZE - + ((UINT32)(UINTN)(LocalCoreHandle->AlignedMiscBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); + + + // + // Enable Physical Endpoints 0 + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EP_DALEPENA_REG, + UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 0) + ); + // + // Enable Physical Endpoints 1 + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EP_DALEPENA_REG, + UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 1) + ); + + DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DEVTEN_REG))); + return status; +} + + +/** + Interface: + This function is used to de-initialize the xDCI core + @CoreHandle: xDCI controller handle + @flags: Special flags for de-initializing the core in + particular way + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreDeinit ( + VOID *CoreHandle, + __attribute__((unused)) UINT32 flags + ) +{ + FreePool (CoreHandle); + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to register event callback function + @CoreHandle: xDCI controller handle + @event: Event for which callback is to be registered + @callbackFn: Callback function to invoke after event occurs + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreRegisterCallback ( + IN VOID *CoreHandle, + IN USB_DEVICE_EVENT_ID Event, + IN USB_DEVICE_CALLBACK_FUNC CallbackFunc + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + + if (LocalCoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreRegisterCallback: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + DEBUG ((DEBUG_INFO, "DwcXdciCoreRegisterCallback: event is %d\n", Event)); + switch (Event) { + case USB_DEVICE_DISCONNECT_EVENT: + LocalCoreHandle->EventCallbacks.DevDisconnectCallback = CallbackFunc; + break; + + case USB_DEVICE_RESET_EVENT: + LocalCoreHandle->EventCallbacks.DevBusResetCallback = CallbackFunc; + break; + + case USB_DEVICE_CONNECTION_DONE: + LocalCoreHandle->EventCallbacks.DevResetDoneCallback = CallbackFunc; + break; + + case USB_DEVICE_STATE_CHANGE_EVENT: + LocalCoreHandle->EventCallbacks.DevLinkStateCallback = CallbackFunc; + break; + + case USB_DEVICE_WAKEUP_EVENT: + LocalCoreHandle->EventCallbacks.DevWakeupCallback = CallbackFunc; + break; + + case USB_DEVICE_HIBERNATION_REQ_EVENT: + LocalCoreHandle->EventCallbacks.DevHibernationCallback = CallbackFunc; + break; + + case USB_DEVICE_SOF_EVENT: + LocalCoreHandle->EventCallbacks.DevSofCallback = CallbackFunc; + break; + + case USB_DEVICE_ERRATIC_ERR_EVENT: + LocalCoreHandle->EventCallbacks.DevErraticErrCallback = CallbackFunc; + break; + + case USB_DEVICE_CMD_CMPLT_EVENT: + LocalCoreHandle->EventCallbacks.DevCmdCmpltCallback = CallbackFunc; + break; + + case USB_DEVICE_BUFF_OVERFLOW_EVENT: + LocalCoreHandle->EventCallbacks.DevBuffOvflwCallback = CallbackFunc; + break; + + case USB_DEVICE_TEST_LMP_RX_EVENT: + LocalCoreHandle->EventCallbacks.DevTestLmpRxCallback = CallbackFunc; + break; + + case USB_DEVICE_SETUP_PKT_RECEIVED: + LocalCoreHandle->EventCallbacks.DevSetupPktReceivedCallback = CallbackFunc; + break; + + case USB_DEVICE_XFER_NRDY: + LocalCoreHandle->EventCallbacks.DevXferNrdyCallback = CallbackFunc; + break; + + case USB_DEVICE_XFER_DONE: + LocalCoreHandle->EventCallbacks.DevXferDoneCallback = CallbackFunc; + break; + + default: + break; + } + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to unregister event callback function + @CoreHandle: xDCI controller handle + @event: Event for which callback function is to be unregistered + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreUnregisterCallback ( + IN VOID *CoreHandle, + IN USB_DEVICE_EVENT_ID event + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + + if (LocalCoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreUnregisterCallback: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + switch (event) { + case USB_DEVICE_DISCONNECT_EVENT: + LocalCoreHandle->EventCallbacks.DevDisconnectCallback = NULL; + break; + + case USB_DEVICE_RESET_EVENT: + LocalCoreHandle->EventCallbacks.DevBusResetCallback = NULL; + break; + + case USB_DEVICE_CONNECTION_DONE: + LocalCoreHandle->EventCallbacks.DevResetDoneCallback = NULL; + break; + + case USB_DEVICE_STATE_CHANGE_EVENT: + LocalCoreHandle->EventCallbacks.DevLinkStateCallback = NULL; + break; + + case USB_DEVICE_WAKEUP_EVENT: + LocalCoreHandle->EventCallbacks.DevWakeupCallback = NULL; + break; + + case USB_DEVICE_HIBERNATION_REQ_EVENT: + LocalCoreHandle->EventCallbacks.DevHibernationCallback = NULL; + break; + + case USB_DEVICE_SOF_EVENT: + LocalCoreHandle->EventCallbacks.DevSofCallback = NULL; + break; + + case USB_DEVICE_ERRATIC_ERR_EVENT: + LocalCoreHandle->EventCallbacks.DevErraticErrCallback = NULL; + break; + + case USB_DEVICE_CMD_CMPLT_EVENT: + LocalCoreHandle->EventCallbacks.DevCmdCmpltCallback = NULL; + break; + + case USB_DEVICE_BUFF_OVERFLOW_EVENT: + LocalCoreHandle->EventCallbacks.DevBuffOvflwCallback = NULL; + break; + + case USB_DEVICE_TEST_LMP_RX_EVENT: + LocalCoreHandle->EventCallbacks.DevTestLmpRxCallback = NULL; + break; + + case USB_DEVICE_SETUP_PKT_RECEIVED: + LocalCoreHandle->EventCallbacks.DevSetupPktReceivedCallback = NULL; + break; + + case USB_DEVICE_XFER_NRDY: + LocalCoreHandle->EventCallbacks.DevXferNrdyCallback = NULL; + break; + + case USB_DEVICE_XFER_DONE: + LocalCoreHandle->EventCallbacks.DevXferDoneCallback = NULL; + break; + + default: + break; + } + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used as an interrupt service routine + @CoreHandle: xDCI controller handle + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreIsrRoutine ( + IN VOID *CoreHandle + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINTN BaseAddr; + UINT32 eventCount; + UINT32 ProcessedEventCount; + UINT32 i; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreIsrRoutine: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (LocalCoreHandle->InterrupProcessing == TRUE) { + DEBUG ((DEBUG_INFO, "interrupProcessing.........\n")); + return EFI_SUCCESS; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + // + // Event Buffer corresponding to each interrupt line needs + // to be Processed + // + LocalCoreHandle->InterrupProcessing = TRUE; + for (i = 0; i < LocalCoreHandle->MaxDevIntLines; i++) { + // + // Get the number of events HW has written for this + // interrupt line + // + eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i)); + eventCount &= DWC_XDCI_EVNTCOUNT_MASK; + ProcessedEventCount = 0; + + // + // Process interrupt line Buffer only if count is non-zero + // + if (eventCount) { + // + // Process events in this Buffer + // + DwcXdciProcessInterruptLineEvents (LocalCoreHandle, eventCount, &ProcessedEventCount); + // + // Write back the Processed number of events so HW decrements it from current + // event count + // + UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i), ProcessedEventCount); + } + } + LocalCoreHandle->InterrupProcessing = FALSE; + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used as an interrupt service routine and it processes only one event at a time. + @CoreHandle: xDCI controller handle + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreIsrRoutineTimerBased ( + IN VOID *CoreHandle + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINTN BaseAddr; + UINT32 eventCount; + UINT32 ProcessedEventCount; + UINT32 currentEventAddr; + UINT32 ProcessedEventSize = 0; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreIsrRoutineTimerBased: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (LocalCoreHandle->CurrentEventBuffer == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreIsrRoutineTimerBased: INVALID event Buffer\n")); + return EFI_INVALID_PARAMETER; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0)) & DWC_XDCI_EVNTCOUNT_MASK; + + if (LocalCoreHandle->InterrupProcessing == TRUE) { + DEBUG ((DEBUG_INFO, "interrupProcessing.........\n")); + return EFI_SUCCESS; + } + + LocalCoreHandle->InterrupProcessing = TRUE; + + ProcessedEventCount = 0; + currentEventAddr = (UINT32)(UINTN)(LocalCoreHandle->CurrentEventBuffer); + + if (LocalCoreHandle->CurrentEventBuffer->Event & DWC_XDCI_EVENT_DEV_MASK) { + DwcXdciProcessDeviceEvent ( + LocalCoreHandle, + LocalCoreHandle->CurrentEventBuffer, + &ProcessedEventSize + ); + } else { + DwcXdciProcessEpEvent ( + LocalCoreHandle, + LocalCoreHandle->CurrentEventBuffer, + &ProcessedEventSize); + } + + eventCount -= ProcessedEventSize; + ProcessedEventCount += ProcessedEventSize; + if ((currentEventAddr + ProcessedEventSize) >= + ((UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers) + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)) + ) { + currentEventAddr = (UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers); + DEBUG ((DEBUG_INFO, "DwcXdciProcessInterruptLineEvents: Event Buffer bound reached\n")); + } else { + currentEventAddr += ProcessedEventSize; + } + + LocalCoreHandle->CurrentEventBuffer = (DWC_XDCI_EVENT_BUFFER *)(UINTN)currentEventAddr; + UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0), ProcessedEventCount); + LocalCoreHandle->InterrupProcessing = FALSE; + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to enable xDCI to connect to the host + @CoreHandle: xDCI controller handle + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreConnect ( + IN VOID *CoreHandle + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + UINTN BaseAddr; + + EFI_STATUS ret = EFI_DEVICE_ERROR; + if (CoreHandle == NULL) { + efi_perror (ret, L"DwcXdciCoreConnect: INVALID handle\n"); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // Clear KeepConnect bit so we can allow disconnect and re-connect + // Also issue No action on state change to aVOID any link change + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + (UsbRegRead(BaseAddr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & ~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK + ); + + // + // Set Run bit to connect to the host + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_RUN_STOP_MASK + ); + + // Wait until core starts running + do { + if (!(UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK)) { + break; + } else { + efi_perror (ret, L"Stall for core run"); + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to disconnect xDCI from the host + @CoreHandle: xDCI controller handle + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreDisconnect ( + IN VOID *CoreHandle + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + UINTN BaseAddr; + UINT32 eventCount; + UINT32 dsts; + UINT32 i; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0)); + eventCount &= DWC_XDCI_EVNTCOUNT_MASK; + + DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: eventCount=%d\n", eventCount)); + while (eventCount) { + DwcXdciCoreIsrRoutine(LocalCoreHandle); + eventCount = UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (0)); + eventCount &= DWC_XDCI_EVNTCOUNT_MASK; + DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: eventCount=%d\n", eventCount)); + } + + // + // Issue DEPENDXFER for active transfers + // + for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++){ + if (LocalCoreHandle->EpHandles[i].CurrentXferRscIdx){ + DwcXdciEndXfer(LocalCoreHandle, i); + } + } + // + // Clear Run bit to disconnect from host + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead(BaseAddr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_RUN_STOP_MASK); + + // + // Wait until core is halted + // + do { + dsts = UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG); + DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: waiting halt: DSTS=0x%x\n", dsts)); + if ((dsts & DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK) != 0){ + break; + } else { + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreDisconnect: Failed to halt the device controller\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to obtain current USB bus Speed + @CoreHandle: xDCI controller handle + @Speed: Address of variable to save the Speed + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreGetSpeed ( + IN VOID *CoreHandle, + IN USB_SPEED *Speed + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreGetSpeed: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (Speed == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreGetSpeed: INVALID parameter\n")); + return EFI_INVALID_PARAMETER; + } + + *Speed = UsbRegRead (LocalCoreHandle->BaseAddress, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_CONN_SPEED_MASK; + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to obtain current USB bus Speed + @CoreHandle: xDCI controller handle + @address: USB address to set (assigned by USB host) + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreSetAddress ( + IN VOID *CoreHandle, + IN UINT32 address + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreSetAddress: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + DEBUG ((DEBUG_INFO, "DwcXdciCoreSetAddress is 0x%x \n", address)); + // + // Program USB device address + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCFG_REG, + (UsbRegRead(BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DEV_ADDRESS_MASK) | (address << DWC_XDCI_DCFG_DEV_ADDRESS_BIT_POS) + ); + + LocalCoreHandle->DevState = UsbDevStateAddress; + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG))); + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DEVTEN_REG))); + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG))); + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG))); + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to set configuration + @CoreHandle: xDCI controller handle + @ConfigNum: config num to set (assigned by USB host) + +**/ +EFI_STATUS +EFIAPI +DwcXdciCoreSetConfig ( + VOID *CoreHandle, + __attribute__((unused)) UINT32 ConfigNum + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS status; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreSetConfig: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Issue DEPSTARTCFG command on EP0 (new config for + // non-control EPs) + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_START_NEW_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreSetConfig: Failed to init params for EPCMD_START_NEW_CONFIG command\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + (EPCMD_START_NEW_CONFIG | (2 << DWC_XDCI_EPCMD_RES_IDX_BIT_POS)), + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreSetConfig: Failed to issue EPCMD_START_NEW_CONFIG command\n")); + return status; + } + + return status; +} + + +/** + Interface: + This function is used to set link state + @CoreHandle: xDCI controller handle + @state: Desired link state + +**/ +EFI_STATUS +EFIAPI +DwcXdciSetLinkState ( + IN VOID *CoreHandle, + IN USB_DEVICE_SS_LINK_STATE state + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciSetLinkState: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // Clear old mask + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK + ); + + // + // Request new state + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | (state << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS) + ); + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to initialize endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + to be initialized + +**/ +EFI_STATUS +EFIAPI +DwcXdciInitEp ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS status; + UINT32 EpNum; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciInitEp: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + + // + // Save EP properties + // + CopyMem (&(LocalCoreHandle->EpHandles[EpNum].EpInfo), EpInfo, sizeof (USB_EP_INFO)); + + // + // Init CheckFlag + // + LocalCoreHandle->EpHandles[EpNum].CheckFlag = FALSE; + + // + // Init DEPCFG cmd params for EP + // + status = DwcXdciCoreInitEpCmdParams ( + CoreHandle, + &LocalCoreHandle->EpHandles[EpNum].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to init params for EPCMD_SET_EP_CONFIG command\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + CoreHandle, + EpNum, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to issue EPCMD_SET_EP_CONFIG command\n")); + return status; + } + + // + // Issue a DEPXFERCFG command for endpoint + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[EpNum].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + EpNum, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciInitEp: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command\n")); + } + + return status; +} + + +/** + Interface: + This function is used to enable non-Ep0 endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + to be enabled + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpEnable ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINT32 EpNum; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpEnable: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + + // + // Enable Physical Endpoint EpNum + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EP_DALEPENA_REG, + UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << EpNum) + ); + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to disable non-Ep0 endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + to be enabled + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpDisable ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINT32 EpNum; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpDisable: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + + // + // Disable Physical Endpoint EpNum + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EP_DALEPENA_REG, + UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) & ~(1 << EpNum) + ); + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to STALL and endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + to be enabled + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpStall ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS status; + UINT32 EpNum; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpStall: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + + // + // Set Ep State Info + // + if (LocalCoreHandle->EpHandles[EpNum].State != USB_EP_STATE_STALLED) { + LocalCoreHandle->EpHandles[EpNum].OrgState = LocalCoreHandle->EpHandles[EpNum].State; + LocalCoreHandle->EpHandles[EpNum].State = USB_EP_STATE_STALLED; + } + // + // Issue a DWC_XDCI_EPCMD_SET_STALL for EP + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + EpNum, + DWC_XDCI_EPCMD_SET_STALL, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpStall: Failed to issue EP stall command\n")); + } + + return status; +} + + +/** + Interface: + This function is used to clear endpoint STALL + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + to be enabled + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpClearStall ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS status; + UINT32 EpNum; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpClearStall: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + + // + // Set Ep State Info + // + LocalCoreHandle->EpHandles[EpNum].State = LocalCoreHandle->EpHandles[EpNum].OrgState; + + // + // Issue a DWC_XDCI_EPCMD_CLEAR_STALL for EP + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + EpNum, + DWC_XDCI_EPCMD_CLEAR_STALL, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpStall: Failed to issue EP clea stall command\n")); + } + + return status; +} + + +/** + Interface: + This function is used to set endpoint in NOT READY state + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + to be enabled + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpSetNrdy ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + UINT32 EpNum; + UINTN BaseAddr; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpSetNrdy: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + + // + // Program the EP number in command's param reg + // + UsbRegWrite (BaseAddr, DWC_XDCI_DGCMD_PARAM_REG, EpNum); + + // + // Issue EP not ready generic device command + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DGCMD_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SET_EP_NRDY) + ); + + // + // Activate the command + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DGCMD_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) + ); + + // + // Wait until command completes + // + do { + if (!(UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) + break; + else + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Interface: + This function is used to queue receive SETUP packet request + @CoreHandle: xDCI controller handle + @Buffer: Address of Buffer to receive SETUP packet + +**/ +EFI_STATUS +EFIAPI +DwcXdciEp0ReceiveSetupPkt ( + IN VOID *CoreHandle, + IN UINT8 *Buffer + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS Status = EFI_DEVICE_ERROR; + DWC_XDCI_TRB *Trb; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveSetupPkt: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + LocalCoreHandle->EpHandles[0].EpInfo.EpNum = 0; + LocalCoreHandle->EpHandles[0].EpInfo.EpDir = 0; + LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_SETUP; + Trb = LocalCoreHandle->Trbs; + DEBUG ((DEBUG_INFO, "(DwcXdciEp0ReceiveSetupPkt)\n")); + + Status = DwcXdciCoreInitTrb ( + LocalCoreHandle, + Trb, + TRBCTL_SETUP, + Buffer, + 8 + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveSetupPkt: Init TRB Failed \n")); + return Status; + } + + // + // Issue a DEPSTRTXFER for EP0 + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Init the lower re-bits for TRB address + // + EpCmdParams.Param1 = (UINT32)(UINTN)Trb; + + // + // Issue the command + // + Status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_START_XFER, + &EpCmdParams + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "\nDwcXdciEp0ReceiveSetupPkt: Failed to issue Start Transfer command")); + } + + // + // Save new resource index for this transfer + // + LocalCoreHandle->EpHandles[0].CurrentXferRscIdx = ((UsbRegRead(LocalCoreHandle->BaseAddress, DWC_XDCI_EPCMD_REG(0)) & + DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS + ); + + return Status; +} + + +/** + Interface: + This function is used to queue receive status packet on EP0 + @CoreHandle: xDCI controller handle + +**/ +EFI_STATUS +EFIAPI +DwcXdciEp0ReceiveStatusPkt ( + IN VOID *CoreHandle + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_TRB *Trb; + DWC_XDCI_TRB_CONTROL TrbCtrl; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS Status; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveStatusPkt: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // We are receiving on EP0 so physical EP is 0 + // + Trb = LocalCoreHandle->Trbs; + DEBUG ((DEBUG_INFO, "(DwcXdciEp0ReceiveStatusPkt)\n")); + if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { + DEBUG ((DEBUG_INFO, "statusPkt still not transferred.\n")); + return EFI_SUCCESS; + } + + LocalCoreHandle->EpHandles[0].EpInfo.EpNum = 0; + LocalCoreHandle->EpHandles[0].EpInfo.EpDir = 0; + + // + // OUT data phase for 3-phased control transfer + // + TrbCtrl = TRBCTL_3_PHASE; + + // + // Init TRB for the transfer + // + Status = DwcXdciCoreInitTrb ( + LocalCoreHandle, + Trb, + TrbCtrl, + LocalCoreHandle->AlignedSetupBuffer, + 0 + ); + + if (!Status) { + // + // Issue a DEPSTRTXFER for EP0 + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Init the lower bits for TRB address + // + EpCmdParams.Param1 = (UINT32)(UINTN)Trb; + + // + // Issue the command + // + Status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_START_XFER, + &EpCmdParams + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0ReceiveStatusPkt: Failed to issue Start Transfer command for EP0\n")); + } + // + // Save new resource index for this transfer + // + LocalCoreHandle->EpHandles[0].CurrentXferRscIdx = ((UsbRegRead(BaseAddr, DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); + + // + // TODO: We are not using the EP state for control transfers + // right now simply because we're only supporting IN + // data phase. For the current use case, we don't + // need OUT data phase. We can add that later and we will + // add some of the state and SETUP packet awareness code + // + LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_STATUS; + } + + return Status; +} + + +/** + Interface: + This function is used to send status packet on EP0 + @CoreHandle: xDCI controller handle + +**/ +EFI_STATUS +EFIAPI +DwcXdciEp0SendStatusPkt ( + IN VOID *CoreHandle + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_TRB *Trb; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + EFI_STATUS Status; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0SendStatusPkt: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // We are sending on EP0 so physical EP is 1 + // + Trb = (LocalCoreHandle->Trbs + (1 * DWC_XDCI_TRB_NUM)); + DEBUG ((DEBUG_INFO, "(DwcXdciEp0SendStatusPkt)\n")); + + LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_STATUS; + Status = DwcXdciCoreInitTrb ( + LocalCoreHandle, + Trb, + TRBCTL_2_PHASE, + LocalCoreHandle->AlignedMiscBuffer, + 0 + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0SendStatusPkt: TRB failed during status phase\n")); + return Status; + } + + // + // Issue a DEPSTRTXFER for EP1 + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Init the lower re-bits for TRB address + // + EpCmdParams.Param1 = (UINT32)(UINTN)Trb; + + // + // Issue the command + // + Status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 1, + EPCMD_START_XFER, + &EpCmdParams + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEp0SendStatusPkt: Failed to issue Start Transfer on EP0\n")); + } + + // + // Save new resource index for this transfer + // + LocalCoreHandle->EpHandles[1].CurrentXferRscIdx = ((UsbRegRead(BaseAddr, DWC_XDCI_EPCMD_REG(1)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); + LocalCoreHandle->EpHandles[0].State = USB_EP_STATE_STATUS; + + return Status; +} + + +/** + Interface: + This function is used to send data on non-EP0 endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + @Buffer: Buffer containing data to transmit + @size: Size of transfer (in bytes) + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpTxData ( + IN VOID *CoreHandle, + IN USB_XFER_REQUEST *XferReq + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + DWC_XDCI_TRB *Trb; + DWC_XDCI_TRB_CONTROL TrbCtrl; + EFI_STATUS Status; + UINT32 EpNum; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (XferReq == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: INVALID transfer request\n")); + return EFI_INVALID_PARAMETER; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum ( + XferReq->EpInfo.EpNum, + XferReq->EpInfo.EpDir + ); + + Trb = (LocalCoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM)); + DEBUG ((DEBUG_INFO, "(DwcXdciEpTxData)EpNum is %d\n", EpNum)); + + + if (EpNum > 1) + TrbCtrl = TRBCTL_NORMAL; + else + TrbCtrl = TRBCTL_CTRL_DATA_PHASE; + + if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { + Status = DwcXdciEndXfer (LocalCoreHandle, EpNum); + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: Failed to end previous transfer\n")); + } + + Status = DwcXdciCoreFlushEpTxFifo (LocalCoreHandle, EpNum); + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: Failed to end previous transfer\n")); + } + } + + // + // Data phase + // + CopyMem (&(LocalCoreHandle->EpHandles[EpNum].XferHandle), XferReq, sizeof (USB_XFER_REQUEST)); + LocalCoreHandle->EpHandles[EpNum].State = USB_EP_STATE_DATA; + + LocalCoreHandle->EpHandles[EpNum].Trb = Trb; + + Status = DwcXdciCoreInitTrb ( + LocalCoreHandle, + Trb, + TrbCtrl, + XferReq->XferBuffer, + XferReq->XferLen + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpTxData: TRB failed\n")); + return Status; + } + + // + // Issue a DEPSTRTXFER for EP + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Init the lower re-bits for TRB address + // + EpCmdParams.Param1 = (UINT32)(UINTN)Trb; + + // + // Issue the command + // + Status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + EpNum, + EPCMD_START_XFER, + &EpCmdParams + ); + + // + // Save new resource index for this transfer + // + LocalCoreHandle->EpHandles[EpNum].CurrentXferRscIdx = ((UsbRegRead (BaseAddr, DWC_XDCI_EPCMD_REG(EpNum)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); + + return Status; +} + + +/** + Interface: + This function is used to receive data on non-EP0 endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + @Buffer: Buffer containing data to transmit + @size: Size of transfer (in bytes) + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpRxData ( + IN VOID *CoreHandle, + IN USB_XFER_REQUEST *XferReq + ) +{ + XDCI_CORE_HANDLE *LocalCoreHandle = (XDCI_CORE_HANDLE *)CoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + DWC_XDCI_TRB *Trb; + DWC_XDCI_TRB_CONTROL TrbCtrl; + EFI_STATUS Status; + UINT32 EpNum; + UINTN BaseAddr; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + if (XferReq == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: INVALID transfer request\n")); + return EFI_INVALID_PARAMETER; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + // + // Convert to physical endpoint + // + EpNum = DwcXdciGetPhysicalEpNum (XferReq->EpInfo.EpNum, XferReq->EpInfo.EpDir); + + Trb = (LocalCoreHandle->Trbs + (EpNum * DWC_XDCI_TRB_NUM)); + DEBUG ((DEBUG_INFO, "(DwcXdciEpRxData)EpNum is %d\n", EpNum)); + + if (EpNum > 1) + TrbCtrl = TRBCTL_NORMAL; + else + TrbCtrl = TRBCTL_CTRL_DATA_PHASE; + + // + // If CheckFlag didn't set to FALSE, means the previous transfer request didn't complete, + // need to wait the previous request done. + // + if (LocalCoreHandle->EpHandles[EpNum].CheckFlag == TRUE) { + return EFI_NOT_READY; + } + + LocalCoreHandle->EpHandles[EpNum].CheckFlag = TRUE; + + // + // Data phase + // + CopyMem (&(LocalCoreHandle->EpHandles[EpNum].XferHandle), XferReq, sizeof (USB_XFER_REQUEST)); + + LocalCoreHandle->EpHandles[EpNum].State = USB_EP_STATE_DATA; + + LocalCoreHandle->EpHandles[EpNum].Trb = Trb; + + DEBUG ((DEBUG_INFO, "(DwcXdciEpRxData)XferReq->XferLen is 0x%x\n", XferReq->XferLen)); + + Status = DwcXdciCoreInitTrb ( + LocalCoreHandle, + Trb, + TrbCtrl, + XferReq->XferBuffer, + XferReq->XferLen + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: TRB failed\n")); + return Status; + } + // + // Issue a DEPSTRTXFER for EP + // Reset params + // + EpCmdParams.Param0 = EpCmdParams.Param1 = EpCmdParams.Param2 = 0; + + // + // Init the lower re-bits for TRB address + // + EpCmdParams.Param1 = (UINT32)(UINTN)Trb; + + // + // Issue the command + // + Status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + EpNum, + EPCMD_START_XFER, + &EpCmdParams + ); + + if (Status) { + DEBUG ((DEBUG_INFO, "DwcXdciEpRxData: Failed to start transfer\n")); + } + + // + // Save new resource index for this transfer + // + LocalCoreHandle->EpHandles[EpNum].CurrentXferRscIdx = ((UsbRegRead(BaseAddr, DWC_XDCI_EPCMD_REG(EpNum)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); + + return Status; +} + + + +STATIC +EFI_STATUS +DwcXdciCoreFlushEpFifo ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum + ) +{ + UINTN BaseAddr; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + UINT32 fifoNum; + UINT32 Param; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: DwcXdciCoreFlushEpTxFifo: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + BaseAddr = CoreHandle->BaseAddress; + + // + // Translate to FIFOnum + // NOTE: Assuming this is a Tx EP + // + fifoNum = (EpNum >> 1); + + // + // TODO: Currently we are only using TxFIFO 0. Later map these + // Write the FIFO num/dir param for the generic command. + // + + Param = UsbRegRead (BaseAddr, DWC_XDCI_DGCMD_PARAM_REG); + Param &= ~(DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK); + + if ((EpNum & 0x01) != 0) { + Param |= (fifoNum | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK); + } else { + Param |= fifoNum; + } + + DEBUG ((DEBUG_INFO, "USB FU Flash: CMD 0x%08x :: Param 0x%08x\n", + (UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK), + Param)); + + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DGCMD_PARAM_REG, + Param + ); + + // + // Write the command to flush all FIFOs + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DGCMD_REG, + (UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) + ); + + + // + // Wait until command completes + // + do { + if (!(UsbRegRead(BaseAddr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) + break; + else + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Interface: + This function is used to cancel a transfer on non-EP0 endpoint + @CoreHandle: xDCI controller handle + @EpInfo: Address of structure describing properties of EP + +**/ +EFI_STATUS +EFIAPI +DwcXdciEpCancelTransfer ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINT32 EpNum; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpCancelTransfer: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Get physical EP num + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + Status = DwcXdciEndXfer(CoreHandle, EpNum); + DwcXdciCoreFlushEpFifo(CoreHandle, EpNum); + + return Status; +} + + +EFI_STATUS +usbProcessDeviceResetDet ( + IN XDCI_CORE_HANDLE *CoreHandle + ) +{ + return DwcXdciProcessDeviceResetDet (CoreHandle); +} + +EFI_STATUS +usbProcessDeviceResetDone ( + IN XDCI_CORE_HANDLE *CoreHandle + ) +{ + return DwcXdciProcessDeviceResetDone (CoreHandle); +} + +UINT32 +UsbGetPhysicalEpNum ( + IN UINT32 EndpointNum, + IN USB_EP_DIR EndpointDir + ) +{ + return DwcXdciGetPhysicalEpNum( + EndpointNum, + EndpointDir + ); +} + + +EFI_STATUS +EFIAPI +UsbXdciCoreReinit ( + IN VOID *CoreHandle + ) +{ + EFI_STATUS status = EFI_DEVICE_ERROR; + UINTN BaseAddr; + XDCI_CORE_HANDLE *LocalCoreHandle; + DWC_XDCI_ENDPOINT_CMD_PARAMS EpCmdParams; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + UINT8 i; + + LocalCoreHandle = CoreHandle; + + if (CoreHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (LocalCoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to allocate handle for xDCI\n")); + return EFI_OUT_OF_RESOURCES; + } + + BaseAddr = LocalCoreHandle->BaseAddress; + + DEBUG ((DEBUG_INFO, "Resetting the USB core\n")); + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_CSFTRST_MASK + ); + + // + // Wait until core soft reset completes + // + do { + if (!(UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & DWC_XDCI_DCTL_CSFTRST_MASK)) { + break; + } else { + uefi_call_wrapper(BS->Stall, 1, DWC_XDCI_MAX_DELAY_ITERATIONS); + } + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "Failed to reset device controller\n")); + return EFI_DEVICE_ERROR; + } + + DEBUG ((DEBUG_INFO, "USB core has been reset\n")); + + LocalCoreHandle->DevState = UsbDevStateDefault; + + // + // Clear KeepConnect bit so we can allow disconnect and + // re-connect. Stay in RX_DETECT state + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCTL_REG, + UsbRegRead (BaseAddr, DWC_XDCI_DCTL_REG) & + (~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & + ((~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK) | + (DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS)) + ); + + DEBUG ((DEBUG_INFO, "Device controller Synopsys ID: %x\n", UsbRegRead (BaseAddr, DWC_XDCI_GSNPSID_REG))); + DEBUG ((DEBUG_INFO, "Default value of xDCI GSBUSCFG0 and GSBUSCFG1: %x, %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG0_REG), + UsbRegRead (BaseAddr, DWC_XDCI_GSBUSCFG1_REG))); + + DEBUG ((DEBUG_INFO, "Default value of xDCI GTXTHRCFG and GRXTHRCFG: %x, %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GTXTHRCFG_REG), + UsbRegRead (BaseAddr, DWC_XDCI_GRXTHRCFG_REG))); + + // + // Clear ULPI auto-resume bit + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB2PHYCFG_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)) & ~DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK) + ); + + DEBUG ((DEBUG_INFO, "Default value of xDCI GUSB2PHYCFG and GUSB3PIPECTL: %x, %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG (0)), + UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG (0)))); + + // + // Only one RxFIFO + // + DEBUG ((DEBUG_INFO, "Default value of DWC_XDCI_GRXFIFOSIZ: %x\n", + UsbRegRead (BaseAddr, DWC_XDCI_GRXFIFOSIZ_REG (0)))); + + for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++) { + DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_GTXFIFOSIZ %d: %x\n", + i, UsbRegRead (BaseAddr, DWC_XDCI_GTXFIFOSIZ_REG (i)))); + } + + // + // TODO: Need to check if TxFIFO should start where RxFIFO ends + // or default is correct i.e. TxFIFO starts at 0 just like RxFIFO + // + + // + // Allocate and Initialize Event Buffers + // + LocalCoreHandle->MaxDevIntLines = ((UsbRegRead (BaseAddr, DWC_XDCI_GHWPARAMS1_REG) & + DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >> + DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS); + + DEBUG ((DEBUG_INFO, "Max dev int lines: %d\n", LocalCoreHandle->MaxDevIntLines)); + // + // One event Buffer per interrupt line. + // Need to align it to size of event Buffer + // Buffer needs to be big enough. Otherwise the core + // won't operate + // + LocalCoreHandle->AlignedEventBuffers = (DWC_XDCI_EVENT_BUFFER *) + ((UINT32)(UINTN)(LocalCoreHandle->EventBuffers) + + ((sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - + (((UINT32)(UINTN)(LocalCoreHandle->EventBuffers)) % + (sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)))); + + for (i = 0; i < LocalCoreHandle->MaxDevIntLines; i++) { + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GEVNTADR_REG (i), + (UINT32)(UINTN)(LocalCoreHandle->AlignedEventBuffers + i * sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) + ); + + // + // Clear High 32bit address register, GEVNTADR register is 64-bit register + // default is 0xffffffffffffffff + // + UsbRegWrite (BaseAddr, DWC_XDCI_GEVNTADR_REG (i) + 4, 0x00000000); + + LocalCoreHandle->CurrentEventBuffer = LocalCoreHandle->AlignedEventBuffers; + // + // Write size and clear the mask + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EVNTSIZ_REG (i), + sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER + ); + + // + // Write 0 to the event count register as the last step + // for event configuration + // + UsbRegWrite (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i), 0); + + DEBUG ((DEBUG_INFO, "Value of xDCI Event Buffer %d: %x, Size: %x, Count: %x\n", + i, + UsbRegRead (BaseAddr, DWC_XDCI_GEVNTADR_REG (i)), + UsbRegRead (BaseAddr, DWC_XDCI_EVNTSIZ_REG (i)), + UsbRegRead (BaseAddr, DWC_XDCI_EVNTCOUNT_REG (i)))); + } + + // + // Program Global Control Register to disable scaledown, + // disable clock gating + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GCTL_REG, + ((UsbRegRead(BaseAddr, DWC_XDCI_GCTL_REG) & + ~(DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK + DWC_XDCI_GCTL_RAMCLKSEL_MASK + DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK)) | + DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK | + (DWC_XDCI_GCTL_PRT_CAP_DEVICE << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS))); + + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG))); + + + // + // TODO: Program desired Speed and set LPM capable + // We will do this when SuperSpeed works. For now, + // force into High-Speed mode to aVOID anyone trying this + // on Super Speed port + // +#ifdef SUPPORT_SUPER_SPEED + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCFG_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | LocalCoreHandle->DesiredSpeed + ); +#else + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DCFG_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | DWC_XDCI_DCFG_DESIRED_HS_SPEED + ); +#endif + + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DCFG_REG))); + DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DSTS_REG))); + + // + // Enable Device Interrupt Events + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_DEVTEN_REG, + DWC_XDCI_DEVTEN_DEVICE_INTS + ); + + // + // Program the desired role + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GCTL_REG, + (UsbRegRead (BaseAddr, DWC_XDCI_GCTL_REG) & ~DWC_XDCI_GCTL_PRT_CAP_DIR_MASK) | (LocalCoreHandle->Role << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS) + ); + + // + // Clear USB2 suspend for start new config command + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB2PHYCFG_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) + ); + // + // Clear USB3 suspend for start new config command + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_GUSB3PIPECTL_REG (0), + (UsbRegRead (BaseAddr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) + ); + // + // Issue DEPSTARTCFG command for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_START_NEW_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for START_NEW_CONFIG EP command on xDCI\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_START_NEW_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue START_NEW_CONFIG EP command on xDCI\n")); + return status; + } + + // + // Issue DEPCFG command for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP0\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_SET_EP_CONFIG, + &EpCmdParams); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP0\n")); + return status; + } + + // + // Issue DEPCFG command for EP1 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[1].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for SET_EP_CONFIG command on xDCI for EP1\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 1, + EPCMD_SET_EP_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue SET_EP_CONFIG command on xDCI for EP1\n")); + return status; + } + + // + // Issue DEPXFERCFG command for EP0 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[0].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 0, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); + return status; + } + + // + // Issue DEPXFERCFG command for EP1 + // + status = DwcXdciCoreInitEpCmdParams ( + LocalCoreHandle, + &LocalCoreHandle->EpHandles[1].EpInfo, + DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); + return status; + } + + // + // Issue the command + // + status = DwcXdciCoreIssueEpCmd ( + LocalCoreHandle, + 1, + EPCMD_SET_EP_XFER_RES_CONFIG, + &EpCmdParams + ); + + if (status) { + DEBUG ((DEBUG_INFO, "DwcXdciCoreInit: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); + return status; + } + + // + // Prepare a Buffer for SETUP packet + // + LocalCoreHandle->Trbs = (DWC_XDCI_TRB *)(UINTN)((UINT32)(UINTN) + LocalCoreHandle->UnalignedTrbs + + (DWC_XDCI_TRB_BYTE_ALIGNMENT - + ((UINT32)(UINTN)LocalCoreHandle->UnalignedTrbs % + DWC_XDCI_TRB_BYTE_ALIGNMENT))); + + DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ unalignedTrbs address is 0x%x\n", LocalCoreHandle->UnalignedTrbs)); + DEBUG ((DEBUG_INFO, "(DwcXdciCoreInit)@@@@@@@@@ TRB address is 0x%x\n", LocalCoreHandle->Trbs)); + + // + // Allocate Setup Buffer that is 8-byte aligned + // + LocalCoreHandle->AlignedSetupBuffer = LocalCoreHandle->DefaultSetupBuffer + + (DWC_XDCI_SETUP_BUFF_SIZE - + ((UINT32)(UINTN)(LocalCoreHandle->DefaultSetupBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); + + // + // Aligned Buffer for status phase + // + LocalCoreHandle->AlignedMiscBuffer = LocalCoreHandle->MiscBuffer + + (DWC_XDCI_SETUP_BUFF_SIZE - + ((UINT32)(UINTN)(LocalCoreHandle->AlignedMiscBuffer) % DWC_XDCI_SETUP_BUFF_SIZE)); + + // + // We will queue SETUP request when we see bus reset + // + + // + // Enable Physical Endpoints 0 + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EP_DALEPENA_REG, + UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 0) + ); + + // + // Enable Physical Endpoints 1 + // + UsbRegWrite ( + BaseAddr, + DWC_XDCI_EP_DALEPENA_REG, + UsbRegRead (BaseAddr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 1) + ); + + DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", UsbRegRead (BaseAddr, DWC_XDCI_DEVTEN_REG))); + return status; + + +} + + +EFI_STATUS +UsbXdciCoreFlushEpFifo ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + UINT32 EpNum; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "DwcXdciEpCancelTransfer: INVALID handle\n")); + return EFI_DEVICE_ERROR; + } + + // + // Get physical EP num + // + EpNum = DwcXdciGetPhysicalEpNum (EpInfo->EpNum, EpInfo->EpDir); + DwcXdciCoreFlushEpFifo(CoreHandle, EpNum); + + return Status; +} diff --git a/libefiusb/device_mode/XdciDWC.h b/libefiusb/device_mode/XdciDWC.h index c756899c..f4178f02 100644 --- a/libefiusb/device_mode/XdciDWC.h +++ b/libefiusb/device_mode/XdciDWC.h @@ -1,742 +1,751 @@ -/** @file - Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _XDCI_DWC_H_ -#define _XDCI_DWC_H_ - -#include "XdciCommon.h" -#include "XdciDevice.h" -#include "protocol/UsbDeviceLib.h" - -#define DWC_XDCI_MAX_ENDPOINTS (16) -#define DWC_XDCI_SS_CTRL_EP_MPS (512) -#define DWC_XDCI_HS_CTRL_EP_MPS (64) -#define DWC_XDCI_FS_CTRL_EP_MPS (64) -#define DWC_XDCI_LS_CTRL_EP_MPS (8) -#define DWC_XDCI_SS_CTRL_BUF_SIZE (512) -#define DWC_XDCI_SETUP_BUFF_SIZE (8) -#define DWC_XDCI_MAX_EVENTS_PER_BUFFER (16) -#define DWC_XDCI_TRB_BYTE_ALIGNMENT (16) -#define DWC_XDCI_DEFAULT_TX_FIFO_SIZE (1024) -#define DWC_XDCI_TRB_NUM (32) -#define DWC_XDCI_MASK (DWC_XDCI_TRB_NUM - 1) - -#define DWC_XDCI_MAX_DELAY_ITERATIONS (1000) - -#define DWC_XDCI_GSBUSCFG0_REG (0xC100) -#define DWC_XDCI_GSBUSCFG1_REG (0xC104) -#define DWC_XDCI_GTXTHRCFG_REG (0xC108) -#define DWC_XDCI_GRXTHRCFG_REG (0xC10C) - -// -// Global Control Register and bit definitions -// -#define DWC_XDCI_GCTL_REG (0xC110) -#define DWC_XDCI_GCTL_PWRDNSCALE_MASK (0xFFF80000) -#define DWC_XDCI_GCTL_PWRDNSCALE_VAL (0x13880000) -#define DWC_XDCI_GCTL_U2RSTECN_MASK (0x00010000) -#define DWC_XDCI_GCTL_PRT_CAP_DIR_MASK (0x00003000) -#define DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS (12) -#define DWC_XDCI_GCTL_PRT_CAP_HOST (1) -#define DWC_XDCI_GCTL_PRT_CAP_DEVICE (2) -#define DWC_XDCI_GCTL_PRT_CAP_OTG (3) -#define DWC_XDCI_GCTL_RAMCLKSEL_MASK (0x000000C0) -#define DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK (0x00000030) -#define DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK (0x00000001) -#define DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK (0x00000008) - -#define DWC_XDCI_GSTS_REG (0xC118) -#define DWC_XDCI_GSNPSID_REG (0xC120) -#define DWC_XDCI_GGPIO_REG (0xC124) -#define DWC_XDCI_GUID_REG (0xC128) -#define DWC_XDCI_GUCTL_REG (0xC12C) -#define DWC_XDCI_GBUSERRADDR (0xC130) - -// -// Global Hardware Parameters Registers -// -#define DWC_XDCI_GHWPARAMS0_REG (0xC140) -#define DWC_XDCI_GHWPARAMS1_REG (0xC144) -#define DWC_XDCI_GHWPARAMS1_NUM_INT_MASK (0x1F8000) -#define DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS (15) - -#define DWC_XDCI_GHWPARAMS2_REG (0xC148) -#define DWC_XDCI_GHWPARAMS3_REG (0xC14C) -#define DWC_XDCI_GHWPARAMS4_REG (0xC150) -#define DWC_XDCI_GHWPARAMS4_CACHE_TRBS_PER_XFER_MASK (0x0000003F) -#define DWC_XDCI_GHWPARAMS5_REG (0xC154) -#define DWC_XDCI_GHWPARAMS6_REG (0xC158) -#define DWC_XDCI_GHWPARAMS7_REG (0xC15C) -#define DWC_XDCI_GHWPARAMS8_REG (0xC600) - -#define DWC_XDCI_GDBGFIFOSPACE_REG (0xC160) - -#define DWC_XDCI_GUSB2PHYCFG_REG(n) (0xC200 + (n << 2)) -#define DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK (0x00008000) -#define DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK (0x00000040) - -#define DWC_XDCI_GUSB3PIPECTL_REG(n) (0xC2C0 + (n << 2)) -#define DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK (0x00020000) - -#define DWC_XDCI_GTXFIFOSIZ_REG(n) (0xC300 + (n << 2)) -#define DWC_XDCI_GTXFIFOSIZ_START_ADDRESS_MASK (0xFFFF0000) -#define DWC_XDCI_GTXFIFOSIZ_START_ADDRESS_BIT_POS (16) -#define DWC_XDCI_GRXFIFOSIZ_REG(n) (0xC380 + (n << 2)) - -// -// Global Event Buffer Registers -// -#define DWC_XDCI_GEVNTADR_REG(n) (0xC400 + (n << 4)) -#define DWC_XDCI_EVNTSIZ_REG(n) (0xC408 + (n << 4)) -#define DWC_XDCI_EVNTSIZ_MASK (0x0000FFFF) -#define DWC_XDCI_EVNT_INTR_MASK (0x80000000) -#define DWC_XDCI_EVNTCOUNT_REG(n) (0xC40C + (n << 4)) -#define DWC_XDCI_EVNTCOUNT_MASK (0x0000FFFF) - -// -// Device Configuration Register and Bit Definitions -// -#define DWC_XDCI_DCFG_REG (0xC700) -#define DWC_XDCI_DCFG_LPM_CAPABLE_MASK (0x00400000) -#define DWC_XDCI_DCFG_DEV_ADDRESS_MASK (0x000003F8) -#define DWC_XDCI_DCFG_DEV_ADDRESS_BIT_POS (3) -#define DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK (0x00000007) -#define DWC_XDCI_DCFG_DESIRED_SS_SPEED (0x00000004) -#define DWC_XDCI_DCFG_DESIRED_FS_SPEED (0x00000001) -#define DWC_XDCI_DCFG_DESIRED_HS_SPEED (0x00000000) - -// -// Device Control Register -// -#define DWC_XDCI_DCTL_REG (0xC704) -#define DWC_XDCI_DCTL_RUN_STOP_MASK (0x80000000) -#define DWC_XDCI_DCTL_RUN_STOP_BIT_POS (31) -#define DWC_XDCI_DCTL_CSFTRST_MASK (0x40000000) -#define DWC_XDCI_DCTL_CSFTRST_BIT_POS (30) -#define DWC_XDCI_DCTL_KEEP_CONNECT_MASK (0x00080000) -#define DWC_XDCI_DCTL_KEEP_CONNECT_BIT_POS (19) -#define DWC_XDCI_DCTL_CSFTRST_BIT_POS (30) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK (0x000001E0) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS (5) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_NO_ACTION (1) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_SS_DISABLED (4) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT (5) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_SS_INACTIVE (6) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_RECOVERY (8) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_COMPLIANCE (10) -#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_REMOTE_WAKEUP (8) - -// -// Device Event Enable Register -// -#define DWC_XDCI_DEVTEN_REG (0xC708) -#define DWC_XDCI_DEVTEN_DISCONN_DET_EN_MASK (0x00000001) -#define DWC_XDCI_DEVTEN_RESET_DET_EN_MASK (0x00000002) -#define DWC_XDCI_DEVTEN_CONN_DONE_DET_EN_MASK (0x00000004) -#define DWC_XDCI_DEVTEN_LINK_STATE_CHANGE_DET_EN_MASK (0x00000008) -#define DWC_XDCI_DEVTEN_RESUME_WAKEUP_DET_EN_MASK (0x00000010) -#define DWC_XDCI_DEVTEN_HIBERNATION_REQ_EN_MASK (0x00000020) -#define DWC_XDCI_DEVTEN_U3L2L1_DET_EN_MASK (0x00000040) -#define DWC_XDCI_DEVTEN_SOF_DET_EN_MASK (0x00000080) -#define DWC_XDCI_DEVTEN_ERRATIC_ERR_DET_EN_MASK (0x00000200) -#define DWC_XDCI_DEVTEN_VNDR_DEV_TST_RX_DET_EN_MASK (0x00001000) - -#define DWC_XDCI_DEVTEN_DEVICE_INTS (DWC_XDCI_DEVTEN_DISCONN_DET_EN_MASK | \ - DWC_XDCI_DEVTEN_RESET_DET_EN_MASK | DWC_XDCI_DEVTEN_CONN_DONE_DET_EN_MASK | \ - DWC_XDCI_DEVTEN_LINK_STATE_CHANGE_DET_EN_MASK | DWC_XDCI_DEVTEN_RESUME_WAKEUP_DET_EN_MASK | \ - DWC_XDCI_DEVTEN_HIBERNATION_REQ_EN_MASK | DWC_XDCI_DEVTEN_U3L2L1_DET_EN_MASK | \ - DWC_XDCI_DEVTEN_ERRATIC_ERR_DET_EN_MASK) - -#define DWC_XDCI_EVENT_BUFF_BULK_STREAM_ID_MASK (0xFFFF0000) -#define DWC_XDCI_EVENT_BUFF_ISOCH_UFRAME_NUM_MASK (0xFFFF0000) -#define DWC_XDCI_EVENT_BUFF_EP_CMD_TYPE_MASK (0x0F000000) -#define DWC_XDCI_EVENT_BUFF_EP_XFER_RES_INDEX_MASK (0x007F0000) -#define DWC_XDCI_EVENT_BUFF_EP_XFER_ACTIVE_MASK (0x00008000) -#define DWC_XDCI_EVENT_BUFF_EP_CTRL_DATA_REQ_MASK (0x00001000) -#define DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK (0x00002000) -#define DWC_XDCI_EVENT_BUFF_EP_LST_MASK (0x00008000) -#define DWC_XDCI_EVENT_BUFF_EP_MISSED_ISOCH_MASK (0x00008000) -#define DWC_XDCI_EVENT_BUFF_EP_IOC_MASK (0x00004000) -#define DWC_XDCI_EVENT_BUFF_EP_LAST_PKT_MASK (0x00002000) -#define DWC_XDCI_EVENT_BUFF_EP_STREAM_NOT_FND_MASK (0x00002000) -#define DWC_XDCI_EVENT_BUFF_EP_STREAM_FND_MASK (0x00001000) -#define DWC_XDCI_EVENT_BUFF_EP_ERR_NO_RES_MASK (0x00001000) -#define DWC_XDCI_EVENT_BUFF_EP_INVALID_RES_MASK (0x00001000) - -#define DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK (0x000003C0) -#define DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS (6) -#define DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT (1) -#define DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS (2) -#define DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY (3) -#define DWC_XDCI_EVENT_BUFF_EP_STREAM_EVENT (6) -#define DWC_XDCI_EVENT_BUFF_EP_CMD_CMPLT (7) - -#define DWC_XDCI_EVENT_BUFF_EP_NUM_MASK (0x0000003E) -#define DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS (1) - -#define DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK (0x0000F000) - - -#define DWC_XDCI_EVENT_BUFF_DEV_HIRD_MASK (0x01E00000) -#define DWC_XDCI_EVENT_BUFF_DEV_HIRD_BIT_POS (21) -#define DWC_XDCI_EVENT_BUFF_DEV_SS_EVENT_MASK (0x00100000) -#define DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_MASK (0x000F0000) -#define DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_BIT_POS (16) - -#define DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK (0x00000F00) -#define DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS (8) -#define DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT (12) -#define DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT (11) -#define DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT (10) -#define DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT (9) -#define DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT (7) -#define DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT (5) -#define DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT (4) -#define DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT (3) -#define DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT (2) -#define DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT (1) -#define DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT (0) - -#define DWC_XDCI_EVENT_DEV_MASK (0x00000001) - -// -// Device Status Register and Bit Definitions -// -#define DWC_XDCI_DSTS_REG (0xC70C) -#define DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK (0x00400000) -#define DWC_XDCI_DSTS_DEV_CTRL_HALTED_BIT_POS (22) -#define DWC_XDCI_DSTS_CORE_IDLE (1 << 23) -#define DWC_XDCI_DSTS_CONN_SPEED_MASK (0x00000007) -#define DWC_XDCI_DSTS_LINK_STATE_MASK (0x003C0000) -#define DWC_XDCI_DSTS_LINK_STATE_DISCONNECT (0x00100000) - -// -// Device Generic Command Parameter Register -// -#define DWC_XDCI_DGCMD_PARAM_REG (0xC710) -#define DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK (0x0000001F) -#define DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK (0x00000020) -#define DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_BIT_POS (5) - -// -// Device Generic Command Register -// -#define DWC_XDCI_DGCMD_REG (0xC714) -#define DWC_XDCI_DGCMD_CMD_STATUS_MASK (0x00008000) -#define DWC_XDCI_DGCMD_CMD_ACTIVE_MASK (0x00000400) -#define DWC_XDCI_DGCMD_CMD_IOC_MASK (0x00000100) -#define DWC_XDCI_DGCMD_CMD_TYPE_MASK (0x000000FF) -#define DWC_XDCI_DGCMD_CMD_SET_PERIODIC_PARAMS (0x2) -#define DWC_XDCI_DGCMD_CMD_SET_SCRATCH_PAD_BUFF_ARR_LO (0x4) -#define DWC_XDCI_DGCMD_CMD_SET_SCRATCH_PAD_BUFF_ARR_HI (0x5) -#define DWC_XDCI_DGCMD_CMD_XMIT_DEVICE_NOTIFICATION (0x7) -#define DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH (0x9) -#define DWC_XDCI_DGCMD_CMD_ALL_FIFO_FLUSH (0xA) -#define DWC_XDCI_DGCMD_CMD_SET_EP_NRDY (0xC) -#define DWC_XDCI_DGCMD_CMD_RUN_SOC_BUS_LPBK (0x10) - -// -// Device Active USB EP Enable Register -// -#define DWC_XDCI_EP_DALEPENA_REG (0xC720) - -// -// Device Physical EP CMD Param 2 Register. Value is 32-bit -// -#define DWC_XDCI_EPCMD_PARAM2_REG(n) (0xC800 + (n << 4)) - -// -// Device Physical EP CMD Param 1 Register. Value is 32-bit -// -#define DWC_XDCI_EPCMD_PARAM1_REG(n) (0xC804 + (n << 4)) - -// -// Device Physical EP CMD Param 0 Register. Value is 32-bit -// -#define DWC_XDCI_EPCMD_PARAM0_REG(n) (0xC808 + (n << 4)) - -// -// Device Physical EP Command Registers and Bit Definitions -// -#define DWC_XDCI_EPCMD_REG(n) (0xC80C + (n << 4)) -#define DWC_XDCI_EPCMD_RES_IDX_MASK (0x007F0000) -#define DWC_XDCI_EPCMD_RES_IDX_BIT_POS (16) -#define DWC_XDCI_EPCMD_CMDTYPE_MASK (0x0000000F) -#define DWC_XDCI_EPCMD_SET_EP_CONFIG (0x1) -#define DWC_XDCI_EPCMD_SET_EP_XFER_RES_CONFIG (0x2) -#define DWC_XDCI_EPCMD_GET_EP_STATE (0x3) -#define DWC_XDCI_EPCMD_SET_STALL (0x4) -#define DWC_XDCI_EPCMD_CLEAR_STALL (0x5) -#define DWC_XDCI_EPCMD_START_XFER (0x6) -#define DWC_XDCI_EPCMD_UPDATE_XFER (0x7) -#define DWC_XDCI_EPCMD_END_XFER (0x8) -#define DWC_XDCI_EPCMD_START_NEW_CONFIG (0x9) - -#define DWC_XDCI_EPCMD_CMD_IOC_MASK (0x00000100) -#define DWC_XDCI_EPCMD_CMD_ACTIVE_MASK (0x00000400) -#define DWC_XDCI_EPCMD_HIGH_PRIO_MASK (0x00000800) -#define DWC_XDCI_EPCMD_FORCE_RM_MASK (0x00000800) - -// -// Command status and parameter values same as event status and parameters values -// -#define DWC_XDCI_EPCMD_CMD_STATUS_MASK (0x0000F000) - -// -// Command Params bit masks -// -#define DWC_XDCI_PARAM1_SET_EP_CFG_FIFO_BASED_MASK (0x80000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_BULK_BASED_MASK (0x40000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_MASK (0x3C000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_MASK (0x02000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK (0x01000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_MASK (0x00FF0000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS (16) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EBC_MASK (0x00008000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK (0x00003F00) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_BIT_POS (8) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_STRM_MASK (0x00002000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK (0x00000400) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK (0x00000200) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK (0x00000100) -#define DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK (0x0000001F) - -// -// CMD 1 param 0 -// -#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MASK (0xC0000000) -#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_BIT_POS (30) -#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE (0) -#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_RESTORE_ST (1) -#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE (2) -#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE (3) -#define DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_MASK (0x03C00000) -#define DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_BIT_POS (22) -#define DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_MASK (0x003E0000) -#define DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_BIT_POS (17) -#define DWC_XDCI_PARAM0_SET_EP_CFG_MPS_MASK (0x00003FF8) -#define DWC_XDCI_PARAM0_SET_EP_CFG_MPS_BIT_POS (3) -#define DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_MASK (0x00000006) -#define DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_BIT_POS (1) -#define DWC_XDCI_PARAM0_EP_TYPE_CTRL (0) -#define DWC_XDCI_PARAM0_EP_TYPE_ISOCH (1) -#define DWC_XDCI_PARAM0_EP_TYPE_BULK (2) -#define DWC_XDCI_PARAM0_EP_TYPE_INTR (3) - -// -// CMD 1 param 1 -// -#define DWC_XDCI_PARAM1_SET_EP_CFG_BULK_BASED_MASK (0x40000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_MASK (0x3C000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_BIT_POS (26) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_MASK (0x02000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_BIT_POS (25) -#define DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK (0x01000000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_MASK (0x00FF0000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS (16) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EBC_MASK (0x00008000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK (0x00003F00) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_BIT_POS (8) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_STRM_MASK (0x00002000) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK (0x00000400) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK (0x00000200) -#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK (0x00000100) -#define DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK (0x0000001F) - -// -// CMD 2 param 0 -// -#define DWC_XDCI_PARAM0_SET_EP_XFER_RES_NUM_MASK (0x0000FFFF) - -// -// CMD 3 param 2 -// -#define DWC_XDCI_PARAM2_GET_EP_STATE_MASK (0xFFFFFFFF) - -// -// CMD 6 param 1 -// -#define DWC_XDCI_PARAM1_STRT_XFER_TD_ADDR_LO_MASK (0xFFFFFFFF) - -// -// CMD 6 param 0 -// -#define DWC_XDCI_PARAM0_STRT_XFER_TD_ADDR_HI_MASK (0xFFFFFFFF) - -// -// Transfer Request Block Fields' Bit Definitions -// -#define DWC_XDCI_TRB_BUFF_SIZE_MASK (0x00FFFFFF) -#define DWC_XDCI_TRB_PCM1_MASK (0x03000000) -#define DWC_XDCI_TRB_PCM1_BIT_POS (24) -#define DWC_XDCI_TRB_STATUS_MASK (0xF0000000) -#define DWC_XDCI_TRB_STATUS_BIT_POS (28) -#define DWC_XDCI_TRB_STATUS_OK (0) -#define DWC_XDCI_TRB_STATUS_MISSED_ISOCH (1) -#define DWC_XDCI_TRB_STATUS_SETUP_PENDING (2) - -#define DWC_XDCI_TRB_CTRL_HWO_MASK (0x00000001) -#define DWC_XDCI_TRB_CTRL_LST_TRB_MASK (0x00000002) -#define DWC_XDCI_TRB_CTRL_LST_TRB_BIT_POS (1) -#define DWC_XDCI_TRB_CTRL_CHAIN_BUFF_MASK (0x00000004) -#define DWC_XDCI_TRB_CTRL_CHAIN_BUFF_BIT_POS (2) -#define DWC_XDCI_TRB_CTRL_CSP_MASK (0x00000008) -#define DWC_XDCI_TRB_CTRL_CSP_BIT_POS (3) -#define DWC_XDCI_TRB_CTRL_TYPE_MASK (0x000003F0) -#define DWC_XDCI_TRB_CTRL_TYPE_BIT_POS (4) -#define DWC_XDCI_TRB_CTRL_TYPE_NORMAL (1) -#define DWC_XDCI_TRB_CTRL_TYPE_SETUP (2) -#define DWC_XDCI_TRB_CTRL_TYPE_STATUS2 (3) -#define DWC_XDCI_TRB_CTRL_TYPE_STATUS3 (4) -#define DWC_XDCI_TRB_CTRL_TYPE_DATA (5) -#define DWC_XDCI_TRB_CTRL_TYPE_ISOCH_FIRST (6) -#define DWC_XDCI_TRB_CTRL_TYPE_ISOCH (7) -#define DWC_XDCI_TRB_CTRL_TYPE_LINK_TRB (8) -#define DWC_XDCI_TRB_CTRL_IOSP_MISOCH_MASK (0x00000400) -#define DWC_XDCI_TRB_CTRL_IOSP_MISOCH_BIT_POS (10) -#define DWC_XDCI_TRB_CTRL_IOC_MASK (0x00000800) -#define DWC_XDCI_TRB_CTRL_IOC_BIT_POS (11) -#define DWC_XDCI_TRB_CTRL_STRM_ID_SOF_NUM_MASK (0x3FFFC000) -#define DWC_XDCI_TRB_CTRL_STRM_ID_SOF_BIT_POS (14) - -#define DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES (4) -#define DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES (12) - -typedef enum { - EPCMD_SET_EP_CONFIG = 1, - EPCMD_SET_EP_XFER_RES_CONFIG, - EPCMD_GET_EP_STATE, - EPCMD_SET_STALL, - EPCMD_CLEAR_STALL, - EPCMD_START_XFER, - EPCMD_UPDATE_XFER, - EPCMD_END_XFER, - EPCMD_START_NEW_CONFIG = 9 -} DWC_XDCI_ENDPOINT_CMD; - -typedef enum { - ON = 0, - SLEEP = 2, - SUSPEND, - DISCONNECTED, - EARLY_SUSPEND, - RESET = 14, - RESUME = 15 -} DWC_XDCI_HS_LINK_STATE; - -typedef enum { - TRBCTL_NORMAL = 1, - TRBCTL_SETUP, - TRBCTL_2_PHASE, - TRBCTL_3_PHASE, - TRBCTL_CTRL_DATA_PHASE, - TRBCTL_ISOCH_FIRST, - TRBCTL_ISOCH, - TRBCTL_LINK -} DWC_XDCI_TRB_CONTROL; - -// -// DWC XDCI Endpoint Commands Parameters struct -// -typedef struct { - UINT32 Param2; - UINT32 Param1; - UINT32 Param0; -} DWC_XDCI_ENDPOINT_CMD_PARAMS; - -// -// Event Buffer Struct -// -typedef struct { - UINT32 Event; - UINT32 DevTstLmp1; - UINT32 DevTstLmp2; - UINT32 Reserved; -} DWC_XDCI_EVENT_BUFFER; - -// -// Transfer Request Block -// -typedef struct { - UINT32 BuffPtrLow; - UINT32 BuffPtrHigh; - UINT32 LenXferParams; - UINT32 TrbCtrl; -} DWC_XDCI_TRB; - -typedef struct { - USB_EP_INFO EpInfo; - DWC_XDCI_TRB *Trb; - USB_XFER_REQUEST XferHandle; - UINT32 CurrentXferRscIdx; - VOID *CoreHandle; - USB_EP_STATE State; - USB_EP_STATE OrgState; - BOOLEAN CheckFlag; -} DWC_XDCI_ENDPOINT; - -typedef struct { - // - // CbEventParams must be copied over by upper layer if - // it defers event processing - // - USB_DEVICE_CALLBACK_PARAM CbEventParams; - - // - // Callback function list - // - USB_DEVICE_CALLBACK_FUNC DevDisconnectCallback; - USB_DEVICE_CALLBACK_FUNC DevBusResetCallback; - USB_DEVICE_CALLBACK_FUNC DevResetDoneCallback; - USB_DEVICE_CALLBACK_FUNC DevLinkStateCallback; - USB_DEVICE_CALLBACK_FUNC DevWakeupCallback; - USB_DEVICE_CALLBACK_FUNC DevHibernationCallback; - USB_DEVICE_CALLBACK_FUNC DevSofCallback; - USB_DEVICE_CALLBACK_FUNC DevErraticErrCallback; - USB_DEVICE_CALLBACK_FUNC DevCmdCmpltCallback; - USB_DEVICE_CALLBACK_FUNC DevBuffOvflwCallback; - USB_DEVICE_CALLBACK_FUNC DevTestLmpRxCallback; - USB_DEVICE_CALLBACK_FUNC DevSetupPktReceivedCallback; - USB_DEVICE_CALLBACK_FUNC DevXferNrdyCallback; - USB_DEVICE_CALLBACK_FUNC DevXferDoneCallback; -} USB_DEV_CALLBACK_LIST; - -typedef struct { - VOID *ParentHandle; // Pointer to the parent this driver is associated - USB_CONTROLLER_ID Id; // ID of the controllers supported in our DCD - USB_SPEED DesiredSpeed; // Desired SS, HS, FS or LS Speeds for the core - USB_ROLE Role; // Desired role i.e. host, Device or OTG - USB_SPEED ActualSpeed; // Actual Speed - USB_DEVICE_STATE DevState; // Device state - UINT32 BaseAddress; // Register Base address - UINT32 Flags; // Init flags - UINT32 MaxDevIntLines; // One event Buffer per interrupt line - DWC_XDCI_EVENT_BUFFER EventBuffers [DWC_XDCI_MAX_EVENTS_PER_BUFFER * 2]; // Event Buffer pool - DWC_XDCI_EVENT_BUFFER *AlignedEventBuffers; // Aligned event Buffer pool - DWC_XDCI_EVENT_BUFFER *CurrentEventBuffer; // Current event Buffer address - DWC_XDCI_TRB UnalignedTrbs [(DWC_XDCI_MAX_ENDPOINTS + 1) * DWC_XDCI_TRB_NUM]; // TRBs. - DWC_XDCI_TRB *Trbs; // 16-bytes aligned TRBs. - DWC_XDCI_ENDPOINT EpHandles [DWC_XDCI_MAX_ENDPOINTS * 2]; // EPs, diretion in and out for each EP - UINT8 DefaultSetupBuffer [DWC_XDCI_SETUP_BUFF_SIZE * 2]; // Unaligned setup Buffer - UINT8 *AlignedSetupBuffer; // Aligned setup Buffer. Aligned to 8-byte boundary - UINT8 MiscBuffer [528]; // Unaligned misc Buffer - UINT8 *AlignedMiscBuffer; // Aligned misc Buffer - UINT32 LinkState; // Link state - UINT32 HirdVal; // HIRD value - USB_DEV_CALLBACK_LIST EventCallbacks; - volatile BOOLEAN InterrupProcessing; -} XDCI_CORE_HANDLE; - -// -// DWC XDCI API prototypes -// -EFI_STATUS -EFIAPI -DwcXdciCoreInit ( - IN USB_DEV_CONFIG_PARAMS *ConfigParams, - IN VOID *ParentHandle, - IN VOID **CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreDeinit ( - IN VOID *CoreHandle, - IN UINT32 flags - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreRegisterCallback ( - IN VOID *CoreHandle, - IN USB_DEVICE_EVENT_ID Event, - IN USB_DEVICE_CALLBACK_FUNC CallbackFunc - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreUnregisterCallback ( - IN VOID *CoreHandle, - IN USB_DEVICE_EVENT_ID Event - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreIsrRoutine ( - IN VOID *CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreIsrRoutineTimerBased ( - IN VOID *CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreConnect ( - IN VOID *CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreDisconnect ( - IN VOID *CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreGetSpeed ( - IN VOID *CoreHandle, - IN USB_SPEED *Speed - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreSetAddress ( - IN VOID *CoreHandle, - IN UINT32 Address - ); - -EFI_STATUS -EFIAPI -DwcXdciCoreSetConfig ( - IN VOID *CoreHandle, - IN UINT32 ConfigNum - ); - -EFI_STATUS -EFIAPI -DwcXdciSetLinkState ( - IN VOID *CoreHandle, - IN USB_DEVICE_SS_LINK_STATE State - ); - -EFI_STATUS -EFIAPI -DwcXdciInitEp ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -EFIAPI -DwcXdciEpEnable ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -EFIAPI -DwcXdciEpDisable ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -EFIAPI -DwcXdciEpStall ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -EFIAPI -DwcXdciEpClearStall ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -EFIAPI -DwcXdciEpSetNrdy ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -EFIAPI -DwcXdciEp0ReceiveSetupPkt ( - IN VOID *CoreHandle, - IN UINT8 *Buffer - ); - -EFI_STATUS -EFIAPI -DwcXdciEp0ReceiveStatusPkt ( - IN VOID *CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciEp0SendStatusPkt ( - IN VOID *CoreHandle - ); - -EFI_STATUS -EFIAPI -DwcXdciEpTxData ( - IN VOID *CoreHandle, - IN USB_XFER_REQUEST *XferReq - ); - -EFI_STATUS -EFIAPI -DwcXdciEpRxData( - IN VOID *CoreHandle, - IN USB_XFER_REQUEST *XferReq - ); - -EFI_STATUS -EFIAPI -DwcXdciEpCancelTransfer ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -usbProcessDeviceResetDet ( - IN XDCI_CORE_HANDLE *CoreHandle - ); - -EFI_STATUS -usbProcessDeviceResetDone ( - IN XDCI_CORE_HANDLE *CoreHandle - ); - -UINT32 -UsbGetPhysicalEpNum ( - IN UINT32 EndpointNum, - IN USB_EP_DIR EndpointDir - ); - -UINT32 -UsbRegRead ( - IN UINT32 Base, - IN UINT32 Offset - ); - -VOID -UsbRegWrite ( - IN UINT32 Base, - IN UINT32 Offset, - IN UINT32 val - ); - -EFI_STATUS -UsbXdciCoreFlushEpFifo ( - IN VOID *CoreHandle, - IN USB_EP_INFO *EpInfo - ); -#endif - +/** @file + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _XDCI_DWC_H_ +#define _XDCI_DWC_H_ + +#include "XdciCommon.h" +#include "XdciDevice.h" +#include "protocol/UsbDeviceLib.h" + +#define DWC_XDCI_MAX_ENDPOINTS (16) +#define DWC_XDCI_SS_CTRL_EP_MPS (512) +#define DWC_XDCI_HS_CTRL_EP_MPS (64) +#define DWC_XDCI_FS_CTRL_EP_MPS (64) +#define DWC_XDCI_LS_CTRL_EP_MPS (8) +#define DWC_XDCI_SS_CTRL_BUF_SIZE (512) +#define DWC_XDCI_SETUP_BUFF_SIZE (8) +#define DWC_XDCI_MAX_EVENTS_PER_BUFFER (16) +#define DWC_XDCI_TRB_BYTE_ALIGNMENT (16) +#define DWC_XDCI_DEFAULT_TX_FIFO_SIZE (1024) +#define DWC_XDCI_TRB_NUM (32) +#define DWC_XDCI_MASK (DWC_XDCI_TRB_NUM - 1) + +/* TODO: Platform-specific define. Later move it to platform-specific + * header file + * */ +#define DWC_XDCI_MAX_DELAY_ITERATIONS (1000) + +/* Top-level register offsets from base address */ +#define DWC_XDCI_GLOBAL_REG_OFFSET (0xC100) +#define DWC_XDCI_DEVICE_REG_OFFSET (0xC700) +#define DWC_XDCI_OTG_BC_REG_OFFSET (0xCC00) +#define DWC_XDCI_GSBUSCFG0_REG (0xC100) +#define DWC_XDCI_GSBUSCFG1_REG (0xC104) +#define DWC_XDCI_GTXTHRCFG_REG (0xC108) +#define DWC_XDCI_GRXTHRCFG_REG (0xC10C) + +// +// Global Control Register and bit definitions +// +#define DWC_XDCI_GCTL_REG (0xC110) +#define DWC_XDCI_GCTL_PWRDNSCALE_MASK (0xFFF80000) +#define DWC_XDCI_GCTL_PWRDNSCALE_VAL (0x13880000) +#define DWC_XDCI_GCTL_U2RSTECN_MASK (0x00010000) +#define DWC_XDCI_GCTL_PRT_CAP_DIR_MASK (0x00003000) +#define DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS (12) +#define DWC_XDCI_GCTL_PRT_CAP_HOST (1) +#define DWC_XDCI_GCTL_PRT_CAP_DEVICE (2) +#define DWC_XDCI_GCTL_PRT_CAP_OTG (3) +#define DWC_XDCI_GCTL_RAMCLKSEL_MASK (0x000000C0) +#define DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK (0x00000030) +#define DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK (0x00000001) +#define DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK (0x00000008) + +#define DWC_XDCI_GSTS_REG (0xC118) +#define DWC_XDCI_GSNPSID_REG (0xC120) +#define DWC_XDCI_GGPIO_REG (0xC124) +#define DWC_XDCI_GUID_REG (0xC128) +#define DWC_XDCI_GUCTL_REG (0xC12C) +#define DWC_XDCI_GBUSERRADDR (0xC130) + +// +// Global Hardware Parameters Registers +// +#define DWC_XDCI_GHWPARAMS0_REG (0xC140) +#define DWC_XDCI_GHWPARAMS1_REG (0xC144) +#define DWC_XDCI_GHWPARAMS1_NUM_INT_MASK (0x1F8000) +#define DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS (15) + +#define DWC_XDCI_GHWPARAMS2_REG (0xC148) +#define DWC_XDCI_GHWPARAMS3_REG (0xC14C) +#define DWC_XDCI_GHWPARAMS4_REG (0xC150) +#define DWC_XDCI_GHWPARAMS4_CACHE_TRBS_PER_XFER_MASK (0x0000003F) +#define DWC_XDCI_GHWPARAMS5_REG (0xC154) +#define DWC_XDCI_GHWPARAMS6_REG (0xC158) +#define DWC_XDCI_GHWPARAMS7_REG (0xC15C) +#define DWC_XDCI_GHWPARAMS8_REG (0xC600) + +#define DWC_XDCI_GDBGFIFOSPACE_REG (0xC160) + +#define DWC_XDCI_GUSB2PHYCFG_REG(n) (0xC200 + (n << 2)) +#define DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK (0x00008000) +#define DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK (0x00000040) + +#define DWC_XDCI_GUSB3PIPECTL_REG(n) (0xC2C0 + (n << 2)) +#define DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK (0x00020000) + +#define DWC_XDCI_GTXFIFOSIZ_REG(n) (0xC300 + (n << 2)) +#define DWC_XDCI_GTXFIFOSIZ_START_ADDRESS_MASK (0xFFFF0000) +#define DWC_XDCI_GTXFIFOSIZ_START_ADDRESS_BIT_POS (16) +#define DWC_XDCI_GRXFIFOSIZ_REG(n) (0xC380 + (n << 2)) + +// +// Global Event Buffer Registers +// +#define DWC_XDCI_GEVNTADR_REG(n) (0xC400 + (n << 4)) +#define DWC_XDCI_EVNTSIZ_REG(n) (0xC408 + (n << 4)) +#define DWC_XDCI_EVNTSIZ_MASK (0x0000FFFF) +#define DWC_XDCI_EVNT_INTR_MASK (0x80000000) +#define DWC_XDCI_EVNTCOUNT_REG(n) (0xC40C + (n << 4)) +#define DWC_XDCI_EVNTCOUNT_MASK (0x0000FFFF) + +// +// Device Configuration Register and Bit Definitions +// +#define DWC_XDCI_DCFG_REG (0xC700) +#define DWC_XDCI_DCFG_LPM_CAPABLE_MASK (0x00400000) +#define DWC_XDCI_DCFG_DEV_ADDRESS_MASK (0x000003F8) +#define DWC_XDCI_DCFG_DEV_ADDRESS_BIT_POS (3) +#define DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK (0x00000007) +#define DWC_XDCI_DCFG_DESIRED_SS_SPEED (0x00000004) +#define DWC_XDCI_DCFG_DESIRED_FS_SPEED (0x00000001) +#define DWC_XDCI_DCFG_DESIRED_HS_SPEED (0x00000000) + +// +// Device Control Register +// +#define DWC_XDCI_DCTL_REG (0xC704) +#define DWC_XDCI_DCTL_RUN_STOP_MASK (0x80000000) +#define DWC_XDCI_DCTL_RUN_STOP_BIT_POS (31) +#define DWC_XDCI_DCTL_CSFTRST_MASK (0x40000000) +#define DWC_XDCI_DCTL_CSFTRST_BIT_POS (30) +#define DWC_XDCI_DCTL_KEEP_CONNECT_MASK (0x00080000) +#define DWC_XDCI_DCTL_KEEP_CONNECT_BIT_POS (19) +#define DWC_XDCI_DCTL_CSFTRST_BIT_POS (30) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK (0x000001E0) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS (5) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_NO_ACTION (1) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_SS_DISABLED (4) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT (5) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_SS_INACTIVE (6) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_RECOVERY (8) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_COMPLIANCE (10) +#define DWC_XDCI_DCTL_STATE_CHANGE_REQ_REMOTE_WAKEUP (8) + +// +// Device Event Enable Register +// +#define DWC_XDCI_DEVTEN_REG (0xC708) +#define DWC_XDCI_DEVTEN_DISCONN_DET_EN_MASK (0x00000001) +#define DWC_XDCI_DEVTEN_RESET_DET_EN_MASK (0x00000002) +#define DWC_XDCI_DEVTEN_CONN_DONE_DET_EN_MASK (0x00000004) +#define DWC_XDCI_DEVTEN_LINK_STATE_CHANGE_DET_EN_MASK (0x00000008) +#define DWC_XDCI_DEVTEN_RESUME_WAKEUP_DET_EN_MASK (0x00000010) +#define DWC_XDCI_DEVTEN_HIBERNATION_REQ_EN_MASK (0x00000020) +#define DWC_XDCI_DEVTEN_U3L2L1_DET_EN_MASK (0x00000040) +#define DWC_XDCI_DEVTEN_SOF_DET_EN_MASK (0x00000080) +#define DWC_XDCI_DEVTEN_ERRATIC_ERR_DET_EN_MASK (0x00000200) +#define DWC_XDCI_DEVTEN_VNDR_DEV_TST_RX_DET_EN_MASK (0x00001000) + +#define DWC_XDCI_DEVTEN_DEVICE_INTS (DWC_XDCI_DEVTEN_DISCONN_DET_EN_MASK | \ + DWC_XDCI_DEVTEN_RESET_DET_EN_MASK | DWC_XDCI_DEVTEN_CONN_DONE_DET_EN_MASK | \ + DWC_XDCI_DEVTEN_LINK_STATE_CHANGE_DET_EN_MASK | DWC_XDCI_DEVTEN_RESUME_WAKEUP_DET_EN_MASK | \ + DWC_XDCI_DEVTEN_HIBERNATION_REQ_EN_MASK | DWC_XDCI_DEVTEN_U3L2L1_DET_EN_MASK | \ + DWC_XDCI_DEVTEN_ERRATIC_ERR_DET_EN_MASK) + +#define DWC_XDCI_EVENT_BUFF_BULK_STREAM_ID_MASK (0xFFFF0000) +#define DWC_XDCI_EVENT_BUFF_ISOCH_UFRAME_NUM_MASK (0xFFFF0000) +#define DWC_XDCI_EVENT_BUFF_EP_CMD_TYPE_MASK (0x0F000000) +#define DWC_XDCI_EVENT_BUFF_EP_XFER_RES_INDEX_MASK (0x007F0000) +#define DWC_XDCI_EVENT_BUFF_EP_XFER_ACTIVE_MASK (0x00008000) +#define DWC_XDCI_EVENT_BUFF_EP_CTRL_DATA_REQ_MASK (0x00001000) +#define DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK (0x00002000) +#define DWC_XDCI_EVENT_BUFF_EP_LST_MASK (0x00008000) +#define DWC_XDCI_EVENT_BUFF_EP_MISSED_ISOCH_MASK (0x00008000) +#define DWC_XDCI_EVENT_BUFF_EP_IOC_MASK (0x00004000) +#define DWC_XDCI_EVENT_BUFF_EP_LAST_PKT_MASK (0x00002000) +#define DWC_XDCI_EVENT_BUFF_EP_STREAM_NOT_FND_MASK (0x00002000) +#define DWC_XDCI_EVENT_BUFF_EP_STREAM_FND_MASK (0x00001000) +#define DWC_XDCI_EVENT_BUFF_EP_ERR_NO_RES_MASK (0x00001000) +#define DWC_XDCI_EVENT_BUFF_EP_INVALID_RES_MASK (0x00001000) + +#define DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK (0x000003C0) +#define DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS (6) +#define DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT (1) +#define DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS (2) +#define DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY (3) +#define DWC_XDCI_EVENT_BUFF_EP_STREAM_EVENT (6) +#define DWC_XDCI_EVENT_BUFF_EP_CMD_CMPLT (7) + +#define DWC_XDCI_EVENT_BUFF_EP_NUM_MASK (0x0000003E) +#define DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS (1) + +#define DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK (0x0000F000) + + +#define DWC_XDCI_EVENT_BUFF_DEV_HIRD_MASK (0x01E00000) +#define DWC_XDCI_EVENT_BUFF_DEV_HIRD_BIT_POS (21) +#define DWC_XDCI_EVENT_BUFF_DEV_SS_EVENT_MASK (0x00100000) +#define DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_MASK (0x000F0000) +#define DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_BIT_POS (16) + +#define DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK (0x00000F00) +#define DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS (8) +#define DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT (12) +#define DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT (11) +#define DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT (10) +#define DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT (9) +#define DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT (7) +#define DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT (5) +#define DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT (4) +#define DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT (3) +#define DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT (2) +#define DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT (1) +#define DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT (0) + +#define DWC_XDCI_EVENT_DEV_MASK (0x00000001) + +// +// Device Status Register and Bit Definitions +// +#define DWC_XDCI_DSTS_REG (0xC70C) +#define DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK (0x00400000) +#define DWC_XDCI_DSTS_DEV_CTRL_HALTED_BIT_POS (22) +#define DWC_XDCI_DSTS_CORE_IDLE (1 << 23) +#define DWC_XDCI_DSTS_CONN_SPEED_MASK (0x00000007) +#define DWC_XDCI_DSTS_LINK_STATE_MASK (0x003C0000) +#define DWC_XDCI_DSTS_LINK_STATE_DISCONNECT (0x00100000) + +// +// Device Generic Command Parameter Register +// +#define DWC_XDCI_DGCMD_PARAM_REG (0xC710) +#define DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK (0x0000001F) +#define DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK (0x00000020) +#define DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_BIT_POS (5) + +// +// Device Generic Command Register +// +#define DWC_XDCI_DGCMD_REG (0xC714) +#define DWC_XDCI_DGCMD_CMD_STATUS_MASK (0x00008000) +#define DWC_XDCI_DGCMD_CMD_ACTIVE_MASK (0x00000400) +#define DWC_XDCI_DGCMD_CMD_IOC_MASK (0x00000100) +#define DWC_XDCI_DGCMD_CMD_TYPE_MASK (0x000000FF) +#define DWC_XDCI_DGCMD_CMD_SET_PERIODIC_PARAMS (0x2) +#define DWC_XDCI_DGCMD_CMD_SET_SCRATCH_PAD_BUFF_ARR_LO (0x4) +#define DWC_XDCI_DGCMD_CMD_SET_SCRATCH_PAD_BUFF_ARR_HI (0x5) +#define DWC_XDCI_DGCMD_CMD_XMIT_DEVICE_NOTIFICATION (0x7) +#define DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH (0x9) +#define DWC_XDCI_DGCMD_CMD_ALL_FIFO_FLUSH (0xA) +#define DWC_XDCI_DGCMD_CMD_SET_EP_NRDY (0xC) +#define DWC_XDCI_DGCMD_CMD_RUN_SOC_BUS_LPBK (0x10) + +// +// Device Active USB EP Enable Register +// +#define DWC_XDCI_EP_DALEPENA_REG (0xC720) + +// +// Device Physical EP CMD Param 2 Register. Value is 32-bit +// +#define DWC_XDCI_EPCMD_PARAM2_REG(n) (0xC800 + (n << 4)) + +// +// Device Physical EP CMD Param 1 Register. Value is 32-bit +// +#define DWC_XDCI_EPCMD_PARAM1_REG(n) (0xC804 + (n << 4)) + +// +// Device Physical EP CMD Param 0 Register. Value is 32-bit +// +#define DWC_XDCI_EPCMD_PARAM0_REG(n) (0xC808 + (n << 4)) + +// +// Device Physical EP Command Registers and Bit Definitions +// +#define DWC_XDCI_EPCMD_REG(n) (0xC80C + (n << 4)) +#define DWC_XDCI_EPCMD_RES_IDX_MASK (0x007F0000) +#define DWC_XDCI_EPCMD_RES_IDX_BIT_POS (16) +#define DWC_XDCI_EPCMD_CMDTYPE_MASK (0x0000000F) +#define DWC_XDCI_EPCMD_SET_EP_CONFIG (0x1) +#define DWC_XDCI_EPCMD_SET_EP_XFER_RES_CONFIG (0x2) +#define DWC_XDCI_EPCMD_GET_EP_STATE (0x3) +#define DWC_XDCI_EPCMD_SET_STALL (0x4) +#define DWC_XDCI_EPCMD_CLEAR_STALL (0x5) +#define DWC_XDCI_EPCMD_START_XFER (0x6) +#define DWC_XDCI_EPCMD_UPDATE_XFER (0x7) +#define DWC_XDCI_EPCMD_END_XFER (0x8) +#define DWC_XDCI_EPCMD_START_NEW_CONFIG (0x9) + +#define DWC_XDCI_EPCMD_CMD_IOC_MASK (0x00000100) +#define DWC_XDCI_EPCMD_CMD_ACTIVE_MASK (0x00000400) +#define DWC_XDCI_EPCMD_HIGH_PRIO_MASK (0x00000800) +#define DWC_XDCI_EPCMD_FORCE_RM_MASK (0x00000800) + +// +// Command status and parameter values same as event status and parameters values +// +#define DWC_XDCI_EPCMD_CMD_STATUS_MASK (0x0000F000) + +// +// Command Params bit masks +// +#define DWC_XDCI_PARAM1_SET_EP_CFG_FIFO_BASED_MASK (0x80000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_BULK_BASED_MASK (0x40000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_MASK (0x3C000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_MASK (0x02000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK (0x01000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_MASK (0x00FF0000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS (16) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EBC_MASK (0x00008000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK (0x00003F00) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_BIT_POS (8) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_STRM_MASK (0x00002000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK (0x00000400) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK (0x00000200) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK (0x00000100) +#define DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK (0x0000001F) + +// +// CMD 1 param 0 +// +#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MASK (0xC0000000) +#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_BIT_POS (30) +#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE (0) +#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_RESTORE_ST (1) +#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE (2) +#define DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE (3) +#define DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_MASK (0x03C00000) +#define DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_BIT_POS (22) +#define DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_MASK (0x003E0000) +#define DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_BIT_POS (17) +#define DWC_XDCI_PARAM0_SET_EP_CFG_MPS_MASK (0x00003FF8) +#define DWC_XDCI_PARAM0_SET_EP_CFG_MPS_BIT_POS (3) +#define DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_MASK (0x00000006) +#define DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_BIT_POS (1) +#define DWC_XDCI_PARAM0_EP_TYPE_CTRL (0) +#define DWC_XDCI_PARAM0_EP_TYPE_ISOCH (1) +#define DWC_XDCI_PARAM0_EP_TYPE_BULK (2) +#define DWC_XDCI_PARAM0_EP_TYPE_INTR (3) + +// +// CMD 1 param 1 +// +#define DWC_XDCI_PARAM1_SET_EP_CFG_BULK_BASED_MASK (0x40000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_MASK (0x3C000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_BIT_POS (26) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_MASK (0x02000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_BIT_POS (25) +#define DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK (0x01000000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_MASK (0x00FF0000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS (16) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EBC_MASK (0x00008000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK (0x00003F00) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_BIT_POS (8) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_STRM_MASK (0x00002000) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK (0x00000400) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK (0x00000200) +#define DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK (0x00000100) +#define DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK (0x0000001F) + +// +// CMD 2 param 0 +// +#define DWC_XDCI_PARAM0_SET_EP_XFER_RES_NUM_MASK (0x0000FFFF) + +// +// CMD 3 param 2 +// +#define DWC_XDCI_PARAM2_GET_EP_STATE_MASK (0xFFFFFFFF) + +// +// CMD 6 param 1 +// +#define DWC_XDCI_PARAM1_STRT_XFER_TD_ADDR_LO_MASK (0xFFFFFFFF) + +// +// CMD 6 param 0 +// +#define DWC_XDCI_PARAM0_STRT_XFER_TD_ADDR_HI_MASK (0xFFFFFFFF) + +// +// Transfer Request Block Fields' Bit Definitions +// +#define DWC_XDCI_TRB_BUFF_SIZE_MASK (0x00FFFFFF) +#define DWC_XDCI_TRB_PCM1_MASK (0x03000000) +#define DWC_XDCI_TRB_PCM1_BIT_POS (24) +#define DWC_XDCI_TRB_STATUS_MASK (0xF0000000) +#define DWC_XDCI_TRB_STATUS_BIT_POS (28) +#define DWC_XDCI_TRB_STATUS_OK (0) +#define DWC_XDCI_TRB_STATUS_MISSED_ISOCH (1) +#define DWC_XDCI_TRB_STATUS_SETUP_PENDING (2) + +#define DWC_XDCI_TRB_CTRL_HWO_MASK (0x00000001) +#define DWC_XDCI_TRB_CTRL_LST_TRB_MASK (0x00000002) +#define DWC_XDCI_TRB_CTRL_LST_TRB_BIT_POS (1) +#define DWC_XDCI_TRB_CTRL_CHAIN_BUFF_MASK (0x00000004) +#define DWC_XDCI_TRB_CTRL_CHAIN_BUFF_BIT_POS (2) +#define DWC_XDCI_TRB_CTRL_CSP_MASK (0x00000008) +#define DWC_XDCI_TRB_CTRL_CSP_BIT_POS (3) +#define DWC_XDCI_TRB_CTRL_TYPE_MASK (0x000003F0) +#define DWC_XDCI_TRB_CTRL_TYPE_BIT_POS (4) +#define DWC_XDCI_TRB_CTRL_TYPE_NORMAL (1) +#define DWC_XDCI_TRB_CTRL_TYPE_SETUP (2) +#define DWC_XDCI_TRB_CTRL_TYPE_STATUS2 (3) +#define DWC_XDCI_TRB_CTRL_TYPE_STATUS3 (4) +#define DWC_XDCI_TRB_CTRL_TYPE_DATA (5) +#define DWC_XDCI_TRB_CTRL_TYPE_ISOCH_FIRST (6) +#define DWC_XDCI_TRB_CTRL_TYPE_ISOCH (7) +#define DWC_XDCI_TRB_CTRL_TYPE_LINK_TRB (8) +#define DWC_XDCI_TRB_CTRL_IOSP_MISOCH_MASK (0x00000400) +#define DWC_XDCI_TRB_CTRL_IOSP_MISOCH_BIT_POS (10) +#define DWC_XDCI_TRB_CTRL_IOC_MASK (0x00000800) +#define DWC_XDCI_TRB_CTRL_IOC_BIT_POS (11) +#define DWC_XDCI_TRB_CTRL_STRM_ID_SOF_NUM_MASK (0x3FFFC000) +#define DWC_XDCI_TRB_CTRL_STRM_ID_SOF_BIT_POS (14) + +#define DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES (4) +#define DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES (12) + +typedef enum { + EPCMD_SET_EP_CONFIG = 1, + EPCMD_SET_EP_XFER_RES_CONFIG, + EPCMD_GET_EP_STATE, + EPCMD_SET_STALL, + EPCMD_CLEAR_STALL, + EPCMD_START_XFER, + EPCMD_UPDATE_XFER, + EPCMD_END_XFER, + EPCMD_START_NEW_CONFIG = 9 +} DWC_XDCI_ENDPOINT_CMD; + +typedef enum { + ON = 0, + SLEEP = 2, + SUSPEND, + DISCONNECTED, + EARLY_SUSPEND, + RESET = 14, + RESUME = 15 +} DWC_XDCI_HS_LINK_STATE; + +typedef enum { + TRBCTL_NORMAL = 1, + TRBCTL_SETUP, + TRBCTL_2_PHASE, + TRBCTL_3_PHASE, + TRBCTL_CTRL_DATA_PHASE, + TRBCTL_ISOCH_FIRST, + TRBCTL_ISOCH, + TRBCTL_LINK +} DWC_XDCI_TRB_CONTROL; + +// +#pragma pack (1) +// DWC XDCI Endpoint Commands Parameters struct +// +typedef struct { + UINT32 Param2; + UINT32 Param1; + UINT32 Param0; +} DWC_XDCI_ENDPOINT_CMD_PARAMS; + +// +// Event Buffer Struct +// +typedef struct { + UINT32 Event; + UINT32 DevTstLmp1; + UINT32 DevTstLmp2; + UINT32 Reserved; +} DWC_XDCI_EVENT_BUFFER; + +// +// Transfer Request Block +// +typedef struct { + UINT32 BuffPtrLow; + UINT32 BuffPtrHigh; + UINT32 LenXferParams; + UINT32 TrbCtrl; +} DWC_XDCI_TRB; + +typedef struct { + USB_EP_INFO EpInfo; + DWC_XDCI_TRB *Trb; + USB_XFER_REQUEST XferHandle; + UINT32 CurrentXferRscIdx; + VOID *CoreHandle; + USB_EP_STATE State; + USB_EP_STATE OrgState; + BOOLEAN CheckFlag; +} DWC_XDCI_ENDPOINT; +#pragma pack () + +typedef struct { + // + // CbEventParams must be copied over by upper layer if + // it defers event processing + // + USB_DEVICE_CALLBACK_PARAM CbEventParams; + + // + // Callback function list + // + USB_DEVICE_CALLBACK_FUNC DevDisconnectCallback; + USB_DEVICE_CALLBACK_FUNC DevBusResetCallback; + USB_DEVICE_CALLBACK_FUNC DevResetDoneCallback; + USB_DEVICE_CALLBACK_FUNC DevLinkStateCallback; + USB_DEVICE_CALLBACK_FUNC DevWakeupCallback; + USB_DEVICE_CALLBACK_FUNC DevHibernationCallback; + USB_DEVICE_CALLBACK_FUNC DevSofCallback; + USB_DEVICE_CALLBACK_FUNC DevErraticErrCallback; + USB_DEVICE_CALLBACK_FUNC DevCmdCmpltCallback; + USB_DEVICE_CALLBACK_FUNC DevBuffOvflwCallback; + USB_DEVICE_CALLBACK_FUNC DevTestLmpRxCallback; + USB_DEVICE_CALLBACK_FUNC DevSetupPktReceivedCallback; + USB_DEVICE_CALLBACK_FUNC DevXferNrdyCallback; + USB_DEVICE_CALLBACK_FUNC DevXferDoneCallback; +} USB_DEV_CALLBACK_LIST; + +typedef struct { + VOID *ParentHandle; // Pointer to the parent this driver is associated + USB_CONTROLLER_ID Id; // ID of the controllers supported in our DCD + USB_SPEED DesiredSpeed; // Desired SS, HS, FS or LS Speeds for the core + USB_ROLE Role; // Desired role i.e. host, Device or OTG + USB_SPEED ActualSpeed; // Actual Speed + USB_DEVICE_STATE DevState; // Device state + UINTN BaseAddress; // Register Base address + UINT32 Flags; // Init flags + UINT32 MaxDevIntLines; // One event Buffer per interrupt line + DWC_XDCI_EVENT_BUFFER EventBuffers [DWC_XDCI_MAX_EVENTS_PER_BUFFER * 2]; // Event Buffer pool + DWC_XDCI_EVENT_BUFFER *AlignedEventBuffers; // Aligned event Buffer pool + DWC_XDCI_EVENT_BUFFER *CurrentEventBuffer; // Current event Buffer address + DWC_XDCI_TRB UnalignedTrbs [(DWC_XDCI_MAX_ENDPOINTS + 1) * DWC_XDCI_TRB_NUM]; // TRBs. + DWC_XDCI_TRB *Trbs; // 16-bytes aligned TRBs. + DWC_XDCI_ENDPOINT EpHandles [DWC_XDCI_MAX_ENDPOINTS * 2]; // EPs, diretion in and out for each EP + UINT8 DefaultSetupBuffer [DWC_XDCI_SETUP_BUFF_SIZE * 2]; // Unaligned setup Buffer + UINT8 *AlignedSetupBuffer; // Aligned setup Buffer. Aligned to 8-byte boundary + UINT8 MiscBuffer [528]; // Unaligned misc Buffer + UINT8 *AlignedMiscBuffer; // Aligned misc Buffer + UINT32 LinkState; // Link state + UINT32 HirdVal; // HIRD value + USB_DEV_CALLBACK_LIST EventCallbacks; + volatile BOOLEAN InterrupProcessing; +} XDCI_CORE_HANDLE; + +// +// DWC XDCI API prototypes +// +EFI_STATUS +EFIAPI +DwcXdciCoreInit ( + IN USB_DEV_CONFIG_PARAMS *ConfigParams, + IN VOID *ParentHandle, + IN VOID **CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreDeinit ( + IN VOID *CoreHandle, + IN UINT32 flags + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreRegisterCallback ( + IN VOID *CoreHandle, + IN USB_DEVICE_EVENT_ID Event, + IN USB_DEVICE_CALLBACK_FUNC CallbackFunc + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreUnregisterCallback ( + IN VOID *CoreHandle, + IN USB_DEVICE_EVENT_ID Event + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreIsrRoutine ( + IN VOID *CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreIsrRoutineTimerBased ( + IN VOID *CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreConnect ( + IN VOID *CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreDisconnect ( + IN VOID *CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreGetSpeed ( + IN VOID *CoreHandle, + IN USB_SPEED *Speed + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreSetAddress ( + IN VOID *CoreHandle, + IN UINT32 Address + ); + +EFI_STATUS +EFIAPI +DwcXdciCoreSetConfig ( + IN VOID *CoreHandle, + IN UINT32 ConfigNum + ); + +EFI_STATUS +EFIAPI +DwcXdciSetLinkState ( + IN VOID *CoreHandle, + IN USB_DEVICE_SS_LINK_STATE State + ); + +EFI_STATUS +EFIAPI +DwcXdciInitEp ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +EFIAPI +DwcXdciEpEnable ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +EFIAPI +DwcXdciEpDisable ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +EFIAPI +DwcXdciEpStall ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +EFIAPI +DwcXdciEpClearStall ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +EFIAPI +DwcXdciEpSetNrdy ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +EFIAPI +DwcXdciEp0ReceiveSetupPkt ( + IN VOID *CoreHandle, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +DwcXdciEp0ReceiveStatusPkt ( + IN VOID *CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciEp0SendStatusPkt ( + IN VOID *CoreHandle + ); + +EFI_STATUS +EFIAPI +DwcXdciEpTxData ( + IN VOID *CoreHandle, + IN USB_XFER_REQUEST *XferReq + ); + +EFI_STATUS +EFIAPI +DwcXdciEpRxData( + IN VOID *CoreHandle, + IN USB_XFER_REQUEST *XferReq + ); + +EFI_STATUS +EFIAPI +DwcXdciEpCancelTransfer ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +usbProcessDeviceResetDet ( + IN XDCI_CORE_HANDLE *CoreHandle + ); + +EFI_STATUS +usbProcessDeviceResetDone ( + IN XDCI_CORE_HANDLE *CoreHandle + ); + +UINT32 +UsbGetPhysicalEpNum ( + IN UINT32 EndpointNum, + IN USB_EP_DIR EndpointDir + ); + +UINT32 +UsbRegRead ( + IN UINTN Base, + IN UINT32 Offset + ); + +VOID +UsbRegWrite ( + IN UINTN Base, + IN UINT32 Offset, + IN UINT32 val + ); + +EFI_STATUS +UsbXdciCoreFlushEpFifo ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); +#endif + diff --git a/libefiusb/device_mode/XdciDevice.h b/libefiusb/device_mode/XdciDevice.h index aee6bdef..3ea139ba 100644 --- a/libefiusb/device_mode/XdciDevice.h +++ b/libefiusb/device_mode/XdciDevice.h @@ -1,184 +1,184 @@ -/** @file - Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _USB_DEVICE_H_ -#define _USB_DEVICE_H_ - -// -// @USB_DEV_CONFIG_PARAMS: Struct to be filled in with configuration -// parameters and passed to the init routine for device controller -// -typedef struct { - USB_CONTROLLER_ID ControllerId; // Controller ID of the core - UINT32 BaseAddress; // Base address of the controller registers and on-chip memory - UINT32 Flags; // Initialization flags - USB_SPEED Speed; // Desired USB bus Speed - USB_ROLE Role; // Default USB role -} USB_DEV_CONFIG_PARAMS; - -// -// @USB_DEV_CORE: Struct used as a handle for all -// hardware-independent APIs -// -typedef struct { - const struct UsbDeviceCoreDriver *CoreDriver; - VOID *ControllerHandle; -} USB_DEV_CORE; - -typedef -EFI_STATUS -(EFIAPI *USB_DEVICE_CALLBACK_FUNC) ( - IN USB_DEVICE_CALLBACK_PARAM *Param - ); - -EFI_STATUS -UsbDeviceInit ( - IN USB_DEV_CONFIG_PARAMS *ConfigParams, - IN OUT VOID **DevCoreHandle - ); - -EFI_STATUS -UsbDeviceDeinit ( - IN VOID *DevCoreHandle, - IN UINT32 Flags - ); - -EFI_STATUS -UsbDeviceRegisterCallback ( - IN VOID *DevCoreHandle, - IN USB_DEVICE_EVENT_ID EventId, - IN USB_DEVICE_CALLBACK_FUNC CallbackFunc - ); - -EFI_STATUS -UsbDeviceUnregisterCallback ( - IN VOID *DevCoreHandle, - IN USB_DEVICE_EVENT_ID EventId - ); - -EFI_STATUS -UsbDeviceIsrRoutine ( - IN VOID *DevCoreHandle - ); - -EFI_STATUS -UsbDeviceIsrRoutineTimerBased ( - IN VOID *DevCoreHandle - ); - -EFI_STATUS -UsbXdciDeviceConnect ( - IN VOID *DevCoreHandle - ); - -EFI_STATUS -UsbDeviceDisconnect ( - IN VOID *DevCoreHandle - ); - -EFI_STATUS -UsbDeviceGetSpeed ( - IN VOID *DevCoreHandle, - IN USB_SPEED *Speed - ); - -EFI_STATUS -UsbDeviceSetLinkState ( - IN VOID *DevCoreHandle, - IN USB_DEVICE_SS_LINK_STATE State - ); - -EFI_STATUS -UsbDeviceSetAddress ( - IN VOID *DevCoreHandle, - IN UINT32 Address - ); - -EFI_STATUS -UsbDeviceSetConfiguration ( - IN VOID *DevCoreHandle, - IN UINT32 ConfigNum - ); - -EFI_STATUS -UsbDeviceInitEp ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -UsbDeviceEpEnable ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -UsbDeviceEpDisable ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -UsbDeviceEpStall ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -UsbDeviceEpClearStall ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -UsbDeviceEpSetNrdy ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -EFI_STATUS -UsbDeviceEp0RxSetup ( - IN VOID *DevCoreHandle, - IN UINT8 *Buffer - ); - -EFI_STATUS -UsbDeviceEp0RxStatus ( - IN VOID *DevCoreHandle - ); - -EFI_STATUS -UsbDeviceEp0TxStatus ( - IN VOID *DevCoreHandle - ); - -EFI_STATUS -UsbXdciDeviceEpTxData ( - IN VOID *DevCoreHandle, - IN USB_XFER_REQUEST *XferReq - ); - -EFI_STATUS -UsbXdciDeviceEpRxData ( - IN VOID *DevCoreHandle, - IN USB_XFER_REQUEST *XferReq - ); - -EFI_STATUS -UsbDeviceEpCancelTransfer ( - IN VOID *DevCoreHandle, - IN USB_EP_INFO *EpInfo - ); - -#endif - +/** @file + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _USB_DEVICE_H_ +#define _USB_DEVICE_H_ + +// +// @USB_DEV_CONFIG_PARAMS: Struct to be filled in with configuration +// parameters and passed to the init routine for device controller +// +typedef struct { + USB_CONTROLLER_ID ControllerId; // Controller ID of the core + UINT64 BaseAddress; // Base address of the controller registers and on-chip memory + UINT32 Flags; // Initialization flags + USB_SPEED Speed; // Desired USB bus Speed + USB_ROLE Role; // Default USB role +} USB_DEV_CONFIG_PARAMS; + +// +// @USB_DEV_CORE: Struct used as a handle for all +// hardware-independent APIs +// +typedef struct { + const struct UsbDeviceCoreDriver *CoreDriver; + VOID *ControllerHandle; +} USB_DEV_CORE; + +typedef +EFI_STATUS +(EFIAPI *USB_DEVICE_CALLBACK_FUNC) ( + IN USB_DEVICE_CALLBACK_PARAM *Param + ); + +EFI_STATUS +UsbDeviceInit ( + IN USB_DEV_CONFIG_PARAMS *ConfigParams, + IN OUT VOID **DevCoreHandle + ); + +EFI_STATUS +UsbDeviceDeinit ( + IN VOID *DevCoreHandle, + IN UINT32 Flags + ); + +EFI_STATUS +UsbDeviceRegisterCallback ( + IN VOID *DevCoreHandle, + IN USB_DEVICE_EVENT_ID EventId, + IN USB_DEVICE_CALLBACK_FUNC CallbackFunc + ); + +EFI_STATUS +UsbDeviceUnregisterCallback ( + IN VOID *DevCoreHandle, + IN USB_DEVICE_EVENT_ID EventId + ); + +EFI_STATUS +UsbDeviceIsrRoutine ( + IN VOID *DevCoreHandle + ); + +EFI_STATUS +UsbDeviceIsrRoutineTimerBased ( + IN VOID *DevCoreHandle + ); + +EFI_STATUS +UsbXdciDeviceConnect ( + IN VOID *DevCoreHandle + ); + +EFI_STATUS +UsbDeviceDisconnect ( + IN VOID *DevCoreHandle + ); + +EFI_STATUS +UsbDeviceGetSpeed ( + IN VOID *DevCoreHandle, + IN USB_SPEED *Speed + ); + +EFI_STATUS +UsbDeviceSetLinkState ( + IN VOID *DevCoreHandle, + IN USB_DEVICE_SS_LINK_STATE State + ); + +EFI_STATUS +UsbDeviceSetAddress ( + IN VOID *DevCoreHandle, + IN UINT32 Address + ); + +EFI_STATUS +UsbDeviceSetConfiguration ( + IN VOID *DevCoreHandle, + IN UINT32 ConfigNum + ); + +EFI_STATUS +UsbDeviceInitEp ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +UsbDeviceEpEnable ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +UsbDeviceEpDisable ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +UsbDeviceEpStall ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +UsbDeviceEpClearStall ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +UsbDeviceEpSetNrdy ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +EFI_STATUS +UsbDeviceEp0RxSetup ( + IN VOID *DevCoreHandle, + IN UINT8 *Buffer + ); + +EFI_STATUS +UsbDeviceEp0RxStatus ( + IN VOID *DevCoreHandle + ); + +EFI_STATUS +UsbDeviceEp0TxStatus ( + IN VOID *DevCoreHandle + ); + +EFI_STATUS +UsbXdciDeviceEpTxData ( + IN VOID *DevCoreHandle, + IN USB_XFER_REQUEST *XferReq + ); + +EFI_STATUS +UsbXdciDeviceEpRxData ( + IN VOID *DevCoreHandle, + IN USB_XFER_REQUEST *XferReq + ); + +EFI_STATUS +UsbDeviceEpCancelTransfer ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ); + +#endif + diff --git a/libefiusb/device_mode/XdciUtility.c b/libefiusb/device_mode/XdciUtility.c index 4fbe1d51..c0aece8d 100644 --- a/libefiusb/device_mode/XdciUtility.c +++ b/libefiusb/device_mode/XdciUtility.c @@ -16,6 +16,7 @@ #include #include "XdciUtility.h" +#include "UsbDeviceMode.h" VOID PrintDeviceDescriptor ( @@ -131,7 +132,7 @@ PrintDeviceRequest ( DEBUG ((DEBUG_INFO, "Length : 0x%x\n", DevReq->Length)); DEBUG ((DEBUG_INFO, "\n")); } - +#ifdef SUPPORT_SUPER_SPEED VOID PrintBOSDescriptor ( IN __attribute__((unused)) EFI_USB_BOS_DESCRIPTOR *BosDesc @@ -144,4 +145,4 @@ PrintBOSDescriptor ( DEBUG ((DEBUG_INFO, "NumDeviceCaps : 0x%x\n", BosDesc->NumDeviceCaps)); DEBUG ((DEBUG_INFO, "\n")); } - +#endif diff --git a/libefiusb/device_mode/XdciUtility.h b/libefiusb/device_mode/XdciUtility.h index 4650f48e..2e7ac374 100644 --- a/libefiusb/device_mode/XdciUtility.h +++ b/libefiusb/device_mode/XdciUtility.h @@ -14,6 +14,7 @@ #ifndef _XDCI_UTILITY_H_ #define _XDCI_UTILITY_H_ +#include "XdciCommon.h" #include "protocol/UsbDeviceLib.h" VOID @@ -51,10 +52,11 @@ PrintDeviceRequest ( IN EFI_USB_DEVICE_REQUEST *DevReq ); +#ifdef SUPPORT_SUPER_SPEED VOID PrintBOSDescriptor ( IN EFI_USB_BOS_DESCRIPTOR *BosDesc ); - +#endif #endif diff --git a/libefiusb/device_mode/cpuio.c b/libefiusb/device_mode/cpuio.c index 6a21fff1..971fd0ce 100644 --- a/libefiusb/device_mode/cpuio.c +++ b/libefiusb/device_mode/cpuio.c @@ -152,6 +152,7 @@ UINT32 MmioWrite32(UINTN add, UINT32 data) efi_perror(ret, L"Fail to write data to 0x%x", add); return 0xFFFFFFFF; } + efi_perror(EFI_SUCCESS, L"write data 0x%x to 0x%016lx", data, add); return data; } diff --git a/libefiusb/protocol/Usb.h b/libefiusb/protocol/Usb.h old mode 100644 new mode 100755 index 299fb4cd..d25490b8 --- a/libefiusb/protocol/Usb.h +++ b/libefiusb/protocol/Usb.h @@ -139,6 +139,7 @@ typedef struct { UINT8 Attributes; UINT16 MaxPacketSize; UINT8 Interval; +/* for super speed, a companion descriptor follows */ } USB_ENDPOINT_DESCRIPTOR; /// diff --git a/libefiusb/protocol/UsbDeviceLib.h b/libefiusb/protocol/UsbDeviceLib.h old mode 100644 new mode 100755 index 83647b7c..9dbdffd8 --- a/libefiusb/protocol/UsbDeviceLib.h +++ b/libefiusb/protocol/UsbDeviceLib.h @@ -55,7 +55,7 @@ // #define USB_BCD_VERSION_LS 0x0110 #define USB_BCD_VERSION_HS 0x0200 -#define USB_BCD_VERSION_SS 0x0300 +#define USB_BCD_VERSION_SS 0x0320 // // Device RequestType Flags @@ -89,8 +89,24 @@ // // USB Descriptor types // -#define USB_DESC_TYPE_SS_ENDPOINT_COMPANION 0x30 #define USB_DESC_TYPE_BOS 0x0F +#define USB_DESC_TYPE_DEVICE_CAPABILITY 0x10 +#define USB_DESC_TYPE_SS_ENDPOINT_COMPANION 0x30 +#pragma pack(1) + +#ifdef SUPPORT_SUPER_SPEED +// +// USB device capability Type Codes +// USB3 Table 9-13 +// +typedef enum { + WirelessUSB = 0x01, + USB2Extension, + SuperSpeedUSB, + ContainerID, + SuperSpeedPlusUSB = 0x0A +} USB_DEVICE_CAP_TYPE_CODE; +#endif // @@ -125,6 +141,7 @@ typedef struct { // // SuperSpeed Endpoint companion descriptor +// USB3 table 9-22 // typedef struct { UINT8 Length; @@ -174,7 +191,85 @@ typedef struct { VOID *ConfigAll; USB_DEVICE_INTERFACE_OBJ *InterfaceObjs; } USB_DEVICE_CONFIG_OBJ; -#pragma pack() + +#ifdef SUPPORT_SUPER_SPEED +// +// SuperSpeed Binary Device Object Store(BOS) descriptor +// USB3 9.6.2 +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT16 TotalLength; + UINT8 NumDeviceCaps; +} EFI_USB_BOS_DESCRIPTOR; + +// +// Generic Header of Device Capability descriptor +// USB3 9.6.2.2 +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 DevCapabilityType; + UINT8 CapDependent; +} EFI_USB_SS_DEVICE_CAP_DESCRIPTOR; + +// +// USB2.0 Extension descriptor +// USB3 Table 9-14 +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 DeviceCapabilityType; + UINT32 Attributes; +} EFI_USB_USB2_EXT_CAP_DESCRIPTOR; + + +// +// SuperSpeed USB Device Capability descriptor +// USB3 Table 9-15 +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 DeviceCapabilityType; + UINT8 Attributes; + UINT16 SpeedSupported; + UINT8 FunctionalitySupport; + UINT8 U1DevExitLat; + UINT16 U2DevExitLat; +} EFI_USB_SS_USB_DEV_CAP_DESCRIPTOR; + +// +// Container ID descriptor +// USB3 Table 9-16 +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 DeviceCapabilityType; + UINT8 Reserved; + UINT8 UUID[16]; +} EFI_USB_CONTAINER_ID_DESCRIPTOR; + +// +// Container ID descriptor +// USB3 Table 9-16 +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 DeviceCapabilityType; + UINT8 ReservedByte; + UINT32 Attributes; + UINT16 FunctionalitySupport; + UINT16 ReservedWord; + UINT32 SublinkSpeedAttr[2]; +} EFI_USB_SS_PLUS_USB_DEV_CAP_DESCRIPTOR; + +#endif typedef EFI_STATUS @@ -192,16 +287,8 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_USB_DATA_CALLBACK) ( - IN EFI_USB_DEVICE_XFER_INFO *XferInfo - ); - -#pragma pack(1) -typedef struct { - UINT8 Length; - UINT8 DescriptorType; - UINT16 TotalLength; - UINT8 NumDeviceCaps; -} EFI_USB_BOS_DESCRIPTOR; + IN EFI_USB_DEVICE_XFER_INFO *XferInfo + ); typedef struct { USB_DEVICE_DESCRIPTOR *DeviceDesc; diff --git a/libefiusb/usb.c b/libefiusb/usb.c old mode 100644 new mode 100755 index 69d9b261..7ac37ec0 --- a/libefiusb/usb.c +++ b/libefiusb/usb.c @@ -44,17 +44,17 @@ #define CONFIG_COUNT 1 #define INTERFACE_COUNT 1 #define ENDPOINT_COUNT 2 -#define CFG_MAX_POWER 0x00 /* Max power consumption of +#define CFG_MAX_POWER 100 /* Max power consumption of the USB device from the bus for this config */ -#define IF_SUBCLASS 0x00 /* Default subclass */ -#define IF_PROTOCOL 0x00 /* Default protocol */ +#define IF_SUBCLASS 66 /* Default subclass */ +#define IF_PROTOCOL 1 /* Default protocol */ #define IN_ENDPOINT_NUM 1 #define OUT_ENDPOINT_NUM 2 #define BULK_EP_PKT_SIZE USB_BULK_EP_PKT_SIZE_HS /* default to using high speed */ #define VENDOR_ID 0x8087 /* Intel Inc. */ #define PRODUCT_ID 0x09EF -#define BCD_DEVICE 0x0100 +#define BCD_DEVICE 0 static data_callback_t rx_callback = NULL; static data_callback_t tx_callback = NULL; @@ -96,6 +96,7 @@ static USB_STRING_DESCRIPTOR string_table[] = { }; /* Complete Configuration structure */ +#ifndef SUPPORT_SUPER_SPEED struct config_descriptor { EFI_USB_CONFIG_DESCRIPTOR config; EFI_USB_INTERFACE_DESCRIPTOR interface; @@ -131,7 +132,7 @@ static struct config_descriptor config_descriptor = { IN_ENDPOINT_NUM | USB_ENDPOINT_DIR_IN, USB_ENDPOINT_BULK, BULK_EP_PKT_SIZE, - 0x00 /* Not specified for bulk endpoint */ + 0x00, /* Not specified for bulk endpoint */ }, .ep_out = { sizeof(EFI_USB_ENDPOINT_DESCRIPTOR), @@ -139,9 +140,10 @@ static struct config_descriptor config_descriptor = { OUT_ENDPOINT_NUM | USB_ENDPOINT_DIR_OUT, USB_ENDPOINT_BULK, BULK_EP_PKT_SIZE, - 0x00 /* Not specified for bulk endpoint */ - } + 0x00, /* Not specified for bulk endpoint */ + }, }; +#endif static USB_DEVICE_DESCRIPTOR device_descriptor = { sizeof(USB_DEVICE_DESCRIPTOR), @@ -160,6 +162,98 @@ static USB_DEVICE_DESCRIPTOR device_descriptor = { CONFIG_COUNT }; +#ifdef SUPPORT_SUPER_SPEED +/* usb 3.0 root hub device descriptor */ + +struct config_descriptor { + EFI_USB_CONFIG_DESCRIPTOR config; + EFI_USB_INTERFACE_DESCRIPTOR interface; + EFI_USB_ENDPOINT_DESCRIPTOR ep_in; + EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR ep_comp_in; + EFI_USB_ENDPOINT_DESCRIPTOR ep_out; + EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR ep_comp_out; +} __attribute__((packed)); + +static struct config_descriptor config_descriptor = { + .config = { + sizeof(EFI_USB_CONFIG_DESCRIPTOR), + USB_DESC_TYPE_CONFIG, + sizeof(struct config_descriptor), + INTERFACE_COUNT, + 1, + STR_TBL_CONFIG, + USB_BM_ATTR_RESERVED, + CFG_MAX_POWER + }, + .interface = { + sizeof(EFI_USB_INTERFACE_DESCRIPTOR), + USB_DESC_TYPE_INTERFACE, + 0x0, + 0x0, + ENDPOINT_COUNT, + USB_DEVICE_VENDOR_CLASS, + IF_SUBCLASS, + IF_PROTOCOL, + STR_TBL_INTERFACE + }, + .ep_in = { + sizeof(EFI_USB_ENDPOINT_DESCRIPTOR), + USB_DESC_TYPE_ENDPOINT, + IN_ENDPOINT_NUM | USB_ENDPOINT_DIR_IN, + USB_ENDPOINT_BULK, + USB_BULK_EP_PKT_SIZE_SS, + 0x00, /* Not specified for bulk endpoint */ + }, + .ep_comp_in = { + sizeof(EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR), + USB_DESC_TYPE_SS_ENDPOINT_COMPANION, + 0x04, + 0x00, + 0x00 + }, + .ep_out = { + sizeof(EFI_USB_ENDPOINT_DESCRIPTOR), + USB_DESC_TYPE_ENDPOINT, + OUT_ENDPOINT_NUM | USB_ENDPOINT_DIR_OUT, + USB_ENDPOINT_BULK, + USB_BULK_EP_PKT_SIZE_SS, + 0x00, /* Not specified for bulk endpoint */ + }, + .ep_comp_out = { + sizeof(EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR), + USB_DESC_TYPE_SS_ENDPOINT_COMPANION, + 0x04, + 0x00, + 0x00 + } +}; + +struct usb_bos_descriptor { + EFI_USB_BOS_DESCRIPTOR bos; + EFI_USB_SS_USB_DEV_CAP_DESCRIPTOR ss_cap; +} __attribute__((packed)); + +static struct usb_bos_descriptor bos_descriptor = { + + .bos = { + .Length = sizeof(EFI_USB_BOS_DESCRIPTOR), + .DescriptorType = USB_DESC_TYPE_BOS, + .TotalLength = sizeof(struct usb_bos_descriptor), + .NumDeviceCaps = 1, + }, + .ss_cap = { + .Length = sizeof(EFI_USB_SS_USB_DEV_CAP_DESCRIPTOR), + .DescriptorType = USB_DESC_TYPE_DEVICE_CAPABILITY, + .DeviceCapabilityType = SuperSpeedUSB, + .Attributes = 0, + .SpeedSupported = 0x000f, + .FunctionalitySupport = 1, + .U1DevExitLat = 1, + .U2DevExitLat =500, + }, +}; +#endif + EFI_STATUS usb_write(void *buf, UINT32 size) { EFI_STATUS ret; @@ -204,9 +298,21 @@ EFI_STATUS usb_read(void *buf, UINT32 size) static EFIAPI EFI_STATUS setup_handler(__attribute__((__unused__)) EFI_USB_DEVICE_REQUEST *CtrlRequest, __attribute__((__unused__)) USB_DEVICE_IO_INFO *IoInfo) { + short version; - /* Does not handle any Class/Vendor specific setup requests */ + if (IoInfo == NULL || CtrlRequest == NULL) + return EFI_UNSUPPORTED; + switch (CtrlRequest->Request) { + case 0x33: // Android Open Accessory (AOA) protocol + version = 0x02; + IoInfo->Length = sizeof(version); + CopyMem (IoInfo->Buffer, &version, IoInfo->Length); + break; + default: + error(L"Unknown Class/Vendor setup 0x%x", CtrlRequest->Request); + break; + } return EFI_SUCCESS; } @@ -347,9 +453,16 @@ static void init_driver_objs(UINT8 subclass, /* Endpoint Data In/Out objects */ gEndpointObjs[0].EndpointDesc = &config_descriptor.ep_in; gEndpointObjs[0].EndpointCompDesc = NULL; - gEndpointObjs[1].EndpointDesc = &config_descriptor.ep_out; gEndpointObjs[1].EndpointCompDesc = NULL; + +#ifdef SUPPORT_SUPER_SPEED + device_descriptor.BcdUSB = USB_BCD_VERSION_SS; + gDevObj.BosDesc = &bos_descriptor.bos; + gEndpointObjs[0].EndpointCompDesc = &config_descriptor.ep_comp_in; + gEndpointObjs[1].EndpointCompDesc = &config_descriptor.ep_comp_out; +#endif + } EFI_STATUS usb_start(UINT8 subclass, UINT8 protocol, @@ -357,7 +470,7 @@ EFI_STATUS usb_start(UINT8 subclass, UINT8 protocol, start_callback_t start_cb, data_callback_t rx_cb, data_callback_t tx_cb) { - EFI_STATUS ret; + EFI_STATUS ret = EFI_UNSUPPORTED; if (!str_configuration || !str_interface || !start_cb || !rx_cb || !tx_cb) return EFI_INVALID_PARAMETER; @@ -366,6 +479,7 @@ EFI_STATUS usb_start(UINT8 subclass, UINT8 protocol, rx_callback = rx_cb; tx_callback = tx_cb; +#ifndef USE_SELF_USB_DEVICE_MODE_PROTOCOL ret = LibLocateProtocol(&gEfiUsbDeviceModeProtocolGuid, (void **)&usb_device); if (EFI_ERROR(ret) || !usb_device) { efi_perror(ret, L"Can't locate USB device mode protocol in BIOS"); @@ -374,7 +488,7 @@ EFI_STATUS usb_start(UINT8 subclass, UINT8 protocol, if (EFI_ERROR(ret)) efi_perror(ret, L"Init USB xDCI failed"); } - +#endif if (EFI_ERROR(ret)) { #ifdef USE_SELF_USB_DEVICE_MODE_PROTOCOL debug(L"Trying self implemented USB device mode protocol"); diff --git a/libkernelflinger/nvme.c b/libkernelflinger/nvme.c index c3e9c8d3..857b0b7c 100644 --- a/libkernelflinger/nvme.c +++ b/libkernelflinger/nvme.c @@ -194,7 +194,7 @@ static EFI_STATUS nvme_erase_blocks( * this work to the following fill_zero */ if (is_UEFI()) - return EFI_UNSUPPORTED; + return EFI_SUCCESS; debug(L"nvme_erase_blocks: 0x%X blocks", end - start + 1); dp = DevicePathFromHandle(handle);