diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec
new file mode 100644
index 000000000000..038e4881a948
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec
@@ -0,0 +1,44 @@
+#/** @file
+# Framework Module Development Environment Industry Standards
+#
+# This Package provides headers and libraries that conform to EFI/PI Industry standards.
+# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro. All rights reserved.<BR>
+#
+#    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]
+  DEC_SPECIFICATION              = 0x00010019
+  PACKAGE_NAME                   = DwUsb3DxePkg
+  PACKAGE_GUID                   = 9b7aa6fe-405b-4955-af1f-5faf183aedec
+  PACKAGE_VERSION                = 0.1
+
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+#                   Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+#  BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+
+[Guids.common]
+  gDwUsb3DxeTokenSpaceGuid      = { 0x098a50d3, 0x92e2, 0x461a, { 0xb6, 0xba, 0xf8, 0x5d, 0x9d, 0x89, 0x49, 0xf5 }}
+
+[Protocols.common]
+  gDwUsbProtocolGuid            = { 0x109fa264, 0x7811, 0x4862, { 0xa9, 0x73, 0x4a, 0xb2, 0xef, 0x2e, 0xe2, 0xff }}
+
+[PcdsFixedAtBuild.common]
+  # DwUsb Driver PCDs
+  gDwUsb3DxeTokenSpaceGuid.PcdDwUsb3DxeBaseAddress|0x0|UINT32|0x00000001
diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf
new file mode 100644
index 000000000000..510b51a34de7
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.inf
@@ -0,0 +1,52 @@
+#/** @file
+#
+#  Copyright (c) 2018, Linaro Limited. 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                    = 0x00010019
+  BASE_NAME                      = DwUsb3Dxe
+  FILE_GUID                      = 0879cd34-c399-4315-9891-56024072e711
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = DwUsb3EntryPoint
+
+[Sources.common]
+  DwUsb3Dxe.c
+
+[LibraryClasses]
+  CacheMaintenanceLib
+  DebugLib
+  DmaLib
+  IoLib
+  MemoryAllocationLib
+  TimerLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UsbSerialNumberLib
+
+[Protocols]
+  gEfiDriverBindingProtocolGuid
+  gUsbDeviceProtocolGuid
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Pcd]
+  gDwUsb3DxeTokenSpaceGuid.PcdDwUsb3DxeBaseAddress
+
+[Depex]
+  TRUE
diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h
new file mode 100644
index 000000000000..92b610553169
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.h
@@ -0,0 +1,632 @@
+/** @file
+
+  Copyright (c) 2017, Linaro Limited. 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 __DW_USB3_DXE_H__
+#define __DW_USB3_DXE_H__
+
+#define DW_USB3_BASE                     FixedPcdGet32 (PcdDwUsb3DxeBaseAddress)
+
+#define GSBUCFG0                         (DW_USB3_BASE + 0xC100)
+#define GCTL                             (DW_USB3_BASE + 0xC110)
+
+#define GCTL_PWRDNSCALE_MASK             (0x1FFF << 19)
+#define GCTL_PWRDNSCALE(x)               (((x) & 0x1FFF) << 19)
+#define GCTL_U2RSTECN                    BIT16
+#define GCTL_PRTCAPDIR_MASK              (BIT13 | BIT12)
+#define GCTL_PRTCAPDIR_HOST              BIT12
+#define GCTL_PRTCAPDIR_DEVICE            BIT13
+#define GCTL_PRTCAPDIR_OTG               (BIT13 | BIT12)
+#define GCTL_U2EXIT_LFPS                 BIT2
+
+#define GUSB2PHYCFG(x)                   (DW_USB3_BASE + 0xC200 + (((x) & 0xF) << 2))
+
+#define GUSB2PHYCFG_USBTRDTIM_MASK       (0xF << 10)
+#define GUSB2PHYCFG_USBTRDTIM(x)         (((x) & 0xF) << 10)
+#define GUSB2PHYCFG_SUSPHY               BIT6
+
+#define GUSB3PIPECTL(x)                  (DW_USB3_BASE + 0xC2C0 + (((x) & 0x3) << 2))
+
+#define PIPECTL_DELAYP1TRANS             BIT18
+#define PIPECTL_SUSPEND_EN               BIT17
+#define PIPECTL_LFPS_FILTER              BIT9
+#define PIPECTL_TX_DEMPH_MASK            (0x3 << 1)
+#define PIPECTL_TX_DEMPH(x)              (((x) & 0x3) << 1)
+
+#define GTXFIFOSIZ(x)                    (DW_USB3_BASE + 0xC300 + (((x) & 0x1F) << 2))
+#define GRXFIFOSIZ(x)                    (DW_USB3_BASE + 0xC380 + (((x) & 0x1F) << 2))
+
+#define FIFOSIZ_ADDR(x)                  (((x) & 0xFFFF) << 16)
+#define FIFOSIZ_DEP(x)                   ((x) & 0xFFFF)
+
+#define GEVNTADRL(x)                     (DW_USB3_BASE + 0xC400 + (((x) & 0x1F) << 2))
+#define GEVNTADRH(x)                     (DW_USB3_BASE + 0xC404 + (((x) & 0x1F) << 2))
+#define GEVNTSIZ(x)                      (DW_USB3_BASE + 0xC408 + (((x) & 0x1F) << 2))
+
+#define GEVNTSIZ_EVNTINTMASK             BIT31
+#define GEVNTSIZ_EVNTSIZ_MASK            (0xFFFF)
+#define GEVNTSIZ_EVNTSIZ(x)              ((x) & 0xFFFF)
+
+#define GEVNTCOUNT(x)                    (DW_USB3_BASE + 0xC40C + (((x) & 0x1F) << 2))
+#define GEVNTCOUNT_EVNTCOUNT_MASK        (0xFFFF)
+#define GEVNTCOUNT_EVNTCOUNT(x)          ((x) & 0xFFFF)
+
+// Non-Endpoint specific event flag
+#define GEVNT_INTTYPE_MASK               (0x7F << 1)
+#define GEVNT_INTTYPE(x)                 (((x) & 0x7F) << 1)
+#define EVENT_I2C_INT                    4
+#define EVENT_CARKIT_INT                 3
+#define EVENT_OTG_INT                    1
+#define EVENT_DEV_INT                    0
+
+#define GEVNT_NON_EP                     BIT0
+// Endpoint specific event flag
+#define GEVNT_DEPEVT_INTTYPE_MASK        (0xF << 6)
+#define GEVNT_DEPEVT_INTTYPE(x)          (((x) & 0xF) << 6)
+#define GEVNT_DEPEVT_INTTYPE_EPCMD_CMPL  (7 << 6)
+#define GEVNT_DEPEVT_INTTYPE_STRM_EVT    (6 << 6)
+#define GEVNT_DEPEVT_INTTYPE_FIFOXRUN    (4 << 6)
+#define GEVNT_DEPEVT_INTTYPE_XFER_NRDY   (3 << 6)
+#define GEVNT_DEPEVT_INTTYPE_XFER_IN_PROG (2 << 6)
+#define GEVNT_DEPEVT_INTTYPE_XFER_CMPL   (1 << 6)
+#define GEVNT_DEPEVT_EPNUM_MASK          (0x1F << 1)
+#define GEVNT_DEPEVT_EPNUM_SHIFT         1
+#define GEVNT_DEPEVT_EPNUM(x)            (((x) & 0x1F) << 1)
+// Devices specific event flag
+#define GEVNT_DEVT_MASK                  (0xF << 8)
+#define GEVNT_DEVT_SHIFT                 8
+#define GEVNT_DEVT(x)                    (((x) & 0xF) << 8)
+#define GEVNT_DEVT_INACT_TIMEOUT_RCVD    (0x15 << 8)
+#define GEVNT_DEVT_VNDR_DEV_TST_RCVD     (0x14 << 8)
+#define GEVNT_DEVT_OVERFLOW              (0x13 << 8)
+#define GEVNT_DEVT_CMD_CMPL              (0x12 << 8)
+#define GEVNT_DEVT_ERRATICERR            (0x11 << 8)
+#define GEVNT_DEVT_SOF                   (0x7 << 8)
+#define GEVNT_DEVT_EOPF                  (0x6 << 8)
+#define GEVNT_DEVT_HIBER_REQ             (0x5 << 8)
+#define GEVNT_DEVT_WKUP                  (0x4 << 8)
+#define GEVNT_DEVT_ULST_CHNG             (0x3 << 8)
+#define GEVNT_DEVT_CONNDONE              (0x2 << 8)
+#define GEVNT_DEVT_USBRESET              (0x1 << 8)
+#define GEVNT_DEVT_DISCONN               (0x0 << 8)
+
+#define DCFG                             (DW_USB3_BASE + 0xC700)
+
+#define DCFG_NUMP_MASK                   (0x1F << 17)
+#define DCFG_NUMP(x)                     (((x) & 0x1F) << 17)
+#define DCFG_DEVADDR_MASK                (0x7F << 3)
+#define DCFG_DEVADDR(x)                  (((x) & 0x7F) << 3)
+#define DCFG_DEVSPD_MASK                 (0x7)
+#define DCFG_DEVSPD(x)                   ((x) & 0x7)
+#define DEVSPD_HS_PHY_30MHZ_OR_60MHZ     0
+#define DEVSPD_FS_PHY_30MHZ_OR_60MHZ     1
+#define DEVSPD_LS_PHY_6MHZ               2
+#define DEVSPD_FS_PHY_48MHZ              3
+#define DEVSPD_SS_PHY_125MHZ_OR_250MHZ   4
+
+#define DCTL                             (DW_USB3_BASE + 0xC704)
+
+#define DCTL_RUN_STOP                    BIT31
+#define DCTL_CSFTRST                     BIT30
+#define DCTL_INIT_U2_EN                  BIT12
+#define DCTL_ACCEPT_U2_EN                BIT11
+#define DCTL_INIT_U1_EN                  BIT10
+#define DCTL_ACCEPT_U1_EN                BIT9
+
+#define DEVTEN                           (DW_USB3_BASE + 0xC708)
+#define DEVTEN_CONNECTDONEEN             BIT2
+#define DEVTEN_USBRSTEN                  BIT1
+#define DEVTEN_DISCONNEN                 BIT0
+
+#define DSTS                             (DW_USB3_BASE + 0xC70C)
+#define DSTS_GET_DEVSPD(x)               ((x) & 0x7)
+
+#define DALEPENA                         (DW_USB3_BASE + 0xC720)
+
+#define DEPCMDPAR2(x)                    (DW_USB3_BASE + 0xC800 + ((x) & 0x1F) * 0x10)
+#define DEPCMDPAR1(x)                    (DW_USB3_BASE + 0xC804 + ((x) & 0x1F) * 0x10)
+#define DEPCMDPAR0(x)                    (DW_USB3_BASE + 0xC808 + ((x) & 0x1F) * 0x10)
+#define DEPCMD(x)                        (DW_USB3_BASE + 0xc80C + ((x) & 0x1F) * 0x10)
+
+#define DEPCMD_COMMANDPARAM_MASK         (0xFFFF << 16)
+#define DEPCMD_COMMANDPARAM(x)           (((x) & 0xFFFF) << 16)
+/* Stream Number or uFrame (input) */
+#define DEPCMD_STR_NUM_OR_UF_MASK        (0xFFFF << 16)
+#define DEPCMD_STR_NUM_OR_UF(x)          (((x) & 0xFFFF) << 16)
+/* Transfer Resource Index (output) */
+#define DEPCMD_XFER_RSRC_IDX_SHIFT       16
+#define DEPCMD_XFER_RSRC_IDX_MASK        (0x7F << 16)
+#define DEPCMD_XFER_RSRC_IDX(x)          (((x) & 0x7F) << 16)
+#define GET_DEPCMD_XFER_RSRC_IDX(x)      (((x) >> 16) & 0x7F)
+#define DEPCMD_CMDACT                    BIT10
+#define DEPCMD_CMDTYPE_MASK              0xFF
+#define DEPCMD_CMDTYPE(x)                ((x) & 0xFF)
+
+/* EP registers range as: OUT0, IN0, OUT1, IN1, ... */
+#define EP_OUT_IDX(x)                    ((x) * 2)
+#define EP_IN_IDX(x)                     (((x) * 2) + 1)
+
+#define CMDTYPE_SET_EP_CFG               1
+#define CMDTYPE_SET_XFER_CFG             2
+#define CMDTYPE_GET_EP_STATE             3
+#define CMDTYPE_SET_STALL                4
+#define CMDTYPE_CLR_STALL                5
+#define CMDTYPE_START_XFER               6
+#define CMDTYPE_UPDATE_XFER              7
+#define CMDTYPE_END_XFER                 8
+#define CMDTYPE_START_NEW_CFG            9
+
+#define EPTYPE_CONTROL                   0
+#define EPTYPE_ISOC                      1
+#define EPTYPE_BULK                      2
+#define EPTYPE_INTR                      3
+
+#define CFG_ACTION_INIT                  0
+#define CFG_ACTION_RESTORE               1
+#define CFG_ACTION_MODIFY                2
+
+#define EPCFG0_CFG_ACTION_MASK           (0x3 << 30)
+#define EPCFG0_CFG_ACTION(x)             (((x) & 0x3) << 30)
+#define EPCFG0_BRSTSIZ_MASK              (0xF << 22)
+#define EPCFG0_BRSTSIZ(x)                (((x) & 0xF) << 22)
+#define EPCFG0_TXFNUM_MASK               (0x1F << 17)
+#define EPCFG0_TXFNUM(x)                 (((x) & 0x1F) << 17)
+#define EPCFG0_MPS_MASK                  (0x7FF << 3)
+#define EPCFG0_MPS(x)                    (((x) & 0x7FF) << 3)
+#define EPCFG0_EPTYPE_MASK               (0x3 << 1)
+#define EPCFG0_EPTYPE_SHIFT              1
+#define EPCFG0_EPTYPE(x)                 (((x) & 0x3) << 1)
+
+/* Endpoint Number */
+#define EPCFG1_EP_NUM_MASK               (0xF << 26)
+#define EPCFG1_EP_NUM(x)                 (((x) & 0xF) << 26)
+/* Endpoint Direction */
+#define EPCFG1_EP_DIR_IN                 BIT25
+/* Stream Not Ready */
+#define EPCFG1_XFER_NRDY                 BIT10
+/* XferInProgress Enable */
+#define EPCFG1_XFER_IN_PROG              BIT9
+/* Stream Completed */
+#define EPCFG1_XFER_CMPL                 BIT8
+
+#define USB_SPEED_UNKNOWN                0
+#define USB_SPEED_LOW                    1
+#define USB_SPEED_FULL                   2
+#define USB_SPEED_HIGH                   3
+#define USB_SPEED_VARIABLE               4
+#define USB_SPEED_SUPER                  5
+
+// DMA registers
+#define DSCSTS_TRBRSP_MASK               (0xF << 28)
+#define DSCSTS_TRBRSP(x)                 (((x) & 0xF) << 28)
+#define GET_DSCSTS_TRBRSP(x)             (((x) >> 28) & 0xF)
+#define TRBRSP_MISSED_ISOC_IN            1
+#define TRBRSP_SETUP_PEND                2
+#define TRBRSP_XFER_IN_PROG              4
+#define DSCSTS_PCM1_MASK                 (0x3 << 24)
+#define DSCSTS_PCM1(x)                   (((x) & 0x3) << 24)
+#define DSCSTS_XFERCNT_MASK              0xFFFFFF
+#define DSCSTS_XFERCNT(x)                ((x) & 0xFFFFFF)
+#define GET_DSCSTS_XFERCNT(x)            ((x) & 0xFFFFFF)
+
+#define DSCCTL_STRMID_SOFN(x)            (((x) & 0xFFFF) << 14)
+#define DSCCTL_IOC                       BIT11
+#define DSCCTL_ISP                       BIT10
+#define DSCCTL_TRBCTL_MASK               (0x3F << 4)
+#define DSCCTL_TRBCTL(x)                 (((x) & 0x3F) << 4)
+#define DSCCTL_LST                       BIT1
+#define DSCCTL_HWO                       BIT0
+#define TRBCTL_NORMAL                    1
+#define TRBCTL_SETUP                     2
+#define TRBCTL_STATUS_2                  3
+#define TRBCTL_STATUS_3                  4
+#define TRBCTL_CTLDATA_1ST               5
+#define TRBCTL_ISOC_1ST                  6
+#define TRBCTL_ISOC                      7
+#define TRBCTL_LINK                      8
+#define TRBCTL_NORMAL_ZLP                9
+
+
+#define UE_DIR_IN                        0x80
+#define UE_DIR_OUT                       0
+#define UE_SET_DIR(a, d)                 ((a) | (((d) & 1) << 7))
+#define UE_GET_DIR(a)                    ((a) & 0x80)
+#define UE_ADDR                          0x0F
+#define UE_GET_ADDR(a)                   ((a) & UE_ADDR)
+
+#define UT_GET_DIR(a)                    ((a) & 0x80)
+#define UT_WRITE                         0x00
+#define UT_READ                          0x80
+
+#define UT_GET_TYPE(a)                   ((a) & 0x60)
+#define UT_STANDARD                      0x00
+#define UT_CLASS                         0x20
+#define UT_VENDOR                        0x40
+
+#define UT_GET_RECIPIENT(a)              ((a) & 0x1f)
+#define UT_DEVICE                        0x00
+#define UT_INTERFACE                     0x01
+#define UT_ENDPOINT                      0x02
+#define UT_OTHER                         0x03
+
+#define UR_GET_STATUS                    0x00
+#define UR_CLEAR_FEATURE                 0x01
+#define UR_SET_FEATURE                   0x03
+#define UR_SET_ADDRESS                   0x05
+#define UR_GET_DESCRIPTOR                0x06
+#define UR_SET_DESCRIPTOR                0x07
+#define UR_GET_CONFIG                    0x08
+#define UR_SET_CONFIG                    0x09
+#define UR_GET_INTERFACE                 0x0A
+#define UR_SET_INTERFACE                 0x0B
+#define UR_SYNCH_FRAME                   0x0C
+#define UR_SET_SEL                       0x30
+#define UR_SET_ISOC_DELAY                0x31
+
+/* Feature numbers */
+#define UF_ENDPOINT_HALT                 0
+#define UF_DEVICE_REMOTE_WAKEUP          1
+#define UF_TEST_MODE                     2
+#define UF_DEVICE_B_HNP_ENABLE           3
+#define UF_DEVICE_A_HNP_SUPPORT          4
+#define UF_DEVICE_A_ALT_HNP_SUPPORT      5
+#define UF_FUNCTION_SUSPEND              0
+#define UF_U1_ENABLE                     48
+#define UF_U2_ENABLE                     49
+#define UF_LTM_ENABLE                    50
+
+#define  UDESC_DEVICE                    0x01
+#define  UDESC_CONFIG                    0x02
+#define  UDESC_STRING                    0x03
+#define  UDESC_INTERFACE                 0x04
+#define  UDESC_ENDPOINT                  0x05
+#define  UDESC_SS_USB_COMPANION          0x30
+#define  UDESC_DEVICE_QUALIFIER          0x06
+#define  UDESC_BOS                       0x0f
+#define  UDESC_DEVICE_CAPABILITY         0x10
+
+#define STRING_LANGUAGE                  0
+#define STRING_MANUFACTURER              1
+#define STRING_PRODUCT                   2
+#define STRING_SERIAL                    3
+
+#define CONFIG_VALUE    1
+
+#define USB3_BULK_IN_EP                  1
+#define USB3_BULK_OUT_EP                 1
+
+#define USB_ENUM_ADB_PORT_VID            0x18D1
+#define USB_ENUM_ADB_PORT_PID            0xD00D
+#define USB_ENUM_INTERFACE_ADB_SUBCLASS  0x42
+#define USB_ENUM_INTERFACE_ADB_PROTOCOL  0x03
+
+struct usb3_pcd;
+
+typedef enum pcd_state {
+  USB3_STATE_UNCONNECTED,                /* no host */
+  USB3_STATE_DEFAULT,
+  USB3_STATE_ADDRESSED,
+  USB3_STATE_CONFIGURED,
+} pcdstate_e;
+
+typedef enum ep0_state {
+  EP0_IDLE,
+  EP0_IN_DATA_PHASE,
+  EP0_OUT_DATA_PHASE,
+  EP0_IN_WAIT_NRDY,
+  EP0_OUT_WAIT_NRDY,
+  EP0_IN_STATUS_PHASE,
+  EP0_OUT_STATUS_PHASE,
+  EP0_STALL,
+} ep0state_e;
+
+typedef struct usb3_dma_desc {
+  /** Buffer Pointer - Low address quadlet */
+  UINT32     bptl;
+
+  /** Buffer Pointer - High address quadlet */
+  UINT32     bpth;
+
+  /** Status quadlet. Fields defined in enum @ref desc_sts_data. */
+  UINT32     status;
+
+  /** Control quadlet. Fields defined in enum @ref desc_ctl_data. */
+  UINT32     control;
+} usb3_dma_desc_t;
+
+typedef struct usb3_pcd_req {
+  usb3_dma_desc_t *trb;
+  UINT64 trbdma;
+
+  UINT32 length;
+  UINT32 actual;
+
+  UINT64 *bufdma;
+  int (*complete)(unsigned actual, int status);
+} usb3_pcd_req_t;
+
+typedef struct usb_device_request {
+  UINT8 bmRequestType;
+  UINT8 bRequest;
+  UINT16 wValue;
+  UINT16 wIndex;
+  UINT16 wLength;
+} usb_device_request_t;
+
+#pragma pack(1)
+/** USB_DT_DEVICE: Device descriptor */
+typedef struct usb_device_descriptor {
+  UINT8  bLength;
+  UINT8  bDescriptorType;
+
+  UINT16 bcdUSB;
+#define USB_CLASS_COMM          0x02
+#define USB_CLASS_VENDOR_SPEC   0xFF
+#define USB_SC_VENDOR_SPEC      0xFF
+#define USB_PR_VENDOR_SPEC      0xFF
+  UINT8  bDeviceClass;
+  UINT8  bDeviceSubClass;
+  UINT8  bDeviceProtocol;
+  UINT8  bMaxPacketSize0;
+  UINT16 idVendor;
+  UINT16 idProduct;
+  UINT16 bcdDevice;
+  UINT8  iManufacturer;
+  UINT8  iProduct;
+  UINT8  iSerialNumber;
+  UINT8  bNumConfigurations;
+} usb_device_descriptor_t;
+
+/* USB_DT_CONFIG: Config descriptor */
+typedef struct usb_config_descriptor {
+  UINT8  bLength;
+  UINT8  bDescriptorType;
+
+  UINT16 wTotalLength;
+  UINT8  bNumInterfaces;
+#define CONFIG_VALUE            1
+  UINT8  bConfigurationValue;
+  UINT8  iConfiguration;
+#define USB_CONFIG_ATT_ONE      (1 << 7)
+  UINT8  bmAttributes;
+#define USB_CONFIG_VBUS_DRAW    (0xFA)
+  UINT8  bMaxPower;
+} usb_config_descriptor_t;
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+typedef struct usb_qualifier_descriptor {
+  UINT8  bLength;
+  UINT8  bDescriptorType;
+
+  UINT16 bcdUSB;
+  UINT8  bDeviceClass;
+  UINT8  bDeviceSubClass;
+  UINT8  bDeviceProtocol;
+  UINT8  bMaxPacketSize0;
+  UINT8  bNumConfigurations;
+  UINT8  bRESERVED;
+} usb_qualifier_descriptor_t;
+
+/* USB_DT_INTERFACE: Interface descriptor */
+typedef struct usb_interface_descriptor {
+  UINT8  bLength;
+  UINT8  bDescriptorType;
+
+  UINT8  bInterfaceNumber;
+  UINT8  bAlternateSetting;
+  UINT8  bNumEndpoints;
+  UINT8  bInterfaceClass;
+  UINT8  bInterfaceSubClass;
+  UINT8  bInterfaceProtocol;
+  UINT8  iInterface;
+} usb_interface_descriptor_t;
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+typedef struct usb_endpoint_descriptor {
+  UINT8  bLength;
+  UINT8  bDescriptorType;
+
+  UINT8  bEndpointAddress;
+  UINT8  bmAttributes;
+#define USB_ENDPOINT_XFER_CONTROL       0x00
+#define USB_ENDPOINT_XFER_ISOC          0x01
+#define USB_ENDPOINT_XFER_BULK          0x02
+#define USB_ENDPOINT_XFER_INT           0x03
+  UINT16 wMaxPacketSize;
+  UINT8  bInterval;
+} usb_endpoint_descriptor_t;
+
+/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
+typedef struct usb_ss_ep_comp_descriptor {
+  UINT8  bLength;
+  UINT8  bDescriptorType;
+
+  UINT8  bMaxBurst;
+  UINT8  bmAttributes;
+  UINT16 wBytesPerInterval;
+} usb_ss_ep_comp_descriptor_t;
+
+/* WUSB BOS Descriptor (Binary device Object Store) */
+typedef struct wusb_bos_desc {
+  UINT8 bLength;
+  UINT8 bDescriptorType;
+  UINT16 wTotalLength;
+  UINT8 bNumDeviceCaps;
+} wusb_bos_desc_t;
+
+#define USB_DEVICE_CAPABILITY_20_EXTENSION      0x02
+typedef struct usb_dev_cap_20_ext_desc {
+  UINT8 bLength;
+  UINT8 bDescriptorType;
+  UINT8 bDevCapabilityType;
+#define USB_20_EXT_LPM                          0x02
+  UINT32 bmAttributes;
+} usb_dev_cap_20_ext_desc_t;
+
+#define USB_DEVICE_CAPABILITY_SS_USB            0x03
+typedef struct usb_dev_cap_ss_usb {
+  UINT8 bLength;
+  UINT8 bDescriptorType;
+  UINT8 bDevCapabilityType;
+#define USB_DC_SS_USB_LTM_CAPABLE               0x02
+  UINT8 bmAttributes;
+#define USB_DC_SS_USB_SPEED_SUPPORT_LOW         0x01
+#define USB_DC_SS_USB_SPEED_SUPPORT_FULL        0x02
+#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH        0x04
+#define USB_DC_SS_USB_SPEED_SUPPORT_SS          0x08
+  UINT32 wSpeedsSupported;
+  UINT8 bFunctionalitySupport;
+  UINT8 bU1DevExitLat;
+  UINT32 wU2DevExitLat;
+} usb_dev_cap_ss_usb_t;
+
+#define USB_DEVICE_CAPABILITY_CONTAINER_ID      0x04
+typedef struct usb_dev_cap_container_id {
+  UINT8 bLength;
+  UINT8 bDescriptorType;
+  UINT8 bDevCapabilityType;
+  UINT8 bReserved;
+  UINT8 containerID[16];
+} usb_dev_cap_container_id_t;
+#pragma pack()
+
+typedef union usb_setup_pkt {
+  usb_device_request_t req;
+  UINT32 d32[2];
+  UINT8 d8[8];
+} usb_setup_pkt_t;
+
+typedef struct usb3_pcd_ep {
+  struct usb3_pcd *pcd;
+
+  UINT8          EpInIdx;
+  UINT8          EpOutIdx;
+  UINT8          phys;
+
+  //UINT8 phys;
+  UINT8 num;
+  UINT8 type;
+  UINT8 maxburst;
+  UINT16 maxpacket;
+  /* Tx FIFO # for IN EPs */
+  UINT8 tx_fifo_num;
+
+  /* The Transfer Resource Index from the Start Transfer command */
+  UINT8 tri_out;
+  UINT8 tri_in;
+
+  UINT8 stopped;
+  /* Send ZLP */
+  UINT8 send_zlp;
+  /* True if 3-stage control transfer */
+  UINT8 three_stage;
+  /* True if transfer has been started on EP */
+  UINT8 xfer_started;
+  /* EP direction 0 = OUT */
+  UINT8 is_in;
+  /* True if endpoint is active */
+  UINT8 active;
+  /* Initial data pid of bulk endpoint */
+  UINT8 data_pid_start;
+
+  /* ep_desc (excluding ep0) */
+  usb3_dma_desc_t *ep_desc;
+
+#if 0
+  /* TRB descriptor must be aligned to 16 bytes */
+  UINT8 epx_desc[32];
+#endif
+
+  /* request (excluding ep0) */
+  usb3_pcd_req_t req;
+} usb3_pcd_ep_t;
+
+typedef struct usb3_pcd {
+  //struct usb3_device *usb3_dev;
+
+  INT32 link_state;
+  pcdstate_e state;
+  UINT8 new_config;
+  ep0state_e ep0state;
+
+  UINT32 eps_enabled;
+  UINT32 ltm_enable;
+
+  usb3_pcd_ep_t ep0;
+  usb3_pcd_ep_t out_ep;
+  usb3_pcd_ep_t in_ep;
+
+  /*
+  usb3_dev_global_regs_t *dev_global_regs;
+  usb3_dev_ep_regs_t *out_ep_regs;
+  usb3_dev_ep_regs_t *in_ep_regs;
+  */
+
+  usb3_pcd_req_t ep0_req;
+
+  UINT8 speed;
+
+  usb3_dma_desc_t *ep0_setup_desc;
+  usb3_dma_desc_t *ep0_in_desc;
+  usb3_dma_desc_t *ep0_out_desc;
+
+  /* TRB descriptor must be aligned to 16 bytes */
+#if 0
+  UINT8 ep0_setup[32];
+  UINT8 ep0_in[32];
+  UINT8 ep0_out[32];
+
+  usb_setup_pkt_t ep0_setup_pkt[5];
+
+#define USB3_STATUS_BUF_SIZE    512
+  UINT8 ep0_status_buf[USB3_STATUS_BUF_SIZE];
+
+#define USB3_BULK_BUF_SIZE      2048
+  UINT8 ss_bulk_buf[USB3_BULK_BUF_SIZE];
+#endif
+
+  UINT32 file_type;
+  UINT32 file_address;
+  UINT32 file_capacity;
+  UINT32 file_total_frame;
+  UINT32 file_curr_frame;
+  UINT32 file_next_frame;
+  UINT32 file_received;
+  UINT32 file_complete;
+
+  UINT16 test_mode_nr;
+  UINT16 test_mode;
+} usb3_pcd_t;
+
+struct usb_enum_port_param {
+  UINT16     idVendor;
+  UINT16     idProduct;
+  UINT8      bInterfaceSubClass;
+  UINT8      bInterfaceProtocol;
+};
+
+#if 0
+typedef struct usb3_pcd_req {
+  usb3_dma_desc_t *trb;
+  UINT64 trbdma;
+
+  UINT32 length;
+  UINT32 actual;
+
+  UINT64 *bufdma;
+  int (*complete)(unsigned actual, int status);
+} usb3_pcd_req_t;
+
+#endif
+
+#endif /* __DW_USB3_DXE_H__ */
diff --git a/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c
new file mode 100644
index 000000000000..83d5e4736de0
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwUsb3Dxe/DwUsb3Dxe.c
@@ -0,0 +1,2434 @@
+/** @file
+
+  Copyright (c) 2018, Linaro Limited. 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 <IndustryStandard/Usb.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DmaLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/DwUsb.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/UsbDevice.h>
+
+#include "DwUsb3Dxe.h"
+
+#define FIFO_DIR_TX                  0
+#define FIFO_DIR_RX                  1
+
+#define TX_FIFO_ADDR                 0
+#define RX_FIFO_ADDR                 0
+
+#define RAM_WIDTH                    8
+#define RAM_TX0_DEPTH                2048
+#define RAM_TX1_DEPTH                4096
+#define RAM_RX_DEPTH                 8192
+
+#define USB_TYPE_LENGTH              16
+#define USB_BLOCK_HIGH_SPEED_SIZE    512
+#define DATA_SIZE                    131072
+#define CMD_SIZE                     512
+#define MATCH_CMD_LITERAL(Cmd, Buf)  !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1)
+
+#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))
+
+//
+// The time between interrupt polls, in units of 100 nanoseconds
+// 10 Microseconds
+//
+#define DW_INTERRUPT_POLL_PERIOD     100
+
+#define DWUSB3_EVENT_BUF_SIZE        256
+
+//
+// Maxpacket size for EP0, defined by USB3 spec
+//
+#define USB3_MAX_EP0_SIZE            512
+
+//
+// Maxpacket size for any EP, defined by USB3 spec
+//
+#define USB3_MAX_PACKET_SIZE         1024
+#define USB2_HS_MAX_PACKET_SIZE      512
+#define USB2_FS_MAX_PACKET_SIZE      64
+
+#define USB3_STATE_UNCONNECTED       0
+#define USB3_STATE_DEFAULT           1
+#define USB3_STATE_ADDRESSED         2
+#define USB3_STATE_CONFIGURED        3
+
+#define USB3_STATUS_BUF_SIZE         512
+
+#define GET_EVENTBUF_COUNT()                                       \
+        (GEVNTCOUNT_EVNTCOUNT (MmioRead32 (GEVNTCOUNT (0))))
+#define UPDATE_EVENTBUF_COUNT(x)                                   \
+        (MmioWrite32 (GEVNTCOUNT (0), GEVNTCOUNT_EVNTCOUNT (x)))
+
+#define SET_DEVADDR(x)                                             \
+        (MmioAndThenOr32 (DCFG, ~DCFG_DEVADDR_MASK, DCFG_DEVADDR (x)))
+
+EFI_GUID  gDwUsbProtocolGuid = DW_USB_PROTOCOL_GUID;
+
+STATIC DW_USB_PROTOCOL                *DwUsb;
+
+STATIC usb3_pcd_t                     gPcd;
+STATIC UINT32                         *gEventBuf, *gEventPtr;
+STATIC struct usb_device_descriptor   gDwUsb3DevDesc;
+STATIC VOID                           *gRxBuf;
+
+STATIC usb_setup_pkt_t                *gEndPoint0SetupPacket;
+STATIC UINT8                          *gEndPoint0StatusBuf;
+STATIC USB_DEVICE_RX_CALLBACK         mDataReceivedCallback;
+STATIC UINTN                          mDataBufferSize;
+
+struct usb_interface_descriptor intf = {
+  sizeof (struct usb_interface_descriptor),
+  UDESC_INTERFACE,
+  0,
+  0,
+  2,
+  USB_CLASS_VENDOR_SPEC,
+  0x42,
+  0x03,
+  0
+};
+
+const struct usb_ss_ep_comp_descriptor ep_comp = {
+  sizeof (struct usb_ss_ep_comp_descriptor),
+  UDESC_SS_USB_COMPANION,
+  0,
+  0,
+  0
+};
+
+const struct usb_endpoint_descriptor hs_bulk_in = {
+  sizeof (struct usb_endpoint_descriptor),
+  UDESC_ENDPOINT,
+  UE_DIR_IN | USB3_BULK_IN_EP,
+  USB_ENDPOINT_XFER_BULK,
+  0x200,
+  0
+};
+
+const struct usb_endpoint_descriptor
+hs_bulk_out = {
+  sizeof(struct usb_endpoint_descriptor), /* bLength */
+  UDESC_ENDPOINT,                         /* bDescriptorType */
+
+  UE_DIR_OUT | USB3_BULK_OUT_EP, /* bEndpointAddress */
+  USB_ENDPOINT_XFER_BULK,        /* bmAttributes */
+  0x200,                         /* wMaxPacketSize: 512 of high-speed */
+  1,                             /* bInterval */
+};
+
+const struct usb_endpoint_descriptor ss_bulk_in = {
+  sizeof(struct usb_endpoint_descriptor), /* bLength */
+  UDESC_ENDPOINT,                         /* bDescriptorType */
+
+  UE_DIR_IN | USB3_BULK_IN_EP,   /* bEndpointAddress */
+  USB_ENDPOINT_XFER_BULK,        /* bmAttributes */
+  0x400,                         /* wMaxPacketSize: 1024 of super-speed */
+  0,                             /* bInterval */
+};
+
+const struct usb_endpoint_descriptor ss_bulk_out = {
+  sizeof(struct usb_endpoint_descriptor), /* bLength */
+  UDESC_ENDPOINT,                         /* bDescriptorType */
+
+  UE_DIR_OUT | USB3_BULK_OUT_EP,  /* bEndpointAddress */
+  USB_ENDPOINT_XFER_BULK,         /* bmAttributes */
+  0x400,                          /* wMaxPacketSize: 1024 of super-speed */
+  0,                              /* bInterval */
+};
+
+/** The BOS Descriptor */
+
+const struct usb_dev_cap_20_ext_desc cap1 = {
+  sizeof(struct usb_dev_cap_20_ext_desc), /* bLength */
+  UDESC_DEVICE_CAPABILITY,                /* bDescriptorType */
+  USB_DEVICE_CAPABILITY_20_EXTENSION,     /* bDevCapabilityType */
+  0x2,                                    /* bmAttributes */
+};
+
+const struct usb_dev_cap_ss_usb
+cap2 = {
+  sizeof(struct usb_dev_cap_ss_usb),      /* bLength */
+  UDESC_DEVICE_CAPABILITY,                /* bDescriptorType */
+  USB_DEVICE_CAPABILITY_SS_USB,           /* bDevCapabilityType */
+  0x0,                                    /* bmAttributes */
+  (USB_DC_SS_USB_SPEED_SUPPORT_SS |
+      USB_DC_SS_USB_SPEED_SUPPORT_HIGH),  /* wSpeedsSupported */
+  0x2,                                    /* bFunctionalitySupport */
+  0xa,                                    /* bU1DevExitLat */
+  0x100,                                  /* wU2DevExitLat */
+};
+
+const struct usb_dev_cap_container_id
+cap3 = {
+  sizeof(struct usb_dev_cap_container_id),/* bLength */
+  UDESC_DEVICE_CAPABILITY,                /* bDescriptorType */
+  USB_DEVICE_CAPABILITY_CONTAINER_ID,     /* bDevCapabilityType */
+  0,                                      /* bReserved */
+  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* containerID */
+};
+
+const struct wusb_bos_desc
+bos = {
+  sizeof(struct wusb_bos_desc),           /* bLength */
+  UDESC_BOS,                              /* bDescriptorType */
+  (sizeof(struct wusb_bos_desc) +         \
+    sizeof(cap1) + sizeof(cap2) +         \
+    sizeof(cap3)),                        /* wTotalLength */
+  3,                                      /* bNumDeviceCaps */
+};
+
+STATIC struct usb_enum_port_param usb_port_activity_config = {
+  .idVendor           = USB_ENUM_ADB_PORT_VID,
+  .idProduct          = USB_ENUM_ADB_PORT_PID,
+  .bInterfaceSubClass = USB_ENUM_INTERFACE_ADB_SUBCLASS,
+  .bInterfaceProtocol = USB_ENUM_INTERFACE_ADB_PROTOCOL
+};
+
+STATIC
+UINT32
+DwUsb3GetEventBufEvent (
+  IN UINTN               Size
+  )
+{
+  UINT32                 Event;
+
+  Event = *gEventPtr++;
+  if ((UINT32)(UINTN)gEventPtr >= (UINT32)(UINTN)gEventBuf + Size) {
+    gEventPtr = gEventBuf;
+  }
+  return Event;
+}
+
+STATIC
+VOID
+DwUsb3SetFifoSize (
+  IN UINT32              Addr,
+  IN UINT32              Depth,
+  IN UINT32              Dir,
+  IN UINT32              FifoNum
+  )
+{
+  UINT32                 Reg = 0;
+
+  if (Dir == FIFO_DIR_TX) {
+    Reg = GTXFIFOSIZ (FifoNum);
+  } else if (Dir == FIFO_DIR_RX) {
+    Reg = GRXFIFOSIZ (FifoNum);
+  } else {
+    ASSERT (0);
+  }
+  MmioWrite32 (Reg, FIFOSIZ_DEP (Depth) | FIFOSIZ_ADDR (Addr));
+}
+
+STATIC
+UINT32
+Handshake (
+  IN UINT32              Reg,
+  IN UINT32              Mask,
+  IN UINT32              Done
+  )
+{
+  UINT32                 Timeout = 100000;
+
+  do {
+    if ((MmioRead32 (Reg) & Mask) == Done) {
+      return 1;
+    }
+    MicroSecondDelay (1);
+  } while (Timeout-- > 0);
+  return 0;
+}
+
+STATIC
+VOID
+DwUsb3FillDesc (
+  IN usb3_dma_desc_t     *desc,
+  IN UINT64              dma_addr,
+  IN UINT32              dma_len,
+  IN UINT32              stream,
+  IN UINT32              type,
+  IN UINT32              ctrlbits,
+  IN UINT32              own
+  )
+{
+  desc->bptl = (UINT32)(dma_addr & 0xFFFFFFFF);
+  desc->bpth = (UINT32)(dma_addr >> 32);
+  desc->status = DSCSTS_XFERCNT (dma_len);
+  if (type) {
+    desc->control = DSCCTL_TRBCTL (type);
+  }
+  desc->control |= DSCCTL_STRMID_SOFN (stream) | ctrlbits;
+  ArmDataSynchronizationBarrier ();
+  /* must execute this operation at last */
+  if (own) {
+    desc->control |= DSCCTL_HWO;
+  }
+  ArmDataSynchronizationBarrier ();
+}
+
+STATIC
+VOID
+DwUsb3DepStartNewCfg (
+  IN UINT32              EpIdx,
+  IN UINT32              RsrcIdx
+  )
+{
+  /* start the command */
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_XFER_RSRC_IDX (RsrcIdx) | DEPCMD_CMDTYPE (CMDTYPE_START_NEW_CFG) | \
+    DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+STATIC
+VOID
+DwUsb3DepCfg (
+  IN UINT32              EpIdx,
+  IN UINT32              DepCfg0,
+  IN UINT32              DepCfg1,
+  IN UINT32              DepCfg2
+  )
+{
+  MmioWrite32 (DEPCMDPAR2 (EpIdx), DepCfg2);
+  MmioWrite32 (DEPCMDPAR1 (EpIdx), DepCfg1);
+  MmioWrite32 (DEPCMDPAR0 (EpIdx), DepCfg0);
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_CMDTYPE (CMDTYPE_SET_EP_CFG) | DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+STATIC
+VOID
+DwUsb3DepXferCfg (
+  IN UINT32              EpIdx,
+  IN UINT32              DepStrmCfg
+  )
+{
+  MmioWrite32 (DEPCMDPAR0 (EpIdx), DepStrmCfg);
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_CMDTYPE (CMDTYPE_SET_XFER_CFG) | DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+STATIC
+UINT8
+DwUsb3DepStartXfer (
+  IN UINT32              EpIdx,
+  IN UINT64              DmaAddr,
+  IN UINT32              StreamOrUf
+  )
+{
+  UINT32                 Data;
+
+  MmioWrite32 (DEPCMDPAR1 (EpIdx), (UINT32)DmaAddr);
+  MmioWrite32 (DEPCMDPAR0 (EpIdx), (UINT32)(DmaAddr >> 32));
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_STR_NUM_OR_UF (StreamOrUf) | DEPCMD_CMDTYPE (CMDTYPE_START_XFER) | \
+    DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+  Data = MmioRead32 (DEPCMD (EpIdx));
+  return GET_DEPCMD_XFER_RSRC_IDX(Data);
+}
+
+STATIC
+VOID
+DwUsb3DepStopXfer (
+  IN UINT32               EpIdx,
+  IN UINT32               Tri
+  )
+{
+  MmioWrite32 (DEPCMDPAR2 (EpIdx), 0);
+  MmioWrite32 (DEPCMDPAR1 (EpIdx), 0);
+  MmioWrite32 (DEPCMDPAR0 (EpIdx), 0);
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_XFER_RSRC_IDX (Tri) | DEPCMD_CMDTYPE (CMDTYPE_END_XFER) | \
+    DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+VOID
+DwUsb3DepUpdateXfer (
+  IN UINT32               EpIdx,
+  IN UINT32               Tri
+  )
+{
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_XFER_RSRC_IDX (Tri) | DEPCMD_CMDTYPE (CMDTYPE_UPDATE_XFER) | \
+    DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+STATIC
+VOID
+DwUsb3DepClearStall (
+  IN UINTN            EpIdx
+  )
+{
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_CMDTYPE (CMDTYPE_CLR_STALL) | DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+
+STATIC
+VOID
+DwUsb3DepSetStall (
+  IN UINTN            EpIdx
+  )
+{
+  MmioWrite32 (
+    DEPCMD (EpIdx),
+    DEPCMD_CMDTYPE (CMDTYPE_SET_STALL) | DEPCMD_CMDACT
+    );
+  Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0);
+}
+
+STATIC
+VOID
+DwUsb3EnableEp (
+  IN UINT32                EpIdx,
+  IN usb3_pcd_ep_t         *ep
+  )
+{
+  UINT32                   Dalepena;
+
+  Dalepena = MmioRead32 (DALEPENA);
+  /* If the EP is already enabled, skip to set it again. */
+  if (Dalepena & (1 << EpIdx)) {
+    return;
+  }
+  Dalepena |= 1 << EpIdx;
+  MmioWrite32 (DALEPENA, Dalepena);
+}
+
+STATIC
+VOID
+DwUsb3Ep0Activate (
+  IN OUT usb3_pcd_t         *pcd
+  )
+{
+  /* issue DEPCFG command to EP0 OUT */
+  DwUsb3DepStartNewCfg (EP_OUT_IDX (0), 0);
+  DwUsb3DepCfg (
+    EP_OUT_IDX (0),
+    EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_MPS (512),
+    EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY,
+    0
+    );
+  /* issue DEPSTRMCFG command to EP0 OUT */
+  DwUsb3DepXferCfg (EP_OUT_IDX (0), 1);  // one stream
+  /* issue DEPCFG command to EP0 IN */
+  DwUsb3DepCfg (
+    EP_IN_IDX (0),
+    EPCFG0_EPTYPE (EPTYPE_CONTROL)  | EPCFG0_MPS (512) | \
+    EPCFG0_TXFNUM (pcd->ep0.tx_fifo_num),
+    EPCFG1_XFER_NRDY | EPCFG1_XFER_CMPL | EPCFG1_EP_DIR_IN,
+    0
+    );
+  /* issue DEPSTRMCFG command to EP0 IN */
+  DwUsb3DepXferCfg (EP_IN_IDX (0), 1);  // one stream
+  pcd->ep0.active = 1;
+}
+
+STATIC
+VOID
+DwUsb3EpActivate (
+  IN OUT usb3_pcd_t         *pcd,
+  IN OUT usb3_pcd_ep_t      *ep
+  )
+{
+  UINT32                    EpIdx, DepCfg0, DepCfg1;
+  if (ep->is_in) {
+    EpIdx = EP_IN_IDX (ep->num);
+  } else {
+    EpIdx = EP_OUT_IDX (ep->num);
+  }
+
+  /* Start a new configurate when enable the first EP. */
+  if (!pcd->eps_enabled) {
+    pcd->eps_enabled = 1;
+    /* Issue DEPCFG command to physical EP1 (logical EP0 IN) first.
+     * It resets the core's Tx FIFO mapping table.
+     */
+    DepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL);
+    DepCfg0 |= EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY);
+    DepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY | EPCFG1_EP_DIR_IN;
+
+    switch (pcd->speed) {
+    case USB_SPEED_SUPER:
+      DepCfg0 |= EPCFG0_MPS (512);
+      break;
+    case USB_SPEED_HIGH:
+    case USB_SPEED_FULL:
+      DepCfg0 |= EPCFG0_MPS (64);
+      break;
+    case USB_SPEED_LOW:
+      DepCfg0 |= EPCFG0_MPS (8);
+      break;
+    default:
+      ASSERT (0);
+      break;
+    }
+    DwUsb3DepCfg (EP_IN_IDX (0), DepCfg0, DepCfg1, 0);
+    DwUsb3DepStartNewCfg (EP_OUT_IDX (0), 2);
+  }
+  /* issue DEPCFG command to EP */
+  DepCfg0 = EPCFG0_EPTYPE (ep->type);
+  DepCfg0 |= EPCFG0_MPS (ep->maxpacket);
+  if (ep->is_in) {
+    DepCfg0 |= EPCFG0_TXFNUM (ep->tx_fifo_num);
+  }
+  DepCfg0 |= EPCFG0_BRSTSIZ (ep->maxburst);
+  DepCfg1 = EPCFG1_EP_NUM (ep->num);
+  if (ep->is_in) {
+    DepCfg1 |= EPCFG1_EP_DIR_IN;
+  } else {
+    DepCfg1 |= EPCFG1_XFER_CMPL;
+  }
+  DwUsb3DepCfg (EpIdx, DepCfg0, DepCfg1, 0);
+  /* issue DEPSTRMCFG command to EP */
+  DwUsb3DepXferCfg (EpIdx, 1);
+  DwUsb3EnableEp (EpIdx, ep);
+  ep->active = 1;
+}
+
+STATIC
+VOID
+DwUsb3Ep0OutStart (
+  IN usb3_pcd_t          *pcd
+  )
+{
+  usb3_dma_desc_t        *desc;
+
+  /* Get the SETUP packet DMA Descriptor (TRB) */
+  desc = pcd->ep0_setup_desc;
+
+  /* DMA Descriptor setup */
+  DwUsb3FillDesc (
+    desc,
+    (UINT64)gEndPoint0SetupPacket,
+    pcd->ep0.maxpacket,
+    0,
+    TRBCTL_SETUP,
+    DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST,
+    1
+    );
+
+  /* issue DEPSTRTXFER command to EP0 OUT */
+  pcd->ep0.tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (0), (UINT64)desc, 0);
+}
+
+STATIC
+VOID
+DwUsb3Init (
+  VOID
+  )
+{
+  UINT32                 Data, Addr;
+  usb3_pcd_t             *pcd = &gPcd;
+
+  /* soft reset the usb core */
+  do {
+    MmioAndThenOr32 (DCTL, ~DCTL_RUN_STOP, DCTL_CSFTRST);
+
+    do {
+      MicroSecondDelay (1000);
+      Data = MmioRead32 (DCTL);
+    } while (Data & DCTL_CSFTRST);
+    //
+    // wait for at least 3 PHY clocks
+    //
+    MicroSecondDelay (1000);
+  } while (0);
+
+  pcd->link_state = 0;
+
+  /* TI PHY: Set Turnaround Time = 9 (8-bit UTMI+ / ULPI) */
+  MmioAndThenOr32 (
+    GUSB2PHYCFG (0),
+    ~GUSB2PHYCFG_USBTRDTIM_MASK,
+    GUSB2PHYCFG_USBTRDTIM (9)
+    );
+
+  /* set TX FIFO size */
+  Addr = TX_FIFO_ADDR;
+  DwUsb3SetFifoSize (Addr, RAM_TX0_DEPTH / RAM_WIDTH, FIFO_DIR_TX, 0);
+  Addr += RAM_TX0_DEPTH / RAM_WIDTH;
+  DwUsb3SetFifoSize (Addr, RAM_TX1_DEPTH / RAM_WIDTH, FIFO_DIR_TX, 1);
+  /* set RX FIFO size */
+  DwUsb3SetFifoSize (RX_FIFO_ADDR, RAM_RX_DEPTH / RAM_WIDTH, FIFO_DIR_RX, 0);
+
+  /* set LFPS filter delay1trans */
+  MmioAndThenOr32 (
+    GUSB3PIPECTL (0),
+    ~PIPECTL_DELAYP1TRANS,
+    PIPECTL_LFPS_FILTER | PIPECTL_TX_DEMPH (1)
+    );
+
+  /* set GCTL */
+  Data = GCTL_U2EXIT_LFPS | GCTL_PRTCAPDIR_DEVICE | GCTL_U2RSTECN |
+         GCTL_PWRDNSCALE(2);
+  MmioWrite32 (GCTL, Data);
+
+  /* init event buf */
+  MmioWrite32 (GEVNTADRL(0), (UINT32)(UINTN)gEventBuf);
+  MmioWrite32 (GEVNTADRH(0), (UINTN)gEventBuf >> 32);
+  MmioWrite32 (GEVNTSIZ(0), DWUSB3_EVENT_BUF_SIZE << 2);
+  MmioWrite32 (GEVNTCOUNT(0), 0);
+
+  /* set max speed to super speed */
+  MmioAndThenOr32 (
+    DCFG,
+    ~DCFG_DEVSPD_MASK,
+    DCFG_DEVSPD (DEVSPD_SS_PHY_125MHZ_OR_250MHZ)
+    );
+
+  /* set nump */
+  MmioAndThenOr32 (DCFG, ~DCFG_NUMP_MASK, DCFG_NUMP (16));
+
+  /* init address */
+  SET_DEVADDR (0);
+
+  /* disable phy suspend */
+  MmioAnd32 (GUSB3PIPECTL (0), ~PIPECTL_SUSPEND_EN);
+  MmioAnd32 (GUSB2PHYCFG (0), ~GUSB2PHYCFG_SUSPHY);
+
+  /* clear any pending interrupts */
+  Data = MmioRead32 (GEVNTCOUNT (0));
+  MmioWrite32 (GEVNTCOUNT (0), Data);
+  /* enable device interrupts */
+  MmioWrite32 (DEVTEN, DEVTEN_CONNECTDONEEN | DEVTEN_USBRSTEN);
+  /* activate EP0 */
+  DwUsb3Ep0Activate (pcd);
+  /* start EP0 to receive SETUP packets */
+  DwUsb3Ep0OutStart (pcd);
+
+  /* enable EP0 OUT/IN in DALEPENA */
+  MmioWrite32 (DALEPENA, (1 << EP_OUT_IDX (0)) | (1 << EP_IN_IDX (0)));
+
+  /* set RUN/STOP bit */
+  MmioOr32 (DCTL, DCTL_RUN_STOP);
+}
+
+STATIC
+VOID
+DriverInit (
+  VOID
+  )
+{
+  usb3_pcd_t          *pcd = &gPcd;
+  usb3_pcd_ep_t       *ep;
+  EFI_STATUS          Status;
+
+  pcd->speed = USB_SPEED_UNKNOWN;
+
+  //
+  // init EP0
+  //
+  ep = &pcd->ep0;
+  ep->pcd = pcd;
+  ep->stopped = 1;
+  ep->is_in = 0;
+  ep->active = 0;
+  ep->phys = 0;
+  ep->num = 0;
+  ep->tx_fifo_num = 0;
+  ep->type = EPTYPE_CONTROL;
+  ep->maxburst = 0;
+  ep->maxpacket = USB3_MAX_EP0_SIZE;
+  ep->send_zlp = 0;
+  ep->req.length = 0;
+  ep->req.actual = 0;
+  pcd->ep0_req.length = 0;
+  pcd->ep0_req.actual = 0;
+
+  //
+  // init EP1 OUT
+  //
+  ep = &pcd->out_ep;
+  ep->pcd = pcd;
+  ep->stopped = 1;
+  ep->is_in = 0;
+  ep->active = 0;
+  ep->phys = USB3_BULK_OUT_EP << 1;
+  ep->num = 1;
+  ep->tx_fifo_num = 0;
+  //
+  // bulk ep is activated
+  //
+  ep->type = EPTYPE_BULK;
+  ep->maxburst = 0;
+  ep->maxpacket = USB3_MAX_PACKET_SIZE;
+  ep->send_zlp = 0;
+  ep->req.length = 0;
+  ep->req.actual = 0;
+
+  //
+  // init EP1 IN
+  //
+  ep = &pcd->in_ep;
+  ep->stopped = 1;
+  ep->is_in = 1;
+  ep->active = 0;
+  ep->phys = (USB3_BULK_IN_EP << 1) | 1;
+  ep->num = 1;
+  ep->tx_fifo_num = USB3_BULK_IN_EP;
+  //
+  // bulk ep is activated
+  //
+  ep->type = EPTYPE_BULK;
+  ep->maxburst = 0;
+  ep->maxpacket = USB3_MAX_PACKET_SIZE;
+  ep->send_zlp = 0;
+  ep->req.length = 0;
+  ep->req.actual = 0;
+
+  pcd->ep0state = EP0_IDLE;
+  pcd->ep0.maxpacket = USB3_MAX_EP0_SIZE;
+  pcd->ep0.type = EPTYPE_CONTROL;
+
+  Status = DmaAllocateBuffer (
+             EfiBootServicesData,
+             EFI_SIZE_TO_PAGES (sizeof (usb3_dma_desc_t) * 5),
+             (VOID *)&pcd->ep0_setup_desc
+             );
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  pcd->ep0_in_desc = pcd->ep0_setup_desc++;
+  pcd->ep0_out_desc = pcd->ep0_in_desc++;
+  pcd->in_ep.ep_desc = pcd->ep0_out_desc++;
+  pcd->out_ep.ep_desc = pcd->in_ep.ep_desc++;
+}
+
+STATIC
+VOID
+DwUsb3HandleUsbResetInterrupt (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb3_pcd_ep_t        *ep;
+
+  //
+  // clear stall on each EP
+  //
+  ep = &pcd->in_ep;
+  if (ep->xfer_started) {
+    if (ep->is_in) {
+      DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in);
+    } else {
+      DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out);
+    }
+  }
+  if (ep->stopped) {
+    if (ep->is_in) {
+      DwUsb3DepClearStall (EP_IN_IDX (ep->num));
+    } else {
+      DwUsb3DepClearStall (EP_OUT_IDX (ep->num));
+    }
+  }
+
+  ep = &pcd->out_ep;
+  if (ep->xfer_started) {
+    if (ep->is_in) {
+      DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in);
+    } else {
+      DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out);
+    }
+  }
+  if (ep->stopped) {
+    if (ep->is_in) {
+      DwUsb3DepClearStall (EP_IN_IDX (ep->num));
+    } else {
+      DwUsb3DepClearStall (EP_OUT_IDX (ep->num));
+    }
+  }
+
+  //
+  // set device address to 0
+  //
+  SET_DEVADDR (0);
+
+  pcd->ltm_enable = 0;
+  DEBUG ((DEBUG_INFO, "usb reset\n"));
+}
+
+STATIC
+UINT32
+DwUsb3GetDeviceSpeed (
+  IN usb3_pcd_t         *pcd
+  )
+{
+  UINT32                Data, Speed;
+
+  Data = MmioRead32 (DSTS);
+  switch (DSTS_GET_DEVSPD (Data)) {
+  case DEVSPD_HS_PHY_30MHZ_OR_60MHZ:
+    Speed = USB_SPEED_HIGH;
+    break;
+  case DEVSPD_FS_PHY_30MHZ_OR_60MHZ:
+  case DEVSPD_FS_PHY_48MHZ:
+    Speed = USB_SPEED_FULL;
+    break;
+  case DEVSPD_LS_PHY_6MHZ:
+    Speed = USB_SPEED_LOW;
+    break;
+  case DEVSPD_SS_PHY_125MHZ_OR_250MHZ:
+    Speed = USB_SPEED_SUPER;
+    break;
+  default:
+    DEBUG ((DEBUG_ERROR, "DwUsb3GetDeviceSpeed: invalid DSTS:0x%x\n", Data));
+    Speed = USB_SPEED_UNKNOWN;
+    break;
+  }
+  return Speed;
+}
+
+STATIC
+VOID
+DwUsb3PcdSetSpeed (
+  IN usb3_pcd_t         *pcd,
+  IN UINTN              speed
+  )
+{
+  //
+  // set the MPS of EP0 based on the connection speed
+  //
+  switch (speed) {
+  case USB_SPEED_SUPER:
+    pcd->ep0.maxpacket = 512;
+    pcd->in_ep.maxpacket = USB3_MAX_PACKET_SIZE;
+    pcd->out_ep.maxpacket = USB3_MAX_PACKET_SIZE;
+    break;
+  case USB_SPEED_HIGH:
+    pcd->ep0.maxpacket = 64;
+    pcd->in_ep.maxpacket = USB2_HS_MAX_PACKET_SIZE;
+    pcd->out_ep.maxpacket = USB2_HS_MAX_PACKET_SIZE;
+    break;
+  case USB_SPEED_FULL:
+    pcd->ep0.maxpacket = 64;
+    pcd->in_ep.maxpacket = USB2_FS_MAX_PACKET_SIZE;
+    pcd->out_ep.maxpacket = USB2_FS_MAX_PACKET_SIZE;
+    break;
+  default:
+    DEBUG ((DEBUG_ERROR, "invalid speed: %d\n", speed));
+    break;
+  }
+}
+
+STATIC
+VOID
+DwUsb3HandleConnectDoneInterrupt (
+  IN usb3_pcd_t         *pcd
+  )
+{
+  usb3_pcd_ep_t         *ep0 = &pcd->ep0;
+  UINT32                DiepCfg0, DoepCfg0, DiepCfg1, DoepCfg1;
+  UINT32                Speed;
+
+  ep0->stopped = 0;
+  Speed = (UINT32)DwUsb3GetDeviceSpeed (pcd);
+  pcd->speed = (UINT8)Speed;
+
+  DwUsb3PcdSetSpeed (pcd, Speed);
+  //
+  // set the MPS of EP0 based on the connection speed
+  //
+  DiepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL) |        \
+             EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY);
+  DiepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY |   \
+             EPCFG1_EP_DIR_IN;
+  DoepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL) |        \
+             EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY);
+  DoepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY;
+
+  switch (Speed) {
+  case USB_SPEED_SUPER:
+    DiepCfg0 |= EPCFG0_MPS (512);
+    DoepCfg0 |= EPCFG0_MPS (512);
+    break;
+  case USB_SPEED_HIGH:
+  case USB_SPEED_FULL:
+    DiepCfg0 |= EPCFG0_MPS (64);
+    DoepCfg0 |= EPCFG0_MPS (64);
+    break;
+  case USB_SPEED_LOW:
+    DiepCfg0 |= EPCFG0_MPS (8);
+    DoepCfg0 |= EPCFG0_MPS (8);
+    break;
+  default:
+    DEBUG ((
+      DEBUG_ERROR,
+      "DwUsb3HandleConnectDoneInterrupt: invalid speed %d\n",
+      Speed
+      ));
+    break;
+  }
+  DiepCfg0 |= EPCFG0_TXFNUM (ep0->tx_fifo_num);
+  //
+  // issue DEPCFG command to EP0 OUT
+  //
+  DwUsb3DepCfg (EP_OUT_IDX (0), DoepCfg0, DoepCfg1, 0);
+  //
+  // issue DEPCFG command to EP0 IN
+  //
+  DwUsb3DepCfg (EP_IN_IDX (0), DiepCfg0, DiepCfg1, 0);
+  pcd->state = USB3_STATE_DEFAULT;
+}
+
+STATIC
+VOID
+DwUsb3HandleDeviceInterrupt (
+  IN usb3_pcd_t       *pcd,
+  IN UINT32           Event
+  )
+{
+  switch (Event & GEVNT_DEVT_MASK) {
+  case GEVNT_DEVT_USBRESET:
+    DwUsb3HandleUsbResetInterrupt (pcd);
+    break;
+  case GEVNT_DEVT_CONNDONE:
+    DwUsb3HandleConnectDoneInterrupt (pcd);
+    break;
+  default:
+    DEBUG ((DEBUG_ERROR, "DwUsb3HandleDeviceInterrupt: invalid event\n"));
+    break;
+  }
+}
+
+STATIC
+usb3_pcd_ep_t *
+DwUsb3GetOutEndPoint (
+  IN usb3_pcd_t       *pcd,
+  IN UINT32           EndPointNum
+  )
+{
+  if (EndPointNum == 0) {
+    return &pcd->ep0;
+  }
+  return &pcd->out_ep;
+}
+
+STATIC
+usb3_pcd_ep_t *
+DwUsb3GetInEndPoint (
+  IN usb3_pcd_t       *pcd,
+  IN UINT32           EndPointNum
+  )
+{
+  if (EndPointNum == 0) {
+    return &pcd->ep0;
+  }
+  return &pcd->in_ep;
+}
+
+STATIC
+VOID
+EndPoint0DoStall (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb3_pcd_ep_t       *ep0 = &pcd->ep0;
+
+  //
+  // stall EP0 IN & OUT simultanelusly
+  //
+  ep0->is_in = 1;
+  DwUsb3DepSetStall (EP_IN_IDX (0));
+  ep0->is_in = 0;
+  DwUsb3DepSetStall (EP_OUT_IDX (0));
+  //
+  // prepare for the next setup transfer
+  //
+  ep0->stopped = 1;
+  pcd->ep0state = EP0_IDLE;
+  DwUsb3Ep0OutStart (pcd);
+}
+
+STATIC
+VOID
+EndPoint0ContinueTransfer (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_req_t   *req
+  )
+{
+  usb3_pcd_ep_t       *ep0 = &pcd->ep0;
+  usb3_dma_desc_t     *desc;
+  UINT64              desc_dma;
+  UINT8               tri;
+
+  //
+  // send a 0-byte length packet after the end of transfer
+  //
+  if (ep0->is_in) {
+    desc = pcd->ep0_in_desc;
+    desc_dma = (UINT64)pcd->ep0_in_desc;
+    //
+    // DMA descriptor setup
+    //
+    DwUsb3FillDesc (
+      desc,
+      (UINT64)req->bufdma,
+      0,
+      0,
+      TRBCTL_NORMAL,
+      DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST,
+      1
+      );
+    tri = DwUsb3DepStartXfer (EP_IN_IDX (0), desc_dma, 0);
+    ep0->tri_in = tri;
+  }
+}
+
+STATIC
+VOID
+EndPoint0CompleteRequest (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_req_t   *req,
+  IN usb3_dma_desc_t  *desc
+  )
+{
+  usb3_pcd_ep_t      *ep = &pcd->ep0;
+
+  if (req == NULL) {
+    return;
+  }
+
+  if ((pcd->ep0state == EP0_OUT_DATA_PHASE) ||
+      (pcd->ep0state == EP0_IN_DATA_PHASE)) {
+    if (ep->is_in) {
+      if (GET_DSCSTS_XFERCNT (desc->status) == 0) {
+        pcd->ep0.is_in = 0;
+        pcd->ep0state = EP0_OUT_WAIT_NRDY;
+      }
+    } else {
+      pcd->ep0.is_in = 1;
+      pcd->ep0state = EP0_IN_WAIT_NRDY;
+    }
+  }
+}
+
+STATIC
+VOID
+DwUsb3OsGetTrb (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_ep_t    *ep,
+  IN usb3_pcd_req_t   *req
+  )
+{
+  //
+  // If EP0, fill request with EP0 IN/OUT data TRB
+  //
+  if (ep == &pcd->ep0) {
+    if (ep->is_in) {
+      req->trb = pcd->ep0_in_desc;
+      req->trbdma = (UINT64)pcd->ep0_in_desc;
+    } else {
+      req->trb = pcd->ep0_out_desc;
+      req->trbdma = (UINT64)pcd->ep0_out_desc;
+    }
+  } else {
+    //
+    // fill request with TRB from the non-EP0 allocation
+    //
+    req->trb = ep->ep_desc;
+    req->trbdma = (UINT64)ep->ep_desc;
+  }
+}
+
+STATIC
+VOID
+DwUsb3EndPoint0StartTransfer (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_req_t   *req
+  )
+{
+  usb3_pcd_ep_t       *ep0 = &pcd->ep0;
+  usb3_dma_desc_t     *desc;
+  UINT64              desc_dma;
+  UINT32              desc_type, len;
+
+  //
+  // get the DMA descriptor (TRB) for this request
+  //
+  DwUsb3OsGetTrb (pcd, ep0, req);
+  desc = req->trb;
+  desc_dma = req->trbdma;
+
+  if (ep0->is_in) {
+    //
+    // start DMA on EP0 IN
+    // DMA Descriptor (TRB) setup
+    //
+    len = req->length;
+    if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
+      if (ep0->three_stage) {
+        desc_type = TRBCTL_STATUS_3;
+      } else {
+        desc_type = TRBCTL_STATUS_2;
+      }
+    } else {
+      desc_type = TRBCTL_CTLDATA_1ST;
+    }
+    DwUsb3FillDesc (
+      desc,
+      (UINT64)req->bufdma,
+      len,
+      0,
+      desc_type,
+      DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST,
+      1
+      );
+    //
+    // issue DEPSTRTXFER command to EP0 IN
+    //
+    ep0->tri_in = DwUsb3DepStartXfer (EP_IN_IDX (0), desc_dma, 0);
+  } else {
+    //
+    // start DMA on EP0 OUT
+    // DMA Descriptor (TRB) setup
+    //
+    len = ALIGN (req->length, ep0->maxpacket);
+    if (pcd->ep0state == EP0_OUT_STATUS_PHASE) {
+      if (ep0->three_stage) {
+        desc_type = TRBCTL_STATUS_3;
+      } else {
+        desc_type = TRBCTL_STATUS_2;
+      }
+    } else {
+      desc_type = TRBCTL_CTLDATA_1ST;
+    }
+    DwUsb3FillDesc (
+      desc,
+      (UINT64)req->bufdma,
+      len,
+      0,
+      desc_type,
+      DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST,
+      1
+      );
+    //
+    // issue DEPSTRTXFER command to EP0 OUT
+    //
+    ep0->tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (0), desc_dma, 0);
+  }
+}
+
+STATIC
+INTN
+DwUsb3EndPointXStartTransfer (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_ep_t    *ep
+  )
+{
+  usb3_pcd_req_t      *req = &ep->req;
+  usb3_dma_desc_t     *desc;
+  UINT64              desc_dma;
+  UINT32              len;
+
+  //
+  // get the TRB for this request
+  //
+  DwUsb3OsGetTrb (pcd, ep, req);
+  desc = req->trb;
+  desc_dma = req->trbdma;
+
+  if (ep->is_in) {
+    //
+    // For IN, TRB length is just xfer length
+    //
+    len = req->length;
+    if (ep->xfer_started && !(desc->control & DSCCTL_HWO)) {
+      DEBUG ((DEBUG_INFO, "[%a] last tx succ, but not in 10s!\n", __func__));
+      ep->xfer_started = 0;
+    }
+  } else {
+    //
+    // For OUT, TRB length must be multiple of maxpacket
+    // must be power of 2, use cheap AND
+    //
+    len = (req->length + ep->maxpacket - 1) & ~(ep->maxpacket - 1);
+    req->length = len;
+  }
+  //
+  // DMA descriptor setup
+  //
+  DwUsb3FillDesc (
+    desc,
+    (UINT64)req->bufdma,
+    len,
+    0,
+    TRBCTL_NORMAL,
+    DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST,
+    1
+    );
+  if (ep->is_in) {
+    //
+    // start DMA on EPn IN
+    //
+    if (ep->xfer_started) {
+      //
+      // issue DEPUPDTXFER command to EP
+      //
+      DwUsb3DepUpdateXfer (EP_IN_IDX (ep->num), ep->tri_in);
+    } else {
+      ep->tri_in = DwUsb3DepStartXfer (EP_IN_IDX (ep->num), desc_dma, 0);
+      ep->xfer_started = 1;
+    }
+  } else {
+    //
+    // start DMA on EPn OUT
+    //
+    if (ep->xfer_started) {
+      //
+      // issue DEPUPDTXFER command to EP
+      //
+      DwUsb3DepUpdateXfer (EP_OUT_IDX (ep->num), ep->tri_out);
+    } else {
+      ep->tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (ep->num), desc_dma, 0);
+      ep->xfer_started = 1;
+    }
+  }
+  if (ep->is_in) {
+    UINT32       count = 0;
+    //
+    // wait until send complete
+    //
+    while ((desc->control & DSCCTL_HWO) && (count < 1000000)) {
+      MicroSecondDelay (10);
+      count++;
+    }
+    if (count >= 1000000) {
+      DEBUG ((DEBUG_INFO, "[%a]: ep%d transfer timeout!\n", __func__, ep->num));
+      DEBUG ((
+        DEBUG_INFO,
+        "please disconnect then connect USB cable again to recovery!\n"
+        ));
+      return -1;
+    }
+    ep->xfer_started = 0;
+  }
+  return 0;
+}
+
+STATIC
+VOID
+SetupInStatusPhase (
+  IN usb3_pcd_t       *pcd,
+  IN VOID             *buf
+  )
+{
+  usb3_pcd_ep_t       *ep0 = &pcd->ep0;
+
+  if (pcd->ep0state == EP0_STALL)
+    return;
+
+  ep0->is_in = 1;
+  pcd->ep0state = EP0_IN_STATUS_PHASE;
+  pcd->ep0_req.bufdma = buf;
+  pcd->ep0_req.length = 0;
+  pcd->ep0_req.actual = 0;
+  DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req);
+}
+
+STATIC
+VOID
+SetupOutStatusPhase (
+  IN usb3_pcd_t       *pcd,
+  IN VOID             *buf
+  )
+{
+  usb3_pcd_ep_t       *ep0 = &pcd->ep0;
+
+  if (pcd->ep0state == EP0_STALL)
+    return;
+
+  ep0->is_in = 0;
+  pcd->ep0state = EP0_OUT_STATUS_PHASE;
+  pcd->ep0_req.bufdma = buf;
+  pcd->ep0_req.length = 0;
+  pcd->ep0_req.actual = 0;
+  DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req);
+}
+
+STATIC
+VOID
+DwUsb3HandleEndPoint0 (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_req_t   *req,
+  IN UINT32           event
+  )
+{
+  usb3_pcd_ep_t       *ep0 = &pcd->ep0;
+  usb3_dma_desc_t     *desc = NULL;
+  UINT32              byte_count, len;
+
+  switch (pcd->ep0state) {
+  case EP0_IN_DATA_PHASE:
+    if (req == NULL) {
+      req = &pcd->ep0_req;
+    }
+    desc = pcd->ep0_in_desc;
+
+    if (desc->control & DSCCTL_HWO) {
+      goto out;
+    }
+
+    if (GET_DSCSTS_TRBRSP (desc->status) == TRBRSP_SETUP_PEND) {
+      //
+      // start of a new control transfer
+      //
+      desc->status = 0;
+    }
+    byte_count = req->length - GET_DSCSTS_XFERCNT (desc->status);
+    req->actual += byte_count;
+    req->bufdma += byte_count;
+
+    if (req->actual < req->length) {
+      //
+      // IN CONTINUE, stall EP0
+      //
+      EndPoint0DoStall (pcd);
+    } else if (ep0->send_zlp) {
+      //
+      // CONTINUE TRANSFER IN ZLP
+      //
+      EndPoint0ContinueTransfer (pcd, req);
+      ep0->send_zlp = 0;
+    } else {
+      //
+      // COMPLETE IN TRANSFER
+      //
+      EndPoint0CompleteRequest (pcd, req, desc);
+    }
+    break;
+  case EP0_OUT_DATA_PHASE:
+    if (req == NULL) {
+      req = &pcd->ep0_req;
+    }
+    desc = pcd->ep0_out_desc;
+
+    if (desc->control & DSCCTL_HWO) {
+      goto out;
+    }
+
+    if (GET_DSCSTS_TRBRSP (desc->status) == TRBRSP_SETUP_PEND) {
+      //
+      // start of a new control transfer
+      //
+      desc->status = 0;
+    }
+    len = (req->length + ep0->maxpacket - 1) & ~(ep0->maxpacket - 1);
+    byte_count = len - GET_DSCSTS_XFERCNT (desc->status);
+    req->actual += byte_count;
+    req->bufdma += byte_count;
+
+    if (req->actual < req->length) {
+      //
+      // IN CONTINUE, stall EP0
+      //
+      EndPoint0DoStall (pcd);
+    } else if (ep0->send_zlp) {
+      //
+      // CONTINUE TRANSFER IN ZLP
+      //
+      EndPoint0ContinueTransfer (pcd, req);
+      ep0->send_zlp = 0;
+    } else {
+      //
+      // COMPLETE IN TRANSFER
+      //
+      EndPoint0CompleteRequest (pcd, req, desc);
+    }
+    break;
+  case EP0_IN_WAIT_NRDY:
+    if (ep0->is_in) {
+      SetupInStatusPhase (pcd, gEndPoint0SetupPacket);
+    } else {
+      ASSERT (0);
+    }
+    break;
+  case EP0_OUT_WAIT_NRDY:
+    if (!ep0->is_in) {
+      SetupOutStatusPhase (pcd, gEndPoint0SetupPacket);
+    } else {
+      ASSERT (0);
+    }
+    break;
+  case EP0_IN_STATUS_PHASE:
+    if (ep0->is_in) {
+      desc = pcd->ep0_in_desc;
+    } else {
+      ASSERT (0);
+    }
+    EndPoint0CompleteRequest (pcd, req, desc);
+    pcd->ep0state = EP0_IDLE;
+    ep0->stopped = 1;
+    ep0->is_in = 0;  // OUT for next SETUP
+    //
+    // prepare for more SETUP packets
+    //
+    DwUsb3Ep0OutStart (pcd);
+    break;
+  case EP0_OUT_STATUS_PHASE:
+    if (!ep0->is_in) {
+      desc = pcd->ep0_out_desc;
+    } else {
+      ASSERT (0);
+    }
+    EndPoint0CompleteRequest (pcd, req, desc);
+    pcd->ep0state = EP0_IDLE;
+    ep0->stopped = 1;
+    ep0->is_in = 0;  // OUT for next SETUP
+    //
+    // prepare for more SETUP packets
+    //
+    DwUsb3Ep0OutStart (pcd);
+    break;
+  case EP0_STALL:
+    break;
+  case EP0_IDLE:
+    break;
+  default:
+    DEBUG ((DEBUG_ERROR, "%a: invalid state %d\n", __func__, pcd->ep0state));
+    break;
+  }
+out:
+  return;
+}
+
+STATIC
+usb3_pcd_ep_t *
+Addr2EndPoint (
+  IN usb3_pcd_t       *pcd,
+  IN UINT16           index
+  )
+{
+  UINT32              ep_num;
+
+  ep_num = UE_GET_ADDR (index);
+  if (ep_num == 0) {
+    return &pcd->ep0;
+  } else {
+    if (UE_GET_DIR (index) == UE_DIR_IN) {
+      return &pcd->in_ep;
+    }
+    return &pcd->out_ep;
+  }
+}
+
+STATIC
+VOID
+DwUsb3DoGetStatus (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t   *ctrl = &gEndPoint0SetupPacket->req;
+  UINT8                  *status = gEndPoint0StatusBuf;
+  usb3_pcd_ep_t          *ep;
+
+  if (ctrl->wLength != 2) {
+    EndPoint0DoStall (pcd);
+    return;
+  }
+
+  switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) {
+  case UT_DEVICE:
+    *status = 0;   // bus powered
+    if (pcd->speed == USB_SPEED_SUPER) {
+      if (pcd->state == USB3_STATE_CONFIGURED) {
+        if (MmioRead32 (DCTL) & DCTL_INIT_U1_EN) {
+          *status |= 1 << 2;
+        }
+        if (MmioRead32 (DCTL) & DCTL_INIT_U2_EN) {
+          *status |= 1 << 3;
+        }
+        *status |= (UINT8)(pcd->ltm_enable << 4);
+      }
+    }
+    *(status + 1) = 0;
+    break;
+  case UT_INTERFACE:
+    *status = 0;
+    *(status + 1) = 0;
+    break;
+  case UT_ENDPOINT:
+    ep = Addr2EndPoint (pcd, ctrl->wIndex);
+    *status = ep->stopped;
+    *(status + 1) = 0;
+    break;
+  default:
+    EndPoint0DoStall (pcd);
+    return;
+  }
+  pcd->ep0_req.bufdma = (UINT64 *)status;
+  pcd->ep0_req.length = 2;
+  pcd->ep0_req.actual = 0;
+  DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req);
+}
+
+STATIC
+VOID
+DoClearHalt (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_ep_t    *ep
+  )
+{
+  if (ep->is_in) {
+    DwUsb3DepClearStall (EP_IN_IDX (ep->num));
+  } else {
+    DwUsb3DepClearStall (EP_OUT_IDX (ep->num));
+  }
+  if (ep->stopped) {
+    ep->stopped = 0;
+  }
+}
+
+STATIC
+VOID
+Usb3PcdEpEnable (
+  IN usb3_pcd_t        *pcd,
+  IN usb3_pcd_ep_t     *ep
+  )
+{
+  //
+  // activate the EP
+  //
+  ep->stopped = 0;
+  ep->xfer_started = 0;
+  ep->ep_desc->control = 0;
+  ep->ep_desc->status = 0;
+  //
+  // set initial data pid.
+  //
+  if (ep->type == EPTYPE_BULK) {
+    ep->data_pid_start = 0;
+  }
+  DwUsb3EpActivate (pcd, ep);
+}
+
+STATIC
+VOID
+DwUsb3DoClearFeature (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t  *ctrl = &gEndPoint0SetupPacket->req;
+  usb3_pcd_ep_t  *ep;
+
+  switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) {
+  case UT_DEVICE:
+    switch (ctrl->wValue) {
+    case UF_U1_ENABLE:
+      if ((pcd->speed != USB_SPEED_SUPER) ||
+          (pcd->state != USB3_STATE_CONFIGURED)) {
+        EndPoint0DoStall (pcd);
+        return;
+      }
+      MmioAnd32 (DCTL, ~DCTL_INIT_U1_EN);
+      break;
+    case UF_U2_ENABLE:
+      if ((pcd->speed != USB_SPEED_SUPER) ||
+          (pcd->state != USB3_STATE_CONFIGURED)) {
+        EndPoint0DoStall (pcd);
+        return;
+      }
+      MmioAnd32 (DCTL, ~DCTL_INIT_U2_EN);
+      break;
+    case UF_LTM_ENABLE:
+      if ((pcd->speed != USB_SPEED_SUPER) ||
+          (pcd->state != USB3_STATE_CONFIGURED) ||
+          (ctrl->wIndex != 0)) {
+        EndPoint0DoStall (pcd);
+        return;
+      }
+      pcd->ltm_enable = 0;
+      break;
+    default:
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    break;
+  case UT_INTERFACE:
+    if (ctrl->wValue) {
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    break;
+  case UT_ENDPOINT:
+    ep = Addr2EndPoint (pcd, ctrl->wIndex);
+    if (ctrl->wValue != UF_ENDPOINT_HALT) {
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    DoClearHalt (pcd, ep);
+    break;
+  default:
+    DEBUG ((DEBUG_ERROR, "invalid bmRequestType :%d\n", UT_GET_RECIPIENT (ctrl->bmRequestType)));
+    break;
+  }
+  pcd->ep0.is_in = 1;
+  pcd->ep0state = EP0_IN_WAIT_NRDY;
+}
+
+STATIC
+VOID
+DwUsb3DoSetFeature (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t  *ctrl = &gEndPoint0SetupPacket->req;
+  usb3_pcd_ep_t  *ep;
+
+  switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) {
+  case UT_DEVICE:
+    switch (ctrl->wValue) {
+    case UF_DEVICE_REMOTE_WAKEUP:
+      break;
+    case UF_TEST_MODE:
+      pcd->test_mode_nr = ctrl->wIndex >> 8;
+      pcd->test_mode = 1;
+      break;
+    case UF_U1_ENABLE:
+      if ((pcd->speed != USB_SPEED_SUPER) ||
+          (pcd->state != USB3_STATE_CONFIGURED)) {
+        EndPoint0DoStall (pcd);
+        return;
+      }
+      MmioOr32 (DCTL, DCTL_INIT_U1_EN);
+      break;
+    case UF_U2_ENABLE:
+      if ((pcd->speed != USB_SPEED_SUPER) ||
+          (pcd->state != USB3_STATE_CONFIGURED)) {
+        EndPoint0DoStall (pcd);
+        return;
+      }
+      MmioOr32 (DCTL, DCTL_INIT_U2_EN);
+      break;
+    case UF_LTM_ENABLE:
+      if ((pcd->speed != USB_SPEED_SUPER) ||
+          (pcd->state != USB3_STATE_CONFIGURED) ||
+          (ctrl->wIndex != 0)) {
+        EndPoint0DoStall (pcd);
+        return;
+      }
+      pcd->ltm_enable = 1;
+      break;
+    default:
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    break;
+  case UT_INTERFACE:
+    if (ctrl->wValue) {
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    break;
+  case UT_ENDPOINT:
+    ep = Addr2EndPoint (pcd, ctrl->wIndex);
+    if (ctrl->wValue != UF_ENDPOINT_HALT) {
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    ep->stopped = 1;
+    if (ep->is_in) {
+      DwUsb3DepClearStall (EP_IN_IDX (ep->num));
+    } else {
+      DwUsb3DepClearStall (EP_OUT_IDX (ep->num));
+    }
+    break;
+  default:
+    DEBUG ((DEBUG_ERROR, "invalid bmRequestType %d\n", UT_GET_RECIPIENT (ctrl->bmRequestType)));
+    break;
+  }
+  pcd->ep0.is_in = 1;
+  pcd->ep0state = EP0_IN_WAIT_NRDY;
+}
+
+STATIC
+VOID
+DwUsb3DoSetAddress (
+  IN usb3_pcd_t          *pcd
+  )
+{
+  usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req;
+
+  if (ctrl->bmRequestType == UT_DEVICE) {
+    SET_DEVADDR (ctrl->wValue);
+    pcd->ep0.is_in = 1;
+    pcd->ep0state = EP0_IN_WAIT_NRDY;
+    if (ctrl->wValue) {
+      pcd->state = USB3_STATE_ADDRESSED;
+    } else {
+      pcd->state = USB3_STATE_DEFAULT;
+    }
+  }
+}
+
+STATIC
+VOID
+DwUsb3DoGetConfig (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t  *ctrl = &gEndPoint0SetupPacket->req;
+  UINT8  *status = gEndPoint0StatusBuf;
+
+  if (ctrl->bmRequestType != (UT_READ | UT_STANDARD | UT_DEVICE)) {
+    EndPoint0DoStall (pcd);
+    return;
+  }
+  //
+  // Notify host the current config value
+  //
+  *status = pcd->new_config;
+  pcd->ep0_req.bufdma = (UINT64 *)status;
+  pcd->ep0_req.length = 1;
+  pcd->ep0_req.actual = 0;
+  DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req);
+}
+
+STATIC
+VOID
+DwUsb3DoSetConfig (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t  *ctrl = &gEndPoint0SetupPacket->req;
+  UINT16  wvalue = ctrl->wValue;
+  usb3_pcd_ep_t  *ep;
+
+  if (ctrl->bmRequestType != (UT_WRITE | UT_STANDARD | UT_DEVICE)) {
+    EndPoint0DoStall (pcd);
+    return;
+  }
+
+  if (!wvalue || (wvalue == CONFIG_VALUE)) {
+    pcd->new_config = (UINT8)wvalue;
+    //
+    // set new configuration
+    //
+    if (wvalue) {
+      //
+      // activate bulk in endpoint
+      //
+      ep = &pcd->in_ep;
+      Usb3PcdEpEnable (pcd, ep);
+      //
+      // activate bulk out endpoint
+      //
+      ep = &pcd->out_ep;
+      Usb3PcdEpEnable (pcd, ep);
+      pcd->state = USB3_STATE_CONFIGURED;
+      {
+        //
+        // prepare for EP1 OUT
+        //
+        usb3_pcd_ep_t                 *ep = &pcd->out_ep;
+        usb3_pcd_req_t                *req = &ep->req;
+
+        //
+        // AndroidFast App will free the rx buffer.
+        //
+        gRxBuf = AllocatePool (DATA_SIZE);
+        ASSERT (gRxBuf != NULL);
+        WriteBackDataCacheRange (gRxBuf, DATA_SIZE);
+        req->bufdma = (UINT64 *)gRxBuf;
+        if (mDataBufferSize == 0) {
+          req->length = CMD_SIZE;
+        } else if (mDataBufferSize > DATA_SIZE) {
+          req->length = DATA_SIZE;
+          mDataBufferSize = mDataBufferSize - DATA_SIZE;
+        } else if (mDataBufferSize > CMD_SIZE) {
+          req->length = CMD_SIZE;
+          mDataBufferSize = mDataBufferSize - CMD_SIZE;
+        } else {
+          req->length = mDataBufferSize;
+          mDataBufferSize = 0;
+        }
+        DwUsb3EndPointXStartTransfer (pcd, ep);
+      }
+    } else {
+      pcd->state = USB3_STATE_ADDRESSED;
+    }
+    pcd->ep0.is_in = 1;
+    pcd->ep0state = EP0_IN_WAIT_NRDY;
+  } else {
+    EndPoint0DoStall (pcd);
+  }
+}
+
+STATIC
+VOID
+DwUsb3DoGetDescriptor (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t  *ctrl = &gEndPoint0SetupPacket->req;
+  UINT8                 dt = ctrl->wValue >> 8;
+  UINT8                 index = (UINT8)ctrl->wValue;
+  UINT16                len = ctrl->wLength;
+  UINT8                 *buf = gEndPoint0StatusBuf;
+  UINT16                value = 0;
+  EFI_USB_STRING_DESCRIPTOR        *Descriptor = NULL;
+
+  if (ctrl->bmRequestType != (UT_READ | UT_STANDARD | UT_DEVICE)) {
+    EndPoint0DoStall (pcd);
+    return;
+  }
+
+  switch (dt) {
+  case UDESC_DEVICE:
+    {
+      struct usb_device_descriptor  *dev = &gDwUsb3DevDesc;
+      dev->bLength = sizeof (struct usb_device_descriptor);
+      dev->bDescriptorType = UDESC_DEVICE;
+      dev->bDeviceClass = 0;
+      dev->bDeviceSubClass = 0;
+      dev->bDeviceProtocol = 0;
+      if (pcd->speed == USB_SPEED_SUPER) {
+        dev->bcdUSB = 0x300;
+        //
+        // 2^9 = 512
+        //
+        dev->bMaxPacketSize0 = 9;
+      } else {
+        dev->bcdUSB = 0x0200;
+        dev->bMaxPacketSize0 = 0x40;
+      }
+      dev->idVendor = usb_port_activity_config.idVendor;
+      dev->idProduct = usb_port_activity_config.idProduct;
+      dev->bcdDevice = 0x0100;
+      dev->iManufacturer = STRING_MANUFACTURER;
+      dev->iProduct = STRING_PRODUCT;
+      dev->iSerialNumber = STRING_SERIAL;
+      dev->bNumConfigurations = 1;
+      value = sizeof (struct usb_device_descriptor);
+      CopyMem ((void *)buf, (void *)dev, value);
+    }
+    break;
+  case UDESC_DEVICE_QUALIFIER:
+    {
+      struct usb_qualifier_descriptor   *qual = (struct usb_qualifier_descriptor *)buf;
+      struct usb_device_descriptor *dev = &gDwUsb3DevDesc;
+
+      qual->bLength = sizeof (*qual);
+      qual->bDescriptorType = UDESC_DEVICE_QUALIFIER;
+      qual->bcdUSB = dev->bcdUSB;
+      qual->bDeviceClass = dev->bDeviceClass;
+      qual->bDeviceSubClass = dev->bDeviceSubClass;
+      qual->bDeviceProtocol = dev->bDeviceProtocol;
+      qual->bMaxPacketSize0 = dev->bMaxPacketSize0;
+      qual->bNumConfigurations = 1;
+      qual->bRESERVED = 0;
+      value = sizeof (struct usb_qualifier_descriptor);
+    }
+    break;
+
+  case UDESC_CONFIG:
+    {
+      struct usb_config_descriptor    *config = (struct usb_config_descriptor *)buf;
+
+      config->bLength = sizeof (*config);
+      config->bDescriptorType = UDESC_CONFIG;
+      config->bNumInterfaces = 1;
+      config->bConfigurationValue = 1;
+      config->iConfiguration = 0;
+      config->bmAttributes = USB_CONFIG_ATT_ONE;
+
+      if (pcd->speed == USB_SPEED_SUPER) {
+        config->bMaxPower = 0x50;
+      } else {
+        config->bMaxPower = 0x80;
+      }
+      buf += sizeof (*config);
+
+      intf.bInterfaceSubClass = usb_port_activity_config.bInterfaceSubClass;
+      intf.bInterfaceProtocol = usb_port_activity_config.bInterfaceProtocol;
+      CopyMem ((void *)buf, (void *)&intf, sizeof (intf));
+      buf += sizeof (intf);
+
+      switch (pcd->speed) {
+      case USB_SPEED_SUPER:
+        CopyMem (buf, &ss_bulk_in, sizeof (ss_bulk_in));
+        buf += sizeof (ss_bulk_in);
+        CopyMem (buf, &ep_comp, sizeof (ep_comp));
+        buf += sizeof (ep_comp);
+        CopyMem (buf, &ss_bulk_out, sizeof (ss_bulk_out));
+        buf += sizeof (ss_bulk_out);
+        CopyMem (buf, &ep_comp, sizeof (ep_comp));
+
+        config->wTotalLength = sizeof (*config) + sizeof (intf) + sizeof (ss_bulk_in) +
+                               sizeof (ep_comp) + sizeof (ss_bulk_out) + sizeof (ep_comp);
+        break;
+
+      default: // HS/FS
+        {
+          struct usb_endpoint_descriptor  *endp = (struct usb_endpoint_descriptor *)buf;
+
+          CopyMem (buf, &hs_bulk_in, sizeof (hs_bulk_in));
+          (endp++)->wMaxPacketSize = pcd->in_ep.maxpacket;
+          buf += sizeof (hs_bulk_in);
+          CopyMem (buf, &hs_bulk_out, sizeof (hs_bulk_out));
+          endp->wMaxPacketSize = pcd->out_ep.maxpacket;
+          config->wTotalLength = sizeof (*config) + sizeof (intf) + sizeof (hs_bulk_in) +
+                                 sizeof (hs_bulk_out);
+          break;
+        }
+      }
+      value = config->wTotalLength;
+    }
+    break;
+
+  case UDESC_STRING:
+    {
+      switch (index) {
+      case STRING_LANGUAGE:
+        Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf;
+        ASSERT (Descriptor != NULL);
+        Descriptor->Length = LANG_LENGTH * sizeof (CHAR16);
+        Descriptor->DescriptorType = USB_DESC_TYPE_STRING;
+        DwUsb->GetLang (Descriptor->String, &Descriptor->Length);
+        value = Descriptor->Length;
+        break;
+      case STRING_MANUFACTURER:
+        Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf;
+        ASSERT (Descriptor != NULL);
+        Descriptor->Length = MANU_FACTURER_STRING_LENGTH * sizeof (CHAR16);
+        Descriptor->DescriptorType = USB_DESC_TYPE_STRING;
+        DwUsb->GetManuFacturer (Descriptor->String, &Descriptor->Length);
+        value = Descriptor->Length;
+        break;
+      case STRING_PRODUCT:
+        Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf;
+        ASSERT (Descriptor != NULL);
+        Descriptor->Length = PRODUCT_STRING_LENGTH * sizeof (CHAR16);
+        Descriptor->DescriptorType = USB_DESC_TYPE_STRING;
+        DwUsb->GetProduct (Descriptor->String, &Descriptor->Length);
+        value = Descriptor->Length;
+        break;
+      case STRING_SERIAL:
+        Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf;
+        ASSERT (Descriptor != NULL);
+        Descriptor->Length = SERIAL_STRING_LENGTH * sizeof (CHAR16);
+        Descriptor->DescriptorType = USB_DESC_TYPE_STRING;
+        DwUsb->GetSerialNo (Descriptor->String, &Descriptor->Length);
+        value = Descriptor->Length;
+        break;
+      default:
+        EndPoint0DoStall (pcd);
+        break;
+      }
+    }
+    break;
+
+  case UDESC_BOS:
+    if (pcd->speed != USB_SPEED_SUPER) {
+      EndPoint0DoStall (pcd);
+      return;
+    }
+    value = bos.wTotalLength;
+    CopyMem (buf, &bos, sizeof (bos));
+    buf += sizeof (bos);
+    CopyMem (buf, &cap1, sizeof (cap1));
+    buf += sizeof (cap1);
+    CopyMem (buf, &cap2, sizeof (cap2));
+    buf += sizeof (cap2);
+    CopyMem (buf, &cap3, sizeof (cap3));
+    break;
+  default:
+    EndPoint0DoStall (pcd);
+    return;
+  }
+  pcd->ep0_req.bufdma = (UINT64 *)gEndPoint0StatusBuf;
+  pcd->ep0_req.length = value < len ? value : len;
+  pcd->ep0_req.actual = 0;
+  DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req);
+}
+
+STATIC
+VOID
+DwUsb3DoSetup (
+  IN usb3_pcd_t       *pcd
+  )
+{
+  usb_device_request_t  *ctrl = &gEndPoint0SetupPacket->req;
+  usb3_pcd_ep_t         *ep0 = &pcd->ep0;
+  UINT16                wLength;
+
+  wLength = ctrl->wLength;
+  ep0->stopped = 0;
+  ep0->three_stage = 1;
+  if (ctrl->bmRequestType & UE_DIR_IN) {
+    ep0->is_in = 1;
+    pcd->ep0state = EP0_IN_DATA_PHASE;
+  } else {
+    ep0->is_in = 0;
+    pcd->ep0state = EP0_OUT_DATA_PHASE;
+  }
+
+  if (wLength == 0) {
+    ep0->is_in = 1;
+    pcd->ep0state = EP0_IN_WAIT_NRDY;
+    ep0->three_stage = 0;
+  }
+  if (UT_GET_TYPE (ctrl->bmRequestType) != UT_STANDARD) {
+    EndPoint0DoStall (pcd);
+    return;
+  }
+
+  switch (ctrl->bRequest) {
+  case UR_GET_STATUS:
+    DwUsb3DoGetStatus (pcd);
+    break;
+  case UR_CLEAR_FEATURE:
+    DwUsb3DoClearFeature (pcd);
+    break;
+  case UR_SET_FEATURE:
+    DwUsb3DoSetFeature (pcd);
+    break;
+  case UR_SET_ADDRESS:
+    DwUsb3DoSetAddress (pcd);
+    break;
+  case UR_SET_CONFIG:
+    DwUsb3DoSetConfig (pcd);
+    MmioOr32 (DCTL, DCTL_ACCEPT_U1_EN);
+    MmioOr32 (DCTL, DCTL_ACCEPT_U2_EN);
+    DEBUG ((DEBUG_INFO, "enum done"));
+    pcd->ltm_enable = 0;
+    break;
+  case UR_GET_CONFIG:
+    DwUsb3DoGetConfig (pcd);
+    break;
+  case UR_GET_DESCRIPTOR:
+    DwUsb3DoGetDescriptor (pcd);
+    break;
+  case UR_SET_SEL:
+    //
+    // for now this is a no-op
+    //
+    pcd->ep0_req.bufdma = (UINT64 *)gEndPoint0StatusBuf;
+    pcd->ep0_req.length = USB3_STATUS_BUF_SIZE;
+    pcd->ep0_req.actual = 0;
+    ep0->send_zlp = 0;
+    DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req);
+    break;
+  default:
+    EndPoint0DoStall (pcd);
+    break;
+  }
+}
+
+STATIC
+VOID
+DwUsb3OsHandleEndPoint0 (
+  IN usb3_pcd_t       *pcd,
+  IN UINT32           event
+  )
+{
+  if (pcd->ep0state == EP0_IDLE) {
+    DwUsb3DoSetup (pcd);
+  } else {
+    DwUsb3HandleEndPoint0 (pcd, NULL, event);
+  }
+}
+
+STATIC
+VOID
+DwUsb3RequestDone (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_ep_t    *ep,
+  IN usb3_pcd_req_t   *req,
+  IN UINTN            status
+  )
+{
+  if (ep != &pcd->ep0) {
+    req->trb = NULL;
+  }
+  if (req->complete) {
+    req->complete (req->actual, status);
+  } else {
+    if (!ep->is_in) {
+      ASSERT (req->actual <= req->length);
+      InvalidateDataCacheRange (gRxBuf, req->actual);
+      mDataReceivedCallback (req->actual, gRxBuf);
+    }
+  }
+  req->actual = 0;
+}
+
+STATIC
+VOID
+DwUsb3EndPointcompleteRequest (
+  IN usb3_pcd_t       *pcd,
+  IN usb3_pcd_ep_t    *ep,
+  IN UINT32           event
+  )
+{
+  usb3_pcd_req_t           *req = &ep->req;
+  usb3_dma_desc_t          *desc = req->trb;
+  UINT32 byte_count;
+
+  ep->send_zlp = 0;
+  if (!desc) {
+    return;
+  }
+
+  if (desc->control & DSCCTL_HWO) {
+    return;
+  }
+
+  if (ep->is_in) {
+    //
+    // IN ep
+    //
+    if (GET_DSCSTS_XFERCNT (desc->status) == 0) {
+      req->actual += req->length;
+    }
+    //
+    // reset IN tri
+    //
+    ep->tri_in = 0;
+    //
+    // complete the IN request
+    //
+    DwUsb3RequestDone (pcd, ep, req, 0);
+  } else {
+    //
+    // OUT ep
+    //
+    byte_count = req->length - GET_DSCSTS_XFERCNT (desc->status);
+    req->actual += byte_count;
+    //
+    //req->bufdma += byte_count;
+    // reset OUT tri
+    //
+    ep->tri_out = 0;
+    //
+    // OUT transfer complete or not
+    // complete the OUT request
+    //
+    DwUsb3RequestDone (pcd, ep, req, 0);
+    {
+      //
+      // prepare for EP1 OUT
+      //
+      usb3_pcd_ep_t                 *ep = &pcd->out_ep;
+      usb3_pcd_req_t                *req = &ep->req;
+
+      ZeroMem (req, sizeof (usb3_pcd_req_t));
+      gRxBuf = AllocatePool (DATA_SIZE);
+      ASSERT (gRxBuf != NULL);
+      WriteBackDataCacheRange (gRxBuf, DATA_SIZE);
+      req->bufdma = (UINT64 *)gRxBuf;
+      if (mDataBufferSize == 0) {
+        req->length = CMD_SIZE;
+      } else if (mDataBufferSize > DATA_SIZE) {
+        req->length = DATA_SIZE;
+        mDataBufferSize = mDataBufferSize - DATA_SIZE;
+      } else if (mDataBufferSize > CMD_SIZE) {
+        req->length = CMD_SIZE;
+        mDataBufferSize = mDataBufferSize - CMD_SIZE;
+      } else {
+        req->length = mDataBufferSize;
+        mDataBufferSize = 0;
+      }
+      DwUsb3EndPointXStartTransfer (pcd, ep);
+    }
+  }
+}
+
+STATIC
+VOID
+DwUsb3HandleEndPointInterrupt (
+  IN usb3_pcd_t       *pcd,
+  IN UINTN            PhySep,
+  IN UINT32           event
+  )
+{
+  usb3_pcd_ep_t       *ep;
+  UINT32              epnum, is_in;
+
+  //
+  // Physical Out EPs are even, physical In EPs are odd
+  //
+  is_in = (UINT32)PhySep & 1;
+  epnum = ((UINT32)PhySep >> 1) & 0xF;
+
+  //
+  // Get the EP pointer
+  //
+  if (is_in) {
+    ep = DwUsb3GetInEndPoint (pcd, epnum);
+  } else {
+    ep = DwUsb3GetOutEndPoint (pcd, epnum);
+  }
+
+  switch (event & GEVNT_DEPEVT_INTTYPE_MASK) {
+  case GEVNT_DEPEVT_INTTYPE_XFER_CMPL:
+    ep->xfer_started = 0;
+    //
+    // complete the transfer
+    //
+    if (epnum == 0) {
+      DwUsb3OsHandleEndPoint0 (pcd, event);
+    } else {
+      DwUsb3EndPointcompleteRequest (pcd, ep, event);
+    }
+    break;
+  case GEVNT_DEPEVT_INTTYPE_XFER_IN_PROG:
+    break;
+  case GEVNT_DEPEVT_INTTYPE_XFER_NRDY:
+    if (epnum == 0) {
+      switch (pcd->ep0state) {
+      case EP0_IN_WAIT_NRDY:
+        if (is_in) {
+          DwUsb3OsHandleEndPoint0 (pcd, event);
+        } else {
+        }
+        break;
+      case EP0_OUT_WAIT_NRDY:
+        if (!is_in) {
+          DwUsb3OsHandleEndPoint0 (pcd, event);
+        } else {
+        }
+        break;
+      default:
+        break;
+      }
+    } else {
+    }
+    break;
+  default:
+    DEBUG ((
+      DEBUG_ERROR,
+      "invalid event %d\n",
+      event & GEVNT_DEPEVT_INTTYPE_MASK
+      ));
+    break;
+  }
+}
+
+STATIC
+UINTN
+DwUsb3HandleEvent (
+  VOID
+  )
+{
+  usb3_pcd_t          *pcd = &gPcd;
+  UINT32              Count, Index, Event, Intr;
+  UINT32              PhySep;
+
+  Count = GET_EVENTBUF_COUNT ();
+  //
+  // reset event buffer when it's full
+  //
+  if ((GEVNTCOUNT_EVNTCOUNT (Count) == GEVNTCOUNT_EVNTCOUNT_MASK) ||
+      (Count >= DWUSB3_EVENT_BUF_SIZE * sizeof (UINT32))) {
+    UPDATE_EVENTBUF_COUNT (Count);
+    Count = 0;
+  }
+
+  for (Index = 0; Index < Count; Index += sizeof (UINT32)) {
+    Event = DwUsb3GetEventBufEvent (DWUSB3_EVENT_BUF_SIZE << 2);
+    UPDATE_EVENTBUF_COUNT (sizeof (UINT32));
+    if (Event == 0) {
+      //
+      // ignore null events
+      //
+      continue;
+    }
+    if (Event & GEVNT_NON_EP) {
+      Intr = Event & GEVNT_INTTYPE_MASK;
+      if (Intr == GEVNT_INTTYPE (EVENT_DEV_INT)) {
+        DwUsb3HandleDeviceInterrupt (pcd, Event);
+      }
+    } else {
+      PhySep = (Event & GEVNT_DEPEVT_EPNUM_MASK) >> GEVNT_DEPEVT_EPNUM_SHIFT;
+      DwUsb3HandleEndPointInterrupt (pcd, PhySep, Event);
+    }
+  }
+  return 0;
+}
+
+STATIC
+VOID
+DwUsb3Poll (
+  IN EFI_EVENT        Event,
+  IN VOID            *Context
+  )
+{
+  if (DwUsb3HandleEvent ()) {
+    DEBUG ((DEBUG_ERROR, "error: exit from usb_poll\n"));
+    return;
+  }
+}
+
+EFI_STATUS
+EFIAPI
+DwUsb3Start (
+  IN USB_DEVICE_DESCRIPTOR   *DeviceDescriptor,
+  IN VOID                   **Descriptors,
+  IN USB_DEVICE_RX_CALLBACK   RxCallback,
+  IN USB_DEVICE_TX_CALLBACK   TxCallback
+  )
+{
+  EFI_STATUS             Status;
+  EFI_EVENT              TimerEvent;
+
+  Status = DmaAllocateBuffer (
+             EfiBootServicesData,
+             EFI_SIZE_TO_PAGES (DWUSB3_EVENT_BUF_SIZE << 2),
+             (VOID *)&gEventBuf
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (gEventBuf == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ZeroMem (gEventBuf, EFI_SIZE_TO_PAGES (DWUSB3_EVENT_BUF_SIZE << 2));
+  gEventPtr = gEventBuf;
+  DriverInit ();
+  DwUsb3Init ();
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  DwUsb3Poll,
+                  NULL,
+                  &TimerEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->SetTimer (
+                  TimerEvent,
+                  TimerPeriodic,
+                  DW_INTERRUPT_POLL_PERIOD
+                  );
+  ASSERT_EFI_ERROR (Status);
+  mDataReceivedCallback = RxCallback;
+  return Status;
+}
+
+EFI_STATUS
+DwUsb3Send (
+  IN        UINT8  EndpointIndex,
+  IN        UINTN  Size,
+  IN  CONST VOID  *Buffer
+  )
+{
+  usb3_pcd_t                    *pcd = &gPcd;
+  usb3_pcd_ep_t                 *ep = &pcd->in_ep;
+  usb3_pcd_req_t                *req = &ep->req;
+
+  WriteBackDataCacheRange ((VOID *)Buffer, Size);
+  req->bufdma = (UINT64 *)Buffer;
+  req->length = Size;
+  DwUsb3EndPointXStartTransfer (pcd, ep);
+  return EFI_SUCCESS;
+}
+
+USB_DEVICE_PROTOCOL mUsbDevice = {
+  DwUsb3Start,
+  DwUsb3Send
+};
+
+EFI_STATUS
+EFIAPI
+DwUsb3EntryPoint (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS      Status;
+
+  Status = DmaAllocateBuffer (
+             EfiBootServicesData,
+             EFI_SIZE_TO_PAGES (sizeof (usb_setup_pkt_t) * 5),
+             (VOID *)&gEndPoint0SetupPacket
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = DmaAllocateBuffer (
+             EfiBootServicesData,
+             EFI_SIZE_TO_PAGES (USB3_STATUS_BUF_SIZE * sizeof (UINT8)),
+             (VOID *)&gEndPoint0StatusBuf
+             );
+  if (EFI_ERROR (Status)) {
+    goto Out;
+  }
+  Status = gBS->LocateProtocol (&gDwUsbProtocolGuid, NULL, (VOID **) &DwUsb);
+  if (EFI_ERROR (Status)) {
+    goto OutProtocol;
+  }
+
+  Status = DwUsb->PhyInit(USB_DEVICE_MODE);
+  if (EFI_ERROR (Status)) {
+    goto OutProtocol;
+  }
+
+  Status = gBS->InstallProtocolInterface (
+                  &ImageHandle,
+                  &gUsbDeviceProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &mUsbDevice
+                  );
+  if (EFI_ERROR (Status)) {
+    goto OutProtocol;
+  }
+  return Status;
+
+OutProtocol:
+  DmaFreeBuffer (
+    EFI_SIZE_TO_PAGES (USB3_STATUS_BUF_SIZE * sizeof (UINT8)),
+    (VOID *)gEndPoint0StatusBuf
+    );
+Out:
+  DmaFreeBuffer (
+    EFI_SIZE_TO_PAGES (sizeof (usb_setup_pkt_t) * 5),
+    (VOID *)gEndPoint0SetupPacket
+    );
+  return Status;
+}
