From 90bcd27ee4f7596ad0d2c02e343e4aaa7ad89456 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Tue, 17 Jan 2017 16:07:34 +0800 Subject: Add USB peripheral mode Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang Reviewed-by: David Wei --- .../Common/Features/UsbDeviceDxe/ComponentName.c | 305 ++ .../Common/Features/UsbDeviceDxe/UsbDeviceDxe.c | 395 ++ .../Common/Features/UsbDeviceDxe/UsbDeviceDxe.h | 159 + .../Common/Features/UsbDeviceDxe/UsbDeviceDxe.inf | 74 + .../Common/Features/UsbDeviceDxe/UsbDeviceMode.c | 1489 ++++++++ .../Common/Features/UsbDeviceDxe/UsbDeviceMode.h | 39 + .../Common/Features/UsbDeviceDxe/UsbFuncIo.c | 2219 +++++++++++ .../Common/Features/UsbDeviceDxe/UsbFuncIo.h | 234 ++ .../Common/Features/UsbDeviceDxe/UsbIoNode.c | 177 + .../Common/Features/UsbDeviceDxe/UsbIoNode.h | 90 + .../Common/Features/UsbDeviceDxe/XdciCommon.h | 156 + .../Common/Features/UsbDeviceDxe/XdciDWC.c | 4033 ++++++++++++++++++++ .../Common/Features/UsbDeviceDxe/XdciDWC.h | 741 ++++ .../Common/Features/UsbDeviceDxe/XdciDevice.c | 695 ++++ .../Common/Features/UsbDeviceDxe/XdciDevice.h | 184 + .../Common/Features/UsbDeviceDxe/XdciInterface.h | 241 ++ .../Common/Features/UsbDeviceDxe/XdciTable.c | 55 + .../Common/Features/UsbDeviceDxe/XdciUtility.c | 148 + .../Common/Features/UsbDeviceDxe/XdciUtility.h | 62 + 19 files changed, 11496 insertions(+) create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/ComponentName.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.inf create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciCommon.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciInterface.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciTable.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.h (limited to 'Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe') diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/ComponentName.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/ComponentName.c new file mode 100644 index 0000000000..94958060e7 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/ComponentName.c @@ -0,0 +1,305 @@ +/** @file + Copyright (c) 2004 - 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 + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mUsbDeviceDxeComponentName = { + UsbDeviceDxeGetDriverName, + UsbDeviceDxeGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDeviceDxeComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDeviceDxeGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDeviceDxeGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDeviceDxeDriverNameTable[] = { + { "eng;en", L"Usb Device Driver" }, + { NULL , NULL } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mUsbDeviceDxeDriverNameTable, + DriverName, + (BOOLEAN)(This == &mUsbDeviceDxeComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.c new file mode 100644 index 0000000000..03bf27d6e5 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.c @@ -0,0 +1,395 @@ +/** @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 "UsbDeviceDxe.h" +#include + +EFI_DRIVER_BINDING_PROTOCOL mUsbDeviceDxeDriverBinding = { + UsbDeviceDxeDriverSupported, + UsbDeviceDxeDriverStart, + UsbDeviceDxeDriverStop, + 0x1, + NULL, + NULL +}; + + + +VOID +EFIAPI +PlatformSpecificInit ( + VOID + ) +{ + UINTN XhciPciMmBase; + EFI_PHYSICAL_ADDRESS XhciMemBaseAddress; + + XhciPciMmBase = MmPciAddress ( + 0, + 0, + PCI_DEVICE_NUMBER_XHCI, + PCI_FUNCTION_NUMBER_XHCI, + 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); + + PmicUSBSwitchControl (TRUE);//conduction USB switch. + return; +} + + +VOID +EFIAPI +UsbDeviceDxeExitBootService ( + 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) { + gBS->SetTimer (UsbXdciDevContext->XdciPollTimer, TimerCancel, 0); + gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer); + UsbXdciDevContext->XdciPollTimer = NULL; + } + + return; +} + +/** + The USB bus driver entry pointer. + + @param ImageHandle The driver image handle. + @param SystemTable The system table. + + @return EFI_SUCCESS The component name protocol is installed. + @return Others Failed to init the usb driver. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &mUsbDeviceDxeDriverBinding, + ImageHandle, + &mUsbDeviceDxeComponentName, + &mUsbDeviceDxeComponentName2 + ); +} + +/** + Check whether USB bus driver support this device. + + @param This The USB bus driver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS The bus supports this controller. + @retval EFI_UNSUPPORTED This device isn't supported. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_CLASSC UsbClassCReg; + + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Test whether the controller belongs to USB device type + // + // 0x0C03FE / 0x0C0380 + // + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || + (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || + ((UsbClassCReg.ProgInterface != PCI_IF_USBDEV) && (UsbClassCReg.ProgInterface != 0x80))) { + Status = EFI_UNSUPPORTED; + } + +ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + + +/** + Start to process the controller. + + @param This The USB bus driver binding instance. + @param Controller The controller to check. + @param RemainingDevicePath The remaining device patch. + + @retval EFI_SUCCESS The controller is controlled by the usb bus. + @retval EFI_ALREADY_STARTED The controller is already controlled by the usb + bus. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbXdciDevContext; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_EVENT ExitBootServicesEvent; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFunIoEntryPoint - Entry\n")); + + UsbXdciDevContext = NULL; + + // + // Provide protocol interface + // + // + // Get the PCI I/O Protocol on PciHandle + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + 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->FirstNodePtr = NULL; + UsbXdciDevContext->Signature = EFI_USB_DEV_SIGNATURE; + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + R_OTG_BAR0, + 1, + &UsbXdciDevContext->XdciMmioBarAddr + ); + + UsbXdciDevContext->XdciMmioBarAddr &= B_OTG_BAR0_BA; + DEBUG ((USB_FUIO_DEBUG_INFO, "USB DEV mode IO addr 0x%08x\n", UsbXdciDevContext->XdciMmioBarAddr)); + + CopyMem ( + &(UsbXdciDevContext->UsbFunIoProtocol), + &mUsbFunIoProtocol, + sizeof (EFI_USBFN_IO_PROTOCOL) + ); + + CopyMem ( + &(UsbXdciDevContext->UsbDevModeProtocol), + &mUsbDeviceModeProtocol, + sizeof (EFI_USB_DEVICE_MODE_PROTOCOL) + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UsbDeviceDxeExitBootService, + UsbXdciDevContext, + &gEfiEventExitBootServicesGuid, + &ExitBootServicesEvent + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &UsbXdciDevContext->XdciHandle, + &gEfiUsbFnIoProtocolGuid, + &UsbXdciDevContext->UsbFunIoProtocol, + &gEfiUsbDeviceModeProtocolGuid, + &UsbXdciDevContext->UsbDevModeProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((USB_FUIO_DEBUG_ERROR, "ERROR - Failed to install upper protocol, Status: %r\n", Status)); + goto ErrorExit; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, "Done - install upper protocol complete\n")); + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFunIoEntryPoint - Exit\n")); + return Status; + +ErrorExit: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if (UsbXdciDevContext != NULL) { + if (UsbXdciDevContext->XdciPollTimer != NULL) { + gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer); + UsbXdciDevContext->XdciPollTimer = NULL; + } + FreePool (UsbXdciDevContext); + } + + DEBUG ((USB_FUIO_DEBUG_ERROR, "ERROR - UsbFunIoEntryPoint - Exit\n")); + return Status; +} + +/** + Stop handle the controller by this USB bus driver. + + @param This The USB bus driver binding protocol. + @param Controller The controller to release. + @param NumberOfChildren The child of USB bus that opened controller + BY_CHILD. + @param ChildHandleBuffer The array of child handle. + + @retval EFI_SUCCESS The controller or children are stopped. + @retval EFI_DEVICE_ERROR Failed to stop the driver. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_USBFN_IO_PROTOCOL *UsbFunIoProtocol; + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbXdciDevContext; + + + // + // Locate USB_BUS for the current host controller + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbFnIoProtocolGuid, + &UsbFunIoProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbXdciDevContext = USBFUIO_CONTEXT_FROM_PROTOCOL (UsbFunIoProtocol); + + // + // free pool + // + while (UsbXdciDevContext->FirstNodePtr != NULL) { + RemoveNode (UsbFunIoProtocol, UsbXdciDevContext->FirstNodePtr); + } + + Status = gBS->UninstallMultipleProtocolInterfaces ( + UsbXdciDevContext->XdciHandle, + &gEfiUsbFnIoProtocolGuid, + &UsbXdciDevContext->UsbFunIoProtocol, + &gEfiUsbDeviceModeProtocolGuid, + &UsbXdciDevContext->UsbDevModeProtocol, + NULL + ); + + if (UsbXdciDevContext->StartUpController == TRUE) { + Status = StopController (UsbFunIoProtocol); + DEBUG ((USB_FUIO_DEBUG_INFO, "USB DEV mode STOP UsbFnDeInitDevice %r\n", Status)); + } + + if (UsbXdciDevContext->XdciPollTimer != NULL) { + gBS->SetTimer (UsbXdciDevContext->XdciPollTimer, TimerCancel, 0); + gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer); + UsbXdciDevContext->XdciPollTimer = NULL; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool (UsbXdciDevContext); + return EFI_SUCCESS; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.h new file mode 100644 index 0000000000..e300fbf153 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.h @@ -0,0 +1,159 @@ +/** @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_DXE_H__ +#define __USB_DEVICE_DXE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UsbFuncIo.h" +#include "UsbDeviceMode.h" + + +#define PCI_IF_USBDEV 0xFE + +#define EFI_USB_DEV_SIGNATURE 0x55534244 //"USBD" +#define USBFUIO_CONTEXT_FROM_PROTOCOL(a) CR (a, USB_XDCI_DEV_CONTEXT, UsbFunIoProtocol, EFI_USB_DEV_SIGNATURE) +#define USBUSBD_CONTEXT_FROM_PROTOCOL(a) CR (a, USB_XDCI_DEV_CONTEXT, UsbDevModeProtocol, EFI_USB_DEV_SIGNATURE) + + +typedef struct _USB_FUIO_EVENT_NODE USB_FUIO_EVENT_NODE; + +#pragma pack(1) +struct _USB_FUIO_EVENT_NODE{ + EFI_USBFN_MESSAGE Message; + UINTN PayloadSize; + EFI_USBFN_MESSAGE_PAYLOAD Payload; + USB_FUIO_EVENT_NODE *Nextptr; +}; + +typedef struct { + UINTN Signature; + UINTN XdciMmioBarAddr; + EFI_HANDLE XdciHandle; + // + // Timer to handle EndPoint event periodically. + // + EFI_EVENT XdciPollTimer; + EFI_USB_DEVICE_MODE_PROTOCOL UsbDevModeProtocol; + EFI_USBFN_IO_PROTOCOL UsbFunIoProtocol; + + // + // Structure members used by UsbFunIoProtocol. + // + USB_MEM_NODE *FirstNodePtr; + EFI_USB_DEVICE_INFO *DevInfoPtr; + EFI_USB_CONFIG_INFO IndexPtrConfig; + EFI_USB_INTERFACE_INFO IndexPtrInteface; + USB_DEVICE_ENDPOINT_INFO IndexPtrInEp; + USB_DEVICE_ENDPOINT_INFO IndexPtrOutEp; + XDCI_CORE_HANDLE *XdciDrvIfHandle; + USB_DEV_CORE *DrvCore; + UINT16 VendorId; + UINT16 DeviceId; + USBD_EP_XFER_REC EndPointXferRec[DWC_XDCI_MAX_ENDPOINTS]; + BOOLEAN StartUpController; + BOOLEAN DevReConnect; + BOOLEAN DevResetFlag; + EFI_EVENT TimerEvent; + USB_FUIO_EVENT_NODE *EventNodePtr; + // + // Following structure members are used by UsbDevModeProtocol. + // + +} USB_XDCI_DEV_CONTEXT; +#pragma pack() + + + +/** + Check whether USB bus driver support this device. + + @param This The USB bus driver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS The bus supports this controller. + @retval EFI_UNSUPPORTED This device isn't supported. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Start to process the controller. + + @param This The USB bus driver binding instance. + @param Controller The controller to check. + @param RemainingDevicePath The remaining device patch. + + @retval EFI_SUCCESS The controller is controlled by the usb bus. + @retval EFI_ALREADY_STARTED The controller is already controlled by the usb + bus. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop handle the controller by this USB bus driver. + + @param This The USB bus driver binding protocol. + @param Controller The controller to release. + @param NumberOfChildren The child of USB bus that opened controller + BY_CHILD. + @param ChildHandleBuffer The array of child handle. + + @retval EFI_SUCCESS The controller or children are stopped. + @retval EFI_DEVICE_ERROR Failed to stop the driver. + +**/ +EFI_STATUS +EFIAPI +UsbDeviceDxeDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +EFIAPI +PlatformSpecificInit ( + VOID + ); + +extern EFI_COMPONENT_NAME_PROTOCOL mUsbDeviceDxeComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL mUsbDeviceDxeComponentName2; + +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.inf b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.inf new file mode 100644 index 0000000000..46c499ab1a --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceDxe.inf @@ -0,0 +1,74 @@ +## @file +# +# Copyright (c) 2008 - 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbDeviceDxe + FILE_GUID = 42CF2D4A-78B4-4B80-80F9-96A83A630D70 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = UsbDeviceDxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + UsbDeviceDxe.c + UsbFuncIo.c + UsbIoNode.c + ComponentName.c + UsbDeviceMode.c + XdciDevice.c + XdciDWC.c + XdciTable.c + XdciUtility.c + +[Packages] + MdePkg/MdePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + BroxtonPlatformPkg/PlatformPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + TimerLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + PmicLib + +[Protocols] + gEfiUsbDeviceModeProtocolGuid + gEfiUsbFnIoProtocolGuid + gEfiPciIoProtocolGuid + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + +[Guids] + gEfiEventExitBootServicesGuid + +#[BuildOptions] +# MSFT:*_*_*_CC_FLAGS = /D SUPPORT_SUPER_SPEED +# GCC:*_*_*_CC_FLAGS = -DSUPPORT_SUPER_SPEED + +[Depex] + TRUE + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.c new file mode 100644 index 0000000000..d0358b9dc8 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.c @@ -0,0 +1,1489 @@ +/** @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 +#include +#include "XdciUtility.h" +#include "UsbDeviceMode.h" +#include "UsbDeviceDxe.h" + +// +// 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; + +STATIC VOID +XhciSwitchSwid(BOOLEAN enable) +{ + UINTN XhciPciMmBase; + EFI_PHYSICAL_ADDRESS XhciMemBaseAddress; + UINT32 DualRoleCfg0; + UINT32 DualRoleCfg1; + + XhciPciMmBase = MmPciAddress (0, 0, PCI_DEVICE_NUMBER_XHCI, PCI_FUNCTION_NUMBER_XHCI, 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 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 *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 *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 *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 *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 *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 *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 = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UsbdMonitorEvents, + XdciDevContext, + &XdciDevContext->XdciPollTimer + ); + if (!EFI_ERROR (Status)) { + Status = gBS->SetTimer (XdciDevContext->XdciPollTimer, TimerPeriodic, EFI_TIMER_PERIOD_MILLISECONDS (20)); + 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")); + gBS->SetTimer (XdciDevContext->XdciPollTimer, TimerCancel, 0); + gBS->CloseEvent (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; + gBS->Stall (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 *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 *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 *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 *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 *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/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.h new file mode 100644 index 0000000000..54459744bc --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbDeviceMode.h @@ -0,0 +1,39 @@ +/** @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_MODE_DXE_H_ +#define _USB_DEVICE_MODE_DXE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "XdciCommon.h" +#include "XdciDevice.h" + + +/// +/// Function declaration +/// +EFI_STATUS +UsbdSetupHdlr ( + IN EFI_USB_DEVICE_REQUEST *CtrlRequest + ); + +extern EFI_USB_DEVICE_MODE_PROTOCOL mUsbDeviceModeProtocol; + +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.c new file mode 100644 index 0000000000..9a156ba9b4 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.c @@ -0,0 +1,2219 @@ +/** @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 "UsbDeviceDxe.h" + +// +// 16 bytes in a guid x 2 characters per byte, 4 chars for dashes and a NUL +// +#define CHARS_IN_GUID (sizeof(GUID) * 2 + 4 + 1) + +// +// Strings that get sent with the USB Connection +// +static CHAR16 mUsbFnDxeMfgString[] = L"Intel Corporation"; +static CHAR16 mUsbFnDxeProductString[] = L"Broxton"; +static CHAR16 mUsbFnDxeSerialNumber[] = L"INT123456"; + +// +// Duplicated from MiscSystemManufacturerData.c Some parts of it will +// replaced with device-specific unique values. +// +static GUID mSmBiosUniqueGuid = { + 0x5e24fe9c, 0xc8d0, 0x45bd, 0xa7, 0x9f, 0x54, 0xea, 0x5f, 0xbd, 0x3d, 0x97 + }; + +EFI_USBFN_IO_PROTOCOL mUsbFunIoProtocol = { + EFI_USBFN_IO_PROTOCOL_REVISION, + DetectPort, + ConfigureEnableEndpoints, + GetEndpointMaxPacketSize, + GetDeviceInfo, + GetVendorIdProductId, + AbortTransfer, + GetEndpointStallState, + SetEndpointStallState, + EventHandler, + Transfer, + GetMaxTransferSize, + AllocateTransferBuffer, + FreeTransferBuffer, + StartController, + StopController, + SetEndpointPolicy, + GetEndpointPolicy +}; + + +EFI_STATUS +PrintEventBuffer( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + UINT32 EventCount; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_DEV_CORE *UsbDeviceCorePtr; + UINT32 Index; + UINT32 *DbBufPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + + EventCount = UsbRegRead ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(0)); + + DbBufPtr = (UINT32*)(UINTN)XdciCorePtr->CurrentEventBuffer; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: XdciCorePtr->AlignedEventBuffers 0x%08x\n", (UINTN)XdciCorePtr->AlignedEventBuffers)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: DUMP BUF_S\n")); + for (Index = 0; Index < ((EventCount / 4) + 1); Index++) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "0x%08x\n", DbBufPtr[Index])); + } + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: DUMP BUF_E\n")); + + return EFI_SUCCESS; +} + +/** +Debug End +**/ + +/** + Returns information about what type of device was attached. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[out] PortType Returns the USB port type. + + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request or the device is not + attached to the host. + + +**/ +EFI_STATUS +EFIAPI +DetectPort ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT EFI_USBFN_PORT_TYPE *PortType + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + EFI_STATUS Status; + UINT8 Value8; + + DEBUG ((USB_FUIO_DEBUG_INFO, "DetectPort - Entry\n")); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + // + // USBSRCDETRSLT Bit[5:2] + // Result of USB HW Source Detection algorithm + // Power-Domain: VRTC + // Result of USB HW Source Detection algorithm : + // 0000 = Not determined + // 0001 = SDP Attached + // 0010 = DCP Attached + // 0011 = CDP Attached + // 0100 = ACA Attached + // 0101 = SE1 Attached + // 0110 = MHL Attached + // 0111 = Floating D+/D- Attached + // 1000 = Other Attached + // 1001 = DCP detected by ext. USB PHY + // 1010-1111 = Rsvd + // Reset: 0000B + // + + Value8 =PmicRead8 (0x5E, 0X29); + if ((Value8 & 0x03) != 0x02) { + *PortType = EfiUsbUnknownPort; + Status = EFI_NOT_READY; + goto out; + } + + Value8 = Value8 >> 2 & 0x0f; + Status = EFI_SUCCESS; + switch (Value8) { + case 1: + *PortType = EfiUsbStandardDownstreamPort; + break; + case 2: + *PortType = EfiUsbDedicatedChargingPort; + break; + case 3: + *PortType = EfiUsbChargingDownstreamPort; + break; + + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + *PortType = EfiUsbUnknownPort; + break; + case 0: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + *PortType = EfiUsbUnknownPort; + Status = EFI_NOT_READY; + break; + } + +out: + DEBUG ((USB_FUIO_DEBUG_INFO, "DetectPort - Exit\n")); + return EFI_SUCCESS; +} + + +/** + The AllocateTransferBuffer function allocates a memory region of Size bytes + and returns the address of the allocated memory that satisfies underlying + controller requirements in the location referenced by Buffer. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Size The number of bytes to allocate for the transfer + Buffer. + @param[in] Buffer A pointer to a pointer to the allocated Buffer + if the call succeeds; undefined otherwise. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval The requested transfer Buffer could not be allocated. + +**/ +EFI_STATUS +EFIAPI +AllocateTransferBuffer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + VOID *AllocateBufferPtr; + USB_MEM_NODE *NodePtr; + + DEBUG ((USB_FUIO_DEBUG_INFO, "AllocateTransferBuffer - Entry\n")); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + if (Size == 0) { + Status = EFI_INVALID_PARAMETER; + goto ErrorExit; + } + + AllocateBufferPtr = AllocateZeroPool (Size); + + if (AllocateBufferPtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + // + // Create new node + // + Status = InsertNewNodeToHead (This, &NodePtr); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + NodePtr->Size = Size; + NodePtr->AllocatePtr = AllocateBufferPtr; + + *Buffer = AllocateBufferPtr; + + DEBUG ((USB_FUIO_DEBUG_INFO, "AllocateTransferBuffer addr 0x%08x\n", AllocateBufferPtr)); + DEBUG ((USB_FUIO_DEBUG_INFO, "AllocateTransferBuffer - Exit\n")); + return EFI_SUCCESS; + +ErrorExit: + + DEBUG ((USB_FUIO_DEBUG_ERROR, "AllocateTransferBuffer - ERRROR %r\n",Status)); + return Status; +} + + +/** + Deallocates the memory allocated for the transfer Buffer by + AllocateTransferBuffer function. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Buffer Buffer Pointer to the transfer Buffer + to deallocate. + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + +**/ +EFI_STATUS +EFIAPI +FreeTransferBuffer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + DEBUG ((USB_FUIO_DEBUG_LOAD, "FreeTransferBuffer - Entry\n")); + + Status = RemoveNode (This, Buffer); + if (EFI_ERROR(Status)) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "FreeTransferBuffer - ERROR\n")); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, "FreeTransferBuffer - Exit\n")); + return EFI_SUCCESS; +} + +/** + Configure endpoints Based on supplied device and configuration descriptors. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] DeviceInfo A pointer to EFI_USBFN_DEVICE_INFO instance. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to + lack of resources. + +**/ +EFI_STATUS +EFIAPI +ConfigureEnableEndpoints ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN EFI_USB_DEVICE_INFO *DeviceInfo + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + Status = EFI_SUCCESS; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "ConfigureEnableEndpoints - Entry\n")); + // + //Assuming that the hardware has already been initialized, + //this function configures the endpoints using supplied + //DeviceInfo, activates the port, and starts receiving USB events + // + Status = EFI_SUCCESS; + if (DeviceInfo == NULL) { + Status = EFI_INVALID_PARAMETER; + goto FUNC_EXIT; + } + + UsbFuncIoDevPtr->DevInfoPtr->DeviceDescriptor = DeviceInfo->DeviceDescriptor; + + // + // Set Configure table + // + if (DeviceInfo->DeviceDescriptor->NumConfigurations > 1) { + DEBUG ((EFI_D_ERROR, "!!!Error ConfigNum over '1' %d\n", DeviceInfo->DeviceDescriptor->NumConfigurations)); + } + UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor = DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor; + UsbFuncIoDevPtr->IndexPtrConfig.InterfaceInfoTable[0] = DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]; + + // + // Set Interface + // + if (DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces > 1) { + DEBUG ((EFI_D_ERROR, "!!!Error NumInterfaces[0] over '1' %d\n", DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces)); + } + UsbFuncIoDevPtr->IndexPtrInteface.InterfaceDescriptor = DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor; + + // + // Set Endpoint + // + if (UsbFuncIoDevPtr->IndexPtrInteface.InterfaceDescriptor->NumEndpoints > 2) { + DEBUG ((EFI_D_ERROR, "!!!Error NumEndPoint[0] over '2' %d\n", UsbFuncIoDevPtr->IndexPtrInteface.InterfaceDescriptor->NumEndpoints)); + } + + UsbFuncIoDevPtr->IndexPtrInEp.EndpointCompDesc = NULL; + UsbFuncIoDevPtr->IndexPtrOutEp.EndpointCompDesc = NULL; + + if ((DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]->EndpointAddress & USB_ENDPOINT_DIR_IN) != 0) { + UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc = DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]; + UsbFuncIoDevPtr->IndexPtrOutEp.EndpointDesc = DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[1]; + } else { + UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc = DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[1]; + UsbFuncIoDevPtr->IndexPtrOutEp.EndpointDesc = DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, " In Ep Num 0x%02x\n", UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc->EndpointAddress)); + + DEBUG ((USB_FUIO_DEBUG_LOAD, " Out Ep Num 0x%02x\n", UsbFuncIoDevPtr->IndexPtrOutEp.EndpointDesc->EndpointAddress)); + +FUNC_EXIT: + DEBUG ((USB_FUIO_DEBUG_LOAD, "ConfigureEnableEndpoints - exit %r\n", Status)); + return Status; +} + +/** + Returns the maximum packet size of the specified endpoint type for + the supplied bus Speed. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointType Endpoint type as defined as EFI_USB_ENDPOINT_TYPE. + @param[in] BusSpeed Bus Speed as defined as EFI_USB_BUS_SPEED. + @param[in] MaxPacketSize The maximum packet size, in bytes, + of the specified endpoint type. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. +**/ +EFI_STATUS +EFIAPI +GetEndpointMaxPacketSize ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN EFI_USB_ENDPOINT_TYPE EndpointType, + IN EFI_USB_BUS_SPEED BusSpeed, + OUT UINT16 *MaxPacketSize + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + USB_DEV_CORE *DevCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + DevCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = DevCorePtr->ControllerHandle; + Status = EFI_SUCCESS; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointMaxPacketSize - Entry\n")); + + switch (EndpointType) { + case UsbEndpointControl: +#ifdef SUPPORT_SUPER_SPEED + *MaxPacketSize = USB_EP0_MAX_PKT_SIZE_SS; // Default to super Speed +#else + *MaxPacketSize = USB_EP0_MAX_PKT_SIZE_HS; // Default to high Speed +#endif + break; + + case UsbEndpointBulk: +#ifdef SUPPORT_SUPER_SPEED + *MaxPacketSize = USB_BULK_EP_PKT_SIZE_SS; // Default to super Speed +#else + *MaxPacketSize = USB_BULK_EP_PKT_SIZE_HS; // Default to high Speed +#endif + break; + + case UsbEndpointInterrupt: + *MaxPacketSize = 1; + break; + + case UsbEndpointIsochronous: + default: + Status = EFI_DEVICE_ERROR; + break; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointMaxPacketSize - Exit %r\n", Status)); + return Status; +} + + +/** + Returns the maximum supported transfer size. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] MaxTransferSize The maximum supported transfer size, in bytes. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. +**/ +EFI_STATUS +EFIAPI +GetMaxTransferSize ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT UINTN *MaxTransferSize + ) +{ + // + // Need to check, Make max transfer package to 8MB + // + *MaxTransferSize = MAX_TRANSFER_PACKET; + return EFI_SUCCESS; +} + + +/** + This function returns the unique device ID of the device--this matches + what is populated in the SMBIOS table. + + @param[in/out] BufferSize On input, the size of the Buffer in bytes. + On output, the amount of data returned in Buffer + in bytes. + + @param[out] Buffer A pointer to a Buffer to return the requested + information as a Unicode string. What string are + we talking about + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_BUFFER_TOO_SMALL A parameter is invalid. + +**/ +STATIC +EFI_STATUS +EFIAPI +GetDeviceSerialNumber ( + IN OUT UINTN *BufferSize, + OUT VOID *Buffer OPTIONAL + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + CHAR16 UuidString[CHARS_IN_GUID]; + UINTN CharsCopied; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "+GetDeviceSerialNumber\n")); + // + // check bounds + // + if (*BufferSize < sizeof(UuidString)) { + Status = EFI_BUFFER_TOO_SMALL; + *BufferSize = 0; + goto Error; + } + + // + // The rest of mSmBiosUniqueGuid will be same. Note that we cannot + // read the SMBIOS table directly, as it might not be ready by the time we + // are to read it. The population of the data from the eMMC is ready + // by the time we are here. + // + + // + // Print to to a string, and copy it off + // + CharsCopied = UnicodeSPrint(UuidString, sizeof(UuidString), L"%g", &mSmBiosUniqueGuid); + if (CharsCopied != (CHARS_IN_GUID - 1)) + { + Status = EFI_BUFFER_TOO_SMALL; + *BufferSize = 0; + goto Error; + } + CopyMem(Buffer, UuidString, sizeof(UuidString)); + *BufferSize = sizeof(UuidString); + +Error: + + DEBUG ((USB_FUIO_DEBUG_LOAD, "-GetDeviceSerialNumber, Status = 0x%08x\r\n", Status)); + + return Status; +} + + +/** + Returns device specific information Based on the supplied identifier as + a Unicode string + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Id Requested information id. + @param[in] BufferSize On input, the size of the Buffer in bytes. + On output, the amount of data returned in Buffer + in bytes. + @param[in] Buffer A pointer to a Buffer to return the requested + information as a Unicode string. What string are + we talking about + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. +**/ +EFI_STATUS +EFIAPI +GetDeviceInfo ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN EFI_USBFN_DEVICE_INFO_ID Id, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer OPTIONAL + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + Status = EFI_SUCCESS; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetDeviceInfo - Entry\n")); + + if ((BufferSize == 0) || (Buffer == NULL)) { + Status = EFI_INVALID_PARAMETER; + goto FUN_EXIT; + } + + switch (Id) { + + // + // FIXME: Get real serial number of board + // + case EfiUsbDeviceInfoSerialNumber: + if (*BufferSize < sizeof(mUsbFnDxeSerialNumber)) { + Status = EFI_BUFFER_TOO_SMALL; + *BufferSize = 0; + goto FUN_EXIT; + } + CopyMem(Buffer, mUsbFnDxeSerialNumber, sizeof(mUsbFnDxeSerialNumber)); + *BufferSize = sizeof(mUsbFnDxeSerialNumber); + break; + + case EfiUsbDeviceInfoManufacturerName: + if (*BufferSize < sizeof(mUsbFnDxeMfgString)) { + Status = EFI_BUFFER_TOO_SMALL; + *BufferSize = 0; + goto FUN_EXIT; + } + CopyMem(Buffer, mUsbFnDxeMfgString, sizeof(mUsbFnDxeMfgString)); + *BufferSize = sizeof(mUsbFnDxeMfgString); + break; + + case EfiUsbDeviceInfoProductName: + if (*BufferSize < sizeof(mUsbFnDxeProductString)) { + Status = EFI_BUFFER_TOO_SMALL; + *BufferSize = 0; + goto FUN_EXIT; + } + CopyMem(Buffer, mUsbFnDxeProductString, sizeof(mUsbFnDxeProductString)); + *BufferSize = sizeof(mUsbFnDxeProductString); + break; + + case EfiUsbDeviceInfoUnknown: + default: + Status = EFI_UNSUPPORTED; + *BufferSize = 0; + DEBUG ((USB_FUIO_DEBUG_ERROR, "Unknown ID %d encountered.\r\n", Id)); + break; + } + +FUN_EXIT: + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - ConfigDescriptor addr 0x%08x \n", (UINTN)UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor)); + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetDeviceInfo - Exit %r\n", Status)); + return Status; +} + + +/** + Returns vendor-id and product-id of the device. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[out] Vid Returned vendor-id of the device. + @param[out] Pid Returned product-id of the device. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND Unable to return vid or pid. + +**/ +EFI_STATUS +EFIAPI +GetVendorIdProductId ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT UINT16 *Vid, + OUT UINT16 *Pid + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + // + // *Vid = 0x8086 + // *Pid = 0x0A65 + // + *Vid = UsbFuncIoDevPtr->VendorId; + *Pid = UsbFuncIoDevPtr->DeviceId; + return EFI_SUCCESS; +} + +/** + Aborts transfer on the specified endpoint. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointIndex Indicates the endpoint on which the ongoing + transfer needs to be canceled. + @param[in] Direction Direction of the endpoint. + + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. + +**/ +EFI_STATUS +EFIAPI +AbortTransfer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_DEV_CORE *UsbDeviceCorePtr; + USB_EP_INFO EpInfo; + EFI_STATUS Status; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "FU:AbortTransfer - Entry\n")); + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + Status = EFI_SUCCESS; + + if (UsbFuncIoDevPtr->DevResetFlag == TRUE) { + return Status; + } + + EpInfo.EpNum = EndpointIndex; + EpInfo.EpDir = Direction? UsbEpDirIn : UsbEpDirOut; + + Status = UsbDeviceEpCancelTransfer (UsbFuncIoDevPtr->DrvCore, &EpInfo); + + DEBUG ((USB_FUIO_DEBUG_LOAD, "FU:AbortTransfer - Exit %r\n", Status)); + return Status; +} + +/** + Returns the stall state on the specified endpoint. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointIndex Indicates the endpoint on which the ongoing + transfer needs to be canceled. + @param[in] Direction Direction of the endpoint. + @param[in] State Boolean, true value indicates that the endpoint + is in a stalled state, false otherwise. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. + +**/ +EFI_STATUS +EFIAPI +GetEndpointStallState ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN OUT BOOLEAN *State + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + XDCI_CORE_HANDLE *XdciCorePtr; + UINT32 EndPoint; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointStallState - Entry\n")); + + EndPoint = UsbGetPhysicalEpNum (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut); + + XdciCorePtr = UsbFuncIoDevPtr->XdciDrvIfHandle; + + if (XdciCorePtr->EpHandles[EndPoint].State == USB_EP_STATE_STALLED) { + *State = TRUE; + } else { + *State = FALSE; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointStallState - Exit\n")); + return EFI_SUCCESS; +} + + +EFI_STATUS +UsbSetAddress ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT32 Address + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_DEV_CORE *UsbDeviceCorePtr; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetAddress - 0x%04x Entry\n", Address)); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + Status = EFI_SUCCESS; + + Status = UsbDeviceSetAddress (UsbDeviceCorePtr, (UINT32)Address); + + if (Status != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + goto EXIT_SET_ADDRESS; + } + + Status = UsbDeviceEp0TxStatus (UsbDeviceCorePtr); + + if (Status != EFI_SUCCESS) { + Status = EFI_NO_RESPONSE; + goto EXIT_SET_ADDRESS; + } + +EXIT_SET_ADDRESS: + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetAddress - Exit %r\n", Status)); + return Status; +} + + +EFI_STATUS +EFIAPI +UsbSetconfigure ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT32 InterFaceIndex + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_DEV_CORE *UsbDeviceCorePtr; + UINT32 InterfaceNum; + UINT32 EndPointNum; + UINT32 EndPointIndex; + EFI_USB_INTERFACE_INFO *InterfaceInfoPtr; + USB_EP_INFO EpInfo; + USB_DEVICE_ENDPOINT_INFO EpDescInfo; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - 0x%04x Entry\n", InterFaceIndex)); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + Status = EFI_SUCCESS; + + InterfaceNum = UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor->NumInterfaces; + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - ConfigDescriptor addr 0x%08x \n", (UINTN)UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor)); + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - DescriptorType 0x%04x ; ConfigurationValue 0x%04x\n", + UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor->DescriptorType, + UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor->ConfigurationValue + )); + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - InterfaceNum 0x%04x \n", InterfaceNum)); + if (InterfaceNum < InterFaceIndex) { + Status = EFI_INVALID_PARAMETER; + goto EXIT__SET_CONFIGURE; + } + + // + // Arry strart form '0', Index start from '1'. + // + InterfaceInfoPtr = UsbFuncIoDevPtr->IndexPtrConfig.InterfaceInfoTable[InterFaceIndex - 1]; + EndPointNum = InterfaceInfoPtr->InterfaceDescriptor->NumEndpoints; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - Total EP NUM 0x%04x \n", EndPointNum)); + + for (EndPointIndex = 0; EndPointIndex < EndPointNum; EndPointIndex++) { + EpDescInfo.EndpointDesc = InterfaceInfoPtr->EndpointDescriptorTable[EndPointIndex]; + EpDescInfo.EndpointCompDesc = NULL; + UsbFnSetEpInfo (&EpInfo, &EpDescInfo); + DEBUG ((USB_FUIO_DEBUG_LOAD, "EndpointAddress 0x%02x\n", EpDescInfo.EndpointDesc->EndpointAddress)); + + if (UsbDeviceInitEp (UsbDeviceCorePtr, &EpInfo) == EFI_SUCCESS) { + if (UsbDeviceEpEnable (UsbDeviceCorePtr, &EpInfo) == EFI_SUCCESS) { + } else { + Status = EFI_DEVICE_ERROR; + DEBUG ((DEBUG_INFO, "UsbDeviceEpEnable() - Failed to enable endpoint\n")); + } + } else { + Status = EFI_DEVICE_ERROR; + DEBUG ((DEBUG_INFO, "UsbDeviceInitEp() - Failed to initialize endpoint\n")); + } + } + + Status = UsbDeviceEp0TxStatus (UsbDeviceCorePtr); + + if (Status != EFI_SUCCESS) { + Status = EFI_NO_RESPONSE; + goto EXIT__SET_CONFIGURE; + } + + +EXIT__SET_CONFIGURE: + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - Exit %r\n", Status)); + + return Status; +} + +/** + Sets or clears the stall state on the specified endpoint. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointIndex Indicates the endpoint on which the ongoing + transfer needs to be canceled. + @param[in] Direction Direction of the endpoint. + @param[in] State Requested stall state on the specified endpoint. + True value causes the endpoint to stall; + false value clears an existing stall. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. + +**/ +EFI_STATUS +EFIAPI +SetEndpointStallState ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN BOOLEAN State + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + USB_EP_INFO pEpInfo; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + DEBUG ((USB_FUIO_DEBUG_LOAD, "SetEndpointStallState - Entry\n")); + Status = EFI_SUCCESS; + + pEpInfo.EpNum = EndpointIndex; + pEpInfo.EpDir = Direction? UsbEpDirIn : UsbEpDirOut; + + if (State == TRUE) { + Status = UsbDeviceEpStall (UsbFuncIoDevPtr->DrvCore, (VOID*)(UINTN) &pEpInfo); + } else { + Status = UsbDeviceEpClearStall (UsbFuncIoDevPtr->DrvCore, (VOID*)(UINTN) &pEpInfo); + } + + if (Status != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, "SetEndpointStallState - Exit\n")); + return Status; +} + +EFI_STATUS +DeviceEventCheck( + IN EFI_USBFN_IO_PROTOCOL *This, + IN USBD_EVENT_BUF *EventIndex, + OUT UINT32 *ProcessSize, + OUT EFI_USBFN_MESSAGE *Message, + OUT BOOLEAN *EventFlag + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + UINT32 EventReg; + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "\n FUEV::DeviceEvent entry....\n")); + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + EventReg = (EventIndex->Event & DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK); + EventReg >>= DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS; + *EventFlag = FALSE; + + // + // Assume default event size. Change it in switch case if + // different + // + *ProcessSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; + + switch (EventReg) { + case DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT\n")); + *Message = EfiUsbMsgBusEventDetach; + break; + + case DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT\n")); + // + // In resetDet will prepare setup Xfer package + // + UsbFuncIoDevPtr->DevReConnect = FALSE; + UsbFuncIoDevPtr->DevResetFlag = TRUE; + + usbProcessDeviceResetDet (XdciCorePtr); + UsbDeviceSetAddress (UsbDeviceCorePtr, 0); + *Message = EfiUsbMsgBusEventReset; + *EventFlag = TRUE; + break; + + case DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT\n")); + usbProcessDeviceResetDone(XdciCorePtr); + UsbDeviceSetAddress(UsbDeviceCorePtr, 0); + UsbFuncIoDevPtr->DevReConnect = TRUE; + UsbFuncIoDevPtr->DevResetFlag = FALSE; + *EventFlag = TRUE; + *Message = EfiUsbMsgNone; + break; + + case DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT\n")); + *Message = EfiUsbMsgBusEventSuspend; + *EventFlag = TRUE; + break; + + case DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT\n")); + *Message = EfiUsbMsgBusEventResume; + break; + + case DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT: + *ProcessSize = DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES; + *Message = EfiUsbMsgNone; + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFUDwcXdciProcessDeviceEvent: UNHANDLED device event: %x\n", EventReg)); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT\n")); + break; + + case DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT\n")); + break; + + default: + *EventFlag = FALSE; + *Message = EfiUsbMsgNone; + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFUWcXdciProcessDeviceEvent: UNHANDLED device event: %x\n", EventReg)); + break; + } + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "\n FUEV::DeviceEvent entry exit.... \n")); + return EFI_SUCCESS; +} + + +EFI_STATUS +Ep0XferDone( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT32 EndPointNum, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload + ) +{ + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + DWC_XDCI_ENDPOINT *EpHandle; + DWC_XDCI_TRB *Trb; + UINT32 TrbCtrl; + UINT32 TrbSts; + UINT32 BufferLen; + EFI_STATUS DevStatus; + USB_EP_INFO EpInfo; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + EpHandle = &XdciCorePtr->EpHandles[EndPointNum]; + Trb = XdciCorePtr->Trbs + (EndPointNum * DWC_XDCI_TRB_NUM); + + if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0XferDone. HW owns TRB: %x!!!\n", (UINT32)(UINTN)Trb)); + } + + DevStatus = EFI_SUCCESS; + BufferLen = 0; + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "EndPointNum:%d, TRB: Addr 0x%08x!!!\n", EndPointNum, (UINTN)Trb)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->TrbCtrl: %x!!!\n", (UINT32)Trb->TrbCtrl)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->LenXferParams: %x!!!\n", (UINT32)Trb->LenXferParams)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->BuffPtrLow: %x!!!\n", (UINT32)Trb->BuffPtrLow)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->BuffPtrHigh: %x!!!\n", (UINT32)Trb->BuffPtrHigh)); + + // + // Set CheckFlag to FALSE for 'DwcXdciEpRxData' function + // check the RX request complete and continue next transfer request + // + EpHandle->CheckFlag = FALSE; + EpHandle->CurrentXferRscIdx = 0; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D01!!\n")); + TrbCtrl = (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_TYPE_MASK) >> DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D02!!\n")); + TrbSts = (Trb->LenXferParams & DWC_XDCI_TRB_STATUS_MASK) >> DWC_XDCI_TRB_STATUS_BIT_POS; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D03!!\n" )); + BufferLen = Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D04 TrbCtrl :: %x!!\n", TrbCtrl)); + switch (TrbCtrl) { + case DWC_XDCI_TRB_CTRL_TYPE_SETUP: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done DWC_XDCI_TRB_CTRL_TYPE_SETUP!!\n")); + // + // This is delay for other host USB controller(none Intel), identify device get fail issue. + // + gBS->Stall(130); + BufferLen = 8; + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "DWC_XDCI_TRB_CTRL_TYPE_SETUP!!\n")); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "AlignedSetupBuffer::0x%08x!!\n", XdciCorePtr->AlignedSetupBuffer)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Payload::0x%08x!!\n", (UINTN)Payload)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "BufferLen::0x%08x!!\n", (UINTN)BufferLen)); + *Message = EfiUsbMsgSetupPacket; + CopyMem (Payload, XdciCorePtr->AlignedSetupBuffer, BufferLen); + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D06!!\n")); + if (!(XdciCorePtr->AlignedSetupBuffer[0] & USB_SETUP_DATA_PHASE_DIRECTION_MASK)) { + if ((XdciCorePtr->AlignedSetupBuffer[0] == 0x00) ) { + if ((XdciCorePtr->AlignedSetupBuffer[1] == USB_DEV_SET_ADDRESS)) { + // + // set address + // + UsbSetAddress ( + This, + (UINT32)(XdciCorePtr->AlignedSetupBuffer[3] << 8 | XdciCorePtr->AlignedSetupBuffer[2]) + ); + + *Message = EfiUsbMsgNone; + } else if ((XdciCorePtr->AlignedSetupBuffer[1] == USB_DEV_SET_CONFIGURATION)) { + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "\n set configure !!!")); + UsbSetconfigure ( + This, + (UINT32)(XdciCorePtr->AlignedSetupBuffer[3] << 8 | XdciCorePtr->AlignedSetupBuffer[2]) + ); + *Message = EfiUsbMsgNone; + } + } + } + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D07!!\n")); + break; + + case DWC_XDCI_TRB_CTRL_TYPE_DATA: + DEBUG ((DEBUG_INFO, "Ep0 done DWC_XDCI_TRB_CTRL_TYPE_DATA!!\n")); + // + // Notify upper layer of control transfer completion + // if a callback function was registerd + // + if ((EndPointNum & 0x01) == 0) { + *Message = EfiUsbMsgEndpointStatusChangedRx; + } else { + *Message = EfiUsbMsgEndpointStatusChangedTx; + } + Payload->utr.EndpointIndex = (UINT8)(EndPointNum >> 1); + Payload->utr.Direction = (UINT8)(EndPointNum & 0x01); + Payload->utr.Buffer = (VOID*)(UINTN)(Trb->BuffPtrLow); + + DEBUG ((DEBUG_INFO, "Ep0 EndPointNum: %x!!!\n", (UINT32)EndPointNum)); + DEBUG ((DEBUG_INFO, "Ep0 done XferLength: %x!!!\n", (UINT32)UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength)); + Payload->utr.Buffer = (VOID*)UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferAddress; + Payload->utr.BytesTransferred = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength; + + if (TrbSts == 0) { + if ((Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK) == 0) { + Payload->utr.TransferStatus = UsbTransferStatusComplete; + } else { + Payload->utr.TransferStatus = UsbTransferStatusActive; + } + } else if (TrbSts != 0) { + Trb->TrbCtrl |= DWC_XDCI_TRB_CTRL_HWO_MASK; + *Message = EfiUsbMsgNone; + Payload->utr.TransferStatus = UsbTransferStatusAborted; + DEBUG ((DEBUG_INFO, "Flush FIFO!!!\n" )); + EpInfo.EpNum = 0; + EpInfo.EpDir =UsbEpDirIn; + UsbXdciCoreFlushEpFifo(XdciCorePtr, &EpInfo); + EpInfo.EpNum = 0; + EpInfo.EpDir =UsbEpDirOut; + UsbXdciCoreFlushEpFifo(XdciCorePtr, &EpInfo); + DevStatus = UsbDeviceEp0RxSetup (UsbDeviceCorePtr, XdciCorePtr->AlignedSetupBuffer); + } + + break; + + case DWC_XDCI_TRB_CTRL_TYPE_STATUS2: + case DWC_XDCI_TRB_CTRL_TYPE_STATUS3: + Payload->utr.Buffer = (VOID*) UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferAddress; + Payload->utr.BytesTransferred = 0; + Payload->utr.EndpointIndex = (UINT8)(EndPointNum >> 1); + if ((EndPointNum & 0x01) == 0) { + *Message = EfiUsbMsgEndpointStatusChangedRx; + } else { + *Message = EfiUsbMsgEndpointStatusChangedTx; + } + + if (TrbSts == 0) { + if ((Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK) == 0) { + Payload->utr.TransferStatus = UsbTransferStatusComplete; + } else { + Payload->utr.TransferStatus = UsbTransferStatusActive; + } + } else if (TrbSts != 0) { + Payload->utr.TransferStatus = UsbTransferStatusAborted; + } + + DevStatus = UsbDeviceEp0RxSetup (UsbDeviceCorePtr, XdciCorePtr->AlignedSetupBuffer); + + if (DevStatus) { + DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone: FAILED to queue SETUP\n")); + } + DEBUG ((DEBUG_INFO, "Status phase done. Queue next SETUP packet==>\n")); + break; + + default: + *Message = EfiUsbMsgNone; + DEBUG ((DEBUG_INFO, "DwcXdciProcessEp0XferPhaseDone: UNHANDLED STATE in TRB\n")); + break; + } + return EFI_SUCCESS; +} + + +EFI_STATUS +NoneEp0XferDone( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT32 EndPointNum, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload + ) +{ + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + DWC_XDCI_ENDPOINT *EpHandle; + DWC_XDCI_TRB *Trb; + UINT32 TrbCtrl; + UINT32 TrbSts; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + EpHandle = &XdciCorePtr->EpHandles[EndPointNum]; + Trb = XdciCorePtr->Trbs + (EndPointNum * DWC_XDCI_TRB_NUM); + + if (Trb->TrbCtrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "NoneEp0XferDone. HW owns TRB: %x!!!, EndPointNum: %x\n", (UINT32)(UINTN)Trb, EndPointNum)); + } + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " TRB: Addr 0x%08x!!!\n", (UINTN)Trb)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->BuffPtrLow: %x!!!\n", (UINT32)Trb->BuffPtrLow)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->BuffPtrHigh: %x!!!\n", (UINT32)Trb->BuffPtrHigh)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->LenXferParams: %x!!!\n", (UINT32)Trb->LenXferParams)); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->TrbCtrl: %x!!!\n", (UINT32)Trb->TrbCtrl)); + + // + // Set CheckFlag to FALSE for 'DwcXdciEpRxData' function + // check the RX request complete and continue next transfer request + // + EpHandle->CheckFlag = FALSE; + EpHandle->CurrentXferRscIdx = 0; + *Message = EfiUsbMsgNone; + + 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; + + Payload->utr.BytesTransferred = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength; + Payload->utr.EndpointIndex = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].LogEpNum; + Payload->utr.Direction = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Direction; + Payload->utr.Buffer = (VOID*)(UINTN)(Trb->BuffPtrLow); + UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Complete = TRUE; + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "EndPointAddress = 0x%08x\n", Payload->utr.EndpointIndex)); + if (Payload->utr.Direction == EfiUsbEndpointDirectionDeviceTx) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Direction::EfiUsbEndpointDirectionDeviceTx\n")); + *Message = EfiUsbMsgEndpointStatusChangedTx; + } else { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Direction::EfiUsbEndpointDirectionDeviceRx\n")); + *Message = EfiUsbMsgEndpointStatusChangedRx; + } + + if (TrbSts == 0) { + if ((Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK) == 0) { + Payload->utr.TransferStatus = UsbTransferStatusComplete; + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::UsbTransferStatusComplete\n")); + } else { + Payload->utr.TransferStatus = UsbTransferStatusComplete; + Payload->utr.BytesTransferred -= (Trb->LenXferParams & DWC_XDCI_TRB_BUFF_SIZE_MASK); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::UsbTransferStatusComplete\n")); + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::Length %d \n", Payload->utr.BytesTransferred )); + } + } else if (TrbSts != 0) { + Payload->utr.TransferStatus = UsbTransferStatusAborted; + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::UsbTransferStatusAborted\n")); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +Ep0XferNotReady( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT32 EndPointNum, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload, + IN UINT32 EpStatus + ) +{ + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + + *Message = EfiUsbMsgNone; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EpEventCheck( + IN EFI_USBFN_IO_PROTOCOL *This, + IN USBD_EVENT_BUF *EventIndex, + OUT UINT32 *ProcessSize, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload, + OUT BOOLEAN *EventFlag + ) +{ + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + UINT32 EventReg; + UINT32 EpEvent; + UINT32 EndPointNumber; + UINT32 EventStatus; + USB_EP_STATE Ep_State; + UINTN TmpBufferSize; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV::EndPoint Event....\n")); + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This); + + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + EventReg = EventIndex->Event; + *ProcessSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; + *EventFlag = TRUE; + TmpBufferSize = 0; + + // + // Get EP num + // + EndPointNumber = (EventReg & DWC_XDCI_EVENT_BUFF_EP_NUM_MASK) >> DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS; + + EventStatus = EventReg & DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK; + + // + // Interpret event and handle transfer completion here + // + EpEvent = (EventReg & DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK) >> DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_EP EventReg 0x%08x\n", EventReg)); + + switch (EpEvent) { + case DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT\n")); + if (EndPointNumber > 1) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP None_Control transfer\n")); + NoneEp0XferDone (This, EndPointNumber, Message, PayloadSize, Payload); + } else { + // + // Control transfer + // + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP Control transfer\n")); + Ep0XferDone (This, EndPointNumber, Message, PayloadSize, Payload); + } + break; + + case DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY\n")); + *Message = EfiUsbMsgNone; + if(EndPointNumber < (sizeof(UsbFuncIoDevPtr->EndPointXferRec) / sizeof(UsbFuncIoDevPtr->EndPointXferRec[0]))) { + if ((UsbFuncIoDevPtr->EndPointXferRec[EndPointNumber].ZlpFlag == TRUE) && \ + (UsbFuncIoDevPtr->EndPointXferRec[EndPointNumber].Complete == TRUE)) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Request send ZLP\n")); + if ((EndPointNumber & 0x01) != 0) { + Transfer(This, + UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc->EndpointAddress, + EfiUsbEndpointDirectionDeviceTx, + &TmpBufferSize, + NULL + ); + UsbFuncIoDevPtr->EndPointXferRec[EndPointNumber].ZlpFlag = FALSE; + } + + } + } else { + // + // Is it data stage or status stage + // + // Data Statge + // + Ep_State = USB_EP_STATE_DATA; + // + // Control transfer + // + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP Control transfer not ready\n")); + Ep0XferNotReady (This, EndPointNumber, Message, PayloadSize, Payload, EventStatus); + *EventFlag = FALSE; + } + break; + + case DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS: + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS\n")); + break; + + default: + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFUDwcXdciProcessEpEvent: UNKNOWN EP event\n")); + break; + } + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV::EndPoint Event....exit\n")); + return EFI_SUCCESS; +} + + +EFI_STATUS +ProcessIntLineEvents( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT32 EventCount, + IN UINT32 *ProceSsEvent, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload, + OUT BOOLEAN *EventFlag + ) +{ + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + UINT32 CurrentEventAddr; + UINT32 ProceSsEventSize; + BOOLEAN EventReport; + BOOLEAN EpEventReport; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + CurrentEventAddr = (UINT32)(UINTN)(XdciCorePtr->CurrentEventBuffer); + EventReport = FALSE; + EpEventReport = FALSE; + ProceSsEventSize = 0; + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV:: ProcessIntLineEvents Entry\n")); + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV:: XdciCorePtr->CurrentEventBuffer 0x%08x\n", XdciCorePtr->CurrentEventBuffer)); + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV::EventCount0x%08x\n", EventCount)); + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV::CurrentEventAddr 0x%08x\n", CurrentEventAddr)); + + while ((EventCount != 0) && (EventReport == FALSE)) { + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV::event0x%08x\n", XdciCorePtr->CurrentEventBuffer->Event)); + if ((XdciCorePtr->CurrentEventBuffer->Event & DWC_XDCI_EVENT_DEV_MASK) != 0) { + // + // Device event + // + DeviceEventCheck ( + This, + (USBD_EVENT_BUF*)(UINTN)CurrentEventAddr, + &ProceSsEventSize, + Message, + &EventReport + ); + if (EventReport == TRUE) { + *EventFlag = TRUE; + } + + } else { + // + // EndPoint Event + // + EpEventCheck ( + This, + (USBD_EVENT_BUF*)(UINTN)CurrentEventAddr, + &ProceSsEventSize, + Message, + PayloadSize, + Payload, + &EpEventReport + ); + } + + if ((*Message != EfiUsbMsgNone) || (EpEventReport == TRUE)) { + EventReport = TRUE; + *EventFlag = TRUE; + } + + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: CurrentEventAddr 0x%08x :: ProceSsEventSize 0x%08x\n", (UINTN)CurrentEventAddr,ProceSsEventSize)); + + EventCount -= ProceSsEventSize; + *ProceSsEvent += ProceSsEventSize; + if ((CurrentEventAddr + ProceSsEventSize) >= \ + ((UINT32)(UINTN)(XdciCorePtr->AlignedEventBuffers) + + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER))) { + CurrentEventAddr = (UINT32)(UINTN)(XdciCorePtr->AlignedEventBuffers); + } else { + CurrentEventAddr += ProceSsEventSize; + } + DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: CurrentEventAddr Update 0x%08x :: ProceSsEventSize 0x%08x\n", CurrentEventAddr,ProceSsEventSize)); + + XdciCorePtr->CurrentEventBuffer = (DWC_XDCI_EVENT_BUFFER*)(UINTN)CurrentEventAddr; + } + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV:: ProcessIntLineEvents Exit\n\n")); + return EFI_SUCCESS; +} + + +/** + ISR inokes Event Handler. Look at which interrupt has happened and see + if there are event handler registerd and if so fire them 1 by one. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Message Indicates the event that initiated this + notification. + @param[in] PayloadSize On input, the size of the memory pointed by Payload. + On output, the amount of data returned in Payload. + @param[in] Payload A pointer to EFI_USBFN_MESSAGE_PAYLOAD instance to + return additional payload for current message. + + + + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. + @retval EFI_BUFFER_TOO_SMALL Supplied Buffer not large enough to hold + the message payload. + +**/ +EFI_STATUS +EFIAPI +EventHandler( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload + ) +{ + UINT32 EventCount; + UINT32 PeventCount; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + UINT32 MaxIntNum; + UINT32 IntIndex; + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + BOOLEAN EventFlag; + EFI_TPL OriginalTpl; + + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_ EventHandler Entry\n")); + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + if (UsbFuncIoDevPtr->StartUpController == FALSE) { + UsbFnInitDevice (This); + } + OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + *Message = EfiUsbMsgNone; + MaxIntNum = (UsbRegRead ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_GHWPARAMS1_REG) & + DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >> + DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS; + + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + EventFlag = TRUE; + + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "XdciCorePtr->MaxDevIntLines 0x%08x\n", XdciCorePtr->MaxDevIntLines)); + EventCount = UsbRegRead ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(0)); + + for (IntIndex = 0; IntIndex < XdciCorePtr->MaxDevIntLines ; IntIndex++) { + // + // Get the number of events HW has written for this + // interrupt line + // + EventCount = UsbRegRead ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(IntIndex)); + EventCount &= DWC_XDCI_EVNTCOUNT_MASK; + PeventCount = 0; + + // + // Process interrupt line Buffer only if count is non-zero + // + if (EventCount) { + // + // Process events in this Buffer + // + ProcessIntLineEvents ( + This, + EventCount, + &PeventCount, + Message, + PayloadSize, + Payload, + &EventFlag + ); + + // + // Write back the Processed number of events so HW decrements it from current + // event count + // + UsbRegWrite ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(IntIndex), PeventCount); + + // + // for debug + // + if (*Message != EfiUsbMsgNone) { + break; + } + + if (EventFlag == TRUE) { + break; + } + } + } + + gBS->RestoreTPL (OriginalTpl); + // + //EVENT_EXIT: + // + DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_ EventHandler Exit\n")); + return EFI_SUCCESS; +} + + + +/** + Copies relevant endpoint data from standard USB endpoint descriptors + to the usbEpInfo structure used by the XDCI + + @param pEpDest destination structure + @param pEpSrc source structure + + @return VOID + +**/ +VOID +UsbFnSetEpInfo ( + 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; + DEBUG ((DEBUG_INFO, "EpDest->EpNum 0x%02x\n", EpDest->EpNum)); + DEBUG ((DEBUG_INFO, "EpDest->EpDir 0x%02x\n", EpDest->EpDir)); + 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; +} + + +EFI_STATUS +SetFnIoReqInfo( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer, + IN OUT USB_XFER_REQUEST *XfIoreq + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + EFI_STATUS Status; + UINTN ReqPacket; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + Status = EFI_SUCCESS; + ReqPacket = 0; + + switch (EndpointIndex) { + case 0: // Control endpoint + XfIoreq->EpInfo.EpNum = 0; + XfIoreq->EpInfo.EpDir = Direction? UsbEpDirIn : UsbEpDirOut; + break; + + + default: + if (Direction == EfiUsbEndpointDirectionDeviceTx) { + UsbFnSetEpInfo (&XfIoreq->EpInfo, &UsbFuncIoDevPtr->IndexPtrInEp); + } else { + UsbFnSetEpInfo (&XfIoreq->EpInfo, &UsbFuncIoDevPtr->IndexPtrOutEp); + // + // reference from "UsbDeviceMode.c", function UsbdEpRxData + // + + // + // Transfer length should be multiple of USB packet size. + // + ReqPacket = *BufferSize/ XfIoreq->EpInfo.MaxPktSize; + ReqPacket = ((XfIoreq->XferLen % XfIoreq->EpInfo.MaxPktSize) == 0)? ReqPacket : ReqPacket + 1; + XfIoreq->XferLen = (UINT32)ReqPacket * XfIoreq->EpInfo.MaxPktSize; + + } + break; + } + + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + XfIoreq->XferBuffer = Buffer; + XfIoreq->XferLen = (UINT32)(*BufferSize); + XfIoreq->XferDone = NULL; + + return EFI_SUCCESS; +} + + +/** + Primary function to handle transfer in either direction Based on specified + direction and on the specified endpoint. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointIndex Indicates the endpoint on which TX or RX transfer + needs to take place. + @param[in] Direction Direction of the endpoint. + @param[in] BufferSize If Direction is EfiUsbEndpointDirectionDeviceRx: + On input, the size of the Buffer in bytes. + On output, the amount of data returned in Buffer in bytes. + If Direction is EfiUsbEndpointDirectionDeviceTx: + On input, the size of the Buffer in bytes. + On output, the amount of data actually transmitted in bytes. + @param[in] Buffer If Direction is EfiUsbEndpointDirectionDeviceRx: + The Buffer to return the received data. + If Direction is EfiUsbEndpointDirectionDeviceTx: + The Buffer that contains the data to be transmitted. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_NOT_READY The physical device is busy or not ready to + process this request. + +**/ +EFI_STATUS +EFIAPI +Transfer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + USB_DEV_CORE *UsbDeviceCorePtr; + XDCI_CORE_HANDLE *XdciCorePtr; + EFI_STATUS Status; + USB_XFER_REQUEST XferReq; + UINT32 EndPoint; + + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:Transfer - Entry\n")); + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:EndpointIndex 0x%02x\n", EndpointIndex)); + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:Direction 0x%02x\n", Direction)); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore; + XdciCorePtr = UsbDeviceCorePtr->ControllerHandle; + EndPoint = UsbGetPhysicalEpNum (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut); + + Status = SetFnIoReqInfo ( + This, + EndpointIndex, + Direction, + BufferSize, + Buffer, + &XferReq + ); + + if (EFI_ERROR(Status)) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "Set SetFnIoReqInfo - Error Stop!!!\n")); + while(1); + Status = EFI_DEVICE_ERROR; + goto FUN_EXIT; + } + + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].EpNum = EndPoint; + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].Direction = Direction; + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].XferAddress = (UINTN)Buffer; + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].XferLength = (UINT32)(*BufferSize); + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].LogEpNum = EndpointIndex; + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].Complete = FALSE; + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag = FALSE; + + Status = EFI_DEVICE_ERROR; + switch (EndpointIndex) { + case 0: // Control endpoint + if (*BufferSize == 0) { + if (Direction == EfiUsbEndpointDirectionDeviceTx) { + Status = UsbDeviceEp0TxStatus(UsbDeviceCorePtr); + } else { + Status = UsbDeviceEp0RxStatus(UsbDeviceCorePtr); + } + } else if (Direction == EfiUsbEndpointDirectionDeviceTx) { + Status = UsbXdciDeviceEpTxData(UsbDeviceCorePtr, &XferReq); + } else if (Direction == EfiUsbEndpointDirectionDeviceRx) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n Set Setup Package - ??? Stop!!!\n")); + } + break; + + default: + Status = EFI_SUCCESS; + if (Direction == EfiUsbEndpointDirectionDeviceTx) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n EfiUsbEndpointDirectionDeviceTx Size = %d\n",(*BufferSize) )); + XferReq.Zlp = TRUE; + if ((((*BufferSize) % 512) == 0) && ((*BufferSize) != 0)) { + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag = TRUE; + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n Set Zlp flag\n")); + } + Status = UsbXdciDeviceEpTxData (UsbDeviceCorePtr, &XferReq); + } else { + DEBUG ((USB_FUIO_DEBUG_LOAD, "\n EfiUsbEndpointDirectionDeviceRx Size = %d\n",(*BufferSize) )); + Status = UsbXdciDeviceEpRxData (UsbDeviceCorePtr, &XferReq); + } + break; + } + + if (EFI_ERROR(Status)) { + goto FUN_EXIT; + } + + if (Status != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + } + +FUN_EXIT: + + DEBUG ((USB_FUIO_DEBUG_LOAD, "FU:Transfer - Exit %r\n", Status)); + return Status; +} + + +/** + This function supplies power to the USB controller if needed, initialize + hardware and internal data structures, and then return. + The port must not be activated by this function. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. +**/ +EFI_STATUS +EFIAPI +StartXdciController ( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + USB_DEV_CONFIG_PARAMS ConfigParams; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + if (UsbFuncIoDevPtr->StartUpController == TRUE) { + goto EXIT_START_CONTROLLER; + } + + ConfigParams.ControllerId = USB_ID_DWC_XDCI; + ConfigParams.BaseAddress = (UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr; + ConfigParams.Role = USB_ROLE_DEVICE; + ConfigParams.Speed = USB_SPEED_HIGH; + + // + //*Vid = 0x8086 + //*Pid = 0x0A65 + // + UsbFuncIoDevPtr->VendorId = USBFU_VID; + UsbFuncIoDevPtr->DeviceId = USBFU_PID; + UsbFuncIoDevPtr->StartUpController = TRUE; + + Status = UsbDeviceInit (&ConfigParams, &UsbFuncIoDevPtr->DrvCore); + if (Status != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + goto EXIT_START_CONTROLLER; + } + + UsbFuncIoDevPtr->XdciDrvIfHandle = UsbFuncIoDevPtr->DrvCore->ControllerHandle; + +EXIT_START_CONTROLLER: + + DEBUG ((USB_FUIO_DEBUG_LOAD, "StartXdciController - Exit :: %r\n", Status)); + return Status; +} + + +/** + This function disables the hardware device by resetting the run/stop bit + and power off the USB controller if needed. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. +**/ +EFI_STATUS +EFIAPI +StopXdciController ( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + EFI_STATUS DevStatus; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + DEBUG ((USB_FUIO_DEBUG_LOAD, "StopController - Entry\n")); + + if (UsbFuncIoDevPtr->StartUpController == FALSE) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "The Controller not yet start up skip deinit\n")); + return EFI_SUCCESS; + } + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DevStatus = UsbDeviceDeinit (UsbFuncIoDevPtr->DrvCore, TRUE); + + UsbFuncIoDevPtr->DrvCore = NULL; + UsbFuncIoDevPtr->XdciDrvIfHandle = NULL; + UsbFuncIoDevPtr->StartUpController = FALSE; + + if (DevStatus != EFI_SUCCESS) { + return EFI_DEVICE_ERROR; + } + + DEBUG ((USB_FUIO_DEBUG_LOAD, "StopController - Exit\n")); + return EFI_SUCCESS; +} + + +/** + This function sets the configuration policy for the specified non-control endpoint. + Refer to the description for calling restrictions + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointIndex Indicates the non-control endpoint for + which the policy needs to be set. + @param[in] Direction Direction of the endpoint. + @param[in] PolicyType Policy type the user is trying to set for + the specified non-control endpoint. + @param[in] BufferSize The size of the Buffer in bytes. + @param[in] Buffer The new value for the policy parameter that + PolicyType specifies. + + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_UNSUPPORTED Changing this policy value is not supported. + +**/ +EFI_STATUS +EFIAPI +SetEndpointPolicy ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN EFI_USBFN_POLICY_TYPE PolicyType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + EFI_STATUS Status; + UINT32 EndPoint; + UINT8 *FlagPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + FlagPtr = NULL; + + switch (PolicyType) { + case EfiUsbPolicyUndefined: + case EfiUsbPolicyMaxTransactionSize: + case EfiUsbPolicyZeroLengthTerminationSupport: + + Status = EFI_UNSUPPORTED; + break; + + default: + FlagPtr = Buffer; + Status = EFI_SUCCESS; + break; + } + + if (BufferSize < 1) { + Status = EFI_INVALID_PARAMETER; + } + + if (EFI_ERROR(Status)) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "SetEndpointPolicy - ERROR %r\n", Status)); + return Status; + } + + EndPoint = UsbGetPhysicalEpNum (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut); + + UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag = *FlagPtr; + + return Status; +} + + +/** + This function retrieves the configuration policy for the specified non-control + endpoint. There are no associated calling restrictions for this function. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] EndpointIndex Indicates the non-control endpoint for + which the policy needs to be set. + @param[in] Direction Direction of the endpoint. + @param[in] PolicyType Policy type the user is trying to set for + the specified non-control endpoint. + @param[in] BufferSize The size of the Buffer in bytes. + @param[in] Buffer The new value for the policy parameter that + PolicyType specifies. + + + @retval EFI_SUCCESS The function returned successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_DEVICE_ERROR The physical device reported an error. + @retval EFI_UNSUPPORTED Changing this policy value is not supported. + @retval EFI_BUFFER_TOO_SMALL Supplied Buffer is not large enough to + hold requested policy value. + +**/ +EFI_STATUS +EFIAPI +GetEndpointPolicy ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN EFI_USBFN_POLICY_TYPE PolicyType, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + EFI_STATUS Status; + UINT32 EndPoint; + UINT32 MaxPacketSize; + BOOLEAN SetFlag; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + MaxPacketSize = 0; + SetFlag = FALSE; + + switch (PolicyType) { + case EfiUsbPolicyUndefined: + + Status = EFI_UNSUPPORTED; + break; + + case EfiUsbPolicyMaxTransactionSize: + case EfiUsbPolicyZeroLengthTerminationSupport: + default: + if (Buffer == NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = EFI_SUCCESS; + } + break; + } + + EndPoint = UsbGetPhysicalEpNum (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut); + + if (EFI_ERROR(Status)) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointPolicy - ERROR %r\n", Status)); + return Status; + } + + if (PolicyType == EfiUsbPolicyMaxTransactionSize) { + + if (*BufferSize < sizeof(UINT32)) { + Status = EFI_INVALID_PARAMETER; + } else { + MaxPacketSize = MAX_TRANSFER_PACKET; + CopyMem (Buffer, &MaxPacketSize, sizeof(UINT32)); + } + + } else if (PolicyType == EfiUsbPolicyZeroLengthTerminationSupport) { + if (*BufferSize < sizeof(BOOLEAN)) { + Status = EFI_INVALID_PARAMETER; + } else { + SetFlag = TRUE; + CopyMem (Buffer, &SetFlag, sizeof(BOOLEAN)); + } + + } else if (PolicyType == EfiUsbPolicyZeroLengthTermination) { + if (*BufferSize < sizeof(BOOLEAN)) { + Status = EFI_INVALID_PARAMETER; + } else { + SetFlag = UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag; + CopyMem (Buffer, &SetFlag, sizeof(BOOLEAN)); + } + } else { + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} + +EFI_STATUS +UsbFnInitDevice ( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + Status = EFI_SUCCESS; + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + PlatformSpecificInit (); + + UsbFuncIoDevPtr->StartUpController = FALSE; + Status = StartXdciController (&UsbFuncIoDevPtr->UsbFunIoProtocol); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto DEV_INIT_EXIT; + } + + Status = UsbXdciDeviceConnect (UsbFuncIoDevPtr->DrvCore); + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbXdciDeviceConnect Status %x\n", Status)); + if (Status != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + goto DEV_INIT_EXIT; + } + + +DEV_INIT_EXIT: + + return Status; +} + +EFI_STATUS +StartController ( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + + +EFI_STATUS +UsbFnDeInitDevice ( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + EFI_STATUS Status; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + if (UsbFuncIoDevPtr->StartUpController == FALSE) { + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFn:StopController:The Controller not yet start up force return EFI_SUCCESS\n")); + return EFI_SUCCESS; + } + + // + // disconnect + // + Status = UsbDeviceDisconnect (UsbFuncIoDevPtr->DrvCore); + DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbDeviceDisconnect Status %x\n", Status)); + if (Status != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + goto DEV_DEINIT_EXIT; + } + + // + // StopController + // + Status = StopXdciController (&UsbFuncIoDevPtr->UsbFunIoProtocol); + UsbFuncIoDevPtr->StartUpController = FALSE; + +DEV_DEINIT_EXIT: + return Status; +} + +EFI_STATUS +StopController ( + IN EFI_USBFN_IO_PROTOCOL *This + ) +{ + return UsbFnDeInitDevice(This); +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.h new file mode 100644 index 0000000000..711be0772f --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbFuncIo.h @@ -0,0 +1,234 @@ +/** @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 __EFI_USB_FUNCTION_IO_INTERFACE_H__ +#define __EFI_USB_FUNCTION_IO_INTERFACE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UsbIoNode.h" +#include "XdciDWC.h" +#include "UsbDeviceMode.h" + +// +// Debug message setting +// +#define USB_FUIO_DEBUG_INFO EFI_D_INFO +#define USB_FUIO_DEBUG_LOAD EFI_D_LOAD +#define USB_FUIO_DEBUG_ERROR EFI_D_ERROR +#define USB_FUIO_DEBUG_EVENT_I 0 //DEBUG_INIT +#define USB_FUIO_DEBUG_EVENT_D EFI_D_ERROR +#define USB_FUIO_DEBUG_EVENT_NOTREADY_D EFI_D_ERROR +#define USB_FUIO_DEBUG_EVENT_NOTREADY_I 0 //DEBUG_INIT + +#define MAX_TRANSFER_PACKET (8 * 1024 * 1024) + +#define USBFU_VID 0x8086 +#define USBFU_PID 0x0A65 + +#pragma pack(1) +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; + +// +// Event Buffer Struct +// +typedef struct { + UINT32 Event; + UINT32 DevTstLmp1; + UINT32 DevTstLmp2; + UINT32 Reserved; +} USBD_EVENT_BUF; + +typedef struct { + UINT32 EpNum; + EFI_USBFN_ENDPOINT_DIRECTION Direction; + UINTN XferAddress; + UINT32 XferLength; + UINT8 LogEpNum; + BOOLEAN Complete; + BOOLEAN ZlpFlag; +} USBD_EP_XFER_REC; + +#pragma pack() + +EFI_STATUS +UsbFnInitDevice ( + IN EFI_USBFN_IO_PROTOCOL *This + ); + +EFI_STATUS +UsbFnDeInitDevice ( + IN EFI_USBFN_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +DetectPort ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT EFI_USBFN_PORT_TYPE *PortType + ); + +EFI_STATUS +EFIAPI +AllocateTransferBuffer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINTN Size, + OUT VOID **Buffer + ); + +EFI_STATUS +EFIAPI +FreeTransferBuffer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN VOID *Buffer + ); + +EFI_STATUS +EFIAPI +ConfigureEnableEndpoints ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN EFI_USB_DEVICE_INFO *DeviceInfo + ); + +EFI_STATUS +EFIAPI +GetEndpointMaxPacketSize ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN EFI_USB_ENDPOINT_TYPE EndpointType, + IN EFI_USB_BUS_SPEED BusSpeed, + OUT UINT16 *MaxPacketSize + ); + +EFI_STATUS +EFIAPI +GetMaxTransferSize ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT UINTN *MaxTransferSize + ); + +EFI_STATUS +EFIAPI +GetDeviceInfo ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN EFI_USBFN_DEVICE_INFO_ID Id, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer OPTIONAL + ); + +EFI_STATUS +EFIAPI +GetVendorIdProductId ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT UINT16 *Vid, + OUT UINT16 *Pid + ); + +EFI_STATUS +EFIAPI +AbortTransfer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction + ); + +EFI_STATUS +EFIAPI +GetEndpointStallState ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN OUT BOOLEAN *State + ); + +EFI_STATUS +EFIAPI +SetEndpointStallState ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN BOOLEAN State + ); + +EFI_STATUS +EFIAPI +EventHandler ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT EFI_USBFN_MESSAGE *Message, + IN OUT UINTN *PayloadSize, + OUT EFI_USBFN_MESSAGE_PAYLOAD *Payload + ); + +EFI_STATUS +EFIAPI +Transfer ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +StartController ( + IN EFI_USBFN_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +StopController ( + IN EFI_USBFN_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +SetEndpointPolicy ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN EFI_USBFN_POLICY_TYPE PolicyType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +EFI_STATUS +EFIAPI +GetEndpointPolicy ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + IN EFI_USBFN_ENDPOINT_DIRECTION Direction, + IN EFI_USBFN_POLICY_TYPE PolicyType, + IN OUT UINTN *BufferSize, + IN OUT VOID *Buffer + ); + +VOID +UsbFnSetEpInfo ( + IN USB_EP_INFO *EpDest, + IN USB_DEVICE_ENDPOINT_INFO *EpSrc + ); + +extern EFI_USBFN_IO_PROTOCOL mUsbFunIoProtocol; +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.c new file mode 100644 index 0000000000..c51ced580f --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.c @@ -0,0 +1,177 @@ +/** @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 "UsbDeviceDxe.h" + + +/** + The SearchNode function search a memory address for record the driver allocate + memory region and the node to the head link list. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Buffer The driver alocate memory address. + @param[out] Node The match node record of the driver aloocate + memory region. + @param[out] PNode The pervious match node record of the driver + aloocate memory region. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_FOUND The memory Buffer didn't find. +**/ +EFI_STATUS +SearchNode ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN VOID *Buffer, + OUT USB_MEM_NODE **Node, + OUT USB_MEM_NODE **PNode + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + USB_MEM_NODE *NodeL; + USB_MEM_NODE *PNodeL; + EFI_STATUS Status; + + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "SearchNode - Entry\n")); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This); + NodeL = UsbFuncIoDevPtr->FirstNodePtr; + PNodeL = NULL; + Status = EFI_NOT_FOUND; + + while (Node != NULL) { + if (NodeL->AllocatePtr == Buffer) { + break; + } + + PNodeL = NodeL; + NodeL = NodeL->NextPtr; + } + + if (NodeL != NULL && Node != NULL) { + *Node = NodeL; + *PNode = PNodeL; + Status = EFI_SUCCESS; + } + + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "SearchNode - Exit %r\n", Status)); + return Status; +} + +/** + The InsertNewNodeToHead function remove a memory for record the driver allocate + memory region and the node to the head link list. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Buffer The driver alocate memory address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_FOUND The memory Buffer didn't find. +**/ +EFI_STATUS +RemoveNode ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN VOID *Buffer + ) +{ + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + USB_MEM_NODE *Node; + USB_MEM_NODE *PNode; + EFI_STATUS Status; + + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "RemoveNode - Entry\n")); + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This); + + Status = SearchNode (This, Buffer, &Node, &PNode); + + if (EFI_ERROR(Status) || PNode == NULL) { + DEBUG ((USB_DEBUG_MEM_NODE_ERROR, "RemoveNode - Node Not Found\n")); + return EFI_NOT_FOUND; + } + + if (Node != UsbFuncIoDevPtr->FirstNodePtr) { + PNode->NextPtr = Node->NextPtr; + } else { + UsbFuncIoDevPtr->FirstNodePtr = Node->NextPtr; + } + + FreePool (Node->AllocatePtr); + FreePool (Node); + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "RemoveNode - Exit\n")); + return EFI_SUCCESS; +} + +/** + The InsertNewNodeToHead function allocates a memory for record the driver allocate + memory region and insert the node to the head link list. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[out] USB_MEM_NODE return the new node address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_OUT_OF_RESOURCES The requested transfer Buffer could not be allocated. + +**/ +EFI_STATUS +InsertNewNodeToHead ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT USB_MEM_NODE **Node + ) +{ + USB_MEM_NODE *NewNodePtr; + USB_MEM_NODE *CurrentNodePtr; + USB_XDCI_DEV_CONTEXT *UsbFuncIoDevPtr; + EFI_STATUS Status; + + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "CreateNewNode - Entry\n")); + + if (This == NULL) { + Status = EFI_INVALID_PARAMETER; + goto ErrorExit; + } + + UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This); + + // + // Create the new node + // + NewNodePtr = AllocateZeroPool (sizeof(USB_MEM_NODE)); + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "NewNodePtr - Addr = 0x%08x\n",(UINTN)NewNodePtr)); + + if (NewNodePtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + // + // insert the new node + // + CurrentNodePtr = UsbFuncIoDevPtr->FirstNodePtr; + UsbFuncIoDevPtr->FirstNodePtr = NewNodePtr; + + if (CurrentNodePtr != NULL) { + NewNodePtr->NextPtr = CurrentNodePtr; + } + + *Node = NewNodePtr; + + DEBUG ((USB_DEBUG_MEM_NODE_INFO, "CreateNewNode - Exit\n")); + return EFI_SUCCESS; + +ErrorExit: + + DEBUG ((USB_DEBUG_MEM_NODE_ERROR, "CreateNewNode - error %r\n",Status)); + return Status; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.h new file mode 100644 index 0000000000..0ff569bdd6 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/UsbIoNode.h @@ -0,0 +1,90 @@ +/** @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 __EFI_USB_FUIO_MEM_NODE__ +#define __EFI_USB_FUIO_MEM_NODE__ + +#include +#include +#include +#include + +#define USB_DEBUG_MEM_NODE_INFO EFI_D_INIT +#define USB_DEBUG_MEM_NODE_ERROR EFI_D_ERROR + + +typedef struct { + UINTN Size; + VOID *AllocatePtr; + VOID *NextPtr; +} USB_MEM_NODE; + +/** + The SearchNode function search a memory address for record the driver allocate + memory region and the node to the head link list. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Buffer The driver alocate memory address. + @param[out] Node The match node record of the driver aloocate + memory region. + @param[out] PNode The pervious match node record of the driver + aloocate memory region. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_FOUND The memory Buffer didn't find. +**/ +EFI_STATUS +SearchNode ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN VOID *Buffer, + OUT USB_MEM_NODE **Node, + OUT USB_MEM_NODE **PNode + ); + +/** + The InsertNewNodeToHead function remove a memory for record the driver allocate + memory region and the node to the head link list. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[in] Buffer The driver alocate memory address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_FOUND The memory Buffer didn't find. +**/ +EFI_STATUS +RemoveNode ( + IN EFI_USBFN_IO_PROTOCOL *This, + IN VOID *Buffer + ); + +/** + The InsertNewNodeToHead function allocates a memory for record the driver allocate + memory region and insert the node to the head link list. + + @param[in] This A pointer to the EFI_USBFN_IO_PROTOCOL instance. + @param[out] USB_MEM_NODE return the new node address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_OUT_OF_RESOURCES The requested transfer Buffer could not be allocated. + +**/ +EFI_STATUS +InsertNewNodeToHead ( + IN EFI_USBFN_IO_PROTOCOL *This, + OUT USB_MEM_NODE **Node + ); + + #endif + + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciCommon.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciCommon.h new file mode 100644 index 0000000000..468e8a83a5 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciCommon.h @@ -0,0 +1,156 @@ +/** @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_COMMON_H_ +#define _XDCI_COMMON_H_ + +#define USB_SETUP_DATA_PHASE_DIRECTION_MASK (0x80) + +// +// EP direction +// +typedef enum { + UsbEpDirOut = 0, + UsbEpDirIn = 1 +} USB_EP_DIR; + +// +// USB Speeds +// +typedef enum { + USB_SPEED_HIGH = 0, + USB_SPEED_FULL, + USB_SPEED_LOW, + USB_SPEED_SUPER = 4 +} USB_SPEED; + +typedef enum { + USB_ID_DWC_XDCI = 0, + USB_CORE_ID_MAX +} USB_CONTROLLER_ID; + +typedef enum { + USB_ROLE_HOST = 1, + USB_ROLE_DEVICE, + USB_ROLE_OTG +} USB_ROLE; + +typedef enum { + USB_XFER_QUEUED = 0, + USB_XFER_SUCCESSFUL, + USB_XFER_STALL +} USB_XFER_STATUS; + +typedef enum { + USB_DEVICE_DISCONNECT_EVENT = 0, + USB_DEVICE_RESET_EVENT, + USB_DEVICE_CONNECTION_DONE, + USB_DEVICE_STATE_CHANGE_EVENT, + USB_DEVICE_WAKEUP_EVENT, + USB_DEVICE_HIBERNATION_REQ_EVENT, + USB_DEVICE_SOF_EVENT = 7, + USB_DEVICE_ERRATIC_ERR_EVENT = 9, + USB_DEVICE_CMD_CMPLT_EVENT, + USB_DEVICE_BUFF_OVERFLOW_EVENT, + USB_DEVICE_TEST_LMP_RX_EVENT, + USB_DEVICE_SETUP_PKT_RECEIVED, + USB_DEVICE_XFER_NRDY, + USB_DEVICE_XFER_DONE +} USB_DEVICE_EVENT_ID; + +typedef enum { + U0 = 0, + U1, + U2, + U3, + SS_DIS, + RX_DET, + SS_INACT, + POLL, + RECOV, + HRESET, + CMPLY, + LPBK, + RESUME_RESET = 15 +} USB_DEVICE_SS_LINK_STATE; + +typedef enum { + CTRL_SETUP_PHASE, + CTRL_DATA_PHASE, + CTRL_STATUS_PHASE +} USB_CONTROL_XFER_PHASE; + +typedef enum { + USB_EP_STATE_DISABLED = 0, + USB_EP_STATE_ENABLED, + USB_EP_STATE_STALLED, + USB_EP_STATE_SETUP, + USB_EP_STATE_IN_DATA, + USB_EP_STATE_OUT_DATA, + USB_EP_STATE_DATA, + USB_EP_STATE_STATUS +} USB_EP_STATE; + +typedef struct { + VOID *ParentHandle; + UINT32 Hird; + UINT32 EpNum; + USB_SPEED Speed; + USB_EP_STATE EpState; + USB_EP_DIR EpDir; + UINT8 EpType; + USB_DEVICE_SS_LINK_STATE LinkState; + UINT8 *Buffer; + BOOLEAN SsEvent; +} USB_DEVICE_CALLBACK_PARAM; + +// +// USB endpoint +// +typedef struct { + UINT32 EpNum; + USB_EP_DIR EpDir; + UINT8 EpType; + UINT32 MaxPktSize; + UINT32 MaxStreams; + UINT32 BurstSize; + UINT32 Interval; + UINT32 Mult; +} USB_EP_INFO; + +// +// USB transfer request +// +typedef struct _USB_XFER_REQUEST USB_XFER_REQUEST; + +typedef +VOID +(EFIAPI *USB_XFER_DONE_CALLBACK) ( + IN VOID *XdciHndl, + IN USB_XFER_REQUEST *XferReq + ); + +struct _USB_XFER_REQUEST { + VOID *XferBuffer; // Buffer address. bus-width aligned + UINT32 XferLen; // Requested transfer length + UINT32 ActualXferLen; // Actual transfer length at completion callback stage + UINT32 StreamId; // Stream ID. Only relevant for bulk streaming + UINT32 FrameNum; // Only relevant for periodic transfer + USB_XFER_STATUS XferStatus; // Transfer status + USB_EP_INFO EpInfo; // EP info + USB_XFER_DONE_CALLBACK XferDone; // Transfer completion callback + BOOLEAN Zlp; // Do zero-length transfer +}; + +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.c new file mode 100644 index 0000000000..47c5b80bd4 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.c @@ -0,0 +1,4033 @@ +/** @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 "UsbDeviceMode.h" +#include "XdciInterface.h" +#include "XdciDWC.h" + +#pragma optimize ("", off) + +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 + gBS->Stall (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 + gBS->Stall (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 ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN UINT32 EpNum + ) +{ + UINT32 BaseAddr; + UINT32 MaxDelayIter = DWC_XDCI_MAX_DELAY_ITERATIONS; + UINT32 fifoNum; + + 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. + // + 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 + gBS->Stall (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 ( + IN XDCI_CORE_HANDLE *CoreHandle, + IN 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 (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; + + 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 { + gBS->Stall (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")); + + // + // 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) { + 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)); + + + // + // 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 ( + IN VOID *CoreHandle, + IN 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; + + if (CoreHandle == NULL) { + DEBUG ((DEBUG_INFO, "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 { + gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); + } + } while (--MaxDelayIter); + + if (!MaxDelayIter) { + DEBUG ((DEBUG_INFO, "Failed to run the device controller\n")); + 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 { + gBS->Stall (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 ( + IN VOID *CoreHandle, + IN 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 + gBS->Stall (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 + gBS->Stall (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 { + gBS->Stall (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; +} +#pragma optimize ("", on) + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.h new file mode 100644 index 0000000000..3470cfd15e --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDWC.h @@ -0,0 +1,741 @@ +/** @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" + +#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]; // EPs + 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 + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.c new file mode 100644 index 0000000000..2dcd44881b --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.c @@ -0,0 +1,695 @@ +/** @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 "XdciCommon.h" +#include "XdciDevice.h" +#include "XdciInterface.h" +#include "UsbDeviceMode.h" + +/** + This function is used to initialize the device controller + @configParams: Parameters from app to configure the core + @DevCoreHandle: Return parameter for upper layers to use + for all HW-independent APIs + +**/ +EFI_STATUS +UsbDeviceInit ( + IN USB_DEV_CONFIG_PARAMS *ConfigParams, + IN OUT VOID **DevCoreHandle + ) +{ + USB_DEV_CORE *DevCorePtr; + EFI_STATUS Status = EFI_INVALID_PARAMETER; + + DEBUG ((DEBUG_INFO, "Call UsbDeviceInit start\n")); + + // + // Allocate device handle + // + DevCorePtr = AllocateZeroPool (sizeof (USB_DEV_CORE)); + DEBUG ((DEBUG_INFO, "device handle = 0x%x\n", DevCorePtr)); + + if (DevCorePtr == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceInit. ERROR: Failed to allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + DEBUG ((DEBUG_INFO, "call UsbDeviceGetCoreDriver, ID=%x, \n", ConfigParams->ControllerId)); + + // + // Get the driver for this USB device core + // + DevCorePtr->CoreDriver = UsbDeviceGetCoreDriver(ConfigParams->ControllerId); + if (DevCorePtr->CoreDriver != NULL) { + DEBUG ((DEBUG_INFO, "call DevCoreInit\n")); + Status = DevCorePtr->CoreDriver->DevCoreInit( + ConfigParams, + (VOID*)DevCorePtr, + &DevCorePtr->ControllerHandle); + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceInit. ERROR: Driver not found\n")); + return EFI_INVALID_PARAMETER; + } + + *DevCoreHandle = (VOID *)DevCorePtr; + return Status; +} + +/** + This function is used to de-initialize the device controller + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @flags: Flags indicating what type of de-initialization is required + +**/ +EFI_STATUS +UsbDeviceDeinit ( + IN VOID *DevCoreHandle, + IN UINT32 Flags + ) +{ + USB_DEV_CORE *Core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (Core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceDeinit: ERROR: INVALID HANDLE\n")); + } else { + if (Core->CoreDriver != NULL) { + Status = Core->CoreDriver->DevCoreDeinit( + Core->ControllerHandle, + Flags + ); + FreePool(DevCoreHandle); + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceDeinit: Driver not found\n")); + Status = EFI_INVALID_PARAMETER; + } + } + + return Status; +} + +/** + This function is used to register callback function for + specified event + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @event: Event for which callback is to be registered + @callbackFn: Callback function to be called by the + controller driver for above event after critical processing + +**/ +EFI_STATUS +UsbDeviceRegisterCallback ( + IN VOID *DevCoreHandle, + IN USB_DEVICE_EVENT_ID EventId, + IN USB_DEVICE_CALLBACK_FUNC CallbackFunc + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + + DEBUG ((DEBUG_INFO, "UsbDeviceRegisterCallback start\n")); + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceRegisterCallback: ERROR: INVALID HANDLE\n")); + } else { + if (core->CoreDriver != NULL) { + DEBUG ((DEBUG_INFO, "Call DevCoreRegisterCallback\n")); + Status = core->CoreDriver->DevCoreRegisterCallback ( + core->ControllerHandle, + EventId, + CallbackFunc + ); + } + } + + return Status; +} + +/** + This function is used to register callback function for + specified event + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @eventId: Event for which callback is to be unregistered + +**/ +EFI_STATUS +UsbDeviceUnregisterCallback ( + IN VOID *DevCoreHandle, + IN USB_DEVICE_EVENT_ID EventId + ) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceUnregisterCallback: ERROR: INVALID HANDLE\n")); + } else { + if (core->CoreDriver != NULL) { + Status = core->CoreDriver->DevCoreUnregisterCallback( + core->ControllerHandle, + EventId + ); + } + } + + return Status; +} + +/** + This function is used to service interrupt events on device + controller. Use this API in your OS/stack-specific ISR framework + In polled mode scenario, invoke this API in a loop to service the + events + @DevCoreHandle: Handle to HW-independent APIs for device + controller + +**/ +EFI_STATUS +UsbDeviceIsrRoutine ( + IN VOID *DevCoreHandle + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceIsrRoutine: ERROR: INVALID HANDLE\n")); + } else { + if (core->CoreDriver != NULL) { + Status = core->CoreDriver->DevCoreIsrRoutine (core->ControllerHandle); + } + } + + return Status; +} + + +/** + This function is used to service interrupt events on device + controller. Use this API in your OS/stack-specific ISR framework + In polled mode scenario, invoke this API in a loop to service the + events + @DevCoreHandle: Handle to HW-independent APIs for device + controller + +**/ +EFI_STATUS +UsbDeviceIsrRoutineTimerBased ( + IN VOID *DevCoreHandle + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceIsrRoutine: ERROR: INVALID HANDLE\n")); + } else { + if (core->CoreDriver != NULL) { + Status = core->CoreDriver->DevCoreIsrRoutineTimerBased (core->ControllerHandle); + } + } + + return Status; +} + + +/** + This function is used to enable device controller to connect + to USB host + @DevCoreHandle: Handle to HW-independent APIs for device + controller + +**/ +EFI_STATUS +UsbXdciDeviceConnect ( + IN VOID *DevCoreHandle + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbXdciDeviceConnect: ERROR: INVALID HANDLE\n")); + } else { + DEBUG ((DEBUG_INFO, "UsbXdciDeviceConnect\n")); + Status = core->CoreDriver->DevCoreConnect (core->ControllerHandle); + } + + return Status; +} + +/** + This function is used to disconnect device controller + from USB host + @DevCoreHandle: Handle to HW-independent APIs for device + controller + +**/ +EFI_STATUS +UsbDeviceDisconnect ( + IN VOID *DevCoreHandle + ) +{ + USB_DEV_CORE *core =(USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceDisconnect: ERROR: INVALID HANDLE\n")); + } else { + DEBUG ((DEBUG_INFO, "UsbDeviceDisconnect\n")); + Status = core->CoreDriver->DevCoreDisconnect(core->ControllerHandle); + } + + return Status; +} + +/** + This function is used to obtain USB bus Speed after bus reset complete + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @Speed: negotiated Speed + +**/ +EFI_STATUS +UsbDeviceGetSpeed ( + IN VOID *DevCoreHandle, + IN USB_SPEED *Speed + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceGetSpeed: ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreGetSpeed(core->ControllerHandle, Speed); + } + + return Status; +} + +/** + This function is used to set USB device address + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @address: USB device address to set + +**/ +EFI_STATUS +UsbDeviceSetAddress ( + IN VOID *DevCoreHandle, + IN UINT32 Address + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + DEBUG ((DEBUG_INFO, "UsbDeviceSetAddress: enter......\n")); + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceSetAddress: ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreSetAddress(core->ControllerHandle, Address); + } + DEBUG ((DEBUG_INFO, "UsbDeviceSetAddress: exit......\n")); + + return Status; +} + +/** + This function is used to do device controller-specific processing + of set configuration device framework request + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @ConfigNum: configuration number selected by USB host + +**/ +EFI_STATUS +UsbDeviceSetConfiguration ( + IN VOID *DevCoreHandle, + IN UINT32 ConfigNum + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceSetConfiguration: ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreSetConfig (core->ControllerHandle, ConfigNum); + } + + return Status; +} + +/** + This function is used to set desired link state in device controller + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @state: Desired link state + +**/ +EFI_STATUS +UsbDeviceSetLinkState ( + IN VOID *DevCoreHandle, + IN USB_DEVICE_SS_LINK_STATE State + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceSetLinkState: ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreSetLinkState (core->ControllerHandle, State); + } + + return Status; +} + +/** + This function is used to initialize non-EP0 endpoints + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint information for EP to be initialized + +**/ +EFI_STATUS +UsbDeviceInitEp ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceInitEp: ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreInitEp (core->ControllerHandle, EpInfo); + } + + return Status; +} + +/** + This function is used to enable an endpoint + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint information for EP to be enabled + +**/ +EFI_STATUS +UsbDeviceEpEnable ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEpEnable: ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpEnable (core->ControllerHandle, EpInfo); + } + + return Status; +} + +/** + This function is used to disable an endpoint + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint information for EP to be disabled + +**/ +EFI_STATUS +UsbDeviceEpDisable ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEpDisable ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpDisable (core->ControllerHandle, EpInfo); + } + + return Status; +} + +/** + This function is used to STALL an endpoint + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint information for EP to be stalled + +**/ +EFI_STATUS +UsbDeviceEpStall ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEpStall ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpStall (core->ControllerHandle, EpInfo); + } + + return Status; +} + +/** + This function is used to clear STALL on an endpoint + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint information for which STALL needs to be cleared + +**/ +EFI_STATUS +UsbDeviceEpClearStall ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEpClearStall ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpClearStall (core->ControllerHandle, EpInfo); + } + + return Status; +} + +/** + This function is used to set EP not ready state + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint information for EP that needs to be + set in not ready state + +**/ +EFI_STATUS +UsbDeviceEpSetNrdy ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEpSetNrdy ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpSetNrdy (core->ControllerHandle, EpInfo); + } + + return Status; +} + +/** + This function is used to queue request to receive SETUP packet + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @Buffer: Buffer (bus-width aligned) where SETUP packet + needs to be received + +**/ +EFI_STATUS +UsbDeviceEp0RxSetup ( + IN VOID *DevCoreHandle, + IN UINT8 *Buffer + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEp0RxSetup ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEp0RxSetupPkt (core->ControllerHandle, Buffer); + } + + return Status; +} + +/** + This function is used to queue request to receive status phase + for control transfer on EP0 + @DevCoreHandle: Handle to HW-independent APIs for device + controller + +**/ +EFI_STATUS +UsbDeviceEp0RxStatus ( + IN VOID *DevCoreHandle + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEp0RxStatus ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEp0RxStatusPkt (core->ControllerHandle); + } + return Status; +} + +/** + This function is used to queue request to send status phase for + control transfer on EP0 + @DevCoreHandle: Handle to HW-independent APIs for device + controller + +**/ +EFI_STATUS +UsbDeviceEp0TxStatus ( + IN VOID *DevCoreHandle + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEp0TxStatus ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEp0TxStatusPkt (core->ControllerHandle); + } + + return Status; +} + +/** + This function is used to queue a single request to transmit data on + an endpoint. If more than one request need to be queued before + previous requests complete then a request queue needs to be + implemented in upper layers. This API should be not be invoked until + current request completes. + Callback for transfer completion is invoked when requested transfer length + is reached or if a short packet is received + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @XferReq: Address to transfer request describing this transfer + +**/ +EFI_STATUS +UsbXdciDeviceEpTxData ( + IN VOID *DevCoreHandle, + IN USB_XFER_REQUEST *XferReq + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbXdciDeviceEpTxData ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpTxData (core->ControllerHandle, XferReq); + } + + return Status; +} + +/** + This function is used to queue a single request to receive data on + an endpoint. If more than one request need to be queued before + previous requests complete then a request queue needs to be implemented + in upper layers. This API should be not be invoked until current request + completes. + Callback for transfer completion is invoked when requested transfer length + is reached or if a short packet is received + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @XferReq: Address to transfer request describing this transfer + +**/ +EFI_STATUS +UsbXdciDeviceEpRxData ( + IN VOID *DevCoreHandle, + IN USB_XFER_REQUEST *XferReq + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbXdciDeviceEpRxData ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpRxData (core->ControllerHandle, XferReq); + } + + return Status; +} + +/** + This function is used to cancel a transfer request that was + previously queued on an endpoint + @DevCoreHandle: Handle to HW-independent APIs for device + controller + @EpInfo: Endpoint info where transfer needs to be cancelled + +**/ +EFI_STATUS +UsbDeviceEpCancelTransfer ( + IN VOID *DevCoreHandle, + IN USB_EP_INFO *EpInfo + ) +{ + USB_DEV_CORE *core = (USB_DEV_CORE *)DevCoreHandle; + EFI_STATUS Status = EFI_DEVICE_ERROR; + + if (core == NULL) { + DEBUG ((DEBUG_INFO, "UsbDeviceEpCancelTransfer ERROR: INVALID HANDLE\n")); + } else { + Status = core->CoreDriver->DevCoreEpCancelTransfer (core->ControllerHandle, EpInfo); + } + + return Status; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.h new file mode 100644 index 0000000000..aee6bdef70 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciDevice.h @@ -0,0 +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 + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciInterface.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciInterface.h new file mode 100644 index 0000000000..90264e84f5 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciInterface.h @@ -0,0 +1,241 @@ +/** @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_DCD_IF_H_ +#define _USB_DCD_IF_H_ + +/* Core driver for device controller + * @DevCoreInit: Intializes device controller + * @DevCoreDeinit: De-initializes device controller + * @DevCoreRegisterCallback: Registers callback function for + * an event to be called by the controller driver + * @DevCoreUnregisterCallback: Unregisters callback function + * for an event + * @DevCoreIsrRoutine: core interrupt service routine for + * device controller to be used by OS/stack-i/f layer + * @DevCoreConnect: Enable device controller to connect to USB host + * @DevCoreDisconnect: Soft disconnect device controller from + * USB host + * @DevCoreGetSpeed: Get USB bus Speed on which device controller + * is attached + * @DevCoreSetAddress: Set USB device address in device controller + * @DevCoreSetConfig: Set configuration number for device controller + * @DevCoreSetLinkState: Set link state for device controller + * @DevCoreInitEp: Initialize non-EP0 endpoint + * @DevCoreEpEnable: Enable endpoint + * @DevCoreEpDisable: Disable endpoint + * @DevCoreEpStall: Stall/Halt endpoint + * @DevCoreEpClearStall: Clear Stall/Halt on endpoint + * @DevCoreEpSetNrdy: Set endpoint to not ready state + * @DevCoreEp0RxSetupPkt: Receive SETUP packet on EP0 + * @DevCoreEp0RxStatusPkt: Receive status packet on EP0 + * @DevCoreEp0TxStatusPkt: Transmit status packet from EP0 + * @DevCoreEpTxData: Transmit data from EP + * @DevCoreEpRxData: Received data on EP + * @DevCoreEpCancelTransfer: Cancel transfer on EP + */ + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_INIT) ( + IN USB_DEV_CONFIG_PARAMS *ConfigParams, + IN VOID *ParentHandle, + IN VOID **CoreHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_DEINIT) ( + IN VOID *CoreHandle, + IN UINT32 Flags + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_REG_CALLBACK) ( + IN VOID *CoreHandle, + IN USB_DEVICE_EVENT_ID Event, + IN EFI_STATUS (*callbackFn)(IN USB_DEVICE_CALLBACK_PARAM *CbEventParams) + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_UNREG_CALLBACK) ( + IN VOID *CoreHandle, + IN USB_DEVICE_EVENT_ID Event + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_ISR_ROUTINE) ( + IN VOID *CoreHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_CONNECT) ( + IN VOID *CoreHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_DISCONNECT) ( + IN VOID *CoreHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_GET_SPEED) ( + IN VOID *CoreHandle, + IN USB_SPEED *Speed + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_SET_ADDRESS) ( + IN VOID *CoreHandle, + IN UINT32 Address + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_SET_CONFIG) ( + IN VOID *CoreHandle, + IN UINT32 ConfigNum + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_SET_LINK_STATE) ( + IN VOID *CoreHandle, + IN USB_DEVICE_SS_LINK_STATE State + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_INIT_EP) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_ENABLE) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_DISABLE) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_STALL) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_CLEAR_STALL) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_SET_NRDY) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP0_RX_SETUP_PKT) ( + IN VOID *CoreHandle, + IN UINT8 *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP0_RX_STATUS_PKT) ( + IN VOID *CoreHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP0_TX_STATUS_PKT) ( + IN VOID *CoreHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_TX_DATA) ( + IN VOID *CoreHandle, + IN USB_XFER_REQUEST *XferHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_RX_DATA) ( + IN VOID *CoreHandle, + IN USB_XFER_REQUEST *XferHandle + ); + +typedef +EFI_STATUS +(EFIAPI *DEV_CORE_EP_CANCEL_TRANSFER) ( + IN VOID *CoreHandle, + IN USB_EP_INFO *EpInfo + ); + +struct UsbDeviceCoreDriver { + DEV_CORE_INIT DevCoreInit; + DEV_CORE_DEINIT DevCoreDeinit; + DEV_CORE_REG_CALLBACK DevCoreRegisterCallback; + DEV_CORE_UNREG_CALLBACK DevCoreUnregisterCallback; + DEV_CORE_ISR_ROUTINE DevCoreIsrRoutine; + DEV_CORE_ISR_ROUTINE DevCoreIsrRoutineTimerBased; + DEV_CORE_CONNECT DevCoreConnect; + DEV_CORE_DISCONNECT DevCoreDisconnect; + DEV_CORE_GET_SPEED DevCoreGetSpeed; + DEV_CORE_SET_ADDRESS DevCoreSetAddress; + DEV_CORE_SET_CONFIG DevCoreSetConfig; + DEV_CORE_SET_LINK_STATE DevCoreSetLinkState; + DEV_CORE_INIT_EP DevCoreInitEp; + DEV_CORE_EP_ENABLE DevCoreEpEnable; + DEV_CORE_EP_DISABLE DevCoreEpDisable; + DEV_CORE_EP_STALL DevCoreEpStall; + DEV_CORE_EP_CLEAR_STALL DevCoreEpClearStall; + DEV_CORE_EP_SET_NRDY DevCoreEpSetNrdy; + DEV_CORE_EP0_RX_SETUP_PKT DevCoreEp0RxSetupPkt; + DEV_CORE_EP0_RX_STATUS_PKT DevCoreEp0RxStatusPkt; + DEV_CORE_EP0_TX_STATUS_PKT DevCoreEp0TxStatusPkt; + DEV_CORE_EP_TX_DATA DevCoreEpTxData; + DEV_CORE_EP_RX_DATA DevCoreEpRxData; + DEV_CORE_EP_CANCEL_TRANSFER DevCoreEpCancelTransfer; +}; + +// +// This API is used to obtain the driver handle for HW-independent API +// @id: The ID of the core for which this driver is requested +// +const struct UsbDeviceCoreDriver *UsbDeviceGetCoreDriver( + USB_CONTROLLER_ID id); + +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciTable.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciTable.c new file mode 100644 index 0000000000..31990ae921 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciTable.c @@ -0,0 +1,55 @@ +/** @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 "XdciCommon.h" +#include "XdciDevice.h" +#include "XdciInterface.h" +#include "XdciDWC.h" +#include "UsbDeviceMode.h" + +static const struct UsbDeviceCoreDriver CoreDriverTbl[USB_CORE_ID_MAX] = { + DwcXdciCoreInit, + DwcXdciCoreDeinit, + DwcXdciCoreRegisterCallback, + DwcXdciCoreUnregisterCallback, + DwcXdciCoreIsrRoutine, + DwcXdciCoreIsrRoutineTimerBased, + DwcXdciCoreConnect, + DwcXdciCoreDisconnect, + DwcXdciCoreGetSpeed, + DwcXdciCoreSetAddress, + DwcXdciCoreSetConfig, + DwcXdciSetLinkState, + DwcXdciInitEp, + DwcXdciEpEnable, + DwcXdciEpDisable, + DwcXdciEpStall, + DwcXdciEpClearStall, + DwcXdciEpSetNrdy, + DwcXdciEp0ReceiveSetupPkt, + DwcXdciEp0ReceiveStatusPkt, + DwcXdciEp0SendStatusPkt, + DwcXdciEpTxData, + DwcXdciEpRxData, + DwcXdciEpCancelTransfer +}; + +const struct UsbDeviceCoreDriver *UsbDeviceGetCoreDriver(USB_CONTROLLER_ID id) +{ + if (id >= USB_CORE_ID_MAX) + return NULL; + + return &CoreDriverTbl[id]; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.c b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.c new file mode 100644 index 0000000000..2a756b9d16 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.c @@ -0,0 +1,148 @@ +/** @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 "XdciUtility.h" + +VOID +PrintDeviceDescriptor ( + IN USB_DEVICE_DESCRIPTOR *DevDesc + ) +{ + DEBUG ((DEBUG_INFO, "--- Device Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", DevDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", DevDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "BcdUSB : 0x%x\n", DevDesc->BcdUSB)); + DEBUG ((DEBUG_INFO, "DeviceClass : 0x%x\n", DevDesc->DeviceClass)); + DEBUG ((DEBUG_INFO, "DeviceSubClass : 0x%x\n", DevDesc->DeviceSubClass)); + DEBUG ((DEBUG_INFO, "DeviceProtocol : 0x%x\n", DevDesc->DeviceProtocol)); + DEBUG ((DEBUG_INFO, "MaxPacketSize0 : 0x%x\n", DevDesc->MaxPacketSize0)); + DEBUG ((DEBUG_INFO, "IdVendor : 0x%x\n", DevDesc->IdVendor)); + DEBUG ((DEBUG_INFO, "IdProduct : 0x%x\n", DevDesc->IdProduct)); + DEBUG ((DEBUG_INFO, "BcdDevice : 0x%x\n", DevDesc->BcdDevice)); + DEBUG ((DEBUG_INFO, "StrManufacturer : 0x%x\n", DevDesc->StrManufacturer)); + DEBUG ((DEBUG_INFO, "StrProduct : 0x%x\n", DevDesc->StrProduct)); + DEBUG ((DEBUG_INFO, "StrSerialNumber : 0x%x\n", DevDesc->StrSerialNumber)); + DEBUG ((DEBUG_INFO, "NumConfigurations : 0x%x\n", DevDesc->NumConfigurations)); + DEBUG ((DEBUG_INFO, "\n")); +} + +VOID +PrintConfigDescriptor ( + IN EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc + ) +{ + DEBUG ((DEBUG_INFO, "--- Configuration Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", ConfigDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", ConfigDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "TotalLength : 0x%x\n", ConfigDesc->TotalLength)); + DEBUG ((DEBUG_INFO, "NumInterfaces : 0x%x\n", ConfigDesc->NumInterfaces)); + DEBUG ((DEBUG_INFO, "ConfigurationValue : 0x%x\n", ConfigDesc->ConfigurationValue)); + DEBUG ((DEBUG_INFO, "Configuration : 0x%x\n", ConfigDesc->Configuration)); + DEBUG ((DEBUG_INFO, "Attributes : 0x%x\n", ConfigDesc->Attributes)); + DEBUG ((DEBUG_INFO, "MaxPower : 0x%x\n", ConfigDesc->MaxPower)); + DEBUG ((DEBUG_INFO, "\n")); +} + +VOID +PrintInterfaceDescriptor ( + IN EFI_USB_INTERFACE_DESCRIPTOR *IfDesc + ) +{ + DEBUG ((DEBUG_INFO, "--- Interface Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", IfDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", IfDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "InterfaceNumber : 0x%x\n", IfDesc->InterfaceNumber)); + DEBUG ((DEBUG_INFO, "AlternateSetting : 0x%x\n", IfDesc->AlternateSetting)); + DEBUG ((DEBUG_INFO, "NumEndpoints : 0x%x\n", IfDesc->NumEndpoints)); + DEBUG ((DEBUG_INFO, "InterfaceClass : 0x%x\n", IfDesc->InterfaceClass)); + DEBUG ((DEBUG_INFO, "InterfaceSubClass : 0x%x\n", IfDesc->InterfaceSubClass)); + DEBUG ((DEBUG_INFO, "InterfaceProtocol : 0x%x\n", IfDesc->InterfaceProtocol)); + DEBUG ((DEBUG_INFO, "Interface : 0x%x\n", IfDesc->Interface)); + DEBUG ((DEBUG_INFO, "\n")); +} + +VOID +PrintEpDescriptor ( + IN EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc + ) +{ + DEBUG ((DEBUG_INFO, "--- Endpoint Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", EpDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", EpDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "EndpointAddress : 0x%x\n", EpDesc->EndpointAddress)); + DEBUG ((DEBUG_INFO, "Attributes : 0x%x\n", EpDesc->Attributes)); + DEBUG ((DEBUG_INFO, "MaxPacketSize : 0x%x\n", EpDesc->MaxPacketSize)); + DEBUG ((DEBUG_INFO, "Interval : 0x%x\n", EpDesc->Interval)); + DEBUG ((DEBUG_INFO, "\n")); +} + +VOID +PrintEpCompDescriptor ( + IN EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR *EpDesc + ) +{ + DEBUG ((DEBUG_INFO, "--- Endpoint Companion Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", EpDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", EpDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "MaxBurst : 0x%x\n", EpDesc->MaxBurst)); + DEBUG ((DEBUG_INFO, "Attributes : 0x%x\n", EpDesc->Attributes)); + DEBUG ((DEBUG_INFO, "BytesPerInterval : 0x%x\n", EpDesc->BytesPerInterval)); + DEBUG ((DEBUG_INFO, "\n")); +} + +VOID +PrintStringDescriptor ( + IN USB_STRING_DESCRIPTOR *StrDesc + ) +{ + UINT16 StrLen = 0; + + if (StrDesc->Length > 2) { + StrLen = ((StrDesc->Length - 2) >> 1); + DEBUG ((DEBUG_INFO, "--- String Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", StrDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", StrDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "String : %s\n", StrDesc->LangID)); + } + DEBUG ((DEBUG_INFO, "\n")); +} + +VOID +PrintDeviceRequest ( + IN EFI_USB_DEVICE_REQUEST *DevReq + ) +{ + DEBUG ((DEBUG_INFO, "--- Device Request ---\n")); + DEBUG ((DEBUG_INFO, "RequestType : 0x%x\n", DevReq->RequestType)); + DEBUG ((DEBUG_INFO, "Request : 0x%x\n", DevReq->Request)); + DEBUG ((DEBUG_INFO, "Value : 0x%x\n", DevReq->Value)); + DEBUG ((DEBUG_INFO, "Index : 0x%x\n", DevReq->Index)); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", DevReq->Length)); + DEBUG ((DEBUG_INFO, "\n")); +} + +#ifdef SUPPORT_SUPER_SPEED +VOID +PrintBOSDescriptor ( + IN EFI_USB_BOS_DESCRIPTOR *BosDesc + ) +{ + DEBUG ((DEBUG_INFO, "--- BOS Descriptor ---\n")); + DEBUG ((DEBUG_INFO, "Length : 0x%x\n", BosDesc->Length)); + DEBUG ((DEBUG_INFO, "DescriptorType : 0x%x\n", BosDesc->DescriptorType)); + DEBUG ((DEBUG_INFO, "TotalLength : 0x%x\n", BosDesc->TotalLength)); + DEBUG ((DEBUG_INFO, "NumDeviceCaps : 0x%x\n", BosDesc->NumDeviceCaps)); + DEBUG ((DEBUG_INFO, "\n")); +} +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.h b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.h new file mode 100644 index 0000000000..c243a5b3fb --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Features/UsbDeviceDxe/XdciUtility.h @@ -0,0 +1,62 @@ +/** @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_UTILITY_H_ +#define _XDCI_UTILITY_H_ + +#include + +VOID +PrintDeviceDescriptor ( + IN USB_DEVICE_DESCRIPTOR *DevDesc + ); + +VOID +PrintConfigDescriptor ( + IN EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc + ); + +VOID +PrintInterfaceDescriptor ( + IN EFI_USB_INTERFACE_DESCRIPTOR *IfDesc + ); + +VOID +PrintEpDescriptor ( + IN EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc + ); + +VOID +PrintEpCompDescriptor ( + IN EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR *EpDesc + ); + +VOID +PrintStringDescriptor ( + IN USB_STRING_DESCRIPTOR *StrDesc + ); + +VOID +PrintDeviceRequest ( + IN EFI_USB_DEVICE_REQUEST *DevReq + ); + +#ifdef SUPPORT_SUPER_SPEED +VOID +PrintBOSDescriptor ( + IN EFI_USB_BOS_DESCRIPTOR *BosDesc + ); +#endif + +#endif + -- cgit v1.2.3