From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001
From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com>
Date: Tue, 10 Oct 2023 14:33:42 +0000
Subject: Add submodule dependency files

Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
---
 roms/u-boot/drivers/usb/Kconfig                    |  136 +
 roms/u-boot/drivers/usb/cdns3/Kconfig              |   58 +
 roms/u-boot/drivers/usb/cdns3/Makefile             |   11 +
 roms/u-boot/drivers/usb/cdns3/cdns3-ti.c           |  195 ++
 roms/u-boot/drivers/usb/cdns3/core.c               |  499 ++++
 roms/u-boot/drivers/usb/cdns3/core.h               |  108 +
 roms/u-boot/drivers/usb/cdns3/debug.h              |  162 ++
 roms/u-boot/drivers/usb/cdns3/drd.c                |  302 +++
 roms/u-boot/drivers/usb/cdns3/drd.h                |  167 ++
 roms/u-boot/drivers/usb/cdns3/ep0.c                |  920 +++++++
 roms/u-boot/drivers/usb/cdns3/gadget-export.h      |   28 +
 roms/u-boot/drivers/usb/cdns3/gadget.c             | 2764 +++++++++++++++++++
 roms/u-boot/drivers/usb/cdns3/gadget.h             | 1339 ++++++++++
 roms/u-boot/drivers/usb/cdns3/host-export.h        |   28 +
 roms/u-boot/drivers/usb/cdns3/host.c               |   56 +
 roms/u-boot/drivers/usb/cdns3/trace.c              |   11 +
 roms/u-boot/drivers/usb/cdns3/trace.h              |   26 +
 roms/u-boot/drivers/usb/common/Makefile            |    8 +
 roms/u-boot/drivers/usb/common/common.c            |  100 +
 roms/u-boot/drivers/usb/common/fsl-dt-fixup.c      |  229 ++
 roms/u-boot/drivers/usb/common/fsl-errata.c        |  256 ++
 roms/u-boot/drivers/usb/dwc3/Kconfig               |   73 +
 roms/u-boot/drivers/usb/dwc3/Makefile              |   15 +
 roms/u-boot/drivers/usb/dwc3/core.c                | 1039 ++++++++
 roms/u-boot/drivers/usb/dwc3/core.h                | 1062 ++++++++
 roms/u-boot/drivers/usb/dwc3/dwc3-generic.c        |  466 ++++
 roms/u-boot/drivers/usb/dwc3/dwc3-meson-g12a.c     |  471 ++++
 roms/u-boot/drivers/usb/dwc3/dwc3-meson-gxl.c      |  425 +++
 roms/u-boot/drivers/usb/dwc3/dwc3-omap.c           |  453 ++++
 roms/u-boot/drivers/usb/dwc3/dwc3-uniphier.c       |  120 +
 roms/u-boot/drivers/usb/dwc3/ep0.c                 | 1115 ++++++++
 roms/u-boot/drivers/usb/dwc3/gadget.c              | 2684 +++++++++++++++++++
 roms/u-boot/drivers/usb/dwc3/gadget.h              |  107 +
 roms/u-boot/drivers/usb/dwc3/io.h                  |   55 +
 roms/u-boot/drivers/usb/dwc3/linux-compat.h        |   16 +
 roms/u-boot/drivers/usb/dwc3/samsung_usb_phy.c     |   78 +
 roms/u-boot/drivers/usb/dwc3/ti_usb_phy.c          |  319 +++
 roms/u-boot/drivers/usb/emul/Kconfig               |    8 +
 roms/u-boot/drivers/usb/emul/Makefile              |    9 +
 roms/u-boot/drivers/usb/emul/sandbox_flash.c       |  426 +++
 roms/u-boot/drivers/usb/emul/sandbox_hub.c         |  334 +++
 roms/u-boot/drivers/usb/emul/sandbox_keyb.c        |  246 ++
 roms/u-boot/drivers/usb/emul/usb-emul-uclass.c     |  304 +++
 roms/u-boot/drivers/usb/eth/Kconfig                |   65 +
 roms/u-boot/drivers/usb/eth/Makefile               |   14 +
 roms/u-boot/drivers/usb/eth/asix.c                 |  912 +++++++
 roms/u-boot/drivers/usb/eth/asix88179.c            |  921 +++++++
 roms/u-boot/drivers/usb/eth/lan75xx.c              |  316 +++
 roms/u-boot/drivers/usb/eth/lan78xx.c              |  479 ++++
 roms/u-boot/drivers/usb/eth/lan7x.c                |  500 ++++
 roms/u-boot/drivers/usb/eth/lan7x.h                |  237 ++
 roms/u-boot/drivers/usb/eth/mcs7830.c              |  945 +++++++
 roms/u-boot/drivers/usb/eth/r8152.c                | 1897 +++++++++++++
 roms/u-boot/drivers/usb/eth/r8152.h                |  683 +++++
 roms/u-boot/drivers/usb/eth/r8152_fw.c             | 1194 +++++++++
 roms/u-boot/drivers/usb/eth/smsc95xx.c             | 1080 ++++++++
 roms/u-boot/drivers/usb/eth/usb_ether.c            |  336 +++
 roms/u-boot/drivers/usb/gadget/Kconfig             |  243 ++
 roms/u-boot/drivers/usb/gadget/Makefile            |   48 +
 roms/u-boot/drivers/usb/gadget/at91_udc.c          | 1546 +++++++++++
 roms/u-boot/drivers/usb/gadget/at91_udc.h          |  167 ++
 roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c    | 1304 +++++++++
 roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h    |  320 +++
 roms/u-boot/drivers/usb/gadget/bcm_udc_otg.h       |   21 +
 roms/u-boot/drivers/usb/gadget/bcm_udc_otg_phy.c   |   55 +
 roms/u-boot/drivers/usb/gadget/ci_udc.c            | 1072 ++++++++
 roms/u-boot/drivers/usb/gadget/ci_udc.h            |  153 ++
 roms/u-boot/drivers/usb/gadget/composite.c         | 1531 +++++++++++
 roms/u-boot/drivers/usb/gadget/config.c            |  107 +
 roms/u-boot/drivers/usb/gadget/core.c              |  633 +++++
 roms/u-boot/drivers/usb/gadget/designware_udc.c    | 1021 +++++++
 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg.c      | 1199 +++++++++
 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_phy.c  |  101 +
 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_priv.h |   95 +
 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_regs.h |  296 +++
 .../drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c     | 1508 +++++++++++
 roms/u-boot/drivers/usb/gadget/ep0.c               |  643 +++++
 roms/u-boot/drivers/usb/gadget/ep0.h               |   25 +
 roms/u-boot/drivers/usb/gadget/epautoconf.c        |  324 +++
 roms/u-boot/drivers/usb/gadget/ether.c             | 2706 +++++++++++++++++++
 roms/u-boot/drivers/usb/gadget/f_dfu.c             |  844 ++++++
 roms/u-boot/drivers/usb/gadget/f_dfu.h             |   85 +
 roms/u-boot/drivers/usb/gadget/f_fastboot.c        |  560 ++++
 roms/u-boot/drivers/usb/gadget/f_mass_storage.c    | 2777 ++++++++++++++++++++
 roms/u-boot/drivers/usb/gadget/f_rockusb.c         |  934 +++++++
 roms/u-boot/drivers/usb/gadget/f_sdp.c             |  956 +++++++
 roms/u-boot/drivers/usb/gadget/f_thor.c            | 1034 ++++++++
 roms/u-boot/drivers/usb/gadget/f_thor.h            |  126 +
 roms/u-boot/drivers/usb/gadget/fotg210.c           |  964 +++++++
 roms/u-boot/drivers/usb/gadget/g_dnl.c             |  318 +++
 roms/u-boot/drivers/usb/gadget/gadget_chips.h      |  236 ++
 roms/u-boot/drivers/usb/gadget/max3420_udc.c       |  875 ++++++
 roms/u-boot/drivers/usb/gadget/ndis.h              |  217 ++
 roms/u-boot/drivers/usb/gadget/pxa25x_udc.c        | 2049 +++++++++++++++
 roms/u-boot/drivers/usb/gadget/pxa25x_udc.h        |  149 ++
 roms/u-boot/drivers/usb/gadget/pxa27x_udc.c        |  703 +++++
 roms/u-boot/drivers/usb/gadget/rndis.c             | 1314 +++++++++
 roms/u-boot/drivers/usb/gadget/rndis.h             |  268 ++
 roms/u-boot/drivers/usb/gadget/storage_common.c    |  617 +++++
 roms/u-boot/drivers/usb/gadget/u_os_desc.h         |  123 +
 roms/u-boot/drivers/usb/gadget/udc/Makefile        |   10 +
 roms/u-boot/drivers/usb/gadget/udc/udc-core.c      |  379 +++
 roms/u-boot/drivers/usb/gadget/udc/udc-uclass.c    |   64 +
 roms/u-boot/drivers/usb/gadget/usbstring.c         |   66 +
 roms/u-boot/drivers/usb/host/Kconfig               |  319 +++
 roms/u-boot/drivers/usb/host/Makefile              |   62 +
 roms/u-boot/drivers/usb/host/dwc2.c                | 1490 +++++++++++
 roms/u-boot/drivers/usb/host/dwc2.h                |  790 ++++++
 roms/u-boot/drivers/usb/host/dwc3-octeon-glue.c    |  395 +++
 roms/u-boot/drivers/usb/host/dwc3-of-simple.c      |  107 +
 roms/u-boot/drivers/usb/host/dwc3-sti-glue.c       |  253 ++
 roms/u-boot/drivers/usb/host/ehci-armada100.c      |   48 +
 roms/u-boot/drivers/usb/host/ehci-atmel.c          |  132 +
 roms/u-boot/drivers/usb/host/ehci-exynos.c         |  265 ++
 roms/u-boot/drivers/usb/host/ehci-faraday.c        |  144 +
 roms/u-boot/drivers/usb/host/ehci-fsl.c            |  315 +++
 roms/u-boot/drivers/usb/host/ehci-generic.c        |  226 ++
 roms/u-boot/drivers/usb/host/ehci-hcd.c            | 1839 +++++++++++++
 roms/u-boot/drivers/usb/host/ehci-marvell.c        |  234 ++
 roms/u-boot/drivers/usb/host/ehci-msm.c            |  150 ++
 roms/u-boot/drivers/usb/host/ehci-mx5.c            |  375 +++
 roms/u-boot/drivers/usb/host/ehci-mx6.c            |  775 ++++++
 roms/u-boot/drivers/usb/host/ehci-mxc.c            |  250 ++
 roms/u-boot/drivers/usb/host/ehci-mxs.c            |  174 ++
 roms/u-boot/drivers/usb/host/ehci-omap.c           |  413 +++
 roms/u-boot/drivers/usb/host/ehci-pci.c            |  178 ++
 roms/u-boot/drivers/usb/host/ehci-rmobile.c        |  129 +
 roms/u-boot/drivers/usb/host/ehci-spear.c          |   77 +
 roms/u-boot/drivers/usb/host/ehci-tegra.c          |  871 ++++++
 roms/u-boot/drivers/usb/host/ehci-vct.c            |   44 +
 roms/u-boot/drivers/usb/host/ehci-vf.c             |  361 +++
 roms/u-boot/drivers/usb/host/ehci-zynq.c           |   91 +
 roms/u-boot/drivers/usb/host/ehci.h                |  303 +++
 roms/u-boot/drivers/usb/host/ohci-at91.c           |   69 +
 roms/u-boot/drivers/usb/host/ohci-da8xx.c          |  180 ++
 roms/u-boot/drivers/usb/host/ohci-ep93xx.c         |   37 +
 roms/u-boot/drivers/usb/host/ohci-generic.c        |  203 ++
 roms/u-boot/drivers/usb/host/ohci-hcd.c            | 2243 ++++++++++++++++
 roms/u-boot/drivers/usb/host/ohci-lpc32xx.c        |  240 ++
 roms/u-boot/drivers/usb/host/ohci-pci.c            |   52 +
 roms/u-boot/drivers/usb/host/ohci.h                |  415 +++
 roms/u-boot/drivers/usb/host/r8a66597-hcd.c        |  899 +++++++
 roms/u-boot/drivers/usb/host/r8a66597.h            |  617 +++++
 roms/u-boot/drivers/usb/host/sl811-hcd.c           |  714 +++++
 roms/u-boot/drivers/usb/host/sl811.h               |  104 +
 roms/u-boot/drivers/usb/host/usb-sandbox.c         |  159 ++
 roms/u-boot/drivers/usb/host/usb-uclass.c          |  868 ++++++
 roms/u-boot/drivers/usb/host/utmi-armada100.c      |   80 +
 roms/u-boot/drivers/usb/host/xhci-brcm.c           |   98 +
 roms/u-boot/drivers/usb/host/xhci-dwc3.c           |  193 ++
 roms/u-boot/drivers/usb/host/xhci-exynos5.c        |  262 ++
 roms/u-boot/drivers/usb/host/xhci-fsl.c            |  216 ++
 roms/u-boot/drivers/usb/host/xhci-mem.c            |  867 ++++++
 roms/u-boot/drivers/usb/host/xhci-mtk.c            |  322 +++
 roms/u-boot/drivers/usb/host/xhci-mvebu.c          |  102 +
 roms/u-boot/drivers/usb/host/xhci-omap.c           |   91 +
 roms/u-boot/drivers/usb/host/xhci-pci.c            |   81 +
 .../drivers/usb/host/xhci-rcar-r8a779x_usb3_v3.h   |  643 +++++
 roms/u-boot/drivers/usb/host/xhci-rcar.c           |  167 ++
 roms/u-boot/drivers/usb/host/xhci-ring.c           |  955 +++++++
 roms/u-boot/drivers/usb/host/xhci.c                | 1585 +++++++++++
 roms/u-boot/drivers/usb/mtu3/Kconfig               |   44 +
 roms/u-boot/drivers/usb/mtu3/Makefile              |   11 +
 roms/u-boot/drivers/usb/mtu3/mtu3.h                |  424 +++
 roms/u-boot/drivers/usb/mtu3/mtu3_core.c           |  838 ++++++
 roms/u-boot/drivers/usb/mtu3/mtu3_dr.h             |   52 +
 roms/u-boot/drivers/usb/mtu3/mtu3_gadget.c         |  686 +++++
 roms/u-boot/drivers/usb/mtu3/mtu3_gadget_ep0.c     |  933 +++++++
 roms/u-boot/drivers/usb/mtu3/mtu3_host.c           |  141 +
 roms/u-boot/drivers/usb/mtu3/mtu3_hw_regs.h        |  515 ++++
 roms/u-boot/drivers/usb/mtu3/mtu3_plat.c           |  369 +++
 roms/u-boot/drivers/usb/mtu3/mtu3_qmu.c            |  508 ++++
 roms/u-boot/drivers/usb/mtu3/mtu3_qmu.h            |   37 +
 roms/u-boot/drivers/usb/musb-new/Kconfig           |  101 +
 roms/u-boot/drivers/usb/musb-new/Makefile          |   19 +
 roms/u-boot/drivers/usb/musb-new/am35x.c           |  704 +++++
 roms/u-boot/drivers/usb/musb-new/da8xx.c           |  354 +++
 roms/u-boot/drivers/usb/musb-new/linux-compat.h    |   26 +
 roms/u-boot/drivers/usb/musb-new/mt85xx.c          |  419 +++
 roms/u-boot/drivers/usb/musb-new/musb_core.c       | 2497 ++++++++++++++++++
 roms/u-boot/drivers/usb/musb-new/musb_core.h       |  589 +++++
 roms/u-boot/drivers/usb/musb-new/musb_debug.h      |   33 +
 roms/u-boot/drivers/usb/musb-new/musb_dma.h        |  150 ++
 roms/u-boot/drivers/usb/musb-new/musb_dsps.c       |  765 ++++++
 roms/u-boot/drivers/usb/musb-new/musb_gadget.c     | 2324 ++++++++++++++++
 roms/u-boot/drivers/usb/musb-new/musb_gadget.h     |  105 +
 roms/u-boot/drivers/usb/musb-new/musb_gadget_ep0.c | 1068 ++++++++
 roms/u-boot/drivers/usb/musb-new/musb_host.c       | 2393 +++++++++++++++++
 roms/u-boot/drivers/usb/musb-new/musb_host.h       |   90 +
 roms/u-boot/drivers/usb/musb-new/musb_io.h         |  101 +
 roms/u-boot/drivers/usb/musb-new/musb_regs.h       |  526 ++++
 roms/u-boot/drivers/usb/musb-new/musb_uboot.c      |  491 ++++
 roms/u-boot/drivers/usb/musb-new/musb_uboot.h      |   27 +
 roms/u-boot/drivers/usb/musb-new/omap2430.c        |  283 ++
 roms/u-boot/drivers/usb/musb-new/omap2430.h        |   60 +
 roms/u-boot/drivers/usb/musb-new/pic32.c           |  294 +++
 roms/u-boot/drivers/usb/musb-new/sunxi.c           |  557 ++++
 roms/u-boot/drivers/usb/musb-new/ti-musb.c         |  344 +++
 roms/u-boot/drivers/usb/musb-new/usb-compat.h      |   79 +
 roms/u-boot/drivers/usb/musb/Kconfig               |   20 +
 roms/u-boot/drivers/usb/musb/Makefile              |    9 +
 roms/u-boot/drivers/usb/musb/am35x.c               |  139 +
 roms/u-boot/drivers/usb/musb/am35x.h               |   81 +
 roms/u-boot/drivers/usb/musb/musb_core.c           |  151 ++
 roms/u-boot/drivers/usb/musb/musb_core.h           |  343 +++
 roms/u-boot/drivers/usb/musb/musb_debug.h          |  191 ++
 roms/u-boot/drivers/usb/musb/musb_hcd.c            | 1162 ++++++++
 roms/u-boot/drivers/usb/musb/musb_hcd.h            |   95 +
 roms/u-boot/drivers/usb/musb/musb_udc.c            |  954 +++++++
 roms/u-boot/drivers/usb/musb/omap3.c               |  145 +
 roms/u-boot/drivers/usb/musb/omap3.h               |   38 +
 roms/u-boot/drivers/usb/phy/Kconfig                |   15 +
 roms/u-boot/drivers/usb/phy/Makefile               |    8 +
 roms/u-boot/drivers/usb/phy/omap_usb_phy.c         |  267 ++
 roms/u-boot/drivers/usb/phy/rockchip_usb2_phy.c    |  110 +
 roms/u-boot/drivers/usb/phy/twl4030.c              |  176 ++
 roms/u-boot/drivers/usb/ulpi/Kconfig               |   32 +
 roms/u-boot/drivers/usb/ulpi/Makefile              |    7 +
 roms/u-boot/drivers/usb/ulpi/omap-ulpi-viewport.c  |   72 +
 roms/u-boot/drivers/usb/ulpi/ulpi-viewport.c       |  113 +
 roms/u-boot/drivers/usb/ulpi/ulpi.c                |  246 ++
 221 files changed, 104196 insertions(+)
 create mode 100644 roms/u-boot/drivers/usb/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/cdns3/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/cdns3/Makefile
 create mode 100644 roms/u-boot/drivers/usb/cdns3/cdns3-ti.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/core.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/core.h
 create mode 100644 roms/u-boot/drivers/usb/cdns3/debug.h
 create mode 100644 roms/u-boot/drivers/usb/cdns3/drd.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/drd.h
 create mode 100644 roms/u-boot/drivers/usb/cdns3/ep0.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/gadget-export.h
 create mode 100644 roms/u-boot/drivers/usb/cdns3/gadget.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/gadget.h
 create mode 100644 roms/u-boot/drivers/usb/cdns3/host-export.h
 create mode 100644 roms/u-boot/drivers/usb/cdns3/host.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/trace.c
 create mode 100644 roms/u-boot/drivers/usb/cdns3/trace.h
 create mode 100644 roms/u-boot/drivers/usb/common/Makefile
 create mode 100644 roms/u-boot/drivers/usb/common/common.c
 create mode 100644 roms/u-boot/drivers/usb/common/fsl-dt-fixup.c
 create mode 100644 roms/u-boot/drivers/usb/common/fsl-errata.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/dwc3/Makefile
 create mode 100644 roms/u-boot/drivers/usb/dwc3/core.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/core.h
 create mode 100644 roms/u-boot/drivers/usb/dwc3/dwc3-generic.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/dwc3-meson-g12a.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/dwc3-meson-gxl.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/dwc3-omap.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/dwc3-uniphier.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/ep0.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/gadget.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/gadget.h
 create mode 100644 roms/u-boot/drivers/usb/dwc3/io.h
 create mode 100644 roms/u-boot/drivers/usb/dwc3/linux-compat.h
 create mode 100644 roms/u-boot/drivers/usb/dwc3/samsung_usb_phy.c
 create mode 100644 roms/u-boot/drivers/usb/dwc3/ti_usb_phy.c
 create mode 100644 roms/u-boot/drivers/usb/emul/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/emul/Makefile
 create mode 100644 roms/u-boot/drivers/usb/emul/sandbox_flash.c
 create mode 100644 roms/u-boot/drivers/usb/emul/sandbox_hub.c
 create mode 100644 roms/u-boot/drivers/usb/emul/sandbox_keyb.c
 create mode 100644 roms/u-boot/drivers/usb/emul/usb-emul-uclass.c
 create mode 100644 roms/u-boot/drivers/usb/eth/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/eth/Makefile
 create mode 100644 roms/u-boot/drivers/usb/eth/asix.c
 create mode 100644 roms/u-boot/drivers/usb/eth/asix88179.c
 create mode 100644 roms/u-boot/drivers/usb/eth/lan75xx.c
 create mode 100644 roms/u-boot/drivers/usb/eth/lan78xx.c
 create mode 100644 roms/u-boot/drivers/usb/eth/lan7x.c
 create mode 100644 roms/u-boot/drivers/usb/eth/lan7x.h
 create mode 100644 roms/u-boot/drivers/usb/eth/mcs7830.c
 create mode 100644 roms/u-boot/drivers/usb/eth/r8152.c
 create mode 100644 roms/u-boot/drivers/usb/eth/r8152.h
 create mode 100644 roms/u-boot/drivers/usb/eth/r8152_fw.c
 create mode 100644 roms/u-boot/drivers/usb/eth/smsc95xx.c
 create mode 100644 roms/u-boot/drivers/usb/eth/usb_ether.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/gadget/Makefile
 create mode 100644 roms/u-boot/drivers/usb/gadget/at91_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/at91_udc.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/bcm_udc_otg.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/bcm_udc_otg_phy.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/ci_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/ci_udc.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/composite.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/config.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/core.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/designware_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_phy.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_priv.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_regs.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/ep0.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/ep0.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/epautoconf.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/ether.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_dfu.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_dfu.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_fastboot.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_mass_storage.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_rockusb.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_sdp.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_thor.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/f_thor.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/fotg210.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/g_dnl.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/gadget_chips.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/max3420_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/ndis.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/pxa25x_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/pxa25x_udc.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/pxa27x_udc.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/rndis.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/rndis.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/storage_common.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/u_os_desc.h
 create mode 100644 roms/u-boot/drivers/usb/gadget/udc/Makefile
 create mode 100644 roms/u-boot/drivers/usb/gadget/udc/udc-core.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/udc/udc-uclass.c
 create mode 100644 roms/u-boot/drivers/usb/gadget/usbstring.c
 create mode 100644 roms/u-boot/drivers/usb/host/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/host/Makefile
 create mode 100644 roms/u-boot/drivers/usb/host/dwc2.c
 create mode 100644 roms/u-boot/drivers/usb/host/dwc2.h
 create mode 100644 roms/u-boot/drivers/usb/host/dwc3-octeon-glue.c
 create mode 100644 roms/u-boot/drivers/usb/host/dwc3-of-simple.c
 create mode 100644 roms/u-boot/drivers/usb/host/dwc3-sti-glue.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-armada100.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-atmel.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-exynos.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-faraday.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-fsl.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-generic.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-hcd.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-marvell.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-msm.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-mx5.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-mx6.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-mxc.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-mxs.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-omap.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-pci.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-rmobile.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-spear.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-tegra.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-vct.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-vf.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci-zynq.c
 create mode 100644 roms/u-boot/drivers/usb/host/ehci.h
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-at91.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-da8xx.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-ep93xx.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-generic.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-hcd.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-lpc32xx.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci-pci.c
 create mode 100644 roms/u-boot/drivers/usb/host/ohci.h
 create mode 100644 roms/u-boot/drivers/usb/host/r8a66597-hcd.c
 create mode 100644 roms/u-boot/drivers/usb/host/r8a66597.h
 create mode 100644 roms/u-boot/drivers/usb/host/sl811-hcd.c
 create mode 100644 roms/u-boot/drivers/usb/host/sl811.h
 create mode 100644 roms/u-boot/drivers/usb/host/usb-sandbox.c
 create mode 100644 roms/u-boot/drivers/usb/host/usb-uclass.c
 create mode 100644 roms/u-boot/drivers/usb/host/utmi-armada100.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-brcm.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-dwc3.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-exynos5.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-fsl.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-mem.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-mtk.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-mvebu.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-omap.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-pci.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-rcar-r8a779x_usb3_v3.h
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-rcar.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci-ring.c
 create mode 100644 roms/u-boot/drivers/usb/host/xhci.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/mtu3/Makefile
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3.h
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_core.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_dr.h
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_gadget.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_gadget_ep0.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_host.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_hw_regs.h
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_plat.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_qmu.c
 create mode 100644 roms/u-boot/drivers/usb/mtu3/mtu3_qmu.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/musb-new/Makefile
 create mode 100644 roms/u-boot/drivers/usb/musb-new/am35x.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/da8xx.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/linux-compat.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/mt85xx.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_core.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_core.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_debug.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_dma.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_dsps.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_gadget.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_gadget.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_gadget_ep0.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_host.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_host.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_io.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_regs.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_uboot.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/musb_uboot.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/omap2430.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/omap2430.h
 create mode 100644 roms/u-boot/drivers/usb/musb-new/pic32.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/sunxi.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/ti-musb.c
 create mode 100644 roms/u-boot/drivers/usb/musb-new/usb-compat.h
 create mode 100644 roms/u-boot/drivers/usb/musb/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/musb/Makefile
 create mode 100644 roms/u-boot/drivers/usb/musb/am35x.c
 create mode 100644 roms/u-boot/drivers/usb/musb/am35x.h
 create mode 100644 roms/u-boot/drivers/usb/musb/musb_core.c
 create mode 100644 roms/u-boot/drivers/usb/musb/musb_core.h
 create mode 100644 roms/u-boot/drivers/usb/musb/musb_debug.h
 create mode 100644 roms/u-boot/drivers/usb/musb/musb_hcd.c
 create mode 100644 roms/u-boot/drivers/usb/musb/musb_hcd.h
 create mode 100644 roms/u-boot/drivers/usb/musb/musb_udc.c
 create mode 100644 roms/u-boot/drivers/usb/musb/omap3.c
 create mode 100644 roms/u-boot/drivers/usb/musb/omap3.h
 create mode 100644 roms/u-boot/drivers/usb/phy/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/phy/Makefile
 create mode 100644 roms/u-boot/drivers/usb/phy/omap_usb_phy.c
 create mode 100644 roms/u-boot/drivers/usb/phy/rockchip_usb2_phy.c
 create mode 100644 roms/u-boot/drivers/usb/phy/twl4030.c
 create mode 100644 roms/u-boot/drivers/usb/ulpi/Kconfig
 create mode 100644 roms/u-boot/drivers/usb/ulpi/Makefile
 create mode 100644 roms/u-boot/drivers/usb/ulpi/omap-ulpi-viewport.c
 create mode 100644 roms/u-boot/drivers/usb/ulpi/ulpi-viewport.c
 create mode 100644 roms/u-boot/drivers/usb/ulpi/ulpi.c

(limited to 'roms/u-boot/drivers/usb')

diff --git a/roms/u-boot/drivers/usb/Kconfig b/roms/u-boot/drivers/usb/Kconfig
new file mode 100644
index 000000000..f6975730b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/Kconfig
@@ -0,0 +1,136 @@
+menuconfig USB
+	bool "USB support"
+	---help---
+	  Universal Serial Bus (USB) is a specification for a serial bus
+	  subsystem which offers higher speeds and more features than the
+	  traditional PC serial port.  The bus supplies power to peripherals
+	  and allows for hot swapping.  Up to 127 USB peripherals can be
+	  connected to a single USB host in a tree structure.
+
+	  The USB host is the root of the tree, the peripherals are the
+	  leaves and the inner nodes are special USB devices called hubs.
+	  Most PCs now have USB host ports, used to connect peripherals
+	  such as scanners, keyboards, mice, modems, cameras, disks,
+	  flash memory, network links, and printers to the PC.
+
+	  Say Y here if your device has an USB port, either host, peripheral or
+	  dual-role.
+
+	  For an USB host port, you then need to say Y to at least one of the
+	  Host Controller Driver (HCD) options below.  Choose a USB 1.1
+	  controller, such as "UHCI HCD support" or "OHCI HCD support",
+	  and "EHCI HCD (USB 2.0) support" except for older systems that
+	  do not have USB 2.0 support.  It doesn't normally hurt to select
+	  them all if you are not certain.
+
+	  If your system has a device-side USB port, used in the peripheral
+	  side of the USB protocol, see the "USB Gadget" framework instead.
+
+	  After choosing your HCD, then select drivers for the USB peripherals
+	  you'll be using.  You may want to check out the information provided
+	  in <file:Documentation/usb/> and especially the links given in
+	  <file:Documentation/usb/usb-help.txt>.
+
+if USB
+
+config DM_USB
+	bool "Enable driver model for USB"
+	depends on USB && DM
+	help
+	  Enable driver model for USB. The USB interface is then implemented
+	  by the USB uclass. Multiple USB controllers of different types
+	  (XHCI, EHCI, OHCI) can be attached and used. The 'usb' command works
+	  as normal.
+
+	  Much of the code is shared but with this option enabled the USB
+	  uclass takes care of device enumeration. USB devices can be
+	  declared with the U_BOOT_USB_DEVICE() macro and will be
+	  automatically probed when found on the bus.
+
+config SPL_DM_USB
+	bool "Enable driver model for USB in SPL"
+	depends on SPL_DM && DM_USB
+	default y
+
+config DM_USB_GADGET
+	bool "Enable driver model for USB Gadget"
+	depends on DM_USB
+	help
+	  Enable driver model for USB Gadget (Peripheral
+	  mode)
+
+config SPL_DM_USB_GADGET
+	bool "Enable driver model for USB Gadget in SPL"
+	depends on SPL_DM_USB
+	help
+	  Enable driver model for USB Gadget in SPL
+	  (Peripheral mode)
+
+source "drivers/usb/host/Kconfig"
+
+source "drivers/usb/cdns3/Kconfig"
+
+source "drivers/usb/dwc3/Kconfig"
+
+source "drivers/usb/mtu3/Kconfig"
+
+source "drivers/usb/musb/Kconfig"
+
+source "drivers/usb/musb-new/Kconfig"
+
+source "drivers/usb/emul/Kconfig"
+
+source "drivers/usb/phy/Kconfig"
+
+source "drivers/usb/ulpi/Kconfig"
+
+comment "USB peripherals"
+
+config USB_STORAGE
+	bool "USB Mass Storage support"
+	depends on !(BLK && !DM_USB)
+	---help---
+	  Say Y here if you want to connect USB mass storage devices to your
+	  board's USB port.
+
+config USB_KEYBOARD
+	bool "USB Keyboard support"
+	select DM_KEYBOARD if DM_USB
+	select SYS_STDIO_DEREGISTER
+	---help---
+	  Say Y here if you want to use a USB keyboard for U-Boot command line
+	  input.
+
+if USB_KEYBOARD
+
+config USB_KEYBOARD_FN_KEYS
+	bool "USB keyboard function key support"
+	help
+	  Say Y here if you want support for keys F1 - F12, INS, HOME, DELETE,
+	  END, PAGE UP, and PAGE DOWN.
+
+choice
+	prompt "USB keyboard polling"
+	default SYS_USB_EVENT_POLL_VIA_INT_QUEUE if ARCH_SUNXI
+	default SYS_USB_EVENT_POLL
+	---help---
+	  Enable a polling mechanism for USB keyboard.
+
+config SYS_USB_EVENT_POLL
+    bool "Interrupt polling"
+
+config SYS_USB_EVENT_POLL_VIA_INT_QUEUE
+    bool "Poll via interrupt queue"
+
+config SYS_USB_EVENT_POLL_VIA_CONTROL_EP
+    bool "Poll via control EP"
+
+endchoice
+
+endif
+
+source "drivers/usb/gadget/Kconfig"
+
+source "drivers/usb/eth/Kconfig"
+
+endif
diff --git a/roms/u-boot/drivers/usb/cdns3/Kconfig b/roms/u-boot/drivers/usb/cdns3/Kconfig
new file mode 100644
index 000000000..4cf59c70d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/Kconfig
@@ -0,0 +1,58 @@
+config USB_CDNS3
+	tristate "Cadence USB3 Dual-Role Controller"
+	depends on USB_HOST || USB_GADGET
+	help
+	  Say Y here if your system has a Cadence USB3 dual-role controller.
+	  It supports: Host-only, and Peripheral-only.
+
+if USB_CDNS3
+
+config USB_CDNS3_GADGET
+	bool "Cadence USB3 device controller"
+	depends on USB_GADGET
+	select USB_GADGET_DUALSPEED
+	help
+	  Say Y here to enable device controller functionality of the
+	  Cadence USBSS-DEV driver.
+
+	  This controller supports FF and HS mode. It doesn't support
+	  LS and SSP mode.
+
+config USB_CDNS3_HOST
+	bool "Cadence USB3 host controller"
+	depends on USB_XHCI_HCD
+	help
+	  Say Y here to enable host controller functionality of the
+	  Cadence driver.
+
+	  Host controller is compliant with XHCI so it will use
+	  standard XHCI driver.
+
+config SPL_USB_CDNS3_GADGET
+	bool "SPL support for Cadence USB3 device controller"
+	depends on SPL_USB_GADGET
+	select USB_GADGET_DUALSPEED
+	help
+	  Say Y here to enable device controller functionality of the
+	  Cadence USBSS-DEV driver in SPL.
+
+	  This controller supports FF and HS mode. It doesn't support
+	  LS and SSP mode.
+
+config SPL_USB_CDNS3_HOST
+	bool "Cadence USB3 host controller"
+	depends on USB_XHCI_HCD && SPL_USB_HOST_SUPPORT
+	help
+	  Say Y here to enable host controller functionality of the
+	  Cadence driver.
+
+	  Host controller is compliant with XHCI so it will use
+	  standard XHCI driver.
+
+config USB_CDNS3_TI
+	tristate "Cadence USB3 support on TI platforms"
+	default USB_CDNS3
+	help
+	  Say 'Y' here if you are building for Texas Instruments
+	  platforms that contain Cadence USB3 controller core. E.g.: J721e.
+endif
diff --git a/roms/u-boot/drivers/usb/cdns3/Makefile b/roms/u-boot/drivers/usb/cdns3/Makefile
new file mode 100644
index 000000000..18d719075
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+cdns3-y					:= core.o drd.o
+
+obj-$(CONFIG_USB_CDNS3)			+= cdns3.o
+
+cdns3-$(CONFIG_$(SPL_)USB_CDNS3_GADGET)	+= gadget.o ep0.o
+
+cdns3-$(CONFIG_$(SPL_)USB_CDNS3_HOST)	+= host.o
+
+obj-$(CONFIG_USB_CDNS3_TI)		+= cdns3-ti.o
diff --git a/roms/u-boot/drivers/usb/cdns3/cdns3-ti.c b/roms/u-boot/drivers/usb/cdns3/cdns3-ti.c
new file mode 100644
index 000000000..43171678e
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/cdns3-ti.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * cdns_ti-ti.c - TI specific Glue layer for Cadence USB Controller
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ */
+
+#include <common.h>
+#include <asm-generic/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <malloc.h>
+
+#include "core.h"
+
+/* USB Wrapper register offsets */
+#define USBSS_PID		0x0
+#define	USBSS_W1		0x4
+#define USBSS_STATIC_CONFIG	0x8
+#define USBSS_PHY_TEST		0xc
+#define	USBSS_DEBUG_CTRL	0x10
+#define	USBSS_DEBUG_INFO	0x14
+#define	USBSS_DEBUG_LINK_STATE	0x18
+#define	USBSS_DEVICE_CTRL	0x1c
+
+/* Wrapper 1 register bits */
+#define USBSS_W1_PWRUP_RST		BIT(0)
+#define USBSS_W1_OVERCURRENT_SEL	BIT(8)
+#define USBSS_W1_MODESTRAP_SEL		BIT(9)
+#define USBSS_W1_OVERCURRENT		BIT(16)
+#define USBSS_W1_MODESTRAP_MASK		GENMASK(18, 17)
+#define USBSS_W1_MODESTRAP_SHIFT	17
+#define USBSS_W1_USB2_ONLY		BIT(19)
+
+/* Static config register bits */
+#define USBSS1_STATIC_PLL_REF_SEL_MASK	GENMASK(8, 5)
+#define USBSS1_STATIC_PLL_REF_SEL_SHIFT	5
+#define USBSS1_STATIC_LOOPBACK_MODE_MASK	GENMASK(4, 3)
+#define USBSS1_STATIC_LOOPBACK_MODE_SHIFT	3
+#define USBSS1_STATIC_VBUS_SEL_MASK	GENMASK(2, 1)
+#define USBSS1_STATIC_VBUS_SEL_SHIFT	1
+#define USBSS1_STATIC_LANE_REVERSE	BIT(0)
+
+/* Modestrap modes */
+enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
+		      USBSS_MODESTRAP_MODE_HOST,
+		      USBSS_MODESTRAP_MODE_PERIPHERAL};
+
+struct cdns_ti {
+	struct udevice *dev;
+	void __iomem *usbss;
+	int usb2_only:1;
+	int vbus_divider:1;
+	struct clk *usb2_refclk;
+	struct clk *lpm_clk;
+};
+
+static const int cdns_ti_rate_table[] = {	/* in KHZ */
+	9600,
+	10000,
+	12000,
+	19200,
+	20000,
+	24000,
+	25000,
+	26000,
+	38400,
+	40000,
+	58000,
+	50000,
+	52000,
+};
+
+static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
+{
+	return readl(data->usbss + offset);
+}
+
+static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
+{
+	writel(value, data->usbss + offset);
+}
+
+static int cdns_ti_probe(struct udevice *dev)
+{
+	struct cdns_ti *data = dev_get_plat(dev);
+	struct clk usb2_refclk;
+	int modestrap_mode;
+	unsigned long rate;
+	int rate_code, i;
+	u32 reg;
+	int ret;
+
+	data->dev = dev;
+
+	data->usbss = dev_remap_addr_index(dev, 0);
+	if (!data->usbss)
+		return -EINVAL;
+
+	ret = clk_get_by_name(dev, "ref", &usb2_refclk);
+	if (ret) {
+		dev_err(dev, "Failed to get usb2_refclk\n");
+		return ret;
+	}
+
+	rate = clk_get_rate(&usb2_refclk);
+	rate /= 1000;	/* To KHz */
+	for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
+		if (cdns_ti_rate_table[i] == rate)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
+		dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
+		return -EINVAL;
+	}
+
+	rate_code = i;
+
+	/* assert RESET */
+	reg = cdns_ti_readl(data, USBSS_W1);
+	reg &= ~USBSS_W1_PWRUP_RST;
+	cdns_ti_writel(data, USBSS_W1, reg);
+
+	/* set static config */
+	reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
+	reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
+	reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
+
+	reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
+	data->vbus_divider = dev_read_bool(dev, "ti,vbus-divider");
+	if (data->vbus_divider)
+		reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
+
+	cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
+	reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
+
+	/* set USB2_ONLY mode if requested */
+	reg = cdns_ti_readl(data, USBSS_W1);
+	data->usb2_only = dev_read_bool(dev, "ti,usb2-only");
+	if (data->usb2_only)
+		reg |= USBSS_W1_USB2_ONLY;
+
+	/* set modestrap  */
+	if (dev_read_bool(dev, "ti,modestrap-host"))
+		modestrap_mode = USBSS_MODESTRAP_MODE_HOST;
+	else if (dev_read_bool(dev, "ti,modestrap-peripheral"))
+		modestrap_mode = USBSS_MODESTRAP_MODE_PERIPHERAL;
+	else
+		modestrap_mode = USBSS_MODESTRAP_MODE_NONE;
+
+	reg |= USBSS_W1_MODESTRAP_SEL;
+	reg &= ~USBSS_W1_MODESTRAP_MASK;
+	reg |= modestrap_mode << USBSS_W1_MODESTRAP_SHIFT;
+	cdns_ti_writel(data, USBSS_W1, reg);
+
+	/* de-assert RESET */
+	reg |= USBSS_W1_PWRUP_RST;
+	cdns_ti_writel(data, USBSS_W1, reg);
+
+	return 0;
+}
+
+static int cdns_ti_remove(struct udevice *dev)
+{
+	struct cdns_ti *data = dev_get_plat(dev);
+	u32 reg;
+
+	/* put device back to RESET*/
+	reg = cdns_ti_readl(data, USBSS_W1);
+	reg &= ~USBSS_W1_PWRUP_RST;
+	cdns_ti_writel(data, USBSS_W1, reg);
+
+	return 0;
+}
+
+static const struct udevice_id cdns_ti_of_match[] = {
+	{ .compatible = "ti,j721e-usb", },
+	{},
+};
+
+U_BOOT_DRIVER(cdns_ti) = {
+	.name = "cdns-ti",
+	.id = UCLASS_NOP,
+	.of_match = cdns_ti_of_match,
+	.bind = cdns3_bind,
+	.probe = cdns_ti_probe,
+	.remove = cdns_ti_remove,
+	.plat_auto	= sizeof(struct cdns_ti),
+	.flags = DM_FLAG_OS_PREPARE,
+};
diff --git a/roms/u-boot/drivers/usb/cdns3/core.c b/roms/u-boot/drivers/usb/cdns3/core.c
new file mode 100644
index 000000000..798a21793
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/core.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cadence USBSS DRD Driver.
+ *
+ * Copyright (C) 2018-2019 Cadence.
+ * Copyright (C) 2017-2018 NXP
+ * Copyright (C) 2019 Texas Instruments
+ *
+ * Author: Peter Chen <peter.chen@nxp.com>
+ *         Pawel Laszczak <pawell@cadence.com>
+ *         Roger Quadros <rogerq@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <usb.h>
+#include <usb/xhci.h>
+
+#include "core.h"
+#include "host-export.h"
+#include "gadget-export.h"
+#include "drd.h"
+
+static int cdns3_idle_init(struct cdns3 *cdns);
+
+struct cdns3_host_priv {
+	struct xhci_ctrl xhci_ctrl;
+	struct cdns3 cdns;
+};
+
+struct cdns3_gadget_priv {
+	struct cdns3 cdns;
+};
+
+static inline
+struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns)
+{
+	WARN_ON(!cdns->roles[cdns->role]);
+	return cdns->roles[cdns->role];
+}
+
+static int cdns3_role_start(struct cdns3 *cdns, enum usb_role role)
+{
+	int ret;
+
+	if (WARN_ON(role > USB_ROLE_DEVICE))
+		return 0;
+
+	mutex_lock(&cdns->mutex);
+	cdns->role = role;
+	mutex_unlock(&cdns->mutex);
+
+	if (!cdns->roles[role])
+		return -ENXIO;
+
+	if (cdns->roles[role]->state == CDNS3_ROLE_STATE_ACTIVE)
+		return 0;
+
+	mutex_lock(&cdns->mutex);
+	ret = cdns->roles[role]->start(cdns);
+	if (!ret)
+		cdns->roles[role]->state = CDNS3_ROLE_STATE_ACTIVE;
+	mutex_unlock(&cdns->mutex);
+
+	return ret;
+}
+
+static void cdns3_role_stop(struct cdns3 *cdns)
+{
+	enum usb_role role = cdns->role;
+
+	if (WARN_ON(role > USB_ROLE_DEVICE))
+		return;
+
+	if (cdns->roles[role]->state == CDNS3_ROLE_STATE_INACTIVE)
+		return;
+
+	mutex_lock(&cdns->mutex);
+	cdns->roles[role]->stop(cdns);
+	cdns->roles[role]->state = CDNS3_ROLE_STATE_INACTIVE;
+	mutex_unlock(&cdns->mutex);
+}
+
+static void cdns3_exit_roles(struct cdns3 *cdns)
+{
+	cdns3_role_stop(cdns);
+	cdns3_drd_exit(cdns);
+}
+
+static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns);
+
+/**
+ * cdns3_core_init_role - initialize role of operation
+ * @cdns: Pointer to cdns3 structure
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_core_init_role(struct cdns3 *cdns)
+{
+	struct udevice *dev = cdns->dev;
+	enum usb_dr_mode best_dr_mode;
+	enum usb_dr_mode dr_mode;
+	int ret = 0;
+
+	dr_mode = usb_get_dr_mode(dev_ofnode(dev));
+	cdns->role = USB_ROLE_NONE;
+
+	/*
+	 * If driver can't read mode by means of usb_get_dr_mode function then
+	 * chooses mode according with Kernel configuration. This setting
+	 * can be restricted later depending on strap pin configuration.
+	 */
+	if (dr_mode == USB_DR_MODE_UNKNOWN) {
+		if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) &&
+		    IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
+			dr_mode = USB_DR_MODE_OTG;
+		else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST))
+			dr_mode = USB_DR_MODE_HOST;
+		else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
+			dr_mode = USB_DR_MODE_PERIPHERAL;
+	}
+
+	/*
+	 * At this point cdns->dr_mode contains strap configuration.
+	 * Driver try update this setting considering kernel configuration
+	 */
+	best_dr_mode = cdns->dr_mode;
+
+	ret = cdns3_idle_init(cdns);
+	if (ret)
+		return ret;
+
+	if (dr_mode == USB_DR_MODE_OTG) {
+		best_dr_mode = cdns->dr_mode;
+	} else if (cdns->dr_mode == USB_DR_MODE_OTG) {
+		best_dr_mode = dr_mode;
+	} else if (cdns->dr_mode != dr_mode) {
+		dev_err(dev, "Incorrect DRD configuration\n");
+		return -EINVAL;
+	}
+
+	dr_mode = best_dr_mode;
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
+	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
+		ret = cdns3_host_init(cdns);
+		if (ret) {
+			dev_err(dev, "Host initialization failed with %d\n",
+				ret);
+			goto err;
+		}
+	}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
+		ret = cdns3_gadget_init(cdns);
+		if (ret) {
+			dev_err(dev, "Device initialization failed with %d\n",
+				ret);
+			goto err;
+		}
+	}
+#endif
+
+	cdns->dr_mode = dr_mode;
+
+	ret = cdns3_drd_update_mode(cdns);
+	if (ret)
+		goto err;
+
+	if (cdns->dr_mode != USB_DR_MODE_OTG) {
+		ret = cdns3_hw_role_switch(cdns);
+		if (ret)
+			goto err;
+	}
+
+	return ret;
+err:
+	cdns3_exit_roles(cdns);
+	return ret;
+}
+
+/**
+ * cdsn3_hw_role_state_machine - role switch state machine based on hw events
+ * @cdns: Pointer to controller structure.
+ *
+ * Returns next role to be entered based on hw events.
+ */
+static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns)
+{
+	enum usb_role role;
+	int id, vbus;
+
+	if (cdns->dr_mode != USB_DR_MODE_OTG)
+		goto not_otg;
+
+	id = cdns3_get_id(cdns);
+	vbus = cdns3_get_vbus(cdns);
+
+	/*
+	 * Role change state machine
+	 * Inputs: ID, VBUS
+	 * Previous state: cdns->role
+	 * Next state: role
+	 */
+	role = cdns->role;
+
+	switch (role) {
+	case USB_ROLE_NONE:
+		/*
+		 * Driver treats USB_ROLE_NONE synonymous to IDLE state from
+		 * controller specification.
+		 */
+		if (!id)
+			role = USB_ROLE_HOST;
+		else if (vbus)
+			role = USB_ROLE_DEVICE;
+		break;
+	case USB_ROLE_HOST: /* from HOST, we can only change to NONE */
+		if (id)
+			role = USB_ROLE_NONE;
+		break;
+	case USB_ROLE_DEVICE: /* from GADGET, we can only change to NONE*/
+		if (!vbus)
+			role = USB_ROLE_NONE;
+		break;
+	}
+
+	dev_dbg(cdns->dev, "role %d -> %d\n", cdns->role, role);
+
+	return role;
+
+not_otg:
+	if (cdns3_is_host(cdns))
+		role = USB_ROLE_HOST;
+	if (cdns3_is_device(cdns))
+		role = USB_ROLE_DEVICE;
+
+	return role;
+}
+
+static int cdns3_idle_role_start(struct cdns3 *cdns)
+{
+	return 0;
+}
+
+static void cdns3_idle_role_stop(struct cdns3 *cdns)
+{
+	/* Program Lane swap and bring PHY out of RESET */
+	generic_phy_reset(&cdns->usb3_phy);
+}
+
+static int cdns3_idle_init(struct cdns3 *cdns)
+{
+	struct cdns3_role_driver *rdrv;
+
+	rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+	if (!rdrv)
+		return -ENOMEM;
+
+	rdrv->start = cdns3_idle_role_start;
+	rdrv->stop = cdns3_idle_role_stop;
+	rdrv->state = CDNS3_ROLE_STATE_INACTIVE;
+	rdrv->suspend = NULL;
+	rdrv->resume = NULL;
+	rdrv->name = "idle";
+
+	cdns->roles[USB_ROLE_NONE] = rdrv;
+
+	return 0;
+}
+
+/**
+ * cdns3_hw_role_switch - switch roles based on HW state
+ * @cdns3: controller
+ */
+int cdns3_hw_role_switch(struct cdns3 *cdns)
+{
+	enum usb_role real_role, current_role;
+	int ret = 0;
+
+	/* Do nothing if role based on syfs. */
+	if (cdns->role_override)
+		return 0;
+
+	current_role = cdns->role;
+	real_role = cdsn3_hw_role_state_machine(cdns);
+
+	/* Do nothing if nothing changed */
+	if (current_role == real_role)
+		goto exit;
+
+	cdns3_role_stop(cdns);
+
+	dev_dbg(cdns->dev, "Switching role %d -> %d", current_role, real_role);
+
+	ret = cdns3_role_start(cdns, real_role);
+	if (ret) {
+		/* Back to current role */
+		dev_err(cdns->dev, "set %d has failed, back to %d\n",
+			real_role, current_role);
+		ret = cdns3_role_start(cdns, current_role);
+		if (ret)
+			dev_err(cdns->dev, "back to %d failed too\n",
+				current_role);
+	}
+exit:
+	return ret;
+}
+
+static int cdns3_probe(struct cdns3 *cdns)
+{
+	struct udevice *dev = cdns->dev;
+	int ret;
+
+	cdns->xhci_regs = dev_remap_addr_name(dev, "xhci");
+	if (!cdns->xhci_regs)
+		return -EINVAL;
+
+	cdns->dev_regs = dev_remap_addr_name(dev, "dev");
+	if (!cdns->dev_regs)
+		return -EINVAL;
+
+	mutex_init(&cdns->mutex);
+
+	ret = generic_phy_get_by_name(dev, "cdns3,usb2-phy", &cdns->usb2_phy);
+	if (ret)
+		dev_warn(dev, "Unable to get USB2 phy (ret %d)\n", ret);
+
+	ret = generic_phy_init(&cdns->usb2_phy);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_get_by_name(dev, "cdns3,usb3-phy", &cdns->usb3_phy);
+	if (ret)
+		dev_warn(dev, "Unable to get USB3 phy (ret %d)\n", ret);
+
+	ret = generic_phy_init(&cdns->usb3_phy);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on(&cdns->usb2_phy);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on(&cdns->usb3_phy);
+	if (ret)
+		return ret;
+
+	ret = cdns3_drd_init(cdns);
+	if (ret)
+		return ret;
+
+	ret = cdns3_core_init_role(cdns);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
+	return 0;
+}
+
+static int cdns3_remove(struct cdns3 *cdns)
+{
+	cdns3_exit_roles(cdns);
+	generic_phy_power_off(&cdns->usb2_phy);
+	generic_phy_power_off(&cdns->usb3_phy);
+	generic_phy_exit(&cdns->usb2_phy);
+	generic_phy_exit(&cdns->usb3_phy);
+	return 0;
+}
+
+static const struct udevice_id cdns3_ids[] = {
+	{ .compatible = "cdns,usb3" },
+	{ },
+};
+
+int cdns3_bind(struct udevice *parent)
+{
+	enum usb_dr_mode dr_mode;
+	struct udevice *dev;
+	const char *driver;
+	const char *name;
+	ofnode node;
+	int ret;
+
+	node = ofnode_by_compatible(dev_ofnode(parent), "cdns,usb3");
+	if (!ofnode_valid(node)) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	name = ofnode_get_name(node);
+	dr_mode = usb_get_dr_mode(node);
+
+	switch (dr_mode) {
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	(!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+	case USB_DR_MODE_HOST:
+		debug("%s: dr_mode: HOST\n", __func__);
+		driver = "cdns-usb3-host";
+		break;
+#endif
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+	case USB_DR_MODE_PERIPHERAL:
+		debug("%s: dr_mode: PERIPHERAL\n", __func__);
+		driver = "cdns-usb3-peripheral";
+		break;
+#endif
+	default:
+		printf("%s: unsupported dr_mode\n", __func__);
+		ret = -ENODEV;
+		goto fail;
+	};
+
+	ret = device_bind_driver_to_node(parent, driver, name, node, &dev);
+	if (ret) {
+		printf("%s: not able to bind usb device mode\n",
+		       __func__);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	/* do not return an error: failing to bind would hang the board */
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+static int cdns3_gadget_probe(struct udevice *dev)
+{
+	struct cdns3_gadget_priv *priv = dev_get_priv(dev);
+	struct cdns3 *cdns = &priv->cdns;
+
+	cdns->dev = dev;
+
+	return cdns3_probe(cdns);
+}
+
+static int cdns3_gadget_remove(struct udevice *dev)
+{
+	struct cdns3_gadget_priv *priv = dev_get_priv(dev);
+	struct cdns3 *cdns = &priv->cdns;
+
+	return cdns3_remove(cdns);
+}
+
+U_BOOT_DRIVER(cdns_usb3_peripheral) = {
+	.name	= "cdns-usb3-peripheral",
+	.id	= UCLASS_USB_GADGET_GENERIC,
+	.of_match = cdns3_ids,
+	.probe = cdns3_gadget_probe,
+	.remove = cdns3_gadget_remove,
+	.priv_auto	= sizeof(struct cdns3_gadget_priv),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	(!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+static int cdns3_host_probe(struct udevice *dev)
+{
+	struct cdns3_host_priv *priv = dev_get_priv(dev);
+	struct cdns3 *cdns = &priv->cdns;
+
+	cdns->dev = dev;
+
+	return cdns3_probe(cdns);
+}
+
+static int cdns3_host_remove(struct udevice *dev)
+{
+	struct cdns3_host_priv *priv = dev_get_priv(dev);
+	struct cdns3 *cdns = &priv->cdns;
+
+	return cdns3_remove(cdns);
+}
+
+U_BOOT_DRIVER(cdns_usb3_host) = {
+	.name	= "cdns-usb3-host",
+	.id	= UCLASS_USB,
+	.of_match = cdns3_ids,
+	.probe = cdns3_host_probe,
+	.remove = cdns3_host_remove,
+	.priv_auto	= sizeof(struct cdns3_host_priv),
+	.ops = &xhci_usb_ops,
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/cdns3/core.h b/roms/u-boot/drivers/usb/cdns3/core.h
new file mode 100644
index 000000000..0668d646f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/core.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence USBSS DRD Header File.
+ *
+ * Copyright (C) 2017-2018 NXP
+ * Copyright (C) 2018-2019 Cadence.
+ *
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *          Pawel Laszczak <pawell@cadence.com>
+ */
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/usb/otg.h>
+#include <generic-phy.h>
+
+#ifndef __LINUX_CDNS3_CORE_H
+#define __LINUX_CDNS3_CORE_H
+
+enum usb_role {
+	USB_ROLE_NONE,
+	USB_ROLE_HOST,
+	USB_ROLE_DEVICE,
+};
+
+struct cdns3;
+
+/**
+ * struct cdns3_role_driver - host/gadget role driver
+ * @start: start this role
+ * @stop: stop this role
+ * @suspend: suspend callback for this role
+ * @resume: resume callback for this role
+ * @irq: irq handler for this role
+ * @name: role name string (host/gadget)
+ * @state: current state
+ */
+struct cdns3_role_driver {
+	int (*start)(struct cdns3 *cdns);
+	void (*stop)(struct cdns3 *cdns);
+	int (*suspend)(struct cdns3 *cdns, bool do_wakeup);
+	int (*resume)(struct cdns3 *cdns, bool hibernated);
+	const char *name;
+#define CDNS3_ROLE_STATE_INACTIVE	0
+#define CDNS3_ROLE_STATE_ACTIVE		1
+	int state;
+};
+
+#define CDNS3_XHCI_RESOURCES_NUM	2
+/**
+ * struct cdns3 - Representation of Cadence USB3 DRD controller.
+ * @dev: pointer to Cadence device struct
+ * @xhci_regs: pointer to base of xhci registers
+ * @dev_regs: pointer to base of dev registers
+ * @otg_v0_regs: pointer to base of v0 otg registers
+ * @otg_v1_regs: pointer to base of v1 otg registers
+ * @otg_regs: pointer to base of otg registers
+ * @otg_irq: irq number for otg controller
+ * @dev_irq: irq number for device controller
+ * @roles: array of supported roles for this controller
+ * @role: current role
+ * @host_dev: the child host device pointer for cdns3 core
+ * @gadget_dev: the child gadget device pointer for cdns3 core
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
+ * @mutex: the mutex for concurrent code at driver
+ * @dr_mode: supported mode of operation it can be only Host, only Device
+ *           or OTG mode that allow to switch between Device and Host mode.
+ *           This field based on firmware setting, kernel configuration
+ *           and hardware configuration.
+ * @role_sw: pointer to role switch object.
+ * @role_override: set 1 if role rely on SW.
+ */
+struct cdns3 {
+	struct udevice			*dev;
+	void __iomem			*xhci_regs;
+	struct cdns3_usb_regs __iomem	*dev_regs;
+
+	struct cdns3_otg_legacy_regs	*otg_v0_regs;
+	struct cdns3_otg_regs		*otg_v1_regs;
+	struct cdns3_otg_common_regs	*otg_regs;
+#define CDNS3_CONTROLLER_V0	0
+#define CDNS3_CONTROLLER_V1	1
+	u32				version;
+
+	int				otg_irq;
+	int				dev_irq;
+	struct cdns3_role_driver	*roles[USB_ROLE_DEVICE + 1];
+	enum usb_role			role;
+	struct cdns3_device		*gadget_dev;
+	struct phy			usb2_phy;
+	struct phy			usb3_phy;
+	/* mutext used in workqueue*/
+	struct mutex			mutex;
+	enum usb_dr_mode		dr_mode;
+	int				role_override;
+};
+
+int cdns3_hw_role_switch(struct cdns3 *cdns);
+
+/**
+ * cdns3_bind - generic bind function
+ * @parent - pointer to parent udevice of which cdns3 USB controller
+ *           node is child of
+ *
+ * return 0 on success, negative errno otherwise
+ */
+int cdns3_bind(struct udevice *dev);
+#endif /* __LINUX_CDNS3_CORE_H */
diff --git a/roms/u-boot/drivers/usb/cdns3/debug.h b/roms/u-boot/drivers/usb/cdns3/debug.h
new file mode 100644
index 000000000..0b4673a3a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/debug.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence USBSS DRD Driver.
+ * Debug header file.
+ *
+ * Copyright (C) 2018-2019 Cadence.
+ *
+ * Author: Pawel Laszczak <pawell@cadence.com>
+ */
+#ifndef __LINUX_CDNS3_DEBUG
+#define __LINUX_CDNS3_DEBUG
+
+#include "core.h"
+#include "gadget.h"
+
+static inline char *cdns3_decode_usb_irq(char *str,
+					 enum usb_device_speed speed,
+					 u32 usb_ists)
+{
+	int ret;
+
+	ret = sprintf(str, "IRQ %08x = ", usb_ists);
+
+	if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) {
+		ret += sprintf(str + ret, "Connection %s\n",
+			       usb_speed_string(speed));
+	}
+	if (usb_ists & USB_ISTS_DIS2I || usb_ists & USB_ISTS_DISI)
+		ret += sprintf(str + ret, "Disconnection ");
+	if (usb_ists & USB_ISTS_L2ENTI)
+		ret += sprintf(str + ret, "suspended ");
+	if (usb_ists & USB_ISTS_L1ENTI)
+		ret += sprintf(str + ret, "L1 enter ");
+	if (usb_ists & USB_ISTS_L1EXTI)
+		ret += sprintf(str + ret, "L1 exit ");
+	if (usb_ists & USB_ISTS_L2ENTI)
+		ret += sprintf(str + ret, "L2 enter ");
+	if (usb_ists & USB_ISTS_L2EXTI)
+		ret += sprintf(str + ret, "L2 exit ");
+	if (usb_ists & USB_ISTS_U3EXTI)
+		ret += sprintf(str + ret, "U3 exit ");
+	if (usb_ists & USB_ISTS_UWRESI)
+		ret += sprintf(str + ret, "Warm Reset ");
+	if (usb_ists & USB_ISTS_UHRESI)
+		ret += sprintf(str + ret, "Hot Reset ");
+	if (usb_ists & USB_ISTS_U2RESI)
+		ret += sprintf(str + ret, "Reset");
+
+	return str;
+}
+
+static inline  char *cdns3_decode_ep_irq(char *str,
+					 u32 ep_sts,
+					 const char *ep_name)
+{
+	int ret;
+
+	ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts);
+
+	if (ep_sts & EP_STS_SETUP)
+		ret += sprintf(str + ret, "SETUP ");
+	if (ep_sts & EP_STS_IOC)
+		ret += sprintf(str + ret, "IOC ");
+	if (ep_sts & EP_STS_ISP)
+		ret += sprintf(str + ret, "ISP ");
+	if (ep_sts & EP_STS_DESCMIS)
+		ret += sprintf(str + ret, "DESCMIS ");
+	if (ep_sts & EP_STS_STREAMR)
+		ret += sprintf(str + ret, "STREAMR ");
+	if (ep_sts & EP_STS_MD_EXIT)
+		ret += sprintf(str + ret, "MD_EXIT ");
+	if (ep_sts & EP_STS_TRBERR)
+		ret += sprintf(str + ret, "TRBERR ");
+	if (ep_sts & EP_STS_NRDY)
+		ret += sprintf(str + ret, "NRDY ");
+	if (ep_sts & EP_STS_PRIME)
+		ret += sprintf(str + ret, "PRIME ");
+	if (ep_sts & EP_STS_SIDERR)
+		ret += sprintf(str + ret, "SIDERRT ");
+	if (ep_sts & EP_STS_OUTSMM)
+		ret += sprintf(str + ret, "OUTSMM ");
+	if (ep_sts & EP_STS_ISOERR)
+		ret += sprintf(str + ret, "ISOERR ");
+	if (ep_sts & EP_STS_IOT)
+		ret += sprintf(str + ret, "IOT ");
+
+	return str;
+}
+
+static inline char *cdns3_decode_epx_irq(char *str,
+					 char *ep_name,
+					 u32 ep_sts)
+{
+	return cdns3_decode_ep_irq(str, ep_sts, ep_name);
+}
+
+static inline char *cdns3_decode_ep0_irq(char *str,
+					 int dir,
+					 u32 ep_sts)
+{
+	return cdns3_decode_ep_irq(str, ep_sts,
+				   dir ? "ep0IN" : "ep0OUT");
+}
+
+/**
+ * Debug a transfer ring.
+ *
+ * Prints out all TRBs in the endpoint ring, even those after the Link TRB.
+ *.
+ */
+static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
+				   struct cdns3_trb *ring, char *str)
+{
+	dma_addr_t addr = priv_ep->trb_pool_dma;
+	struct cdns3_trb *trb;
+	int trb_per_sector;
+	int ret = 0;
+	int i;
+
+	trb_per_sector = GET_TRBS_PER_SEGMENT(priv_ep->type);
+
+	trb = &priv_ep->trb_pool[priv_ep->dequeue];
+	ret += sprintf(str + ret, "\n\t\tRing contents for %s:", priv_ep->name);
+
+	ret += sprintf(str + ret,
+		       "\n\t\tRing deq index: %d, trb: %p (virt), 0x%llx (dma)\n",
+		       priv_ep->dequeue, trb,
+		       (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb));
+
+	trb = &priv_ep->trb_pool[priv_ep->enqueue];
+	ret += sprintf(str + ret,
+		       "\t\tRing enq index: %d, trb: %p (virt), 0x%llx (dma)\n",
+		       priv_ep->enqueue, trb,
+		       (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb));
+
+	ret += sprintf(str + ret,
+		       "\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
+		       priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs);
+
+	if (trb_per_sector > TRBS_PER_SEGMENT)
+		trb_per_sector = TRBS_PER_SEGMENT;
+
+	if (trb_per_sector > TRBS_PER_SEGMENT) {
+		sprintf(str + ret, "\t\tTo big transfer ring %d\n",
+			trb_per_sector);
+		return str;
+	}
+
+	for (i = 0; i < trb_per_sector; ++i) {
+		trb = &ring[i];
+		ret += sprintf(str + ret,
+			"\t\t@%pad %08x %08x %08x\n", &addr,
+			le32_to_cpu(trb->buffer),
+			le32_to_cpu(trb->length),
+			le32_to_cpu(trb->control));
+		addr += sizeof(*trb);
+	}
+
+	return str;
+}
+
+#endif /*__LINUX_CDNS3_DEBUG*/
diff --git a/roms/u-boot/drivers/usb/cdns3/drd.c b/roms/u-boot/drivers/usb/cdns3/drd.c
new file mode 100644
index 000000000..47874fec2
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/drd.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cadence USBSS DRD Driver.
+ *
+ * Copyright (C) 2018-2019 Cadence.
+ * Copyright (C) 2019 Texas Instruments
+ *
+ * Author: Pawel Laszczak <pawell@cadence.com>
+ *         Roger Quadros <rogerq@ti.com>
+ *
+ *
+ */
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/usb/otg.h>
+
+#include "gadget.h"
+#include "drd.h"
+#include "core.h"
+
+#define readl_poll_timeout_atomic readl_poll_timeout
+#define usleep_range(a, b) udelay((b))
+/**
+ * cdns3_set_mode - change mode of OTG Core
+ * @cdns: pointer to context structure
+ * @mode: selected mode from cdns_role
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode)
+{
+	int ret = 0;
+	u32 reg;
+
+	switch (mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		break;
+	case USB_DR_MODE_HOST:
+		break;
+	case USB_DR_MODE_OTG:
+		dev_dbg(cdns->dev, "Set controller to OTG mode\n");
+		if (cdns->version == CDNS3_CONTROLLER_V1) {
+			reg = readl(&cdns->otg_v1_regs->override);
+			reg |= OVERRIDE_IDPULLUP;
+			writel(reg, &cdns->otg_v1_regs->override);
+		} else {
+			reg = readl(&cdns->otg_v0_regs->ctrl1);
+			reg |= OVERRIDE_IDPULLUP_V0;
+			writel(reg, &cdns->otg_v0_regs->ctrl1);
+		}
+
+		/*
+		 * Hardware specification says: "ID_VALUE must be valid within
+		 * 50ms after idpullup is set to '1" so driver must wait
+		 * 50ms before reading this pin.
+		 */
+		usleep_range(50000, 60000);
+		break;
+	default:
+		dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int cdns3_get_id(struct cdns3 *cdns)
+{
+	int id;
+
+	id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE;
+	dev_dbg(cdns->dev, "OTG ID: %d", id);
+
+	return id;
+}
+
+int cdns3_get_vbus(struct cdns3 *cdns)
+{
+	int vbus;
+
+	vbus = !!(readl(&cdns->otg_regs->sts) & OTGSTS_VBUS_VALID);
+	dev_dbg(cdns->dev, "OTG VBUS: %d", vbus);
+
+	return vbus;
+}
+
+int cdns3_is_host(struct cdns3 *cdns)
+{
+	if (cdns->dr_mode == USB_DR_MODE_HOST)
+		return 1;
+	else if (!cdns3_get_id(cdns))
+		return 1;
+
+	return 0;
+}
+
+int cdns3_is_device(struct cdns3 *cdns)
+{
+	if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL)
+		return 1;
+	else if (cdns->dr_mode == USB_DR_MODE_OTG)
+		if (cdns3_get_id(cdns))
+			return 1;
+
+	return 0;
+}
+
+/**
+ * cdns3_drd_switch_host - start/stop host
+ * @cdns: Pointer to controller context structure
+ * @on: 1 for start, 0 for stop
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+int cdns3_drd_switch_host(struct cdns3 *cdns, int on)
+{
+	int ret, val;
+	u32 reg = OTGCMD_OTG_DIS;
+
+	/* switch OTG core */
+	if (on) {
+		writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd);
+
+		dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
+		ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
+						val & OTGSTS_XHCI_READY,
+						100000);
+		if (ret) {
+			dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
+			return ret;
+		}
+	} else {
+		writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
+		       OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
+		       &cdns->otg_regs->cmd);
+		/* Waiting till H_IDLE state.*/
+		readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
+					  !(val & OTGSTATE_HOST_STATE_MASK),
+					  2000000);
+	}
+
+	return 0;
+}
+
+/**
+ * cdns3_drd_switch_gadget - start/stop gadget
+ * @cdns: Pointer to controller context structure
+ * @on: 1 for start, 0 for stop
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on)
+{
+	int ret, val;
+	u32 reg = OTGCMD_OTG_DIS;
+
+	/* switch OTG core */
+	if (on) {
+		writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
+
+		dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n");
+
+		ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
+						val & OTGSTS_DEV_READY,
+						100000);
+		if (ret) {
+			dev_err(cdns->dev, "timeout waiting for dev_ready\n");
+			return ret;
+		}
+	} else {
+		/*
+		 * driver should wait at least 10us after disabling Device
+		 * before turning-off Device (DEV_BUS_DROP)
+		 */
+		usleep_range(20, 30);
+		writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
+		       OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
+		       &cdns->otg_regs->cmd);
+		/* Waiting till DEV_IDLE state.*/
+		readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
+					  !(val & OTGSTATE_DEV_STATE_MASK),
+					  2000000);
+	}
+
+	return 0;
+}
+
+/**
+ * cdns3_init_otg_mode - initialize drd controller
+ * @cdns: Pointer to controller context structure
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_init_otg_mode(struct cdns3 *cdns)
+{
+	int ret = 0;
+
+	/* clear all interrupts */
+	writel(~0, &cdns->otg_regs->ivect);
+
+	ret = cdns3_set_mode(cdns, USB_DR_MODE_OTG);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+/**
+ * cdns3_drd_update_mode - initialize mode of operation
+ * @cdns: Pointer to controller context structure
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+int cdns3_drd_update_mode(struct cdns3 *cdns)
+{
+	int ret = 0;
+
+	switch (cdns->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
+		break;
+	case USB_DR_MODE_HOST:
+		ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST);
+		break;
+	case USB_DR_MODE_OTG:
+		ret = cdns3_init_otg_mode(cdns);
+		break;
+	default:
+		dev_err(cdns->dev, "Unsupported mode of operation %d\n",
+			cdns->dr_mode);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int cdns3_drd_init(struct cdns3 *cdns)
+{
+	void __iomem *regs;
+	int ret = 0;
+	u32 state;
+
+	regs = dev_remap_addr_name(cdns->dev, "otg");
+	if (!regs)
+		return -EINVAL;
+
+	/* Detection of DRD version. Controller has been released
+	 * in two versions. Both are similar, but they have same changes
+	 * in register maps.
+	 * The first register in old version is command register and it's read
+	 * only, so driver should read 0 from it. On the other hand, in v1
+	 * the first register contains device ID number which is not set to 0.
+	 * Driver uses this fact to detect the proper version of
+	 * controller.
+	 */
+	cdns->otg_v0_regs = regs;
+	if (!readl(&cdns->otg_v0_regs->cmd)) {
+		cdns->version  = CDNS3_CONTROLLER_V0;
+		cdns->otg_v1_regs = NULL;
+		cdns->otg_regs = regs;
+		writel(1, &cdns->otg_v0_regs->simulate);
+		dev_info(cdns->dev, "DRD version v0 (%08x)\n",
+			 readl(&cdns->otg_v0_regs->version));
+	} else {
+		cdns->otg_v0_regs = NULL;
+		cdns->otg_v1_regs = regs;
+		cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd;
+		cdns->version  = CDNS3_CONTROLLER_V1;
+		writel(1, &cdns->otg_v1_regs->simulate);
+		dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
+			 readl(&cdns->otg_v1_regs->did),
+			 readl(&cdns->otg_v1_regs->rid));
+	}
+
+	state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts));
+
+	/* Update dr_mode according to STRAP configuration. */
+	cdns->dr_mode = USB_DR_MODE_OTG;
+	if (state == OTGSTS_STRAP_HOST) {
+		dev_dbg(cdns->dev, "Controller strapped to HOST\n");
+		cdns->dr_mode = USB_DR_MODE_HOST;
+	} else if (state == OTGSTS_STRAP_GADGET) {
+		dev_dbg(cdns->dev, "Controller strapped to PERIPHERAL\n");
+		cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
+	}
+
+	state = readl(&cdns->otg_regs->sts);
+	if (OTGSTS_OTG_NRDY(state) != 0) {
+		dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
+		return -ENODEV;
+	}
+
+	return ret;
+}
+
+int cdns3_drd_exit(struct cdns3 *cdns)
+{
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/cdns3/drd.h b/roms/u-boot/drivers/usb/cdns3/drd.h
new file mode 100644
index 000000000..fffda7b43
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/drd.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence USB3 DRD header file.
+ *
+ * Copyright (C) 2018-2019 Cadence.
+ *
+ * Author: Pawel Laszczak <pawell@cadence.com>
+ */
+#ifndef __LINUX_CDNS3_DRD
+#define __LINUX_CDNS3_DRD
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/usb/otg.h>
+#include "core.h"
+
+/*  DRD register interface for version v1. */
+struct cdns3_otg_regs {
+	__le32 did;
+	__le32 rid;
+	__le32 capabilities;
+	__le32 reserved1;
+	__le32 cmd;
+	__le32 sts;
+	__le32 state;
+	__le32 reserved2;
+	__le32 ien;
+	__le32 ivect;
+	__le32 refclk;
+	__le32 tmr;
+	__le32 reserved3[4];
+	__le32 simulate;
+	__le32 override;
+	__le32 susp_ctrl;
+	__le32 reserved4;
+	__le32 anasts;
+	__le32 adp_ramp_time;
+	__le32 ctrl1;
+	__le32 ctrl2;
+};
+
+/*  DRD register interface for version v0. */
+struct cdns3_otg_legacy_regs {
+	__le32 cmd;
+	__le32 sts;
+	__le32 state;
+	__le32 refclk;
+	__le32 ien;
+	__le32 ivect;
+	__le32 reserved1[3];
+	__le32 tmr;
+	__le32 reserved2[2];
+	__le32 version;
+	__le32 capabilities;
+	__le32 reserved3[2];
+	__le32 simulate;
+	__le32 reserved4[5];
+	__le32 ctrl1;
+};
+
+/*
+ * Common registers interface for both version of DRD.
+ */
+struct cdns3_otg_common_regs {
+	__le32 cmd;
+	__le32 sts;
+	__le32 state;
+	__le32 different1;
+	__le32 ien;
+	__le32 ivect;
+};
+
+/* CDNS_RID - bitmasks */
+#define CDNS_RID(p)			((p) & GENMASK(15, 0))
+
+/* CDNS_VID - bitmasks */
+#define CDNS_DID(p)			((p) & GENMASK(31, 0))
+
+/* OTGCMD - bitmasks */
+/* "Request the bus for Device mode. */
+#define OTGCMD_DEV_BUS_REQ		BIT(0)
+/* Request the bus for Host mode */
+#define OTGCMD_HOST_BUS_REQ		BIT(1)
+/* Enable OTG mode. */
+#define OTGCMD_OTG_EN			BIT(2)
+/* Disable OTG mode */
+#define OTGCMD_OTG_DIS			BIT(3)
+/*"Configure OTG as A-Device. */
+#define OTGCMD_A_DEV_EN			BIT(4)
+/*"Configure OTG as A-Device. */
+#define OTGCMD_A_DEV_DIS		BIT(5)
+/* Drop the bus for Device mod	e. */
+#define OTGCMD_DEV_BUS_DROP		BIT(8)
+/* Drop the bus for Host mode*/
+#define OTGCMD_HOST_BUS_DROP		BIT(9)
+/* Power Down USBSS-DEV. */
+#define OTGCMD_DEV_POWER_OFF		BIT(11)
+/* Power Down CDNSXHCI. */
+#define OTGCMD_HOST_POWER_OFF		BIT(12)
+
+/* OTGIEN - bitmasks */
+/* ID change interrupt enable */
+#define OTGIEN_ID_CHANGE_INT		BIT(0)
+/* Vbusvalid fall detected interrupt enable.*/
+#define OTGIEN_VBUSVALID_RISE_INT	BIT(4)
+/* Vbusvalid fall detected interrupt enable */
+#define OTGIEN_VBUSVALID_FALL_INT	BIT(5)
+
+/* OTGSTS - bitmasks */
+/*
+ * Current value of the ID pin. It is only valid when idpullup in
+ *  OTGCTRL1_TYPE register is set to '1'.
+ */
+#define OTGSTS_ID_VALUE			BIT(0)
+/* Current value of the vbus_valid */
+#define OTGSTS_VBUS_VALID		BIT(1)
+/* Current value of the b_sess_vld */
+#define OTGSTS_SESSION_VALID		BIT(2)
+/*Device mode is active*/
+#define OTGSTS_DEV_ACTIVE		BIT(3)
+/* Host mode is active. */
+#define OTGSTS_HOST_ACTIVE		BIT(4)
+/* OTG Controller not ready. */
+#define OTGSTS_OTG_NRDY_MASK		BIT(11)
+#define OTGSTS_OTG_NRDY(p)		((p) & OTGSTS_OTG_NRDY_MASK)
+/*
+ * Value of the strap pins.
+ * 000 - no default configuration
+ * 010 - Controller initiall configured as Host
+ * 100 - Controller initially configured as Device
+ */
+#define OTGSTS_STRAP(p)			(((p) & GENMASK(14, 12)) >> 12)
+#define OTGSTS_STRAP_NO_DEFAULT_CFG	0x00
+#define OTGSTS_STRAP_HOST_OTG		0x01
+#define OTGSTS_STRAP_HOST		0x02
+#define OTGSTS_STRAP_GADGET		0x04
+/* Host mode is turned on. */
+#define OTGSTS_XHCI_READY		BIT(26)
+/* "Device mode is turned on .*/
+#define OTGSTS_DEV_READY		BIT(27)
+
+/* OTGSTATE- bitmasks */
+#define OTGSTATE_DEV_STATE_MASK		GENMASK(2, 0)
+#define OTGSTATE_HOST_STATE_MASK	GENMASK(5, 3)
+#define OTGSTATE_HOST_STATE_IDLE	0x0
+#define OTGSTATE_HOST_STATE_VBUS_FALL	0x7
+#define OTGSTATE_HOST_STATE(p)		(((p) & OTGSTATE_HOST_STATE_MASK) >> 3)
+
+/* OTGREFCLK - bitmasks */
+#define OTGREFCLK_STB_CLK_SWITCH_EN	BIT(31)
+
+/* OVERRIDE - bitmasks */
+#define OVERRIDE_IDPULLUP		BIT(0)
+/* Only for CDNS3_CONTROLLER_V0 version */
+#define OVERRIDE_IDPULLUP_V0		BIT(24)
+
+int cdns3_is_host(struct cdns3 *cdns);
+int cdns3_is_device(struct cdns3 *cdns);
+int cdns3_get_id(struct cdns3 *cdns);
+int cdns3_get_vbus(struct cdns3 *cdns);
+int cdns3_drd_init(struct cdns3 *cdns);
+int cdns3_drd_exit(struct cdns3 *cdns);
+int cdns3_drd_update_mode(struct cdns3 *cdns);
+int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on);
+int cdns3_drd_switch_host(struct cdns3 *cdns, int on);
+
+#endif /* __LINUX_CDNS3_DRD */
diff --git a/roms/u-boot/drivers/usb/cdns3/ep0.c b/roms/u-boot/drivers/usb/cdns3/ep0.c
new file mode 100644
index 000000000..acff79ae1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/ep0.c
@@ -0,0 +1,920 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cadence USBSS DRD Driver - gadget side.
+ *
+ * Copyright (C) 2018 Cadence Design Systems.
+ * Copyright (C) 2017-2018 NXP
+ *
+ * Authors: Pawel Jez <pjez@cadence.com>,
+ *          Pawel Laszczak <pawell@cadence.com>
+ *          Peter Chen <peter.chen@nxp.com>
+ */
+
+#include <cpu_func.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <asm/cache.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/usb/composite.h>
+#include <linux/iopoll.h>
+
+#include "gadget.h"
+#include "trace.h"
+
+#define readl_poll_timeout_atomic readl_poll_timeout
+#define usleep_range(a, b) udelay((b))
+
+static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
+};
+
+/**
+ * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware
+ * @priv_dev: extended gadget object
+ * @dma_addr: physical address where data is/will be stored
+ * @length: data length
+ * @erdy: set it to 1 when ERDY packet should be sent -
+ *        exit from flow control state
+ */
+static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev,
+				   dma_addr_t dma_addr,
+				   unsigned int length, int erdy, int zlp)
+{
+	struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
+	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
+
+	priv_ep->trb_pool[0].buffer = TRB_BUFFER(dma_addr);
+	priv_ep->trb_pool[0].length = TRB_LEN(length);
+
+	if (zlp) {
+		priv_ep->trb_pool[0].control = TRB_CYCLE | TRB_TYPE(TRB_NORMAL);
+		priv_ep->trb_pool[1].buffer = TRB_BUFFER(dma_addr);
+		priv_ep->trb_pool[1].length = TRB_LEN(0);
+		priv_ep->trb_pool[1].control = TRB_CYCLE | TRB_IOC |
+		    TRB_TYPE(TRB_NORMAL);
+	} else {
+		priv_ep->trb_pool[0].control = TRB_CYCLE | TRB_IOC |
+		    TRB_TYPE(TRB_NORMAL);
+		priv_ep->trb_pool[1].control = 0;
+	}
+
+	/* Flush both TRBs */
+	flush_dcache_range((unsigned long)priv_ep->trb_pool,
+			   (unsigned long)priv_ep->trb_pool +
+			   ROUND(sizeof(struct cdns3_trb) * 2,
+				 CONFIG_SYS_CACHELINE_SIZE));
+
+	trace_cdns3_prepare_trb(priv_ep, priv_ep->trb_pool);
+
+	cdns3_select_ep(priv_dev, priv_dev->ep0_data_dir);
+
+	writel(EP_STS_TRBERR, &regs->ep_sts);
+	writel(EP_TRADDR_TRADDR(priv_ep->trb_pool_dma), &regs->ep_traddr);
+	trace_cdns3_doorbell_ep0(priv_dev->ep0_data_dir ? "ep0in" : "ep0out",
+				 readl(&regs->ep_traddr));
+
+	/* TRB should be prepared before starting transfer. */
+	writel(EP_CMD_DRDY, &regs->ep_cmd);
+
+	/* Resume controller before arming transfer. */
+	__cdns3_gadget_wakeup(priv_dev);
+
+	if (erdy)
+		writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd);
+}
+
+/**
+ * cdns3_ep0_delegate_req - Returns status of handling setup packet
+ * Setup is handled by gadget driver
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns zero on success or negative value on failure
+ */
+static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev,
+				  struct usb_ctrlrequest *ctrl_req)
+{
+	int ret;
+
+	spin_unlock(&priv_dev->lock);
+	priv_dev->setup_pending = 1;
+	ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req);
+	priv_dev->setup_pending = 0;
+	spin_lock(&priv_dev->lock);
+	return ret;
+}
+
+static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev)
+{
+	priv_dev->ep0_data_dir = 0;
+	priv_dev->ep0_stage = CDNS3_SETUP_STAGE;
+	cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
+			       sizeof(struct usb_ctrlrequest), 0, 0);
+}
+
+static void cdns3_ep0_complete_setup(struct cdns3_device *priv_dev,
+				     u8 send_stall, u8 send_erdy)
+{
+	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
+	struct usb_request *request;
+
+	request = cdns3_next_request(&priv_ep->pending_req_list);
+	if (request)
+		list_del_init(&request->list);
+
+	if (send_stall) {
+		trace_cdns3_halt(priv_ep, send_stall, 0);
+		/* set_stall on ep0 */
+		cdns3_select_ep(priv_dev, 0x00);
+		writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd);
+	} else {
+		cdns3_prepare_setup_packet(priv_dev);
+	}
+
+	priv_dev->ep0_stage = CDNS3_SETUP_STAGE;
+	writel((send_erdy ? EP_CMD_ERDY : 0) | EP_CMD_REQ_CMPL,
+	       &priv_dev->regs->ep_cmd);
+
+	cdns3_allow_enable_l1(priv_dev, 1);
+}
+
+/**
+ * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, USB_GADGET_DELAYED_STATUS on deferred status stage,
+ * error code on error
+ */
+static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev,
+					   struct usb_ctrlrequest *ctrl_req)
+{
+	enum usb_device_state device_state = priv_dev->gadget.state;
+	struct cdns3_endpoint *priv_ep;
+	u32 config = le16_to_cpu(ctrl_req->wValue);
+	int result = 0;
+	int i;
+
+	switch (device_state) {
+	case USB_STATE_ADDRESS:
+		/* Configure non-control EPs */
+		for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) {
+			priv_ep = priv_dev->eps[i];
+			if (!priv_ep)
+				continue;
+
+			if (priv_ep->flags & EP_CLAIMED)
+				cdns3_ep_config(priv_ep);
+		}
+
+		result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
+
+		if (result)
+			return result;
+
+		if (config) {
+			cdns3_set_hw_configuration(priv_dev);
+		} else {
+			cdns3_hw_reset_eps_config(priv_dev);
+			usb_gadget_set_state(&priv_dev->gadget,
+					     USB_STATE_ADDRESS);
+		}
+		break;
+	case USB_STATE_CONFIGURED:
+		result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
+
+		if (!config && !result) {
+			cdns3_hw_reset_eps_config(priv_dev);
+			usb_gadget_set_state(&priv_dev->gadget,
+					     USB_STATE_ADDRESS);
+		}
+		break;
+	default:
+		result = -EINVAL;
+	}
+
+	return result;
+}
+
+/**
+ * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev,
+				     struct usb_ctrlrequest *ctrl_req)
+{
+	enum usb_device_state device_state = priv_dev->gadget.state;
+	u32 reg;
+	u32 addr;
+
+	addr = le16_to_cpu(ctrl_req->wValue);
+
+	if (addr > USB_DEVICE_MAX_ADDRESS) {
+		dev_err(priv_dev->dev,
+			"Device address (%d) cannot be greater than %d\n",
+			addr, USB_DEVICE_MAX_ADDRESS);
+		return -EINVAL;
+	}
+
+	if (device_state == USB_STATE_CONFIGURED) {
+		dev_err(priv_dev->dev,
+			"can't set_address from configured state\n");
+		return -EINVAL;
+	}
+
+	reg = readl(&priv_dev->regs->usb_cmd);
+
+	writel(reg | USB_CMD_FADDR(addr) | USB_CMD_SET_ADDR,
+	       &priv_dev->regs->usb_cmd);
+
+	usb_gadget_set_state(&priv_dev->gadget,
+			     (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT));
+
+	return 0;
+}
+
+/**
+ * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev,
+				    struct usb_ctrlrequest *ctrl)
+{
+	__le16 *response_pkt;
+	u16 usb_status = 0;
+	u32 recip;
+
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		/* self powered */
+		if (priv_dev->is_selfpowered)
+			usb_status = BIT(USB_DEVICE_SELF_POWERED);
+
+		if (priv_dev->wake_up_flag)
+			usb_status |= BIT(USB_DEVICE_REMOTE_WAKEUP);
+
+		if (priv_dev->gadget.speed != USB_SPEED_SUPER)
+			break;
+
+		if (priv_dev->u1_allowed)
+			usb_status |= BIT(USB_DEV_STAT_U1_ENABLED);
+
+		if (priv_dev->u2_allowed)
+			usb_status |= BIT(USB_DEV_STAT_U2_ENABLED);
+
+		break;
+	case USB_RECIP_INTERFACE:
+		return cdns3_ep0_delegate_req(priv_dev, ctrl);
+	case USB_RECIP_ENDPOINT:
+		/* check if endpoint is stalled */
+		cdns3_select_ep(priv_dev, ctrl->wIndex);
+		if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts)))
+			usb_status =  BIT(USB_ENDPOINT_HALT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	response_pkt = (__le16 *)priv_dev->setup_buf;
+	*response_pkt = cpu_to_le16(usb_status);
+
+	/* Flush setup response */
+	flush_dcache_range((unsigned long)priv_dev->setup_buf,
+			   (unsigned long)priv_dev->setup_buf +
+			   ROUND(sizeof(struct usb_ctrlrequest),
+				 CONFIG_SYS_CACHELINE_SIZE));
+
+	cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
+			       sizeof(*response_pkt), 1, 0);
+	return 0;
+}
+
+static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev,
+					   struct usb_ctrlrequest *ctrl,
+					   int set)
+{
+	enum usb_device_state state;
+	enum usb_device_speed speed;
+	int ret = 0;
+	u16 tmode;
+
+	state = priv_dev->gadget.state;
+	speed = priv_dev->gadget.speed;
+
+	switch (ctrl->wValue) {
+	case USB_DEVICE_REMOTE_WAKEUP:
+		priv_dev->wake_up_flag = !!set;
+		break;
+	case USB_DEVICE_U1_ENABLE:
+		if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER)
+			return -EINVAL;
+
+		priv_dev->u1_allowed = !!set;
+		break;
+	case USB_DEVICE_U2_ENABLE:
+		if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER)
+			return -EINVAL;
+
+		priv_dev->u2_allowed = !!set;
+		break;
+	case USB_DEVICE_LTM_ENABLE:
+		ret = -EINVAL;
+		break;
+	case USB_DEVICE_TEST_MODE:
+		if (state != USB_STATE_CONFIGURED || speed > USB_SPEED_HIGH)
+			return -EINVAL;
+
+		tmode = le16_to_cpu(ctrl->wIndex);
+
+		if (!set || (tmode & 0xff) != 0)
+			return -EINVAL;
+
+		switch (tmode >> 8) {
+		case TEST_J:
+		case TEST_K:
+		case TEST_SE0_NAK:
+		case TEST_PACKET:
+			cdns3_ep0_complete_setup(priv_dev, 0, 1);
+			/**
+			 *  Little delay to give the controller some time
+			 * for sending status stage.
+			 * This time should be less then 3ms.
+			 */
+			usleep_range(1000, 2000);
+			cdns3_set_register_bit(&priv_dev->regs->usb_cmd,
+					       USB_CMD_STMODE |
+					       USB_STS_TMODE_SEL(tmode - 1));
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cdns3_ep0_feature_handle_intf(struct cdns3_device *priv_dev,
+					 struct usb_ctrlrequest *ctrl,
+					 int set)
+{
+	u32 wValue;
+	int ret = 0;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+
+	switch (wValue) {
+	case USB_INTRF_FUNC_SUSPEND:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev,
+					     struct usb_ctrlrequest *ctrl,
+					     int set)
+{
+	struct cdns3_endpoint *priv_ep;
+	int ret = 0;
+	u8 index;
+
+	if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT)
+		return -EINVAL;
+
+	if (!(ctrl->wIndex & ~USB_DIR_IN))
+		return 0;
+
+	index = cdns3_ep_addr_to_index(ctrl->wIndex);
+	priv_ep = priv_dev->eps[index];
+
+	cdns3_select_ep(priv_dev, ctrl->wIndex);
+
+	if (set)
+		__cdns3_gadget_ep_set_halt(priv_ep);
+	else if (!(priv_ep->flags & EP_WEDGE))
+		ret = __cdns3_gadget_ep_clear_halt(priv_ep);
+
+	cdns3_select_ep(priv_dev, 0x00);
+
+	return ret;
+}
+
+/**
+ * cdns3_req_ep0_handle_feature -
+ * Handling of GET/SET_FEATURE standard USB request
+ *
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ * @set: must be set to 1 for SET_FEATURE request
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns3_req_ep0_handle_feature(struct cdns3_device *priv_dev,
+					struct usb_ctrlrequest *ctrl,
+					int set)
+{
+	int ret = 0;
+	u32 recip;
+
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		ret = cdns3_ep0_feature_handle_device(priv_dev, ctrl, set);
+		break;
+	case USB_RECIP_INTERFACE:
+		ret = cdns3_ep0_feature_handle_intf(priv_dev, ctrl, set);
+		break;
+	case USB_RECIP_ENDPOINT:
+		ret = cdns3_ep0_feature_handle_endpoint(priv_dev, ctrl, set);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * cdns3_req_ep0_set_sel - Handling of SET_SEL standard USB request
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns3_req_ep0_set_sel(struct cdns3_device *priv_dev,
+				 struct usb_ctrlrequest *ctrl_req)
+{
+	if (priv_dev->gadget.state < USB_STATE_ADDRESS)
+		return -EINVAL;
+
+	if (ctrl_req->wLength != 6) {
+		dev_err(priv_dev->dev, "Set SEL should be 6 bytes, got %d\n",
+			ctrl_req->wLength);
+		return -EINVAL;
+	}
+
+	cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 6, 1, 0);
+	return 0;
+}
+
+/**
+ * cdns3_req_ep0_set_isoch_delay -
+ * Handling of GET_ISOCH_DELAY standard USB request
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns3_req_ep0_set_isoch_delay(struct cdns3_device *priv_dev,
+					 struct usb_ctrlrequest *ctrl_req)
+{
+	if (ctrl_req->wIndex || ctrl_req->wLength)
+		return -EINVAL;
+
+	priv_dev->isoch_delay = ctrl_req->wValue;
+
+	return 0;
+}
+
+/**
+ * cdns3_ep0_standard_request - Handling standard USB requests
+ * @priv_dev: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns3_ep0_standard_request(struct cdns3_device *priv_dev,
+				      struct usb_ctrlrequest *ctrl_req)
+{
+	int ret;
+
+	switch (ctrl_req->bRequest) {
+	case USB_REQ_SET_ADDRESS:
+		ret = cdns3_req_ep0_set_address(priv_dev, ctrl_req);
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		ret = cdns3_req_ep0_set_configuration(priv_dev, ctrl_req);
+		break;
+	case USB_REQ_GET_STATUS:
+		ret = cdns3_req_ep0_get_status(priv_dev, ctrl_req);
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 1);
+		break;
+	case USB_REQ_SET_SEL:
+		ret = cdns3_req_ep0_set_sel(priv_dev, ctrl_req);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		ret = cdns3_req_ep0_set_isoch_delay(priv_dev, ctrl_req);
+		break;
+	default:
+		ret = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
+		break;
+	}
+
+	return ret;
+}
+
+static void __pending_setup_status_handler(struct cdns3_device *priv_dev)
+{
+	struct usb_request *request = priv_dev->pending_status_request;
+
+	if (priv_dev->status_completion_no_call && request &&
+	    request->complete) {
+		request->complete(&priv_dev->eps[0]->endpoint, request);
+		priv_dev->status_completion_no_call = 0;
+	}
+}
+
+void cdns3_pending_setup_status_handler(struct work_struct *work)
+{
+	struct cdns3_device *priv_dev = container_of(work, struct cdns3_device,
+			pending_status_wq);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+	__pending_setup_status_handler(priv_dev);
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+}
+
+/**
+ * cdns3_ep0_setup_phase - Handling setup USB requests
+ * @priv_dev: extended gadget object
+ */
+static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev)
+{
+	struct usb_ctrlrequest *ctrl = priv_dev->setup_buf;
+	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
+	int result;
+
+	/* Invalidate Setup Packet received */
+	invalidate_dcache_range(priv_dev->setup_dma,
+				priv_dev->setup_dma + ARCH_DMA_MINALIGN);
+
+	priv_dev->ep0_data_dir = ctrl->bRequestType & USB_DIR_IN;
+
+	trace_cdns3_ctrl_req(ctrl);
+
+	if (!list_empty(&priv_ep->pending_req_list)) {
+		struct usb_request *request;
+
+		request = cdns3_next_request(&priv_ep->pending_req_list);
+		priv_ep->dir = priv_dev->ep0_data_dir;
+		cdns3_gadget_giveback(priv_ep, to_cdns3_request(request),
+				      -ECONNRESET);
+	}
+
+	if (le16_to_cpu(ctrl->wLength))
+		priv_dev->ep0_stage = CDNS3_DATA_STAGE;
+	else
+		priv_dev->ep0_stage = CDNS3_STATUS_STAGE;
+
+	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		result = cdns3_ep0_standard_request(priv_dev, ctrl);
+	else
+		result = cdns3_ep0_delegate_req(priv_dev, ctrl);
+
+	if (result == USB_GADGET_DELAYED_STATUS)
+		return;
+
+	if (result < 0)
+		cdns3_ep0_complete_setup(priv_dev, 1, 1);
+	else if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE)
+		cdns3_ep0_complete_setup(priv_dev, 0, 1);
+}
+
+static void cdns3_transfer_completed(struct cdns3_device *priv_dev)
+{
+	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
+
+	if (!list_empty(&priv_ep->pending_req_list)) {
+		struct usb_request *request;
+
+		trace_cdns3_complete_trb(priv_ep, priv_ep->trb_pool);
+		request = cdns3_next_request(&priv_ep->pending_req_list);
+
+		/* Invalidate TRB before accessing it */
+		invalidate_dcache_range((unsigned long)priv_ep->trb_pool,
+					(unsigned long)priv_ep->trb_pool +
+					ROUND(sizeof(struct cdns3_trb),
+					      CONFIG_SYS_CACHELINE_SIZE));
+
+		request->actual =
+			TRB_LEN(le32_to_cpu(priv_ep->trb_pool->length));
+
+		priv_ep->dir = priv_dev->ep0_data_dir;
+		cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), 0);
+	}
+
+	cdns3_ep0_complete_setup(priv_dev, 0, 0);
+}
+
+/**
+ * cdns3_check_new_setup - Check if controller receive new SETUP packet.
+ * @priv_dev: extended gadget object
+ *
+ * The SETUP packet can be kept in on-chip memory or in system memory.
+ */
+static bool cdns3_check_new_setup(struct cdns3_device *priv_dev)
+{
+	u32 ep_sts_reg;
+
+	cdns3_select_ep(priv_dev, 0 | USB_DIR_OUT);
+	ep_sts_reg = readl(&priv_dev->regs->ep_sts);
+
+	return !!(ep_sts_reg & (EP_STS_SETUP | EP_STS_STPWAIT));
+}
+
+/**
+ * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
+ * @priv_dev: extended gadget object
+ * @dir: USB_DIR_IN for IN direction, USB_DIR_OUT for OUT direction
+ */
+void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
+{
+	u32 ep_sts_reg;
+
+	cdns3_select_ep(priv_dev, dir);
+
+	ep_sts_reg = readl(&priv_dev->regs->ep_sts);
+	writel(ep_sts_reg, &priv_dev->regs->ep_sts);
+
+	trace_cdns3_ep0_irq(priv_dev, ep_sts_reg);
+
+	__pending_setup_status_handler(priv_dev);
+
+	if (ep_sts_reg & EP_STS_SETUP)
+		priv_dev->wait_for_setup = 1;
+
+	if (priv_dev->wait_for_setup && ep_sts_reg & EP_STS_IOC) {
+		priv_dev->wait_for_setup = 0;
+		cdns3_allow_enable_l1(priv_dev, 0);
+		cdns3_ep0_setup_phase(priv_dev);
+	} else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
+		priv_dev->ep0_data_dir = dir;
+		cdns3_transfer_completed(priv_dev);
+	}
+
+	if (ep_sts_reg & EP_STS_DESCMIS) {
+		if (dir == 0 && !priv_dev->setup_pending)
+			cdns3_prepare_setup_packet(priv_dev);
+	}
+}
+
+/**
+ * cdns3_gadget_ep0_enable
+ * Function shouldn't be called by gadget driver,
+ * endpoint 0 is allways active
+ */
+static int cdns3_gadget_ep0_enable(struct usb_ep *ep,
+				   const struct usb_endpoint_descriptor *desc)
+{
+	return -EINVAL;
+}
+
+/**
+ * cdns3_gadget_ep0_disable
+ * Function shouldn't be called by gadget driver,
+ * endpoint 0 is allways active
+ */
+static int cdns3_gadget_ep0_disable(struct usb_ep *ep)
+{
+	return -EINVAL;
+}
+
+/**
+ * cdns3_gadget_ep0_set_halt
+ * @ep: pointer to endpoint zero object
+ * @value: 1 for set stall, 0 for clear stall
+ *
+ * Returns 0
+ */
+static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+	/* TODO */
+	return 0;
+}
+
+/**
+ * cdns3_gadget_ep0_queue Transfer data on endpoint zero
+ * @ep: pointer to endpoint zero object
+ * @request: pointer to request object
+ * @gfp_flags: gfp flags
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
+				  struct usb_request *request,
+				  gfp_t gfp_flags)
+{
+	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	unsigned long flags;
+	int erdy_sent = 0;
+	int ret = 0;
+	u8 zlp = 0;
+
+	trace_cdns3_ep0_queue(priv_dev, request);
+
+	/* cancel the request if controller receive new SETUP packet. */
+	if (cdns3_check_new_setup(priv_dev))
+		return -ECONNRESET;
+
+	/* send STATUS stage. Should be called only for SET_CONFIGURATION */
+	if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) {
+		spin_lock_irqsave(&priv_dev->lock, flags);
+		cdns3_select_ep(priv_dev, 0x00);
+
+		erdy_sent = !priv_dev->hw_configured_flag;
+		cdns3_set_hw_configuration(priv_dev);
+
+		if (!erdy_sent)
+			cdns3_ep0_complete_setup(priv_dev, 0, 1);
+
+		cdns3_allow_enable_l1(priv_dev, 1);
+
+		request->actual = 0;
+		priv_dev->status_completion_no_call = true;
+		priv_dev->pending_status_request = request;
+		spin_unlock_irqrestore(&priv_dev->lock, flags);
+
+		/*
+		 * Since there is no completion interrupt for status stage,
+		 * it needs to call ->completion in software after
+		 * ep0_queue is back.
+		 */
+#ifndef __UBOOT__
+		queue_work(system_freezable_wq, &priv_dev->pending_status_wq);
+#else
+		__pending_setup_status_handler(priv_dev);
+#endif
+		return 0;
+	}
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+	if (!list_empty(&priv_ep->pending_req_list)) {
+		dev_err(priv_dev->dev,
+			"can't handle multiple requests for ep0\n");
+		spin_unlock_irqrestore(&priv_dev->lock, flags);
+		return -EBUSY;
+	}
+
+	ret = usb_gadget_map_request(&priv_dev->gadget, request,
+				     priv_dev->ep0_data_dir);
+	if (ret) {
+		spin_unlock_irqrestore(&priv_dev->lock, flags);
+		dev_err(priv_dev->dev, "failed to map request\n");
+		return -EINVAL;
+	}
+
+	request->status = -EINPROGRESS;
+	list_add_tail(&request->list, &priv_ep->pending_req_list);
+
+	if (request->zero && request->length &&
+	    (request->length % ep->maxpacket == 0))
+		zlp = 1;
+
+	cdns3_ep0_run_transfer(priv_dev, request->dma, request->length, 1, zlp);
+
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+
+	return ret;
+}
+
+/**
+ * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint
+ * @ep: endpoint object
+ *
+ * Returns 0
+ */
+int cdns3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
+
+	dev_dbg(priv_ep->cdns3_dev->dev, "Wedge for %s\n", ep->name);
+	cdns3_gadget_ep_set_halt(ep, 1);
+	priv_ep->flags |= EP_WEDGE;
+
+	return 0;
+}
+
+const struct usb_ep_ops cdns3_gadget_ep0_ops = {
+	.enable = cdns3_gadget_ep0_enable,
+	.disable = cdns3_gadget_ep0_disable,
+	.alloc_request = cdns3_gadget_ep_alloc_request,
+	.free_request = cdns3_gadget_ep_free_request,
+	.queue = cdns3_gadget_ep0_queue,
+	.dequeue = cdns3_gadget_ep_dequeue,
+	.set_halt = cdns3_gadget_ep0_set_halt,
+	.set_wedge = cdns3_gadget_ep_set_wedge,
+};
+
+/**
+ * cdns3_ep0_config - Configures default endpoint
+ * @priv_dev: extended gadget object
+ *
+ * Functions sets parameters: maximal packet size and enables interrupts
+ */
+void cdns3_ep0_config(struct cdns3_device *priv_dev)
+{
+	struct cdns3_usb_regs __iomem *regs;
+	struct cdns3_endpoint *priv_ep;
+	u32 max_packet_size = 64;
+
+	regs = priv_dev->regs;
+
+	if (priv_dev->gadget.speed == USB_SPEED_SUPER)
+		max_packet_size = 512;
+
+	priv_ep = priv_dev->eps[0];
+
+	if (!list_empty(&priv_ep->pending_req_list)) {
+		struct usb_request *request;
+
+		request = cdns3_next_request(&priv_ep->pending_req_list);
+		list_del_init(&request->list);
+	}
+
+	priv_dev->u1_allowed = 0;
+	priv_dev->u2_allowed = 0;
+
+	priv_dev->gadget.ep0->maxpacket = max_packet_size;
+	cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
+
+	/* init ep out */
+	cdns3_select_ep(priv_dev, USB_DIR_OUT);
+
+	if (priv_dev->dev_ver >= DEV_VER_V3) {
+		cdns3_set_register_bit(&priv_dev->regs->dtrans,
+				       BIT(0) | BIT(16));
+		cdns3_set_register_bit(&priv_dev->regs->tdl_from_trb,
+				       BIT(0) | BIT(16));
+	}
+
+	writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size),
+	       &regs->ep_cfg);
+
+	writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN,
+	       &regs->ep_sts_en);
+
+	/* init ep in */
+	cdns3_select_ep(priv_dev, USB_DIR_IN);
+
+	writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size),
+	       &regs->ep_cfg);
+
+	writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, &regs->ep_sts_en);
+
+	cdns3_set_register_bit(&regs->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS);
+}
+
+/**
+ * cdns3_init_ep0 Initializes software endpoint 0 of gadget
+ * @priv_dev: extended gadget object
+ * @ep_priv: extended endpoint object
+ *
+ * Returns 0 on success else error code.
+ */
+int cdns3_init_ep0(struct cdns3_device *priv_dev,
+		   struct cdns3_endpoint *priv_ep)
+{
+	sprintf(priv_ep->name, "ep0");
+
+	/* fill linux fields */
+	priv_ep->endpoint.ops = &cdns3_gadget_ep0_ops;
+	priv_ep->endpoint.maxburst = 1;
+	usb_ep_set_maxpacket_limit(&priv_ep->endpoint,
+				   CDNS3_EP0_MAX_PACKET_LIMIT);
+#ifndef __UBOOT__
+	priv_ep->endpoint.address = 0;
+#endif
+	priv_ep->endpoint.caps.type_control = 1;
+	priv_ep->endpoint.caps.dir_in = 1;
+	priv_ep->endpoint.caps.dir_out = 1;
+	priv_ep->endpoint.name = priv_ep->name;
+	priv_ep->endpoint.desc = &cdns3_gadget_ep0_desc;
+	priv_dev->gadget.ep0 = &priv_ep->endpoint;
+	priv_ep->type = USB_ENDPOINT_XFER_CONTROL;
+
+	return cdns3_allocate_trb_pool(priv_ep);
+}
diff --git a/roms/u-boot/drivers/usb/cdns3/gadget-export.h b/roms/u-boot/drivers/usb/cdns3/gadget-export.h
new file mode 100644
index 000000000..577469eee
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/gadget-export.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence USBSS DRD Driver - Gadget Export APIs.
+ *
+ * Copyright (C) 2017 NXP
+ * Copyright (C) 2017-2018 NXP
+ *
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ */
+#ifndef __LINUX_CDNS3_GADGET_EXPORT
+#define __LINUX_CDNS3_GADGET_EXPORT
+
+#ifdef CONFIG_USB_CDNS3_GADGET
+
+int cdns3_gadget_init(struct cdns3 *cdns);
+void cdns3_gadget_exit(struct cdns3 *cdns);
+#else
+
+static inline int cdns3_gadget_init(struct cdns3 *cdns)
+{
+	return -ENXIO;
+}
+
+static inline void cdns3_gadget_exit(struct cdns3 *cdns) { }
+
+#endif
+
+#endif /* __LINUX_CDNS3_GADGET_EXPORT */
diff --git a/roms/u-boot/drivers/usb/cdns3/gadget.c b/roms/u-boot/drivers/usb/cdns3/gadget.c
new file mode 100644
index 000000000..83dbb5a10
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/gadget.c
@@ -0,0 +1,2764 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cadence USBSS DRD Driver - gadget side.
+ *
+ * Copyright (C) 2018-2019 Cadence Design Systems.
+ * Copyright (C) 2017-2018 NXP
+ *
+ * Authors: Pawel Jez <pjez@cadence.com>,
+ *          Pawel Laszczak <pawell@cadence.com>
+ *          Peter Chen <peter.chen@nxp.com>
+ */
+
+/*
+ * Work around 1:
+ * At some situations, the controller may get stale data address in TRB
+ * at below sequences:
+ * 1. Controller read TRB includes data address
+ * 2. Software updates TRBs includes data address and Cycle bit
+ * 3. Controller read TRB which includes Cycle bit
+ * 4. DMA run with stale data address
+ *
+ * To fix this problem, driver needs to make the first TRB in TD as invalid.
+ * After preparing all TRBs driver needs to check the position of DMA and
+ * if the DMA point to the first just added TRB and doorbell is 1,
+ * then driver must defer making this TRB as valid. This TRB will be make
+ * as valid during adding next TRB only if DMA is stopped or at TRBERR
+ * interrupt.
+ *
+ * Issue has been fixed in DEV_VER_V3 version of controller.
+ *
+ * Work around 2:
+ * Controller for OUT endpoints has shared on-chip buffers for all incoming
+ * packets, including ep0out. It's FIFO buffer, so packets must be handle by DMA
+ * in correct order. If the first packet in the buffer will not be handled,
+ * then the following packets directed for other endpoints and  functions
+ * will be blocked.
+ * Additionally the packets directed to one endpoint can block entire on-chip
+ * buffers. In this case transfer to other endpoints also will blocked.
+ *
+ * To resolve this issue after raising the descriptor missing interrupt
+ * driver prepares internal usb_request object and use it to arm DMA transfer.
+ *
+ * The problematic situation was observed in case when endpoint has been enabled
+ * but no usb_request were queued. Driver try detects such endpoints and will
+ * use this workaround only for these endpoint.
+ *
+ * Driver use limited number of buffer. This number can be set by macro
+ * CDNS3_WA2_NUM_BUFFERS.
+ *
+ * Such blocking situation was observed on ACM gadget. For this function
+ * host send OUT data packet but ACM function is not prepared for this packet.
+ * It's cause that buffer placed in on chip memory block transfer to other
+ * endpoints.
+ *
+ * Issue has been fixed in DEV_VER_V2 version of controller.
+ *
+ */
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/usb/gadget.h>
+#include <linux/compat.h>
+#include <linux/iopoll.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitmap.h>
+#include <linux/bug.h>
+
+#include "core.h"
+#include "gadget-export.h"
+#include "gadget.h"
+#include "trace.h"
+#include "drd.h"
+
+#define readl_poll_timeout_atomic readl_poll_timeout
+#define usleep_range(a, b) udelay((b))
+
+static int __cdns3_gadget_ep_queue(struct usb_ep *ep,
+				   struct usb_request *request,
+				   gfp_t gfp_flags);
+
+/**
+ * cdns3_set_register_bit - set bit in given register.
+ * @ptr: address of device controller register to be read and changed
+ * @mask: bits requested to set
+ */
+void cdns3_set_register_bit(void __iomem *ptr, u32 mask)
+{
+	mask = readl(ptr) | mask;
+	writel(mask, ptr);
+}
+
+/**
+ * cdns3_ep_addr_to_index - Macro converts endpoint address to
+ * index of endpoint object in cdns3_device.eps[] container
+ * @ep_addr: endpoint address for which endpoint object is required
+ *
+ */
+u8 cdns3_ep_addr_to_index(u8 ep_addr)
+{
+	return (((ep_addr & 0x7F)) + ((ep_addr & USB_DIR_IN) ? 16 : 0));
+}
+
+static int cdns3_get_dma_pos(struct cdns3_device *priv_dev,
+			     struct cdns3_endpoint *priv_ep)
+{
+	int dma_index;
+
+	dma_index = readl(&priv_dev->regs->ep_traddr) - priv_ep->trb_pool_dma;
+
+	return dma_index / TRB_SIZE;
+}
+
+/**
+ * cdns3_next_request - returns next request from list
+ * @list: list containing requests
+ *
+ * Returns request or NULL if no requests in list
+ */
+struct usb_request *cdns3_next_request(struct list_head *list)
+{
+	return list_first_entry_or_null(list, struct usb_request, list);
+}
+
+/**
+ * cdns3_next_align_buf - returns next buffer from list
+ * @list: list containing buffers
+ *
+ * Returns buffer or NULL if no buffers in list
+ */
+struct cdns3_aligned_buf *cdns3_next_align_buf(struct list_head *list)
+{
+	return list_first_entry_or_null(list, struct cdns3_aligned_buf, list);
+}
+
+/**
+ * cdns3_next_priv_request - returns next request from list
+ * @list: list containing requests
+ *
+ * Returns request or NULL if no requests in list
+ */
+struct cdns3_request *cdns3_next_priv_request(struct list_head *list)
+{
+	return list_first_entry_or_null(list, struct cdns3_request, list);
+}
+
+/**
+ * select_ep - selects endpoint
+ * @priv_dev:  extended gadget object
+ * @ep: endpoint address
+ */
+void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep)
+{
+	if (priv_dev->selected_ep == ep)
+		return;
+
+	priv_dev->selected_ep = ep;
+	writel(ep, &priv_dev->regs->ep_sel);
+}
+
+dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep,
+				 struct cdns3_trb *trb)
+{
+	u32 offset = (char *)trb - (char *)priv_ep->trb_pool;
+
+	return priv_ep->trb_pool_dma + offset;
+}
+
+int cdns3_ring_size(struct cdns3_endpoint *priv_ep)
+{
+	switch (priv_ep->type) {
+	case USB_ENDPOINT_XFER_ISOC:
+		return TRB_ISO_RING_SIZE;
+	case USB_ENDPOINT_XFER_CONTROL:
+		return TRB_CTRL_RING_SIZE;
+	default:
+		return TRB_RING_SIZE;
+	}
+}
+
+/**
+ * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint
+ * @priv_ep:  endpoint object
+ *
+ * Function will return 0 on success or -ENOMEM on allocation error
+ */
+int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep)
+{
+	int ring_size = cdns3_ring_size(priv_ep);
+	struct cdns3_trb *link_trb;
+
+	if (!priv_ep->trb_pool) {
+		priv_ep->trb_pool =
+		dma_alloc_coherent(ring_size,
+				   (unsigned long *)&priv_ep->trb_pool_dma);
+		if (!priv_ep->trb_pool)
+			return -ENOMEM;
+	} else {
+		memset(priv_ep->trb_pool, 0, ring_size);
+	}
+
+	if (!priv_ep->num)
+		return 0;
+
+	priv_ep->num_trbs = ring_size / TRB_SIZE;
+	/* Initialize the last TRB as Link TRB. */
+	link_trb = (priv_ep->trb_pool + (priv_ep->num_trbs - 1));
+	link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma);
+	link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | TRB_TOGGLE;
+
+	return 0;
+}
+
+static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep)
+{
+	if (priv_ep->trb_pool) {
+		dma_free_coherent(priv_ep->trb_pool);
+		priv_ep->trb_pool = NULL;
+	}
+}
+
+/**
+ * cdns3_ep_stall_flush - Stalls and flushes selected endpoint
+ * @priv_ep: endpoint object
+ *
+ * Endpoint must be selected before call to this function
+ */
+static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	int val;
+
+	trace_cdns3_halt(priv_ep, 1, 1);
+
+	writel(EP_CMD_DFLUSH | EP_CMD_ERDY | EP_CMD_SSTALL,
+	       &priv_dev->regs->ep_cmd);
+
+	/* wait for DFLUSH cleared */
+	readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
+				  !(val & EP_CMD_DFLUSH), 1000);
+	priv_ep->flags |= EP_STALLED;
+	priv_ep->flags &= ~EP_STALL_PENDING;
+}
+
+/**
+ * cdns3_hw_reset_eps_config - reset endpoints configuration kept by controller.
+ * @priv_dev: extended gadget object
+ */
+void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev)
+{
+	writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf);
+
+	cdns3_allow_enable_l1(priv_dev, 0);
+	priv_dev->hw_configured_flag = 0;
+	priv_dev->onchip_used_size = 0;
+	priv_dev->out_mem_is_allocated = 0;
+	priv_dev->wait_for_setup = 0;
+}
+
+/**
+ * cdns3_ep_inc_trb - increment a trb index.
+ * @index: Pointer to the TRB index to increment.
+ * @cs: Cycle state
+ * @trb_in_seg: number of TRBs in segment
+ *
+ * The index should never point to the link TRB. After incrementing,
+ * if it is point to the link TRB, wrap around to the beginning and revert
+ * cycle state bit The
+ * link TRB is always at the last TRB entry.
+ */
+static void cdns3_ep_inc_trb(int *index, u8 *cs, int trb_in_seg)
+{
+	(*index)++;
+	if (*index == (trb_in_seg - 1)) {
+		*index = 0;
+		*cs ^=  1;
+	}
+}
+
+/**
+ * cdns3_ep_inc_enq - increment endpoint's enqueue pointer
+ * @priv_ep: The endpoint whose enqueue pointer we're incrementing
+ */
+static void cdns3_ep_inc_enq(struct cdns3_endpoint *priv_ep)
+{
+	priv_ep->free_trbs--;
+	cdns3_ep_inc_trb(&priv_ep->enqueue, &priv_ep->pcs, priv_ep->num_trbs);
+}
+
+/**
+ * cdns3_ep_inc_deq - increment endpoint's dequeue pointer
+ * @priv_ep: The endpoint whose dequeue pointer we're incrementing
+ */
+static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep)
+{
+	priv_ep->free_trbs++;
+	cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs, priv_ep->num_trbs);
+}
+
+void cdns3_move_deq_to_next_trb(struct cdns3_request *priv_req)
+{
+	struct cdns3_endpoint *priv_ep = priv_req->priv_ep;
+	int current_trb = priv_req->start_trb;
+
+	while (current_trb != priv_req->end_trb) {
+		cdns3_ep_inc_deq(priv_ep);
+		current_trb = priv_ep->dequeue;
+	}
+
+	cdns3_ep_inc_deq(priv_ep);
+}
+
+/**
+ * cdns3_allow_enable_l1 - enable/disable permits to transition to L1.
+ * @priv_dev: Extended gadget object
+ * @enable: Enable/disable permit to transition to L1.
+ *
+ * If bit USB_CONF_L1EN is set and device receive Extended Token packet,
+ * then controller answer with ACK handshake.
+ * If bit USB_CONF_L1DS is set and device receive Extended Token packet,
+ * then controller answer with NYET handshake.
+ */
+void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable)
+{
+	if (enable)
+		writel(USB_CONF_L1EN, &priv_dev->regs->usb_conf);
+	else
+		writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf);
+}
+
+enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev)
+{
+	u32 reg;
+
+	reg = readl(&priv_dev->regs->usb_sts);
+
+	if (DEV_SUPERSPEED(reg))
+		return USB_SPEED_SUPER;
+	else if (DEV_HIGHSPEED(reg))
+		return USB_SPEED_HIGH;
+	else if (DEV_FULLSPEED(reg))
+		return USB_SPEED_FULL;
+	else if (DEV_LOWSPEED(reg))
+		return USB_SPEED_LOW;
+	return USB_SPEED_UNKNOWN;
+}
+
+/**
+ * cdns3_start_all_request - add to ring all request not started
+ * @priv_dev: Extended gadget object
+ * @priv_ep: The endpoint for whom request will be started.
+ *
+ * Returns return ENOMEM if transfer ring i not enough TRBs to start
+ *         all requests.
+ */
+static int cdns3_start_all_request(struct cdns3_device *priv_dev,
+				   struct cdns3_endpoint *priv_ep)
+{
+	struct usb_request *request;
+	int ret = 0;
+
+	while (!list_empty(&priv_ep->deferred_req_list)) {
+		request = cdns3_next_request(&priv_ep->deferred_req_list);
+
+		ret = cdns3_ep_run_transfer(priv_ep, request);
+		if (ret)
+			return ret;
+
+		list_del(&request->list);
+		list_add_tail(&request->list,
+			      &priv_ep->pending_req_list);
+	}
+
+	priv_ep->flags &= ~EP_RING_FULL;
+	return ret;
+}
+
+/*
+ * WA2: Set flag for all not ISOC OUT endpoints. If this flag is set
+ * driver try to detect whether endpoint need additional internal
+ * buffer for unblocking on-chip FIFO buffer. This flag will be cleared
+ * if before first DESCMISS interrupt the DMA will be armed.
+ */
+#define cdns3_wa2_enable_detection(priv_dev, ep_priv, reg) do { \
+	if (!priv_ep->dir && priv_ep->type != USB_ENDPOINT_XFER_ISOC) { \
+		priv_ep->flags |= EP_QUIRK_EXTRA_BUF_DET; \
+		(reg) |= EP_STS_EN_DESCMISEN; \
+	} } while (0)
+
+/**
+ * cdns3_wa2_descmiss_copy_data copy data from internal requests to
+ * request queued by class driver.
+ * @priv_ep: extended endpoint object
+ * @request: request object
+ */
+static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep,
+					 struct usb_request *request)
+{
+	struct usb_request *descmiss_req;
+	struct cdns3_request *descmiss_priv_req;
+
+	while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
+		int chunk_end;
+		int length;
+
+		descmiss_priv_req =
+			cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
+		descmiss_req = &descmiss_priv_req->request;
+
+		/* driver can't touch pending request */
+		if (descmiss_priv_req->flags & REQUEST_PENDING)
+			break;
+
+		chunk_end = descmiss_priv_req->flags & REQUEST_INTERNAL_CH;
+		length = request->actual + descmiss_req->actual;
+
+		request->status = descmiss_req->status;
+
+		if (length <= request->length) {
+			memcpy(&((u8 *)request->buf)[request->actual],
+			       descmiss_req->buf,
+			       descmiss_req->actual);
+			request->actual = length;
+		} else {
+			/* It should never occur */
+			request->status = -ENOMEM;
+		}
+
+		list_del_init(&descmiss_priv_req->list);
+
+		kfree(descmiss_req->buf);
+		cdns3_gadget_ep_free_request(&priv_ep->endpoint, descmiss_req);
+		--priv_ep->wa2_counter;
+
+		if (!chunk_end)
+			break;
+	}
+}
+
+struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_dev,
+					      struct cdns3_endpoint *priv_ep,
+					      struct cdns3_request *priv_req)
+{
+	if (priv_ep->flags & EP_QUIRK_EXTRA_BUF_EN &&
+	    priv_req->flags & REQUEST_INTERNAL) {
+		struct usb_request *req;
+
+		req = cdns3_next_request(&priv_ep->deferred_req_list);
+
+		priv_ep->descmis_req = NULL;
+
+		if (!req)
+			return NULL;
+
+		cdns3_wa2_descmiss_copy_data(priv_ep, req);
+		if (!(priv_ep->flags & EP_QUIRK_END_TRANSFER) &&
+		    req->length != req->actual) {
+			/* wait for next part of transfer */
+			return NULL;
+		}
+
+		if (req->status == -EINPROGRESS)
+			req->status = 0;
+
+		list_del_init(&req->list);
+		cdns3_start_all_request(priv_dev, priv_ep);
+		return req;
+	}
+
+	return &priv_req->request;
+}
+
+int cdns3_wa2_gadget_ep_queue(struct cdns3_device *priv_dev,
+			      struct cdns3_endpoint *priv_ep,
+			      struct cdns3_request *priv_req)
+{
+	int deferred = 0;
+
+	/*
+	 * If transfer was queued before DESCMISS appear than we
+	 * can disable handling of DESCMISS interrupt. Driver assumes that it
+	 * can disable special treatment for this endpoint.
+	 */
+	if (priv_ep->flags & EP_QUIRK_EXTRA_BUF_DET) {
+		u32 reg;
+
+		cdns3_select_ep(priv_dev, priv_ep->num | priv_ep->dir);
+		priv_ep->flags &= ~EP_QUIRK_EXTRA_BUF_DET;
+		reg = readl(&priv_dev->regs->ep_sts_en);
+		reg &= ~EP_STS_EN_DESCMISEN;
+		trace_cdns3_wa2(priv_ep, "workaround disabled\n");
+		writel(reg, &priv_dev->regs->ep_sts_en);
+	}
+
+	if (priv_ep->flags & EP_QUIRK_EXTRA_BUF_EN) {
+		u8 pending_empty = list_empty(&priv_ep->pending_req_list);
+		u8 descmiss_empty = list_empty(&priv_ep->wa2_descmiss_req_list);
+
+		/*
+		 *  DESCMISS transfer has been finished, so data will be
+		 *  directly copied from internal allocated usb_request
+		 *  objects.
+		 */
+		if (pending_empty && !descmiss_empty &&
+		    !(priv_req->flags & REQUEST_INTERNAL)) {
+			cdns3_wa2_descmiss_copy_data(priv_ep,
+						     &priv_req->request);
+
+			trace_cdns3_wa2(priv_ep, "get internal stored data");
+
+			list_add_tail(&priv_req->request.list,
+				      &priv_ep->pending_req_list);
+			cdns3_gadget_giveback(priv_ep, priv_req,
+					      priv_req->request.status);
+
+			/*
+			 * Intentionally driver returns positive value as
+			 * correct value. It informs that transfer has
+			 * been finished.
+			 */
+			return EINPROGRESS;
+		}
+
+		/*
+		 * Driver will wait for completion DESCMISS transfer,
+		 * before starts new, not DESCMISS transfer.
+		 */
+		if (!pending_empty && !descmiss_empty) {
+			trace_cdns3_wa2(priv_ep, "wait for pending transfer\n");
+			deferred = 1;
+		}
+
+		if (priv_req->flags & REQUEST_INTERNAL)
+			list_add_tail(&priv_req->list,
+				      &priv_ep->wa2_descmiss_req_list);
+	}
+
+	return deferred;
+}
+
+static void cdns3_wa2_remove_old_request(struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_request *priv_req;
+
+	while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
+		u8 chain;
+
+		priv_req = cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
+		chain = !!(priv_req->flags & REQUEST_INTERNAL_CH);
+
+		trace_cdns3_wa2(priv_ep, "removes eldest request");
+
+		kfree(priv_req->request.buf);
+		cdns3_gadget_ep_free_request(&priv_ep->endpoint,
+					     &priv_req->request);
+		list_del_init(&priv_req->list);
+		--priv_ep->wa2_counter;
+
+		if (!chain)
+			break;
+	}
+}
+
+/**
+ * cdns3_wa2_descmissing_packet - handles descriptor missing event.
+ * @priv_dev: extended gadget object
+ *
+ * This function is used only for WA2. For more information see Work around 2
+ * description.
+ */
+static void cdns3_wa2_descmissing_packet(struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_request *priv_req;
+	struct usb_request *request;
+
+	if (priv_ep->flags & EP_QUIRK_EXTRA_BUF_DET) {
+		priv_ep->flags &= ~EP_QUIRK_EXTRA_BUF_DET;
+		priv_ep->flags |= EP_QUIRK_EXTRA_BUF_EN;
+	}
+
+	trace_cdns3_wa2(priv_ep, "Description Missing detected\n");
+
+	if (priv_ep->wa2_counter >= CDNS3_WA2_NUM_BUFFERS)
+		cdns3_wa2_remove_old_request(priv_ep);
+
+	request = cdns3_gadget_ep_alloc_request(&priv_ep->endpoint,
+						GFP_ATOMIC);
+	if (!request)
+		goto err;
+
+	priv_req = to_cdns3_request(request);
+	priv_req->flags |= REQUEST_INTERNAL;
+
+	/* if this field is still assigned it indicate that transfer related
+	 * with this request has not been finished yet. Driver in this
+	 * case simply allocate next request and assign flag REQUEST_INTERNAL_CH
+	 * flag to previous one. It will indicate that current request is
+	 * part of the previous one.
+	 */
+	if (priv_ep->descmis_req)
+		priv_ep->descmis_req->flags |= REQUEST_INTERNAL_CH;
+
+	priv_req->request.buf = kzalloc(CDNS3_DESCMIS_BUF_SIZE,
+					GFP_ATOMIC);
+	priv_ep->wa2_counter++;
+
+	if (!priv_req->request.buf) {
+		cdns3_gadget_ep_free_request(&priv_ep->endpoint, request);
+		goto err;
+	}
+
+	priv_req->request.length = CDNS3_DESCMIS_BUF_SIZE;
+	priv_ep->descmis_req = priv_req;
+
+	__cdns3_gadget_ep_queue(&priv_ep->endpoint,
+				&priv_ep->descmis_req->request,
+				GFP_ATOMIC);
+
+	return;
+
+err:
+	dev_err(priv_ep->cdns3_dev->dev,
+		"Failed: No sufficient memory for DESCMIS\n");
+}
+
+/**
+ * cdns3_gadget_giveback - call struct usb_request's ->complete callback
+ * @priv_ep: The endpoint to whom the request belongs to
+ * @priv_req: The request we're giving back
+ * @status: completion code for the request
+ *
+ * Must be called with controller's lock held and interrupts disabled. This
+ * function will unmap @req and call its ->complete() callback to notify upper
+ * layers that it has completed.
+ */
+void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
+			   struct cdns3_request *priv_req,
+			   int status)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct usb_request *request = &priv_req->request;
+
+	list_del_init(&request->list);
+
+	if (request->status == -EINPROGRESS)
+		request->status = status;
+
+	usb_gadget_unmap_request(&priv_dev->gadget, request,
+				 priv_ep->dir);
+
+	if ((priv_req->flags & REQUEST_UNALIGNED) &&
+	    priv_ep->dir == USB_DIR_OUT && !request->status)
+		memcpy(request->buf, priv_req->aligned_buf->buf,
+		       request->length);
+
+	priv_req->flags &= ~(REQUEST_PENDING | REQUEST_UNALIGNED);
+	trace_cdns3_gadget_giveback(priv_req);
+
+	if (priv_dev->dev_ver < DEV_VER_V2) {
+		request = cdns3_wa2_gadget_giveback(priv_dev, priv_ep,
+						    priv_req);
+		if (!request)
+			return;
+	}
+
+	if (request->complete) {
+		spin_unlock(&priv_dev->lock);
+		usb_gadget_giveback_request(&priv_ep->endpoint,
+					    request);
+		spin_lock(&priv_dev->lock);
+	}
+
+	if (request->buf == priv_dev->zlp_buf)
+		cdns3_gadget_ep_free_request(&priv_ep->endpoint, request);
+}
+
+void cdns3_wa1_restore_cycle_bit(struct cdns3_endpoint *priv_ep)
+{
+	/* Work around for stale data address in TRB*/
+	if (priv_ep->wa1_set) {
+		trace_cdns3_wa1(priv_ep, "restore cycle bit");
+
+		priv_ep->wa1_set = 0;
+		priv_ep->wa1_trb_index = 0xFFFF;
+		if (priv_ep->wa1_cycle_bit) {
+			priv_ep->wa1_trb->control =
+				priv_ep->wa1_trb->control | 0x1;
+		} else {
+			priv_ep->wa1_trb->control =
+				priv_ep->wa1_trb->control & ~0x1;
+		}
+	}
+}
+
+static void cdns3_free_aligned_request_buf(struct cdns3_device *priv_dev)
+{
+	struct cdns3_aligned_buf *buf, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	list_for_each_entry_safe(buf, tmp, &priv_dev->aligned_buf_list, list) {
+		if (!buf->in_use) {
+			list_del(&buf->list);
+
+			/*
+			 * Re-enable interrupts to free DMA capable memory.
+			 * Driver can't free this memory with disabled
+			 * interrupts.
+			 */
+			spin_unlock_irqrestore(&priv_dev->lock, flags);
+			dma_free_coherent(buf->buf);
+			kfree(buf);
+			spin_lock_irqsave(&priv_dev->lock, flags);
+		}
+	}
+
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+}
+
+static int cdns3_prepare_aligned_request_buf(struct cdns3_request *priv_req)
+{
+	struct cdns3_endpoint *priv_ep = priv_req->priv_ep;
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct cdns3_aligned_buf *buf;
+
+	/* check if buffer is aligned to 8. */
+	if (!((uintptr_t)priv_req->request.buf & 0x7))
+		return 0;
+
+	buf = priv_req->aligned_buf;
+
+	if (!buf || priv_req->request.length > buf->size) {
+		buf = kzalloc(sizeof(*buf), GFP_ATOMIC);
+		if (!buf)
+			return -ENOMEM;
+
+		buf->size = priv_req->request.length;
+
+		buf->buf = dma_alloc_coherent(buf->size,
+					      (unsigned long *)&buf->dma);
+		if (!buf->buf) {
+			kfree(buf);
+			return -ENOMEM;
+		}
+
+		if (priv_req->aligned_buf) {
+			trace_cdns3_free_aligned_request(priv_req);
+			priv_req->aligned_buf->in_use = 0;
+#ifndef __UBOOT__
+			queue_work(system_freezable_wq,
+				   &priv_dev->aligned_buf_wq);
+#else
+			cdns3_free_aligned_request_buf(priv_dev);
+#endif
+		}
+
+		buf->in_use = 1;
+		priv_req->aligned_buf = buf;
+
+		list_add_tail(&buf->list,
+			      &priv_dev->aligned_buf_list);
+	}
+
+	if (priv_ep->dir == USB_DIR_IN) {
+		memcpy(buf->buf, priv_req->request.buf,
+		       priv_req->request.length);
+	}
+
+	priv_req->flags |= REQUEST_UNALIGNED;
+	trace_cdns3_prepare_aligned_request(priv_req);
+
+	return 0;
+}
+
+static int cdns3_wa1_update_guard(struct cdns3_endpoint *priv_ep,
+				  struct cdns3_trb *trb)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+
+	if (!priv_ep->wa1_set) {
+		u32 doorbell;
+
+		doorbell = !!(readl(&priv_dev->regs->ep_cmd) & EP_CMD_DRDY);
+
+		if (doorbell) {
+			priv_ep->wa1_cycle_bit = priv_ep->pcs ? TRB_CYCLE : 0;
+			priv_ep->wa1_set = 1;
+			priv_ep->wa1_trb = trb;
+			priv_ep->wa1_trb_index = priv_ep->enqueue;
+			trace_cdns3_wa1(priv_ep, "set guard");
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static void cdns3_wa1_tray_restore_cycle_bit(struct cdns3_device *priv_dev,
+					     struct cdns3_endpoint *priv_ep)
+{
+	int dma_index;
+	u32 doorbell;
+
+	doorbell = !!(readl(&priv_dev->regs->ep_cmd) & EP_CMD_DRDY);
+	dma_index = cdns3_get_dma_pos(priv_dev, priv_ep);
+
+	if (!doorbell || dma_index != priv_ep->wa1_trb_index)
+		cdns3_wa1_restore_cycle_bit(priv_ep);
+}
+
+/**
+ * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware
+ * @priv_ep: endpoint object
+ *
+ * Returns zero on success or negative value on failure
+ */
+int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
+			  struct usb_request *request)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct cdns3_request *priv_req;
+	struct cdns3_trb *trb;
+	dma_addr_t trb_dma;
+	u32 togle_pcs = 1;
+	int sg_iter = 0;
+	int num_trb = 1;
+	int address;
+	u32 control;
+	int pcs;
+
+	if (num_trb > priv_ep->free_trbs) {
+		priv_ep->flags |= EP_RING_FULL;
+		return -ENOBUFS;
+	}
+
+	priv_req = to_cdns3_request(request);
+	address = priv_ep->endpoint.desc->bEndpointAddress;
+
+	priv_ep->flags |= EP_PENDING_REQUEST;
+
+	/* must allocate buffer aligned to 8 */
+	if (priv_req->flags & REQUEST_UNALIGNED)
+		trb_dma = priv_req->aligned_buf->dma;
+	else
+		trb_dma = request->dma;
+
+	trb = priv_ep->trb_pool + priv_ep->enqueue;
+	priv_req->start_trb = priv_ep->enqueue;
+	priv_req->trb = trb;
+
+	cdns3_select_ep(priv_ep->cdns3_dev, address);
+
+	/* prepare ring */
+	if ((priv_ep->enqueue + num_trb)  >= (priv_ep->num_trbs - 1)) {
+		struct cdns3_trb *link_trb;
+		int doorbell, dma_index;
+		u32 ch_bit = 0;
+
+		doorbell = !!(readl(&priv_dev->regs->ep_cmd) & EP_CMD_DRDY);
+		dma_index = cdns3_get_dma_pos(priv_dev, priv_ep);
+
+		/* Driver can't update LINK TRB if it is current processed. */
+		if (doorbell && dma_index == priv_ep->num_trbs - 1) {
+			priv_ep->flags |= EP_DEFERRED_DRDY;
+			return -ENOBUFS;
+		}
+
+		/*updating C bt in  Link TRB before starting DMA*/
+		link_trb = priv_ep->trb_pool + (priv_ep->num_trbs - 1);
+		/*
+		 * For TRs size equal 2 enabling TRB_CHAIN for epXin causes
+		 * that DMA stuck at the LINK TRB.
+		 * On the other hand, removing TRB_CHAIN for longer TRs for
+		 * epXout cause that DMA stuck after handling LINK TRB.
+		 * To eliminate this strange behavioral driver set TRB_CHAIN
+		 * bit only for TR size > 2.
+		 */
+		if (priv_ep->type == USB_ENDPOINT_XFER_ISOC ||
+		    TRBS_PER_SEGMENT > 2)
+			ch_bit = TRB_CHAIN;
+
+		link_trb->control = ((priv_ep->pcs) ? TRB_CYCLE : 0) |
+				    TRB_TYPE(TRB_LINK) | TRB_TOGGLE | ch_bit;
+	}
+
+	if (priv_dev->dev_ver <= DEV_VER_V2)
+		togle_pcs = cdns3_wa1_update_guard(priv_ep, trb);
+
+	/* set incorrect Cycle Bit for first trb*/
+	control = priv_ep->pcs ? 0 : TRB_CYCLE;
+
+	do {
+		u32 length;
+		u16 td_size = 0;
+
+		/* fill TRB */
+		control |= TRB_TYPE(TRB_NORMAL);
+		trb->buffer = TRB_BUFFER(trb_dma);
+
+		length = request->length;
+
+		if (likely(priv_dev->dev_ver >= DEV_VER_V2))
+			td_size = DIV_ROUND_UP(length,
+					       priv_ep->endpoint.maxpacket);
+
+		trb->length = TRB_BURST_LEN(priv_ep->trb_burst_size) |
+					TRB_LEN(length);
+		if (priv_dev->gadget.speed == USB_SPEED_SUPER)
+			trb->length |= TRB_TDL_SS_SIZE(td_size);
+		else
+			control |= TRB_TDL_HS_SIZE(td_size);
+
+		pcs = priv_ep->pcs ? TRB_CYCLE : 0;
+
+		/*
+		 * first trb should be prepared as last to avoid processing
+		 *  transfer to early
+		 */
+		if (sg_iter != 0)
+			control |= pcs;
+
+		if (priv_ep->type == USB_ENDPOINT_XFER_ISOC  && !priv_ep->dir) {
+			control |= TRB_IOC | TRB_ISP;
+		} else {
+			/* for last element in TD or in SG list */
+			if (sg_iter == (num_trb - 1) && sg_iter != 0)
+				control |= pcs | TRB_IOC | TRB_ISP;
+		}
+
+		if (sg_iter)
+			trb->control = control;
+		else
+			priv_req->trb->control = control;
+
+		control = 0;
+		++sg_iter;
+		priv_req->end_trb = priv_ep->enqueue;
+		cdns3_ep_inc_enq(priv_ep);
+		trb = priv_ep->trb_pool + priv_ep->enqueue;
+	} while (sg_iter < num_trb);
+
+	trb = priv_req->trb;
+
+	priv_req->flags |= REQUEST_PENDING;
+
+	if (sg_iter == 1)
+		trb->control |= TRB_IOC | TRB_ISP;
+
+	/*
+	 * Memory barrier - cycle bit must be set before other filds in trb.
+	 */
+	dmb();
+
+	/* give the TD to the consumer*/
+	if (togle_pcs)
+		trb->control =  trb->control ^ 1;
+
+	if (priv_dev->dev_ver <= DEV_VER_V2)
+		cdns3_wa1_tray_restore_cycle_bit(priv_dev, priv_ep);
+
+	trace_cdns3_prepare_trb(priv_ep, priv_req->trb);
+
+	/*
+	 * Memory barrier - Cycle Bit must be set before trb->length  and
+	 * trb->buffer fields.
+	 */
+	dmb();
+
+	/*
+	 * For DMULT mode we can set address to transfer ring only once after
+	 * enabling endpoint.
+	 */
+	if (priv_ep->flags & EP_UPDATE_EP_TRBADDR) {
+		/*
+		 * Until SW is not ready to handle the OUT transfer the ISO OUT
+		 * Endpoint should be disabled (EP_CFG.ENABLE = 0).
+		 * EP_CFG_ENABLE must be set before updating ep_traddr.
+		 */
+		if (priv_ep->type == USB_ENDPOINT_XFER_ISOC  && !priv_ep->dir &&
+		    !(priv_ep->flags & EP_QUIRK_ISO_OUT_EN)) {
+			priv_ep->flags |= EP_QUIRK_ISO_OUT_EN;
+			cdns3_set_register_bit(&priv_dev->regs->ep_cfg,
+					       EP_CFG_ENABLE);
+		}
+
+		writel(EP_TRADDR_TRADDR(priv_ep->trb_pool_dma +
+					priv_req->start_trb * TRB_SIZE),
+					&priv_dev->regs->ep_traddr);
+
+		priv_ep->flags &= ~EP_UPDATE_EP_TRBADDR;
+	}
+
+	if (!priv_ep->wa1_set && !(priv_ep->flags & EP_STALLED)) {
+		trace_cdns3_ring(priv_ep);
+		/*clearing TRBERR and EP_STS_DESCMIS before seting DRDY*/
+		writel(EP_STS_TRBERR | EP_STS_DESCMIS, &priv_dev->regs->ep_sts);
+		writel(EP_CMD_DRDY, &priv_dev->regs->ep_cmd);
+		trace_cdns3_doorbell_epx(priv_ep->name,
+					 readl(&priv_dev->regs->ep_traddr));
+	}
+
+	/* WORKAROUND for transition to L0 */
+	__cdns3_gadget_wakeup(priv_dev);
+
+	return 0;
+}
+
+void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)
+{
+	struct cdns3_endpoint *priv_ep;
+	struct usb_ep *ep;
+	int val;
+
+	if (priv_dev->hw_configured_flag)
+		return;
+
+	writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf);
+	writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd);
+
+	cdns3_set_register_bit(&priv_dev->regs->usb_conf,
+			       USB_CONF_U1EN | USB_CONF_U2EN);
+
+	/* wait until configuration set */
+	readl_poll_timeout_atomic(&priv_dev->regs->usb_sts, val,
+				  val & USB_STS_CFGSTS_MASK, 100);
+
+	priv_dev->hw_configured_flag = 1;
+
+	list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) {
+		priv_ep = ep_to_cdns3_ep(ep);
+		if (priv_ep->flags & EP_ENABLED)
+			cdns3_start_all_request(priv_dev, priv_ep);
+	}
+}
+
+/**
+ * cdns3_request_handled - check whether request has been handled by DMA
+ *
+ * @priv_ep: extended endpoint object.
+ * @priv_req: request object for checking
+ *
+ * Endpoint must be selected before invoking this function.
+ *
+ * Returns false if request has not been handled by DMA, else returns true.
+ *
+ * SR - start ring
+ * ER -  end ring
+ * DQ = priv_ep->dequeue - dequeue position
+ * EQ = priv_ep->enqueue -  enqueue position
+ * ST = priv_req->start_trb - index of first TRB in transfer ring
+ * ET = priv_req->end_trb - index of last TRB in transfer ring
+ * CI = current_index - index of processed TRB by DMA.
+ *
+ * As first step, function checks if cycle bit for priv_req->start_trb is
+ * correct.
+ *
+ * some rules:
+ * 1. priv_ep->dequeue never exceed current_index.
+ * 2  priv_ep->enqueue never exceed priv_ep->dequeue
+ * 3. exception: priv_ep->enqueue == priv_ep->dequeue
+ *    and priv_ep->free_trbs is zero.
+ *    This case indicate that TR is full.
+ *
+ * Then We can split recognition into two parts:
+ * Case 1 - priv_ep->dequeue < current_index
+ *      SR ... EQ ... DQ ... CI ... ER
+ *      SR ... DQ ... CI ... EQ ... ER
+ *
+ *      Request has been handled by DMA if ST and ET is between DQ and CI.
+ *
+ * Case 2 - priv_ep->dequeue > current_index
+ * This situation take place when CI go through the LINK TRB at the end of
+ * transfer ring.
+ *      SR ... CI ... EQ ... DQ ... ER
+ *
+ *      Request has been handled by DMA if ET is less then CI or
+ *      ET is greater or equal DQ.
+ */
+static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep,
+				  struct cdns3_request *priv_req)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct cdns3_trb *trb = priv_req->trb;
+	int current_index = 0;
+	int handled = 0;
+	int doorbell;
+
+	current_index = cdns3_get_dma_pos(priv_dev, priv_ep);
+	doorbell = !!(readl(&priv_dev->regs->ep_cmd) & EP_CMD_DRDY);
+
+	trb = &priv_ep->trb_pool[priv_req->start_trb];
+
+	if ((trb->control  & TRB_CYCLE) != priv_ep->ccs)
+		goto finish;
+
+	if (doorbell == 1 && current_index == priv_ep->dequeue)
+		goto finish;
+
+	/* The corner case for TRBS_PER_SEGMENT equal 2). */
+	if (TRBS_PER_SEGMENT == 2 && priv_ep->type != USB_ENDPOINT_XFER_ISOC) {
+		handled = 1;
+		goto finish;
+	}
+
+	if (priv_ep->enqueue == priv_ep->dequeue &&
+	    priv_ep->free_trbs == 0) {
+		handled = 1;
+	} else if (priv_ep->dequeue < current_index) {
+		if ((current_index == (priv_ep->num_trbs - 1)) &&
+		    !priv_ep->dequeue)
+			goto finish;
+
+		if (priv_req->end_trb >= priv_ep->dequeue &&
+		    priv_req->end_trb < current_index)
+			handled = 1;
+	} else if (priv_ep->dequeue  > current_index) {
+		if (priv_req->end_trb  < current_index ||
+		    priv_req->end_trb >= priv_ep->dequeue)
+			handled = 1;
+	}
+
+finish:
+	trace_cdns3_request_handled(priv_req, current_index, handled);
+
+	return handled;
+}
+
+static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
+				     struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_request *priv_req;
+	struct usb_request *request;
+	struct cdns3_trb *trb;
+
+	while (!list_empty(&priv_ep->pending_req_list)) {
+		request = cdns3_next_request(&priv_ep->pending_req_list);
+		priv_req = to_cdns3_request(request);
+
+		/* Re-select endpoint. It could be changed by other CPU during
+		 * handling usb_gadget_giveback_request.
+		 */
+#ifndef __UBOOT__
+		cdns3_select_ep(priv_dev, priv_ep->endpoint.address);
+#else
+		cdns3_select_ep(priv_dev,
+				priv_ep->endpoint.desc->bEndpointAddress);
+#endif
+
+		if (!cdns3_request_handled(priv_ep, priv_req))
+			goto prepare_next_td;
+
+		trb = priv_ep->trb_pool + priv_ep->dequeue;
+		trace_cdns3_complete_trb(priv_ep, trb);
+
+		if (trb != priv_req->trb)
+			dev_warn(priv_dev->dev,
+				 "request_trb=0x%p, queue_trb=0x%p\n",
+				 priv_req->trb, trb);
+
+		request->actual = TRB_LEN(le32_to_cpu(trb->length));
+		cdns3_move_deq_to_next_trb(priv_req);
+		cdns3_gadget_giveback(priv_ep, priv_req, 0);
+
+		if (priv_ep->type != USB_ENDPOINT_XFER_ISOC &&
+		    TRBS_PER_SEGMENT == 2)
+			break;
+	}
+	priv_ep->flags &= ~EP_PENDING_REQUEST;
+
+prepare_next_td:
+	if (!(priv_ep->flags & EP_STALLED) &&
+	    !(priv_ep->flags & EP_STALL_PENDING))
+		cdns3_start_all_request(priv_dev, priv_ep);
+}
+
+void cdns3_rearm_transfer(struct cdns3_endpoint *priv_ep, u8 rearm)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+
+	cdns3_wa1_restore_cycle_bit(priv_ep);
+
+	if (rearm) {
+		trace_cdns3_ring(priv_ep);
+
+		/* Cycle Bit must be updated before arming DMA. */
+		dmb();
+		writel(EP_CMD_DRDY, &priv_dev->regs->ep_cmd);
+
+		__cdns3_gadget_wakeup(priv_dev);
+
+		trace_cdns3_doorbell_epx(priv_ep->name,
+					 readl(&priv_dev->regs->ep_traddr));
+	}
+}
+
+/**
+ * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint
+ * @priv_ep: endpoint object
+ *
+ * Returns 0
+ */
+static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	u32 ep_sts_reg;
+
+#ifndef __UBOOT__
+	cdns3_select_ep(priv_dev, priv_ep->endpoint.address);
+#else
+	cdns3_select_ep(priv_dev, priv_ep->endpoint.desc->bEndpointAddress);
+#endif
+
+	trace_cdns3_epx_irq(priv_dev, priv_ep);
+
+	ep_sts_reg = readl(&priv_dev->regs->ep_sts);
+	writel(ep_sts_reg, &priv_dev->regs->ep_sts);
+
+	if (ep_sts_reg & EP_STS_TRBERR) {
+		if (priv_ep->flags & EP_STALL_PENDING &&
+		    !(ep_sts_reg & EP_STS_DESCMIS &&
+		    priv_dev->dev_ver < DEV_VER_V2)) {
+			cdns3_ep_stall_flush(priv_ep);
+		}
+
+		/*
+		 * For isochronous transfer driver completes request on
+		 * IOC or on TRBERR. IOC appears only when device receive
+		 * OUT data packet. If host disable stream or lost some packet
+		 * then the only way to finish all queued transfer is to do it
+		 * on TRBERR event.
+		 */
+		if (priv_ep->type == USB_ENDPOINT_XFER_ISOC &&
+		    !priv_ep->wa1_set) {
+			if (!priv_ep->dir) {
+				u32 ep_cfg = readl(&priv_dev->regs->ep_cfg);
+
+				ep_cfg &= ~EP_CFG_ENABLE;
+				writel(ep_cfg, &priv_dev->regs->ep_cfg);
+				priv_ep->flags &= ~EP_QUIRK_ISO_OUT_EN;
+			}
+			cdns3_transfer_completed(priv_dev, priv_ep);
+		} else if (!(priv_ep->flags & EP_STALLED) &&
+			  !(priv_ep->flags & EP_STALL_PENDING)) {
+			if (priv_ep->flags & EP_DEFERRED_DRDY) {
+				priv_ep->flags &= ~EP_DEFERRED_DRDY;
+				cdns3_start_all_request(priv_dev, priv_ep);
+			} else {
+				cdns3_rearm_transfer(priv_ep,
+						     priv_ep->wa1_set);
+			}
+		}
+	}
+
+	if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
+		if (priv_ep->flags & EP_QUIRK_EXTRA_BUF_EN) {
+			if (ep_sts_reg & EP_STS_ISP)
+				priv_ep->flags |= EP_QUIRK_END_TRANSFER;
+			else
+				priv_ep->flags &= ~EP_QUIRK_END_TRANSFER;
+		}
+
+		cdns3_transfer_completed(priv_dev, priv_ep);
+	}
+
+	/*
+	 * WA2: this condition should only be meet when
+	 * priv_ep->flags & EP_QUIRK_EXTRA_BUF_DET or
+	 * priv_ep->flags & EP_QUIRK_EXTRA_BUF_EN.
+	 * In other cases this interrupt will be disabled/
+	 */
+	if (ep_sts_reg & EP_STS_DESCMIS && priv_dev->dev_ver < DEV_VER_V2 &&
+	    !(priv_ep->flags & EP_STALLED))
+		cdns3_wa2_descmissing_packet(priv_ep);
+
+	return 0;
+}
+
+static void cdns3_disconnect_gadget(struct cdns3_device *priv_dev)
+{
+	if (priv_dev->gadget_driver && priv_dev->gadget_driver->disconnect) {
+		spin_unlock(&priv_dev->lock);
+		priv_dev->gadget_driver->disconnect(&priv_dev->gadget);
+		spin_lock(&priv_dev->lock);
+	}
+}
+
+/**
+ * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device
+ * @priv_dev: extended gadget object
+ * @usb_ists: bitmap representation of device's reported interrupts
+ * (usb_ists register value)
+ */
+static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
+					      u32 usb_ists)
+{
+	int speed = 0;
+
+	trace_cdns3_usb_irq(priv_dev, usb_ists);
+	if (usb_ists & USB_ISTS_L1ENTI) {
+		/*
+		 * WORKAROUND: CDNS3 controller has issue with hardware resuming
+		 * from L1. To fix it, if any DMA transfer is pending driver
+		 * must starts driving resume signal immediately.
+		 */
+		if (readl(&priv_dev->regs->drbl))
+			__cdns3_gadget_wakeup(priv_dev);
+	}
+
+	/* Connection detected */
+	if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) {
+		speed = cdns3_get_speed(priv_dev);
+		priv_dev->gadget.speed = speed;
+		usb_gadget_set_state(&priv_dev->gadget, USB_STATE_POWERED);
+		cdns3_ep0_config(priv_dev);
+	}
+
+	/* Disconnection detected */
+	if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) {
+		cdns3_disconnect_gadget(priv_dev);
+		priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
+		usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
+		cdns3_hw_reset_eps_config(priv_dev);
+	}
+
+	if (usb_ists & (USB_ISTS_L2ENTI | USB_ISTS_U3ENTI)) {
+		if (priv_dev->gadget_driver &&
+		    priv_dev->gadget_driver->suspend) {
+			spin_unlock(&priv_dev->lock);
+			priv_dev->gadget_driver->suspend(&priv_dev->gadget);
+			spin_lock(&priv_dev->lock);
+		}
+	}
+
+	if (usb_ists & (USB_ISTS_L2EXTI | USB_ISTS_U3EXTI)) {
+		if (priv_dev->gadget_driver &&
+		    priv_dev->gadget_driver->resume) {
+			spin_unlock(&priv_dev->lock);
+			priv_dev->gadget_driver->resume(&priv_dev->gadget);
+			spin_lock(&priv_dev->lock);
+		}
+	}
+
+	/* reset*/
+	if (usb_ists & (USB_ISTS_UWRESI | USB_ISTS_UHRESI | USB_ISTS_U2RESI)) {
+		if (priv_dev->gadget_driver) {
+			spin_unlock(&priv_dev->lock);
+			usb_gadget_udc_reset(&priv_dev->gadget,
+					     priv_dev->gadget_driver);
+			spin_lock(&priv_dev->lock);
+
+			/*read again to check the actual speed*/
+			speed = cdns3_get_speed(priv_dev);
+			priv_dev->gadget.speed = speed;
+			cdns3_hw_reset_eps_config(priv_dev);
+			cdns3_ep0_config(priv_dev);
+		}
+	}
+}
+
+/**
+ * cdns3_device_irq_handler- interrupt handler for device part of controller
+ *
+ * @irq: irq number for cdns3 core device
+ * @data: structure of cdns3
+ *
+ * Returns IRQ_HANDLED or IRQ_NONE
+ */
+static irqreturn_t cdns3_device_irq_handler(int irq, void *data)
+{
+	struct cdns3_device *priv_dev;
+	struct cdns3 *cdns = data;
+	irqreturn_t ret = IRQ_NONE;
+	u32 reg;
+
+	priv_dev = cdns->gadget_dev;
+
+	/* check USB device interrupt */
+	reg = readl(&priv_dev->regs->usb_ists);
+	if (reg) {
+		/* After masking interrupts the new interrupts won't be
+		 * reported in usb_ists/ep_ists. In order to not lose some
+		 * of them driver disables only detected interrupts.
+		 * They will be enabled ASAP after clearing source of
+		 * interrupt. This an unusual behavior only applies to
+		 * usb_ists register.
+		 */
+		reg = ~reg & readl(&priv_dev->regs->usb_ien);
+		/* mask deferred interrupt. */
+		writel(reg, &priv_dev->regs->usb_ien);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	/* check endpoint interrupt */
+	reg = readl(&priv_dev->regs->ep_ists);
+	if (reg) {
+		writel(0, &priv_dev->regs->ep_ien);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	return ret;
+}
+
+/**
+ * cdns3_device_thread_irq_handler- interrupt handler for device part
+ * of controller
+ *
+ * @irq: irq number for cdns3 core device
+ * @data: structure of cdns3
+ *
+ * Returns IRQ_HANDLED or IRQ_NONE
+ */
+static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data)
+{
+	struct cdns3_device *priv_dev;
+	struct cdns3 *cdns = data;
+	irqreturn_t ret = IRQ_NONE;
+	unsigned long flags;
+	int bit;
+	u32 reg;
+
+	priv_dev = cdns->gadget_dev;
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	reg = readl(&priv_dev->regs->usb_ists);
+	if (reg) {
+		writel(reg, &priv_dev->regs->usb_ists);
+		writel(USB_IEN_INIT, &priv_dev->regs->usb_ien);
+		cdns3_check_usb_interrupt_proceed(priv_dev, reg);
+		ret = IRQ_HANDLED;
+	}
+
+	reg = readl(&priv_dev->regs->ep_ists);
+
+	/* handle default endpoint OUT */
+	if (reg & EP_ISTS_EP_OUT0) {
+		cdns3_check_ep0_interrupt_proceed(priv_dev, USB_DIR_OUT);
+		ret = IRQ_HANDLED;
+	}
+
+	/* handle default endpoint IN */
+	if (reg & EP_ISTS_EP_IN0) {
+		cdns3_check_ep0_interrupt_proceed(priv_dev, USB_DIR_IN);
+		ret = IRQ_HANDLED;
+	}
+
+	/* check if interrupt from non default endpoint, if no exit */
+	reg &= ~(EP_ISTS_EP_OUT0 | EP_ISTS_EP_IN0);
+	if (!reg)
+		goto irqend;
+
+	for_each_set_bit(bit, (unsigned long *)&reg,
+			 sizeof(u32) * BITS_PER_BYTE) {
+		cdns3_check_ep_interrupt_proceed(priv_dev->eps[bit]);
+		ret = IRQ_HANDLED;
+	}
+
+irqend:
+	writel(~0, &priv_dev->regs->ep_ien);
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+
+	return ret;
+}
+
+/**
+ * cdns3_ep_onchip_buffer_reserve - Try to reserve onchip buf for EP
+ *
+ * The real reservation will occur during write to EP_CFG register,
+ * this function is used to check if the 'size' reservation is allowed.
+ *
+ * @priv_dev: extended gadget object
+ * @size: the size (KB) for EP would like to allocate
+ * @is_in: endpoint direction
+ *
+ * Return 0 if the required size can met or negative value on failure
+ */
+static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev,
+					  int size, int is_in)
+{
+	int remained;
+
+	/* 2KB are reserved for EP0*/
+	remained = priv_dev->onchip_buffers - priv_dev->onchip_used_size - 2;
+
+	if (is_in) {
+		if (remained < size)
+			return -EPERM;
+
+		priv_dev->onchip_used_size += size;
+	} else {
+		int required;
+
+		/**
+		 *  ALL OUT EPs are shared the same chunk onchip memory, so
+		 * driver checks if it already has assigned enough buffers
+		 */
+		if (priv_dev->out_mem_is_allocated >= size)
+			return 0;
+
+		required = size - priv_dev->out_mem_is_allocated;
+
+		if (required > remained)
+			return -EPERM;
+
+		priv_dev->out_mem_is_allocated += required;
+		priv_dev->onchip_used_size += required;
+	}
+
+	return 0;
+}
+
+void cdns3_configure_dmult(struct cdns3_device *priv_dev,
+			   struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
+
+	/* For dev_ver > DEV_VER_V2 DMULT is configured per endpoint */
+	if (priv_dev->dev_ver <= DEV_VER_V2)
+		writel(USB_CONF_DMULT, &regs->usb_conf);
+
+	if (priv_dev->dev_ver == DEV_VER_V2)
+		writel(USB_CONF2_EN_TDL_TRB, &regs->usb_conf2);
+
+	if (priv_dev->dev_ver >= DEV_VER_V3 && priv_ep) {
+		u32 mask;
+
+		if (priv_ep->dir)
+			mask = BIT(priv_ep->num + 16);
+		else
+			mask = BIT(priv_ep->num);
+
+		if (priv_ep->type != USB_ENDPOINT_XFER_ISOC) {
+			cdns3_set_register_bit(&regs->tdl_from_trb, mask);
+			cdns3_set_register_bit(&regs->tdl_beh, mask);
+			cdns3_set_register_bit(&regs->tdl_beh2, mask);
+			cdns3_set_register_bit(&regs->dma_adv_td, mask);
+		}
+
+		if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir)
+			cdns3_set_register_bit(&regs->tdl_from_trb, mask);
+
+		cdns3_set_register_bit(&regs->dtrans, mask);
+	}
+}
+
+/**
+ * cdns3_ep_config Configure hardware endpoint
+ * @priv_ep: extended endpoint object
+ */
+void cdns3_ep_config(struct cdns3_endpoint *priv_ep)
+{
+	bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC);
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	u32 bEndpointAddress = priv_ep->num | priv_ep->dir;
+	u32 max_packet_size = 0;
+	u8 maxburst = 0;
+	u32 ep_cfg = 0;
+	u8 buffering;
+	u8 mult = 0;
+	int ret;
+
+	buffering = CDNS3_EP_BUF_SIZE - 1;
+
+	cdns3_configure_dmult(priv_dev, priv_ep);
+
+	switch (priv_ep->type) {
+	case USB_ENDPOINT_XFER_INT:
+		ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_INT);
+
+		if ((priv_dev->dev_ver == DEV_VER_V2 && !priv_ep->dir) ||
+		    priv_dev->dev_ver > DEV_VER_V2)
+			ep_cfg |= EP_CFG_TDL_CHK;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_BULK);
+
+		if ((priv_dev->dev_ver == DEV_VER_V2  && !priv_ep->dir) ||
+		    priv_dev->dev_ver > DEV_VER_V2)
+			ep_cfg |= EP_CFG_TDL_CHK;
+		break;
+	default:
+		ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC);
+		mult = CDNS3_EP_ISO_HS_MULT - 1;
+		buffering = mult + 1;
+	}
+
+	switch (priv_dev->gadget.speed) {
+	case USB_SPEED_FULL:
+		max_packet_size = is_iso_ep ? 1023 : 64;
+		break;
+	case USB_SPEED_HIGH:
+		max_packet_size = is_iso_ep ? 1024 : 512;
+		break;
+	case USB_SPEED_SUPER:
+		/* It's limitation that driver assumes in driver. */
+		mult = 0;
+		max_packet_size = 1024;
+		if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) {
+			maxburst = CDNS3_EP_ISO_SS_BURST - 1;
+			buffering = (mult + 1) *
+				    (maxburst + 1);
+
+			if (priv_ep->interval > 1)
+				buffering++;
+		} else {
+			maxburst = CDNS3_EP_BUF_SIZE - 1;
+		}
+		break;
+	default:
+		/* all other speed are not supported */
+		return;
+	}
+
+	if (max_packet_size == 1024)
+		priv_ep->trb_burst_size = 128;
+	else if (max_packet_size >= 512)
+		priv_ep->trb_burst_size = 64;
+	else
+		priv_ep->trb_burst_size = 16;
+
+	ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1,
+					     !!priv_ep->dir);
+	if (ret) {
+		dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n");
+		return;
+	}
+
+	ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) |
+		  EP_CFG_MULT(mult) |
+		  EP_CFG_BUFFERING(buffering) |
+		  EP_CFG_MAXBURST(maxburst);
+
+	cdns3_select_ep(priv_dev, bEndpointAddress);
+	writel(ep_cfg, &priv_dev->regs->ep_cfg);
+
+	dev_dbg(priv_dev->dev, "Configure %s: with val %08x\n",
+		priv_ep->name, ep_cfg);
+}
+
+/* Find correct direction for HW endpoint according to description */
+static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc,
+				   struct cdns3_endpoint *priv_ep)
+{
+	return (priv_ep->endpoint.caps.dir_in && usb_endpoint_dir_in(desc)) ||
+	       (priv_ep->endpoint.caps.dir_out && usb_endpoint_dir_out(desc));
+}
+
+static struct
+cdns3_endpoint *cdns3_find_available_ep(struct cdns3_device *priv_dev,
+					struct usb_endpoint_descriptor *desc)
+{
+	struct usb_ep *ep;
+	struct cdns3_endpoint *priv_ep;
+
+	list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) {
+		unsigned long num;
+		/* ep name pattern likes epXin or epXout */
+		char c[2] = {ep->name[2], '\0'};
+
+		num = simple_strtoul(c, NULL, 10);
+
+		priv_ep = ep_to_cdns3_ep(ep);
+		if (cdns3_ep_dir_is_correct(desc, priv_ep)) {
+			if (!(priv_ep->flags & EP_CLAIMED)) {
+				priv_ep->num  = num;
+				return priv_ep;
+			}
+		}
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+
+/*
+ *  Cadence IP has one limitation that all endpoints must be configured
+ * (Type & MaxPacketSize) before setting configuration through hardware
+ * register, it means we can't change endpoints configuration after
+ * set_configuration.
+ *
+ * This function set EP_CLAIMED flag which is added when the gadget driver
+ * uses usb_ep_autoconfig to configure specific endpoint;
+ * When the udc driver receives set_configurion request,
+ * it goes through all claimed endpoints, and configure all endpoints
+ * accordingly.
+ *
+ * At usb_ep_ops.enable/disable, we only enable and disable endpoint through
+ * ep_cfg register which can be changed after set_configuration, and do
+ * some software operation accordingly.
+ */
+static struct
+usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget,
+			      struct usb_endpoint_descriptor *desc,
+			      struct usb_ss_ep_comp_descriptor *comp_desc)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+	struct cdns3_endpoint *priv_ep;
+	unsigned long flags;
+
+	priv_ep = cdns3_find_available_ep(priv_dev, desc);
+	if (IS_ERR(priv_ep)) {
+		dev_err(priv_dev->dev, "no available ep\n");
+		return NULL;
+	}
+
+	dev_dbg(priv_dev->dev, "match endpoint: %s\n", priv_ep->name);
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+	priv_ep->endpoint.desc = desc;
+	priv_ep->dir  = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT;
+	priv_ep->type = usb_endpoint_type(desc);
+	priv_ep->flags |= EP_CLAIMED;
+	priv_ep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0;
+
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+	return &priv_ep->endpoint;
+}
+
+/**
+ * cdns3_gadget_ep_alloc_request Allocates request
+ * @ep: endpoint object associated with request
+ * @gfp_flags: gfp flags
+ *
+ * Returns allocated request address, NULL on allocation error
+ */
+struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep,
+						  gfp_t gfp_flags)
+{
+	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
+	struct cdns3_request *priv_req;
+
+	priv_req = kzalloc(sizeof(*priv_req), gfp_flags);
+	if (!priv_req)
+		return NULL;
+
+	priv_req->priv_ep = priv_ep;
+
+	trace_cdns3_alloc_request(priv_req);
+	return &priv_req->request;
+}
+
+/**
+ * cdns3_gadget_ep_free_request Free memory occupied by request
+ * @ep: endpoint object associated with request
+ * @request: request to free memory
+ */
+void cdns3_gadget_ep_free_request(struct usb_ep *ep,
+				  struct usb_request *request)
+{
+	struct cdns3_request *priv_req = to_cdns3_request(request);
+
+	if (priv_req->aligned_buf)
+		priv_req->aligned_buf->in_use = 0;
+
+	trace_cdns3_free_request(priv_req);
+	kfree(priv_req);
+}
+
+/**
+ * cdns3_gadget_ep_enable Enable endpoint
+ * @ep: endpoint object
+ * @desc: endpoint descriptor
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int cdns3_gadget_ep_enable(struct usb_ep *ep,
+				  const struct usb_endpoint_descriptor *desc)
+{
+	struct cdns3_endpoint *priv_ep;
+	struct cdns3_device *priv_dev;
+	u32 reg = EP_STS_EN_TRBERREN;
+	u32 bEndpointAddress;
+	unsigned long flags;
+	int enable = 1;
+	int ret;
+	int val;
+
+	priv_ep = ep_to_cdns3_ep(ep);
+	priv_dev = priv_ep->cdns3_dev;
+
+	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+		dev_dbg(priv_dev->dev, "usbss: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	if (!desc->wMaxPacketSize) {
+		dev_err(priv_dev->dev, "usbss: missing wMaxPacketSize\n");
+		return -EINVAL;
+	}
+
+	if (WARN_ON(priv_ep->flags & EP_ENABLED))
+		return 0;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	priv_ep->endpoint.desc = desc;
+	priv_ep->type = usb_endpoint_type(desc);
+	priv_ep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0;
+
+	if (priv_ep->interval > ISO_MAX_INTERVAL &&
+	    priv_ep->type == USB_ENDPOINT_XFER_ISOC) {
+		dev_err(priv_dev->dev, "Driver is limited to %d period\n",
+			ISO_MAX_INTERVAL);
+
+		ret =  -EINVAL;
+		goto exit;
+	}
+
+	ret = cdns3_allocate_trb_pool(priv_ep);
+
+	if (ret)
+		goto exit;
+
+	bEndpointAddress = priv_ep->num | priv_ep->dir;
+	cdns3_select_ep(priv_dev, bEndpointAddress);
+
+	trace_cdns3_gadget_ep_enable(priv_ep);
+
+	writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd);
+
+	ret = readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
+					!(val & (EP_CMD_CSTALL | EP_CMD_EPRST)),
+					1000);
+
+	if (unlikely(ret)) {
+		cdns3_free_trb_pool(priv_ep);
+		ret =  -EINVAL;
+		goto exit;
+	}
+
+	/* enable interrupt for selected endpoint */
+	cdns3_set_register_bit(&priv_dev->regs->ep_ien,
+			       BIT(cdns3_ep_addr_to_index(bEndpointAddress)));
+
+	if (priv_dev->dev_ver < DEV_VER_V2)
+		cdns3_wa2_enable_detection(priv_dev, priv_ep, reg);
+
+	writel(reg, &priv_dev->regs->ep_sts_en);
+
+	/*
+	 * For some versions of controller at some point during ISO OUT traffic
+	 * DMA reads Transfer Ring for the EP which has never got doorbell.
+	 * This issue was detected only on simulation, but to avoid this issue
+	 * driver add protection against it. To fix it driver enable ISO OUT
+	 * endpoint before setting DRBL. This special treatment of ISO OUT
+	 * endpoints are recommended by controller specification.
+	 */
+	if (priv_ep->type == USB_ENDPOINT_XFER_ISOC  && !priv_ep->dir)
+		enable = 0;
+
+	if (enable)
+		cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE);
+
+	ep->desc = desc;
+	priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALLED | EP_STALL_PENDING |
+			    EP_QUIRK_ISO_OUT_EN | EP_QUIRK_EXTRA_BUF_EN);
+	priv_ep->flags |= EP_ENABLED | EP_UPDATE_EP_TRBADDR;
+	priv_ep->wa1_set = 0;
+	priv_ep->enqueue = 0;
+	priv_ep->dequeue = 0;
+	reg = readl(&priv_dev->regs->ep_sts);
+	priv_ep->pcs = !!EP_STS_CCS(reg);
+	priv_ep->ccs = !!EP_STS_CCS(reg);
+	/* one TRB is reserved for link TRB used in DMULT mode*/
+	priv_ep->free_trbs = priv_ep->num_trbs - 1;
+exit:
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+
+	return ret;
+}
+
+/**
+ * cdns3_gadget_ep_disable Disable endpoint
+ * @ep: endpoint object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int cdns3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct cdns3_endpoint *priv_ep;
+	struct cdns3_request *priv_req;
+	struct cdns3_device *priv_dev;
+	struct usb_request *request;
+	unsigned long flags;
+	int ret = 0;
+	u32 ep_cfg;
+	int val;
+
+	if (!ep) {
+		pr_err("usbss: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	priv_ep = ep_to_cdns3_ep(ep);
+	priv_dev = priv_ep->cdns3_dev;
+
+	if (WARN_ON(!(priv_ep->flags & EP_ENABLED)))
+		return 0;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	trace_cdns3_gadget_ep_disable(priv_ep);
+
+	cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress);
+
+	ep_cfg = readl(&priv_dev->regs->ep_cfg);
+	ep_cfg &= ~EP_CFG_ENABLE;
+	writel(ep_cfg, &priv_dev->regs->ep_cfg);
+
+	/**
+	 * Driver needs some time before resetting endpoint.
+	 * It need waits for clearing DBUSY bit or for timeout expired.
+	 * 10us is enough time for controller to stop transfer.
+	 */
+	readl_poll_timeout_atomic(&priv_dev->regs->ep_sts, val,
+				  !(val & EP_STS_DBUSY), 10);
+	writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd);
+
+	readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
+				  !(val & (EP_CMD_CSTALL | EP_CMD_EPRST)),
+				  1000);
+	if (unlikely(ret))
+		dev_err(priv_dev->dev, "Timeout: %s resetting failed.\n",
+			priv_ep->name);
+
+	while (!list_empty(&priv_ep->pending_req_list)) {
+		request = cdns3_next_request(&priv_ep->pending_req_list);
+
+		cdns3_gadget_giveback(priv_ep, to_cdns3_request(request),
+				      -ESHUTDOWN);
+	}
+
+	while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
+		priv_req = cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
+
+		kfree(priv_req->request.buf);
+		cdns3_gadget_ep_free_request(&priv_ep->endpoint,
+					     &priv_req->request);
+		list_del_init(&priv_req->list);
+		--priv_ep->wa2_counter;
+	}
+
+	while (!list_empty(&priv_ep->deferred_req_list)) {
+		request = cdns3_next_request(&priv_ep->deferred_req_list);
+
+		cdns3_gadget_giveback(priv_ep, to_cdns3_request(request),
+				      -ESHUTDOWN);
+	}
+
+	priv_ep->descmis_req = NULL;
+
+	ep->desc = NULL;
+	priv_ep->flags &= ~EP_ENABLED;
+
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+
+	return ret;
+}
+
+/**
+ * cdns3_gadget_ep_queue Transfer data on endpoint
+ * @ep: endpoint object
+ * @request: request object
+ * @gfp_flags: gfp flags
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int __cdns3_gadget_ep_queue(struct usb_ep *ep,
+				   struct usb_request *request,
+				   gfp_t gfp_flags)
+{
+	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct cdns3_request *priv_req;
+	int ret = 0;
+
+	request->actual = 0;
+	request->status = -EINPROGRESS;
+	priv_req = to_cdns3_request(request);
+	trace_cdns3_ep_queue(priv_req);
+
+	if (priv_dev->dev_ver < DEV_VER_V2) {
+		ret = cdns3_wa2_gadget_ep_queue(priv_dev, priv_ep,
+						priv_req);
+
+		if (ret == EINPROGRESS)
+			return 0;
+	}
+
+	ret = cdns3_prepare_aligned_request_buf(priv_req);
+	if (ret < 0)
+		return ret;
+
+	ret = usb_gadget_map_request(&priv_dev->gadget, request,
+				     usb_endpoint_dir_in(ep->desc));
+	if (ret)
+		return ret;
+
+	list_add_tail(&request->list, &priv_ep->deferred_req_list);
+
+	/*
+	 * If hardware endpoint configuration has not been set yet then
+	 * just queue request in deferred list. Transfer will be started in
+	 * cdns3_set_hw_configuration.
+	 */
+	if (priv_dev->hw_configured_flag && !(priv_ep->flags & EP_STALLED) &&
+	    !(priv_ep->flags & EP_STALL_PENDING))
+		cdns3_start_all_request(priv_dev, priv_ep);
+
+	return 0;
+}
+
+static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+				 gfp_t gfp_flags)
+{
+	struct usb_request *zlp_request;
+	struct cdns3_endpoint *priv_ep;
+	struct cdns3_device *priv_dev;
+	unsigned long flags;
+	int ret;
+
+	if (!request || !ep)
+		return -EINVAL;
+
+	priv_ep = ep_to_cdns3_ep(ep);
+	priv_dev = priv_ep->cdns3_dev;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	ret = __cdns3_gadget_ep_queue(ep, request, gfp_flags);
+
+	if (ret == 0 && request->zero && request->length &&
+	    (request->length % ep->maxpacket == 0)) {
+		struct cdns3_request *priv_req;
+
+		zlp_request = cdns3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
+		zlp_request->buf = priv_dev->zlp_buf;
+		zlp_request->length = 0;
+
+		priv_req = to_cdns3_request(zlp_request);
+		priv_req->flags |= REQUEST_ZLP;
+
+		dev_dbg(priv_dev->dev, "Queuing ZLP for endpoint: %s\n",
+			priv_ep->name);
+		ret = __cdns3_gadget_ep_queue(ep, zlp_request, gfp_flags);
+	}
+
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+	return ret;
+}
+
+/**
+ * cdns3_gadget_ep_dequeue Remove request from transfer queue
+ * @ep: endpoint object associated with request
+ * @request: request object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
+			    struct usb_request *request)
+{
+	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct usb_request *req, *req_temp;
+	struct cdns3_request *priv_req;
+	struct cdns3_trb *link_trb;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!ep || !request || !ep->desc)
+		return -EINVAL;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	priv_req = to_cdns3_request(request);
+
+	trace_cdns3_ep_dequeue(priv_req);
+
+	cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress);
+
+	list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
+				 list) {
+		if (request == req)
+			goto found;
+	}
+
+	list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
+				 list) {
+		if (request == req)
+			goto found;
+	}
+
+	goto not_found;
+
+found:
+
+	if (priv_ep->wa1_trb == priv_req->trb)
+		cdns3_wa1_restore_cycle_bit(priv_ep);
+
+	link_trb = priv_req->trb;
+	cdns3_move_deq_to_next_trb(priv_req);
+	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
+
+	/* Update ring */
+	request = cdns3_next_request(&priv_ep->deferred_req_list);
+	if (request) {
+		priv_req = to_cdns3_request(request);
+
+		link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
+					      (priv_req->start_trb * TRB_SIZE));
+		link_trb->control = (link_trb->control & TRB_CYCLE) |
+				    TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
+	} else {
+		priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
+	}
+
+not_found:
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+	return ret;
+}
+
+/**
+ * __cdns3_gadget_ep_set_halt Sets stall on selected endpoint
+ * Should be called after acquiring spin_lock and selecting ep
+ * @ep: endpoint object to set stall on.
+ */
+void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+
+	trace_cdns3_halt(priv_ep, 1, 0);
+
+	if (!(priv_ep->flags & EP_STALLED)) {
+		u32 ep_sts_reg = readl(&priv_dev->regs->ep_sts);
+
+		if (!(ep_sts_reg & EP_STS_DBUSY))
+			cdns3_ep_stall_flush(priv_ep);
+		else
+			priv_ep->flags |= EP_STALL_PENDING;
+	}
+}
+
+/**
+ * __cdns3_gadget_ep_clear_halt Clears stall on selected endpoint
+ * Should be called after acquiring spin_lock and selecting ep
+ * @ep: endpoint object to clear stall on
+ */
+int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep)
+{
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	struct usb_request *request;
+	int ret = 0;
+	int val;
+
+	trace_cdns3_halt(priv_ep, 0, 0);
+
+	writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd);
+
+	/* wait for EPRST cleared */
+	readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
+				  !(val & EP_CMD_EPRST), 100);
+	if (ret)
+		return -EINVAL;
+
+	priv_ep->flags &= ~(EP_STALLED | EP_STALL_PENDING);
+
+	request = cdns3_next_request(&priv_ep->pending_req_list);
+
+	if (request)
+		cdns3_rearm_transfer(priv_ep, 1);
+
+	cdns3_start_all_request(priv_dev, priv_ep);
+	return ret;
+}
+
+/**
+ * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint
+ * @ep: endpoint object to set/clear stall on
+ * @value: 1 for set stall, 0 for clear stall
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
+	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!(priv_ep->flags & EP_ENABLED))
+		return -EPERM;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+
+	cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress);
+
+	if (!value) {
+		priv_ep->flags &= ~EP_WEDGE;
+		ret = __cdns3_gadget_ep_clear_halt(priv_ep);
+	} else {
+		__cdns3_gadget_ep_set_halt(priv_ep);
+	}
+
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+
+	return ret;
+}
+
+extern const struct usb_ep_ops cdns3_gadget_ep0_ops;
+
+static const struct usb_ep_ops cdns3_gadget_ep_ops = {
+	.enable = cdns3_gadget_ep_enable,
+	.disable = cdns3_gadget_ep_disable,
+	.alloc_request = cdns3_gadget_ep_alloc_request,
+	.free_request = cdns3_gadget_ep_free_request,
+	.queue = cdns3_gadget_ep_queue,
+	.dequeue = cdns3_gadget_ep_dequeue,
+	.set_halt = cdns3_gadget_ep_set_halt,
+	.set_wedge = cdns3_gadget_ep_set_wedge,
+};
+
+/**
+ * cdns3_gadget_get_frame Returns number of actual ITP frame
+ * @gadget: gadget object
+ *
+ * Returns number of actual ITP frame
+ */
+static int cdns3_gadget_get_frame(struct usb_gadget *gadget)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+
+	return readl(&priv_dev->regs->usb_itpn);
+}
+
+int __cdns3_gadget_wakeup(struct cdns3_device *priv_dev)
+{
+	enum usb_device_speed speed;
+
+	speed = cdns3_get_speed(priv_dev);
+
+	if (speed >= USB_SPEED_SUPER)
+		return 0;
+
+	/* Start driving resume signaling to indicate remote wakeup. */
+	writel(USB_CONF_LGO_L0, &priv_dev->regs->usb_conf);
+
+	return 0;
+}
+
+static int cdns3_gadget_wakeup(struct usb_gadget *gadget)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+	ret = __cdns3_gadget_wakeup(priv_dev);
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+	return ret;
+}
+
+static int cdns3_gadget_set_selfpowered(struct usb_gadget *gadget,
+					int is_selfpowered)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+	priv_dev->is_selfpowered = !!is_selfpowered;
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+	return 0;
+}
+
+static int cdns3_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+
+	if (is_on)
+		writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf);
+	else
+		writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf);
+
+	return 0;
+}
+
+static void cdns3_gadget_config(struct cdns3_device *priv_dev)
+{
+	struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
+	u32 reg;
+
+	cdns3_ep0_config(priv_dev);
+
+	/* enable interrupts for endpoint 0 (in and out) */
+	writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, &regs->ep_ien);
+
+	/*
+	 * Driver needs to modify LFPS minimal U1 Exit time for DEV_VER_TI_V1
+	 * revision of controller.
+	 */
+	if (priv_dev->dev_ver == DEV_VER_TI_V1) {
+		reg = readl(&regs->dbg_link1);
+
+		reg &= ~DBG_LINK1_LFPS_MIN_GEN_U1_EXIT_MASK;
+		reg |= DBG_LINK1_LFPS_MIN_GEN_U1_EXIT(0x55) |
+		       DBG_LINK1_LFPS_MIN_GEN_U1_EXIT_SET;
+		writel(reg, &regs->dbg_link1);
+	}
+
+	/*
+	 * By default some platforms has set protected access to memory.
+	 * This cause problem with cache, so driver restore non-secure
+	 * access to memory.
+	 */
+	reg = readl(&regs->dma_axi_ctrl);
+	reg |= DMA_AXI_CTRL_MARPROT(DMA_AXI_CTRL_NON_SECURE) |
+	       DMA_AXI_CTRL_MAWPROT(DMA_AXI_CTRL_NON_SECURE);
+	writel(reg, &regs->dma_axi_ctrl);
+
+	/* enable generic interrupt*/
+	writel(USB_IEN_INIT, &regs->usb_ien);
+	writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, &regs->usb_conf);
+
+	cdns3_configure_dmult(priv_dev, NULL);
+
+	cdns3_gadget_pullup(&priv_dev->gadget, 1);
+}
+
+/**
+ * cdns3_gadget_udc_start Gadget start
+ * @gadget: gadget object
+ * @driver: driver which operates on this gadget
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int cdns3_gadget_udc_start(struct usb_gadget *gadget,
+				  struct usb_gadget_driver *driver)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv_dev->lock, flags);
+	priv_dev->gadget_driver = driver;
+	cdns3_gadget_config(priv_dev);
+	spin_unlock_irqrestore(&priv_dev->lock, flags);
+	return 0;
+}
+
+/**
+ * cdns3_gadget_udc_stop Stops gadget
+ * @gadget: gadget object
+ *
+ * Returns 0
+ */
+static int cdns3_gadget_udc_stop(struct usb_gadget *gadget)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+	struct cdns3_endpoint *priv_ep;
+	u32 bEndpointAddress;
+	struct usb_ep *ep;
+	int ret = 0;
+	int val;
+
+	priv_dev->gadget_driver = NULL;
+
+	priv_dev->onchip_used_size = 0;
+	priv_dev->out_mem_is_allocated = 0;
+	priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) {
+		priv_ep = ep_to_cdns3_ep(ep);
+		bEndpointAddress = priv_ep->num | priv_ep->dir;
+		cdns3_select_ep(priv_dev, bEndpointAddress);
+		writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd);
+		readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
+					  !(val & EP_CMD_EPRST), 100);
+	}
+
+	/* disable interrupt for device */
+	writel(0, &priv_dev->regs->usb_ien);
+	writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf);
+
+	return ret;
+}
+
+static void cdns3_gadget_udc_set_speed(struct usb_gadget *gadget,
+				       enum usb_device_speed speed)
+{
+	struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
+
+	switch (speed) {
+	case USB_SPEED_FULL:
+		writel(USB_CONF_SFORCE_FS, &priv_dev->regs->usb_conf);
+		writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf);
+		break;
+	case USB_SPEED_HIGH:
+		writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf);
+		break;
+	case USB_SPEED_SUPER:
+		break;
+	default:
+		dev_err(priv_dev->dev, "invalid speed parameter %d\n", speed);
+	}
+
+	priv_dev->gadget.speed = speed;
+}
+
+static const struct usb_gadget_ops cdns3_gadget_ops = {
+	.get_frame = cdns3_gadget_get_frame,
+	.wakeup = cdns3_gadget_wakeup,
+	.set_selfpowered = cdns3_gadget_set_selfpowered,
+	.pullup = cdns3_gadget_pullup,
+	.udc_start = cdns3_gadget_udc_start,
+	.udc_stop = cdns3_gadget_udc_stop,
+	.match_ep = cdns3_gadget_match_ep,
+	.udc_set_speed = cdns3_gadget_udc_set_speed,
+};
+
+static void cdns3_free_all_eps(struct cdns3_device *priv_dev)
+{
+	int i;
+
+	/* ep0 OUT point to ep0 IN. */
+	priv_dev->eps[16] = NULL;
+
+	for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++)
+		if (priv_dev->eps[i]) {
+			cdns3_free_trb_pool(priv_dev->eps[i]);
+			devm_kfree(priv_dev->dev, priv_dev->eps[i]);
+		}
+}
+
+/**
+ * cdns3_init_eps Initializes software endpoints of gadget
+ * @cdns3: extended gadget object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int cdns3_init_eps(struct cdns3_device *priv_dev)
+{
+	u32 ep_enabled_reg, iso_ep_reg;
+	struct cdns3_endpoint *priv_ep;
+	int ep_dir, ep_number;
+	u32 ep_mask;
+	int ret = 0;
+	int i;
+
+	/* Read it from USB_CAP3 to USB_CAP5 */
+	ep_enabled_reg = readl(&priv_dev->regs->usb_cap3);
+	iso_ep_reg = readl(&priv_dev->regs->usb_cap4);
+
+	dev_dbg(priv_dev->dev, "Initializing non-zero endpoints\n");
+
+	for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) {
+		ep_dir = i >> 4;	/* i div 16 */
+		ep_number = i & 0xF;	/* i % 16 */
+		ep_mask = BIT(i);
+
+		if (!(ep_enabled_reg & ep_mask))
+			continue;
+
+		if (ep_dir && !ep_number) {
+			priv_dev->eps[i] = priv_dev->eps[0];
+			continue;
+		}
+
+		priv_ep = devm_kzalloc(priv_dev->dev, sizeof(*priv_ep),
+				       GFP_KERNEL);
+		if (!priv_ep) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		/* set parent of endpoint object */
+		priv_ep->cdns3_dev = priv_dev;
+		priv_dev->eps[i] = priv_ep;
+		priv_ep->num = ep_number;
+		priv_ep->dir = ep_dir ? USB_DIR_IN : USB_DIR_OUT;
+
+		if (!ep_number) {
+			ret = cdns3_init_ep0(priv_dev, priv_ep);
+			if (ret) {
+				dev_err(priv_dev->dev, "Failed to init ep0\n");
+				goto err;
+			}
+		} else {
+			snprintf(priv_ep->name, sizeof(priv_ep->name), "ep%d%s",
+				 ep_number, !!ep_dir ? "in" : "out");
+			priv_ep->endpoint.name = priv_ep->name;
+
+			usb_ep_set_maxpacket_limit(&priv_ep->endpoint,
+						   CDNS3_EP_MAX_PACKET_LIMIT);
+			priv_ep->endpoint.max_streams = CDNS3_EP_MAX_STREAMS;
+			priv_ep->endpoint.ops = &cdns3_gadget_ep_ops;
+			if (ep_dir)
+				priv_ep->endpoint.caps.dir_in = 1;
+			else
+				priv_ep->endpoint.caps.dir_out = 1;
+
+			if (iso_ep_reg & ep_mask)
+				priv_ep->endpoint.caps.type_iso = 1;
+
+			priv_ep->endpoint.caps.type_bulk = 1;
+			priv_ep->endpoint.caps.type_int = 1;
+
+			list_add_tail(&priv_ep->endpoint.ep_list,
+				      &priv_dev->gadget.ep_list);
+		}
+
+		priv_ep->flags = 0;
+
+		dev_info(priv_dev->dev, "Initialized  %s support: %s %s\n",
+			 priv_ep->name,
+			 priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "",
+			 priv_ep->endpoint.caps.type_iso ? "ISO" : "");
+
+		INIT_LIST_HEAD(&priv_ep->pending_req_list);
+		INIT_LIST_HEAD(&priv_ep->deferred_req_list);
+		INIT_LIST_HEAD(&priv_ep->wa2_descmiss_req_list);
+	}
+
+	return 0;
+err:
+	cdns3_free_all_eps(priv_dev);
+	return -ENOMEM;
+}
+
+void cdns3_gadget_exit(struct cdns3 *cdns)
+{
+	struct cdns3_device *priv_dev;
+
+	priv_dev = cdns->gadget_dev;
+
+	usb_del_gadget_udc(&priv_dev->gadget);
+
+	cdns3_free_all_eps(priv_dev);
+
+	while (!list_empty(&priv_dev->aligned_buf_list)) {
+		struct cdns3_aligned_buf *buf;
+
+		buf = cdns3_next_align_buf(&priv_dev->aligned_buf_list);
+		dma_free_coherent(buf->buf);
+
+		list_del(&buf->list);
+		kfree(buf);
+	}
+
+	dma_free_coherent(priv_dev->setup_buf);
+
+	kfree(priv_dev->zlp_buf);
+	kfree(priv_dev);
+	cdns->gadget_dev = NULL;
+	cdns3_drd_switch_gadget(cdns, 0);
+}
+
+static int cdns3_gadget_start(struct cdns3 *cdns)
+{
+	struct cdns3_device *priv_dev;
+	u32 max_speed;
+	int ret;
+
+	priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL);
+	if (!priv_dev)
+		return -ENOMEM;
+
+	cdns->gadget_dev = priv_dev;
+	priv_dev->sysdev = cdns->dev;
+	priv_dev->dev = cdns->dev;
+	priv_dev->regs = cdns->dev_regs;
+
+	dev_read_u32(priv_dev->dev, "cdns,on-chip-buff-size",
+		     &priv_dev->onchip_buffers);
+
+	if (priv_dev->onchip_buffers <=  0) {
+		u32 reg = readl(&priv_dev->regs->usb_cap2);
+
+		priv_dev->onchip_buffers = USB_CAP2_ACTUAL_MEM_SIZE(reg);
+	}
+
+	if (!priv_dev->onchip_buffers)
+		priv_dev->onchip_buffers = 256;
+
+	max_speed = usb_get_maximum_speed(dev_ofnode(cdns->dev));
+
+	/* Check the maximum_speed parameter */
+	switch (max_speed) {
+	case USB_SPEED_FULL:
+		/* fall through */
+	case USB_SPEED_HIGH:
+		/* fall through */
+	case USB_SPEED_SUPER:
+		break;
+	default:
+		dev_err(cdns->dev, "invalid maximum_speed parameter %d\n",
+			max_speed);
+		/* fall through */
+	case USB_SPEED_UNKNOWN:
+		/* default to superspeed */
+		max_speed = USB_SPEED_SUPER;
+		break;
+	}
+
+	/* fill gadget fields */
+	priv_dev->gadget.max_speed = max_speed;
+	priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
+	priv_dev->gadget.ops = &cdns3_gadget_ops;
+	priv_dev->gadget.name = "cdns3-gadget";
+#ifndef __UBOOT__
+	priv_dev->gadget.name = "usb-ss-gadget";
+	priv_dev->gadget.sg_supported = 1;
+	priv_dev->gadget.quirk_avoids_skb_reserve = 1;
+#endif
+
+	spin_lock_init(&priv_dev->lock);
+	INIT_WORK(&priv_dev->pending_status_wq,
+		  cdns3_pending_setup_status_handler);
+
+	/* initialize endpoint container */
+	INIT_LIST_HEAD(&priv_dev->gadget.ep_list);
+	INIT_LIST_HEAD(&priv_dev->aligned_buf_list);
+
+	ret = cdns3_init_eps(priv_dev);
+	if (ret) {
+		dev_err(priv_dev->dev, "Failed to create endpoints\n");
+		goto err1;
+	}
+
+	/* allocate memory for setup packet buffer */
+	priv_dev->setup_buf =
+		dma_alloc_coherent(8, (unsigned long *)&priv_dev->setup_dma);
+	if (!priv_dev->setup_buf) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	priv_dev->dev_ver = readl(&priv_dev->regs->usb_cap6);
+
+	dev_dbg(priv_dev->dev, "Device Controller version: %08x\n",
+		readl(&priv_dev->regs->usb_cap6));
+	dev_dbg(priv_dev->dev, "USB Capabilities:: %08x\n",
+		readl(&priv_dev->regs->usb_cap1));
+	dev_dbg(priv_dev->dev, "On-Chip memory cnfiguration: %08x\n",
+		readl(&priv_dev->regs->usb_cap2));
+
+	priv_dev->dev_ver = GET_DEV_BASE_VERSION(priv_dev->dev_ver);
+
+	priv_dev->zlp_buf = kzalloc(CDNS3_EP_ZLP_BUF_SIZE, GFP_KERNEL);
+	if (!priv_dev->zlp_buf) {
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	/* add USB gadget device */
+	ret = usb_add_gadget_udc((struct device *)priv_dev->dev,
+				 &priv_dev->gadget);
+	if (ret < 0) {
+		dev_err(priv_dev->dev,
+			"Failed to register USB device controller\n");
+		goto err4;
+	}
+
+	return 0;
+err4:
+	kfree(priv_dev->zlp_buf);
+err3:
+	dma_free_coherent(priv_dev->setup_buf);
+err2:
+	cdns3_free_all_eps(priv_dev);
+err1:
+	cdns->gadget_dev = NULL;
+	return ret;
+}
+
+static int __cdns3_gadget_init(struct cdns3 *cdns)
+{
+	int ret = 0;
+
+	cdns3_drd_switch_gadget(cdns, 1);
+
+	ret = cdns3_gadget_start(cdns);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup)
+{
+	struct cdns3_device *priv_dev = cdns->gadget_dev;
+
+	cdns3_disconnect_gadget(priv_dev);
+
+	priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
+	usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
+	cdns3_hw_reset_eps_config(priv_dev);
+
+	/* disable interrupt for device */
+	writel(0, &priv_dev->regs->usb_ien);
+
+	cdns3_gadget_pullup(&priv_dev->gadget, 0);
+
+	return 0;
+}
+
+static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated)
+{
+	struct cdns3_device *priv_dev = cdns->gadget_dev;
+
+	if (!priv_dev->gadget_driver)
+		return 0;
+
+	cdns3_gadget_config(priv_dev);
+
+	return 0;
+}
+
+/**
+ * cdns3_gadget_init - initialize device structure
+ *
+ * cdns: cdns3 instance
+ *
+ * This function initializes the gadget.
+ */
+int cdns3_gadget_init(struct cdns3 *cdns)
+{
+	struct cdns3_role_driver *rdrv;
+
+	rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+	if (!rdrv)
+		return -ENOMEM;
+
+	rdrv->start	= __cdns3_gadget_init;
+	rdrv->stop	= cdns3_gadget_exit;
+	rdrv->suspend	= cdns3_gadget_suspend;
+	rdrv->resume	= cdns3_gadget_resume;
+	rdrv->state	= CDNS3_ROLE_STATE_INACTIVE;
+	rdrv->name	= "gadget";
+	cdns->roles[USB_ROLE_DEVICE] = rdrv;
+
+	return 0;
+}
+
+/**
+ * cdns3_gadget_uboot_handle_interrupt - handle cdns3 gadget interrupt
+ * @cdns: pointer to struct cdns3
+ *
+ * Handles ep0 and gadget interrupt
+ */
+static void cdns3_gadget_uboot_handle_interrupt(struct cdns3 *cdns)
+{
+	int ret = cdns3_device_irq_handler(0, cdns);
+
+	if (ret == IRQ_WAKE_THREAD)
+		cdns3_device_thread_irq_handler(0, cdns);
+}
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct cdns3 *cdns = dev_get_priv(dev);
+
+	cdns3_gadget_uboot_handle_interrupt(cdns);
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/cdns3/gadget.h b/roms/u-boot/drivers/usb/cdns3/gadget.h
new file mode 100644
index 000000000..8803fa48b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/gadget.h
@@ -0,0 +1,1339 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * USBSS device controller driver header file
+ *
+ * Copyright (C) 2018-2019 Cadence.
+ * Copyright (C) 2017-2018 NXP
+ *
+ * Author: Pawel Laszczak <pawell@cadence.com>
+ *         Pawel Jez <pjez@cadence.com>
+ *         Peter Chen <peter.chen@nxp.com>
+ */
+#ifndef __LINUX_CDNS3_GADGET
+#define __LINUX_CDNS3_GADGET
+#include <linux/bitops.h>
+#include <linux/usb/gadget.h>
+
+/*
+ * USBSS-DEV register interface.
+ * This corresponds to the USBSS Device Controller Interface
+ */
+
+/**
+ * struct cdns3_usb_regs - device controller registers.
+ * @usb_conf:      Global Configuration.
+ * @usb_sts:       Global Status.
+ * @usb_cmd:       Global Command.
+ * @usb_itpn:      ITP/SOF number.
+ * @usb_lpm:       Global Command.
+ * @usb_ien:       USB Interrupt Enable.
+ * @usb_ists:      USB Interrupt Status.
+ * @ep_sel:        Endpoint Select.
+ * @ep_traddr:     Endpoint Transfer Ring Address.
+ * @ep_cfg:        Endpoint Configuration.
+ * @ep_cmd:        Endpoint Command.
+ * @ep_sts:        Endpoint Status.
+ * @ep_sts_sid:    Endpoint Status.
+ * @ep_sts_en:     Endpoint Status Enable.
+ * @drbl:          Doorbell.
+ * @ep_ien:        EP Interrupt Enable.
+ * @ep_ists:       EP Interrupt Status.
+ * @usb_pwr:       Global Power Configuration.
+ * @usb_conf2:     Global Configuration 2.
+ * @usb_cap1:      Capability 1.
+ * @usb_cap2:      Capability 2.
+ * @usb_cap3:      Capability 3.
+ * @usb_cap4:      Capability 4.
+ * @usb_cap5:      Capability 5.
+ * @usb_cap6:      Capability 6.
+ * @usb_cpkt1:     Custom Packet 1.
+ * @usb_cpkt2:     Custom Packet 2.
+ * @usb_cpkt3:     Custom Packet 3.
+ * @ep_dma_ext_addr: Upper address for DMA operations.
+ * @buf_addr:      Address for On-chip Buffer operations.
+ * @buf_data:      Data for On-chip Buffer operations.
+ * @buf_ctrl:      On-chip Buffer Access Control.
+ * @dtrans:        DMA Transfer Mode.
+ * @tdl_from_trb:  Source of TD Configuration.
+ * @tdl_beh:       TDL Behavior Configuration.
+ * @ep_tdl:        Endpoint TDL.
+ * @tdl_beh2:      TDL Behavior 2 Configuration.
+ * @dma_adv_td:    DMA Advance TD Configuration.
+ * @reserved1:     Reserved.
+ * @cfg_regs:      Configuration.
+ * @reserved2:     Reserved.
+ * @dma_axi_ctrl:  AXI Control.
+ * @dma_axi_id:    AXI ID register.
+ * @dma_axi_cap:   AXI Capability.
+ * @dma_axi_ctrl0: AXI Control 0.
+ * @dma_axi_ctrl1: AXI Control 1.
+ */
+struct cdns3_usb_regs {
+	__le32 usb_conf;
+	__le32 usb_sts;
+	__le32 usb_cmd;
+	__le32 usb_itpn;
+	__le32 usb_lpm;
+	__le32 usb_ien;
+	__le32 usb_ists;
+	__le32 ep_sel;
+	__le32 ep_traddr;
+	__le32 ep_cfg;
+	__le32 ep_cmd;
+	__le32 ep_sts;
+	__le32 ep_sts_sid;
+	__le32 ep_sts_en;
+	__le32 drbl;
+	__le32 ep_ien;
+	__le32 ep_ists;
+	__le32 usb_pwr;
+	__le32 usb_conf2;
+	__le32 usb_cap1;
+	__le32 usb_cap2;
+	__le32 usb_cap3;
+	__le32 usb_cap4;
+	__le32 usb_cap5;
+	__le32 usb_cap6;
+	__le32 usb_cpkt1;
+	__le32 usb_cpkt2;
+	__le32 usb_cpkt3;
+	__le32 ep_dma_ext_addr;
+	__le32 buf_addr;
+	__le32 buf_data;
+	__le32 buf_ctrl;
+	__le32 dtrans;
+	__le32 tdl_from_trb;
+	__le32 tdl_beh;
+	__le32 ep_tdl;
+	__le32 tdl_beh2;
+	__le32 dma_adv_td;
+	__le32 reserved1[26];
+	__le32 cfg_reg1;
+	__le32 dbg_link1;
+	__le32 dbg_link2;
+	__le32 cfg_regs[74];
+	__le32 reserved2[51];
+	__le32 dma_axi_ctrl;
+	__le32 dma_axi_id;
+	__le32 dma_axi_cap;
+	__le32 dma_axi_ctrl0;
+	__le32 dma_axi_ctrl1;
+};
+
+/* USB_CONF - bitmasks */
+/* Reset USB device configuration. */
+#define USB_CONF_CFGRST		BIT(0)
+/* Set Configuration. */
+#define USB_CONF_CFGSET		BIT(1)
+/* Disconnect USB device in SuperSpeed. */
+#define USB_CONF_USB3DIS	BIT(3)
+/* Disconnect USB device in HS/FS */
+#define USB_CONF_USB2DIS	BIT(4)
+/* Little Endian access - default */
+#define USB_CONF_LENDIAN	BIT(5)
+/*
+ * Big Endian access. Driver assume that byte order for
+ * SFRs access always is as Little Endian so this bit
+ * is not used.
+ */
+#define USB_CONF_BENDIAN	BIT(6)
+/* Device software reset. */
+#define USB_CONF_SWRST		BIT(7)
+/* Singular DMA transfer mode. Only for VER < DEV_VER_V3*/
+#define USB_CONF_DSING		BIT(8)
+/* Multiple DMA transfers mode. Only for VER < DEV_VER_V3 */
+#define USB_CONF_DMULT		BIT(9)
+/* DMA clock turn-off enable. */
+#define USB_CONF_DMAOFFEN	BIT(10)
+/* DMA clock turn-off disable. */
+#define USB_CONF_DMAOFFDS	BIT(11)
+/* Clear Force Full Speed. */
+#define USB_CONF_CFORCE_FS	BIT(12)
+/* Set Force Full Speed. */
+#define USB_CONF_SFORCE_FS	BIT(13)
+/* Device enable. */
+#define USB_CONF_DEVEN		BIT(14)
+/* Device disable. */
+#define USB_CONF_DEVDS		BIT(15)
+/* L1 LPM state entry enable (used in HS/FS mode). */
+#define USB_CONF_L1EN		BIT(16)
+/* L1 LPM state entry disable (used in HS/FS mode). */
+#define USB_CONF_L1DS		BIT(17)
+/* USB 2.0 clock gate disable. */
+#define USB_CONF_CLK2OFFEN	BIT(18)
+/* USB 2.0 clock gate enable. */
+#define USB_CONF_CLK2OFFDS	BIT(19)
+/* L0 LPM state entry request (used in HS/FS mode). */
+#define USB_CONF_LGO_L0		BIT(20)
+/* USB 3.0 clock gate disable. */
+#define USB_CONF_CLK3OFFEN	BIT(21)
+/* USB 3.0 clock gate enable. */
+#define USB_CONF_CLK3OFFDS	BIT(22)
+/* Bit 23 is reserved*/
+/* U1 state entry enable (used in SS mode). */
+#define USB_CONF_U1EN		BIT(24)
+/* U1 state entry disable (used in SS mode). */
+#define USB_CONF_U1DS		BIT(25)
+/* U2 state entry enable (used in SS mode). */
+#define USB_CONF_U2EN		BIT(26)
+/* U2 state entry disable (used in SS mode). */
+#define USB_CONF_U2DS		BIT(27)
+/* U0 state entry request (used in SS mode). */
+#define USB_CONF_LGO_U0		BIT(28)
+/* U1 state entry request (used in SS mode). */
+#define USB_CONF_LGO_U1		BIT(29)
+/* U2 state entry request (used in SS mode). */
+#define USB_CONF_LGO_U2		BIT(30)
+/* SS.Inactive state entry request (used in SS mode) */
+#define USB_CONF_LGO_SSINACT	BIT(31)
+
+/* USB_STS - bitmasks */
+/*
+ * Configuration status.
+ * 1 - device is in the configured state.
+ * 0 - device is not configured.
+ */
+#define USB_STS_CFGSTS_MASK	BIT(0)
+#define USB_STS_CFGSTS(p)	((p) & USB_STS_CFGSTS_MASK)
+/*
+ * On-chip memory overflow.
+ * 0 - On-chip memory status OK.
+ * 1 - On-chip memory overflow.
+ */
+#define USB_STS_OV_MASK		BIT(1)
+#define USB_STS_OV(p)		((p) & USB_STS_OV_MASK)
+/*
+ * SuperSpeed connection status.
+ * 0 - USB in SuperSpeed mode disconnected.
+ * 1 - USB in SuperSpeed mode connected.
+ */
+#define USB_STS_USB3CONS_MASK	BIT(2)
+#define USB_STS_USB3CONS(p)	((p) & USB_STS_USB3CONS_MASK)
+/*
+ * DMA transfer configuration status.
+ * 0 - single request.
+ * 1 - multiple TRB chain
+ * Supported only for controller version <  DEV_VER_V3
+ */
+#define USB_STS_DTRANS_MASK	BIT(3)
+#define USB_STS_DTRANS(p)	((p) & USB_STS_DTRANS_MASK)
+/*
+ * Device speed.
+ * 0 - Undefined (value after reset).
+ * 1 - Low speed
+ * 2 - Full speed
+ * 3 - High speed
+ * 4 - Super speed
+ */
+#define USB_STS_USBSPEED_MASK	GENMASK(6, 4)
+#define USB_STS_USBSPEED(p)	(((p) & USB_STS_USBSPEED_MASK) >> 4)
+#define USB_STS_LS		(0x1 << 4)
+#define USB_STS_FS		(0x2 << 4)
+#define USB_STS_HS		(0x3 << 4)
+#define USB_STS_SS		(0x4 << 4)
+#define DEV_UNDEFSPEED(p)	(((p) & USB_STS_USBSPEED_MASK) == (0x0 << 4))
+#define DEV_LOWSPEED(p)		(((p) & USB_STS_USBSPEED_MASK) == USB_STS_LS)
+#define DEV_FULLSPEED(p)	(((p) & USB_STS_USBSPEED_MASK) == USB_STS_FS)
+#define DEV_HIGHSPEED(p)	(((p) & USB_STS_USBSPEED_MASK) == USB_STS_HS)
+#define DEV_SUPERSPEED(p)	(((p) & USB_STS_USBSPEED_MASK) == USB_STS_SS)
+/*
+ * Endianness for SFR access.
+ * 0 - Little Endian order (default after hardware reset).
+ * 1 - Big Endian order
+ */
+#define USB_STS_ENDIAN_MASK	BIT(7)
+#define USB_STS_ENDIAN(p)	((p) & USB_STS_ENDIAN_MASK)
+/*
+ * HS/FS clock turn-off status.
+ * 0 - hsfs clock is always on.
+ * 1 - hsfs clock turn-off in L2 (HS/FS mode) is enabled
+ *          (default after hardware reset).
+ */
+#define USB_STS_CLK2OFF_MASK	BIT(8)
+#define USB_STS_CLK2OFF(p)	((p) & USB_STS_CLK2OFF_MASK)
+/*
+ * PCLK clock turn-off status.
+ * 0 - pclk clock is always on.
+ * 1 - pclk clock turn-off in U3 (SS mode) is enabled
+ *          (default after hardware reset).
+ */
+#define USB_STS_CLK3OFF_MASK	BIT(9)
+#define USB_STS_CLK3OFF(p)	((p) & USB_STS_CLK3OFF_MASK)
+/*
+ * Controller in reset state.
+ * 0 - Internal reset is active.
+ * 1 - Internal reset is not active and controller is fully operational.
+ */
+#define USB_STS_IN_RST_MASK	BIT(10)
+#define USB_STS_IN_RST(p)	((p) & USB_STS_IN_RST_MASK)
+/*
+ * Status of the "TDL calculation basing on TRB" feature.
+ * 0 - disabled
+ * 1 - enabled
+ * Supported only for DEV_VER_V2 controller version.
+ */
+#define USB_STS_TDL_TRB_ENABLED	BIT(11)
+/*
+ * Device enable Status.
+ * 0 - USB device is disabled (VBUS input is disconnected from internal logic).
+ * 1 - USB device is enabled (VBUS input is connected to the internal logic).
+ */
+#define USB_STS_DEVS_MASK	BIT(14)
+#define USB_STS_DEVS(p)		((p) & USB_STS_DEVS_MASK)
+/*
+ * Address status.
+ * 0 - USB device is default state.
+ * 1 - USB device is at least in address state.
+ */
+#define USB_STS_ADDRESSED_MASK	BIT(15)
+#define USB_STS_ADDRESSED(p)	((p) & USB_STS_ADDRESSED_MASK)
+/*
+ * L1 LPM state enable status (used in HS/FS mode).
+ * 0 - Entering to L1 LPM state disabled.
+ * 1 - Entering to L1 LPM state enabled.
+ */
+#define USB_STS_L1ENS_MASK	BIT(16)
+#define USB_STS_L1ENS(p)	((p) & USB_STS_L1ENS_MASK)
+/*
+ * Internal VBUS connection status (used both in HS/FS  and SS mode).
+ * 0 - internal VBUS is not detected.
+ * 1 - internal VBUS is detected.
+ */
+#define USB_STS_VBUSS_MASK	BIT(17)
+#define USB_STS_VBUSS(p)	((p) & USB_STS_VBUSS_MASK)
+/*
+ * HS/FS LPM  state (used in FS/HS mode).
+ * 0 - L0 State
+ * 1 - L1 State
+ * 2 - L2 State
+ * 3 - L3 State
+ */
+#define USB_STS_LPMST_MASK	GENMASK(19, 18)
+#define DEV_L0_STATE(p)		(((p) & USB_STS_LPMST_MASK) == (0x0 << 18))
+#define DEV_L1_STATE(p)		(((p) & USB_STS_LPMST_MASK) == (0x1 << 18))
+#define DEV_L2_STATE(p)		(((p) & USB_STS_LPMST_MASK) == (0x2 << 18))
+#define DEV_L3_STATE(p)		(((p) & USB_STS_LPMST_MASK) == (0x3 << 18))
+/*
+ * Disable HS status (used in FS/HS mode).
+ * 0 - the disconnect bit for HS/FS mode is set .
+ * 1 - the disconnect bit for HS/FS mode is not set.
+ */
+#define USB_STS_USB2CONS_MASK	BIT(20)
+#define USB_STS_USB2CONS(p)	((p) & USB_STS_USB2CONS_MASK)
+/*
+ * HS/FS mode connection status (used in FS/HS mode).
+ * 0 - High Speed operations in USB2.0 (FS/HS) mode not disabled.
+ * 1 - High Speed operations in USB2.0 (FS/HS).
+ */
+#define USB_STS_DISABLE_HS_MASK	BIT(21)
+#define USB_STS_DISABLE_HS(p)	((p) & USB_STS_DISABLE_HS_MASK)
+/*
+ * U1 state enable status (used in SS mode).
+ * 0 - Entering to  U1 state disabled.
+ * 1 - Entering to  U1 state enabled.
+ */
+#define USB_STS_U1ENS_MASK	BIT(24)
+#define USB_STS_U1ENS(p)	((p) & USB_STS_U1ENS_MASK)
+/*
+ * U2 state enable status (used in SS mode).
+ * 0 - Entering to  U2 state disabled.
+ * 1 - Entering to  U2 state enabled.
+ */
+#define USB_STS_U2ENS_MASK	BIT(25)
+#define USB_STS_U2ENS(p)	((p) & USB_STS_U2ENS_MASK)
+/*
+ * SuperSpeed Link LTSSM state. This field reflects USBSS-DEV current
+ * SuperSpeed link state
+ */
+#define USB_STS_LST_MASK	GENMASK(29, 26)
+#define DEV_LST_U0		(((p) & USB_STS_LST_MASK) == (0x0 << 26))
+#define DEV_LST_U1		(((p) & USB_STS_LST_MASK) == (0x1 << 26))
+#define DEV_LST_U2		(((p) & USB_STS_LST_MASK) == (0x2 << 26))
+#define DEV_LST_U3		(((p) & USB_STS_LST_MASK) == (0x3 << 26))
+#define DEV_LST_DISABLED	(((p) & USB_STS_LST_MASK) == (0x4 << 26))
+#define DEV_LST_RXDETECT	(((p) & USB_STS_LST_MASK) == (0x5 << 26))
+#define DEV_LST_INACTIVE	(((p) & USB_STS_LST_MASK) == (0x6 << 26))
+#define DEV_LST_POLLING		(((p) & USB_STS_LST_MASK) == (0x7 << 26))
+#define DEV_LST_RECOVERY	(((p) & USB_STS_LST_MASK) == (0x8 << 26))
+#define DEV_LST_HOT_RESET	(((p) & USB_STS_LST_MASK) == (0x9 << 26))
+#define DEV_LST_COMP_MODE	(((p) & USB_STS_LST_MASK) == (0xa << 26))
+#define DEV_LST_LB_STATE	(((p) & USB_STS_LST_MASK) == (0xb << 26))
+/*
+ * DMA clock turn-off status.
+ * 0 - DMA clock is always on (default after hardware reset).
+ * 1 - DMA clock turn-off in U1, U2 and U3 (SS mode) is enabled.
+ */
+#define USB_STS_DMAOFF_MASK	BIT(30)
+#define USB_STS_DMAOFF(p)	((p) & USB_STS_DMAOFF_MASK)
+/*
+ * SFR Endian status.
+ * 0 - Little Endian order (default after hardware reset).
+ * 1 - Big Endian order.
+ */
+#define USB_STS_ENDIAN2_MASK	BIT(31)
+#define USB_STS_ENDIAN2(p)	((p) & USB_STS_ENDIAN2_MASK)
+
+/* USB_CMD -  bitmasks */
+/* Set Function Address */
+#define USB_CMD_SET_ADDR	BIT(0)
+/*
+ * Function Address This field is saved to the device only when the field
+ * SET_ADDR is set '1 ' during write to USB_CMD register.
+ * Software is responsible for entering the address of the device during
+ * SET_ADDRESS request service. This field should be set immediately after
+ * the SETUP packet is decoded, and prior to confirmation of the status phase
+ */
+#define USB_CMD_FADDR_MASK	GENMASK(7, 1)
+#define USB_CMD_FADDR(p)	(((p) << 1) & USB_CMD_FADDR_MASK)
+/* Send Function Wake Device Notification TP (used only in SS mode). */
+#define USB_CMD_SDNFW		BIT(8)
+/* Set Test Mode (used only in HS/FS mode). */
+#define USB_CMD_STMODE		BIT(9)
+/* Test mode selector (used only in HS/FS mode) */
+#define USB_STS_TMODE_SEL_MASK	GENMASK(11, 10)
+#define USB_STS_TMODE_SEL(p)	(((p) << 10) & USB_STS_TMODE_SEL_MASK)
+/*
+ *  Send Latency Tolerance Message Device Notification TP (used only
+ *  in SS mode).
+ */
+#define USB_CMD_SDNLTM		BIT(12)
+/* Send Custom Transaction Packet (used only in SS mode) */
+#define USB_CMD_SPKT		BIT(13)
+/*Device Notification 'Function Wake' - Interface value (only in SS mode. */
+#define USB_CMD_DNFW_INT_MASK	GENMASK(23, 16)
+#define USB_STS_DNFW_INT(p)	(((p) << 16) & USB_CMD_DNFW_INT_MASK)
+/*
+ * Device Notification 'Latency Tolerance Message' -373 BELT value [7:0]
+ * (used only in SS mode).
+ */
+#define USB_CMD_DNLTM_BELT_MASK	GENMASK(27, 16)
+#define USB_STS_DNLTM_BELT(p)	(((p) << 16) & USB_CMD_DNLTM_BELT_MASK)
+
+/* USB_ITPN - bitmasks */
+/*
+ * ITP(SS) / SOF (HS/FS) number
+ * In SS mode this field represent number of last ITP received from host.
+ * In HS/FS mode this field represent number of last SOF received from host.
+ */
+#define USB_ITPN_MASK		GENMASK(13, 0)
+#define USB_ITPN(p)		((p) & USB_ITPN_MASK)
+
+/* USB_LPM - bitmasks */
+/* Host Initiated Resume Duration. */
+#define USB_LPM_HIRD_MASK	GENMASK(3, 0)
+#define USB_LPM_HIRD(p)		((p) & USB_LPM_HIRD_MASK)
+/* Remote Wakeup Enable (bRemoteWake). */
+#define USB_LPM_BRW		BIT(4)
+
+/* USB_IEN - bitmasks */
+/* SS connection interrupt enable */
+#define USB_IEN_CONIEN		BIT(0)
+/* SS disconnection interrupt enable. */
+#define USB_IEN_DISIEN		BIT(1)
+/* USB SS warm reset interrupt enable. */
+#define USB_IEN_UWRESIEN	BIT(2)
+/* USB SS hot reset interrupt enable */
+#define USB_IEN_UHRESIEN	BIT(3)
+/* SS link U3 state enter interrupt enable (suspend).*/
+#define USB_IEN_U3ENTIEN	BIT(4)
+/* SS link U3 state exit interrupt enable (wakeup). */
+#define USB_IEN_U3EXTIEN	BIT(5)
+/* SS link U2 state enter interrupt enable.*/
+#define USB_IEN_U2ENTIEN	BIT(6)
+/* SS link U2 state exit interrupt enable.*/
+#define USB_IEN_U2EXTIEN	BIT(7)
+/* SS link U1 state enter interrupt enable.*/
+#define USB_IEN_U1ENTIEN	BIT(8)
+/* SS link U1 state exit interrupt enable.*/
+#define USB_IEN_U1EXTIEN	BIT(9)
+/* ITP/SOF packet detected interrupt enable.*/
+#define USB_IEN_ITPIEN		BIT(10)
+/* Wakeup interrupt enable.*/
+#define USB_IEN_WAKEIEN		BIT(11)
+/* Send Custom Packet interrupt enable.*/
+#define USB_IEN_SPKTIEN		BIT(12)
+/* HS/FS mode connection interrupt enable.*/
+#define USB_IEN_CON2IEN		BIT(16)
+/* HS/FS mode disconnection interrupt enable.*/
+#define USB_IEN_DIS2IEN		BIT(17)
+/* USB reset (HS/FS mode) interrupt enable.*/
+#define USB_IEN_U2RESIEN	BIT(18)
+/* LPM L2 state enter interrupt enable.*/
+#define USB_IEN_L2ENTIEN	BIT(20)
+/* LPM  L2 state exit interrupt enable.*/
+#define USB_IEN_L2EXTIEN	BIT(21)
+/* LPM L1 state enter interrupt enable.*/
+#define USB_IEN_L1ENTIEN	BIT(24)
+/* LPM  L1 state exit interrupt enable.*/
+#define USB_IEN_L1EXTIEN	BIT(25)
+/* Configuration reset interrupt enable.*/
+#define USB_IEN_CFGRESIEN	BIT(26)
+/* Start of the USB SS warm reset interrupt enable.*/
+#define USB_IEN_UWRESSIEN	BIT(28)
+/* End of the USB SS warm reset interrupt enable.*/
+#define USB_IEN_UWRESEIEN	BIT(29)
+
+#define USB_IEN_INIT  (USB_IEN_U2RESIEN | USB_ISTS_DIS2I | USB_IEN_CON2IEN \
+		       | USB_IEN_UHRESIEN | USB_IEN_UWRESIEN | USB_IEN_DISIEN \
+		       | USB_IEN_CONIEN | USB_IEN_U3EXTIEN | USB_IEN_L2ENTIEN \
+		       | USB_IEN_L2EXTIEN | USB_IEN_L1ENTIEN | USB_IEN_U3ENTIEN)
+
+/* USB_ISTS - bitmasks */
+/* SS Connection detected. */
+#define USB_ISTS_CONI		BIT(0)
+/* SS Disconnection detected. */
+#define USB_ISTS_DISI		BIT(1)
+/* UUSB warm reset detectede. */
+#define USB_ISTS_UWRESI		BIT(2)
+/* USB hot reset detected. */
+#define USB_ISTS_UHRESI		BIT(3)
+/* U3 link state enter detected (suspend).*/
+#define USB_ISTS_U3ENTI		BIT(4)
+/* U3 link state exit detected (wakeup). */
+#define USB_ISTS_U3EXTI		BIT(5)
+/* U2 link state enter detected.*/
+#define USB_ISTS_U2ENTI		BIT(6)
+/* U2 link state exit detected.*/
+#define USB_ISTS_U2EXTI		BIT(7)
+/* U1 link state enter detected.*/
+#define USB_ISTS_U1ENTI		BIT(8)
+/* U1 link state exit detected.*/
+#define USB_ISTS_U1EXTI		BIT(9)
+/* ITP/SOF packet detected.*/
+#define USB_ISTS_ITPI		BIT(10)
+/* Wakeup detected.*/
+#define USB_ISTS_WAKEI		BIT(11)
+/* Send Custom Packet detected.*/
+#define USB_ISTS_SPKTI		BIT(12)
+/* HS/FS mode connection detected.*/
+#define USB_ISTS_CON2I		BIT(16)
+/* HS/FS mode disconnection detected.*/
+#define USB_ISTS_DIS2I		BIT(17)
+/* USB reset (HS/FS mode) detected.*/
+#define USB_ISTS_U2RESI		BIT(18)
+/* LPM L2 state enter detected.*/
+#define USB_ISTS_L2ENTI		BIT(20)
+/* LPM  L2 state exit detected.*/
+#define USB_ISTS_L2EXTI		BIT(21)
+/* LPM L1 state enter detected.*/
+#define USB_ISTS_L1ENTI		BIT(24)
+/* LPM L1 state exit detected.*/
+#define USB_ISTS_L1EXTI		BIT(25)
+/* USB configuration reset detected.*/
+#define USB_ISTS_CFGRESI	BIT(26)
+/* Start of the USB warm reset detected.*/
+#define USB_ISTS_UWRESSI	BIT(28)
+/* End of the USB warm reset detected.*/
+#define USB_ISTS_UWRESEI	BIT(29)
+
+/* USB_SEL - bitmasks */
+#define EP_SEL_EPNO_MASK	GENMASK(3, 0)
+/* Endpoint number. */
+#define EP_SEL_EPNO(p)		((p) & EP_SEL_EPNO_MASK)
+/* Endpoint direction bit - 0 - OUT, 1 - IN. */
+#define EP_SEL_DIR		BIT(7)
+
+#define select_ep_in(nr)	(EP_SEL_EPNO(p) | EP_SEL_DIR)
+#define select_ep_out		(EP_SEL_EPNO(p))
+
+/* EP_TRADDR - bitmasks */
+/* Transfer Ring address. */
+#define EP_TRADDR_TRADDR(p)	((p))
+
+/* EP_CFG - bitmasks */
+/* Endpoint enable */
+#define EP_CFG_ENABLE		BIT(0)
+/*
+ *  Endpoint type.
+ * 1 - isochronous
+ * 2 - bulk
+ * 3 - interrupt
+ */
+#define EP_CFG_EPTYPE_MASK	GENMASK(2, 1)
+#define EP_CFG_EPTYPE(p)	(((p) << 1)  & EP_CFG_EPTYPE_MASK)
+/* Stream support enable (only in SS mode). */
+#define EP_CFG_STREAM_EN	BIT(3)
+/* TDL check (only in SS mode for BULK EP). */
+#define EP_CFG_TDL_CHK		BIT(4)
+/* SID check (only in SS mode for BULK OUT EP). */
+#define EP_CFG_SID_CHK		BIT(5)
+/* DMA transfer endianness. */
+#define EP_CFG_EPENDIAN		BIT(7)
+/* Max burst size (used only in SS mode). */
+#define EP_CFG_MAXBURST_MASK	GENMASK(11, 8)
+#define EP_CFG_MAXBURST(p)	(((p) << 8) & EP_CFG_MAXBURST_MASK)
+/* ISO max burst. */
+#define EP_CFG_MULT_MASK	GENMASK(15, 14)
+#define EP_CFG_MULT(p)		(((p) << 14) & EP_CFG_MULT_MASK)
+/* ISO max burst. */
+#define EP_CFG_MAXPKTSIZE_MASK	GENMASK(26, 16)
+#define EP_CFG_MAXPKTSIZE(p)	(((p) << 16) & EP_CFG_MAXPKTSIZE_MASK)
+/* Max number of buffered packets. */
+#define EP_CFG_BUFFERING_MASK	GENMASK(31, 27)
+#define EP_CFG_BUFFERING(p)	(((p) << 27) & EP_CFG_BUFFERING_MASK)
+
+/* EP_CMD - bitmasks */
+/* Endpoint reset. */
+#define EP_CMD_EPRST		BIT(0)
+/* Endpoint STALL set. */
+#define EP_CMD_SSTALL		BIT(1)
+/* Endpoint STALL clear. */
+#define EP_CMD_CSTALL		BIT(2)
+/* Send ERDY TP. */
+#define EP_CMD_ERDY		BIT(3)
+/* Request complete. */
+#define EP_CMD_REQ_CMPL		BIT(5)
+/* Transfer descriptor ready. */
+#define EP_CMD_DRDY		BIT(6)
+/* Data flush. */
+#define EP_CMD_DFLUSH		BIT(7)
+/*
+ * Transfer Descriptor Length write  (used only for Bulk Stream capable
+ * endpoints in SS mode).
+ * Bit Removed from DEV_VER_V3 controller version.
+ */
+#define EP_CMD_STDL		BIT(8)
+/*
+ * Transfer Descriptor Length (used only in SS mode for bulk endpoints).
+ * Bits Removed from DEV_VER_V3 controller version.
+ */
+#define EP_CMD_TDL_MASK		GENMASK(15, 9)
+#define EP_CMD_TDL_SET(p)	(((p) << 9) & EP_CMD_TDL_MASK)
+#define EP_CMD_TDL_GET(p)	(((p) & EP_CMD_TDL_MASK) >> 9)
+
+/* ERDY Stream ID value (used in SS mode). */
+#define EP_CMD_ERDY_SID_MASK	GENMASK(31, 16)
+#define EP_CMD_ERDY_SID(p)	(((p) << 16) & EP_CMD_ERDY_SID_MASK)
+
+/* EP_STS - bitmasks */
+/* Setup transfer complete. */
+#define EP_STS_SETUP		BIT(0)
+/* Endpoint STALL status. */
+#define EP_STS_STALL(p)		((p) & BIT(1))
+/* Interrupt On Complete. */
+#define EP_STS_IOC		BIT(2)
+/* Interrupt on Short Packet. */
+#define EP_STS_ISP		BIT(3)
+/* Transfer descriptor missing. */
+#define EP_STS_DESCMIS		BIT(4)
+/* Stream Rejected (used only in SS mode) */
+#define EP_STS_STREAMR		BIT(5)
+/* EXIT from MOVE DATA State (used only for stream transfers in SS mode). */
+#define EP_STS_MD_EXIT		BIT(6)
+/* TRB error. */
+#define EP_STS_TRBERR		BIT(7)
+/* Not ready (used only in SS mode). */
+#define EP_STS_NRDY		BIT(8)
+/* DMA busy bit. */
+#define EP_STS_DBUSY		BIT(9)
+/* Endpoint Buffer Empty */
+#define EP_STS_BUFFEMPTY(p)	((p) & BIT(10))
+/* Current Cycle Status */
+#define EP_STS_CCS(p)		((p) & BIT(11))
+/* Prime (used only in SS mode. */
+#define EP_STS_PRIME		BIT(12)
+/* Stream error (used only in SS mode). */
+#define EP_STS_SIDERR		BIT(13)
+/* OUT size mismatch. */
+#define EP_STS_OUTSMM		BIT(14)
+/* ISO transmission error. */
+#define EP_STS_ISOERR		BIT(15)
+/* Host Packet Pending (only for SS mode). */
+#define EP_STS_HOSTPP(p)	((p) & BIT(16))
+/* Stream Protocol State Machine State (only for Bulk stream endpoints). */
+#define EP_STS_SPSMST_MASK		GENMASK(18, 17)
+#define EP_STS_SPSMST_DISABLED(p)	(((p) & EP_STS_SPSMST_MASK) >> 17)
+#define EP_STS_SPSMST_IDLE(p)		(((p) & EP_STS_SPSMST_MASK) >> 17)
+#define EP_STS_SPSMST_START_STREAM(p)	(((p) & EP_STS_SPSMST_MASK) >> 17)
+#define EP_STS_SPSMST_MOVE_DATA(p)	(((p) & EP_STS_SPSMST_MASK) >> 17)
+/* Interrupt On Transfer complete. */
+#define EP_STS_IOT		BIT(19)
+/* OUT queue endpoint number. */
+#define EP_STS_OUTQ_NO_MASK	GENMASK(27, 24)
+#define EP_STS_OUTQ_NO(p)	(((p) & EP_STS_OUTQ_NO_MASK) >> 24)
+/* OUT queue valid flag. */
+#define EP_STS_OUTQ_VAL_MASK	BIT(28)
+#define EP_STS_OUTQ_VAL(p)	((p) & EP_STS_OUTQ_VAL_MASK)
+/* SETUP WAIT. */
+#define EP_STS_STPWAIT		BIT(31)
+
+/* EP_STS_SID - bitmasks */
+/* Stream ID (used only in SS mode). */
+#define EP_STS_SID_MASK		GENMASK(15, 0)
+#define EP_STS_SID(p)		((p) & EP_STS_SID_MASK)
+
+/* EP_STS_EN - bitmasks */
+/* SETUP interrupt enable. */
+#define EP_STS_EN_SETUPEN	BIT(0)
+/* OUT transfer missing descriptor enable. */
+#define EP_STS_EN_DESCMISEN	BIT(4)
+/* Stream Rejected enable. */
+#define EP_STS_EN_STREAMREN	BIT(5)
+/* Move Data Exit enable.*/
+#define EP_STS_EN_MD_EXITEN	BIT(6)
+/* TRB enable. */
+#define EP_STS_EN_TRBERREN	BIT(7)
+/* NRDY enable. */
+#define EP_STS_EN_NRDYEN	BIT(8)
+/* Prime enable. */
+#define EP_STS_EN_PRIMEEEN	BIT(12)
+/* Stream error enable. */
+#define EP_STS_EN_SIDERREN	BIT(13)
+/* OUT size mismatch enable. */
+#define EP_STS_EN_OUTSMMEN	BIT(14)
+/* ISO transmission error enable. */
+#define EP_STS_EN_ISOERREN	BIT(15)
+/* Interrupt on Transmission complete enable. */
+#define EP_STS_EN_IOTEN		BIT(19)
+/* Setup Wait interrupt enable. */
+#define EP_STS_EN_STPWAITEN	BIT(31)
+
+/* DRBL- bitmasks */
+#define DB_VALUE_BY_INDEX(index) (1 << (index))
+#define DB_VALUE_EP0_OUT	BIT(0)
+#define DB_VALUE_EP0_IN		BIT(16)
+
+/* EP_IEN - bitmasks */
+#define EP_IEN(index)		(1 << (index))
+#define EP_IEN_EP_OUT0		BIT(0)
+#define EP_IEN_EP_IN0		BIT(16)
+
+/* EP_ISTS - bitmasks */
+#define EP_ISTS(index)		(1 << (index))
+#define EP_ISTS_EP_OUT0		BIT(0)
+#define EP_ISTS_EP_IN0		BIT(16)
+
+/* USB_PWR- bitmasks */
+/*Power Shut Off capability enable*/
+#define PUSB_PWR_PSO_EN		BIT(0)
+/*Power Shut Off capability disable*/
+#define PUSB_PWR_PSO_DS		BIT(1)
+/*
+ * Enables turning-off Reference Clock.
+ * This bit is optional and implemented only when support for OTG is
+ * implemented (indicated by OTG_READY bit set to '1').
+ */
+#define PUSB_PWR_STB_CLK_SWITCH_EN	BIT(8)
+/*
+ * Status bit indicating that operation required by STB_CLK_SWITCH_EN write
+ * is completed
+ */
+#define PUSB_PWR_STB_CLK_SWITCH_DONE	BIT(9)
+/* This bit informs if Fast Registers Access is enabled. */
+#define PUSB_PWR_FST_REG_ACCESS_STAT	BIT(30)
+/* Fast Registers Access Enable. */
+#define PUSB_PWR_FST_REG_ACCESS		BIT(31)
+
+/* USB_CONF2- bitmasks */
+/*
+ * Writing 1 disables TDL calculation basing on TRB feature in controller
+ * for DMULT mode.
+ * Bit supported only for DEV_VER_V2 version.
+ */
+#define USB_CONF2_DIS_TDL_TRB		BIT(1)
+/*
+ * Writing 1 enables TDL calculation basing on TRB feature in controller
+ * for DMULT mode.
+ * Bit supported only for DEV_VER_V2 version.
+ */
+#define USB_CONF2_EN_TDL_TRB		BIT(2)
+
+/* USB_CAP1- bitmasks */
+/*
+ * SFR Interface type
+ * These field reflects type of SFR interface implemented:
+ * 0x0 - OCP
+ * 0x1 - AHB,
+ * 0x2 - PLB
+ * 0x3 - AXI
+ * 0x4-0xF - reserved
+ */
+#define USB_CAP1_SFR_TYPE_MASK	GENMASK(3, 0)
+#define DEV_SFR_TYPE_OCP(p)	(((p) & USB_CAP1_SFR_TYPE_MASK) == 0x0)
+#define DEV_SFR_TYPE_AHB(p)	(((p) & USB_CAP1_SFR_TYPE_MASK) == 0x1)
+#define DEV_SFR_TYPE_PLB(p)	(((p) & USB_CAP1_SFR_TYPE_MASK) == 0x2)
+#define DEV_SFR_TYPE_AXI(p)	(((p) & USB_CAP1_SFR_TYPE_MASK) == 0x3)
+/*
+ * SFR Interface width
+ * These field reflects width of SFR interface implemented:
+ * 0x0 - 8 bit interface,
+ * 0x1 - 16 bit interface,
+ * 0x2 - 32 bit interface
+ * 0x3 - 64 bit interface
+ * 0x4-0xF - reserved
+ */
+#define USB_CAP1_SFR_WIDTH_MASK	GENMASK(7, 4)
+#define DEV_SFR_WIDTH_8(p)	(((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x0 << 4))
+#define DEV_SFR_WIDTH_16(p)	(((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x1 << 4))
+#define DEV_SFR_WIDTH_32(p)	(((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x2 << 4))
+#define DEV_SFR_WIDTH_64(p)	(((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x3 << 4))
+/*
+ * DMA Interface type
+ * These field reflects type of DMA interface implemented:
+ * 0x0 - OCP
+ * 0x1 - AHB,
+ * 0x2 - PLB
+ * 0x3 - AXI
+ * 0x4-0xF - reserved
+ */
+#define USB_CAP1_DMA_TYPE_MASK	GENMASK(11, 8)
+#define DEV_DMA_TYPE_OCP(p)	(((p) & USB_CAP1_DMA_TYPE_MASK) == (0x0 << 8))
+#define DEV_DMA_TYPE_AHB(p)	(((p) & USB_CAP1_DMA_TYPE_MASK) == (0x1 << 8))
+#define DEV_DMA_TYPE_PLB(p)	(((p) & USB_CAP1_DMA_TYPE_MASK) == (0x2 << 8))
+#define DEV_DMA_TYPE_AXI(p)	(((p) & USB_CAP1_DMA_TYPE_MASK) == (0x3 << 8))
+/*
+ * DMA Interface width
+ * These field reflects width of DMA interface implemented:
+ * 0x0 - reserved,
+ * 0x1 - reserved,
+ * 0x2 - 32 bit interface
+ * 0x3 - 64 bit interface
+ * 0x4-0xF - reserved
+ */
+#define USB_CAP1_DMA_WIDTH_MASK	GENMASK(15, 12)
+#define DEV_DMA_WIDTH_32(p)	(((p) & USB_CAP1_DMA_WIDTH_MASK) == (0x2 << 12))
+#define DEV_DMA_WIDTH_64(p)	(((p) & USB_CAP1_DMA_WIDTH_MASK) == (0x3 << 12))
+/*
+ * USB3 PHY Interface type
+ * These field reflects type of USB3 PHY interface implemented:
+ * 0x0 - USB PIPE,
+ * 0x1 - RMMI,
+ * 0x2-0xF - reserved
+ */
+#define USB_CAP1_U3PHY_TYPE_MASK GENMASK(19, 16)
+#define DEV_U3PHY_PIPE(p) (((p) & USB_CAP1_U3PHY_TYPE_MASK) == (0x0 << 16))
+#define DEV_U3PHY_RMMI(p) (((p) & USB_CAP1_U3PHY_TYPE_MASK) == (0x1 << 16))
+/*
+ * USB3 PHY Interface width
+ * These field reflects width of USB3 PHY interface implemented:
+ * 0x0 - 8 bit PIPE interface,
+ * 0x1 - 16 bit PIPE interface,
+ * 0x2 - 32 bit PIPE interface,
+ * 0x3 - 64 bit PIPE interface
+ * 0x4-0xF - reserved
+ * Note: When SSIC interface is implemented this field shows the width of
+ * internal PIPE interface. The RMMI interface is always 20bit wide.
+ */
+#define USB_CAP1_U3PHY_WIDTH_MASK GENMASK(23, 20)
+#define DEV_U3PHY_WIDTH_8(p) \
+	(((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x0 << 20))
+#define DEV_U3PHY_WIDTH_16(p) \
+	(((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x1 << 16))
+#define DEV_U3PHY_WIDTH_32(p) \
+	(((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x2 << 20))
+#define DEV_U3PHY_WIDTH_64(p) \
+	(((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x3 << 16))
+
+/*
+ * USB2 PHY Interface enable
+ * These field informs if USB2 PHY interface is implemented:
+ * 0x0 - interface NOT implemented,
+ * 0x1 - interface implemented
+ */
+#define USB_CAP1_U2PHY_EN(p)	((p) & BIT(24))
+/*
+ * USB2 PHY Interface type
+ * These field reflects type of USB2 PHY interface implemented:
+ * 0x0 - UTMI,
+ * 0x1 - ULPI
+ */
+#define DEV_U2PHY_ULPI(p)	((p) & BIT(25))
+/*
+ * USB2 PHY Interface width
+ * These field reflects width of USB2 PHY interface implemented:
+ * 0x0 - 8 bit interface,
+ * 0x1 - 16 bit interface,
+ * Note: The ULPI interface is always 8bit wide.
+ */
+#define DEV_U2PHY_WIDTH_16(p)	((p) & BIT(26))
+/*
+ * OTG Ready
+ * 0x0 - pure device mode
+ * 0x1 - some features and ports for CDNS USB OTG controller are implemented.
+ */
+#define USB_CAP1_OTG_READY(p)	((p) & BIT(27))
+
+/*
+ * When set, indicates that controller supports automatic internal TDL
+ * calculation basing on the size provided in TRB (TRB[22:17]) for DMULT mode
+ * Supported only for DEV_VER_V2 controller version.
+ */
+#define USB_CAP1_TDL_FROM_TRB(p)	((p) & BIT(28))
+
+/* USB_CAP2- bitmasks */
+/*
+ * The actual size of the connected On-chip RAM memory in kB:
+ * - 0 means 256 kB (max supported mem size)
+ * - value other than 0 reflects the mem size in kB
+ */
+#define USB_CAP2_ACTUAL_MEM_SIZE(p) ((p) & GENMASK(7, 0))
+/*
+ * Max supported mem size
+ * These field reflects width of on-chip RAM address bus width,
+ * which determines max supported mem size:
+ * 0x0-0x7 - reserved,
+ * 0x8 - support for 4kB mem,
+ * 0x9 - support for 8kB mem,
+ * 0xA - support for 16kB mem,
+ * 0xB - support for 32kB mem,
+ * 0xC - support for 64kB mem,
+ * 0xD - support for 128kB mem,
+ * 0xE - support for 256kB mem,
+ * 0xF - reserved
+ */
+#define USB_CAP2_MAX_MEM_SIZE(p) ((p) & GENMASK(11, 8))
+
+/* USB_CAP3- bitmasks */
+#define EP_IS_IMPLEMENTED(reg, index) ((reg) & (1 << (index)))
+
+/* USB_CAP4- bitmasks */
+#define EP_SUPPORT_ISO(reg, index) ((reg) & (1 << (index)))
+
+/* USB_CAP5- bitmasks */
+#define EP_SUPPORT_STREAM(reg, index) ((reg) & (1 << (index)))
+
+/* USB_CAP6- bitmasks */
+/* The USBSS-DEV Controller  Internal build number. */
+#define GET_DEV_BASE_VERSION(p) ((p) & GENMASK(23, 0))
+/* The USBSS-DEV Controller version number. */
+#define GET_DEV_CUSTOM_VERSION(p) ((p) & GENMASK(31, 24))
+
+#define DEV_VER_NXP_V1		0x00024502
+#define DEV_VER_TI_V1		0x00024509
+#define DEV_VER_V2		0x0002450C
+#define DEV_VER_V3		0x0002450d
+
+/* DBG_LINK1- bitmasks */
+/*
+ * LFPS_MIN_DET_U1_EXIT value This parameter configures the minimum
+ * time required for decoding the received LFPS as an LFPS.U1_Exit.
+ */
+#define DBG_LINK1_LFPS_MIN_DET_U1_EXIT(p)	((p) & GENMASK(7, 0))
+/*
+ * LFPS_MIN_GEN_U1_EXIT value This parameter configures the minimum time for
+ * phytxelecidle deassertion when LFPS.U1_Exit
+ */
+#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT_MASK	GENMASK(15, 8)
+#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT(p)	(((p) << 8) & GENMASK(15, 8))
+/*
+ * RXDET_BREAK_DIS value This parameter configures terminating the Far-end
+ * Receiver termination detection sequence:
+ * 0: it is possible that USBSS_DEV will terminate Farend receiver
+ *    termination detection sequence
+ * 1: USBSS_DEV will not terminate Far-end receiver termination
+ *    detection sequence
+ */
+#define DBG_LINK1_RXDET_BREAK_DIS		BIT(16)
+/* LFPS_GEN_PING value This parameter configures the LFPS.Ping generation */
+#define DBG_LINK1_LFPS_GEN_PING(p)		(((p) << 17) & GENMASK(21, 17))
+/*
+ * Set the LFPS_MIN_DET_U1_EXIT value Writing '1' to this bit writes the
+ * LFPS_MIN_DET_U1_EXIT field value to the device. This bit is automatically
+ * cleared. Writing '0' has no effect
+ */
+#define DBG_LINK1_LFPS_MIN_DET_U1_EXIT_SET	BIT(24)
+/*
+ * Set the LFPS_MIN_GEN_U1_EXIT value. Writing '1' to this bit writes the
+ * LFPS_MIN_GEN_U1_EXIT field value to the device. This bit is automatically
+ * cleared. Writing '0' has no effect
+ */
+#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT_SET	BIT(25)
+/*
+ * Set the RXDET_BREAK_DIS value Writing '1' to this bit writes
+ * the RXDET_BREAK_DIS field value to the device. This bit is automatically
+ * cleared. Writing '0' has no effect
+ */
+#define DBG_LINK1_RXDET_BREAK_DIS_SET		BIT(26)
+/*
+ * Set the LFPS_GEN_PING_SET value Writing '1' to this bit writes
+ * the LFPS_GEN_PING field value to the device. This bit is automatically
+ * cleared. Writing '0' has no effect."
+ */
+#define DBG_LINK1_LFPS_GEN_PING_SET		BIT(27)
+
+/* DMA_AXI_CTRL- bitmasks */
+/* The mawprot pin configuration. */
+#define DMA_AXI_CTRL_MARPROT(p) ((p) & GENMASK(2, 0))
+/* The marprot pin configuration. */
+#define DMA_AXI_CTRL_MAWPROT(p) (((p) & GENMASK(2, 0)) << 16)
+#define DMA_AXI_CTRL_NON_SECURE 0x02
+
+#define gadget_to_cdns3_device(g) (container_of(g, struct cdns3_device, gadget))
+
+#define ep_to_cdns3_ep(ep) (container_of(ep, struct cdns3_endpoint, endpoint))
+
+/*-------------------------------------------------------------------------*/
+/*
+ * USBSS-DEV DMA interface.
+ */
+#define TRBS_PER_SEGMENT	40
+
+#define ISO_MAX_INTERVAL	10
+
+#if TRBS_PER_SEGMENT < 2
+#error "Incorrect TRBS_PER_SEGMENT. Minimal Transfer Ring size is 2."
+#endif
+
+/*
+ *Only for ISOC endpoints - maximum number of TRBs is calculated as
+ * pow(2, bInterval-1) * number of usb requests. It is limitation made by
+ * driver to save memory. Controller must prepare TRB for each ITP even
+ * if bInterval > 1. It's the reason why driver needs so many TRBs for
+ * isochronous endpoints.
+ */
+#define TRBS_PER_ISOC_SEGMENT	(ISO_MAX_INTERVAL * 8)
+
+#define GET_TRBS_PER_SEGMENT(ep_type) ((ep_type) == USB_ENDPOINT_XFER_ISOC ? \
+				      TRBS_PER_ISOC_SEGMENT : TRBS_PER_SEGMENT)
+/**
+ * struct cdns3_trb - represent Transfer Descriptor block.
+ * @buffer:	pointer to buffer data
+ * @length:	length of data
+ * @control:	control flags.
+ *
+ * This structure describes transfer block serviced by DMA module.
+ */
+struct cdns3_trb {
+	__le32 buffer;
+	__le32 length;
+	__le32 control;
+};
+
+#define TRB_SIZE		(sizeof(struct cdns3_trb))
+#define TRB_RING_SIZE		(TRB_SIZE * TRBS_PER_SEGMENT)
+#define TRB_ISO_RING_SIZE	(TRB_SIZE * TRBS_PER_ISOC_SEGMENT)
+#define TRB_CTRL_RING_SIZE	(TRB_SIZE * 2)
+
+/* TRB bit mask */
+#define TRB_TYPE_BITMASK	GENMASK(15, 10)
+#define TRB_TYPE(p)		((p) << 10)
+#define TRB_FIELD_TO_TYPE(p)	(((p) & TRB_TYPE_BITMASK) >> 10)
+
+/* TRB type IDs */
+/* bulk, interrupt, isoc , and control data stage */
+#define TRB_NORMAL		1
+/* TRB for linking ring segments */
+#define TRB_LINK		6
+
+/* Cycle bit - indicates TRB ownership by driver or hw*/
+#define TRB_CYCLE		BIT(0)
+/*
+ * When set to '1', the device will toggle its interpretation of the Cycle bit
+ */
+#define TRB_TOGGLE		BIT(1)
+
+/*
+ * Short Packet (SP). OUT EPs at DMULT=1 only. Indicates if the TRB was
+ * processed while USB short packet was received. No more buffers defined by
+ * the TD will be used. DMA will automatically advance to next TD.
+ * - Shall be set to 0 by Software when putting TRB on the Transfer Ring
+ * - Shall be set to 1 by Controller when Short Packet condition for this TRB
+ *   is detected independent if ISP is set or not.
+ */
+#define TRB_SP			BIT(1)
+
+/* Interrupt on short packet*/
+#define TRB_ISP			BIT(2)
+/*Setting this bit enables FIFO DMA operation mode*/
+#define TRB_FIFO_MODE		BIT(3)
+/* Set PCIe no snoop attribute */
+#define TRB_CHAIN		BIT(4)
+/* Interrupt on completion */
+#define TRB_IOC			BIT(5)
+
+/* stream ID bitmasks. */
+#define TRB_STREAM_ID_BITMASK		GENMASK(31, 16)
+#define TRB_STREAM_ID(p)		((p) << 16)
+#define TRB_FIELD_TO_STREAMID(p)	(((p) & TRB_STREAM_ID_BITMASK) >> 16)
+
+/* Size of TD expressed in USB packets for HS/FS mode. */
+#define TRB_TDL_HS_SIZE(p)	(((p) << 16) & GENMASK(31, 16))
+#define TRB_TDL_HS_SIZE_GET(p)	(((p) & GENMASK(31, 16)) >> 16)
+
+/* transfer_len bitmasks. */
+#define TRB_LEN(p)		((p) & GENMASK(16, 0))
+
+/* Size of TD expressed in USB packets for SS mode. */
+#define TRB_TDL_SS_SIZE(p)	(((p) << 17) & GENMASK(23, 17))
+#define TRB_TDL_SS_SIZE_GET(p)	(((p) & GENMASK(23, 17)) >> 17)
+
+/* transfer_len bitmasks - bits 31:24 */
+#define TRB_BURST_LEN(p)	(((p) << 24) & GENMASK(31, 24))
+#define TRB_BURST_LEN_GET(p)	(((p) & GENMASK(31, 24)) >> 24)
+
+/* Data buffer pointer bitmasks*/
+#define TRB_BUFFER(p)		((p) & GENMASK(31, 0))
+
+/*-------------------------------------------------------------------------*/
+/* Driver numeric constants */
+
+/* Such declaration should be added to ch9.h */
+#define USB_DEVICE_MAX_ADDRESS		127
+
+/* Endpoint init values */
+#define CDNS3_EP_MAX_PACKET_LIMIT	1024
+#define CDNS3_EP_MAX_STREAMS		15
+#define CDNS3_EP0_MAX_PACKET_LIMIT	512
+
+/* All endpoints including EP0 */
+#define CDNS3_ENDPOINTS_MAX_COUNT	32
+#define CDNS3_EP_ZLP_BUF_SIZE		1024
+
+#define CDNS3_EP_BUF_SIZE		2	/* KB */
+#define CDNS3_EP_ISO_HS_MULT		3
+#define CDNS3_EP_ISO_SS_BURST		3
+#define CDNS3_MAX_NUM_DESCMISS_BUF	32
+#define CDNS3_DESCMIS_BUF_SIZE		2048	/* Bytes */
+#define CDNS3_WA2_NUM_BUFFERS		128
+/*-------------------------------------------------------------------------*/
+/* Used structs */
+
+struct cdns3_device;
+
+/**
+ * struct cdns3_endpoint - extended device side representation of USB endpoint.
+ * @endpoint: usb endpoint
+ * @pending_req_list: list of requests queuing on transfer ring.
+ * @deferred_req_list: list of requests waiting for queuing on transfer ring.
+ * @wa2_descmiss_req_list: list of requests internally allocated by driver.
+ * @trb_pool: transfer ring - array of transaction buffers
+ * @trb_pool_dma: dma address of transfer ring
+ * @cdns3_dev: device associated with this endpoint
+ * @name: a human readable name e.g. ep1out
+ * @flags: specify the current state of endpoint
+ * @descmis_req: internal transfer object used for getting data from on-chip
+ *     buffer. It can happen only if function driver doesn't send usb_request
+ *     object on time.
+ * @dir: endpoint direction
+ * @num: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @interval: interval between packets used for ISOC endpoint.
+ * @free_trbs: number of free TRBs in transfer ring
+ * @num_trbs: number of all TRBs in transfer ring
+ * @pcs: producer cycle state
+ * @ccs: consumer cycle state
+ * @enqueue: enqueue index in transfer ring
+ * @dequeue: dequeue index in transfer ring
+ * @trb_burst_size: number of burst used in trb.
+ */
+struct cdns3_endpoint {
+	struct usb_ep		endpoint;
+	struct list_head	pending_req_list;
+	struct list_head	deferred_req_list;
+	struct list_head	wa2_descmiss_req_list;
+	int			wa2_counter;
+
+	struct cdns3_trb	*trb_pool;
+	dma_addr_t		trb_pool_dma;
+
+	struct cdns3_device	*cdns3_dev;
+	char			name[20];
+
+#define EP_ENABLED		BIT(0)
+#define EP_STALLED		BIT(1)
+#define EP_STALL_PENDING	BIT(2)
+#define EP_WEDGE		BIT(3)
+#define EP_TRANSFER_STARTED	BIT(4)
+#define EP_UPDATE_EP_TRBADDR	BIT(5)
+#define EP_PENDING_REQUEST	BIT(6)
+#define EP_RING_FULL		BIT(7)
+#define EP_CLAIMED		BIT(8)
+#define EP_DEFERRED_DRDY	BIT(9)
+#define EP_QUIRK_ISO_OUT_EN	BIT(10)
+#define EP_QUIRK_END_TRANSFER	BIT(11)
+#define EP_QUIRK_EXTRA_BUF_DET	BIT(12)
+#define EP_QUIRK_EXTRA_BUF_EN	BIT(13)
+	u32			flags;
+
+	struct cdns3_request	*descmis_req;
+
+	u8			dir;
+	u8			num;
+	u8			type;
+	int			interval;
+
+	int			free_trbs;
+	int			num_trbs;
+	u8			pcs;
+	u8			ccs;
+	int			enqueue;
+	int			dequeue;
+	u8			trb_burst_size;
+
+	unsigned int		wa1_set:1;
+	struct cdns3_trb	*wa1_trb;
+	unsigned int		wa1_trb_index;
+	unsigned int		wa1_cycle_bit:1;
+};
+
+/**
+ * struct cdns3_aligned_buf - represent aligned buffer used for DMA transfer
+ * @buf: aligned to 8 bytes data buffer. Buffer address used in
+ *       TRB shall be aligned to 8.
+ * @dma: dma address
+ * @size: size of buffer
+ * @in_use: inform if this buffer is associated with usb_request
+ * @list: used to adding instance of this object to list
+ */
+struct cdns3_aligned_buf {
+	void			*buf;
+	dma_addr_t		dma;
+	u32			size;
+	int			in_use:1;
+	struct list_head	list;
+};
+
+/**
+ * struct cdns3_request - extended device side representation of usb_request
+ *                        object .
+ * @request: generic usb_request object describing single I/O request.
+ * @priv_ep: extended representation of usb_ep object
+ * @trb: the first TRB association with this request
+ * @start_trb: number of the first TRB in transfer ring
+ * @end_trb: number of the last TRB in transfer ring
+ * @aligned_buf: object holds information about aligned buffer associated whit
+ *               this endpoint
+ * @flags: flag specifying special usage of request
+ * @list: used by internally allocated request to add to wa2_descmiss_req_list.
+ */
+struct cdns3_request {
+	struct usb_request		request;
+	struct cdns3_endpoint		*priv_ep;
+	struct cdns3_trb		*trb;
+	int				start_trb;
+	int				end_trb;
+	struct cdns3_aligned_buf	*aligned_buf;
+#define REQUEST_PENDING			BIT(0)
+#define REQUEST_INTERNAL		BIT(1)
+#define REQUEST_INTERNAL_CH		BIT(2)
+#define REQUEST_ZLP			BIT(3)
+#define REQUEST_UNALIGNED		BIT(4)
+	u32				flags;
+	struct list_head		list;
+};
+
+#define to_cdns3_request(r) (container_of(r, struct cdns3_request, request))
+
+/*Stages used during enumeration process.*/
+#define CDNS3_SETUP_STAGE		0x0
+#define CDNS3_DATA_STAGE		0x1
+#define CDNS3_STATUS_STAGE		0x2
+
+/**
+ * struct cdns3_device - represent USB device.
+ * @dev: pointer to device structure associated whit this controller
+ * @sysdev: pointer to the DMA capable device
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @dev_ver: device controller version.
+ * @lock: for synchronizing
+ * @regs: base address for device side registers
+ * @setup_buf: used while processing usb control requests
+ * @setup_dma: dma address for setup_buf
+ * @zlp_buf - zlp buffer
+ * @ep0_stage: ep0 stage during enumeration process.
+ * @ep0_data_dir: direction for control transfer
+ * @eps: array of pointers to all endpoints with exclusion ep0
+ * @aligned_buf_list: list of aligned buffers internally allocated by driver
+ * @aligned_buf_wq: workqueue freeing  no longer used aligned buf.
+ * @selected_ep: actually selected endpoint. It's used only to improve
+ *               performance.
+ * @isoch_delay: value from Set Isoch Delay request. Only valid on SS/SSP.
+ * @u1_allowed: allow device transition to u1 state
+ * @u2_allowed: allow device transition to u2 state
+ * @is_selfpowered: device is self powered
+ * @setup_pending: setup packet is processing by gadget driver
+ * @hw_configured_flag: hardware endpoint configuration was set.
+ * @wake_up_flag: allow device to remote up the host
+ * @status_completion_no_call: indicate that driver is waiting for status s
+ *     stage completion. It's used in deferred SET_CONFIGURATION request.
+ * @onchip_buffers: number of available on-chip buffers.
+ * @onchip_used_size: actual size of on-chip memory assigned to endpoints.
+ * @pending_status_wq: workqueue handling status stage for deferred requests.
+ * @pending_status_request: request for which status stage was deferred
+ */
+struct cdns3_device {
+	struct udevice			*dev;
+	struct udevice			*sysdev;
+
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*gadget_driver;
+
+#define CDNS_REVISION_V0		0x00024501
+#define CDNS_REVISION_V1		0x00024509
+	u32				dev_ver;
+
+	/* generic spin-lock for drivers */
+	spinlock_t			lock;
+
+	struct cdns3_usb_regs		__iomem *regs;
+
+	struct usb_ctrlrequest		*setup_buf;
+	dma_addr_t			setup_dma;
+	void				*zlp_buf;
+
+	u8				ep0_stage;
+	int				ep0_data_dir;
+
+	struct cdns3_endpoint		*eps[CDNS3_ENDPOINTS_MAX_COUNT];
+
+	struct list_head		aligned_buf_list;
+	struct work_struct		aligned_buf_wq;
+
+	u32				selected_ep;
+	u16				isoch_delay;
+
+	unsigned			wait_for_setup:1;
+	unsigned			u1_allowed:1;
+	unsigned			u2_allowed:1;
+	unsigned			is_selfpowered:1;
+	unsigned			setup_pending:1;
+	int				hw_configured_flag:1;
+	int				wake_up_flag:1;
+	unsigned			status_completion_no_call:1;
+	int				out_mem_is_allocated;
+
+	struct work_struct		pending_status_wq;
+	struct usb_request		*pending_status_request;
+
+	/*in KB */
+	u32				onchip_buffers;
+	u16				onchip_used_size;
+};
+
+void cdns3_set_register_bit(void __iomem *ptr, u32 mask);
+dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep,
+				 struct cdns3_trb *trb);
+enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev);
+void cdns3_pending_setup_status_handler(struct work_struct *work);
+void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev);
+void cdns3_set_hw_configuration(struct cdns3_device *priv_dev);
+void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep);
+void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable);
+struct usb_request *cdns3_next_request(struct list_head *list);
+int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
+			  struct usb_request *request);
+void cdns3_rearm_transfer(struct cdns3_endpoint *priv_ep, u8 rearm);
+int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep);
+u8 cdns3_ep_addr_to_index(u8 ep_addr);
+int cdns3_gadget_ep_set_wedge(struct usb_ep *ep);
+int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value);
+void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep);
+int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep);
+struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep,
+						  gfp_t gfp_flags);
+void cdns3_gadget_ep_free_request(struct usb_ep *ep,
+				  struct usb_request *request);
+int cdns3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request);
+void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
+			   struct cdns3_request *priv_req,
+			   int status);
+
+int cdns3_init_ep0(struct cdns3_device *priv_dev,
+		   struct cdns3_endpoint *priv_ep);
+void cdns3_ep0_config(struct cdns3_device *priv_dev);
+void cdns3_ep_config(struct cdns3_endpoint *priv_ep);
+void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir);
+int __cdns3_gadget_wakeup(struct cdns3_device *priv_dev);
+
+#endif /* __LINUX_CDNS3_GADGET */
diff --git a/roms/u-boot/drivers/usb/cdns3/host-export.h b/roms/u-boot/drivers/usb/cdns3/host-export.h
new file mode 100644
index 000000000..b498a170b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/host-export.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cadence USBSS DRD Driver - Host Export APIs
+ *
+ * Copyright (C) 2017-2018 NXP
+ *
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ */
+#ifndef __LINUX_CDNS3_HOST_EXPORT
+#define __LINUX_CDNS3_HOST_EXPORT
+
+#ifdef CONFIG_USB_CDNS3_HOST
+
+int cdns3_host_init(struct cdns3 *cdns);
+void cdns3_host_exit(struct cdns3 *cdns);
+
+#else
+
+static inline int cdns3_host_init(struct cdns3 *cdns)
+{
+	return -ENXIO;
+}
+
+static inline void cdns3_host_exit(struct cdns3 *cdns) { }
+
+#endif /* CONFIG_USB_CDNS3_HOST */
+
+#endif /* __LINUX_CDNS3_HOST_EXPORT */
diff --git a/roms/u-boot/drivers/usb/cdns3/host.c b/roms/u-boot/drivers/usb/cdns3/host.c
new file mode 100644
index 000000000..b44e7df11
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/host.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cadence USBSS DRD Driver - host side
+ *
+ * Copyright (C) 2018-2019 Cadence Design Systems.
+ * Copyright (C) 2017-2018 NXP
+ *
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *          Pawel Laszczak <pawell@cadence.com>
+ */
+#include <dm.h>
+#include <dm/devres.h>
+#include <linux/compat.h>
+#include <usb.h>
+#include <usb/xhci.h>
+
+#include "core.h"
+#include "drd.h"
+
+static int __cdns3_host_init(struct cdns3 *cdns)
+{
+	struct xhci_hcor *hcor;
+	struct xhci_hccr *hccr;
+
+	cdns3_drd_switch_host(cdns, 1);
+
+	hccr = (struct xhci_hccr *)cdns->xhci_regs;
+	hcor = (struct xhci_hcor *)(cdns->xhci_regs +
+			HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
+
+	return xhci_register(cdns->dev, hccr, hcor);
+}
+
+static void cdns3_host_exit(struct cdns3 *cdns)
+{
+	xhci_deregister(cdns->dev);
+	cdns3_drd_switch_host(cdns, 0);
+}
+
+int cdns3_host_init(struct cdns3 *cdns)
+{
+	struct cdns3_role_driver *rdrv;
+
+	rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+	if (!rdrv)
+		return -ENOMEM;
+
+	rdrv->start	= __cdns3_host_init;
+	rdrv->stop	= cdns3_host_exit;
+	rdrv->state	= CDNS3_ROLE_STATE_INACTIVE;
+	rdrv->name	= "host";
+
+	cdns->roles[USB_ROLE_HOST] = rdrv;
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/cdns3/trace.c b/roms/u-boot/drivers/usb/cdns3/trace.c
new file mode 100644
index 000000000..459fa72d9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/trace.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USBSS device controller driver Trace Support
+ *
+ * Copyright (C) 2018-2019 Cadence.
+ *
+ * Author: Pawel Laszczak <pawell@cadence.com>
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/roms/u-boot/drivers/usb/cdns3/trace.h b/roms/u-boot/drivers/usb/cdns3/trace.h
new file mode 100644
index 000000000..e86c02ae9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/cdns3/trace.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define trace_cdns3_prepare_trb(a, b)
+#define trace_cdns3_doorbell_ep0(a, b)
+#define trace_cdns3_ctrl_req(a)
+#define trace_cdns3_complete_trb(a, b)
+#define trace_cdns3_ep0_irq(a, b)
+#define trace_cdns3_gadget_giveback(a)
+#define trace_cdns3_free_aligned_request(a)
+#define trace_cdns3_prepare_aligned_request(a)
+#define trace_cdns3_ring(a)
+#define trace_cdns3_doorbell_epx(a, b)
+#define trace_cdns3_request_handled(a, b, c)
+#define trace_cdns3_epx_irq(a, b)
+#define trace_cdns3_usb_irq(a, b)
+#define trace_cdns3_alloc_request(a)
+#define trace_cdns3_free_request(a)
+#define trace_cdns3_gadget_ep_enable(a)
+#define trace_cdns3_gadget_ep_disable(a)
+#define trace_cdns3_ep0_queue(a, b)
+#define trace_cdns3_ep0_dequeue(a)
+#define trace_cdns3_ep_queue(a)
+#define trace_cdns3_ep_dequeue(a)
+#define trace_cdns3_halt(a, b, c)
+#define trace_cdns3_wa1(a, b)
+#define trace_cdns3_wa2(a, b)
diff --git a/roms/u-boot/drivers/usb/common/Makefile b/roms/u-boot/drivers/usb/common/Makefile
new file mode 100644
index 000000000..3bedbf213
--- /dev/null
+++ b/roms/u-boot/drivers/usb/common/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Freescale Semiconductor, Inc.
+#
+
+obj-$(CONFIG_$(SPL_)DM_USB) += common.o
+obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o fsl-errata.o
+obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o fsl-errata.o
diff --git a/roms/u-boot/drivers/usb/common/common.c b/roms/u-boot/drivers/usb/common/common.c
new file mode 100644
index 000000000..2a47f40bb
--- /dev/null
+++ b/roms/u-boot/drivers/usb/common/common.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Provides code common for host and device side USB.
+ *
+ * (C) Copyright 2016
+ *     Texas Instruments Incorporated, <www.ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *const usb_dr_modes[] = {
+	[USB_DR_MODE_UNKNOWN]		= "",
+	[USB_DR_MODE_HOST]		= "host",
+	[USB_DR_MODE_PERIPHERAL]	= "peripheral",
+	[USB_DR_MODE_OTG]		= "otg",
+};
+
+enum usb_dr_mode usb_get_dr_mode(ofnode node)
+{
+	const char *dr_mode;
+	int i;
+
+	dr_mode = ofnode_read_string(node, "dr_mode");
+	if (!dr_mode) {
+		pr_err("usb dr_mode not found\n");
+		return USB_DR_MODE_UNKNOWN;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
+		if (!strcmp(dr_mode, usb_dr_modes[i]))
+			return i;
+
+	return USB_DR_MODE_UNKNOWN;
+}
+
+static const char *const speed_names[] = {
+	[USB_SPEED_UNKNOWN] = "UNKNOWN",
+	[USB_SPEED_LOW] = "low-speed",
+	[USB_SPEED_FULL] = "full-speed",
+	[USB_SPEED_HIGH] = "high-speed",
+	[USB_SPEED_WIRELESS] = "wireless",
+	[USB_SPEED_SUPER] = "super-speed",
+	[USB_SPEED_SUPER_PLUS] = "super-speed-plus",
+};
+
+const char *usb_speed_string(enum usb_device_speed speed)
+{
+	if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
+		speed = USB_SPEED_UNKNOWN;
+	return speed_names[speed];
+}
+
+enum usb_device_speed usb_get_maximum_speed(ofnode node)
+{
+	const char *max_speed;
+	int i;
+
+	max_speed = ofnode_read_string(node, "maximum-speed");
+	if (!max_speed) {
+		pr_err("usb maximum-speed not found\n");
+		return USB_SPEED_UNKNOWN;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(speed_names); i++)
+		if (!strcmp(max_speed, speed_names[i]))
+			return i;
+
+	return USB_SPEED_UNKNOWN;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static const char *const usbphy_modes[] = {
+	[USBPHY_INTERFACE_MODE_UNKNOWN]	= "",
+	[USBPHY_INTERFACE_MODE_UTMI]	= "utmi",
+	[USBPHY_INTERFACE_MODE_UTMIW]	= "utmi_wide",
+};
+
+enum usb_phy_interface usb_get_phy_mode(ofnode node)
+{
+	const char *phy_type;
+	int i;
+
+	phy_type = ofnode_get_property(node, "phy_type", NULL);
+	if (!phy_type)
+		return USBPHY_INTERFACE_MODE_UNKNOWN;
+
+	for (i = 0; i < ARRAY_SIZE(usbphy_modes); i++)
+		if (!strcmp(phy_type, usbphy_modes[i]))
+			return i;
+
+	return USBPHY_INTERFACE_MODE_UNKNOWN;
+}
+#endif
diff --git a/roms/u-boot/drivers/usb/common/fsl-dt-fixup.c b/roms/u-boot/drivers/usb/common/fsl-dt-fixup.c
new file mode 100644
index 000000000..4d7a2acd8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/common/fsl-dt-fixup.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009, 2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
+ *
+ * Author: Tor Krill tor@excito.com
+ */
+
+#include <common.h>
+#include <log.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <hwconfig.h>
+#include <fsl_errata.h>
+#include <fsl_usb.h>
+#include <fdt_support.h>
+
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+/* USB Controllers */
+#define FSL_USB2_MPH	"fsl-usb2-mph"
+#define FSL_USB2_DR	"fsl-usb2-dr"
+#define CHIPIDEA_USB2	"chipidea,usb2"
+#define SNPS_DWC3	"snps,dwc3"
+
+static const char * const compat_usb_fsl[] = {
+	FSL_USB2_MPH,
+	FSL_USB2_DR,
+	SNPS_DWC3,
+	NULL
+};
+
+static int fdt_usb_get_node_type(void *blob, int start_offset,
+				 int *node_offset, const char **node_type)
+{
+	int i;
+	int ret = -ENOENT;
+
+	for (i = 0; compat_usb_fsl[i]; i++) {
+		*node_offset = fdt_node_offset_by_compatible
+					(blob, start_offset,
+					 compat_usb_fsl[i]);
+		if (*node_offset >= 0) {
+			*node_type = compat_usb_fsl[i];
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int fdt_fixup_usb_mode_phy_type(void *blob, const char *mode,
+				       const char *phy_type, int start_offset)
+{
+	const char *prop_mode = "dr_mode";
+	const char *prop_type = "phy_type";
+	const char *node_type = NULL;
+	int node_offset;
+	int err;
+
+	err = fdt_usb_get_node_type(blob, start_offset,
+				    &node_offset, &node_type);
+	if (err < 0)
+		return err;
+
+	if (mode) {
+		err = fdt_setprop(blob, node_offset, prop_mode, mode,
+				  strlen(mode) + 1);
+		if (err < 0)
+			printf("WARNING: could not set %s for %s: %s.\n",
+			       prop_mode, node_type, fdt_strerror(err));
+	}
+
+	if (phy_type) {
+		err = fdt_setprop(blob, node_offset, prop_type, phy_type,
+				  strlen(phy_type) + 1);
+		if (err < 0)
+			printf("WARNING: could not set %s for %s: %s.\n",
+			       prop_type, node_type, fdt_strerror(err));
+	}
+
+	return node_offset;
+}
+
+static int fsl_fdt_fixup_usb_erratum(void *blob, const char *prop_erratum,
+				     const char *controller_type,
+				     int start_offset)
+{
+	int node_offset, err;
+	const char *node_type = NULL;
+	const char *node_name = NULL;
+
+	err = fdt_usb_get_node_type(blob, start_offset,
+				    &node_offset, &node_type);
+	if (err < 0)
+		return err;
+
+	if (!strcmp(node_type, FSL_USB2_MPH) || !strcmp(node_type, FSL_USB2_DR))
+		node_name = CHIPIDEA_USB2;
+	else
+		node_name = node_type;
+	if (strcmp(node_name, controller_type))
+		return err;
+
+	err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0);
+	if (err < 0) {
+		printf("ERROR: could not set %s for %s: %s.\n",
+		       prop_erratum, node_type, fdt_strerror(err));
+	}
+
+	return node_offset;
+}
+
+static int fsl_fdt_fixup_erratum(int *usb_erratum_off, void *blob,
+				 const char *controller_type, char *str,
+				 bool (*has_erratum)(void))
+{
+	char buf[32] = {0};
+
+	snprintf(buf, sizeof(buf), "fsl,usb-erratum-%s", str);
+	if (!has_erratum())
+		return -EINVAL;
+	*usb_erratum_off = fsl_fdt_fixup_usb_erratum(blob, buf, controller_type,
+						     *usb_erratum_off);
+	if (*usb_erratum_off < 0)
+		return -ENOSPC;
+	debug("Adding USB erratum %s\n", str);
+	return 0;
+}
+
+void fsl_fdt_fixup_dr_usb(void *blob, struct bd_info *bd)
+{
+	static const char * const modes[] = { "host", "peripheral", "otg" };
+	static const char * const phys[] = { "ulpi", "utmi", "utmi_dual" };
+	int usb_erratum_a006261_off = -1;
+	int usb_erratum_a007075_off = -1;
+	int usb_erratum_a007792_off = -1;
+	int usb_erratum_a005697_off = -1;
+	int usb_erratum_a008751_off = -1;
+	int usb_mode_off = -1;
+	int usb_phy_off = -1;
+	char str[5];
+	int i, j;
+	int ret;
+
+	for (i = 1; i <= CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
+		const char *dr_mode_type = NULL;
+		const char *dr_phy_type = NULL;
+		int mode_idx = -1, phy_idx = -1;
+
+		snprintf(str, 5, "%s%d", "usb", i);
+		if (hwconfig(str)) {
+			for (j = 0; j < ARRAY_SIZE(modes); j++) {
+				if (hwconfig_subarg_cmp(str, "dr_mode",
+							modes[j])) {
+					mode_idx = j;
+					break;
+				}
+			}
+
+			for (j = 0; j < ARRAY_SIZE(phys); j++) {
+				if (hwconfig_subarg_cmp(str, "phy_type",
+							phys[j])) {
+					phy_idx = j;
+					break;
+				}
+			}
+
+			if (mode_idx < 0 && phy_idx < 0) {
+				printf("WARNING: invalid phy or mode\n");
+				return;
+			}
+
+			if (mode_idx > -1)
+				dr_mode_type = modes[mode_idx];
+
+			if (phy_idx > -1)
+				dr_phy_type = phys[phy_idx];
+		}
+
+		if (has_dual_phy())
+			dr_phy_type = phys[2];
+
+		usb_mode_off = fdt_fixup_usb_mode_phy_type(blob,
+							   dr_mode_type, NULL,
+							   usb_mode_off);
+
+		if (usb_mode_off < 0)
+			return;
+
+		usb_phy_off = fdt_fixup_usb_mode_phy_type(blob,
+							  NULL, dr_phy_type,
+							  usb_phy_off);
+
+		if (usb_phy_off < 0)
+			return;
+
+		ret = fsl_fdt_fixup_erratum(&usb_erratum_a006261_off, blob,
+					    CHIPIDEA_USB2, "a006261",
+					    has_erratum_a006261);
+		if (ret == -ENOSPC)
+			return;
+		ret = fsl_fdt_fixup_erratum(&usb_erratum_a007075_off, blob,
+					    CHIPIDEA_USB2, "a007075",
+					    has_erratum_a007075);
+		if (ret == -ENOSPC)
+			return;
+		ret = fsl_fdt_fixup_erratum(&usb_erratum_a007792_off, blob,
+					    CHIPIDEA_USB2, "a007792",
+					    has_erratum_a007792);
+		if (ret == -ENOSPC)
+			return;
+		ret = fsl_fdt_fixup_erratum(&usb_erratum_a005697_off, blob,
+					    CHIPIDEA_USB2, "a005697",
+					    has_erratum_a005697);
+		if (ret == -ENOSPC)
+			return;
+		ret = fsl_fdt_fixup_erratum(&usb_erratum_a008751_off, blob,
+					    SNPS_DWC3, "a008751",
+					    has_erratum_a008751);
+		if (ret == -ENOSPC)
+			return;
+
+	}
+}
diff --git a/roms/u-boot/drivers/usb/common/fsl-errata.c b/roms/u-boot/drivers/usb/common/fsl-errata.c
new file mode 100644
index 000000000..9eb1d2306
--- /dev/null
+++ b/roms/u-boot/drivers/usb/common/fsl-errata.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale USB Controller
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <hwconfig.h>
+#include <fsl_errata.h>
+#include<fsl_usb.h>
+#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
+	defined(CONFIG_ARM)
+#include <asm/arch/clock.h>
+#endif
+
+/* USB Erratum Checking code */
+#if defined(CONFIG_PPC) || defined(CONFIG_ARM)
+bool has_dual_phy(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_T1023:
+	case SVR_T1024:
+	case SVR_T1013:
+	case SVR_T1014:
+		return IS_SVR_REV(svr, 1, 0);
+	case SVR_T1040:
+	case SVR_T1042:
+	case SVR_T1020:
+	case SVR_T1022:
+	case SVR_T2080:
+	case SVR_T2081:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+	case SVR_T4240:
+	case SVR_T4160:
+	case SVR_T4080:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+#endif
+	}
+
+	return false;
+}
+
+bool has_erratum_a005275(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	if (hwconfig("no_erratum_a005275"))
+		return false;
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_P3041:
+	case SVR_P2041:
+	case SVR_P2040:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+	case SVR_P5010:
+	case SVR_P5020:
+	case SVR_P5021:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_P5040:
+	case SVR_P1010:
+		return IS_SVR_REV(svr, 1, 0);
+#endif
+	}
+
+	return false;
+}
+
+bool has_erratum_a006261(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_P1010:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_P2041:
+	case SVR_P2040:
+		return IS_SVR_REV(svr, 1, 0) ||
+			IS_SVR_REV(svr, 1, 1) ||
+			IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 2, 1);
+	case SVR_P3041:
+		return IS_SVR_REV(svr, 1, 0) ||
+			IS_SVR_REV(svr, 1, 1) ||
+			IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 2, 1);
+	case SVR_P5010:
+	case SVR_P5020:
+	case SVR_P5021:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_T4240:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_P5040:
+		return IS_SVR_REV(svr, 1, 0) ||
+			IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 2, 1);
+#endif
+	}
+
+	return false;
+}
+
+bool has_erratum_a007075(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_B4860:
+	case SVR_B4420:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_P1010:
+		return IS_SVR_REV(svr, 1, 0);
+	case SVR_P4080:
+		return IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 3, 0);
+#endif
+	}
+	return false;
+}
+
+bool has_erratum_a007798(void)
+{
+#ifdef CONFIG_PPC
+	return SVR_SOC_VER(get_svr()) == SVR_T4240 &&
+		IS_SVR_REV(get_svr(), 2, 0);
+#endif
+	return false;
+}
+
+bool has_erratum_a007792(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_T4240:
+	case SVR_T4160:
+	case SVR_T4080:
+		return IS_SVR_REV(svr, 2, 0);
+	case SVR_T1024:
+	case SVR_T1023:
+		return IS_SVR_REV(svr, 1, 0);
+	case SVR_T1040:
+	case SVR_T1042:
+	case SVR_T1020:
+	case SVR_T1022:
+	case SVR_T2080:
+	case SVR_T2081:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+#endif
+	}
+	return false;
+}
+
+bool has_erratum_a005697(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_9131:
+	case SVR_9132:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+#endif
+#ifdef ONFIG_ARM64
+	case SVR_LS1012A:
+		return IS_SVR_REV(svr, 1, 0);
+#endif
+	}
+	return false;
+}
+
+bool has_erratum_a004477(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_PPC
+	case SVR_P1010:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_P1022:
+	case SVR_9131:
+	case SVR_9132:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+	case SVR_P2020:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0) ||
+			IS_SVR_REV(svr, 2, 1);
+	case SVR_B4860:
+	case SVR_B4420:
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0);
+	case SVR_P4080:
+		return IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 3, 0);
+#endif
+	}
+
+	return false;
+}
+
+bool has_erratum_a008751(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+	switch (soc) {
+#ifdef CONFIG_ARM64
+	case SVR_LS2080A:
+	case SVR_LS2085A:
+		return IS_SVR_REV(svr, 1, 0);
+#endif
+	}
+	return false;
+}
+
+bool has_erratum_a010151(void)
+{
+	u32 svr = get_svr();
+	u32 soc = SVR_SOC_VER(svr);
+
+#ifdef CONFIG_ARM64
+	if (IS_SVR_DEV(svr, SVR_DEV(SVR_LS1043A)))
+		return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1);
+#endif
+
+	switch (soc) {
+#ifdef CONFIG_ARM64
+	case SVR_LS2080A:
+	case SVR_LS2085A:
+			/* fallthrough */
+	case SVR_LS2088A:
+			/* fallthrough */
+	case SVR_LS2081A:
+	case SVR_LS1046A:
+	case SVR_LS1012A:
+		return IS_SVR_REV(svr, 1, 0);
+#endif
+#ifdef CONFIG_ARCH_LS1021A
+	case SOC_VER_LS1020:
+	case SOC_VER_LS1021:
+	case SOC_VER_LS1022:
+	case SOC_VER_SLS1020:
+		return IS_SVR_REV(svr, 2, 0);
+#endif
+	}
+	return false;
+}
+
+#endif
diff --git a/roms/u-boot/drivers/usb/dwc3/Kconfig b/roms/u-boot/drivers/usb/dwc3/Kconfig
new file mode 100644
index 000000000..802ee508d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/Kconfig
@@ -0,0 +1,73 @@
+config USB_DWC3
+	bool "DesignWare USB3 DRD Core Support"
+	depends on USB_HOST || USB_GADGET
+	help
+	  Say Y here if your system has a Dual Role SuperSpeed
+	  USB controller based on the DesignWare USB3 IP Core.
+
+if USB_DWC3
+
+config USB_DWC3_GADGET
+	bool "USB Gadget support for DWC3"
+	default y
+	depends on USB_GADGET
+	select USB_GADGET_DUALSPEED
+
+comment "Platform Glue Driver Support"
+
+config USB_DWC3_OMAP
+	bool "Texas Instruments OMAP5 and similar Platforms"
+	help
+	  Some platforms from Texas Instruments like OMAP5, DRA7xxx and
+	  AM437x use this IP for USB2/3 functionality.
+
+	  Say 'Y' here if you have one such device
+
+config USB_DWC3_GENERIC
+	bool "Generic implementation of a DWC3 wrapper (aka dwc3 glue)"
+	depends on DM_USB && USB_DWC3 && MISC
+	help
+	  Select this for Xilinx ZynqMP and similar Platforms.
+	  This wrapper supports Host and Peripheral operation modes.
+
+config USB_DWC3_MESON_G12A
+	bool "Amlogic Meson G12A USB wrapper"
+	depends on DM_USB && USB_DWC3 && ARCH_MESON
+	imply PHY
+	help
+	  Select this for Amlogic Meson G12A Platforms.
+	  This wrapper supports Host and Peripheral operation modes.
+
+config USB_DWC3_MESON_GXL
+	bool "Amlogic Meson GXL USB wrapper"
+	depends on DM_USB && USB_DWC3 && ARCH_MESON
+	imply PHY
+	help
+	  Select this for Amlogic Meson GXL and GXM Platforms.
+	  This wrapper supports Host and Peripheral operation modes.
+
+config USB_DWC3_UNIPHIER
+	bool "DesignWare USB3 Host Support on UniPhier Platforms"
+	depends on ARCH_UNIPHIER && USB_XHCI_DWC3
+	help
+	  Support of USB2/3 functionality in Socionext UniPhier platforms.
+	  Say 'Y' here if you have one such device.
+
+menu "PHY Subsystem"
+
+config USB_DWC3_PHY_OMAP
+	bool "TI OMAP SoC series USB DRD PHY driver"
+	help
+	  Enable single driver for both USB2 PHY programming and USB3 PHY
+	  programming for TI SoCs.
+
+config USB_DWC3_PHY_SAMSUNG
+	bool "Exynos5 SoC series USB DRD PHY driver"
+	help
+	  Enable USB DRD PHY support for Exynos 5 SoC series.
+	  This driver provides PHY interface for USB 3.0 DRD controller
+	  present on Exynos5 SoC series.
+
+endmenu
+
+endif
diff --git a/roms/u-boot/drivers/usb/dwc3/Makefile b/roms/u-boot/drivers/usb/dwc3/Makefile
new file mode 100644
index 000000000..6e3e024e9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_USB_DWC3)			+= dwc3.o
+
+dwc3-y					:= core.o
+
+obj-$(CONFIG_USB_DWC3_GADGET)		+= gadget.o ep0.o
+
+obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_MESON_G12A)	+= dwc3-meson-g12a.o
+obj-$(CONFIG_USB_DWC3_MESON_GXL)	+= dwc3-meson-gxl.o
+obj-$(CONFIG_USB_DWC3_GENERIC)		+= dwc3-generic.o
+obj-$(CONFIG_USB_DWC3_UNIPHIER)		+= dwc3-uniphier.o
+obj-$(CONFIG_USB_DWC3_PHY_OMAP)		+= ti_usb_phy.o
+obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG)	+= samsung_usb_phy.o
diff --git a/roms/u-boot/drivers/usb/dwc3/core.c b/roms/u-boot/drivers/usb/dwc3/core.c
new file mode 100644
index 000000000..dfd7cf683
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/core.c
@@ -0,0 +1,1039 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.c) and ported
+ * to uboot.
+ *
+ * commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <malloc.h>
+#include <dwc3-uboot.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "linux-compat.h"
+
+static LIST_HEAD(dwc3_list);
+/* -------------------------------------------------------------------------- */
+
+static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+	reg |= DWC3_GCTL_PRTCAPDIR(mode);
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static int dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+	u32		reg;
+
+	/* Before Resetting PHY, put Core in Reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg |= DWC3_GCTL_CORESOFTRESET;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	/* Assert USB3 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	/* Assert USB2 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	mdelay(100);
+
+	/* Clear USB3 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	/* Clear USB2 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	mdelay(100);
+
+	/* After PHYs are stable we can take Core out of reset state */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_CORESOFTRESET;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	return 0;
+}
+
+/**
+ * dwc3_free_one_event_buffer - Frees one event buffer
+ * @dwc: Pointer to our controller context structure
+ * @evt: Pointer to event buffer to be freed
+ */
+static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
+		struct dwc3_event_buffer *evt)
+{
+	dma_free_coherent(evt->buf);
+}
+
+/**
+ * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
+ * @dwc: Pointer to our controller context structure
+ * @length: size of the event buffer
+ *
+ * Returns a pointer to the allocated event buffer structure on success
+ * otherwise ERR_PTR(errno).
+ */
+static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
+		unsigned length)
+{
+	struct dwc3_event_buffer	*evt;
+
+	evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt),
+			   GFP_KERNEL);
+	if (!evt)
+		return ERR_PTR(-ENOMEM);
+
+	evt->dwc	= dwc;
+	evt->length	= length;
+	evt->buf	= dma_alloc_coherent(length,
+					     (unsigned long *)&evt->dma);
+	if (!evt->buf)
+		return ERR_PTR(-ENOMEM);
+
+	dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
+
+	return evt;
+}
+
+/**
+ * dwc3_free_event_buffers - frees all allocated event buffers
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_free_event_buffers(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int i;
+
+	for (i = 0; i < dwc->num_event_buffers; i++) {
+		evt = dwc->ev_buffs[i];
+		if (evt)
+			dwc3_free_one_event_buffer(dwc, evt);
+	}
+}
+
+/**
+ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
+ * @dwc: pointer to our controller context structure
+ * @length: size of event buffer
+ *
+ * Returns 0 on success otherwise negative errno. In the error case, dwc
+ * may contain some buffers allocated but not all which were requested.
+ */
+static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
+{
+	int			num;
+	int			i;
+
+	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
+	dwc->num_event_buffers = num;
+
+	dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE,
+				 sizeof(*dwc->ev_buffs) * num);
+	if (!dwc->ev_buffs)
+		return -ENOMEM;
+
+	for (i = 0; i < num; i++) {
+		struct dwc3_event_buffer	*evt;
+
+		evt = dwc3_alloc_one_event_buffer(dwc, length);
+		if (IS_ERR(evt)) {
+			dev_err(dwc->dev, "can't allocate event buffer\n");
+			return PTR_ERR(evt);
+		}
+		dwc->ev_buffs[i] = evt;
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_event_buffers_setup - setup our allocated event buffers
+ * @dwc: pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int				n;
+
+	for (n = 0; n < dwc->num_event_buffers; n++) {
+		evt = dwc->ev_buffs[n];
+		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+				evt->buf, (unsigned long long) evt->dma,
+				evt->length);
+
+		evt->lpos = 0;
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
+				lower_32_bits(evt->dma));
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
+				upper_32_bits(evt->dma));
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
+				DWC3_GEVNTSIZ_SIZE(evt->length));
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+	}
+
+	return 0;
+}
+
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int				n;
+
+	for (n = 0; n < dwc->num_event_buffers; n++) {
+		evt = dwc->ev_buffs[n];
+
+		evt->lpos = 0;
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
+				| DWC3_GEVNTSIZ_SIZE(0));
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+	}
+}
+
+static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
+{
+	if (!dwc->has_hibernation)
+		return 0;
+
+	if (!dwc->nr_scratch)
+		return 0;
+
+	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
+			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
+	if (!dwc->scratchbuf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
+{
+	dma_addr_t scratch_addr;
+	u32 param;
+	int ret;
+
+	if (!dwc->has_hibernation)
+		return 0;
+
+	if (!dwc->nr_scratch)
+		return 0;
+
+	scratch_addr = dma_map_single(dwc->scratchbuf,
+				      dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+				      DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dwc->dev, scratch_addr)) {
+		dev_err(dwc->dev, "failed to map scratch buffer\n");
+		ret = -EFAULT;
+		goto err0;
+	}
+
+	dwc->scratch_addr = scratch_addr;
+
+	param = lower_32_bits(scratch_addr);
+
+	ret = dwc3_send_gadget_generic_command(dwc,
+			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
+	if (ret < 0)
+		goto err1;
+
+	param = upper_32_bits(scratch_addr);
+
+	ret = dwc3_send_gadget_generic_command(dwc,
+			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
+	if (ret < 0)
+		goto err1;
+
+	return 0;
+
+err1:
+	dma_unmap_single(scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+			 DMA_BIDIRECTIONAL);
+
+err0:
+	return ret;
+}
+
+static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
+{
+	if (!dwc->has_hibernation)
+		return;
+
+	if (!dwc->nr_scratch)
+		return;
+
+	dma_unmap_single(dwc->scratch_addr, dwc->nr_scratch *
+			 DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+	kfree(dwc->scratchbuf);
+}
+
+static void dwc3_core_num_eps(struct dwc3 *dwc)
+{
+	struct dwc3_hwparams	*parms = &dwc->hwparams;
+
+	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
+	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
+
+	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
+			dwc->num_in_eps, dwc->num_out_eps);
+}
+
+static void dwc3_cache_hwparams(struct dwc3 *dwc)
+{
+	struct dwc3_hwparams	*parms = &dwc->hwparams;
+
+	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
+	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
+	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
+	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
+	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
+	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
+	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
+	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+}
+
+static void dwc3_hsphy_mode_setup(struct dwc3 *dwc)
+{
+	enum usb_phy_interface hsphy_mode = dwc->hsphy_mode;
+	u32 reg;
+
+	/* Set dwc3 usb2 phy config */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+	switch (hsphy_mode) {
+	case USBPHY_INTERFACE_MODE_UTMI:
+		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+			DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
+			DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
+		break;
+	case USBPHY_INTERFACE_MODE_UTMIW:
+		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+			DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
+			DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
+		break;
+	default:
+		break;
+	}
+
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
+/**
+ * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_phy_setup(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+	/*
+	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
+	 * to '0' during coreConsultant configuration. So default value
+	 * will be '0' when the core is reset. Application needs to set it
+	 * to '1' after the core initialization is completed.
+	 */
+	if (dwc->revision > DWC3_REVISION_194A)
+		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+	if (dwc->u2ss_inp3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
+
+	if (dwc->req_p1p2p3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
+
+	if (dwc->del_p1p2p3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
+
+	if (dwc->del_phy_power_chg_quirk)
+		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
+	if (dwc->lfps_filter_quirk)
+		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
+
+	if (dwc->rx_detect_poll_quirk)
+		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
+
+	if (dwc->tx_de_emphasis_quirk)
+		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
+
+	if (dwc->dis_u3_susphy_quirk)
+		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+
+	if (dwc->dis_del_phy_power_chg_quirk)
+		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	dwc3_hsphy_mode_setup(dwc);
+
+	mdelay(100);
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+	/*
+	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
+	 * '0' during coreConsultant configuration. So default value will
+	 * be '0' when the core is reset. Application needs to set it to
+	 * '1' after the core initialization is completed.
+	 */
+	if (dwc->revision > DWC3_REVISION_194A)
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+	if (dwc->dis_u2_susphy_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+	if (dwc->dis_enblslpm_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+	if (dwc->dis_u2_freeclk_exists_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	mdelay(100);
+}
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_core_init(struct dwc3 *dwc)
+{
+	unsigned long		timeout;
+	u32			hwparams4 = dwc->hwparams.hwparams4;
+	u32			reg;
+	int			ret;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+	/* This should read as U3 followed by revision number */
+	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
+		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+		ret = -ENODEV;
+		goto err0;
+	}
+	dwc->revision = reg;
+
+	/* Handle USB2.0-only core configuration */
+	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
+			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
+		if (dwc->maximum_speed == USB_SPEED_SUPER)
+			dwc->maximum_speed = USB_SPEED_HIGH;
+	}
+
+	/* issue device SoftReset too */
+	timeout = 5000;
+	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+	while (timeout--) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		if (!(reg & DWC3_DCTL_CSFTRST))
+			break;
+	};
+
+	if (!timeout) {
+		dev_err(dwc->dev, "Reset Timed Out\n");
+		ret = -ETIMEDOUT;
+		goto err0;
+	}
+
+	dwc3_phy_setup(dwc);
+
+	ret = dwc3_core_soft_reset(dwc);
+	if (ret)
+		goto err0;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
+
+	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+		/**
+		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
+		 * issue which would cause xHCI compliance tests to fail.
+		 *
+		 * Because of that we cannot enable clock gating on such
+		 * configurations.
+		 *
+		 * Refers to:
+		 *
+		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
+		 * SOF/ITP Mode Used
+		 */
+		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
+				dwc->dr_mode == USB_DR_MODE_OTG) &&
+				(dwc->revision >= DWC3_REVISION_210A &&
+				dwc->revision <= DWC3_REVISION_250A))
+			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
+		else
+			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		break;
+	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
+		/* enable hibernation here */
+		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
+
+		/*
+		 * REVISIT Enabling this bit so that host-mode hibernation
+		 * will work. Device-mode hibernation is not yet implemented.
+		 */
+		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
+		break;
+	default:
+		dev_dbg(dwc->dev, "No power optimization available\n");
+	}
+
+	/* check if current dwc3 is on simulation board */
+	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
+		dev_dbg(dwc->dev, "it is on FPGA board\n");
+		dwc->is_fpga = true;
+	}
+
+	if(dwc->disable_scramble_quirk && !dwc->is_fpga)
+		WARN(true,
+		     "disable_scramble cannot be used on non-FPGA builds\n");
+
+	if (dwc->disable_scramble_quirk && dwc->is_fpga)
+		reg |= DWC3_GCTL_DISSCRAMBLE;
+	else
+		reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+	if (dwc->u2exit_lfps_quirk)
+		reg |= DWC3_GCTL_U2EXIT_LFPS;
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.90a have a bug
+	 * where the device can fail to connect at SuperSpeed
+	 * and falls back to high-speed mode which causes
+	 * the device to enter a Connect/Disconnect loop
+	 */
+	if (dwc->revision < DWC3_REVISION_190A)
+		reg |= DWC3_GCTL_U2RSTECN;
+
+	dwc3_core_num_eps(dwc);
+
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	ret = dwc3_alloc_scratch_buffers(dwc);
+	if (ret)
+		goto err0;
+
+	ret = dwc3_setup_scratch_buffers(dwc);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	dwc3_free_scratch_buffers(dwc);
+
+err0:
+	return ret;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+	dwc3_free_scratch_buffers(dwc);
+}
+
+static int dwc3_core_init_mode(struct dwc3 *dwc)
+{
+	int ret;
+
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to initialize gadget\n");
+			return ret;
+		}
+		break;
+	case USB_DR_MODE_HOST:
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to initialize host\n");
+			return ret;
+		}
+		break;
+	case USB_DR_MODE_OTG:
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to initialize host\n");
+			return ret;
+		}
+
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to initialize gadget\n");
+			return ret;
+		}
+		break;
+	default:
+		dev_err(dwc->dev,
+			"Unsupported mode of operation %d\n", dwc->dr_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void dwc3_gadget_run(struct dwc3 *dwc)
+{
+	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_RUN_STOP);
+	mdelay(100);
+}
+
+static void dwc3_core_exit_mode(struct dwc3 *dwc)
+{
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		dwc3_gadget_exit(dwc);
+		break;
+	case USB_DR_MODE_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case USB_DR_MODE_OTG:
+		dwc3_host_exit(dwc);
+		dwc3_gadget_exit(dwc);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	/*
+	 * switch back to peripheral mode
+	 * This enables the phy to enter idle and then, if enabled, suspend.
+	 */
+	dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+	dwc3_gadget_run(dwc);
+}
+
+#define DWC3_ALIGN_MASK		(16 - 1)
+
+/**
+ * dwc3_uboot_init - dwc3 core uboot initialization code
+ * @dwc3_dev: struct dwc3_device containing initialization data
+ *
+ * Entry point for dwc3 driver (equivalent to dwc3_probe in linux
+ * kernel driver). Pointer to dwc3_device should be passed containing
+ * base address and other initialization data. Returns '0' on success and
+ * a negative value on failure.
+ *
+ * Generally called from board_usb_init() implemented in board file.
+ */
+int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
+{
+	struct dwc3		*dwc;
+	struct device		*dev = NULL;
+	u8			lpm_nyet_threshold;
+	u8			tx_de_emphasis;
+	u8			hird_threshold;
+
+	int			ret;
+
+	void			*mem;
+
+	mem = devm_kzalloc((struct udevice *)dev,
+			   sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
+	dwc->mem = mem;
+
+	dwc->regs = (void *)(uintptr_t)(dwc3_dev->base +
+					DWC3_GLOBALS_REGS_START);
+
+	/* default to highest possible threshold */
+	lpm_nyet_threshold = 0xff;
+
+	/* default to -3.5dB de-emphasis */
+	tx_de_emphasis = 1;
+
+	/*
+	 * default to assert utmi_sleep_n and use maximum allowed HIRD
+	 * threshold value of 0b1100
+	 */
+	hird_threshold = 12;
+
+	dwc->maximum_speed = dwc3_dev->maximum_speed;
+	dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum;
+	if (dwc3_dev->lpm_nyet_threshold)
+		lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold;
+	dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend;
+	if (dwc3_dev->hird_threshold)
+		hird_threshold = dwc3_dev->hird_threshold;
+
+	dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize;
+	dwc->dr_mode = dwc3_dev->dr_mode;
+
+	dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk;
+	dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk;
+	dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk;
+	dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk;
+	dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk;
+	dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk;
+	dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk;
+	dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
+	dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
+	dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
+	dwc->dis_del_phy_power_chg_quirk = dwc3_dev->dis_del_phy_power_chg_quirk;
+	dwc->dis_tx_ipgap_linecheck_quirk = dwc3_dev->dis_tx_ipgap_linecheck_quirk;
+	dwc->dis_enblslpm_quirk = dwc3_dev->dis_enblslpm_quirk;
+	dwc->dis_u2_freeclk_exists_quirk = dwc3_dev->dis_u2_freeclk_exists_quirk;
+
+	dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
+	if (dwc3_dev->tx_de_emphasis)
+		tx_de_emphasis = dwc3_dev->tx_de_emphasis;
+
+	/* default to superspeed if no maximum_speed passed */
+	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
+		dwc->maximum_speed = USB_SPEED_SUPER;
+
+	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+	dwc->tx_de_emphasis = tx_de_emphasis;
+
+	dwc->hird_threshold = hird_threshold
+		| (dwc->is_utmi_l1_suspend << 4);
+
+	dwc->hsphy_mode = dwc3_dev->hsphy_mode;
+
+	dwc->index = dwc3_dev->index;
+
+	dwc3_cache_hwparams(dwc);
+
+	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+	if (ret) {
+		dev_err(dwc->dev, "failed to allocate event buffers\n");
+		return -ENOMEM;
+	}
+
+	if (!IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+		dwc->dr_mode = USB_DR_MODE_HOST;
+	else if (!IS_ENABLED(CONFIG_USB_HOST))
+		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+		dwc->dr_mode = USB_DR_MODE_OTG;
+
+	ret = dwc3_core_init(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to initialize core\n");
+		goto err0;
+	}
+
+	ret = dwc3_event_buffers_setup(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to setup event buffers\n");
+		goto err1;
+	}
+
+	ret = dwc3_core_init_mode(dwc);
+	if (ret)
+		goto err2;
+
+	list_add_tail(&dwc->list, &dwc3_list);
+
+	return 0;
+
+err2:
+	dwc3_event_buffers_cleanup(dwc);
+
+err1:
+	dwc3_core_exit(dwc);
+
+err0:
+	dwc3_free_event_buffers(dwc);
+
+	return ret;
+}
+
+/**
+ * dwc3_uboot_exit - dwc3 core uboot cleanup code
+ * @index: index of this controller
+ *
+ * Performs cleanup of memory allocated in dwc3_uboot_init and other misc
+ * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller
+ * should be passed and should match with the index passed in
+ * dwc3_device during init.
+ *
+ * Generally called from board file.
+ */
+void dwc3_uboot_exit(int index)
+{
+	struct dwc3 *dwc;
+
+	list_for_each_entry(dwc, &dwc3_list, list) {
+		if (dwc->index != index)
+			continue;
+
+		dwc3_core_exit_mode(dwc);
+		dwc3_event_buffers_cleanup(dwc);
+		dwc3_free_event_buffers(dwc);
+		dwc3_core_exit(dwc);
+		list_del(&dwc->list);
+		kfree(dwc->mem);
+		break;
+	}
+}
+
+/**
+ * dwc3_uboot_handle_interrupt - handle dwc3 core interrupt
+ * @index: index of this controller
+ *
+ * Invokes dwc3 gadget interrupts.
+ *
+ * Generally called from board file.
+ */
+void dwc3_uboot_handle_interrupt(int index)
+{
+	struct dwc3 *dwc = NULL;
+
+	list_for_each_entry(dwc, &dwc3_list, list) {
+		if (dwc->index != index)
+			continue;
+
+		dwc3_gadget_uboot_handle_interrupt(dwc);
+		break;
+	}
+}
+
+MODULE_ALIAS("platform:dwc3");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
+
+#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
+int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys)
+{
+	int ret;
+
+	ret = generic_phy_get_bulk(dev, phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_init_bulk(phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on_bulk(phys);
+	if (ret)
+		generic_phy_exit_bulk(phys);
+
+	return ret;
+}
+
+int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys)
+{
+	int ret;
+
+	ret = generic_phy_power_off_bulk(phys);
+	ret |= generic_phy_exit_bulk(phys);
+	return ret;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+void dwc3_of_parse(struct dwc3 *dwc)
+{
+	const u8 *tmp;
+	struct udevice *dev = dwc->dev;
+	u8 lpm_nyet_threshold;
+	u8 tx_de_emphasis;
+	u8 hird_threshold;
+
+	/* default to highest possible threshold */
+	lpm_nyet_threshold = 0xff;
+
+	/* default to -3.5dB de-emphasis */
+	tx_de_emphasis = 1;
+
+	/*
+	 * default to assert utmi_sleep_n and use maximum allowed HIRD
+	 * threshold value of 0b1100
+	 */
+	hird_threshold = 12;
+
+	dwc->hsphy_mode = usb_get_phy_mode(dev_ofnode(dev));
+
+	dwc->has_lpm_erratum = dev_read_bool(dev,
+				"snps,has-lpm-erratum");
+	tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1);
+	if (tmp)
+		lpm_nyet_threshold = *tmp;
+
+	dwc->is_utmi_l1_suspend = dev_read_bool(dev,
+				"snps,is-utmi-l1-suspend");
+	tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1);
+	if (tmp)
+		hird_threshold = *tmp;
+
+	dwc->disable_scramble_quirk = dev_read_bool(dev,
+				"snps,disable_scramble_quirk");
+	dwc->u2exit_lfps_quirk = dev_read_bool(dev,
+				"snps,u2exit_lfps_quirk");
+	dwc->u2ss_inp3_quirk = dev_read_bool(dev,
+				"snps,u2ss_inp3_quirk");
+	dwc->req_p1p2p3_quirk = dev_read_bool(dev,
+				"snps,req_p1p2p3_quirk");
+	dwc->del_p1p2p3_quirk = dev_read_bool(dev,
+				"snps,del_p1p2p3_quirk");
+	dwc->del_phy_power_chg_quirk = dev_read_bool(dev,
+				"snps,del_phy_power_chg_quirk");
+	dwc->lfps_filter_quirk = dev_read_bool(dev,
+				"snps,lfps_filter_quirk");
+	dwc->rx_detect_poll_quirk = dev_read_bool(dev,
+				"snps,rx_detect_poll_quirk");
+	dwc->dis_u3_susphy_quirk = dev_read_bool(dev,
+				"snps,dis_u3_susphy_quirk");
+	dwc->dis_u2_susphy_quirk = dev_read_bool(dev,
+				"snps,dis_u2_susphy_quirk");
+	dwc->dis_del_phy_power_chg_quirk = dev_read_bool(dev,
+				"snps,dis-del-phy-power-chg-quirk");
+	dwc->dis_tx_ipgap_linecheck_quirk = dev_read_bool(dev,
+				"snps,dis-tx-ipgap-linecheck-quirk");
+	dwc->dis_enblslpm_quirk = dev_read_bool(dev,
+				"snps,dis_enblslpm_quirk");
+	dwc->dis_u2_freeclk_exists_quirk = dev_read_bool(dev,
+				"snps,dis-u2-freeclk-exists-quirk");
+	dwc->tx_de_emphasis_quirk = dev_read_bool(dev,
+				"snps,tx_de_emphasis_quirk");
+	tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1);
+	if (tmp)
+		tx_de_emphasis = *tmp;
+
+	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+	dwc->tx_de_emphasis = tx_de_emphasis;
+
+	dwc->hird_threshold = hird_threshold
+		| (dwc->is_utmi_l1_suspend << 4);
+}
+
+int dwc3_init(struct dwc3 *dwc)
+{
+	int ret;
+	u32 reg;
+
+	dwc3_cache_hwparams(dwc);
+
+	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+	if (ret) {
+		dev_err(dwc->dev, "failed to allocate event buffers\n");
+		return -ENOMEM;
+	}
+
+	ret = dwc3_core_init(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to initialize core\n");
+		goto core_fail;
+	}
+
+	ret = dwc3_event_buffers_setup(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to setup event buffers\n");
+		goto event_fail;
+	}
+
+	if (dwc->revision >= DWC3_REVISION_250A) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
+
+		/*
+		 * Enable hardware control of sending remote wakeup
+		 * in HS when the device is in the L1 state.
+		 */
+		if (dwc->revision >= DWC3_REVISION_290A)
+			reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
+
+		if (dwc->dis_tx_ipgap_linecheck_quirk)
+			reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
+
+		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+	}
+
+	if (dwc->dr_mode == USB_DR_MODE_HOST ||
+	    dwc->dr_mode == USB_DR_MODE_OTG) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+
+		reg |= DWC3_GUCTL_HSTINAUTORETRY;
+
+		dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+	}
+
+	ret = dwc3_core_init_mode(dwc);
+	if (ret)
+		goto mode_fail;
+
+	return 0;
+
+mode_fail:
+	dwc3_event_buffers_cleanup(dwc);
+
+event_fail:
+	dwc3_core_exit(dwc);
+
+core_fail:
+	dwc3_free_event_buffers(dwc);
+
+	return ret;
+}
+
+void dwc3_remove(struct dwc3 *dwc)
+{
+	dwc3_core_exit_mode(dwc);
+	dwc3_event_buffers_cleanup(dwc);
+	dwc3_free_event_buffers(dwc);
+	dwc3_core_exit(dwc);
+	kfree(dwc->mem);
+}
+#endif
diff --git a/roms/u-boot/drivers/usb/dwc3/core.h b/roms/u-boot/drivers/usb/dwc3/core.h
new file mode 100644
index 000000000..44533fd7f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/core.h
@@ -0,0 +1,1062 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.h) and ported
+ * to uboot.
+ *
+ * commit 460d098cb6 : usb: dwc3: make HIRD threshold configurable
+ *
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/bitops.h>
+#include <linux/ioport.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
+
+#define DWC3_MSG_MAX	500
+
+/* Global constants */
+#define DWC3_EP0_BOUNCE_SIZE	512
+#define DWC3_ENDPOINTS_NUM	32
+#define DWC3_XHCI_RESOURCES_NUM	2
+
+#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */
+#define DWC3_EVENT_SIZE		4	/* bytes */
+#define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */
+#define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
+#define DWC3_EVENT_TYPE_MASK	0xfe
+
+#define DWC3_EVENT_TYPE_DEV	0
+#define DWC3_EVENT_TYPE_CARKIT	3
+#define DWC3_EVENT_TYPE_I2C	4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT		0
+#define DWC3_DEVICE_EVENT_RESET			1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE		2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
+#define DWC3_DEVICE_EVENT_WAKEUP		4
+#define DWC3_DEVICE_EVENT_HIBER_REQ		5
+#define DWC3_DEVICE_EVENT_EOPF			6
+#define DWC3_DEVICE_EVENT_SOF			7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
+#define DWC3_DEVICE_EVENT_CMD_CMPL		10
+#define DWC3_DEVICE_EVENT_OVERFLOW		11
+
+#define DWC3_GEVNTCOUNT_MASK	0xfffc
+#define DWC3_GSNPSID_MASK	0xffff0000
+#define DWC3_GSNPSREV_MASK	0xffff
+
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START		0x0
+#define DWC3_XHCI_REGS_END		0x7fff
+#define DWC3_GLOBALS_REGS_START		0xc100
+#define DWC3_GLOBALS_REGS_END		0xc6ff
+#define DWC3_DEVICE_REGS_START		0xc700
+#define DWC3_DEVICE_REGS_END		0xcbff
+#define DWC3_OTG_REGS_START		0xcc00
+#define DWC3_OTG_REGS_END		0xccff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0		0xc100
+#define DWC3_GSBUSCFG1		0xc104
+#define DWC3_GTXTHRCFG		0xc108
+#define DWC3_GRXTHRCFG		0xc10c
+#define DWC3_GCTL		0xc110
+#define DWC3_GEVTEN		0xc114
+#define DWC3_GSTS		0xc118
+#define DWC3_GUCTL1		0xc11c
+#define DWC3_GSNPSID		0xc120
+#define DWC3_GGPIO		0xc124
+#define DWC3_GUID		0xc128
+#define DWC3_GUCTL		0xc12c
+#define DWC3_GBUSERRADDR0	0xc130
+#define DWC3_GBUSERRADDR1	0xc134
+#define DWC3_GPRTBIMAP0		0xc138
+#define DWC3_GPRTBIMAP1		0xc13c
+#define DWC3_GHWPARAMS0		0xc140
+#define DWC3_GHWPARAMS1		0xc144
+#define DWC3_GHWPARAMS2		0xc148
+#define DWC3_GHWPARAMS3		0xc14c
+#define DWC3_GHWPARAMS4		0xc150
+#define DWC3_GHWPARAMS5		0xc154
+#define DWC3_GHWPARAMS6		0xc158
+#define DWC3_GHWPARAMS7		0xc15c
+#define DWC3_GDBGFIFOSPACE	0xc160
+#define DWC3_GDBGLTSSM		0xc164
+#define DWC3_GPRTBIMAP_HS0	0xc180
+#define DWC3_GPRTBIMAP_HS1	0xc184
+#define DWC3_GPRTBIMAP_FS0	0xc188
+#define DWC3_GPRTBIMAP_FS1	0xc18c
+
+#define DWC3_GUSB2PHYCFG(n)	(0xc200 + (n * 0x04))
+#define DWC3_GUSB2I2CCTL(n)	(0xc240 + (n * 0x04))
+
+#define DWC3_GUSB2PHYACC(n)	(0xc280 + (n * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n)	(0xc2c0 + (n * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n)	(0xc300 + (n * 0x04))
+#define DWC3_GRXFIFOSIZ(n)	(0xc380 + (n * 0x04))
+
+#define DWC3_GEVNTADRLO(n)	(0xc400 + (n * 0x10))
+#define DWC3_GEVNTADRHI(n)	(0xc404 + (n * 0x10))
+#define DWC3_GEVNTSIZ(n)	(0xc408 + (n * 0x10))
+#define DWC3_GEVNTCOUNT(n)	(0xc40c + (n * 0x10))
+
+#define DWC3_GHWPARAMS8		0xc600
+
+/* Device Registers */
+#define DWC3_DCFG		0xc700
+#define DWC3_DCTL		0xc704
+#define DWC3_DEVTEN		0xc708
+#define DWC3_DSTS		0xc70c
+#define DWC3_DGCMDPAR		0xc710
+#define DWC3_DGCMD		0xc714
+#define DWC3_DALEPENA		0xc720
+#define DWC3_DEPCMDPAR2(n)	(0xc800 + (n * 0x10))
+#define DWC3_DEPCMDPAR1(n)	(0xc804 + (n * 0x10))
+#define DWC3_DEPCMDPAR0(n)	(0xc808 + (n * 0x10))
+#define DWC3_DEPCMD(n)		(0xc80c + (n * 0x10))
+
+/* OTG Registers */
+#define DWC3_OCFG		0xcc00
+#define DWC3_OCTL		0xcc04
+#define DWC3_OEVT		0xcc08
+#define DWC3_OEVTEN		0xcc0C
+#define DWC3_OSTS		0xcc10
+
+/* Bit fields */
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
+#define DWC3_GCTL_U2RSTECN	(1 << 16)
+#define DWC3_GCTL_RAMCLKSEL(x)	(((x) & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_CLK_BUS	(0)
+#define DWC3_GCTL_CLK_PIPE	(1)
+#define DWC3_GCTL_CLK_PIPEHALF	(2)
+#define DWC3_GCTL_CLK_MASK	(3)
+
+#define DWC3_GCTL_PRTCAP(n)	(((n) & (3 << 12)) >> 12)
+#define DWC3_GCTL_PRTCAPDIR(n)	((n) << 12)
+#define DWC3_GCTL_PRTCAP_HOST	1
+#define DWC3_GCTL_PRTCAP_DEVICE	2
+#define DWC3_GCTL_PRTCAP_OTG	3
+
+#define DWC3_GCTL_CORESOFTRESET		(1 << 11)
+#define DWC3_GCTL_SOFITPSYNC		(1 << 10)
+#define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)
+#define DWC3_GCTL_DISSCRAMBLE		(1 << 3)
+#define DWC3_GCTL_U2EXIT_LFPS		(1 << 2)
+#define DWC3_GCTL_GBLHIBERNATIONEN	(1 << 1)
+#define DWC3_GCTL_DSBLCLKGTNG		(1 << 0)
+
+/* Global User Control Register */
+#define DWC3_GUCTL_HSTINAUTORETRY	BIT(14)
+
+/* Global User Control 1 Register */
+#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS	BIT(28)
+#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW	BIT(24)
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
+#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS	(1 << 30)
+#define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
+#define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
+#define DWC3_GUSB2PHYCFG_PHYIF(n)	((n) << 3)
+#define DWC3_GUSB2PHYCFG_PHYIF_MASK	DWC3_GUSB2PHYCFG_PHYIF(1)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM(n)	((n) << 10)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK	DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
+#define USBTRDTIM_UTMI_8_BIT		9
+#define USBTRDTIM_UTMI_16_BIT		5
+#define UTMI_PHYIF_16_BIT		1
+#define UTMI_PHYIF_8_BIT		0
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST	(1 << 31)
+#define DWC3_GUSB3PIPECTL_U2SSINP3OK	(1 << 29)
+#define DWC3_GUSB3PIPECTL_REQP1P2P3	(1 << 24)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3(n)	((n) << 19)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK	DWC3_GUSB3PIPECTL_DEP1P2P3(7)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN	DWC3_GUSB3PIPECTL_DEP1P2P3(1)
+#define DWC3_GUSB3PIPECTL_DEPOCHANGE	(1 << 18)
+#define DWC3_GUSB3PIPECTL_SUSPHY	(1 << 17)
+#define DWC3_GUSB3PIPECTL_LFPSFILT	(1 << 9)
+#define DWC3_GUSB3PIPECTL_RX_DETOPOLL	(1 << 8)
+#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK	DWC3_GUSB3PIPECTL_TX_DEEPH(3)
+#define DWC3_GUSB3PIPECTL_TX_DEEPH(n)	((n) << 1)
+
+/* Global TX Fifo Size Register */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
+
+/* Global Event Size Registers */
+#define DWC3_GEVNTSIZ_INTMASK		(1 << 31)
+#define DWC3_GEVNTSIZ_SIZE(n)		((n) & 0xffff)
+
+/* Global HWPARAMS1 Register */
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
+#define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
+#define DWC3_GHWPARAMS1_EN_PWROPT_HIB	2
+#define DWC3_GHWPARAMS1_PWROPT(n)	((n) << 24)
+#define DWC3_GHWPARAMS1_PWROPT_MASK	DWC3_GHWPARAMS1_PWROPT(3)
+
+/* Global HWPARAMS3 Register */
+#define DWC3_GHWPARAMS3_SSPHY_IFC(n)		((n) & 3)
+#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_SSPHY_IFC_ENA		1
+#define DWC3_GHWPARAMS3_HSPHY_IFC(n)		(((n) & (3 << 2)) >> 2)
+#define DWC3_GHWPARAMS3_HSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI		1
+#define DWC3_GHWPARAMS3_HSPHY_IFC_ULPI		2
+#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI	3
+#define DWC3_GHWPARAMS3_FSPHY_IFC(n)		(((n) & (3 << 4)) >> 4)
+#define DWC3_GHWPARAMS3_FSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_FSPHY_IFC_ENA		1
+
+/* Global HWPARAMS4 Register */
+#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n)	(((n) & (0x0f << 13)) >> 13)
+#define DWC3_MAX_HIBER_SCRATCHBUFS		15
+
+/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_EN_FPGA			(1 << 7)
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK	(7 << 0)
+#define DWC3_DCFG_SUPERSPEED	(4 << 0)
+#define DWC3_DCFG_HIGHSPEED	(0 << 0)
+#define DWC3_DCFG_FULLSPEED2	(1 << 0)
+#define DWC3_DCFG_LOWSPEED	(2 << 0)
+#define DWC3_DCFG_FULLSPEED1	(3 << 0)
+
+#define DWC3_DCFG_LPM_CAP	(1 << 22)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP	(1 << 31)
+#define DWC3_DCTL_CSFTRST	(1 << 30)
+#define DWC3_DCTL_LSFTRST	(1 << 29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n)	((n) << 24)
+
+#define DWC3_DCTL_APPL1RES	(1 << 23)
+
+/* These apply for core versions 1.87a and earlier */
+#define DWC3_DCTL_TRGTULST_MASK		(0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)		((n) << 17)
+#define DWC3_DCTL_TRGTULST_U2		(DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3		(DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS	(DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET	(DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT	(DWC3_DCTL_TRGTULST(6))
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DCTL_LPM_ERRATA_MASK	DWC3_DCTL_LPM_ERRATA(0xf)
+#define DWC3_DCTL_LPM_ERRATA(n)		((n) << 20)
+
+#define DWC3_DCTL_KEEP_CONNECT		(1 << 19)
+#define DWC3_DCTL_L1_HIBER_EN		(1 << 18)
+#define DWC3_DCTL_CRS			(1 << 17)
+#define DWC3_DCTL_CSS			(1 << 16)
+
+#define DWC3_DCTL_INITU2ENA		(1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA		(1 << 11)
+#define DWC3_DCTL_INITU1ENA		(1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA		(1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK		(0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK	(0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION	(DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED	(DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT	(DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE	(DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY	(DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE	(DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK	(DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN	(1 << 12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN	(1 << 11)
+#define DWC3_DEVTEN_CMDCMPLTEN		(1 << 10)
+#define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
+#define DWC3_DEVTEN_SOFEN		(1 << 7)
+#define DWC3_DEVTEN_EOPFEN		(1 << 6)
+#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	(1 << 5)
+#define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
+#define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
+#define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
+#define DWC3_DEVTEN_USBRSTEN		(1 << 1)
+#define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
+
+/* Device Status Register */
+#define DWC3_DSTS_DCNRD			(1 << 29)
+
+/* This applies for core versions 1.87a and earlier */
+#define DWC3_DSTS_PWRUPREQ		(1 << 24)
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DSTS_RSS			(1 << 25)
+#define DWC3_DSTS_SSS			(1 << 24)
+
+#define DWC3_DSTS_COREIDLE		(1 << 23)
+#define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
+
+#define DWC3_DSTS_USBLNKST_MASK		(0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n)		(((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY		(1 << 17)
+
+#define DWC3_DSTS_SOFFN_MASK		(0x3fff << 3)
+#define DWC3_DSTS_SOFFN(n)		(((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD		(7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED		(4 << 0)
+#define DWC3_DSTS_HIGHSPEED		(0 << 0)
+#define DWC3_DSTS_FULLSPEED2		(1 << 0)
+#define DWC3_DSTS_LOWSPEED		(2 << 0)
+#define DWC3_DSTS_FULLSPEED1		(3 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP		0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
+#define DWC3_DGCMD_XMIT_FUNCTION	0x03
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO	0x04
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI	0x05
+
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
+
+#define DWC3_DGCMD_STATUS(n)		(((n) >> 15) & 1)
+#define DWC3_DGCMD_CMDACT		(1 << 10)
+#define DWC3_DGCMD_CMDIOC		(1 << 8)
+
+/* Device Generic Command Parameter Register */
+#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT	(1 << 0)
+#define DWC3_DGCMDPAR_FIFO_NUM(n)		((n) << 0)
+#define DWC3_DGCMDPAR_RX_FIFO			(0 << 5)
+#define DWC3_DGCMDPAR_TX_FIFO			(1 << 5)
+#define DWC3_DGCMDPAR_LOOPBACK_DIS		(0 << 0)
+#define DWC3_DGCMDPAR_LOOPBACK_ENA		(1 << 0)
+
+/* Device Endpoint Command Register */
+#define DWC3_DEPCMD_PARAM_SHIFT		16
+#define DWC3_DEPCMD_PARAM(x)		((x) << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)	(((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_STATUS(x)		(((x) >> 15) & 1)
+#define DWC3_DEPCMD_HIPRI_FORCERM	(1 << 11)
+#define DWC3_DEPCMD_CMDACT		(1 << 10)
+#define DWC3_DEPCMD_CMDIOC		(1 << 8)
+
+#define DWC3_DEPCMD_DEPSTARTCFG		(0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER		(0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER	(0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
+/* This applies for core versions 1.90a and earlier */
+#define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
+/* This applies for core versions 1.94a and later */
+#define DWC3_DEPCMD_GETEPSTATE		(0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n)		(1 << n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL	0
+#define DWC3_DEPCMD_TYPE_ISOC		1
+#define DWC3_DEPCMD_TYPE_BULK		2
+#define DWC3_DEPCMD_TYPE_INTR		3
+
+/* Structures */
+
+struct dwc3_trb;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @buf: _THE_ buffer
+ * @length: size of this buffer
+ * @lpos: event offset
+ * @count: cache of last read event count register
+ * @flags: flags related to this event buffer
+ * @dma: dma_addr_t
+ * @dwc: pointer to DWC controller
+ */
+struct dwc3_event_buffer {
+	void			*buf;
+	unsigned		length;
+	unsigned int		lpos;
+	unsigned int		count;
+	unsigned int		flags;
+
+#define DWC3_EVENT_PENDING	(1UL << 0)
+
+	dma_addr_t		dma;
+
+	struct dwc3		*dwc;
+};
+
+#define DWC3_EP_FLAG_STALLED	(1 << 0)
+#define DWC3_EP_FLAG_WEDGED	(1 << 1)
+
+#define DWC3_EP_DIRECTION_TX	true
+#define DWC3_EP_DIRECTION_RX	false
+
+#define DWC3_TRB_NUM		32
+#define DWC3_TRB_MASK		(DWC3_TRB_NUM - 1)
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @request_list: list of requests for this endpoint
+ * @req_queued: list of requests on this ep which have TRBs setup
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @saved_state: ep state saved during hibernation
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @resource_index: Resource transfer index
+ * @interval: the interval on which the ISOC transfer is started
+ * @name: a human readable name e.g. ep1out-bulk
+ * @direction: true for TX, false for RX
+ * @stream_capable: true when streams are enabled
+ */
+struct dwc3_ep {
+	struct usb_ep		endpoint;
+	struct list_head	request_list;
+	struct list_head	req_queued;
+
+	struct dwc3_trb		*trb_pool;
+	dma_addr_t		trb_pool_dma;
+	u32			free_slot;
+	u32			busy_slot;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	struct dwc3		*dwc;
+
+	u32			saved_state;
+	unsigned		flags;
+#define DWC3_EP_ENABLED		(1 << 0)
+#define DWC3_EP_STALL		(1 << 1)
+#define DWC3_EP_WEDGE		(1 << 2)
+#define DWC3_EP_BUSY		(1 << 4)
+#define DWC3_EP_PENDING_REQUEST	(1 << 5)
+#define DWC3_EP_MISSED_ISOC	(1 << 6)
+
+	/* This last one is specific to EP0 */
+#define DWC3_EP0_DIR_IN		(1 << 31)
+
+	unsigned		current_trb;
+
+	u8			number;
+	u8			type;
+	u8			resource_index;
+	u32			interval;
+
+	char			name[20];
+
+	unsigned		direction:1;
+	unsigned		stream_capable:1;
+};
+
+enum dwc3_phy {
+	DWC3_PHY_UNKNOWN = 0,
+	DWC3_PHY_USB3,
+	DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_next {
+	DWC3_EP0_UNKNOWN = 0,
+	DWC3_EP0_COMPLETE,
+	DWC3_EP0_NRDY_DATA,
+	DWC3_EP0_NRDY_STATUS,
+};
+
+enum dwc3_ep0_state {
+	EP0_UNCONNECTED		= 0,
+	EP0_SETUP_PHASE,
+	EP0_DATA_PHASE,
+	EP0_STATUS_PHASE,
+};
+
+enum dwc3_link_state {
+	/* In SuperSpeed */
+	DWC3_LINK_STATE_U0		= 0x00, /* in HS, means ON */
+	DWC3_LINK_STATE_U1		= 0x01,
+	DWC3_LINK_STATE_U2		= 0x02, /* in HS, means SLEEP */
+	DWC3_LINK_STATE_U3		= 0x03, /* in HS, means SUSPEND */
+	DWC3_LINK_STATE_SS_DIS		= 0x04,
+	DWC3_LINK_STATE_RX_DET		= 0x05, /* in HS, means Early Suspend */
+	DWC3_LINK_STATE_SS_INACT	= 0x06,
+	DWC3_LINK_STATE_POLL		= 0x07,
+	DWC3_LINK_STATE_RECOV		= 0x08,
+	DWC3_LINK_STATE_HRESET		= 0x09,
+	DWC3_LINK_STATE_CMPLY		= 0x0a,
+	DWC3_LINK_STATE_LPBK		= 0x0b,
+	DWC3_LINK_STATE_RESET		= 0x0e,
+	DWC3_LINK_STATE_RESUME		= 0x0f,
+	DWC3_LINK_STATE_MASK		= 0x0f,
+};
+
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK	(0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n)	((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n)	(((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n)	(((n) & (0x0f << 28)) >> 28)
+
+#define DWC3_TRBSTS_OK			0
+#define DWC3_TRBSTS_MISSED_ISOC		1
+#define DWC3_TRBSTS_SETUP_PENDING	2
+#define DWC3_TRB_STS_XFER_IN_PROG	4
+
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO		(1 << 0)
+#define DWC3_TRB_CTRL_LST		(1 << 1)
+#define DWC3_TRB_CTRL_CHN		(1 << 2)
+#define DWC3_TRB_CTRL_CSP		(1 << 3)
+#define DWC3_TRB_CTRL_TRBCTL(n)		(((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI		(1 << 10)
+#define DWC3_TRB_CTRL_IOC		(1 << 11)
+#define DWC3_TRB_CTRL_SID_SOFN(n)	(((n) & 0xffff) << 14)
+
+#define DWC3_TRBCTL_NORMAL		DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP	DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2	DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3	DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA	DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST	DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS		DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB		DWC3_TRB_CTRL_TRBCTL(8)
+
+/**
+ * struct dwc3_trb - transfer request block (hw format)
+ * @bpl: DW0-3
+ * @bph: DW4-7
+ * @size: DW8-B
+ * @trl: DWC-F
+ */
+struct dwc3_trb {
+	u32		bpl;
+	u32		bph;
+	u32		size;
+	u32		ctrl;
+} __packed;
+
+/**
+ * dwc3_hwparams - copy of HWPARAMS registers
+ * @hwparams0 - GHWPARAMS0
+ * @hwparams1 - GHWPARAMS1
+ * @hwparams2 - GHWPARAMS2
+ * @hwparams3 - GHWPARAMS3
+ * @hwparams4 - GHWPARAMS4
+ * @hwparams5 - GHWPARAMS5
+ * @hwparams6 - GHWPARAMS6
+ * @hwparams7 - GHWPARAMS7
+ * @hwparams8 - GHWPARAMS8
+ */
+struct dwc3_hwparams {
+	u32	hwparams0;
+	u32	hwparams1;
+	u32	hwparams2;
+	u32	hwparams3;
+	u32	hwparams4;
+	u32	hwparams5;
+	u32	hwparams6;
+	u32	hwparams7;
+	u32	hwparams8;
+};
+
+/* HWPARAMS0 */
+#define DWC3_MODE(n)		((n) & 0x7)
+
+#define DWC3_MDWIDTH(n)		(((n) & 0xff00) >> 8)
+
+/* HWPARAMS1 */
+#define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS3 */
+#define DWC3_NUM_IN_EPS_MASK	(0x1f << 18)
+#define DWC3_NUM_EPS_MASK	(0x3f << 12)
+#define DWC3_NUM_EPS(p)		(((p)->hwparams3 &		\
+			(DWC3_NUM_EPS_MASK)) >> 12)
+#define DWC3_NUM_IN_EPS(p)	(((p)->hwparams3 &		\
+			(DWC3_NUM_IN_EPS_MASK)) >> 18)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)
+
+struct dwc3_request {
+	struct usb_request	request;
+	struct list_head	list;
+	struct dwc3_ep		*dep;
+	u32			start_slot;
+
+	u8			epnum;
+	struct dwc3_trb		*trb;
+	dma_addr_t		trb_dma;
+
+	unsigned		direction:1;
+	unsigned		mapped:1;
+	unsigned		queued:1;
+};
+
+/*
+ * struct dwc3_scratchpad_array - hibernation scratchpad array
+ * (format defined by hw)
+ */
+struct dwc3_scratchpad_array {
+	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
+};
+
+/**
+ * struct dwc3 - representation of our controller
+ * @ctrl_req: usb control request which is used for ep0
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @ep0_bounce: bounce buffer for ep0
+ * @setup_buf: used while precessing STD USB requests
+ * @ctrl_req_addr: dma address of ctrl_req
+ * @ep0_trb: dma address of ep0_trb
+ * @ep0_usb_req: dummy req used while handling STD USB requests
+ * @ep0_bounce_addr: dma address of ep0_bounce
+ * @scratch_addr: dma address of scratchbuf
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @xhci: pointer to our xHCI child
+ * @event_buffer_list: a list of event buffers
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @nr_scratch: number of scratch buffers
+ * @num_event_buffers: calculated number of event buffers
+ * @u1u2: only used on revisions <1.83a for workaround
+ * @maximum_speed: maximum speed requested (mainly for testing purposes)
+ * @revision: revision register contents
+ * @dr_mode: requested mode of operation
+ * @hsphy_mode: UTMI phy mode, one of following:
+ *		- USBPHY_INTERFACE_MODE_UTMI
+ *		- USBPHY_INTERFACE_MODE_UTMIW
+ * @dcfg: saved contents of DCFG register
+ * @gctl: saved contents of GCTL register
+ * @isoch_delay: wValue from Set Isochronous Delay request;
+ * @u2sel: parameter from Set SEL request.
+ * @u2pel: parameter from Set SEL request.
+ * @u1sel: parameter from Set SEL request.
+ * @u1pel: parameter from Set SEL request.
+ * @num_out_eps: number of out endpoints
+ * @num_in_eps: number of in endpoints
+ * @ep0_next_event: hold the next expected event
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @mem: points to start of memory which is used for this struct.
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ * @regset: debugfs pointer to regdump file
+ * @test_mode: true when we're entering a USB test mode
+ * @test_mode_nr: test feature selector
+ * @lpm_nyet_threshold: LPM NYET response threshold
+ * @hird_threshold: HIRD threshold
+ * @delayed_status: true when gadget driver asks for delayed status
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @has_hibernation: true when dwc3 was configured with Hibernation
+ * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
+ *			there's now way for software to detect this in runtime.
+ * @is_utmi_l1_suspend: the core asserts output signal
+ * 	0	- utmi_sleep_n
+ * 	1	- utmi_l1_suspend_n
+ * @is_selfpowered: true when we are selfpowered
+ * @is_fpga: true when we are using the FPGA board
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @pullups_connected: true when Run/Stop bit is set
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @start_config_issued: true when StartConfig command has been issued
+ * @three_stage_setup: set if we perform a three phase setup
+ * @disable_scramble_quirk: set if we enable the disable scramble quirk
+ * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk
+ * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
+ * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk
+ * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk
+ * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk
+ * @lfps_filter_quirk: set if we enable LFPS filter quirk
+ * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk
+ * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy
+ * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
+ * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
+ * @tx_de_emphasis: Tx de-emphasis value
+ * 	0	- -6dB de-emphasis
+ * 	1	- -3.5dB de-emphasis
+ * 	2	- No de-emphasis
+ * 	3	- Reserved
+ * @index: index of _this_ controller
+ * @list: to maintain the list of dwc3 controllers
+ */
+struct dwc3 {
+	struct usb_ctrlrequest	*ctrl_req;
+	struct dwc3_trb		*ep0_trb;
+	void			*ep0_bounce;
+	void			*scratchbuf;
+	u8			*setup_buf;
+	dma_addr_t		ctrl_req_addr;
+	dma_addr_t		ep0_trb_addr;
+	dma_addr_t		ep0_bounce_addr;
+	dma_addr_t		scratch_addr;
+	struct dwc3_request	ep0_usb_req;
+
+	/* device lock */
+	spinlock_t		lock;
+
+#if defined(__UBOOT__) && CONFIG_IS_ENABLED(DM_USB)
+	struct udevice		*dev;
+#else
+	struct device		*dev;
+#endif
+
+	struct platform_device	*xhci;
+	struct resource		xhci_resources[DWC3_XHCI_RESOURCES_NUM];
+
+	struct dwc3_event_buffer **ev_buffs;
+	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
+
+	struct usb_gadget	gadget;
+	struct usb_gadget_driver *gadget_driver;
+
+	void __iomem		*regs;
+	size_t			regs_size;
+
+	enum usb_dr_mode	dr_mode;
+	enum usb_phy_interface	hsphy_mode;
+
+	/* used for suspend/resume */
+	u32			dcfg;
+	u32			gctl;
+
+	u32			nr_scratch;
+	u32			num_event_buffers;
+	u32			u1u2;
+	u32			maximum_speed;
+	u32			revision;
+
+#define DWC3_REVISION_173A	0x5533173a
+#define DWC3_REVISION_175A	0x5533175a
+#define DWC3_REVISION_180A	0x5533180a
+#define DWC3_REVISION_183A	0x5533183a
+#define DWC3_REVISION_185A	0x5533185a
+#define DWC3_REVISION_187A	0x5533187a
+#define DWC3_REVISION_188A	0x5533188a
+#define DWC3_REVISION_190A	0x5533190a
+#define DWC3_REVISION_194A	0x5533194a
+#define DWC3_REVISION_200A	0x5533200a
+#define DWC3_REVISION_202A	0x5533202a
+#define DWC3_REVISION_210A	0x5533210a
+#define DWC3_REVISION_220A	0x5533220a
+#define DWC3_REVISION_230A	0x5533230a
+#define DWC3_REVISION_240A	0x5533240a
+#define DWC3_REVISION_250A	0x5533250a
+#define DWC3_REVISION_260A	0x5533260a
+#define DWC3_REVISION_270A	0x5533270a
+#define DWC3_REVISION_280A	0x5533280a
+#define DWC3_REVISION_290A	0x5533290a
+
+	enum dwc3_ep0_next	ep0_next_event;
+	enum dwc3_ep0_state	ep0state;
+	enum dwc3_link_state	link_state;
+
+	u16			isoch_delay;
+	u16			u2sel;
+	u16			u2pel;
+	u8			u1sel;
+	u8			u1pel;
+
+	u8			speed;
+
+	u8			num_out_eps;
+	u8			num_in_eps;
+
+	void			*mem;
+
+	struct dwc3_hwparams	hwparams;
+	struct dentry		*root;
+	struct debugfs_regset32	*regset;
+
+	u8			test_mode;
+	u8			test_mode_nr;
+	u8			lpm_nyet_threshold;
+	u8			hird_threshold;
+
+	unsigned		delayed_status:1;
+	unsigned		ep0_bounced:1;
+	unsigned		ep0_expect_in:1;
+	unsigned		has_hibernation:1;
+	unsigned		has_lpm_erratum:1;
+	unsigned		is_utmi_l1_suspend:1;
+	unsigned		is_selfpowered:1;
+	unsigned		is_fpga:1;
+	unsigned		needs_fifo_resize:1;
+	unsigned		pullups_connected:1;
+	unsigned		resize_fifos:1;
+	unsigned		setup_packet_pending:1;
+	unsigned		start_config_issued:1;
+	unsigned		three_stage_setup:1;
+
+	unsigned		disable_scramble_quirk:1;
+	unsigned		u2exit_lfps_quirk:1;
+	unsigned		u2ss_inp3_quirk:1;
+	unsigned		req_p1p2p3_quirk:1;
+	unsigned                del_p1p2p3_quirk:1;
+	unsigned		del_phy_power_chg_quirk:1;
+	unsigned		lfps_filter_quirk:1;
+	unsigned		rx_detect_poll_quirk:1;
+	unsigned		dis_u3_susphy_quirk:1;
+	unsigned		dis_u2_susphy_quirk:1;
+	unsigned		dis_del_phy_power_chg_quirk:1;
+	unsigned		dis_tx_ipgap_linecheck_quirk:1;
+	unsigned		dis_enblslpm_quirk:1;
+	unsigned		dis_u2_freeclk_exists_quirk:1;
+
+	unsigned		tx_de_emphasis_quirk:1;
+	unsigned		tx_de_emphasis:2;
+	int			index;
+	struct list_head        list;
+};
+
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_event_type {
+	u32	is_devspec:1;
+	u32	type:7;
+	u32	reserved8_31:24;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE	0x01
+#define DWC3_DEPEVT_XFERINPROGRESS	0x02
+#define DWC3_DEPEVT_XFERNOTREADY	0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT		0x04
+#define DWC3_DEPEVT_STREAMEVT		0x06
+#define DWC3_DEPEVT_EPCMDCMPLT		0x07
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		return "Transfer Complete";
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		return "Transfer In-Progress";
+	case DWC3_DEPEVT_XFERNOTREADY:
+		return "Transfer Not Ready";
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		return "FIFO";
+	case DWC3_DEPEVT_STREAMEVT:
+		return "Stream";
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		return "Endpoint Command Complete";
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ *	0x00	- Reserved
+ *	0x01	- XferComplete
+ *	0x02	- XferInProgress
+ *	0x03	- XferNotReady
+ *	0x04	- RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ *	0x05	- Reserved
+ *	0x06	- StreamEvt
+ *	0x07	- EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ *	more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ *	more information.
+ */
+struct dwc3_event_depevt {
+	u32	one_bit:1;
+	u32	endpoint_number:5;
+	u32	endpoint_event:4;
+	u32	reserved11_10:2;
+	u32	status:4;
+
+/* Within XferNotReady */
+#define DEPEVT_STATUS_TRANSFER_ACTIVE	(1 << 3)
+
+/* Within XferComplete */
+#define DEPEVT_STATUS_BUSERR	(1 << 0)
+#define DEPEVT_STATUS_SHORT	(1 << 1)
+#define DEPEVT_STATUS_IOC	(1 << 2)
+#define DEPEVT_STATUS_LST	(1 << 3)
+
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND		1
+#define DEPEVT_STREAMEVT_NOTFOUND	2
+
+/* Control-only Status */
+#define DEPEVT_STATUS_CONTROL_DATA	1
+#define DEPEVT_STATUS_CONTROL_STATUS	2
+
+	u32	parameters:16;
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ *	0	- DisconnEvt
+ *	1	- USBRst
+ *	2	- ConnectDone
+ *	3	- ULStChng
+ *	4	- WkUpEvt
+ *	5	- Reserved
+ *	6	- EOPF
+ *	7	- SOF
+ *	8	- Reserved
+ *	9	- ErrticErr
+ *	10	- CmdCmplt
+ *	11	- EvntOverflow
+ *	12	- VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_25: Reserved, not used
+ */
+struct dwc3_event_devt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	type:4;
+	u32	reserved15_12:4;
+	u32	event_info:9;
+	u32	reserved31_25:7;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	phy_port_number:4;
+	u32	reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+	u32				raw;
+	struct dwc3_event_type		type;
+	struct dwc3_event_depevt	depevt;
+	struct dwc3_event_devt		devt;
+	struct dwc3_event_gevt		gevt;
+};
+
+/**
+ * struct dwc3_gadget_ep_cmd_params - representation of endpoint command
+ * parameters
+ * @param2: third parameter
+ * @param1: second parameter
+ * @param0: first parameter
+ */
+struct dwc3_gadget_ep_cmd_params {
+	u32	param2;
+	u32	param1;
+	u32	param0;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL		BIT(0)
+#define DWC3_HAS_XHCI			BIT(1)
+#define DWC3_HAS_OTG			BIT(3)
+
+/* prototypes */
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+void dwc3_of_parse(struct dwc3 *dwc);
+int dwc3_init(struct dwc3 *dwc);
+void dwc3_remove(struct dwc3 *dwc);
+
+static inline int dwc3_host_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_host_exit(struct dwc3 *dwc)
+{ }
+
+#ifdef CONFIG_USB_DWC3_GADGET
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_get_link_state(struct dwc3 *dwc);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc)
+{ }
+static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
+{ return 0; }
+static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc)
+{ return 0; }
+static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc,
+		enum dwc3_link_state state)
+{ return 0; }
+
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{ return 0; }
+static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
+		int cmd, u32 param)
+{ return 0; }
+#endif
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/roms/u-boot/drivers/usb/dwc3/dwc3-generic.c b/roms/u-boot/drivers/usb/dwc3/dwc3-generic.c
new file mode 100644
index 000000000..c8bf4ae85
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/dwc3-generic.c
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic DWC3 Glue layer
+ *
+ * Copyright (C) 2016 - 2018 Xilinx, Inc.
+ *
+ * Based on dwc3-omap.c.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dwc3-uboot.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <usb.h>
+#include "core.h"
+#include "gadget.h"
+#include <reset.h>
+#include <clk.h>
+#include <usb/xhci.h>
+
+struct dwc3_glue_data {
+	struct clk_bulk		clks;
+	struct reset_ctl_bulk	resets;
+	fdt_addr_t regs;
+};
+
+struct dwc3_generic_plat {
+	fdt_addr_t base;
+	u32 maximum_speed;
+	enum usb_dr_mode dr_mode;
+};
+
+struct dwc3_generic_priv {
+	void *base;
+	struct dwc3 dwc3;
+	struct phy_bulk phys;
+};
+
+struct dwc3_generic_host_priv {
+	struct xhci_ctrl xhci_ctrl;
+	struct dwc3_generic_priv gen_priv;
+};
+
+static int dwc3_generic_probe(struct udevice *dev,
+			      struct dwc3_generic_priv *priv)
+{
+	int rc;
+	struct dwc3_generic_plat *plat = dev_get_plat(dev);
+	struct dwc3 *dwc3 = &priv->dwc3;
+	struct dwc3_glue_data *glue = dev_get_plat(dev->parent);
+
+	dwc3->dev = dev;
+	dwc3->maximum_speed = plat->maximum_speed;
+	dwc3->dr_mode = plat->dr_mode;
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	dwc3_of_parse(dwc3);
+#endif
+
+	/*
+	 * It must hold whole USB3.0 OTG controller in resetting to hold pipe
+	 * power state in P2 before initializing TypeC PHY on RK3399 platform.
+	 */
+	if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3")) {
+		reset_assert_bulk(&glue->resets);
+		udelay(1);
+	}
+
+	rc = dwc3_setup_phy(dev, &priv->phys);
+	if (rc && rc != -ENOTSUPP)
+		return rc;
+
+	if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3"))
+		reset_deassert_bulk(&glue->resets);
+
+	priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
+	dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
+
+
+	rc =  dwc3_init(dwc3);
+	if (rc) {
+		unmap_physmem(priv->base, MAP_NOCACHE);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int dwc3_generic_remove(struct udevice *dev,
+			       struct dwc3_generic_priv *priv)
+{
+	struct dwc3 *dwc3 = &priv->dwc3;
+
+	dwc3_remove(dwc3);
+	dwc3_shutdown_phy(dev, &priv->phys);
+	unmap_physmem(dwc3->regs, MAP_NOCACHE);
+
+	return 0;
+}
+
+static int dwc3_generic_of_to_plat(struct udevice *dev)
+{
+	struct dwc3_generic_plat *plat = dev_get_plat(dev);
+	ofnode node = dev_ofnode(dev);
+
+	plat->base = dev_read_addr(dev);
+
+	plat->maximum_speed = usb_get_maximum_speed(node);
+	if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
+		pr_info("No USB maximum speed specified. Using super speed\n");
+		plat->maximum_speed = USB_SPEED_SUPER;
+	}
+
+	plat->dr_mode = usb_get_dr_mode(node);
+	if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
+		pr_err("Invalid usb mode setup\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct dwc3_generic_priv *priv = dev_get_priv(dev);
+	struct dwc3 *dwc3 = &priv->dwc3;
+
+	dwc3_gadget_uboot_handle_interrupt(dwc3);
+
+	return 0;
+}
+
+static int dwc3_generic_peripheral_probe(struct udevice *dev)
+{
+	struct dwc3_generic_priv *priv = dev_get_priv(dev);
+
+	return dwc3_generic_probe(dev, priv);
+}
+
+static int dwc3_generic_peripheral_remove(struct udevice *dev)
+{
+	struct dwc3_generic_priv *priv = dev_get_priv(dev);
+
+	return dwc3_generic_remove(dev, priv);
+}
+
+U_BOOT_DRIVER(dwc3_generic_peripheral) = {
+	.name	= "dwc3-generic-peripheral",
+	.id	= UCLASS_USB_GADGET_GENERIC,
+	.of_to_plat = dwc3_generic_of_to_plat,
+	.probe = dwc3_generic_peripheral_probe,
+	.remove = dwc3_generic_peripheral_remove,
+	.priv_auto	= sizeof(struct dwc3_generic_priv),
+	.plat_auto	= sizeof(struct dwc3_generic_plat),
+};
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)
+static int dwc3_generic_host_probe(struct udevice *dev)
+{
+	struct xhci_hcor *hcor;
+	struct xhci_hccr *hccr;
+	struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
+	int rc;
+
+	rc = dwc3_generic_probe(dev, &priv->gen_priv);
+	if (rc)
+		return rc;
+
+	hccr = (struct xhci_hccr *)priv->gen_priv.base;
+	hcor = (struct xhci_hcor *)(priv->gen_priv.base +
+			HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
+
+	return xhci_register(dev, hccr, hcor);
+}
+
+static int dwc3_generic_host_remove(struct udevice *dev)
+{
+	struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
+	int rc;
+
+	rc = xhci_deregister(dev);
+	if (rc)
+		return rc;
+
+	return dwc3_generic_remove(dev, &priv->gen_priv);
+}
+
+U_BOOT_DRIVER(dwc3_generic_host) = {
+	.name	= "dwc3-generic-host",
+	.id	= UCLASS_USB,
+	.of_to_plat = dwc3_generic_of_to_plat,
+	.probe = dwc3_generic_host_probe,
+	.remove = dwc3_generic_host_remove,
+	.priv_auto	= sizeof(struct dwc3_generic_host_priv),
+	.plat_auto	= sizeof(struct dwc3_generic_plat),
+	.ops = &xhci_usb_ops,
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
+
+struct dwc3_glue_ops {
+	void (*select_dr_mode)(struct udevice *dev, int index,
+			       enum usb_dr_mode mode);
+};
+
+void dwc3_ti_select_dr_mode(struct udevice *dev, int index,
+			    enum usb_dr_mode mode)
+{
+#define USBOTGSS_UTMI_OTG_STATUS		0x0084
+#define USBOTGSS_UTMI_OTG_OFFSET		0x0480
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE	BIT(31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT	BIT(9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG		BIT(4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND	BIT(3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID	BIT(2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	BIT(1)
+enum dwc3_omap_utmi_mode {
+	DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
+	DWC3_OMAP_UTMI_MODE_HW,
+	DWC3_OMAP_UTMI_MODE_SW,
+};
+
+	u32 use_id_pin;
+	u32 host_mode;
+	u32 reg;
+	u32 utmi_mode;
+	u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS;
+
+	struct dwc3_glue_data *glue = dev_get_plat(dev);
+	void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE);
+
+	if (device_is_compatible(dev, "ti,am437x-dwc3"))
+		utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET;
+
+	utmi_mode = dev_read_u32_default(dev, "utmi-mode",
+					 DWC3_OMAP_UTMI_MODE_UNKNOWN);
+	if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) {
+		debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
+		      dev->name);
+		mode = USB_DR_MODE_PERIPHERAL;
+	}
+
+	switch (mode)  {
+	case USB_DR_MODE_PERIPHERAL:
+		use_id_pin = 0;
+		host_mode = 0;
+		break;
+	case USB_DR_MODE_HOST:
+		use_id_pin = 0;
+		host_mode = 1;
+		break;
+	case USB_DR_MODE_OTG:
+	default:
+		use_id_pin = 1;
+		host_mode = 0;
+		break;
+	}
+
+	reg = readl(base + utmi_status_offset);
+
+	reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE);
+	if (!use_id_pin)
+		reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+
+	writel(reg, base + utmi_status_offset);
+
+	reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND |
+		USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
+		USBOTGSS_UTMI_OTG_STATUS_IDDIG);
+
+	reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID |
+		USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
+
+	if (!host_mode)
+		reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG |
+			USBOTGSS_UTMI_OTG_STATUS_VBUSVALID;
+
+	writel(reg, base + utmi_status_offset);
+
+	unmap_physmem(base, MAP_NOCACHE);
+}
+
+struct dwc3_glue_ops ti_ops = {
+	.select_dr_mode = dwc3_ti_select_dr_mode,
+};
+
+static int dwc3_glue_bind(struct udevice *parent)
+{
+	ofnode node;
+	int ret;
+
+	ofnode_for_each_subnode(node, dev_ofnode(parent)) {
+		const char *name = ofnode_get_name(node);
+		enum usb_dr_mode dr_mode;
+		struct udevice *dev;
+		const char *driver = NULL;
+
+		debug("%s: subnode name: %s\n", __func__, name);
+
+		dr_mode = usb_get_dr_mode(node);
+
+		switch (dr_mode) {
+		case USB_DR_MODE_PERIPHERAL:
+		case USB_DR_MODE_OTG:
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+			debug("%s: dr_mode: OTG or Peripheral\n", __func__);
+			driver = "dwc3-generic-peripheral";
+#endif
+			break;
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
+		case USB_DR_MODE_HOST:
+			debug("%s: dr_mode: HOST\n", __func__);
+			driver = "dwc3-generic-host";
+			break;
+#endif
+		default:
+			debug("%s: unsupported dr_mode\n", __func__);
+			return -ENODEV;
+		};
+
+		if (!driver)
+			continue;
+
+		ret = device_bind_driver_to_node(parent, driver, name,
+						 node, &dev);
+		if (ret) {
+			debug("%s: not able to bind usb device mode\n",
+			      __func__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int dwc3_glue_reset_init(struct udevice *dev,
+				struct dwc3_glue_data *glue)
+{
+	int ret;
+
+	ret = reset_get_bulk(dev, &glue->resets);
+	if (ret == -ENOTSUPP || ret == -ENOENT)
+		return 0;
+	else if (ret)
+		return ret;
+
+	ret = reset_deassert_bulk(&glue->resets);
+	if (ret) {
+		reset_release_bulk(&glue->resets);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc3_glue_clk_init(struct udevice *dev,
+			      struct dwc3_glue_data *glue)
+{
+	int ret;
+
+	ret = clk_get_bulk(dev, &glue->clks);
+	if (ret == -ENOSYS || ret == -ENOENT)
+		return 0;
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_enable_bulk(&glue->clks);
+	if (ret) {
+		clk_release_bulk(&glue->clks);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static int dwc3_glue_probe(struct udevice *dev)
+{
+	struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
+	struct dwc3_glue_data *glue = dev_get_plat(dev);
+	struct udevice *child = NULL;
+	int index = 0;
+	int ret;
+
+	glue->regs = dev_read_addr(dev);
+
+	ret = dwc3_glue_clk_init(dev, glue);
+	if (ret)
+		return ret;
+
+	ret = dwc3_glue_reset_init(dev, glue);
+	if (ret)
+		return ret;
+
+	ret = device_find_first_child(dev, &child);
+	if (ret)
+		return ret;
+
+	if (glue->resets.count == 0) {
+		ret = dwc3_glue_reset_init(child, glue);
+		if (ret)
+			return ret;
+	}
+
+	while (child) {
+		enum usb_dr_mode dr_mode;
+
+		dr_mode = usb_get_dr_mode(dev_ofnode(child));
+		device_find_next_child(&child);
+		if (ops && ops->select_dr_mode)
+			ops->select_dr_mode(dev, index, dr_mode);
+		index++;
+	}
+
+	return 0;
+}
+
+static int dwc3_glue_remove(struct udevice *dev)
+{
+	struct dwc3_glue_data *glue = dev_get_plat(dev);
+
+	reset_release_bulk(&glue->resets);
+
+	clk_release_bulk(&glue->clks);
+
+	return 0;
+}
+
+static const struct udevice_id dwc3_glue_ids[] = {
+	{ .compatible = "xlnx,zynqmp-dwc3" },
+	{ .compatible = "xlnx,versal-dwc3" },
+	{ .compatible = "ti,keystone-dwc3"},
+	{ .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
+	{ .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
+	{ .compatible = "ti,am654-dwc3" },
+	{ .compatible = "rockchip,rk3328-dwc3" },
+	{ .compatible = "rockchip,rk3399-dwc3" },
+	{ .compatible = "qcom,dwc3" },
+	{ .compatible = "intel,tangier-dwc3" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_generic_wrapper) = {
+	.name	= "dwc3-generic-wrapper",
+	.id	= UCLASS_NOP,
+	.of_match = dwc3_glue_ids,
+	.bind = dwc3_glue_bind,
+	.probe = dwc3_glue_probe,
+	.remove = dwc3_glue_remove,
+	.plat_auto	= sizeof(struct dwc3_glue_data),
+
+};
diff --git a/roms/u-boot/drivers/usb/dwc3/dwc3-meson-g12a.c b/roms/u-boot/drivers/usb/dwc3/dwc3-meson-g12a.c
new file mode 100644
index 000000000..90418ddc1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Amlogic G12A DWC3 Glue layer
+ *
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm-generic/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dwc3-uboot.h>
+#include <generic-phy.h>
+#include <linux/delay.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <regmap.h>
+#include <usb.h>
+#include "core.h"
+#include "gadget.h"
+#include <reset.h>
+#include <clk.h>
+#include <power/regulator.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+
+/* USB2 Ports Control Registers */
+
+#define U2P_REG_SIZE						0x20
+
+#define U2P_R0							0x0
+	#define U2P_R0_HOST_DEVICE				BIT(0)
+	#define U2P_R0_POWER_OK					BIT(1)
+	#define U2P_R0_HAST_MODE				BIT(2)
+	#define U2P_R0_POWER_ON_RESET				BIT(3)
+	#define U2P_R0_ID_PULLUP				BIT(4)
+	#define U2P_R0_DRV_VBUS					BIT(5)
+
+#define U2P_R1							0x4
+	#define U2P_R1_PHY_READY				BIT(0)
+	#define U2P_R1_ID_DIG					BIT(1)
+	#define U2P_R1_OTG_SESSION_VALID			BIT(2)
+	#define U2P_R1_VBUS_VALID				BIT(3)
+
+/* USB Glue Control Registers */
+
+#define USB_R0							0x80
+	#define USB_R0_P30_LANE0_TX2RX_LOOPBACK			BIT(17)
+	#define USB_R0_P30_LANE0_EXT_PCLK_REQ			BIT(18)
+	#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK		GENMASK(28, 19)
+	#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK		GENMASK(30, 29)
+	#define USB_R0_U2D_ACT					BIT(31)
+
+#define USB_R1							0x84
+	#define USB_R1_U3H_BIGENDIAN_GS				BIT(0)
+	#define USB_R1_U3H_PME_ENABLE				BIT(1)
+	#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK		GENMASK(4, 2)
+	#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK		GENMASK(9, 7)
+	#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK		GENMASK(13, 12)
+	#define USB_R1_U3H_HOST_U3_PORT_DISABLE			BIT(16)
+	#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT	BIT(17)
+	#define USB_R1_U3H_HOST_MSI_ENABLE			BIT(18)
+	#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK			GENMASK(24, 19)
+	#define USB_R1_P30_PCS_TX_SWING_FULL_MASK		GENMASK(31, 25)
+
+#define USB_R2							0x88
+	#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK		GENMASK(25, 20)
+	#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK		GENMASK(31, 26)
+
+#define USB_R3							0x8c
+	#define USB_R3_P30_SSC_ENABLE				BIT(0)
+	#define USB_R3_P30_SSC_RANGE_MASK			GENMASK(3, 1)
+	#define USB_R3_P30_SSC_REF_CLK_SEL_MASK			GENMASK(12, 4)
+	#define USB_R3_P30_REF_SSP_EN				BIT(13)
+
+#define USB_R4							0x90
+	#define USB_R4_P21_PORT_RESET_0				BIT(0)
+	#define USB_R4_P21_SLEEP_M0				BIT(1)
+	#define USB_R4_MEM_PD_MASK				GENMASK(3, 2)
+	#define USB_R4_P21_ONLY					BIT(4)
+
+#define USB_R5							0x94
+	#define USB_R5_ID_DIG_SYNC				BIT(0)
+	#define USB_R5_ID_DIG_REG				BIT(1)
+	#define USB_R5_ID_DIG_CFG_MASK				GENMASK(3, 2)
+	#define USB_R5_ID_DIG_EN_0				BIT(4)
+	#define USB_R5_ID_DIG_EN_1				BIT(5)
+	#define USB_R5_ID_DIG_CURR				BIT(6)
+	#define USB_R5_ID_DIG_IRQ				BIT(7)
+	#define USB_R5_ID_DIG_TH_MASK				GENMASK(15, 8)
+	#define USB_R5_ID_DIG_CNT_MASK				GENMASK(23, 16)
+
+enum {
+	USB2_HOST_PHY = 0,
+	USB2_OTG_PHY,
+	USB3_HOST_PHY,
+	PHY_COUNT,
+};
+
+static const char *phy_names[PHY_COUNT] = {
+	"usb2-phy0", "usb2-phy1", "usb3-phy0",
+};
+
+struct dwc3_meson_g12a {
+	struct udevice		*dev;
+	struct regmap           *regmap;
+	struct clk		clk;
+	struct reset_ctl	reset;
+	struct phy		phys[PHY_COUNT];
+	enum usb_dr_mode	otg_mode;
+	enum usb_dr_mode	otg_phy_mode;
+	unsigned int		usb2_ports;
+	unsigned int		usb3_ports;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	struct udevice		*vbus_supply;
+#endif
+};
+
+#define U2P_REG_SIZE						0x20
+#define USB_REG_OFFSET						0x80
+
+static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
+					  int i, enum usb_dr_mode mode)
+{
+	switch (mode) {
+	case USB_DR_MODE_HOST:
+	case USB_DR_MODE_OTG:
+	case USB_DR_MODE_UNKNOWN:
+		regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+				U2P_R0_HOST_DEVICE,
+				U2P_R0_HOST_DEVICE);
+		break;
+
+	case USB_DR_MODE_PERIPHERAL:
+		regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+				U2P_R0_HOST_DEVICE, 0);
+		break;
+	}
+}
+
+static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
+{
+	int i;
+
+	if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
+		priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
+	else
+		priv->otg_phy_mode = USB_DR_MODE_HOST;
+
+	for (i = 0 ; i < USB3_HOST_PHY ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+				   U2P_R0_POWER_ON_RESET,
+				   U2P_R0_POWER_ON_RESET);
+
+		if (i == USB2_OTG_PHY) {
+			regmap_update_bits(priv->regmap,
+					   U2P_R0 + (U2P_REG_SIZE * i),
+					   U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
+					   U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
+
+			dwc3_meson_g12a_usb2_set_mode(priv, i,
+						      priv->otg_phy_mode);
+		} else
+			dwc3_meson_g12a_usb2_set_mode(priv, i,
+						      USB_DR_MODE_HOST);
+
+		regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+				   U2P_R0_POWER_ON_RESET, 0);
+	}
+
+	return 0;
+}
+
+static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
+{
+	regmap_update_bits(priv->regmap, USB_R3,
+			USB_R3_P30_SSC_RANGE_MASK |
+			USB_R3_P30_REF_SSP_EN,
+			USB_R3_P30_SSC_ENABLE |
+			FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
+			USB_R3_P30_REF_SSP_EN);
+	udelay(2);
+
+	regmap_update_bits(priv->regmap, USB_R2,
+			USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
+			FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
+
+	regmap_update_bits(priv->regmap, USB_R2,
+			USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
+			FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
+
+	udelay(2);
+
+	regmap_update_bits(priv->regmap, USB_R1,
+			USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
+			USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
+
+	regmap_update_bits(priv->regmap, USB_R1,
+			USB_R1_P30_PCS_TX_SWING_FULL_MASK,
+			FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
+}
+
+static void dwc3_meson_g12a_usb_init_mode(struct dwc3_meson_g12a *priv)
+{
+	if (priv->otg_phy_mode == USB_DR_MODE_PERIPHERAL) {
+		regmap_update_bits(priv->regmap, USB_R0,
+				USB_R0_U2D_ACT, USB_R0_U2D_ACT);
+		regmap_update_bits(priv->regmap, USB_R0,
+				USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
+		regmap_update_bits(priv->regmap, USB_R4,
+				USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
+	} else {
+		regmap_update_bits(priv->regmap, USB_R0,
+				USB_R0_U2D_ACT, 0);
+		regmap_update_bits(priv->regmap, USB_R4,
+				USB_R4_P21_SLEEP_M0, 0);
+	}
+}
+
+static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
+{
+	int ret;
+
+	ret = dwc3_meson_g12a_usb2_init(priv);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(priv->regmap, USB_R1,
+			USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
+			FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
+
+	regmap_update_bits(priv->regmap, USB_R5,
+			USB_R5_ID_DIG_EN_0,
+			USB_R5_ID_DIG_EN_0);
+	regmap_update_bits(priv->regmap, USB_R5,
+			USB_R5_ID_DIG_EN_1,
+			USB_R5_ID_DIG_EN_1);
+	regmap_update_bits(priv->regmap, USB_R5,
+			USB_R5_ID_DIG_TH_MASK,
+			FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
+
+	/* If we have an actual SuperSpeed port, initialize it */
+	if (priv->usb3_ports)
+		dwc3_meson_g12a_usb3_init(priv);
+
+	dwc3_meson_g12a_usb_init_mode(priv);
+
+	return 0;
+}
+
+int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
+{
+	struct dwc3_meson_g12a *priv = dev_get_plat(dev);
+
+	if (!priv)
+		return -EINVAL;
+
+	if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
+		return -EINVAL;
+
+	if (!priv->phys[USB2_OTG_PHY].dev)
+		return -EINVAL;
+
+	if (mode == USB_DR_MODE_HOST)
+		debug("%s: switching to Host Mode\n", __func__);
+	else
+		debug("%s: switching to Device Mode\n", __func__);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	if (priv->vbus_supply) {
+		int ret = regulator_set_enable(priv->vbus_supply,
+					(mode == USB_DR_MODE_PERIPHERAL));
+		if (ret)
+			return ret;
+	}
+#endif
+	priv->otg_phy_mode = mode;
+
+	dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode);
+
+	dwc3_meson_g12a_usb_init_mode(priv);
+
+	return 0;
+}
+
+static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
+{
+	int i, ret;
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		ret = generic_phy_get_by_name(priv->dev, phy_names[i],
+					      &priv->phys[i]);
+		if (ret == -ENOENT || ret == -ENODATA)
+			continue;
+
+		if (ret)
+			return ret;
+
+		if (i == USB3_HOST_PHY)
+			priv->usb3_ports++;
+		else
+			priv->usb2_ports++;
+	}
+
+	debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
+	debug("%s: usb3 ports: %d\n", __func__, priv->usb3_ports);
+
+	return 0;
+}
+
+static int dwc3_meson_g12a_reset_init(struct dwc3_meson_g12a *priv)
+{
+	int ret;
+
+	ret = reset_get_by_index(priv->dev, 0, &priv->reset);
+	if (ret)
+		return ret;
+
+	ret = reset_assert(&priv->reset);
+	udelay(1);
+	ret |= reset_deassert(&priv->reset);
+	if (ret) {
+		reset_free(&priv->reset);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv)
+{
+	int ret;
+
+	ret = clk_get_by_index(priv->dev, 0, &priv->clk);
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_enable(&priv->clk);
+	if (ret) {
+		clk_free(&priv->clk);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static int dwc3_meson_g12a_probe(struct udevice *dev)
+{
+	struct dwc3_meson_g12a *priv = dev_get_plat(dev);
+	int ret, i;
+
+	priv->dev = dev;
+
+	ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_g12a_clk_init(priv);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_g12a_reset_init(priv);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_g12a_get_phys(priv);
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &priv->vbus_supply);
+	if (ret && ret != -ENOENT) {
+		pr_err("Failed to get PHY regulator\n");
+		return ret;
+	}
+
+	if (priv->vbus_supply) {
+		ret = regulator_set_enable(priv->vbus_supply, true);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	priv->otg_mode = usb_get_dr_mode(dev_ofnode(dev));
+
+	ret = dwc3_meson_g12a_usb_init(priv);
+	if (ret)
+		return ret;
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		ret = generic_phy_init(&priv->phys[i]);
+		if (ret)
+			goto err_phy_init;
+	}
+
+	for (i = 0; i < PHY_COUNT; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		ret = generic_phy_power_on(&priv->phys[i]);
+		if (ret)
+			goto err_phy_init;
+	}
+
+	return 0;
+
+err_phy_init:
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		 generic_phy_exit(&priv->phys[i]);
+	}
+
+	return ret;
+}
+
+static int dwc3_meson_g12a_remove(struct udevice *dev)
+{
+	struct dwc3_meson_g12a *priv = dev_get_plat(dev);
+	int i;
+
+	reset_release_all(&priv->reset, 1);
+
+	clk_release_all(&priv->clk, 1);
+
+	for (i = 0; i < PHY_COUNT; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		 generic_phy_power_off(&priv->phys[i]);
+	}
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		 generic_phy_exit(&priv->phys[i]);
+	}
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id dwc3_meson_g12a_ids[] = {
+	{ .compatible = "amlogic,meson-g12a-usb-ctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_generic_wrapper) = {
+	.name	= "dwc3-meson-g12a",
+	.id	= UCLASS_SIMPLE_BUS,
+	.of_match = dwc3_meson_g12a_ids,
+	.probe = dwc3_meson_g12a_probe,
+	.remove = dwc3_meson_g12a_remove,
+	.plat_auto	= sizeof(struct dwc3_meson_g12a),
+
+};
diff --git a/roms/u-boot/drivers/usb/dwc3/dwc3-meson-gxl.c b/roms/u-boot/drivers/usb/dwc3/dwc3-meson-gxl.c
new file mode 100644
index 000000000..08467d621
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/dwc3-meson-gxl.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Amlogic GXL DWC3 Glue layer
+ *
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#define DEBUG
+#include <common.h>
+#include <asm-generic/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dwc3-uboot.h>
+#include <generic-phy.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <regmap.h>
+#include <usb.h>
+#include "core.h"
+#include "gadget.h"
+#include <reset.h>
+#include <clk.h>
+#include <power/regulator.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <asm/arch/usb-gx.h>
+
+/* USB Glue Control Registers */
+
+#define USB_R0							0x00
+	#define USB_R0_P30_FSEL_MASK				GENMASK(5, 0)
+	#define USB_R0_P30_PHY_RESET				BIT(6)
+	#define USB_R0_P30_TEST_POWERDOWN_HSP			BIT(7)
+	#define USB_R0_P30_TEST_POWERDOWN_SSP			BIT(8)
+	#define USB_R0_P30_ACJT_LEVEL_MASK			GENMASK(13, 9)
+	#define USB_R0_P30_TX_BOOST_LEVEL_MASK			GENMASK(16, 14)
+	#define USB_R0_P30_LANE0_TX2RX_LOOPBACK			BIT(17)
+	#define USB_R0_P30_LANE0_EXT_PCLK_REQ			BIT(18)
+	#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK		GENMASK(28, 19)
+	#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK		GENMASK(30, 29)
+	#define USB_R0_U2D_ACT					BIT(31)
+
+#define USB_R1							0x04
+	#define USB_R1_U3H_BIGENDIAN_GS				BIT(0)
+	#define USB_R1_U3H_PME_ENABLE				BIT(1)
+	#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK		GENMASK(6, 2)
+	#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK		GENMASK(11, 7)
+	#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK		GENMASK(15, 12)
+	#define USB_R1_U3H_HOST_U3_PORT_DISABLE			BIT(16)
+	#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT	BIT(17)
+	#define USB_R1_U3H_HOST_MSI_ENABLE			BIT(18)
+	#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK			GENMASK(24, 19)
+	#define USB_R1_P30_PCS_TX_SWING_FULL_MASK		GENMASK(31, 25)
+
+#define USB_R2							0x08
+	#define USB_R2_P30_CR_DATA_IN_MASK			GENMASK(15, 0)
+	#define USB_R2_P30_CR_READ				BIT(16)
+	#define USB_R2_P30_CR_WRITE				BIT(17)
+	#define USB_R2_P30_CR_CAP_ADDR				BIT(18)
+	#define USB_R2_P30_CR_CAP_DATA				BIT(19)
+	#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK		GENMASK(25, 20)
+	#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK		GENMASK(31, 26)
+
+#define USB_R3							0x0c
+	#define USB_R3_P30_SSC_ENABLE				BIT(0)
+	#define USB_R3_P30_SSC_RANGE_MASK			GENMASK(3, 1)
+	#define USB_R3_P30_SSC_REF_CLK_SEL_MASK			GENMASK(12, 4)
+	#define USB_R3_P30_REF_SSP_EN				BIT(13)
+	#define USB_R3_P30_LOS_BIAS_MASK			GENMASK(18, 16)
+	#define USB_R3_P30_LOS_LEVEL_MASK			GENMASK(23, 19)
+	#define USB_R3_P30_MPLL_MULTIPLIER_MASK			GENMASK(30, 24)
+
+#define USB_R4							0x10
+	#define USB_R4_P21_PORT_RESET_0				BIT(0)
+	#define USB_R4_P21_SLEEP_M0				BIT(1)
+	#define USB_R4_MEM_PD_MASK				GENMASK(3, 2)
+	#define USB_R4_P21_ONLY					BIT(4)
+
+#define USB_R5							0x14
+	#define USB_R5_ID_DIG_SYNC				BIT(0)
+	#define USB_R5_ID_DIG_REG				BIT(1)
+	#define USB_R5_ID_DIG_CFG_MASK				GENMASK(3, 2)
+	#define USB_R5_ID_DIG_EN_0				BIT(4)
+	#define USB_R5_ID_DIG_EN_1				BIT(5)
+	#define USB_R5_ID_DIG_CURR				BIT(6)
+	#define USB_R5_ID_DIG_IRQ				BIT(7)
+	#define USB_R5_ID_DIG_TH_MASK				GENMASK(15, 8)
+	#define USB_R5_ID_DIG_CNT_MASK				GENMASK(23, 16)
+
+/* read-only register */
+#define USB_R6							0x18
+	#define USB_R6_P30_CR_DATA_OUT_MASK			GENMASK(15, 0)
+	#define USB_R6_P30_CR_ACK				BIT(16)
+
+enum {
+	USB2_HOST_PHY0 = 0,
+	USB2_OTG_PHY1,
+	USB2_HOST_PHY2,
+	PHY_COUNT,
+};
+
+static const char *phy_names[PHY_COUNT] = {
+	"usb2-phy0", "usb2-phy1", "usb2-phy2",
+};
+
+struct dwc3_meson_gxl {
+	struct udevice		*dev;
+	struct regmap           *regmap;
+	struct clk		clk;
+	struct reset_ctl	reset;
+	struct phy		phys[PHY_COUNT];
+	enum usb_dr_mode	otg_mode;
+	enum usb_dr_mode	otg_phy_mode;
+	unsigned int		usb2_ports;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	struct udevice		*vbus_supply;
+#endif
+};
+
+#define U2P_REG_SIZE						0x20
+#define USB_REG_OFFSET						0x80
+
+#define USB2_OTG_PHY						USB2_OTG_PHY1
+
+static void dwc3_meson_gxl_usb2_set_mode(struct dwc3_meson_gxl *priv, enum usb_dr_mode mode)
+{
+	switch (mode) {
+	case USB_DR_MODE_HOST:
+	case USB_DR_MODE_OTG:
+	case USB_DR_MODE_UNKNOWN:
+		regmap_update_bits(priv->regmap, USB_R1,
+				   USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 0);
+		regmap_update_bits(priv->regmap, USB_R0,
+				   USB_R0_U2D_ACT, 0);
+		regmap_update_bits(priv->regmap, USB_R4,
+				   USB_R4_P21_SLEEP_M0, 0);
+		break;
+
+	case USB_DR_MODE_PERIPHERAL:
+		regmap_update_bits(priv->regmap, USB_R0,
+				   USB_R0_U2D_ACT, USB_R0_U2D_ACT);
+		regmap_update_bits(priv->regmap, USB_R0,
+				   USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
+		regmap_update_bits(priv->regmap, USB_R4,
+				   USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
+		break;
+	}
+}
+
+static int dwc3_meson_gxl_usb2_init(struct dwc3_meson_gxl *priv)
+{
+	int i;
+
+	for (i = 0; i < PHY_COUNT; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		phy_meson_gxl_usb2_set_mode(&priv->phys[i],
+				(i == USB2_OTG_PHY) ? USB_DR_MODE_PERIPHERAL
+						    : USB_DR_MODE_HOST);
+	}
+
+	return 0;
+}
+
+static int dwc3_meson_gxl_usb_init(struct dwc3_meson_gxl *priv)
+{
+	int ret;
+	
+	ret = dwc3_meson_gxl_usb2_init(priv);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(priv->regmap, USB_R1,
+			   USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
+			   FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
+
+	regmap_update_bits(priv->regmap, USB_R5,
+			   USB_R5_ID_DIG_EN_0,
+			   USB_R5_ID_DIG_EN_0);
+	regmap_update_bits(priv->regmap, USB_R5,
+			   USB_R5_ID_DIG_EN_1,
+			   USB_R5_ID_DIG_EN_1);
+	regmap_update_bits(priv->regmap, USB_R5,
+			   USB_R5_ID_DIG_TH_MASK,
+			   FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
+
+	dwc3_meson_gxl_usb2_set_mode(priv, priv->otg_phy_mode);
+
+	return 0;
+}
+
+int dwc3_meson_gxl_force_mode(struct udevice *dev, enum usb_dr_mode mode)
+{
+	struct dwc3_meson_gxl *priv = dev_get_plat(dev);
+
+	if (!priv)
+		return -EINVAL;
+
+	if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
+		return -EINVAL;
+
+	if (!priv->phys[USB2_OTG_PHY].dev)
+		return -EINVAL;
+
+	if (mode == priv->otg_phy_mode)
+		return 0;
+
+	if (mode == USB_DR_MODE_HOST)
+		debug("%s: switching to Host Mode\n", __func__);
+	else
+		debug("%s: switching to Device Mode\n", __func__);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	if (priv->vbus_supply) {
+		int ret = regulator_set_enable(priv->vbus_supply,
+					(mode == USB_DR_MODE_PERIPHERAL));
+		if (ret)
+			return ret;
+	}
+#endif
+	priv->otg_phy_mode = mode;
+
+	phy_meson_gxl_usb2_set_mode(&priv->phys[USB2_OTG_PHY], mode);
+
+	dwc3_meson_gxl_usb2_set_mode(priv, mode);
+
+	return 0;
+}
+
+static int dwc3_meson_gxl_get_phys(struct dwc3_meson_gxl *priv)
+{
+	int i, ret;
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		ret = generic_phy_get_by_name(priv->dev, phy_names[i],
+					      &priv->phys[i]);
+		if (ret == -ENOENT || ret == -ENODATA) {
+			priv->phys[i].dev = NULL;
+			continue;
+		}
+
+		if (ret)
+			return ret;
+
+		priv->usb2_ports++;
+	}
+
+	debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
+
+	return 0;
+}
+
+static int dwc3_meson_gxl_reset_init(struct dwc3_meson_gxl *priv)
+{
+	int ret;
+
+	ret = reset_get_by_index(priv->dev, 0, &priv->reset);
+	if (ret)
+		return ret;
+
+	ret = reset_assert(&priv->reset);
+	udelay(1);
+	ret |= reset_deassert(&priv->reset);
+	if (ret) {
+		reset_free(&priv->reset);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc3_meson_gxl_clk_init(struct dwc3_meson_gxl *priv)
+{
+	int ret;
+
+	ret = clk_get_by_index(priv->dev, 0, &priv->clk);
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_enable(&priv->clk);
+	if (ret) {
+		clk_free(&priv->clk);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static int dwc3_meson_gxl_probe(struct udevice *dev)
+{
+	struct dwc3_meson_gxl *priv = dev_get_plat(dev);
+	int ret, i;
+
+	priv->dev = dev;
+
+	ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_gxl_clk_init(priv);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_gxl_reset_init(priv);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_gxl_get_phys(priv);
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &priv->vbus_supply);
+	if (ret && ret != -ENOENT) {
+		pr_err("Failed to get PHY regulator\n");
+		return ret;
+	}
+
+	if (priv->vbus_supply) {
+		ret = regulator_set_enable(priv->vbus_supply, true);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	/* On GXL PHY must be started in device mode for DWC2 init */
+	priv->otg_mode = USB_DR_MODE_PERIPHERAL;
+
+	ret = dwc3_meson_gxl_usb_init(priv);
+	if (ret)
+		return ret;
+
+	priv->otg_mode = usb_get_dr_mode(dev_ofnode(dev));
+
+	if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
+		priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
+	else
+		priv->otg_phy_mode = USB_DR_MODE_HOST;
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		ret = generic_phy_init(&priv->phys[i]);
+		if (ret)
+			goto err_phy_init;
+	}
+
+	for (i = 0; i < PHY_COUNT; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		ret = generic_phy_power_on(&priv->phys[i]);
+		if (ret)
+			goto err_phy_init;
+	}
+
+	if (priv->phys[USB2_OTG_PHY].dev)
+		phy_meson_gxl_usb2_set_mode(&priv->phys[USB2_OTG_PHY],
+					    priv->otg_phy_mode);
+
+	dwc3_meson_gxl_usb2_set_mode(priv, priv->otg_phy_mode);
+
+	return 0;
+
+err_phy_init:
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		 generic_phy_exit(&priv->phys[i]);
+	}
+
+	return ret;
+}
+
+static int dwc3_meson_gxl_remove(struct udevice *dev)
+{
+	struct dwc3_meson_gxl *priv = dev_get_plat(dev);
+	int i;
+
+	reset_release_all(&priv->reset, 1);
+
+	clk_release_all(&priv->clk, 1);
+
+	for (i = 0; i < PHY_COUNT; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		 generic_phy_power_off(&priv->phys[i]);
+	}
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		if (!priv->phys[i].dev)
+			continue;
+
+		 generic_phy_exit(&priv->phys[i]);
+	}
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id dwc3_meson_gxl_ids[] = {
+	{ .compatible = "amlogic,meson-gxl-usb-ctrl" },
+	{ .compatible = "amlogic,meson-gxm-usb-ctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_generic_wrapper) = {
+	.name	= "dwc3-meson-gxl",
+	.id	= UCLASS_SIMPLE_BUS,
+	.of_match = dwc3_meson_gxl_ids,
+	.probe = dwc3_meson_gxl_probe,
+	.remove = dwc3_meson_gxl_remove,
+	.plat_auto	= sizeof(struct dwc3_meson_gxl),
+
+};
diff --git a/roms/u-boot/drivers/usb/dwc3/dwc3-omap.c b/roms/u-boot/drivers/usb/dwc3/dwc3-omap.c
new file mode 100644
index 000000000..9596bf144
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/dwc3-omap.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/dwc3-omap.c) and ported
+ * to uboot.
+ *
+ * commit 7ee2566ff5 : usb: dwc3: dwc3-omap: get rid of ->prepare()/->complete()
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dwc3-omap-uboot.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/usb/dwc3-omap.h>
+#include <linux/ioport.h>
+
+#include <linux/usb/otg.h>
+#include <linux/compat.h>
+
+#include "linux-compat.h"
+
+/*
+ * All these registers belong to OMAP's Wrapper around the
+ * DesignWare USB3 Core.
+ */
+
+#define USBOTGSS_REVISION			0x0000
+#define USBOTGSS_SYSCONFIG			0x0010
+#define USBOTGSS_IRQ_EOI			0x0020
+#define USBOTGSS_EOI_OFFSET			0x0008
+#define USBOTGSS_IRQSTATUS_RAW_0		0x0024
+#define USBOTGSS_IRQSTATUS_0			0x0028
+#define USBOTGSS_IRQENABLE_SET_0		0x002c
+#define USBOTGSS_IRQENABLE_CLR_0		0x0030
+#define USBOTGSS_IRQ0_OFFSET			0x0004
+#define USBOTGSS_IRQSTATUS_RAW_1		0x0030
+#define USBOTGSS_IRQSTATUS_1			0x0034
+#define USBOTGSS_IRQENABLE_SET_1		0x0038
+#define USBOTGSS_IRQENABLE_CLR_1		0x003c
+#define USBOTGSS_IRQSTATUS_RAW_2		0x0040
+#define USBOTGSS_IRQSTATUS_2			0x0044
+#define USBOTGSS_IRQENABLE_SET_2		0x0048
+#define USBOTGSS_IRQENABLE_CLR_2		0x004c
+#define USBOTGSS_IRQSTATUS_RAW_3		0x0050
+#define USBOTGSS_IRQSTATUS_3			0x0054
+#define USBOTGSS_IRQENABLE_SET_3		0x0058
+#define USBOTGSS_IRQENABLE_CLR_3		0x005c
+#define USBOTGSS_IRQSTATUS_EOI_MISC		0x0030
+#define USBOTGSS_IRQSTATUS_RAW_MISC		0x0034
+#define USBOTGSS_IRQSTATUS_MISC			0x0038
+#define USBOTGSS_IRQENABLE_SET_MISC		0x003c
+#define USBOTGSS_IRQENABLE_CLR_MISC		0x0040
+#define USBOTGSS_IRQMISC_OFFSET			0x03fc
+#define USBOTGSS_UTMI_OTG_CTRL			0x0080
+#define USBOTGSS_UTMI_OTG_STATUS		0x0084
+#define USBOTGSS_UTMI_OTG_OFFSET		0x0480
+#define USBOTGSS_TXFIFO_DEPTH			0x0508
+#define USBOTGSS_RXFIFO_DEPTH			0x050c
+#define USBOTGSS_MMRAM_OFFSET			0x0100
+#define USBOTGSS_FLADJ				0x0104
+#define USBOTGSS_DEBUG_CFG			0x0108
+#define USBOTGSS_DEBUG_DATA			0x010c
+#define USBOTGSS_DEV_EBC_EN			0x0110
+#define USBOTGSS_DEBUG_OFFSET			0x0600
+
+/* SYSCONFIG REGISTER */
+#define USBOTGSS_SYSCONFIG_DMADISABLE		(1 << 16)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER		(1 << 0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST		(1 << 0)
+
+/* IRQMISC BITS */
+#define USBOTGSS_IRQMISC_DMADISABLECLR		(1 << 17)
+#define USBOTGSS_IRQMISC_OEVT			(1 << 16)
+#define USBOTGSS_IRQMISC_DRVVBUS_RISE		(1 << 13)
+#define USBOTGSS_IRQMISC_CHRGVBUS_RISE		(1 << 12)
+#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE	(1 << 11)
+#define USBOTGSS_IRQMISC_IDPULLUP_RISE		(1 << 8)
+#define USBOTGSS_IRQMISC_DRVVBUS_FALL		(1 << 5)
+#define USBOTGSS_IRQMISC_CHRGVBUS_FALL		(1 << 4)
+#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL		(1 << 3)
+#define USBOTGSS_IRQMISC_IDPULLUP_FALL		(1 << 0)
+
+#define USBOTGSS_INTERRUPTS (USBOTGSS_IRQMISC_OEVT | \
+			     USBOTGSS_IRQMISC_DRVVBUS_RISE | \
+			     USBOTGSS_IRQMISC_CHRGVBUS_RISE | \
+			     USBOTGSS_IRQMISC_DISCHRGVBUS_RISE | \
+			     USBOTGSS_IRQMISC_IDPULLUP_RISE | \
+			     USBOTGSS_IRQMISC_DRVVBUS_FALL | \
+			     USBOTGSS_IRQMISC_CHRGVBUS_FALL | \
+			     USBOTGSS_IRQMISC_DISCHRGVBUS_FALL | \
+			     USBOTGSS_IRQMISC_IDPULLUP_FALL)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS		(1 << 5)
+#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS		(1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS	(1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP		(1 << 0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE	(1 << 31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT	(1 << 9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG		(1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND	(1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID	(1 << 2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	(1 << 1)
+
+struct dwc3_omap {
+	struct device		*dev;
+
+	void __iomem		*base;
+
+	u32			utmi_otg_status;
+	u32			utmi_otg_offset;
+	u32			irqmisc_offset;
+	u32			irq_eoi_offset;
+	u32			debug_offset;
+	u32			irq0_offset;
+
+	u32			dma_status:1;
+	struct list_head	list;
+	u32			index;
+};
+
+static LIST_HEAD(dwc3_omap_list);
+
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+static u32 dwc3_omap_read_utmi_status(struct dwc3_omap *omap)
+{
+	return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS +
+							omap->utmi_otg_offset);
+}
+
+static void dwc3_omap_write_utmi_status(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS +
+					omap->utmi_otg_offset, value);
+
+}
+
+static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap)
+{
+	return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0 -
+						omap->irq0_offset);
+}
+
+static void dwc3_omap_write_irq0_status(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0 -
+						omap->irq0_offset, value);
+
+}
+
+static u32 dwc3_omap_read_irqmisc_status(struct dwc3_omap *omap)
+{
+	return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_MISC +
+						omap->irqmisc_offset);
+}
+
+static void dwc3_omap_write_irqmisc_status(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_MISC +
+					omap->irqmisc_offset, value);
+
+}
+
+static void dwc3_omap_write_irqmisc_set(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_MISC +
+						omap->irqmisc_offset, value);
+
+}
+
+static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0 -
+						omap->irq0_offset, value);
+}
+
+static void dwc3_omap_write_irqmisc_clr(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_MISC +
+						omap->irqmisc_offset, value);
+}
+
+static void dwc3_omap_write_irq0_clr(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_0 -
+						omap->irq0_offset, value);
+}
+
+static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
+	enum omap_dwc3_vbus_id_status status)
+{
+	u32	val;
+
+	switch (status) {
+	case OMAP_DWC3_ID_GROUND:
+		dev_dbg(omap->dev, "ID GND\n");
+
+		val = dwc3_omap_read_utmi_status(omap);
+		val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
+				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_SESSEND);
+		val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
+		dwc3_omap_write_utmi_status(omap, val);
+		break;
+
+	case OMAP_DWC3_VBUS_VALID:
+		dev_dbg(omap->dev, "VBUS Connect\n");
+
+		val = dwc3_omap_read_utmi_status(omap);
+		val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND;
+		val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG
+				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_SESSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
+		dwc3_omap_write_utmi_status(omap, val);
+		break;
+
+	case OMAP_DWC3_ID_FLOAT:
+	case OMAP_DWC3_VBUS_OFF:
+		dev_dbg(omap->dev, "VBUS Disconnect\n");
+
+		val = dwc3_omap_read_utmi_status(omap);
+		val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT);
+		val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND
+				| USBOTGSS_UTMI_OTG_STATUS_IDDIG;
+		dwc3_omap_write_utmi_status(omap, val);
+		break;
+
+	default:
+		dev_dbg(omap->dev, "invalid state\n");
+	}
+}
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+	struct dwc3_omap	*omap = _omap;
+	u32			reg;
+
+	reg = dwc3_omap_read_irqmisc_status(omap);
+
+	if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) {
+		dev_dbg(omap->dev, "DMA Disable was Cleared\n");
+		omap->dma_status = false;
+	}
+
+	if (reg & USBOTGSS_IRQMISC_OEVT)
+		dev_dbg(omap->dev, "OTG Event\n");
+
+	if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE)
+		dev_dbg(omap->dev, "DRVVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE)
+		dev_dbg(omap->dev, "CHRGVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE)
+		dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE)
+		dev_dbg(omap->dev, "IDPULLUP Rise\n");
+
+	if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL)
+		dev_dbg(omap->dev, "DRVVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL)
+		dev_dbg(omap->dev, "CHRGVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL)
+		dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL)
+		dev_dbg(omap->dev, "IDPULLUP Fall\n");
+
+	dwc3_omap_write_irqmisc_status(omap, reg);
+
+	reg = dwc3_omap_read_irq0_status(omap);
+
+	dwc3_omap_write_irq0_status(omap, reg);
+
+	return IRQ_HANDLED;
+}
+
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
+{
+	/* enable all IRQs */
+	dwc3_omap_write_irq0_set(omap, USBOTGSS_IRQO_COREIRQ_ST);
+
+	dwc3_omap_write_irqmisc_set(omap, USBOTGSS_INTERRUPTS);
+}
+
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
+{
+	/* disable all IRQs */
+	dwc3_omap_write_irq0_clr(omap, USBOTGSS_IRQO_COREIRQ_ST);
+
+	dwc3_omap_write_irqmisc_clr(omap, USBOTGSS_INTERRUPTS);
+}
+
+static void dwc3_omap_map_offset(struct dwc3_omap *omap)
+{
+	/*
+	 * Differentiate between OMAP5 and AM437x.
+	 *
+	 * For OMAP5(ES2.0) and AM437x wrapper revision is same, even
+	 * though there are changes in wrapper register offsets.
+	 *
+	 * Using dt compatible to differentiate AM437x.
+	 */
+#ifdef CONFIG_AM43XX
+	omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
+	omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
+	omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
+	omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
+	omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
+#endif
+}
+
+static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap, int utmi_mode)
+{
+	u32			reg;
+
+	reg = dwc3_omap_read_utmi_status(omap);
+
+	switch (utmi_mode) {
+	case DWC3_OMAP_UTMI_MODE_SW:
+		reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+		break;
+	case DWC3_OMAP_UTMI_MODE_HW:
+		reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+		break;
+	default:
+		dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
+	}
+
+	dwc3_omap_write_utmi_status(omap, reg);
+}
+
+/**
+ * dwc3_omap_uboot_init - dwc3 omap uboot initialization code
+ * @dev: struct dwc3_omap_device containing initialization data
+ *
+ * Entry point for dwc3 omap driver (equivalent to dwc3_omap_probe in linux
+ * kernel driver). Pointer to dwc3_omap_device should be passed containing
+ * base address and other initialization data. Returns '0' on success and
+ * a negative value on failure.
+ *
+ * Generally called from board_usb_init() implemented in board file.
+ */
+int dwc3_omap_uboot_init(struct dwc3_omap_device *omap_dev)
+{
+	u32			reg;
+	struct device		*dev = NULL;
+	struct dwc3_omap	*omap;
+
+	omap = devm_kzalloc((struct udevice *)dev, sizeof(*omap), GFP_KERNEL);
+	if (!omap)
+		return -ENOMEM;
+
+	omap->base	= omap_dev->base;
+	omap->index	= omap_dev->index;
+
+	dwc3_omap_map_offset(omap);
+	dwc3_omap_set_utmi_mode(omap, omap_dev->utmi_mode);
+
+	/* check the DMA Status */
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
+	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
+
+	dwc3_omap_set_mailbox(omap, omap_dev->vbus_id_status);
+
+	dwc3_omap_enable_irqs(omap);
+	list_add_tail(&omap->list, &dwc3_omap_list);
+
+	return 0;
+}
+
+/**
+ * dwc3_omap_uboot_exit - dwc3 omap uboot cleanup code
+ * @index: index of this controller
+ *
+ * Performs cleanup of memory allocated in dwc3_omap_uboot_init
+ * (equivalent to dwc3_omap_remove in linux). index of _this_ controller
+ * should be passed and should match with the index passed in
+ * dwc3_omap_device during init.
+ *
+ * Generally called from board file.
+ */
+void dwc3_omap_uboot_exit(int index)
+{
+	struct dwc3_omap *omap = NULL;
+
+	list_for_each_entry(omap, &dwc3_omap_list, list) {
+		if (omap->index != index)
+			continue;
+
+		dwc3_omap_disable_irqs(omap);
+		list_del(&omap->list);
+		kfree(omap);
+		break;
+	}
+}
+
+/**
+ * dwc3_omap_uboot_interrupt_status - check the status of interrupt
+ * @index: index of this controller
+ *
+ * Checks the status of interrupts and returns true if an interrupt
+ * is detected or false otherwise.
+ *
+ * Generally called from board file.
+ */
+int dwc3_omap_uboot_interrupt_status(int index)
+{
+	struct dwc3_omap *omap = NULL;
+
+	list_for_each_entry(omap, &dwc3_omap_list, list)
+		if (omap->index == index)
+			return dwc3_omap_interrupt(-1, omap);
+
+	return 0;
+}
+
+MODULE_ALIAS("platform:omap-dwc3");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
diff --git a/roms/u-boot/drivers/usb/dwc3/dwc3-uniphier.c b/roms/u-boot/drivers/usb/dwc3/dwc3-uniphier.c
new file mode 100644
index 000000000..54b52dcd6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/dwc3-uniphier.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * UniPhier Specific Glue Layer for DWC3
+ *
+ * Copyright (C) 2016-2017 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ */
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+
+#define UNIPHIER_PRO4_DWC3_RESET	0x40
+#define   UNIPHIER_PRO4_DWC3_RESET_XIOMMU	BIT(5)
+#define   UNIPHIER_PRO4_DWC3_RESET_XLINK	BIT(4)
+#define   UNIPHIER_PRO4_DWC3_RESET_PHY_SS	BIT(2)
+
+#define UNIPHIER_PRO5_DWC3_RESET	0x00
+#define   UNIPHIER_PRO5_DWC3_RESET_PHY_S1	BIT(17)
+#define   UNIPHIER_PRO5_DWC3_RESET_PHY_S0	BIT(16)
+#define   UNIPHIER_PRO5_DWC3_RESET_XLINK	BIT(15)
+#define   UNIPHIER_PRO5_DWC3_RESET_XIOMMU	BIT(14)
+
+#define UNIPHIER_PXS2_DWC3_RESET	0x00
+#define   UNIPHIER_PXS2_DWC3_RESET_XLINK	BIT(15)
+
+static int uniphier_pro4_dwc3_init(void __iomem *regs)
+{
+	u32 tmp;
+
+	tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET);
+	tmp &= ~UNIPHIER_PRO4_DWC3_RESET_PHY_SS;
+	tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK;
+	writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET);
+
+	return 0;
+}
+
+static int uniphier_pro5_dwc3_init(void __iomem *regs)
+{
+	u32 tmp;
+
+	tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET);
+	tmp &= ~(UNIPHIER_PRO5_DWC3_RESET_PHY_S1 |
+		 UNIPHIER_PRO5_DWC3_RESET_PHY_S0);
+	tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU;
+	writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET);
+
+	return 0;
+}
+
+static int uniphier_pxs2_dwc3_init(void __iomem *regs)
+{
+	u32 tmp;
+
+	tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET);
+	tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK;
+	writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET);
+
+	return 0;
+}
+
+static int uniphier_dwc3_probe(struct udevice *dev)
+{
+	fdt_addr_t base;
+	void __iomem *regs;
+	int (*init)(void __iomem *regs);
+	int ret;
+
+	base = dev_read_addr(dev);
+	if (base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	regs = ioremap(base, SZ_32K);
+	if (!regs)
+		return -ENOMEM;
+
+	init = (typeof(init))dev_get_driver_data(dev);
+	ret = init(regs);
+	if (ret)
+		dev_err(dev, "failed to init glue layer\n");
+
+	iounmap(regs);
+
+	return ret;
+}
+
+static const struct udevice_id uniphier_dwc3_match[] = {
+	{
+		.compatible = "socionext,uniphier-pro4-dwc3",
+		.data = (ulong)uniphier_pro4_dwc3_init,
+	},
+	{
+		.compatible = "socionext,uniphier-pro5-dwc3",
+		.data = (ulong)uniphier_pro5_dwc3_init,
+	},
+	{
+		.compatible = "socionext,uniphier-pxs2-dwc3",
+		.data = (ulong)uniphier_pxs2_dwc3_init,
+	},
+	{
+		.compatible = "socionext,uniphier-ld20-dwc3",
+		.data = (ulong)uniphier_pxs2_dwc3_init,
+	},
+	{
+		.compatible = "socionext,uniphier-pxs3-dwc3",
+		.data = (ulong)uniphier_pxs2_dwc3_init,
+	},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name = "uniphier-dwc3",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = uniphier_dwc3_match,
+	.probe = uniphier_dwc3_probe,
+};
diff --git a/roms/u-boot/drivers/usb/dwc3/ep0.c b/roms/u-boot/drivers/usb/dwc3/ep0.c
new file mode 100644
index 000000000..75ac993bc
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/ep0.c
@@ -0,0 +1,1115 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/ep0.c) and ported
+ * to uboot.
+ *
+ * commit c00552ebaf : Merge 3.18-rc7 into usb-next
+ */
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "linux-compat.h"
+
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
+static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		struct dwc3_ep *dep, struct dwc3_request *req);
+
+static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+	switch (state) {
+	case EP0_UNCONNECTED:
+		return "Unconnected";
+	case EP0_SETUP_PHASE:
+		return "Setup Phase";
+	case EP0_DATA_PHASE:
+		return "Data Phase";
+	case EP0_STATUS_PHASE:
+		return "Status Phase";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
+				u32 len, u32 type, unsigned chain)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_trb			*trb;
+	struct dwc3_ep			*dep;
+
+	int				ret;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_BUSY) {
+		dev_vdbg(dwc->dev, "%s still busy", dep->name);
+		return 0;
+	}
+
+	trb = &dwc->ep0_trb[dep->free_slot];
+
+	if (chain)
+		dep->free_slot++;
+
+	trb->bpl = lower_32_bits(buf_dma);
+	trb->bph = upper_32_bits(buf_dma);
+	trb->size = len;
+	trb->ctrl = type;
+
+	trb->ctrl |= (DWC3_TRB_CTRL_HWO
+			| DWC3_TRB_CTRL_ISP_IMI);
+
+	if (chain)
+		trb->ctrl |= DWC3_TRB_CTRL_CHN;
+	else
+		trb->ctrl |= (DWC3_TRB_CTRL_IOC
+				| DWC3_TRB_CTRL_LST);
+
+	dwc3_flush_cache((uintptr_t)buf_dma, len);
+	dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+
+	if (chain)
+		return 0;
+
+	memset(&params, 0, sizeof(params));
+	params.param0 = upper_32_bits(dwc->ep0_trb_addr);
+	params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_STARTTRANSFER, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "%s STARTTRANSFER failed", dep->name);
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+	dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
+			dep->number);
+
+	dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+	return 0;
+}
+
+static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
+		struct dwc3_request *req)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	req->epnum		= dep->number;
+
+	list_add_tail(&req->list, &dep->request_list);
+
+	/*
+	 * Gadget driver might not be quick enough to queue a request
+	 * before we get a Transfer Not Ready event on this endpoint.
+	 *
+	 * In that case, we will set DWC3_EP_PENDING_REQUEST. When that
+	 * flag is set, it's telling us that as soon as Gadget queues the
+	 * required request, we should kick the transfer here because the
+	 * IRQ we were waiting for is long gone.
+	 */
+	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+		unsigned	direction;
+
+		direction = !!(dep->flags & DWC3_EP0_DIR_IN);
+
+		if (dwc->ep0state != EP0_DATA_PHASE) {
+			dev_WARN(dwc->dev, "Unexpected pending request\n");
+			return 0;
+		}
+
+		__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
+
+		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
+				DWC3_EP0_DIR_IN);
+
+		return 0;
+	}
+
+	/*
+	 * In case gadget driver asked us to delay the STATUS phase,
+	 * handle it here.
+	 */
+	if (dwc->delayed_status) {
+		unsigned	direction;
+
+		direction = !dwc->ep0_expect_in;
+		dwc->delayed_status = false;
+		usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
+
+		if (dwc->ep0state == EP0_STATUS_PHASE)
+			__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
+		else
+			dev_dbg(dwc->dev, "too early for delayed status");
+
+		return 0;
+	}
+
+	/*
+	 * Unfortunately we have uncovered a limitation wrt the Data Phase.
+	 *
+	 * Section 9.4 says we can wait for the XferNotReady(DATA) event to
+	 * come before issueing Start Transfer command, but if we do, we will
+	 * miss situations where the host starts another SETUP phase instead of
+	 * the DATA phase.  Such cases happen at least on TD.7.6 of the Link
+	 * Layer Compliance Suite.
+	 *
+	 * The problem surfaces due to the fact that in case of back-to-back
+	 * SETUP packets there will be no XferNotReady(DATA) generated and we
+	 * will be stuck waiting for XferNotReady(DATA) forever.
+	 *
+	 * By looking at tables 9-13 and 9-14 of the Databook, we can see that
+	 * it tells us to start Data Phase right away. It also mentions that if
+	 * we receive a SETUP phase instead of the DATA phase, core will issue
+	 * XferComplete for the DATA phase, before actually initiating it in
+	 * the wire, with the TRB's status set to "SETUP_PENDING". Such status
+	 * can only be used to print some debugging logs, as the core expects
+	 * us to go through to the STATUS phase and start a CONTROL_STATUS TRB,
+	 * just so it completes right away, without transferring anything and,
+	 * only then, we can go back to the SETUP phase.
+	 *
+	 * Because of this scenario, SNPS decided to change the programming
+	 * model of control transfers and support on-demand transfers only for
+	 * the STATUS phase. To fix the issue we have now, we will always wait
+	 * for gadget driver to queue the DATA phase's struct usb_request, then
+	 * start it right away.
+	 *
+	 * If we're actually in a 2-stage transfer, we will wait for
+	 * XferNotReady(STATUS).
+	 */
+	if (dwc->three_stage_setup) {
+		unsigned        direction;
+
+		direction = dwc->ep0_expect_in;
+		dwc->ep0state = EP0_DATA_PHASE;
+
+		__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
+
+		dep->flags &= ~DWC3_EP0_DIR_IN;
+	}
+
+	return 0;
+}
+
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+		gfp_t gfp_flags)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!dep->endpoint.desc) {
+		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s",
+				request, dep->name);
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	/* we share one TRB for ep0/1 */
+	if (!list_empty(&dep->request_list)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	dev_vdbg(dwc->dev, "queueing request %p to %s length %d state '%s'",
+			request, dep->name, request->length,
+			dwc3_ep0_state_string(dwc->ep0state));
+
+	ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+{
+	struct dwc3_ep		*dep;
+
+	/* reinitialize physical ep1 */
+	dep = dwc->eps[1];
+	dep->flags = DWC3_EP_ENABLED;
+
+	/* stall is always issued on EP0 */
+	dep = dwc->eps[0];
+	__dwc3_gadget_ep_set_halt(dep, 1, false);
+	dep->flags = DWC3_EP_ENABLED;
+	dwc->delayed_status = false;
+
+	if (!list_empty(&dep->request_list)) {
+		struct dwc3_request	*req;
+
+		req = next_request(&dep->request_list);
+		dwc3_gadget_giveback(dep, req, -ECONNRESET);
+	}
+
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	dwc3_ep0_stall_and_restart(dwc);
+
+	return 0;
+}
+
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+	unsigned long			flags;
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep0_set_halt(ep, value);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+void dwc3_ep0_out_start(struct dwc3 *dwc)
+{
+	int				ret;
+
+	ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
+				   DWC3_TRBCTL_CONTROL_SETUP, 0);
+	WARN_ON(ret < 0);
+}
+
+static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
+{
+	struct dwc3_ep		*dep;
+	u32			windex = le16_to_cpu(wIndex_le);
+	u32			epnum;
+
+	epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
+	if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+		epnum |= 1;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_ENABLED)
+		return dep;
+
+	return NULL;
+}
+
+static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+}
+/*
+ * ch 9.4.5
+ */
+static int dwc3_ep0_handle_status(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl)
+{
+	struct dwc3_ep		*dep;
+	u32			recip;
+	u32			reg;
+	u16			usb_status = 0;
+	__le16			*response_pkt;
+
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		/*
+		 * LTM will be set once we know how to set this in HW.
+		 */
+		usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+
+		if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (reg & DWC3_DCTL_INITU1ENA)
+				usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
+			if (reg & DWC3_DCTL_INITU2ENA)
+				usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
+		}
+
+		break;
+
+	case USB_RECIP_INTERFACE:
+		/*
+		 * Function Remote Wake Capable	D0
+		 * Function Remote Wakeup	D1
+		 */
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+		if (!dep)
+			return -EINVAL;
+
+		if (dep->flags & DWC3_EP_STALL)
+			usb_status = 1 << USB_ENDPOINT_HALT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	response_pkt = (__le16 *) dwc->setup_buf;
+	*response_pkt = cpu_to_le16(usb_status);
+
+	dep = dwc->eps[0];
+	dwc->ep0_usb_req.dep = dep;
+	dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
+	dwc->ep0_usb_req.request.buf = dwc->setup_buf;
+	dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
+
+	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	struct dwc3_ep		*dep;
+	u32			recip;
+	u32			wValue;
+	u32			wIndex;
+	u32			reg;
+	int			ret;
+	enum usb_device_state	state;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+	state = dwc->gadget.state;
+
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+
+		switch (wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			break;
+		/*
+		 * 9.4.1 says only only for SS, in AddressState only for
+		 * default control pipe
+		 */
+		case USB_DEVICE_U1_ENABLE:
+			if (state != USB_STATE_CONFIGURED)
+				return -EINVAL;
+			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+				return -EINVAL;
+
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (set)
+				reg |= DWC3_DCTL_INITU1ENA;
+			else
+				reg &= ~DWC3_DCTL_INITU1ENA;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+			break;
+
+		case USB_DEVICE_U2_ENABLE:
+			if (state != USB_STATE_CONFIGURED)
+				return -EINVAL;
+			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+				return -EINVAL;
+
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (set)
+				reg |= DWC3_DCTL_INITU2ENA;
+			else
+				reg &= ~DWC3_DCTL_INITU2ENA;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+			break;
+
+		case USB_DEVICE_LTM_ENABLE:
+			return -EINVAL;
+
+		case USB_DEVICE_TEST_MODE:
+			if ((wIndex & 0xff) != 0)
+				return -EINVAL;
+			if (!set)
+				return -EINVAL;
+
+			dwc->test_mode_nr = wIndex >> 8;
+			dwc->test_mode = true;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case USB_RECIP_INTERFACE:
+		switch (wValue) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
+				/* XXX enable Low power suspend */
+				;
+			if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
+				/* XXX enable remote wakeup */
+				;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		switch (wValue) {
+		case USB_ENDPOINT_HALT:
+			dep = dwc3_wIndex_to_dep(dwc, wIndex);
+			if (!dep)
+				return -EINVAL;
+			if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
+				break;
+			ret = __dwc3_gadget_ep_set_halt(dep, set, true);
+			if (ret)
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	enum usb_device_state state = dwc->gadget.state;
+	u32 addr;
+	u32 reg;
+
+	addr = le16_to_cpu(ctrl->wValue);
+	if (addr > 127) {
+		dev_dbg(dwc->dev, "invalid device address %d", addr);
+		return -EINVAL;
+	}
+
+	if (state == USB_STATE_CONFIGURED) {
+		dev_dbg(dwc->dev, "trying to set address when configured");
+		return -EINVAL;
+	}
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	reg |= DWC3_DCFG_DEVADDR(addr);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	if (addr)
+		usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
+	else
+		usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
+
+	return 0;
+}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+
+	spin_unlock(&dwc->lock);
+	ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+	spin_lock(&dwc->lock);
+	return ret;
+}
+
+static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	enum usb_device_state state = dwc->gadget.state;
+	u32 cfg;
+	int ret;
+	u32 reg;
+
+	dwc->start_config_issued = false;
+	cfg = le16_to_cpu(ctrl->wValue);
+
+	switch (state) {
+	case USB_STATE_DEFAULT:
+		return -EINVAL;
+
+	case USB_STATE_ADDRESS:
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		/* if the cfg matches and the cfg is non zero */
+		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
+
+			/*
+			 * only change state if set_config has already
+			 * been processed. If gadget driver returns
+			 * USB_GADGET_DELAYED_STATUS, we will wait
+			 * to change the state on the next usb_ep_queue()
+			 */
+			if (ret == 0)
+				usb_gadget_set_state(&dwc->gadget,
+						USB_STATE_CONFIGURED);
+
+			/*
+			 * Enable transition to U1/U2 state when
+			 * nothing is pending from application.
+			 */
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+			dwc->resize_fifos = true;
+			dev_dbg(dwc->dev, "resize FIFOs flag SET");
+		}
+		break;
+
+	case USB_STATE_CONFIGURED:
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		if (!cfg && !ret)
+			usb_gadget_set_state(&dwc->gadget,
+					USB_STATE_ADDRESS);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct dwc3_ep	*dep = to_dwc3_ep(ep);
+	struct dwc3	*dwc = dep->dwc;
+
+	u32		param = 0;
+	u32		reg;
+
+	struct timing {
+		u8	u1sel;
+		u8	u1pel;
+		u16	u2sel;
+		u16	u2pel;
+	} __packed timing;
+
+	int		ret;
+
+	memcpy(&timing, req->buf, sizeof(timing));
+
+	dwc->u1sel = timing.u1sel;
+	dwc->u1pel = timing.u1pel;
+	dwc->u2sel = le16_to_cpu(timing.u2sel);
+	dwc->u2pel = le16_to_cpu(timing.u2pel);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (reg & DWC3_DCTL_INITU2ENA)
+		param = dwc->u2pel;
+	if (reg & DWC3_DCTL_INITU1ENA)
+		param = dwc->u1pel;
+
+	/*
+	 * According to Synopsys Databook, if parameter is
+	 * greater than 125, a value of zero should be
+	 * programmed in the register.
+	 */
+	if (param > 125)
+		param = 0;
+
+	/* now that we have the time, issue DGCMD Set Sel */
+	ret = dwc3_send_gadget_generic_command(dwc,
+			DWC3_DGCMD_SET_PERIODIC_PAR, param);
+	WARN_ON(ret < 0);
+}
+
+static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	struct dwc3_ep	*dep;
+	enum usb_device_state state = dwc->gadget.state;
+	u16		wLength;
+
+	if (state == USB_STATE_DEFAULT)
+		return -EINVAL;
+
+	wLength = le16_to_cpu(ctrl->wLength);
+
+	if (wLength != 6) {
+		dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
+				wLength);
+		return -EINVAL;
+	}
+
+	/*
+	 * To handle Set SEL we need to receive 6 bytes from Host. So let's
+	 * queue a usb_request for 6 bytes.
+	 *
+	 * Remember, though, this controller can't handle non-wMaxPacketSize
+	 * aligned transfers on the OUT direction, so we queue a request for
+	 * wMaxPacketSize instead.
+	 */
+	dep = dwc->eps[0];
+	dwc->ep0_usb_req.dep = dep;
+	dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
+	dwc->ep0_usb_req.request.buf = dwc->setup_buf;
+	dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
+
+	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
+}
+
+static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	u16		wLength;
+	u16		wValue;
+	u16		wIndex;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wLength = le16_to_cpu(ctrl->wLength);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+
+	if (wIndex || wLength)
+		return -EINVAL;
+
+	/*
+	 * REVISIT It's unclear from Databook what to do with this
+	 * value. For now, just cache it.
+	 */
+	dwc->isoch_delay = wValue;
+
+	return 0;
+}
+
+static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_GET_STATUS:
+		dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS");
+		ret = dwc3_ep0_handle_status(dwc, ctrl);
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE");
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE");
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+		break;
+	case USB_REQ_SET_ADDRESS:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS");
+		ret = dwc3_ep0_set_address(dwc, ctrl);
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION");
+		ret = dwc3_ep0_set_config(dwc, ctrl);
+		break;
+	case USB_REQ_SET_SEL:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_SEL");
+		ret = dwc3_ep0_set_sel(dwc, ctrl);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY");
+		ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
+		break;
+	default:
+		dev_vdbg(dwc->dev, "Forwarding to gadget driver");
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		break;
+	}
+
+	return ret;
+}
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+	int ret = -EINVAL;
+	u32 len;
+
+	if (!dwc->gadget_driver)
+		goto out;
+
+	len = le16_to_cpu(ctrl->wLength);
+	if (!len) {
+		dwc->three_stage_setup = false;
+		dwc->ep0_expect_in = false;
+		dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+	} else {
+		dwc->three_stage_setup = true;
+		dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN);
+		dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
+	}
+
+	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		ret = dwc3_ep0_std_request(dwc, ctrl);
+	else
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+
+	if (ret == USB_GADGET_DELAYED_STATUS)
+		dwc->delayed_status = true;
+
+out:
+	if (ret < 0)
+		dwc3_ep0_stall_and_restart(dwc);
+}
+
+static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_request	*r = NULL;
+	struct usb_request	*ur;
+	struct dwc3_trb		*trb;
+	struct dwc3_ep		*ep0;
+	unsigned		transfer_size = 0;
+	unsigned		maxp;
+	void			*buf;
+	u32			transferred = 0;
+	u32			status;
+	u32			length;
+	u8			epnum;
+
+	epnum = event->endpoint_number;
+	ep0 = dwc->eps[0];
+
+	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+
+	trb = dwc->ep0_trb;
+
+	r = next_request(&ep0->request_list);
+	if (!r)
+		return;
+
+	dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+
+	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+	if (status == DWC3_TRBSTS_SETUP_PENDING) {
+		dev_dbg(dwc->dev, "Setup Pending received");
+
+		if (r)
+			dwc3_gadget_giveback(ep0, r, -ECONNRESET);
+
+		return;
+	}
+
+	ur = &r->request;
+	buf = ur->buf;
+
+	length = trb->size & DWC3_TRB_SIZE_MASK;
+
+	maxp = ep0->endpoint.maxpacket;
+
+	if (dwc->ep0_bounced) {
+		/*
+		 * Handle the first TRB before handling the bounce buffer if
+		 * the request length is greater than the bounce buffer size.
+		 */
+		if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
+			transfer_size = (ur->length / maxp) * maxp;
+			transferred = transfer_size - length;
+			buf = (u8 *)buf + transferred;
+			ur->actual += transferred;
+
+			trb++;
+			dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+			length = trb->size & DWC3_TRB_SIZE_MASK;
+
+			ep0->free_slot = 0;
+		}
+
+		transfer_size = roundup((ur->length - transfer_size),
+					maxp);
+		transferred = min_t(u32, ur->length - transferred,
+				    transfer_size - length);
+		dwc3_flush_cache((uintptr_t)dwc->ep0_bounce, DWC3_EP0_BOUNCE_SIZE);
+		memcpy(buf, dwc->ep0_bounce, transferred);
+	} else {
+		transferred = ur->length - length;
+	}
+
+	ur->actual += transferred;
+
+	if ((epnum & 1) && ur->actual < ur->length) {
+		/* for some reason we did not get everything out */
+
+		dwc3_ep0_stall_and_restart(dwc);
+	} else {
+		dwc3_gadget_giveback(ep0, r, 0);
+
+		if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+				ur->length && ur->zero) {
+			int ret;
+
+			dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+			ret = dwc3_ep0_start_trans(dwc, epnum,
+					dwc->ctrl_req_addr, 0,
+					DWC3_TRBCTL_CONTROL_DATA, 0);
+			WARN_ON(ret < 0);
+		}
+	}
+}
+
+static void dwc3_ep0_complete_status(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_request	*r;
+	struct dwc3_ep		*dep;
+	struct dwc3_trb		*trb;
+	u32			status;
+
+	dep = dwc->eps[0];
+	trb = dwc->ep0_trb;
+
+	if (!list_empty(&dep->request_list)) {
+		r = next_request(&dep->request_list);
+
+		dwc3_gadget_giveback(dep, r, 0);
+	}
+
+	if (dwc->test_mode) {
+		int ret;
+
+		ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
+		if (ret < 0) {
+			dev_dbg(dwc->dev, "Invalid Test #%d",
+					dwc->test_mode_nr);
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+	}
+
+	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+	if (status == DWC3_TRBSTS_SETUP_PENDING)
+		dev_dbg(dwc->dev, "Setup Pending received");
+
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
+			const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
+
+	dep->flags &= ~DWC3_EP_BUSY;
+	dep->resource_index = 0;
+	dwc->setup_packet_pending = false;
+
+	switch (dwc->ep0state) {
+	case EP0_SETUP_PHASE:
+		dev_vdbg(dwc->dev, "Setup Phase");
+		dwc3_ep0_inspect_setup(dwc, event);
+		break;
+
+	case EP0_DATA_PHASE:
+		dev_vdbg(dwc->dev, "Data Phase");
+		dwc3_ep0_complete_data(dwc, event);
+		break;
+
+	case EP0_STATUS_PHASE:
+		dev_vdbg(dwc->dev, "Status Phase");
+		dwc3_ep0_complete_status(dwc, event);
+		break;
+	default:
+		WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
+	}
+}
+
+static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		struct dwc3_ep *dep, struct dwc3_request *req)
+{
+	int			ret;
+
+	req->direction = !!dep->number;
+
+	if (req->request.length == 0) {
+		ret = dwc3_ep0_start_trans(dwc, dep->number,
+					   dwc->ctrl_req_addr, 0,
+					   DWC3_TRBCTL_CONTROL_DATA, 0);
+	} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
+			(dep->number == 0)) {
+		u32	transfer_size = 0;
+		u32	maxpacket;
+
+		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+				dep->number);
+		if (ret) {
+			dev_dbg(dwc->dev, "failed to map request\n");
+			return;
+		}
+
+		maxpacket = dep->endpoint.maxpacket;
+		if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
+			transfer_size = (req->request.length / maxpacket) *
+						maxpacket;
+			ret = dwc3_ep0_start_trans(dwc, dep->number,
+						   req->request.dma,
+						   transfer_size,
+						   DWC3_TRBCTL_CONTROL_DATA, 1);
+		}
+
+		transfer_size = roundup((req->request.length - transfer_size),
+					maxpacket);
+
+		dwc->ep0_bounced = true;
+
+		/*
+		 * REVISIT in case request length is bigger than
+		 * DWC3_EP0_BOUNCE_SIZE we will need two chained
+		 * TRBs to handle the transfer.
+		 */
+		ret = dwc3_ep0_start_trans(dwc, dep->number,
+					   dwc->ep0_bounce_addr, transfer_size,
+					   DWC3_TRBCTL_CONTROL_DATA, 0);
+	} else {
+		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+				dep->number);
+		if (ret) {
+			dev_dbg(dwc->dev, "failed to map request\n");
+			return;
+		}
+
+		ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
+					   req->request.length,
+					   DWC3_TRBCTL_CONTROL_DATA, 0);
+	}
+
+	WARN_ON(ret < 0);
+}
+
+static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			type;
+
+	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
+		: DWC3_TRBCTL_CONTROL_STATUS2;
+
+	return dwc3_ep0_start_trans(dwc, dep->number,
+			dwc->ctrl_req_addr, 0, type, 0);
+}
+
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	if (dwc->resize_fifos) {
+		dev_dbg(dwc->dev, "Resizing FIFOs");
+		dwc3_gadget_resize_tx_fifos(dwc);
+		dwc->resize_fifos = 0;
+	}
+
+	WARN_ON(dwc3_ep0_start_control_status(dep));
+}
+
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
+
+	__dwc3_ep0_do_control_status(dwc, dep);
+}
+
+static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	u32			cmd;
+	int			ret;
+
+	if (!dep->resource_index)
+		return;
+
+	cmd = DWC3_DEPCMD_ENDTRANSFER;
+	cmd |= DWC3_DEPCMD_CMDIOC;
+	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
+	memset(&params, 0, sizeof(params));
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	WARN_ON_ONCE(ret);
+	dep->resource_index = 0;
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	dwc->setup_packet_pending = true;
+
+	switch (event->status) {
+	case DEPEVT_STATUS_CONTROL_DATA:
+		dev_vdbg(dwc->dev, "Control Data");
+
+		/*
+		 * We already have a DATA transfer in the controller's cache,
+		 * if we receive a XferNotReady(DATA) we will ignore it, unless
+		 * it's for the wrong direction.
+		 *
+		 * In that case, we must issue END_TRANSFER command to the Data
+		 * Phase we already have started and issue SetStall on the
+		 * control endpoint.
+		 */
+		if (dwc->ep0_expect_in != event->endpoint_number) {
+			struct dwc3_ep	*dep = dwc->eps[dwc->ep0_expect_in];
+
+			dev_vdbg(dwc->dev, "Wrong direction for Data phase");
+			dwc3_ep0_end_control_data(dwc, dep);
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+
+		break;
+
+	case DEPEVT_STATUS_CONTROL_STATUS:
+		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS)
+			return;
+
+		dev_vdbg(dwc->dev, "Control Status");
+
+		dwc->ep0state = EP0_STATUS_PHASE;
+
+		if (dwc->delayed_status) {
+			WARN_ON_ONCE(event->endpoint_number != 1);
+			dev_vdbg(dwc->dev, "Delayed Status");
+			return;
+		}
+
+		dwc3_ep0_do_control_status(dwc, event);
+	}
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	u8			epnum = event->endpoint_number;
+
+	dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'",
+			dwc3_ep_event_string(event->endpoint_event),
+			epnum >> 1, (epnum & 1) ? "in" : "out",
+			dwc3_ep0_state_string(dwc->ep0state));
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		dwc3_ep0_xfer_complete(dwc, event);
+		break;
+
+	case DWC3_DEPEVT_XFERNOTREADY:
+		dwc3_ep0_xfernotready(dwc, event);
+		break;
+
+	case DWC3_DEPEVT_XFERINPROGRESS:
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+	case DWC3_DEPEVT_STREAMEVT:
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		break;
+	}
+}
diff --git a/roms/u-boot/drivers/usb/dwc3/gadget.c b/roms/u-boot/drivers/usb/dwc3/gadget.c
new file mode 100644
index 000000000..4e68fb0a8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/gadget.c
@@ -0,0 +1,2684 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/gadget.c) and ported
+ * to uboot.
+ *
+ * commit 8e74475b0e : usb: dwc3: gadget: use udc-core's reset notifier
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "linux-compat.h"
+
+/**
+ * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
+ * @dwc: pointer to our context structure
+ * @mode: the mode to set (J, K SE0 NAK, Force Enable)
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -EINVAL if wrong Test Selector
+ * is passed
+ */
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
+{
+	u32		reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+	switch (mode) {
+	case TEST_J:
+	case TEST_K:
+	case TEST_SE0_NAK:
+	case TEST_PACKET:
+	case TEST_FORCE_EN:
+		reg |= mode << 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	return 0;
+}
+
+/**
+ * dwc3_gadget_get_link_state - Gets current state of USB Link
+ * @dwc: pointer to our context structure
+ *
+ * Caller should take care of locking. This function will
+ * return the link state on success (>= 0) or -ETIMEDOUT.
+ */
+int dwc3_gadget_get_link_state(struct dwc3 *dwc)
+{
+	u32		reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+	return DWC3_DSTS_USBLNKST(reg);
+}
+
+/**
+ * dwc3_gadget_set_link_state - Sets USB Link to a particular State
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -ETIMEDOUT.
+ */
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
+{
+	int		retries = 10000;
+	u32		reg;
+
+	/*
+	 * Wait until device controller is ready. Only applies to 1.94a and
+	 * later RTL.
+	 */
+	if (dwc->revision >= DWC3_REVISION_194A) {
+		while (--retries) {
+			reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+			if (reg & DWC3_DSTS_DCNRD)
+				udelay(5);
+			else
+				break;
+		}
+
+		if (retries <= 0)
+			return -ETIMEDOUT;
+	}
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+
+	/* set requested state */
+	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	/*
+	 * The following code is racy when called from dwc3_gadget_wakeup,
+	 * and is not needed, at least on newer versions
+	 */
+	if (dwc->revision >= DWC3_REVISION_194A)
+		return 0;
+
+	/* wait for a change in DSTS */
+	retries = 10000;
+	while (--retries) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+		if (DWC3_DSTS_USBLNKST(reg) == state)
+			return 0;
+
+		udelay(5);
+	}
+
+	dev_vdbg(dwc->dev, "link state change request timed out\n");
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
+ * @dwc: pointer to our context structure
+ *
+ * This function will a best effort FIFO allocation in order
+ * to improve FIFO usage and throughput, while still allowing
+ * us to enable as many endpoints as possible.
+ *
+ * Keep in mind that this operation will be highly dependent
+ * on the configured size for RAM1 - which contains TxFifo -,
+ * the amount of endpoints enabled on coreConsultant tool, and
+ * the width of the Master Bus.
+ *
+ * In the ideal world, we would always be able to satisfy the
+ * following equation:
+ *
+ * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
+ * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
+ *
+ * Unfortunately, due to many variables that's not always the case.
+ */
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
+{
+	int		last_fifo_depth = 0;
+	int		fifo_size;
+	int		mdwidth;
+	int		num;
+
+	if (!dwc->needs_fifo_resize)
+		return 0;
+
+	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+
+	/* MDWIDTH is represented in bits, we need it in bytes */
+	mdwidth >>= 3;
+
+	/*
+	 * FIXME For now we will only allocate 1 wMaxPacketSize space
+	 * for each enabled endpoint, later patches will come to
+	 * improve this algorithm so that we better use the internal
+	 * FIFO space
+	 */
+	for (num = 0; num < dwc->num_in_eps; num++) {
+		/* bit0 indicates direction; 1 means IN ep */
+		struct dwc3_ep	*dep = dwc->eps[(num << 1) | 1];
+		int		mult = 1;
+		int		tmp;
+
+		if (!(dep->flags & DWC3_EP_ENABLED))
+			continue;
+
+		if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
+				|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
+			mult = 3;
+
+		/*
+		 * REVISIT: the following assumes we will always have enough
+		 * space available on the FIFO RAM for all possible use cases.
+		 * Make sure that's true somehow and change FIFO allocation
+		 * accordingly.
+		 *
+		 * If we have Bulk or Isochronous endpoints, we want
+		 * them to be able to be very, very fast. So we're giving
+		 * those endpoints a fifo_size which is enough for 3 full
+		 * packets
+		 */
+		tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+		tmp += mdwidth;
+
+		fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+
+		fifo_size |= (last_fifo_depth << 16);
+
+		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+				dep->name, last_fifo_depth, fifo_size & 0xffff);
+
+		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
+
+		last_fifo_depth += (fifo_size & 0xffff);
+	}
+
+	return 0;
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status)
+{
+	struct dwc3			*dwc = dep->dwc;
+
+	if (req->queued) {
+		dep->busy_slot++;
+		/*
+		 * Skip LINK TRB. We can't use req->trb and check for
+		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we
+		 * just completed (not the LINK TRB).
+		 */
+		if (((dep->busy_slot & DWC3_TRB_MASK) ==
+			DWC3_TRB_NUM- 1) &&
+			usb_endpoint_xfer_isoc(dep->endpoint.desc))
+			dep->busy_slot++;
+		req->queued = false;
+	}
+
+	list_del(&req->list);
+	req->trb = NULL;
+	if (req->request.length)
+		dwc3_flush_cache((uintptr_t)req->request.dma, req->request.length);
+
+	if (req->request.status == -EINPROGRESS)
+		req->request.status = status;
+
+	if (dwc->ep0_bounced && dep->number == 0)
+		dwc->ep0_bounced = false;
+	else
+		usb_gadget_unmap_request(&dwc->gadget, &req->request,
+				req->direction);
+
+	dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
+			req, dep->name, req->request.actual,
+			req->request.length, status);
+
+	spin_unlock(&dwc->lock);
+	usb_gadget_giveback_request(&dep->endpoint, &req->request);
+	spin_lock(&dwc->lock);
+}
+
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
+{
+	u32		timeout = 500;
+	u32		reg;
+
+	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
+	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+		if (!(reg & DWC3_DGCMD_CMDACT)) {
+			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+					DWC3_DGCMD_STATUS(reg));
+			return 0;
+		}
+
+		/*
+		 * We can't sleep here, because it's also called from
+		 * interrupt context.
+		 */
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+		udelay(1);
+	} while (1);
+}
+
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+	u32			timeout = 500;
+	u32			reg;
+
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
+
+	dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+		if (!(reg & DWC3_DEPCMD_CMDACT)) {
+			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+					DWC3_DEPCMD_STATUS(reg));
+			return 0;
+		}
+
+		/*
+		 * We can't sleep here, because it is also called from
+		 * interrupt context.
+		 */
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+
+		udelay(1);
+	} while (1);
+}
+
+static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+		struct dwc3_trb *trb)
+{
+	u32		offset = (char *) trb - (char *) dep->trb_pool;
+
+	return dep->trb_pool_dma + offset;
+}
+
+static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+{
+	if (dep->trb_pool)
+		return 0;
+
+	if (dep->number == 0 || dep->number == 1)
+		return 0;
+
+	dep->trb_pool = dma_alloc_coherent(sizeof(struct dwc3_trb) *
+					   DWC3_TRB_NUM,
+					   (unsigned long *)&dep->trb_pool_dma);
+	if (!dep->trb_pool) {
+		dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+				dep->name);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+	dma_free_coherent(dep->trb_pool);
+
+	dep->trb_pool = NULL;
+	dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	u32			cmd;
+
+	memset(&params, 0x00, sizeof(params));
+
+	if (dep->number != 1) {
+		cmd = DWC3_DEPCMD_DEPSTARTCFG;
+		/* XferRscIdx == 0 for ep0 and 2 for the remaining */
+		if (dep->number > 1) {
+			if (dwc->start_config_issued)
+				return 0;
+			dwc->start_config_issued = true;
+			cmd |= DWC3_DEPCMD_PARAM(2);
+		}
+
+		return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+	}
+
+	return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc,
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool ignore, bool restore)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+
+	memset(&params, 0x00, sizeof(params));
+
+	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
+		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
+
+	/* Burst size is only needed in SuperSpeed mode */
+	if (dwc->gadget.speed == USB_SPEED_SUPER) {
+		u32 burst = dep->endpoint.maxburst - 1;
+
+		params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
+	}
+
+	if (ignore)
+		params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
+
+	if (restore) {
+		params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
+		params.param2 |= dep->saved_state;
+	}
+
+	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
+		| DWC3_DEPCFG_XFER_NOT_READY_EN;
+
+	if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
+		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+			| DWC3_DEPCFG_STREAM_EVENT_EN;
+		dep->stream_capable = true;
+	}
+
+	if (!usb_endpoint_xfer_control(desc))
+		params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
+
+	/*
+	 * We are doing 1:1 mapping for endpoints, meaning
+	 * Physical Endpoints 2 maps to Logical Endpoint 2 and
+	 * so on. We consider the direction bit as part of the physical
+	 * endpoint number. So USB endpoint 0x81 is 0x03.
+	 */
+	params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
+
+	/*
+	 * We must use the lower 16 TX FIFOs even though
+	 * HW might have more
+	 */
+	if (dep->direction)
+		params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
+
+	if (desc->bInterval) {
+		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
+		dep->interval = 1 << (desc->bInterval - 1);
+	}
+
+	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETEPCONFIG, &params);
+}
+
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+
+	memset(&params, 0x00, sizeof(params));
+
+	params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
+
+	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
+ * @dep: endpoint to be initialized
+ * @desc: USB Endpoint Descriptor
+ *
+ * Caller should take care of locking
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc,
+		const struct usb_ss_ep_comp_descriptor *comp_desc,
+		bool ignore, bool restore)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+	int			ret;
+
+	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		ret = dwc3_gadget_start_config(dwc, dep);
+		if (ret)
+			return ret;
+	}
+
+	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore,
+			restore);
+	if (ret)
+		return ret;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		struct dwc3_trb	*trb_st_hw;
+		struct dwc3_trb	*trb_link;
+
+		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+		if (ret)
+			return ret;
+
+		dep->endpoint.desc = desc;
+		dep->comp_desc = comp_desc;
+		dep->type = usb_endpoint_type(desc);
+		dep->flags |= DWC3_EP_ENABLED;
+
+		reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+		reg |= DWC3_DALEPENA_EP(dep->number);
+		dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+		if (!usb_endpoint_xfer_isoc(desc))
+			return 0;
+
+		/* Link TRB for ISOC. The HWO bit is never reset */
+		trb_st_hw = &dep->trb_pool[0];
+
+		trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
+		memset(trb_link, 0, sizeof(*trb_link));
+
+		trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+		trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+		trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
+		trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
+	}
+
+	return 0;
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_request		*req;
+
+	if (!list_empty(&dep->req_queued)) {
+		dwc3_stop_active_transfer(dwc, dep->number, true);
+
+		/* - giveback all requests to gadget driver */
+		while (!list_empty(&dep->req_queued)) {
+			req = next_request(&dep->req_queued);
+
+			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+		}
+	}
+
+	while (!list_empty(&dep->request_list)) {
+		req = next_request(&dep->request_list);
+
+		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+	}
+}
+
+/**
+ * __dwc3_gadget_ep_disable - Disables a HW endpoint
+ * @dep: the endpoint to disable
+ *
+ * This function also removes requests which are currently processed ny the
+ * hardware and those which are not yet scheduled.
+ * Caller should take care of locking.
+ */
+static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+
+	dwc3_remove_requests(dwc, dep);
+
+	/* make sure HW endpoint isn't stalled */
+	if (dep->flags & DWC3_EP_STALL)
+		__dwc3_gadget_ep_set_halt(dep, 0, false);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+	reg &= ~DWC3_DALEPENA_EP(dep->number);
+	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+	dep->stream_capable = false;
+	dep->endpoint.desc = NULL;
+	dep->comp_desc = NULL;
+	dep->type = 0;
+	dep->flags = 0;
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	return -EINVAL;
+}
+
+static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
+{
+	return -EINVAL;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3_ep			*dep;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	if (!desc->wMaxPacketSize) {
+		pr_debug("dwc3: missing wMaxPacketSize\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+
+	if (dep->flags & DWC3_EP_ENABLED) {
+		WARN(true, "%s is already enabled\n",
+				dep->name);
+		return 0;
+	}
+
+	switch (usb_endpoint_type(desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		strlcat(dep->name, "-control", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		strlcat(dep->name, "-isoc", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		strlcat(dep->name, "-bulk", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		strlcat(dep->name, "-int", sizeof(dep->name));
+		break;
+	default:
+		dev_err(dep->dwc->dev, "invalid endpoint transfer type\n");
+	}
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		WARN(true, "%s is already disabled\n",
+				dep->name);
+		return 0;
+	}
+
+	snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+			dep->number >> 1,
+			(dep->number & 1) ? "in" : "out");
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_disable(dep);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
+	gfp_t gfp_flags)
+{
+	struct dwc3_request		*req;
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	req->epnum	= dep->number;
+	req->dep	= dep;
+
+	return &req->request;
+}
+
+static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+		struct usb_request *request)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+
+	kfree(req);
+}
+
+/**
+ * dwc3_prepare_one_trb - setup one TRB from one request
+ * @dep: endpoint for which this request is prepared
+ * @req: dwc3_request pointer
+ */
+static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+		struct dwc3_request *req, dma_addr_t dma,
+		unsigned length, unsigned last, unsigned chain, unsigned node)
+{
+	struct dwc3_trb		*trb;
+
+	dev_vdbg(dep->dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+		 dep->name, req, (unsigned long long)dma,
+		 length, last ? " last" : "", chain ? " chain" : "");
+
+
+	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+
+	if (!req->trb) {
+		dwc3_gadget_move_request_queued(req);
+		req->trb = trb;
+		req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+		req->start_slot = dep->free_slot & DWC3_TRB_MASK;
+	}
+
+	dep->free_slot++;
+	/* Skip the LINK-TRB on ISOC */
+	if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+			usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		dep->free_slot++;
+
+	trb->size = DWC3_TRB_SIZE_LENGTH(length);
+	trb->bpl = lower_32_bits(dma);
+	trb->bph = upper_32_bits(dma);
+
+	switch (usb_endpoint_type(dep->endpoint.desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
+		break;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!node)
+			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+		else
+			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		trb->ctrl = DWC3_TRBCTL_NORMAL;
+		break;
+	default:
+		/*
+		 * This is only possible with faulty memory because we
+		 * checked it already :)
+		 */
+		BUG();
+	}
+
+	if (!req->request.no_interrupt && !chain)
+		trb->ctrl |= DWC3_TRB_CTRL_IOC;
+
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+		trb->ctrl |= DWC3_TRB_CTRL_CSP;
+	} else if (last) {
+		trb->ctrl |= DWC3_TRB_CTRL_LST;
+	}
+
+	if (chain)
+		trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
+	if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
+		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
+
+	trb->ctrl |= DWC3_TRB_CTRL_HWO;
+
+	dwc3_flush_cache((uintptr_t)dma, length);
+	dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ * @starting: true if the endpoint is idle and no requests are queued.
+ *
+ * The function goes through the requests list and sets up TRBs for the
+ * transfers. The function returns once there are no more TRBs available or
+ * it runs out of requests.
+ */
+static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+{
+	struct dwc3_request	*req, *n;
+	u32			trbs_left;
+	u32			max;
+
+	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+	/* the first request must not be queued */
+	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+
+	/* Can't wrap around on a non-isoc EP since there's no link TRB */
+	if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+		max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
+		if (trbs_left > max)
+			trbs_left = max;
+	}
+
+	/*
+	 * If busy & slot are equal than it is either full or empty. If we are
+	 * starting to process requests then we are empty. Otherwise we are
+	 * full and don't do anything
+	 */
+	if (!trbs_left) {
+		if (!starting)
+			return;
+		trbs_left = DWC3_TRB_NUM;
+		/*
+		 * In case we start from scratch, we queue the ISOC requests
+		 * starting from slot 1. This is done because we use ring
+		 * buffer and have no LST bit to stop us. Instead, we place
+		 * IOC bit every TRB_NUM/4. We try to avoid having an interrupt
+		 * after the first request so we start at slot 1 and have
+		 * 7 requests proceed before we hit the first IOC.
+		 * Other transfer types don't use the ring buffer and are
+		 * processed from the first TRB until the last one. Since we
+		 * don't wrap around we have to start at the beginning.
+		 */
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+			dep->busy_slot = 1;
+			dep->free_slot = 1;
+		} else {
+			dep->busy_slot = 0;
+			dep->free_slot = 0;
+		}
+	}
+
+	/* The last TRB is a link TRB, not used for xfer */
+	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		return;
+
+	list_for_each_entry_safe(req, n, &dep->request_list, list) {
+		unsigned	length;
+		dma_addr_t	dma;
+
+		dma = req->request.dma;
+		length = req->request.length;
+
+		dwc3_prepare_one_trb(dep, req, dma, length,
+				     true, false, 0);
+
+		break;
+	}
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+		int start_new)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_request		*req;
+	struct dwc3			*dwc = dep->dwc;
+	int				ret;
+	u32				cmd;
+
+	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+		return -EBUSY;
+	}
+	dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+	/*
+	 * If we are getting here after a short-out-packet we don't enqueue any
+	 * new requests as we try to set the IOC bit only on the last request.
+	 */
+	if (start_new) {
+		if (list_empty(&dep->req_queued))
+			dwc3_prepare_trbs(dep, start_new);
+
+		/* req points to the first request which will be sent */
+		req = next_request(&dep->req_queued);
+	} else {
+		dwc3_prepare_trbs(dep, start_new);
+
+		/*
+		 * req points to the first request where HWO changed from 0 to 1
+		 */
+		req = next_request(&dep->req_queued);
+	}
+	if (!req) {
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return 0;
+	}
+
+	memset(&params, 0, sizeof(params));
+
+	if (start_new) {
+		params.param0 = upper_32_bits(req->trb_dma);
+		params.param1 = lower_32_bits(req->trb_dma);
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+	} else {
+		cmd = DWC3_DEPCMD_UPDATETRANSFER;
+	}
+
+	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+		/*
+		 * FIXME we need to iterate over the list of requests
+		 * here and stop, unmap, free and del each of the linked
+		 * requests instead of what we do now.
+		 */
+		usb_gadget_unmap_request(&dwc->gadget, &req->request,
+				req->direction);
+		list_del(&req->list);
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+
+	if (start_new) {
+		dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
+				dep->number);
+		WARN_ON_ONCE(!dep->resource_index);
+	}
+
+	return 0;
+}
+
+static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
+		struct dwc3_ep *dep, u32 cur_uf)
+{
+	u32 uf;
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+			dep->name);
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return;
+	}
+
+	/* 4 micro frames in the future */
+	uf = cur_uf + dep->interval * 4;
+
+	__dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+	u32 cur_uf, mask;
+
+	mask = ~(dep->interval - 1);
+	cur_uf = event->parameters & mask;
+
+	__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+	struct dwc3		*dwc = dep->dwc;
+	int			ret;
+
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	req->direction		= dep->direction;
+	req->epnum		= dep->number;
+
+	/*
+	 * DWC3 hangs on OUT requests smaller than maxpacket size,
+	 * so HACK the request length
+	 */
+	if (dep->direction == 0 &&
+	    req->request.length < dep->endpoint.maxpacket)
+		req->request.length = dep->endpoint.maxpacket;
+
+	/*
+	 * We only add to our list of requests now and
+	 * start consuming the list once we get XferNotReady
+	 * IRQ.
+	 *
+	 * That way, we avoid doing anything that we don't need
+	 * to do now and defer it until the point we receive a
+	 * particular token from the Host side.
+	 *
+	 * This will also avoid Host cancelling URBs due to too
+	 * many NAKs.
+	 */
+	ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+			dep->direction);
+	if (ret)
+		return ret;
+
+	list_add_tail(&req->list, &dep->request_list);
+
+	/*
+	 * There are a few special cases:
+	 *
+	 * 1. XferNotReady with empty list of requests. We need to kick the
+	 *    transfer here in that situation, otherwise we will be NAKing
+	 *    forever. If we get XferNotReady before gadget driver has a
+	 *    chance to queue a request, we will ACK the IRQ but won't be
+	 *    able to receive the data until the next request is queued.
+	 *    The following code is handling exactly that.
+	 *
+	 */
+	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+		/*
+		 * If xfernotready is already elapsed and it is a case
+		 * of isoc transfer, then issue END TRANSFER, so that
+		 * you can receive xfernotready again and can have
+		 * notion of current microframe.
+		 */
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+			if (list_empty(&dep->req_queued)) {
+				dwc3_stop_active_transfer(dwc, dep->number, true);
+				dep->flags = DWC3_EP_ENABLED;
+			}
+			return 0;
+		}
+
+		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+		if (ret && ret != -EBUSY)
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		return ret;
+	}
+
+	/*
+	 * 2. XferInProgress on Isoc EP with an active transfer. We need to
+	 *    kick the transfer here after queuing a request, otherwise the
+	 *    core may not see the modified TRB(s).
+	 */
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+			(dep->flags & DWC3_EP_BUSY) &&
+			!(dep->flags & DWC3_EP_MISSED_ISOC)) {
+		WARN_ON_ONCE(!dep->resource_index);
+		ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
+				false);
+		if (ret && ret != -EBUSY)
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		return ret;
+	}
+
+	/*
+	 * 4. Stream Capable Bulk Endpoints. We need to start the transfer
+	 * right away, otherwise host will not know we have streams to be
+	 * handled.
+	 */
+	if (dep->stream_capable) {
+		int	ret;
+
+		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+		if (ret && ret != -EBUSY) {
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		}
+	}
+
+	return 0;
+}
+
+static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+	gfp_t gfp_flags)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!dep->endpoint.desc) {
+		dev_dbg(dep->dwc->dev,
+			"trying to queue request %p to disabled %s\n", request,
+			ep->name);
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	if (req->dep != dep) {
+		WARN(true, "request %p belongs to '%s'\n", request,
+		     req->dep->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev_vdbg(dep->dwc->dev, "queing request %p to %s length %d\n",
+		 request, ep->name, request->length);
+
+	ret = __dwc3_gadget_ep_queue(dep, req);
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+		struct usb_request *request)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_request		*r = NULL;
+
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+	int				ret = 0;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	list_for_each_entry(r, &dep->request_list, list) {
+		if (r == req)
+			break;
+	}
+
+	if (r != req) {
+		list_for_each_entry(r, &dep->req_queued, list) {
+			if (r == req)
+				break;
+		}
+		if (r == req) {
+			/* wait until it is processed */
+			dwc3_stop_active_transfer(dwc, dep->number, true);
+			goto out1;
+		}
+		dev_err(dwc->dev, "request %p was not queued to %s\n",
+				request, ep->name);
+		ret = -EINVAL;
+		goto out0;
+	}
+
+out1:
+	/* giveback the request */
+	dwc3_gadget_giveback(dep, req, -ECONNRESET);
+
+out0:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
+{
+	struct dwc3_gadget_ep_cmd_params	params;
+	struct dwc3				*dwc = dep->dwc;
+	int					ret;
+
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+		dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+		return -EINVAL;
+	}
+
+	memset(&params, 0x00, sizeof(params));
+
+	if (value) {
+		if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
+				(!list_empty(&dep->req_queued) ||
+				 !list_empty(&dep->request_list)))) {
+			dev_dbg(dwc->dev, "%s: pending request, cannot halt\n",
+					dep->name);
+			return -EAGAIN;
+		}
+
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETSTALL, &params);
+		if (ret)
+			dev_err(dwc->dev, "failed to set STALL on %s\n",
+					dep->name);
+		else
+			dep->flags |= DWC3_EP_STALL;
+	} else {
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_CLEARSTALL, &params);
+		if (ret)
+			dev_err(dwc->dev, "failed to clear STALL on %s\n",
+					dep->name);
+		else
+			dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
+	}
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_set_halt(dep, value, false);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	unsigned long			flags;
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dep->flags |= DWC3_EP_WEDGE;
+
+	if (dep->number == 0 || dep->number == 1)
+		ret = __dwc3_gadget_ep0_set_halt(ep, 1);
+	else
+		ret = __dwc3_gadget_ep_set_halt(dep, 1, false);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+	.bLength	= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bmAttributes	= USB_ENDPOINT_XFER_CONTROL,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
+	.enable		= dwc3_gadget_ep0_enable,
+	.disable	= dwc3_gadget_ep0_disable,
+	.alloc_request	= dwc3_gadget_ep_alloc_request,
+	.free_request	= dwc3_gadget_ep_free_request,
+	.queue		= dwc3_gadget_ep0_queue,
+	.dequeue	= dwc3_gadget_ep_dequeue,
+	.set_halt	= dwc3_gadget_ep0_set_halt,
+	.set_wedge	= dwc3_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep_ops = {
+	.enable		= dwc3_gadget_ep_enable,
+	.disable	= dwc3_gadget_ep_disable,
+	.alloc_request	= dwc3_gadget_ep_alloc_request,
+	.free_request	= dwc3_gadget_ep_free_request,
+	.queue		= dwc3_gadget_ep_queue,
+	.dequeue	= dwc3_gadget_ep_dequeue,
+	.set_halt	= dwc3_gadget_ep_set_halt,
+	.set_wedge	= dwc3_gadget_ep_set_wedge,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	return DWC3_DSTS_SOFFN(reg);
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+
+	unsigned long		timeout;
+	unsigned long		flags;
+
+	u32			reg;
+
+	int			ret = 0;
+
+	u8			link_state;
+	u8			speed;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	/*
+	 * According to the Databook Remote wakeup request should
+	 * be issued only when the device is in early suspend state.
+	 *
+	 * We can check that via USB Link State bits in DSTS register.
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	if (speed == DWC3_DSTS_SUPERSPEED) {
+		dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	link_state = DWC3_DSTS_USBLNKST(reg);
+
+	switch (link_state) {
+	case DWC3_LINK_STATE_RX_DET:	/* in HS, means Early Suspend */
+	case DWC3_LINK_STATE_U3:	/* in HS, means SUSPEND */
+		break;
+	default:
+		dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
+				link_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
+	if (ret < 0) {
+		dev_err(dwc->dev, "failed to put link in Recovery\n");
+		goto out;
+	}
+
+	/* Recent versions do this automatically */
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* write zeroes to Link Change Request */
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
+
+	/* poll until Link State changes to ON */
+	timeout = 1000;
+
+	while (timeout--) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+		/* in HS, means ON */
+		if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
+			break;
+	}
+
+	if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
+		dev_err(dwc->dev, "failed to send remote wakeup\n");
+		ret = -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+		int is_selfpowered)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc->is_selfpowered = !!is_selfpowered;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
+{
+	u32			reg;
+	u32			timeout = 500;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (is_on) {
+		if (dwc->revision <= DWC3_REVISION_187A) {
+			reg &= ~DWC3_DCTL_TRGTULST_MASK;
+			reg |= DWC3_DCTL_TRGTULST_RX_DET;
+		}
+
+		if (dwc->revision >= DWC3_REVISION_194A)
+			reg &= ~DWC3_DCTL_KEEP_CONNECT;
+		reg |= DWC3_DCTL_RUN_STOP;
+
+		if (dwc->has_hibernation)
+			reg |= DWC3_DCTL_KEEP_CONNECT;
+
+		dwc->pullups_connected = true;
+	} else {
+		reg &= ~DWC3_DCTL_RUN_STOP;
+
+		if (dwc->has_hibernation && !suspend)
+			reg &= ~DWC3_DCTL_KEEP_CONNECT;
+
+		dwc->pullups_connected = false;
+	}
+
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+		if (is_on) {
+			if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+				break;
+		} else {
+			if (reg & DWC3_DSTS_DEVCTRLHLT)
+				break;
+		}
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+		udelay(1);
+	} while (1);
+
+	dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+			dwc->gadget_driver
+			? dwc->gadget_driver->function : "no-function",
+			is_on ? "connect" : "disconnect");
+
+	return 0;
+}
+
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	int			ret;
+
+	is_on = !!is_on;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = dwc3_gadget_run_stop(dwc, is_on, false);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
+{
+	u32			reg;
+
+	/* Enable all but Start and End of Frame IRQs */
+	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+			DWC3_DEVTEN_EVNTOVERFLOWEN |
+			DWC3_DEVTEN_CMDCMPLTEN |
+			DWC3_DEVTEN_ERRTICERREN |
+			DWC3_DEVTEN_WKUPEVTEN |
+			DWC3_DEVTEN_ULSTCNGEN |
+			DWC3_DEVTEN_CONNECTDONEEN |
+			DWC3_DEVTEN_USBRSTEN |
+			DWC3_DEVTEN_DISCONNEVTEN);
+
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+}
+
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
+{
+	/* mask all interrupts */
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_ep		*dep;
+	unsigned long		flags;
+	int			ret = 0;
+	u32			reg;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	if (dwc->gadget_driver) {
+		dev_err(dwc->dev, "%s is already bound to %s\n",
+				dwc->gadget.name,
+				dwc->gadget_driver->function);
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	dwc->gadget_driver	= driver;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+	/**
+	 * WORKAROUND: DWC3 revision < 2.20a have an issue
+	 * which would cause metastability state on Run/Stop
+	 * bit if we try to force the IP to USB2-only mode.
+	 *
+	 * Because of that, we cannot configure the IP to any
+	 * speed other than the SuperSpeed
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000525659: Clock Domain Crossing on DCTL in
+	 * USB 2.0 Mode
+	 */
+	if (dwc->revision < DWC3_REVISION_220A) {
+		reg |= DWC3_DCFG_SUPERSPEED;
+	} else {
+		switch (dwc->maximum_speed) {
+		case USB_SPEED_LOW:
+			reg |= DWC3_DSTS_LOWSPEED;
+			break;
+		case USB_SPEED_FULL:
+			reg |= DWC3_DSTS_FULLSPEED1;
+			break;
+		case USB_SPEED_HIGH:
+			reg |= DWC3_DSTS_HIGHSPEED;
+			break;
+		case USB_SPEED_SUPER:	/* FALLTHROUGH */
+		case USB_SPEED_UNKNOWN:	/* FALTHROUGH */
+		default:
+			reg |= DWC3_DSTS_SUPERSPEED;
+		}
+	}
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	dwc->start_config_issued = false;
+
+	/* Start with SuperSpeed Default */
+	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+			false);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err2;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+			false);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err3;
+	}
+
+	/* begin to receive SETUP packets */
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+
+	dwc3_gadget_enable_irq(dwc);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+
+err3:
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err2:
+	dwc->gadget_driver = NULL;
+
+err1:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_stop(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	dwc3_gadget_disable_irq(dwc);
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+	__dwc3_gadget_ep_disable(dwc->eps[1]);
+
+	dwc->gadget_driver	= NULL;
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops dwc3_gadget_ops = {
+	.get_frame		= dwc3_gadget_get_frame,
+	.wakeup			= dwc3_gadget_wakeup,
+	.set_selfpowered	= dwc3_gadget_set_selfpowered,
+	.pullup			= dwc3_gadget_pullup,
+	.udc_start		= dwc3_gadget_start,
+	.udc_stop		= dwc3_gadget_stop,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
+		u8 num, u32 direction)
+{
+	struct dwc3_ep			*dep;
+	u8				i;
+
+	for (i = 0; i < num; i++) {
+		u8 epnum = (i << 1) | (!!direction);
+
+		dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+		if (!dep)
+			return -ENOMEM;
+
+		dep->dwc = dwc;
+		dep->number = epnum;
+		dep->direction = !!direction;
+		dwc->eps[epnum] = dep;
+
+		snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+				(epnum & 1) ? "in" : "out");
+
+		dep->endpoint.name = dep->name;
+
+		dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
+
+		if (epnum == 0 || epnum == 1) {
+			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
+			dep->endpoint.maxburst = 1;
+			dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+			if (!epnum)
+				dwc->gadget.ep0 = &dep->endpoint;
+		} else {
+			int		ret;
+
+			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
+			dep->endpoint.max_streams = 15;
+			dep->endpoint.ops = &dwc3_gadget_ep_ops;
+			list_add_tail(&dep->endpoint.ep_list,
+					&dwc->gadget.ep_list);
+
+			ret = dwc3_alloc_trb_pool(dep);
+			if (ret)
+				return ret;
+		}
+
+		INIT_LIST_HEAD(&dep->request_list);
+		INIT_LIST_HEAD(&dep->req_queued);
+	}
+
+	return 0;
+}
+
+static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+	int				ret;
+
+	INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
+	if (ret < 0) {
+		dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
+		return ret;
+	}
+
+	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
+	if (ret < 0) {
+		dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
+{
+	struct dwc3_ep			*dep;
+	u8				epnum;
+
+	for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		dep = dwc->eps[epnum];
+		if (!dep)
+			continue;
+		/*
+		 * Physical endpoints 0 and 1 are special; they form the
+		 * bi-directional USB endpoint 0.
+		 *
+		 * For those two physical endpoints, we don't allocate a TRB
+		 * pool nor do we add them the endpoints list. Due to that, we
+		 * shouldn't do these two operations otherwise we would end up
+		 * with all sorts of bugs when removing dwc3.ko.
+		 */
+		if (epnum != 0 && epnum != 1) {
+			dwc3_free_trb_pool(dep);
+			list_del(&dep->endpoint.ep_list);
+		}
+
+		kfree(dep);
+	}
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
+		struct dwc3_request *req, struct dwc3_trb *trb,
+		const struct dwc3_event_depevt *event, int status)
+{
+	unsigned int		count;
+	unsigned int		s_pkt = 0;
+	unsigned int		trb_status;
+
+	if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
+		/*
+		 * We continue despite the error. There is not much we
+		 * can do. If we don't clean it up we loop forever. If
+		 * we skip the TRB then it gets overwritten after a
+		 * while since we use them in a ring buffer. A BUG()
+		 * would help. Lets hope that if this occurs, someone
+		 * fixes the root cause instead of looking away :)
+		 */
+		dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+				dep->name, trb);
+	count = trb->size & DWC3_TRB_SIZE_MASK;
+
+	if (dep->direction) {
+		if (count) {
+			trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+			if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
+				dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
+						dep->name);
+				/*
+				 * If missed isoc occurred and there is
+				 * no request queued then issue END
+				 * TRANSFER, so that core generates
+				 * next xfernotready and we will issue
+				 * a fresh START TRANSFER.
+				 * If there are still queued request
+				 * then wait, do not issue either END
+				 * or UPDATE TRANSFER, just attach next
+				 * request in request_list during
+				 * giveback.If any future queued request
+				 * is successfully transferred then we
+				 * will issue UPDATE TRANSFER for all
+				 * request in the request_list.
+				 */
+				dep->flags |= DWC3_EP_MISSED_ISOC;
+			} else {
+				dev_err(dwc->dev, "incomplete IN transfer %s\n",
+						dep->name);
+				status = -ECONNRESET;
+			}
+		} else {
+			dep->flags &= ~DWC3_EP_MISSED_ISOC;
+		}
+	} else {
+		if (count && (event->status & DEPEVT_STATUS_SHORT))
+			s_pkt = 1;
+	}
+
+	/*
+	 * We assume here we will always receive the entire data block
+	 * which we should receive. Meaning, if we program RX to
+	 * receive 4K but we receive only 2K, we assume that's all we
+	 * should receive and we simply bounce the request back to the
+	 * gadget driver for further processing.
+	 */
+	req->request.actual += req->request.length - count;
+	if (s_pkt)
+		return 1;
+	if ((event->status & DEPEVT_STATUS_LST) &&
+			(trb->ctrl & (DWC3_TRB_CTRL_LST |
+				DWC3_TRB_CTRL_HWO)))
+		return 1;
+	if ((event->status & DEPEVT_STATUS_IOC) &&
+			(trb->ctrl & DWC3_TRB_CTRL_IOC))
+		return 1;
+	return 0;
+}
+
+static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event, int status)
+{
+	struct dwc3_request	*req;
+	struct dwc3_trb		*trb;
+	unsigned int		slot;
+
+	req = next_request(&dep->req_queued);
+	if (!req) {
+		WARN_ON_ONCE(1);
+		return 1;
+	}
+
+	slot = req->start_slot;
+	if ((slot == DWC3_TRB_NUM - 1) &&
+	    usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		slot++;
+	slot %= DWC3_TRB_NUM;
+	trb = &dep->trb_pool[slot];
+
+	dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+	__dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
+	dwc3_gadget_giveback(dep, req, status);
+
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+			list_empty(&dep->req_queued)) {
+		if (list_empty(&dep->request_list)) {
+			/*
+			 * If there is no entry in request list then do
+			 * not issue END TRANSFER now. Just set PENDING
+			 * flag, so that END TRANSFER is issued when an
+			 * entry is added into request list.
+			 */
+			dep->flags = DWC3_EP_PENDING_REQUEST;
+		} else {
+			dwc3_stop_active_transfer(dwc, dep->number, true);
+			dep->flags = DWC3_EP_ENABLED;
+		}
+		return 1;
+	}
+
+	return 1;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+	unsigned		status = 0;
+	int			clean_busy;
+
+	if (event->status & DEPEVT_STATUS_BUSERR)
+		status = -ECONNRESET;
+
+	clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+	if (clean_busy)
+		dep->flags &= ~DWC3_EP_BUSY;
+
+	/*
+	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
+	 * See dwc3_gadget_linksts_change_interrupt() for 1st half.
+	 */
+	if (dwc->revision < DWC3_REVISION_183A) {
+		u32		reg;
+		int		i;
+
+		for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+			dep = dwc->eps[i];
+
+			if (!(dep->flags & DWC3_EP_ENABLED))
+				continue;
+
+			if (!list_empty(&dep->req_queued))
+				return;
+		}
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg |= dwc->u1u2;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+		dwc->u1u2 = 0;
+	}
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	u8			epnum = event->endpoint_number;
+
+	dep = dwc->eps[epnum];
+
+	if (!(dep->flags & DWC3_EP_ENABLED))
+		return;
+
+	if (epnum == 0 || epnum == 1) {
+		dwc3_ep0_interrupt(dwc, event);
+		return;
+	}
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		dep->resource_index = 0;
+
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+					dep->name);
+			return;
+		}
+
+		dwc3_endpoint_transfer_complete(dwc, dep, event);
+		break;
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		dwc3_endpoint_transfer_complete(dwc, dep, event);
+		break;
+	case DWC3_DEPEVT_XFERNOTREADY:
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+			dwc3_gadget_start_isoc(dwc, dep, event);
+		} else {
+			int ret;
+
+			dev_vdbg(dwc->dev, "%s: reason %s\n",
+					dep->name, event->status &
+					DEPEVT_STATUS_TRANSFER_ACTIVE
+					? "Transfer Active"
+					: "Transfer Not Active");
+
+			ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+			if (!ret || ret == -EBUSY)
+				return;
+
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		}
+
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
+		if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
+			dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
+					dep->name);
+			return;
+		}
+
+		switch (event->status) {
+		case DEPEVT_STREAMEVT_FOUND:
+			dev_vdbg(dwc->dev, "Stream %d found and started\n",
+					event->parameters);
+
+			break;
+		case DEPEVT_STREAMEVT_NOTFOUND:
+			/* FALLTHROUGH */
+		default:
+			dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+		}
+		break;
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
+		break;
+	}
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+	if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+		spin_unlock(&dwc->lock);
+		dwc->gadget_driver->disconnect(&dwc->gadget);
+		spin_lock(&dwc->lock);
+	}
+}
+
+static void dwc3_suspend_gadget(struct dwc3 *dwc)
+{
+	if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
+		spin_unlock(&dwc->lock);
+		dwc->gadget_driver->suspend(&dwc->gadget);
+		spin_lock(&dwc->lock);
+	}
+}
+
+static void dwc3_resume_gadget(struct dwc3 *dwc)
+{
+	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
+		spin_unlock(&dwc->lock);
+		dwc->gadget_driver->resume(&dwc->gadget);
+	}
+}
+
+static void dwc3_reset_gadget(struct dwc3 *dwc)
+{
+	if (!dwc->gadget_driver)
+		return;
+
+	if (dwc->gadget.speed != USB_SPEED_UNKNOWN) {
+		spin_unlock(&dwc->lock);
+		usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver);
+		spin_lock(&dwc->lock);
+	}
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
+{
+	struct dwc3_ep *dep;
+	struct dwc3_gadget_ep_cmd_params params;
+	u32 cmd;
+	int ret;
+
+	dep = dwc->eps[epnum];
+
+	if (!dep->resource_index)
+		return;
+
+	/*
+	 * NOTICE: We are violating what the Databook says about the
+	 * EndTransfer command. Ideally we would _always_ wait for the
+	 * EndTransfer Command Completion IRQ, but that's causing too
+	 * much trouble synchronizing between us and gadget driver.
+	 *
+	 * We have discussed this with the IP Provider and it was
+	 * suggested to giveback all requests here, but give HW some
+	 * extra time to synchronize with the interconnect. We're using
+	 * an arbitraty 100us delay for that.
+	 *
+	 * Note also that a similar handling was tested by Synopsys
+	 * (thanks a lot Paul) and nothing bad has come out of it.
+	 * In short, what we're doing is:
+	 *
+	 * - Issue EndTransfer WITH CMDIOC bit set
+	 * - Wait 100us
+	 */
+
+	cmd = DWC3_DEPCMD_ENDTRANSFER;
+	cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
+	cmd |= DWC3_DEPCMD_CMDIOC;
+	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
+	memset(&params, 0, sizeof(params));
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	WARN_ON_ONCE(ret);
+	dep->resource_index = 0;
+	dep->flags &= ~DWC3_EP_BUSY;
+	udelay(100);
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+
+		dep = dwc->eps[epnum];
+		if (!dep)
+			continue;
+
+		if (!(dep->flags & DWC3_EP_ENABLED))
+			continue;
+
+		dwc3_remove_requests(dwc, dep);
+	}
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+		struct dwc3_gadget_ep_cmd_params params;
+		int ret;
+
+		dep = dwc->eps[epnum];
+		if (!dep)
+			continue;
+
+		if (!(dep->flags & DWC3_EP_STALL))
+			continue;
+
+		dep->flags &= ~DWC3_EP_STALL;
+
+		memset(&params, 0, sizeof(params));
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+				DWC3_DEPCMD_CLEARSTALL, &params);
+		WARN_ON_ONCE(ret);
+	}
+}
+
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+{
+	int			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_INITU1ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	reg &= ~DWC3_DCTL_INITU2ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	dwc3_disconnect_gadget(dwc);
+	dwc->start_config_issued = false;
+
+	dwc->gadget.speed = USB_SPEED_UNKNOWN;
+	dwc->setup_packet_pending = false;
+	usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+	u32			reg;
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.88a have an issue which
+	 * would cause a missing Disconnect Event if there's a
+	 * pending Setup Packet in the FIFO.
+	 *
+	 * There's no suggested workaround on the official Bug
+	 * report, which states that "unless the driver/application
+	 * is doing any special handling of a disconnect event,
+	 * there is no functional issue".
+	 *
+	 * Unfortunately, it turns out that we _do_ some special
+	 * handling of a disconnect event, namely complete all
+	 * pending transfers, notify gadget driver of the
+	 * disconnection, and so on.
+	 *
+	 * Our suggested workaround is to follow the Disconnect
+	 * Event steps here, instead, based on a setup_packet_pending
+	 * flag. Such flag gets set whenever we have a XferNotReady
+	 * event on EP0 and gets cleared on XferComplete for the
+	 * same endpoint.
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000466709: RTL: Device : Disconnect event not
+	 * generated if setup packet pending in FIFO
+	 */
+	if (dwc->revision < DWC3_REVISION_188A) {
+		if (dwc->setup_packet_pending)
+			dwc3_gadget_disconnect_interrupt(dwc);
+	}
+
+	dwc3_reset_gadget(dwc);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	dwc->test_mode = false;
+
+	dwc3_stop_active_transfers(dwc);
+	dwc3_clear_stall_all_ep(dwc);
+	dwc->start_config_issued = false;
+
+	/* Reset device address to zero */
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
+{
+	u32 reg;
+	u32 usb30_clock = DWC3_GCTL_CLK_BUS;
+
+	/*
+	 * We change the clock only at SS but I dunno why I would want to do
+	 * this. Maybe it becomes part of the power saving plan.
+	 */
+
+	if (speed != DWC3_DSTS_SUPERSPEED)
+		return;
+
+	/*
+	 * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+	 * each time on Connect Done.
+	 */
+	if (!usb30_clock)
+		return;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+{
+	struct dwc3_ep		*dep;
+	int			ret;
+	u32			reg;
+	u8			speed;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	dwc->speed = speed;
+
+	dwc3_update_ram_clk_sel(dwc, speed);
+
+	switch (speed) {
+	case DWC3_DCFG_SUPERSPEED:
+		/*
+		 * WORKAROUND: DWC3 revisions <1.90a have an issue which
+		 * would cause a missing USB3 Reset event.
+		 *
+		 * In such situations, we should force a USB3 Reset
+		 * event by calling our dwc3_gadget_reset_interrupt()
+		 * routine.
+		 *
+		 * Refers to:
+		 *
+		 * STAR#9000483510: RTL: SS : USB3 reset event may
+		 * not be generated always when the link enters poll
+		 */
+		if (dwc->revision < DWC3_REVISION_190A)
+			dwc3_gadget_reset_interrupt(dwc);
+
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+		dwc->gadget.ep0->maxpacket = 512;
+		dwc->gadget.speed = USB_SPEED_SUPER;
+		break;
+	case DWC3_DCFG_HIGHSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case DWC3_DCFG_FULLSPEED2:
+	case DWC3_DCFG_FULLSPEED1:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_FULL;
+		break;
+	case DWC3_DCFG_LOWSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+		dwc->gadget.ep0->maxpacket = 8;
+		dwc->gadget.speed = USB_SPEED_LOW;
+		break;
+	}
+
+	/* Enable USB2 LPM Capability */
+
+	if ((dwc->revision > DWC3_REVISION_194A)
+			&& (speed != DWC3_DCFG_SUPERSPEED)) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+		reg |= DWC3_DCFG_LPM_CAP;
+		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+
+		reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold);
+
+		/*
+		 * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and
+		 * DCFG.LPMCap is set, core responses with an ACK and the
+		 * BESL value in the LPM token is less than or equal to LPM
+		 * NYET threshold.
+		 */
+		if (dwc->revision < DWC3_REVISION_240A 	&& dwc->has_lpm_erratum)
+			WARN(true, "LPM Erratum not available on dwc3 revisisions < 2.40a\n");
+
+		if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
+			reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold);
+
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	} else {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true,
+			false);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		return;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true,
+			false);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		return;
+	}
+
+	/*
+	 * Configure PHY via GUSB3PIPECTLn if required.
+	 *
+	 * Update GTXFIFOSIZn
+	 *
+	 * In both cases reset values should be sufficient.
+	 */
+}
+
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+{
+	/*
+	 * TODO take core out of low power mode when that's
+	 * implemented.
+	 */
+
+	dwc->gadget_driver->resume(&dwc->gadget);
+}
+
+static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+		unsigned int evtinfo)
+{
+	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK;
+	unsigned int		pwropt;
+
+	/*
+	 * WORKAROUND: DWC3 < 2.50a have an issue when configured without
+	 * Hibernation mode enabled which would show up when device detects
+	 * host-initiated U3 exit.
+	 *
+	 * In that case, device will generate a Link State Change Interrupt
+	 * from U3 to RESUME which is only necessary if Hibernation is
+	 * configured in.
+	 *
+	 * There are no functional changes due to such spurious event and we
+	 * just need to ignore it.
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
+	 * operational mode
+	 */
+	pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
+	if ((dwc->revision < DWC3_REVISION_250A) &&
+			(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
+		if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
+				(next == DWC3_LINK_STATE_RESUME)) {
+			dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
+			return;
+		}
+	}
+
+	/*
+	 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
+	 * on the link partner, the USB session might do multiple entry/exit
+	 * of low power states before a transfer takes place.
+	 *
+	 * Due to this problem, we might experience lower throughput. The
+	 * suggested workaround is to disable DCTL[12:9] bits if we're
+	 * transitioning from U1/U2 to U0 and enable those bits again
+	 * after a transfer completes and there are no pending transfers
+	 * on any of the enabled endpoints.
+	 *
+	 * This is the first half of that workaround.
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
+	 * core send LGO_Ux entering U0
+	 */
+	if (dwc->revision < DWC3_REVISION_183A) {
+		if (next == DWC3_LINK_STATE_U0) {
+			u32	u1u2;
+			u32	reg;
+
+			switch (dwc->link_state) {
+			case DWC3_LINK_STATE_U1:
+			case DWC3_LINK_STATE_U2:
+				reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+				u1u2 = reg & (DWC3_DCTL_INITU2ENA
+						| DWC3_DCTL_ACCEPTU2ENA
+						| DWC3_DCTL_INITU1ENA
+						| DWC3_DCTL_ACCEPTU1ENA);
+
+				if (!dwc->u1u2)
+					dwc->u1u2 = reg & u1u2;
+
+				reg &= ~u1u2;
+
+				dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+	}
+
+	switch (next) {
+	case DWC3_LINK_STATE_U1:
+		if (dwc->speed == USB_SPEED_SUPER)
+			dwc3_suspend_gadget(dwc);
+		break;
+	case DWC3_LINK_STATE_U2:
+	case DWC3_LINK_STATE_U3:
+		dwc3_suspend_gadget(dwc);
+		break;
+	case DWC3_LINK_STATE_RESUME:
+		dwc3_resume_gadget(dwc);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	dwc->link_state = next;
+}
+
+static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
+		unsigned int evtinfo)
+{
+	unsigned int is_ss = evtinfo & (1UL << 4);
+
+	/**
+	 * WORKAROUND: DWC3 revison 2.20a with hibernation support
+	 * have a known issue which can cause USB CV TD.9.23 to fail
+	 * randomly.
+	 *
+	 * Because of this issue, core could generate bogus hibernation
+	 * events which SW needs to ignore.
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
+	 * Device Fallback from SuperSpeed
+	 */
+	if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
+		return;
+
+	/* enter hibernation here */
+}
+
+static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_devt *event)
+{
+	switch (event->type) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		dwc3_gadget_disconnect_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_RESET:
+		dwc3_gadget_reset_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		dwc3_gadget_conndone_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		dwc3_gadget_wakeup_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_HIBER_REQ:
+		if (!dwc->has_hibernation) {
+			WARN(1 ,"unexpected hibernation event\n");
+			break;
+		}
+		dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
+		break;
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+		break;
+	case DWC3_DEVICE_EVENT_EOPF:
+		dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+		break;
+	case DWC3_DEVICE_EVENT_SOF:
+		dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+		break;
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		dev_vdbg(dwc->dev, "Erratic Error\n");
+		break;
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		dev_vdbg(dwc->dev, "Command Complete\n");
+		break;
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		dev_vdbg(dwc->dev, "Overflow\n");
+		break;
+	default:
+		dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+	}
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+		const union dwc3_event *event)
+{
+	/* Endpoint IRQ, handle it and return early */
+	if (event->type.is_devspec == 0) {
+		/* depevt */
+		return dwc3_endpoint_interrupt(dwc, &event->depevt);
+	}
+
+	switch (event->type.type) {
+	case DWC3_EVENT_TYPE_DEV:
+		dwc3_gadget_interrupt(dwc, &event->devt);
+		break;
+	/* REVISIT what to do with Carkit and I2C events ? */
+	default:
+		dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+	}
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+	struct dwc3_event_buffer *evt;
+	irqreturn_t ret = IRQ_NONE;
+	int left;
+	u32 reg;
+
+	evt = dwc->ev_buffs[buf];
+	left = evt->count;
+
+	if (!(evt->flags & DWC3_EVENT_PENDING))
+		return IRQ_NONE;
+
+	while (left > 0) {
+		union dwc3_event event;
+
+		event.raw = *(u32 *) (evt->buf + evt->lpos);
+
+		dwc3_process_event_entry(dwc, &event);
+
+		/*
+		 * FIXME we wrap around correctly to the next entry as
+		 * almost all entries are 4 bytes in size. There is one
+		 * entry which has 12 bytes which is a regular entry
+		 * followed by 8 bytes data. ATM I don't know how
+		 * things are organized if we get next to the a
+		 * boundary so I worry about that once we try to handle
+		 * that.
+		 */
+		evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+		left -= 4;
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+	}
+
+	evt->count = 0;
+	evt->flags &= ~DWC3_EVENT_PENDING;
+	ret = IRQ_HANDLED;
+
+	/* Unmask interrupt */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+	reg &= ~DWC3_GEVNTSIZ_INTMASK;
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
+	return ret;
+}
+
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+	struct dwc3 *dwc = _dwc;
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+	int i;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	for (i = 0; i < dwc->num_event_buffers; i++)
+		ret |= dwc3_process_event_buf(dwc, i);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
+{
+	struct dwc3_event_buffer *evt;
+	u32 count;
+	u32 reg;
+
+	evt = dwc->ev_buffs[buf];
+
+	count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
+	count &= DWC3_GEVNTCOUNT_MASK;
+	if (!count)
+		return IRQ_NONE;
+
+	evt->count = count;
+	evt->flags |= DWC3_EVENT_PENDING;
+
+	/* Mask interrupt */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+	reg |= DWC3_GEVNTSIZ_INTMASK;
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+{
+	struct dwc3			*dwc = _dwc;
+	int				i;
+	irqreturn_t			ret = IRQ_NONE;
+
+	spin_lock(&dwc->lock);
+
+	for (i = 0; i < dwc->num_event_buffers; i++) {
+		irqreturn_t status;
+
+		status = dwc3_check_event_buf(dwc, i);
+		if (status == IRQ_WAKE_THREAD)
+			ret = status;
+	}
+
+	spin_unlock(&dwc->lock);
+
+	return ret;
+}
+
+/**
+ * dwc3_gadget_init - Initializes gadget related registers
+ * @dwc: pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int dwc3_gadget_init(struct dwc3 *dwc)
+{
+	int					ret;
+
+	dwc->ctrl_req = dma_alloc_coherent(sizeof(*dwc->ctrl_req),
+					(unsigned long *)&dwc->ctrl_req_addr);
+	if (!dwc->ctrl_req) {
+		dev_err(dwc->dev, "failed to allocate ctrl request\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	dwc->ep0_trb = dma_alloc_coherent(sizeof(*dwc->ep0_trb) * 2,
+					  (unsigned long *)&dwc->ep0_trb_addr);
+	if (!dwc->ep0_trb) {
+		dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
+				  DWC3_EP0_BOUNCE_SIZE);
+	if (!dwc->setup_buf) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	dwc->ep0_bounce = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE,
+					(unsigned long *)&dwc->ep0_bounce_addr);
+	if (!dwc->ep0_bounce) {
+		dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	dwc->gadget.ops			= &dwc3_gadget_ops;
+	dwc->gadget.max_speed		= USB_SPEED_SUPER;
+	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
+	dwc->gadget.name		= "dwc3-gadget";
+
+	/*
+	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
+	 * on ep out.
+	 */
+	dwc->gadget.quirk_ep_out_aligned_size = true;
+
+	/*
+	 * REVISIT: Here we should clear all pending IRQs to be
+	 * sure we're starting from a well known location.
+	 */
+
+	ret = dwc3_gadget_init_endpoints(dwc);
+	if (ret)
+		goto err4;
+
+	ret = usb_add_gadget_udc((struct device *)dwc->dev, &dwc->gadget);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register udc\n");
+		goto err4;
+	}
+
+	return 0;
+
+err4:
+	dwc3_gadget_free_endpoints(dwc);
+	dma_free_coherent(dwc->ep0_bounce);
+
+err3:
+	kfree(dwc->setup_buf);
+
+err2:
+	dma_free_coherent(dwc->ep0_trb);
+
+err1:
+	dma_free_coherent(dwc->ctrl_req);
+
+err0:
+	return ret;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void dwc3_gadget_exit(struct dwc3 *dwc)
+{
+	usb_del_gadget_udc(&dwc->gadget);
+
+	dwc3_gadget_free_endpoints(dwc);
+
+	dma_free_coherent(dwc->ep0_bounce);
+
+	kfree(dwc->setup_buf);
+
+	dma_free_coherent(dwc->ep0_trb);
+
+	dma_free_coherent(dwc->ctrl_req);
+}
+
+/**
+ * dwc3_gadget_uboot_handle_interrupt - handle dwc3 gadget interrupt
+ * @dwc: struct dwce *
+ *
+ * Handles ep0 and gadget interrupt
+ *
+ * Should be called from dwc3 core.
+ */
+void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc)
+{
+	int ret = dwc3_interrupt(0, dwc);
+
+	if (ret == IRQ_WAKE_THREAD) {
+		int i;
+		struct dwc3_event_buffer *evt;
+
+		dwc3_thread_interrupt(0, dwc);
+
+		/* Clean + Invalidate the buffers after touching them */
+		for (i = 0; i < dwc->num_event_buffers; i++) {
+			evt = dwc->ev_buffs[i];
+			dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
+		}
+	}
+}
diff --git a/roms/u-boot/drivers/usb/dwc3/gadget.h b/roms/u-boot/drivers/usb/dwc3/gadget.h
new file mode 100644
index 000000000..7806ce59a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/gadget.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/gadget.h) and ported
+ * to uboot.
+ *
+ * commit 7a60855972 : usb: dwc3: gadget: fix set_halt() bug with pending
+		       transfers
+ *
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GADGET_H
+#define __DRIVERS_USB_DWC3_GADGET_H
+
+#include <linux/list.h>
+#include <linux/usb/gadget.h>
+#include "io.h"
+
+struct dwc3;
+#define to_dwc3_ep(ep)		(container_of(ep, struct dwc3_ep, endpoint))
+#define gadget_to_dwc(g)	(container_of(g, struct dwc3, gadget))
+
+/* DEPCFG parameter 1 */
+#define DWC3_DEPCFG_INT_NUM(n)		((n) << 0)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN	(1 << 8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN	(1 << 9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN	(1 << 10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN	(1 << 11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN	(1 << 13)
+#define DWC3_DEPCFG_BINTERVAL_M1(n)	((n) << 16)
+#define DWC3_DEPCFG_STREAM_CAPABLE	(1 << 24)
+#define DWC3_DEPCFG_EP_NUMBER(n)	((n) << 25)
+#define DWC3_DEPCFG_BULK_BASED		(1 << 30)
+#define DWC3_DEPCFG_FIFO_BASED		(1 << 31)
+
+/* DEPCFG parameter 0 */
+#define DWC3_DEPCFG_EP_TYPE(n)		((n) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n)	((n) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
+#define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
+/* This applies for core versions earlier than 1.94a */
+#define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
+/* These apply for core versions 1.94a and later */
+#define DWC3_DEPCFG_ACTION_INIT		(0 << 30)
+#define DWC3_DEPCFG_ACTION_RESTORE	(1 << 30)
+#define DWC3_DEPCFG_ACTION_MODIFY	(2 << 30)
+
+/* DEPXFERCFG parameter 0 */
+#define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
+
+/* -------------------------------------------------------------------------- */
+
+#define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))
+
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+	if (list_empty(list))
+		return NULL;
+
+	return list_first_entry(list, struct dwc3_request, list);
+}
+
+static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
+{
+	struct dwc3_ep		*dep = req->dep;
+
+	req->queued = true;
+	list_move_tail(&req->list, &dep->req_queued);
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status);
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event);
+void dwc3_ep0_out_start(struct dwc3 *dwc);
+int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+		gfp_t gfp_flags);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
+void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc);
+
+/**
+ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+ * @dwc: DesignWare USB3 Pointer
+ * @number: DWC endpoint number
+ *
+ * Caller should take care of locking
+ */
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+{
+	u32			res_id;
+
+	res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+
+	return DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */
diff --git a/roms/u-boot/drivers/usb/dwc3/io.h b/roms/u-boot/drivers/usb/dwc3/io.h
new file mode 100644
index 000000000..2407f826c
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/io.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/io.h) and ported
+ * to uboot.
+ *
+ * commit 2c4cbe6e5a : usb: dwc3: add tracepoints to aid debugging
+ *
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <cpu_func.h>
+#include <asm/io.h>
+
+#define	CACHELINE_SIZE		CONFIG_SYS_CACHELINE_SIZE
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+	unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
+	u32 value;
+
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	value = readl(base + offs);
+
+	return value;
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
+
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	writel(value, base + offs);
+}
+
+static inline void dwc3_flush_cache(uintptr_t addr, int length)
+{
+	flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE));
+}
+#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/roms/u-boot/drivers/usb/dwc3/linux-compat.h b/roms/u-boot/drivers/usb/dwc3/linux-compat.h
new file mode 100644
index 000000000..3bb0bda5a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/linux-compat.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * linux-compat.h - DesignWare USB3 Linux Compatibiltiy Adapter  Header
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ */
+
+#ifndef __DWC3_LINUX_COMPAT__
+#define __DWC3_LINUX_COMPAT__
+
+#define dev_WARN(dev, format, arg...)	debug(format, ##arg)
+
+#endif
diff --git a/roms/u-boot/drivers/usb/dwc3/samsung_usb_phy.c b/roms/u-boot/drivers/usb/dwc3/samsung_usb_phy.c
new file mode 100644
index 000000000..abbd41368
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/samsung_usb_phy.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * samsung_usb_phy.c - DesignWare USB3 (DWC3) PHY handling file
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ */
+
+#include <common.h>
+#include <asm/arch/power.h>
+#include <asm/arch/xhci-exynos.h>
+#include <linux/delay.h>
+
+void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
+{
+	u32 reg;
+
+	/* Reset USB 3.0 PHY */
+	writel(0x0, &phy->phy_reg0);
+
+	clrbits_le32(&phy->phy_param0,
+			/* Select PHY CLK source */
+			PHYPARAM0_REF_USE_PAD |
+			/* Set Loss-of-Signal Detector sensitivity */
+			PHYPARAM0_REF_LOSLEVEL_MASK);
+	setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
+
+
+	writel(0x0, &phy->phy_resume);
+
+	/*
+	 * Setting the Frame length Adj value[6:1] to default 0x20
+	 * See xHCI 1.0 spec, 5.2.4
+	 */
+	setbits_le32(&phy->link_system,
+			LINKSYSTEM_XHCI_VERSION_CONTROL |
+			LINKSYSTEM_FLADJ(0x20));
+
+	/* Set Tx De-Emphasis level */
+	clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
+	setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
+
+	setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
+
+	/* PHYTEST POWERDOWN Control */
+	clrbits_le32(&phy->phy_test,
+			PHYTEST_POWERDOWN_SSP |
+			PHYTEST_POWERDOWN_HSP);
+
+	/* UTMI Power Control */
+	writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
+
+		/* Use core clock from main PLL */
+	reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+		/* Default 24Mhz crystal clock */
+		PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
+		PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+		PHYCLKRST_SSC_REFCLKSEL(0) |
+		/* Force PortReset of PHY */
+		PHYCLKRST_PORTRESET |
+		/* Digital power supply in normal operating mode */
+		PHYCLKRST_RETENABLEN |
+		/* Enable ref clock for SS function */
+		PHYCLKRST_REF_SSP_EN |
+		/* Enable spread spectrum */
+		PHYCLKRST_SSC_EN |
+		/* Power down HS Bias and PLL blocks in suspend mode */
+		PHYCLKRST_COMMONONN;
+
+	writel(reg, &phy->phy_clk_rst);
+
+	/* giving time to Phy clock to settle before resetting */
+	udelay(10);
+
+	reg &= ~PHYCLKRST_PORTRESET;
+	writel(reg, &phy->phy_clk_rst);
+}
diff --git a/roms/u-boot/drivers/usb/dwc3/ti_usb_phy.c b/roms/u-boot/drivers/usb/dwc3/ti_usb_phy.c
new file mode 100644
index 000000000..f47681076
--- /dev/null
+++ b/roms/u-boot/drivers/usb/dwc3/ti_usb_phy.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * ti_usb_phy.c - USB3 and USB3 PHY programming for dwc3
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Taken from Linux Kernel v3.16 (drivers/phy/phy-ti-pipe3.c and
+ * drivers/phy/phy-omap-usb2.c) and ported to uboot.
+ *
+ * "commit 56042e : phy: ti-pipe3: Fix suspend/resume and module reload" for
+ * phy-ti-pipe3.c
+ *
+ * "commit eb82a3 : phy: omap-usb2: Balance pm_runtime_enable() on probe failure
+ * and remove" for phy-omap-usb2.c
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <ti-usb-phy-uboot.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <dm.h>
+
+#include "linux-compat.h"
+
+#define PLL_STATUS		0x00000004
+#define PLL_GO			0x00000008
+#define PLL_CONFIGURATION1	0x0000000C
+#define PLL_CONFIGURATION2	0x00000010
+#define PLL_CONFIGURATION3	0x00000014
+#define PLL_CONFIGURATION4	0x00000020
+
+#define PLL_REGM_MASK		0x001FFE00
+#define PLL_REGM_SHIFT		0x9
+#define PLL_REGM_F_MASK		0x0003FFFF
+#define PLL_REGM_F_SHIFT	0x0
+#define PLL_REGN_MASK		0x000001FE
+#define PLL_REGN_SHIFT		0x1
+#define PLL_SELFREQDCO_MASK	0x0000000E
+#define PLL_SELFREQDCO_SHIFT	0x1
+#define PLL_SD_MASK		0x0003FC00
+#define PLL_SD_SHIFT		10
+#define SET_PLL_GO		0x1
+#define PLL_LDOPWDN		BIT(15)
+#define PLL_TICOPWDN		BIT(16)
+#define PLL_LOCK		0x2
+#define PLL_IDLE		0x1
+
+#define OMAP_CTRL_DEV_PHY_PD				BIT(0)
+#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_MASK		0x003FC000
+#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_SHIFT		0xE
+
+#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_MASK		0xFFC00000
+#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_SHIFT	0x16
+
+#define OMAP_CTRL_USB3_PHY_TX_RX_POWERON	0x3
+#define OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF	0x0
+
+#define OMAP_CTRL_USB2_PHY_PD			BIT(28)
+
+#define AM437X_CTRL_USB2_PHY_PD			BIT(0)
+#define AM437X_CTRL_USB2_OTG_PD			BIT(1)
+#define AM437X_CTRL_USB2_OTGVDET_EN		BIT(19)
+#define AM437X_CTRL_USB2_OTGSESSEND_EN		BIT(20)
+
+static LIST_HEAD(ti_usb_phy_list);
+typedef unsigned int u32;
+
+struct usb3_dpll_params {
+	u16	m;
+	u8	n;
+	u8	freq:3;
+	u8	sd;
+	u32	mf;
+};
+
+struct usb3_dpll_map {
+	unsigned long rate;
+	struct usb3_dpll_params params;
+	struct usb3_dpll_map *dpll_map;
+};
+
+struct ti_usb_phy {
+	void __iomem *pll_ctrl_base;
+	void __iomem *usb2_phy_power;
+	void __iomem *usb3_phy_power;
+	struct usb3_dpll_map *dpll_map;
+	struct list_head list;
+	int index;
+};
+
+static struct usb3_dpll_map dpll_map_usb[] = {
+	{12000000, {1250, 5, 4, 20, 0} },	/* 12 MHz */
+	{16800000, {3125, 20, 4, 20, 0} },	/* 16.8 MHz */
+	{19200000, {1172, 8, 4, 20, 65537} },	/* 19.2 MHz */
+	{20000000, {1000, 7, 4, 10, 0} },	/* 20 MHz */
+	{26000000, {1250, 12, 4, 20, 0} },	/* 26 MHz */
+	{38400000, {3125, 47, 4, 20, 92843} },	/* 38.4 MHz */
+	{ },					/* Terminator */
+};
+
+static inline unsigned int ti_usb3_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void ti_usb3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+#ifndef CONFIG_AM43XX
+static struct usb3_dpll_params *ti_usb3_get_dpll_params(struct ti_usb_phy *phy)
+{
+	unsigned long rate;
+	struct usb3_dpll_map *dpll_map = phy->dpll_map;
+
+	rate = get_sys_clk_freq();
+
+	for (; dpll_map->rate; dpll_map++) {
+		if (rate == dpll_map->rate)
+			return &dpll_map->params;
+	}
+
+	log_err("No DPLL configuration for %lu Hz SYS CLK\n", rate);
+
+	return NULL;
+}
+
+static int ti_usb3_dpll_wait_lock(struct ti_usb_phy *phy)
+{
+	u32 val;
+	do {
+		val = ti_usb3_readl(phy->pll_ctrl_base, PLL_STATUS);
+			if (val & PLL_LOCK)
+				break;
+	} while (1);
+
+	return 0;
+}
+
+static int ti_usb3_dpll_program(struct ti_usb_phy *phy)
+{
+	u32			val;
+	struct usb3_dpll_params	*dpll_params;
+
+	if (!phy->pll_ctrl_base)
+		return -EINVAL;
+
+	dpll_params = ti_usb3_get_dpll_params(phy);
+	if (!dpll_params)
+		return -EINVAL;
+
+	val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+	val &= ~PLL_REGN_MASK;
+	val |= dpll_params->n << PLL_REGN_SHIFT;
+	ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+	val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+	val &= ~PLL_SELFREQDCO_MASK;
+	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
+	ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+	val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+	val &= ~PLL_REGM_MASK;
+	val |= dpll_params->m << PLL_REGM_SHIFT;
+	ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+	val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
+	val &= ~PLL_REGM_F_MASK;
+	val |= dpll_params->mf << PLL_REGM_F_SHIFT;
+	ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
+
+	val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
+	val &= ~PLL_SD_MASK;
+	val |= dpll_params->sd << PLL_SD_SHIFT;
+	ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
+
+	ti_usb3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
+
+	return ti_usb3_dpll_wait_lock(phy);
+}
+#endif
+
+void ti_usb2_phy_power(struct ti_usb_phy *phy, int on)
+{
+	u32 val;
+
+	val = readl(phy->usb2_phy_power);
+
+	if (on) {
+#if defined(CONFIG_DRA7XX)
+		if (phy->index == 1)
+			val &= ~OMAP_CTRL_USB2_PHY_PD;
+		else
+			val &= ~OMAP_CTRL_DEV_PHY_PD;
+#elif defined(CONFIG_AM43XX)
+		val &= ~(AM437X_CTRL_USB2_PHY_PD |
+			 AM437X_CTRL_USB2_OTG_PD);
+		val |= (AM437X_CTRL_USB2_OTGVDET_EN |
+			AM437X_CTRL_USB2_OTGSESSEND_EN);
+#endif
+	} else {
+#if defined(CONFIG_DRA7XX)
+		if (phy->index == 1)
+			val |= OMAP_CTRL_USB2_PHY_PD;
+		else
+			val |= OMAP_CTRL_DEV_PHY_PD;
+
+#elif defined(CONFIG_AM43XX)
+		val &= ~(AM437X_CTRL_USB2_OTGVDET_EN |
+			 AM437X_CTRL_USB2_OTGSESSEND_EN);
+		val |= (AM437X_CTRL_USB2_PHY_PD |
+			AM437X_CTRL_USB2_OTG_PD);
+#endif
+	}
+	writel(val, phy->usb2_phy_power);
+}
+
+#ifndef CONFIG_AM43XX
+void ti_usb3_phy_power(struct ti_usb_phy *phy, int on)
+{
+	u32 val;
+	u32 rate;
+	rate = get_sys_clk_freq();
+	rate = rate/1000000;
+
+	if (!phy->usb3_phy_power)
+		return;
+
+	val = readl(phy->usb3_phy_power);
+	if (on) {
+		val &= ~(OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_MASK |
+			OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_MASK);
+		val |= (OMAP_CTRL_USB3_PHY_TX_RX_POWERON) <<
+			OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_SHIFT;
+		val |= rate <<
+			OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_SHIFT;
+	} else {
+		val &= ~OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_MASK;
+		val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF <<
+			OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_SHIFT;
+	}
+	writel(val, phy->usb3_phy_power);
+}
+#endif
+
+/**
+ * ti_usb_phy_uboot_init - usb phy uboot initialization code
+ * @dev: struct ti_usb_phy_device containing initialization data
+ *
+ * Entry point for ti usb phy driver. This driver handles initialization
+ * of both usb2 phy and usb3 phy. Pointer to ti_usb_phy_device should be
+ * passed containing base address and other initialization data.
+ * Returns '0' on success and a negative value on failure.
+ *
+ * Generally called from board_usb_init() implemented in board file.
+ */
+int ti_usb_phy_uboot_init(struct ti_usb_phy_device *dev)
+{
+	struct ti_usb_phy *phy;
+
+	phy = devm_kzalloc(NULL, sizeof(*phy), GFP_KERNEL);
+	if (!phy) {
+		log_err("unable to alloc mem for TI USB3 PHY\n");
+		return -ENOMEM;
+	}
+
+	phy->dpll_map = dpll_map_usb;
+	phy->index = dev->index;
+	phy->pll_ctrl_base = dev->pll_ctrl_base;
+	phy->usb2_phy_power = dev->usb2_phy_power;
+	phy->usb3_phy_power = dev->usb3_phy_power;
+
+#ifndef CONFIG_AM43XX
+	ti_usb3_dpll_program(phy);
+	ti_usb3_phy_power(phy, 1);
+#endif
+	ti_usb2_phy_power(phy, 1);
+	mdelay(150);
+	list_add_tail(&phy->list, &ti_usb_phy_list);
+
+	return 0;
+}
+
+/**
+ * ti_usb_phy_uboot_exit - usb phy uboot cleanup code
+ * @index: index of this controller
+ *
+ * Performs cleanup of memory allocated in ti_usb_phy_uboot_init.
+ * index of _this_ controller should be passed and should match with
+ * the index passed in ti_usb_phy_device during init.
+ *
+ * Generally called from board file.
+ */
+void ti_usb_phy_uboot_exit(int index)
+{
+	struct ti_usb_phy *phy = NULL;
+
+	list_for_each_entry(phy, &ti_usb_phy_list, list) {
+		if (phy->index != index)
+			continue;
+
+		ti_usb2_phy_power(phy, 0);
+#ifndef CONFIG_AM43XX
+		ti_usb3_phy_power(phy, 0);
+#endif
+		list_del(&phy->list);
+		kfree(phy);
+		break;
+	}
+}
diff --git a/roms/u-boot/drivers/usb/emul/Kconfig b/roms/u-boot/drivers/usb/emul/Kconfig
new file mode 100644
index 000000000..ae1ab23a3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/emul/Kconfig
@@ -0,0 +1,8 @@
+config USB_EMUL
+	bool "Support for USB device emulation"
+	depends on DM_USB && SANDBOX
+	help
+	  Since sandbox does not have access to a real USB bus, it is possible
+	  to use device emulators instead. This allows testing of the USB
+	  stack on sandbox without needing a real device, or any host machine
+	  USB resources.
diff --git a/roms/u-boot/drivers/usb/emul/Makefile b/roms/u-boot/drivers/usb/emul/Makefile
new file mode 100644
index 000000000..bf2d49a53
--- /dev/null
+++ b/roms/u-boot/drivers/usb/emul/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+
+obj-$(CONFIG_USB_EMUL) += sandbox_flash.o
+obj-$(CONFIG_USB_EMUL) += sandbox_hub.o
+obj-$(CONFIG_USB_EMUL) += sandbox_keyb.o
+obj-$(CONFIG_USB_EMUL) += usb-emul-uclass.o
diff --git a/roms/u-boot/drivers/usb/emul/sandbox_flash.c b/roms/u-boot/drivers/usb/emul/sandbox_flash.c
new file mode 100644
index 000000000..edabc1b3a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/emul/sandbox_flash.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <os.h>
+#include <scsi.h>
+#include <usb.h>
+
+/*
+ * This driver emulates a flash stick using the UFI command specification and
+ * the BBB (bulk/bulk/bulk) protocol. It supports only a single logical unit
+ * number (LUN 0).
+ */
+
+enum {
+	SANDBOX_FLASH_EP_OUT		= 1,	/* endpoints */
+	SANDBOX_FLASH_EP_IN		= 2,
+	SANDBOX_FLASH_BLOCK_LEN		= 512,
+};
+
+enum cmd_phase {
+	PHASE_START,
+	PHASE_DATA,
+	PHASE_STATUS,
+};
+
+enum {
+	STRINGID_MANUFACTURER = 1,
+	STRINGID_PRODUCT,
+	STRINGID_SERIAL,
+
+	STRINGID_COUNT,
+};
+
+/**
+ * struct sandbox_flash_priv - private state for this driver
+ *
+ * @error:	true if there is an error condition
+ * @alloc_len:	Allocation length from the last incoming command
+ * @transfer_len: Transfer length from CBW header
+ * @read_len:	Number of blocks of data left in the current read command
+ * @tag:	Tag value from last command
+ * @fd:		File descriptor of backing file
+ * @file_size:	Size of file in bytes
+ * @status_buff:	Data buffer for outgoing status
+ * @buff_used:	Number of bytes ready to transfer back to host
+ * @buff:	Data buffer for outgoing data
+ */
+struct sandbox_flash_priv {
+	bool error;
+	int alloc_len;
+	int transfer_len;
+	int read_len;
+	enum cmd_phase phase;
+	u32 tag;
+	int fd;
+	loff_t file_size;
+	struct umass_bbb_csw status;
+	int buff_used;
+	u8 buff[512];
+};
+
+struct sandbox_flash_plat {
+	const char *pathname;
+	struct usb_string flash_strings[STRINGID_COUNT];
+};
+
+struct scsi_inquiry_resp {
+	u8 type;
+	u8 flags;
+	u8 version;
+	u8 data_format;
+	u8 additional_len;
+	u8 spare[3];
+	char vendor[8];
+	char product[16];
+	char revision[4];
+};
+
+struct scsi_read_capacity_resp {
+	u32 last_block_addr;
+	u32 block_len;
+};
+
+struct __packed scsi_read10_req {
+	u8 cmd;
+	u8 lun_flags;
+	u32 lba;
+	u8 spare;
+	u16 transfer_len;
+	u8 spare2[3];
+};
+
+static struct usb_device_descriptor flash_device_desc = {
+	.bLength =		sizeof(flash_device_desc),
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+
+	.bDeviceClass =		0,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
+
+	.idVendor =		__constant_cpu_to_le16(0x1234),
+	.idProduct =		__constant_cpu_to_le16(0x5678),
+	.iManufacturer =	STRINGID_MANUFACTURER,
+	.iProduct =		STRINGID_PRODUCT,
+	.iSerialNumber =	STRINGID_SERIAL,
+	.bNumConfigurations =	1,
+};
+
+static struct usb_config_descriptor flash_config0 = {
+	.bLength		= sizeof(flash_config0),
+	.bDescriptorType	= USB_DT_CONFIG,
+
+	/* wTotalLength is set up by usb-emul-uclass */
+	.bNumInterfaces		= 1,
+	.bConfigurationValue	= 0,
+	.iConfiguration		= 0,
+	.bmAttributes		= 1 << 7,
+	.bMaxPower		= 50,
+};
+
+static struct usb_interface_descriptor flash_interface0 = {
+	.bLength		= sizeof(flash_interface0),
+	.bDescriptorType	= USB_DT_INTERFACE,
+
+	.bInterfaceNumber	= 0,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 2,
+	.bInterfaceClass	= USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass	= US_SC_UFI,
+	.bInterfaceProtocol	= US_PR_BULK,
+	.iInterface		= 0,
+};
+
+static struct usb_endpoint_descriptor flash_endpoint0_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+
+	.bEndpointAddress	= SANDBOX_FLASH_EP_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= __constant_cpu_to_le16(1024),
+	.bInterval		= 0,
+};
+
+static struct usb_endpoint_descriptor flash_endpoint1_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+
+	.bEndpointAddress	= SANDBOX_FLASH_EP_IN | USB_ENDPOINT_DIR_MASK,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= __constant_cpu_to_le16(1024),
+	.bInterval		= 0,
+};
+
+static void *flash_desc_list[] = {
+	&flash_device_desc,
+	&flash_config0,
+	&flash_interface0,
+	&flash_endpoint0_out,
+	&flash_endpoint1_in,
+	NULL,
+};
+
+static int sandbox_flash_control(struct udevice *dev, struct usb_device *udev,
+				 unsigned long pipe, void *buff, int len,
+				 struct devrequest *setup)
+{
+	struct sandbox_flash_priv *priv = dev_get_priv(dev);
+
+	if (pipe == usb_rcvctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case US_BBB_RESET:
+			priv->error = false;
+			return 0;
+		case US_BBB_GET_MAX_LUN:
+			*(char *)buff = '\0';
+			return 1;
+		default:
+			debug("request=%x\n", setup->request);
+			break;
+		}
+	}
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+static void setup_fail_response(struct sandbox_flash_priv *priv)
+{
+	struct umass_bbb_csw *csw = &priv->status;
+
+	csw->dCSWSignature = CSWSIGNATURE;
+	csw->dCSWTag = priv->tag;
+	csw->dCSWDataResidue = 0;
+	csw->bCSWStatus = CSWSTATUS_FAILED;
+	priv->buff_used = 0;
+}
+
+/**
+ * setup_response() - set up a response to send back to the host
+ *
+ * @priv:	Sandbox flash private data
+ * @resp:	Response to send, or NULL if none
+ * @size:	Size of response
+ */
+static void setup_response(struct sandbox_flash_priv *priv, void *resp,
+			   int size)
+{
+	struct umass_bbb_csw *csw = &priv->status;
+
+	csw->dCSWSignature = CSWSIGNATURE;
+	csw->dCSWTag = priv->tag;
+	csw->dCSWDataResidue = 0;
+	csw->bCSWStatus = CSWSTATUS_GOOD;
+
+	assert(!resp || resp == priv->buff);
+	priv->buff_used = size;
+}
+
+static void handle_read(struct sandbox_flash_priv *priv, ulong lba,
+			ulong transfer_len)
+{
+	debug("%s: lba=%lx, transfer_len=%lx\n", __func__, lba, transfer_len);
+	if (priv->fd != -1) {
+		os_lseek(priv->fd, lba * SANDBOX_FLASH_BLOCK_LEN, OS_SEEK_SET);
+		priv->read_len = transfer_len;
+		setup_response(priv, priv->buff,
+			       transfer_len * SANDBOX_FLASH_BLOCK_LEN);
+	} else {
+		setup_fail_response(priv);
+	}
+}
+
+static int handle_ufi_command(struct sandbox_flash_plat *plat,
+			      struct sandbox_flash_priv *priv, const void *buff,
+			      int len)
+{
+	const struct scsi_cmd *req = buff;
+
+	switch (*req->cmd) {
+	case SCSI_INQUIRY: {
+		struct scsi_inquiry_resp *resp = (void *)priv->buff;
+
+		priv->alloc_len = req->cmd[4];
+		memset(resp, '\0', sizeof(*resp));
+		resp->data_format = 1;
+		resp->additional_len = 0x1f;
+		strncpy(resp->vendor,
+			plat->flash_strings[STRINGID_MANUFACTURER -  1].s,
+			sizeof(resp->vendor));
+		strncpy(resp->product,
+			plat->flash_strings[STRINGID_PRODUCT - 1].s,
+			sizeof(resp->product));
+		strncpy(resp->revision, "1.0", sizeof(resp->revision));
+		setup_response(priv, resp, sizeof(*resp));
+		break;
+	}
+	case SCSI_TST_U_RDY:
+		setup_response(priv, NULL, 0);
+		break;
+	case SCSI_RD_CAPAC: {
+		struct scsi_read_capacity_resp *resp = (void *)priv->buff;
+		uint blocks;
+
+		if (priv->file_size)
+			blocks = priv->file_size / SANDBOX_FLASH_BLOCK_LEN - 1;
+		else
+			blocks = 0;
+		resp->last_block_addr = cpu_to_be32(blocks);
+		resp->block_len = cpu_to_be32(SANDBOX_FLASH_BLOCK_LEN);
+		setup_response(priv, resp, sizeof(*resp));
+		break;
+	}
+	case SCSI_READ10: {
+		struct scsi_read10_req *req = (void *)buff;
+
+		handle_read(priv, be32_to_cpu(req->lba),
+			    be16_to_cpu(req->transfer_len));
+		break;
+	}
+	default:
+		debug("Command not supported: %x\n", req->cmd[0]);
+		return -EPROTONOSUPPORT;
+	}
+
+	priv->phase = priv->transfer_len ? PHASE_DATA : PHASE_STATUS;
+	return 0;
+}
+
+static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
+			      unsigned long pipe, void *buff, int len)
+{
+	struct sandbox_flash_plat *plat = dev_get_plat(dev);
+	struct sandbox_flash_priv *priv = dev_get_priv(dev);
+	int ep = usb_pipeendpoint(pipe);
+	struct umass_bbb_cbw *cbw = buff;
+
+	debug("%s: dev=%s, pipe=%lx, ep=%x, len=%x, phase=%d\n", __func__,
+	      dev->name, pipe, ep, len, priv->phase);
+	switch (ep) {
+	case SANDBOX_FLASH_EP_OUT:
+		switch (priv->phase) {
+		case PHASE_START:
+			priv->alloc_len = 0;
+			priv->read_len = 0;
+			if (priv->error || len != UMASS_BBB_CBW_SIZE ||
+			    cbw->dCBWSignature != CBWSIGNATURE)
+				goto err;
+			if ((cbw->bCBWFlags & CBWFLAGS_SBZ) ||
+			    cbw->bCBWLUN != 0)
+				goto err;
+			if (cbw->bCDBLength < 1 || cbw->bCDBLength >= 0x10)
+				goto err;
+			priv->transfer_len = cbw->dCBWDataTransferLength;
+			priv->tag = cbw->dCBWTag;
+			return handle_ufi_command(plat, priv, cbw->CBWCDB,
+						  cbw->bCDBLength);
+		case PHASE_DATA:
+			debug("data out\n");
+			break;
+		default:
+			break;
+		}
+	case SANDBOX_FLASH_EP_IN:
+		switch (priv->phase) {
+		case PHASE_DATA:
+			debug("data in, len=%x, alloc_len=%x, priv->read_len=%x\n",
+			      len, priv->alloc_len, priv->read_len);
+			if (priv->read_len) {
+				ulong bytes_read;
+
+				bytes_read = os_read(priv->fd, buff, len);
+				if (bytes_read != len)
+					return -EIO;
+				priv->read_len -= len / SANDBOX_FLASH_BLOCK_LEN;
+				if (!priv->read_len)
+					priv->phase = PHASE_STATUS;
+			} else {
+				if (priv->alloc_len && len > priv->alloc_len)
+					len = priv->alloc_len;
+				memcpy(buff, priv->buff, len);
+				priv->phase = PHASE_STATUS;
+			}
+			return len;
+		case PHASE_STATUS:
+			debug("status in, len=%x\n", len);
+			if (len > sizeof(priv->status))
+				len = sizeof(priv->status);
+			memcpy(buff, &priv->status, len);
+			priv->phase = PHASE_START;
+			return len;
+		default:
+			break;
+		}
+	}
+err:
+	priv->error = true;
+	debug("%s: Detected transfer error\n", __func__);
+	return 0;
+}
+
+static int sandbox_flash_of_to_plat(struct udevice *dev)
+{
+	struct sandbox_flash_plat *plat = dev_get_plat(dev);
+
+	plat->pathname = dev_read_string(dev, "sandbox,filepath");
+
+	return 0;
+}
+
+static int sandbox_flash_bind(struct udevice *dev)
+{
+	struct sandbox_flash_plat *plat = dev_get_plat(dev);
+	struct usb_string *fs;
+
+	fs = plat->flash_strings;
+	fs[0].id = STRINGID_MANUFACTURER;
+	fs[0].s = "sandbox";
+	fs[1].id = STRINGID_PRODUCT;
+	fs[1].s = "flash";
+	fs[2].id = STRINGID_SERIAL;
+	fs[2].s = dev->name;
+
+	return usb_emul_setup_device(dev, plat->flash_strings, flash_desc_list);
+}
+
+static int sandbox_flash_probe(struct udevice *dev)
+{
+	struct sandbox_flash_plat *plat = dev_get_plat(dev);
+	struct sandbox_flash_priv *priv = dev_get_priv(dev);
+
+	priv->fd = os_open(plat->pathname, OS_O_RDONLY);
+	if (priv->fd != -1)
+		return os_get_filesize(plat->pathname, &priv->file_size);
+
+	return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_flash_ops = {
+	.control	= sandbox_flash_control,
+	.bulk		= sandbox_flash_bulk,
+};
+
+static const struct udevice_id sandbox_usb_flash_ids[] = {
+	{ .compatible = "sandbox,usb-flash" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox_flash) = {
+	.name	= "usb_sandbox_flash",
+	.id	= UCLASS_USB_EMUL,
+	.of_match = sandbox_usb_flash_ids,
+	.bind	= sandbox_flash_bind,
+	.probe	= sandbox_flash_probe,
+	.of_to_plat = sandbox_flash_of_to_plat,
+	.ops	= &sandbox_usb_flash_ops,
+	.priv_auto	= sizeof(struct sandbox_flash_priv),
+	.plat_auto	= sizeof(struct sandbox_flash_plat),
+};
diff --git a/roms/u-boot/drivers/usb/emul/sandbox_hub.c b/roms/u-boot/drivers/usb/emul/sandbox_hub.c
new file mode 100644
index 000000000..041ec3772
--- /dev/null
+++ b/roms/u-boot/drivers/usb/emul/sandbox_hub.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <dm/device-internal.h>
+
+/* We only support up to 8 */
+#define SANDBOX_NUM_PORTS	4
+
+struct sandbox_hub_plat {
+	struct usb_dev_plat plat;
+	int port;	/* Port number (numbered from 0) */
+};
+
+enum {
+	STRING_MANUFACTURER = 1,
+	STRING_PRODUCT,
+	STRING_SERIAL,
+
+	STRING_count,
+};
+
+static struct usb_string hub_strings[] = {
+	{STRING_MANUFACTURER,	"sandbox"},
+	{STRING_PRODUCT,	"hub"},
+	{STRING_SERIAL,		"2345"},
+	{},
+};
+
+static struct usb_device_descriptor hub_device_desc = {
+	.bLength =		sizeof(hub_device_desc),
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+
+	.bDeviceClass =		USB_CLASS_HUB,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
+
+	.idVendor =		__constant_cpu_to_le16(0x1234),
+	.idProduct =		__constant_cpu_to_le16(0x5678),
+	.iManufacturer =	STRING_MANUFACTURER,
+	.iProduct =		STRING_PRODUCT,
+	.iSerialNumber =	STRING_SERIAL,
+	.bNumConfigurations =	1,
+};
+
+static struct usb_config_descriptor hub_config1 = {
+	.bLength		= sizeof(hub_config1),
+	.bDescriptorType	= USB_DT_CONFIG,
+
+	/* wTotalLength is set up by usb-emul-uclass */
+	.bNumInterfaces		= 1,
+	.bConfigurationValue	= 0,
+	.iConfiguration		= 0,
+	.bmAttributes		= 1 << 7,
+	.bMaxPower		= 50,
+};
+
+static struct usb_interface_descriptor hub_interface0 = {
+	.bLength		= sizeof(hub_interface0),
+	.bDescriptorType	= USB_DT_INTERFACE,
+
+	.bInterfaceNumber	= 0,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_HUB,
+	.bInterfaceSubClass	= 0,
+	.bInterfaceProtocol	= US_PR_CB,
+	.iInterface		= 0,
+};
+
+static struct usb_endpoint_descriptor hub_endpoint0_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+
+	.bEndpointAddress	= 1 | USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize		= __constant_cpu_to_le16(1024),
+	.bInterval		= 0,
+};
+
+static struct usb_hub_descriptor hub_desc = {
+	.bLength		= sizeof(hub_desc),
+	.bDescriptorType	= USB_DT_HUB,
+	.bNbrPorts		= SANDBOX_NUM_PORTS,
+	.wHubCharacteristics	= __constant_cpu_to_le16(1 << 0 | 1 << 3 |
+								1 << 7),
+	.bPwrOn2PwrGood		= 2,
+	.bHubContrCurrent	= 5,
+	{
+		{
+			/* all ports removeable */
+			.DeviceRemovable	= {0, 0xff}
+		}
+	}
+#if SANDBOX_NUM_PORTS > 8
+#error "This code sets up an incorrect mask"
+#endif
+};
+
+static void *hub_desc_list[] = {
+	&hub_device_desc,
+	&hub_config1,
+	&hub_interface0,
+	&hub_endpoint0_in,
+	&hub_desc,
+	NULL,
+};
+
+struct sandbox_hub_priv {
+	int status[SANDBOX_NUM_PORTS];
+	int change[SANDBOX_NUM_PORTS];
+};
+
+static struct udevice *hub_find_device(struct udevice *hub, int port,
+				       enum usb_device_speed *speed)
+{
+	struct udevice *dev;
+	struct usb_generic_descriptor **gen_desc;
+	struct usb_device_descriptor **dev_desc;
+
+	for (device_find_first_child(hub, &dev);
+	     dev;
+	     device_find_next_child(&dev)) {
+		struct sandbox_hub_plat *plat;
+
+		plat = dev_get_parent_plat(dev);
+		if (plat->port == port) {
+			gen_desc = plat->plat.desc_list;
+			gen_desc = usb_emul_find_descriptor(gen_desc,
+							    USB_DT_DEVICE, 0);
+			dev_desc = (struct usb_device_descriptor **)gen_desc;
+
+			switch (le16_to_cpu((*dev_desc)->bcdUSB)) {
+			case 0x0100:
+				*speed = USB_SPEED_LOW;
+				break;
+			case 0x0101:
+				*speed = USB_SPEED_FULL;
+				break;
+			case 0x0200:
+			default:
+				*speed = USB_SPEED_HIGH;
+				break;
+			}
+
+			return dev;
+		}
+	}
+
+	return NULL;
+}
+
+static int clrset_post_state(struct udevice *hub, int port, int clear, int set)
+{
+	struct sandbox_hub_priv *priv = dev_get_priv(hub);
+	int *status = &priv->status[port];
+	int *change = &priv->change[port];
+	int ret = 0;
+
+	if ((clear | set) & USB_PORT_STAT_POWER) {
+		enum usb_device_speed speed;
+		struct udevice *dev = hub_find_device(hub, port, &speed);
+
+		if (dev) {
+			if (set & USB_PORT_STAT_POWER) {
+				ret = device_probe(dev);
+				debug("%s: %s: power on, probed, ret=%d\n",
+				      __func__, dev->name, ret);
+				if (!ret) {
+					set |= USB_PORT_STAT_CONNECTION |
+						USB_PORT_STAT_ENABLE;
+					if (speed == USB_SPEED_LOW)
+						set |= USB_PORT_STAT_LOW_SPEED;
+					else if (speed == USB_SPEED_HIGH)
+						set |= USB_PORT_STAT_HIGH_SPEED;
+				}
+
+			} else if (clear & USB_PORT_STAT_POWER) {
+				debug("%s: %s: power off, removed, ret=%d\n",
+				      __func__, dev->name, ret);
+				ret = device_remove(dev, DM_REMOVE_NORMAL);
+				clear |= USB_PORT_STAT_CONNECTION;
+			}
+		}
+	}
+	*change |= *status & clear;
+	*change |= ~*status & set;
+	*change &= 0x1f;
+	*status = (*status & ~clear) | set;
+
+	return ret;
+}
+
+static int sandbox_hub_submit_control_msg(struct udevice *bus,
+					  struct usb_device *udev,
+					  unsigned long pipe,
+					  void *buffer, int length,
+					  struct devrequest *setup)
+{
+	struct sandbox_hub_priv *priv = dev_get_priv(bus);
+	int ret = 0;
+
+	if (pipe == usb_rcvctrlpipe(udev, 0)) {
+		switch (setup->requesttype) {
+		case USB_RT_HUB | USB_DIR_IN:
+			switch (setup->request) {
+			case USB_REQ_GET_STATUS: {
+				struct usb_hub_status *hubsts = buffer;
+
+				hubsts->wHubStatus = 0;
+				hubsts->wHubChange = 0;
+				udev->status = 0;
+				udev->act_len = sizeof(*hubsts);
+				return 0;
+			}
+			default:
+				debug("%s: rx ctl requesttype=%x, request=%x\n",
+				      __func__, setup->requesttype,
+				      setup->request);
+				break;
+			}
+		case USB_RT_PORT | USB_DIR_IN:
+			switch (setup->request) {
+			case USB_REQ_GET_STATUS: {
+				struct usb_port_status *portsts = buffer;
+				int port;
+
+				port = (setup->index & USB_HUB_PORT_MASK) - 1;
+				portsts->wPortStatus = priv->status[port];
+				portsts->wPortChange = priv->change[port];
+				udev->status = 0;
+				udev->act_len = sizeof(*portsts);
+				return 0;
+			}
+			}
+		default:
+			debug("%s: rx ctl requesttype=%x, request=%x\n",
+			      __func__, setup->requesttype, setup->request);
+			break;
+		}
+	} else if (pipe == usb_sndctrlpipe(udev, 0)) {
+		switch (setup->requesttype) {
+		case USB_RT_PORT:
+			switch (setup->request) {
+			case USB_REQ_SET_FEATURE: {
+				int port;
+
+				port = (setup->index & USB_HUB_PORT_MASK) - 1;
+				debug("set feature port=%x, feature=%x\n",
+				      port, setup->value);
+				if (setup->value < USB_PORT_FEAT_C_CONNECTION) {
+					ret = clrset_post_state(bus, port, 0,
+							1 << setup->value);
+				} else {
+					debug("  ** Invalid feature\n");
+				}
+				return ret;
+			}
+			case USB_REQ_CLEAR_FEATURE: {
+				int port;
+
+				port = (setup->index & USB_HUB_PORT_MASK) - 1;
+				debug("clear feature port=%x, feature=%x\n",
+				      port, setup->value);
+				if (setup->value < USB_PORT_FEAT_C_CONNECTION) {
+					ret = clrset_post_state(bus, port,
+							1 << setup->value, 0);
+				} else {
+					priv->change[port] &= 1 <<
+						(setup->value - 16);
+				}
+				udev->status = 0;
+				return 0;
+			}
+			default:
+				debug("%s: tx ctl requesttype=%x, request=%x\n",
+				      __func__, setup->requesttype,
+				      setup->request);
+				break;
+			}
+		default:
+			debug("%s: tx ctl requesttype=%x, request=%x\n",
+			      __func__, setup->requesttype, setup->request);
+			break;
+		}
+	}
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+static int sandbox_hub_bind(struct udevice *dev)
+{
+	return usb_emul_setup_device(dev, hub_strings, hub_desc_list);
+}
+
+static int sandbox_child_post_bind(struct udevice *dev)
+{
+	struct sandbox_hub_plat *plat = dev_get_parent_plat(dev);
+	struct usb_emul_plat *emul = dev_get_uclass_plat(dev);
+
+	plat->port = dev_read_u32_default(dev, "reg", -1);
+	emul->port1 = plat->port + 1;
+
+	return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_hub_ops = {
+	.control	= sandbox_hub_submit_control_msg,
+};
+
+static const struct udevice_id sandbox_usb_hub_ids[] = {
+	{ .compatible = "sandbox,usb-hub" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox_hub) = {
+	.name	= "usb_sandbox_hub",
+	.id	= UCLASS_USB_EMUL,
+	.of_match = sandbox_usb_hub_ids,
+	.bind	= sandbox_hub_bind,
+	.ops	= &sandbox_usb_hub_ops,
+	.priv_auto	= sizeof(struct sandbox_hub_priv),
+	.per_child_plat_auto	= sizeof(struct sandbox_hub_plat),
+	.child_post_bind = sandbox_child_post_bind,
+};
diff --git a/roms/u-boot/drivers/usb/emul/sandbox_keyb.c b/roms/u-boot/drivers/usb/emul/sandbox_keyb.c
new file mode 100644
index 000000000..5ec1e98e4
--- /dev/null
+++ b/roms/u-boot/drivers/usb/emul/sandbox_keyb.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <os.h>
+#include <scsi.h>
+#include <usb.h>
+
+/*
+ * This driver emulates a USB keyboard using the USB HID specification (boot
+ * protocol)
+ */
+
+enum {
+	SANDBOX_KEYB_EP_IN		= 1,	/* endpoints */
+};
+
+enum cmd_phase {
+	PHASE_START,
+	PHASE_DATA,
+	PHASE_STATUS,
+};
+
+enum {
+	STRINGID_MANUFACTURER = 1,
+	STRINGID_PRODUCT,
+	STRINGID_SERIAL,
+
+	STRINGID_COUNT,
+};
+
+/**
+ * struct sandbox_keyb_priv - private state for this driver
+ *
+ */
+struct sandbox_keyb_priv {
+	struct membuff in;
+};
+
+struct sandbox_keyb_plat {
+	struct usb_string keyb_strings[STRINGID_COUNT];
+};
+
+static struct usb_device_descriptor keyb_device_desc = {
+	.bLength =		sizeof(keyb_device_desc),
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0100),
+
+	.bDeviceClass =		0,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
+
+	.idVendor =		__constant_cpu_to_le16(0x1234),
+	.idProduct =		__constant_cpu_to_le16(0x5679),
+	.iManufacturer =	STRINGID_MANUFACTURER,
+	.iProduct =		STRINGID_PRODUCT,
+	.iSerialNumber =	STRINGID_SERIAL,
+	.bNumConfigurations =	1,
+};
+
+static struct usb_config_descriptor keyb_config0 = {
+	.bLength		= sizeof(keyb_config0),
+	.bDescriptorType	= USB_DT_CONFIG,
+
+	/* wTotalLength is set up by usb-emul-uclass */
+	.bNumInterfaces		= 2,
+	.bConfigurationValue	= 0,
+	.iConfiguration		= 0,
+	.bmAttributes		= 1 << 7 | 1 << 5,
+	.bMaxPower		= 50,
+};
+
+static struct usb_interface_descriptor keyb_interface0 = {
+	.bLength		= sizeof(keyb_interface0),
+	.bDescriptorType	= USB_DT_INTERFACE,
+
+	.bInterfaceNumber	= 0,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_HID,
+	.bInterfaceSubClass	= USB_SUB_HID_BOOT,
+	.bInterfaceProtocol	= USB_PROT_HID_KEYBOARD,
+	.iInterface		= 0,
+};
+
+static struct usb_class_hid_descriptor keyb_report0 = {
+	.bLength		= sizeof(keyb_report0),
+	.bDescriptorType	= USB_DT_HID,
+	.bcdCDC			= 0x101,
+	.bCountryCode		= 0,
+	.bNumDescriptors	= 1,
+	.bDescriptorType0	= USB_DT_HID_REPORT,
+	.wDescriptorLength0	= 0x3f,
+};
+
+static struct usb_endpoint_descriptor keyb_endpoint0_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+
+	.bEndpointAddress	= SANDBOX_KEYB_EP_IN | USB_ENDPOINT_DIR_MASK,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK |
+					USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize		= __constant_cpu_to_le16(8),
+	.bInterval		= 0xa,
+};
+
+static struct usb_interface_descriptor keyb_interface1 = {
+	.bLength		= sizeof(keyb_interface1),
+	.bDescriptorType	= USB_DT_INTERFACE,
+
+	.bInterfaceNumber	= 1,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_HID,
+	.bInterfaceSubClass	= USB_SUB_HID_BOOT,
+	.bInterfaceProtocol	= USB_PROT_HID_MOUSE,
+	.iInterface		= 0,
+};
+
+static struct usb_class_hid_descriptor keyb_report1 = {
+	.bLength		= sizeof(struct usb_class_hid_descriptor),
+	.bDescriptorType	= USB_DT_HID,
+	.bcdCDC			= 0x101,
+	.bCountryCode		= 0,
+	.bNumDescriptors	= 1,
+	.bDescriptorType0	= USB_DT_HID_REPORT,
+	.wDescriptorLength0	= 0x32,
+};
+
+static struct usb_endpoint_descriptor keyb_endpoint1_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+
+	.bEndpointAddress	= SANDBOX_KEYB_EP_IN | USB_ENDPOINT_DIR_MASK,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK |
+					USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize		= __constant_cpu_to_le16(8),
+	.bInterval		= 0xa,
+};
+
+static void *keyb_desc_list[] = {
+	&keyb_device_desc,
+	&keyb_config0,
+	&keyb_interface0,
+	&keyb_report0,
+	&keyb_endpoint0_in,
+	&keyb_interface1,
+	&keyb_report1,
+	&keyb_endpoint1_in,
+	NULL,
+};
+
+/**
+ * sandbox_usb_keyb_add_string() - provide a USB scancode buffer
+ *
+ * @dev:	the keyboard emulation device
+ * @scancode:	scancode buffer with USB_KBD_BOOT_REPORT_SIZE bytes
+ */
+int sandbox_usb_keyb_add_string(struct udevice *dev,
+				const char scancode[USB_KBD_BOOT_REPORT_SIZE])
+{
+	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = membuff_put(&priv->in, scancode, USB_KBD_BOOT_REPORT_SIZE);
+	if (ret != USB_KBD_BOOT_REPORT_SIZE)
+		return -ENOSPC;
+
+	return 0;
+}
+
+static int sandbox_keyb_control(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buff, int len,
+				struct devrequest *setup)
+{
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+static int sandbox_keyb_interrupt(struct udevice *dev, struct usb_device *udev,
+		unsigned long pipe, void *buffer, int length, int interval,
+		bool nonblock)
+{
+	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
+	uint8_t *data = buffer;
+
+	memset(data, '\0', length);
+	if (length < USB_KBD_BOOT_REPORT_SIZE)
+		return 0;
+
+	membuff_get(&priv->in, buffer, USB_KBD_BOOT_REPORT_SIZE);
+
+	return 0;
+}
+
+static int sandbox_keyb_bind(struct udevice *dev)
+{
+	struct sandbox_keyb_plat *plat = dev_get_plat(dev);
+	struct usb_string *fs;
+
+	fs = plat->keyb_strings;
+	fs[0].id = STRINGID_MANUFACTURER;
+	fs[0].s = "sandbox";
+	fs[1].id = STRINGID_PRODUCT;
+	fs[1].s = "keyboard";
+	fs[2].id = STRINGID_SERIAL;
+	fs[2].s = dev->name;
+
+	return usb_emul_setup_device(dev, plat->keyb_strings, keyb_desc_list);
+}
+
+static int sandbox_keyb_probe(struct udevice *dev)
+{
+	struct sandbox_keyb_priv *priv = dev_get_priv(dev);
+
+	/* Provide an 80 character keyboard buffer */
+	return membuff_new(&priv->in, 80 * USB_KBD_BOOT_REPORT_SIZE);
+}
+
+static const struct dm_usb_ops sandbox_usb_keyb_ops = {
+	.control	= sandbox_keyb_control,
+	.interrupt	= sandbox_keyb_interrupt,
+};
+
+static const struct udevice_id sandbox_usb_keyb_ids[] = {
+	{ .compatible = "sandbox,usb-keyb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox_keyb) = {
+	.name	= "usb_sandbox_keyb",
+	.id	= UCLASS_USB_EMUL,
+	.of_match = sandbox_usb_keyb_ids,
+	.bind	= sandbox_keyb_bind,
+	.probe	= sandbox_keyb_probe,
+	.ops	= &sandbox_usb_keyb_ops,
+	.priv_auto	= sizeof(struct sandbox_keyb_priv),
+	.plat_auto	= sizeof(struct sandbox_keyb_plat),
+};
diff --git a/roms/u-boot/drivers/usb/emul/usb-emul-uclass.c b/roms/u-boot/drivers/usb/emul/usb-emul-uclass.c
new file mode 100644
index 000000000..f5d98b917
--- /dev/null
+++ b/roms/u-boot/drivers/usb/emul/usb-emul-uclass.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <dm/device-internal.h>
+
+static int copy_to_unicode(char *buff, int length, const char *str)
+{
+	int ptr;
+	int i;
+
+	if (length < 2)
+		return 0;
+	buff[1] = USB_DT_STRING;
+	for (ptr = 2, i = 0; ptr + 1 < length && *str; i++, ptr += 2) {
+		buff[ptr] = str[i];
+		buff[ptr + 1] = 0;
+	}
+	buff[0] = ptr;
+
+	return ptr;
+}
+
+static int usb_emul_get_string(struct usb_string *strings, int index,
+			       char *buff, int length)
+{
+	if (index == 0) {
+		char *desc = buff;
+
+		desc[0] = 4;
+		desc[1] = USB_DT_STRING;
+		desc[2] = 0x09;
+		desc[3] = 0x14;
+		return 4;
+	} else if (strings) {
+		struct usb_string *ptr;
+
+		for (ptr = strings; ptr->s; ptr++) {
+			if (ptr->id == index)
+				return copy_to_unicode(buff, length, ptr->s);
+		}
+	}
+
+	return -EINVAL;
+}
+
+struct usb_generic_descriptor **usb_emul_find_descriptor(
+		struct usb_generic_descriptor **ptr, int type, int index)
+{
+	debug("%s: type=%x, index=%d\n", __func__, type, index);
+	for (; *ptr; ptr++) {
+		if ((*ptr)->bDescriptorType != type)
+			continue;
+		switch (type) {
+		case USB_DT_CONFIG: {
+			struct usb_config_descriptor *cdesc;
+
+			cdesc = (struct usb_config_descriptor *)*ptr;
+			if (cdesc && cdesc->bConfigurationValue == index)
+				return ptr;
+			break;
+		}
+		default:
+			return ptr;
+		}
+	}
+	debug("%s: config ptr=%p\n", __func__, *ptr);
+
+	return ptr;
+}
+
+static int usb_emul_get_descriptor(struct usb_dev_plat *plat, int value,
+				   void *buffer, int length)
+{
+	struct usb_generic_descriptor **ptr;
+	int type = value >> 8;
+	int index = value & 0xff;
+	int upto, todo;
+
+	debug("%s: type=%d, index=%d, plat=%p\n", __func__, type, index, plat);
+	if (type == USB_DT_STRING) {
+		return usb_emul_get_string(plat->strings, index, buffer,
+					   length);
+	}
+
+	ptr = usb_emul_find_descriptor(plat->desc_list, type, index);
+	if (!ptr) {
+		debug("%s: Could not find descriptor type %d, index %d\n",
+		      __func__, type, index);
+		return -ENOENT;
+	}
+	for (upto = 0; *ptr && upto < length; ptr++, upto += todo) {
+		todo = min(length - upto, (int)(*ptr)->bLength);
+
+		memcpy(buffer + upto, *ptr, todo);
+	}
+
+	return upto ? upto : length ? -EIO : 0;
+}
+
+static int usb_emul_find_devnum(int devnum, int port1, struct udevice **emulp)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	*emulp = NULL;
+	ret = uclass_get(UCLASS_USB_EMUL, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct usb_dev_plat *udev = dev_get_parent_plat(dev);
+
+		/*
+		 * devnum is initialzied to zero at the beginning of the
+		 * enumeration process in usb_setup_device(). At this
+		 * point, udev->devnum has not been assigned to any valid
+		 * USB address either, so we can't rely on the comparison
+		 * result between udev->devnum and devnum to select an
+		 * emulator device.
+		 */
+		if (!devnum) {
+			struct usb_emul_plat *plat;
+
+			/*
+			 * If the parent is sandbox USB controller, we are
+			 * the root hub. And there is only one root hub
+			 * in the system.
+			 */
+			if (device_get_uclass_id(dev->parent) == UCLASS_USB) {
+				debug("%s: Found emulator '%s'\n",
+				      __func__, dev->name);
+				*emulp = dev;
+				return 0;
+			}
+
+			plat = dev_get_uclass_plat(dev);
+			if (plat->port1 == port1) {
+				debug("%s: Found emulator '%s', port %d\n",
+				      __func__, dev->name, port1);
+				*emulp = dev;
+				return 0;
+			}
+		} else if (udev->devnum == devnum) {
+			debug("%s: Found emulator '%s', addr %d\n", __func__,
+			      dev->name, udev->devnum);
+			*emulp = dev;
+			return 0;
+		}
+	}
+
+	debug("%s: No emulator found, addr %d\n", __func__, devnum);
+	return -ENOENT;
+}
+
+int usb_emul_find(struct udevice *bus, ulong pipe, int port1,
+		  struct udevice **emulp)
+{
+	int devnum = usb_pipedevice(pipe);
+
+	return usb_emul_find_devnum(devnum, port1, emulp);
+}
+
+int usb_emul_find_for_dev(struct udevice *dev, struct udevice **emulp)
+{
+	struct usb_dev_plat *udev = dev_get_parent_plat(dev);
+
+	return usb_emul_find_devnum(udev->devnum, 0, emulp);
+}
+
+int usb_emul_control(struct udevice *emul, struct usb_device *udev,
+		     unsigned long pipe, void *buffer, int length,
+		     struct devrequest *setup)
+{
+	struct dm_usb_ops *ops = usb_get_emul_ops(emul);
+	struct usb_dev_plat *plat;
+	int ret;
+
+	/* We permit getting the descriptor before we are probed */
+	plat = dev_get_parent_plat(emul);
+	if (!ops->control)
+		return -ENOSYS;
+	debug("%s: dev=%s\n", __func__, emul->name);
+	if (pipe == usb_rcvctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case USB_REQ_GET_DESCRIPTOR: {
+			return usb_emul_get_descriptor(plat, setup->value,
+						       buffer, length);
+		}
+		default:
+			ret = device_probe(emul);
+			if (ret)
+				return ret;
+			return ops->control(emul, udev, pipe, buffer, length,
+					    setup);
+		}
+	} else if (pipe == usb_snddefctrl(udev)) {
+		switch (setup->request) {
+		case USB_REQ_SET_ADDRESS:
+			debug("   ** set address %s %d\n", emul->name,
+			      setup->value);
+			plat->devnum = setup->value;
+			return 0;
+		default:
+			debug("requestsend =%x\n", setup->request);
+			break;
+		}
+	} else if (pipe == usb_sndctrlpipe(udev, 0)) {
+		switch (setup->request) {
+		case USB_REQ_SET_CONFIGURATION:
+			plat->configno = setup->value;
+			return 0;
+		default:
+			ret = device_probe(emul);
+			if (ret)
+				return ret;
+			return ops->control(emul, udev, pipe, buffer, length,
+					    setup);
+		}
+	}
+	debug("pipe=%lx\n", pipe);
+
+	return -EIO;
+}
+
+int usb_emul_bulk(struct udevice *emul, struct usb_device *udev,
+		  unsigned long pipe, void *buffer, int length)
+{
+	struct dm_usb_ops *ops = usb_get_emul_ops(emul);
+	int ret;
+
+	/* We permit getting the descriptor before we are probed */
+	if (!ops->bulk)
+		return -ENOSYS;
+	debug("%s: dev=%s\n", __func__, emul->name);
+	ret = device_probe(emul);
+	if (ret)
+		return ret;
+	return ops->bulk(emul, udev, pipe, buffer, length);
+}
+
+int usb_emul_int(struct udevice *emul, struct usb_device *udev,
+		  unsigned long pipe, void *buffer, int length, int interval,
+		  bool nonblock)
+{
+	struct dm_usb_ops *ops = usb_get_emul_ops(emul);
+
+	if (!ops->interrupt)
+		return -ENOSYS;
+	debug("%s: dev=%s\n", __func__, emul->name);
+
+	return ops->interrupt(emul, udev, pipe, buffer, length, interval,
+			      nonblock);
+}
+
+int usb_emul_setup_device(struct udevice *dev, struct usb_string *strings,
+			  void **desc_list)
+{
+	struct usb_dev_plat *plat = dev_get_parent_plat(dev);
+	struct usb_generic_descriptor **ptr;
+	struct usb_config_descriptor *cdesc;
+	int upto;
+
+	plat->strings = strings;
+	plat->desc_list = (struct usb_generic_descriptor **)desc_list;
+
+	/* Fill in wTotalLength for each configuration descriptor */
+	ptr = plat->desc_list;
+	for (cdesc = NULL, upto = 0; *ptr; upto += (*ptr)->bLength, ptr++) {
+		debug("   - upto=%d, type=%d\n", upto, (*ptr)->bDescriptorType);
+		if ((*ptr)->bDescriptorType == USB_DT_CONFIG) {
+			if (cdesc) {
+				cdesc->wTotalLength = upto;
+				debug("%s: config %d length %d\n", __func__,
+				      cdesc->bConfigurationValue,
+				      cdesc->bLength);
+			}
+			cdesc = (struct usb_config_descriptor *)*ptr;
+			upto = 0;
+		}
+	}
+	if (cdesc) {
+		cdesc->wTotalLength = upto;
+		debug("%s: config %d length %d\n", __func__,
+		      cdesc->bConfigurationValue, cdesc->wTotalLength);
+	}
+
+	return 0;
+}
+
+UCLASS_DRIVER(usb_emul) = {
+	.id		= UCLASS_USB_EMUL,
+	.name		= "usb_emul",
+	.post_bind	= dm_scan_fdt_dev,
+	.per_device_plat_auto	= sizeof(struct usb_emul_plat),
+	.per_child_auto	= sizeof(struct usb_device),
+	.per_child_plat_auto	= sizeof(struct usb_dev_plat),
+};
diff --git a/roms/u-boot/drivers/usb/eth/Kconfig b/roms/u-boot/drivers/usb/eth/Kconfig
new file mode 100644
index 000000000..2f6bfa8e7
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/Kconfig
@@ -0,0 +1,65 @@
+menuconfig USB_HOST_ETHER
+	bool "USB to Ethernet Controller Drivers"
+	---help---
+	  Say Y here if you would like to enable support for USB Ethernet
+	  adapters.
+
+if USB_HOST_ETHER
+
+config USB_ETHER_ASIX
+	bool "ASIX AX8817X (USB 2.0) support"
+	depends on USB_HOST_ETHER
+	---help---
+	  Say Y here if you would like to support ASIX AX8817X based USB 2.0
+	  Ethernet Devices.
+
+config USB_ETHER_ASIX88179
+	bool "ASIX AX88179 (USB 3.0) support"
+	depends on USB_HOST_ETHER
+	---help---
+	  Say Y here if you would like to support ASIX AX88179 based USB 3.0
+	  Ethernet Devices.
+
+config USB_ETHER_LAN75XX
+	bool "Microchip LAN75XX support"
+	depends on USB_HOST_ETHER
+	depends on PHYLIB
+	---help---
+	  Say Y here if you would like to support Microchip LAN75XX Hi-Speed
+	  USB 2.0 to 10/100/1000 Gigabit Ethernet controller.
+	  Supports 10Base-T/ 100Base-TX/1000Base-T.
+	  This driver supports the internal PHY.
+
+config USB_ETHER_LAN78XX
+	bool "Microchip LAN78XX support"
+	depends on USB_HOST_ETHER
+	depends on PHYLIB
+	---help---
+	  Say Y here if you would like to support Microchip LAN78XX USB 3.1
+	  Gen 1 to 10/100/1000 Gigabit Ethernet controller.
+	  Supports 10Base-T/ 100Base-TX/1000Base-T.
+	  This driver supports the internal PHY.
+
+config USB_ETHER_MCS7830
+	bool "MOSCHIP MCS7830 (7730/7830/7832) suppport"
+	depends on USB_HOST_ETHER
+	---help---
+	  Say Y here if you would like to support MOSCHIP MCS7830 based
+	  (7730/7830/7832) USB 2.0 Ethernet Devices.
+
+config USB_ETHER_RTL8152
+	bool "Realtek RTL8152B/RTL8153 support"
+	depends on USB_HOST_ETHER
+	---help---
+	  Say Y here if you would like to support Realtek RTL8152B/RTL8153 base
+	  USB Ethernet Devices. This driver also supports compatible devices
+	  from Samsung, Lenovo, TP-LINK and Nvidia.
+
+config USB_ETHER_SMSC95XX
+	bool "SMSC LAN95x support"
+	depends on USB_HOST_ETHER
+	---help---
+	  Say Y here if you would like to support SMSC LAN95xx based USB 2.0
+	  Ethernet Devices.
+
+endif
diff --git a/roms/u-boot/drivers/usb/eth/Makefile b/roms/u-boot/drivers/usb/eth/Makefile
new file mode 100644
index 000000000..2e5d0782e
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+
+# new USB host ethernet layer dependencies
+obj-$(CONFIG_USB_HOST_ETHER) += usb_ether.o
+obj-$(CONFIG_USB_ETHER_ASIX) += asix.o
+obj-$(CONFIG_USB_ETHER_ASIX88179) += asix88179.o
+obj-$(CONFIG_USB_ETHER_MCS7830) += mcs7830.o
+obj-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o
+obj-$(CONFIG_USB_ETHER_LAN75XX) += lan7x.o lan75xx.o
+obj-$(CONFIG_USB_ETHER_LAN78XX) += lan7x.o lan78xx.o
+obj-$(CONFIG_USB_ETHER_RTL8152) += r8152.o r8152_fw.o
diff --git a/roms/u-boot/drivers/usb/eth/asix.c b/roms/u-boot/drivers/usb/eth/asix.c
new file mode 100644
index 000000000..674f78e21
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/asix.c
@@ -0,0 +1,912 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * Patched for AX88772B by Antmicro Ltd <www.antmicro.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <net.h>
+#include <usb.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+
+/* ASIX AX8817X based USB 2.0 Ethernet Devices */
+
+#define AX_CMD_SET_SW_MII		0x06
+#define AX_CMD_READ_MII_REG		0x07
+#define AX_CMD_WRITE_MII_REG		0x08
+#define AX_CMD_SET_HW_MII		0x0a
+#define AX_CMD_READ_EEPROM		0x0b
+#define AX_CMD_READ_RX_CTL		0x0f
+#define AX_CMD_WRITE_RX_CTL		0x10
+#define AX_CMD_WRITE_IPG0		0x12
+#define AX_CMD_READ_NODE_ID		0x13
+#define AX_CMD_WRITE_NODE_ID	0x14
+#define AX_CMD_READ_PHY_ID		0x19
+#define AX_CMD_WRITE_MEDIUM_MODE	0x1b
+#define AX_CMD_WRITE_GPIOS		0x1f
+#define AX_CMD_SW_RESET			0x20
+#define AX_CMD_SW_PHY_SELECT		0x22
+
+#define AX_SWRESET_CLEAR		0x00
+#define AX_SWRESET_PRTE			0x04
+#define AX_SWRESET_PRL			0x08
+#define AX_SWRESET_IPRL			0x20
+#define AX_SWRESET_IPPD			0x40
+
+#define AX88772_IPG0_DEFAULT		0x15
+#define AX88772_IPG1_DEFAULT		0x0c
+#define AX88772_IPG2_DEFAULT		0x12
+
+/* AX88772 & AX88178 Medium Mode Register */
+#define AX_MEDIUM_PF		0x0080
+#define AX_MEDIUM_JFE		0x0040
+#define AX_MEDIUM_TFC		0x0020
+#define AX_MEDIUM_RFC		0x0010
+#define AX_MEDIUM_ENCK		0x0008
+#define AX_MEDIUM_AC		0x0004
+#define AX_MEDIUM_FD		0x0002
+#define AX_MEDIUM_GM		0x0001
+#define AX_MEDIUM_SM		0x1000
+#define AX_MEDIUM_SBP		0x0800
+#define AX_MEDIUM_PS		0x0200
+#define AX_MEDIUM_RE		0x0100
+
+#define AX88178_MEDIUM_DEFAULT	\
+	(AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
+	 AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
+	 AX_MEDIUM_RE)
+
+#define AX88772_MEDIUM_DEFAULT	\
+	(AX_MEDIUM_FD | AX_MEDIUM_RFC | \
+	 AX_MEDIUM_TFC | AX_MEDIUM_PS | \
+	 AX_MEDIUM_AC | AX_MEDIUM_RE)
+
+/* AX88772 & AX88178 RX_CTL values */
+#define AX_RX_CTL_SO			0x0080
+#define AX_RX_CTL_AB			0x0008
+
+#define AX_DEFAULT_RX_CTL	\
+	(AX_RX_CTL_SO | AX_RX_CTL_AB)
+
+/* GPIO 2 toggles */
+#define AX_GPIO_GPO2EN		0x10	/* GPIO2 Output enable */
+#define AX_GPIO_GPO_2		0x20	/* GPIO2 Output value */
+#define AX_GPIO_RSE		0x80	/* Reload serial EEPROM */
+
+/* local defines */
+#define ASIX_BASE_NAME "asx"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define AX_RX_URB_SIZE 2048
+#define PHY_CONNECT_TIMEOUT 5000
+
+/* asix_flags defines */
+#define FLAG_NONE			0
+#define FLAG_TYPE_AX88172	(1U << 0)
+#define FLAG_TYPE_AX88772	(1U << 1)
+#define FLAG_TYPE_AX88772B	(1U << 2)
+#define FLAG_EEPROM_MAC		(1U << 3) /* initial mac address in eeprom */
+
+
+/* driver private */
+struct asix_private {
+	int flags;
+#ifdef CONFIG_DM_ETH
+	struct ueth_data ueth;
+#endif
+};
+
+#ifndef CONFIG_DM_ETH
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+#endif
+
+/*
+ * Asix infrastructure commands
+ */
+static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+			     u16 size, void *data)
+{
+	int len;
+
+	debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x "
+		"size=%d\n", cmd, value, index, size);
+
+	len = usb_control_msg(
+		dev->pusb_dev,
+		usb_sndctrlpipe(dev->pusb_dev, 0),
+		cmd,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		data,
+		size,
+		USB_CTRL_SET_TIMEOUT);
+
+	return len == size ? 0 : -1;
+}
+
+static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+			    u16 size, void *data)
+{
+	int len;
+
+	debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+		cmd, value, index, size);
+
+	len = usb_control_msg(
+		dev->pusb_dev,
+		usb_rcvctrlpipe(dev->pusb_dev, 0),
+		cmd,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		data,
+		size,
+		USB_CTRL_GET_TIMEOUT);
+	return len == size ? 0 : -1;
+}
+
+static inline int asix_set_sw_mii(struct ueth_data *dev)
+{
+	int ret;
+
+	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+	if (ret < 0)
+		debug("Failed to enable software MII access\n");
+	return ret;
+}
+
+static inline int asix_set_hw_mii(struct ueth_data *dev)
+{
+	int ret;
+
+	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+	if (ret < 0)
+		debug("Failed to enable hardware MII access\n");
+	return ret;
+}
+
+static int asix_mdio_read(struct ueth_data *dev, int phy_id, int loc)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1);
+
+	asix_set_sw_mii(dev);
+	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res);
+	asix_set_hw_mii(dev);
+
+	debug("asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+			phy_id, loc, le16_to_cpu(*res));
+
+	return le16_to_cpu(*res);
+}
+
+static void
+asix_mdio_write(struct ueth_data *dev, int phy_id, int loc, int val)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1);
+	*res = cpu_to_le16(val);
+
+	debug("asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+			phy_id, loc, val);
+	asix_set_sw_mii(dev);
+	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, res);
+	asix_set_hw_mii(dev);
+}
+
+/*
+ * Asix "high level" commands
+ */
+static int asix_sw_reset(struct ueth_data *dev, u8 flags)
+{
+	int ret;
+
+	ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
+	if (ret < 0)
+		debug("Failed to send software reset: %02x\n", ret);
+	else
+		udelay(150 * 1000);
+
+	return ret;
+}
+
+static inline int asix_get_phy_addr(struct ueth_data *dev)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(u8, buf, 2);
+
+	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
+
+	debug("asix_get_phy_addr()\n");
+
+	if (ret < 0) {
+		debug("Error reading PHYID register: %02x\n", ret);
+		goto out;
+	}
+	debug("asix_get_phy_addr() returning 0x%02x%02x\n", buf[0], buf[1]);
+	ret = buf[1];
+
+out:
+	return ret;
+}
+
+static int asix_write_medium_mode(struct ueth_data *dev, u16 mode)
+{
+	int ret;
+
+	debug("asix_write_medium_mode() - mode = 0x%04x\n", mode);
+	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode,
+			0, 0, NULL);
+	if (ret < 0) {
+		debug("Failed to write Medium Mode mode to 0x%04x: %02x\n",
+			mode, ret);
+	}
+	return ret;
+}
+
+static u16 asix_read_rx_ctl(struct ueth_data *dev)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(__le16, v, 1);
+
+	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, v);
+
+	if (ret < 0)
+		debug("Error reading RX_CTL register: %02x\n", ret);
+	else
+		ret = le16_to_cpu(*v);
+	return ret;
+}
+
+static int asix_write_rx_ctl(struct ueth_data *dev, u16 mode)
+{
+	int ret;
+
+	debug("asix_write_rx_ctl() - mode = 0x%04x\n", mode);
+	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+	if (ret < 0) {
+		debug("Failed to write RX_CTL mode to 0x%04x: %02x\n",
+				mode, ret);
+	}
+	return ret;
+}
+
+static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)
+{
+	int ret;
+
+	debug("asix_write_gpio() - value = 0x%04x\n", value);
+	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+	if (ret < 0) {
+		debug("Failed to write GPIO value 0x%04x: %02x\n",
+			value, ret);
+	}
+	if (sleep)
+		udelay(sleep * 1000);
+
+	return ret;
+}
+
+static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr)
+{
+	int ret;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+
+	memcpy(buf, enetaddr, ETH_ALEN);
+
+	ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
+	if (ret < 0)
+		debug("Failed to set MAC address: %02x\n", ret);
+
+	return ret;
+}
+
+/*
+ * mii commands
+ */
+
+/*
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ *
+ * Returns 0 on success, negative on error.
+ */
+static int mii_nway_restart(struct ueth_data *dev)
+{
+	int bmcr;
+	int r = -1;
+
+	/* if autoneg is off, it's an error */
+	bmcr = asix_mdio_read(dev, dev->phy_id, MII_BMCR);
+
+	if (bmcr & BMCR_ANENABLE) {
+		bmcr |= BMCR_ANRESTART;
+		asix_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
+		r = 0;
+	}
+
+	return r;
+}
+
+static int asix_read_mac_common(struct ueth_data *dev,
+				struct asix_private *priv, uint8_t *enetaddr)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+	int i;
+
+	if (priv->flags & FLAG_EEPROM_MAC) {
+		for (i = 0; i < (ETH_ALEN >> 1); i++) {
+			if (asix_read_cmd(dev, AX_CMD_READ_EEPROM,
+					  0x04 + i, 0, 2, buf) < 0) {
+				debug("Failed to read SROM address 04h.\n");
+				return -1;
+			}
+			memcpy(enetaddr + i * 2, buf, 2);
+		}
+	} else {
+		if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
+		     < 0) {
+			debug("Failed to read MAC address.\n");
+			return -1;
+		}
+		memcpy(enetaddr, buf, ETH_ALEN);
+	}
+
+	return 0;
+}
+
+static int asix_basic_reset(struct ueth_data *dev)
+{
+	int embd_phy;
+	u16 rx_ctl;
+
+	if (asix_write_gpio(dev,
+			AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5) < 0)
+		return -1;
+
+	/* 0x10 is the phy id of the embedded 10/100 ethernet phy */
+	embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
+	if (asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+				embd_phy, 0, 0, NULL) < 0) {
+		debug("Select PHY #1 failed\n");
+		return -1;
+	}
+
+	if (asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL) < 0)
+		return -1;
+
+	if (asix_sw_reset(dev, AX_SWRESET_CLEAR) < 0)
+		return -1;
+
+	if (embd_phy) {
+		if (asix_sw_reset(dev, AX_SWRESET_IPRL) < 0)
+			return -1;
+	} else {
+		if (asix_sw_reset(dev, AX_SWRESET_PRTE) < 0)
+			return -1;
+	}
+
+	rx_ctl = asix_read_rx_ctl(dev);
+	debug("RX_CTL is 0x%04x after software reset\n", rx_ctl);
+	if (asix_write_rx_ctl(dev, 0x0000) < 0)
+		return -1;
+
+	rx_ctl = asix_read_rx_ctl(dev);
+	debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+
+	dev->phy_id = asix_get_phy_addr(dev);
+	if (dev->phy_id < 0)
+		debug("Failed to read phy id\n");
+
+	asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
+	asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
+			ADVERTISE_ALL | ADVERTISE_CSMA);
+	mii_nway_restart(dev);
+
+	if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0)
+		return -1;
+
+	if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
+				AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
+				AX88772_IPG2_DEFAULT, 0, NULL) < 0) {
+		debug("Write IPG,IPG1,IPG2 failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int asix_init_common(struct ueth_data *dev, uint8_t *enetaddr)
+{
+	int timeout = 0;
+#define TIMEOUT_RESOLUTION 50	/* ms */
+	int link_detected;
+
+	debug("** %s()\n", __func__);
+
+	if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0)
+		goto out_err;
+
+	if (asix_write_hwaddr_common(dev, enetaddr) < 0)
+		goto out_err;
+
+	do {
+		link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) &
+			BMSR_LSTATUS;
+		if (!link_detected) {
+			if (timeout == 0)
+				printf("Waiting for Ethernet connection... ");
+			udelay(TIMEOUT_RESOLUTION * 1000);
+			timeout += TIMEOUT_RESOLUTION;
+		}
+	} while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+	if (link_detected) {
+		if (timeout != 0)
+			printf("done.\n");
+	} else {
+		printf("unable to connect.\n");
+		goto out_err;
+	}
+
+	/*
+	 * Wait some more to avoid timeout on first transfer
+	 * (e.g. EHCI timed out on TD - token=0x8008d80)
+	 */
+	mdelay(25);
+
+	return 0;
+out_err:
+	return -1;
+}
+
+static int asix_send_common(struct ueth_data *dev, void *packet, int length)
+{
+	int err;
+	u32 packet_len;
+	int actual_len;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+		PKTSIZE + sizeof(packet_len));
+
+	debug("** %s(), len %d\n", __func__, length);
+
+	packet_len = (((length) ^ 0x0000ffff) << 16) + (length);
+	cpu_to_le32s(&packet_len);
+
+	memcpy(msg, &packet_len, sizeof(packet_len));
+	memcpy(msg + sizeof(packet_len), (void *)packet, length);
+
+	err = usb_bulk_msg(dev->pusb_dev,
+				usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+				(void *)msg,
+				length + sizeof(packet_len),
+				&actual_len,
+				USB_BULK_SEND_TIMEOUT);
+	debug("Tx: len = %zu, actual = %u, err = %d\n",
+			length + sizeof(packet_len), actual_len, err);
+
+	return err;
+}
+
+#ifndef CONFIG_DM_ETH
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, struct bd_info *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_init_common(dev, eth->enetaddr);
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_send_common(dev, packet, length);
+}
+
+static int asix_recv(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);
+	unsigned char *buf_ptr;
+	int err;
+	int actual_len;
+	u32 packet_len;
+
+	debug("** %s()\n", __func__);
+
+	err = usb_bulk_msg(dev->pusb_dev,
+				usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+				(void *)recv_buf,
+				AX_RX_URB_SIZE,
+				&actual_len,
+				USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
+		actual_len, err);
+	if (err != 0) {
+		debug("Rx: failed to receive\n");
+		return -1;
+	}
+	if (actual_len > AX_RX_URB_SIZE) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -1;
+	}
+
+	buf_ptr = recv_buf;
+	while (actual_len > 0) {
+		/*
+		 * 1st 4 bytes contain the length of the actual data as two
+		 * complementary 16-bit words. Extract the length of the data.
+		 */
+		if (actual_len < sizeof(packet_len)) {
+			debug("Rx: incomplete packet length\n");
+			return -1;
+		}
+		memcpy(&packet_len, buf_ptr, sizeof(packet_len));
+		le32_to_cpus(&packet_len);
+		if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
+			debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
+			      packet_len, (~packet_len >> 16) & 0x7ff,
+			      packet_len & 0x7ff);
+			return -1;
+		}
+		packet_len = packet_len & 0x7ff;
+		if (packet_len > actual_len - sizeof(packet_len)) {
+			debug("Rx: too large packet: %d\n", packet_len);
+			return -1;
+		}
+
+		/* Notify net stack */
+		net_process_received_packet(buf_ptr + sizeof(packet_len),
+					    packet_len);
+
+		/* Adjust for next iteration. Packets are padded to 16-bits */
+		if (packet_len & 1)
+			packet_len++;
+		actual_len -= sizeof(packet_len) + packet_len;
+		buf_ptr += sizeof(packet_len) + packet_len;
+	}
+
+	return err;
+}
+
+static void asix_halt(struct eth_device *eth)
+{
+	debug("** %s()\n", __func__);
+}
+
+static int asix_write_hwaddr(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_write_hwaddr_common(dev, eth->enetaddr);
+}
+
+/*
+ * Asix probing functions
+ */
+void asix_eth_before_probe(void)
+{
+	curr_eth_dev = 0;
+}
+
+struct asix_dongle {
+	unsigned short vendor;
+	unsigned short product;
+	int flags;
+};
+
+static const struct asix_dongle asix_dongles[] = {
+	{ 0x05ac, 0x1402, FLAG_TYPE_AX88772 },	/* Apple USB Ethernet Adapter */
+	{ 0x07d1, 0x3c05, FLAG_TYPE_AX88772 },	/* D-Link DUB-E100 H/W Ver B1 */
+	{ 0x2001, 0x1a02, FLAG_TYPE_AX88772 },	/* D-Link DUB-E100 H/W Ver C1 */
+	/* Cables-to-Go USB Ethernet Adapter */
+	{ 0x0b95, 0x772a, FLAG_TYPE_AX88772 },
+	{ 0x0b95, 0x7720, FLAG_TYPE_AX88772 },	/* Trendnet TU2-ET100 V3.0R */
+	{ 0x0b95, 0x1720, FLAG_TYPE_AX88172 },	/* SMC */
+	{ 0x0db0, 0xa877, FLAG_TYPE_AX88772 },	/* MSI - ASIX 88772a */
+	{ 0x13b1, 0x0018, FLAG_TYPE_AX88172 },	/* Linksys 200M v2.1 */
+	{ 0x1557, 0x7720, FLAG_TYPE_AX88772 },	/* 0Q0 cable ethernet */
+	/* DLink DUB-E100 H/W Ver B1 Alternate */
+	{ 0x2001, 0x3c05, FLAG_TYPE_AX88772 },
+	/* ASIX 88772B */
+	{ 0x0b95, 0x772b, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
+	{ 0x0b95, 0x7e2b, FLAG_TYPE_AX88772B },
+	{ 0x0000, 0x0000, FLAG_NONE }	/* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an asix device */
+int asix_eth_probe(struct usb_device *dev, unsigned int ifnum,
+		      struct ueth_data *ss)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *iface_desc;
+	int ep_in_found = 0, ep_out_found = 0;
+	int i;
+
+	/* let's examine the device now */
+	iface = &dev->config.if_desc[ifnum];
+	iface_desc = &dev->config.if_desc[ifnum].desc;
+
+	for (i = 0; asix_dongles[i].vendor != 0; i++) {
+		if (dev->descriptor.idVendor == asix_dongles[i].vendor &&
+		    dev->descriptor.idProduct == asix_dongles[i].product)
+			/* Found a supported dongle */
+			break;
+	}
+
+	if (asix_dongles[i].vendor == 0)
+		return 0;
+
+	memset(ss, 0, sizeof(struct ueth_data));
+
+	/* At this point, we know we've got a live one */
+	debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
+	      dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	/* Initialize the ueth_data structure with some useful info */
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->subclass = iface_desc->bInterfaceSubClass;
+	ss->protocol = iface_desc->bInterfaceProtocol;
+
+	/* alloc driver private */
+	ss->dev_priv = calloc(1, sizeof(struct asix_private));
+	if (!ss->dev_priv)
+		return 0;
+
+	((struct asix_private *)ss->dev_priv)->flags = asix_dongles[i].flags;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and
+	 * int. We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		/* is it an BULK endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
+			if (ep_addr & USB_DIR_IN) {
+				if (!ep_in_found) {
+					ss->ep_in = ep_addr &
+						USB_ENDPOINT_NUMBER_MASK;
+					ep_in_found = 1;
+				}
+			} else {
+				if (!ep_out_found) {
+					ss->ep_out = ep_addr &
+						USB_ENDPOINT_NUMBER_MASK;
+					ep_out_found = 1;
+				}
+			}
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ss->irqinterval = iface->ep_desc[i].bInterval;
+		}
+	}
+	debug("Endpoints In %d Out %d Int %d\n",
+		  ss->ep_in, ss->ep_out, ss->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+	    !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+		debug("Problems with device\n");
+		return 0;
+	}
+	dev->privptr = (void *)ss;
+	return 1;
+}
+
+int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+				struct eth_device *eth)
+{
+	struct asix_private *priv = (struct asix_private *)ss->dev_priv;
+
+	if (!eth) {
+		debug("%s: missing parameter.\n", __func__);
+		return 0;
+	}
+	sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++);
+	eth->init = asix_init;
+	eth->send = asix_send;
+	eth->recv = asix_recv;
+	eth->halt = asix_halt;
+	if (!(priv->flags & FLAG_TYPE_AX88172))
+		eth->write_hwaddr = asix_write_hwaddr;
+	eth->priv = ss;
+
+	if (asix_basic_reset(ss))
+		return 0;
+
+	/* Get the MAC address */
+	if (asix_read_mac_common(ss, priv, eth->enetaddr))
+		return 0;
+	debug("MAC %pM\n", eth->enetaddr);
+
+	return 1;
+}
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int asix_eth_start(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_init_common(&priv->ueth, pdata->enetaddr);
+}
+
+void asix_eth_stop(struct udevice *dev)
+{
+	debug("** %s()\n", __func__);
+}
+
+int asix_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_send_common(&priv->ueth, packet, length);
+}
+
+int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	uint8_t *ptr;
+	int ret, len;
+	u32 packet_len;
+
+	len = usb_ether_get_rx_bytes(ueth, &ptr);
+	debug("%s: first try, len=%d\n", __func__, len);
+	if (!len) {
+		if (!(flags & ETH_RECV_CHECK_DEVICE))
+			return -EAGAIN;
+		ret = usb_ether_receive(ueth, AX_RX_URB_SIZE);
+		if (ret == -EAGAIN)
+			return ret;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: second try, len=%d\n", __func__, len);
+	}
+
+	/*
+	 * 1st 4 bytes contain the length of the actual data as two
+	 * complementary 16-bit words. Extract the length of the data.
+	 */
+	if (len < sizeof(packet_len)) {
+		debug("Rx: incomplete packet length\n");
+		goto err;
+	}
+	memcpy(&packet_len, ptr, sizeof(packet_len));
+	le32_to_cpus(&packet_len);
+	if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
+		debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
+		      packet_len, (~packet_len >> 16) & 0x7ff,
+		      packet_len & 0x7ff);
+		goto err;
+	}
+	packet_len = packet_len & 0x7ff;
+	if (packet_len > len - sizeof(packet_len)) {
+		debug("Rx: too large packet: %d\n", packet_len);
+		goto err;
+	}
+
+	*packetp = ptr + sizeof(packet_len);
+	return packet_len;
+
+err:
+	usb_ether_advance_rxbuf(ueth, -1);
+	return -EINVAL;
+}
+
+static int asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	if (packet_len & 1)
+		packet_len++;
+	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+	return 0;
+}
+
+int asix_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+
+	if (priv->flags & FLAG_TYPE_AX88172)
+		return -ENOSYS;
+
+	return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr);
+}
+
+static int asix_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ss = &priv->ueth;
+	int ret;
+
+	priv->flags = dev->driver_data;
+	ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE);
+	if (ret)
+		return ret;
+
+	ret = asix_basic_reset(ss);
+	if (ret)
+		goto err;
+
+	/* Get the MAC address */
+	ret = asix_read_mac_common(ss, priv, pdata->enetaddr);
+	if (ret)
+		goto err;
+	debug("MAC %pM\n", pdata->enetaddr);
+
+	return 0;
+
+err:
+	return usb_ether_deregister(ss);
+}
+
+static const struct eth_ops asix_eth_ops = {
+	.start	= asix_eth_start,
+	.send	= asix_eth_send,
+	.recv	= asix_eth_recv,
+	.free_pkt = asix_free_pkt,
+	.stop	= asix_eth_stop,
+	.write_hwaddr = asix_write_hwaddr,
+};
+
+U_BOOT_DRIVER(asix_eth) = {
+	.name	= "asix_eth",
+	.id	= UCLASS_ETH,
+	.probe = asix_eth_probe,
+	.ops	= &asix_eth_ops,
+	.priv_auto	= sizeof(struct asix_private),
+	.plat_auto	= sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id asix_eth_id_table[] = {
+	/* Apple USB Ethernet Adapter */
+	{ USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 },
+	/* D-Link DUB-E100 H/W Ver B1 */
+	{ USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+	/* D-Link DUB-E100 H/W Ver C1 */
+	{ USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 },
+	/* Cables-to-Go USB Ethernet Adapter */
+	{ USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 },
+	/* Trendnet TU2-ET100 V3.0R */
+	{ USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+	/* SMC */
+	{ USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 },
+	/* MSI - ASIX 88772a */
+	{ USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 },
+	/* Linksys 200M v2.1 */
+	{ USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 },
+	/* 0Q0 cable ethernet */
+	{ USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+	/* DLink DUB-E100 H/W Ver B1 Alternate */
+	{ USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+	/* ASIX 88772B */
+	{ USB_DEVICE(0x0b95, 0x772b),
+		.driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
+	{ USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B },
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table);
+#endif
diff --git a/roms/u-boot/drivers/usb/eth/asix88179.c b/roms/u-boot/drivers/usb/eth/asix88179.c
new file mode 100644
index 000000000..4742a95af
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/asix88179.c
@@ -0,0 +1,921 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Rene Griessl <rgriessl@cit-ec.uni-bielefeld.de>
+ * based on the U-Boot Asix driver as well as information
+ * from the Linux AX88179_178a driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <net.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+#include <malloc.h>
+#include <memalign.h>
+#include <errno.h>
+
+/* ASIX AX88179 based USB 3.0 Ethernet Devices */
+#define AX88179_PHY_ID				0x03
+#define AX_EEPROM_LEN				0x100
+#define AX88179_EEPROM_MAGIC			0x17900b95
+#define AX_MCAST_FLTSIZE			8
+#define AX_MAX_MCAST				64
+#define AX_INT_PPLS_LINK			(1 << 16)
+#define AX_RXHDR_L4_TYPE_MASK			0x1c
+#define AX_RXHDR_L4_TYPE_UDP			4
+#define AX_RXHDR_L4_TYPE_TCP			16
+#define AX_RXHDR_L3CSUM_ERR			2
+#define AX_RXHDR_L4CSUM_ERR			1
+#define AX_RXHDR_CRC_ERR			(1 << 29)
+#define AX_RXHDR_DROP_ERR			(1 << 31)
+#define AX_ENDPOINT_INT				0x01
+#define AX_ENDPOINT_IN				0x02
+#define AX_ENDPOINT_OUT				0x03
+#define AX_ACCESS_MAC				0x01
+#define AX_ACCESS_PHY				0x02
+#define AX_ACCESS_EEPROM			0x04
+#define AX_ACCESS_EFUS				0x05
+#define AX_PAUSE_WATERLVL_HIGH			0x54
+#define AX_PAUSE_WATERLVL_LOW			0x55
+
+#define PHYSICAL_LINK_STATUS			0x02
+	#define	AX_USB_SS		(1 << 2)
+	#define	AX_USB_HS		(1 << 1)
+
+#define GENERAL_STATUS				0x03
+	#define	AX_SECLD		(1 << 2)
+
+#define AX_SROM_ADDR				0x07
+#define AX_SROM_CMD				0x0a
+	#define EEP_RD			(1 << 2)
+	#define EEP_BUSY		(1 << 4)
+
+#define AX_SROM_DATA_LOW			0x08
+#define AX_SROM_DATA_HIGH			0x09
+
+#define AX_RX_CTL				0x0b
+	#define AX_RX_CTL_DROPCRCERR	(1 << 8)
+	#define AX_RX_CTL_IPE		(1 << 9)
+	#define AX_RX_CTL_START		(1 << 7)
+	#define AX_RX_CTL_AP		(1 << 5)
+	#define AX_RX_CTL_AM		(1 << 4)
+	#define AX_RX_CTL_AB		(1 << 3)
+	#define AX_RX_CTL_AMALL		(1 << 1)
+	#define AX_RX_CTL_PRO		(1 << 0)
+	#define AX_RX_CTL_STOP		0
+
+#define AX_NODE_ID				0x10
+#define AX_MULFLTARY				0x16
+
+#define AX_MEDIUM_STATUS_MODE			0x22
+	#define AX_MEDIUM_GIGAMODE	(1 << 0)
+	#define AX_MEDIUM_FULL_DUPLEX	(1 << 1)
+	#define AX_MEDIUM_EN_125MHZ	(1 << 3)
+	#define AX_MEDIUM_RXFLOW_CTRLEN	(1 << 4)
+	#define AX_MEDIUM_TXFLOW_CTRLEN	(1 << 5)
+	#define AX_MEDIUM_RECEIVE_EN	(1 << 8)
+	#define AX_MEDIUM_PS		(1 << 9)
+	#define AX_MEDIUM_JUMBO_EN	0x8040
+
+#define AX_MONITOR_MOD				0x24
+	#define AX_MONITOR_MODE_RWLC	(1 << 1)
+	#define AX_MONITOR_MODE_RWMP	(1 << 2)
+	#define AX_MONITOR_MODE_PMEPOL	(1 << 5)
+	#define AX_MONITOR_MODE_PMETYPE	(1 << 6)
+
+#define AX_GPIO_CTRL				0x25
+	#define AX_GPIO_CTRL_GPIO3EN	(1 << 7)
+	#define AX_GPIO_CTRL_GPIO2EN	(1 << 6)
+	#define AX_GPIO_CTRL_GPIO1EN	(1 << 5)
+
+#define AX_PHYPWR_RSTCTL			0x26
+	#define AX_PHYPWR_RSTCTL_BZ	(1 << 4)
+	#define AX_PHYPWR_RSTCTL_IPRL	(1 << 5)
+	#define AX_PHYPWR_RSTCTL_AT	(1 << 12)
+
+#define AX_RX_BULKIN_QCTRL			0x2e
+#define AX_CLK_SELECT				0x33
+	#define AX_CLK_SELECT_BCS	(1 << 0)
+	#define AX_CLK_SELECT_ACS	(1 << 1)
+	#define AX_CLK_SELECT_ULR	(1 << 3)
+
+#define AX_RXCOE_CTL				0x34
+	#define AX_RXCOE_IP		(1 << 0)
+	#define AX_RXCOE_TCP		(1 << 1)
+	#define AX_RXCOE_UDP		(1 << 2)
+	#define AX_RXCOE_TCPV6		(1 << 5)
+	#define AX_RXCOE_UDPV6		(1 << 6)
+
+#define AX_TXCOE_CTL				0x35
+	#define AX_TXCOE_IP		(1 << 0)
+	#define AX_TXCOE_TCP		(1 << 1)
+	#define AX_TXCOE_UDP		(1 << 2)
+	#define AX_TXCOE_TCPV6		(1 << 5)
+	#define AX_TXCOE_UDPV6		(1 << 6)
+
+#define AX_LEDCTRL				0x73
+
+#define GMII_PHY_PHYSR				0x11
+	#define GMII_PHY_PHYSR_SMASK	0xc000
+	#define GMII_PHY_PHYSR_GIGA	(1 << 15)
+	#define GMII_PHY_PHYSR_100	(1 << 14)
+	#define GMII_PHY_PHYSR_FULL	(1 << 13)
+	#define GMII_PHY_PHYSR_LINK	(1 << 10)
+
+#define GMII_LED_ACT				0x1a
+	#define	GMII_LED_ACTIVE_MASK	0xff8f
+	#define	GMII_LED0_ACTIVE	(1 << 4)
+	#define	GMII_LED1_ACTIVE	(1 << 5)
+	#define	GMII_LED2_ACTIVE	(1 << 6)
+
+#define GMII_LED_LINK				0x1c
+	#define	GMII_LED_LINK_MASK	0xf888
+	#define	GMII_LED0_LINK_10	(1 << 0)
+	#define	GMII_LED0_LINK_100	(1 << 1)
+	#define	GMII_LED0_LINK_1000	(1 << 2)
+	#define	GMII_LED1_LINK_10	(1 << 4)
+	#define	GMII_LED1_LINK_100	(1 << 5)
+	#define	GMII_LED1_LINK_1000	(1 << 6)
+	#define	GMII_LED2_LINK_10	(1 << 8)
+	#define	GMII_LED2_LINK_100	(1 << 9)
+	#define	GMII_LED2_LINK_1000	(1 << 10)
+	#define	LED0_ACTIVE		(1 << 0)
+	#define	LED0_LINK_10		(1 << 1)
+	#define	LED0_LINK_100		(1 << 2)
+	#define	LED0_LINK_1000		(1 << 3)
+	#define	LED0_FD			(1 << 4)
+	#define	LED0_USB3_MASK		0x001f
+	#define	LED1_ACTIVE		(1 << 5)
+	#define	LED1_LINK_10		(1 << 6)
+	#define	LED1_LINK_100		(1 << 7)
+	#define	LED1_LINK_1000		(1 << 8)
+	#define	LED1_FD			(1 << 9)
+	#define	LED1_USB3_MASK		0x03e0
+	#define	LED2_ACTIVE		(1 << 10)
+	#define	LED2_LINK_1000		(1 << 13)
+	#define	LED2_LINK_100		(1 << 12)
+	#define	LED2_LINK_10		(1 << 11)
+	#define	LED2_FD			(1 << 14)
+	#define	LED_VALID		(1 << 15)
+	#define	LED2_USB3_MASK		0x7c00
+
+#define GMII_PHYPAGE				0x1e
+#define GMII_PHY_PAGE_SELECT			0x1f
+	#define GMII_PHY_PGSEL_EXT	0x0007
+	#define GMII_PHY_PGSEL_PAGE0	0x0000
+
+/* local defines */
+#define ASIX_BASE_NAME "axg"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define AX_RX_URB_SIZE 1024 * 0x12
+#define BLK_FRAME_SIZE 0x200
+#define PHY_CONNECT_TIMEOUT 5000
+
+#define TIMEOUT_RESOLUTION 50	/* ms */
+
+#define FLAG_NONE			0
+#define FLAG_TYPE_AX88179	(1U << 0)
+#define FLAG_TYPE_AX88178a	(1U << 1)
+#define FLAG_TYPE_DLINK_DUB1312	(1U << 2)
+#define FLAG_TYPE_SITECOM	(1U << 3)
+#define FLAG_TYPE_SAMSUNG	(1U << 4)
+#define FLAG_TYPE_LENOVO	(1U << 5)
+#define FLAG_TYPE_GX3		(1U << 6)
+
+/* local vars */
+static const struct {
+	unsigned char ctrl, timer_l, timer_h, size, ifg;
+} AX88179_BULKIN_SIZE[] =	{
+	{7, 0x4f, 0,	0x02, 0xff},
+	{7, 0x20, 3,	0x03, 0xff},
+	{7, 0xae, 7,	0x04, 0xff},
+	{7, 0xcc, 0x4c, 0x04, 8},
+};
+
+#ifndef CONFIG_DM_ETH
+static int curr_eth_dev; /* index for name of next device detected */
+#endif
+
+/* driver private */
+struct asix_private {
+#ifdef CONFIG_DM_ETH
+	struct ueth_data ueth;
+	unsigned pkt_cnt;
+	uint8_t *pkt_data;
+	uint32_t *pkt_hdr;
+#endif
+	int flags;
+	int rx_urb_size;
+	int maxpacketsize;
+};
+
+/*
+ * Asix infrastructure commands
+ */
+static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+			     u16 size, void *data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, size);
+
+	debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+	      cmd, value, index, size);
+
+	memcpy(buf, data, size);
+
+	len = usb_control_msg(
+		dev->pusb_dev,
+		usb_sndctrlpipe(dev->pusb_dev, 0),
+		cmd,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		buf,
+		size,
+		USB_CTRL_SET_TIMEOUT);
+
+	return len == size ? 0 : ECOMM;
+}
+
+static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+			    u16 size, void *data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, size);
+
+	debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+	      cmd, value, index, size);
+
+	len = usb_control_msg(
+		dev->pusb_dev,
+		usb_rcvctrlpipe(dev->pusb_dev, 0),
+		cmd,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		buf,
+		size,
+		USB_CTRL_GET_TIMEOUT);
+
+	memcpy(data, buf, size);
+
+	return len == size ? 0 : ECOMM;
+}
+
+static int asix_read_mac(struct ueth_data *dev, uint8_t *enetaddr)
+{
+	int ret;
+
+	ret = asix_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, 6, 6, enetaddr);
+	if (ret < 0)
+		debug("Failed to read MAC address: %02x\n", ret);
+
+	return ret;
+}
+
+static int asix_write_mac(struct ueth_data *dev, uint8_t *enetaddr)
+{
+	int ret;
+
+	ret = asix_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
+				 ETH_ALEN, enetaddr);
+	if (ret < 0)
+		debug("Failed to set MAC address: %02x\n", ret);
+
+	return ret;
+}
+
+static int asix_basic_reset(struct ueth_data *dev,
+			struct asix_private *dev_priv)
+{
+	u8 buf[5];
+	u16 *tmp16;
+	u8 *tmp;
+
+	tmp16 = (u16 *)buf;
+	tmp = (u8 *)buf;
+
+	/* Power up ethernet PHY */
+	*tmp16 = 0;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+
+	*tmp16 = AX_PHYPWR_RSTCTL_IPRL;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
+	mdelay(200);
+
+	*tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
+	mdelay(200);
+
+	/* RX bulk configuration */
+	memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+	dev_priv->rx_urb_size = 128 * 20;
+
+	/* Water Level configuration */
+	*tmp = 0x34;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
+
+	*tmp = 0x52;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, 1, 1, tmp);
+
+	/* Enable checksum offload */
+	*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
+	       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
+
+	*tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
+	       AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
+
+	/* Configure RX control register => start operation */
+	*tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
+		 AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
+
+	*tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
+	       AX_MONITOR_MODE_RWMP;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp);
+
+	/* Configure default medium type => giga */
+	*tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
+		 AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX |
+		 AX_MEDIUM_GIGAMODE | AX_MEDIUM_JUMBO_EN;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, 2, 2, tmp16);
+
+	u16 adv = 0;
+	adv = ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_LPACK |
+	      ADVERTISE_NPAGE | ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP;
+	asix_write_cmd(dev, AX_ACCESS_PHY, 0x03, MII_ADVERTISE, 2, &adv);
+
+	adv = ADVERTISE_1000FULL;
+	asix_write_cmd(dev, AX_ACCESS_PHY, 0x03, MII_CTRL1000, 2, &adv);
+
+	return 0;
+}
+
+static int asix_wait_link(struct ueth_data *dev)
+{
+	int timeout = 0;
+	int link_detected;
+	u8 buf[2];
+	u16 *tmp16;
+
+	tmp16 = (u16 *)buf;
+
+	do {
+		asix_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+			      MII_BMSR, 2, buf);
+		link_detected = *tmp16 & BMSR_LSTATUS;
+		if (!link_detected) {
+			if (timeout == 0)
+				printf("Waiting for Ethernet connection... ");
+			mdelay(TIMEOUT_RESOLUTION);
+			timeout += TIMEOUT_RESOLUTION;
+		}
+	} while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+
+	if (link_detected) {
+		if (timeout > 0)
+			printf("done.\n");
+		return 0;
+	} else {
+		printf("unable to connect.\n");
+		return -ENETUNREACH;
+	}
+}
+
+static int asix_init_common(struct ueth_data *dev,
+			struct asix_private *dev_priv)
+{
+	u8 buf[2], tmp[5], link_sts;
+	u16 *tmp16, mode;
+
+
+	tmp16 = (u16 *)buf;
+
+	debug("** %s()\n", __func__);
+
+	/* Configure RX control register => start operation */
+	*tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
+		 AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
+	if (asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16) != 0)
+		goto out_err;
+
+	if (asix_wait_link(dev) != 0) {
+		/*reset device and try again*/
+		printf("Reset Ethernet Device\n");
+		asix_basic_reset(dev, dev_priv);
+		if (asix_wait_link(dev) != 0)
+			goto out_err;
+	}
+
+	/* Configure link */
+	mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
+	       AX_MEDIUM_RXFLOW_CTRLEN;
+
+	asix_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS,
+		      1, 1, &link_sts);
+
+	asix_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
+		      GMII_PHY_PHYSR, 2, tmp16);
+
+	if (!(*tmp16 & GMII_PHY_PHYSR_LINK)) {
+		return 0;
+	} else if (GMII_PHY_PHYSR_GIGA == (*tmp16 & GMII_PHY_PHYSR_SMASK)) {
+		mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ |
+			AX_MEDIUM_JUMBO_EN;
+
+		if (link_sts & AX_USB_SS)
+			memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
+		else if (link_sts & AX_USB_HS)
+			memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5);
+		else
+			memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+	} else if (GMII_PHY_PHYSR_100 == (*tmp16 & GMII_PHY_PHYSR_SMASK)) {
+		mode |= AX_MEDIUM_PS;
+
+		if (link_sts & (AX_USB_SS | AX_USB_HS))
+			memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5);
+		else
+			memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+	} else {
+		memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
+	}
+
+	/* RX bulk configuration */
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
+
+	dev_priv->rx_urb_size = (1024 * (tmp[3] + 2));
+	if (*tmp16 & GMII_PHY_PHYSR_FULL)
+		mode |= AX_MEDIUM_FULL_DUPLEX;
+	asix_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
+		       2, 2, &mode);
+
+	return 0;
+out_err:
+	return -1;
+}
+
+static int asix_send_common(struct ueth_data *dev,
+			struct asix_private *dev_priv,
+			void *packet, int length)
+{
+	int err;
+	u32 packet_len, tx_hdr2;
+	int actual_len, framesize;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+				 PKTSIZE + (2 * sizeof(packet_len)));
+
+	debug("** %s(), len %d\n", __func__, length);
+
+	packet_len = length;
+	cpu_to_le32s(&packet_len);
+
+	memcpy(msg, &packet_len, sizeof(packet_len));
+	framesize = dev_priv->maxpacketsize;
+	tx_hdr2 = 0;
+	if (((length + 8) % framesize) == 0)
+		tx_hdr2 |= 0x80008000;	/* Enable padding */
+
+	cpu_to_le32s(&tx_hdr2);
+
+	memcpy(msg + sizeof(packet_len), &tx_hdr2, sizeof(tx_hdr2));
+
+	memcpy(msg + sizeof(packet_len) + sizeof(tx_hdr2),
+	       (void *)packet, length);
+
+	err = usb_bulk_msg(dev->pusb_dev,
+				usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+				(void *)msg,
+				length + sizeof(packet_len) + sizeof(tx_hdr2),
+				&actual_len,
+				USB_BULK_SEND_TIMEOUT);
+	debug("Tx: len = %zu, actual = %u, err = %d\n",
+	      length + sizeof(packet_len), actual_len, err);
+
+	return err;
+}
+
+#ifndef CONFIG_DM_ETH
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, struct bd_info *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+
+	return asix_init_common(dev, dev_priv);
+}
+
+static int asix_write_hwaddr(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return asix_write_mac(dev, eth->enetaddr);
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+
+	return asix_send_common(dev, dev_priv, packet, length);
+}
+
+static int asix_recv(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv;
+
+	u16 frame_pos;
+	int err;
+	int actual_len;
+
+	int pkt_cnt;
+	u32 rx_hdr;
+	u16 hdr_off;
+	u32 *pkt_hdr;
+	ALLOC_CACHE_ALIGN_BUFFER(u8, recv_buf, dev_priv->rx_urb_size);
+
+	actual_len = -1;
+
+	debug("** %s()\n", __func__);
+
+	err = usb_bulk_msg(dev->pusb_dev,
+				usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+				(void *)recv_buf,
+				dev_priv->rx_urb_size,
+				&actual_len,
+				USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", dev_priv->rx_urb_size,
+	      actual_len, err);
+
+	if (err != 0) {
+		debug("Rx: failed to receive\n");
+		return -ECOMM;
+	}
+	if (actual_len > dev_priv->rx_urb_size) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -EMSGSIZE;
+	}
+
+
+	rx_hdr = *(u32 *)(recv_buf + actual_len - 4);
+	le32_to_cpus(&rx_hdr);
+
+	pkt_cnt = (u16)rx_hdr;
+	hdr_off = (u16)(rx_hdr >> 16);
+	pkt_hdr = (u32 *)(recv_buf + hdr_off);
+
+
+	frame_pos = 0;
+
+	while (pkt_cnt--) {
+		u16 pkt_len;
+
+		le32_to_cpus(pkt_hdr);
+		pkt_len = (*pkt_hdr >> 16) & 0x1fff;
+
+		frame_pos += 2;
+
+		net_process_received_packet(recv_buf + frame_pos, pkt_len);
+
+		pkt_hdr++;
+		frame_pos += ((pkt_len + 7) & 0xFFF8)-2;
+
+		if (pkt_cnt == 0)
+			return 0;
+	}
+	return err;
+}
+
+static void asix_halt(struct eth_device *eth)
+{
+	debug("** %s()\n", __func__);
+}
+
+/*
+ * Asix probing functions
+ */
+void ax88179_eth_before_probe(void)
+{
+	curr_eth_dev = 0;
+}
+
+struct asix_dongle {
+	unsigned short vendor;
+	unsigned short product;
+	int flags;
+};
+
+static const struct asix_dongle asix_dongles[] = {
+	{ 0x0b95, 0x1790, FLAG_TYPE_AX88179 },
+	{ 0x0b95, 0x178a, FLAG_TYPE_AX88178a },
+	{ 0x2001, 0x4a00, FLAG_TYPE_DLINK_DUB1312 },
+	{ 0x0df6, 0x0072, FLAG_TYPE_SITECOM },
+	{ 0x04e8, 0xa100, FLAG_TYPE_SAMSUNG },
+	{ 0x17ef, 0x304b, FLAG_TYPE_LENOVO },
+	{ 0x04b4, 0x3610, FLAG_TYPE_GX3 },
+	{ 0x0000, 0x0000, FLAG_NONE }	/* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an asix device */
+int ax88179_eth_probe(struct usb_device *dev, unsigned int ifnum,
+		      struct ueth_data *ss)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *iface_desc;
+	struct asix_private *dev_priv;
+	int ep_in_found = 0, ep_out_found = 0;
+	int i;
+
+	/* let's examine the device now */
+	iface = &dev->config.if_desc[ifnum];
+	iface_desc = &dev->config.if_desc[ifnum].desc;
+
+	for (i = 0; asix_dongles[i].vendor != 0; i++) {
+		if (dev->descriptor.idVendor == asix_dongles[i].vendor &&
+		    dev->descriptor.idProduct == asix_dongles[i].product)
+			/* Found a supported dongle */
+			break;
+	}
+
+	if (asix_dongles[i].vendor == 0)
+		return 0;
+
+	memset(ss, 0, sizeof(struct ueth_data));
+
+	/* At this point, we know we've got a live one */
+	debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
+	      dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	/* Initialize the ueth_data structure with some useful info */
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->subclass = iface_desc->bInterfaceSubClass;
+	ss->protocol = iface_desc->bInterfaceProtocol;
+
+	/* alloc driver private */
+	ss->dev_priv = calloc(1, sizeof(struct asix_private));
+	if (!ss->dev_priv)
+		return 0;
+	dev_priv = ss->dev_priv;
+	dev_priv->flags = asix_dongles[i].flags;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and
+	 * int. We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ss->irqinterval = iface->ep_desc[i].bInterval;
+			continue;
+		}
+
+		/* is it an BULK endpoint? */
+		if (!((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
+			continue;
+
+		u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
+		if ((ep_addr & USB_DIR_IN) && !ep_in_found) {
+			ss->ep_in = ep_addr &
+				USB_ENDPOINT_NUMBER_MASK;
+			ep_in_found = 1;
+		}
+		if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
+			ss->ep_out = ep_addr &
+				USB_ENDPOINT_NUMBER_MASK;
+			dev_priv->maxpacketsize =
+				dev->epmaxpacketout[AX_ENDPOINT_OUT];
+			ep_out_found = 1;
+		}
+	}
+	debug("Endpoints In %d Out %d Int %d\n",
+	      ss->ep_in, ss->ep_out, ss->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+	    !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+		debug("Problems with device\n");
+		return 0;
+	}
+	dev->privptr = (void *)ss;
+	return 1;
+}
+
+int ax88179_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+				struct eth_device *eth)
+{
+	struct asix_private *dev_priv = (struct asix_private *)ss->dev_priv;
+
+	if (!eth) {
+		debug("%s: missing parameter.\n", __func__);
+		return 0;
+	}
+	sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++);
+	eth->init = asix_init;
+	eth->send = asix_send;
+	eth->recv = asix_recv;
+	eth->halt = asix_halt;
+	eth->write_hwaddr = asix_write_hwaddr;
+	eth->priv = ss;
+
+	if (asix_basic_reset(ss, dev_priv))
+		return 0;
+
+	/* Get the MAC address */
+	if (asix_read_mac(ss, eth->enetaddr))
+		return 0;
+	debug("MAC %pM\n", eth->enetaddr);
+
+	return 1;
+}
+
+#else /* !CONFIG_DM_ETH */
+
+static int ax88179_eth_start(struct udevice *dev)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_init_common(&priv->ueth, priv);
+}
+
+void ax88179_eth_stop(struct udevice *dev)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+
+	debug("** %s()\n", __func__);
+
+	usb_ether_advance_rxbuf(ueth, -1);
+	priv->pkt_cnt = 0;
+	priv->pkt_data = NULL;
+	priv->pkt_hdr = NULL;
+}
+
+int ax88179_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+
+	return asix_send_common(&priv->ueth, priv, packet, length);
+}
+
+int ax88179_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	int ret, len;
+	u16 pkt_len;
+
+	/* No packet left, get a new one */
+	if (priv->pkt_cnt == 0) {
+		uint8_t *ptr;
+		u16 pkt_cnt;
+		u16 hdr_off;
+		u32 rx_hdr;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: first try, len=%d\n", __func__, len);
+		if (!len) {
+			if (!(flags & ETH_RECV_CHECK_DEVICE))
+				return -EAGAIN;
+
+			ret = usb_ether_receive(ueth, priv->rx_urb_size);
+			if (ret < 0)
+				return ret;
+
+			len = usb_ether_get_rx_bytes(ueth, &ptr);
+			debug("%s: second try, len=%d\n", __func__, len);
+		}
+
+		if (len < 4) {
+			usb_ether_advance_rxbuf(ueth, -1);
+			return -EMSGSIZE;
+		}
+
+		rx_hdr = *(u32 *)(ptr + len - 4);
+		le32_to_cpus(&rx_hdr);
+
+		pkt_cnt = (u16)rx_hdr;
+		if (pkt_cnt == 0) {
+			usb_ether_advance_rxbuf(ueth, -1);
+			return 0;
+		}
+
+		hdr_off = (u16)(rx_hdr >> 16);
+		if (hdr_off > len - 4) {
+			usb_ether_advance_rxbuf(ueth, -1);
+			return -EIO;
+		}
+
+		priv->pkt_cnt = pkt_cnt;
+		priv->pkt_data = ptr;
+		priv->pkt_hdr = (u32 *)(ptr + hdr_off);
+		debug("%s: %d packets received, pkt header at %d\n",
+		      __func__, (int)priv->pkt_cnt, (int)hdr_off);
+	}
+
+	le32_to_cpus(priv->pkt_hdr);
+	pkt_len = (*priv->pkt_hdr >> 16) & 0x1fff;
+
+	*packetp = priv->pkt_data + 2;
+
+	priv->pkt_data += (pkt_len + 7) & 0xFFF8;
+	priv->pkt_cnt--;
+	priv->pkt_hdr++;
+
+	debug("%s: return packet of %d bytes (%d packets left)\n",
+	      __func__, (int)pkt_len, priv->pkt_cnt);
+	return pkt_len;
+}
+
+static int ax88179_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+
+	if (priv->pkt_cnt == 0)
+		usb_ether_advance_rxbuf(ueth, -1);
+
+	return 0;
+}
+
+int ax88179_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+
+	return asix_write_mac(ueth, pdata->enetaddr);
+}
+
+static int ax88179_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct asix_private *priv = dev_get_priv(dev);
+	struct usb_device *usb_dev;
+	int ret;
+
+	priv->flags = dev->driver_data;
+	ret = usb_ether_register(dev, &priv->ueth, AX_RX_URB_SIZE);
+	if (ret)
+		return ret;
+
+	usb_dev = priv->ueth.pusb_dev;
+	priv->maxpacketsize = usb_dev->epmaxpacketout[AX_ENDPOINT_OUT];
+
+	/* Get the MAC address */
+	ret = asix_read_mac(&priv->ueth, pdata->enetaddr);
+	if (ret)
+		return ret;
+	debug("MAC %pM\n", pdata->enetaddr);
+
+	return 0;
+}
+
+static const struct eth_ops ax88179_eth_ops = {
+	.start = ax88179_eth_start,
+	.send = ax88179_eth_send,
+	.recv = ax88179_eth_recv,
+	.free_pkt = ax88179_free_pkt,
+	.stop = ax88179_eth_stop,
+	.write_hwaddr = ax88179_write_hwaddr,
+};
+
+U_BOOT_DRIVER(ax88179_eth) = {
+	.name = "ax88179_eth",
+	.id = UCLASS_ETH,
+	.probe = ax88179_eth_probe,
+	.ops = &ax88179_eth_ops,
+	.priv_auto	= sizeof(struct asix_private),
+	.plat_auto	= sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id ax88179_eth_id_table[] = {
+	{ USB_DEVICE(0x0b95, 0x1790), .driver_info = FLAG_TYPE_AX88179 },
+	{ USB_DEVICE(0x0b95, 0x178a), .driver_info = FLAG_TYPE_AX88178a },
+	{ USB_DEVICE(0x2001, 0x4a00), .driver_info = FLAG_TYPE_DLINK_DUB1312 },
+	{ USB_DEVICE(0x0df6, 0x0072), .driver_info = FLAG_TYPE_SITECOM },
+	{ USB_DEVICE(0x04e8, 0xa100), .driver_info = FLAG_TYPE_SAMSUNG },
+	{ USB_DEVICE(0x17ef, 0x304b), .driver_info = FLAG_TYPE_LENOVO },
+	{ USB_DEVICE(0x04b4, 0x3610), .driver_info = FLAG_TYPE_GX3 },
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(ax88179_eth, ax88179_eth_id_table);
+#endif /* !CONFIG_DM_ETH */
diff --git a/roms/u-boot/drivers/usb/eth/lan75xx.c b/roms/u-boot/drivers/usb/eth/lan75xx.c
new file mode 100644
index 000000000..4effbc5c8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/lan75xx.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Microchip Technology Inc. All rights reserved.
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <linux/bitops.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+#include "lan7x.h"
+
+/* LAN75xx specific register/bit defines */
+#define LAN75XX_HW_CFG_BIR		BIT(7)
+
+#define LAN75XX_BURST_CAP		0x034
+
+#define LAN75XX_BULK_IN_DLY		0x03C
+
+#define LAN75XX_RFE_CTL			0x060
+
+#define LAN75XX_FCT_RX_CTL		0x090
+
+#define LAN75XX_FCT_TX_CTL		0x094
+
+#define LAN75XX_FCT_RX_FIFO_END		0x098
+
+#define LAN75XX_FCT_TX_FIFO_END		0x09C
+
+#define LAN75XX_FCT_FLOW		0x0A0
+
+/* MAC ADDRESS PERFECT FILTER For LAN75xx */
+#define LAN75XX_ADDR_FILTX		0x300
+#define LAN75XX_ADDR_FILTX_FB_VALID	BIT(31)
+
+/*
+ * Lan75xx infrastructure commands
+ */
+static int lan75xx_phy_gig_workaround(struct usb_device *udev,
+				      struct ueth_data *dev)
+{
+	int ret = 0;
+
+	/* Only internal phy */
+	/* Set the phy in Gig loopback */
+	lan7x_mdio_write(udev, dev->phy_id, MII_BMCR,
+			 (BMCR_LOOPBACK | BMCR_SPEED1000));
+
+	/* Wait for the link up */
+	ret = lan7x_mdio_wait_for_bit(udev, "BMSR_LSTATUS",
+				      dev->phy_id, MII_BMSR, BMSR_LSTATUS,
+				      true, PHY_CONNECT_TIMEOUT_MS, 1);
+	if (ret)
+		return ret;
+
+	/* phy reset */
+	return lan7x_pmt_phy_reset(udev, dev);
+}
+
+static int lan75xx_update_flowcontrol(struct usb_device *udev,
+				      struct ueth_data *dev)
+{
+	uint32_t flow = 0, fct_flow = 0;
+	int ret;
+
+	ret = lan7x_update_flowcontrol(udev, dev, &flow, &fct_flow);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN75XX_FCT_FLOW, fct_flow);
+	if (ret)
+		return ret;
+	return lan7x_write_reg(udev, FLOW, flow);
+}
+
+static int lan75xx_set_receive_filter(struct usb_device *udev)
+{
+	/* No multicast in u-boot */
+	return lan7x_write_reg(udev, LAN75XX_RFE_CTL,
+			       RFE_CTL_BCAST_EN | RFE_CTL_DA_PERFECT);
+}
+
+/* starts the TX path */
+static void lan75xx_start_tx_path(struct usb_device *udev)
+{
+	/* Enable Tx at MAC */
+	lan7x_write_reg(udev, MAC_TX, MAC_TX_TXEN);
+
+	/* Enable Tx at SCSRs */
+	lan7x_write_reg(udev, LAN75XX_FCT_TX_CTL, FCT_TX_CTL_EN);
+}
+
+/* Starts the Receive path */
+static void lan75xx_start_rx_path(struct usb_device *udev)
+{
+	/* Enable Rx at MAC */
+	lan7x_write_reg(udev, MAC_RX,
+			LAN7X_MAC_RX_MAX_SIZE_DEFAULT |
+			MAC_RX_FCS_STRIP | MAC_RX_RXEN);
+
+	/* Enable Rx at SCSRs */
+	lan7x_write_reg(udev, LAN75XX_FCT_RX_CTL, FCT_RX_CTL_EN);
+}
+
+static int lan75xx_basic_reset(struct usb_device *udev,
+			       struct ueth_data *dev,
+			       struct lan7x_private *priv)
+{
+	int ret;
+	u32 val;
+
+	ret = lan7x_basic_reset(udev, dev);
+	if (ret)
+		return ret;
+
+	/* Keep the chip ID */
+	ret = lan7x_read_reg(udev, ID_REV, &val);
+	if (ret)
+		return ret;
+	debug("LAN75xx ID_REV = 0x%08x\n", val);
+
+	priv->chipid = (val & ID_REV_CHIP_ID_MASK) >> 16;
+
+	/* Respond to the IN token with a NAK */
+	ret = lan7x_read_reg(udev, HW_CFG, &val);
+	if (ret)
+		return ret;
+	val |= LAN75XX_HW_CFG_BIR;
+	return lan7x_write_reg(udev, HW_CFG, val);
+}
+
+int lan75xx_write_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	unsigned char *enetaddr = pdata->enetaddr;
+	u32 addr_lo = get_unaligned_le32(&enetaddr[0]);
+	u32 addr_hi = (u32)get_unaligned_le16(&enetaddr[4]);
+	int ret;
+
+	/* set hardware address */
+	ret = lan7x_write_reg(udev, RX_ADDRL, addr_lo);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, RX_ADDRH, addr_hi);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN75XX_ADDR_FILTX + 4, addr_lo);
+	if (ret)
+		return ret;
+
+	addr_hi |= LAN75XX_ADDR_FILTX_FB_VALID;
+	ret = lan7x_write_reg(udev, LAN75XX_ADDR_FILTX, addr_hi);
+	if (ret)
+		return ret;
+
+	debug("MAC addr %pM written\n", enetaddr);
+
+	return 0;
+}
+
+static int lan75xx_eth_start(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct lan7x_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	int ret;
+	u32 write_buf;
+
+	/* Reset and read Mac addr were done in probe() */
+	ret = lan75xx_write_hwaddr(dev);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, INT_STS, 0xFFFFFFFF);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN75XX_BURST_CAP, 0);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN75XX_BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
+	if (ret)
+		return ret;
+
+	/* set FIFO sizes */
+	write_buf = (MAX_RX_FIFO_SIZE - 512) / 512;
+	ret = lan7x_write_reg(udev, LAN75XX_FCT_RX_FIFO_END, write_buf);
+	if (ret)
+		return ret;
+
+	write_buf = (MAX_TX_FIFO_SIZE - 512) / 512;
+	ret = lan7x_write_reg(udev, LAN75XX_FCT_TX_FIFO_END, write_buf);
+	if (ret)
+		return ret;
+
+	/* Init Tx */
+	ret = lan7x_write_reg(udev, FLOW, 0);
+	if (ret)
+		return ret;
+
+	/* Init Rx. Set Vlan, keep default for VLAN on 75xx */
+	ret = lan75xx_set_receive_filter(udev);
+	if (ret)
+		return ret;
+
+	/* phy workaround for gig link */
+	ret = lan75xx_phy_gig_workaround(udev, ueth);
+	if (ret)
+		return ret;
+
+	/* Init PHY, autonego, and link */
+	ret = lan7x_eth_phylib_connect(dev, &priv->ueth);
+	if (ret)
+		return ret;
+	ret = lan7x_eth_phylib_config_start(dev);
+	if (ret)
+		return ret;
+
+	/*
+	 * MAC_CR has to be set after PHY init.
+	 * MAC will auto detect the PHY speed.
+	 */
+	ret = lan7x_read_reg(udev, MAC_CR, &write_buf);
+	if (ret)
+		return ret;
+	write_buf |= MAC_CR_AUTO_DUPLEX | MAC_CR_AUTO_SPEED | MAC_CR_ADP;
+	ret = lan7x_write_reg(udev, MAC_CR, write_buf);
+	if (ret)
+		return ret;
+
+	lan75xx_start_tx_path(udev);
+	lan75xx_start_rx_path(udev);
+
+	return lan75xx_update_flowcontrol(udev, ueth);
+}
+
+int lan75xx_read_rom_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	int ret;
+
+	/*
+	 * Refer to the doc/README.enetaddr and doc/README.usb for
+	 * the U-Boot MAC address policy
+	 */
+	ret = lan7x_read_eeprom_mac(pdata->enetaddr, udev);
+	if (ret)
+		memset(pdata->enetaddr, 0, 6);
+
+	return 0;
+}
+
+static int lan75xx_eth_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct lan7x_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	int ret;
+
+	/* Do a reset in order to get the MAC address from HW */
+	if (lan75xx_basic_reset(udev, ueth, priv))
+		return 0;
+
+	/* Get the MAC address */
+	/*
+	 * We must set the eth->enetaddr from HW because the upper layer
+	 * will force to use the environmental var (usbethaddr) or random if
+	 * there is no valid MAC address in eth->enetaddr.
+	 *
+	 * Refer to the doc/README.enetaddr and doc/README.usb for
+	 * the U-Boot MAC address policy
+	 */
+	lan7x_read_eeprom_mac(pdata->enetaddr, udev);
+	/* Do not return 0 for not finding MAC addr in HW */
+
+	ret = usb_ether_register(dev, ueth, RX_URB_SIZE);
+	if (ret)
+		return ret;
+
+	/* Register phylib */
+	return lan7x_phylib_register(dev);
+}
+
+static const struct eth_ops lan75xx_eth_ops = {
+	.start	= lan75xx_eth_start,
+	.send	= lan7x_eth_send,
+	.recv	= lan7x_eth_recv,
+	.free_pkt = lan7x_free_pkt,
+	.stop	= lan7x_eth_stop,
+	.write_hwaddr = lan75xx_write_hwaddr,
+	.read_rom_hwaddr = lan75xx_read_rom_hwaddr,
+};
+
+U_BOOT_DRIVER(lan75xx_eth) = {
+	.name	= "lan75xx_eth",
+	.id	= UCLASS_ETH,
+	.probe	= lan75xx_eth_probe,
+	.remove	= lan7x_eth_remove,
+	.ops	= &lan75xx_eth_ops,
+	.priv_auto	= sizeof(struct lan7x_private),
+	.plat_auto	= sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id lan75xx_eth_id_table[] = {
+	{ USB_DEVICE(0x0424, 0x7500) },	/* LAN7500 USB Ethernet */
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(lan75xx_eth, lan75xx_eth_id_table);
diff --git a/roms/u-boot/drivers/usb/eth/lan78xx.c b/roms/u-boot/drivers/usb/eth/lan78xx.c
new file mode 100644
index 000000000..37912a1d0
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/lan78xx.c
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Microchip Technology Inc. All rights reserved.
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <net.h>
+#include <usb.h>
+#include <linux/bitops.h>
+#include "usb_ether.h"
+#include "lan7x.h"
+
+/* LAN78xx specific register/bit defines */
+#define LAN78XX_HW_CFG_LED1_EN		BIT(21) /* Muxed with EEDO */
+#define LAN78XX_HW_CFG_LED0_EN		BIT(20) /* Muxed with EECLK */
+
+#define LAN78XX_USB_CFG0		0x080
+#define LAN78XX_USB_CFG0_BIR		BIT(6)
+
+#define LAN78XX_BURST_CAP		0x090
+
+#define LAN78XX_BULK_IN_DLY		0x094
+
+#define LAN78XX_RFE_CTL			0x0B0
+
+#define LAN78XX_FCT_RX_CTL		0x0C0
+
+#define LAN78XX_FCT_TX_CTL		0x0C4
+
+#define LAN78XX_FCT_RX_FIFO_END		0x0C8
+
+#define LAN78XX_FCT_TX_FIFO_END		0x0CC
+
+#define LAN78XX_FCT_FLOW		0x0D0
+
+#define LAN78XX_MAF_BASE		0x400
+#define LAN78XX_MAF_HIX			0x00
+#define LAN78XX_MAF_LOX			0x04
+#define LAN78XX_MAF_HI_BEGIN		(LAN78XX_MAF_BASE + LAN78XX_MAF_HIX)
+#define LAN78XX_MAF_LO_BEGIN		(LAN78XX_MAF_BASE + LAN78XX_MAF_LOX)
+#define LAN78XX_MAF_HI(index)		(LAN78XX_MAF_BASE + (8 * (index)) + \
+					LAN78XX_MAF_HIX)
+#define LAN78XX_MAF_LO(index)		(LAN78XX_MAF_BASE + (8 * (index)) + \
+					LAN78XX_MAF_LOX)
+#define LAN78XX_MAF_HI_VALID		BIT(31)
+
+/* OTP registers */
+#define LAN78XX_OTP_BASE_ADDR		0x00001000
+
+#define LAN78XX_OTP_PWR_DN		(LAN78XX_OTP_BASE_ADDR + 4 * 0x00)
+#define LAN78XX_OTP_PWR_DN_PWRDN_N	BIT(0)
+
+#define LAN78XX_OTP_ADDR1		(LAN78XX_OTP_BASE_ADDR + 4 * 0x01)
+#define LAN78XX_OTP_ADDR1_15_11		0x1F
+
+#define LAN78XX_OTP_ADDR2		(LAN78XX_OTP_BASE_ADDR + 4 * 0x02)
+#define LAN78XX_OTP_ADDR2_10_3		0xFF
+
+#define LAN78XX_OTP_RD_DATA		(LAN78XX_OTP_BASE_ADDR + 4 * 0x06)
+
+#define LAN78XX_OTP_FUNC_CMD		(LAN78XX_OTP_BASE_ADDR + 4 * 0x08)
+#define LAN78XX_OTP_FUNC_CMD_READ	BIT(0)
+
+#define LAN78XX_OTP_CMD_GO		(LAN78XX_OTP_BASE_ADDR + 4 * 0x0A)
+#define LAN78XX_OTP_CMD_GO_GO		BIT(0)
+
+#define LAN78XX_OTP_STATUS		(LAN78XX_OTP_BASE_ADDR + 4 * 0x0C)
+#define LAN78XX_OTP_STATUS_BUSY		BIT(0)
+
+#define LAN78XX_OTP_INDICATOR_1		0xF3
+#define LAN78XX_OTP_INDICATOR_2		0xF7
+
+/*
+ * Lan78xx infrastructure commands
+ */
+static int lan78xx_read_raw_otp(struct usb_device *udev, u32 offset,
+				u32 length, u8 *data)
+{
+	int i;
+	int ret;
+	u32 buf;
+
+	ret = lan7x_read_reg(udev, LAN78XX_OTP_PWR_DN, &buf);
+	if (ret)
+		return ret;
+
+	if (buf & LAN78XX_OTP_PWR_DN_PWRDN_N) {
+		/* clear it and wait to be cleared */
+		ret = lan7x_write_reg(udev, LAN78XX_OTP_PWR_DN, 0);
+		if (ret)
+			return ret;
+
+		ret = lan7x_wait_for_bit(udev, "LAN78XX_OTP_PWR_DN_PWRDN_N",
+					 LAN78XX_OTP_PWR_DN,
+					 LAN78XX_OTP_PWR_DN_PWRDN_N,
+					 false, 1000, 0);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < length; i++) {
+		ret = lan7x_write_reg(udev, LAN78XX_OTP_ADDR1,
+				      ((offset + i) >> 8) &
+				      LAN78XX_OTP_ADDR1_15_11);
+		if (ret)
+			return ret;
+		ret = lan7x_write_reg(udev, LAN78XX_OTP_ADDR2,
+				      ((offset + i) & LAN78XX_OTP_ADDR2_10_3));
+		if (ret)
+			return ret;
+
+		ret = lan7x_write_reg(udev, LAN78XX_OTP_FUNC_CMD,
+				      LAN78XX_OTP_FUNC_CMD_READ);
+		if (ret)
+			return ret;
+		ret = lan7x_write_reg(udev, LAN78XX_OTP_CMD_GO,
+				      LAN78XX_OTP_CMD_GO_GO);
+
+		if (ret)
+			return ret;
+
+		ret = lan7x_wait_for_bit(udev, "LAN78XX_OTP_STATUS_BUSY",
+					 LAN78XX_OTP_STATUS,
+					 LAN78XX_OTP_STATUS_BUSY,
+					 false, 1000, 0);
+		if (ret)
+			return ret;
+
+		ret = lan7x_read_reg(udev, LAN78XX_OTP_RD_DATA, &buf);
+		if (ret)
+			return ret;
+
+		data[i] = (u8)(buf & 0xFF);
+	}
+
+	return 0;
+}
+
+static int lan78xx_read_otp(struct usb_device *udev, u32 offset,
+			    u32 length, u8 *data)
+{
+	u8 sig;
+	int ret;
+
+	ret = lan78xx_read_raw_otp(udev, 0, 1, &sig);
+
+	if (!ret) {
+		if (sig == LAN78XX_OTP_INDICATOR_1)
+			offset = offset;
+		else if (sig == LAN78XX_OTP_INDICATOR_2)
+			offset += 0x100;
+		else
+			return -EINVAL;
+		ret = lan78xx_read_raw_otp(udev, offset, length, data);
+		if (ret)
+			return ret;
+	}
+	debug("LAN78x: MAC address from OTP = %pM\n", data);
+
+	return ret;
+}
+
+static int lan78xx_read_otp_mac(unsigned char *enetaddr,
+				struct usb_device *udev)
+{
+	int ret;
+
+	memset(enetaddr, 0, 6);
+
+	ret = lan78xx_read_otp(udev,
+			       EEPROM_MAC_OFFSET,
+			       ETH_ALEN,
+			       enetaddr);
+	if (!ret && is_valid_ethaddr(enetaddr)) {
+		/* eeprom values are valid so use them */
+		debug("MAC address read from OTP %pM\n", enetaddr);
+		return 0;
+	}
+	debug("MAC address read from OTP invalid %pM\n", enetaddr);
+
+	memset(enetaddr, 0, 6);
+	return -EINVAL;
+}
+
+static int lan78xx_update_flowcontrol(struct usb_device *udev,
+				      struct ueth_data *dev)
+{
+	uint32_t flow = 0, fct_flow = 0;
+	int ret;
+
+	ret = lan7x_update_flowcontrol(udev, dev, &flow, &fct_flow);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN78XX_FCT_FLOW, fct_flow);
+	if (ret)
+		return ret;
+	return lan7x_write_reg(udev, FLOW, flow);
+}
+
+static int lan78xx_read_mac(unsigned char *enetaddr,
+			    struct usb_device *udev,
+			    struct lan7x_private *priv)
+{
+	u32 val;
+	int ret;
+	int saved = 0, done = 0;
+
+	/*
+	 * Depends on chip, some EEPROM pins are muxed with LED function.
+	 * disable & restore LED function to access EEPROM.
+	 */
+	if ((priv->chipid == ID_REV_CHIP_ID_7800) ||
+	    (priv->chipid == ID_REV_CHIP_ID_7850)) {
+		ret = lan7x_read_reg(udev, HW_CFG, &val);
+		if (ret)
+			return ret;
+		saved = val;
+		val &= ~(LAN78XX_HW_CFG_LED1_EN | LAN78XX_HW_CFG_LED0_EN);
+		ret = lan7x_write_reg(udev, HW_CFG, val);
+		if (ret)
+			goto restore;
+	}
+
+	/*
+	 * Refer to the doc/README.enetaddr and doc/README.usb for
+	 * the U-Boot MAC address policy
+	 */
+	/* try reading mac address from EEPROM, then from OTP */
+	ret = lan7x_read_eeprom_mac(enetaddr, udev);
+	if (!ret)
+		done = 1;
+
+restore:
+	if ((priv->chipid == ID_REV_CHIP_ID_7800) ||
+	    (priv->chipid == ID_REV_CHIP_ID_7850)) {
+		ret = lan7x_write_reg(udev, HW_CFG, saved);
+		if (ret)
+			return ret;
+	}
+	/* if the EEPROM mac address is good, then exit */
+	if (done)
+		return 0;
+
+	/* try reading mac address from OTP if the device is LAN78xx */
+	return lan78xx_read_otp_mac(enetaddr, udev);
+}
+
+static int lan78xx_set_receive_filter(struct usb_device *udev)
+{
+	/* No multicast in u-boot for now */
+	return lan7x_write_reg(udev, LAN78XX_RFE_CTL,
+			       RFE_CTL_BCAST_EN | RFE_CTL_DA_PERFECT);
+}
+
+/* starts the TX path */
+static void lan78xx_start_tx_path(struct usb_device *udev)
+{
+	/* Enable Tx at MAC */
+	lan7x_write_reg(udev, MAC_TX, MAC_TX_TXEN);
+
+	/* Enable Tx at SCSRs */
+	lan7x_write_reg(udev, LAN78XX_FCT_TX_CTL, FCT_TX_CTL_EN);
+}
+
+/* Starts the Receive path */
+static void lan78xx_start_rx_path(struct usb_device *udev)
+{
+	/* Enable Rx at MAC */
+	lan7x_write_reg(udev, MAC_RX,
+			LAN7X_MAC_RX_MAX_SIZE_DEFAULT |
+			MAC_RX_FCS_STRIP | MAC_RX_RXEN);
+
+	/* Enable Rx at SCSRs */
+	lan7x_write_reg(udev, LAN78XX_FCT_RX_CTL, FCT_RX_CTL_EN);
+}
+
+static int lan78xx_basic_reset(struct usb_device *udev,
+			       struct ueth_data *dev,
+			       struct lan7x_private *priv)
+{
+	int ret;
+	u32 val;
+
+	ret = lan7x_basic_reset(udev, dev);
+	if (ret)
+		return ret;
+
+	/* Keep the chip ID */
+	ret = lan7x_read_reg(udev, ID_REV, &val);
+	if (ret)
+		return ret;
+	debug("LAN78xx ID_REV = 0x%08x\n", val);
+
+	priv->chipid = (val & ID_REV_CHIP_ID_MASK) >> 16;
+
+	/* Respond to the IN token with a NAK */
+	ret = lan7x_read_reg(udev, LAN78XX_USB_CFG0, &val);
+	if (ret)
+		return ret;
+	val &= ~LAN78XX_USB_CFG0_BIR;
+	return lan7x_write_reg(udev, LAN78XX_USB_CFG0, val);
+}
+
+int lan78xx_write_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	unsigned char *enetaddr = pdata->enetaddr;
+	u32 addr_lo = get_unaligned_le32(&enetaddr[0]);
+	u32 addr_hi = (u32)get_unaligned_le16(&enetaddr[4]);
+	int ret;
+
+	/* set hardware address */
+	ret = lan7x_write_reg(udev, RX_ADDRL, addr_lo);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, RX_ADDRH, addr_hi);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN78XX_MAF_LO(0), addr_lo);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN78XX_MAF_HI(0),
+			      addr_hi | LAN78XX_MAF_HI_VALID);
+	if (ret)
+		return ret;
+
+	debug("MAC addr %pM written\n", enetaddr);
+
+	return 0;
+}
+
+static int lan78xx_eth_start(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct lan7x_private *priv = dev_get_priv(dev);
+
+	int ret;
+	u32 write_buf;
+
+	/* Reset and read Mac addr were done in probe() */
+	ret = lan78xx_write_hwaddr(dev);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN78XX_BURST_CAP, 0);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN78XX_BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, INT_STS, 0xFFFFFFFF);
+	if (ret)
+		return ret;
+
+	/* set FIFO sizes */
+	ret = lan7x_write_reg(udev, LAN78XX_FCT_RX_FIFO_END,
+			      (MAX_RX_FIFO_SIZE - 512) / 512);
+	if (ret)
+		return ret;
+
+	ret = lan7x_write_reg(udev, LAN78XX_FCT_TX_FIFO_END,
+			      (MAX_TX_FIFO_SIZE - 512) / 512);
+	if (ret)
+		return ret;
+
+	/* Init Tx */
+	ret = lan7x_write_reg(udev, FLOW, 0);
+	if (ret)
+		return ret;
+
+	/* Init Rx. Set Vlan, keep default for VLAN on 78xx */
+	ret = lan78xx_set_receive_filter(udev);
+	if (ret)
+		return ret;
+
+	/* Init PHY, autonego, and link */
+	ret = lan7x_eth_phylib_connect(dev, &priv->ueth);
+	if (ret)
+		return ret;
+	ret = lan7x_eth_phylib_config_start(dev);
+	if (ret)
+		return ret;
+
+	/*
+	 * MAC_CR has to be set after PHY init.
+	 * MAC will auto detect the PHY speed.
+	 */
+	ret = lan7x_read_reg(udev, MAC_CR, &write_buf);
+	if (ret)
+		return ret;
+	write_buf |= MAC_CR_AUTO_DUPLEX | MAC_CR_AUTO_SPEED | MAC_CR_ADP;
+	ret = lan7x_write_reg(udev, MAC_CR, write_buf);
+	if (ret)
+		return ret;
+
+	lan78xx_start_tx_path(udev);
+	lan78xx_start_rx_path(udev);
+
+	return lan78xx_update_flowcontrol(udev, &priv->ueth);
+}
+
+int lan78xx_read_rom_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct lan7x_private *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = lan78xx_read_mac(pdata->enetaddr, udev, priv);
+	if (ret)
+		memset(pdata->enetaddr, 0, 6);
+
+	return 0;
+}
+
+static int lan78xx_eth_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct lan7x_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	int ret;
+
+	/* Do a reset in order to get the MAC address from HW */
+	if (lan78xx_basic_reset(udev, ueth, priv))
+		return 0;
+
+	/* Get the MAC address */
+	/*
+	 * We must set the eth->enetaddr from HW because the upper layer
+	 * will force to use the environmental var (usbethaddr) or random if
+	 * there is no valid MAC address in eth->enetaddr.
+	 */
+	lan78xx_read_mac(pdata->enetaddr, udev, priv);
+	/* Do not return 0 for not finding MAC addr in HW */
+
+	ret = usb_ether_register(dev, ueth, RX_URB_SIZE);
+	if (ret)
+		return ret;
+
+	/* Register phylib */
+	return lan7x_phylib_register(dev);
+}
+
+static const struct eth_ops lan78xx_eth_ops = {
+	.start	= lan78xx_eth_start,
+	.send	= lan7x_eth_send,
+	.recv	= lan7x_eth_recv,
+	.free_pkt = lan7x_free_pkt,
+	.stop	= lan7x_eth_stop,
+	.write_hwaddr = lan78xx_write_hwaddr,
+	.read_rom_hwaddr = lan78xx_read_rom_hwaddr,
+};
+
+U_BOOT_DRIVER(lan78xx_eth) = {
+	.name	= "lan78xx_eth",
+	.id	= UCLASS_ETH,
+	.probe	= lan78xx_eth_probe,
+	.remove	= lan7x_eth_remove,
+	.ops	= &lan78xx_eth_ops,
+	.priv_auto	= sizeof(struct lan7x_private),
+	.plat_auto	= sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id lan78xx_eth_id_table[] = {
+	{ USB_DEVICE(0x0424, 0x7800) },	/* LAN7800 USB Ethernet */
+	{ USB_DEVICE(0x0424, 0x7850) },	/* LAN7850 USB Ethernet */
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(lan78xx_eth, lan78xx_eth_id_table);
diff --git a/roms/u-boot/drivers/usb/eth/lan7x.c b/roms/u-boot/drivers/usb/eth/lan7x.c
new file mode 100644
index 000000000..0a283619a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/lan7x.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Microchip Technology Inc. All rights reserved.
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <memalign.h>
+#include <net.h>
+#include <usb.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+#include "lan7x.h"
+
+/*
+ * Lan7x infrastructure commands
+ */
+int lan7x_write_reg(struct usb_device *udev, u32 index, u32 data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
+
+	cpu_to_le32s(&data);
+	tmpbuf[0] = data;
+
+	len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      USB_VENDOR_REQUEST_WRITE_REGISTER,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, index, tmpbuf, sizeof(data),
+			      USB_CTRL_SET_TIMEOUT_MS);
+	if (len != sizeof(data)) {
+		debug("%s failed: index=%d, data=%d, len=%d",
+		      __func__, index, data, len);
+		return -EIO;
+	}
+	return 0;
+}
+
+int lan7x_read_reg(struct usb_device *udev, u32 index, u32 *data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
+
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      USB_VENDOR_REQUEST_READ_REGISTER,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, index, tmpbuf, sizeof(*data),
+			      USB_CTRL_GET_TIMEOUT_MS);
+	*data = tmpbuf[0];
+	if (len != sizeof(*data)) {
+		debug("%s failed: index=%d, len=%d", __func__, index, len);
+		return -EIO;
+	}
+
+	le32_to_cpus(data);
+	return 0;
+}
+
+static int lan7x_phy_wait_not_busy(struct usb_device *udev)
+{
+	return lan7x_wait_for_bit(udev, __func__,
+				  MII_ACC, MII_ACC_MII_BUSY,
+				  false, 100, 0);
+}
+
+int lan7x_mdio_read(struct usb_device *udev, int phy_id, int idx)
+{
+	u32 val, addr;
+
+	/* confirm MII not busy */
+	if (lan7x_phy_wait_not_busy(udev)) {
+		debug("MII is busy in %s\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	/* set the address, index & direction (read from PHY) */
+	addr = (phy_id << 11) | (idx << 6) |
+		MII_ACC_MII_READ | MII_ACC_MII_BUSY;
+	lan7x_write_reg(udev, MII_ACC, addr);
+
+	if (lan7x_phy_wait_not_busy(udev)) {
+		debug("Timed out reading MII reg %02X\n", idx);
+		return -ETIMEDOUT;
+	}
+
+	lan7x_read_reg(udev, MII_DATA, &val);
+
+	return val & 0xFFFF;
+}
+
+void lan7x_mdio_write(struct usb_device *udev, int phy_id, int idx, int regval)
+{
+	u32 addr;
+
+	/* confirm MII not busy */
+	if (lan7x_phy_wait_not_busy(udev)) {
+		debug("MII is busy in %s\n", __func__);
+		return;
+	}
+
+	lan7x_write_reg(udev, MII_DATA, regval);
+
+	/* set the address, index & direction (write to PHY) */
+	addr = (phy_id << 11) | (idx << 6) |
+		MII_ACC_MII_WRITE | MII_ACC_MII_BUSY;
+	lan7x_write_reg(udev, MII_ACC, addr);
+
+	if (lan7x_phy_wait_not_busy(udev))
+		debug("Timed out writing MII reg %02X\n", idx);
+}
+
+/*
+ * Lan7x phylib wrappers
+ */
+static int lan7x_phylib_mdio_read(struct mii_dev *bus,
+				  int addr, int devad, int reg)
+{
+	struct usb_device *udev = dev_get_parent_priv(bus->priv);
+
+	return lan7x_mdio_read(udev, addr, reg);
+}
+
+static int lan7x_phylib_mdio_write(struct mii_dev *bus,
+				   int addr, int devad, int reg, u16 val)
+{
+	struct usb_device *udev = dev_get_parent_priv(bus->priv);
+
+	lan7x_mdio_write(udev, addr, reg, (int)val);
+
+	return 0;
+}
+
+/*
+ * Lan7x eeprom functions
+ */
+static int lan7x_eeprom_confirm_not_busy(struct usb_device *udev)
+{
+	return lan7x_wait_for_bit(udev, __func__,
+				  E2P_CMD, E2P_CMD_EPC_BUSY,
+				  false, 100, 0);
+}
+
+static int lan7x_wait_eeprom(struct usb_device *udev)
+{
+	return lan7x_wait_for_bit(udev, __func__,
+				  E2P_CMD,
+				  (E2P_CMD_EPC_BUSY | E2P_CMD_EPC_TIMEOUT),
+				  false, 100, 0);
+}
+
+static int lan7x_read_eeprom(struct usb_device *udev,
+			     u32 offset, u32 length, u8 *data)
+{
+	u32 val;
+	int i, ret;
+
+	ret = lan7x_eeprom_confirm_not_busy(udev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < length; i++) {
+		val = E2P_CMD_EPC_BUSY | E2P_CMD_EPC_CMD_READ |
+			(offset & E2P_CMD_EPC_ADDR_MASK);
+		lan7x_write_reg(udev, E2P_CMD, val);
+
+		ret = lan7x_wait_eeprom(udev);
+		if (ret)
+			return ret;
+
+		lan7x_read_reg(udev, E2P_DATA, &val);
+		data[i] = val & 0xFF;
+		offset++;
+	}
+	return ret;
+}
+
+/*
+ * Lan7x phylib functions
+ */
+int lan7x_phylib_register(struct udevice *udev)
+{
+	struct usb_device *usbdev = dev_get_parent_priv(udev);
+	struct lan7x_private *priv = dev_get_priv(udev);
+	int ret;
+
+	priv->mdiobus = mdio_alloc();
+	if (!priv->mdiobus) {
+		printf("mdio_alloc failed\n");
+		return -ENOMEM;
+	}
+	priv->mdiobus->read = lan7x_phylib_mdio_read;
+	priv->mdiobus->write = lan7x_phylib_mdio_write;
+	sprintf(priv->mdiobus->name,
+		"lan7x_mdiobus-d%hu-p%hu", usbdev->devnum, usbdev->portnr);
+	priv->mdiobus->priv = (void *)udev;
+
+	ret = mdio_register(priv->mdiobus);
+	if (ret) {
+		printf("mdio_register failed\n");
+		free(priv->mdiobus);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int lan7x_eth_phylib_connect(struct udevice *udev, struct ueth_data *dev)
+{
+	struct lan7x_private *priv = dev_get_priv(udev);
+
+	priv->phydev = phy_connect(priv->mdiobus, dev->phy_id,
+			     udev, PHY_INTERFACE_MODE_MII);
+
+	if (!priv->phydev) {
+		printf("phy_connect failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+int lan7x_eth_phylib_config_start(struct udevice *udev)
+{
+	struct lan7x_private *priv = dev_get_priv(udev);
+	int ret;
+
+	/* configure supported modes */
+	priv->phydev->supported = PHY_BASIC_FEATURES |
+				  SUPPORTED_1000baseT_Full |
+				  SUPPORTED_Pause |
+				  SUPPORTED_Asym_Pause;
+
+	priv->phydev->advertising = ADVERTISED_10baseT_Half |
+				    ADVERTISED_10baseT_Full |
+				    ADVERTISED_100baseT_Half |
+				    ADVERTISED_100baseT_Full |
+				    ADVERTISED_1000baseT_Full |
+				    ADVERTISED_Pause |
+				    ADVERTISED_Asym_Pause |
+				    ADVERTISED_Autoneg;
+
+	priv->phydev->autoneg = AUTONEG_ENABLE;
+
+	ret = genphy_config_aneg(priv->phydev);
+	if (ret) {
+		printf("genphy_config_aneg failed\n");
+		return ret;
+	}
+	ret = phy_startup(priv->phydev);
+	if (ret) {
+		printf("phy_startup failed\n");
+		return ret;
+	}
+
+	debug("** %s() speed %i duplex %i adv %X supp %X\n", __func__,
+	      priv->phydev->speed, priv->phydev->duplex,
+	      priv->phydev->advertising, priv->phydev->supported);
+
+	return 0;
+}
+
+int lan7x_update_flowcontrol(struct usb_device *udev,
+			     struct ueth_data *dev,
+			     uint32_t *flow, uint32_t *fct_flow)
+{
+	uint32_t lcladv, rmtadv;
+	u8 cap = 0;
+	struct lan7x_private *priv = dev_get_priv(udev->dev);
+
+	debug("** %s()\n", __func__);
+	debug("** %s() priv->phydev->speed %i duplex %i\n", __func__,
+	      priv->phydev->speed, priv->phydev->duplex);
+
+	if (priv->phydev->duplex == DUPLEX_FULL) {
+		lcladv = lan7x_mdio_read(udev, dev->phy_id, MII_ADVERTISE);
+		rmtadv = lan7x_mdio_read(udev, dev->phy_id, MII_LPA);
+		cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+		debug("TX Flow ");
+		if (cap & FLOW_CTRL_TX) {
+			*flow = (FLOW_CR_TX_FCEN | 0xFFFF);
+			/* set fct_flow thresholds to 20% and 80% */
+			*fct_flow = ((MAX_RX_FIFO_SIZE * 2) / (10 * 512))
+					& 0x7FUL;
+			*fct_flow <<= 8UL;
+			*fct_flow |= ((MAX_RX_FIFO_SIZE * 8) / (10 * 512))
+					& 0x7FUL;
+			debug("EN ");
+		} else {
+			debug("DIS ");
+		}
+		debug("RX Flow ");
+		if (cap & FLOW_CTRL_RX) {
+			*flow |= FLOW_CR_RX_FCEN;
+			debug("EN");
+		} else {
+			debug("DIS");
+		}
+	}
+	debug("\n");
+	return 0;
+}
+
+int lan7x_read_eeprom_mac(unsigned char *enetaddr, struct usb_device *udev)
+{
+	int ret;
+
+	memset(enetaddr, 0, 6);
+
+	ret = lan7x_read_eeprom(udev, 0, 1, enetaddr);
+
+	if ((ret == 0) && (enetaddr[0] == EEPROM_INDICATOR)) {
+		ret = lan7x_read_eeprom(udev,
+					EEPROM_MAC_OFFSET, ETH_ALEN,
+					enetaddr);
+		if ((ret == 0) && is_valid_ethaddr(enetaddr)) {
+			/* eeprom values are valid so use them */
+			debug("MAC address read from EEPROM %pM\n",
+			      enetaddr);
+			return 0;
+		}
+	}
+	debug("MAC address read from EEPROM invalid %pM\n", enetaddr);
+
+	memset(enetaddr, 0, 6);
+	return -EINVAL;
+}
+
+int lan7x_pmt_phy_reset(struct usb_device *udev,
+			struct ueth_data *dev)
+{
+	int ret;
+	u32 data;
+
+	ret = lan7x_read_reg(udev, PMT_CTL, &data);
+	if (ret)
+		return ret;
+	ret = lan7x_write_reg(udev, PMT_CTL, data | PMT_CTL_PHY_RST);
+	if (ret)
+		return ret;
+
+	/* for LAN7x, we need to check PMT_CTL_READY asserted */
+	ret = lan7x_wait_for_bit(udev, "PMT_CTL_PHY_RST",
+				 PMT_CTL, PMT_CTL_PHY_RST,
+				 false, 1000, 0); /* could take over 125mS */
+	if (ret)
+		return ret;
+
+	return lan7x_wait_for_bit(udev, "PMT_CTL_READY",
+				 PMT_CTL, PMT_CTL_READY,
+				 true, 1000, 0);
+}
+
+int lan7x_basic_reset(struct usb_device *udev,
+		      struct ueth_data *dev)
+{
+	int ret;
+
+	dev->phy_id = LAN7X_INTERNAL_PHY_ID; /* fixed phy id */
+
+	ret = lan7x_write_reg(udev, HW_CFG, HW_CFG_LRST);
+	if (ret)
+		return ret;
+
+	ret = lan7x_wait_for_bit(udev, "HW_CFG_LRST",
+				 HW_CFG, HW_CFG_LRST,
+				 false, 1000, 0);
+	if (ret)
+		return ret;
+
+	debug("USB devnum %d portnr %d\n", udev->devnum, udev->portnr);
+
+	return lan7x_pmt_phy_reset(udev, dev);
+}
+
+void lan7x_eth_stop(struct udevice *dev)
+{
+	debug("** %s()\n", __func__);
+}
+
+int lan7x_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct lan7x_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	int err;
+	int actual_len;
+	u32 tx_cmd_a;
+	u32 tx_cmd_b;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+				 PKTSIZE + sizeof(tx_cmd_a) + sizeof(tx_cmd_b));
+
+	debug("** %s(), len %d, buf %#x\n", __func__, length,
+	      (unsigned int)(ulong) msg);
+	if (length > PKTSIZE)
+		return -ENOSPC;
+
+	/* LAN7x disable all TX offload features for u-boot */
+	tx_cmd_a = (u32) (length & TX_CMD_A_LEN_MASK) | TX_CMD_A_FCS;
+	tx_cmd_b = 0;
+	cpu_to_le32s(&tx_cmd_a);
+	cpu_to_le32s(&tx_cmd_b);
+
+	/* prepend cmd_a and cmd_b */
+	memcpy(msg, &tx_cmd_a, sizeof(tx_cmd_a));
+	memcpy(msg + sizeof(tx_cmd_a), &tx_cmd_b, sizeof(tx_cmd_b));
+	memcpy(msg + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), (void *)packet,
+	       length);
+	err = usb_bulk_msg(ueth->pusb_dev,
+			   usb_sndbulkpipe(ueth->pusb_dev, ueth->ep_out),
+			   (void *)msg,
+			   length + sizeof(tx_cmd_a) +
+			   sizeof(tx_cmd_b),
+			   &actual_len, USB_BULK_SEND_TIMEOUT_MS);
+	debug("Tx: len = %u, actual = %u, err = %d\n",
+	      (unsigned int)(length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b)),
+	      (unsigned int)actual_len, err);
+
+	return err;
+}
+
+int lan7x_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct lan7x_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	uint8_t *ptr;
+	int ret, len;
+	u32 packet_len = 0;
+	u32 rx_cmd_a = 0;
+
+	len = usb_ether_get_rx_bytes(ueth, &ptr);
+	debug("%s: first try, len=%d\n", __func__, len);
+	if (!len) {
+		if (!(flags & ETH_RECV_CHECK_DEVICE))
+			return -EAGAIN;
+		ret = usb_ether_receive(ueth, RX_URB_SIZE);
+		if (ret == -EAGAIN)
+			return ret;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: second try, len=%d\n", __func__, len);
+	}
+
+	/*
+	 * 1st 4 bytes contain the length of the actual data plus error info.
+	 * Extract data length.
+	 */
+	if (len < sizeof(packet_len)) {
+		debug("Rx: incomplete packet length\n");
+		goto err;
+	}
+	memcpy(&rx_cmd_a, ptr, sizeof(rx_cmd_a));
+	le32_to_cpus(&rx_cmd_a);
+	if (rx_cmd_a & RX_CMD_A_RXE) {
+		debug("Rx: Error header=%#x", rx_cmd_a);
+		goto err;
+	}
+	packet_len = (u16) (rx_cmd_a & RX_CMD_A_LEN_MASK);
+
+	if (packet_len > len - sizeof(packet_len)) {
+		debug("Rx: too large packet: %d\n", packet_len);
+		goto err;
+	}
+
+	/*
+	 * For LAN7x, the length in command A does not
+	 * include command A, B, and C length.
+	 * So use it as is.
+	 */
+
+	*packetp = ptr + 10;
+	return packet_len;
+
+err:
+	usb_ether_advance_rxbuf(ueth, -1);
+	return -EINVAL;
+}
+
+int lan7x_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct lan7x_private *priv = dev_get_priv(dev);
+
+	packet_len = ALIGN(packet_len, 4);
+	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+	return 0;
+}
+
+int lan7x_eth_remove(struct udevice *dev)
+{
+	struct lan7x_private *priv = dev_get_priv(dev);
+
+	debug("** %s()\n", __func__);
+	free(priv->phydev);
+	mdio_unregister(priv->mdiobus);
+	mdio_free(priv->mdiobus);
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/eth/lan7x.h b/roms/u-boot/drivers/usb/eth/lan7x.h
new file mode 100644
index 000000000..f71e8c726
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/lan7x.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2017 Microchip Technology Inc. All rights reserved.
+ */
+
+#include <console.h>
+#include <time.h>
+#include <watchdog.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER	0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER	0xA1
+#define USB_VENDOR_REQUEST_GET_STATS		0xA2
+
+/* Tx Command A */
+#define TX_CMD_A_FCS			BIT(22)
+#define TX_CMD_A_LEN_MASK		0x000FFFFF
+
+/* Rx Command A */
+#define RX_CMD_A_RXE			BIT(18)
+#define RX_CMD_A_LEN_MASK		0x00003FFF
+
+/* SCSRs */
+#define ID_REV				0x00
+#define ID_REV_CHIP_ID_MASK		0xFFFF0000
+#define ID_REV_CHIP_ID_7500		0x7500
+#define ID_REV_CHIP_ID_7800		0x7800
+#define ID_REV_CHIP_ID_7850		0x7850
+
+#define INT_STS				0x0C
+
+#define HW_CFG				0x010
+#define HW_CFG_LRST			BIT(1)
+
+#define PMT_CTL				0x014
+#define PMT_CTL_PHY_PWRUP		BIT(10)
+#define PMT_CTL_READY			BIT(7)
+#define PMT_CTL_PHY_RST			BIT(4)
+
+#define E2P_CMD				0x040
+#define E2P_CMD_EPC_BUSY		BIT(31)
+#define E2P_CMD_EPC_CMD_READ		0x00000000
+#define E2P_CMD_EPC_TIMEOUT		BIT(10)
+#define E2P_CMD_EPC_ADDR_MASK		0x000001FF
+
+#define E2P_DATA			0x044
+
+#define RFE_CTL_BCAST_EN		BIT(10)
+#define RFE_CTL_DA_PERFECT		BIT(1)
+
+#define FCT_RX_CTL_EN			BIT(31)
+
+#define FCT_TX_CTL_EN			BIT(31)
+
+#define MAC_CR				0x100
+#define MAC_CR_ADP			BIT(13)
+#define MAC_CR_AUTO_DUPLEX		BIT(12)
+#define MAC_CR_AUTO_SPEED		BIT(11)
+
+#define MAC_RX				0x104
+#define MAC_RX_FCS_STRIP		BIT(4)
+#define MAC_RX_RXEN			BIT(0)
+
+#define MAC_TX				0x108
+#define MAC_TX_TXEN			BIT(0)
+
+#define FLOW				0x10C
+#define FLOW_CR_TX_FCEN			BIT(30)
+#define FLOW_CR_RX_FCEN			BIT(29)
+
+#define RX_ADDRH			0x118
+#define RX_ADDRL			0x11C
+
+#define MII_ACC				0x120
+#define MII_ACC_MII_READ		0x00000000
+#define MII_ACC_MII_WRITE		0x00000002
+#define MII_ACC_MII_BUSY		BIT(0)
+
+#define MII_DATA			0x124
+
+#define SS_USB_PKT_SIZE			1024
+#define HS_USB_PKT_SIZE			512
+#define FS_USB_PKT_SIZE			64
+
+#define MAX_RX_FIFO_SIZE		(12 * 1024)
+#define MAX_TX_FIFO_SIZE		(12 * 1024)
+#define DEFAULT_BULK_IN_DELAY		0x0800
+
+#define EEPROM_INDICATOR		0xA5
+#define EEPROM_MAC_OFFSET		0x01
+
+/* Some extra defines */
+#define LAN7X_INTERNAL_PHY_ID		1
+
+#define LAN7X_MAC_RX_MAX_SIZE(mtu) \
+	((mtu) << 16)			/* Max frame size */
+#define LAN7X_MAC_RX_MAX_SIZE_DEFAULT \
+	LAN7X_MAC_RX_MAX_SIZE(PKTSIZE_ALIGN + 4 /* VLAN */ + 4 /* CRC */)
+
+/* Timeouts */
+#define USB_CTRL_SET_TIMEOUT_MS		5000
+#define USB_CTRL_GET_TIMEOUT_MS		5000
+#define USB_BULK_SEND_TIMEOUT_MS	5000
+#define USB_BULK_RECV_TIMEOUT_MS	5000
+#define TIMEOUT_RESOLUTION_MS		50
+#define PHY_CONNECT_TIMEOUT_MS		5000
+
+#define RX_URB_SIZE	2048
+
+/* driver private */
+struct lan7x_private {
+	struct ueth_data ueth;
+	u32 chipid;		/* Chip or device ID */
+	struct mii_dev *mdiobus;
+	struct phy_device *phydev;
+};
+
+/*
+ * Lan7x infrastructure commands
+ */
+
+int lan7x_write_reg(struct usb_device *udev, u32 index, u32 data);
+
+int lan7x_read_reg(struct usb_device *udev, u32 index, u32 *data);
+
+/*
+ * FIXME: Code should not be in header files. Nive this to a file common to
+ * the two drivers.
+ */
+static inline int lan7x_wait_for_bit(struct usb_device *udev,
+				     const char *prefix, const u32 reg,
+				     const u32 mask, const bool set,
+				     const unsigned int timeout_ms,
+				     const bool breakable)
+{
+	u32 val;
+	unsigned long start = get_timer(0);
+
+	while (1) {
+		lan7x_read_reg(udev, reg, &val);
+
+		if (!set)
+			val = ~val;
+
+		if ((val & mask) == mask)
+			return 0;
+
+		if (get_timer(start) > timeout_ms)
+			break;
+
+		if (breakable && ctrlc()) {
+			puts("Abort\n");
+			return -EINTR;
+		}
+
+		udelay(1);
+		WATCHDOG_RESET();
+	}
+
+	debug("%s: Timeout (reg=0x%x mask=%08x wait_set=%i)\n", prefix, reg,
+	      mask, set);
+
+	return -ETIMEDOUT;
+}
+
+int lan7x_mdio_read(struct usb_device *udev, int phy_id, int idx);
+
+void lan7x_mdio_write(struct usb_device *udev, int phy_id, int idx,
+		      int regval);
+
+static inline int lan7x_mdio_wait_for_bit(struct usb_device *udev,
+					  const char *prefix,
+					  int phy_id, const u32 reg,
+					  const u32 mask, const bool set,
+					  const unsigned int timeout_ms,
+					  const bool breakable)
+{
+	u32 val;
+	unsigned long start = get_timer(0);
+
+	while (1) {
+		val = lan7x_mdio_read(udev, phy_id, reg);
+
+		if (!set)
+			val = ~val;
+
+		if ((val & mask) == mask)
+			return 0;
+
+		if (get_timer(start) > timeout_ms)
+			break;
+
+		if (breakable && ctrlc()) {
+			puts("Abort\n");
+			return -EINTR;
+		}
+
+		udelay(1);
+		WATCHDOG_RESET();
+	}
+
+	debug("%s: Timeout (reg=0x%x mask=%08x wait_set=%i)\n", prefix, reg,
+	      mask, set);
+
+	return -ETIMEDOUT;
+}
+
+int lan7x_phylib_register(struct udevice *udev);
+
+int lan7x_eth_phylib_connect(struct udevice *udev, struct ueth_data *dev);
+
+int lan7x_eth_phylib_config_start(struct udevice *udev);
+
+int lan7x_pmt_phy_reset(struct usb_device *udev,
+			struct ueth_data *dev);
+
+int lan7x_update_flowcontrol(struct usb_device *udev,
+			     struct ueth_data *dev,
+			     uint32_t *flow, uint32_t *fct_flow);
+
+int lan7x_read_eeprom_mac(unsigned char *enetaddr, struct usb_device *udev);
+
+int lan7x_basic_reset(struct usb_device *udev,
+		      struct ueth_data *dev);
+
+void lan7x_eth_stop(struct udevice *dev);
+
+int lan7x_eth_send(struct udevice *dev, void *packet, int length);
+
+int lan7x_eth_recv(struct udevice *dev, int flags, uchar **packetp);
+
+int lan7x_free_pkt(struct udevice *dev, uchar *packet, int packet_len);
+
+int lan7x_eth_remove(struct udevice *dev);
diff --git a/roms/u-boot/drivers/usb/eth/mcs7830.c b/roms/u-boot/drivers/usb/eth/mcs7830.c
new file mode 100644
index 000000000..783ab62f6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/mcs7830.c
@@ -0,0 +1,945 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Gerhard Sittig <gsi@denx.de>
+ * based on the U-Boot Asix driver as well as information
+ * from the Linux Moschip driver
+ */
+
+/*
+ * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <net.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <usb.h>
+
+#include "usb_ether.h"
+
+#define MCS7830_BASE_NAME	"mcs"
+
+#define USBCALL_TIMEOUT		1000
+#define LINKSTATUS_TIMEOUT	5000	/* link status, connect timeout */
+#define LINKSTATUS_TIMEOUT_RES	50	/* link status, resolution in msec */
+
+#define MCS7830_RX_URB_SIZE	2048
+
+/* command opcodes */
+#define MCS7830_WR_BREQ		0x0d
+#define MCS7830_RD_BREQ		0x0e
+
+/* register layout, numerical offset specs for USB API calls */
+struct mcs7830_regs {
+	uint8_t multicast_hashes[8];
+	uint8_t packet_gap[2];
+	uint8_t phy_data[2];
+	uint8_t phy_command[2];
+	uint8_t configuration;
+	uint8_t ether_address[6];
+	uint8_t frame_drop_count;
+	uint8_t pause_threshold;
+};
+#define REG_MULTICAST_HASH	offsetof(struct mcs7830_regs, multicast_hashes)
+#define REG_PHY_DATA		offsetof(struct mcs7830_regs, phy_data)
+#define REG_PHY_CMD		offsetof(struct mcs7830_regs, phy_command)
+#define REG_CONFIG		offsetof(struct mcs7830_regs, configuration)
+#define REG_ETHER_ADDR		offsetof(struct mcs7830_regs, ether_address)
+#define REG_FRAME_DROP_COUNTER	offsetof(struct mcs7830_regs, frame_drop_count)
+#define REG_PAUSE_THRESHOLD	offsetof(struct mcs7830_regs, pause_threshold)
+
+/* bit masks and default values for the above registers */
+#define PHY_CMD1_READ		0x40
+#define PHY_CMD1_WRITE		0x20
+#define PHY_CMD1_PHYADDR	0x01
+
+#define PHY_CMD2_PEND		0x80
+#define PHY_CMD2_READY		0x40
+
+#define CONF_CFG		0x80
+#define CONF_SPEED100		0x40
+#define CONF_FDX_ENABLE		0x20
+#define CONF_RXENABLE		0x10
+#define CONF_TXENABLE		0x08
+#define CONF_SLEEPMODE		0x04
+#define CONF_ALLMULTICAST	0x02
+#define CONF_PROMISCUOUS	0x01
+
+#define PAUSE_THRESHOLD_DEFAULT	0
+
+/* bit masks for the status byte which follows received ethernet frames */
+#define STAT_RX_FRAME_CORRECT	0x20
+#define STAT_RX_LARGE_FRAME	0x10
+#define STAT_RX_CRC_ERROR	0x08
+#define STAT_RX_ALIGNMENT_ERROR	0x04
+#define STAT_RX_LENGTH_ERROR	0x02
+#define STAT_RX_SHORT_FRAME	0x01
+
+/*
+ * struct mcs7830_private - private driver data for an individual adapter
+ * @config:	shadow for the network adapter's configuration register
+ * @mchash:	shadow for the network adapter's multicast hash registers
+ */
+struct mcs7830_private {
+#ifdef CONFIG_DM_ETH
+	uint8_t rx_buf[MCS7830_RX_URB_SIZE];
+	struct ueth_data ueth;
+#endif
+	uint8_t config;
+	uint8_t mchash[8];
+};
+
+/*
+ * mcs7830_read_reg() - read a register of the network adapter
+ * @udev:	network device to read from
+ * @idx:	index of the register to start reading from
+ * @size:	number of bytes to read
+ * @data:	buffer to read into
+ * Return: zero upon success, negative upon error
+ */
+static int mcs7830_read_reg(struct usb_device *udev, uint8_t idx,
+			    uint16_t size, void *data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, size);
+
+	debug("%s() idx=0x%04X sz=%d\n", __func__, idx, size);
+
+	len = usb_control_msg(udev,
+			      usb_rcvctrlpipe(udev, 0),
+			      MCS7830_RD_BREQ,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, idx, buf, size,
+			      USBCALL_TIMEOUT);
+	if (len != size) {
+		debug("%s() len=%d != sz=%d\n", __func__, len, size);
+		return -EIO;
+	}
+	memcpy(data, buf, size);
+	return 0;
+}
+
+/*
+ * mcs7830_write_reg() - write a register of the network adapter
+ * @udev:	network device to write to
+ * @idx:	index of the register to start writing to
+ * @size:	number of bytes to write
+ * @data:	buffer holding the data to write
+ * Return: zero upon success, negative upon error
+ */
+static int mcs7830_write_reg(struct usb_device *udev, uint8_t idx,
+			     uint16_t size, void *data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, size);
+
+	debug("%s() idx=0x%04X sz=%d\n", __func__, idx, size);
+
+	memcpy(buf, data, size);
+	len = usb_control_msg(udev,
+			      usb_sndctrlpipe(udev, 0),
+			      MCS7830_WR_BREQ,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, idx, buf, size,
+			      USBCALL_TIMEOUT);
+	if (len != size) {
+		debug("%s() len=%d != sz=%d\n", __func__, len, size);
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * mcs7830_phy_emit_wait() - emit PHY read/write access, wait for its execution
+ * @udev:	network device to talk to
+ * @rwflag:	PHY_CMD1_READ or PHY_CMD1_WRITE opcode
+ * @index:	number of the PHY register to read or write
+ * Return: zero upon success, negative upon error
+ */
+static int mcs7830_phy_emit_wait(struct usb_device *udev,
+				 uint8_t rwflag, uint8_t index)
+{
+	int rc;
+	int retry;
+	uint8_t cmd[2];
+
+	/* send the PHY read/write request */
+	cmd[0] = rwflag | PHY_CMD1_PHYADDR;
+	cmd[1] = PHY_CMD2_PEND | (index & 0x1f);
+	rc = mcs7830_write_reg(udev, REG_PHY_CMD, sizeof(cmd), cmd);
+	if (rc < 0)
+		return rc;
+
+	/* wait for the response to become available (usually < 1ms) */
+	retry = 10;
+	do {
+		rc = mcs7830_read_reg(udev, REG_PHY_CMD, sizeof(cmd), cmd);
+		if (rc < 0)
+			return rc;
+		if (cmd[1] & PHY_CMD2_READY)
+			return 0;
+		if (!retry--)
+			return -ETIMEDOUT;
+		mdelay(1);
+	} while (1);
+	/* UNREACH */
+}
+
+/*
+ * mcs7830_read_phy() - read a PHY register of the network adapter
+ * @udev:	network device to read from
+ * @index:	index of the PHY register to read from
+ * Return: non-negative 16bit register content, negative upon error
+ */
+static int mcs7830_read_phy(struct usb_device *udev, uint8_t index)
+{
+	int rc;
+	uint16_t val;
+
+	/* issue the PHY read request and wait for its execution */
+	rc = mcs7830_phy_emit_wait(udev, PHY_CMD1_READ, index);
+	if (rc < 0)
+		return rc;
+
+	/* fetch the PHY data which was read */
+	rc = mcs7830_read_reg(udev, REG_PHY_DATA, sizeof(val), &val);
+	if (rc < 0)
+		return rc;
+	rc = le16_to_cpu(val);
+	debug("%s(%d) => 0x%04X\n", __func__, index, rc);
+	return rc;
+}
+
+/*
+ * mcs7830_write_phy() - write a PHY register of the network adapter
+ * @udev:	network device to write to
+ * @index:	index of the PHY register to write to
+ * @val:	value to write to the PHY register
+ * Return: zero upon success, negative upon error
+ */
+static int mcs7830_write_phy(struct usb_device *udev, uint8_t index,
+			     uint16_t val)
+{
+	int rc;
+
+	debug("%s(%d, 0x%04X)\n", __func__, index, val);
+
+	/* setup the PHY data which is to get written */
+	val = cpu_to_le16(val);
+	rc = mcs7830_write_reg(udev, REG_PHY_DATA, sizeof(val), &val);
+	if (rc < 0)
+		return rc;
+
+	/* issue the PHY write request and wait for its execution */
+	rc = mcs7830_phy_emit_wait(udev, PHY_CMD1_WRITE, index);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+/*
+ * mcs7830_write_config() - write to the network adapter's config register
+ * @udev:	network device to write to
+ * @priv:	private data
+ * Return: zero upon success, negative upon error
+ *
+ * the data which gets written is taken from the shadow config register
+ * within the device driver's private data
+ */
+static int mcs7830_write_config(struct usb_device *udev,
+				struct mcs7830_private *priv)
+{
+	int rc;
+
+	debug("%s()\n", __func__);
+
+	rc = mcs7830_write_reg(udev, REG_CONFIG,
+			       sizeof(priv->config), &priv->config);
+	if (rc < 0) {
+		debug("writing config to adapter failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+/*
+ * mcs7830_write_mchash() - write the network adapter's multicast filter
+ * @udev:	network device to write to
+ * @priv:	private data
+ * Return: zero upon success, negative upon error
+ *
+ * the data which gets written is taken from the shadow multicast hashes
+ * within the device driver's private data
+ */
+static int mcs7830_write_mchash(struct usb_device *udev,
+				struct mcs7830_private *priv)
+{
+	int rc;
+
+	debug("%s()\n", __func__);
+
+	rc = mcs7830_write_reg(udev, REG_MULTICAST_HASH,
+			       sizeof(priv->mchash), &priv->mchash);
+	if (rc < 0) {
+		debug("writing multicast hash to adapter failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+/*
+ * mcs7830_set_autoneg() - setup and trigger ethernet link autonegotiation
+ * @udev:	network device to run link negotiation on
+ * Return: zero upon success, negative upon error
+ *
+ * the routine advertises available media and starts autonegotiation
+ */
+static int mcs7830_set_autoneg(struct usb_device *udev)
+{
+	int adv, flg;
+	int rc;
+
+	debug("%s()\n", __func__);
+
+	/*
+	 * algorithm taken from the Linux driver, which took it from
+	 * "the original mcs7830 version 1.4 driver":
+	 *
+	 * enable all media, reset BMCR, enable auto neg, restart
+	 * auto neg while keeping the enable auto neg flag set
+	 */
+
+	adv = ADVERTISE_PAUSE_CAP | ADVERTISE_ALL | ADVERTISE_CSMA;
+	rc = mcs7830_write_phy(udev, MII_ADVERTISE, adv);
+
+	flg = 0;
+	if (!rc)
+		rc = mcs7830_write_phy(udev, MII_BMCR, flg);
+
+	flg |= BMCR_ANENABLE;
+	if (!rc)
+		rc = mcs7830_write_phy(udev, MII_BMCR, flg);
+
+	flg |= BMCR_ANRESTART;
+	if (!rc)
+		rc = mcs7830_write_phy(udev, MII_BMCR, flg);
+
+	return rc;
+}
+
+/*
+ * mcs7830_get_rev() - identify a network adapter's chip revision
+ * @udev:	network device to identify
+ * Return: non-negative number, reflecting the revision number
+ *
+ * currently, only "rev C and higher" and "below rev C" are needed, so
+ * the return value is #1 for "below rev C", and #2 for "rev C and above"
+ */
+static int mcs7830_get_rev(struct usb_device *udev)
+{
+	uint8_t buf[2];
+	int rc;
+	int rev;
+
+	/* register 22 is readable in rev C and higher */
+	rc = mcs7830_read_reg(udev, REG_FRAME_DROP_COUNTER, sizeof(buf), buf);
+	if (rc < 0)
+		rev = 1;
+	else
+		rev = 2;
+	debug("%s() rc=%d, rev=%d\n", __func__, rc, rev);
+	return rev;
+}
+
+/*
+ * mcs7830_apply_fixup() - identify an adapter and potentially apply fixups
+ * @udev:	network device to identify and apply fixups to
+ * Return: zero upon success (no errors emitted from here)
+ *
+ * this routine identifies the network adapter's chip revision, and applies
+ * fixups for known issues
+ */
+static int mcs7830_apply_fixup(struct usb_device *udev)
+{
+	int rev;
+	int i;
+	uint8_t thr;
+
+	rev = mcs7830_get_rev(udev);
+	debug("%s() rev=%d\n", __func__, rev);
+
+	/*
+	 * rev C requires setting the pause threshold (the Linux driver
+	 * is inconsistent, the implementation does it for "rev C
+	 * exactly", the introductory comment says "rev C and above")
+	 */
+	if (rev == 2) {
+		debug("%s: applying rev C fixup\n", __func__);
+		thr = PAUSE_THRESHOLD_DEFAULT;
+		for (i = 0; i < 2; i++) {
+			(void)mcs7830_write_reg(udev, REG_PAUSE_THRESHOLD,
+						sizeof(thr), &thr);
+			mdelay(1);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * mcs7830_basic_reset() - bring the network adapter into a known first state
+ * @eth:	network device to act upon
+ * Return: zero upon success, negative upon error
+ *
+ * this routine initializes the network adapter such that subsequent invocations
+ * of the interface callbacks can exchange ethernet frames; link negotiation is
+ * triggered from here already and continues in background
+ */
+static int mcs7830_basic_reset(struct usb_device *udev,
+			       struct mcs7830_private *priv)
+{
+	int rc;
+
+	debug("%s()\n", __func__);
+
+	/*
+	 * comment from the respective Linux driver, which
+	 * unconditionally sets the ALLMULTICAST flag as well:
+	 * should not be needed, but does not work otherwise
+	 */
+	priv->config = CONF_TXENABLE;
+	priv->config |= CONF_ALLMULTICAST;
+
+	rc = mcs7830_set_autoneg(udev);
+	if (rc < 0) {
+		pr_err("setting autoneg failed\n");
+		return rc;
+	}
+
+	rc = mcs7830_write_mchash(udev, priv);
+	if (rc < 0) {
+		pr_err("failed to set multicast hash\n");
+		return rc;
+	}
+
+	rc = mcs7830_write_config(udev, priv);
+	if (rc < 0) {
+		pr_err("failed to set configuration\n");
+		return rc;
+	}
+
+	rc = mcs7830_apply_fixup(udev);
+	if (rc < 0) {
+		pr_err("fixup application failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+/*
+ * mcs7830_read_mac() - read an ethernet adapter's MAC address
+ * @udev:	network device to read from
+ * @enetaddr:	place to put ethernet MAC address
+ * Return: zero upon success, negative upon error
+ *
+ * this routine fetches the MAC address stored within the ethernet adapter,
+ * and stores it in the ethernet interface's data structure
+ */
+static int mcs7830_read_mac(struct usb_device *udev, unsigned char enetaddr[])
+{
+	int rc;
+	uint8_t buf[ETH_ALEN];
+
+	debug("%s()\n", __func__);
+
+	rc = mcs7830_read_reg(udev, REG_ETHER_ADDR, ETH_ALEN, buf);
+	if (rc < 0) {
+		debug("reading MAC from adapter failed\n");
+		return rc;
+	}
+
+	memcpy(enetaddr, buf, ETH_ALEN);
+	return 0;
+}
+
+static int mcs7830_write_mac_common(struct usb_device *udev,
+				    unsigned char enetaddr[])
+{
+	int rc;
+
+	debug("%s()\n", __func__);
+
+	rc = mcs7830_write_reg(udev, REG_ETHER_ADDR, ETH_ALEN, enetaddr);
+	if (rc < 0) {
+		debug("writing MAC to adapter failed\n");
+		return rc;
+	}
+	return 0;
+}
+
+static int mcs7830_init_common(struct usb_device *udev)
+{
+	int timeout;
+	int have_link;
+
+	debug("%s()\n", __func__);
+
+	timeout = 0;
+	do {
+		have_link = mcs7830_read_phy(udev, MII_BMSR) & BMSR_LSTATUS;
+		if (have_link)
+			break;
+		udelay(LINKSTATUS_TIMEOUT_RES * 1000);
+		timeout += LINKSTATUS_TIMEOUT_RES;
+	} while (timeout < LINKSTATUS_TIMEOUT);
+	if (!have_link) {
+		debug("ethernet link is down\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int mcs7830_send_common(struct ueth_data *ueth, void *packet,
+			       int length)
+{
+	struct usb_device *udev = ueth->pusb_dev;
+	int rc;
+	int gotlen;
+	/* there is a status byte after the ethernet frame */
+	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, PKTSIZE + sizeof(uint8_t));
+
+	memcpy(buf, packet, length);
+	rc = usb_bulk_msg(udev,
+			  usb_sndbulkpipe(udev, ueth->ep_out),
+			  &buf[0], length, &gotlen,
+			  USBCALL_TIMEOUT);
+	debug("%s() TX want len %d, got len %d, rc %d\n",
+	      __func__, length, gotlen, rc);
+	return rc;
+}
+
+static int mcs7830_recv_common(struct ueth_data *ueth, uint8_t *buf)
+{
+	int rc, wantlen, gotlen;
+	uint8_t sts;
+
+	debug("%s()\n", __func__);
+
+	/* fetch input data from the adapter */
+	wantlen = MCS7830_RX_URB_SIZE;
+	rc = usb_bulk_msg(ueth->pusb_dev,
+			  usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
+			  &buf[0], wantlen, &gotlen,
+			  USBCALL_TIMEOUT);
+	debug("%s() RX want len %d, got len %d, rc %d\n",
+	      __func__, wantlen, gotlen, rc);
+	if (rc != 0) {
+		pr_err("RX: failed to receive\n");
+		return rc;
+	}
+	if (gotlen > wantlen) {
+		pr_err("RX: got too many bytes (%d)\n", gotlen);
+		return -EIO;
+	}
+
+	/*
+	 * the bulk message that we received from USB contains exactly
+	 * one ethernet frame and a trailing status byte
+	 */
+	if (gotlen < sizeof(sts))
+		return -EIO;
+	gotlen -= sizeof(sts);
+	sts = buf[gotlen];
+
+	if (sts == STAT_RX_FRAME_CORRECT) {
+		debug("%s() got a frame, len=%d\n", __func__, gotlen);
+		return gotlen;
+	}
+
+	debug("RX: frame error (sts 0x%02X, %s %s %s %s %s)\n",
+	      sts,
+	      (sts & STAT_RX_LARGE_FRAME) ? "large" : "-",
+	      (sts & STAT_RX_LENGTH_ERROR) ?  "length" : "-",
+	      (sts & STAT_RX_SHORT_FRAME) ? "short" : "-",
+	      (sts & STAT_RX_CRC_ERROR) ? "crc" : "-",
+	      (sts & STAT_RX_ALIGNMENT_ERROR) ?  "align" : "-");
+	return -EIO;
+}
+
+#ifndef CONFIG_DM_ETH
+/*
+ * mcs7830_init() - network interface's init callback
+ * @udev:	network device to initialize
+ * @bd:		board information
+ * Return: zero upon success, negative upon error
+ *
+ * after initial setup during probe() and get_info(), this init() callback
+ * ensures that the link is up and subsequent send() and recv() calls can
+ * exchange ethernet frames
+ */
+static int mcs7830_init(struct eth_device *eth, struct bd_info *bd)
+{
+	struct ueth_data *dev = eth->priv;
+
+	return mcs7830_init_common(dev->pusb_dev);
+}
+
+/*
+ * mcs7830_send() - network interface's send callback
+ * @eth:	network device to send the frame from
+ * @packet:	ethernet frame content
+ * @length:	ethernet frame length
+ * Return: zero upon success, negative upon error
+ *
+ * this routine send an ethernet frame out of the network interface
+ */
+static int mcs7830_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = eth->priv;
+
+	return mcs7830_send_common(dev, packet, length);
+}
+
+/*
+ * mcs7830_recv() - network interface's recv callback
+ * @eth:	network device to receive frames from
+ * Return: zero upon success, negative upon error
+ *
+ * this routine checks for available ethernet frames that the network
+ * interface might have received, and notifies the network stack
+ */
+static int mcs7830_recv(struct eth_device *eth)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, MCS7830_RX_URB_SIZE);
+	struct ueth_data *ueth = eth->priv;
+	int len;
+
+	len = mcs7830_recv_common(ueth, buf);
+	if (len >= 0) {
+		net_process_received_packet(buf, len);
+		return 0;
+	}
+
+	return len;
+}
+
+/*
+ * mcs7830_halt() - network interface's halt callback
+ * @eth:	network device to cease operation of
+ * Return: none
+ *
+ * this routine is supposed to undo the effect of previous initialization and
+ * ethernet frames exchange; in this implementation it's a NOP
+ */
+static void mcs7830_halt(struct eth_device *eth)
+{
+	debug("%s()\n", __func__);
+}
+
+/*
+ * mcs7830_write_mac() - write an ethernet adapter's MAC address
+ * @eth:	network device to write to
+ * Return: zero upon success, negative upon error
+ *
+ * this routine takes the MAC address from the ethernet interface's data
+ * structure, and writes it into the ethernet adapter such that subsequent
+ * exchange of ethernet frames uses this address
+ */
+static int mcs7830_write_mac(struct eth_device *eth)
+{
+	struct ueth_data *ueth = eth->priv;
+
+	return mcs7830_write_mac_common(ueth->pusb_dev, eth->enetaddr);
+}
+
+/*
+ * mcs7830_iface_idx - index of detected network interfaces
+ *
+ * this counter keeps track of identified supported interfaces,
+ * to assign unique names as more interfaces are found
+ */
+static int mcs7830_iface_idx;
+
+/*
+ * mcs7830_eth_before_probe() - network driver's before_probe callback
+ * Return: none
+ *
+ * this routine initializes driver's internal data in preparation of
+ * subsequent probe callbacks
+ */
+void mcs7830_eth_before_probe(void)
+{
+	mcs7830_iface_idx = 0;
+}
+
+/*
+ * struct mcs7830_dongle - description of a supported Moschip ethernet dongle
+ * @vendor:	16bit USB vendor identification
+ * @product:	16bit USB product identification
+ *
+ * this structure describes a supported USB ethernet dongle by means of the
+ * vendor and product codes found during USB enumeration; no flags are held
+ * here since all supported dongles have identical behaviour, and required
+ * fixups get determined at runtime, such that no manual configuration is
+ * needed
+ */
+struct mcs7830_dongle {
+	uint16_t vendor;
+	uint16_t product;
+};
+
+/*
+ * mcs7830_dongles - the list of supported Moschip based USB ethernet dongles
+ */
+static const struct mcs7830_dongle mcs7830_dongles[] = {
+	{ 0x9710, 0x7832, },	/* Moschip 7832 */
+	{ 0x9710, 0x7830, },	/* Moschip 7830 */
+	{ 0x9710, 0x7730, },	/* Moschip 7730 */
+	{ 0x0df6, 0x0021, },	/* Sitecom LN 30 */
+};
+
+/*
+ * mcs7830_eth_probe() - network driver's probe callback
+ * @dev:	detected USB device to check
+ * @ifnum:	detected USB interface to check
+ * @ss:		USB ethernet data structure to fill in upon match
+ * Return: #1 upon match, #0 upon mismatch or error
+ *
+ * this routine checks whether the found USB device is supported by
+ * this ethernet driver, and upon match fills in the USB ethernet
+ * data structure which later is passed to the get_info callback
+ */
+int mcs7830_eth_probe(struct usb_device *dev, unsigned int ifnum,
+		      struct ueth_data *ss)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *iface_desc;
+	int i;
+	struct mcs7830_private *priv;
+	int ep_in_found, ep_out_found, ep_intr_found;
+
+	debug("%s()\n", __func__);
+
+	/* iterate the list of supported dongles */
+	iface = &dev->config.if_desc[ifnum];
+	iface_desc = &iface->desc;
+	for (i = 0; i < ARRAY_SIZE(mcs7830_dongles); i++) {
+		if (dev->descriptor.idVendor == mcs7830_dongles[i].vendor &&
+		    dev->descriptor.idProduct == mcs7830_dongles[i].product)
+			break;
+	}
+	if (i == ARRAY_SIZE(mcs7830_dongles))
+		return 0;
+	debug("detected USB ethernet device: %04X:%04X\n",
+	      dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	/* fill in driver private data */
+	priv = calloc(1, sizeof(*priv));
+	if (!priv)
+		return 0;
+
+	/* fill in the ueth_data structure, attach private data */
+	memset(ss, 0, sizeof(*ss));
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->subclass = iface_desc->bInterfaceSubClass;
+	ss->protocol = iface_desc->bInterfaceProtocol;
+	ss->dev_priv = priv;
+
+	/*
+	 * a minimum of three endpoints is expected: in (bulk),
+	 * out (bulk), and interrupt; ignore all others
+	 */
+	ep_in_found = ep_out_found = ep_intr_found = 0;
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		uint8_t eptype, epaddr;
+		bool is_input;
+
+		eptype = iface->ep_desc[i].bmAttributes;
+		eptype &= USB_ENDPOINT_XFERTYPE_MASK;
+
+		epaddr = iface->ep_desc[i].bEndpointAddress;
+		is_input = epaddr & USB_DIR_IN;
+		epaddr &= USB_ENDPOINT_NUMBER_MASK;
+
+		if (eptype == USB_ENDPOINT_XFER_BULK) {
+			if (is_input && !ep_in_found) {
+				ss->ep_in = epaddr;
+				ep_in_found++;
+			}
+			if (!is_input && !ep_out_found) {
+				ss->ep_out = epaddr;
+				ep_out_found++;
+			}
+		}
+
+		if (eptype == USB_ENDPOINT_XFER_INT) {
+			if (is_input && !ep_intr_found) {
+				ss->ep_int = epaddr;
+				ss->irqinterval = iface->ep_desc[i].bInterval;
+				ep_intr_found++;
+			}
+		}
+	}
+	debug("endpoints: in %d, out %d, intr %d\n",
+	      ss->ep_in, ss->ep_out, ss->ep_int);
+
+	/* apply basic sanity checks */
+	if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+	    !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+		debug("device probe incomplete\n");
+		return 0;
+	}
+
+	dev->privptr = ss;
+	return 1;
+}
+
+/*
+ * mcs7830_eth_get_info() - network driver's get_info callback
+ * @dev:	detected USB device
+ * @ss:		USB ethernet data structure filled in at probe()
+ * @eth:	ethernet interface data structure to fill in
+ * Return: #1 upon success, #0 upon error
+ *
+ * this routine registers the mandatory init(), send(), recv(), and
+ * halt() callbacks with the ethernet interface, can register the
+ * optional write_hwaddr() callback with the ethernet interface,
+ * and initiates configuration of the interface such that subsequent
+ * calls to those callbacks results in network communication
+ */
+int mcs7830_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+			 struct eth_device *eth)
+{
+	debug("%s()\n", __func__);
+	if (!eth) {
+		debug("%s: missing parameter.\n", __func__);
+		return 0;
+	}
+
+	snprintf(eth->name, sizeof(eth->name), "%s%d",
+		 MCS7830_BASE_NAME, mcs7830_iface_idx++);
+	eth->init = mcs7830_init;
+	eth->send = mcs7830_send;
+	eth->recv = mcs7830_recv;
+	eth->halt = mcs7830_halt;
+	eth->write_hwaddr = mcs7830_write_mac;
+	eth->priv = ss;
+
+	if (mcs7830_basic_reset(ss->pusb_dev, ss->dev_priv))
+		return 0;
+
+	if (mcs7830_read_mac(ss->pusb_dev, eth->enetaddr))
+		return 0;
+	debug("MAC %pM\n", eth->enetaddr);
+
+	return 1;
+}
+#endif
+
+
+#ifdef CONFIG_DM_ETH
+static int mcs7830_eth_start(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+
+	return mcs7830_init_common(udev);
+}
+
+void mcs7830_eth_stop(struct udevice *dev)
+{
+	debug("** %s()\n", __func__);
+}
+
+int mcs7830_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct mcs7830_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+
+	return mcs7830_send_common(ueth, packet, length);
+}
+
+int mcs7830_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct mcs7830_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	int len;
+
+	len = mcs7830_recv_common(ueth, priv->rx_buf);
+	*packetp = priv->rx_buf;
+
+	return len;
+}
+
+static int mcs7830_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct mcs7830_private *priv = dev_get_priv(dev);
+
+	packet_len = ALIGN(packet_len, 4);
+	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+	return 0;
+}
+
+int mcs7830_write_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+
+	return mcs7830_write_mac_common(udev, pdata->enetaddr);
+}
+
+static int mcs7830_eth_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct mcs7830_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct ueth_data *ueth = &priv->ueth;
+
+	if (mcs7830_basic_reset(udev, priv))
+		return 0;
+
+	if (mcs7830_read_mac(udev, pdata->enetaddr))
+		return 0;
+
+	return usb_ether_register(dev, ueth, MCS7830_RX_URB_SIZE);
+}
+
+static const struct eth_ops mcs7830_eth_ops = {
+	.start	= mcs7830_eth_start,
+	.send	= mcs7830_eth_send,
+	.recv	= mcs7830_eth_recv,
+	.free_pkt = mcs7830_free_pkt,
+	.stop	= mcs7830_eth_stop,
+	.write_hwaddr = mcs7830_write_hwaddr,
+};
+
+U_BOOT_DRIVER(mcs7830_eth) = {
+	.name	= "mcs7830_eth",
+	.id	= UCLASS_ETH,
+	.probe = mcs7830_eth_probe,
+	.ops	= &mcs7830_eth_ops,
+	.priv_auto	= sizeof(struct mcs7830_private),
+	.plat_auto	= sizeof(struct eth_pdata),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static const struct usb_device_id mcs7830_eth_id_table[] = {
+	{ USB_DEVICE(0x9710, 0x7832) },		/* Moschip 7832 */
+	{ USB_DEVICE(0x9710, 0x7830), },	/* Moschip 7830 */
+	{ USB_DEVICE(0x9710, 0x7730), },	/* Moschip 7730 */
+	{ USB_DEVICE(0x0df6, 0x0021), },	/* Sitecom LN 30 */
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(mcs7830_eth, mcs7830_eth_id_table);
+#endif
diff --git a/roms/u-boot/drivers/usb/eth/r8152.c b/roms/u-boot/drivers/usb/eth/r8152.c
new file mode 100644
index 000000000..4677da9f2
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/r8152.c
@@ -0,0 +1,1897 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015 Realtek Semiconductor Corp. All rights reserved.
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <net.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/bitops.h>
+#include "usb_ether.h"
+#include "r8152.h"
+
+#ifndef CONFIG_DM_ETH
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+
+struct r8152_dongle {
+	unsigned short vendor;
+	unsigned short product;
+};
+
+static const struct r8152_dongle r8152_dongles[] = {
+	/* Realtek */
+	{ 0x0bda, 0x8050 },
+	{ 0x0bda, 0x8152 },
+	{ 0x0bda, 0x8153 },
+
+	/* Samsung */
+	{ 0x04e8, 0xa101 },
+
+	/* Lenovo */
+	{ 0x17ef, 0x304f },
+	{ 0x17ef, 0x3052 },
+	{ 0x17ef, 0x3054 },
+	{ 0x17ef, 0x3057 },
+	{ 0x17ef, 0x7205 },
+	{ 0x17ef, 0x720a },
+	{ 0x17ef, 0x720b },
+	{ 0x17ef, 0x720c },
+
+	/* TP-LINK */
+	{ 0x2357, 0x0601 },
+
+	/* Nvidia */
+	{ 0x0955, 0x09ff },
+};
+#endif
+
+struct r8152_version {
+	unsigned short tcr;
+	unsigned short version;
+	bool           gmii;
+};
+
+static const struct r8152_version r8152_versions[] = {
+	{ 0x4c00, RTL_VER_01, 0 },
+	{ 0x4c10, RTL_VER_02, 0 },
+	{ 0x5c00, RTL_VER_03, 1 },
+	{ 0x5c10, RTL_VER_04, 1 },
+	{ 0x5c20, RTL_VER_05, 1 },
+	{ 0x5c30, RTL_VER_06, 1 },
+	{ 0x4800, RTL_VER_07, 0 },
+	{ 0x6000, RTL_VER_08, 1 },
+	{ 0x6010, RTL_VER_09, 1 },
+};
+
+static
+int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(void *, tmp, size);
+	int ret;
+
+	ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
+		RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
+		value, index, tmp, size, 500);
+	memcpy(data, tmp, size);
+	return ret;
+}
+
+static
+int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(void *, tmp, size);
+
+	memcpy(tmp, data, size);
+	return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
+			       RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
+			       value, index, tmp, size, 500);
+}
+
+int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
+		     void *data, u16 type)
+{
+	u16 burst_size = 64;
+	int ret;
+	int txsize;
+
+	/* both size and index must be 4 bytes align */
+	if ((size & 3) || !size || (index & 3) || !data)
+		return -EINVAL;
+
+	if (index + size > 0xffff)
+		return -EINVAL;
+
+	while (size) {
+		txsize = min(size, burst_size);
+		ret = get_registers(tp, index, type, txsize, data);
+		if (ret < 0)
+			break;
+
+		index += txsize;
+		data += txsize;
+		size -= txsize;
+	}
+
+	return ret;
+}
+
+int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
+		      u16 size, void *data, u16 type)
+{
+	int ret;
+	u16 byteen_start, byteen_end, byte_en_to_hw;
+	u16 burst_size = 512;
+	int txsize;
+
+	/* both size and index must be 4 bytes align */
+	if ((size & 3) || !size || (index & 3) || !data)
+		return -EINVAL;
+
+	if (index + size > 0xffff)
+		return -EINVAL;
+
+	byteen_start = byteen & BYTE_EN_START_MASK;
+	byteen_end = byteen & BYTE_EN_END_MASK;
+
+	byte_en_to_hw = byteen_start | (byteen_start << 4);
+	ret = set_registers(tp, index, type | byte_en_to_hw, 4, data);
+	if (ret < 0)
+		return ret;
+
+	index += 4;
+	data += 4;
+	size -= 4;
+
+	if (size) {
+		size -= 4;
+
+		while (size) {
+			txsize = min(size, burst_size);
+
+			ret = set_registers(tp, index,
+					    type | BYTE_EN_DWORD,
+					    txsize, data);
+			if (ret < 0)
+				return ret;
+
+			index += txsize;
+			data += txsize;
+			size -= txsize;
+		}
+
+		byte_en_to_hw = byteen_end | (byteen_end >> 4);
+		ret = set_registers(tp, index, type | byte_en_to_hw, 4, data);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
+{
+	return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
+}
+
+int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
+{
+	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
+}
+
+int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
+{
+	return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB);
+}
+
+int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
+{
+	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
+}
+
+u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
+{
+	__le32 data;
+
+	generic_ocp_read(tp, index, sizeof(data), &data, type);
+
+	return __le32_to_cpu(data);
+}
+
+void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
+{
+	__le32 tmp = __cpu_to_le32(data);
+
+	generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
+}
+
+u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
+{
+	u32 data;
+	__le32 tmp;
+	u8 shift = index & 2;
+
+	index &= ~3;
+
+	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
+
+	data = __le32_to_cpu(tmp);
+	data >>= (shift * 8);
+	data &= 0xffff;
+
+	return data;
+}
+
+void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
+{
+	u32 mask = 0xffff;
+	__le32 tmp;
+	u16 byen = BYTE_EN_WORD;
+	u8 shift = index & 2;
+
+	data &= mask;
+
+	if (index & 2) {
+		byen <<= shift;
+		mask <<= (shift * 8);
+		data <<= (shift * 8);
+		index &= ~3;
+	}
+
+	tmp = __cpu_to_le32(data);
+
+	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
+}
+
+u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
+{
+	u32 data;
+	__le32 tmp;
+	u8 shift = index & 3;
+
+	index &= ~3;
+
+	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
+
+	data = __le32_to_cpu(tmp);
+	data >>= (shift * 8);
+	data &= 0xff;
+
+	return data;
+}
+
+void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
+{
+	u32 mask = 0xff;
+	__le32 tmp;
+	u16 byen = BYTE_EN_BYTE;
+	u8 shift = index & 3;
+
+	data &= mask;
+
+	if (index & 3) {
+		byen <<= shift;
+		mask <<= (shift * 8);
+		data <<= (shift * 8);
+		index &= ~3;
+	}
+
+	tmp = __cpu_to_le32(data);
+
+	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
+}
+
+u16 ocp_reg_read(struct r8152 *tp, u16 addr)
+{
+	u16 ocp_base, ocp_index;
+
+	ocp_base = addr & 0xf000;
+	if (ocp_base != tp->ocp_base) {
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
+		tp->ocp_base = ocp_base;
+	}
+
+	ocp_index = (addr & 0x0fff) | 0xb000;
+	return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
+}
+
+void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
+{
+	u16 ocp_base, ocp_index;
+
+	ocp_base = addr & 0xf000;
+	if (ocp_base != tp->ocp_base) {
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
+		tp->ocp_base = ocp_base;
+	}
+
+	ocp_index = (addr & 0x0fff) | 0xb000;
+	ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
+}
+
+static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
+{
+	ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
+}
+
+static int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
+{
+	return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
+}
+
+void sram_write(struct r8152 *tp, u16 addr, u16 data)
+{
+	ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
+	ocp_reg_write(tp, OCP_SRAM_DATA, data);
+}
+
+static u16 sram_read(struct r8152 *tp, u16 addr)
+{
+	ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
+	return ocp_reg_read(tp, OCP_SRAM_DATA);
+}
+
+int r8152_wait_for_bit(struct r8152 *tp, bool ocp_reg, u16 type, u16 index,
+		       const u32 mask, bool set, unsigned int timeout)
+{
+	u32 val;
+
+	while (--timeout) {
+		if (ocp_reg)
+			val = ocp_reg_read(tp, index);
+		else
+			val = ocp_read_dword(tp, type, index);
+
+		if (!set)
+			val = ~val;
+
+		if ((val & mask) == mask)
+			return 0;
+
+		mdelay(1);
+	}
+
+	debug("%s: Timeout (index=%04x mask=%08x timeout=%d)\n",
+	      __func__, index, mask, timeout);
+
+	return -ETIMEDOUT;
+}
+
+static void r8152b_reset_packet_filter(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
+	ocp_data &= ~FMC_FCR_MCU_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
+	ocp_data |= FMC_FCR_MCU_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
+}
+
+static void rtl8152_wait_fifo_empty(struct r8152 *tp)
+{
+	int ret;
+
+	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_PHY_PWR,
+				 PLA_PHY_PWR_TXEMP, 1, R8152_WAIT_TIMEOUT);
+	if (ret)
+		debug("Timeout waiting for FIFO empty\n");
+
+	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_TCR0,
+				 TCR0_TX_EMPTY, 1, R8152_WAIT_TIMEOUT);
+	if (ret)
+		debug("Timeout waiting for TX empty\n");
+}
+
+static void rtl8152_nic_reset(struct r8152 *tp)
+{
+	int ret;
+	u32 ocp_data;
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, BIST_CTRL);
+	ocp_data |= BIST_CTRL_SW_RESET;
+	ocp_write_dword(tp, MCU_TYPE_PLA, BIST_CTRL, ocp_data);
+
+	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, BIST_CTRL,
+				 BIST_CTRL_SW_RESET, 0, R8152_WAIT_TIMEOUT);
+	if (ret)
+		debug("Timeout waiting for NIC reset\n");
+}
+
+static u8 rtl8152_get_speed(struct r8152 *tp)
+{
+	return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
+}
+
+static void rtl_set_eee_plus(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
+	ocp_data &= ~EEEP_CR_EEEP_TX;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
+}
+
+static void rxdy_gated_en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
+	if (enable)
+		ocp_data |= RXDY_GATED_EN;
+	else
+		ocp_data &= ~RXDY_GATED_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+}
+
+static void rtl8152_set_rx_mode(struct r8152 *tp)
+{
+	u32 ocp_data;
+	__le32 tmp[2];
+
+	tmp[0] = 0xffffffff;
+	tmp[1] = 0xffffffff;
+
+	pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp)
+{
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
+		       OWN_UPDATE | OWN_CLEAR);
+}
+
+static int rtl_enable(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	r8152b_reset_packet_filter(tp);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
+	ocp_data |= PLA_CR_RE | PLA_CR_TE;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+	switch (tp->version) {
+	case RTL_VER_08:
+	case RTL_VER_09:
+		r8153b_rx_agg_chg_indicate(tp);
+		break;
+	default:
+		break;
+	}
+
+	rxdy_gated_en(tp, false);
+
+	rtl8152_set_rx_mode(tp);
+
+	return 0;
+}
+
+static int rtl8152_enable(struct r8152 *tp)
+{
+	rtl_set_eee_plus(tp);
+
+	return rtl_enable(tp);
+}
+
+static void r8153_set_rx_early_timeout(struct r8152 *tp)
+{
+	u32 ocp_data = tp->coalesce / 8;
+
+	switch (tp->version) {
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
+			       ocp_data);
+		break;
+
+	case RTL_VER_08:
+	case RTL_VER_09:
+		/* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout
+		 * primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 1264ns.
+		 */
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
+			       RX_AUXILIARY_TIMER / 8);
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
+			       ocp_data);
+		break;
+
+	default:
+		debug("** %s Invalid Device\n", __func__);
+		break;
+	}
+}
+
+static void r8153_set_rx_early_size(struct r8152 *tp)
+{
+	u32 ocp_data = (RTL8152_AGG_BUF_SZ - RTL8153_RMS -
+			sizeof(struct rx_desc));
+
+	switch (tp->version) {
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
+			       ocp_data / 4);
+		break;
+
+	case RTL_VER_08:
+	case RTL_VER_09:
+		ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
+			       ocp_data / 8);
+		break;
+
+	default:
+		debug("** %s Invalid Device\n", __func__);
+		break;
+	}
+}
+
+static int rtl8153_enable(struct r8152 *tp)
+{
+	rtl_set_eee_plus(tp);
+	r8153_set_rx_early_timeout(tp);
+	r8153_set_rx_early_size(tp);
+
+	return rtl_enable(tp);
+}
+
+static void rtl_disable(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	rxdy_gated_en(tp, true);
+
+	rtl8152_wait_fifo_empty(tp);
+	rtl8152_nic_reset(tp);
+}
+
+static void r8152_power_cut_en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
+	if (enable)
+		ocp_data |= POWER_CUT;
+	else
+		ocp_data &= ~POWER_CUT;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
+	ocp_data &= ~RESUME_INDICATE;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+}
+
+static void rtl_rx_vlan_en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
+	if (enable)
+		ocp_data |= CPCR_RX_VLAN;
+	else
+		ocp_data &= ~CPCR_RX_VLAN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+}
+
+static void r8153_u1u2en(struct r8152 *tp, bool enable)
+{
+	u8 u1u2[8];
+
+	if (enable)
+		memset(u1u2, 0xff, sizeof(u1u2));
+	else
+		memset(u1u2, 0x00, sizeof(u1u2));
+
+	usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
+}
+
+static void r8153b_u1u2en(struct r8152 *tp, bool enable)
+{
+	u16 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG);
+	if (enable)
+		ocp_data |= LPM_U1U2_EN;
+	else
+		ocp_data &= ~LPM_U1U2_EN;
+
+	ocp_write_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG, ocp_data);
+}
+
+static void r8153_u2p3en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
+	if (enable && tp->version != RTL_VER_03 && tp->version != RTL_VER_04)
+		ocp_data |= U2P3_ENABLE;
+	else
+		ocp_data &= ~U2P3_ENABLE;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
+}
+
+static void r8153_power_cut_en(struct r8152 *tp, bool enable)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
+	if (enable)
+		ocp_data |= PWR_EN | PHASE2_EN;
+	else
+		ocp_data &= ~(PWR_EN | PHASE2_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+	ocp_data &= ~PCUT_STATUS;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+}
+
+static void rtl_reset_bmu(struct r8152 *tp)
+{
+	u8 ocp_data;
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_BMU_RESET);
+	ocp_data &= ~(BMU_RESET_EP_IN | BMU_RESET_EP_OUT);
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
+	ocp_data |= BMU_RESET_EP_IN | BMU_RESET_EP_OUT;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
+}
+
+static int r8152_read_mac(struct r8152 *tp, unsigned char *macaddr)
+{
+	int ret;
+	unsigned char enetaddr[8] = {0};
+
+	ret = pla_ocp_read(tp, PLA_IDR, 8, enetaddr);
+	if (ret < 0)
+		return ret;
+
+	memcpy(macaddr, enetaddr, ETH_ALEN);
+	return 0;
+}
+
+static void r8152b_disable_aldps(struct r8152 *tp)
+{
+	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
+	mdelay(20);
+}
+
+static void r8152b_enable_aldps(struct r8152 *tp)
+{
+	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
+		LINKENA | DIS_SDSAVE);
+}
+
+static void rtl8152_disable(struct r8152 *tp)
+{
+	r8152b_disable_aldps(tp);
+	rtl_disable(tp);
+	r8152b_enable_aldps(tp);
+}
+
+static void r8152b_hw_phy_cfg(struct r8152 *tp)
+{
+	u16 data;
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	r8152b_firmware(tp);
+}
+
+static void rtl8152_reinit_ll(struct r8152 *tp)
+{
+	u32 ocp_data;
+	int ret;
+
+	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_PHY_PWR,
+				 PLA_PHY_PWR_LLR, 1, R8152_WAIT_TIMEOUT);
+	if (ret)
+		debug("Timeout waiting for link list ready\n");
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data |= RE_INIT_LL;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_PHY_PWR,
+				 PLA_PHY_PWR_LLR, 1, R8152_WAIT_TIMEOUT);
+	if (ret)
+		debug("Timeout waiting for link list ready\n");
+}
+
+static void r8152b_exit_oob(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	rxdy_gated_en(tp, true);
+	r8152b_hw_phy_cfg(tp);
+
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data &= ~MCU_BORW_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	rtl8152_reinit_ll(tp);
+	rtl8152_nic_reset(tp);
+
+	/* rx share fifo credit full threshold */
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
+
+	if (tp->udev->speed == USB_SPEED_FULL ||
+	    tp->udev->speed == USB_SPEED_LOW) {
+		/* rx share fifo credit near full threshold */
+		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+				RXFIFO_THR2_FULL);
+		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+				RXFIFO_THR3_FULL);
+	} else {
+		/* rx share fifo credit near full threshold */
+		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+				RXFIFO_THR2_HIGH);
+		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+				RXFIFO_THR3_HIGH);
+	}
+
+	/* TX share fifo free credit full threshold */
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
+
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
+	ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
+			TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
+	ocp_data |= TCR0_AUTO_FIFO;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
+}
+
+static void r8152b_enter_oob(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
+
+	rtl_disable(tp);
+
+	rtl8152_reinit_ll(tp);
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+
+	rtl_rx_vlan_en(tp, false);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
+	ocp_data |= ALDPS_PROXY_MODE;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	rxdy_gated_en(tp, false);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static void r8153_hw_phy_cfg(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+
+	if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 ||
+	    tp->version == RTL_VER_05)
+		ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L);
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	r8153_firmware(tp);
+
+	if (tp->version == RTL_VER_03) {
+		data = ocp_reg_read(tp, OCP_EEE_CFG);
+		data &= ~CTAP_SHORT_EN;
+		ocp_reg_write(tp, OCP_EEE_CFG, data);
+	}
+
+	data = ocp_reg_read(tp, OCP_POWER_CFG);
+	data |= EEE_CLKDIV_EN;
+	ocp_reg_write(tp, OCP_POWER_CFG, data);
+
+	data = ocp_reg_read(tp, OCP_DOWN_SPEED);
+	data |= EN_10M_BGOFF;
+	ocp_reg_write(tp, OCP_DOWN_SPEED, data);
+	data = ocp_reg_read(tp, OCP_POWER_CFG);
+	data |= EN_10M_PLLOFF;
+	ocp_reg_write(tp, OCP_POWER_CFG, data);
+	sram_write(tp, SRAM_IMPEDANCE, 0x0b13);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+	ocp_data |= PFM_PWM_SWITCH;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+
+	/* Enable LPF corner auto tune */
+	sram_write(tp, SRAM_LPF_CFG, 0xf70f);
+
+	/* Adjust 10M Amplitude */
+	sram_write(tp, SRAM_10M_AMP1, 0x00af);
+	sram_write(tp, SRAM_10M_AMP2, 0x0208);
+}
+
+static u32 r8152_efuse_read(struct r8152 *tp, u8 addr)
+{
+	u32 ocp_data;
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD, EFUSE_READ_CMD | addr);
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD);
+	ocp_data = (ocp_data & EFUSE_DATA_BIT16) << 9;	/* data of bit16 */
+	ocp_data |= ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_DATA);
+
+	return ocp_data;
+}
+
+static void r8153b_hw_phy_cfg(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 data;
+
+	data = r8152_mdio_read(tp, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(tp, MII_BMCR, data);
+	}
+
+	/* U1/U2/L1 idle timer. 500 us */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
+
+	r8153b_firmware(tp);
+
+	data = sram_read(tp, SRAM_GREEN_CFG);
+	data |= R_TUNE_EN;
+	sram_write(tp, SRAM_GREEN_CFG, data);
+	data = ocp_reg_read(tp, OCP_NCTL_CFG);
+	data |= PGA_RETURN_EN;
+	ocp_reg_write(tp, OCP_NCTL_CFG, data);
+
+	/* ADC Bias Calibration:
+	 * read efuse offset 0x7d to get a 17-bit data. Remove the dummy/fake
+	 * bit (bit3) to rebuild the real 16-bit data. Write the data to the
+	 * ADC ioffset.
+	 */
+	ocp_data = r8152_efuse_read(tp, 0x7d);
+	ocp_data = ((ocp_data & 0x1fff0) >> 1) | (ocp_data & 0x7);
+	if (ocp_data != 0xffff)
+		ocp_reg_write(tp, OCP_ADC_IOFFSET, ocp_data);
+
+	/* ups mode tx-link-pulse timing adjustment:
+	 * rg_saw_cnt = OCP reg 0xC426 Bit[13:0]
+	 * swr_cnt_1ms_ini = 16000000 / rg_saw_cnt
+	 */
+	ocp_data = ocp_reg_read(tp, 0xc426);
+	ocp_data &= 0x3fff;
+	if (ocp_data) {
+		u32 swr_cnt_1ms_ini;
+
+		swr_cnt_1ms_ini = (16000000 / ocp_data) & SAW_CNT_1MS_MASK;
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG);
+		ocp_data = (ocp_data & ~SAW_CNT_1MS_MASK) | swr_cnt_1ms_ini;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CFG, ocp_data);
+	}
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+	ocp_data |= PFM_PWM_SWITCH;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+}
+
+static void r8153_first_init(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	rxdy_gated_en(tp, true);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	r8153_hw_phy_cfg(tp);
+
+	rtl8152_nic_reset(tp);
+	rtl_reset_bmu(tp);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data &= ~MCU_BORW_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	rtl8152_reinit_ll(tp);
+
+	rtl_rx_vlan_en(tp, false);
+
+	ocp_data = RTL8153_RMS;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
+	ocp_data |= TCR0_AUTO_FIFO;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
+
+	rtl8152_nic_reset(tp);
+
+	/* rx share fifo credit full threshold */
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL);
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);
+	/* TX share fifo free credit full threshold */
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
+
+	/* rx aggregation */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+
+	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+}
+
+static void r8153_enter_oob(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	rtl_disable(tp);
+	rtl_reset_bmu(tp);
+
+	rtl8152_reinit_ll(tp);
+
+	ocp_data = RTL8153_RMS;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
+	ocp_data &= ~TEREDO_WAKE_MASK;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
+
+	rtl_rx_vlan_en(tp, false);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
+	ocp_data |= ALDPS_PROXY_MODE;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	rxdy_gated_en(tp, false);
+
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static void r8153_disable_aldps(struct r8152 *tp)
+{
+	u16 data;
+
+	data = ocp_reg_read(tp, OCP_POWER_CFG);
+	data &= ~EN_ALDPS;
+	ocp_reg_write(tp, OCP_POWER_CFG, data);
+	mdelay(20);
+}
+
+static void rtl8153_disable(struct r8152 *tp)
+{
+	r8153_disable_aldps(tp);
+	rtl_disable(tp);
+	rtl_reset_bmu(tp);
+}
+
+static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
+{
+	u16 bmcr, anar, gbcr;
+
+	anar = r8152_mdio_read(tp, MII_ADVERTISE);
+	anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+		  ADVERTISE_100HALF | ADVERTISE_100FULL);
+	if (tp->supports_gmii) {
+		gbcr = r8152_mdio_read(tp, MII_CTRL1000);
+		gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+	} else {
+		gbcr = 0;
+	}
+
+	if (autoneg == AUTONEG_DISABLE) {
+		if (speed == SPEED_10) {
+			bmcr = 0;
+			anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+		} else if (speed == SPEED_100) {
+			bmcr = BMCR_SPEED100;
+			anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+		} else if (speed == SPEED_1000 && tp->supports_gmii) {
+			bmcr = BMCR_SPEED1000;
+			gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+		} else {
+			return -EINVAL;
+		}
+
+		if (duplex == DUPLEX_FULL)
+			bmcr |= BMCR_FULLDPLX;
+	} else {
+		if (speed == SPEED_10) {
+			if (duplex == DUPLEX_FULL)
+				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+			else
+				anar |= ADVERTISE_10HALF;
+		} else if (speed == SPEED_100) {
+			if (duplex == DUPLEX_FULL) {
+				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+			} else {
+				anar |= ADVERTISE_10HALF;
+				anar |= ADVERTISE_100HALF;
+			}
+		} else if (speed == SPEED_1000 && tp->supports_gmii) {
+			if (duplex == DUPLEX_FULL) {
+				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+				gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+			} else {
+				anar |= ADVERTISE_10HALF;
+				anar |= ADVERTISE_100HALF;
+				gbcr |= ADVERTISE_1000HALF;
+			}
+		} else {
+			return -EINVAL;
+		}
+
+		bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
+	}
+
+	if (tp->supports_gmii)
+		r8152_mdio_write(tp, MII_CTRL1000, gbcr);
+
+	r8152_mdio_write(tp, MII_ADVERTISE, anar);
+	r8152_mdio_write(tp, MII_BMCR, bmcr);
+
+	return 0;
+}
+
+static void rtl8152_up(struct r8152 *tp)
+{
+	r8152b_disable_aldps(tp);
+	r8152b_exit_oob(tp);
+	r8152b_enable_aldps(tp);
+}
+
+static void rtl8152_down(struct r8152 *tp)
+{
+	r8152_power_cut_en(tp, false);
+	r8152b_disable_aldps(tp);
+	r8152b_enter_oob(tp);
+	r8152b_enable_aldps(tp);
+}
+
+static void rtl8153_up(struct r8152 *tp)
+{
+	r8153_u1u2en(tp, false);
+	r8153_disable_aldps(tp);
+	r8153_first_init(tp);
+	r8153_u2p3en(tp, false);
+}
+
+static void rtl8153_down(struct r8152 *tp)
+{
+	r8153_u1u2en(tp, false);
+	r8153_u2p3en(tp, false);
+	r8153_power_cut_en(tp, false);
+	r8153_disable_aldps(tp);
+	r8153_enter_oob(tp);
+}
+
+static void rtl8153b_up(struct r8152 *tp)
+{
+	r8153_first_init(tp);
+}
+
+static void rtl8153b_down(struct r8152 *tp)
+{
+	r8153_enter_oob(tp);
+}
+
+static void r8152b_get_version(struct r8152 *tp)
+{
+	u32 ocp_data;
+	u16 tcr;
+	int i;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1);
+	tcr = (u16)(ocp_data & VERSION_MASK);
+
+	for (i = 0; i < ARRAY_SIZE(r8152_versions); i++) {
+		if (tcr == r8152_versions[i].tcr) {
+			/* Found a supported version */
+			tp->version = r8152_versions[i].version;
+			tp->supports_gmii = r8152_versions[i].gmii;
+			break;
+		}
+	}
+
+	if (tp->version == RTL_VER_UNKNOWN)
+		debug("r8152 Unknown tcr version 0x%04x\n", tcr);
+}
+
+static void r8152b_enable_fc(struct r8152 *tp)
+{
+	u16 anar;
+	anar = r8152_mdio_read(tp, MII_ADVERTISE);
+	anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+	r8152_mdio_write(tp, MII_ADVERTISE, anar);
+}
+
+static void rtl_tally_reset(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
+	ocp_data |= TALLY_RESET;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
+}
+
+static void r8152b_init(struct r8152 *tp)
+{
+	u32 ocp_data;
+
+	r8152b_disable_aldps(tp);
+
+	if (tp->version == RTL_VER_01) {
+		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
+		ocp_data &= ~LED_MODE_MASK;
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
+	}
+
+	r8152_power_cut_en(tp, false);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+	ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
+	ocp_data &= ~MCU_CLK_RATIO_MASK;
+	ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
+	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
+	ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
+		   SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_TIMER);
+	ocp_data |= BIT(15);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_TIMER, ocp_data);
+	ocp_write_word(tp, MCU_TYPE_USB, 0xcbfc, 0x03e8);
+	ocp_data &= ~BIT(15);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_TIMER, ocp_data);
+
+	r8152b_enable_fc(tp);
+	rtl_tally_reset(tp);
+
+	/* enable rx aggregation */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+
+	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+}
+
+static void r8153_init(struct r8152 *tp)
+{
+	int i;
+	u32 ocp_data;
+
+	r8153_disable_aldps(tp);
+	r8153_u1u2en(tp, false);
+
+	r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_BOOT_CTRL,
+			   AUTOLOAD_DONE, 1, R8152_WAIT_TIMEOUT);
+
+	for (i = 0; i < R8152_WAIT_TIMEOUT; i++) {
+		ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK;
+		if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN)
+			break;
+
+		mdelay(1);
+	}
+
+	r8153_u2p3en(tp, false);
+
+	if (tp->version == RTL_VER_04) {
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2);
+		ocp_data &= ~pwd_dn_scale_mask;
+		ocp_data |= pwd_dn_scale(96);
+		ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
+		ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
+	} else if (tp->version == RTL_VER_05) {
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0);
+		ocp_data &= ~ECM_ALDPS;
+		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
+		if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
+			ocp_data &= ~DYNAMIC_BURST;
+		else
+			ocp_data |= DYNAMIC_BURST;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
+	} else if (tp->version == RTL_VER_06) {
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
+		if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
+			ocp_data &= ~DYNAMIC_BURST;
+		else
+			ocp_data |= DYNAMIC_BURST;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
+	}
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2);
+	ocp_data |= EP4_FULL_FC;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
+	ocp_data &= ~TIMER11_EN;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
+	ocp_data &= ~LED_MODE_MASK;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
+
+	ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM;
+	if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER)
+		ocp_data |= LPM_TIMER_500MS;
+	else
+		ocp_data |= LPM_TIMER_500US;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2);
+	ocp_data &= ~SEN_VAL_MASK;
+	ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
+
+	ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
+
+	r8153_power_cut_en(tp, false);
+
+	r8152b_enable_fc(tp);
+	rtl_tally_reset(tp);
+}
+
+static void r8153b_init(struct r8152 *tp)
+{
+	u32 ocp_data;
+	int i;
+
+	r8153_disable_aldps(tp);
+	r8153b_u1u2en(tp, false);
+
+	r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_BOOT_CTRL,
+			   AUTOLOAD_DONE, 1, R8152_WAIT_TIMEOUT);
+
+	for (i = 0; i < R8152_WAIT_TIMEOUT; i++) {
+		ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK;
+		if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN)
+			break;
+
+		mdelay(1);
+	}
+
+	r8153_u2p3en(tp, false);
+
+	/* MSC timer = 0xfff * 8ms = 32760 ms */
+	ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
+
+	r8153_power_cut_en(tp, false);
+
+	/* MAC clock speed down */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
+	ocp_data |= MAC_CLK_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
+	ocp_data &= ~PLA_MCU_SPDWN_EN;
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
+
+	if (tp->version == RTL_VER_09) {
+		/* Disable Test IO for 32QFN */
+		if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) {
+			ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+			ocp_data |= TEST_IO_OFF;
+			ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+		}
+	}
+
+	/* rx aggregation */
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+	rtl_tally_reset(tp);
+	r8153b_hw_phy_cfg(tp);
+	r8152b_enable_fc(tp);
+}
+
+static void rtl8152_unload(struct r8152 *tp)
+{
+	if (tp->version != RTL_VER_01)
+		r8152_power_cut_en(tp, true);
+}
+
+static void rtl8153_unload(struct r8152 *tp)
+{
+	r8153_power_cut_en(tp, false);
+}
+
+static int rtl_ops_init(struct r8152 *tp)
+{
+	struct rtl_ops *ops = &tp->rtl_ops;
+	int ret = 0;
+
+	switch (tp->version) {
+	case RTL_VER_01:
+	case RTL_VER_02:
+	case RTL_VER_07:
+		ops->init		= r8152b_init;
+		ops->enable		= rtl8152_enable;
+		ops->disable		= rtl8152_disable;
+		ops->up			= rtl8152_up;
+		ops->down		= rtl8152_down;
+		ops->unload		= rtl8152_unload;
+		break;
+
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+		ops->init		= r8153_init;
+		ops->enable		= rtl8153_enable;
+		ops->disable		= rtl8153_disable;
+		ops->up			= rtl8153_up;
+		ops->down		= rtl8153_down;
+		ops->unload		= rtl8153_unload;
+		break;
+
+	case RTL_VER_08:
+	case RTL_VER_09:
+		ops->init		= r8153b_init;
+		ops->enable		= rtl8153_enable;
+		ops->disable		= rtl8153_disable;
+		ops->up			= rtl8153b_up;
+		ops->down		= rtl8153b_down;
+		break;
+
+	default:
+		ret = -ENODEV;
+		printf("r8152 Unknown Device\n");
+		break;
+	}
+
+	return ret;
+}
+
+static int r8152_init_common(struct r8152 *tp)
+{
+	u8 speed;
+	int timeout = 0;
+	int link_detected;
+
+	debug("** %s()\n", __func__);
+
+	do {
+		speed = rtl8152_get_speed(tp);
+
+		link_detected = speed & LINK_STATUS;
+		if (!link_detected) {
+			if (timeout == 0)
+				printf("Waiting for Ethernet connection... ");
+			mdelay(TIMEOUT_RESOLUTION);
+			timeout += TIMEOUT_RESOLUTION;
+		}
+	} while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+	if (link_detected) {
+		tp->rtl_ops.enable(tp);
+
+		if (timeout != 0)
+			printf("done.\n");
+	} else {
+		printf("unable to connect.\n");
+	}
+
+	return 0;
+}
+
+static int r8152_send_common(struct ueth_data *ueth, void *packet, int length)
+{
+	struct usb_device *udev = ueth->pusb_dev;
+	u32 opts1, opts2 = 0;
+	int err;
+	int actual_len;
+	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, msg,
+				 PKTSIZE + sizeof(struct tx_desc));
+	struct tx_desc *tx_desc = (struct tx_desc *)msg;
+
+	debug("** %s(), len %d\n", __func__, length);
+
+	opts1 = length | TX_FS | TX_LS;
+
+	tx_desc->opts2 = cpu_to_le32(opts2);
+	tx_desc->opts1 = cpu_to_le32(opts1);
+
+	memcpy(msg + sizeof(struct tx_desc), (void *)packet, length);
+
+	err = usb_bulk_msg(udev, usb_sndbulkpipe(udev, ueth->ep_out),
+			   (void *)msg, length + sizeof(struct tx_desc),
+			   &actual_len, USB_BULK_SEND_TIMEOUT);
+	debug("Tx: len = %zu, actual = %u, err = %d\n",
+	      length + sizeof(struct tx_desc), actual_len, err);
+
+	return err;
+}
+
+#ifndef CONFIG_DM_ETH
+static int r8152_init(struct eth_device *eth, struct bd_info *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct r8152 *tp = (struct r8152 *)dev->dev_priv;
+
+	return r8152_init_common(tp);
+}
+
+static int r8152_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return r8152_send_common(dev, packet, length);
+}
+
+static int r8152_recv(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, recv_buf, RTL8152_AGG_BUF_SZ);
+	unsigned char *pkt_ptr;
+	int err;
+	int actual_len;
+	u16 packet_len;
+
+	u32 bytes_process = 0;
+	struct rx_desc *rx_desc;
+
+	debug("** %s()\n", __func__);
+
+	err = usb_bulk_msg(dev->pusb_dev,
+				usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+				(void *)recv_buf,
+				RTL8152_AGG_BUF_SZ,
+				&actual_len,
+				USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", RTL8152_AGG_BUF_SZ,
+	      actual_len, err);
+	if (err != 0) {
+		debug("Rx: failed to receive\n");
+		return -1;
+	}
+	if (actual_len > RTL8152_AGG_BUF_SZ) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -1;
+	}
+
+	while (bytes_process < actual_len) {
+		rx_desc = (struct rx_desc *)(recv_buf + bytes_process);
+		pkt_ptr = recv_buf + sizeof(struct rx_desc) + bytes_process;
+
+		packet_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
+		packet_len -= CRC_SIZE;
+
+		net_process_received_packet(pkt_ptr, packet_len);
+
+		bytes_process +=
+			(packet_len + sizeof(struct rx_desc) + CRC_SIZE);
+
+		if (bytes_process % 8)
+			bytes_process = bytes_process + 8 - (bytes_process % 8);
+	}
+
+	return 0;
+}
+
+static void r8152_halt(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct r8152 *tp = (struct r8152 *)dev->dev_priv;
+
+	debug("** %s()\n", __func__);
+
+	tp->rtl_ops.disable(tp);
+}
+
+static int r8152_write_hwaddr(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct r8152 *tp = (struct r8152 *)dev->dev_priv;
+
+	unsigned char enetaddr[8] = {0};
+
+	memcpy(enetaddr, eth->enetaddr, ETH_ALEN);
+
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+	pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, enetaddr);
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+
+	debug("MAC %pM\n", eth->enetaddr);
+	return 0;
+}
+
+void r8152_eth_before_probe(void)
+{
+	curr_eth_dev = 0;
+}
+
+/* Probe to see if a new device is actually an realtek device */
+int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum,
+		      struct ueth_data *ss)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *iface_desc;
+	int ep_in_found = 0, ep_out_found = 0;
+	struct r8152 *tp;
+	int i;
+
+	/* let's examine the device now */
+	iface = &dev->config.if_desc[ifnum];
+	iface_desc = &dev->config.if_desc[ifnum].desc;
+
+	for (i = 0; i < ARRAY_SIZE(r8152_dongles); i++) {
+		if (dev->descriptor.idVendor == r8152_dongles[i].vendor &&
+		    dev->descriptor.idProduct == r8152_dongles[i].product)
+			/* Found a supported dongle */
+			break;
+	}
+
+	if (i == ARRAY_SIZE(r8152_dongles))
+		return 0;
+
+	memset(ss, 0, sizeof(struct ueth_data));
+
+	/* At this point, we know we've got a live one */
+	debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
+	      dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	/* Initialize the ueth_data structure with some useful info */
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->subclass = iface_desc->bInterfaceSubClass;
+	ss->protocol = iface_desc->bInterfaceProtocol;
+
+	/* alloc driver private */
+	ss->dev_priv = calloc(1, sizeof(struct r8152));
+
+	if (!ss->dev_priv)
+		return 0;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and
+	 * int. We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		/* is it an BULK endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
+
+			if (ep_addr & USB_DIR_IN) {
+				if (!ep_in_found) {
+					ss->ep_in = ep_addr &
+						USB_ENDPOINT_NUMBER_MASK;
+					ep_in_found = 1;
+				}
+			} else {
+				if (!ep_out_found) {
+					ss->ep_out = ep_addr &
+						USB_ENDPOINT_NUMBER_MASK;
+					ep_out_found = 1;
+				}
+			}
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ss->irqinterval = iface->ep_desc[i].bInterval;
+		}
+	}
+
+	debug("Endpoints In %d Out %d Int %d\n",
+	      ss->ep_in, ss->ep_out, ss->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+	    !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+		debug("Problems with device\n");
+		goto error;
+	}
+
+	dev->privptr = (void *)ss;
+
+	tp = ss->dev_priv;
+	tp->udev = dev;
+	tp->intf = iface;
+
+	r8152b_get_version(tp);
+
+	if (rtl_ops_init(tp))
+		goto error;
+
+	tp->rtl_ops.init(tp);
+	tp->rtl_ops.up(tp);
+
+	rtl8152_set_speed(tp, AUTONEG_ENABLE,
+			  tp->supports_gmii ? SPEED_1000 : SPEED_100,
+			  DUPLEX_FULL);
+
+	return 1;
+
+error:
+	cfree(ss->dev_priv);
+	ss->dev_priv = 0;
+	return 0;
+}
+
+int r8152_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+				struct eth_device *eth)
+{
+	if (!eth) {
+		debug("%s: missing parameter.\n", __func__);
+		return 0;
+	}
+
+	sprintf(eth->name, "%s#%d", R8152_BASE_NAME, curr_eth_dev++);
+	eth->init = r8152_init;
+	eth->send = r8152_send;
+	eth->recv = r8152_recv;
+	eth->halt = r8152_halt;
+	eth->write_hwaddr = r8152_write_hwaddr;
+	eth->priv = ss;
+
+	/* Get the MAC address */
+	if (r8152_read_mac(ss->dev_priv, eth->enetaddr) < 0)
+		return 0;
+
+	debug("MAC %pM\n", eth->enetaddr);
+	return 1;
+}
+#endif /* !CONFIG_DM_ETH */
+
+#ifdef CONFIG_DM_ETH
+static int r8152_eth_start(struct udevice *dev)
+{
+	struct r8152 *tp = dev_get_priv(dev);
+
+	debug("** %s (%d)\n", __func__, __LINE__);
+
+	return r8152_init_common(tp);
+}
+
+void r8152_eth_stop(struct udevice *dev)
+{
+	struct r8152 *tp = dev_get_priv(dev);
+
+	debug("** %s (%d)\n", __func__, __LINE__);
+
+	tp->rtl_ops.disable(tp);
+}
+
+int r8152_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct r8152 *tp = dev_get_priv(dev);
+
+	return r8152_send_common(&tp->ueth, packet, length);
+}
+
+int r8152_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct r8152 *tp = dev_get_priv(dev);
+	struct ueth_data *ueth = &tp->ueth;
+	uint8_t *ptr;
+	int ret, len;
+	struct rx_desc *rx_desc;
+	u16 packet_len;
+
+	len = usb_ether_get_rx_bytes(ueth, &ptr);
+	debug("%s: first try, len=%d\n", __func__, len);
+	if (!len) {
+		if (!(flags & ETH_RECV_CHECK_DEVICE))
+			return -EAGAIN;
+		ret = usb_ether_receive(ueth, RTL8152_AGG_BUF_SZ);
+		if (ret)
+			return ret;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: second try, len=%d\n", __func__, len);
+	}
+
+	rx_desc = (struct rx_desc *)ptr;
+	packet_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
+	packet_len -= CRC_SIZE;
+
+	if (packet_len > len - (sizeof(struct rx_desc) + CRC_SIZE)) {
+		debug("Rx: too large packet: %d\n", packet_len);
+		goto err;
+	}
+
+	*packetp = ptr + sizeof(struct rx_desc);
+	return packet_len;
+
+err:
+	usb_ether_advance_rxbuf(ueth, -1);
+	return -ENOSPC;
+}
+
+static int r8152_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct r8152 *tp = dev_get_priv(dev);
+
+	packet_len += sizeof(struct rx_desc) + CRC_SIZE;
+	packet_len = ALIGN(packet_len, 8);
+	usb_ether_advance_rxbuf(&tp->ueth, packet_len);
+
+	return 0;
+}
+
+static int r8152_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct r8152 *tp = dev_get_priv(dev);
+
+	unsigned char enetaddr[8] = { 0 };
+
+	debug("** %s (%d)\n", __func__, __LINE__);
+	memcpy(enetaddr, pdata->enetaddr, ETH_ALEN);
+
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+	pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, enetaddr);
+	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+
+	debug("MAC %pM\n", pdata->enetaddr);
+	return 0;
+}
+
+int r8152_read_rom_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct r8152 *tp = dev_get_priv(dev);
+
+	debug("** %s (%d)\n", __func__, __LINE__);
+	r8152_read_mac(tp, pdata->enetaddr);
+	return 0;
+}
+
+static int r8152_eth_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct r8152 *tp = dev_get_priv(dev);
+	struct ueth_data *ueth = &tp->ueth;
+	int ret;
+
+	tp->udev = udev;
+	r8152_read_mac(tp, pdata->enetaddr);
+
+	r8152b_get_version(tp);
+
+	ret = rtl_ops_init(tp);
+	if (ret)
+		return ret;
+
+	tp->rtl_ops.init(tp);
+	tp->rtl_ops.up(tp);
+
+	rtl8152_set_speed(tp, AUTONEG_ENABLE,
+			  tp->supports_gmii ? SPEED_1000 : SPEED_100,
+			  DUPLEX_FULL);
+
+	return usb_ether_register(dev, ueth, RTL8152_AGG_BUF_SZ);
+}
+
+static const struct eth_ops r8152_eth_ops = {
+	.start	= r8152_eth_start,
+	.send	= r8152_eth_send,
+	.recv	= r8152_eth_recv,
+	.free_pkt = r8152_free_pkt,
+	.stop	= r8152_eth_stop,
+	.write_hwaddr = r8152_write_hwaddr,
+	.read_rom_hwaddr = r8152_read_rom_hwaddr,
+};
+
+U_BOOT_DRIVER(r8152_eth) = {
+	.name	= "r8152_eth",
+	.id	= UCLASS_ETH,
+	.probe = r8152_eth_probe,
+	.ops	= &r8152_eth_ops,
+	.priv_auto	= sizeof(struct r8152),
+	.plat_auto	= sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id r8152_eth_id_table[] = {
+	/* Realtek */
+	{ USB_DEVICE(0x0bda, 0x8050) },
+	{ USB_DEVICE(0x0bda, 0x8152) },
+	{ USB_DEVICE(0x0bda, 0x8153) },
+
+	/* Samsung */
+	{ USB_DEVICE(0x04e8, 0xa101) },
+
+	/* Lenovo */
+	{ USB_DEVICE(0x17ef, 0x304f) },
+	{ USB_DEVICE(0x17ef, 0x3052) },
+	{ USB_DEVICE(0x17ef, 0x3054) },
+	{ USB_DEVICE(0x17ef, 0x3057) },
+	{ USB_DEVICE(0x17ef, 0x7205) },
+	{ USB_DEVICE(0x17ef, 0x720a) },
+	{ USB_DEVICE(0x17ef, 0x720b) },
+	{ USB_DEVICE(0x17ef, 0x720c) },
+
+	/* TP-LINK */
+	{ USB_DEVICE(0x2357, 0x0601) },
+
+	/* Nvidia */
+	{ USB_DEVICE(0x0955, 0x09ff) },
+
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(r8152_eth, r8152_eth_id_table);
+#endif /* CONFIG_DM_ETH */
+
diff --git a/roms/u-boot/drivers/usb/eth/r8152.h b/roms/u-boot/drivers/usb/eth/r8152.h
new file mode 100644
index 000000000..45172c055
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/r8152.h
@@ -0,0 +1,683 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2015 Realtek Semiconductor Corp. All rights reserved.
+ *
+  */
+
+#ifndef _RTL8152_ETH_H
+#define _RTL8152_ETH_H
+
+#include <linux/bitops.h>
+#define R8152_BASE_NAME		"r8152"
+
+#define PLA_IDR			0xc000
+#define PLA_RCR			0xc010
+#define PLA_RMS			0xc016
+#define PLA_RXFIFO_CTRL0	0xc0a0
+#define PLA_RXFIFO_CTRL1	0xc0a4
+#define PLA_RXFIFO_CTRL2	0xc0a8
+#define PLA_DMY_REG0		0xc0b0
+#define PLA_FMC			0xc0b4
+#define PLA_CFG_WOL		0xc0b6
+#define PLA_TEREDO_CFG		0xc0bc
+#define PLA_MAR			0xcd00
+#define PLA_BACKUP		0xd000
+#define PLA_BDC_CR		0xd1a0
+#define PLA_TEREDO_TIMER	0xd2cc
+#define PLA_REALWOW_TIMER	0xd2e8
+#define PLA_EXTRA_STATUS	0xd398
+#define PLA_EFUSE_DATA		0xdd00
+#define PLA_EFUSE_CMD		0xdd02
+#define PLA_LEDSEL		0xdd90
+#define PLA_LED_FEATURE		0xdd92
+#define PLA_PHYAR		0xde00
+#define PLA_BOOT_CTRL		0xe004
+#define PLA_GPHY_INTR_IMR	0xe022
+#define PLA_EEE_CR		0xe040
+#define PLA_EEEP_CR		0xe080
+#define PLA_MAC_PWR_CTRL	0xe0c0
+#define PLA_MAC_PWR_CTRL2	0xe0ca
+#define PLA_MAC_PWR_CTRL3	0xe0cc
+#define PLA_MAC_PWR_CTRL4	0xe0ce
+#define PLA_WDT6_CTRL		0xe428
+#define PLA_TCR0		0xe610
+#define PLA_TCR1		0xe612
+#define PLA_MTPS		0xe615
+#define PLA_TXFIFO_CTRL		0xe618
+#define PLA_RSTTALLY		0xe800
+#define BIST_CTRL		0xe810
+#define PLA_CR			0xe813
+#define PLA_CRWECR		0xe81c
+#define PLA_CONFIG12		0xe81e	/* CONFIG1, CONFIG2 */
+#define PLA_CONFIG34		0xe820	/* CONFIG3, CONFIG4 */
+#define PLA_CONFIG5		0xe822
+#define PLA_PHY_PWR		0xe84c
+#define PLA_OOB_CTRL		0xe84f
+#define PLA_CPCR		0xe854
+#define PLA_MISC_0		0xe858
+#define PLA_MISC_1		0xe85a
+#define PLA_OCP_GPHY_BASE	0xe86c
+#define PLA_TALLYCNT		0xe890
+#define PLA_SFF_STS_7		0xe8de
+#define PLA_PHYSTATUS		0xe908
+#define PLA_BP_BA		0xfc26
+#define PLA_BP_0		0xfc28
+#define PLA_BP_1		0xfc2a
+#define PLA_BP_2		0xfc2c
+#define PLA_BP_3		0xfc2e
+#define PLA_BP_4		0xfc30
+#define PLA_BP_5		0xfc32
+#define PLA_BP_6		0xfc34
+#define PLA_BP_7		0xfc36
+#define PLA_BP_EN		0xfc38
+
+#define USB_USB2PHY		0xb41e
+#define USB_SSPHYLINK2		0xb428
+#define USB_U2P3_CTRL		0xb460
+#define USB_CSR_DUMMY1		0xb464
+#define USB_CSR_DUMMY2		0xb466
+#define USB_DEV_STAT		0xb808
+#define USB_CONNECT_TIMER	0xcbf8
+#define USB_MSC_TIMER		0xcbfc
+#define USB_BURST_SIZE		0xcfc0
+#define USB_FW_FIX_EN1		0xcfcc
+#define USB_LPM_CONFIG		0xcfd8
+#define USB_USB_CTRL		0xd406
+#define USB_PHY_CTRL		0xd408
+#define USB_TX_AGG		0xd40a
+#define USB_RX_BUF_TH		0xd40c
+#define USB_USB_TIMER		0xd428
+#define USB_RX_EARLY_TIMEOUT	0xd42c
+#define USB_RX_EARLY_SIZE	0xd42e
+#define USB_PM_CTRL_STATUS	0xd432	/* RTL8153A */
+#define USB_RX_EXTRA_AGGR_TMR	0xd432	/* RTL8153B */
+#define USB_TX_DMA		0xd434
+#define USB_UPT_RXDMA_OWN	0xd437
+#define USB_TOLERANCE		0xd490
+#define USB_LPM_CTRL		0xd41a
+#define USB_BMU_RESET		0xd4b0
+#define USB_U1U2_TIMER		0xd4da
+#define USB_UPS_CTRL		0xd800
+#define USB_POWER_CUT		0xd80a
+#define USB_MISC_0		0xd81a
+#define USB_AFE_CTRL2		0xd824
+#define USB_UPS_CFG		0xd842
+#define USB_WDT11_CTRL		0xe43c
+#define USB_BP_BA		PLA_BP_BA
+#define USB_BP(n)		(0xfc28 + 2 * (n))
+#define USB_BP_EN		PLA_BP_EN	/* RTL8153A */
+#define USB_BP2_EN		0xfc48
+
+/* OCP Registers */
+#define OCP_ALDPS_CONFIG	0x2010
+#define OCP_EEE_CONFIG1		0x2080
+#define OCP_EEE_CONFIG2		0x2092
+#define OCP_EEE_CONFIG3		0x2094
+#define OCP_BASE_MII		0xa400
+#define OCP_EEE_AR		0xa41a
+#define OCP_EEE_DATA		0xa41c
+#define OCP_PHY_STATUS		0xa420
+#define OCP_NCTL_CFG		0xa42c
+#define OCP_POWER_CFG		0xa430
+#define OCP_EEE_CFG		0xa432
+#define OCP_SRAM_ADDR		0xa436
+#define OCP_SRAM_DATA		0xa438
+#define OCP_DOWN_SPEED		0xa442
+#define OCP_EEE_ABLE		0xa5c4
+#define OCP_EEE_ADV		0xa5d0
+#define OCP_EEE_LPABLE		0xa5d2
+#define OCP_PHY_STATE		0xa708		/* nway state for 8153 */
+#define OCP_ADC_IOFFSET		0xbcfc
+#define OCP_ADC_CFG		0xbc06
+
+/* SRAM Register */
+#define SRAM_GREEN_CFG		0x8011
+#define SRAM_LPF_CFG		0x8012
+#define SRAM_10M_AMP1		0x8080
+#define SRAM_10M_AMP2		0x8082
+#define SRAM_IMPEDANCE		0x8084
+
+/* PLA_RCR */
+#define RCR_AAP			0x00000001
+#define RCR_APM			0x00000002
+#define RCR_AM			0x00000004
+#define RCR_AB			0x00000008
+#define RCR_ACPT_ALL		(RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
+
+/* PLA_RXFIFO_CTRL0 */
+#define RXFIFO_THR1_NORMAL	0x00080002
+#define RXFIFO_THR1_OOB		0x01800003
+
+/* PLA_RXFIFO_CTRL1 */
+#define RXFIFO_THR2_FULL	0x00000060
+#define RXFIFO_THR2_HIGH	0x00000038
+#define RXFIFO_THR2_OOB		0x0000004a
+#define RXFIFO_THR2_NORMAL	0x00a0
+
+/* PLA_RXFIFO_CTRL2 */
+#define RXFIFO_THR3_FULL	0x00000078
+#define RXFIFO_THR3_HIGH	0x00000048
+#define RXFIFO_THR3_OOB		0x0000005a
+#define RXFIFO_THR3_NORMAL	0x0110
+
+/* PLA_TXFIFO_CTRL */
+#define TXFIFO_THR_NORMAL	0x00400008
+#define TXFIFO_THR_NORMAL2	0x01000008
+
+/* PLA_DMY_REG0 */
+#define ECM_ALDPS		0x0002
+
+/* PLA_FMC */
+#define FMC_FCR_MCU_EN		0x0001
+
+/* PLA_EEEP_CR */
+#define EEEP_CR_EEEP_TX		0x0002
+
+/* PLA_WDT6_CTRL */
+#define WDT6_SET_MODE		0x0010
+
+/* PLA_TCR0 */
+#define TCR0_TX_EMPTY		0x0800
+#define TCR0_AUTO_FIFO		0x0080
+
+/* PLA_TCR1 */
+#define VERSION_MASK		0x7cf0
+
+/* PLA_MTPS */
+#define MTPS_JUMBO		(12 * 1024 / 64)
+#define MTPS_DEFAULT		(6 * 1024 / 64)
+
+/* PLA_RSTTALLY */
+#define TALLY_RESET		0x0001
+
+/* PLA_CR */
+#define PLA_CR_RST		0x10
+#define PLA_CR_RE		0x08
+#define PLA_CR_TE		0x04
+
+/* PLA_BIST_CTRL */
+#define BIST_CTRL_SW_RESET (0x10 << 24)
+
+/* PLA_CRWECR */
+#define CRWECR_NORAML		0x00
+#define CRWECR_CONFIG		0xc0
+
+/* PLA_OOB_CTRL */
+#define NOW_IS_OOB		0x80
+#define TXFIFO_EMPTY		0x20
+#define RXFIFO_EMPTY		0x10
+#define LINK_LIST_READY		0x02
+#define DIS_MCU_CLROOB		0x01
+#define FIFO_EMPTY		(TXFIFO_EMPTY | RXFIFO_EMPTY)
+
+/* PLA_PHY_PWR */
+#define PLA_PHY_PWR_LLR	(LINK_LIST_READY << 24)
+#define PLA_PHY_PWR_TXEMP	(TXFIFO_EMPTY << 24)
+#define TEST_IO_OFF		BIT(4)
+
+/* PLA_MISC_1 */
+#define RXDY_GATED_EN		0x0008
+
+/* PLA_SFF_STS_7 */
+#define RE_INIT_LL		0x8000
+#define MCU_BORW_EN		0x4000
+
+/* PLA_CPCR */
+#define CPCR_RX_VLAN		0x0040
+
+/* PLA_CFG_WOL */
+#define MAGIC_EN		0x0001
+
+/* PLA_TEREDO_CFG */
+#define TEREDO_SEL		0x8000
+#define TEREDO_WAKE_MASK	0x7f00
+#define TEREDO_RS_EVENT_MASK	0x00fe
+#define OOB_TEREDO_EN		0x0001
+
+/* PLA_BDC_CR */
+#define ALDPS_PROXY_MODE	0x0001
+
+/* PLA_EFUSE_CMD */
+#define EFUSE_READ_CMD		BIT(15)
+#define EFUSE_DATA_BIT16	BIT(7)
+
+/* PLA_CONFIG34 */
+#define LINK_ON_WAKE_EN		0x0010
+#define LINK_OFF_WAKE_EN	0x0008
+
+/* PLA_CONFIG5 */
+#define BWF_EN			0x0040
+#define MWF_EN			0x0020
+#define UWF_EN			0x0010
+#define LAN_WAKE_EN		0x0002
+
+/* PLA_LED_FEATURE */
+#define LED_MODE_MASK		0x0700
+
+/* PLA_PHY_PWR */
+#define TX_10M_IDLE_EN		0x0080
+#define PFM_PWM_SWITCH		0x0040
+
+/* PLA_MAC_PWR_CTRL */
+#define D3_CLK_GATED_EN		0x00004000
+#define MCU_CLK_RATIO		0x07010f07
+#define MCU_CLK_RATIO_MASK	0x0f0f0f0f
+#define ALDPS_SPDWN_RATIO	0x0f87
+
+/* PLA_MAC_PWR_CTRL2 */
+#define EEE_SPDWN_RATIO		0x8007
+#define MAC_CLK_SPDWN_EN	BIT(15)
+
+/* PLA_MAC_PWR_CTRL3 */
+#define PLA_MCU_SPDWN_EN	BIT(14)
+#define PKT_AVAIL_SPDWN_EN	0x0100
+#define SUSPEND_SPDWN_EN	0x0004
+#define U1U2_SPDWN_EN		0x0002
+#define L1_SPDWN_EN		0x0001
+
+/* PLA_MAC_PWR_CTRL4 */
+#define PWRSAVE_SPDWN_EN	0x1000
+#define RXDV_SPDWN_EN		0x0800
+#define TX10MIDLE_EN		0x0100
+#define TP100_SPDWN_EN		0x0020
+#define TP500_SPDWN_EN		0x0010
+#define TP1000_SPDWN_EN		0x0008
+#define EEE_SPDWN_EN		0x0001
+
+/* PLA_GPHY_INTR_IMR */
+#define GPHY_STS_MSK		0x0001
+#define SPEED_DOWN_MSK		0x0002
+#define SPDWN_RXDV_MSK		0x0004
+#define SPDWN_LINKCHG_MSK	0x0008
+
+/* PLA_PHYAR */
+#define PHYAR_FLAG		0x80000000
+
+/* PLA_EEE_CR */
+#define EEE_RX_EN		0x0001
+#define EEE_TX_EN		0x0002
+
+/* PLA_BOOT_CTRL */
+#define AUTOLOAD_DONE		0x0002
+
+/* PLA_EXTRA_STATUS */
+#define U3P3_CHECK_EN		BIT(7)
+
+/* USB_USB2PHY */
+#define USB2PHY_SUSPEND		0x0001
+#define USB2PHY_L1		0x0002
+
+/* USB_SSPHYLINK2 */
+#define pwd_dn_scale_mask	0x3ffe
+#define pwd_dn_scale(x)		((x) << 1)
+
+/* USB_CSR_DUMMY1 */
+#define DYNAMIC_BURST		0x0001
+
+/* USB_CSR_DUMMY2 */
+#define EP4_FULL_FC		0x0001
+
+/* USB_DEV_STAT */
+#define STAT_SPEED_MASK		0x0006
+#define STAT_SPEED_HIGH		0x0000
+#define STAT_SPEED_FULL		0x0002
+
+/* USB_FW_FIX_EN1 */
+#define FW_IP_RESET_EN		BIT(9)
+
+/* USB_LPM_CONFIG */
+#define LPM_U1U2_EN		BIT(0)
+
+/* USB_TX_AGG */
+#define TX_AGG_MAX_THRESHOLD	0x03
+
+/* USB_RX_BUF_TH */
+#define RX_THR_SUPPER		0x0c350180
+#define RX_THR_HIGH		0x7a120180
+#define RX_THR_SLOW		0xffff0180
+
+/* USB_RX_EARLY_TIMEOUT */
+#define RX_AUXILIARY_TIMER	1264
+
+/* USB_TX_DMA */
+#define TEST_MODE_DISABLE	0x00000001
+#define TX_SIZE_ADJUST1		0x00000100
+
+/* USB_BMU_RESET */
+#define BMU_RESET_EP_IN		0x01
+#define BMU_RESET_EP_OUT	0x02
+
+/* USB_UPT_RXDMA_OWN */
+#define OWN_UPDATE		BIT(0)
+#define OWN_CLEAR		BIT(1)
+
+/* USB_UPS_CTRL */
+#define POWER_CUT		0x0100
+
+/* USB_PM_CTRL_STATUS */
+#define RESUME_INDICATE		0x0001
+
+/* USB_USB_CTRL */
+#define RX_AGG_DISABLE		0x0010
+#define RX_ZERO_EN		0x0080
+
+/* USB_U2P3_CTRL */
+#define U2P3_ENABLE		0x0001
+
+/* USB_POWER_CUT */
+#define PWR_EN			0x0001
+#define PHASE2_EN		0x0008
+
+/* USB_MISC_0 */
+#define PCUT_STATUS		0x0001
+
+/* USB_RX_EARLY_TIMEOUT */
+#define COALESCE_SUPER		 85000U
+#define COALESCE_HIGH		250000U
+#define COALESCE_SLOW		524280U
+
+/* USB_WDT11_CTRL */
+#define TIMER11_EN		0x0001
+
+/* USB_LPM_CTRL */
+/* bit 4 ~ 5: fifo empty boundary */
+#define FIFO_EMPTY_1FB		0x30	/* 0x1fb * 64 = 32448 bytes */
+/* bit 2 ~ 3: LMP timer */
+#define LPM_TIMER_MASK		0x0c
+#define LPM_TIMER_500MS		0x04	/* 500 ms */
+#define LPM_TIMER_500US		0x0c	/* 500 us */
+#define ROK_EXIT_LPM		0x02
+
+/* USB_AFE_CTRL2 */
+#define SEN_VAL_MASK		0xf800
+#define SEN_VAL_NORMAL		0xa000
+#define SEL_RXIDLE		0x0100
+
+/* USB_UPS_CFG */
+#define SAW_CNT_1MS_MASK	0x0fff
+
+/* OCP_ALDPS_CONFIG */
+#define ENPWRSAVE		0x8000
+#define ENPDNPS			0x0200
+#define LINKENA			0x0100
+#define DIS_SDSAVE		0x0010
+
+/* OCP_PHY_STATUS */
+#define PHY_STAT_MASK		0x0007
+#define PHY_STAT_LAN_ON		3
+#define PHY_STAT_PWRDN		5
+
+/* OCP_NCTL_CFG */
+#define PGA_RETURN_EN		BIT(1)
+
+/* OCP_POWER_CFG */
+#define EEE_CLKDIV_EN		0x8000
+#define EN_ALDPS		0x0004
+#define EN_10M_PLLOFF		0x0001
+
+/* OCP_EEE_CONFIG1 */
+#define RG_TXLPI_MSK_HFDUP	0x8000
+#define RG_MATCLR_EN		0x4000
+#define EEE_10_CAP		0x2000
+#define EEE_NWAY_EN		0x1000
+#define TX_QUIET_EN		0x0200
+#define RX_QUIET_EN		0x0100
+#define sd_rise_time_mask	0x0070
+#define sd_rise_time(x)		(min((x), 7) << 4)	/* bit 4 ~ 6 */
+#define RG_RXLPI_MSK_HFDUP	0x0008
+#define SDFALLTIME		0x0007	/* bit 0 ~ 2 */
+
+/* OCP_EEE_CONFIG2 */
+#define RG_LPIHYS_NUM		0x7000	/* bit 12 ~ 15 */
+#define RG_DACQUIET_EN		0x0400
+#define RG_LDVQUIET_EN		0x0200
+#define RG_CKRSEL		0x0020
+#define RG_EEEPRG_EN		0x0010
+
+/* OCP_EEE_CONFIG3 */
+#define fast_snr_mask		0xff80
+#define fast_snr(x)		(min((x), 0x1ff) << 7)	/* bit 7 ~ 15 */
+#define RG_LFS_SEL		0x0060	/* bit 6 ~ 5 */
+#define MSK_PH			0x0006	/* bit 0 ~ 3 */
+
+/* OCP_EEE_AR */
+/* bit[15:14] function */
+#define FUN_ADDR		0x0000
+#define FUN_DATA		0x4000
+/* bit[4:0] device addr */
+
+/* OCP_EEE_CFG */
+#define CTAP_SHORT_EN		0x0040
+#define EEE10_EN		0x0010
+
+/* OCP_DOWN_SPEED */
+#define EN_10M_BGOFF		0x0080
+
+/* OCP_PHY_STATE */
+#define TXDIS_STATE		0x01
+#define ABD_STATE		0x02
+
+/* OCP_ADC_CFG */
+#define CKADSEL_L		0x0100
+#define ADC_EN			0x0080
+#define EN_EMI_L		0x0040
+
+/* SRAM_GREEN_CFG */
+#define GREEN_ETH_EN		BIT(15)
+#define R_TUNE_EN		BIT(11)
+
+/* SRAM_LPF_CFG */
+#define LPF_AUTO_TUNE		0x8000
+
+/* SRAM_10M_AMP1 */
+#define GDAC_IB_UPALL		0x0008
+
+/* SRAM_10M_AMP2 */
+#define AMP_DN			0x0200
+
+/* SRAM_IMPEDANCE */
+#define RX_DRIVING_MASK		0x6000
+
+#define RTL8152_MAX_TX		4
+#define RTL8152_MAX_RX		10
+#define INTBUFSIZE		2
+#define CRC_SIZE		4
+#define TX_ALIGN		4
+#define RX_ALIGN		8
+
+#define INTR_LINK		0x0004
+
+#define RTL8152_REQT_READ	0xc0
+#define RTL8152_REQT_WRITE	0x40
+#define RTL8152_REQ_GET_REGS	0x05
+#define RTL8152_REQ_SET_REGS	0x05
+
+#define BYTE_EN_DWORD		0xff
+#define BYTE_EN_WORD		0x33
+#define BYTE_EN_BYTE		0x11
+#define BYTE_EN_SIX_BYTES	0x3f
+#define BYTE_EN_START_MASK	0x0f
+#define BYTE_EN_END_MASK	0xf0
+
+#define RTL8152_ETH_FRAME_LEN	1514
+#define RTL8152_AGG_BUF_SZ	2048
+
+#define RTL8152_RMS		(RTL8152_ETH_FRAME_LEN + CRC_SIZE)
+#define RTL8153_RMS		(RTL8152_ETH_FRAME_LEN + CRC_SIZE)
+#define RTL8152_TX_TIMEOUT	(5 * HZ)
+
+#define MCU_TYPE_PLA			0x0100
+#define MCU_TYPE_USB			0x0000
+
+/* The forced speed, 10Mb, 100Mb, gigabit. */
+#define SPEED_10                10
+#define SPEED_100               100
+#define SPEED_1000              1000
+
+#define SPEED_UNKNOWN           -1
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF             0x00
+#define DUPLEX_FULL             0x01
+#define DUPLEX_UNKNOWN          0xff
+
+/* Enable or disable autonegotiation. */
+#define AUTONEG_DISABLE         0x00
+#define AUTONEG_ENABLE          0x01
+
+/* Generic MII registers. */
+#define MII_BMCR                0x00    /* Basic mode control register */
+#define MII_BMSR                0x01    /* Basic mode status register  */
+#define MII_PHYSID1             0x02    /* PHYS ID 1                   */
+#define MII_PHYSID2             0x03    /* PHYS ID 2                   */
+#define MII_ADVERTISE           0x04    /* Advertisement control reg   */
+#define MII_LPA                 0x05    /* Link partner ability reg    */
+#define MII_EXPANSION           0x06    /* Expansion register          */
+#define MII_CTRL1000            0x09    /* 1000BASE-T control          */
+#define MII_STAT1000            0x0a    /* 1000BASE-T status           */
+#define MII_MMD_CTRL            0x0d    /* MMD Access Control Register */
+#define MII_MMD_DATA            0x0e    /* MMD Access Data Register */
+#define MII_ESTATUS             0x0f    /* Extended Status             */
+#define MII_DCOUNTER            0x12    /* Disconnect counter          */
+#define MII_FCSCOUNTER          0x13    /* False carrier counter       */
+#define MII_NWAYTEST            0x14    /* N-way auto-neg test reg     */
+#define MII_RERRCOUNTER         0x15    /* Receive error counter       */
+#define MII_SREVISION           0x16    /* Silicon revision            */
+#define MII_RESV1               0x17    /* Reserved...                 */
+#define MII_LBRERROR            0x18    /* Lpback, rx, bypass error    */
+#define MII_PHYADDR             0x19    /* PHY address                 */
+#define MII_RESV2               0x1a    /* Reserved...                 */
+#define MII_TPISTATUS           0x1b    /* TPI status for 10mbps       */
+#define MII_NCONFIG             0x1c    /* Network interface config    */
+
+#define TIMEOUT_RESOLUTION	50
+#define PHY_CONNECT_TIMEOUT     5000
+#define USB_BULK_SEND_TIMEOUT   5000
+#define USB_BULK_RECV_TIMEOUT   5000
+#define R8152_WAIT_TIMEOUT	2000
+
+struct rx_desc {
+	__le32 opts1;
+#define RD_CRC				BIT(15)
+#define RX_LEN_MASK			0x7fff
+
+	__le32 opts2;
+#define RD_UDP_CS			BIT(23)
+#define RD_TCP_CS			BIT(22)
+#define RD_IPV6_CS			BIT(20)
+#define RD_IPV4_CS			BIT(19)
+
+	__le32 opts3;
+#define IPF				BIT(23) /* IP checksum fail */
+#define UDPF				BIT(22) /* UDP checksum fail */
+#define TCPF				BIT(21) /* TCP checksum fail */
+#define RX_VLAN_TAG			BIT(16)
+
+	__le32 opts4;
+	__le32 opts5;
+	__le32 opts6;
+};
+
+struct tx_desc {
+	__le32 opts1;
+#define TX_FS			BIT(31) /* First segment of a packet */
+#define TX_LS			BIT(30) /* Final segment of a packet */
+#define LGSEND			BIT(29)
+#define GTSENDV4		BIT(28)
+#define GTSENDV6		BIT(27)
+#define GTTCPHO_SHIFT		18
+#define GTTCPHO_MAX		0x7fU
+#define TX_LEN_MAX		0x3ffffU
+
+	__le32 opts2;
+#define UDP_CS			BIT(31) /* Calculate UDP/IP checksum */
+#define TCP_CS			BIT(30) /* Calculate TCP/IP checksum */
+#define IPV4_CS			BIT(29) /* Calculate IPv4 checksum */
+#define IPV6_CS			BIT(28) /* Calculate IPv6 checksum */
+#define MSS_SHIFT		17
+#define MSS_MAX			0x7ffU
+#define TCPHO_SHIFT		17
+#define TCPHO_MAX		0x7ffU
+#define TX_VLAN_TAG		BIT(16)
+};
+
+enum rtl_version {
+	RTL_VER_UNKNOWN = 0,
+	RTL_VER_01,
+	RTL_VER_02,
+	RTL_VER_03,
+	RTL_VER_04,
+	RTL_VER_05,
+	RTL_VER_06,
+	RTL_VER_07,
+	RTL_VER_08,
+	RTL_VER_09,
+	RTL_VER_MAX
+};
+
+enum rtl_register_content {
+	_1000bps	= 0x10,
+	_100bps		= 0x08,
+	_10bps		= 0x04,
+	LINK_STATUS	= 0x02,
+	FULL_DUP	= 0x01,
+};
+
+struct r8152 {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	bool supports_gmii;
+
+	struct rtl_ops {
+		void (*init)(struct r8152 *);
+		int (*enable)(struct r8152 *);
+		void (*disable)(struct r8152 *);
+		void (*up)(struct r8152 *);
+		void (*down)(struct r8152 *);
+		void (*unload)(struct r8152 *);
+	} rtl_ops;
+
+	u32 coalesce;
+	u16 ocp_base;
+
+	u8 version;
+
+#ifdef CONFIG_DM_ETH
+	struct ueth_data ueth;
+#endif
+};
+
+int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
+		      u16 size, void *data, u16 type);
+int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
+		     void *data, u16 type);
+
+int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data);
+int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
+		  u16 size, void *data);
+
+int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data);
+int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
+		  u16 size, void *data);
+
+u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index);
+void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data);
+
+u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index);
+void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data);
+
+u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index);
+void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data);
+
+u16 ocp_reg_read(struct r8152 *tp, u16 addr);
+void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data);
+
+void sram_write(struct r8152 *tp, u16 addr, u16 data);
+
+int r8152_wait_for_bit(struct r8152 *tp, bool ocp_reg, u16 type, u16 index,
+		       const u32 mask, bool set, unsigned int timeout);
+
+void r8152b_firmware(struct r8152 *tp);
+void r8153_firmware(struct r8152 *tp);
+void r8153b_firmware(struct r8152 *tp);
+#endif
diff --git a/roms/u-boot/drivers/usb/eth/r8152_fw.c b/roms/u-boot/drivers/usb/eth/r8152_fw.c
new file mode 100644
index 000000000..a41abed30
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/r8152_fw.c
@@ -0,0 +1,1194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015 Realtek Semiconductor Corp. All rights reserved.
+ *
+  */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include "usb_ether.h"
+#include "r8152.h"
+
+static u8 r8152b_pla_patch_a[] = {
+	0x08, 0xe0, 0x40, 0xe0, 0x78, 0xe0, 0x85, 0xe0,
+	0x5d, 0xe1, 0xa1, 0xe1, 0xa3, 0xe1, 0xab, 0xe1,
+	0x31, 0xc3, 0x60, 0x72, 0xa0, 0x49, 0x10, 0xf0,
+	0xa4, 0x49, 0x0e, 0xf0, 0x2c, 0xc3, 0x62, 0x72,
+	0x26, 0x70, 0x80, 0x49, 0x05, 0xf0, 0x2f, 0x48,
+	0x62, 0x9a, 0x24, 0x70, 0x60, 0x98, 0x24, 0xc3,
+	0x60, 0x99, 0x23, 0xc3, 0x00, 0xbb, 0x2c, 0x75,
+	0xdc, 0x21, 0xbc, 0x25, 0x04, 0x13, 0x0a, 0xf0,
+	0x03, 0x13, 0x08, 0xf0, 0x02, 0x13, 0x06, 0xf0,
+	0x01, 0x13, 0x04, 0xf0, 0x08, 0x13, 0x02, 0xf0,
+	0x03, 0xe0, 0xd4, 0x49, 0x04, 0xf1, 0x14, 0xc2,
+	0x12, 0xc3, 0x00, 0xbb, 0x12, 0xc3, 0x60, 0x75,
+	0xd0, 0x49, 0x05, 0xf1, 0x50, 0x48, 0x60, 0x9d,
+	0x09, 0xc6, 0x00, 0xbe, 0xd0, 0x48, 0x60, 0x9d,
+	0xf3, 0xe7, 0xc2, 0xc0, 0x38, 0xd2, 0xc6, 0xd2,
+	0x84, 0x17, 0xa2, 0x13, 0x0c, 0x17, 0xbc, 0xc0,
+	0xa2, 0xd1, 0x33, 0xc5, 0xa0, 0x74, 0xc0, 0x49,
+	0x1f, 0xf0, 0x30, 0xc5, 0xa0, 0x73, 0x00, 0x13,
+	0x04, 0xf1, 0xa2, 0x73, 0x00, 0x13, 0x14, 0xf0,
+	0x28, 0xc5, 0xa0, 0x74, 0xc8, 0x49, 0x1b, 0xf1,
+	0x26, 0xc5, 0xa0, 0x76, 0xa2, 0x74, 0x01, 0x06,
+	0x20, 0x37, 0xa0, 0x9e, 0xa2, 0x9c, 0x1e, 0xc5,
+	0xa2, 0x73, 0x23, 0x40, 0x10, 0xf8, 0x04, 0xf3,
+	0xa0, 0x73, 0x33, 0x40, 0x0c, 0xf8, 0x15, 0xc5,
+	0xa0, 0x74, 0x41, 0x48, 0xa0, 0x9c, 0x14, 0xc5,
+	0xa0, 0x76, 0x62, 0x48, 0xe0, 0x48, 0xa0, 0x9e,
+	0x10, 0xc6, 0x00, 0xbe, 0x0a, 0xc5, 0xa0, 0x74,
+	0x48, 0x48, 0xa0, 0x9c, 0x0b, 0xc5, 0x20, 0x1e,
+	0xa0, 0x9e, 0xe5, 0x48, 0xa0, 0x9e, 0xf0, 0xe7,
+	0xbc, 0xc0, 0xc8, 0xd2, 0xcc, 0xd2, 0x28, 0xe4,
+	0x22, 0x02, 0xf0, 0xc0, 0x0b, 0xc0, 0x00, 0x71,
+	0x0a, 0xc0, 0x00, 0x72, 0xa0, 0x49, 0x04, 0xf0,
+	0xa4, 0x49, 0x02, 0xf0, 0x93, 0x48, 0x04, 0xc0,
+	0x00, 0xb8, 0x00, 0xe4, 0xc2, 0xc0, 0x8c, 0x09,
+	0x14, 0xc2, 0x40, 0x73, 0xba, 0x48, 0x40, 0x9b,
+	0x11, 0xc2, 0x40, 0x73, 0xb0, 0x49, 0x17, 0xf0,
+	0xbf, 0x49, 0x03, 0xf1, 0x09, 0xc5, 0x00, 0xbd,
+	0xb1, 0x49, 0x11, 0xf0, 0xb1, 0x48, 0x40, 0x9b,
+	0x02, 0xc2, 0x00, 0xba, 0x82, 0x18, 0x00, 0xa0,
+	0x1e, 0xfc, 0xbc, 0xc0, 0xf0, 0xc0, 0xde, 0xe8,
+	0x00, 0x80, 0x00, 0x60, 0x2c, 0x75, 0xd4, 0x49,
+	0x12, 0xf1, 0x29, 0xe0, 0xf8, 0xc2, 0x46, 0x71,
+	0xf7, 0xc2, 0x40, 0x73, 0xbe, 0x49, 0x03, 0xf1,
+	0xf5, 0xc7, 0x02, 0xe0, 0xf2, 0xc7, 0x4f, 0x30,
+	0x26, 0x62, 0xa1, 0x49, 0xf0, 0xf1, 0x22, 0x72,
+	0xa0, 0x49, 0xed, 0xf1, 0x25, 0x25, 0x18, 0x1f,
+	0x97, 0x30, 0x91, 0x30, 0x36, 0x9a, 0x2c, 0x75,
+	0x32, 0xc3, 0x60, 0x73, 0xb1, 0x49, 0x0d, 0xf1,
+	0xdc, 0x21, 0xbc, 0x25, 0x27, 0xc6, 0xc0, 0x77,
+	0x04, 0x13, 0x18, 0xf0, 0x03, 0x13, 0x19, 0xf0,
+	0x02, 0x13, 0x1a, 0xf0, 0x01, 0x13, 0x1b, 0xf0,
+	0xd4, 0x49, 0x03, 0xf1, 0x1c, 0xc5, 0x00, 0xbd,
+	0xcd, 0xc6, 0xc6, 0x67, 0x2e, 0x75, 0xd7, 0x22,
+	0xdd, 0x26, 0x05, 0x15, 0x1a, 0xf0, 0x14, 0xc6,
+	0x00, 0xbe, 0x13, 0xc5, 0x00, 0xbd, 0x12, 0xc5,
+	0x00, 0xbd, 0xf1, 0x49, 0xfb, 0xf1, 0xef, 0xe7,
+	0xf4, 0x49, 0xfa, 0xf1, 0xec, 0xe7, 0xf3, 0x49,
+	0xf7, 0xf1, 0xe9, 0xe7, 0xf2, 0x49, 0xf4, 0xf1,
+	0xe6, 0xe7, 0xb6, 0xc0, 0x6a, 0x14, 0xac, 0x13,
+	0xd6, 0x13, 0xfa, 0x14, 0xa0, 0xd1, 0x00, 0x00,
+	0xc0, 0x75, 0xd0, 0x49, 0x46, 0xf0, 0x26, 0x72,
+	0xa7, 0x49, 0x43, 0xf0, 0x22, 0x72, 0x25, 0x25,
+	0x20, 0x1f, 0x97, 0x30, 0x91, 0x30, 0x40, 0x73,
+	0xf3, 0xc4, 0x1c, 0x40, 0x04, 0xf0, 0xd7, 0x49,
+	0x05, 0xf1, 0x37, 0xe0, 0x53, 0x48, 0xc0, 0x9d,
+	0x08, 0x02, 0x40, 0x66, 0x64, 0x27, 0x06, 0x16,
+	0x30, 0xf1, 0x46, 0x63, 0x3b, 0x13, 0x2d, 0xf1,
+	0x34, 0x9b, 0x18, 0x1b, 0x93, 0x30, 0x2b, 0xc3,
+	0x10, 0x1c, 0x2b, 0xe8, 0x01, 0x14, 0x25, 0xf1,
+	0x00, 0x1d, 0x26, 0x1a, 0x8a, 0x30, 0x22, 0x73,
+	0xb5, 0x25, 0x0e, 0x0b, 0x00, 0x1c, 0x2c, 0xe8,
+	0x1f, 0xc7, 0x27, 0x40, 0x1a, 0xf1, 0x38, 0xe8,
+	0x32, 0x1f, 0x8f, 0x30, 0x08, 0x1b, 0x24, 0xe8,
+	0x36, 0x72, 0x46, 0x77, 0x00, 0x17, 0x0d, 0xf0,
+	0x13, 0xc3, 0x1f, 0x40, 0x03, 0xf1, 0x00, 0x1f,
+	0x46, 0x9f, 0x44, 0x77, 0x9f, 0x44, 0x5f, 0x44,
+	0x17, 0xe8, 0x0a, 0xc7, 0x27, 0x40, 0x05, 0xf1,
+	0x02, 0xc3, 0x00, 0xbb, 0x50, 0x1a, 0x06, 0x1a,
+	0xff, 0xc7, 0x00, 0xbf, 0xb8, 0xcd, 0xff, 0xff,
+	0x02, 0x0c, 0x54, 0xa5, 0xdc, 0xa5, 0x2f, 0x40,
+	0x05, 0xf1, 0x00, 0x14, 0xfa, 0xf1, 0x01, 0x1c,
+	0x02, 0xe0, 0x00, 0x1c, 0x80, 0xff, 0xb0, 0x49,
+	0x04, 0xf0, 0x01, 0x0b, 0xd3, 0xa1, 0x03, 0xe0,
+	0x02, 0x0b, 0xd3, 0xa5, 0x27, 0x31, 0x20, 0x37,
+	0x02, 0x0b, 0xd3, 0xa5, 0x27, 0x31, 0x20, 0x37,
+	0x00, 0x13, 0xfb, 0xf1, 0x80, 0xff, 0x22, 0x73,
+	0xb5, 0x25, 0x18, 0x1e, 0xde, 0x30, 0xd9, 0x30,
+	0x64, 0x72, 0x11, 0x1e, 0x68, 0x23, 0x16, 0x31,
+	0x80, 0xff, 0xd4, 0x49, 0x28, 0xf0, 0x02, 0xb4,
+	0x2a, 0xc4, 0x00, 0x1d, 0x2e, 0xe8, 0xe0, 0x73,
+	0xb9, 0x21, 0xbd, 0x25, 0x04, 0x13, 0x02, 0xf0,
+	0x1a, 0xe0, 0x22, 0xc4, 0x23, 0xc3, 0x2f, 0xe8,
+	0x23, 0xc3, 0x2d, 0xe8, 0x00, 0x1d, 0x21, 0xe8,
+	0xe2, 0x73, 0xbb, 0x49, 0xfc, 0xf0, 0xe0, 0x73,
+	0xb7, 0x48, 0x03, 0xb4, 0x81, 0x1d, 0x19, 0xe8,
+	0x40, 0x1a, 0x84, 0x1d, 0x16, 0xe8, 0x12, 0xc3,
+	0x1e, 0xe8, 0x03, 0xb0, 0x81, 0x1d, 0x11, 0xe8,
+	0x0e, 0xc3, 0x19, 0xe8, 0x02, 0xb0, 0x06, 0xc7,
+	0x04, 0x1e, 0xe0, 0x9e, 0x02, 0xc6, 0x00, 0xbe,
+	0x22, 0x02, 0x20, 0xe4, 0x04, 0xb8, 0x34, 0xb0,
+	0x00, 0x02, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x0c,
+	0x09, 0xc7, 0xe0, 0x9b, 0xe2, 0x9a, 0xe4, 0x9c,
+	0xe6, 0x8d, 0xe6, 0x76, 0xef, 0x49, 0xfe, 0xf1,
+	0x80, 0xff, 0x08, 0xea, 0x82, 0x1d, 0xf5, 0xef,
+	0x00, 0x1a, 0x88, 0x1d, 0xf2, 0xef, 0xed, 0xc2,
+	0xf0, 0xef, 0x80, 0xff, 0x02, 0xc6, 0x00, 0xbe,
+	0x46, 0x06, 0x08, 0xc2, 0x40, 0x73, 0x3a, 0x48,
+	0x40, 0x9b, 0x06, 0xff, 0x02, 0xc6, 0x00, 0xbe,
+	0x86, 0x17, 0x1e, 0xfc, 0x36, 0xf0, 0x08, 0x1c,
+	0xea, 0x8c, 0xe3, 0x64, 0xc7, 0x49, 0x25, 0xf1,
+	0xe0, 0x75, 0xff, 0x1b, 0xeb, 0x47, 0xff, 0x1b,
+	0x6b, 0x47, 0xe0, 0x9d, 0x15, 0xc3, 0x60, 0x75,
+	0xd8, 0x49, 0x04, 0xf0, 0x81, 0x1d, 0xe2, 0x8d,
+	0x05, 0xe0, 0xe2, 0x63, 0x81, 0x1d, 0xdd, 0x47,
+	0xe2, 0x8b, 0x0b, 0xc3, 0x00, 0x1d, 0x61, 0x8d,
+	0x3c, 0x03, 0x60, 0x75, 0xd8, 0x49, 0x06, 0xf1,
+	0xdf, 0x48, 0x61, 0x95, 0x16, 0xe0, 0x4e, 0xe8,
+	0x12, 0xe8, 0x21, 0xc5, 0xa0, 0x73, 0xb0, 0x49,
+	0x03, 0xf0, 0x31, 0x48, 0xa0, 0x9b, 0x0d, 0xe0,
+	0xc0, 0x49, 0x0b, 0xf1, 0xe2, 0x63, 0x7e, 0x1d,
+	0xdd, 0x46, 0xe2, 0x8b, 0xe0, 0x75, 0x83, 0x1b,
+	0xeb, 0x46, 0xfe, 0x1b, 0x6b, 0x46, 0xe0, 0x9d,
+	0xe4, 0x49, 0x11, 0xf0, 0x10, 0x1d, 0xea, 0x8d,
+	0xe3, 0x64, 0xc6, 0x49, 0x09, 0xf1, 0x07, 0xc5,
+	0xa0, 0x73, 0xb1, 0x48, 0xa0, 0x9b, 0x02, 0xc5,
+	0x00, 0xbd, 0xe6, 0x04, 0xa0, 0xd1, 0x02, 0xc5,
+	0x00, 0xbd, 0xfe, 0x04, 0x02, 0xc5, 0x00, 0xbd,
+	0x30, 0x05, 0x00, 0x00 };
+
+static u16 r8152b_ram_code1[] = {
+	0x9700, 0x7fe0, 0x4c00, 0x4007, 0x4400, 0x4800, 0x7c1f, 0x4c00,
+	0x5310, 0x6000, 0x7c07, 0x6800, 0x673e, 0x0000, 0x0000, 0x571f,
+	0x5ffb, 0xaa05, 0x5b58, 0x7d80, 0x6100, 0x3019, 0x5b64, 0x7d80,
+	0x6080, 0xa6f8, 0xdcdb, 0x0015, 0xb915, 0xb511, 0xd16b, 0x000f,
+	0xb40f, 0xd06b, 0x000d, 0xb206, 0x7c01, 0x5800, 0x7c04, 0x5c00,
+	0x3011, 0x7c01, 0x5801, 0x7c04, 0x5c04, 0x3019, 0x30a5, 0x3127,
+	0x31d5, 0x7fe0, 0x4c60, 0x7c07, 0x6803, 0x7d00, 0x6900, 0x65a0,
+	0x0000, 0x0000, 0xaf03, 0x6015, 0x303e, 0x6017, 0x57e0, 0x580c,
+	0x588c, 0x7fdd, 0x5fa2, 0x4827, 0x7c1f, 0x4c00, 0x7c1f, 0x4c10,
+	0x8400, 0x7c30, 0x6020, 0x48bf, 0x7c1f, 0x4c00, 0x7c1f, 0x4c01,
+	0x7c07, 0x6803, 0xb806, 0x7c08, 0x6800, 0x0000, 0x0000, 0x305c,
+	0x7c08, 0x6808, 0x0000, 0x0000, 0xae06, 0x7c02, 0x5c02, 0x0000,
+	0x0000, 0x3067, 0x8e05, 0x7c02, 0x5c00, 0x0000, 0x0000, 0xad06,
+	0x7c20, 0x5c20, 0x0000, 0x0000, 0x3072, 0x8d05, 0x7c20, 0x5c00,
+	0x0000, 0x0000, 0xa008, 0x7c07, 0x6800, 0xb8db, 0x7c07, 0x6803,
+	0xd9b3, 0x00d7, 0x7fe0, 0x4c80, 0x7c08, 0x6800, 0x0000, 0x0000,
+	0x7c23, 0x5c23, 0x481d, 0x7c1f, 0x4c00, 0x7c1f, 0x4c02, 0x5310,
+	0x81ff, 0x30f5, 0x7fe0, 0x4d00, 0x4832, 0x7c1f, 0x4c00, 0x7c1f,
+	0x4c10, 0x7c08, 0x6000, 0xa49e, 0x7c07, 0x6800, 0xb89b, 0x7c07,
+	0x6803, 0xd9b3, 0x00f9, 0x7fe0, 0x4d20, 0x7e00, 0x6200, 0x3001,
+	0x7fe0, 0x4dc0, 0xd09d, 0x0002, 0xb4fe, 0x7fe0, 0x4d80, 0x7c04,
+	0x6004, 0x7c07, 0x6802, 0x6728, 0x0000, 0x0000, 0x7c08, 0x6000,
+	0x486c, 0x7c1f, 0x4c00, 0x7c1f, 0x4c01, 0x9503, 0x7e00, 0x6200,
+	0x571f, 0x5fbb, 0xaa05, 0x5b58, 0x7d80, 0x6100, 0x30c2, 0x5b64,
+	0x7d80, 0x6080, 0xcdab, 0x0063, 0xcd8d, 0x0061, 0xd96b, 0x005f,
+	0xd0a0, 0x00d7, 0xcba0, 0x0003, 0x80ec, 0x30cf, 0x30dc, 0x7fe0,
+	0x4ce0, 0x4832, 0x7c1f, 0x4c00, 0x7c1f, 0x4c08, 0x7c08, 0x6008,
+	0x8300, 0xb902, 0x30a5, 0x308a, 0x7fe0, 0x4da0, 0x65a8, 0x0000,
+	0x0000, 0x56a0, 0x590c, 0x7ffd, 0x5fa2, 0xae06, 0x7c02, 0x5c02,
+	0x0000, 0x0000, 0x30f0, 0x8e05, 0x7c02, 0x5c00, 0x0000, 0x0000,
+	0xcba4, 0x0004, 0xcd8d, 0x0002, 0x80f1, 0x7fe0, 0x4ca0, 0x7c08,
+	0x6408, 0x0000, 0x0000, 0x7d00, 0x6800, 0xb603, 0x7c10, 0x6010,
+	0x7d1f, 0x551f, 0x5fb3, 0xaa07, 0x7c80, 0x5800, 0x5b58, 0x7d80,
+	0x6100, 0x310f, 0x7c80, 0x5800, 0x5b64, 0x7d80, 0x6080, 0x4827,
+	0x7c1f, 0x4c00, 0x7c1f, 0x4c10, 0x8400, 0x7c10, 0x6000, 0x7fe0,
+	0x4cc0, 0x5fbb, 0x4824, 0x7c1f, 0x4c00, 0x7c1f, 0x4c04, 0x8200,
+	0x7ce0, 0x5400, 0x6728, 0x0000, 0x0000, 0x30cf, 0x3001, 0x7fe0,
+	0x4e00, 0x4007, 0x4400, 0x5310, 0x7c07, 0x6800, 0x673e, 0x0000,
+	0x0000, 0x570f, 0x5fff, 0xaa05, 0x585b, 0x7d80, 0x6100, 0x313b,
+	0x5867, 0x7d80, 0x6080, 0x9403, 0x7e00, 0x6200, 0xcda3, 0x00e7,
+	0xcd85, 0x00e5, 0xd96b, 0x00e3, 0x96e3, 0x7c07, 0x6800, 0x673e,
+	0x0000, 0x0000, 0x7fe0, 0x4e20, 0x96db, 0x8b04, 0x7c08, 0x5008,
+	0xab03, 0x7c08, 0x5000, 0x7c07, 0x6801, 0x677e, 0x0000, 0x0000,
+	0xdb7c, 0x00ec, 0x0000, 0x7fe1, 0x4f40, 0x4837, 0x4418, 0x41c7,
+	0x7fe0, 0x4e40, 0x7c40, 0x5400, 0x7c1f, 0x4c01, 0x7c1f, 0x4c01,
+	0x8fbf, 0xd2a0, 0x004b, 0x9204, 0xa042, 0x3168, 0x3127, 0x7fe1,
+	0x4f60, 0x489c, 0x4628, 0x7fe0, 0x4e60, 0x7e28, 0x4628, 0x7c40,
+	0x5400, 0x7c01, 0x5800, 0x7c04, 0x5c00, 0x41e8, 0x7c1f, 0x4c01,
+	0x7c1f, 0x4c01, 0x8fa5, 0xb241, 0xa02a, 0x3182, 0x7fe0, 0x4ea0,
+	0x7c02, 0x4402, 0x4448, 0x4894, 0x7c1f, 0x4c01, 0x7c1f, 0x4c03,
+	0x4824, 0x7c1f, 0x4c07, 0x41ef, 0x41ff, 0x4891, 0x7c1f, 0x4c07,
+	0x7c1f, 0x4c17, 0x8400, 0x8ef8, 0x41c7, 0x8f8a, 0x92d5, 0xa10f,
+	0xd480, 0x0008, 0xd580, 0x00b8, 0xa202, 0x319d, 0x7c04, 0x4404,
+	0x319d, 0xd484, 0x00f3, 0xd484, 0x00f1, 0x3127, 0x7fe0, 0x4ee0,
+	0x7c40, 0x5400, 0x4488, 0x41cf, 0x3127, 0x7fe0, 0x4ec0, 0x48f3,
+	0x7c1f, 0x4c01, 0x7c1f, 0x4c09, 0x4508, 0x41c7, 0x8fb0, 0xd218,
+	0x00ae, 0xd2a4, 0x009e, 0x31be, 0x7fe0, 0x4e80, 0x4832, 0x7c1f,
+	0x4c01, 0x7c1f, 0x4c11, 0x4428, 0x7c40, 0x5440, 0x7c01, 0x5801,
+	0x7c04, 0x5c04, 0x41e8, 0xa4b3, 0x31d3, 0x7fe0, 0x4f20, 0x7c07,
+	0x6800, 0x673e, 0x0000, 0x0000, 0x570f, 0x5fff, 0xaa04, 0x585b,
+	0x6100, 0x31e4, 0x5867, 0x6080, 0xbcf1, 0x3001 };
+
+static u16 r8152b_pla_patch_a_bp[] = {
+	0xfc26, 0x8000, 0xfc28, 0x170b, 0xfc2a, 0x01e1, 0xfc2c, 0x0989,
+	0xfc2e, 0x1349, 0xfc30, 0x01b7, 0xfc32, 0x061d, 0xe422, 0x0020,
+	0xe420, 0x0018, 0xfc34, 0x1785, 0xfc36, 0x047b };
+
+static u8 r8152b_pla_patch_a2[] = {
+	0x08, 0xe0, 0x1a, 0xe0, 0xf2, 0xe0, 0xfa, 0xe0,
+	0x32, 0xe1, 0x34, 0xe1, 0x36, 0xe1, 0x38, 0xe1,
+	0x2c, 0x75, 0xdc, 0x21, 0xbc, 0x25, 0x04, 0x13,
+	0x0b, 0xf0, 0x03, 0x13, 0x09, 0xf0, 0x02, 0x13,
+	0x07, 0xf0, 0x01, 0x13, 0x05, 0xf0, 0x08, 0x13,
+	0x03, 0xf0, 0x04, 0xc3, 0x00, 0xbb, 0x03, 0xc3,
+	0x00, 0xbb, 0xd2, 0x17, 0xbc, 0x17, 0x14, 0xc2,
+	0x40, 0x73, 0xba, 0x48, 0x40, 0x9b, 0x11, 0xc2,
+	0x40, 0x73, 0xb0, 0x49, 0x17, 0xf0, 0xbf, 0x49,
+	0x03, 0xf1, 0x09, 0xc5, 0x00, 0xbd, 0xb1, 0x49,
+	0x11, 0xf0, 0xb1, 0x48, 0x40, 0x9b, 0x02, 0xc2,
+	0x00, 0xba, 0x4e, 0x19, 0x00, 0xa0, 0x1e, 0xfc,
+	0xbc, 0xc0, 0xf0, 0xc0, 0xde, 0xe8, 0x00, 0x80,
+	0x00, 0x60, 0x2c, 0x75, 0xd4, 0x49, 0x12, 0xf1,
+	0x29, 0xe0, 0xf8, 0xc2, 0x46, 0x71, 0xf7, 0xc2,
+	0x40, 0x73, 0xbe, 0x49, 0x03, 0xf1, 0xf5, 0xc7,
+	0x02, 0xe0, 0xf2, 0xc7, 0x4f, 0x30, 0x26, 0x62,
+	0xa1, 0x49, 0xf0, 0xf1, 0x22, 0x72, 0xa0, 0x49,
+	0xed, 0xf1, 0x25, 0x25, 0x18, 0x1f, 0x97, 0x30,
+	0x91, 0x30, 0x36, 0x9a, 0x2c, 0x75, 0x32, 0xc3,
+	0x60, 0x73, 0xb1, 0x49, 0x0d, 0xf1, 0xdc, 0x21,
+	0xbc, 0x25, 0x27, 0xc6, 0xc0, 0x77, 0x04, 0x13,
+	0x18, 0xf0, 0x03, 0x13, 0x19, 0xf0, 0x02, 0x13,
+	0x1a, 0xf0, 0x01, 0x13, 0x1b, 0xf0, 0xd4, 0x49,
+	0x03, 0xf1, 0x1c, 0xc5, 0x00, 0xbd, 0xcd, 0xc6,
+	0xc6, 0x67, 0x2e, 0x75, 0xd7, 0x22, 0xdd, 0x26,
+	0x05, 0x15, 0x1a, 0xf0, 0x14, 0xc6, 0x00, 0xbe,
+	0x13, 0xc5, 0x00, 0xbd, 0x12, 0xc5, 0x00, 0xbd,
+	0xf1, 0x49, 0xfb, 0xf1, 0xef, 0xe7, 0xf4, 0x49,
+	0xfa, 0xf1, 0xec, 0xe7, 0xf3, 0x49, 0xf7, 0xf1,
+	0xe9, 0xe7, 0xf2, 0x49, 0xf4, 0xf1, 0xe6, 0xe7,
+	0xb6, 0xc0, 0xf6, 0x14, 0x36, 0x14, 0x62, 0x14,
+	0x86, 0x15, 0xa0, 0xd1, 0x00, 0x00, 0xc0, 0x75,
+	0xd0, 0x49, 0x46, 0xf0, 0x26, 0x72, 0xa7, 0x49,
+	0x43, 0xf0, 0x22, 0x72, 0x25, 0x25, 0x20, 0x1f,
+	0x97, 0x30, 0x91, 0x30, 0x40, 0x73, 0xf3, 0xc4,
+	0x1c, 0x40, 0x04, 0xf0, 0xd7, 0x49, 0x05, 0xf1,
+	0x37, 0xe0, 0x53, 0x48, 0xc0, 0x9d, 0x08, 0x02,
+	0x40, 0x66, 0x64, 0x27, 0x06, 0x16, 0x30, 0xf1,
+	0x46, 0x63, 0x3b, 0x13, 0x2d, 0xf1, 0x34, 0x9b,
+	0x18, 0x1b, 0x93, 0x30, 0x2b, 0xc3, 0x10, 0x1c,
+	0x2b, 0xe8, 0x01, 0x14, 0x25, 0xf1, 0x00, 0x1d,
+	0x26, 0x1a, 0x8a, 0x30, 0x22, 0x73, 0xb5, 0x25,
+	0x0e, 0x0b, 0x00, 0x1c, 0x2c, 0xe8, 0x1f, 0xc7,
+	0x27, 0x40, 0x1a, 0xf1, 0x38, 0xe8, 0x32, 0x1f,
+	0x8f, 0x30, 0x08, 0x1b, 0x24, 0xe8, 0x36, 0x72,
+	0x46, 0x77, 0x00, 0x17, 0x0d, 0xf0, 0x13, 0xc3,
+	0x1f, 0x40, 0x03, 0xf1, 0x00, 0x1f, 0x46, 0x9f,
+	0x44, 0x77, 0x9f, 0x44, 0x5f, 0x44, 0x17, 0xe8,
+	0x0a, 0xc7, 0x27, 0x40, 0x05, 0xf1, 0x02, 0xc3,
+	0x00, 0xbb, 0x1c, 0x1b, 0xd2, 0x1a, 0xff, 0xc7,
+	0x00, 0xbf, 0xb8, 0xcd, 0xff, 0xff, 0x02, 0x0c,
+	0x54, 0xa5, 0xdc, 0xa5, 0x2f, 0x40, 0x05, 0xf1,
+	0x00, 0x14, 0xfa, 0xf1, 0x01, 0x1c, 0x02, 0xe0,
+	0x00, 0x1c, 0x80, 0xff, 0xb0, 0x49, 0x04, 0xf0,
+	0x01, 0x0b, 0xd3, 0xa1, 0x03, 0xe0, 0x02, 0x0b,
+	0xd3, 0xa5, 0x27, 0x31, 0x20, 0x37, 0x02, 0x0b,
+	0xd3, 0xa5, 0x27, 0x31, 0x20, 0x37, 0x00, 0x13,
+	0xfb, 0xf1, 0x80, 0xff, 0x22, 0x73, 0xb5, 0x25,
+	0x18, 0x1e, 0xde, 0x30, 0xd9, 0x30, 0x64, 0x72,
+	0x11, 0x1e, 0x68, 0x23, 0x16, 0x31, 0x80, 0xff,
+	0x08, 0xc2, 0x40, 0x73, 0x3a, 0x48, 0x40, 0x9b,
+	0x06, 0xff, 0x02, 0xc6, 0x00, 0xbe, 0x4e, 0x18,
+	0x1e, 0xfc, 0x33, 0xc5, 0xa0, 0x74, 0xc0, 0x49,
+	0x1f, 0xf0, 0x30, 0xc5, 0xa0, 0x73, 0x00, 0x13,
+	0x04, 0xf1, 0xa2, 0x73, 0x00, 0x13, 0x14, 0xf0,
+	0x28, 0xc5, 0xa0, 0x74, 0xc8, 0x49, 0x1b, 0xf1,
+	0x26, 0xc5, 0xa0, 0x76, 0xa2, 0x74, 0x01, 0x06,
+	0x20, 0x37, 0xa0, 0x9e, 0xa2, 0x9c, 0x1e, 0xc5,
+	0xa2, 0x73, 0x23, 0x40, 0x10, 0xf8, 0x04, 0xf3,
+	0xa0, 0x73, 0x33, 0x40, 0x0c, 0xf8, 0x15, 0xc5,
+	0xa0, 0x74, 0x41, 0x48, 0xa0, 0x9c, 0x14, 0xc5,
+	0xa0, 0x76, 0x62, 0x48, 0xe0, 0x48, 0xa0, 0x9e,
+	0x10, 0xc6, 0x00, 0xbe, 0x0a, 0xc5, 0xa0, 0x74,
+	0x48, 0x48, 0xa0, 0x9c, 0x0b, 0xc5, 0x20, 0x1e,
+	0xa0, 0x9e, 0xe5, 0x48, 0xa0, 0x9e, 0xf0, 0xe7,
+	0xbc, 0xc0, 0xc8, 0xd2, 0xcc, 0xd2, 0x28, 0xe4,
+	0x22, 0x02, 0xf0, 0xc0, 0x02, 0xc6, 0x00, 0xbe,
+	0x00, 0x00, 0x02, 0xc6, 0x00, 0xbe, 0x00, 0x00,
+	0x02, 0xc6, 0x00, 0xbe, 0x00, 0x00, 0x02, 0xc6,
+	0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static u16 r8152b_pla_patch_a2_bp[] = {
+	0xfc26, 0x8000, 0xfc28, 0x17a5, 0xfc2a, 0x13ad,
+	0xfc2c, 0x184d, 0xfc2e, 0x01e1 };
+
+static u16 r8153_ram_code_a[] = {
+	0xE86C, 0xA000, 0xB436, 0xB820, 0xB438, 0x0290, 0xB436, 0xA012,
+	0xB438, 0x0000, 0xB436, 0xA014, 0xB438, 0x2c04, 0xB438, 0x2c18,
+	0xB438, 0x2c45, 0xB438, 0x2c45, 0xB438, 0xd502, 0xB438, 0x8301,
+	0xB438, 0x8306, 0xB438, 0xd500, 0xB438, 0x8208, 0xB438, 0xd501,
+	0xB438, 0xe018, 0xB438, 0x0308, 0xB438, 0x60f2, 0xB438, 0x8404,
+	0xB438, 0x607d, 0xB438, 0xc117, 0xB438, 0x2c16, 0xB438, 0xc116,
+	0xB438, 0x2c16, 0xB438, 0x607d, 0xB438, 0xc117, 0xB438, 0xa404,
+	0xB438, 0xd500, 0xB438, 0x0800, 0xB438, 0xd501, 0xB438, 0x62d2,
+	0xB438, 0x615d, 0xB438, 0xc115, 0xB438, 0xa404, 0xB438, 0xc307,
+	0xB438, 0xd502, 0xB438, 0x8301, 0xB438, 0x8306, 0xB438, 0xd500,
+	0xB438, 0x8208, 0xB438, 0x2c42, 0xB438, 0xc114, 0xB438, 0x8404,
+	0xB438, 0xc317, 0xB438, 0xd701, 0xB438, 0x435d, 0xB438, 0xd500,
+	0xB438, 0xa208, 0xB438, 0xd502, 0xB438, 0xa306, 0xB438, 0xa301,
+	0xB438, 0x2c42, 0xB438, 0x8404, 0xB438, 0x613d, 0xB438, 0xc115,
+	0xB438, 0xc307, 0xB438, 0xd502, 0xB438, 0x8301, 0xB438, 0x8306,
+	0xB438, 0xd500, 0xB438, 0x8208, 0xB438, 0x2c42, 0xB438, 0xc114,
+	0xB438, 0xc317, 0xB438, 0xd701, 0xB438, 0x40dd, 0xB438, 0xd500,
+	0xB438, 0xa208, 0xB438, 0xd502, 0xB438, 0xa306, 0xB438, 0xa301,
+	0xB438, 0xd500, 0xB438, 0xd702, 0xB438, 0x0800, 0xB436, 0xA01A,
+	0xB438, 0x0000, 0xB436, 0xA006, 0xB438, 0x0fff, 0xB436, 0xA004,
+	0xB438, 0x0fff, 0xB436, 0xA002, 0xB438, 0x05a3, 0xB436, 0xA000,
+	0xB438, 0x3591, 0xB436, 0xB820, 0xB438, 0x0210 };
+
+static u8 r8153_usb_patch_c[] = {
+	0x08, 0xe0, 0x0a, 0xe0, 0x14, 0xe0, 0x58, 0xe0,
+	0x64, 0xe0, 0x79, 0xe0, 0xab, 0xe0, 0xb6, 0xe0,
+	0x02, 0xc5, 0x00, 0xbd, 0x38, 0x3b, 0xdb, 0x49,
+	0x04, 0xf1, 0x06, 0xc3, 0x00, 0xbb, 0x5a, 0x02,
+	0x05, 0xc4, 0x03, 0xc3, 0x00, 0xbb, 0xa4, 0x04,
+	0x7e, 0x02, 0x30, 0xd4, 0x65, 0xc6, 0x66, 0x61,
+	0x92, 0x49, 0x12, 0xf1, 0x3e, 0xc0, 0x02, 0x61,
+	0x97, 0x49, 0x05, 0xf0, 0x3c, 0xc0, 0x00, 0x61,
+	0x90, 0x49, 0x0a, 0xf1, 0xca, 0x63, 0xb0, 0x49,
+	0x09, 0xf1, 0xb1, 0x49, 0x05, 0xf0, 0x32, 0xc0,
+	0x00, 0x71, 0x9e, 0x49, 0x03, 0xf1, 0xb0, 0x48,
+	0x05, 0xe0, 0x30, 0x48, 0xda, 0x61, 0x10, 0x48,
+	0xda, 0x89, 0x4a, 0xc6, 0xc0, 0x60, 0x85, 0x49,
+	0x03, 0xf0, 0x31, 0x48, 0x04, 0xe0, 0xb1, 0x48,
+	0xb2, 0x48, 0x0f, 0xe0, 0x30, 0x18, 0x1b, 0xc1,
+	0x0f, 0xe8, 0x1a, 0xc6, 0xc7, 0x65, 0xd0, 0x49,
+	0x05, 0xf0, 0x32, 0x48, 0x02, 0xc2, 0x00, 0xba,
+	0x3e, 0x16, 0x02, 0xc2, 0x00, 0xba, 0x48, 0x16,
+	0x02, 0xc2, 0x00, 0xba, 0x4a, 0x16, 0x02, 0xb4,
+	0x09, 0xc2, 0x40, 0x99, 0x0e, 0x48, 0x42, 0x98,
+	0x42, 0x70, 0x8e, 0x49, 0xfe, 0xf1, 0x02, 0xb0,
+	0x80, 0xff, 0xc0, 0xd4, 0xe4, 0x40, 0x20, 0xd4,
+	0xca, 0xcf, 0x00, 0xcf, 0x3c, 0xe4, 0x0c, 0xc0,
+	0x00, 0x63, 0xb5, 0x49, 0x09, 0xc0, 0x30, 0x18,
+	0x06, 0xc1, 0xea, 0xef, 0xf5, 0xc7, 0x02, 0xc0,
+	0x00, 0xb8, 0xd0, 0x10, 0xe4, 0x4b, 0x00, 0xd8,
+	0x14, 0xc3, 0x60, 0x61, 0x90, 0x49, 0x06, 0xf0,
+	0x11, 0xc3, 0x70, 0x61, 0x12, 0x48, 0x70, 0x89,
+	0x08, 0xe0, 0x0a, 0xc6, 0xd4, 0x61, 0x93, 0x48,
+	0xd4, 0x89, 0x02, 0xc1, 0x00, 0xb9, 0x72, 0x17,
+	0x02, 0xc1, 0x00, 0xb9, 0x9c, 0x15, 0x00, 0xd8,
+	0xef, 0xcf, 0x20, 0xd4, 0x30, 0x18, 0xe7, 0xc1,
+	0xcb, 0xef, 0x2b, 0xc5, 0xa0, 0x77, 0x00, 0x1c,
+	0xa0, 0x9c, 0x28, 0xc5, 0xa0, 0x64, 0xc0, 0x48,
+	0xc1, 0x48, 0xc2, 0x48, 0xa0, 0x8c, 0xb1, 0x64,
+	0xc0, 0x48, 0xb1, 0x8c, 0x20, 0xc5, 0xa0, 0x64,
+	0x40, 0x48, 0x41, 0x48, 0xc2, 0x48, 0xa0, 0x8c,
+	0x19, 0xc5, 0xa4, 0x64, 0x44, 0x48, 0xa4, 0x8c,
+	0xb1, 0x64, 0x40, 0x48, 0xb1, 0x8c, 0x14, 0xc4,
+	0x80, 0x73, 0x13, 0xc4, 0x82, 0x9b, 0x11, 0x1b,
+	0x80, 0x9b, 0x0c, 0xc5, 0xa0, 0x64, 0x40, 0x48,
+	0x41, 0x48, 0x42, 0x48, 0xa0, 0x8c, 0x05, 0xc5,
+	0xa0, 0x9f, 0x02, 0xc5, 0x00, 0xbd, 0x6c, 0x3a,
+	0x1e, 0xfc, 0x10, 0xd8, 0x86, 0xd4, 0xf8, 0xcb,
+	0x20, 0xe4, 0x0a, 0xc0, 0x16, 0x61, 0x91, 0x48,
+	0x16, 0x89, 0x07, 0xc0, 0x11, 0x19, 0x0c, 0x89,
+	0x02, 0xc1, 0x00, 0xb9, 0x02, 0x06, 0x00, 0xd4,
+	0x40, 0xb4, 0xfe, 0xc0, 0x16, 0x61, 0x91, 0x48,
+	0x16, 0x89, 0xfb, 0xc0, 0x11, 0x19, 0x0c, 0x89,
+	0x02, 0xc1, 0x00, 0xb9, 0xd2, 0x05, 0x00, 0x00 };
+
+static u16 r8153_usb_patch_c_bp[] = {
+	0xfc26, 0xa000, 0xfc28, 0x3b34, 0xfc2a, 0x027c, 0xfc2c, 0x15de,
+	0xfc2e, 0x10ce, 0xfc30, 0x1adc, 0xfc32, 0x3a28, 0xfc34, 0x05f8,
+	0xfc36, 0x05c8, 0xfc38, 0x00f3 };
+
+static u8 r8153_pla_patch_c[] = {
+	0x5d, 0xe0, 0x07, 0xe0, 0x0f, 0xe0, 0x5a, 0xe0,
+	0x59, 0xe0, 0x1f, 0xe0, 0x57, 0xe0, 0x3e, 0xe1,
+	0x08, 0xc2, 0x40, 0x73, 0x3a, 0x48, 0x40, 0x9b,
+	0x06, 0xff, 0x02, 0xc6, 0x00, 0xbe, 0xcc, 0x17,
+	0x1e, 0xfc, 0x2c, 0x75, 0xdc, 0x21, 0xbc, 0x25,
+	0x04, 0x13, 0x0b, 0xf0, 0x03, 0x13, 0x09, 0xf0,
+	0x02, 0x13, 0x07, 0xf0, 0x01, 0x13, 0x05, 0xf0,
+	0x08, 0x13, 0x03, 0xf0, 0x04, 0xc3, 0x00, 0xbb,
+	0x03, 0xc3, 0x00, 0xbb, 0x50, 0x17, 0x3a, 0x17,
+	0x33, 0xc5, 0xa0, 0x74, 0xc0, 0x49, 0x1f, 0xf0,
+	0x30, 0xc5, 0xa0, 0x73, 0x00, 0x13, 0x04, 0xf1,
+	0xa2, 0x73, 0x00, 0x13, 0x14, 0xf0, 0x28, 0xc5,
+	0xa0, 0x74, 0xc8, 0x49, 0x1b, 0xf1, 0x26, 0xc5,
+	0xa0, 0x76, 0xa2, 0x74, 0x01, 0x06, 0x20, 0x37,
+	0xa0, 0x9e, 0xa2, 0x9c, 0x1e, 0xc5, 0xa2, 0x73,
+	0x23, 0x40, 0x10, 0xf8, 0x04, 0xf3, 0xa0, 0x73,
+	0x33, 0x40, 0x0c, 0xf8, 0x15, 0xc5, 0xa0, 0x74,
+	0x41, 0x48, 0xa0, 0x9c, 0x14, 0xc5, 0xa0, 0x76,
+	0x62, 0x48, 0xe0, 0x48, 0xa0, 0x9e, 0x10, 0xc6,
+	0x00, 0xbe, 0x0a, 0xc5, 0xa0, 0x74, 0x48, 0x48,
+	0xa0, 0x9c, 0x0b, 0xc5, 0x20, 0x1e, 0xa0, 0x9e,
+	0xe5, 0x48, 0xa0, 0x9e, 0xf0, 0xe7, 0xbc, 0xc0,
+	0xc8, 0xd2, 0xcc, 0xd2, 0x28, 0xe4, 0xfa, 0x01,
+	0xf0, 0xc0, 0x18, 0x89, 0x74, 0xc0, 0xcd, 0xe8,
+	0x80, 0x76, 0x00, 0x1d, 0x6e, 0xc3, 0x66, 0x62,
+	0xa0, 0x49, 0x06, 0xf0, 0x64, 0xc0, 0x02, 0x71,
+	0x60, 0x99, 0x62, 0xc1, 0x03, 0xe0, 0x5f, 0xc0,
+	0x60, 0xc1, 0x02, 0x99, 0x00, 0x61, 0x0f, 0x1b,
+	0x59, 0x41, 0x03, 0x13, 0x18, 0xf1, 0xe4, 0x49,
+	0x20, 0xf1, 0xe5, 0x49, 0x1e, 0xf0, 0x59, 0xc6,
+	0xd0, 0x73, 0xb7, 0x49, 0x08, 0xf0, 0x01, 0x0b,
+	0x80, 0x13, 0x03, 0xf0, 0xd0, 0x8b, 0x03, 0xe0,
+	0x3f, 0x48, 0xd0, 0x9b, 0x51, 0xc0, 0x10, 0x1a,
+	0x84, 0x1b, 0xb1, 0xe8, 0x4b, 0xc2, 0x40, 0x63,
+	0x30, 0x48, 0x0a, 0xe0, 0xe5, 0x49, 0x09, 0xf0,
+	0x47, 0xc0, 0x00, 0x1a, 0x84, 0x1b, 0xa7, 0xe8,
+	0x41, 0xc2, 0x40, 0x63, 0xb0, 0x48, 0x40, 0x8b,
+	0x67, 0x11, 0x3f, 0xf1, 0x69, 0x33, 0x32, 0xc0,
+	0x28, 0x40, 0xd2, 0xf1, 0x33, 0xc0, 0x00, 0x19,
+	0x81, 0x1b, 0x99, 0xe8, 0x30, 0xc0, 0x04, 0x1a,
+	0x84, 0x1b, 0x95, 0xe8, 0x8a, 0xe8, 0xa3, 0x49,
+	0xfe, 0xf0, 0x2a, 0xc0, 0x86, 0xe8, 0xa1, 0x48,
+	0x84, 0x1b, 0x8d, 0xe8, 0x00, 0x1d, 0x69, 0x33,
+	0x00, 0x1e, 0x01, 0x06, 0xff, 0x18, 0x30, 0x40,
+	0xfd, 0xf1, 0x1f, 0xc0, 0x00, 0x76, 0x2e, 0x40,
+	0xf7, 0xf1, 0x21, 0x48, 0x19, 0xc0, 0x84, 0x1b,
+	0x7e, 0xe8, 0x74, 0x08, 0x72, 0xe8, 0xa1, 0x49,
+	0xfd, 0xf0, 0x11, 0xc0, 0x00, 0x1a, 0x84, 0x1b,
+	0x76, 0xe8, 0x6b, 0xe8, 0xa5, 0x49, 0xfe, 0xf0,
+	0x09, 0xc0, 0x01, 0x19, 0x81, 0x1b, 0x6f, 0xe8,
+	0x5a, 0xe0, 0xb8, 0x0b, 0x50, 0xe8, 0x83, 0x00,
+	0x82, 0x00, 0x20, 0xb4, 0x10, 0xd8, 0x84, 0xd4,
+	0x88, 0xd3, 0x10, 0xe0, 0x00, 0xd8, 0x24, 0xd4,
+	0xf9, 0xc0, 0x57, 0xe8, 0x48, 0x33, 0xf3, 0xc0,
+	0x00, 0x61, 0x6a, 0xc0, 0x47, 0x11, 0x03, 0xf0,
+	0x57, 0x11, 0x05, 0xf1, 0x00, 0x61, 0x17, 0x48,
+	0x00, 0x89, 0x41, 0xe0, 0x9c, 0x20, 0x9c, 0x24,
+	0xd0, 0x49, 0x09, 0xf0, 0x04, 0x11, 0x07, 0xf1,
+	0x00, 0x61, 0x97, 0x49, 0x38, 0xf0, 0x97, 0x48,
+	0x00, 0x89, 0x2b, 0xe0, 0x00, 0x11, 0x05, 0xf1,
+	0x00, 0x61, 0x92, 0x48, 0x00, 0x89, 0x2f, 0xe0,
+	0x06, 0x11, 0x05, 0xf1, 0x00, 0x61, 0x11, 0x48,
+	0x00, 0x89, 0x29, 0xe0, 0x05, 0x11, 0x0f, 0xf1,
+	0x00, 0x61, 0x93, 0x49, 0x1a, 0xf1, 0x91, 0x49,
+	0x0a, 0xf0, 0x91, 0x48, 0x00, 0x89, 0x0f, 0xe0,
+	0xc6, 0xc0, 0x00, 0x61, 0x98, 0x20, 0x98, 0x24,
+	0x25, 0x11, 0x80, 0xff, 0xfa, 0xef, 0x17, 0xf1,
+	0x38, 0xc0, 0x1f, 0xe8, 0x95, 0x49, 0x13, 0xf0,
+	0xf4, 0xef, 0x11, 0xf1, 0x31, 0xc0, 0x00, 0x61,
+	0x92, 0x49, 0x0d, 0xf1, 0x12, 0x48, 0x00, 0x89,
+	0x29, 0xc0, 0x00, 0x19, 0x00, 0x89, 0x27, 0xc0,
+	0x01, 0x89, 0x23, 0xc0, 0x0e, 0xe8, 0x12, 0x48,
+	0x81, 0x1b, 0x15, 0xe8, 0xae, 0xc3, 0x66, 0x62,
+	0xa0, 0x49, 0x04, 0xf0, 0x64, 0x71, 0xa3, 0xc0,
+	0x02, 0x99, 0x02, 0xc0, 0x00, 0xb8, 0xd6, 0x07,
+	0x13, 0xc4, 0x84, 0x98, 0x00, 0x1b, 0x86, 0x8b,
+	0x86, 0x73, 0xbf, 0x49, 0xfe, 0xf1, 0x80, 0x71,
+	0x82, 0x72, 0x80, 0xff, 0x09, 0xc4, 0x84, 0x98,
+	0x80, 0x99, 0x82, 0x9a, 0x86, 0x8b, 0x86, 0x73,
+	0xbf, 0x49, 0xfe, 0xf1, 0x80, 0xff, 0x08, 0xea,
+	0x30, 0xd4, 0x10, 0xc0, 0x12, 0xe8, 0x8a, 0xd3,
+	0x00, 0xd8, 0x02, 0xc6, 0x00, 0xbe, 0xe0, 0x08 };
+
+static u16 r8153_pla_patch_c_bp[] = {
+	0xfc26, 0x8000, 0xfc28, 0x1306, 0xfc2a, 0x17ca, 0xfc2c, 0x171e,
+	0xfc2e, 0x0000, 0xfc30, 0x0000, 0xfc32, 0x01b4, 0xfc34, 0x07d4,
+	0xfc36, 0x0894, 0xfc38, 0x00e6 };
+
+static u16 r8153_ram_code_bc[] = {
+	0xB436, 0xB820, 0xB438, 0x0290, 0xB436, 0xA012, 0xB438, 0x0000,
+	0xB436, 0xA014, 0xB438, 0x2c04, 0xB438, 0x2c07, 0xB438, 0x2c0a,
+	0xB438, 0x2c0d, 0xB438, 0xa240, 0xB438, 0xa104, 0xB438, 0x292d,
+	0xB438, 0x8620, 0xB438, 0xa480, 0xB438, 0x2a2c, 0xB438, 0x8480,
+	0xB438, 0xa101, 0xB438, 0x2a36, 0xB438, 0xd056, 0xB438, 0x2223,
+	0xB436, 0xA01A, 0xB438, 0x0000, 0xB436, 0xA006, 0xB438, 0x0222,
+	0xB436, 0xA004, 0xB438, 0x0a35, 0xB436, 0xA002, 0xB438, 0x0a2b,
+	0xB436, 0xA000, 0xB438, 0xf92c, 0xB436, 0xB820, 0xB438, 0x0210 };
+
+static u8 r8153_usb_patch_b[] = {
+	0x08, 0xe0, 0x0f, 0xe0, 0x18, 0xe0, 0x24, 0xe0,
+	0x26, 0xe0, 0x3a, 0xe0, 0x84, 0xe0, 0x9c, 0xe0,
+	0xc2, 0x49, 0x04, 0xf0, 0x02, 0xc0, 0x00, 0xb8,
+	0x14, 0x18, 0x02, 0xc0, 0x00, 0xb8, 0x2e, 0x18,
+	0x06, 0x89, 0x08, 0xc0, 0x0c, 0x61, 0x92, 0x48,
+	0x93, 0x48, 0x0c, 0x89, 0x02, 0xc0, 0x00, 0xb8,
+	0x08, 0x05, 0x40, 0xb4, 0x16, 0x89, 0x6d, 0xc0,
+	0x00, 0x61, 0x95, 0x49, 0x06, 0xf0, 0xfa, 0xc0,
+	0x0c, 0x61, 0x92, 0x48, 0x93, 0x48, 0x0c, 0x89,
+	0x02, 0xc0, 0x00, 0xb8, 0xe2, 0x04, 0x02, 0xc2,
+	0x00, 0xba, 0xec, 0x11, 0x60, 0x60, 0x85, 0x49,
+	0x0d, 0xf1, 0x11, 0xc6, 0xd2, 0x61, 0x91, 0x49,
+	0xfd, 0xf0, 0x74, 0x60, 0x04, 0x48, 0x74, 0x88,
+	0x08, 0xc6, 0x08, 0xc0, 0xc4, 0x98, 0x01, 0x18,
+	0xc0, 0x88, 0x02, 0xc0, 0x00, 0xb8, 0x6e, 0x12,
+	0x04, 0xe4, 0x0d, 0x00, 0x00, 0xd4, 0xd1, 0x49,
+	0x3c, 0xf1, 0xd2, 0x49, 0x16, 0xf1, 0xd3, 0x49,
+	0x18, 0xf1, 0xd4, 0x49, 0x19, 0xf1, 0xd5, 0x49,
+	0x1a, 0xf1, 0xd6, 0x49, 0x1b, 0xf1, 0xd7, 0x49,
+	0x1c, 0xf1, 0xd8, 0x49, 0x1d, 0xf1, 0xd9, 0x49,
+	0x20, 0xf1, 0xda, 0x49, 0x23, 0xf1, 0xdb, 0x49,
+	0x24, 0xf1, 0x02, 0xc4, 0x00, 0xbc, 0x20, 0x04,
+	0xe5, 0x8e, 0x02, 0xc4, 0x00, 0xbc, 0x14, 0x02,
+	0x02, 0xc4, 0x00, 0xbc, 0x16, 0x02, 0x02, 0xc4,
+	0x00, 0xbc, 0x18, 0x02, 0x02, 0xc4, 0x00, 0xbc,
+	0x1a, 0x02, 0x02, 0xc4, 0x00, 0xbc, 0x1c, 0x02,
+	0x02, 0xc4, 0x00, 0xbc, 0x94, 0x02, 0x10, 0xc7,
+	0xe0, 0x8e, 0x02, 0xc4, 0x00, 0xbc, 0x8a, 0x02,
+	0x0b, 0xc7, 0xe4, 0x8e, 0x02, 0xc4, 0x00, 0xbc,
+	0x88, 0x02, 0x02, 0xc4, 0x00, 0xbc, 0x6e, 0x02,
+	0x02, 0xc4, 0x00, 0xbc, 0x5a, 0x02, 0x30, 0xe4,
+	0x0c, 0xc3, 0x60, 0x64, 0xc5, 0x49, 0x04, 0xf1,
+	0x74, 0x64, 0xc4, 0x48, 0x74, 0x8c, 0x06, 0xc3,
+	0x64, 0x8e, 0x02, 0xc4, 0x00, 0xbc, 0x20, 0x04,
+	0x00, 0xd8, 0x00, 0xe4, 0xb2, 0xc0, 0x00, 0x61,
+	0x90, 0x49, 0x09, 0xf1, 0x8b, 0xc6, 0xca, 0x61,
+	0x94, 0x49, 0x0e, 0xf1, 0xf6, 0xc6, 0xda, 0x60,
+	0x81, 0x49, 0x0a, 0xf0, 0x65, 0x60, 0x03, 0x48,
+	0x65, 0x88, 0xef, 0xc6, 0xdc, 0x60, 0x80, 0x48,
+	0xdc, 0x88, 0x05, 0xc6, 0x00, 0xbe, 0x02, 0xc6,
+	0x00, 0xbe, 0x36, 0x13, 0x4c, 0x17, 0x99, 0xc4,
+	0x80, 0x65, 0xd0, 0x49, 0x04, 0xf1, 0xfa, 0x75,
+	0x04, 0xc4, 0x00, 0xbc, 0x03, 0xc4, 0x00, 0xbc,
+	0x9a, 0x00, 0xee, 0x01 };
+
+static u16 r8153_usb_patch_b_bp[] = {
+	0xfc26, 0xa000, 0xfc28, 0x180c, 0xfc2a, 0x0506, 0xfc2c, 0x04E0,
+	0xfc2e, 0x11E4, 0xfc30, 0x125C, 0xfc32, 0x0232, 0xfc34, 0x131E,
+	0xfc36, 0x0098, 0xfc38, 0x00FF };
+
+static u8 r8153_pla_patch_b[] = {
+	0x08, 0xe0, 0xea, 0xe0, 0xf2, 0xe0, 0x04, 0xe1,
+	0x09, 0xe1, 0x0e, 0xe1, 0x46, 0xe1, 0xf7, 0xe1,
+	0x14, 0xc2, 0x40, 0x73, 0xba, 0x48, 0x40, 0x9b,
+	0x11, 0xc2, 0x40, 0x73, 0xb0, 0x49, 0x17, 0xf0,
+	0xbf, 0x49, 0x03, 0xf1, 0x09, 0xc5, 0x00, 0xbd,
+	0xb1, 0x49, 0x11, 0xf0, 0xb1, 0x48, 0x40, 0x9b,
+	0x02, 0xc2, 0x00, 0xba, 0x1a, 0x17, 0x00, 0xe0,
+	0x1e, 0xfc, 0xbc, 0xc0, 0xf0, 0xc0, 0xde, 0xe8,
+	0x00, 0x80, 0x00, 0x20, 0x2c, 0x75, 0xd4, 0x49,
+	0x12, 0xf1, 0x32, 0xe0, 0xf8, 0xc2, 0x46, 0x71,
+	0xf7, 0xc2, 0x40, 0x73, 0xbe, 0x49, 0x03, 0xf1,
+	0xf5, 0xc7, 0x02, 0xe0, 0xf2, 0xc7, 0x4f, 0x30,
+	0x26, 0x62, 0xa1, 0x49, 0xf0, 0xf1, 0x22, 0x72,
+	0xa0, 0x49, 0xed, 0xf1, 0x25, 0x25, 0x18, 0x1f,
+	0x97, 0x30, 0x91, 0x30, 0x36, 0x9a, 0x2c, 0x75,
+	0x3c, 0xc3, 0x60, 0x73, 0xb1, 0x49, 0x0d, 0xf1,
+	0xdc, 0x21, 0xbc, 0x25, 0x30, 0xc6, 0xc0, 0x77,
+	0x04, 0x13, 0x21, 0xf0, 0x03, 0x13, 0x22, 0xf0,
+	0x02, 0x13, 0x23, 0xf0, 0x01, 0x13, 0x24, 0xf0,
+	0x08, 0x13, 0x08, 0xf1, 0x2e, 0x73, 0xba, 0x21,
+	0xbd, 0x25, 0x05, 0x13, 0x03, 0xf1, 0x24, 0xc5,
+	0x00, 0xbd, 0xd4, 0x49, 0x03, 0xf1, 0x1c, 0xc5,
+	0x00, 0xbd, 0xc4, 0xc6, 0xc6, 0x67, 0x2e, 0x75,
+	0xd7, 0x22, 0xdd, 0x26, 0x05, 0x15, 0x1b, 0xf0,
+	0x14, 0xc6, 0x00, 0xbe, 0x13, 0xc5, 0x00, 0xbd,
+	0x12, 0xc5, 0x00, 0xbd, 0xf1, 0x49, 0xfb, 0xf1,
+	0xef, 0xe7, 0xf4, 0x49, 0xfa, 0xf1, 0xec, 0xe7,
+	0xf3, 0x49, 0xf7, 0xf1, 0xe9, 0xe7, 0xf2, 0x49,
+	0xf4, 0xf1, 0xe6, 0xe7, 0xb6, 0xc0, 0x9e, 0x12,
+	0xde, 0x11, 0x0a, 0x12, 0x3c, 0x13, 0x00, 0xa0,
+	0xa0, 0xd1, 0x00, 0x00, 0xc0, 0x75, 0xd0, 0x49,
+	0x46, 0xf0, 0x26, 0x72, 0xa7, 0x49, 0x43, 0xf0,
+	0x22, 0x72, 0x25, 0x25, 0x20, 0x1f, 0x97, 0x30,
+	0x91, 0x30, 0x40, 0x73, 0xf3, 0xc4, 0x1c, 0x40,
+	0x04, 0xf0, 0xd7, 0x49, 0x05, 0xf1, 0x37, 0xe0,
+	0x53, 0x48, 0xc0, 0x9d, 0x08, 0x02, 0x40, 0x66,
+	0x64, 0x27, 0x06, 0x16, 0x30, 0xf1, 0x46, 0x63,
+	0x3b, 0x13, 0x2d, 0xf1, 0x34, 0x9b, 0x18, 0x1b,
+	0x93, 0x30, 0x2b, 0xc3, 0x10, 0x1c, 0x2b, 0xe8,
+	0x01, 0x14, 0x25, 0xf1, 0x00, 0x1d, 0x26, 0x1a,
+	0x8a, 0x30, 0x22, 0x73, 0xb5, 0x25, 0x0e, 0x0b,
+	0x00, 0x1c, 0x2c, 0xe8, 0x1f, 0xc7, 0x27, 0x40,
+	0x1a, 0xf1, 0x38, 0xe8, 0x32, 0x1f, 0x8f, 0x30,
+	0x08, 0x1b, 0x24, 0xe8, 0x36, 0x72, 0x46, 0x77,
+	0x00, 0x17, 0x0d, 0xf0, 0x13, 0xc3, 0x1f, 0x40,
+	0x03, 0xf1, 0x00, 0x1f, 0x46, 0x9f, 0x44, 0x77,
+	0x9f, 0x44, 0x5f, 0x44, 0x17, 0xe8, 0x0a, 0xc7,
+	0x27, 0x40, 0x05, 0xf1, 0x02, 0xc3, 0x00, 0xbb,
+	0xfa, 0x18, 0xb0, 0x18, 0xff, 0xc7, 0x00, 0xbf,
+	0xb8, 0xcd, 0xff, 0xff, 0x02, 0x0c, 0x54, 0xa5,
+	0xdc, 0xa5, 0x2f, 0x40, 0x05, 0xf1, 0x00, 0x14,
+	0xfa, 0xf1, 0x01, 0x1c, 0x02, 0xe0, 0x00, 0x1c,
+	0x80, 0xff, 0xb0, 0x49, 0x04, 0xf0, 0x01, 0x0b,
+	0xd3, 0xa1, 0x03, 0xe0, 0x02, 0x0b, 0xd3, 0xa5,
+	0x27, 0x31, 0x20, 0x37, 0x02, 0x0b, 0xd3, 0xa5,
+	0x27, 0x31, 0x20, 0x37, 0x00, 0x13, 0xfb, 0xf1,
+	0x80, 0xff, 0x22, 0x73, 0xb5, 0x25, 0x18, 0x1e,
+	0xde, 0x30, 0xd9, 0x30, 0x64, 0x72, 0x11, 0x1e,
+	0x68, 0x23, 0x16, 0x31, 0x80, 0xff, 0x08, 0xc2,
+	0x40, 0x73, 0x3a, 0x48, 0x40, 0x9b, 0x06, 0xff,
+	0x02, 0xc6, 0x00, 0xbe, 0x08, 0x16, 0x1e, 0xfc,
+	0x2c, 0x75, 0xdc, 0x21, 0xbc, 0x25, 0x04, 0x13,
+	0x0b, 0xf0, 0x03, 0x13, 0x09, 0xf0, 0x02, 0x13,
+	0x07, 0xf0, 0x01, 0x13, 0x05, 0xf0, 0x08, 0x13,
+	0x03, 0xf0, 0x04, 0xc3, 0x00, 0xbb, 0x03, 0xc3,
+	0x00, 0xbb, 0x8c, 0x15, 0x76, 0x15, 0xa0, 0x64,
+	0x40, 0x48, 0xa0, 0x8c, 0x02, 0xc4, 0x00, 0xbc,
+	0x82, 0x00, 0xa0, 0x62, 0x21, 0x48, 0xa0, 0x8a,
+	0x02, 0xc2, 0x00, 0xba, 0x40, 0x03, 0x33, 0xc5,
+	0xa0, 0x74, 0xc0, 0x49, 0x1f, 0xf0, 0x30, 0xc5,
+	0xa0, 0x73, 0x00, 0x13, 0x04, 0xf1, 0xa2, 0x73,
+	0x00, 0x13, 0x14, 0xf0, 0x28, 0xc5, 0xa0, 0x74,
+	0xc8, 0x49, 0x1b, 0xf1, 0x26, 0xc5, 0xa0, 0x76,
+	0xa2, 0x74, 0x01, 0x06, 0x20, 0x37, 0xa0, 0x9e,
+	0xa2, 0x9c, 0x1e, 0xc5, 0xa2, 0x73, 0x23, 0x40,
+	0x10, 0xf8, 0x04, 0xf3, 0xa0, 0x73, 0x33, 0x40,
+	0x0c, 0xf8, 0x15, 0xc5, 0xa0, 0x74, 0x41, 0x48,
+	0xa0, 0x9c, 0x14, 0xc5, 0xa0, 0x76, 0x62, 0x48,
+	0xe0, 0x48, 0xa0, 0x9e, 0x10, 0xc6, 0x00, 0xbe,
+	0x0a, 0xc5, 0xa0, 0x74, 0x48, 0x48, 0xa0, 0x9c,
+	0x0b, 0xc5, 0x20, 0x1e, 0xa0, 0x9e, 0xe5, 0x48,
+	0xa0, 0x9e, 0xf0, 0xe7, 0xbc, 0xc0, 0xc8, 0xd2,
+	0xcc, 0xd2, 0x28, 0xe4, 0xe6, 0x01, 0xf0, 0xc0,
+	0x18, 0x89, 0x00, 0x1d, 0x3c, 0xc3, 0x64, 0x71,
+	0x3c, 0xc0, 0x02, 0x99, 0x00, 0x61, 0x67, 0x11,
+	0x3c, 0xf1, 0x69, 0x33, 0x35, 0xc0, 0x28, 0x40,
+	0xf6, 0xf1, 0x34, 0xc0, 0x00, 0x19, 0x81, 0x1b,
+	0x91, 0xe8, 0x31, 0xc0, 0x04, 0x1a, 0x84, 0x1b,
+	0x8d, 0xe8, 0x82, 0xe8, 0xa3, 0x49, 0xfe, 0xf0,
+	0x2b, 0xc0, 0x7e, 0xe8, 0xa1, 0x48, 0x28, 0xc0,
+	0x84, 0x1b, 0x84, 0xe8, 0x00, 0x1d, 0x69, 0x33,
+	0x00, 0x1e, 0x01, 0x06, 0xff, 0x18, 0x30, 0x40,
+	0xfd, 0xf1, 0x19, 0xc0, 0x00, 0x76, 0x2e, 0x40,
+	0xf7, 0xf1, 0x21, 0x48, 0x19, 0xc0, 0x84, 0x1b,
+	0x75, 0xe8, 0x10, 0xc0, 0x69, 0xe8, 0xa1, 0x49,
+	0xfd, 0xf0, 0x11, 0xc0, 0x00, 0x1a, 0x84, 0x1b,
+	0x6d, 0xe8, 0x62, 0xe8, 0xa5, 0x49, 0xfe, 0xf0,
+	0x09, 0xc0, 0x01, 0x19, 0x81, 0x1b, 0x66, 0xe8,
+	0x54, 0xe0, 0x10, 0xd4, 0x88, 0xd3, 0xb8, 0x0b,
+	0x50, 0xe8, 0x20, 0xb4, 0x10, 0xd8, 0x84, 0xd4,
+	0xfd, 0xc0, 0x52, 0xe8, 0x48, 0x33, 0xf9, 0xc0,
+	0x00, 0x61, 0x9c, 0x20, 0x9c, 0x24, 0xd0, 0x49,
+	0x04, 0xf0, 0x04, 0x11, 0x02, 0xf1, 0x03, 0xe0,
+	0x00, 0x11, 0x06, 0xf1, 0x5c, 0xc0, 0x00, 0x61,
+	0x92, 0x48, 0x00, 0x89, 0x3a, 0xe0, 0x06, 0x11,
+	0x06, 0xf1, 0x55, 0xc0, 0x00, 0x61, 0x11, 0x48,
+	0x00, 0x89, 0x33, 0xe0, 0x05, 0x11, 0x08, 0xf1,
+	0x4e, 0xc0, 0x00, 0x61, 0x91, 0x49, 0x04, 0xf0,
+	0x91, 0x48, 0x00, 0x89, 0x11, 0xe0, 0xd9, 0xc0,
+	0x00, 0x61, 0x98, 0x20, 0x98, 0x24, 0x25, 0x11,
+	0x24, 0xf1, 0x44, 0xc0, 0x29, 0xe8, 0x95, 0x49,
+	0x20, 0xf0, 0xcf, 0xc0, 0x00, 0x61, 0x98, 0x20,
+	0x98, 0x24, 0x25, 0x11, 0x1a, 0xf1, 0x37, 0xc0,
+	0x00, 0x61, 0x92, 0x49, 0x16, 0xf1, 0x12, 0x48,
+	0x00, 0x89, 0x2f, 0xc0, 0x00, 0x19, 0x00, 0x89,
+	0x2d, 0xc0, 0x01, 0x89, 0x2d, 0xc0, 0x04, 0x19,
+	0x81, 0x1b, 0x1c, 0xe8, 0x2a, 0xc0, 0x14, 0x19,
+	0x81, 0x1b, 0x18, 0xe8, 0x21, 0xc0, 0x0c, 0xe8,
+	0x1f, 0xc0, 0x12, 0x48, 0x81, 0x1b, 0x12, 0xe8,
+	0xae, 0xc3, 0x66, 0x71, 0xae, 0xc0, 0x02, 0x99,
+	0x02, 0xc0, 0x00, 0xb8, 0x96, 0x07, 0x13, 0xc4,
+	0x84, 0x98, 0x00, 0x1b, 0x86, 0x8b, 0x86, 0x73,
+	0xbf, 0x49, 0xfe, 0xf1, 0x80, 0x71, 0x82, 0x72,
+	0x80, 0xff, 0x09, 0xc4, 0x84, 0x98, 0x80, 0x99,
+	0x82, 0x9a, 0x86, 0x8b, 0x86, 0x73, 0xbf, 0x49,
+	0xfe, 0xf1, 0x80, 0xff, 0x08, 0xea, 0x30, 0xd4,
+	0x10, 0xc0, 0x12, 0xe8, 0x8a, 0xd3, 0x28, 0xe4,
+	0x2c, 0xe4, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00 };
+
+static u16 r8153_pla_patch_b_bp[] = {
+	0xfc26, 0x8000, 0xfc28, 0x1154, 0xfc2a, 0x1606, 0xfc2c, 0x155a,
+	0xfc2e, 0x0080, 0xfc30, 0x033c, 0xfc32, 0x01a0, 0xfc34, 0x0794,
+	0xfc36, 0x0000, 0xfc38, 0x007f };
+
+static u16 r8153_ram_code_d[] = {
+	0xB436, 0xB820, 0xB438, 0x0290, 0xB436, 0xA012, 0xB438, 0x0000,
+	0xB436, 0xA014, 0xB438, 0x2c04, 0xB438, 0x2c07, 0xB438, 0x2c07,
+	0xB438, 0x2c07, 0xB438, 0xa240, 0xB438, 0xa104, 0xB438, 0x2944,
+	0xB436, 0xA01A, 0xB438, 0x0000, 0xB436, 0xA006, 0xB438, 0x0fff,
+	0xB436, 0xA004, 0xB438, 0x0fff, 0xB436, 0xA002, 0xB438, 0x0fff,
+	0xB436, 0xA000, 0xB438, 0x1943, 0xB436, 0xB820, 0xB438, 0x0210 };
+
+static u8 usb_patch_d[] = {
+	0x08, 0xe0, 0x0e, 0xe0, 0x11, 0xe0, 0x24, 0xe0,
+	0x2b, 0xe0, 0x33, 0xe0, 0x3a, 0xe0, 0x3c, 0xe0,
+	0x1e, 0xc3, 0x70, 0x61, 0x12, 0x48, 0x70, 0x89,
+	0x02, 0xc3, 0x00, 0xbb, 0x02, 0x17, 0x32, 0x19,
+	0x02, 0xc3, 0x00, 0xbb, 0x44, 0x14, 0x30, 0x18,
+	0x11, 0xc1, 0x05, 0xe8, 0x10, 0xc6, 0x02, 0xc2,
+	0x00, 0xba, 0x94, 0x17, 0x02, 0xb4, 0x09, 0xc2,
+	0x40, 0x99, 0x0e, 0x48, 0x42, 0x98, 0x42, 0x70,
+	0x8e, 0x49, 0xfe, 0xf1, 0x02, 0xb0, 0x80, 0xff,
+	0xc0, 0xd4, 0xe4, 0x40, 0x20, 0xd4, 0x30, 0x18,
+	0x06, 0xc1, 0xf1, 0xef, 0xfc, 0xc7, 0x02, 0xc0,
+	0x00, 0xb8, 0x38, 0x12, 0xe4, 0x4b, 0x0c, 0x61,
+	0x92, 0x48, 0x93, 0x48, 0x95, 0x48, 0x96, 0x48,
+	0x0c, 0x89, 0x02, 0xc0, 0x00, 0xb8, 0x0e, 0x06,
+	0x30, 0x18, 0xf5, 0xc1, 0xe0, 0xef, 0x04, 0xc5,
+	0x02, 0xc4, 0x00, 0xbc, 0x76, 0x3c, 0x1e, 0xfc,
+	0x02, 0xc6, 0x00, 0xbe, 0x00, 0x00, 0x02, 0xc6,
+	0x00, 0xbe, 0x00, 0x00 };
+
+static u16 r8153_usb_patch_d_bp[] = {
+	0xfc26, 0xa000, 0xfc28, 0x16de, 0xfc2a, 0x1442, 0xfc2c, 0x1792,
+	0xfc2e, 0x1236, 0xfc30, 0x0606, 0xfc32, 0x3c74, 0xfc34, 0x0000,
+	0xfc36, 0x0000, 0xfc38, 0x003e };
+
+static u8 pla_patch_d[] = {
+	0x03, 0xe0, 0x16, 0xe0, 0x30, 0xe0, 0x12, 0xc2,
+	0x40, 0x73, 0xb0, 0x49, 0x08, 0xf0, 0xb8, 0x49,
+	0x06, 0xf0, 0xb8, 0x48, 0x40, 0x9b, 0x0b, 0xc2,
+	0x40, 0x76, 0x05, 0xe0, 0x02, 0x61, 0x02, 0xc3,
+	0x00, 0xbb, 0x54, 0x08, 0x02, 0xc3, 0x00, 0xbb,
+	0x64, 0x08, 0x98, 0xd3, 0x1e, 0xfc, 0xfe, 0xc0,
+	0x02, 0x62, 0xa0, 0x48, 0x02, 0x8a, 0x00, 0x72,
+	0xa0, 0x49, 0x11, 0xf0, 0x13, 0xc1, 0x20, 0x62,
+	0x2e, 0x21, 0x2f, 0x25, 0x00, 0x71, 0x9f, 0x24,
+	0x0a, 0x40, 0x09, 0xf0, 0x00, 0x71, 0x18, 0x48,
+	0xa0, 0x49, 0x03, 0xf1, 0x9f, 0x48, 0x02, 0xe0,
+	0x1f, 0x48, 0x00, 0x99, 0x02, 0xc2, 0x00, 0xba,
+	0xac, 0x0c, 0x08, 0xe9, 0x36, 0xc0, 0x00, 0x61,
+	0x9c, 0x20, 0x9c, 0x24, 0x33, 0xc0, 0x07, 0x11,
+	0x05, 0xf1, 0x00, 0x61, 0x17, 0x48, 0x00, 0x89,
+	0x0d, 0xe0, 0x04, 0x11, 0x0b, 0xf1, 0x00, 0x61,
+	0x97, 0x49, 0x08, 0xf0, 0x97, 0x48, 0x00, 0x89,
+	0x23, 0xc0, 0x0e, 0xe8, 0x12, 0x48, 0x81, 0x1b,
+	0x15, 0xe8, 0x1f, 0xc0, 0x00, 0x61, 0x67, 0x11,
+	0x04, 0xf0, 0x02, 0xc0, 0x00, 0xb8, 0x42, 0x09,
+	0x02, 0xc0, 0x00, 0xb8, 0x90, 0x08, 0x13, 0xc4,
+	0x84, 0x98, 0x00, 0x1b, 0x86, 0x8b, 0x86, 0x73,
+	0xbf, 0x49, 0xfe, 0xf1, 0x80, 0x71, 0x82, 0x72,
+	0x80, 0xff, 0x09, 0xc4, 0x84, 0x98, 0x80, 0x99,
+	0x82, 0x9a, 0x86, 0x8b, 0x86, 0x73, 0xbf, 0x49,
+	0xfe, 0xf1, 0x80, 0xff, 0x08, 0xea, 0x30, 0xd4,
+	0x50, 0xe8, 0x8a, 0xd3 };
+
+static u16 r8153_pla_patch_d_bp[] = {
+	0xfc26, 0x8000, 0xfc28, 0x0852, 0xfc2a, 0x0c92, 0xfc2c, 0x088c,
+	0xfc2e, 0x0000, 0xfc30, 0x0000, 0xfc32, 0x0000, 0xfc34, 0x0000,
+	0xfc36, 0x0000, 0xfc38, 0x0007 };
+
+static u8 usb_patch2_b[] = {
+	0x10, 0xe0, 0x26, 0xe0, 0x3a, 0xe0, 0x58, 0xe0,
+	0x6c, 0xe0, 0x85, 0xe0, 0xa5, 0xe0, 0xbe, 0xe0,
+	0xd8, 0xe0, 0xdb, 0xe0, 0xf3, 0xe0, 0xf5, 0xe0,
+	0xf7, 0xe0, 0xf9, 0xe0, 0xfb, 0xe0, 0xfd, 0xe0,
+	0x16, 0xc0, 0x00, 0x75, 0xd1, 0x49, 0x0d, 0xf0,
+	0x0f, 0xc0, 0x0f, 0xc5, 0x00, 0x1e, 0x08, 0x9e,
+	0x0c, 0x9d, 0x0c, 0xc6, 0x0a, 0x9e, 0x8f, 0x1c,
+	0x0e, 0x8c, 0x0e, 0x74, 0xcf, 0x49, 0xfe, 0xf1,
+	0x02, 0xc0, 0x00, 0xb8, 0x96, 0x31, 0x00, 0xdc,
+	0x24, 0xe4, 0x80, 0x02, 0x34, 0xd3, 0xff, 0xc3,
+	0x60, 0x72, 0xa1, 0x49, 0x0d, 0xf0, 0xf8, 0xc3,
+	0xf8, 0xc2, 0x00, 0x1c, 0x68, 0x9c, 0xf6, 0xc4,
+	0x6a, 0x9c, 0x6c, 0x9a, 0x8f, 0x1c, 0x6e, 0x8c,
+	0x6e, 0x74, 0xcf, 0x49, 0xfe, 0xf1, 0x04, 0xc0,
+	0x02, 0xc2, 0x00, 0xba, 0xa8, 0x28, 0xf8, 0xc7,
+	0xea, 0xc0, 0x00, 0x75, 0xd1, 0x49, 0x15, 0xf0,
+	0x19, 0xc7, 0x17, 0xc2, 0xec, 0x9a, 0x00, 0x19,
+	0xee, 0x89, 0xee, 0x71, 0x9f, 0x49, 0xfe, 0xf1,
+	0xea, 0x71, 0x9f, 0x49, 0x0a, 0xf0, 0xd9, 0xc2,
+	0xec, 0x9a, 0x00, 0x19, 0xe8, 0x99, 0x81, 0x19,
+	0xee, 0x89, 0xee, 0x71, 0x9f, 0x49, 0xfe, 0xf1,
+	0x06, 0xc3, 0x02, 0xc2, 0x00, 0xba, 0xf0, 0x1d,
+	0x4c, 0xe8, 0x00, 0xdc, 0x00, 0xd4, 0xcb, 0xc0,
+	0x00, 0x75, 0xd1, 0x49, 0x0d, 0xf0, 0xc4, 0xc0,
+	0xc4, 0xc5, 0x00, 0x1e, 0x08, 0x9e, 0xc2, 0xc6,
+	0x0a, 0x9e, 0x0c, 0x9d, 0x8f, 0x1c, 0x0e, 0x8c,
+	0x0e, 0x74, 0xcf, 0x49, 0xfe, 0xf1, 0x04, 0xc0,
+	0x02, 0xc1, 0x00, 0xb9, 0xc4, 0x16, 0x20, 0xd4,
+	0xb6, 0xc0, 0x00, 0x75, 0xd1, 0x48, 0x00, 0x9d,
+	0xe5, 0xc7, 0xaf, 0xc2, 0xec, 0x9a, 0x00, 0x19,
+	0xe8, 0x9a, 0x81, 0x19, 0xee, 0x89, 0xee, 0x71,
+	0x9f, 0x49, 0xfe, 0xf1, 0x2c, 0xc1, 0xec, 0x99,
+	0x81, 0x19, 0xee, 0x89, 0xee, 0x71, 0x9f, 0x49,
+	0xfe, 0xf1, 0x04, 0xc3, 0x02, 0xc2, 0x00, 0xba,
+	0x96, 0x1c, 0xc0, 0xd4, 0xc0, 0x88, 0x1e, 0xc6,
+	0xc0, 0x70, 0x8f, 0x49, 0x0e, 0xf0, 0x8f, 0x48,
+	0x93, 0xc6, 0xca, 0x98, 0x11, 0x18, 0xc8, 0x98,
+	0x16, 0xc0, 0xcc, 0x98, 0x8f, 0x18, 0xce, 0x88,
+	0xce, 0x70, 0x8f, 0x49, 0xfe, 0xf1, 0x0b, 0xe0,
+	0x43, 0xc6, 0x00, 0x18, 0xc8, 0x98, 0x0b, 0xc0,
+	0xcc, 0x98, 0x81, 0x18, 0xce, 0x88, 0xce, 0x70,
+	0x8f, 0x49, 0xfe, 0xf1, 0x02, 0xc0, 0x00, 0xb8,
+	0xf2, 0x19, 0x40, 0xd3, 0x20, 0xe4, 0x33, 0xc2,
+	0x40, 0x71, 0x91, 0x48, 0x40, 0x99, 0x30, 0xc2,
+	0x00, 0x19, 0x48, 0x99, 0xf8, 0xc1, 0x4c, 0x99,
+	0x81, 0x19, 0x4e, 0x89, 0x4e, 0x71, 0x9f, 0x49,
+	0xfe, 0xf1, 0x0b, 0xc1, 0x4c, 0x99, 0x81, 0x19,
+	0x4e, 0x89, 0x4e, 0x71, 0x9f, 0x49, 0xfe, 0xf1,
+	0x02, 0x71, 0x02, 0xc2, 0x00, 0xba, 0x0e, 0x34,
+	0x24, 0xe4, 0x19, 0xc2, 0x40, 0x71, 0x91, 0x48,
+	0x40, 0x99, 0x16, 0xc2, 0x00, 0x19, 0x48, 0x99,
+	0xde, 0xc1, 0x4c, 0x99, 0x81, 0x19, 0x4e, 0x89,
+	0x4e, 0x71, 0x9f, 0x49, 0xfe, 0xf1, 0xf1, 0xc1,
+	0x4c, 0x99, 0x81, 0x19, 0x4e, 0x89, 0x4e, 0x71,
+	0x9f, 0x49, 0xfe, 0xf1, 0x02, 0x71, 0x02, 0xc2,
+	0x00, 0xba, 0x60, 0x33, 0x34, 0xd3, 0x00, 0xdc,
+	0x1e, 0x89, 0x02, 0xc0, 0x00, 0xb8, 0xfa, 0x12,
+	0x18, 0xc0, 0x00, 0x65, 0xd1, 0x49, 0x0e, 0xf0,
+	0x11, 0xc0, 0x11, 0xc5, 0x00, 0x1e, 0x08, 0x9e,
+	0x0c, 0x9d, 0x0e, 0xc6, 0x0a, 0x9e, 0x8f, 0x1c,
+	0x0e, 0x8c, 0x0e, 0x74, 0xcf, 0x49, 0xfe, 0xf1,
+	0x04, 0xc0, 0x02, 0xc2, 0x00, 0xba, 0xa0, 0x41,
+	0x06, 0xd4, 0x00, 0xdc, 0x24, 0xe4, 0x80, 0x02,
+	0x34, 0xd3, 0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00,
+	0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00, 0x02, 0xc0,
+	0x00, 0xb8, 0x00, 0x00, 0x02, 0xc0, 0x00, 0xb8,
+	0x00, 0x00, 0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00,
+	0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00 };
+
+static u16 r8153b_usb_patch_b_bp[] = {
+	0xfc26, 0xa000, 0xfc28, 0x2a20, 0xfc2a, 0x28a6, 0xfc2c, 0x1dee,
+	0xfc2e, 0x16c2, 0xfc30, 0x1c94, 0xfc32, 0x19f0, 0xfc34, 0x340c,
+	0xfc36, 0x335e, 0xfc38, 0x12f8, 0xfc3a, 0x419e, 0xfc3c, 0x0000,
+	0xfc3e, 0x0000, 0xfc40, 0x0000, 0xfc42, 0x0000, 0xfc44, 0x0000,
+	0xfc46, 0x0000, 0xfc48, 0x03ff };
+
+static u8 pla_patch2_b[] = {
+	0x05, 0xe0, 0x1b, 0xe0, 0x2c, 0xe0, 0x60, 0xe0,
+	0x73, 0xe0, 0x15, 0xc6, 0xc2, 0x64, 0xd2, 0x49,
+	0x06, 0xf1, 0xc4, 0x48, 0xc5, 0x48, 0xc6, 0x48,
+	0xc7, 0x48, 0x05, 0xe0, 0x44, 0x48, 0x45, 0x48,
+	0x46, 0x48, 0x47, 0x48, 0xc2, 0x8c, 0xc0, 0x64,
+	0x46, 0x48, 0xc0, 0x8c, 0x05, 0xc5, 0x02, 0xc4,
+	0x00, 0xbc, 0x18, 0x02, 0x06, 0xdc, 0xb0, 0xc0,
+	0x10, 0xc5, 0xa0, 0x77, 0xa0, 0x74, 0x46, 0x48,
+	0x47, 0x48, 0xa0, 0x9c, 0x0b, 0xc5, 0xa0, 0x74,
+	0x44, 0x48, 0x43, 0x48, 0xa0, 0x9c, 0x05, 0xc5,
+	0xa0, 0x9f, 0x02, 0xc5, 0x00, 0xbd, 0x3c, 0x03,
+	0x1c, 0xe8, 0x20, 0xe8, 0xd4, 0x49, 0x04, 0xf1,
+	0xd5, 0x49, 0x20, 0xf1, 0x28, 0xe0, 0x2a, 0xc7,
+	0xe0, 0x75, 0xda, 0x49, 0x14, 0xf0, 0x27, 0xc7,
+	0xe0, 0x75, 0xdc, 0x49, 0x10, 0xf1, 0x24, 0xc7,
+	0xe0, 0x75, 0x25, 0xc7, 0xe0, 0x74, 0x2c, 0x40,
+	0x0a, 0xfa, 0x1f, 0xc7, 0xe4, 0x75, 0xd0, 0x49,
+	0x09, 0xf1, 0x1c, 0xc5, 0xe6, 0x9d, 0x11, 0x1d,
+	0xe4, 0x8d, 0x04, 0xe0, 0x16, 0xc7, 0x00, 0x1d,
+	0xe4, 0x8d, 0xe0, 0x8e, 0x11, 0x1d, 0xe0, 0x8d,
+	0x07, 0xe0, 0x0c, 0xc7, 0xe0, 0x75, 0xda, 0x48,
+	0xe0, 0x9d, 0x0b, 0xc7, 0xe4, 0x8e, 0x02, 0xc4,
+	0x00, 0xbc, 0x28, 0x03, 0x02, 0xc4, 0x00, 0xbc,
+	0x14, 0x03, 0x12, 0xe8, 0x4e, 0xe8, 0x1c, 0xe6,
+	0x20, 0xe4, 0x80, 0x02, 0xa4, 0xc0, 0x12, 0xc2,
+	0x40, 0x73, 0xb0, 0x49, 0x08, 0xf0, 0xb8, 0x49,
+	0x06, 0xf0, 0xb8, 0x48, 0x40, 0x9b, 0x0b, 0xc2,
+	0x40, 0x76, 0x05, 0xe0, 0x02, 0x61, 0x02, 0xc3,
+	0x00, 0xbb, 0x0a, 0x0a, 0x02, 0xc3, 0x00, 0xbb,
+	0x1a, 0x0a, 0x98, 0xd3, 0x1e, 0xfc, 0xfe, 0xc0,
+	0x02, 0x62, 0xa0, 0x48, 0x02, 0x8a, 0x00, 0x72,
+	0xa0, 0x49, 0x11, 0xf0, 0x13, 0xc1, 0x20, 0x62,
+	0x2e, 0x21, 0x2f, 0x25, 0x00, 0x71, 0x9f, 0x24,
+	0x0a, 0x40, 0x09, 0xf0, 0x00, 0x71, 0x18, 0x48,
+	0xa0, 0x49, 0x03, 0xf1, 0x9f, 0x48, 0x02, 0xe0,
+	0x1f, 0x48, 0x00, 0x99, 0x02, 0xc2, 0x00, 0xba,
+	0xda, 0x0e, 0x08, 0xe9 };
+
+static u16 r8153b_pla_patch_b_bp[] = {
+	0xfc26, 0x8000, 0xfc28, 0x0216, 0xfc2a, 0x0332, 0xfc2c, 0x030c,
+	0xfc2e, 0x0a08, 0xfc30, 0x0ec0, 0xfc32, 0x0000, 0xfc34, 0x0000,
+	0xfc36, 0x0000, 0xfc38, 0x001e };
+
+static void rtl_clear_bp(struct r8152 *tp, u16 type)
+{
+	u8 zeros[16] = {0};
+
+	switch (tp->version) {
+	case RTL_VER_01:
+	case RTL_VER_02:
+	case RTL_VER_07:
+		break;
+	case RTL_VER_03:
+	case RTL_VER_04:
+	case RTL_VER_05:
+	case RTL_VER_06:
+		ocp_write_byte(tp, type, PLA_BP_EN, 0);
+		break;
+	case RTL_VER_08:
+	case RTL_VER_09:
+	default:
+		if (type == MCU_TYPE_USB) {
+			ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0);
+
+			generic_ocp_write(tp, USB_BP(8), 0xff, sizeof(zeros),
+					  zeros, type);
+		} else {
+			ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
+		}
+		break;
+	}
+
+	generic_ocp_write(tp, USB_BP(0), 0xff, sizeof(zeros), zeros, type);
+
+	mdelay(6);
+
+	ocp_write_word(tp, type, PLA_BP_BA, 0);
+}
+
+static void r8152b_set_dq_desc(struct r8152 *tp)
+{
+	u8 data;
+
+	data = ocp_read_byte(tp, MCU_TYPE_USB, 0xd429);
+	data |= 0x80;
+	ocp_write_byte(tp, MCU_TYPE_USB, 0xd429, data);
+	ocp_write_word(tp, MCU_TYPE_USB, 0xc0ce, 0x0210);
+	data = ocp_read_byte(tp, MCU_TYPE_USB, 0xd429);
+	data &= ~0x80;
+	ocp_write_byte(tp, MCU_TYPE_USB, 0xd429, data);
+}
+
+static int r8153_pre_ram_code(struct r8152 *tp, u16 patch_key)
+{
+	u16 data;
+	int i;
+
+	data = ocp_reg_read(tp, 0xb820);
+	data |= 0x0010;
+	ocp_reg_write(tp, 0xb820, data);
+
+	for (i = 0, data = 0; !data && i < 5000; i++) {
+		mdelay(2);
+		data = ocp_reg_read(tp, 0xb800) & 0x0040;
+	}
+
+	sram_write(tp, 0x8146, patch_key);
+	sram_write(tp, 0xb82e, 0x0001);
+
+	return -EBUSY;
+}
+
+static int r8153_post_ram_code(struct r8152 *tp)
+{
+	u16 data;
+
+	sram_write(tp, 0x0000, 0x0000);
+
+	data = ocp_reg_read(tp, 0xb82e);
+	data &= ~0x0001;
+	ocp_reg_write(tp, 0xb82e, data);
+
+	sram_write(tp, 0x8146, 0x0000);
+
+	data = ocp_reg_read(tp, 0xb820);
+	data &= ~0x0010;
+	ocp_reg_write(tp, 0xb820, data);
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
+
+	return 0;
+}
+
+static void r8153_wdt1_end(struct r8152 *tp)
+{
+	int i;
+
+	for (i = 0; i < 104; i++) {
+		if (!(ocp_read_byte(tp, MCU_TYPE_USB, 0xe404) & 1))
+			break;
+		mdelay(2);
+	}
+}
+
+void r8152b_firmware(struct r8152 *tp)
+{
+	int i;
+
+	if (tp->version == RTL_VER_01) {
+		int i;
+
+		r8152b_set_dq_desc(tp);
+		rtl_clear_bp(tp, MCU_TYPE_PLA);
+
+		generic_ocp_write(tp, 0xf800, 0x3f,
+				  sizeof(r8152b_pla_patch_a),
+				  r8152b_pla_patch_a, MCU_TYPE_PLA);
+
+		for (i = 0; i < ARRAY_SIZE(r8152b_pla_patch_a_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8152b_pla_patch_a_bp[i],
+				       r8152b_pla_patch_a_bp[i+1]);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000);
+		ocp_write_word(tp, MCU_TYPE_PLA, 0xb092, 0x7070);
+		ocp_write_word(tp, MCU_TYPE_PLA, 0xb098, 0x0600);
+		for (i = 0; i < ARRAY_SIZE(r8152b_ram_code1); i++)
+			ocp_write_word(tp, MCU_TYPE_PLA, 0xb09a,
+				       r8152b_ram_code1[i]);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, 0xb098, 0x0200);
+		ocp_write_word(tp, MCU_TYPE_PLA, 0xb092, 0x7030);
+	} else if (tp->version == RTL_VER_02) {
+		rtl_clear_bp(tp, MCU_TYPE_PLA);
+
+		generic_ocp_write(tp, 0xf800, 0xff,
+				  sizeof(r8152b_pla_patch_a2),
+				  r8152b_pla_patch_a2, MCU_TYPE_PLA);
+
+		for (i = 0; i < ARRAY_SIZE(r8152b_pla_patch_a2_bp);
+		     i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8152b_pla_patch_a2_bp[i],
+				       r8152b_pla_patch_a2_bp[i+1]);
+	}
+}
+
+void r8153_firmware(struct r8152 *tp)
+{
+	int i;
+
+	if (tp->version == RTL_VER_03) {
+		r8153_pre_ram_code(tp, 0x7000);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_ram_code_a); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_ram_code_a[i],
+				       r8153_ram_code_a[i+1]);
+
+		r8153_post_ram_code(tp);
+	} else if (tp->version == RTL_VER_04) {
+		r8153_pre_ram_code(tp, 0x7001);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_ram_code_bc); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_ram_code_bc[i],
+				       r8153_ram_code_bc[i+1]);
+
+		r8153_post_ram_code(tp);
+
+		r8153_wdt1_end(tp);
+
+		rtl_clear_bp(tp, MCU_TYPE_USB);
+
+		ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
+		generic_ocp_write(tp, 0xf800, 0xff,
+				  sizeof(r8153_usb_patch_b),
+				  r8153_usb_patch_b, MCU_TYPE_USB);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_usb_patch_b_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_USB,
+				       r8153_usb_patch_b_bp[i],
+				       r8153_usb_patch_b_bp[i+1]);
+
+		if (!(ocp_read_word(tp, MCU_TYPE_PLA, 0xd38e) & BIT(0))) {
+			ocp_write_word(tp, MCU_TYPE_PLA, 0xd38c, 0x0082);
+			ocp_write_word(tp, MCU_TYPE_PLA, 0xd38e, 0x0082);
+		}
+
+		rtl_clear_bp(tp, MCU_TYPE_PLA);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
+		generic_ocp_write(tp, 0xf800, 0xff,
+				  sizeof(r8153_pla_patch_b),
+				  r8153_pla_patch_b, MCU_TYPE_PLA);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_pla_patch_b_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_pla_patch_b_bp[i],
+				       r8153_pla_patch_b_bp[i+1]);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, 0xd388, 0x08ca);
+	} else if (tp->version == RTL_VER_05) {
+		u32 ocp_data;
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xcfca);
+		ocp_data &= ~0x4000;
+		ocp_write_word(tp, MCU_TYPE_USB, 0xcfca, ocp_data);
+
+		r8153_pre_ram_code(tp, 0x7001);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_ram_code_bc); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_ram_code_bc[i],
+				       r8153_ram_code_bc[i+1]);
+
+		r8153_post_ram_code(tp);
+
+		r8153_wdt1_end(tp);
+
+		rtl_clear_bp(tp, MCU_TYPE_USB);
+
+		ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
+		generic_ocp_write(tp, 0xf800, 0xff,
+				  sizeof(r8153_usb_patch_c),
+				  r8153_usb_patch_c, MCU_TYPE_USB);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_usb_patch_c_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_USB,
+				       r8153_usb_patch_c_bp[i],
+				       r8153_usb_patch_c_bp[i+1]);
+
+		if (ocp_read_byte(tp, MCU_TYPE_USB, 0xcfef) & 1) {
+			ocp_write_word(tp, MCU_TYPE_USB, 0xfc30, 0x1578);
+			ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x00ff);
+		} else {
+			ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x00ef);
+		}
+
+		rtl_clear_bp(tp, MCU_TYPE_PLA);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
+		generic_ocp_write(tp, 0xf800, 0xff,
+				  sizeof(r8153_pla_patch_c),
+				  r8153_pla_patch_c, MCU_TYPE_PLA);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_pla_patch_c_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_pla_patch_c_bp[i],
+				       r8153_pla_patch_c_bp[i+1]);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, 0xd388, 0x08ca);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS,
+			       U3P3_CHECK_EN | 4);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, 0xcfca);
+		ocp_data |= 0x4000;
+		ocp_write_word(tp, MCU_TYPE_USB, 0xcfca, ocp_data);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
+		ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
+	} else if (tp->version == RTL_VER_06) {
+		u32 ocp_data;
+
+		r8153_pre_ram_code(tp, 0x7002);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_ram_code_d); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_ram_code_d[i],
+				       r8153_ram_code_d[i+1]);
+
+		r8153_post_ram_code(tp);
+
+		rtl_clear_bp(tp, MCU_TYPE_USB);
+
+		ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
+		generic_ocp_write(tp, 0xf800, 0xff, sizeof(usb_patch_d),
+				  usb_patch_d, MCU_TYPE_USB);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_usb_patch_d_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_USB,
+				       r8153_usb_patch_d_bp[i],
+				       r8153_usb_patch_d_bp[i+1]);
+
+		rtl_clear_bp(tp, MCU_TYPE_PLA);
+
+		ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
+		generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch_d),
+				  pla_patch_d, MCU_TYPE_PLA);
+
+		for (i = 0; i < ARRAY_SIZE(r8153_pla_patch_d_bp); i += 2)
+			ocp_write_word(tp, MCU_TYPE_PLA,
+				       r8153_pla_patch_d_bp[i],
+				       r8153_pla_patch_d_bp[i + 1]);
+
+		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
+		ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
+		ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
+
+		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
+		ocp_data |= FW_IP_RESET_EN;
+		ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
+	}
+}
+
+void r8153b_firmware(struct r8152 *tp)
+{
+	u32 ocp_data;
+	int i;
+
+	if (tp->version != RTL_VER_09)
+		return;
+
+	rtl_clear_bp(tp, MCU_TYPE_USB);
+
+	ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
+	generic_ocp_write(tp, 0xe600, 0xff, sizeof(usb_patch2_b),
+			  usb_patch2_b, MCU_TYPE_USB);
+
+	for (i = 0; i < ARRAY_SIZE(r8153b_usb_patch_b_bp); i += 2)
+		ocp_write_word(tp, MCU_TYPE_USB,
+			       r8153b_usb_patch_b_bp[i],
+			       r8153b_usb_patch_b_bp[i + 1]);
+
+	rtl_clear_bp(tp, MCU_TYPE_PLA);
+
+	ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
+	generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch2_b),
+			  pla_patch2_b, MCU_TYPE_PLA);
+
+	for (i = 0; i < ARRAY_SIZE(r8153b_pla_patch_b_bp); i += 2)
+		ocp_write_word(tp, MCU_TYPE_PLA,
+			       r8153b_pla_patch_b_bp[i],
+			       r8153b_pla_patch_b_bp[i + 1]);
+
+	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
+	ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
+	ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
+
+	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
+	ocp_data |= FW_IP_RESET_EN;
+	ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
+}
diff --git a/roms/u-boot/drivers/usb/eth/smsc95xx.c b/roms/u-boot/drivers/usb/eth/smsc95xx.c
new file mode 100644
index 000000000..283c52c16
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/smsc95xx.c
@@ -0,0 +1,1080 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (C) 2009 NVIDIA, Corporation
+ * Copyright (C) 2007-2008 SMSC (Steve Glendinning)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <net.h>
+#include <usb.h>
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+
+/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
+
+/* LED defines */
+#define LED_GPIO_CFG			(0x24)
+#define LED_GPIO_CFG_SPD_LED		(0x01000000)
+#define LED_GPIO_CFG_LNK_LED		(0x00100000)
+#define LED_GPIO_CFG_FDX_LED		(0x00010000)
+
+/* Tx command words */
+#define TX_CMD_A_FIRST_SEG_		0x00002000
+#define TX_CMD_A_LAST_SEG_		0x00001000
+
+/* Rx status word */
+#define RX_STS_FL_			0x3FFF0000	/* Frame Length */
+#define RX_STS_ES_			0x00008000	/* Error Summary */
+
+/* SCSRs */
+#define ID_REV				0x00
+
+#define INT_STS				0x08
+
+#define TX_CFG				0x10
+#define TX_CFG_ON_			0x00000004
+
+#define HW_CFG				0x14
+#define HW_CFG_BIR_			0x00001000
+#define HW_CFG_RXDOFF_			0x00000600
+#define HW_CFG_MEF_			0x00000020
+#define HW_CFG_BCE_			0x00000002
+#define HW_CFG_LRST_			0x00000008
+
+#define PM_CTRL				0x20
+#define PM_CTL_PHY_RST_			0x00000010
+
+#define AFC_CFG				0x2C
+
+/*
+ * Hi watermark = 15.5Kb (~10 mtu pkts)
+ * low watermark = 3k (~2 mtu pkts)
+ * backpressure duration = ~ 350us
+ * Apply FC on any frame.
+ */
+#define AFC_CFG_DEFAULT			0x00F830A1
+
+#define E2P_CMD				0x30
+#define E2P_CMD_BUSY_			0x80000000
+#define E2P_CMD_READ_			0x00000000
+#define E2P_CMD_TIMEOUT_		0x00000400
+#define E2P_CMD_LOADED_			0x00000200
+#define E2P_CMD_ADDR_			0x000001FF
+
+#define E2P_DATA			0x34
+
+#define BURST_CAP			0x38
+
+#define INT_EP_CTL			0x68
+#define INT_EP_CTL_PHY_INT_		0x00008000
+
+#define BULK_IN_DLY			0x6C
+
+/* MAC CSRs */
+#define MAC_CR				0x100
+#define MAC_CR_MCPAS_			0x00080000
+#define MAC_CR_PRMS_			0x00040000
+#define MAC_CR_HPFILT_			0x00002000
+#define MAC_CR_TXEN_			0x00000008
+#define MAC_CR_RXEN_			0x00000004
+
+#define ADDRH				0x104
+
+#define ADDRL				0x108
+
+#define MII_ADDR			0x114
+#define MII_WRITE_			0x02
+#define MII_BUSY_			0x01
+#define MII_READ_			0x00 /* ~of MII Write bit */
+
+#define MII_DATA			0x118
+
+#define FLOW				0x11C
+
+#define VLAN1				0x120
+
+#define COE_CR				0x130
+#define Tx_COE_EN_			0x00010000
+#define Rx_COE_EN_			0x00000001
+
+/* Vendor-specific PHY Definitions */
+#define PHY_INT_SRC			29
+
+#define PHY_INT_MASK			30
+#define PHY_INT_MASK_ANEG_COMP_		((u16)0x0040)
+#define PHY_INT_MASK_LINK_DOWN_		((u16)0x0010)
+#define PHY_INT_MASK_DEFAULT_		(PHY_INT_MASK_ANEG_COMP_ | \
+					 PHY_INT_MASK_LINK_DOWN_)
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER	0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER	0xA1
+
+/* Some extra defines */
+#define HS_USB_PKT_SIZE			512
+#define FS_USB_PKT_SIZE			64
+/* 5/33 is lower limit for BURST_CAP to work */
+#define DEFAULT_HS_BURST_CAP_SIZE	(5 * HS_USB_PKT_SIZE)
+#define DEFAULT_FS_BURST_CAP_SIZE	(33 * FS_USB_PKT_SIZE)
+#define DEFAULT_BULK_IN_DELAY		0x00002000
+#define MAX_SINGLE_PACKET_SIZE		2048
+#define EEPROM_MAC_OFFSET		0x01
+#define SMSC95XX_INTERNAL_PHY_ID	1
+#define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
+
+/* local defines */
+#define SMSC95XX_BASE_NAME "sms"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define RX_URB_SIZE DEFAULT_HS_BURST_CAP_SIZE
+#define PHY_CONNECT_TIMEOUT 5000
+
+#define TURBO_MODE
+
+#ifndef CONFIG_DM_ETH
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+#endif
+
+/* driver private */
+struct smsc95xx_private {
+#ifdef CONFIG_DM_ETH
+	struct ueth_data ueth;
+#endif
+	size_t rx_urb_size;  /* maximum USB URB size */
+	u32 mac_cr;  /* MAC control register value */
+	int have_hwaddr;  /* 1 if we have a hardware MAC address */
+};
+
+/*
+ * Smsc95xx infrastructure commands
+ */
+static int smsc95xx_write_reg(struct usb_device *udev, u32 index, u32 data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
+
+	cpu_to_le32s(&data);
+	tmpbuf[0] = data;
+
+	len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      USB_VENDOR_REQUEST_WRITE_REGISTER,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, index, tmpbuf, sizeof(data),
+			      USB_CTRL_SET_TIMEOUT);
+	if (len != sizeof(data)) {
+		debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d",
+		      index, data, len);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int smsc95xx_read_reg(struct usb_device *udev, u32 index, u32 *data)
+{
+	int len;
+	ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
+
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      USB_VENDOR_REQUEST_READ_REGISTER,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, index, tmpbuf, sizeof(*data),
+			      USB_CTRL_GET_TIMEOUT);
+	*data = tmpbuf[0];
+	if (len != sizeof(*data)) {
+		debug("smsc95xx_read_reg failed: index=%d, len=%d",
+		      index, len);
+		return -EIO;
+	}
+
+	le32_to_cpus(data);
+	return 0;
+}
+
+/* Loop until the read is completed with timeout */
+static int smsc95xx_phy_wait_not_busy(struct usb_device *udev)
+{
+	unsigned long start_time = get_timer(0);
+	u32 val;
+
+	do {
+		smsc95xx_read_reg(udev, MII_ADDR, &val);
+		if (!(val & MII_BUSY_))
+			return 0;
+	} while (get_timer(start_time) < 1000);
+
+	return -ETIMEDOUT;
+}
+
+static int smsc95xx_mdio_read(struct usb_device *udev, int phy_id, int idx)
+{
+	u32 val, addr;
+
+	/* confirm MII not busy */
+	if (smsc95xx_phy_wait_not_busy(udev)) {
+		debug("MII is busy in smsc95xx_mdio_read\n");
+		return -ETIMEDOUT;
+	}
+
+	/* set the address, index & direction (read from PHY) */
+	addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+	smsc95xx_write_reg(udev, MII_ADDR, addr);
+
+	if (smsc95xx_phy_wait_not_busy(udev)) {
+		debug("Timed out reading MII reg %02X\n", idx);
+		return -ETIMEDOUT;
+	}
+
+	smsc95xx_read_reg(udev, MII_DATA, &val);
+
+	return (u16)(val & 0xFFFF);
+}
+
+static void smsc95xx_mdio_write(struct usb_device *udev, int phy_id, int idx,
+				int regval)
+{
+	u32 val, addr;
+
+	/* confirm MII not busy */
+	if (smsc95xx_phy_wait_not_busy(udev)) {
+		debug("MII is busy in smsc95xx_mdio_write\n");
+		return;
+	}
+
+	val = regval;
+	smsc95xx_write_reg(udev, MII_DATA, val);
+
+	/* set the address, index & direction (write to PHY) */
+	addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+	smsc95xx_write_reg(udev, MII_ADDR, addr);
+
+	if (smsc95xx_phy_wait_not_busy(udev))
+		debug("Timed out writing MII reg %02X\n", idx);
+}
+
+static int smsc95xx_eeprom_confirm_not_busy(struct usb_device *udev)
+{
+	unsigned long start_time = get_timer(0);
+	u32 val;
+
+	do {
+		smsc95xx_read_reg(udev, E2P_CMD, &val);
+		if (!(val & E2P_CMD_BUSY_))
+			return 0;
+		udelay(40);
+	} while (get_timer(start_time) < 1 * 1000 * 1000);
+
+	debug("EEPROM is busy\n");
+	return -ETIMEDOUT;
+}
+
+static int smsc95xx_wait_eeprom(struct usb_device *udev)
+{
+	unsigned long start_time = get_timer(0);
+	u32 val;
+
+	do {
+		smsc95xx_read_reg(udev, E2P_CMD, &val);
+		if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
+			break;
+		udelay(40);
+	} while (get_timer(start_time) < 1 * 1000 * 1000);
+
+	if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
+		debug("EEPROM read operation timeout\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int smsc95xx_read_eeprom(struct usb_device *udev, u32 offset, u32 length,
+				u8 *data)
+{
+	u32 val;
+	int i, ret;
+
+	ret = smsc95xx_eeprom_confirm_not_busy(udev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < length; i++) {
+		val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
+		smsc95xx_write_reg(udev, E2P_CMD, val);
+
+		ret = smsc95xx_wait_eeprom(udev);
+		if (ret < 0)
+			return ret;
+
+		smsc95xx_read_reg(udev, E2P_DATA, &val);
+		data[i] = val & 0xFF;
+		offset++;
+	}
+	return 0;
+}
+
+/*
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ *
+ * Returns 0 on success, negative on error.
+ */
+static int mii_nway_restart(struct usb_device *udev, struct ueth_data *dev)
+{
+	int bmcr;
+	int r = -1;
+
+	/* if autoneg is off, it's an error */
+	bmcr = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMCR);
+
+	if (bmcr & BMCR_ANENABLE) {
+		bmcr |= BMCR_ANRESTART;
+		smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, bmcr);
+		r = 0;
+	}
+	return r;
+}
+
+static int smsc95xx_phy_initialize(struct usb_device *udev,
+				   struct ueth_data *dev)
+{
+	smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, BMCR_RESET);
+	smsc95xx_mdio_write(udev, dev->phy_id, MII_ADVERTISE,
+			    ADVERTISE_ALL | ADVERTISE_CSMA |
+			    ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+	/* read to clear */
+	smsc95xx_mdio_read(udev, dev->phy_id, PHY_INT_SRC);
+
+	smsc95xx_mdio_write(udev, dev->phy_id, PHY_INT_MASK,
+			    PHY_INT_MASK_DEFAULT_);
+	mii_nway_restart(udev, dev);
+
+	debug("phy initialised succesfully\n");
+	return 0;
+}
+
+static int smsc95xx_init_mac_address(unsigned char *enetaddr,
+				     struct usb_device *udev)
+{
+	int ret;
+
+	/* try reading mac address from EEPROM */
+	ret = smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN, enetaddr);
+	if (ret)
+		return ret;
+
+	if (is_valid_ethaddr(enetaddr)) {
+		/* eeprom values are valid so use them */
+		debug("MAC address read from EEPROM\n");
+		return 0;
+	}
+
+	/*
+	 * No eeprom, or eeprom values are invalid. Generating a random MAC
+	 * address is not safe. Just return an error.
+	 */
+	debug("Invalid MAC address read from EEPROM\n");
+
+	return -ENXIO;
+}
+
+static int smsc95xx_write_hwaddr_common(struct usb_device *udev,
+					struct smsc95xx_private *priv,
+					unsigned char *enetaddr)
+{
+	u32 addr_lo = get_unaligned_le32(&enetaddr[0]);
+	u32 addr_hi = get_unaligned_le16(&enetaddr[4]);
+	int ret;
+
+	/* set hardware address */
+	debug("** %s()\n", __func__);
+	ret = smsc95xx_write_reg(udev, ADDRL, addr_lo);
+	if (ret < 0)
+		return ret;
+
+	ret = smsc95xx_write_reg(udev, ADDRH, addr_hi);
+	if (ret < 0)
+		return ret;
+
+	debug("MAC %pM\n", enetaddr);
+	priv->have_hwaddr = 1;
+
+	return 0;
+}
+
+/* Enable or disable Tx & Rx checksum offload engines */
+static int smsc95xx_set_csums(struct usb_device *udev, int use_tx_csum,
+			      int use_rx_csum)
+{
+	u32 read_buf;
+	int ret = smsc95xx_read_reg(udev, COE_CR, &read_buf);
+	if (ret < 0)
+		return ret;
+
+	if (use_tx_csum)
+		read_buf |= Tx_COE_EN_;
+	else
+		read_buf &= ~Tx_COE_EN_;
+
+	if (use_rx_csum)
+		read_buf |= Rx_COE_EN_;
+	else
+		read_buf &= ~Rx_COE_EN_;
+
+	ret = smsc95xx_write_reg(udev, COE_CR, read_buf);
+	if (ret < 0)
+		return ret;
+
+	debug("COE_CR = 0x%08x\n", read_buf);
+	return 0;
+}
+
+static void smsc95xx_set_multicast(struct smsc95xx_private *priv)
+{
+	/* No multicast in u-boot */
+	priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+}
+
+/* starts the TX path */
+static void smsc95xx_start_tx_path(struct usb_device *udev,
+				   struct smsc95xx_private *priv)
+{
+	u32 reg_val;
+
+	/* Enable Tx at MAC */
+	priv->mac_cr |= MAC_CR_TXEN_;
+
+	smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
+
+	/* Enable Tx at SCSRs */
+	reg_val = TX_CFG_ON_;
+	smsc95xx_write_reg(udev, TX_CFG, reg_val);
+}
+
+/* Starts the Receive path */
+static void smsc95xx_start_rx_path(struct usb_device *udev,
+				   struct smsc95xx_private *priv)
+{
+	priv->mac_cr |= MAC_CR_RXEN_;
+	smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
+}
+
+static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev,
+				struct smsc95xx_private *priv,
+				unsigned char *enetaddr)
+{
+	int ret;
+	u32 write_buf;
+	u32 read_buf;
+	u32 burst_cap;
+	int timeout;
+#define TIMEOUT_RESOLUTION 50	/* ms */
+	int link_detected;
+
+	debug("** %s()\n", __func__);
+	dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */
+
+	write_buf = HW_CFG_LRST_;
+	ret = smsc95xx_write_reg(udev, HW_CFG, write_buf);
+	if (ret < 0)
+		return ret;
+
+	timeout = 0;
+	do {
+		ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
+		if (ret < 0)
+			return ret;
+		udelay(10 * 1000);
+		timeout++;
+	} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
+
+	if (timeout >= 100) {
+		debug("timeout waiting for completion of Lite Reset\n");
+		return -ETIMEDOUT;
+	}
+
+	write_buf = PM_CTL_PHY_RST_;
+	ret = smsc95xx_write_reg(udev, PM_CTRL, write_buf);
+	if (ret < 0)
+		return ret;
+
+	timeout = 0;
+	do {
+		ret = smsc95xx_read_reg(udev, PM_CTRL, &read_buf);
+		if (ret < 0)
+			return ret;
+		udelay(10 * 1000);
+		timeout++;
+	} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
+	if (timeout >= 100) {
+		debug("timeout waiting for PHY Reset\n");
+		return -ETIMEDOUT;
+	}
+#ifndef CONFIG_DM_ETH
+	if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) ==
+			0)
+		priv->have_hwaddr = 1;
+#endif
+	if (!priv->have_hwaddr) {
+		puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n");
+		return -EADDRNOTAVAIL;
+	}
+	ret = smsc95xx_write_hwaddr_common(udev, priv, enetaddr);
+	if (ret < 0)
+		return ret;
+
+#ifdef TURBO_MODE
+	if (dev->pusb_dev->speed == USB_SPEED_HIGH) {
+		burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+		priv->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+	} else {
+		burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+		priv->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+	}
+#else
+	burst_cap = 0;
+	priv->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+#endif
+	debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size);
+
+	ret = smsc95xx_write_reg(udev, BURST_CAP, burst_cap);
+	if (ret < 0)
+		return ret;
+
+	ret = smsc95xx_read_reg(udev, BURST_CAP, &read_buf);
+	if (ret < 0)
+		return ret;
+	debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf);
+
+	read_buf = DEFAULT_BULK_IN_DELAY;
+	ret = smsc95xx_write_reg(udev, BULK_IN_DLY, read_buf);
+	if (ret < 0)
+		return ret;
+
+	ret = smsc95xx_read_reg(udev, BULK_IN_DLY, &read_buf);
+	if (ret < 0)
+		return ret;
+	debug("Read Value from BULK_IN_DLY after writing: "
+			"0x%08x\n", read_buf);
+
+	ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
+	if (ret < 0)
+		return ret;
+	debug("Read Value from HW_CFG: 0x%08x\n", read_buf);
+
+#ifdef TURBO_MODE
+	read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
+#endif
+	read_buf &= ~HW_CFG_RXDOFF_;
+
+#define NET_IP_ALIGN 0
+	read_buf |= NET_IP_ALIGN << 9;
+
+	ret = smsc95xx_write_reg(udev, HW_CFG, read_buf);
+	if (ret < 0)
+		return ret;
+
+	ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
+	if (ret < 0)
+		return ret;
+	debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
+
+	write_buf = 0xFFFFFFFF;
+	ret = smsc95xx_write_reg(udev, INT_STS, write_buf);
+	if (ret < 0)
+		return ret;
+
+	ret = smsc95xx_read_reg(udev, ID_REV, &read_buf);
+	if (ret < 0)
+		return ret;
+	debug("ID_REV = 0x%08x\n", read_buf);
+
+	/* Configure GPIO pins as LED outputs */
+	write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
+		LED_GPIO_CFG_FDX_LED;
+	ret = smsc95xx_write_reg(udev, LED_GPIO_CFG, write_buf);
+	if (ret < 0)
+		return ret;
+	debug("LED_GPIO_CFG set\n");
+
+	/* Init Tx */
+	write_buf = 0;
+	ret = smsc95xx_write_reg(udev, FLOW, write_buf);
+	if (ret < 0)
+		return ret;
+
+	read_buf = AFC_CFG_DEFAULT;
+	ret = smsc95xx_write_reg(udev, AFC_CFG, read_buf);
+	if (ret < 0)
+		return ret;
+
+	ret = smsc95xx_read_reg(udev, MAC_CR, &priv->mac_cr);
+	if (ret < 0)
+		return ret;
+
+	/* Init Rx. Set Vlan */
+	write_buf = (u32)ETH_P_8021Q;
+	ret = smsc95xx_write_reg(udev, VLAN1, write_buf);
+	if (ret < 0)
+		return ret;
+
+	/* Disable checksum offload engines */
+	ret = smsc95xx_set_csums(udev, 0, 0);
+	if (ret < 0) {
+		debug("Failed to set csum offload: %d\n", ret);
+		return ret;
+	}
+	smsc95xx_set_multicast(priv);
+
+	ret = smsc95xx_phy_initialize(udev, dev);
+	if (ret < 0)
+		return ret;
+	ret = smsc95xx_read_reg(udev, INT_EP_CTL, &read_buf);
+	if (ret < 0)
+		return ret;
+
+	/* enable PHY interrupts */
+	read_buf |= INT_EP_CTL_PHY_INT_;
+
+	ret = smsc95xx_write_reg(udev, INT_EP_CTL, read_buf);
+	if (ret < 0)
+		return ret;
+
+	smsc95xx_start_tx_path(udev, priv);
+	smsc95xx_start_rx_path(udev, priv);
+
+	timeout = 0;
+	do {
+		link_detected = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMSR)
+			& BMSR_LSTATUS;
+		if (!link_detected) {
+			if (timeout == 0)
+				printf("Waiting for Ethernet connection... ");
+			udelay(TIMEOUT_RESOLUTION * 1000);
+			timeout += TIMEOUT_RESOLUTION;
+		}
+	} while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+	if (link_detected) {
+		if (timeout != 0)
+			printf("done.\n");
+	} else {
+		printf("unable to connect.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length)
+{
+	int err;
+	int actual_len;
+	u32 tx_cmd_a;
+	u32 tx_cmd_b;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+				 PKTSIZE + sizeof(tx_cmd_a) + sizeof(tx_cmd_b));
+
+	debug("** %s(), len %d, buf %#x\n", __func__, length,
+	      (unsigned int)(ulong)msg);
+	if (length > PKTSIZE)
+		return -ENOSPC;
+
+	tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+	tx_cmd_b = (u32)length;
+	cpu_to_le32s(&tx_cmd_a);
+	cpu_to_le32s(&tx_cmd_b);
+
+	/* prepend cmd_a and cmd_b */
+	memcpy(msg, &tx_cmd_a, sizeof(tx_cmd_a));
+	memcpy(msg + sizeof(tx_cmd_a), &tx_cmd_b, sizeof(tx_cmd_b));
+	memcpy(msg + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), (void *)packet,
+	       length);
+	err = usb_bulk_msg(dev->pusb_dev,
+				usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+				(void *)msg,
+				length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
+				&actual_len,
+				USB_BULK_SEND_TIMEOUT);
+	debug("Tx: len = %u, actual = %u, err = %d\n",
+	      (unsigned int)(length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b)),
+	      (unsigned int)actual_len, err);
+
+	return err;
+}
+
+#ifndef CONFIG_DM_ETH
+/*
+ * Smsc95xx callbacks
+ */
+static int smsc95xx_init(struct eth_device *eth, struct bd_info *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	struct usb_device *udev = dev->pusb_dev;
+	struct smsc95xx_private *priv =
+		(struct smsc95xx_private *)dev->dev_priv;
+
+	return smsc95xx_init_common(udev, dev, priv, eth->enetaddr);
+}
+
+static int smsc95xx_send(struct eth_device *eth, void *packet, int length)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	return smsc95xx_send_common(dev, packet, length);
+}
+
+static int smsc95xx_recv(struct eth_device *eth)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+	DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, RX_URB_SIZE);
+	unsigned char *buf_ptr;
+	int err;
+	int actual_len;
+	u32 packet_len;
+	int cur_buf_align;
+
+	debug("** %s()\n", __func__);
+	err = usb_bulk_msg(dev->pusb_dev,
+			   usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+			   (void *)recv_buf, RX_URB_SIZE, &actual_len,
+			   USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE,
+	      actual_len, err);
+	if (err != 0) {
+		debug("Rx: failed to receive\n");
+		return -err;
+	}
+	if (actual_len > RX_URB_SIZE) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -ENOSPC;
+	}
+
+	buf_ptr = recv_buf;
+	while (actual_len > 0) {
+		/*
+		 * 1st 4 bytes contain the length of the actual data plus error
+		 * info. Extract data length.
+		 */
+		if (actual_len < sizeof(packet_len)) {
+			debug("Rx: incomplete packet length\n");
+			return -EIO;
+		}
+		memcpy(&packet_len, buf_ptr, sizeof(packet_len));
+		le32_to_cpus(&packet_len);
+		if (packet_len & RX_STS_ES_) {
+			debug("Rx: Error header=%#x", packet_len);
+			return -EIO;
+		}
+		packet_len = ((packet_len & RX_STS_FL_) >> 16);
+
+		if (packet_len > actual_len - sizeof(packet_len)) {
+			debug("Rx: too large packet: %d\n", packet_len);
+			return -EIO;
+		}
+
+		/* Notify net stack */
+		net_process_received_packet(buf_ptr + sizeof(packet_len),
+					    packet_len - 4);
+
+		/* Adjust for next iteration */
+		actual_len -= sizeof(packet_len) + packet_len;
+		buf_ptr += sizeof(packet_len) + packet_len;
+		cur_buf_align = (ulong)buf_ptr - (ulong)recv_buf;
+
+		if (cur_buf_align & 0x03) {
+			int align = 4 - (cur_buf_align & 0x03);
+
+			actual_len -= align;
+			buf_ptr += align;
+		}
+	}
+	return err;
+}
+
+static void smsc95xx_halt(struct eth_device *eth)
+{
+	debug("** %s()\n", __func__);
+}
+
+static int smsc95xx_write_hwaddr(struct eth_device *eth)
+{
+	struct ueth_data *dev = eth->priv;
+	struct usb_device *udev = dev->pusb_dev;
+	struct smsc95xx_private *priv = dev->dev_priv;
+
+	return smsc95xx_write_hwaddr_common(udev, priv, eth->enetaddr);
+}
+
+/*
+ * SMSC probing functions
+ */
+void smsc95xx_eth_before_probe(void)
+{
+	curr_eth_dev = 0;
+}
+
+struct smsc95xx_dongle {
+	unsigned short vendor;
+	unsigned short product;
+};
+
+static const struct smsc95xx_dongle smsc95xx_dongles[] = {
+	{ 0x0424, 0xec00 },	/* LAN9512/LAN9514 Ethernet */
+	{ 0x0424, 0x9500 },	/* LAN9500 Ethernet */
+	{ 0x0424, 0x9730 },	/* LAN9730 Ethernet (HSIC) */
+	{ 0x0424, 0x9900 },	/* SMSC9500 USB Ethernet Device (SAL10) */
+	{ 0x0424, 0x9e00 },	/* LAN9500A Ethernet */
+	{ 0x0000, 0x0000 }	/* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an SMSC device */
+int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,
+		      struct ueth_data *ss)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *iface_desc;
+	int i;
+
+	/* let's examine the device now */
+	iface = &dev->config.if_desc[ifnum];
+	iface_desc = &dev->config.if_desc[ifnum].desc;
+
+	for (i = 0; smsc95xx_dongles[i].vendor != 0; i++) {
+		if (dev->descriptor.idVendor == smsc95xx_dongles[i].vendor &&
+		    dev->descriptor.idProduct == smsc95xx_dongles[i].product)
+			/* Found a supported dongle */
+			break;
+	}
+	if (smsc95xx_dongles[i].vendor == 0)
+		return 0;
+
+	/* At this point, we know we've got a live one */
+	debug("\n\nUSB Ethernet device detected\n");
+	memset(ss, '\0', sizeof(struct ueth_data));
+
+	/* Initialize the ueth_data structure with some useful info */
+	ss->ifnum = ifnum;
+	ss->pusb_dev = dev;
+	ss->subclass = iface_desc->bInterfaceSubClass;
+	ss->protocol = iface_desc->bInterfaceProtocol;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		/* is it an BULK endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
+				ss->ep_in =
+					iface->ep_desc[i].bEndpointAddress &
+					USB_ENDPOINT_NUMBER_MASK;
+			else
+				ss->ep_out =
+					iface->ep_desc[i].bEndpointAddress &
+					USB_ENDPOINT_NUMBER_MASK;
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ss->irqinterval = iface->ep_desc[i].bInterval;
+		}
+	}
+	debug("Endpoints In %d Out %d Int %d\n",
+		  ss->ep_in, ss->ep_out, ss->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+	    !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+		debug("Problems with device\n");
+		return 0;
+	}
+	dev->privptr = (void *)ss;
+
+	/* alloc driver private */
+	ss->dev_priv = calloc(1, sizeof(struct smsc95xx_private));
+	if (!ss->dev_priv)
+		return 0;
+
+	return 1;
+}
+
+int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+				struct eth_device *eth)
+{
+	debug("** %s()\n", __func__);
+	if (!eth) {
+		debug("%s: missing parameter.\n", __func__);
+		return 0;
+	}
+	sprintf(eth->name, "%s%d", SMSC95XX_BASE_NAME, curr_eth_dev++);
+	eth->init = smsc95xx_init;
+	eth->send = smsc95xx_send;
+	eth->recv = smsc95xx_recv;
+	eth->halt = smsc95xx_halt;
+	eth->write_hwaddr = smsc95xx_write_hwaddr;
+	eth->priv = ss;
+	return 1;
+}
+#endif /* !CONFIG_DM_ETH */
+
+#ifdef CONFIG_DM_ETH
+static int smsc95xx_eth_start(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct smsc95xx_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+
+	/* Driver-model Ethernet ensures we have this */
+	priv->have_hwaddr = 1;
+
+	return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr);
+}
+
+void smsc95xx_eth_stop(struct udevice *dev)
+{
+	debug("** %s()\n", __func__);
+}
+
+int smsc95xx_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct smsc95xx_private *priv = dev_get_priv(dev);
+
+	return smsc95xx_send_common(&priv->ueth, packet, length);
+}
+
+int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct smsc95xx_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+	uint8_t *ptr;
+	int ret, len;
+	u32 packet_len;
+
+	len = usb_ether_get_rx_bytes(ueth, &ptr);
+	debug("%s: first try, len=%d\n", __func__, len);
+	if (!len) {
+		if (!(flags & ETH_RECV_CHECK_DEVICE))
+			return -EAGAIN;
+		ret = usb_ether_receive(ueth, RX_URB_SIZE);
+		if (ret == -EAGAIN)
+			return ret;
+
+		len = usb_ether_get_rx_bytes(ueth, &ptr);
+		debug("%s: second try, len=%d\n", __func__, len);
+	}
+
+	/*
+	 * 1st 4 bytes contain the length of the actual data plus error info.
+	 * Extract data length.
+	 */
+	if (len < sizeof(packet_len)) {
+		debug("Rx: incomplete packet length\n");
+		goto err;
+	}
+	memcpy(&packet_len, ptr, sizeof(packet_len));
+	le32_to_cpus(&packet_len);
+	if (packet_len & RX_STS_ES_) {
+		debug("Rx: Error header=%#x", packet_len);
+		goto err;
+	}
+	packet_len = ((packet_len & RX_STS_FL_) >> 16);
+
+	if (packet_len > len - sizeof(packet_len)) {
+		debug("Rx: too large packet: %d\n", packet_len);
+		goto err;
+	}
+
+	*packetp = ptr + sizeof(packet_len);
+	return packet_len - 4;
+
+err:
+	usb_ether_advance_rxbuf(ueth, -1);
+	return -EINVAL;
+}
+
+static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+	struct smsc95xx_private *priv = dev_get_priv(dev);
+
+	packet_len = ALIGN(packet_len + sizeof(u32), 4);
+	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+	return 0;
+}
+
+int smsc95xx_write_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct smsc95xx_private *priv = dev_get_priv(dev);
+
+	return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr);
+}
+
+int smsc95xx_read_rom_hwaddr(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	int ret;
+
+	ret = smsc95xx_init_mac_address(pdata->enetaddr, udev);
+	if (ret)
+		memset(pdata->enetaddr, 0, 6);
+
+	return 0;
+}
+
+static int smsc95xx_eth_probe(struct udevice *dev)
+{
+	struct smsc95xx_private *priv = dev_get_priv(dev);
+	struct ueth_data *ueth = &priv->ueth;
+
+	return usb_ether_register(dev, ueth, RX_URB_SIZE);
+}
+
+static const struct eth_ops smsc95xx_eth_ops = {
+	.start	= smsc95xx_eth_start,
+	.send	= smsc95xx_eth_send,
+	.recv	= smsc95xx_eth_recv,
+	.free_pkt = smsc95xx_free_pkt,
+	.stop	= smsc95xx_eth_stop,
+	.write_hwaddr = smsc95xx_write_hwaddr,
+	.read_rom_hwaddr = smsc95xx_read_rom_hwaddr,
+};
+
+U_BOOT_DRIVER(smsc95xx_eth) = {
+	.name	= "smsc95xx_eth",
+	.id	= UCLASS_ETH,
+	.probe = smsc95xx_eth_probe,
+	.ops	= &smsc95xx_eth_ops,
+	.priv_auto	= sizeof(struct smsc95xx_private),
+	.plat_auto	= sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id smsc95xx_eth_id_table[] = {
+	{ USB_DEVICE(0x05ac, 0x1402) },
+	{ USB_DEVICE(0x0424, 0xec00) },	/* LAN9512/LAN9514 Ethernet */
+	{ USB_DEVICE(0x0424, 0x9500) },	/* LAN9500 Ethernet */
+	{ USB_DEVICE(0x0424, 0x9730) },	/* LAN9730 Ethernet (HSIC) */
+	{ USB_DEVICE(0x0424, 0x9900) },	/* SMSC9500 USB Ethernet (SAL10) */
+	{ USB_DEVICE(0x0424, 0x9e00) },	/* LAN9500A Ethernet */
+	{ }		/* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table);
+#endif
diff --git a/roms/u-boot/drivers/usb/eth/usb_ether.c b/roms/u-boot/drivers/usb/eth/usb_ether.c
new file mode 100644
index 000000000..e368ecda0
--- /dev/null
+++ b/roms/u-boot/drivers/usb/eth/usb_ether.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <net.h>
+#include <usb.h>
+#include <asm/cache.h>
+#include <dm/device-internal.h>
+
+#include "usb_ether.h"
+
+#ifdef CONFIG_DM_ETH
+
+#define USB_BULK_RECV_TIMEOUT 500
+
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct usb_interface_descriptor *iface_desc;
+	bool ep_in_found = false, ep_out_found = false;
+	struct usb_interface *iface;
+	const int ifnum = 0; /* Always use interface 0 */
+	int ret, i;
+
+	iface = &udev->config.if_desc[ifnum];
+	iface_desc = &udev->config.if_desc[ifnum].desc;
+
+	/* Initialize the ueth_data structure with some useful info */
+	ueth->ifnum = ifnum;
+	ueth->subclass = iface_desc->bInterfaceSubClass;
+	ueth->protocol = iface_desc->bInterfaceProtocol;
+
+	/*
+	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+		int ep_addr = iface->ep_desc[i].bEndpointAddress;
+
+		/* is it an BULK endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			if (ep_addr & USB_DIR_IN && !ep_in_found) {
+				ueth->ep_in = ep_addr &
+					USB_ENDPOINT_NUMBER_MASK;
+				ep_in_found = true;
+			} else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
+				ueth->ep_out = ep_addr &
+					USB_ENDPOINT_NUMBER_MASK;
+				ep_out_found = true;
+			}
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((iface->ep_desc[i].bmAttributes &
+		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ueth->ep_int = iface->ep_desc[i].bEndpointAddress &
+				USB_ENDPOINT_NUMBER_MASK;
+			ueth->irqinterval = iface->ep_desc[i].bInterval;
+		}
+	}
+	debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out,
+	      ueth->ep_int);
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) {
+		debug("%s: %s: Cannot find endpoints\n", __func__, dev->name);
+		return -ENXIO;
+	}
+
+	ueth->rxsize = rxsize;
+	ueth->rxbuf = memalign(ARCH_DMA_MINALIGN, rxsize);
+	if (!ueth->rxbuf)
+		return -ENOMEM;
+
+	ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum);
+	if (ret) {
+		debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name,
+		      ret);
+		return ret;
+	}
+	ueth->pusb_dev = udev;
+
+	return 0;
+}
+
+int usb_ether_deregister(struct ueth_data *ueth)
+{
+	return 0;
+}
+
+int usb_ether_receive(struct ueth_data *ueth, int rxsize)
+{
+	int actual_len;
+	int ret;
+
+	if (rxsize > ueth->rxsize)
+		return -EINVAL;
+	ret = usb_bulk_msg(ueth->pusb_dev,
+			   usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
+			   ueth->rxbuf, rxsize, &actual_len,
+			   USB_BULK_RECV_TIMEOUT);
+	debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret);
+	if (ret) {
+		printf("Rx: failed to receive: %d\n", ret);
+		return ret;
+	}
+	if (actual_len > rxsize) {
+		debug("Rx: received too many bytes %d\n", actual_len);
+		return -ENOSPC;
+	}
+	ueth->rxlen = actual_len;
+	ueth->rxptr = 0;
+
+	return actual_len ? 0 : -EAGAIN;
+}
+
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes)
+{
+	ueth->rxptr += num_bytes;
+	if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen)
+		ueth->rxlen = 0;
+}
+
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp)
+{
+	if (!ueth->rxlen)
+		return 0;
+
+	*ptrp = &ueth->rxbuf[ueth->rxptr];
+
+	return ueth->rxlen - ueth->rxptr;
+}
+
+#else
+
+typedef void (*usb_eth_before_probe)(void);
+typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
+			struct ueth_data *ss);
+typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss,
+			struct eth_device *dev_desc);
+
+struct usb_eth_prob_dev {
+	usb_eth_before_probe	before_probe; /* optional */
+	usb_eth_probe			probe;
+	usb_eth_get_info		get_info;
+};
+
+/* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */
+static const struct usb_eth_prob_dev prob_dev[] = {
+#ifdef CONFIG_USB_ETHER_ASIX
+	{
+		.before_probe = asix_eth_before_probe,
+		.probe = asix_eth_probe,
+		.get_info = asix_eth_get_info,
+	},
+#endif
+#ifdef CONFIG_USB_ETHER_ASIX88179
+	{
+		.before_probe = ax88179_eth_before_probe,
+		.probe = ax88179_eth_probe,
+		.get_info = ax88179_eth_get_info,
+	},
+#endif
+#ifdef CONFIG_USB_ETHER_MCS7830
+	{
+		.before_probe = mcs7830_eth_before_probe,
+		.probe = mcs7830_eth_probe,
+		.get_info = mcs7830_eth_get_info,
+	},
+#endif
+#ifdef CONFIG_USB_ETHER_SMSC95XX
+	{
+		.before_probe = smsc95xx_eth_before_probe,
+		.probe = smsc95xx_eth_probe,
+		.get_info = smsc95xx_eth_get_info,
+	},
+#endif
+#ifdef CONFIG_USB_ETHER_RTL8152
+	{
+		.before_probe = r8152_eth_before_probe,
+		.probe = r8152_eth_probe,
+		.get_info = r8152_eth_get_info,
+	},
+#endif
+	{ },		/* END */
+};
+
+static int usb_max_eth_dev; /* number of highest available usb eth device */
+static struct ueth_data usb_eth[USB_MAX_ETH_DEV];
+
+/*******************************************************************************
+ * tell if current ethernet device is a usb dongle
+ */
+int is_eth_dev_on_usb_host(void)
+{
+	int i;
+	struct eth_device *dev = eth_get_dev();
+
+	if (dev) {
+		for (i = 0; i < usb_max_eth_dev; i++)
+			if (&usb_eth[i].eth_dev == dev)
+				return 1;
+	}
+	return 0;
+}
+
+/*
+ * Given a USB device, ask each driver if it can support it, and attach it
+ * to the first driver that says 'yes'
+ */
+static void probe_valid_drivers(struct usb_device *dev)
+{
+	struct eth_device *eth;
+	int j;
+
+	for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) {
+		if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev]))
+			continue;
+		/*
+		 * ok, it is a supported eth device. Get info and fill it in
+		 */
+		eth = &usb_eth[usb_max_eth_dev].eth_dev;
+		if (prob_dev[j].get_info(dev,
+			&usb_eth[usb_max_eth_dev],
+			eth)) {
+			/* found proper driver */
+			/* register with networking stack */
+			usb_max_eth_dev++;
+
+			/*
+			 * usb_max_eth_dev must be incremented prior to this
+			 * call since eth_current_changed (internally called)
+			 * relies on it
+			 */
+			eth_register(eth);
+			if (eth_write_hwaddr(eth, "usbeth",
+					usb_max_eth_dev - 1))
+				puts("Warning: failed to set MAC address\n");
+			break;
+			}
+		}
+	}
+
+/*******************************************************************************
+ * scan the usb and reports device info
+ * to the user if mode = 1
+ * returns current device or -1 if no
+ */
+int usb_host_eth_scan(int mode)
+{
+	int i, old_async;
+
+	if (mode == 1)
+		printf("       scanning usb for ethernet devices... ");
+
+	old_async = usb_disable_asynch(1); /* asynch transfer not allowed */
+
+	/* unregister a previously detected device */
+	for (i = 0; i < usb_max_eth_dev; i++)
+		eth_unregister(&usb_eth[i].eth_dev);
+
+	memset(usb_eth, 0, sizeof(usb_eth));
+
+	for (i = 0; prob_dev[i].probe; i++) {
+		if (prob_dev[i].before_probe)
+			prob_dev[i].before_probe();
+	}
+
+	usb_max_eth_dev = 0;
+#if CONFIG_IS_ENABLED(DM_USB)
+	/*
+	 * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+	 * Ethernet driver and then most of this file can be removed.
+	 */
+	struct udevice *bus;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_USB, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(bus, uc) {
+		for (i = 0; i < USB_MAX_DEVICE; i++) {
+			struct usb_device *dev;
+
+			dev = usb_get_dev_index(bus, i); /* get device */
+			debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)");
+			if (!dev)
+				break; /* no more devices available */
+
+			/*
+			 * find valid usb_ether driver for this device,
+			 * if any
+			 */
+			probe_valid_drivers(dev);
+
+			/* check limit */
+			if (usb_max_eth_dev == USB_MAX_ETH_DEV)
+				break;
+		} /* for */
+	}
+#else
+	for (i = 0; i < USB_MAX_DEVICE; i++) {
+		struct usb_device *dev;
+
+		dev = usb_get_dev_index(i); /* get device */
+		debug("i=%d\n", i);
+		if (!dev)
+			break; /* no more devices available */
+
+		/* find valid usb_ether driver for this device, if any */
+		probe_valid_drivers(dev);
+
+		/* check limit */
+		if (usb_max_eth_dev == USB_MAX_ETH_DEV)
+			break;
+	} /* for */
+#endif
+	if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
+		printf("max USB Ethernet Device reached: %d stopping\n",
+		       usb_max_eth_dev);
+	}
+	usb_disable_asynch(old_async); /* restore asynch value */
+	printf("%d Ethernet Device(s) found\n", usb_max_eth_dev);
+	if (usb_max_eth_dev > 0)
+		return 0;
+	return -1;
+}
+#endif
diff --git a/roms/u-boot/drivers/usb/gadget/Kconfig b/roms/u-boot/drivers/usb/gadget/Kconfig
new file mode 100644
index 000000000..4a3b22e6d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/Kconfig
@@ -0,0 +1,243 @@
+#
+# USB Gadget support on a system involves
+#    (a) a peripheral controller, and
+#    (b) the gadget driver using it.
+#
+# NOTE:  Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !!
+#
+#  - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
+#  - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
+#  - Some systems have both kinds of controllers.
+#
+# With help from a special transceiver and a "Mini-AB" jack, systems with
+# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
+#
+
+menuconfig USB_GADGET
+	bool "USB Gadget Support"
+	help
+	   USB is a master/slave protocol, organized with one master
+	   host (such as a PC) controlling up to 127 peripheral devices.
+	   The USB hardware is asymmetric, which makes it easier to set up:
+	   you can't connect a "to-the-host" connector to a peripheral.
+
+	   U-Boot can run in the host, or in the peripheral.  In both cases
+	   you need a low level bus controller driver, and some software
+	   talking to it.  Peripheral controllers are often discrete silicon,
+	   or are integrated with the CPU in a microcontroller.  The more
+	   familiar host side controllers have names like "EHCI", "OHCI",
+	   or "UHCI", and are usually integrated into southbridges on PC
+	   motherboards.
+
+	   Enable this configuration option if you want to run U-Boot inside
+	   a USB peripheral device.  Configure one hardware driver for your
+	   peripheral/device side bus controller, and a "gadget driver" for
+	   your peripheral protocol.
+
+if USB_GADGET
+
+config USB_GADGET_MANUFACTURER
+	string "Vendor name of the USB device"
+	default "Allwinner Technology" if ARCH_SUNXI
+	default "Rockchip" if ARCH_ROCKCHIP
+	default "U-Boot"
+	help
+	  Vendor name of the USB device emulated, reported to the host device.
+	  This is usually either the manufacturer of the device or the SoC.
+
+config USB_GADGET_VENDOR_NUM
+	hex "Vendor ID of the USB device"
+	default 0x1f3a if ARCH_SUNXI
+	default 0x2207 if ARCH_ROCKCHIP
+	default 0x0
+	help
+	  Vendor ID of the USB device emulated, reported to the host device.
+	  This is usually the board or SoC vendor's, unless you've registered
+	  for one.
+
+config USB_GADGET_PRODUCT_NUM
+	hex "Product ID of the USB device"
+	default 0x1010 if ARCH_SUNXI
+	default 0x310a if ROCKCHIP_RK3036
+	default 0x310c if ROCKCHIP_RK3128
+	default 0x320a if ROCKCHIP_RK3229 || ROCKCHIP_RK3288
+	default 0x330a if ROCKCHIP_RK3328
+	default 0x330c if ROCKCHIP_RK3399
+	default 0x0
+	help
+	  Product ID of the USB device emulated, reported to the host device.
+
+config USB_GADGET_ATMEL_USBA
+	bool "Atmel USBA"
+	select USB_GADGET_DUALSPEED
+	help
+	  USBA is the integrated high-speed USB Device controller on
+	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
+
+config USB_GADGET_BCM_UDC_OTG_PHY
+	bool "Broadcom UDC OTG PHY"
+	help
+	  Enable the Broadcom UDC OTG physical device interface.
+
+config USB_GADGET_DWC2_OTG
+	bool "DesignWare USB2.0 HS OTG controller (gadget mode)"
+	select USB_GADGET_DUALSPEED
+	help
+	  The Designware USB2.0 high-speed gadget controller
+	  integrated into many SoCs. Select this option if you want the
+	  driver to operate in Peripheral mode. This option requires
+	  USB_GADGET to be enabled.
+
+if USB_GADGET_DWC2_OTG
+
+config USB_GADGET_DWC2_OTG_PHY_BUS_WIDTH_8
+	bool "DesignWare USB2.0 HS OTG controller 8-bit PHY bus width"
+	help
+	  Set the Designware USB2.0 high-speed OTG controller
+	  PHY interface width to 8 bits, rather than the default (16 bits).
+
+endif # USB_GADGET_DWC2_OTG
+
+config USB_GADGET_OS_DESCRIPTORS
+	bool "USB OS Feature Descriptors support"
+	help
+	  This is a porting patch from linux kernel: 37a3a533429e
+	  ("usb: gadget: OS Feature Descriptors support"), the original commit
+	  log see below:
+	  There is a custom (non-USB IF) extension to the USB standard:
+	  http://msdn.microsoft.com/library/windows/hardware/gg463182
+
+config CI_UDC
+	bool "ChipIdea device controller"
+	select USB_GADGET_DUALSPEED
+	help
+	  Say Y here to enable device controller functionality of the
+	  ChipIdea driver.
+
+config USB_GADGET_MAX3420
+	bool "MAX3420 USB Over SPI"
+	depends on DM_SPI
+	help
+	  MAX3420, from MAXIM, implements USB-over-SPI Full-Speed device controller.
+
+config USB_GADGET_VBUS_DRAW
+	int "Maximum VBUS Power usage (2-500 mA)"
+	range 2 500
+	default 2
+	help
+	   Some devices need to draw power from USB when they are
+	   configured, perhaps to operate circuitry or to recharge
+	   batteries.  This is in addition to any local power supply,
+	   such as an AC adapter or batteries.
+
+	   Enter the maximum power your device draws through USB, in
+	   milliAmperes.  The permitted range of values is 2 - 500 mA;
+	   0 mA would be legal, but can make some hosts misbehave.
+
+	   This value will be used except for system-specific gadget
+	   drivers that have more specific information.
+
+config SDP_LOADADDR
+	hex "Default load address at SDP_WRITE and SDP_JUMP"
+	default 0
+
+# Selected by UDC drivers that support high-speed operation.
+config USB_GADGET_DUALSPEED
+	bool
+
+config USB_GADGET_DOWNLOAD
+	bool "Enable USB download gadget"
+	help
+	  Composite USB download gadget support (g_dnl) for download functions.
+	  This code works on top of composite gadget.
+
+if USB_GADGET_DOWNLOAD
+
+config USB_FUNCTION_MASS_STORAGE
+	bool "Enable USB mass storage gadget"
+	help
+	  Enable mass storage protocol support in U-Boot. It allows exporting
+	  the eMMC/SD card content to HOST PC so it can be mounted.
+
+config USB_FUNCTION_ROCKUSB
+        bool "Enable USB rockusb gadget"
+        help
+          Rockusb protocol is widely used by Rockchip SoC based devices. It can
+          read/write info, image to/from devices. This enables the USB part of
+          the rockusb gadget.for more detail about Rockusb protocol, please see
+          doc/README.rockusb
+
+config USB_FUNCTION_SDP
+	bool "Enable USB SDP (Serial Download Protocol)"
+	help
+	  Enable Serial Download Protocol (SDP) device support in U-Boot. This
+	  allows to download images into memory and execute (jump to) them
+	  using the same protocol as implemented by the i.MX family's boot ROM.
+
+config USB_FUNCTION_THOR
+	bool "Enable USB THOR gadget"
+	help
+	  Enable Tizen's THOR download protocol support in U-Boot. It
+	  allows downloading images into memory and flash them to target device.
+
+endif # USB_GADGET_DOWNLOAD
+
+config USB_ETHER
+	bool "USB Ethernet Gadget"
+	depends on NET
+	default y if ARCH_SUNXI && USB_MUSB_GADGET
+	help
+	  Creates an Ethernet network device through a USB peripheral
+	  controller. This will create a network interface on both the device
+	  (U-Boot) and the host (remote device) that can be used just like any
+	  other nework interface.
+	  It will bind on the peripheral USB controller, ignoring the USB hosts
+	  controllers in the system.
+
+if USB_ETHER
+
+choice
+	prompt "USB Ethernet Gadget Model"
+	default USB_ETH_RNDIS
+	help
+	  There is several models (protocols) to implement Ethernet over USB
+	  devices. The main ones are Microsoft's RNDIS and USB's CDC-Ethernet
+	  (also called CDC-ECM). RNDIS is obviously compatible with Windows,
+	  while CDC-ECM is not. Most other operating systems support both, so
+	  if inter-operability is a concern, RNDIS is to be preferred.
+
+config USB_ETH_CDC
+	bool "CDC-ECM Protocol"
+	help
+	  CDC (Communications Device Class) is the standard for Ethernet over
+	  USB devices. While there's several alternatives, the most widely used
+	  protocol is ECM (Ethernet Control Model). However, compatibility with
+	  Windows is not that great.
+
+config USB_ETH_RNDIS
+	bool "RNDIS Protocol"
+	help
+	  The RNDIS (Remote Network Driver Interface Specification) is a
+	  Microsoft proprietary protocol to create an Ethernet device over USB.
+	  Windows obviously supports it, as well as all the major operating
+	  systems, so it's the best option for compatibility.
+
+endchoice
+
+config USBNET_DEVADDR
+	string "USB Gadget Ethernet device mac address"
+	default "de:ad:be:ef:00:01"
+	help
+	  Ethernet MAC address of the device-side (ie. local board's) MAC
+	  address of the usb_ether interface
+
+config USBNET_HOST_ADDR
+	string "USB Gadget Ethernet host mac address"
+	default "de:ad:be:ef:00:00"
+	help
+	  Ethernet MAC address of the host-side (ie. remote device's) MAC
+	  address of the usb_ether interface
+
+endif # USB_ETHER
+
+endif # USB_GADGET
diff --git a/roms/u-boot/drivers/usb/gadget/Makefile b/roms/u-boot/drivers/usb/gadget/Makefile
new file mode 100644
index 000000000..f560068b4
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/Makefile
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+obj-$(CONFIG_USB_GADGET) += epautoconf.o config.o usbstring.o
+obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_USB_GADGET) += g_dnl.o
+obj-$(CONFIG_SPL_DFU) += f_dfu.o
+obj-$(CONFIG_SPL_USB_SDP_SUPPORT) += f_sdp.o
+endif
+
+# new USB gadget layer dependencies
+ifdef CONFIG_USB_GADGET
+obj-$(CONFIG_USB_GADGET_AT91) += at91_udc.o
+obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o
+obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o
+obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o
+obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o
+obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
+obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o
+obj-$(CONFIG_CI_UDC)	+= ci_udc.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o
+obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o
+obj-$(CONFIG_DFU_OVER_USB) += f_dfu.o
+obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o
+obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o
+obj-$(CONFIG_USB_FUNCTION_SDP) += f_sdp.o
+obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o
+endif
+endif
+ifdef CONFIG_USB_ETHER
+obj-y += ether.o
+obj-$(CONFIG_USB_ETH_RNDIS) += rndis.o
+obj-$(CONFIG_CI_UDC)	+= ci_udc.o
+obj-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o
+else
+# Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
+ifdef CONFIG_USB_DEVICE
+obj-y += core.o
+obj-y += ep0.o
+obj-$(CONFIG_DW_UDC) += designware_udc.o
+obj-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o
+endif
+endif
diff --git a/roms/u-boot/drivers/usb/gadget/at91_udc.c b/roms/u-boot/drivers/usb/gadget/at91_udc.c
new file mode 100644
index 000000000..1feed417d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/at91_udc.c
@@ -0,0 +1,1546 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * from linux:
+ * c94e289f195e: usb: gadget: remove incorrect __init/__exit annotations
+ *
+ * at91_udc -- driver for at91-series USB peripheral controller
+ *
+ * Copyright (C) 2004 by Thomas Rathbone
+ * Copyright (C) 2005 by HP Labs
+ * Copyright (C) 2005 by David Brownell
+ */
+
+#undef	VERBOSE_DEBUG
+#undef	PACKET_TRACE
+
+#include <common.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <mach/at91_matrix.h>
+#include <linux/list.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/at91_udc.h>
+#include <malloc.h>
+
+#include "at91_udc.h"
+
+/*
+ * This controller is simple and PIO-only.  It's used in many AT91-series
+ * full speed USB controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam926x (arm926ejs, with MMU), and several no-mmu versions.
+ *
+ * This driver expects the board has been wired with two GPIOs supporting
+ * a VBUS sensing IRQ, and a D+ pullup.  (They may be omitted, but the
+ * testing hasn't covered such cases.)
+ *
+ * The pullup is most important (so it's integrated on sam926x parts).  It
+ * provides software control over whether the host enumerates the device.
+ *
+ * The VBUS sensing helps during enumeration, and allows both USB clocks
+ * (and the transceiver) to stay gated off until they're necessary, saving
+ * power.  During USB suspend, the 48 MHz clock is gated off in hardware;
+ * it may also be gated off by software during some Linux sleep states.
+ */
+
+#define	DRIVER_VERSION	"3 May 2006"
+
+static const char driver_name [] = "at91_udc";
+static const char * const ep_names[] = {
+	"ep0",
+	"ep1",
+	"ep2",
+	"ep3-int",
+	"ep4",
+	"ep5",
+};
+#define ep0name		ep_names[0]
+
+#define at91_udp_read(udc, reg) \
+	__raw_readl((udc)->udp_baseaddr + (reg))
+#define at91_udp_write(udc, reg, val) \
+	__raw_writel((val), (udc)->udp_baseaddr + (reg))
+
+static struct at91_udc *controller;
+
+/*-------------------------------------------------------------------------*/
+
+static void done(struct at91_ep *ep, struct at91_request *req, int status)
+{
+	unsigned	stopped = ep->stopped;
+	struct at91_udc	*udc = ep->udc;
+
+	list_del_init(&req->queue);
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+	if (status && status != -ESHUTDOWN)
+		VDBG("%s done %p, status %d\n", ep->ep.name, req, status);
+
+	ep->stopped = 1;
+	spin_unlock(&udc->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&udc->lock);
+	ep->stopped = stopped;
+
+	/* ep0 is always ready; other endpoints need a non-empty queue */
+	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
+		at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bits indicating OUT fifo has data ready */
+#define	RX_DATA_READY	(AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)
+
+/*
+ * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write
+ * back most of the value you just read (because of side effects, including
+ * bits that may change after reading and before writing).
+ *
+ * Except when changing a specific bit, always write values which:
+ *  - clear SET_FX bits (setting them could change something)
+ *  - set CLR_FX bits (clearing them could change something)
+ *
+ * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
+ * that shouldn't normally be changed.
+ *
+ * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains,
+ * implying a need to wait for one write to complete (test relevant bits)
+ * before starting the next write.  This shouldn't be an issue given how
+ * infrequently we write, except maybe for write-then-read idioms.
+ */
+#define	SET_FX	(AT91_UDP_TXPKTRDY)
+#define	CLR_FX	(RX_DATA_READY | AT91_UDP_RXSETUP \
+		| AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+
+/* pull OUT packet data from the endpoint's fifo */
+static int read_fifo (struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	u32		csr;
+	u8		*buf;
+	unsigned int	count, bufferspace, is_done;
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+
+	/*
+	 * there might be nothing to read if ep_queue() calls us,
+	 * or if we already emptied both pingpong buffers
+	 */
+rescan:
+	csr = __raw_readl(creg);
+	if ((csr & RX_DATA_READY) == 0)
+		return 0;
+
+	count = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (count > ep->ep.maxpacket)
+		count = ep->ep.maxpacket;
+	if (count > bufferspace) {
+		DBG("%s buffer overflow\n", ep->ep.name);
+		req->req.status = -EOVERFLOW;
+		count = bufferspace;
+	}
+	__raw_readsb((unsigned long)dreg, buf, count);
+
+	/* release and swap pingpong mem bank */
+	csr |= CLR_FX;
+	if (ep->is_pingpong) {
+		if (ep->fifo_bank == 0) {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+			ep->fifo_bank = 1;
+		} else {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);
+			ep->fifo_bank = 0;
+		}
+	} else
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+	__raw_writel(csr, creg);
+
+	req->req.actual += count;
+	is_done = (count < ep->ep.maxpacket);
+	if (count == bufferspace)
+		is_done = 1;
+
+	PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,
+			is_done ? " (done)" : "");
+
+	/*
+	 * avoid extra trips through IRQ logic for packets already in
+	 * the fifo ... maybe preventing an extra (expensive) OUT-NAK
+	 */
+	if (is_done)
+		done(ep, req, 0);
+	else if (ep->is_pingpong) {
+		/*
+		 * One dummy read to delay the code because of a HW glitch:
+		 * CSR returns bad RXCOUNT when read too soon after updating
+		 * RX_DATA_BK flags.
+		 */
+		csr = __raw_readl(creg);
+
+		bufferspace -= count;
+		buf += count;
+		goto rescan;
+	}
+
+	return is_done;
+}
+
+/* load fifo for an IN packet */
+static int write_fifo(struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u32		csr = __raw_readl(creg);
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	total, count, is_last;
+	u8		*buf;
+
+	/*
+	 * TODO: allow for writing two packets to the fifo ... that'll
+	 * reduce the amount of IN-NAKing, but probably won't affect
+	 * throughput much.  (Unlike preventing OUT-NAKing!)
+	 */
+
+	/*
+	 * If ep_queue() calls us, the queue is empty and possibly in
+	 * odd states like TXCOMP not yet cleared (we do it, saving at
+	 * least one IRQ) or the fifo not yet being free.  Those aren't
+	 * issues normally (IRQ handler fast path).
+	 */
+	if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {
+		if (csr & AT91_UDP_TXCOMP) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (csr & AT91_UDP_TXPKTRDY)
+			return 0;
+	}
+
+	buf = req->req.buf + req->req.actual;
+	prefetch(buf);
+	total = req->req.length - req->req.actual;
+	if (ep->ep.maxpacket < total) {
+		count = ep->ep.maxpacket;
+		is_last = 0;
+	} else {
+		count = total;
+		is_last = (count < ep->ep.maxpacket) || !req->req.zero;
+	}
+
+	/*
+	 * Write the packet, maybe it's a ZLP.
+	 *
+	 * NOTE:  incrementing req->actual before we receive the ACK means
+	 * gadget driver IN bytecounts can be wrong in fault cases.  That's
+	 * fixable with PIO drivers like this one (save "count" here, and
+	 * do the increment later on TX irq), but not for most DMA hardware.
+	 *
+	 * So all gadget drivers must accept that potential error.  Some
+	 * hardware supports precise fifo status reporting, letting them
+	 * recover when the actual bytecount matters (e.g. for USB Test
+	 * and Measurement Class devices).
+	 */
+	__raw_writesb((unsigned long)dreg, buf, count);
+	csr &= ~SET_FX;
+	csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	req->req.actual += count;
+
+	PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+			is_last ? " (done)" : "");
+	if (is_last)
+		done(ep, req, 0);
+	return is_last;
+}
+
+static void nuke(struct at91_ep *ep, int status)
+{
+	struct at91_request *req;
+
+	/* terminate any request in the queue */
+	ep->stopped = 1;
+	if (list_empty(&ep->queue))
+		return;
+
+	VDBG("%s %s\n", __func__, ep->ep.name);
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct at91_request, queue);
+		done(ep, req, status);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_ep_enable(struct usb_ep *_ep,
+				const struct usb_endpoint_descriptor *desc)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc *udc;
+	u16		maxpacket;
+	u32		tmp;
+	unsigned long	flags;
+
+	if (!_ep || !ep
+			|| !desc || _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| (maxpacket = usb_endpoint_maxp(desc)) == 0
+			|| maxpacket > ep->maxpacket) {
+		DBG("bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	udc = ep->udc;
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	tmp = usb_endpoint_type(desc);
+	switch (tmp) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		DBG("only one control endpoint\n");
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_INT:
+		if (maxpacket > 64)
+			goto bogus_max;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		switch (maxpacket) {
+		case 8:
+		case 16:
+		case 32:
+		case 64:
+			goto ok;
+		}
+bogus_max:
+		DBG("bogus maxpacket %d\n", maxpacket);
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->is_pingpong) {
+			DBG("iso requires double buffering\n");
+			return -EINVAL;
+		}
+		break;
+	}
+
+ok:
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* initialize endpoint to match this descriptor */
+	ep->is_in = usb_endpoint_dir_in(desc);
+	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+	ep->stopped = 0;
+	if (ep->is_in)
+		tmp |= 0x04;
+	tmp <<= 8;
+	tmp |= AT91_UDP_EPEDS;
+	__raw_writel(tmp, ep->creg);
+
+	ep->ep.maxpacket = maxpacket;
+
+	/*
+	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
+	 * since endpoint resets don't reset hw pingpong state.
+	 */
+	at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+	at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_ep_disable (struct usb_ep * _ep)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*udc = ep->udc;
+	unsigned long	flags;
+
+	if (ep == &ep->udc->ep[0])
+		return -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	nuke(ep, -ESHUTDOWN);
+
+	/* restore the endpoint's pristine config */
+	ep->ep.desc = NULL;
+	ep->ep.maxpacket = ep->maxpacket;
+
+	/* reset fifos and endpoint */
+	if (ep->udc->clocked) {
+		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+		__raw_writel(0, ep->creg);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+/*
+ * this is a PIO-only driver, so there's nothing
+ * interesting for request or buffer allocation.
+ */
+
+static struct usb_request *
+at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct at91_request *req;
+
+	req = kzalloc(sizeof (struct at91_request), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_request *req;
+
+	req = container_of(_req, struct at91_request, req);
+	BUG_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+static int at91_ep_queue(struct usb_ep *_ep,
+			struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct at91_request	*req;
+	struct at91_ep		*ep;
+	struct at91_udc		*udc;
+	int			status;
+	unsigned long		flags;
+
+	req = container_of(_req, struct at91_request, req);
+	ep = container_of(_ep, struct at91_ep, ep);
+
+	if (!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue)) {
+		DBG("invalid request\n");
+		return -EINVAL;
+	}
+
+	if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) {
+		DBG("invalid ep\n");
+		return -EINVAL;
+	}
+
+	udc = ep->udc;
+
+	if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("invalid device\n");
+		return -EINVAL;
+	}
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* try to kickstart any empty and idle queue */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		int	is_ep0;
+
+		/*
+		 * If this control request has a non-empty DATA stage, this
+		 * will start that stage.  It works just like a non-control
+		 * request (until the status stage starts, maybe early).
+		 *
+		 * If the data stage is empty, then this starts a successful
+		 * IN/STATUS stage.  (Unsuccessful ones use set_halt.)
+		 */
+		is_ep0 = (ep->ep.name == ep0name);
+		if (is_ep0) {
+			u32	tmp;
+
+			if (!udc->req_pending) {
+				status = -EINVAL;
+				goto done;
+			}
+
+			/*
+			 * defer changing CONFG until after the gadget driver
+			 * reconfigures the endpoints.
+			 */
+			if (udc->wait_for_config_ack) {
+				tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+				tmp ^= AT91_UDP_CONFG;
+				VDBG("toggle config\n");
+				at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+			}
+			if (req->req.length == 0) {
+ep0_in_status:
+				PACKET("ep0 in/status\n");
+				status = 0;
+				tmp = __raw_readl(ep->creg);
+				tmp &= ~SET_FX;
+				tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+				__raw_writel(tmp, ep->creg);
+				udc->req_pending = 0;
+				goto done;
+			}
+		}
+
+		if (ep->is_in)
+			status = write_fifo(ep, req);
+		else {
+			status = read_fifo(ep, req);
+
+			/* IN/STATUS stage is otherwise triggered by irq */
+			if (status && is_ep0)
+				goto ep0_in_status;
+		}
+	} else
+		status = 0;
+
+	if (req && !status) {
+		list_add_tail (&req->queue, &ep->queue);
+		at91_udp_write(udc, AT91_UDP_IER, ep->int_mask);
+	}
+done:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return (status < 0) ? status : 0;
+}
+
+static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_ep		*ep;
+	struct at91_request	*req;
+	unsigned long		flags;
+
+	ep = container_of(_ep, struct at91_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*udc = ep->udc;
+	u32 __iomem	*creg;
+	u32		csr;
+	unsigned long	flags;
+	int		status = 0;
+
+	if (!_ep || ep->is_iso || !ep->udc->clocked)
+		return -EINVAL;
+
+	creg = ep->creg;
+	spin_lock_irqsave(&udc->lock, flags);
+
+	csr = __raw_readl(creg);
+
+	/*
+	 * fail with still-busy IN endpoints, ensuring correct sequencing
+	 * of data tx then stall.  note that the fifo rx bytecount isn't
+	 * completely accurate as a tx bytecount.
+	 */
+	if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))
+		status = -EAGAIN;
+	else {
+		csr |= CLR_FX;
+		csr &= ~SET_FX;
+		if (value) {
+			csr |= AT91_UDP_FORCESTALL;
+			VDBG("halt %s\n", ep->ep.name);
+		} else {
+			at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+			at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+			csr &= ~AT91_UDP_FORCESTALL;
+		}
+		__raw_writel(csr, creg);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return status;
+}
+
+static const struct usb_ep_ops at91_ep_ops = {
+	.enable		= at91_ep_enable,
+	.disable	= at91_ep_disable,
+	.alloc_request	= at91_ep_alloc_request,
+	.free_request	= at91_ep_free_request,
+	.queue		= at91_ep_queue,
+	.dequeue	= at91_ep_dequeue,
+	.set_halt	= at91_ep_set_halt,
+	/* there's only imprecise fifo status reporting */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_get_frame(struct usb_gadget *gadget)
+{
+	struct at91_udc *udc = to_udc(gadget);
+
+	if (!to_udc(gadget)->clocked)
+		return -EINVAL;
+	return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+}
+
+static int at91_wakeup(struct usb_gadget *gadget)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	u32		glbstate;
+	int		status = -EINVAL;
+	unsigned long	flags;
+
+	DBG("%s\n", __func__ );
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!udc->clocked || !udc->suspended)
+		goto done;
+
+	/* NOTE:  some "early versions" handle ESR differently ... */
+
+	glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+	if (!(glbstate & AT91_UDP_ESR))
+		goto done;
+	glbstate |= AT91_UDP_ESR;
+	at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
+
+done:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return status;
+}
+
+/* reinit == restore initial software state */
+static void udc_reinit(struct at91_udc *udc)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		ep->ep.desc = NULL;
+		ep->stopped = 0;
+		ep->fifo_bank = 0;
+		usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);
+		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
+		/* initialize one queue per endpoint */
+		INIT_LIST_HEAD(&ep->queue);
+	}
+}
+
+static void reset_gadget(struct at91_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->suspended = 0;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver) {
+		spin_unlock(&udc->lock);
+		udc->driver->disconnect(&udc->gadget);
+		spin_lock(&udc->lock);
+	}
+
+	udc_reinit(udc);
+}
+
+static void stop_activity(struct at91_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->suspended = 0;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver) {
+		spin_unlock(&udc->lock);
+		driver->disconnect(&udc->gadget);
+		spin_lock(&udc->lock);
+	}
+
+	udc_reinit(udc);
+}
+
+static void clk_on(struct at91_udc *udc)
+{
+	if (udc->clocked)
+		return;
+	udc->clocked = 1;
+}
+
+static void clk_off(struct at91_udc *udc)
+{
+	if (!udc->clocked)
+		return;
+	udc->clocked = 0;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ * activate/deactivate link with host; minimize power usage for
+ * inactive links by cutting clocks and transceiver power.
+ */
+static void pullup(struct at91_udc *udc, int is_on)
+{
+	if (!udc->enabled || !udc->vbus)
+		is_on = 0;
+	DBG("%sactive\n", is_on ? "" : "in");
+
+	if (is_on) {
+		clk_on(udc);
+		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+		at91_udp_write(udc, AT91_UDP_TXVC, 0);
+	} else {
+		stop_activity(udc);
+		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+		clk_off(udc);
+	}
+
+	if (udc->caps && udc->caps->pullup)
+		udc->caps->pullup(udc, is_on);
+}
+
+/* vbus is here!  turn everything on that's ready */
+static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	/* VDBG("vbus %s\n", is_active ? "on" : "off"); */
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->vbus = (is_active != 0);
+	if (udc->driver)
+		pullup(udc, is_active);
+	else
+		pullup(udc, 0);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->enabled = is_on = !!is_on;
+	pullup(udc, is_on);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->selfpowered = (is_on != 0);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+static int at91_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int at91_stop(struct usb_gadget *gadget);
+
+static const struct usb_gadget_ops at91_udc_ops = {
+	.get_frame		= at91_get_frame,
+	.wakeup			= at91_wakeup,
+	.set_selfpowered	= at91_set_selfpowered,
+	.vbus_session		= at91_vbus_session,
+	.pullup			= at91_pullup,
+	.udc_start		= at91_start,
+	.udc_stop		= at91_stop,
+
+	/*
+	 * VBUS-powered devices may also also want to support bigger
+	 * power budgets after an appropriate SET_CONFIGURATION.
+	 */
+	/* .vbus_power		= at91_vbus_power, */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_ep(struct at91_ep *ep)
+{
+	struct at91_request	*req;
+	u32 __iomem		*creg = ep->creg;
+	u32			csr = __raw_readl(creg);
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+			struct at91_request, queue);
+	else
+		req = NULL;
+
+	if (ep->is_in) {
+		if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+		}
+		if (req)
+			return write_fifo(ep, req);
+
+	} else {
+		if (csr & AT91_UDP_STALLSENT) {
+			/* STALLSENT bit == ISOERR */
+			if (ep->is_iso && req)
+				req->req.status = -EILSEQ;
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (req && (csr & RX_DATA_READY))
+			return read_fifo(ep, req);
+	}
+	return 0;
+}
+
+union setup {
+	u8			raw[8];
+	struct usb_ctrlrequest	r;
+};
+
+static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	rxcount, i = 0;
+	u32		tmp;
+	union setup	pkt;
+	int		status = 0;
+
+	/* read and ack SETUP; hard-fail for bogus packets */
+	rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (likely(rxcount == 8)) {
+		while (rxcount--)
+			pkt.raw[i++] = __raw_readb(dreg);
+		if (pkt.r.bRequestType & USB_DIR_IN) {
+			csr |= AT91_UDP_DIR;
+			ep->is_in = 1;
+		} else {
+			csr &= ~AT91_UDP_DIR;
+			ep->is_in = 0;
+		}
+	} else {
+		/* REVISIT this happens sometimes under load; why?? */
+		ERR("SETUP len %d, csr %08x\n", rxcount, csr);
+		status = -EINVAL;
+	}
+	csr |= CLR_FX;
+	csr &= ~(SET_FX | AT91_UDP_RXSETUP);
+	__raw_writel(csr, creg);
+	udc->wait_for_addr_ack = 0;
+	udc->wait_for_config_ack = 0;
+	ep->stopped = 0;
+	if (unlikely(status != 0))
+		goto stall;
+
+#define w_index		le16_to_cpu(pkt.r.wIndex)
+#define w_value		le16_to_cpu(pkt.r.wValue)
+#define w_length	le16_to_cpu(pkt.r.wLength)
+
+	VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
+			pkt.r.bRequestType, pkt.r.bRequest,
+			w_value, w_index, w_length);
+
+	/*
+	 * A few standard requests get handled here, ones that touch
+	 * hardware ... notably for device and endpoint features.
+	 */
+	udc->req_pending = 1;
+	csr = __raw_readl(creg);
+	csr |= CLR_FX;
+	csr &= ~SET_FX;
+	switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_ADDRESS:
+		__raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
+		udc->addr = w_value;
+		udc->wait_for_addr_ack = 1;
+		udc->req_pending = 0;
+		/* FADDR is set later, when we ack host STATUS */
+		return;
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_CONFIGURATION:
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+		if (pkt.r.wValue)
+			udc->wait_for_config_ack = (tmp == 0);
+		else
+			udc->wait_for_config_ack = (tmp != 0);
+		if (udc->wait_for_config_ack)
+			VDBG("wait for config\n");
+		/* CONFG is toggled later, if gadget driver succeeds */
+		break;
+
+	/*
+	 * Hosts may set or clear remote wakeup status, and
+	 * devices may report they're VBUS powered.
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+		PACKET("get device status\n");
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+		tmp |= AT91_UDP_ESR;
+		at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+		tmp &= ~AT91_UDP_ESR;
+		at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+
+	/*
+	 * Interfaces have no feature settings; this is pretty useless.
+	 * we won't even insist the interface exists...
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_GET_STATUS:
+		PACKET("get interface status\n");
+		__raw_writeb(0, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_SET_FEATURE:
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		goto stall;
+
+	/*
+	 * Hosts may clear bulk/intr endpoint halt after the gadget
+	 * driver sets it (not widely used); or set it (for testing)
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc))
+			goto stall;
+
+		if (tmp) {
+			if ((w_index & USB_DIR_IN)) {
+				if (!ep->is_in)
+					goto stall;
+			} else if (ep->is_in)
+				goto stall;
+		}
+		PACKET("get %s status\n", ep->ep.name);
+		if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
+			tmp = (1 << USB_ENDPOINT_HALT);
+		else
+			tmp = 0;
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_SET_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+			goto stall;
+		if (!ep->ep.desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		tmp = __raw_readl(ep->creg);
+		tmp &= ~SET_FX;
+		tmp |= CLR_FX | AT91_UDP_FORCESTALL;
+		__raw_writel(tmp, ep->creg);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+			goto stall;
+		if (tmp == 0)
+			goto succeed;
+		if (!ep->ep.desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+		tmp = __raw_readl(ep->creg);
+		tmp |= CLR_FX;
+		tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
+		__raw_writel(tmp, ep->creg);
+		if (!list_empty(&ep->queue))
+			handle_ep(ep);
+		goto succeed;
+	}
+
+#undef w_value
+#undef w_index
+#undef w_length
+
+	/* pass request up to the gadget driver */
+	if (udc->driver) {
+		spin_unlock(&udc->lock);
+		status = udc->driver->setup(&udc->gadget, &pkt.r);
+		spin_lock(&udc->lock);
+	}
+	else
+		status = -ENODEV;
+	if (status < 0) {
+stall:
+		VDBG("req %02x.%02x protocol STALL; stat %d\n",
+				pkt.r.bRequestType, pkt.r.bRequest, status);
+		csr |= AT91_UDP_FORCESTALL;
+		__raw_writel(csr, creg);
+		udc->req_pending = 0;
+	}
+	return;
+
+succeed:
+	/* immediate successful (IN) STATUS after zero length DATA */
+	PACKET("ep0 in/status\n");
+write_in:
+	csr |= AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	udc->req_pending = 0;
+}
+
+static void handle_ep0(struct at91_udc *udc)
+{
+	struct at91_ep		*ep0 = &udc->ep[0];
+	u32 __iomem		*creg = ep0->creg;
+	u32			csr = __raw_readl(creg);
+	struct at91_request	*req;
+
+	if (unlikely(csr & AT91_UDP_STALLSENT)) {
+		nuke(ep0, -EPROTO);
+		udc->req_pending = 0;
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL);
+		__raw_writel(csr, creg);
+		VDBG("ep0 stalled\n");
+		csr = __raw_readl(creg);
+	}
+	if (csr & AT91_UDP_RXSETUP) {
+		nuke(ep0, 0);
+		udc->req_pending = 0;
+		handle_setup(udc, ep0, csr);
+		return;
+	}
+
+	if (list_empty(&ep0->queue))
+		req = NULL;
+	else
+		req = list_entry(ep0->queue.next, struct at91_request, queue);
+
+	/* host ACKed an IN packet that we sent */
+	if (csr & AT91_UDP_TXCOMP) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+
+		/* write more IN DATA? */
+		if (req && ep0->is_in) {
+			if (handle_ep(ep0))
+				udc->req_pending = 0;
+
+		/*
+		 * Ack after:
+		 *  - last IN DATA packet (including GET_STATUS)
+		 *  - IN/STATUS for OUT DATA
+		 *  - IN/STATUS for any zero-length DATA stage
+		 * except for the IN DATA case, the host should send
+		 * an OUT status later, which we'll ack.
+		 */
+		} else {
+			udc->req_pending = 0;
+			__raw_writel(csr, creg);
+
+			/*
+			 * SET_ADDRESS takes effect only after the STATUS
+			 * (to the original address) gets acked.
+			 */
+			if (udc->wait_for_addr_ack) {
+				u32	tmp;
+
+				at91_udp_write(udc, AT91_UDP_FADDR,
+						AT91_UDP_FEN | udc->addr);
+				tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+				tmp &= ~AT91_UDP_FADDEN;
+				if (udc->addr)
+					tmp |= AT91_UDP_FADDEN;
+				at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+
+				udc->wait_for_addr_ack = 0;
+				VDBG("address %d\n", udc->addr);
+			}
+		}
+	}
+
+	/* OUT packet arrived ... */
+	else if (csr & AT91_UDP_RX_DATA_BK0) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+
+		/* OUT DATA stage */
+		if (!ep0->is_in) {
+			if (req) {
+				if (handle_ep(ep0)) {
+					/* send IN/STATUS */
+					PACKET("ep0 in/status\n");
+					csr = __raw_readl(creg);
+					csr &= ~SET_FX;
+					csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+					__raw_writel(csr, creg);
+					udc->req_pending = 0;
+				}
+			} else if (udc->req_pending) {
+				/*
+				 * AT91 hardware has a hard time with this
+				 * "deferred response" mode for control-OUT
+				 * transfers.  (For control-IN it's fine.)
+				 *
+				 * The normal solution leaves OUT data in the
+				 * fifo until the gadget driver is ready.
+				 * We couldn't do that here without disabling
+				 * the IRQ that tells about SETUP packets,
+				 * e.g. when the host gets impatient...
+				 *
+				 * Working around it by copying into a buffer
+				 * would almost be a non-deferred response,
+				 * except that it wouldn't permit reliable
+				 * stalling of the request.  Instead, demand
+				 * that gadget drivers not use this mode.
+				 */
+				DBG("no control-OUT deferred responses!\n");
+				__raw_writel(csr | AT91_UDP_FORCESTALL, creg);
+				udc->req_pending = 0;
+			}
+
+		/* STATUS stage for control-IN; ack.  */
+		} else {
+			PACKET("ep0 out/status ACK\n");
+			__raw_writel(csr, creg);
+
+			/* "early" status stage */
+			if (req)
+				done(ep0, req, 0);
+		}
+	}
+}
+
+static irqreturn_t at91_udc_irq(struct at91_udc *udc)
+{
+	u32			rescans = 5;
+	int			disable_clock = 0;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!udc->clocked) {
+		clk_on(udc);
+		disable_clock = 1;
+	}
+
+	while (rescans--) {
+		u32 status;
+
+		status = at91_udp_read(udc, AT91_UDP_ISR)
+			& at91_udp_read(udc, AT91_UDP_IMR);
+		if (!status)
+			break;
+
+		/* USB reset irq:  not maskable */
+		if (status & AT91_UDP_ENDBUSRES) {
+			at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+			at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+			/* Atmel code clears this irq twice */
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			VDBG("end bus reset\n");
+			udc->addr = 0;
+			reset_gadget(udc);
+
+			/* enable ep0 */
+			at91_udp_write(udc, AT91_UDP_CSR(0),
+					AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+			udc->gadget.speed = USB_SPEED_FULL;
+			udc->suspended = 0;
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0));
+
+			/*
+			 * NOTE:  this driver keeps clocks off unless the
+			 * USB host is present.  That saves power, but for
+			 * boards that don't support VBUS detection, both
+			 * clocks need to be active most of the time.
+			 */
+
+		/* host initiated suspend (3+ms bus idle) */
+		} else if (status & AT91_UDP_RXSUSP) {
+			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
+			/* VDBG("bus suspend\n"); */
+			if (udc->suspended)
+				continue;
+			udc->suspended = 1;
+
+			/*
+			 * NOTE:  when suspending a VBUS-powered device, the
+			 * gadget driver should switch into slow clock mode
+			 * and then into standby to avoid drawing more than
+			 * 500uA power (2500uA for some high-power configs).
+			 */
+			if (udc->driver && udc->driver->suspend) {
+				spin_unlock(&udc->lock);
+				udc->driver->suspend(&udc->gadget);
+				spin_lock(&udc->lock);
+			}
+
+		/* host initiated resume */
+		} else if (status & AT91_UDP_RXRSM) {
+			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+			/* VDBG("bus resume\n"); */
+			if (!udc->suspended)
+				continue;
+			udc->suspended = 0;
+
+			/*
+			 * NOTE:  for a VBUS-powered device, the gadget driver
+			 * would normally want to switch out of slow clock
+			 * mode into normal mode.
+			 */
+			if (udc->driver && udc->driver->resume) {
+				spin_unlock(&udc->lock);
+				udc->driver->resume(&udc->gadget);
+				spin_lock(&udc->lock);
+			}
+
+		/* endpoint IRQs are cleared by handling them */
+		} else {
+			int		i;
+			unsigned	mask = 1;
+			struct at91_ep	*ep = &udc->ep[1];
+
+			if (status & mask)
+				handle_ep0(udc);
+			for (i = 1; i < NUM_ENDPOINTS; i++) {
+				mask <<= 1;
+				if (status & mask)
+					handle_ep(ep);
+				ep++;
+			}
+		}
+	}
+
+	if (disable_clock)
+		clk_off(udc);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = controller;
+
+	udc->driver = driver;
+	udc->enabled = 1;
+	udc->selfpowered = 1;
+
+	return 0;
+}
+
+static int at91_stop(struct usb_gadget *gadget)
+{
+	struct at91_udc *udc = controller;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->enabled = 0;
+	at91_udp_write(udc, AT91_UDP_IDR, ~0);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	udc->driver = NULL;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9G20)
+static int at91sam9260_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0 ... 3:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 512;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void at91sam9260_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+	if (is_on)
+		txvc |= AT91_UDP_TXVC_PUON;
+	else
+		txvc &= ~AT91_UDP_TXVC_PUON;
+
+	at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+}
+
+static const struct at91_udc_caps at91sam9260_udc_caps = {
+	.init = at91sam9260_udc_init,
+	.pullup = at91sam9260_udc_pullup,
+};
+#endif
+
+#if defined(CONFIG_AT91SAM9261)
+static int at91sam9261_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+			ep->maxpacket = 8;
+			break;
+		case 1 ... 3:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	udc->matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX;
+
+	if (IS_ERR(udc->matrix))
+		return PTR_ERR(udc->matrix);
+
+	return 0;
+}
+
+static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	u32 usbpucr = 0;
+
+	usbpucr = readl(&udc->matrix->pucr);
+	if (is_on)
+		usbpucr |= AT91_MATRIX_USBPUCR_PUON;
+
+	writel(usbpucr, &udc->matrix->pucr);
+}
+
+static const struct at91_udc_caps at91sam9261_udc_caps = {
+	.init = at91sam9261_udc_init,
+	.pullup = at91sam9261_udc_pullup,
+};
+#endif
+
+int usb_gadget_handle_interrupts(int index)
+{
+	struct at91_udc *udc = controller;
+
+	return at91_udc_irq(udc);
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = controller;
+	int ret;
+
+	if (!driver || !driver->bind || !driver->setup) {
+		printf("bad paramter\n");
+		return -EINVAL;
+	}
+
+	if (udc->driver) {
+		printf("UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+
+	at91_start(&udc->gadget, driver);
+
+	udc->driver = driver;
+
+	ret = driver->bind(&udc->gadget);
+	if (ret) {
+		pr_err("driver->bind() returned %d\n", ret);
+		udc->driver = NULL;
+	}
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = controller;
+
+	if (!driver || !driver->unbind || !driver->disconnect) {
+		pr_err("bad paramter\n");
+		return -EINVAL;
+	}
+
+	driver->disconnect(&udc->gadget);
+	driver->unbind(&udc->gadget);
+	udc->driver = NULL;
+
+	at91_stop(&udc->gadget);
+
+	return 0;
+}
+
+int at91_udc_probe(struct at91_udc_data *pdata)
+{
+	struct at91_udc	*udc;
+	int		retval;
+	struct at91_ep	*ep;
+	int		i;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
+
+	controller = udc;
+	memcpy(&udc->board, pdata, sizeof(struct at91_udc_data));
+	if (udc->board.vbus_pin) {
+		printf("%s: gpio vbus pin not supported yet.\n", __func__);
+		return -ENXIO;
+	} else {
+		DBG("no VBUS detection, assuming always-on\n");
+		udc->vbus = 1;
+	}
+
+#if defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9G20)
+	udc->caps = &at91sam9260_udc_caps;
+#endif
+
+	udc->enabled = 0;
+	spin_lock_init(&udc->lock);
+
+	udc->gadget.ops = &at91_udc_ops;
+	udc->gadget.ep0 = &udc->ep[0].ep;
+	udc->gadget.name = driver_name;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+		ep->ep.name = ep_names[i];
+		ep->ep.ops = &at91_ep_ops;
+		ep->udc = udc;
+		ep->int_mask = (1 << i);
+		if (i != 0 && i != 3)
+			ep->is_pingpong = 1;
+	}
+
+	udc->udp_baseaddr = (void *)udc->board.baseaddr;
+	if (IS_ERR(udc->udp_baseaddr))
+		return PTR_ERR(udc->udp_baseaddr);
+
+	if (udc->caps && udc->caps->init) {
+		retval = udc->caps->init(udc);
+		if (retval)
+			return retval;
+	}
+
+	udc_reinit(udc);
+
+	at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+	at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
+	/* Clear all pending interrupts - UDP may be used by bootloader. */
+	at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
+
+	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/at91_udc.h b/roms/u-boot/drivers/usb/gadget/at91_udc.h
new file mode 100644
index 000000000..668b8c4a7
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/at91_udc.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2004 by Thomas Rathbone, HP Labs
+ * Copyright (C) 2005 by Ivan Kokshaysky
+ * Copyright (C) 2006 by SAN People
+ */
+
+#ifndef AT91_UDC_H
+#define AT91_UDC_H
+
+/*
+ * USB Device Port (UDP) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ */
+
+#define AT91_UDP_FRM_NUM	0x00		/* Frame Number Register */
+#define     AT91_UDP_NUM	(0x7ff <<  0)	/* Frame Number */
+#define     AT91_UDP_FRM_ERR	(1     << 16)	/* Frame Error */
+#define     AT91_UDP_FRM_OK	(1     << 17)	/* Frame OK */
+
+#define AT91_UDP_GLB_STAT	0x04		/* Global State Register */
+#define     AT91_UDP_FADDEN	(1 <<  0)	/* Function Address Enable */
+#define     AT91_UDP_CONFG	(1 <<  1)	/* Configured */
+#define     AT91_UDP_ESR	(1 <<  2)	/* Enable Send Resume */
+#define     AT91_UDP_RSMINPR	(1 <<  3)	/* Resume has been sent */
+#define     AT91_UDP_RMWUPE	(1 <<  4)	/* Remote Wake Up Enable */
+
+#define AT91_UDP_FADDR		0x08		/* Function Address Register */
+#define     AT91_UDP_FADD	(0x7f << 0)	/* Function Address Value */
+#define     AT91_UDP_FEN	(1    << 8)	/* Function Enable */
+
+#define AT91_UDP_IER		0x10		/* Interrupt Enable Register */
+#define AT91_UDP_IDR		0x14		/* Interrupt Disable Register */
+#define AT91_UDP_IMR		0x18		/* Interrupt Mask Register */
+
+#define AT91_UDP_ISR		0x1c		/* Interrupt Status Register */
+#define     AT91_UDP_EP(n)	(1 << (n))	/* Endpoint Interrupt Status */
+#define     AT91_UDP_RXSUSP	(1 <<  8) 	/* USB Suspend Interrupt Status */
+#define     AT91_UDP_RXRSM	(1 <<  9)	/* USB Resume Interrupt Status */
+#define     AT91_UDP_EXTRSM	(1 << 10)	/* External Resume Interrupt Status [AT91RM9200 only] */
+#define     AT91_UDP_SOFINT	(1 << 11)	/* Start of Frame Interrupt Status */
+#define     AT91_UDP_ENDBUSRES	(1 << 12)	/* End of Bus Reset Interrupt Status */
+#define     AT91_UDP_WAKEUP	(1 << 13)	/* USB Wakeup Interrupt Status [AT91RM9200 only] */
+
+#define AT91_UDP_ICR		0x20		/* Interrupt Clear Register */
+#define AT91_UDP_RST_EP		0x28		/* Reset Endpoint Register */
+
+#define AT91_UDP_CSR(n)		(0x30+((n)*4))	/* Endpoint Control/Status Registers 0-7 */
+#define     AT91_UDP_TXCOMP	(1 <<  0)	/* Generates IN packet with data previously written in DPR */
+#define     AT91_UDP_RX_DATA_BK0 (1 <<  1)	/* Receive Data Bank 0 */
+#define     AT91_UDP_RXSETUP	(1 <<  2)	/* Send STALL to the host */
+#define     AT91_UDP_STALLSENT	(1 <<  3)	/* Stall Sent / Isochronous error (Isochronous endpoints) */
+#define     AT91_UDP_TXPKTRDY	(1 <<  4)	/* Transmit Packet Ready */
+#define     AT91_UDP_FORCESTALL	(1 <<  5)	/* Force Stall */
+#define     AT91_UDP_RX_DATA_BK1 (1 <<  6)	/* Receive Data Bank 1 */
+#define     AT91_UDP_DIR	(1 <<  7)	/* Transfer Direction */
+#define     AT91_UDP_EPTYPE	(7 <<  8)	/* Endpoint Type */
+#define		AT91_UDP_EPTYPE_CTRL		(0 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_OUT		(1 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_OUT	(2 <<  8)
+#define		AT91_UDP_EPTYPE_INT_OUT		(3 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_IN		(5 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_IN		(6 <<  8)
+#define		AT91_UDP_EPTYPE_INT_IN		(7 <<  8)
+#define     AT91_UDP_DTGLE	(1 << 11)	/* Data Toggle */
+#define     AT91_UDP_EPEDS	(1 << 15)	/* Endpoint Enable/Disable */
+#define     AT91_UDP_RXBYTECNT	(0x7ff << 16)	/* Number of bytes in FIFO */
+
+#define AT91_UDP_FDR(n)		(0x50+((n)*4))	/* Endpoint FIFO Data Registers 0-7 */
+
+#define AT91_UDP_TXVC		0x74		/* Transceiver Control Register */
+#define     AT91_UDP_TXVC_TXVDIS (1 << 8)	/* Transceiver Disable */
+#define     AT91_UDP_TXVC_PUON   (1 << 9)	/* PullUp On [AT91SAM9260 only] */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * controller driver data structures
+ */
+
+#define	NUM_ENDPOINTS	6
+
+/*
+ * hardware won't disable bus reset, or resume while the controller
+ * is suspended ... watching suspend helps keep the logic symmetric.
+ */
+#define	MINIMUS_INTERRUPTUS \
+	(AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
+
+struct at91_ep {
+	struct usb_ep			ep;
+	struct list_head		queue;
+	struct at91_udc			*udc;
+	void __iomem			*creg;
+
+	unsigned			maxpacket:16;
+	u8				int_mask;
+	unsigned			is_pingpong:1;
+
+	unsigned			stopped:1;
+	unsigned			is_in:1;
+	unsigned			is_iso:1;
+	unsigned			fifo_bank:1;
+};
+
+struct at91_udc_caps {
+	int (*init)(struct at91_udc *udc);
+	void (*pullup)(struct at91_udc *udc, int is_on);
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+struct at91_udc {
+	struct usb_gadget		gadget;
+	struct at91_ep			ep[NUM_ENDPOINTS];
+	struct usb_gadget_driver	*driver;
+	const struct at91_udc_caps	*caps;
+	unsigned			vbus:1;
+	unsigned			enabled:1;
+	unsigned			clocked:1;
+	unsigned			suspended:1;
+	unsigned			req_pending:1;
+	unsigned			wait_for_addr_ack:1;
+	unsigned			wait_for_config_ack:1;
+	unsigned			selfpowered:1;
+	unsigned			active_suspend:1;
+	u8				addr;
+	struct at91_udc_data		board;
+	void __iomem			*udp_baseaddr;
+	int				udp_irq;
+	spinlock_t			lock;
+	struct at91_matrix		*matrix;
+};
+
+static inline struct at91_udc *to_udc(struct usb_gadget *g)
+{
+	return container_of(g, struct at91_udc, gadget);
+}
+
+struct at91_request {
+	struct usb_request		req;
+	struct list_head		queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef VERBOSE_DEBUG
+#    define VDBG		DBG
+#else
+#    define VDBG(stuff...)	do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET		VDBG
+#else
+#    define PACKET(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		debug("udc: " stuff)
+#define WARNING(stuff...)	debug("udc: " stuff)
+#define INFO(stuff...)		debug("udc: " stuff)
+#define DBG(stuff...)		debug("udc: " stuff)
+
+#endif
+
diff --git a/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c b/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 000000000..7d5182149
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,1304 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ * [Original from Linux kernel: drivers/usb/gadget/atmel_usba_udc.c]
+ *
+ * Copyright (C) 2005-2013 Atmel Corporation
+ *			   Bo Shen <voice.shen@atmel.com>
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <linux/list.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/atmel_usba_udc.h>
+#include <malloc.h>
+
+#include "atmel_usba_udc.h"
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+	/* No Vbus detection: Assume always present */
+	return 1;
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+	unsigned int transaction_len;
+
+	transaction_len = req->req.length - req->req.actual;
+	req->last_transaction = 1;
+	if (transaction_len > ep->ep.maxpacket) {
+		transaction_len = ep->ep.maxpacket;
+		req->last_transaction = 0;
+	} else if (transaction_len == ep->ep.maxpacket && req->req.zero) {
+			req->last_transaction = 0;
+	}
+
+	DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+	    ep->ep.name, req, transaction_len,
+	    req->last_transaction ? ", done" : "");
+
+	memcpy(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+	DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d), dma: %d\n",
+	    ep->ep.name, req, req->req.length, req->using_dma);
+
+	req->req.actual = 0;
+	req->submitted = 1;
+
+	next_fifo_transaction(ep, req);
+	if (req->last_transaction) {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+		usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+	} else {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+		usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+	}
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+	struct usba_request *req;
+
+	if (list_empty(&ep->queue)) {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+		return;
+	}
+
+	req = list_entry(ep->queue.next, struct usba_request, queue);
+	if (!req->submitted)
+		submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+	ep->state = STATUS_STAGE_IN;
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req;
+	unsigned long status;
+	unsigned int bytecount, nr_busy;
+	int is_complete = 0;
+
+	status = usba_ep_readl(ep, STA);
+	nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+	DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+	while (nr_busy > 0) {
+		if (list_empty(&ep->queue)) {
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			break;
+		}
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+		bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+		if (status & USBA_SHORT_PACKET)
+			is_complete = 1;
+		if (req->req.actual + bytecount >= req->req.length) {
+			is_complete = 1;
+			bytecount = req->req.length - req->req.actual;
+		}
+
+		memcpy(req->req.buf + req->req.actual, ep->fifo, bytecount);
+		req->req.actual += bytecount;
+
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+		if (is_complete) {
+			DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+			req->req.status = 0;
+			list_del_init(&req->queue);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			spin_lock(&udc->lock);
+			req->req.complete(&ep->ep, &req->req);
+			spin_unlock(&udc->lock);
+		}
+
+		status = usba_ep_readl(ep, STA);
+		nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+		if (is_complete && ep_is_control(ep)) {
+			send_status(udc, ep);
+			break;
+		}
+	}
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+
+	DBG(DBG_GADGET | DBG_REQ, "%s: req %p complete: status %d, actual %u\n",
+	    ep->ep.name, req, req->req.status, req->req.actual);
+
+	req->req.complete(&ep->ep, &req->req);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, list, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, status);
+	}
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags = 0, ept_cfg, maxpacket;
+	unsigned int nr_trans;
+
+	DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+	maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
+
+	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+	      != ep->index) ||
+	      ep->index == 0 ||
+	      desc->bDescriptorType != USB_DT_ENDPOINT ||
+	      maxpacket == 0 ||
+	      maxpacket > ep->fifo_size) {
+		DBG(DBG_ERR, "ep_enable: Invalid argument");
+		return -EINVAL;
+	}
+
+	ep->is_isoc = 0;
+	ep->is_in = 0;
+
+	if (maxpacket <= 8)
+		ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+	else
+		/* LSB is bit 1, not 0 */
+		ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+	DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+	    ep->ep.name, ept_cfg, maxpacket);
+
+	if (usb_endpoint_dir_in(desc)) {
+		ep->is_in = 1;
+		ept_cfg |= USBA_EPT_DIR_IN;
+	}
+
+	switch (usb_endpoint_type(desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->can_isoc) {
+			DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+			    ep->ep.name);
+			return -EINVAL;
+		}
+
+		/*
+		 * Bits 11:12 specify number of _additional_
+		 * transactions per microframe.
+		 */
+		nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;
+		if (nr_trans > 3)
+			return -EINVAL;
+
+		ep->is_isoc = 1;
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+		/*
+		 * Do triple-buffering on high-bandwidth iso endpoints.
+		 */
+		if (nr_trans > 1 && ep->nr_banks == 3)
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+		else
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		break;
+	}
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	usba_ep_writel(ep, CFG, ept_cfg);
+	usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+	usba_writel(udc, INT_ENB,
+		    (usba_readl(udc, INT_ENB)
+		     | USBA_BF(EPT_INT, 1 << ep->index)));
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+	    (unsigned long)usba_ep_readl(ep, CFG));
+	DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+	    (unsigned long)usba_readl(udc, INT_ENB));
+
+	return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	LIST_HEAD(req_list);
+	unsigned long flags = 0;
+
+	DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!ep->desc) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		/* REVISIT because this driver disables endpoints in
+		 * reset_all_endpoints() before calling disconnect(),
+		 * most gadget drivers would trigger this non-error ...
+		 */
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN)
+			DBG(DBG_ERR, "ep_disable: %s not enabled\n",
+			    ep->ep.name);
+		return -EINVAL;
+	}
+	ep->desc = NULL;
+
+	list_splice_init(&ep->queue, &req_list);
+	usba_ep_writel(ep, CFG, 0);
+	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+	usba_writel(udc, INT_ENB,
+		    usba_readl(udc, INT_ENB) &
+		    ~USBA_BF(EPT_INT, 1 << ep->index));
+
+	request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct usba_request *req;
+
+	DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+	req = calloc(1, sizeof(struct usba_request));
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_request *req = to_usba_req(_req);
+
+	DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+	free(req);
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct usba_request *req = to_usba_req(_req);
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags = 0;
+	int ret;
+
+	DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+	    ep->ep.name, req, _req->length);
+
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN ||
+	    !ep->desc)
+		return -ESHUTDOWN;
+
+	req->submitted = 0;
+	req->using_dma = 0;
+	req->last_transaction = 0;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* May have received a reset since last time we checked */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		list_add_tail(&req->queue, &ep->queue);
+
+		if ((!ep_is_control(ep) && ep->is_in) ||
+		    (ep_is_control(ep) && (ep->state == DATA_STAGE_IN ||
+		    ep->state == STATUS_STAGE_IN)))
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		else
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_request *req = to_usba_req(_req);
+
+	DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+	    ep->ep.name, req);
+
+	/*
+	 * Errors should stop the queue from advancing until the
+	 * completion function returns.
+	 */
+	list_del_init(&req->queue);
+
+	request_complete(ep, req, -ECONNRESET);
+
+	/* Process the next request if any */
+	submit_next_request(ep);
+
+	return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	unsigned long flags = 0;
+	int ret = 0;
+
+	DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+	    value ? "set" : "clear");
+
+	if (!ep->desc) {
+		DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+		    ep->ep.name);
+		return -ENODEV;
+	}
+
+	if (ep->is_isoc) {
+		DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+		    ep->ep.name);
+		return -ENOTTY;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*
+	 * We can't halt IN endpoints while there are still data to be
+	 * transferred
+	 */
+	if (!list_empty(&ep->queue) ||
+	    ((value && ep->is_in && (usba_ep_readl(ep, STA) &
+	    USBA_BF(BUSY_BANKS, -1L))))) {
+		ret = -EAGAIN;
+	} else {
+		if (value)
+			usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+		else
+			usba_ep_writel(ep, CLR_STA,
+				       USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+		usba_ep_readl(ep, STA);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+
+	return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+
+	usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+	.enable		= usba_ep_enable,
+	.disable	= usba_ep_disable,
+	.alloc_request	= usba_ep_alloc_request,
+	.free_request	= usba_ep_free_request,
+	.queue		= usba_ep_queue,
+	.dequeue	= usba_ep_dequeue,
+	.set_halt	= usba_ep_set_halt,
+	.fifo_status	= usba_ep_fifo_status,
+	.fifo_flush	= usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+
+	return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags = 0;
+	u32 ctrl;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+		ctrl = usba_readl(udc, CTRL);
+		usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (is_selfpowered)
+		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+	.get_frame		= usba_udc_get_frame,
+	.wakeup			= usba_udc_wakeup,
+	.set_selfpowered	= usba_udc_set_selfpowered,
+};
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = cpu_to_le16(64),
+	/* FIXME: I have no idea what to put here */
+	.bInterval = 1,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+	struct usba_ep *ep;
+	struct usba_request *req, *tmp_req;
+
+	usba_writel(udc, EPT_RST, ~0UL);
+
+	ep = to_usba_ep(udc->gadget.ep0);
+	list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, -ECONNRESET);
+	}
+
+	/* NOTE:  normally, the next call to the gadget driver is in
+	 * charge of disabling endpoints... usually disconnect().
+	 * The exception would be entering a high speed test mode.
+	 *
+	 * FIXME remove this code ... and retest thoroughly.
+	 */
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		if (ep->desc) {
+			spin_unlock(&udc->lock);
+			usba_ep_disable(&ep->ep);
+			spin_lock(&udc->lock);
+		}
+	}
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+	struct usba_ep *ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return to_usba_ep(udc->gadget.ep0);
+
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		u8 bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+				== (wIndex & USB_ENDPOINT_NUMBER_MASK))
+			return ep;
+	}
+
+	return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+	usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+	ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+	if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+		return 1;
+	return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+	u32 regval;
+
+	DBG(DBG_BUS, "setting address %u...\n", addr);
+	regval = usba_readl(udc, CTRL);
+	regval = USBA_BFINS(DEV_ADDR, addr, regval);
+	usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+	static const char test_packet_buffer[] = {
+		/* JKJKJKJK * 9 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		/* JJKKJJKK * 8 */
+		0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+		/* JJKKJJKK * 8 */
+		0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+		/* JJJJJJJKKKKKKK * 8 */
+		0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		/* JJJJJJJK * 8 */
+		0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+		/* {JKKKKKKK * 10}, JK */
+		0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+	};
+	struct usba_ep *ep;
+	int test_mode;
+
+	test_mode = udc->test_mode;
+
+	/* Start from a clean slate */
+	reset_all_endpoints(udc);
+
+	switch (test_mode) {
+	case 0x0100:
+		/* Test_J */
+		usba_writel(udc, TST, USBA_TST_J_MODE);
+		DBG(DBG_ALL, "Entering Test_J mode...\n");
+		break;
+	case 0x0200:
+		/* Test_K */
+		usba_writel(udc, TST, USBA_TST_K_MODE);
+		DBG(DBG_ALL, "Entering Test_K mode...\n");
+		break;
+	case 0x0300:
+		/*
+		 * Test_SE0_NAK: Force high-speed mode and set up ep0
+		 * for Bulk IN transfers
+		 */
+		ep = &udc->usba_ep[0];
+		usba_writel(udc, TST,
+			    USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+		usba_ep_writel(ep, CFG,
+			       USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+			       | USBA_EPT_DIR_IN
+			       | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+			       | USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			DBG(DBG_ALL, "Test_SE0_NAK: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			DBG(DBG_ALL, "Entering Test_SE0_NAK mode...\n");
+		}
+		break;
+	case 0x0400:
+		/* Test_Packet */
+		ep = &udc->usba_ep[0];
+		usba_ep_writel(ep, CFG,
+			       USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+			       | USBA_EPT_DIR_IN
+			       | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+			       | USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			DBG(DBG_ALL, "Test_Packet: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			usba_writel(udc, TST, USBA_TST_PKT_MODE);
+			memcpy(ep->fifo, test_packet_buffer,
+			       sizeof(test_packet_buffer));
+			usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+			DBG(DBG_ALL, "Entering Test_Packet mode...\n");
+		}
+		break;
+	default:
+		DBG(DBG_ERR, "Invalid test mode: 0x%04x\n", test_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == cpu_to_le16(USB_DEVICE_TEST_MODE))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == cpu_to_le16(USB_ENDPOINT_HALT))
+		return true;
+	return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+		struct usb_ctrlrequest *crq)
+{
+	int retval = 0;
+
+	switch (crq->bRequest) {
+	case USB_REQ_GET_STATUS: {
+		u16 status;
+
+		if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+			status = cpu_to_le16(udc->devstatus);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+			status = cpu_to_le16(0);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+			struct usba_ep *target;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			status = 0;
+			if (is_stalled(udc, target))
+				status |= cpu_to_le16(1);
+		} else {
+			goto delegate;
+		}
+
+		/* Write directly to the FIFO. No queueing is done. */
+		if (crq->wLength != cpu_to_le16(sizeof(status)))
+			goto stall;
+		ep->state = DATA_STAGE_IN;
+		__raw_writew(status, ep->fifo);
+		usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+		break;
+	}
+
+	case USB_REQ_CLEAR_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_remote_wakeup(crq))
+				udc->devstatus
+					&= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+			else
+				/* Can't CLEAR_FEATURE TEST_MODE */
+				goto stall;
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != cpu_to_le16(0) ||
+			    !feature_is_ep_halt(crq))
+				goto stall;
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+			if (target->index != 0)
+				usba_ep_writel(target, CLR_STA,
+					       USBA_TOGGLE_CLR);
+		} else {
+			goto delegate;
+		}
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_test_mode(crq)) {
+				send_status(udc, ep);
+				ep->state = STATUS_STAGE_TEST;
+				udc->test_mode = le16_to_cpu(crq->wIndex);
+				return 0;
+			} else if (feature_is_dev_remote_wakeup(crq)) {
+				udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+			} else {
+				goto stall;
+			}
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != cpu_to_le16(0) ||
+			    !feature_is_ep_halt(crq))
+				goto stall;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+		} else {
+			goto delegate;
+		}
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_ADDRESS:
+		if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			goto delegate;
+
+		set_address(udc, le16_to_cpu(crq->wValue));
+		send_status(udc, ep);
+		ep->state = STATUS_STAGE_ADDR;
+		break;
+
+	default:
+delegate:
+		spin_unlock(&udc->lock);
+		retval = udc->driver->setup(&udc->gadget, crq);
+		spin_lock(&udc->lock);
+	}
+
+	return retval;
+
+stall:
+	DBG(DBG_ALL, "%s: Invalid setup request: %02x.%02x v%04x i%04x l%d\n",
+	    ep->ep.name, crq->bRequestType, crq->bRequest,
+	    le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+	    le16_to_cpu(crq->wLength));
+	set_protocol_stall(udc, ep);
+
+	return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+restart:
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+	    ep->ep.name, ep->state, epstatus, epctrl);
+
+	req = NULL;
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+	if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		if (req->submitted)
+			next_fifo_transaction(ep, req);
+		else
+			submit_request(ep, req);
+
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		}
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+		usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+		switch (ep->state) {
+		case DATA_STAGE_IN:
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = STATUS_STAGE_OUT;
+			break;
+		case STATUS_STAGE_ADDR:
+			/* Activate our new address */
+			usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+						| USBA_FADDR_EN));
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_IN:
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+				submit_next_request(ep);
+			}
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_TEST:
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			if (do_test_mode(udc))
+				set_protocol_stall(udc, ep);
+			break;
+		default:
+			DBG(DBG_ALL, "%s: TXCOMP: Invalid endpoint state %d\n",
+			    ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		switch (ep->state) {
+		case STATUS_STAGE_OUT:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+			}
+			ep->state = WAIT_FOR_SETUP;
+			break;
+
+		case DATA_STAGE_OUT:
+			receive_data(ep);
+			break;
+
+		default:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			DBG(DBG_ALL, "%s: RXRDY: Invalid endpoint state %d\n",
+			    ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if (epstatus & USBA_RX_SETUP) {
+		union {
+			struct usb_ctrlrequest crq;
+			unsigned long data[2];
+		} crq;
+		unsigned int pkt_len;
+		int ret;
+
+		if (ep->state != WAIT_FOR_SETUP) {
+			/*
+			 * Didn't expect a SETUP packet at this
+			 * point. Clean up any pending requests (which
+			 * may be successful).
+			 */
+			int status = -EPROTO;
+
+			/*
+			 * RXRDY and TXCOMP are dropped when SETUP
+			 * packets arrive.  Just pretend we received
+			 * the status packet.
+			 */
+			if (ep->state == STATUS_STAGE_OUT ||
+			    ep->state == STATUS_STAGE_IN) {
+				usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+				status = 0;
+			}
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, status);
+			}
+		}
+
+		pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+		DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+		if (pkt_len != sizeof(crq)) {
+			DBG(DBG_ALL, "udc: Invalid length %u (expected %zu)\n",
+			    pkt_len, sizeof(crq));
+			set_protocol_stall(udc, ep);
+			return;
+		}
+
+		DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+		memcpy(crq.data, ep->fifo, sizeof(crq));
+
+		/* Free up one bank in the FIFO so that we can
+		 * generate or receive a reply right away. */
+		usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+		if (crq.crq.bRequestType & USB_DIR_IN) {
+			/*
+			 * The USB 2.0 spec states that "if wLength is
+			 * zero, there is no data transfer phase."
+			 * However, testusb #14 seems to actually
+			 * expect a data phase even if wLength = 0...
+			 */
+			ep->state = DATA_STAGE_IN;
+		} else {
+			if (crq.crq.wLength != cpu_to_le16(0))
+				ep->state = DATA_STAGE_OUT;
+			else
+				ep->state = STATUS_STAGE_IN;
+		}
+
+		ret = -1;
+		if (ep->index == 0) {
+			ret = handle_ep0_setup(udc, ep, &crq.crq);
+		} else {
+			spin_unlock(&udc->lock);
+			ret = udc->driver->setup(&udc->gadget, &crq.crq);
+			spin_lock(&udc->lock);
+		}
+
+		DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+		    crq.crq.bRequestType, crq.crq.bRequest,
+		    le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+		if (ret < 0) {
+			/* Let the host know that we failed */
+			set_protocol_stall(udc, ep);
+		}
+	}
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+	while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+		if (list_empty(&ep->queue)) {
+			DBG(DBG_INT, "ep_irq: queue empty\n");
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			return;
+		}
+
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+
+		if (req->submitted)
+			next_fifo_transaction(ep, req);
+		else
+			submit_request(ep, req);
+
+		if (req->last_transaction) {
+			list_del_init(&req->queue);
+			submit_next_request(ep);
+			request_complete(ep, req, 0);
+		}
+
+		epstatus = usba_ep_readl(ep, STA);
+		epctrl = usba_ep_readl(ep, CTL);
+	}
+
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+		receive_data(ep);
+	}
+}
+
+static int usba_udc_irq(struct usba_udc *udc)
+{
+	u32 status, ep_status;
+
+	spin_lock(&udc->lock);
+
+	status = usba_readl(udc, INT_STA);
+	DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+	if (status & USBA_DET_SUSPEND) {
+		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		DBG(DBG_BUS, "Suspend detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+		    udc->driver && udc->driver->suspend) {
+			spin_unlock(&udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	if (status & USBA_WAKE_UP) {
+		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+		DBG(DBG_BUS, "Wake Up CPU detected\n");
+	}
+
+	if (status & USBA_END_OF_RESUME) {
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+		DBG(DBG_BUS, "Resume detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+		    udc->driver && udc->driver->resume) {
+			spin_unlock(&udc->lock);
+			udc->driver->resume(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	ep_status = USBA_BFEXT(EPT_INT, status);
+	if (ep_status) {
+		int i;
+
+		for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+			if (ep_status & (1 << i)) {
+				if (ep_is_control(&udc->usba_ep[i]))
+					usba_control_irq(udc, &udc->usba_ep[i]);
+				else
+					usba_ep_irq(udc, &udc->usba_ep[i]);
+			}
+	}
+
+	if (status & USBA_END_OF_RESET) {
+		struct usba_ep *ep0;
+
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+		reset_all_endpoints(udc);
+
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+		    udc->driver->disconnect) {
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			spin_unlock(&udc->lock);
+			udc->driver->disconnect(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+
+		if (status & USBA_HIGH_SPEED)
+			udc->gadget.speed = USB_SPEED_HIGH;
+		else
+			udc->gadget.speed = USB_SPEED_FULL;
+
+		ep0 = &udc->usba_ep[0];
+		ep0->desc = &usba_ep0_desc;
+		ep0->state = WAIT_FOR_SETUP;
+		usba_ep_writel(ep0, CFG,
+			       (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+		usba_ep_writel(ep0, CTL_ENB,
+			       USBA_EPT_ENABLE | USBA_RX_SETUP);
+		usba_writel(udc, INT_ENB,
+			    (usba_readl(udc, INT_ENB)
+			     | USBA_BF(EPT_INT, 1)
+			     | USBA_DET_SUSPEND
+			     | USBA_END_OF_RESUME));
+
+		/*
+		 * Unclear why we hit this irregularly, e.g. in usbtest,
+		 * but it's clearly harmless...
+		 */
+		if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+			DBG(DBG_ALL, "ODD: EP0 configuration is invalid!\n");
+	}
+
+	spin_unlock(&udc->lock);
+
+	return 0;
+}
+
+static int atmel_usba_start(struct usba_udc *udc)
+{
+	udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+
+	udc->vbus_prev = 0;
+
+	/* If Vbus is present, enable the controller and wait for reset */
+	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+		usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+	}
+
+	return 0;
+}
+
+static int atmel_usba_stop(struct usba_udc *udc)
+{
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	reset_all_endpoints(udc);
+
+	/* This will also disable the DP pullup */
+	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+
+	return 0;
+}
+
+static struct usba_udc controller = {
+	.regs = (unsigned *)ATMEL_BASE_UDPHS,
+	.fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
+	.gadget = {
+		.ops		= &usba_udc_ops,
+		.ep_list	= LIST_HEAD_INIT(controller.gadget.ep_list),
+		.speed		= USB_SPEED_HIGH,
+		.is_dualspeed	= 1,
+		.name		= "atmel_usba_udc",
+	},
+};
+
+int usb_gadget_handle_interrupts(int index)
+{
+	struct usba_udc *udc = &controller;
+
+	return usba_udc_irq(udc);
+}
+
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &controller;
+	int ret;
+
+	if (!driver || !driver->bind || !driver->setup) {
+		printf("bad paramter\n");
+		return -EINVAL;
+	}
+
+	if (udc->driver) {
+		printf("UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+
+	atmel_usba_start(udc);
+
+	udc->driver = driver;
+
+	ret = driver->bind(&udc->gadget);
+	if (ret) {
+		pr_err("driver->bind() returned %d\n", ret);
+		udc->driver = NULL;
+	}
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &controller;
+
+	if (!driver || !driver->unbind || !driver->disconnect) {
+		pr_err("bad paramter\n");
+		return -EINVAL;
+	}
+
+	driver->disconnect(&udc->gadget);
+	driver->unbind(&udc->gadget);
+	udc->driver = NULL;
+
+	atmel_usba_stop(udc);
+
+	return 0;
+}
+
+static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata,
+				      struct usba_udc *udc)
+{
+	struct usba_ep *eps;
+	int i;
+
+	eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
+	if (!eps) {
+		pr_err("failed to alloc eps\n");
+		return NULL;
+	}
+
+	udc->gadget.ep0 = &eps[0].ep;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+	for (i = 0; i < pdata->num_ep; i++) {
+		struct usba_ep *ep = &eps[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+		ep->ep.ops = &usba_ep_ops;
+		ep->ep.name = pdata->ep[i].name;
+		ep->ep.maxpacket = pdata->ep[i].fifo_size;
+		ep->fifo_size = ep->ep.maxpacket;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->nr_banks = pdata->ep[i].nr_banks;
+		ep->index = pdata->ep[i].index;
+		ep->can_dma = pdata->ep[i].can_dma;
+		ep->can_isoc = pdata->ep[i].can_isoc;
+		if (i)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	};
+
+	return eps;
+}
+
+int usba_udc_probe(struct usba_platform_data *pdata)
+{
+	struct usba_udc *udc;
+
+	udc = &controller;
+
+	udc->usba_ep = usba_udc_pdata(pdata, udc);
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h b/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644
index 000000000..f6cb48c1c
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h
@@ -0,0 +1,320 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Register definition for Atmel USBA high speed USB device controller
+ * [Original from Linux kernel: drivers/usb/gadget/atmel_usba_udc.h]
+ *
+ * Copyright (C) 2005-2013 Atmel Corporation
+ *			   Bo Shen <voice.shen@atmel.com>
+ */
+
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL				0x0000
+#define USBA_FNUM				0x0004
+#define USBA_INT_ENB				0x0010
+#define USBA_INT_STA				0x0014
+#define USBA_INT_CLR				0x0018
+#define USBA_EPT_RST				0x001c
+#define USBA_TST				0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG				0x0000
+#define USBA_EPT_CTL_ENB			0x0004
+#define USBA_EPT_CTL_DIS			0x0008
+#define USBA_EPT_CTL				0x000c
+#define USBA_EPT_SET_STA			0x0014
+#define USBA_EPT_CLR_STA			0x0018
+#define USBA_EPT_STA				0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC			0x0000
+#define USBA_DMA_ADDRESS			0x0004
+#define USBA_DMA_CONTROL			0x0008
+#define USBA_DMA_STATUS				0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET			0
+#define USBA_DEV_ADDR_SIZE			7
+#define USBA_FADDR_EN				(1 <<  7)
+#define USBA_EN_USBA				(1 <<  8)
+#define USBA_DETACH				(1 <<  9)
+#define USBA_REMOTE_WAKE_UP			(1 << 10)
+#define USBA_PULLD_DIS				(1 << 11)
+
+#define USBA_ENABLE_MASK			(USBA_EN_USBA | USBA_PULLD_DIS)
+#define USBA_DISABLE_MASK			USBA_DETACH
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET		0
+#define USBA_MICRO_FRAME_NUM_SIZE		3
+#define USBA_FRAME_NUMBER_OFFSET		3
+#define USBA_FRAME_NUMBER_SIZE			11
+#define USBA_FRAME_NUM_ERROR			(1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED				(1 <<  0)
+#define USBA_DET_SUSPEND			(1 <<  1)
+#define USBA_MICRO_SOF				(1 <<  2)
+#define USBA_SOF				(1 <<  3)
+#define USBA_END_OF_RESET			(1 <<  4)
+#define USBA_WAKE_UP				(1 <<  5)
+#define USBA_END_OF_RESUME			(1 <<  6)
+#define USBA_UPSTREAM_RESUME			(1 <<  7)
+#define USBA_EPT_INT_OFFSET			8
+#define USBA_EPT_INT_SIZE			16
+#define USBA_DMA_INT_OFFSET			24
+#define USBA_DMA_INT_SIZE			8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET				0
+#define USBA_RST_SIZE				16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET			0
+#define USBA_SPEED_CFG_SIZE			2
+#define USBA_TST_J_MODE				(1 <<  2)
+#define USBA_TST_K_MODE				(1 <<  3)
+#define USBA_TST_PKT_MODE			(1 <<  4)
+#define USBA_OPMODE2				(1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET			0
+#define USBA_EPT_SIZE_SIZE			3
+#define USBA_EPT_DIR_IN				(1 <<  3)
+#define USBA_EPT_TYPE_OFFSET			4
+#define USBA_EPT_TYPE_SIZE			2
+#define USBA_BK_NUMBER_OFFSET			6
+#define USBA_BK_NUMBER_SIZE			2
+#define USBA_NB_TRANS_OFFSET			8
+#define USBA_NB_TRANS_SIZE			2
+#define USBA_EPT_MAPPED				(1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE				(1 <<  0)
+#define USBA_AUTO_VALID				(1 <<  1)
+#define USBA_INTDIS_DMA				(1 <<  3)
+#define USBA_NYET_DIS				(1 <<  4)
+#define USBA_DATAX_RX				(1 <<  6)
+#define USBA_MDATA_RX				(1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE			(1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL			(1 <<  5)
+#define USBA_TOGGLE_CLR				(1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET			6
+#define USBA_TOGGLE_SEQ_SIZE			2
+#define USBA_ERR_OVFLW				(1 <<  8)
+#define USBA_RX_BK_RDY				(1 <<  9)
+#define USBA_KILL_BANK				(1 <<  9)
+#define USBA_TX_COMPLETE			(1 << 10)
+#define USBA_TX_PK_RDY				(1 << 11)
+#define USBA_ISO_ERR_TRANS			(1 << 11)
+#define USBA_RX_SETUP				(1 << 12)
+#define USBA_ISO_ERR_FLOW			(1 << 12)
+#define USBA_STALL_SENT				(1 << 13)
+#define USBA_ISO_ERR_CRC			(1 << 13)
+#define USBA_ISO_ERR_NBTRANS			(1 << 13)
+#define USBA_NAK_IN				(1 << 14)
+#define USBA_ISO_ERR_FLUSH			(1 << 14)
+#define USBA_NAK_OUT				(1 << 15)
+#define USBA_CURRENT_BANK_OFFSET		16
+#define USBA_CURRENT_BANK_SIZE			2
+#define USBA_BUSY_BANKS_OFFSET			18
+#define USBA_BUSY_BANKS_SIZE			2
+#define USBA_BYTE_COUNT_OFFSET			20
+#define USBA_BYTE_COUNT_SIZE			11
+#define USBA_SHORT_PACKET			(1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN				(1 <<  0)
+#define USBA_DMA_LINK				(1 <<  1)
+#define USBA_DMA_END_TR_EN			(1 <<  2)
+#define USBA_DMA_END_BUF_EN			(1 <<  3)
+#define USBA_DMA_END_TR_IE			(1 <<  4)
+#define USBA_DMA_END_BUF_IE			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE			(1 <<  6)
+#define USBA_DMA_BURST_LOCK			(1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET			16
+#define USBA_DMA_BUF_LEN_SIZE			16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE			(1 <<  1)
+#define USBA_DMA_END_TR_ST			(1 <<  4)
+#define USBA_DMA_END_BUF_ST			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST			(1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL			0
+#define USBA_SPEED_CFG_FORCE_HIGH		2
+#define USBA_SPEED_CFG_FORCE_FULL		3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8				0
+#define USBA_EPT_SIZE_16			1
+#define USBA_EPT_SIZE_32			2
+#define USBA_EPT_SIZE_64			3
+#define USBA_EPT_SIZE_128			4
+#define USBA_EPT_SIZE_256			5
+#define USBA_EPT_SIZE_512			6
+#define USBA_EPT_SIZE_1024			7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL			0
+#define USBA_EPT_TYPE_ISO			1
+#define USBA_EPT_TYPE_BULK			2
+#define USBA_EPT_TYPE_INT			3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO			0
+#define USBA_BK_NUMBER_ONE			1
+#define USBA_BK_NUMBER_DOUBLE			2
+#define USBA_BK_NUMBER_TRIPLE			3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)					\
+	(((value) & ((1 << USBA_##name##_SIZE) - 1))		\
+	 << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)					\
+	(((value) >> USBA_##name##_OFFSET)			\
+	 & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)				\
+	(((old) & ~(((1 << USBA_##name##_SIZE) - 1)		\
+		    << USBA_##name##_OFFSET))			\
+	 | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)					\
+	__raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)				\
+	__raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)					\
+	__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)					\
+	__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)	(0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)	(0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)	((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS	7
+
+#define EP0_FIFO_SIZE		64
+#define EP0_EPT_SIZE		USBA_EPT_SIZE_64
+#define EP0_NR_BANKS		1
+
+#define DBG_ERR		0x0001	/* report all error returns */
+#define DBG_HW		0x0002	/* debug hardware initialization */
+#define DBG_GADGET	0x0004	/* calls to/from gadget driver */
+#define DBG_INT		0x0008	/* interrupts */
+#define DBG_BUS		0x0010	/* report changes in bus state */
+#define DBG_QUEUE	0x0020  /* debug request queue processing */
+#define DBG_FIFO	0x0040  /* debug FIFO contents */
+#define DBG_DMA		0x0080  /* debug DMA handling */
+#define DBG_REQ		0x0100	/* print out queued request length */
+#define DBG_ALL		0xffff
+#define DBG_NONE	0x0000
+
+#define DEBUG_LEVEL	(DBG_ERR)
+
+#define DBG(level, fmt, ...)					\
+	do {							\
+		if ((level) & DEBUG_LEVEL)			\
+			debug("udc: " fmt, ## __VA_ARGS__);	\
+	} while (0)
+
+enum usba_ctrl_state {
+	WAIT_FOR_SETUP,
+	DATA_STAGE_IN,
+	DATA_STAGE_OUT,
+	STATUS_STAGE_IN,
+	STATUS_STAGE_OUT,
+	STATUS_STAGE_ADDR,
+	STATUS_STAGE_TEST,
+};
+
+struct usba_dma_desc {
+	dma_addr_t next;
+	dma_addr_t addr;
+	u32 ctrl;
+};
+
+struct usba_ep {
+	int					state;
+	void					*ep_regs;
+	void					*dma_regs;
+	void					*fifo;
+	struct usb_ep				ep;
+	struct usba_udc				*udc;
+
+	struct list_head			queue;
+
+	u16					fifo_size;
+	u8					nr_banks;
+	u8					index;
+	unsigned int				can_dma:1;
+	unsigned int				can_isoc:1;
+	unsigned int				is_isoc:1;
+	unsigned int				is_in:1;
+
+	const struct usb_endpoint_descriptor	*desc;
+};
+
+struct usba_request {
+	struct usb_request			req;
+	struct list_head			queue;
+
+	u32					ctrl;
+
+	unsigned int				submitted:1;
+	unsigned int				last_transaction:1;
+	unsigned int				using_dma:1;
+	unsigned int				mapped:1;
+};
+
+struct usba_udc {
+	void *regs;
+	void *fifo;
+
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct platform_device *pdev;
+	int irq;
+	int vbus_pin;
+	int vbus_pin_inverted;
+	int num_ep;
+	struct usba_ep *usba_ep;
+
+	u16 devstatus;
+
+	u16 test_mode;
+	int vbus_prev;
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+	return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep)	((ep)->index == 0)
+#define ep_is_idle(ep)		((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/roms/u-boot/drivers/usb/gadget/bcm_udc_otg.h b/roms/u-boot/drivers/usb/gadget/bcm_udc_otg.h
new file mode 100644
index 000000000..24cc936c6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/bcm_udc_otg.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2015 Broadcom Corporation.
+ */
+
+#ifndef __BCM_UDC_OTG_H
+#define __BCM_UDC_OTG_H
+
+#include <common.h>
+
+static inline void wfld_set(uintptr_t addr, uint32_t fld_val, uint32_t fld_mask)
+{
+	writel(((readl(addr) & ~(fld_mask)) | (fld_val)), (addr));
+}
+
+static inline void wfld_clear(uintptr_t addr, uint32_t fld_mask)
+{
+	writel((readl(addr) & ~(fld_mask)), (addr));
+}
+
+#endif
diff --git a/roms/u-boot/drivers/usb/gadget/bcm_udc_otg_phy.c b/roms/u-boot/drivers/usb/gadget/bcm_udc_otg_phy.c
new file mode 100644
index 000000000..c89cd57c2
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/bcm_udc_otg_phy.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015 Broadcom Corporation.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include <linux/delay.h>
+
+#include "dwc2_udc_otg_priv.h"
+#include "bcm_udc_otg.h"
+
+void otg_phy_init(struct dwc2_udc *dev)
+{
+	/* turn on the USB OTG clocks */
+	clk_usb_otg_enable((void *)HSOTG_BASE_ADDR);
+
+	/* set Phy to driving mode */
+	wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		   HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK);
+
+	udelay(100);
+
+	/* clear Soft Disconnect */
+	wfld_clear(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
+		   HSOTG_DCTL_SFTDISCON_MASK);
+
+	/* invoke Reset (active low) */
+	wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		   HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK);
+
+	/* Reset needs to be asserted for 2ms */
+	udelay(2000);
+
+	/* release Reset */
+	wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		 HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK,
+		 HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK);
+}
+
+void otg_phy_off(struct dwc2_udc *dev)
+{
+	/* Soft Disconnect */
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
+		 HSOTG_DCTL_SFTDISCON_MASK,
+		 HSOTG_DCTL_SFTDISCON_MASK);
+
+	/* set Phy to non-driving (reset) mode */
+	wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		 HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK,
+		 HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/ci_udc.c b/roms/u-boot/drivers/usb/gadget/ci_udc.c
new file mode 100644
index 000000000..226a9e6d6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/ci_udc.c
@@ -0,0 +1,1072 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <cpu_func.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <asm/cache.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <usb/ci_udc.h>
+#include "../host/ehci.h"
+#include "ci_udc.h"
+
+/*
+ * Check if the system has too long cachelines. If the cachelines are
+ * longer then 128b, the driver will not be able flush/invalidate data
+ * cache over separate QH entries. We use 128b because one QH entry is
+ * 64b long and there are always two QH list entries for each endpoint.
+ */
+#if ARCH_DMA_MINALIGN > 128
+#error This driver can not work on systems with caches longer than 128b
+#endif
+
+/*
+ * Every QTD must be individually aligned, since we can program any
+ * QTD's address into HW. Cache flushing requires ARCH_DMA_MINALIGN,
+ * and the USB HW requires 32-byte alignment. Align to both:
+ */
+#define ILIST_ALIGN		roundup(ARCH_DMA_MINALIGN, 32)
+/* Each QTD is this size */
+#define ILIST_ENT_RAW_SZ	sizeof(struct ept_queue_item)
+/*
+ * Align the size of the QTD too, so we can add this value to each
+ * QTD's address to get another aligned address.
+ */
+#define ILIST_ENT_SZ		roundup(ILIST_ENT_RAW_SZ, ILIST_ALIGN)
+/* For each endpoint, we need 2 QTDs, one for each of IN and OUT */
+#define ILIST_SZ		(NUM_ENDPOINTS * 2 * ILIST_ENT_SZ)
+
+#define EP_MAX_LENGTH_TRANSFER	0x4000
+
+#ifndef DEBUG
+#define DBG(x...) do {} while (0)
+#else
+#define DBG(x...) printf(x)
+static const char *reqname(unsigned r)
+{
+	switch (r) {
+	case USB_REQ_GET_STATUS: return "GET_STATUS";
+	case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE";
+	case USB_REQ_SET_FEATURE: return "SET_FEATURE";
+	case USB_REQ_SET_ADDRESS: return "SET_ADDRESS";
+	case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
+	case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
+	case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION";
+	case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION";
+	case USB_REQ_GET_INTERFACE: return "GET_INTERFACE";
+	case USB_REQ_SET_INTERFACE: return "SET_INTERFACE";
+	default: return "*UNKNOWN*";
+	}
+}
+#endif
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
+};
+
+static int ci_pullup(struct usb_gadget *gadget, int is_on);
+static int ci_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc);
+static int ci_ep_disable(struct usb_ep *ep);
+static int ci_ep_queue(struct usb_ep *ep,
+		struct usb_request *req, gfp_t gfp_flags);
+static int ci_ep_dequeue(struct usb_ep *ep, struct usb_request *req);
+static struct usb_request *
+ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
+static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
+
+static struct usb_gadget_ops ci_udc_ops = {
+	.pullup = ci_pullup,
+};
+
+static struct usb_ep_ops ci_ep_ops = {
+	.enable         = ci_ep_enable,
+	.disable        = ci_ep_disable,
+	.queue          = ci_ep_queue,
+	.dequeue	= ci_ep_dequeue,
+	.alloc_request  = ci_ep_alloc_request,
+	.free_request   = ci_ep_free_request,
+};
+
+__weak void ci_init_after_reset(struct ehci_ctrl *ctrl)
+{
+}
+
+/* Init values for USB endpoints. */
+static const struct usb_ep ci_ep_init[5] = {
+	[0] = {	/* EP 0 */
+		.maxpacket	= 64,
+		.name		= "ep0",
+		.ops		= &ci_ep_ops,
+	},
+	[1] = {
+		.maxpacket	= 512,
+		.name		= "ep1in-bulk",
+		.ops		= &ci_ep_ops,
+	},
+	[2] = {
+		.maxpacket	= 512,
+		.name		= "ep2out-bulk",
+		.ops		= &ci_ep_ops,
+	},
+	[3] = {
+		.maxpacket	= 512,
+		.name		= "ep3in-int",
+		.ops		= &ci_ep_ops,
+	},
+	[4] = {
+		.maxpacket	= 512,
+		.name		= "ep-",
+		.ops		= &ci_ep_ops,
+	},
+};
+
+static struct ci_drv controller = {
+	.gadget	= {
+		.name	= "ci_udc",
+		.ops	= &ci_udc_ops,
+		.is_dualspeed = 1,
+		.max_speed = USB_SPEED_HIGH,
+	},
+};
+
+/**
+ * ci_get_qh() - return queue head for endpoint
+ * @ep_num:	Endpoint number
+ * @dir_in:	Direction of the endpoint (IN = 1, OUT = 0)
+ *
+ * This function returns the QH associated with particular endpoint
+ * and it's direction.
+ */
+static struct ept_queue_head *ci_get_qh(int ep_num, int dir_in)
+{
+	return &controller.epts[(ep_num * 2) + dir_in];
+}
+
+/**
+ * ci_get_qtd() - return queue item for endpoint
+ * @ep_num:	Endpoint number
+ * @dir_in:	Direction of the endpoint (IN = 1, OUT = 0)
+ *
+ * This function returns the QH associated with particular endpoint
+ * and it's direction.
+ */
+static struct ept_queue_item *ci_get_qtd(int ep_num, int dir_in)
+{
+	int index = (ep_num * 2) + dir_in;
+	uint8_t *imem = controller.items_mem + (index * ILIST_ENT_SZ);
+	return (struct ept_queue_item *)imem;
+}
+
+/**
+ * ci_flush_qh - flush cache over queue head
+ * @ep_num:	Endpoint number
+ *
+ * This function flushes cache over QH for particular endpoint.
+ */
+static void ci_flush_qh(int ep_num)
+{
+	struct ept_queue_head *head = ci_get_qh(ep_num, 0);
+	const unsigned long start = (unsigned long)head;
+	const unsigned long end = start + 2 * sizeof(*head);
+
+	flush_dcache_range(start, end);
+}
+
+/**
+ * ci_invalidate_qh - invalidate cache over queue head
+ * @ep_num:	Endpoint number
+ *
+ * This function invalidates cache over QH for particular endpoint.
+ */
+static void ci_invalidate_qh(int ep_num)
+{
+	struct ept_queue_head *head = ci_get_qh(ep_num, 0);
+	unsigned long start = (unsigned long)head;
+	unsigned long end = start + 2 * sizeof(*head);
+
+	invalidate_dcache_range(start, end);
+}
+
+/**
+ * ci_flush_qtd - flush cache over queue item
+ * @ep_num:	Endpoint number
+ *
+ * This function flushes cache over qTD pair for particular endpoint.
+ */
+static void ci_flush_qtd(int ep_num)
+{
+	struct ept_queue_item *item = ci_get_qtd(ep_num, 0);
+	const unsigned long start = (unsigned long)item;
+	const unsigned long end = start + 2 * ILIST_ENT_SZ;
+
+	flush_dcache_range(start, end);
+}
+
+/**
+ * ci_flush_td - flush cache over queue item
+ * @td:	td pointer
+ *
+ * This function flushes cache for particular transfer descriptor.
+ */
+static void ci_flush_td(struct ept_queue_item *td)
+{
+	const unsigned long start = (unsigned long)td;
+	const unsigned long end = (unsigned long)td + ILIST_ENT_SZ;
+	flush_dcache_range(start, end);
+}
+
+/**
+ * ci_invalidate_qtd - invalidate cache over queue item
+ * @ep_num:	Endpoint number
+ *
+ * This function invalidates cache over qTD pair for particular endpoint.
+ */
+static void ci_invalidate_qtd(int ep_num)
+{
+	struct ept_queue_item *item = ci_get_qtd(ep_num, 0);
+	const unsigned long start = (unsigned long)item;
+	const unsigned long end = start + 2 * ILIST_ENT_SZ;
+
+	invalidate_dcache_range(start, end);
+}
+
+/**
+ * ci_invalidate_td - invalidate cache over queue item
+ * @td:	td pointer
+ *
+ * This function invalidates cache for particular transfer descriptor.
+ */
+static void ci_invalidate_td(struct ept_queue_item *td)
+{
+	const unsigned long start = (unsigned long)td;
+	const unsigned long end = start + ILIST_ENT_SZ;
+	invalidate_dcache_range(start, end);
+}
+
+static struct usb_request *
+ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
+{
+	struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+	int num = -1;
+	struct ci_req *ci_req;
+
+	if (ci_ep->desc)
+		num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+
+	if (num == 0 && controller.ep0_req)
+		return &controller.ep0_req->req;
+
+	ci_req = calloc(1, sizeof(*ci_req));
+	if (!ci_req)
+		return NULL;
+
+	INIT_LIST_HEAD(&ci_req->queue);
+
+	if (num == 0)
+		controller.ep0_req = ci_req;
+
+	return &ci_req->req;
+}
+
+static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+	struct ci_req *ci_req = container_of(req, struct ci_req, req);
+	int num = -1;
+
+	if (ci_ep->desc)
+		num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+
+	if (num == 0) {
+		if (!controller.ep0_req)
+			return;
+		controller.ep0_req = 0;
+	}
+
+	if (ci_req->b_buf)
+		free(ci_req->b_buf);
+	free(ci_req);
+}
+
+static void ep_enable(int num, int in, int maxpacket)
+{
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	unsigned n;
+
+	n = readl(&udc->epctrl[num]);
+	if (in)
+		n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
+	else
+		n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
+
+	if (num != 0) {
+		struct ept_queue_head *head = ci_get_qh(num, in);
+
+		head->config = CONFIG_MAX_PKT(maxpacket) | CONFIG_ZLT;
+		ci_flush_qh(num);
+	}
+	writel(n, &udc->epctrl[num]);
+}
+
+static int ci_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+	int num, in;
+	num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+	ci_ep->desc = desc;
+	ep->desc = desc;
+
+	if (num) {
+		int max = get_unaligned_le16(&desc->wMaxPacketSize);
+
+		if ((max > 64) && (controller.gadget.speed == USB_SPEED_FULL))
+			max = 64;
+		if (ep->maxpacket != max) {
+			DBG("%s: from %d to %d\n", __func__,
+			    ep->maxpacket, max);
+			ep->maxpacket = max;
+		}
+	}
+	ep_enable(num, in, ep->maxpacket);
+	DBG("%s: num=%d maxpacket=%d\n", __func__, num, ep->maxpacket);
+	return 0;
+}
+
+static int ci_ep_disable(struct usb_ep *ep)
+{
+	struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+
+	ci_ep->desc = NULL;
+	ep->desc = NULL;
+	return 0;
+}
+
+static int ci_bounce(struct ci_req *ci_req, int in)
+{
+	struct usb_request *req = &ci_req->req;
+	unsigned long addr = (unsigned long)req->buf;
+	unsigned long hwaddr;
+	uint32_t aligned_used_len;
+
+	/* Input buffer address is not aligned. */
+	if (addr & (ARCH_DMA_MINALIGN - 1))
+		goto align;
+
+	/* Input buffer length is not aligned. */
+	if (req->length & (ARCH_DMA_MINALIGN - 1))
+		goto align;
+
+	/* The buffer is well aligned, only flush cache. */
+	ci_req->hw_len = req->length;
+	ci_req->hw_buf = req->buf;
+	goto flush;
+
+align:
+	if (ci_req->b_buf && req->length > ci_req->b_len) {
+		free(ci_req->b_buf);
+		ci_req->b_buf = 0;
+	}
+	if (!ci_req->b_buf) {
+		ci_req->b_len = roundup(req->length, ARCH_DMA_MINALIGN);
+		ci_req->b_buf = memalign(ARCH_DMA_MINALIGN, ci_req->b_len);
+		if (!ci_req->b_buf)
+			return -ENOMEM;
+	}
+	ci_req->hw_len = ci_req->b_len;
+	ci_req->hw_buf = ci_req->b_buf;
+
+	if (in)
+		memcpy(ci_req->hw_buf, req->buf, req->length);
+
+flush:
+	hwaddr = (unsigned long)ci_req->hw_buf;
+	aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN);
+	flush_dcache_range(hwaddr, hwaddr + aligned_used_len);
+
+	return 0;
+}
+
+static void ci_debounce(struct ci_req *ci_req, int in)
+{
+	struct usb_request *req = &ci_req->req;
+	unsigned long addr = (unsigned long)req->buf;
+	unsigned long hwaddr = (unsigned long)ci_req->hw_buf;
+	uint32_t aligned_used_len;
+
+	if (in)
+		return;
+
+	aligned_used_len = roundup(req->actual, ARCH_DMA_MINALIGN);
+	invalidate_dcache_range(hwaddr, hwaddr + aligned_used_len);
+
+	if (addr == hwaddr)
+		return; /* not a bounce */
+
+	memcpy(req->buf, ci_req->hw_buf, req->actual);
+}
+
+static void ci_ep_submit_next_request(struct ci_ep *ci_ep)
+{
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	struct ept_queue_item *item;
+	struct ept_queue_head *head;
+	int bit, num, len, in;
+	struct ci_req *ci_req;
+	u8 *buf;
+	uint32_t len_left, len_this_dtd;
+	struct ept_queue_item *dtd, *qtd;
+
+	ci_ep->req_primed = true;
+
+	num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+	item = ci_get_qtd(num, in);
+	head = ci_get_qh(num, in);
+
+	ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+	len = ci_req->req.length;
+
+	head->next = (unsigned long)item;
+	head->info = 0;
+
+	ci_req->dtd_count = 0;
+	buf = ci_req->hw_buf;
+	len_left = len;
+	dtd = item;
+
+	do {
+		len_this_dtd = min(len_left, (unsigned)EP_MAX_LENGTH_TRANSFER);
+
+		dtd->info = INFO_BYTES(len_this_dtd) | INFO_ACTIVE;
+		dtd->page0 = (unsigned long)buf;
+		dtd->page1 = ((unsigned long)buf & 0xfffff000) + 0x1000;
+		dtd->page2 = ((unsigned long)buf & 0xfffff000) + 0x2000;
+		dtd->page3 = ((unsigned long)buf & 0xfffff000) + 0x3000;
+		dtd->page4 = ((unsigned long)buf & 0xfffff000) + 0x4000;
+
+		len_left -= len_this_dtd;
+		buf += len_this_dtd;
+
+		if (len_left) {
+			qtd = (struct ept_queue_item *)
+			       memalign(ILIST_ALIGN, ILIST_ENT_SZ);
+			dtd->next = (unsigned long)qtd;
+			dtd = qtd;
+			memset(dtd, 0, ILIST_ENT_SZ);
+		}
+
+		ci_req->dtd_count++;
+	} while (len_left);
+
+	item = dtd;
+	/*
+	 * When sending the data for an IN transaction, the attached host
+	 * knows that all data for the IN is sent when one of the following
+	 * occurs:
+	 * a) A zero-length packet is transmitted.
+	 * b) A packet with length that isn't an exact multiple of the ep's
+	 *    maxpacket is transmitted.
+	 * c) Enough data is sent to exactly fill the host's maximum expected
+	 *    IN transaction size.
+	 *
+	 * One of these conditions MUST apply at the end of an IN transaction,
+	 * or the transaction will not be considered complete by the host. If
+	 * none of (a)..(c) already applies, then we must force (a) to apply
+	 * by explicitly sending an extra zero-length packet.
+	 */
+	/*  IN    !a     !b                              !c */
+	if (in && len && !(len % ci_ep->ep.maxpacket) && ci_req->req.zero) {
+		/*
+		 * Each endpoint has 2 items allocated, even though typically
+		 * only 1 is used at a time since either an IN or an OUT but
+		 * not both is queued. For an IN transaction, item currently
+		 * points at the second of these items, so we know that we
+		 * can use the other to transmit the extra zero-length packet.
+		 */
+		struct ept_queue_item *other_item = ci_get_qtd(num, 0);
+		item->next = (unsigned long)other_item;
+		item = other_item;
+		item->info = INFO_ACTIVE;
+	}
+
+	item->next = TERMINATE;
+	item->info |= INFO_IOC;
+
+	ci_flush_qtd(num);
+
+	item = (struct ept_queue_item *)(unsigned long)head->next;
+	while (item->next != TERMINATE) {
+		ci_flush_td((struct ept_queue_item *)(unsigned long)item->next);
+		item = (struct ept_queue_item *)(unsigned long)item->next;
+	}
+
+	DBG("ept%d %s queue len %x, req %p, buffer %p\n",
+	    num, in ? "in" : "out", len, ci_req, ci_req->hw_buf);
+	ci_flush_qh(num);
+
+	if (in)
+		bit = EPT_TX(num);
+	else
+		bit = EPT_RX(num);
+
+	writel(bit, &udc->epprime);
+}
+
+static int ci_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct ci_ep *ci_ep = container_of(_ep, struct ci_ep, ep);
+	struct ci_req *ci_req;
+
+	list_for_each_entry(ci_req, &ci_ep->queue, queue) {
+		if (&ci_req->req == _req)
+			break;
+	}
+
+	if (&ci_req->req != _req)
+		return -EINVAL;
+
+	list_del_init(&ci_req->queue);
+
+	if (ci_req->req.status == -EINPROGRESS) {
+		ci_req->req.status = -ECONNRESET;
+		if (ci_req->req.complete)
+			ci_req->req.complete(_ep, _req);
+	}
+
+	return 0;
+}
+
+static int ci_ep_queue(struct usb_ep *ep,
+		struct usb_request *req, gfp_t gfp_flags)
+{
+	struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+	struct ci_req *ci_req = container_of(req, struct ci_req, req);
+	int in, ret;
+	int __maybe_unused num;
+
+	num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+
+	if (!num && ci_ep->req_primed) {
+		/*
+		 * The flipping of ep0 between IN and OUT relies on
+		 * ci_ep_queue consuming the current IN/OUT setting
+		 * immediately. If this is deferred to a later point when the
+		 * req is pulled out of ci_req->queue, then the IN/OUT setting
+		 * may have been changed since the req was queued, and state
+		 * will get out of sync. This condition doesn't occur today,
+		 * but could if bugs were introduced later, and this error
+		 * check will save a lot of debugging time.
+		 */
+		printf("%s: ep0 transaction already in progress\n", __func__);
+		return -EPROTO;
+	}
+
+	ret = ci_bounce(ci_req, in);
+	if (ret)
+		return ret;
+
+	DBG("ept%d %s pre-queue req %p, buffer %p\n",
+	    num, in ? "in" : "out", ci_req, ci_req->hw_buf);
+	list_add_tail(&ci_req->queue, &ci_ep->queue);
+
+	if (!ci_ep->req_primed)
+		ci_ep_submit_next_request(ci_ep);
+
+	return 0;
+}
+
+static void flip_ep0_direction(void)
+{
+	if (ep0_desc.bEndpointAddress == USB_DIR_IN) {
+		DBG("%s: Flipping ep0 to OUT\n", __func__);
+		ep0_desc.bEndpointAddress = 0;
+	} else {
+		DBG("%s: Flipping ep0 to IN\n", __func__);
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	}
+}
+
+static void handle_ep_complete(struct ci_ep *ci_ep)
+{
+	struct ept_queue_item *item, *next_td;
+	int num, in, len, j;
+	struct ci_req *ci_req;
+
+	num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+	item = ci_get_qtd(num, in);
+	ci_invalidate_qtd(num);
+	ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+
+	next_td = item;
+	len = 0;
+	for (j = 0; j < ci_req->dtd_count; j++) {
+		ci_invalidate_td(next_td);
+		item = next_td;
+		len += (item->info >> 16) & 0x7fff;
+		if (item->info & 0xff)
+			printf("EP%d/%s FAIL info=%x pg0=%x\n",
+			       num, in ? "in" : "out", item->info, item->page0);
+		if (j != ci_req->dtd_count - 1)
+			next_td = (struct ept_queue_item *)(unsigned long)
+				item->next;
+		if (j != 0)
+			free(item);
+	}
+
+	list_del_init(&ci_req->queue);
+	ci_ep->req_primed = false;
+
+	if (!list_empty(&ci_ep->queue))
+		ci_ep_submit_next_request(ci_ep);
+
+	ci_req->req.actual = ci_req->req.length - len;
+	ci_debounce(ci_req, in);
+
+	DBG("ept%d %s req %p, complete %x\n",
+	    num, in ? "in" : "out", ci_req, len);
+	if (num != 0 || controller.ep0_data_phase)
+		ci_req->req.complete(&ci_ep->ep, &ci_req->req);
+	if (num == 0 && controller.ep0_data_phase) {
+		/*
+		 * Data Stage is complete, so flip ep0 dir for Status Stage,
+		 * which always transfers a packet in the opposite direction.
+		 */
+		DBG("%s: flip ep0 dir for Status Stage\n", __func__);
+		flip_ep0_direction();
+		controller.ep0_data_phase = false;
+		ci_req->req.length = 0;
+		usb_ep_queue(&ci_ep->ep, &ci_req->req, 0);
+	}
+}
+
+#define SETUP(type, request) (((type) << 8) | (request))
+
+static void handle_setup(void)
+{
+	struct ci_ep *ci_ep = &controller.ep[0];
+	struct ci_req *ci_req;
+	struct usb_request *req;
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	struct ept_queue_head *head;
+	struct usb_ctrlrequest r;
+	int status = 0;
+	int num, in, _num, _in, i;
+	char *buf;
+
+	ci_req = controller.ep0_req;
+	req = &ci_req->req;
+	head = ci_get_qh(0, 0);	/* EP0 OUT */
+
+	ci_invalidate_qh(0);
+	memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest));
+#ifdef CONFIG_CI_UDC_HAS_HOSTPC
+	writel(EPT_RX(0), &udc->epsetupstat);
+#else
+	writel(EPT_RX(0), &udc->epstat);
+#endif
+	DBG("handle setup %s, %x, %x index %x value %x length %x\n",
+	    reqname(r.bRequest), r.bRequestType, r.bRequest, r.wIndex,
+	    r.wValue, r.wLength);
+
+	/* Set EP0 dir for Data Stage based on Setup Stage data */
+	if (r.bRequestType & USB_DIR_IN) {
+		DBG("%s: Set ep0 to IN for Data Stage\n", __func__);
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	} else {
+		DBG("%s: Set ep0 to OUT for Data Stage\n", __func__);
+		ep0_desc.bEndpointAddress = 0;
+	}
+	if (r.wLength) {
+		controller.ep0_data_phase = true;
+	} else {
+		/* 0 length -> no Data Stage. Flip dir for Status Stage */
+		DBG("%s: 0 length: flip ep0 dir for Status Stage\n", __func__);
+		flip_ep0_direction();
+		controller.ep0_data_phase = false;
+	}
+
+	list_del_init(&ci_req->queue);
+	ci_ep->req_primed = false;
+
+	switch (SETUP(r.bRequestType, r.bRequest)) {
+	case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
+		_num = r.wIndex & 15;
+		_in = !!(r.wIndex & 0x80);
+
+		if ((r.wValue == 0) && (r.wLength == 0)) {
+			req->length = 0;
+			for (i = 0; i < NUM_ENDPOINTS; i++) {
+				struct ci_ep *ep = &controller.ep[i];
+
+				if (!ep->desc)
+					continue;
+				num = ep->desc->bEndpointAddress
+						& USB_ENDPOINT_NUMBER_MASK;
+				in = (ep->desc->bEndpointAddress
+						& USB_DIR_IN) != 0;
+				if ((num == _num) && (in == _in)) {
+					ep_enable(num, in, ep->ep.maxpacket);
+					usb_ep_queue(controller.gadget.ep0,
+							req, 0);
+					break;
+				}
+			}
+		}
+		return;
+
+	case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS):
+		/*
+		 * write address delayed (will take effect
+		 * after the next IN txn)
+		 */
+		writel((r.wValue << 25) | (1 << 24), &udc->devaddr);
+		req->length = 0;
+		usb_ep_queue(controller.gadget.ep0, req, 0);
+		return;
+
+	case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS):
+		req->length = 2;
+		buf = (char *)req->buf;
+		buf[0] = 1 << USB_DEVICE_SELF_POWERED;
+		buf[1] = 0;
+		usb_ep_queue(controller.gadget.ep0, req, 0);
+		return;
+	}
+	/* pass request up to the gadget driver */
+	if (controller.driver)
+		status = controller.driver->setup(&controller.gadget, &r);
+	else
+		status = -ENODEV;
+
+	if (!status)
+		return;
+	DBG("STALL reqname %s type %x value %x, index %x\n",
+	    reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex);
+	writel((1<<16) | (1 << 0), &udc->epctrl[0]);
+}
+
+static void stop_activity(void)
+{
+	int i, num, in;
+	struct ept_queue_head *head;
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	writel(readl(&udc->epcomp), &udc->epcomp);
+#ifdef CONFIG_CI_UDC_HAS_HOSTPC
+	writel(readl(&udc->epsetupstat), &udc->epsetupstat);
+#endif
+	writel(readl(&udc->epstat), &udc->epstat);
+	writel(0xffffffff, &udc->epflush);
+
+	/* error out any pending reqs */
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		if (i != 0)
+			writel(0, &udc->epctrl[i]);
+		if (controller.ep[i].desc) {
+			num = controller.ep[i].desc->bEndpointAddress
+				& USB_ENDPOINT_NUMBER_MASK;
+			in = (controller.ep[i].desc->bEndpointAddress
+				& USB_DIR_IN) != 0;
+			head = ci_get_qh(num, in);
+			head->info = INFO_ACTIVE;
+			ci_flush_qh(num);
+		}
+	}
+}
+
+void udc_irq(void)
+{
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	unsigned n = readl(&udc->usbsts);
+	writel(n, &udc->usbsts);
+	int bit, i, num, in;
+
+	n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
+	if (n == 0)
+		return;
+
+	if (n & STS_URI) {
+		DBG("-- reset --\n");
+		stop_activity();
+	}
+	if (n & STS_SLI)
+		DBG("-- suspend --\n");
+
+	if (n & STS_PCI) {
+		int max = 64;
+		int speed = USB_SPEED_FULL;
+
+#ifdef CONFIG_CI_UDC_HAS_HOSTPC
+		bit = (readl(&udc->hostpc1_devlc) >> 25) & 3;
+#else
+		bit = (readl(&udc->portsc) >> 26) & 3;
+#endif
+		DBG("-- portchange %x %s\n", bit, (bit == 2) ? "High" : "Full");
+		if (bit == 2) {
+			speed = USB_SPEED_HIGH;
+			max = 512;
+		}
+		controller.gadget.speed = speed;
+		for (i = 1; i < NUM_ENDPOINTS; i++) {
+			if (controller.ep[i].ep.maxpacket > max)
+				controller.ep[i].ep.maxpacket = max;
+		}
+	}
+
+	if (n & STS_UEI)
+		printf("<UEI %x>\n", readl(&udc->epcomp));
+
+	if ((n & STS_UI) || (n & STS_UEI)) {
+#ifdef CONFIG_CI_UDC_HAS_HOSTPC
+		n = readl(&udc->epsetupstat);
+#else
+		n = readl(&udc->epstat);
+#endif
+		if (n & EPT_RX(0))
+			handle_setup();
+
+		n = readl(&udc->epcomp);
+		if (n != 0)
+			writel(n, &udc->epcomp);
+
+		for (i = 0; i < NUM_ENDPOINTS && n; i++) {
+			if (controller.ep[i].desc) {
+				num = controller.ep[i].desc->bEndpointAddress
+					& USB_ENDPOINT_NUMBER_MASK;
+				in = (controller.ep[i].desc->bEndpointAddress
+						& USB_DIR_IN) != 0;
+				bit = (in) ? EPT_TX(num) : EPT_RX(num);
+				if (n & bit)
+					handle_ep_complete(&controller.ep[i]);
+			}
+		}
+	}
+}
+
+int usb_gadget_handle_interrupts(int index)
+{
+	u32 value;
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+
+	value = readl(&udc->usbsts);
+	if (value)
+		udc_irq();
+
+	return value;
+}
+
+void udc_disconnect(void)
+{
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	/* disable pullup */
+	stop_activity();
+	writel(USBCMD_FS2, &udc->usbcmd);
+	udelay(800);
+	if (controller.driver)
+		controller.driver->disconnect(&controller.gadget);
+}
+
+static int ci_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+	if (is_on) {
+		/* RESET */
+		writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd);
+		udelay(200);
+
+		ci_init_after_reset(controller.ctrl);
+
+		writel((unsigned long)controller.epts, &udc->epinitaddr);
+
+		/* select DEVICE mode */
+		writel(USBMODE_DEVICE, &udc->usbmode);
+
+#if !defined(CONFIG_USB_GADGET_DUALSPEED)
+		/* Port force Full-Speed Connect */
+		setbits_le32(&udc->portsc, PFSC);
+#endif
+
+		writel(0xffffffff, &udc->epflush);
+
+		/* Turn on the USB connection by enabling the pullup resistor */
+		setbits_le32(&udc->usbcmd, USBCMD_ITC(MICRO_8FRAME) |
+			     USBCMD_RUN);
+	} else {
+		udc_disconnect();
+	}
+
+	return 0;
+}
+
+static int ci_udc_probe(void)
+{
+	struct ept_queue_head *head;
+	int i;
+
+	const int num = 2 * NUM_ENDPOINTS;
+
+	const int eplist_min_align = 4096;
+	const int eplist_align = roundup(eplist_min_align, ARCH_DMA_MINALIGN);
+	const int eplist_raw_sz = num * sizeof(struct ept_queue_head);
+	const int eplist_sz = roundup(eplist_raw_sz, ARCH_DMA_MINALIGN);
+
+	/* The QH list must be aligned to 4096 bytes. */
+	controller.epts = memalign(eplist_align, eplist_sz);
+	if (!controller.epts)
+		return -ENOMEM;
+	memset(controller.epts, 0, eplist_sz);
+
+	controller.items_mem = memalign(ILIST_ALIGN, ILIST_SZ);
+	if (!controller.items_mem) {
+		free(controller.epts);
+		return -ENOMEM;
+	}
+	memset(controller.items_mem, 0, ILIST_SZ);
+
+	for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+		/*
+		 * Configure QH for each endpoint. The structure of the QH list
+		 * is such that each two subsequent fields, N and N+1 where N is
+		 * even, in the QH list represent QH for one endpoint. The Nth
+		 * entry represents OUT configuration and the N+1th entry does
+		 * represent IN configuration of the endpoint.
+		 */
+		head = controller.epts + i;
+		if (i < 2)
+			head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE)
+				| CONFIG_ZLT | CONFIG_IOS;
+		else
+			head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE)
+				| CONFIG_ZLT;
+		head->next = TERMINATE;
+		head->info = 0;
+
+		if (i & 1) {
+			ci_flush_qh(i / 2);
+			ci_flush_qtd(i / 2);
+		}
+	}
+
+	INIT_LIST_HEAD(&controller.gadget.ep_list);
+
+	/* Init EP 0 */
+	memcpy(&controller.ep[0].ep, &ci_ep_init[0], sizeof(*ci_ep_init));
+	controller.ep[0].desc = &ep0_desc;
+	INIT_LIST_HEAD(&controller.ep[0].queue);
+	controller.ep[0].req_primed = false;
+	controller.gadget.ep0 = &controller.ep[0].ep;
+	INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
+
+	/* Init EP 1..3 */
+	for (i = 1; i < 4; i++) {
+		memcpy(&controller.ep[i].ep, &ci_ep_init[i],
+		       sizeof(*ci_ep_init));
+		INIT_LIST_HEAD(&controller.ep[i].queue);
+		controller.ep[i].req_primed = false;
+		list_add_tail(&controller.ep[i].ep.ep_list,
+			      &controller.gadget.ep_list);
+	}
+
+	/* Init EP 4..n */
+	for (i = 4; i < NUM_ENDPOINTS; i++) {
+		memcpy(&controller.ep[i].ep, &ci_ep_init[4],
+		       sizeof(*ci_ep_init));
+		INIT_LIST_HEAD(&controller.ep[i].queue);
+		controller.ep[i].req_primed = false;
+		list_add_tail(&controller.ep[i].ep.ep_list,
+			      &controller.gadget.ep_list);
+	}
+
+	ci_ep_alloc_request(&controller.ep[0].ep, 0);
+	if (!controller.ep0_req) {
+		free(controller.items_mem);
+		free(controller.epts);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int ret;
+
+	if (!driver)
+		return -EINVAL;
+	if (!driver->bind || !driver->setup || !driver->disconnect)
+		return -EINVAL;
+
+#if CONFIG_IS_ENABLED(DM_USB)
+	ret = usb_setup_ehci_gadget(&controller.ctrl);
+#else
+	ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
+#endif
+	if (ret)
+		return ret;
+
+	ret = ci_udc_probe();
+	if (ret) {
+		DBG("udc probe failed, returned %d\n", ret);
+		return ret;
+	}
+
+	ret = driver->bind(&controller.gadget);
+	if (ret) {
+		DBG("driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	controller.driver = driver;
+
+	return 0;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	udc_disconnect();
+
+	driver->unbind(&controller.gadget);
+	controller.driver = NULL;
+
+	ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
+	free(controller.items_mem);
+	free(controller.epts);
+
+#if CONFIG_IS_ENABLED(DM_USB)
+	usb_remove_ehci_gadget(&controller.ctrl);
+#else
+	usb_lowlevel_stop(0);
+	controller.ctrl = NULL;
+#endif
+
+	return 0;
+}
+
+bool dfu_usb_get_reset(void)
+{
+	struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+
+	return !!(readl(&udc->usbsts) & STS_URI);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/ci_udc.h b/roms/u-boot/drivers/usb/gadget/ci_udc.h
new file mode 100644
index 000000000..95cc07992
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/ci_udc.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef __GADGET__CI_UDC_H__
+#define __GADGET__CI_UDC_H__
+
+#define NUM_ENDPOINTS		6
+
+#ifdef CONFIG_CI_UDC_HAS_HOSTPC
+struct ci_udc {
+	u32 usbcmd;		/* 0x130 */
+	u32 usbsts;		/* 0x134 */
+	u32 pad1[3];
+	u32 devaddr;		/* 0x144 */
+	u32 epinitaddr;		/* 0x148 */
+	u32 pad2[10];
+	u32 portsc;		/* 0x174 */
+	u32 pad178[(0x1b4 - (0x174 + 4)) / 4];
+	u32 hostpc1_devlc;	/* 0x1b4 */
+	u32 pad1b8[(0x1f8 - (0x1b4 + 4)) / 4];
+	u32 usbmode;		/* 0x1f8 */
+	u32 pad1fc[(0x208 - (0x1f8 + 4)) / 4];
+	u32 epsetupstat;	/* 0x208 */
+	u32 epprime;		/* 0x20c */
+	u32 epflush;		/* 0x210 */
+	u32 epstat;		/* 0x214 */
+	u32 epcomp;		/* 0x218 */
+	u32 epctrl[16];		/* 0x21c */
+};
+#else
+struct ci_udc {
+	u32 usbcmd;		/* 0x140 */
+	u32 usbsts;		/* 0x144 */
+	u32 pad1[3];
+	u32 devaddr;		/* 0x154 */
+	u32 epinitaddr;		/* 0x158 */
+	u32 pad2[10];
+	u32 portsc;		/* 0x184 */
+	u32 pad3[8];
+	u32 usbmode;		/* 0x1a8 */
+	u32 epstat;		/* 0x1ac */
+	u32 epprime;		/* 0x1b0 */
+	u32 epflush;		/* 0x1b4 */
+	u32 pad4;
+	u32 epcomp;		/* 0x1bc */
+	u32 epctrl[16];		/* 0x1c0 */
+};
+
+#define PTS_ENABLE	2
+#define PTS(x)		(((x) & 0x3) << 30)
+#define PFSC		(1 << 24)
+#endif
+
+#define MICRO_8FRAME	0x8
+#define USBCMD_ITC(x)	((((x) > 0xff) ? 0xff : x) << 16)
+#define USBCMD_FS2	(1 << 15)
+#define USBCMD_RST	(1 << 1)
+#define USBCMD_RUN	(1)
+
+#define STS_SLI		(1 << 8)
+#define STS_URI		(1 << 6)
+#define STS_PCI		(1 << 2)
+#define STS_UEI		(1 << 1)
+#define STS_UI		(1 << 0)
+
+#define USBMODE_DEVICE	2
+
+#define EPT_TX(x)	(1 << (((x) & 0xffff) + 16))
+#define EPT_RX(x)	(1 << ((x) & 0xffff))
+
+#define CTRL_TXE	(1 << 23)
+#define CTRL_TXR	(1 << 22)
+#define CTRL_RXE	(1 << 7)
+#define CTRL_RXR	(1 << 6)
+#define CTRL_TXT_BULK	(2 << 18)
+#define CTRL_RXT_BULK	(2 << 2)
+
+struct ci_req {
+	struct usb_request	req;
+	struct list_head	queue;
+	/* Bounce buffer allocated if needed to align the transfer */
+	uint8_t *b_buf;
+	uint32_t b_len;
+	/* Buffer for the current transfer. Either req.buf/len or b_buf/len */
+	uint8_t *hw_buf;
+	uint32_t hw_len;
+	uint32_t dtd_count;
+};
+
+struct ci_ep {
+	struct usb_ep ep;
+	struct list_head queue;
+	bool req_primed;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct ci_drv {
+	struct usb_gadget		gadget;
+	struct ci_req			*ep0_req;
+	bool				ep0_data_phase;
+	struct usb_gadget_driver	*driver;
+	struct ehci_ctrl		*ctrl;
+	struct ept_queue_head		*epts;
+	uint8_t				*items_mem;
+	struct ci_ep			ep[NUM_ENDPOINTS];
+};
+
+struct ept_queue_head {
+	unsigned config;
+	unsigned current;	/* read-only */
+
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved_0;
+
+	unsigned char setup_data[8];
+
+	unsigned reserved_1;
+	unsigned reserved_2;
+	unsigned reserved_3;
+	unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)	((n) << 16)
+#define CONFIG_ZLT		(1 << 29)	/* stop on zero-len xfer */
+#define CONFIG_IOS		(1 << 15)	/* IRQ on setup */
+
+struct ept_queue_item {
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved;
+};
+
+#define TERMINATE 1
+#define INFO_BYTES(n)		((n) << 16)
+#define INFO_IOC		(1 << 15)
+#define INFO_ACTIVE		(1 << 7)
+#define INFO_HALTED		(1 << 6)
+#define INFO_BUFFER_ERROR	(1 << 5)
+#define INFO_TX_ERROR		(1 << 3)
+#endif
diff --git a/roms/u-boot/drivers/usb/gadget/composite.c b/roms/u-boot/drivers/usb/gadget/composite.c
new file mode 100644
index 000000000..2a309e624
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/composite.c
@@ -0,0 +1,1531 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * composite.c - infrastructure for Composite USB Gadgets
+ *
+ * Copyright (C) 2006-2008 David Brownell
+ * U-Boot porting: Lukasz Majewski <l.majewski@samsung.com>
+ */
+#undef DEBUG
+
+#include <log.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/usb/composite.h>
+#include "u_os_desc.h"
+
+#define USB_BUFSIZ	4096
+
+/* Helper type for accessing packed u16 pointers */
+typedef struct { __le16 val; } __packed __le16_packed;
+
+static struct usb_composite_driver *composite;
+static struct usb_configuration *os_desc_config;
+
+/* Microsoft OS String Descriptor */
+static char qw_sign_buf[OS_STRING_QW_SIGN_LEN / 2] = {'M', 'S', 'F', 'T', '1', '0', '0'};
+
+static inline void le16_add_cpu_packed(__le16_packed *var, u16 val)
+{
+	var->val = cpu_to_le16(le16_to_cpu(var->val) + val);
+}
+
+/**
+ * struct usb_os_string - represents OS String to be reported by a gadget
+ * @bLength: total length of the entire descritor, always 0x12
+ * @bDescriptorType: USB_DT_STRING
+ * @qwSignature: the OS String proper
+ * @bMS_VendorCode: code used by the host for subsequent requests
+ * @bPad: not used, must be zero
+ */
+struct usb_os_string {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	qwSignature[OS_STRING_QW_SIGN_LEN];
+	__u8	bMS_VendorCode;
+	__u8	bPad;
+} __packed;
+
+/**
+ * usb_add_function() - add a function to a configuration
+ * @config: the configuration
+ * @function: the function being added
+ * Context: single threaded during gadget setup
+ *
+ * After initialization, each configuration must have one or more
+ * functions added to it.  Adding a function involves calling its @bind()
+ * method to allocate resources such as interface and string identifiers
+ * and endpoints.
+ *
+ * This function returns the value of the function's bind(), which is
+ * zero for success else a negative errno value.
+ */
+int usb_add_function(struct usb_configuration *config,
+		struct usb_function *function)
+{
+	int	value = -EINVAL;
+
+	debug("adding '%s'/%p to config '%s'/%p\n",
+			function->name, function,
+			config->label, config);
+
+	if (!function->set_alt || !function->disable)
+		goto done;
+
+	function->config = config;
+	list_add_tail(&function->list, &config->functions);
+
+	if (function->bind) {
+		value = function->bind(config, function);
+		if (value < 0) {
+			list_del(&function->list);
+			function->config = NULL;
+		}
+	} else
+		value = 0;
+
+	if (!config->fullspeed && function->descriptors)
+		config->fullspeed = 1;
+	if (!config->highspeed && function->hs_descriptors)
+		config->highspeed = 1;
+	if (!config->superspeed && function->ss_descriptors)
+		config->superspeed = 1;
+
+done:
+	if (value)
+		debug("adding '%s'/%p --> %d\n",
+				function->name, function, value);
+	return value;
+}
+
+/**
+ * usb_function_deactivate - prevent function and gadget enumeration
+ * @function: the function that isn't yet ready to respond
+ *
+ * Blocks response of the gadget driver to host enumeration by
+ * preventing the data line pullup from being activated.  This is
+ * normally called during @bind() processing to change from the
+ * initial "ready to respond" state, or when a required resource
+ * becomes available.
+ *
+ * For example, drivers that serve as a passthrough to a userspace
+ * daemon can block enumeration unless that daemon (such as an OBEX,
+ * MTP, or print server) is ready to handle host requests.
+ *
+ * Not all systems support software control of their USB peripheral
+ * data pullups.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_deactivate(struct usb_function *function)
+{
+	struct usb_composite_dev	*cdev = function->config->cdev;
+	int				status = 0;
+
+	if (cdev->deactivations == 0)
+		status = usb_gadget_disconnect(cdev->gadget);
+	if (status == 0)
+		cdev->deactivations++;
+
+	return status;
+}
+
+/**
+ * usb_function_activate - allow function and gadget enumeration
+ * @function: function on which usb_function_activate() was called
+ *
+ * Reverses effect of usb_function_deactivate().  If no more functions
+ * are delaying their activation, the gadget driver will respond to
+ * host enumeration procedures.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_activate(struct usb_function *function)
+{
+	struct usb_composite_dev	*cdev = function->config->cdev;
+	int				status = 0;
+
+	if (cdev->deactivations == 0)
+		status = -EINVAL;
+	else {
+		cdev->deactivations--;
+		if (cdev->deactivations == 0)
+			status = usb_gadget_connect(cdev->gadget);
+	}
+
+	return status;
+}
+
+/**
+ * usb_interface_id() - allocate an unused interface ID
+ * @config: configuration associated with the interface
+ * @function: function handling the interface
+ * Context: single threaded during gadget setup
+ *
+ * usb_interface_id() is called from usb_function.bind() callbacks to
+ * allocate new interface IDs.  The function driver will then store that
+ * ID in interface, association, CDC union, and other descriptors.  It
+ * will also handle any control requests targetted at that interface,
+ * particularly changing its altsetting via set_alt().  There may
+ * also be class-specific or vendor-specific requests to handle.
+ *
+ * All interface identifier should be allocated using this routine, to
+ * ensure that for example different functions don't wrongly assign
+ * different meanings to the same identifier.  Note that since interface
+ * identifers are configuration-specific, functions used in more than
+ * one configuration (or more than once in a given configuration) need
+ * multiple versions of the relevant descriptors.
+ *
+ * Returns the interface ID which was allocated; or -ENODEV if no
+ * more interface IDs can be allocated.
+ */
+int usb_interface_id(struct usb_configuration *config,
+		struct usb_function *function)
+{
+	unsigned char id = config->next_interface_id;
+
+	if (id < MAX_CONFIG_INTERFACES) {
+		config->interface[id] = function;
+		config->next_interface_id = id + 1;
+		return id;
+	}
+	return -ENODEV;
+}
+
+static int config_buf(struct usb_configuration *config,
+		enum usb_device_speed speed, void *buf, u8 type)
+{
+	int				len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
+	void				*next = buf + USB_DT_CONFIG_SIZE;
+	struct usb_descriptor_header    **descriptors;
+	struct usb_config_descriptor	*c;
+	int				status;
+	struct usb_function		*f;
+
+	/* write the config descriptor */
+	c = buf;
+	c->bLength = USB_DT_CONFIG_SIZE;
+	c->bDescriptorType = type;
+
+	c->bNumInterfaces = config->next_interface_id;
+	c->bConfigurationValue = config->bConfigurationValue;
+	c->iConfiguration = config->iConfiguration;
+	c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
+	c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
+
+	/* There may be e.g. OTG descriptors */
+	if (config->descriptors) {
+		status = usb_descriptor_fillbuf(next, len,
+				config->descriptors);
+		if (status < 0)
+			return status;
+		len -= status;
+		next += status;
+	}
+
+	/* add each function's descriptors */
+	list_for_each_entry(f, &config->functions, list) {
+		if (speed == USB_SPEED_SUPER)
+			descriptors = f->ss_descriptors;
+		else if (speed == USB_SPEED_HIGH)
+			descriptors = f->hs_descriptors;
+		else
+			descriptors = f->descriptors;
+		if (!descriptors)
+			continue;
+		status = usb_descriptor_fillbuf(next, len,
+			(const struct usb_descriptor_header **) descriptors);
+		if (status < 0)
+			return status;
+		len -= status;
+		next += status;
+	}
+
+	len = next - buf;
+	c->wTotalLength = cpu_to_le16(len);
+	return len;
+}
+
+static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
+{
+	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
+	struct usb_gadget		*gadget = cdev->gadget;
+	u8				type = w_value >> 8;
+	int                             hs = 0;
+	struct usb_configuration	*c;
+	struct list_head		*pos;
+
+	if (gadget_is_superspeed(gadget)) {
+		speed = gadget->speed;
+	} else if (gadget_is_dualspeed(gadget)) {
+		if (gadget->speed == USB_SPEED_HIGH)
+			hs = 1;
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+		if (hs)
+			speed = USB_SPEED_HIGH;
+	}
+
+	w_value &= 0xff;
+
+	pos = &cdev->configs;
+	c = cdev->os_desc_config;
+	if (c)
+		goto check_config;
+
+	while ((pos = pos->next) !=  &cdev->configs) {
+		c = list_entry(pos, typeof(*c), list);
+
+		/* skip OS Descriptors config which is handled separately */
+		if (c == cdev->os_desc_config)
+			continue;
+
+check_config:
+		if (speed == USB_SPEED_SUPER) {
+			if (!c->superspeed)
+				continue;
+		} else if (speed == USB_SPEED_HIGH) {
+			if (!c->highspeed)
+				continue;
+		} else {
+			if (!c->fullspeed)
+				continue;
+		}
+		if (w_value == 0)
+			return config_buf(c, speed, cdev->req->buf, type);
+		w_value--;
+	}
+	return -EINVAL;
+}
+
+static int count_configs(struct usb_composite_dev *cdev, unsigned type)
+{
+	struct usb_gadget		*gadget = cdev->gadget;
+	unsigned			count = 0;
+	int				hs = 0;
+	int				ss = 0;
+	struct usb_configuration	*c;
+
+	if (gadget->speed == USB_SPEED_SUPER)
+		ss = 1;
+
+	if (gadget_is_dualspeed(gadget)) {
+		if (gadget->speed == USB_SPEED_HIGH)
+			hs = 1;
+		if (type == USB_DT_DEVICE_QUALIFIER)
+			hs = !hs;
+	}
+	list_for_each_entry(c, &cdev->configs, list) {
+		/* ignore configs that won't work at this speed */
+		if (ss) {
+			if (!c->superspeed)
+				continue;
+		} else if (hs) {
+			if (!c->highspeed)
+				continue;
+		} else {
+			if (!c->fullspeed)
+				continue;
+		}
+		count++;
+	}
+	return count;
+}
+
+static void device_qual(struct usb_composite_dev *cdev)
+{
+	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
+
+	qual->bLength = sizeof(*qual);
+	qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+	/* POLICY: same bcdUSB and device type info at both speeds */
+	qual->bcdUSB = cdev->desc.bcdUSB;
+	qual->bDeviceClass = cdev->desc.bDeviceClass;
+	qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
+	qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
+	/* ASSUME same EP0 fifo size at both speeds */
+	qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
+	qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
+	qual->bRESERVED = 0;
+}
+
+static void reset_config(struct usb_composite_dev *cdev)
+{
+	struct usb_function		*f;
+
+	debug("%s:\n", __func__);
+
+	list_for_each_entry(f, &cdev->config->functions, list) {
+		if (f->disable)
+			f->disable(f);
+
+		bitmap_zero(f->endpoints, 32);
+	}
+	cdev->config = NULL;
+}
+
+static int set_config(struct usb_composite_dev *cdev,
+		const struct usb_ctrlrequest *ctrl, unsigned number)
+{
+	struct usb_gadget	*gadget = cdev->gadget;
+	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
+	struct usb_descriptor_header **descriptors;
+	int			result = -EINVAL;
+	struct usb_endpoint_descriptor *ep;
+	struct usb_configuration *c = NULL;
+	int                     addr;
+	int			tmp;
+	struct usb_function	*f;
+
+	if (cdev->config)
+		reset_config(cdev);
+
+	if (number) {
+		list_for_each_entry(c, &cdev->configs, list) {
+			if (c->bConfigurationValue == number) {
+				result = 0;
+				break;
+			}
+		}
+		if (result < 0)
+			goto done;
+	} else
+		result = 0;
+
+	debug("%s: %s speed config #%d: %s\n", __func__,
+	     ({ char *speed;
+		     switch (gadget->speed) {
+		     case USB_SPEED_LOW:
+			     speed = "low";
+			     break;
+		     case USB_SPEED_FULL:
+			     speed = "full";
+			     break;
+		     case USB_SPEED_HIGH:
+			     speed = "high";
+			     break;
+		     case USB_SPEED_SUPER:
+			     speed = "super";
+			     break;
+		     default:
+			     speed = "?";
+			     break;
+		     };
+		     speed;
+	     }), number, c ? c->label : "unconfigured");
+
+	if (!c)
+		goto done;
+
+	cdev->config = c;
+
+	/* Initialize all interfaces by setting them to altsetting zero. */
+	for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
+		f = c->interface[tmp];
+		if (!f)
+			break;
+
+		/*
+		 * Record which endpoints are used by the function. This is used
+		 * to dispatch control requests targeted at that endpoint to the
+		 * function's setup callback instead of the current
+		 * configuration's setup callback.
+		 */
+		if (gadget->speed == USB_SPEED_SUPER)
+			descriptors = f->ss_descriptors;
+		else if (gadget->speed == USB_SPEED_HIGH)
+			descriptors = f->hs_descriptors;
+		else
+			descriptors = f->descriptors;
+
+		for (; *descriptors; ++descriptors) {
+			if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
+				continue;
+
+			ep = (struct usb_endpoint_descriptor *)*descriptors;
+			addr = ((ep->bEndpointAddress & 0x80) >> 3)
+			     |	(ep->bEndpointAddress & 0x0f);
+			generic_set_bit(addr, f->endpoints);
+		}
+
+		result = f->set_alt(f, tmp, 0);
+		if (result < 0) {
+			debug("interface %d (%s/%p) alt 0 --> %d\n",
+					tmp, f->name, f, result);
+
+			reset_config(cdev);
+			goto done;
+		}
+	}
+
+	/* when we return, be sure our power usage is valid */
+	power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
+done:
+	usb_gadget_vbus_draw(gadget, power);
+	return result;
+}
+
+/**
+ * usb_add_config() - add a configuration to a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration, with bConfigurationValue assigned
+ * Context: single threaded during gadget setup
+ *
+ * One of the main tasks of a composite driver's bind() routine is to
+ * add each of the configurations it supports, using this routine.
+ *
+ * This function returns the value of the configuration's bind(), which
+ * is zero for success else a negative errno value.  Binding configurations
+ * assigns global resources including string IDs, and per-configuration
+ * resources such as interface IDs and endpoints.
+ */
+int usb_add_config(struct usb_composite_dev *cdev,
+		struct usb_configuration *config)
+{
+	int				status = -EINVAL;
+	struct usb_configuration	*c;
+	struct usb_function		*f;
+	unsigned int			i;
+
+	debug("%s: adding config #%u '%s'/%p\n", __func__,
+			config->bConfigurationValue,
+			config->label, config);
+
+	if (!config->bConfigurationValue || !config->bind)
+		goto done;
+
+	/* Prevent duplicate configuration identifiers */
+	list_for_each_entry(c, &cdev->configs, list) {
+		if (c->bConfigurationValue == config->bConfigurationValue) {
+			status = -EBUSY;
+			goto done;
+		}
+	}
+
+	config->cdev = cdev;
+	list_add_tail(&config->list, &cdev->configs);
+
+	INIT_LIST_HEAD(&config->functions);
+	config->next_interface_id = 0;
+
+	status = config->bind(config);
+	if (status < 0) {
+		list_del(&config->list);
+		config->cdev = NULL;
+	} else {
+		debug("cfg %d/%p speeds:%s%s%s\n",
+			config->bConfigurationValue, config,
+			config->superspeed ? " super" : "",
+			config->highspeed ? " high" : "",
+			config->fullspeed
+				? (gadget_is_dualspeed(cdev->gadget)
+					? " full"
+					: " full/low")
+				: "");
+
+		for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
+			f = config->interface[i];
+			if (!f)
+				continue;
+			debug("%s: interface %d = %s/%p\n",
+			      __func__, i, f->name, f);
+		}
+	}
+
+	/*
+	 * If one function of config is not super speed capable,
+	 * force the gadget to be high speed so controller driver
+	 * can init HW to be USB 2.0
+	 */
+	if (gadget_is_superspeed(cdev->gadget)) {
+		list_for_each_entry(f, &config->functions, list) {
+			if (!f->ss_descriptors)
+				cdev->gadget->max_speed =
+					USB_SPEED_HIGH;
+		}
+	}
+
+	usb_ep_autoconfig_reset(cdev->gadget);
+
+	os_desc_config = config;
+	cdev->os_desc_config = os_desc_config;
+
+done:
+	if (status)
+		debug("added config '%s'/%u --> %d\n", config->label,
+				config->bConfigurationValue, status);
+	return status;
+}
+
+/*
+ * We support strings in multiple languages ... string descriptor zero
+ * says which languages are supported.	The typical case will be that
+ * only one language (probably English) is used, with I18N handled on
+ * the host side.
+ */
+
+static void collect_langs(struct usb_gadget_strings **sp, void *buf)
+{
+	const struct usb_gadget_strings	*s;
+	u16				language;
+	__le16_packed			*tmp;
+	__le16_packed			*end = (buf + 252);
+
+	while (*sp) {
+		s = *sp;
+		language = cpu_to_le16(s->language);
+		for (tmp = buf; tmp->val && tmp < end; tmp++) {
+			if (tmp->val == language)
+				goto repeat;
+		}
+		tmp->val = language;
+repeat:
+		sp++;
+	}
+}
+
+static int lookup_string(
+	struct usb_gadget_strings	**sp,
+	void				*buf,
+	u16				language,
+	int				id
+)
+{
+	int				value;
+	struct usb_gadget_strings	*s;
+
+	while (*sp) {
+		s = *sp++;
+		if (s->language != language)
+			continue;
+		value = usb_gadget_get_string(s, id, buf);
+		if (value > 0)
+			return value;
+	}
+	return -EINVAL;
+}
+
+static int get_string(struct usb_composite_dev *cdev,
+		void *buf, u16 language, int id)
+{
+	struct usb_string_descriptor	*s = buf;
+	struct usb_gadget_strings	**sp;
+	int				len;
+	struct usb_configuration	*c;
+	struct usb_function		*f;
+
+	/*
+	 * Yes, not only is USB's I18N support probably more than most
+	 * folk will ever care about ... also, it's all supported here.
+	 * (Except for UTF8 support for Unicode's "Astral Planes".)
+	 */
+
+	/* 0 == report all available language codes */
+	if (id == 0) {
+		memset(s, 0, 256);
+		s->bDescriptorType = USB_DT_STRING;
+
+		sp = composite->strings;
+		if (sp)
+			collect_langs(sp, s->wData);
+
+		list_for_each_entry(c, &cdev->configs, list) {
+			sp = c->strings;
+			if (sp)
+				collect_langs(sp, s->wData);
+
+			list_for_each_entry(f, &c->functions, list) {
+				sp = f->strings;
+				if (sp)
+					collect_langs(sp, s->wData);
+			}
+		}
+
+		for (len = 0; len <= 126 && s->wData[len]; len++)
+			continue;
+		if (!len)
+			return -EINVAL;
+
+		s->bLength = 2 * (len + 1);
+		return s->bLength;
+	}
+
+	if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) {
+		struct usb_os_string *b = buf;
+		b->bLength = sizeof(*b);
+		b->bDescriptorType = USB_DT_STRING;
+		memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature));
+		b->bMS_VendorCode = cdev->b_vendor_code;
+		b->bPad = 0;
+		return sizeof(*b);
+	}
+
+	/*
+	 * Otherwise, look up and return a specified string.  String IDs
+	 * are device-scoped, so we look up each string table we're told
+	 * about.  These lookups are infrequent; simpler-is-better here.
+	 */
+	if (composite->strings) {
+		len = lookup_string(composite->strings, buf, language, id);
+		if (len > 0)
+			return len;
+	}
+	list_for_each_entry(c, &cdev->configs, list) {
+		if (c->strings) {
+			len = lookup_string(c->strings, buf, language, id);
+			if (len > 0)
+				return len;
+		}
+		list_for_each_entry(f, &c->functions, list) {
+			if (!f->strings)
+				continue;
+			len = lookup_string(f->strings, buf, language, id);
+			if (len > 0)
+				return len;
+		}
+	}
+	return -EINVAL;
+}
+
+/**
+ * usb_string_id() - allocate an unused string ID
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_id() is called from bind() callbacks to allocate
+ * string IDs.	Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
+ * that for example different functions don't wrongly assign different
+ * meanings to the same identifier.
+ */
+int usb_string_id(struct usb_composite_dev *cdev)
+{
+	if (cdev->next_string_id < 254) {
+		/*
+		 * string id 0 is reserved by USB spec for list of
+		 * supported languages
+		 * 255 reserved as well? -- mina86
+		 */
+		cdev->next_string_id++;
+		return cdev->next_string_id;
+	}
+	return -ENODEV;
+}
+
+/**
+ * usb_string_ids() - allocate unused string IDs in batch
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * @str: an array of usb_string objects to assign numbers to
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_ids() is called from bind() callbacks to allocate
+ * string IDs.	Drivers for functions, configurations, or gadgets will
+ * then copy IDs from the string table to the appropriate descriptors
+ * and string table for other languages.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
+{
+	u8 next = cdev->next_string_id;
+
+	for (; str->s; ++str) {
+		if (next >= 254)
+			return -ENODEV;
+		str->id = ++next;
+	}
+
+	cdev->next_string_id = next;
+
+	return 0;
+}
+
+/**
+ * usb_string_ids_n() - allocate unused string IDs in batch
+ * @c: the device whose string descriptor IDs are being allocated
+ * @n: number of string IDs to allocate
+ * Context: single threaded during gadget setup
+ *
+ * Returns the first requested ID.  This ID and next @n-1 IDs are now
+ * valid IDs.  At least provided that @n is non-zero because if it
+ * is, returns last requested ID which is now very useful information.
+ *
+ * @usb_string_ids_n() is called from bind() callbacks to allocate
+ * string IDs.	Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
+{
+	u8 next = c->next_string_id;
+
+	if (n > 254 || next + n > 254)
+		return -ENODEV;
+
+	c->next_string_id += n;
+	return next + 1;
+}
+
+static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		debug("%s: setup complete --> %d, %d/%d\n", __func__,
+				req->status, req->actual, req->length);
+}
+
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+	struct usb_ext_cap_descriptor   *usb_ext;
+	struct usb_dcd_config_params	dcd_config_params;
+	struct usb_bos_descriptor       *bos = cdev->req->buf;
+
+	bos->bLength = USB_DT_BOS_SIZE;
+	bos->bDescriptorType = USB_DT_BOS;
+
+	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+	bos->bNumDeviceCaps = 0;
+
+	/*
+	 * A SuperSpeed device shall include the USB2.0 extension descriptor
+	 * and shall support LPM when operating in USB2.0 HS mode.
+	 */
+	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu_packed((__le16_packed *)&bos->wTotalLength,
+			    USB_DT_USB_EXT_CAP_SIZE);
+	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+	usb_ext->bmAttributes =
+		cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
+
+	/*
+	 * The Superspeed USB Capability descriptor shall be implemented
+	 * by all SuperSpeed devices.
+	 */
+	if (gadget_is_superspeed(cdev->gadget)) {
+		struct usb_ss_cap_descriptor *ss_cap;
+
+		ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+		bos->bNumDeviceCaps++;
+		le16_add_cpu_packed((__le16_packed *)&bos->wTotalLength,
+				    USB_DT_USB_SS_CAP_SIZE);
+		ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+		ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+		ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+		ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+		ss_cap->wSpeedSupported =
+			cpu_to_le16(USB_LOW_SPEED_OPERATION |
+				    USB_FULL_SPEED_OPERATION |
+				    USB_HIGH_SPEED_OPERATION |
+				    USB_5GBPS_OPERATION);
+		ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+		/* Get Controller configuration */
+		if (cdev->gadget->ops->get_config_params) {
+			cdev->gadget->ops->get_config_params(
+				&dcd_config_params);
+		} else {
+			dcd_config_params.bU1devExitLat =
+				USB_DEFAULT_U1_DEV_EXIT_LAT;
+			dcd_config_params.bU2DevExitLat =
+				cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+		}
+		ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+		ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+	}
+	return le16_to_cpu(bos->wTotalLength);
+}
+
+static int count_ext_compat(struct usb_configuration *c)
+{
+	int i, res;
+
+	res = 0;
+	for (i = 0; i < c->next_interface_id; ++i) {
+		struct usb_function *f;
+		int j;
+
+		f = c->interface[i];
+		for (j = 0; j < f->os_desc_n; ++j) {
+			struct usb_os_desc *d;
+
+			if (i != f->os_desc_table[j].if_id)
+				continue;
+			d = f->os_desc_table[j].os_desc;
+			if (d && d->ext_compat_id)
+				++res;
+		}
+	}
+	BUG_ON(res > 255);
+	return res;
+}
+
+static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
+{
+	int i, count;
+
+	count = 16;
+	for (i = 0; i < c->next_interface_id; ++i) {
+		struct usb_function *f;
+		int j;
+
+		f = c->interface[i];
+		for (j = 0; j < f->os_desc_n; ++j) {
+			struct usb_os_desc *d;
+
+			if (i != f->os_desc_table[j].if_id)
+				continue;
+			d = f->os_desc_table[j].os_desc;
+			if (d && d->ext_compat_id) {
+				*buf++ = i;
+				*buf++ = 0x01;
+				memcpy(buf, d->ext_compat_id, 16);
+				buf += 22;
+			} else {
+				++buf;
+				*buf = 0x01;
+				buf += 23;
+			}
+			count += 24;
+			if (count >= 4096)
+				return;
+		}
+	}
+}
+
+static int count_ext_prop(struct usb_configuration *c, int interface)
+{
+	struct usb_function *f;
+	int j;
+
+	f = c->interface[interface];
+	for (j = 0; j < f->os_desc_n; ++j) {
+		struct usb_os_desc *d;
+
+		if (interface != f->os_desc_table[j].if_id)
+			continue;
+		d = f->os_desc_table[j].os_desc;
+		if (d && d->ext_compat_id)
+			return d->ext_prop_count;
+	}
+	return 0;
+}
+
+static int len_ext_prop(struct usb_configuration *c, int interface)
+{
+	struct usb_function *f;
+	struct usb_os_desc *d;
+	int j, res;
+
+	res = 10; /* header length */
+	f = c->interface[interface];
+	for (j = 0; j < f->os_desc_n; ++j) {
+		if (interface != f->os_desc_table[j].if_id)
+			continue;
+		d = f->os_desc_table[j].os_desc;
+		if (d)
+			return min(res + d->ext_prop_len, 4096);
+	}
+	return res;
+}
+
+static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
+{
+	struct usb_function *f;
+	struct usb_os_desc *d;
+	struct usb_os_desc_ext_prop *ext_prop;
+	int j, count, n, ret;
+	u8 *start = buf;
+
+	f = c->interface[interface];
+	for (j = 0; j < f->os_desc_n; ++j) {
+		if (interface != f->os_desc_table[j].if_id)
+			continue;
+		d = f->os_desc_table[j].os_desc;
+		if (d)
+			list_for_each_entry(ext_prop, &d->ext_prop, entry) {
+				/* 4kB minus header length */
+				n = buf - start;
+				if (n >= 4086)
+					return 0;
+
+				count = ext_prop->data_len +
+					ext_prop->name_len + 14;
+				if (count > 4086 - n)
+					return -EINVAL;
+				usb_ext_prop_put_size(buf, count);
+				usb_ext_prop_put_type(buf, ext_prop->type);
+				ret = usb_ext_prop_put_name(buf, ext_prop->name,
+							    ext_prop->name_len);
+				if (ret < 0)
+					return ret;
+				switch (ext_prop->type) {
+				case USB_EXT_PROP_UNICODE:
+				case USB_EXT_PROP_UNICODE_ENV:
+				case USB_EXT_PROP_UNICODE_LINK:
+					usb_ext_prop_put_unicode(buf, ret,
+							 ext_prop->data,
+							 ext_prop->data_len);
+					break;
+				case USB_EXT_PROP_BINARY:
+					usb_ext_prop_put_binary(buf, ret,
+							ext_prop->data,
+							ext_prop->data_len);
+					break;
+				case USB_EXT_PROP_LE32:
+					/* not implemented */
+				case USB_EXT_PROP_BE32:
+					/* not implemented */
+				default:
+					return -EINVAL;
+				}
+				buf += count;
+			}
+	}
+
+	return 0;
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's
+ * not handled lower down, in hardware or the hardware driver(like
+ * device and endpoint feature flags, and their status).  It's all
+ * housekeeping for the gadget function we're implementing.  Most of
+ * the work is in config and function specific setup.
+ */
+static int
+composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	u16				w_length = le16_to_cpu(ctrl->wLength);
+	u16				w_index = le16_to_cpu(ctrl->wIndex);
+	u16				w_value = le16_to_cpu(ctrl->wValue);
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	u8				intf = w_index & 0xFF;
+	int				value = -EOPNOTSUPP;
+	struct usb_request		*req = cdev->req;
+	struct usb_function		*f = NULL;
+	int				standard;
+	u8				endp;
+	struct usb_configuration	*c;
+
+	/*
+	 * partial re-init of the response message; the function or the
+	 * gadget might need to intercept e.g. a control-OUT completion
+	 * when we delegate to it.
+	 */
+	req->zero = 0;
+	req->complete = composite_setup_complete;
+	req->length = USB_BUFSIZ;
+	gadget->ep0->driver_data = cdev;
+	standard = (ctrl->bRequestType & USB_TYPE_MASK)
+						== USB_TYPE_STANDARD;
+	if (!standard)
+		goto unknown;
+
+	switch (ctrl->bRequest) {
+
+	/* we handle all standard USB descriptors */
+	case USB_REQ_GET_DESCRIPTOR:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			goto unknown;
+		switch (w_value >> 8) {
+
+		case USB_DT_DEVICE:
+			cdev->desc.bNumConfigurations =
+				count_configs(cdev, USB_DT_DEVICE);
+
+			cdev->desc.bMaxPacketSize0 =
+				cdev->gadget->ep0->maxpacket;
+			if (gadget->speed >= USB_SPEED_SUPER) {
+				cdev->desc.bcdUSB = cpu_to_le16(0x0310);
+				cdev->desc.bMaxPacketSize0 = 9;
+			} else {
+				cdev->desc.bcdUSB = cpu_to_le16(0x0200);
+			}
+			value = min(w_length, (u16) sizeof cdev->desc);
+			memcpy(req->buf, &cdev->desc, value);
+			break;
+		case USB_DT_DEVICE_QUALIFIER:
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
+				break;
+			device_qual(cdev);
+			value = min_t(int, w_length,
+				      sizeof(struct usb_qualifier_descriptor));
+			break;
+		case USB_DT_OTHER_SPEED_CONFIG:
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
+				break;
+
+		case USB_DT_CONFIG:
+			value = config_desc(cdev, w_value);
+			if (value >= 0)
+				value = min(w_length, (u16) value);
+			break;
+		case USB_DT_STRING:
+			value = get_string(cdev, req->buf,
+					w_index, w_value & 0xff);
+			if (value >= 0)
+				value = min(w_length, (u16) value);
+			break;
+		case USB_DT_BOS:
+			/*
+			 * Super speed connection should support BOS, and
+			 * USB compliance test (USB 2.0 Command Verifier)
+			 * also issues this request, return for now for
+			 * USB 2.0 connection.
+			 */
+			if (gadget->speed >= USB_SPEED_SUPER) {
+				value = bos_desc(cdev);
+				value = min(w_length, (u16)value);
+			}
+			break;
+		default:
+			goto unknown;
+		}
+		break;
+
+	/* any number of configs can work */
+	case USB_REQ_SET_CONFIGURATION:
+		if (ctrl->bRequestType != 0)
+			goto unknown;
+		if (gadget_is_otg(gadget)) {
+			if (gadget->a_hnp_support)
+				debug("HNP available\n");
+			else if (gadget->a_alt_hnp_support)
+				debug("HNP on another port\n");
+			else
+				debug("HNP inactive\n");
+		}
+
+		value = set_config(cdev, ctrl, w_value);
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			goto unknown;
+		if (cdev->config)
+			*(u8 *)req->buf = cdev->config->bConfigurationValue;
+		else
+			*(u8 *)req->buf = 0;
+		value = min(w_length, (u16) 1);
+		break;
+
+	/*
+	 * function drivers must handle get/set altsetting; if there's
+	 * no get() method, we know only altsetting zero works.
+	 */
+	case USB_REQ_SET_INTERFACE:
+		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+			goto unknown;
+		if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		if (w_value && !f->set_alt)
+			break;
+		value = f->set_alt(f, w_index, w_value);
+		break;
+	case USB_REQ_GET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+			goto unknown;
+		if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		/* lots of interfaces only need altsetting zero... */
+		value = f->get_alt ? f->get_alt(f, w_index) : 0;
+		if (value < 0)
+			break;
+		*((u8 *)req->buf) = value;
+		value = min(w_length, (u16) 1);
+		break;
+	default:
+unknown:
+		/*
+		 * OS descriptors handling
+		 */
+		if (CONFIG_IS_ENABLED(USB_GADGET_OS_DESCRIPTORS) && cdev->use_os_string &&
+		    cdev->os_desc_config && (ctrl->bRequestType & USB_TYPE_VENDOR) &&
+		    ctrl->bRequest == cdev->b_vendor_code) {
+			struct usb_configuration	*os_desc_cfg;
+			u8				*buf;
+			int				interface;
+			int				count = 0;
+
+			buf = req->buf;
+			os_desc_cfg = cdev->os_desc_config;
+			memset(buf, 0, w_length);
+			buf[5] = 0x01;
+			switch (ctrl->bRequestType & USB_RECIP_MASK) {
+			case USB_RECIP_DEVICE:
+				if (w_index != 0x4 || (w_value >> 8))
+					break;
+				buf[6] = w_index;
+				if (w_length == 0x10) {
+					/* Number of ext compat interfaces */
+					count = count_ext_compat(os_desc_cfg);
+					buf[8] = count;
+					count *= 24; /* 24 B/ext compat desc */
+					count += 16; /* header */
+					put_unaligned_le32(count, buf);
+					value = w_length;
+				} else {
+					/* "extended compatibility ID"s */
+					count = count_ext_compat(os_desc_cfg);
+					buf[8] = count;
+					count *= 24; /* 24 B/ext compat desc */
+					count += 16; /* header */
+					put_unaligned_le32(count, buf);
+					buf += 16;
+					fill_ext_compat(os_desc_cfg, buf);
+					value = w_length;
+				}
+				break;
+			case USB_RECIP_INTERFACE:
+				if (w_index != 0x5 || (w_value >> 8))
+					break;
+				interface = w_value & 0xFF;
+				buf[6] = w_index;
+				if (w_length == 0x0A) {
+					count = count_ext_prop(os_desc_cfg,
+						interface);
+					put_unaligned_le16(count, buf + 8);
+					count = len_ext_prop(os_desc_cfg,
+						interface);
+					put_unaligned_le32(count, buf);
+
+					value = w_length;
+				} else {
+					count = count_ext_prop(os_desc_cfg,
+						interface);
+					put_unaligned_le16(count, buf + 8);
+					count = len_ext_prop(os_desc_cfg,
+						interface);
+					put_unaligned_le32(count, buf);
+					buf += 10;
+					value = fill_ext_prop(os_desc_cfg,
+							      interface, buf);
+					if (value < 0)
+						return value;
+
+					value = w_length;
+				}
+				break;
+			}
+
+			if (value >= 0) {
+				req->length = value;
+				req->zero = value < w_length;
+				value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL);
+				if (value < 0) {
+					debug("ep_queue --> %d\n", value);
+					req->status = 0;
+					composite_setup_complete(gadget->ep0, req);
+				}
+			}
+			return value;
+		}
+
+		debug("non-core control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+
+		if (!cdev->config)
+			goto done;
+
+		/*
+		 * functions always handle their interfaces and endpoints...
+		 * punt other recipients (other, WUSB, ...) to the current
+		 * configuration code.
+		 */
+		switch (ctrl->bRequestType & USB_RECIP_MASK) {
+		case USB_RECIP_INTERFACE:
+			f = cdev->config->interface[intf];
+			break;
+
+		case USB_RECIP_ENDPOINT:
+			endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
+			list_for_each_entry(f, &cdev->config->functions, list) {
+				if (test_bit(endp, f->endpoints))
+					break;
+			}
+			if (&f->list == &cdev->config->functions)
+				f = NULL;
+			break;
+		/*
+		 * dfu-util (version 0.5) sets bmRequestType.Receipent = Device
+		 * for non-standard request (w_value = 0x21,
+		 * bRequest = GET_DESCRIPTOR in this case).
+		 * When only one interface is registered (as it is done now),
+		 * then this request shall be handled as it was requested for
+		 * interface.
+		 *
+		 * In the below code it is checked if only one interface is
+		 * present and proper function for it is extracted. Due to that
+		 * function's setup (f->setup) is called to handle this
+		 * special non-standard request.
+		 */
+		case USB_RECIP_DEVICE:
+			debug("cdev->config->next_interface_id: %d intf: %d\n",
+			       cdev->config->next_interface_id, intf);
+			if (cdev->config->next_interface_id == 1)
+				f = cdev->config->interface[intf];
+			break;
+		}
+
+		if (f && f->setup)
+			value = f->setup(f, ctrl);
+		else {
+			c = cdev->config;
+			if (c->setup)
+				value = c->setup(c, ctrl);
+		}
+
+		goto done;
+	}
+
+	/* respond with data transfer before status phase? */
+	if (value >= 0) {
+		req->length = value;
+		req->zero = value < w_length;
+		value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL);
+		if (value < 0) {
+			debug("ep_queue --> %d\n", value);
+			req->status = 0;
+			composite_setup_complete(gadget->ep0, req);
+		}
+	}
+
+done:
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+static void composite_disconnect(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+
+	if (cdev->config)
+		reset_config(cdev);
+	if (composite->disconnect)
+		composite->disconnect(cdev);
+}
+
+static void composite_unbind(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_configuration	*c;
+	struct usb_function		*f;
+
+	/*
+	 * composite_disconnect() must already have been called
+	 * by the underlying peripheral controller driver!
+	 * so there's no i/o concurrency that could affect the
+	 * state protected by cdev->lock.
+	 */
+#ifdef __UBOOT__
+	assert_noisy(!cdev->config);
+#else
+	BUG_ON(cdev->config);
+#endif
+
+	while (!list_empty(&cdev->configs)) {
+		c = list_first_entry(&cdev->configs,
+				struct usb_configuration, list);
+		while (!list_empty(&c->functions)) {
+			f = list_first_entry(&c->functions,
+					struct usb_function, list);
+			list_del(&f->list);
+			if (f->unbind) {
+				debug("unbind function '%s'/%p\n",
+						f->name, f);
+				f->unbind(c, f);
+			}
+		}
+		list_del(&c->list);
+		if (c->unbind) {
+			debug("unbind config '%s'/%p\n", c->label, c);
+			c->unbind(c);
+		}
+		free(c);
+	}
+	if (composite->unbind)
+		composite->unbind(cdev);
+
+	if (cdev->req) {
+		kfree(cdev->req->buf);
+		usb_ep_free_request(gadget->ep0, cdev->req);
+	}
+	kfree(cdev);
+	set_gadget_data(gadget, NULL);
+
+	composite = NULL;
+}
+
+static int composite_bind(struct usb_gadget *gadget)
+{
+	int				status = -ENOMEM;
+	struct usb_composite_dev	*cdev;
+
+	cdev = calloc(sizeof *cdev, 1);
+	if (!cdev)
+		return status;
+
+	cdev->gadget = gadget;
+	set_gadget_data(gadget, cdev);
+	INIT_LIST_HEAD(&cdev->configs);
+
+	/* preallocate control response and buffer */
+	cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+	if (!cdev->req)
+		goto fail;
+	cdev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, USB_BUFSIZ);
+	if (!cdev->req->buf)
+		goto fail;
+	cdev->req->complete = composite_setup_complete;
+	gadget->ep0->driver_data = cdev;
+
+	cdev->bufsiz = USB_BUFSIZ;
+	cdev->driver = composite;
+
+	usb_gadget_set_selfpowered(gadget);
+	usb_ep_autoconfig_reset(cdev->gadget);
+
+	status = composite->bind(cdev);
+	if (status < 0)
+		goto fail;
+
+	memcpy(&cdev->desc, composite->dev,
+	       sizeof(struct usb_device_descriptor));
+	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+
+	if (cdev->use_os_string) {
+		/* TODO: Do we want to pass this via platform? */
+		cdev->b_vendor_code = 0x40;
+
+		/* Microsoft OS String Descriptor */
+		utf8_to_utf16le(qw_sign_buf, (__le16 *)cdev->qw_sign,
+				OS_STRING_QW_SIGN_LEN / 2);
+	}
+
+	debug("%s: ready\n", composite->name);
+	return 0;
+
+fail:
+	composite_unbind(gadget);
+	return status;
+}
+
+static void
+composite_suspend(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_function		*f;
+
+	debug("%s: suspend\n", __func__);
+	if (cdev->config) {
+		list_for_each_entry(f, &cdev->config->functions, list) {
+			if (f->suspend)
+				f->suspend(f);
+		}
+	}
+	if (composite->suspend)
+		composite->suspend(cdev);
+
+	cdev->suspended = 1;
+}
+
+static void
+composite_resume(struct usb_gadget *gadget)
+{
+	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
+	struct usb_function		*f;
+
+	debug("%s: resume\n", __func__);
+	if (composite->resume)
+		composite->resume(cdev);
+	if (cdev->config) {
+		list_for_each_entry(f, &cdev->config->functions, list) {
+			if (f->resume)
+				f->resume(f);
+		}
+	}
+
+	cdev->suspended = 0;
+}
+
+static struct usb_gadget_driver composite_driver = {
+	.speed		= USB_SPEED_SUPER,
+
+	.bind		= composite_bind,
+	.unbind         = composite_unbind,
+
+	.setup		= composite_setup,
+	.reset          = composite_disconnect,
+	.disconnect	= composite_disconnect,
+
+	.suspend        = composite_suspend,
+	.resume         = composite_resume,
+};
+
+/**
+ * usb_composite_register() - register a composite driver
+ * @driver: the driver to register
+ * Context: single threaded during gadget setup
+ *
+ * This function is used to register drivers using the composite driver
+ * framework.  The return value is zero, or a negative errno value.
+ * Those values normally come from the driver's @bind method, which does
+ * all the work of setting up the driver to match the hardware.
+ *
+ * On successful return, the gadget is ready to respond to requests from
+ * the host, unless one of its components invokes usb_gadget_disconnect()
+ * while it was binding.  That would usually be done in order to wait for
+ * some userspace participation.
+ */
+int usb_composite_register(struct usb_composite_driver *driver)
+{
+	int res;
+
+	if (!driver || !driver->dev || !driver->bind || composite)
+		return -EINVAL;
+
+	if (!driver->name)
+		driver->name = "composite";
+	composite = driver;
+
+	res = usb_gadget_register_driver(&composite_driver);
+	if (res != 0)
+		composite = NULL;
+
+	return res;
+}
+
+/**
+ * usb_composite_unregister() - unregister a composite driver
+ * @driver: the driver to unregister
+ *
+ * This function is used to unregister drivers using the composite
+ * driver framework.
+ */
+void usb_composite_unregister(struct usb_composite_driver *driver)
+{
+	if (composite != driver)
+		return;
+	usb_gadget_unregister_driver(&composite_driver);
+	composite = NULL;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/config.c b/roms/u-boot/drivers/usb/gadget/config.c
new file mode 100644
index 000000000..e96782644
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/config.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * usb/gadget/config.c -- simplify building config descriptors
+ *
+ * Copyright (C) 2003 David Brownell
+ *
+ * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and
+ *                      Remy Bohmer <linux@bohmer.net>
+ */
+
+#include <common.h>
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/string.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+
+/**
+ * usb_descriptor_fillbuf - fill buffer with descriptors
+ * @buf: Buffer to be filled
+ * @buflen: Size of buf
+ * @src: Array of descriptor pointers, terminated by null pointer.
+ *
+ * Copies descriptors into the buffer, returning the length or a
+ * negative error code if they can't all be copied.  Useful when
+ * assembling descriptors for an associated set of interfaces used
+ * as part of configuring a composite device; or in other cases where
+ * sets of descriptors need to be marshaled.
+ */
+int
+usb_descriptor_fillbuf(void *buf, unsigned buflen,
+		const struct usb_descriptor_header **src)
+{
+	u8	*dest = buf;
+
+	if (!src)
+		return -EINVAL;
+
+	/* fill buffer from src[] until null descriptor ptr */
+	for (; NULL != *src; src++) {
+		unsigned		len = (*src)->bLength;
+
+		if (len > buflen)
+			return -EINVAL;
+		memcpy(dest, *src, len);
+		buflen -= len;
+		dest += len;
+	}
+	return dest - (u8 *)buf;
+}
+
+
+/**
+ * usb_gadget_config_buf - builts a complete configuration descriptor
+ * @config: Header for the descriptor, including characteristics such
+ *	as power requirements and number of interfaces.
+ * @desc: Null-terminated vector of pointers to the descriptors (interface,
+ *	endpoint, etc) defining all functions in this device configuration.
+ * @buf: Buffer for the resulting configuration descriptor.
+ * @length: Length of buffer.  If this is not big enough to hold the
+ *	entire configuration descriptor, an error code will be returned.
+ *
+ * This copies descriptors into the response buffer, building a descriptor
+ * for that configuration.  It returns the buffer length or a negative
+ * status code.  The config.wTotalLength field is set to match the length
+ * of the result, but other descriptor fields (including power usage and
+ * interface count) must be set by the caller.
+ *
+ * Gadget drivers could use this when constructing a config descriptor
+ * in response to USB_REQ_GET_DESCRIPTOR.  They will need to patch the
+ * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
+ */
+int usb_gadget_config_buf(
+	const struct usb_config_descriptor	*config,
+	void					*buf,
+	unsigned				length,
+	const struct usb_descriptor_header	**desc
+)
+{
+	struct usb_config_descriptor		*cp = buf;
+	int					len;
+
+	/* config descriptor first */
+	if (length < USB_DT_CONFIG_SIZE || !desc)
+		return -EINVAL;
+	/* config need not be aligned */
+	memcpy(cp, config, sizeof(*cp));
+
+	/* then interface/endpoint/class/vendor/... */
+	len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf,
+			length - USB_DT_CONFIG_SIZE, desc);
+	if (len < 0)
+		return len;
+	len += USB_DT_CONFIG_SIZE;
+	if (len > 0xffff)
+		return -EINVAL;
+
+	/* patch up the config descriptor */
+	cp->bLength = USB_DT_CONFIG_SIZE;
+	cp->bDescriptorType = USB_DT_CONFIG;
+	put_unaligned_le16(len, &cp->wTotalLength);
+	cp->bmAttributes |= USB_CONFIG_ATT_ONE;
+	return len;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/core.c b/roms/u-boot/drivers/usb/gadget/core.c
new file mode 100644
index 000000000..888f0cfea
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/core.c
@@ -0,0 +1,633 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *	Stuart Lynne <sl@lineo.com>,
+ *	Tom Rushworth <tbr@lineo.com>,
+ *	Bruce Balden <balden@lineo.com>
+ */
+
+#include <log.h>
+#include <malloc.h>
+#include <serial.h>
+#include <usbdevice.h>
+
+#define MAX_INTERFACES 2
+
+
+int maxstrings = 20;
+
+/* Global variables ************************************************************************** */
+
+struct usb_string_descriptor **usb_strings;
+
+int usb_devices;
+
+extern struct usb_function_driver ep0_driver;
+
+int registered_functions;
+int registered_devices;
+
+__maybe_unused static char *usbd_device_events[] = {
+	"DEVICE_UNKNOWN",
+	"DEVICE_INIT",
+	"DEVICE_CREATE",
+	"DEVICE_HUB_CONFIGURED",
+	"DEVICE_RESET",
+	"DEVICE_ADDRESS_ASSIGNED",
+	"DEVICE_CONFIGURED",
+	"DEVICE_SET_INTERFACE",
+	"DEVICE_SET_FEATURE",
+	"DEVICE_CLEAR_FEATURE",
+	"DEVICE_DE_CONFIGURED",
+	"DEVICE_BUS_INACTIVE",
+	"DEVICE_BUS_ACTIVITY",
+	"DEVICE_POWER_INTERRUPTION",
+	"DEVICE_HUB_RESET",
+	"DEVICE_DESTROY",
+	"DEVICE_FUNCTION_PRIVATE",
+};
+
+__maybe_unused static char *usbd_device_status[] = {
+	"USBD_OPENING",
+	"USBD_OK",
+	"USBD_SUSPENDED",
+	"USBD_CLOSING",
+};
+
+#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
+
+
+/* Descriptor support functions ************************************************************** */
+
+
+/**
+ * usbd_get_string - find and return a string descriptor
+ * @index: string index to return
+ *
+ * Find an indexed string and return a pointer to a it.
+ */
+struct usb_string_descriptor *usbd_get_string (__u8 index)
+{
+	if (index >= maxstrings) {
+		return NULL;
+	}
+	return usb_strings[index];
+}
+
+
+/* Access to device descriptor functions ***************************************************** */
+
+
+/* *
+ * usbd_device_configuration_instance - find a configuration instance for this device
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Get specifed device configuration. Index should be bConfigurationValue-1.
+ */
+static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
+		unsigned int port, unsigned int configuration)
+{
+	if (configuration >= device->configurations)
+		return NULL;
+
+	return device->configuration_instance_array + configuration;
+}
+
+
+/* *
+ * usbd_device_interface_instance
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
+{
+	struct usb_configuration_instance *configuration_instance;
+
+	if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
+		return NULL;
+	}
+	if (interface >= configuration_instance->interfaces) {
+		return NULL;
+	}
+	return configuration_instance->interface_instance_array + interface;
+}
+
+/* *
+ * usbd_device_alternate_descriptor_list
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified alternate descriptor for the specified device.
+ */
+struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
+{
+	struct usb_interface_instance *interface_instance;
+
+	if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
+		return NULL;
+	}
+
+	if (alternate >= interface_instance->alternates) {
+		return NULL;
+	}
+
+	return interface_instance->alternates_instance_array + alternate;
+}
+
+
+/* *
+ * usbd_device_device_descriptor
+ * @device: which device
+ * @configuration: index to configuration, 0 - N-1
+ * @port: which port
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
+{
+	return (device->device_descriptor);
+}
+
+/**
+ * usbd_device_configuration_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
+									   usb_device_instance
+									   *device, int port, int configuration)
+{
+	struct usb_configuration_instance *configuration_instance;
+	if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
+		return NULL;
+	}
+	return (configuration_instance->configuration_descriptor);
+}
+
+
+/**
+ * usbd_device_interface_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
+								   *device, int port, int configuration, int interface, int alternate)
+{
+	struct usb_interface_instance *interface_instance;
+	if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
+		return NULL;
+	}
+	if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
+		return NULL;
+	}
+	return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
+}
+
+/**
+ * usbd_device_endpoint_descriptor_index
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: index setting
+ * @index: which index
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
+								       *device, int port, int configuration, int interface, int alternate, int index)
+{
+	struct usb_alternate_instance *alternate_instance;
+
+	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+		return NULL;
+	}
+	if (index >= alternate_instance->endpoints) {
+		return NULL;
+	}
+	return *(alternate_instance->endpoints_descriptor_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_transfersize
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @index: which index
+ *
+ * Return the specified endpoint transfer size;
+ */
+int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
+{
+	struct usb_alternate_instance *alternate_instance;
+
+	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+		return 0;
+	}
+	if (index >= alternate_instance->endpoints) {
+		return 0;
+	}
+	return *(alternate_instance->endpoint_transfersize_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ * @endpoint: which endpoint
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
+{
+	struct usb_endpoint_descriptor *endpoint_descriptor;
+	int i;
+
+	for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
+		if (endpoint_descriptor->bEndpointAddress == endpoint) {
+			return endpoint_descriptor;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * usbd_endpoint_halted
+ * @device: point to struct usb_device_instance
+ * @endpoint: endpoint to check
+ *
+ * Return non-zero if endpoint is halted.
+ */
+int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
+{
+	return (device->status == USB_STATUS_HALT);
+}
+
+
+/**
+ * usbd_rcv_complete - complete a receive
+ * @endpoint:
+ * @len:
+ * @urb_bad:
+ *
+ * Called from rcv interrupt to complete.
+ */
+void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
+{
+	if (endpoint) {
+		struct urb *rcv_urb;
+
+		/*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
+
+		/* if we had an urb then update actual_length, dispatch if neccessary */
+		if ((rcv_urb = endpoint->rcv_urb)) {
+
+			/*usbdbg("actual: %d buffer: %d\n", */
+			/*rcv_urb->actual_length, rcv_urb->buffer_length); */
+
+			/* check the urb is ok, are we adding data less than the packetsize */
+			if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
+			  /*usbdbg("updating actual_length by %d\n",len); */
+
+				/* increment the received data size */
+				rcv_urb->actual_length += len;
+
+			} else {
+				usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
+				       rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
+
+				rcv_urb->actual_length = 0;
+				rcv_urb->status = RECV_ERROR;
+			}
+		} else {
+			usberr("no rcv_urb!");
+		}
+	} else {
+		usberr("no endpoint!");
+	}
+
+}
+
+/**
+ * usbd_tx_complete - complete a transmit
+ * @endpoint:
+ * @resetart:
+ *
+ * Called from tx interrupt to complete.
+ */
+void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
+{
+	if (endpoint) {
+		struct urb *tx_urb;
+
+		/* if we have a tx_urb advance or reset, finish if complete */
+		if ((tx_urb = endpoint->tx_urb)) {
+			int sent = endpoint->last;
+			endpoint->sent += sent;
+			endpoint->last -= sent;
+
+			if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
+				tx_urb->actual_length = 0;
+				endpoint->sent = 0;
+				endpoint->last = 0;
+
+				/* Remove from active, save for re-use */
+				urb_detach(tx_urb);
+				urb_append(&endpoint->done, tx_urb);
+				/*usbdbg("done->next %p, tx_urb %p, done %p", */
+				/*	 endpoint->done.next, tx_urb, &endpoint->done); */
+
+				endpoint->tx_urb = first_urb_detached(&endpoint->tx);
+				if( endpoint->tx_urb ) {
+					endpoint->tx_queue--;
+					usbdbg("got urb from tx list");
+				}
+				if( !endpoint->tx_urb ) {
+					/*usbdbg("taking urb from done list"); */
+					endpoint->tx_urb = first_urb_detached(&endpoint->done);
+				}
+				if( !endpoint->tx_urb ) {
+					usbdbg("allocating new urb for tx_urb");
+					endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
+				}
+			}
+		}
+	}
+}
+
+/* URB linked list functions ***************************************************** */
+
+/*
+ * Initialize an urb_link to be a single element list.
+ * If the urb_link is being used as a distinguished list head
+ * the list is empty when the head is the only link in the list.
+ */
+void urb_link_init (urb_link * ul)
+{
+	if (ul) {
+		ul->prev = ul->next = ul;
+	}
+}
+
+/*
+ * Detach an urb_link from a list, and set it
+ * up as a single element list, so no dangling
+ * pointers can be followed, and so it can be
+ * joined to another list if so desired.
+ */
+void urb_detach (struct urb *urb)
+{
+	if (urb) {
+		urb_link *ul = &urb->link;
+		ul->next->prev = ul->prev;
+		ul->prev->next = ul->next;
+		urb_link_init (ul);
+	}
+}
+
+/*
+ * Return the first urb_link in a list with a distinguished
+ * head "hd", or NULL if the list is empty.  This will also
+ * work as a predicate, returning NULL if empty, and non-NULL
+ * otherwise.
+ */
+urb_link *first_urb_link (urb_link * hd)
+{
+	urb_link *nx;
+	if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
+		/* There is at least one element in the list */
+		/* (besides the distinguished head). */
+		return (nx);
+	}
+	/* The list is empty */
+	return (NULL);
+}
+
+/*
+ * Return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ */
+struct urb *first_urb (urb_link * hd)
+{
+	urb_link *nx;
+	if (NULL == (nx = first_urb_link (hd))) {
+		/* The list is empty */
+		return (NULL);
+	}
+	return (p2surround (struct urb, link, nx));
+}
+
+/*
+ * Detach and return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ */
+struct urb *first_urb_detached (urb_link * hd)
+{
+	struct urb *urb;
+	if ((urb = first_urb (hd))) {
+		urb_detach (urb);
+	}
+	return urb;
+}
+
+
+/*
+ * Append an urb_link (or a whole list of
+ * urb_links) to the tail of another list
+ * of urb_links.
+ */
+void urb_append (urb_link * hd, struct urb *urb)
+{
+	if (hd && urb) {
+		urb_link *new = &urb->link;
+
+		/* This allows the new urb to be a list of urbs, */
+		/* with new pointing at the first, but the link */
+		/* must be initialized. */
+		/* Order is important here... */
+		urb_link *pul = hd->prev;
+		new->prev->next = hd;
+		hd->prev = new->prev;
+		new->prev = pul;
+		pul->next = new;
+	}
+}
+
+/* URB create/destroy functions ***************************************************** */
+
+/**
+ * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
+ * @device: device instance
+ * @endpoint: endpoint
+ *
+ * Allocate an urb structure. The usb device urb structure is used to
+ * contain all data associated with a transfer, including a setup packet for
+ * control transfers.
+ *
+ * NOTE: endpoint_address MUST contain a direction flag.
+ */
+struct urb *usbd_alloc_urb (struct usb_device_instance *device,
+			    struct usb_endpoint_instance *endpoint)
+{
+	struct urb *urb;
+
+	if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
+		usberr (" F A T A L:  malloc(%zu) FAILED!!!!",
+			sizeof (struct urb));
+		return NULL;
+	}
+
+	/* Fill in known fields */
+	memset (urb, 0, sizeof (struct urb));
+	urb->endpoint = endpoint;
+	urb->device = device;
+	urb->buffer = (u8 *) urb->buffer_data;
+	urb->buffer_length = sizeof (urb->buffer_data);
+
+	urb_link_init (&urb->link);
+
+	return urb;
+}
+
+/**
+ * usbd_dealloc_urb - deallocate an URB and associated buffer
+ * @urb: pointer to an urb structure
+ *
+ * Deallocate an urb structure and associated data.
+ */
+void usbd_dealloc_urb (struct urb *urb)
+{
+	if (urb) {
+		free (urb);
+	}
+}
+
+/* Event signaling functions ***************************************************** */
+
+/**
+ * usbd_device_event - called to respond to various usb events
+ * @device: pointer to struct device
+ * @event: event to respond to
+ *
+ * Used by a Bus driver to indicate an event.
+ */
+void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
+{
+	usb_device_state_t state;
+
+	if (!device || !device->bus) {
+		usberr("(%p,%d) NULL device or device->bus", device, event);
+		return;
+	}
+
+	state = device->device_state;
+
+	usbinfo("%s", usbd_device_events[event]);
+
+	switch (event) {
+	case DEVICE_UNKNOWN:
+		break;
+	case DEVICE_INIT:
+		device->device_state = STATE_INIT;
+		break;
+
+	case DEVICE_CREATE:
+		device->device_state = STATE_ATTACHED;
+		break;
+
+	case DEVICE_HUB_CONFIGURED:
+		device->device_state = STATE_POWERED;
+		break;
+
+	case DEVICE_RESET:
+		device->device_state = STATE_DEFAULT;
+		device->address = 0;
+		break;
+
+	case DEVICE_ADDRESS_ASSIGNED:
+		device->device_state = STATE_ADDRESSED;
+		break;
+
+	case DEVICE_CONFIGURED:
+		device->device_state = STATE_CONFIGURED;
+		break;
+
+	case DEVICE_DE_CONFIGURED:
+		device->device_state = STATE_ADDRESSED;
+		break;
+
+	case DEVICE_BUS_INACTIVE:
+		if (device->status != USBD_CLOSING) {
+			device->status = USBD_SUSPENDED;
+		}
+		break;
+	case DEVICE_BUS_ACTIVITY:
+		if (device->status != USBD_CLOSING) {
+			device->status = USBD_OK;
+		}
+		break;
+
+	case DEVICE_SET_INTERFACE:
+		break;
+	case DEVICE_SET_FEATURE:
+		break;
+	case DEVICE_CLEAR_FEATURE:
+		break;
+
+	case DEVICE_POWER_INTERRUPTION:
+		device->device_state = STATE_POWERED;
+		break;
+	case DEVICE_HUB_RESET:
+		device->device_state = STATE_ATTACHED;
+		break;
+	case DEVICE_DESTROY:
+		device->device_state = STATE_UNKNOWN;
+		break;
+
+	case DEVICE_FUNCTION_PRIVATE:
+		break;
+
+	default:
+		usbdbg("event %d - not handled",event);
+		break;
+	}
+	debug("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
+		device->name, event, state,
+		device->device_state, device->status, device->address);
+
+	/* tell the bus interface driver */
+	if( device->event ) {
+		/* usbdbg("calling device->event"); */
+		device->event(device, event, data);
+	}
+}
diff --git a/roms/u-boot/drivers/usb/gadget/designware_udc.c b/roms/u-boot/drivers/usb/gadget/designware_udc.c
new file mode 100644
index 000000000..7fc5d27d4
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/designware_udc.c
@@ -0,0 +1,1021 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Based on drivers/usb/gadget/omap1510_udc.c
+ * TI OMAP1510 USB bus interface driver
+ *
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ */
+
+#include <common.h>
+#include <serial.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#include <env.h>
+#include <usbdevice.h>
+#include "ep0.h"
+#include <usb/designware_udc.h>
+#include <usb/udc.h>
+#include <asm/arch/hardware.h>
+
+#define UDC_INIT_MDELAY		80	/* Device settle delay */
+
+/* Some kind of debugging output... */
+#ifndef DEBUG_DWUSBTTY
+#define UDCDBG(str)
+#define UDCDBGA(fmt, args...)
+#else
+#define UDCDBG(str) serial_printf(str "\n")
+#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args)
+#endif
+
+static struct urb *ep0_urb;
+static struct usb_device_instance *udc_device;
+
+static struct plug_regs *const plug_regs_p =
+    (struct plug_regs * const)CONFIG_SYS_PLUG_BASE;
+static struct udc_regs *const udc_regs_p =
+    (struct udc_regs * const)CONFIG_SYS_USBD_BASE;
+static struct udc_endp_regs *const outep_regs_p =
+    &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0];
+static struct udc_endp_regs *const inep_regs_p =
+    &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0];
+
+/*
+ * udc_state_transition - Write the next packet to TxFIFO.
+ * @initial:	Initial state.
+ * @final:	Final state.
+ *
+ * Helper function to implement device state changes. The device states and
+ * the events that transition between them are:
+ *
+ *				STATE_ATTACHED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET
+ *				||	/\
+ *				\/	||
+ *				STATE_POWERED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION
+ *				||	/\
+ *				\/	||
+ *				STATE_DEFAULT
+ *				||	/\
+ *				\/	||
+ *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET
+ *				||	/\
+ *				\/	||
+ *				STATE_ADDRESSED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED
+ *				||	/\
+ *				\/	||
+ *				STATE_CONFIGURED
+ *
+ * udc_state_transition transitions up (in the direction from STATE_ATTACHED
+ * to STATE_CONFIGURED) from the specified initial state to the specified final
+ * state, passing through each intermediate state on the way. If the initial
+ * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
+ * no state transitions will take place.
+ *
+ * udc_state_transition also transitions down (in the direction from
+ * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
+ * specified final state, passing through each intermediate state on the way.
+ * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
+ * state, then no state transitions will take place.
+ *
+ * This function must only be called with interrupts disabled.
+ */
+static void udc_state_transition(usb_device_state_t initial,
+				 usb_device_state_t final)
+{
+	if (initial < final) {
+		switch (initial) {
+		case STATE_ATTACHED:
+			usbd_device_event_irq(udc_device,
+					      DEVICE_HUB_CONFIGURED, 0);
+			if (final == STATE_POWERED)
+				break;
+		case STATE_POWERED:
+			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+			if (final == STATE_DEFAULT)
+				break;
+		case STATE_DEFAULT:
+			usbd_device_event_irq(udc_device,
+					      DEVICE_ADDRESS_ASSIGNED, 0);
+			if (final == STATE_ADDRESSED)
+				break;
+		case STATE_ADDRESSED:
+			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+		case STATE_CONFIGURED:
+			break;
+		default:
+			break;
+		}
+	} else if (initial > final) {
+		switch (initial) {
+		case STATE_CONFIGURED:
+			usbd_device_event_irq(udc_device,
+					      DEVICE_DE_CONFIGURED, 0);
+			if (final == STATE_ADDRESSED)
+				break;
+		case STATE_ADDRESSED:
+			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+			if (final == STATE_DEFAULT)
+				break;
+		case STATE_DEFAULT:
+			usbd_device_event_irq(udc_device,
+					      DEVICE_POWER_INTERRUPTION, 0);
+			if (final == STATE_POWERED)
+				break;
+		case STATE_POWERED:
+			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+		case STATE_ATTACHED:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/* Stall endpoint */
+static void udc_stall_ep(u32 ep_num)
+{
+	writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL,
+	       &inep_regs_p[ep_num].endp_cntl);
+
+	writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL,
+	       &outep_regs_p[ep_num].endp_cntl);
+}
+
+static void *get_fifo(int ep_num, int in)
+{
+	u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE;
+
+	switch (ep_num) {
+	case UDC_EP3:
+		fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn);
+		/* break intentionally left out */
+
+	case UDC_EP1:
+		fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn);
+		/* break intentionally left out */
+
+	case UDC_EP0:
+	default:
+		if (in) {
+			fifo_ptr +=
+			    readl(&outep_regs_p[2].endp_maxpacksize) >> 16;
+			/* break intentionally left out */
+		} else {
+			break;
+		}
+
+	case UDC_EP2:
+		fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16;
+		/* break intentionally left out */
+	}
+
+	return (void *)fifo_ptr;
+}
+
+static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len)
+{
+	u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0);
+	u32 i, nw, nb;
+	u32 *wrdp;
+	u8 *bytp;
+	u32 tmp[128];
+
+	if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY)
+		return -1;
+
+	nw = len / sizeof(u32);
+	nb = len % sizeof(u32);
+
+	/* use tmp buf if bufp is not word aligned */
+	if ((int)bufp & 0x3)
+		wrdp = (u32 *)&tmp[0];
+	else
+		wrdp = (u32 *)bufp;
+
+	for (i = 0; i < nw; i++) {
+		writel(readl(fifo_ptr), wrdp);
+		wrdp++;
+	}
+
+	bytp = (u8 *)wrdp;
+	for (i = 0; i < nb; i++) {
+		writeb(readb(fifo_ptr), bytp);
+		fifo_ptr++;
+		bytp++;
+	}
+	readl(&outep_regs_p[epNum].write_done);
+
+	/* copy back tmp buffer to bufp if bufp is not word aligned */
+	if ((int)bufp & 0x3)
+		memcpy(bufp, tmp, len);
+
+	return 0;
+}
+
+static void usbputpcktofifo(int epNum, u8 *bufp, u32 len)
+{
+	u32 i, nw, nb;
+	u32 *wrdp;
+	u8 *bytp;
+	u8 *fifo_ptr = get_fifo(epNum, 1);
+
+	nw = len / sizeof(int);
+	nb = len % sizeof(int);
+	wrdp = (u32 *)bufp;
+	for (i = 0; i < nw; i++) {
+		writel(*wrdp, fifo_ptr);
+		wrdp++;
+	}
+
+	bytp = (u8 *)wrdp;
+	for (i = 0; i < nb; i++) {
+		writeb(*bytp, fifo_ptr);
+		fifo_ptr++;
+		bytp++;
+	}
+}
+
+/*
+ * dw_write_noniso_tx_fifo - Write the next packet to TxFIFO.
+ * @endpoint:		Endpoint pointer.
+ *
+ * If the endpoint has an active tx_urb, then the next packet of data from the
+ * URB is written to the tx FIFO.  The total amount of data in the urb is given
+ * by urb->actual_length.  The maximum amount of data that can be sent in any
+ * one packet is given by endpoint->tx_packetSize.  The number of data bytes
+ * from this URB that have already been transmitted is given by endpoint->sent.
+ * endpoint->last is updated by this routine with the number of data bytes
+ * transmitted in this packet.
+ *
+ */
+static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance
+				       *endpoint)
+{
+	struct urb *urb = endpoint->tx_urb;
+	int align;
+
+	if (urb) {
+		u32 last;
+
+		UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d",
+			urb->buffer, urb->buffer_length, urb->actual_length);
+
+		last = min_t(u32, urb->actual_length - endpoint->sent,
+			     endpoint->tx_packetSize);
+
+		if (last) {
+			u8 *cp = urb->buffer + endpoint->sent;
+
+			/*
+			 * This ensures that USBD packet fifo is accessed
+			 * - through word aligned pointer or
+			 * - through non word aligned pointer but only
+			 *   with a max length to make the next packet
+			 *   word aligned
+			 */
+
+			align = ((ulong)cp % sizeof(int));
+			if (align)
+				last = min(last, sizeof(int) - align);
+
+			UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d",
+				endpoint->sent, endpoint->tx_packetSize, last);
+
+			usbputpcktofifo(endpoint->endpoint_address &
+					USB_ENDPOINT_NUMBER_MASK, cp, last);
+		}
+		endpoint->last = last;
+	}
+}
+
+/*
+ * Handle SETUP USB interrupt.
+ * This function implements TRM Figure 14-14.
+ */
+static void dw_udc_setup(struct usb_endpoint_instance *endpoint)
+{
+	u8 *datap = (u8 *)&ep0_urb->device_request;
+	int ep_addr = endpoint->endpoint_address;
+
+	UDCDBG("-> Entering device setup");
+	usbgetpckfromfifo(ep_addr, datap, 8);
+
+	/* Try to process setup packet */
+	if (ep0_recv_setup(ep0_urb)) {
+		/* Not a setup packet, stall next EP0 transaction */
+		udc_stall_ep(0);
+		UDCDBG("can't parse setup packet, still waiting for setup");
+		return;
+	}
+
+	/* Check direction */
+	if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
+	    == USB_REQ_HOST2DEVICE) {
+		UDCDBG("control write on EP0");
+		if (le16_to_cpu(ep0_urb->device_request.wLength)) {
+			/* Stall this request */
+			UDCDBG("Stalling unsupported EP0 control write data "
+			       "stage.");
+			udc_stall_ep(0);
+		}
+	} else {
+
+		UDCDBG("control read on EP0");
+		/*
+		 * The ep0_recv_setup function has already placed our response
+		 * packet data in ep0_urb->buffer and the packet length in
+		 * ep0_urb->actual_length.
+		 */
+		endpoint->tx_urb = ep0_urb;
+		endpoint->sent = 0;
+		/*
+		 * Write packet data to the FIFO.  dw_write_noniso_tx_fifo
+		 * will update endpoint->last with the number of bytes written
+		 * to the FIFO.
+		 */
+		dw_write_noniso_tx_fifo(endpoint);
+
+		writel(0x0, &inep_regs_p[ep_addr].write_done);
+	}
+
+	udc_unset_nak(endpoint->endpoint_address);
+
+	UDCDBG("<- Leaving device setup");
+}
+
+/*
+ * Handle endpoint 0 RX interrupt
+ */
+static void dw_udc_ep0_rx(struct usb_endpoint_instance *endpoint)
+{
+	u8 dummy[64];
+
+	UDCDBG("RX on EP0");
+
+	/* Check direction */
+	if ((ep0_urb->device_request.bmRequestType
+	     & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+		/*
+		 * This rx interrupt must be for a control write data
+		 * stage packet.
+		 *
+		 * We don't support control write data stages.
+		 * We should never end up here.
+		 */
+
+		UDCDBG("Stalling unexpected EP0 control write "
+		       "data stage packet");
+		udc_stall_ep(0);
+	} else {
+		/*
+		 * This rx interrupt must be for a control read status
+		 * stage packet.
+		 */
+		UDCDBG("ACK on EP0 control read status stage packet");
+		u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff;
+		usbgetpckfromfifo(0, dummy, len);
+	}
+}
+
+/*
+ * Handle endpoint 0 TX interrupt
+ */
+static void dw_udc_ep0_tx(struct usb_endpoint_instance *endpoint)
+{
+	struct usb_device_request *request = &ep0_urb->device_request;
+	int ep_addr;
+
+	UDCDBG("TX on EP0");
+
+	/* Check direction */
+	if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
+	    USB_REQ_HOST2DEVICE) {
+		/*
+		 * This tx interrupt must be for a control write status
+		 * stage packet.
+		 */
+		UDCDBG("ACK on EP0 control write status stage packet");
+	} else {
+		/*
+		 * This tx interrupt must be for a control read data
+		 * stage packet.
+		 */
+		int wLength = le16_to_cpu(request->wLength);
+
+		/*
+		 * Update our count of bytes sent so far in this
+		 * transfer.
+		 */
+		endpoint->sent += endpoint->last;
+
+		/*
+		 * We are finished with this transfer if we have sent
+		 * all of the bytes in our tx urb (urb->actual_length)
+		 * unless we need a zero-length terminating packet.  We
+		 * need a zero-length terminating packet if we returned
+		 * fewer bytes than were requested (wLength) by the host,
+		 * and the number of bytes we returned is an exact
+		 * multiple of the packet size endpoint->tx_packetSize.
+		 */
+		if ((endpoint->sent == ep0_urb->actual_length) &&
+		    ((ep0_urb->actual_length == wLength) ||
+		     (endpoint->last != endpoint->tx_packetSize))) {
+			/* Done with control read data stage. */
+			UDCDBG("control read data stage complete");
+		} else {
+			/*
+			 * We still have another packet of data to send
+			 * in this control read data stage or else we
+			 * need a zero-length terminating packet.
+			 */
+			UDCDBG("ACK control read data stage packet");
+			dw_write_noniso_tx_fifo(endpoint);
+
+			ep_addr = endpoint->endpoint_address;
+			writel(0x0, &inep_regs_p[ep_addr].write_done);
+		}
+	}
+}
+
+static struct usb_endpoint_instance *dw_find_ep(int ep)
+{
+	int i;
+
+	for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+		if ((udc_device->bus->endpoint_array[i].endpoint_address &
+		     USB_ENDPOINT_NUMBER_MASK) == ep)
+			return &udc_device->bus->endpoint_array[i];
+	}
+	return NULL;
+}
+
+/*
+ * Handle RX transaction on non-ISO endpoint.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 1 to 15.
+ */
+static void dw_udc_epn_rx(int ep)
+{
+	int nbytes = 0;
+	struct urb *urb;
+	struct usb_endpoint_instance *endpoint = dw_find_ep(ep);
+
+	if (endpoint) {
+		urb = endpoint->rcv_urb;
+
+		if (urb) {
+			u8 *cp = urb->buffer + urb->actual_length;
+
+			nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) &
+			    0xfff;
+			usbgetpckfromfifo(ep, cp, nbytes);
+			usbd_rcv_complete(endpoint, nbytes, 0);
+		}
+	}
+}
+
+/*
+ * Handle TX transaction on non-ISO endpoint.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 16 to 30.
+ */
+static void dw_udc_epn_tx(int ep)
+{
+	struct usb_endpoint_instance *endpoint = dw_find_ep(ep);
+
+	if (!endpoint)
+		return;
+
+	/*
+	 * We need to transmit a terminating zero-length packet now if
+	 * we have sent all of the data in this URB and the transfer
+	 * size was an exact multiple of the packet size.
+	 */
+	if (endpoint->tx_urb &&
+	    (endpoint->last == endpoint->tx_packetSize) &&
+	    (endpoint->tx_urb->actual_length - endpoint->sent -
+	     endpoint->last == 0)) {
+		/* handle zero length packet here */
+		writel(0x0, &inep_regs_p[ep].write_done);
+
+	}
+
+	if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
+		/* retire the data that was just sent */
+		usbd_tx_complete(endpoint);
+		/*
+		 * Check to see if we have more data ready to transmit
+		 * now.
+		 */
+		if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
+			/* write data to FIFO */
+			dw_write_noniso_tx_fifo(endpoint);
+			writel(0x0, &inep_regs_p[ep].write_done);
+
+		} else if (endpoint->tx_urb
+			   && (endpoint->tx_urb->actual_length == 0)) {
+			/* udc_set_nak(ep); */
+		}
+	}
+}
+
+/*
+ * Start of public functions.
+ */
+
+/* Called to start packet transmission. */
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+	udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK);
+	return 0;
+}
+
+/* Start to initialize h/w stuff */
+int udc_init(void)
+{
+	int i;
+	u32 plug_st;
+
+	udc_device = NULL;
+
+	UDCDBG("starting");
+
+	readl(&plug_regs_p->plug_pending);
+
+	for (i = 0; i < UDC_INIT_MDELAY; i++)
+		udelay(1000);
+
+	plug_st = readl(&plug_regs_p->plug_state);
+	writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state);
+
+	writel(~0x0, &udc_regs_p->endp_int);
+	writel(~0x0, &udc_regs_p->dev_int_mask);
+	writel(~0x0, &udc_regs_p->endp_int_mask);
+
+#ifndef CONFIG_USBD_HS
+	writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW |
+	       DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf);
+#else
+	writel(DEV_CONF_HS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW |
+			DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf);
+#endif
+
+	writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl);
+
+	/* Clear all interrupts pending */
+	writel(DEV_INT_MSK, &udc_regs_p->dev_int);
+
+	return 0;
+}
+
+int is_usbd_high_speed(void)
+{
+	return (readl(&udc_regs_p->dev_stat) & DEV_STAT_ENUM) ? 0 : 1;
+}
+
+/*
+ * udc_setup_ep - setup endpoint
+ * Associate a physical endpoint with endpoint_instance
+ */
+void udc_setup_ep(struct usb_device_instance *device,
+		  u32 ep, struct usb_endpoint_instance *endpoint)
+{
+	UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address);
+	int ep_addr;
+	int ep_num, ep_type;
+	int packet_size;
+	int buffer_size;
+	int attributes;
+	char *tt;
+	u32 endp_intmask;
+
+	if ((ep != 0) && (udc_device->device_state < STATE_ADDRESSED))
+		return;
+
+	tt = env_get("usbtty");
+	if (!tt)
+		tt = "generic";
+
+	ep_addr = endpoint->endpoint_address;
+	ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+	if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		/* IN endpoint */
+		packet_size = endpoint->tx_packetSize;
+		buffer_size = packet_size * 2;
+		attributes = endpoint->tx_attributes;
+	} else {
+		/* OUT endpoint */
+		packet_size = endpoint->rcv_packetSize;
+		buffer_size = packet_size * 2;
+		attributes = endpoint->rcv_attributes;
+	}
+
+	switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ep_type = ENDP_EPTYPE_CNTL;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+	default:
+		ep_type = ENDP_EPTYPE_BULK;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ep_type = ENDP_EPTYPE_INT;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		ep_type = ENDP_EPTYPE_ISO;
+		break;
+	}
+
+	struct udc_endp_regs *out_p = &outep_regs_p[ep_num];
+	struct udc_endp_regs *in_p = &inep_regs_p[ep_num];
+
+	if (!ep_addr) {
+		/* Setup endpoint 0 */
+		buffer_size = packet_size;
+
+		writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK,
+		       &in_p->endp_cntl);
+
+		writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK,
+		       &out_p->endp_cntl);
+
+		writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl);
+
+		writel(buffer_size / sizeof(int), &in_p->endp_bsorfn);
+
+		writel(packet_size, &in_p->endp_maxpacksize);
+
+		writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl);
+
+		writel(packet_size | ((buffer_size / sizeof(int)) << 16),
+		       &out_p->endp_maxpacksize);
+
+	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		/* Setup the IN endpoint */
+		writel(0x0, &in_p->endp_status);
+		writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl);
+		writel(buffer_size / sizeof(int), &in_p->endp_bsorfn);
+		writel(packet_size, &in_p->endp_maxpacksize);
+
+		if (!strcmp(tt, "cdc_acm")) {
+			if (ep_type == ENDP_EPTYPE_INT) {
+				/* Conf no. 1 Interface no. 0 */
+				writel((packet_size << 19) |
+				       ENDP_EPDIR_IN | (1 << 7) |
+				       (0 << 11) | (ep_type << 5) | ep_num,
+				       &udc_regs_p->udc_endp_reg[ep_num]);
+			} else {
+				/* Conf no. 1 Interface no. 1 */
+				writel((packet_size << 19) |
+				       ENDP_EPDIR_IN | (1 << 7) |
+				       (1 << 11) | (ep_type << 5) | ep_num,
+				       &udc_regs_p->udc_endp_reg[ep_num]);
+			}
+		} else {
+			/* Conf no. 1 Interface no. 0 */
+			writel((packet_size << 19) |
+			       ENDP_EPDIR_IN | (1 << 7) |
+			       (0 << 11) | (ep_type << 5) | ep_num,
+			       &udc_regs_p->udc_endp_reg[ep_num]);
+		}
+
+	} else {
+		/* Setup the OUT endpoint */
+		writel(0x0, &out_p->endp_status);
+		writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl);
+		writel(packet_size | ((buffer_size / sizeof(int)) << 16),
+		       &out_p->endp_maxpacksize);
+
+		if (!strcmp(tt, "cdc_acm")) {
+			writel((packet_size << 19) |
+			       ENDP_EPDIR_OUT | (1 << 7) |
+			       (1 << 11) | (ep_type << 5) | ep_num,
+			       &udc_regs_p->udc_endp_reg[ep_num]);
+		} else {
+			writel((packet_size << 19) |
+			       ENDP_EPDIR_OUT | (1 << 7) |
+			       (0 << 11) | (ep_type << 5) | ep_num,
+			       &udc_regs_p->udc_endp_reg[ep_num]);
+		}
+
+	}
+
+	endp_intmask = readl(&udc_regs_p->endp_int_mask);
+	endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num);
+	writel(endp_intmask, &udc_regs_p->endp_int_mask);
+}
+
+/* Turn on the USB connection by enabling the pullup resistor */
+void udc_connect(void)
+{
+	u32 plug_st, dev_cntl;
+
+	dev_cntl = readl(&udc_regs_p->dev_cntl);
+	dev_cntl |= DEV_CNTL_SOFTDISCONNECT;
+	writel(dev_cntl, &udc_regs_p->dev_cntl);
+
+	udelay(1000);
+
+	dev_cntl = readl(&udc_regs_p->dev_cntl);
+	dev_cntl &= ~DEV_CNTL_SOFTDISCONNECT;
+	writel(dev_cntl, &udc_regs_p->dev_cntl);
+
+	plug_st = readl(&plug_regs_p->plug_state);
+	plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE);
+	writel(plug_st, &plug_regs_p->plug_state);
+}
+
+/* Turn off the USB connection by disabling the pullup resistor */
+void udc_disconnect(void)
+{
+	u32 plug_st;
+
+	writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl);
+
+	plug_st = readl(&plug_regs_p->plug_state);
+	plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE);
+	writel(plug_st, &plug_regs_p->plug_state);
+}
+
+/* Switch on the UDC */
+void udc_enable(struct usb_device_instance *device)
+{
+	UDCDBGA("enable device %p, status %d", device, device->status);
+
+	/* Save the device structure pointer */
+	udc_device = device;
+
+	/* Setup ep0 urb */
+	if (!ep0_urb) {
+		ep0_urb =
+		    usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array);
+	} else {
+		serial_printf("udc_enable: ep0_urb already allocated %p\n",
+			      ep0_urb);
+	}
+
+	writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask);
+}
+
+/**
+ * udc_startup - allow udc code to do any additional startup
+ */
+void udc_startup_events(struct usb_device_instance *device)
+{
+	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+	usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+	/*
+	 * The DEVICE_CREATE event puts the USB device in the state
+	 * STATE_ATTACHED.
+	 */
+	usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+	/*
+	 * Some USB controller driver implementations signal
+	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+	 * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
+	 * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
+	 * The DW USB client controller has the capability to detect when the
+	 * USB cable is connected to a powered USB bus, so we will defer the
+	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later.
+	 */
+
+	udc_enable(device);
+}
+
+/*
+ * Plug detection interrupt handling
+ */
+static void dw_udc_plug_irq(void)
+{
+	if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) {
+		/*
+		 * USB cable attached
+		 * Turn off PHY reset bit (PLUG detect).
+		 * Switch PHY opmode to normal operation (PLUG detect).
+		 */
+		udc_connect();
+		writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask);
+
+		UDCDBG("device attached and powered");
+		udc_state_transition(udc_device->device_state, STATE_POWERED);
+	} else {
+		writel(~0x0, &udc_regs_p->dev_int_mask);
+
+		UDCDBG("device detached or unpowered");
+		udc_state_transition(udc_device->device_state, STATE_ATTACHED);
+	}
+}
+
+/*
+ * Device interrupt handling
+ */
+static void dw_udc_dev_irq(void)
+{
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) {
+		writel(~0x0, &udc_regs_p->endp_int_mask);
+
+		writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH,
+		       &inep_regs_p[0].endp_cntl);
+
+		writel(DEV_INT_USBRESET, &udc_regs_p->dev_int);
+
+		/*
+		 * This endpoint0 specific register can be programmed only
+		 * after the phy clock is initialized
+		 */
+		writel((EP0_MAX_PACKET_SIZE << 19) | ENDP_EPTYPE_CNTL,
+				&udc_regs_p->udc_endp_reg[0]);
+
+		UDCDBG("device reset in progess");
+		udc_state_transition(udc_device->device_state, STATE_DEFAULT);
+	}
+
+	/* Device Enumeration completed */
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) {
+		writel(DEV_INT_ENUM, &udc_regs_p->dev_int);
+
+		/* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */
+		writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001,
+		       &udc_regs_p->endp_int_mask);
+
+		UDCDBG("default -> addressed");
+		udc_state_transition(udc_device->device_state, STATE_ADDRESSED);
+	}
+
+	/* The USB will be in SUSPEND in 3 ms */
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) {
+		writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int);
+
+		UDCDBG("entering inactive state");
+		/* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */
+	}
+
+	/* SetConfiguration command received */
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) {
+		writel(DEV_INT_SETCFG, &udc_regs_p->dev_int);
+
+		UDCDBG("entering configured state");
+		udc_state_transition(udc_device->device_state,
+				     STATE_CONFIGURED);
+	}
+
+	/* SetInterface command received */
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF)
+		writel(DEV_INT_SETINTF, &udc_regs_p->dev_int);
+
+	/* USB Suspend detected on cable */
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) {
+		writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int);
+
+		UDCDBG("entering suspended state");
+		usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0);
+	}
+
+	/* USB Start-Of-Frame detected on cable */
+	if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF)
+		writel(DEV_INT_SOF, &udc_regs_p->dev_int);
+}
+
+/*
+ * Endpoint interrupt handling
+ */
+static void dw_udc_endpoint_irq(void)
+{
+	while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) {
+
+		writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int);
+
+		if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK)
+		    == ENDP_STATUS_OUT_SETUP) {
+			dw_udc_setup(udc_device->bus->endpoint_array + 0);
+			writel(ENDP_STATUS_OUT_SETUP,
+			       &outep_regs_p[0].endp_status);
+
+		} else if ((readl(&outep_regs_p[0].endp_status) &
+			    ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) {
+			dw_udc_ep0_rx(udc_device->bus->endpoint_array + 0);
+			writel(ENDP_STATUS_OUT_DATA,
+			       &outep_regs_p[0].endp_status);
+
+		} else if ((readl(&outep_regs_p[0].endp_status) &
+			    ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) {
+			/* NONE received */
+		}
+
+		writel(0x0, &outep_regs_p[0].endp_status);
+	}
+
+	if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) {
+		dw_udc_ep0_tx(udc_device->bus->endpoint_array + 0);
+
+		writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status);
+		writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int);
+	}
+
+	if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) {
+		u32 epnum = 0;
+		u32 ep_int = readl(&udc_regs_p->endp_int) &
+		    ENDP_INT_NONISOOUT_MSK;
+
+		ep_int >>= 16;
+		while (0x0 == (ep_int & 0x1)) {
+			ep_int >>= 1;
+			epnum++;
+		}
+
+		writel((1 << 16) << epnum, &udc_regs_p->endp_int);
+
+		if ((readl(&outep_regs_p[epnum].endp_status) &
+		     ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) {
+
+			dw_udc_epn_rx(epnum);
+			writel(ENDP_STATUS_OUT_DATA,
+			       &outep_regs_p[epnum].endp_status);
+		} else if ((readl(&outep_regs_p[epnum].endp_status) &
+			    ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) {
+			writel(0x0, &outep_regs_p[epnum].endp_status);
+		}
+	}
+
+	if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) {
+		u32 epnum = 0;
+		u32 ep_int = readl(&udc_regs_p->endp_int) &
+		    ENDP_INT_NONISOIN_MSK;
+
+		while (0x0 == (ep_int & 0x1)) {
+			ep_int >>= 1;
+			epnum++;
+		}
+
+		if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) {
+			writel(ENDP_STATUS_IN,
+			       &outep_regs_p[epnum].endp_status);
+			dw_udc_epn_tx(epnum);
+
+			writel(ENDP_STATUS_IN,
+			       &outep_regs_p[epnum].endp_status);
+		}
+
+		writel((1 << epnum), &udc_regs_p->endp_int);
+	}
+}
+
+/*
+ * UDC interrupts
+ */
+void udc_irq(void)
+{
+	/*
+	 * Loop while we have interrupts.
+	 * If we don't do this, the input chain
+	 * polling delay is likely to miss
+	 * host requests.
+	 */
+	while (readl(&plug_regs_p->plug_pending))
+		dw_udc_plug_irq();
+
+	while (readl(&udc_regs_p->dev_int))
+		dw_udc_dev_irq();
+
+	if (readl(&udc_regs_p->endp_int))
+		dw_udc_endpoint_irq();
+}
+
+/* Flow control */
+void udc_set_nak(int epid)
+{
+	writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK,
+	       &inep_regs_p[epid].endp_cntl);
+
+	writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK,
+	       &outep_regs_p[epid].endp_cntl);
+}
+
+void udc_unset_nak(int epid)
+{
+	u32 val;
+
+	val = readl(&inep_regs_p[epid].endp_cntl);
+	val &= ~ENDP_CNTL_SNAK;
+	val |= ENDP_CNTL_CNAK;
+	writel(val, &inep_regs_p[epid].endp_cntl);
+
+	val = readl(&outep_regs_p[epid].endp_cntl);
+	val &= ~ENDP_CNTL_SNAK;
+	val |= ENDP_CNTL_CNAK;
+	writel(val, &outep_regs_p[epid].endp_cntl);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg.c b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg.c
new file mode 100644
index 000000000..2f3181444
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg.c
@@ -0,0 +1,1199 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/usb/gadget/dwc2_udc_otg.c
+ * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2008 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ */
+#undef DEBUG
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <reset.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+
+#include <linux/errno.h>
+#include <linux/list.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+
+#include <phys2bus.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <asm/io.h>
+
+#include <asm/mach-types.h>
+
+#include <power/regulator.h>
+
+#include "dwc2_udc_otg_regs.h"
+#include "dwc2_udc_otg_priv.h"
+
+/***********************************************************/
+
+#define OTG_DMA_MODE		1
+
+#define DEBUG_SETUP 0
+#define DEBUG_EP0 0
+#define DEBUG_ISR 0
+#define DEBUG_OUT_EP 0
+#define DEBUG_IN_EP 0
+
+#include <usb/dwc2_udc.h>
+
+#define EP0_CON		0
+#define EP_MASK		0xF
+
+static char *state_names[] = {
+	"WAIT_FOR_SETUP",
+	"DATA_STATE_XMIT",
+	"DATA_STATE_NEED_ZLP",
+	"WAIT_FOR_OUT_STATUS",
+	"DATA_STATE_RECV",
+	"WAIT_FOR_COMPLETE",
+	"WAIT_FOR_OUT_COMPLETE",
+	"WAIT_FOR_IN_COMPLETE",
+	"WAIT_FOR_NULL_COMPLETE",
+};
+
+#define DRIVER_VERSION "15 March 2009"
+
+struct dwc2_udc	*the_controller;
+
+static const char driver_name[] = "dwc2-udc";
+static const char ep0name[] = "ep0-control";
+
+/* Max packet size*/
+static unsigned int ep0_fifo_size = 64;
+static unsigned int ep_fifo_size =  512;
+static unsigned int ep_fifo_size2 = 1024;
+static int reset_available = 1;
+
+static struct usb_ctrlrequest *usb_ctrl;
+static dma_addr_t usb_ctrl_dma_addr;
+
+/*
+  Local declarations.
+*/
+static int dwc2_ep_enable(struct usb_ep *ep,
+			 const struct usb_endpoint_descriptor *);
+static int dwc2_ep_disable(struct usb_ep *ep);
+static struct usb_request *dwc2_alloc_request(struct usb_ep *ep,
+					     gfp_t gfp_flags);
+static void dwc2_free_request(struct usb_ep *ep, struct usb_request *);
+
+static int dwc2_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags);
+static int dwc2_dequeue(struct usb_ep *ep, struct usb_request *);
+static int dwc2_fifo_status(struct usb_ep *ep);
+static void dwc2_fifo_flush(struct usb_ep *ep);
+static void dwc2_ep0_read(struct dwc2_udc *dev);
+static void dwc2_ep0_kick(struct dwc2_udc *dev, struct dwc2_ep *ep);
+static void dwc2_handle_ep0(struct dwc2_udc *dev);
+static int dwc2_ep0_write(struct dwc2_udc *dev);
+static int write_fifo_ep0(struct dwc2_ep *ep, struct dwc2_request *req);
+static void done(struct dwc2_ep *ep, struct dwc2_request *req, int status);
+static void stop_activity(struct dwc2_udc *dev,
+			  struct usb_gadget_driver *driver);
+static int udc_enable(struct dwc2_udc *dev);
+static void udc_set_address(struct dwc2_udc *dev, unsigned char address);
+static void reconfig_usbd(struct dwc2_udc *dev);
+static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed);
+static void nuke(struct dwc2_ep *ep, int status);
+static int dwc2_udc_set_halt(struct usb_ep *_ep, int value);
+static void dwc2_udc_set_nak(struct dwc2_ep *ep);
+
+void set_udc_gadget_private_data(void *p)
+{
+	debug_cond(DEBUG_SETUP != 0,
+		   "%s: the_controller: 0x%p, p: 0x%p\n", __func__,
+		   the_controller, p);
+	the_controller->gadget.dev.device_data = p;
+}
+
+void *get_udc_gadget_private_data(struct usb_gadget *gadget)
+{
+	return gadget->dev.device_data;
+}
+
+static struct usb_ep_ops dwc2_ep_ops = {
+	.enable = dwc2_ep_enable,
+	.disable = dwc2_ep_disable,
+
+	.alloc_request = dwc2_alloc_request,
+	.free_request = dwc2_free_request,
+
+	.queue = dwc2_queue,
+	.dequeue = dwc2_dequeue,
+
+	.set_halt = dwc2_udc_set_halt,
+	.fifo_status = dwc2_fifo_status,
+	.fifo_flush = dwc2_fifo_flush,
+};
+
+#define create_proc_files() do {} while (0)
+#define remove_proc_files() do {} while (0)
+
+/***********************************************************/
+
+struct dwc2_usbotg_reg *reg;
+
+bool dfu_usb_get_reset(void)
+{
+	return !!(readl(&reg->gintsts) & INT_RESET);
+}
+
+__weak void otg_phy_init(struct dwc2_udc *dev) {}
+__weak void otg_phy_off(struct dwc2_udc *dev) {}
+
+/***********************************************************/
+
+#include "dwc2_udc_otg_xfer_dma.c"
+
+/*
+ *	udc_disable - disable USB device controller
+ */
+static void udc_disable(struct dwc2_udc *dev)
+{
+	debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev);
+
+	udc_set_address(dev, 0);
+
+	dev->ep0state = WAIT_FOR_SETUP;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	dev->usb_address = 0;
+
+	otg_phy_off(dev);
+}
+
+/*
+ *	udc_reinit - initialize software state
+ */
+static void udc_reinit(struct dwc2_udc *dev)
+{
+	unsigned int i;
+
+	debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev);
+
+	/* device/ep0 records init */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+	dev->ep0state = WAIT_FOR_SETUP;
+
+	/* basic endpoint records init */
+	for (i = 0; i < DWC2_MAX_ENDPOINTS; i++) {
+		struct dwc2_ep *ep = &dev->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+		ep->desc = 0;
+		ep->stopped = 0;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->pio_irqs = 0;
+	}
+
+	/* the rest was statically initialized, and is read-only */
+}
+
+#define BYTES2MAXP(x)	(x / 8)
+#define MAXP2BYTES(x)	(x * 8)
+
+/* until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static int udc_enable(struct dwc2_udc *dev)
+{
+	debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev);
+
+	otg_phy_init(dev);
+	reconfig_usbd(dev);
+
+	debug_cond(DEBUG_SETUP != 0,
+		   "DWC2 USB 2.0 OTG Controller Core Initialized : 0x%x\n",
+		    readl(&reg->gintmsk));
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
+/*
+  Register entry point for the peripheral controller driver.
+*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct dwc2_udc *dev = the_controller;
+	int retval = 0;
+	unsigned long flags = 0;
+
+	debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name");
+
+	if (!driver || driver->speed < USB_SPEED_FULL
+	    || !driver->bind || !driver->disconnect || !driver->setup)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	/* first hook up the driver ... */
+	dev->driver = driver;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (retval) { /* TODO */
+		printf("target device_add failed, error %d\n", retval);
+		return retval;
+	}
+
+	retval = driver->bind(&dev->gadget);
+	if (retval) {
+		debug_cond(DEBUG_SETUP != 0,
+			   "%s: bind to driver --> error %d\n",
+			    dev->gadget.name, retval);
+		dev->driver = 0;
+		return retval;
+	}
+
+	enable_irq(IRQ_OTG);
+
+	debug_cond(DEBUG_SETUP != 0,
+		   "Registered gadget driver %s\n", dev->gadget.name);
+	udc_enable(dev);
+
+	return 0;
+}
+
+/*
+ * Unregister entry point for the peripheral controller driver.
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct dwc2_udc *dev = the_controller;
+	unsigned long flags = 0;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->driver = 0;
+	stop_activity(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	driver->unbind(&dev->gadget);
+
+	disable_irq(IRQ_OTG);
+
+	udc_disable(dev);
+	return 0;
+}
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
+static int dwc2_gadget_start(struct usb_gadget *g,
+			     struct usb_gadget_driver *driver)
+{
+	struct dwc2_udc *dev = the_controller;
+
+	debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name");
+
+	if (!driver || driver->speed < USB_SPEED_FULL ||
+	    !driver->bind || !driver->disconnect || !driver->setup)
+		return -EINVAL;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (dev->driver)
+		return -EBUSY;
+
+	/* first hook up the driver ... */
+	dev->driver = driver;
+
+	debug_cond(DEBUG_SETUP != 0,
+		   "Registered gadget driver %s\n", dev->gadget.name);
+	return udc_enable(dev);
+}
+
+static int dwc2_gadget_stop(struct usb_gadget *g)
+{
+	struct dwc2_udc *dev = the_controller;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (!dev->driver)
+		return -EINVAL;
+
+	dev->driver = 0;
+	stop_activity(dev, dev->driver);
+
+	udc_disable(dev);
+
+	return 0;
+}
+
+#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
+/*
+ *	done - retire a request; caller blocked irqs
+ */
+static void done(struct dwc2_ep *ep, struct dwc2_request *req, int status)
+{
+	unsigned int stopped = ep->stopped;
+
+	debug("%s: %s %p, req = %p, stopped = %d\n",
+	      __func__, ep->ep.name, ep, &req->req, stopped);
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	if (status && status != -ESHUTDOWN) {
+		debug("complete %s req %p stat %d len %u/%u\n",
+		      ep->ep.name, &req->req, status,
+		      req->req.actual, req->req.length);
+	}
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+
+#ifdef DEBUG
+	printf("calling complete callback\n");
+	{
+		int i, len = req->req.length;
+
+		printf("pkt[%d] = ", req->req.length);
+		if (len > 64)
+			len = 64;
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)req->req.buf)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+	spin_unlock(&ep->dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&ep->dev->lock);
+
+	debug("callback completed\n");
+
+	ep->stopped = stopped;
+}
+
+/*
+ *	nuke - dequeue ALL requests
+ */
+static void nuke(struct dwc2_ep *ep, int status)
+{
+	struct dwc2_request *req;
+
+	debug("%s: %s %p\n", __func__, ep->ep.name, ep);
+
+	/* called with irqs blocked */
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct dwc2_request, queue);
+		done(ep, req, status);
+	}
+}
+
+static void stop_activity(struct dwc2_udc *dev,
+			  struct usb_gadget_driver *driver)
+{
+	int i;
+
+	/* don't disconnect drivers more than once */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = 0;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* prevent new request submissions, kill any outstanding requests  */
+	for (i = 0; i < DWC2_MAX_ENDPOINTS; i++) {
+		struct dwc2_ep *ep = &dev->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+
+	/* re-init driver-visible data structures */
+	udc_reinit(dev);
+}
+
+static void reconfig_usbd(struct dwc2_udc *dev)
+{
+	/* 2. Soft-reset OTG Core and then unreset again. */
+	int i;
+	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
+	uint32_t dflt_gusbcfg;
+	uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
+	u32 max_hw_ep;
+	int pdata_hw_ep;
+
+	debug("Reseting OTG controller\n");
+
+	dflt_gusbcfg =
+		0<<15		/* PHY Low Power Clock sel*/
+		|1<<14		/* Non-Periodic TxFIFO Rewind Enable*/
+		|0x5<<10	/* Turnaround time*/
+		|0<<9 | 0<<8	/* [0:HNP disable,1:HNP enable][ 0:SRP disable*/
+				/* 1:SRP enable] H1= 1,1*/
+		|0<<7		/* Ulpi DDR sel*/
+		|0<<6		/* 0: high speed utmi+, 1: full speed serial*/
+		|0<<4		/* 0: utmi+, 1:ulpi*/
+#ifdef CONFIG_USB_GADGET_DWC2_OTG_PHY_BUS_WIDTH_8
+		|0<<3		/* phy i/f  0:8bit, 1:16bit*/
+#else
+		|1<<3		/* phy i/f  0:8bit, 1:16bit*/
+#endif
+		|0x7<<0;	/* HS/FS Timeout**/
+
+	if (dev->pdata->usb_gusbcfg)
+		dflt_gusbcfg = dev->pdata->usb_gusbcfg;
+
+	writel(dflt_gusbcfg, &reg->gusbcfg);
+
+	/* 3. Put the OTG device core in the disconnected state.*/
+	uTemp = readl(&reg->dctl);
+	uTemp |= SOFT_DISCONNECT;
+	writel(uTemp, &reg->dctl);
+
+	udelay(20);
+
+	/* 4. Make the OTG device core exit from the disconnected state.*/
+	uTemp = readl(&reg->dctl);
+	uTemp = uTemp & ~SOFT_DISCONNECT;
+	writel(uTemp, &reg->dctl);
+
+	/* 5. Configure OTG Core to initial settings of device mode.*/
+	/* [][1: full speed(30Mhz) 0:high speed]*/
+	writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, &reg->dcfg);
+
+	mdelay(1);
+
+	/* 6. Unmask the core interrupts*/
+	writel(GINTMSK_INIT, &reg->gintmsk);
+
+	/* 7. Set NAK bit of EP0, EP1, EP2*/
+	writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[EP0_CON].doepctl);
+	writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[EP0_CON].diepctl);
+
+	for (i = 1; i < DWC2_MAX_ENDPOINTS; i++) {
+		writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[i].doepctl);
+		writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[i].diepctl);
+	}
+
+	/* 8. Unmask EPO interrupts*/
+	writel(((1 << EP0_CON) << DAINT_OUT_BIT)
+	       | (1 << EP0_CON), &reg->daintmsk);
+
+	/* 9. Unmask device OUT EP common interrupts*/
+	writel(DOEPMSK_INIT, &reg->doepmsk);
+
+	/* 10. Unmask device IN EP common interrupts*/
+	writel(DIEPMSK_INIT, &reg->diepmsk);
+
+	rx_fifo_sz = RX_FIFO_SIZE;
+	np_tx_fifo_sz = NPTX_FIFO_SIZE;
+	tx_fifo_sz = PTX_FIFO_SIZE;
+
+	if (dev->pdata->rx_fifo_sz)
+		rx_fifo_sz = dev->pdata->rx_fifo_sz;
+	if (dev->pdata->np_tx_fifo_sz)
+		np_tx_fifo_sz = dev->pdata->np_tx_fifo_sz;
+	if (dev->pdata->tx_fifo_sz)
+		tx_fifo_sz = dev->pdata->tx_fifo_sz;
+
+	/* 11. Set Rx FIFO Size (in 32-bit words) */
+	writel(rx_fifo_sz, &reg->grxfsiz);
+
+	/* 12. Set Non Periodic Tx FIFO Size */
+	writel((np_tx_fifo_sz << 16) | rx_fifo_sz,
+	       &reg->gnptxfsiz);
+
+	/* retrieve the number of IN Endpoints (excluding ep0) */
+	max_hw_ep = (readl(&reg->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >>
+		    GHWCFG4_NUM_IN_EPS_SHIFT;
+	pdata_hw_ep = dev->pdata->tx_fifo_sz_nb;
+
+	/* tx_fifo_sz_nb should equal to number of IN Endpoint */
+	if (pdata_hw_ep && max_hw_ep != pdata_hw_ep)
+		pr_warn("Got %d hw endpoint but %d tx-fifo-size in array !!\n",
+			max_hw_ep, pdata_hw_ep);
+
+	for (i = 0; i < max_hw_ep; i++) {
+		if (pdata_hw_ep)
+			tx_fifo_sz = dev->pdata->tx_fifo_sz_array[i];
+
+		writel((rx_fifo_sz + np_tx_fifo_sz + (tx_fifo_sz * i)) |
+			tx_fifo_sz << 16, &reg->dieptxf[i]);
+	}
+	/* Flush the RX FIFO */
+	writel(RX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & RX_FIFO_FLUSH)
+		debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__);
+
+	/* Flush all the Tx FIFO's */
+	writel(TX_FIFO_FLUSH_ALL, &reg->grstctl);
+	writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
+		debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__);
+
+	/* 13. Clear NAK bit of EP0, EP1, EP2*/
+	/* For Slave mode*/
+	/* EP0: Control OUT */
+	writel(DEPCTL_EPDIS | DEPCTL_CNAK,
+	       &reg->out_endp[EP0_CON].doepctl);
+
+	/* 14. Initialize OTG Link Core.*/
+	writel(GAHBCFG_INIT, &reg->gahbcfg);
+}
+
+static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed)
+{
+	unsigned int ep_ctrl;
+	int i;
+
+	if (speed == USB_SPEED_HIGH) {
+		ep0_fifo_size = 64;
+		ep_fifo_size = 512;
+		ep_fifo_size2 = 1024;
+		dev->gadget.speed = USB_SPEED_HIGH;
+	} else {
+		ep0_fifo_size = 64;
+		ep_fifo_size = 64;
+		ep_fifo_size2 = 64;
+		dev->gadget.speed = USB_SPEED_FULL;
+	}
+
+	dev->ep[0].ep.maxpacket = ep0_fifo_size;
+	for (i = 1; i < DWC2_MAX_ENDPOINTS; i++)
+		dev->ep[i].ep.maxpacket = ep_fifo_size;
+
+	/* EP0 - Control IN (64 bytes)*/
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|(0<<0), &reg->in_endp[EP0_CON].diepctl);
+
+	/* EP0 - Control OUT (64 bytes)*/
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|(0<<0), &reg->out_endp[EP0_CON].doepctl);
+}
+
+static int dwc2_ep_enable(struct usb_ep *_ep,
+			 const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc2_ep *ep;
+	struct dwc2_udc *dev;
+	unsigned long flags = 0;
+
+	debug("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+	    || desc->bDescriptorType != USB_DT_ENDPOINT
+	    || ep->bEndpointAddress != desc->bEndpointAddress
+	    || ep_maxpacket(ep) <
+	    le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) {
+
+		debug("%s: bad ep or descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	/* xfer types must match, except that interrupt ~= bulk */
+	if (ep->bmAttributes != desc->bmAttributes
+	    && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+	    && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+
+		debug("%s: %s type mismatch\n", __func__, _ep->name);
+		return -EINVAL;
+	}
+
+	/* hardware _could_ do smaller, but driver doesn't */
+	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK &&
+	     le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) >
+	     ep_maxpacket(ep)) || !get_unaligned(&desc->wMaxPacketSize)) {
+
+		debug("%s: bad %s maxpacket\n", __func__, _ep->name);
+		return -ERANGE;
+	}
+
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+
+		debug("%s: bogus device state\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	ep->stopped = 0;
+	ep->desc = desc;
+	ep->pio_irqs = 0;
+	ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+
+	/* Reset halt state */
+	dwc2_udc_set_nak(ep);
+	dwc2_udc_set_halt(_ep, 0);
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	dwc2_udc_ep_activate(ep);
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	debug("%s: enabled %s, stopped = %d, maxpacket = %d\n",
+	      __func__, _ep->name, ep->stopped, ep->ep.maxpacket);
+	return 0;
+}
+
+/*
+ * Disable EP
+ */
+static int dwc2_ep_disable(struct usb_ep *_ep)
+{
+	struct dwc2_ep *ep;
+	unsigned long flags = 0;
+
+	debug("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	if (!_ep || !ep->desc) {
+		debug("%s: %s not enabled\n", __func__,
+		      _ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* Nuke all pending requests */
+	nuke(ep, -ESHUTDOWN);
+
+	ep->desc = 0;
+	ep->stopped = 1;
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	debug("%s: disabled %s\n", __func__, _ep->name);
+	return 0;
+}
+
+static struct usb_request *dwc2_alloc_request(struct usb_ep *ep,
+					     gfp_t gfp_flags)
+{
+	struct dwc2_request *req;
+
+	debug("%s: %s %p\n", __func__, ep->name, ep);
+
+	req = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*req));
+	if (!req)
+		return 0;
+
+	memset(req, 0, sizeof *req);
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void dwc2_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	struct dwc2_request *req;
+
+	debug("%s: %p\n", __func__, ep);
+
+	req = container_of(_req, struct dwc2_request, req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+/* dequeue JUST ONE request */
+static int dwc2_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct dwc2_ep *ep;
+	struct dwc2_request *req;
+	unsigned long flags = 0;
+
+	debug("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return 0;
+}
+
+/*
+ * Return bytes in EP FIFO
+ */
+static int dwc2_fifo_status(struct usb_ep *_ep)
+{
+	int count = 0;
+	struct dwc2_ep *ep;
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	if (!_ep) {
+		debug("%s: bad ep\n", __func__);
+		return -ENODEV;
+	}
+
+	debug("%s: %d\n", __func__, ep_index(ep));
+
+	/* LPD can't report unclaimed bytes from IN fifos */
+	if (ep_is_in(ep))
+		return -EOPNOTSUPP;
+
+	return count;
+}
+
+/*
+ * Flush EP FIFO
+ */
+static void dwc2_fifo_flush(struct usb_ep *_ep)
+{
+	struct dwc2_ep *ep;
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		debug("%s: bad ep\n", __func__);
+		return;
+	}
+
+	debug("%s: %d\n", __func__, ep_index(ep));
+}
+
+static const struct usb_gadget_ops dwc2_udc_ops = {
+	/* current versions must always be self-powered */
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+	.udc_start		= dwc2_gadget_start,
+	.udc_stop		= dwc2_gadget_stop,
+#endif
+};
+
+static struct dwc2_udc memory = {
+	.usb_address = 0,
+	.gadget = {
+		.ops = &dwc2_udc_ops,
+		.ep0 = &memory.ep[0].ep,
+		.name = driver_name,
+	},
+
+	/* control endpoint */
+	.ep[0] = {
+		.ep = {
+			.name = ep0name,
+			.ops = &dwc2_ep_ops,
+			.maxpacket = EP0_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = 0,
+		.bmAttributes = 0,
+
+		.ep_type = ep_control,
+	},
+
+	/* first group of endpoints */
+	.ep[1] = {
+		.ep = {
+			.name = "ep1in-bulk",
+			.ops = &dwc2_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_IN | 1,
+		.bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+		.ep_type = ep_bulk_out,
+		.fifo_num = 1,
+	},
+
+	.ep[2] = {
+		.ep = {
+			.name = "ep2out-bulk",
+			.ops = &dwc2_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_OUT | 2,
+		.bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+		.ep_type = ep_bulk_in,
+		.fifo_num = 2,
+	},
+
+	.ep[3] = {
+		.ep = {
+			.name = "ep3in-int",
+			.ops = &dwc2_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_IN | 3,
+		.bmAttributes = USB_ENDPOINT_XFER_INT,
+
+		.ep_type = ep_interrupt,
+		.fifo_num = 3,
+	},
+};
+
+/*
+ *	probe - binds to the platform device
+ */
+
+int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata)
+{
+	struct dwc2_udc *dev = &memory;
+	int retval = 0;
+
+	debug("%s: %p\n", __func__, pdata);
+
+	dev->pdata = pdata;
+
+	reg = (struct dwc2_usbotg_reg *)pdata->regs_otg;
+
+	dev->gadget.is_dualspeed = 1;	/* Hack only*/
+	dev->gadget.is_otg = 0;
+	dev->gadget.is_a_peripheral = 0;
+	dev->gadget.b_hnp_enable = 0;
+	dev->gadget.a_hnp_support = 0;
+	dev->gadget.a_alt_hnp_support = 0;
+
+	the_controller = dev;
+
+	usb_ctrl = memalign(CONFIG_SYS_CACHELINE_SIZE,
+			    ROUND(sizeof(struct usb_ctrlrequest),
+				  CONFIG_SYS_CACHELINE_SIZE));
+	if (!usb_ctrl) {
+		pr_err("No memory available for UDC!\n");
+		return -ENOMEM;
+	}
+
+	usb_ctrl_dma_addr = (dma_addr_t) usb_ctrl;
+
+	udc_reinit(dev);
+
+	return retval;
+}
+
+int dwc2_udc_handle_interrupt(void)
+{
+	u32 intr_status = readl(&reg->gintsts);
+	u32 gintmsk = readl(&reg->gintmsk);
+
+	if (intr_status & gintmsk)
+		return dwc2_udc_irq(1, (void *)the_controller);
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
+
+int usb_gadget_handle_interrupts(int index)
+{
+	return dwc2_udc_handle_interrupt();
+}
+
+#else /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
+struct dwc2_priv_data {
+	struct clk_bulk		clks;
+	struct reset_ctl_bulk	resets;
+	struct phy_bulk phys;
+	struct udevice *usb33d_supply;
+};
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	return dwc2_udc_handle_interrupt();
+}
+
+static int dwc2_phy_setup(struct udevice *dev, struct phy_bulk *phys)
+{
+	int ret;
+
+	ret = generic_phy_get_bulk(dev, phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_init_bulk(phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on_bulk(phys);
+	if (ret)
+		generic_phy_exit_bulk(phys);
+
+	return ret;
+}
+
+static void dwc2_phy_shutdown(struct udevice *dev, struct phy_bulk *phys)
+{
+	generic_phy_power_off_bulk(phys);
+	generic_phy_exit_bulk(phys);
+}
+
+static int dwc2_udc_otg_of_to_plat(struct udevice *dev)
+{
+	struct dwc2_plat_otg_data *plat = dev_get_plat(dev);
+	ulong drvdata;
+	void (*set_params)(struct dwc2_plat_otg_data *data);
+	int ret;
+
+	if (usb_get_dr_mode(dev_ofnode(dev)) != USB_DR_MODE_PERIPHERAL &&
+	    usb_get_dr_mode(dev_ofnode(dev)) != USB_DR_MODE_OTG) {
+		dev_dbg(dev, "Invalid mode\n");
+		return -ENODEV;
+	}
+
+	plat->regs_otg = dev_read_addr(dev);
+
+	plat->rx_fifo_sz = dev_read_u32_default(dev, "g-rx-fifo-size", 0);
+	plat->np_tx_fifo_sz = dev_read_u32_default(dev, "g-np-tx-fifo-size", 0);
+
+	plat->tx_fifo_sz_nb =
+		dev_read_size(dev, "g-tx-fifo-size") / sizeof(u32);
+	if (plat->tx_fifo_sz_nb > DWC2_MAX_HW_ENDPOINTS)
+		plat->tx_fifo_sz_nb = DWC2_MAX_HW_ENDPOINTS;
+	if (plat->tx_fifo_sz_nb) {
+		ret = dev_read_u32_array(dev, "g-tx-fifo-size",
+					 plat->tx_fifo_sz_array,
+					 plat->tx_fifo_sz_nb);
+		if (ret)
+			return ret;
+	}
+
+	plat->force_b_session_valid =
+		dev_read_bool(dev, "u-boot,force-b-session-valid");
+
+	plat->force_vbus_detection =
+		dev_read_bool(dev, "u-boot,force-vbus-detection");
+
+	/* force plat according compatible */
+	drvdata = dev_get_driver_data(dev);
+	if (drvdata) {
+		set_params = (void *)drvdata;
+		set_params(plat);
+	}
+
+	return 0;
+}
+
+static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_plat_otg_data *p)
+{
+	p->activate_stm_id_vb_detection = true;
+	p->usb_gusbcfg =
+		0 << 15		/* PHY Low Power Clock sel*/
+		| 0x9 << 10	/* USB Turnaround time (0x9 for HS phy) */
+		| 0 << 9	/* [0:HNP disable,1:HNP enable]*/
+		| 0 << 8	/* [0:SRP disable 1:SRP enable]*/
+		| 0 << 6	/* 0: high speed utmi+, 1: full speed serial*/
+		| 0x7 << 0;	/* FS timeout calibration**/
+
+	if (p->force_b_session_valid)
+		p->usb_gusbcfg |= 1 << 30; /* FDMOD: Force device mode */
+}
+
+static int dwc2_udc_otg_reset_init(struct udevice *dev,
+				   struct reset_ctl_bulk *resets)
+{
+	int ret;
+
+	ret = reset_get_bulk(dev, resets);
+	if (ret == -ENOTSUPP || ret == -ENOENT)
+		return 0;
+
+	if (ret)
+		return ret;
+
+	ret = reset_assert_bulk(resets);
+
+	if (!ret) {
+		udelay(2);
+		ret = reset_deassert_bulk(resets);
+	}
+	if (ret) {
+		reset_release_bulk(resets);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc2_udc_otg_clk_init(struct udevice *dev,
+				 struct clk_bulk *clks)
+{
+	int ret;
+
+	ret = clk_get_bulk(dev, clks);
+	if (ret == -ENOSYS)
+		return 0;
+
+	if (ret)
+		return ret;
+
+	ret = clk_enable_bulk(clks);
+	if (ret) {
+		clk_release_bulk(clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc2_udc_otg_probe(struct udevice *dev)
+{
+	struct dwc2_plat_otg_data *plat = dev_get_plat(dev);
+	struct dwc2_priv_data *priv = dev_get_priv(dev);
+	struct dwc2_usbotg_reg *usbotg_reg =
+		(struct dwc2_usbotg_reg *)plat->regs_otg;
+	int ret;
+
+	ret = dwc2_udc_otg_clk_init(dev, &priv->clks);
+	if (ret)
+		return ret;
+
+	ret = dwc2_udc_otg_reset_init(dev, &priv->resets);
+	if (ret)
+		return ret;
+
+	ret = dwc2_phy_setup(dev, &priv->phys);
+	if (ret)
+		return ret;
+
+	if (plat->activate_stm_id_vb_detection) {
+		if (CONFIG_IS_ENABLED(DM_REGULATOR) &&
+		    (!plat->force_b_session_valid ||
+		     plat->force_vbus_detection)) {
+			ret = device_get_supply_regulator(dev, "usb33d-supply",
+							  &priv->usb33d_supply);
+			if (ret) {
+				dev_err(dev, "can't get voltage level detector supply\n");
+				return ret;
+			}
+			ret = regulator_set_enable(priv->usb33d_supply, true);
+			if (ret) {
+				dev_err(dev, "can't enable voltage level detector supply\n");
+				return ret;
+			}
+		}
+
+		if (plat->force_b_session_valid &&
+		    !plat->force_vbus_detection) {
+			/* Override VBUS detection: enable then value*/
+			setbits_le32(&usbotg_reg->gotgctl, VB_VALOEN);
+			setbits_le32(&usbotg_reg->gotgctl, VB_VALOVAL);
+		} else {
+			/* Enable VBUS sensing */
+			setbits_le32(&usbotg_reg->ggpio,
+				     GGPIO_STM32_OTG_GCCFG_VBDEN);
+		}
+		if (plat->force_b_session_valid) {
+			/* Override B session bits: enable then value */
+			setbits_le32(&usbotg_reg->gotgctl, A_VALOEN | B_VALOEN);
+			setbits_le32(&usbotg_reg->gotgctl,
+				     A_VALOVAL | B_VALOVAL);
+		} else {
+			/* Enable ID detection */
+			setbits_le32(&usbotg_reg->ggpio,
+				     GGPIO_STM32_OTG_GCCFG_IDEN);
+		}
+	}
+
+	ret = dwc2_udc_probe(plat);
+	if (ret)
+		return ret;
+
+	the_controller->driver = 0;
+
+	ret = usb_add_gadget_udc((struct device *)dev, &the_controller->gadget);
+
+	return ret;
+}
+
+static int dwc2_udc_otg_remove(struct udevice *dev)
+{
+	struct dwc2_priv_data *priv = dev_get_priv(dev);
+
+	usb_del_gadget_udc(&the_controller->gadget);
+
+	reset_release_bulk(&priv->resets);
+
+	clk_release_bulk(&priv->clks);
+
+	dwc2_phy_shutdown(dev, &priv->phys);
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id dwc2_udc_otg_ids[] = {
+	{ .compatible = "snps,dwc2" },
+	{ .compatible = "brcm,bcm2835-usb" },
+	{ .compatible = "st,stm32mp15-hsotg",
+	  .data = (ulong)dwc2_set_stm32mp1_hsotg_params },
+	{},
+};
+
+U_BOOT_DRIVER(dwc2_udc_otg) = {
+	.name	= "dwc2-udc-otg",
+	.id	= UCLASS_USB_GADGET_GENERIC,
+	.of_match = dwc2_udc_otg_ids,
+	.of_to_plat = dwc2_udc_otg_of_to_plat,
+	.probe = dwc2_udc_otg_probe,
+	.remove = dwc2_udc_otg_remove,
+	.plat_auto	= sizeof(struct dwc2_plat_otg_data),
+	.priv_auto	= sizeof(struct dwc2_priv_data),
+};
+
+int dwc2_udc_B_session_valid(struct udevice *dev)
+{
+	struct dwc2_plat_otg_data *plat = dev_get_plat(dev);
+	struct dwc2_usbotg_reg *usbotg_reg =
+		(struct dwc2_usbotg_reg *)plat->regs_otg;
+
+	return readl(&usbotg_reg->gotgctl) & B_SESSION_VALID;
+}
+#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
diff --git a/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_phy.c b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_phy.c
new file mode 100644
index 000000000..7f8e9564b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_phy.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/usb/gadget/dwc2_udc_otg.c
+ * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2008 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ */
+
+#include <common.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <asm/io.h>
+
+#include <asm/mach-types.h>
+
+#include "dwc2_udc_otg_regs.h"
+#include "dwc2_udc_otg_priv.h"
+
+#include <usb/dwc2_udc.h>
+
+void otg_phy_init(struct dwc2_udc *dev)
+{
+	unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl;
+	struct dwc2_usbotg_phy *phy =
+		(struct dwc2_usbotg_phy *)dev->pdata->regs_phy;
+
+	dev->pdata->phy_control(1);
+
+	/* USB PHY0 Enable */
+	printf("USB PHY0 Enable\n");
+
+	/* Enable PHY */
+	writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+	if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */
+		writel((readl(&phy->phypwr)
+			&~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN)
+			&~FORCE_SUSPEND_0), &phy->phypwr);
+	else /* C110 GONI */
+		writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
+			&~FORCE_SUSPEND_0), &phy->phypwr);
+
+	if (s5p_cpu_id == 0x4412)
+		writel((readl(&phy->phyclk) & ~(EXYNOS4X12_ID_PULLUP0 |
+			EXYNOS4X12_COMMON_ON_N0)) | EXYNOS4X12_CLK_SEL_24MHZ,
+		       &phy->phyclk); /* PLL 24Mhz */
+	else
+		writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)) |
+		       CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
+
+	writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST))
+	       | PHY_SW_RST0, &phy->rstcon);
+	udelay(10);
+	writel(readl(&phy->rstcon)
+	       &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon);
+	udelay(10);
+}
+
+void otg_phy_off(struct dwc2_udc *dev)
+{
+	unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl;
+	struct dwc2_usbotg_phy *phy =
+		(struct dwc2_usbotg_phy *)dev->pdata->regs_phy;
+
+	/* reset controller just in case */
+	writel(PHY_SW_RST0, &phy->rstcon);
+	udelay(20);
+	writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon);
+	udelay(20);
+
+	writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN
+	       | FORCE_SUSPEND_0, &phy->phypwr);
+
+	writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+	writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)),
+	      &phy->phyclk);
+
+	udelay(10000);
+
+	dev->pdata->phy_control(0);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_priv.h b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_priv.h
new file mode 100644
index 000000000..e72b22ac6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_priv.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Designware DWC2 on-chip full/high speed USB device controllers
+ * Copyright (C) 2005 for Samsung Electronics
+ */
+
+#ifndef __DWC2_UDC_OTG_PRIV__
+#define __DWC2_UDC_OTG_PRIV__
+
+#include <linux/errno.h>
+#include <linux/sizes.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/list.h>
+#include <usb/dwc2_udc.h>
+
+/*-------------------------------------------------------------------------*/
+/* DMA bounce buffer size, 16K is enough even for mass storage */
+#define DMA_BUFFER_SIZE	(16*SZ_1K)
+
+#define EP0_FIFO_SIZE		64
+#define EP_FIFO_SIZE		512
+#define EP_FIFO_SIZE2		1024
+/* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */
+#define DWC2_MAX_ENDPOINTS	4
+
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_NEED_ZLP     2
+#define WAIT_FOR_OUT_STATUS     3
+#define DATA_STATE_RECV         4
+#define WAIT_FOR_COMPLETE	5
+#define WAIT_FOR_OUT_COMPLETE	6
+#define WAIT_FOR_IN_COMPLETE	7
+#define WAIT_FOR_NULL_COMPLETE	8
+
+#define TEST_J_SEL		0x1
+#define TEST_K_SEL		0x2
+#define TEST_SE0_NAK_SEL	0x3
+#define TEST_PACKET_SEL		0x4
+#define TEST_FORCE_ENABLE_SEL	0x5
+
+/* ************************************************************************* */
+/* IO
+ */
+
+enum ep_type {
+	ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
+};
+
+struct dwc2_ep {
+	struct usb_ep ep;
+	struct dwc2_udc *dev;
+
+	const struct usb_endpoint_descriptor *desc;
+	struct list_head queue;
+	unsigned long pio_irqs;
+	int len;
+	void *dma_buf;
+
+	u8 stopped;
+	u8 bEndpointAddress;
+	u8 bmAttributes;
+
+	enum ep_type ep_type;
+	int fifo_num;
+};
+
+struct dwc2_request {
+	struct usb_request req;
+	struct list_head queue;
+};
+
+struct dwc2_udc {
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+
+	struct dwc2_plat_otg_data *pdata;
+
+	int ep0state;
+	struct dwc2_ep ep[DWC2_MAX_ENDPOINTS];
+
+	unsigned char usb_address;
+
+	unsigned req_pending:1, req_std:1;
+};
+
+#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN)
+#define ep_index(EP) ((EP)->bEndpointAddress&0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+
+void otg_phy_init(struct dwc2_udc *dev);
+void otg_phy_off(struct dwc2_udc *dev);
+
+#endif	/* __DWC2_UDC_OTG_PRIV__ */
diff --git a/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_regs.h b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_regs.h
new file mode 100644
index 000000000..9ca6f4237
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_regs.h
@@ -0,0 +1,296 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* linux/arch/arm/plat-s3c/include/plat/regs-otg.h
+ *
+ * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
+ *
+ * Registers remapping:
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ */
+
+#ifndef __ASM_ARCH_REGS_USB_OTG_HS_H
+#define __ASM_ARCH_REGS_USB_OTG_HS_H
+
+/* USB2.0 OTG Controller register */
+#include <linux/bitops.h>
+struct dwc2_usbotg_phy {
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+};
+
+/* Device Logical IN Endpoint-Specific Registers */
+struct dwc2_dev_in_endp {
+	u32 diepctl;
+	u8  res1[4];
+	u32 diepint;
+	u8  res2[4];
+	u32 dieptsiz;
+	u32 diepdma;
+	u8  res3[4];
+	u32 diepdmab;
+};
+
+/* Device Logical OUT Endpoint-Specific Registers */
+struct dwc2_dev_out_endp {
+	u32 doepctl;
+	u8  res1[4];
+	u32 doepint;
+	u8  res2[4];
+	u32 doeptsiz;
+	u32 doepdma;
+	u8  res3[4];
+	u32 doepdmab;
+};
+
+struct ep_fifo {
+	u32 fifo;
+	u8  res[4092];
+};
+
+/* USB2.0 OTG Controller register */
+struct dwc2_usbotg_reg {
+	/* Core Global Registers */
+	u32 gotgctl; /* OTG Control & Status */
+	u32 gotgint; /* OTG Interrupt */
+	u32 gahbcfg; /* Core AHB Configuration */
+	u32 gusbcfg; /* Core USB Configuration */
+	u32 grstctl; /* Core Reset */
+	u32 gintsts; /* Core Interrupt */
+	u32 gintmsk; /* Core Interrupt Mask */
+	u32 grxstsr; /* Receive Status Debug Read/Status Read */
+	u32 grxstsp; /* Receive Status Debug Pop/Status Pop */
+	u32 grxfsiz; /* Receive FIFO Size */
+	u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
+	u8  res0[12];
+	u32 ggpio;     /* 0x038 */
+	u8  res1[20];
+	u32 ghwcfg4; /* User HW Config4 */
+	u8  res2[176];
+	u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
+	u8  res3[1728];
+	/* Device Configuration */
+	u32 dcfg; /* Device Configuration Register */
+	u32 dctl; /* Device Control */
+	u32 dsts; /* Device Status */
+	u8  res4[4];
+	u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
+	u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
+	u32 daint; /* Device All Endpoints Interrupt */
+	u32 daintmsk; /* Device All Endpoints Interrupt Mask */
+	u8  res5[224];
+	struct dwc2_dev_in_endp in_endp[16];
+	struct dwc2_dev_out_endp out_endp[16];
+	u8  res6[768];
+	struct ep_fifo ep[16];
+};
+
+/*===================================================================== */
+/*definitions related to CSR setting */
+
+/* DWC2_UDC_OTG_GOTGCTL */
+#define B_SESSION_VALID			BIT(19)
+#define A_SESSION_VALID			BIT(18)
+#define B_VALOVAL			BIT(7)
+#define B_VALOEN			BIT(6)
+#define A_VALOVAL			BIT(5)
+#define A_VALOEN			BIT(4)
+#define VB_VALOVAL			BIT(3)
+#define VB_VALOEN			BIT(2)
+
+/* DWC2_UDC_OTG_GOTINT */
+#define GOTGINT_SES_END_DET		(1<<2)
+
+/* DWC2_UDC_OTG_GAHBCFG */
+#define PTXFE_HALF			(0<<8)
+#define PTXFE_ZERO			(1<<8)
+#define NPTXFE_HALF			(0<<7)
+#define NPTXFE_ZERO			(1<<7)
+#define MODE_SLAVE			(0<<5)
+#define MODE_DMA			(1<<5)
+#define BURST_SINGLE			(0<<1)
+#define BURST_INCR			(1<<1)
+#define BURST_INCR4			(3<<1)
+#define BURST_INCR8			(5<<1)
+#define BURST_INCR16			(7<<1)
+#define GBL_INT_UNMASK			(1<<0)
+#define GBL_INT_MASK			(0<<0)
+
+/* DWC2_UDC_OTG_GRSTCTL */
+#define AHB_MASTER_IDLE		(1u<<31)
+#define CORE_SOFT_RESET		(0x1<<0)
+
+/* DWC2_UDC_OTG_GINTSTS/DWC2_UDC_OTG_GINTMSK core interrupt register */
+#define INT_RESUME			(1u<<31)
+#define INT_DISCONN			(0x1<<29)
+#define INT_CONN_ID_STS_CNG		(0x1<<28)
+#define INT_OUT_EP			(0x1<<19)
+#define INT_IN_EP			(0x1<<18)
+#define INT_ENUMDONE			(0x1<<13)
+#define INT_RESET			(0x1<<12)
+#define INT_SUSPEND			(0x1<<11)
+#define INT_EARLY_SUSPEND		(0x1<<10)
+#define INT_NP_TX_FIFO_EMPTY		(0x1<<5)
+#define INT_RX_FIFO_NOT_EMPTY		(0x1<<4)
+#define INT_SOF			(0x1<<3)
+#define INT_OTG			(0x1<<2)
+#define INT_DEV_MODE			(0x0<<0)
+#define INT_HOST_MODE			(0x1<<1)
+#define INT_GOUTNakEff			(0x01<<7)
+#define INT_GINNakEff			(0x01<<6)
+
+#define FULL_SPEED_CONTROL_PKT_SIZE	8
+#define FULL_SPEED_BULK_PKT_SIZE	64
+
+#define HIGH_SPEED_CONTROL_PKT_SIZE	64
+#define HIGH_SPEED_BULK_PKT_SIZE	512
+
+#define RX_FIFO_SIZE			(1024)
+#define NPTX_FIFO_SIZE			(1024)
+#define PTX_FIFO_SIZE			(384)
+
+#define DEPCTL_TXFNUM_0		(0x0<<22)
+#define DEPCTL_TXFNUM_1		(0x1<<22)
+#define DEPCTL_TXFNUM_2		(0x2<<22)
+#define DEPCTL_TXFNUM_3		(0x3<<22)
+#define DEPCTL_TXFNUM_4		(0x4<<22)
+
+/* Enumeration speed */
+#define USB_HIGH_30_60MHZ		(0x0<<1)
+#define USB_FULL_30_60MHZ		(0x1<<1)
+#define USB_LOW_6MHZ			(0x2<<1)
+#define USB_FULL_48MHZ			(0x3<<1)
+
+/* DWC2_UDC_OTG_GRXSTSP STATUS */
+#define OUT_PKT_RECEIVED		(0x2<<17)
+#define OUT_TRANSFER_COMPLELTED	(0x3<<17)
+#define SETUP_TRANSACTION_COMPLETED	(0x4<<17)
+#define SETUP_PKT_RECEIVED		(0x6<<17)
+#define GLOBAL_OUT_NAK			(0x1<<17)
+
+/* DWC2_UDC_OTG_DCTL device control register */
+#define NORMAL_OPERATION		(0x1<<0)
+#define SOFT_DISCONNECT		(0x1<<1)
+
+/* DWC2_UDC_OTG_DAINT device all endpoint interrupt register */
+#define DAINT_OUT_BIT			(16)
+#define DAINT_MASK			(0xFFFF)
+
+/* DWC2_UDC_OTG_DIEPCTL0/DOEPCTL0 device
+   control IN/OUT endpoint 0 control register */
+#define DEPCTL_EPENA			(0x1<<31)
+#define DEPCTL_EPDIS			(0x1<<30)
+#define DEPCTL_SETD1PID		(0x1<<29)
+#define DEPCTL_SETD0PID		(0x1<<28)
+#define DEPCTL_SNAK			(0x1<<27)
+#define DEPCTL_CNAK			(0x1<<26)
+#define DEPCTL_STALL			(0x1<<21)
+#define DEPCTL_TYPE_BIT		(18)
+#define DEPCTL_TYPE_MASK		(0x3<<18)
+#define DEPCTL_CTRL_TYPE		(0x0<<18)
+#define DEPCTL_ISO_TYPE		(0x1<<18)
+#define DEPCTL_BULK_TYPE		(0x2<<18)
+#define DEPCTL_INTR_TYPE		(0x3<<18)
+#define DEPCTL_USBACTEP		(0x1<<15)
+#define DEPCTL_NEXT_EP_BIT		(11)
+#define DEPCTL_MPS_BIT			(0)
+#define DEPCTL_MPS_MASK		(0x7FF)
+
+#define DEPCTL0_MPS_64			(0x0<<0)
+#define DEPCTL0_MPS_32			(0x1<<0)
+#define DEPCTL0_MPS_16			(0x2<<0)
+#define DEPCTL0_MPS_8			(0x3<<0)
+#define DEPCTL_MPS_BULK_512		(512<<0)
+#define DEPCTL_MPS_INT_MPS_16		(16<<0)
+
+#define DIEPCTL0_NEXT_EP_BIT		(11)
+
+
+/* DWC2_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint
+   common interrupt mask register */
+/* DWC2_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */
+#define BACK2BACK_SETUP_RECEIVED	(0x1<<6)
+#define INTKNEPMIS			(0x1<<5)
+#define INTKN_TXFEMP			(0x1<<4)
+#define NON_ISO_IN_EP_TIMEOUT		(0x1<<3)
+#define CTRL_OUT_EP_SETUP_PHASE_DONE	(0x1<<3)
+#define AHB_ERROR			(0x1<<2)
+#define EPDISBLD			(0x1<<1)
+#define TRANSFER_DONE			(0x1<<0)
+
+#define USB_PHY_CTRL_EN0                (0x1 << 0)
+
+/* OPHYPWR */
+#define PHY_0_SLEEP                     (0x1 << 5)
+#define OTG_DISABLE_0                   (0x1 << 4)
+#define ANALOG_PWRDOWN                  (0x1 << 3)
+#define FORCE_SUSPEND_0                 (0x1 << 0)
+
+/* URSTCON */
+#define HOST_SW_RST                     (0x1 << 4)
+#define PHY_SW_RST1                     (0x1 << 3)
+#define PHYLNK_SW_RST                   (0x1 << 2)
+#define LINK_SW_RST                     (0x1 << 1)
+#define PHY_SW_RST0                     (0x1 << 0)
+
+/* OPHYCLK */
+#define COMMON_ON_N1                    (0x1 << 7)
+#define COMMON_ON_N0                    (0x1 << 4)
+#define ID_PULLUP0                      (0x1 << 2)
+#define CLK_SEL_24MHZ                   (0x3 << 0)
+#define CLK_SEL_12MHZ                   (0x2 << 0)
+#define CLK_SEL_48MHZ                   (0x0 << 0)
+
+#define EXYNOS4X12_ID_PULLUP0		(0x01 << 3)
+#define EXYNOS4X12_COMMON_ON_N0	(0x01 << 4)
+#define EXYNOS4X12_CLK_SEL_12MHZ	(0x02 << 0)
+#define EXYNOS4X12_CLK_SEL_24MHZ	(0x05 << 0)
+
+/* Device Configuration Register DCFG */
+#define DEV_SPEED_HIGH_SPEED_20         (0x0 << 0)
+#define DEV_SPEED_FULL_SPEED_20         (0x1 << 0)
+#define DEV_SPEED_LOW_SPEED_11          (0x2 << 0)
+#define DEV_SPEED_FULL_SPEED_11         (0x3 << 0)
+#define EP_MISS_CNT(x)                  (x << 18)
+#define DEVICE_ADDRESS(x)               (x << 4)
+
+/* Core Reset Register (GRSTCTL) */
+#define TX_FIFO_FLUSH                   (0x1 << 5)
+#define RX_FIFO_FLUSH                   (0x1 << 4)
+#define TX_FIFO_NUMBER(x)               (x << 6)
+#define TX_FIFO_FLUSH_ALL               TX_FIFO_NUMBER(0x10)
+
+/* Masks definitions */
+#define GINTMSK_INIT	(INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
+			| INT_RESET | INT_SUSPEND | INT_OTG)
+#define DOEPMSK_INIT	(CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE)
+#define DIEPMSK_INIT	(NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
+#define GAHBCFG_INIT	(PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\
+			| GBL_INT_UNMASK)
+
+/* Device Endpoint X Transfer Size Register (DIEPTSIZX) */
+#define DIEPT_SIZ_PKT_CNT(x)                      (x << 19)
+#define DIEPT_SIZ_XFER_SIZE(x)                    (x << 0)
+
+/* Device OUT Endpoint X Transfer Size Register (DOEPTSIZX) */
+#define DOEPT_SIZ_PKT_CNT(x)                      (x << 19)
+#define DOEPT_SIZ_XFER_SIZE(x)                    (x << 0)
+#define DOEPT_SIZ_XFER_SIZE_MAX_EP0               (0x7F << 0)
+#define DOEPT_SIZ_XFER_SIZE_MAX_EP                (0x7FFF << 0)
+
+/* Device Endpoint-N Control Register (DIEPCTLn/DOEPCTLn) */
+#define DIEPCTL_TX_FIFO_NUM(x)                    (x << 22)
+#define DIEPCTL_TX_FIFO_NUM_MASK                  (~DIEPCTL_TX_FIFO_NUM(0xF))
+
+/* Device ALL Endpoints Interrupt Register (DAINT) */
+#define DAINT_IN_EP_INT(x)                        (x << 0)
+#define DAINT_OUT_EP_INT(x)                       (x << 16)
+
+/* User HW Config4 */
+#define GHWCFG4_NUM_IN_EPS_MASK		(0xf << 26)
+#define GHWCFG4_NUM_IN_EPS_SHIFT	26
+
+/* OTG general core configuration register (OTG_GCCFG:0x38) for STM32MP1 */
+#define GGPIO_STM32_OTG_GCCFG_VBDEN               BIT(21)
+#define GGPIO_STM32_OTG_GCCFG_IDEN                BIT(22)
+
+#endif
diff --git a/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
new file mode 100644
index 000000000..f17009a29
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
@@ -0,0 +1,1508 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
+ * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2009 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <linux/bug.h>
+
+static u8 clear_feature_num;
+int clear_feature_flag;
+
+/* Bulk-Only Mass Storage Reset (class-specific request) */
+#define GET_MAX_LUN_REQUEST	0xFE
+#define BOT_RESET_REQUEST	0xFF
+
+static inline void dwc2_udc_ep0_zlp(struct dwc2_udc *dev)
+{
+	u32 ep_ctrl;
+
+	writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), &reg->in_endp[EP0_CON].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(1), &reg->in_endp[EP0_CON].dieptsiz);
+
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->in_endp[EP0_CON].diepctl);
+
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	dev->ep0state = WAIT_FOR_IN_COMPLETE;
+}
+
+static void dwc2_udc_pre_setup(void)
+{
+	u32 ep_ctrl;
+
+	debug_cond(DEBUG_IN_EP,
+		   "%s : Prepare Setup packets.\n", __func__);
+
+	writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
+	       &reg->out_endp[EP0_CON].doeptsiz);
+	writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), &reg->out_endp[EP0_CON].doepdma);
+
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|DEPCTL_EPENA, &reg->out_endp[EP0_CON].doepctl);
+
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+}
+
+static inline void dwc2_ep0_complete_out(void)
+{
+	u32 ep_ctrl;
+
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+	debug_cond(DEBUG_IN_EP,
+		"%s : Prepare Complete Out packet.\n", __func__);
+
+	writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
+	       &reg->out_endp[EP0_CON].doeptsiz);
+	writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), &reg->out_endp[EP0_CON].doepdma);
+
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->out_endp[EP0_CON].doepctl);
+
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+}
+
+
+static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req)
+{
+	u32 *buf, ctrl;
+	u32 length, pktcnt;
+	u32 ep_num = ep_index(ep);
+
+	buf = req->req.buf + req->req.actual;
+	length = min_t(u32, req->req.length - req->req.actual,
+		       ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket);
+
+	ep->len = length;
+	ep->dma_buf = buf;
+
+	if (ep_num == EP0_CON || length == 0)
+		pktcnt = 1;
+	else
+		pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+	ctrl =  readl(&reg->out_endp[ep_num].doepctl);
+
+	invalidate_dcache_range((unsigned long) ep->dma_buf,
+				(unsigned long) ep->dma_buf +
+				ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE));
+
+	writel(phys_to_bus((unsigned long)ep->dma_buf), &reg->out_endp[ep_num].doepdma);
+	writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length),
+	       &reg->out_endp[ep_num].doeptsiz);
+	writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->out_endp[ep_num].doepctl);
+
+	debug_cond(DEBUG_OUT_EP != 0,
+		   "%s: EP%d RX DMA start : DOEPDMA = 0x%x,"
+		   "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n"
+		   "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+		   __func__, ep_num,
+		   readl(&reg->out_endp[ep_num].doepdma),
+		   readl(&reg->out_endp[ep_num].doeptsiz),
+		   readl(&reg->out_endp[ep_num].doepctl),
+		   buf, pktcnt, length);
+	return 0;
+
+}
+
+static int setdma_tx(struct dwc2_ep *ep, struct dwc2_request *req)
+{
+	u32 *buf, ctrl = 0;
+	u32 length, pktcnt;
+	u32 ep_num = ep_index(ep);
+
+	buf = req->req.buf + req->req.actual;
+	length = req->req.length - req->req.actual;
+
+	if (ep_num == EP0_CON)
+		length = min(length, (u32)ep_maxpacket(ep));
+
+	ep->len = length;
+	ep->dma_buf = buf;
+
+	flush_dcache_range((unsigned long) ep->dma_buf,
+			   (unsigned long) ep->dma_buf +
+			   ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE));
+
+	if (length == 0)
+		pktcnt = 1;
+	else
+		pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+	/* Flush the endpoint's Tx FIFO */
+	writel(TX_FIFO_NUMBER(ep->fifo_num), &reg->grstctl);
+	writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
+		;
+
+	writel(phys_to_bus((unsigned long)ep->dma_buf), &reg->in_endp[ep_num].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length),
+	       &reg->in_endp[ep_num].dieptsiz);
+
+	ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+	/* Write the FIFO number to be used for this endpoint */
+	ctrl &= DIEPCTL_TX_FIFO_NUM_MASK;
+	ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num);
+
+	/* Clear reserved (Next EP) bits */
+	ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT));
+
+	writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->in_endp[ep_num].diepctl);
+
+	debug_cond(DEBUG_IN_EP,
+		"%s:EP%d TX DMA start : DIEPDMA0 = 0x%x,"
+		"DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n"
+		"\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+		__func__, ep_num,
+		readl(&reg->in_endp[ep_num].diepdma),
+		readl(&reg->in_endp[ep_num].dieptsiz),
+		readl(&reg->in_endp[ep_num].diepctl),
+		buf, pktcnt, length);
+
+	return length;
+}
+
+static void complete_rx(struct dwc2_udc *dev, u8 ep_num)
+{
+	struct dwc2_ep *ep = &dev->ep[ep_num];
+	struct dwc2_request *req = NULL;
+	u32 ep_tsr = 0, xfer_size = 0, is_short = 0;
+
+	if (list_empty(&ep->queue)) {
+		debug_cond(DEBUG_OUT_EP != 0,
+			   "%s: RX DMA done : NULL REQ on OUT EP-%d\n",
+			   __func__, ep_num);
+		return;
+
+	}
+
+	req = list_entry(ep->queue.next, struct dwc2_request, queue);
+	ep_tsr = readl(&reg->out_endp[ep_num].doeptsiz);
+
+	if (ep_num == EP0_CON)
+		xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0);
+	else
+		xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP);
+
+	xfer_size = ep->len - xfer_size;
+
+	/*
+	 * NOTE:
+	 *
+	 * Please be careful with proper buffer allocation for USB request,
+	 * which needs to be aligned to CONFIG_SYS_CACHELINE_SIZE, not only
+	 * with starting address, but also its size shall be a cache line
+	 * multiplication.
+	 *
+	 * This will prevent from corruption of data allocated immediatelly
+	 * before or after the buffer.
+	 *
+	 * For armv7, the cache_v7.c provides proper code to emit "ERROR"
+	 * message to warn users.
+	 */
+	invalidate_dcache_range((unsigned long) ep->dma_buf,
+				(unsigned long) ep->dma_buf +
+				ROUND(xfer_size, CONFIG_SYS_CACHELINE_SIZE));
+
+	req->req.actual += min(xfer_size, req->req.length - req->req.actual);
+	is_short = !!(xfer_size % ep->ep.maxpacket);
+
+	debug_cond(DEBUG_OUT_EP != 0,
+		   "%s: RX DMA done : ep = %d, rx bytes = %d/%d, "
+		   "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n",
+		   __func__, ep_num, req->req.actual, req->req.length,
+		   is_short, ep_tsr, req->req.length - req->req.actual);
+
+	if (is_short || req->req.actual == req->req.length) {
+		if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) {
+			debug_cond(DEBUG_OUT_EP != 0, "	=> Send ZLP\n");
+			dwc2_udc_ep0_zlp(dev);
+			/* packet will be completed in complete_tx() */
+			dev->ep0state = WAIT_FOR_IN_COMPLETE;
+		} else {
+			done(ep, req, 0);
+
+			if (!list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+					struct dwc2_request, queue);
+				debug_cond(DEBUG_OUT_EP != 0,
+					   "%s: Next Rx request start...\n",
+					   __func__);
+				setdma_rx(ep, req);
+			}
+		}
+	} else
+		setdma_rx(ep, req);
+}
+
+static void complete_tx(struct dwc2_udc *dev, u8 ep_num)
+{
+	struct dwc2_ep *ep = &dev->ep[ep_num];
+	struct dwc2_request *req;
+	u32 ep_tsr = 0, xfer_size = 0, is_short = 0;
+	u32 last;
+
+	if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) {
+		dev->ep0state = WAIT_FOR_OUT_COMPLETE;
+		dwc2_ep0_complete_out();
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		debug_cond(DEBUG_IN_EP,
+			"%s: TX DMA done : NULL REQ on IN EP-%d\n",
+			__func__, ep_num);
+		return;
+
+	}
+
+	req = list_entry(ep->queue.next, struct dwc2_request, queue);
+
+	ep_tsr = readl(&reg->in_endp[ep_num].dieptsiz);
+
+	xfer_size = ep->len;
+	is_short = (xfer_size < ep->ep.maxpacket);
+	req->req.actual += min(xfer_size, req->req.length - req->req.actual);
+
+	debug_cond(DEBUG_IN_EP,
+		"%s: TX DMA done : ep = %d, tx bytes = %d/%d, "
+		"is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n",
+		__func__, ep_num, req->req.actual, req->req.length,
+		is_short, ep_tsr, req->req.length - req->req.actual);
+
+	if (ep_num == 0) {
+		if (dev->ep0state == DATA_STATE_XMIT) {
+			debug_cond(DEBUG_IN_EP,
+				"%s: ep_num = %d, ep0stat =="
+				"DATA_STATE_XMIT\n",
+				__func__, ep_num);
+			last = write_fifo_ep0(ep, req);
+			if (last)
+				dev->ep0state = WAIT_FOR_COMPLETE;
+		} else if (dev->ep0state == WAIT_FOR_IN_COMPLETE) {
+			debug_cond(DEBUG_IN_EP,
+				"%s: ep_num = %d, completing request\n",
+				__func__, ep_num);
+			done(ep, req, 0);
+			dev->ep0state = WAIT_FOR_SETUP;
+		} else if (dev->ep0state == WAIT_FOR_COMPLETE) {
+			debug_cond(DEBUG_IN_EP,
+				"%s: ep_num = %d, completing request\n",
+				__func__, ep_num);
+			done(ep, req, 0);
+			dev->ep0state = WAIT_FOR_OUT_COMPLETE;
+			dwc2_ep0_complete_out();
+		} else {
+			debug_cond(DEBUG_IN_EP,
+				"%s: ep_num = %d, invalid ep state\n",
+				__func__, ep_num);
+		}
+		return;
+	}
+
+	if (req->req.actual == req->req.length)
+		done(ep, req, 0);
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct dwc2_request, queue);
+		debug_cond(DEBUG_IN_EP,
+			"%s: Next Tx request start...\n", __func__);
+		setdma_tx(ep, req);
+	}
+}
+
+static inline void dwc2_udc_check_tx_queue(struct dwc2_udc *dev, u8 ep_num)
+{
+	struct dwc2_ep *ep = &dev->ep[ep_num];
+	struct dwc2_request *req;
+
+	debug_cond(DEBUG_IN_EP,
+		"%s: Check queue, ep_num = %d\n", __func__, ep_num);
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct dwc2_request, queue);
+		debug_cond(DEBUG_IN_EP,
+			"%s: Next Tx request(0x%p) start...\n",
+			__func__, req);
+
+		if (ep_is_in(ep))
+			setdma_tx(ep, req);
+		else
+			setdma_rx(ep, req);
+	} else {
+		debug_cond(DEBUG_IN_EP,
+			"%s: NULL REQ on IN EP-%d\n", __func__, ep_num);
+
+		return;
+	}
+
+}
+
+static void process_ep_in_intr(struct dwc2_udc *dev)
+{
+	u32 ep_intr, ep_intr_status;
+	u8 ep_num = 0;
+
+	ep_intr = readl(&reg->daint);
+	debug_cond(DEBUG_IN_EP,
+		"*** %s: EP In interrupt : DAINT = 0x%x\n", __func__, ep_intr);
+
+	ep_intr &= DAINT_MASK;
+
+	while (ep_intr) {
+		if (ep_intr & DAINT_IN_EP_INT(1)) {
+			ep_intr_status = readl(&reg->in_endp[ep_num].diepint);
+			debug_cond(DEBUG_IN_EP,
+				   "\tEP%d-IN : DIEPINT = 0x%x\n",
+				   ep_num, ep_intr_status);
+
+			/* Interrupt Clear */
+			writel(ep_intr_status, &reg->in_endp[ep_num].diepint);
+
+			if (ep_intr_status & TRANSFER_DONE) {
+				complete_tx(dev, ep_num);
+
+				if (ep_num == 0) {
+					if (dev->ep0state ==
+					    WAIT_FOR_IN_COMPLETE)
+						dev->ep0state = WAIT_FOR_SETUP;
+
+					if (dev->ep0state == WAIT_FOR_SETUP)
+						dwc2_udc_pre_setup();
+
+					/* continue transfer after
+					   set_clear_halt for DMA mode */
+					if (clear_feature_flag == 1) {
+						dwc2_udc_check_tx_queue(dev,
+							clear_feature_num);
+						clear_feature_flag = 0;
+					}
+				}
+			}
+		}
+		ep_num++;
+		ep_intr >>= 1;
+	}
+}
+
+static void process_ep_out_intr(struct dwc2_udc *dev)
+{
+	u32 ep_intr, ep_intr_status;
+	u8 ep_num = 0;
+	u32 ep_tsr = 0, xfer_size = 0;
+	u32 epsiz_reg = reg->out_endp[ep_num].doeptsiz;
+	u32 req_size = sizeof(struct usb_ctrlrequest);
+
+	ep_intr = readl(&reg->daint);
+	debug_cond(DEBUG_OUT_EP != 0,
+		   "*** %s: EP OUT interrupt : DAINT = 0x%x\n",
+		   __func__, ep_intr);
+
+	ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK;
+
+	while (ep_intr) {
+		if (ep_intr & 0x1) {
+			ep_intr_status = readl(&reg->out_endp[ep_num].doepint);
+			debug_cond(DEBUG_OUT_EP != 0,
+				   "\tEP%d-OUT : DOEPINT = 0x%x\n",
+				   ep_num, ep_intr_status);
+
+			/* Interrupt Clear */
+			writel(ep_intr_status, &reg->out_endp[ep_num].doepint);
+
+			if (ep_num == 0) {
+				if (ep_intr_status & TRANSFER_DONE) {
+					ep_tsr = readl(&epsiz_reg);
+					xfer_size = ep_tsr &
+						   DOEPT_SIZ_XFER_SIZE_MAX_EP0;
+
+					if (xfer_size == req_size &&
+					    dev->ep0state == WAIT_FOR_SETUP) {
+						dwc2_udc_pre_setup();
+					} else if (dev->ep0state !=
+						   WAIT_FOR_OUT_COMPLETE) {
+						complete_rx(dev, ep_num);
+					} else {
+						dev->ep0state = WAIT_FOR_SETUP;
+						dwc2_udc_pre_setup();
+					}
+				}
+
+				if (ep_intr_status &
+				    CTRL_OUT_EP_SETUP_PHASE_DONE) {
+					debug_cond(DEBUG_OUT_EP != 0,
+						   "SETUP packet arrived\n");
+					dwc2_handle_ep0(dev);
+				}
+			} else {
+				if (ep_intr_status & TRANSFER_DONE)
+					complete_rx(dev, ep_num);
+			}
+		}
+		ep_num++;
+		ep_intr >>= 1;
+	}
+}
+
+/*
+ *	usb client interrupt handler.
+ */
+static int dwc2_udc_irq(int irq, void *_dev)
+{
+	struct dwc2_udc *dev = _dev;
+	u32 intr_status, gotgint;
+	u32 usb_status, gintmsk;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	intr_status = readl(&reg->gintsts);
+	gintmsk = readl(&reg->gintmsk);
+
+	debug_cond(DEBUG_ISR,
+		  "\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x,"
+		  "DAINT : 0x%x, DAINTMSK : 0x%x\n",
+		  __func__, intr_status, state_names[dev->ep0state], gintmsk,
+		  readl(&reg->daint), readl(&reg->daintmsk));
+
+	if (!intr_status) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	if (intr_status & INT_ENUMDONE) {
+		debug_cond(DEBUG_ISR, "\tSpeed Detection interrupt\n");
+
+		writel(INT_ENUMDONE, &reg->gintsts);
+		usb_status = (readl(&reg->dsts) & 0x6);
+
+		if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) {
+			debug_cond(DEBUG_ISR,
+				   "\t\tFull Speed Detection\n");
+			set_max_pktsize(dev, USB_SPEED_FULL);
+
+		} else {
+			debug_cond(DEBUG_ISR,
+				"\t\tHigh Speed Detection : 0x%x\n",
+				usb_status);
+			set_max_pktsize(dev, USB_SPEED_HIGH);
+		}
+	}
+
+	if (intr_status & INT_EARLY_SUSPEND) {
+		debug_cond(DEBUG_ISR, "\tEarly suspend interrupt\n");
+		writel(INT_EARLY_SUSPEND, &reg->gintsts);
+	}
+
+	if (intr_status & INT_SUSPEND) {
+		usb_status = readl(&reg->dsts);
+		debug_cond(DEBUG_ISR,
+			"\tSuspend interrupt :(DSTS):0x%x\n", usb_status);
+		writel(INT_SUSPEND, &reg->gintsts);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+		    && dev->driver) {
+			if (dev->driver->suspend)
+				dev->driver->suspend(&dev->gadget);
+		}
+	}
+
+	if (intr_status & INT_OTG) {
+		gotgint = readl(&reg->gotgint);
+		debug_cond(DEBUG_ISR,
+			   "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint);
+
+		if (gotgint & GOTGINT_SES_END_DET) {
+			debug_cond(DEBUG_ISR, "\t\tSession End Detected\n");
+			/* Let gadget detect disconnected state */
+			if (dev->driver->disconnect) {
+				spin_unlock_irqrestore(&dev->lock, flags);
+				dev->driver->disconnect(&dev->gadget);
+				spin_lock_irqsave(&dev->lock, flags);
+			}
+		}
+		writel(gotgint, &reg->gotgint);
+	}
+
+	if (intr_status & INT_RESUME) {
+		debug_cond(DEBUG_ISR, "\tResume interrupt\n");
+		writel(INT_RESUME, &reg->gintsts);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+		    && dev->driver
+		    && dev->driver->resume) {
+
+			dev->driver->resume(&dev->gadget);
+		}
+	}
+
+	if (intr_status & INT_RESET) {
+		usb_status = readl(&reg->gotgctl);
+		debug_cond(DEBUG_ISR,
+			"\tReset interrupt - (GOTGCTL):0x%x\n", usb_status);
+		writel(INT_RESET, &reg->gintsts);
+
+		if ((usb_status & 0xc0000) == (0x3 << 18)) {
+			if (reset_available) {
+				debug_cond(DEBUG_ISR,
+					"\t\tOTG core got reset (%d)!!\n",
+					reset_available);
+				reconfig_usbd(dev);
+				dev->ep0state = WAIT_FOR_SETUP;
+				reset_available = 0;
+				dwc2_udc_pre_setup();
+			} else
+				reset_available = 1;
+
+		} else {
+			reset_available = 1;
+			debug_cond(DEBUG_ISR,
+				   "\t\tRESET handling skipped\n");
+		}
+	}
+
+	if (intr_status & INT_IN_EP)
+		process_ep_in_intr(dev);
+
+	if (intr_status & INT_OUT_EP)
+		process_ep_out_intr(dev);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/** Queue one request
+ *  Kickstart transfer if needed
+ */
+static int dwc2_queue(struct usb_ep *_ep, struct usb_request *_req,
+			 gfp_t gfp_flags)
+{
+	struct dwc2_request *req;
+	struct dwc2_ep *ep;
+	struct dwc2_udc *dev;
+	unsigned long flags = 0;
+	u32 ep_num, gintsts;
+
+	req = container_of(_req, struct dwc2_request, req);
+	if (unlikely(!_req || !_req->complete || !_req->buf
+		     || !list_empty(&req->queue))) {
+
+		debug("%s: bad params\n", __func__);
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+
+		debug("%s: bad ep: %s, %d, %p\n", __func__,
+		      ep->ep.name, !ep->desc, _ep);
+		return -EINVAL;
+	}
+
+	ep_num = ep_index(ep);
+	dev = ep->dev;
+	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+
+		debug("%s: bogus device state %p\n", __func__, dev->driver);
+		return -ESHUTDOWN;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* kickstart this i/o queue? */
+	debug("\n*** %s: %s-%s req = %p, len = %d, buf = %p"
+		"Q empty = %d, stopped = %d\n",
+		__func__, _ep->name, ep_is_in(ep) ? "in" : "out",
+		_req, _req->length, _req->buf,
+		list_empty(&ep->queue), ep->stopped);
+
+#ifdef DEBUG
+	{
+		int i, len = _req->length;
+
+		printf("pkt = ");
+		if (len > 64)
+			len = 64;
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)_req->buf)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+
+	if (list_empty(&ep->queue) && !ep->stopped) {
+
+		if (ep_num == 0) {
+			/* EP0 */
+			list_add_tail(&req->queue, &ep->queue);
+			dwc2_ep0_kick(dev, ep);
+			req = 0;
+
+		} else if (ep_is_in(ep)) {
+			gintsts = readl(&reg->gintsts);
+			debug_cond(DEBUG_IN_EP,
+				   "%s: ep_is_in, DWC2_UDC_OTG_GINTSTS=0x%x\n",
+				   __func__, gintsts);
+
+			setdma_tx(ep, req);
+		} else {
+			gintsts = readl(&reg->gintsts);
+			debug_cond(DEBUG_OUT_EP != 0,
+				   "%s:ep_is_out, DWC2_UDC_OTG_GINTSTS=0x%x\n",
+				   __func__, gintsts);
+
+			setdma_rx(ep, req);
+		}
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely(req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/****************************************************************/
+/* End Point 0 related functions                                */
+/****************************************************************/
+
+/* return:  0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct dwc2_ep *ep, struct dwc2_request *req)
+{
+	u32 max;
+	unsigned count;
+	int is_last;
+
+	max = ep_maxpacket(ep);
+
+	debug_cond(DEBUG_EP0 != 0, "%s: max = %d\n", __func__, max);
+
+	count = setdma_tx(ep, req);
+
+	/* last packet is usually short (or a zlp) */
+	if (likely(count != max))
+		is_last = 1;
+	else {
+		if (likely(req->req.length != req->req.actual + count)
+		    || req->req.zero)
+			is_last = 0;
+		else
+			is_last = 1;
+	}
+
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: wrote %s %d bytes%s %d left %p\n", __func__,
+		   ep->ep.name, count,
+		   is_last ? "/L" : "",
+		   req->req.length - req->req.actual - count, req);
+
+	/* requests complete when all IN data is in the FIFO */
+	if (is_last) {
+		ep->dev->ep0state = WAIT_FOR_SETUP;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int dwc2_fifo_read(struct dwc2_ep *ep, void *cp, int max)
+{
+	invalidate_dcache_range((unsigned long)cp, (unsigned long)cp +
+				ROUND(max, CONFIG_SYS_CACHELINE_SIZE));
+
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: bytes=%d, ep_index=%d 0x%p\n", __func__,
+		   max, ep_index(ep), cp);
+
+	return max;
+}
+
+/**
+ * udc_set_address - set the USB address for this device
+ * @address:
+ *
+ * Called from control endpoint function
+ * after it decodes a set address setup packet.
+ */
+static void udc_set_address(struct dwc2_udc *dev, unsigned char address)
+{
+	u32 ctrl = readl(&reg->dcfg);
+	writel(DEVICE_ADDRESS(address) | ctrl, &reg->dcfg);
+
+	dwc2_udc_ep0_zlp(dev);
+
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n",
+		   __func__, address, readl(&reg->dcfg));
+
+	dev->usb_address = address;
+}
+
+static inline void dwc2_udc_ep0_set_stall(struct dwc2_ep *ep)
+{
+	struct dwc2_udc *dev;
+	u32		ep_ctrl = 0;
+
+	dev = ep->dev;
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+
+	/* set the disable and stall bits */
+	if (ep_ctrl & DEPCTL_EPENA)
+		ep_ctrl |= DEPCTL_EPDIS;
+
+	ep_ctrl |= DEPCTL_STALL;
+
+	writel(ep_ctrl, &reg->in_endp[EP0_CON].diepctl);
+
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: set ep%d stall, DIEPCTL0 = 0x%p\n",
+		   __func__, ep_index(ep), &reg->in_endp[EP0_CON].diepctl);
+	/*
+	 * The application can only set this bit, and the core clears it,
+	 * when a SETUP token is received for this endpoint
+	 */
+	dev->ep0state = WAIT_FOR_SETUP;
+
+	dwc2_udc_pre_setup();
+}
+
+static void dwc2_ep0_read(struct dwc2_udc *dev)
+{
+	struct dwc2_request *req;
+	struct dwc2_ep *ep = &dev->ep[0];
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct dwc2_request, queue);
+
+	} else {
+		debug("%s: ---> BUG\n", __func__);
+		BUG();
+		return;
+	}
+
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+		   __func__, req, req->req.length, req->req.actual);
+
+	if (req->req.length == 0) {
+		/* zlp for Set_configuration, Set_interface,
+		 * or Bulk-Only mass storge reset */
+
+		ep->len = 0;
+		dwc2_udc_ep0_zlp(dev);
+
+		debug_cond(DEBUG_EP0 != 0,
+			   "%s: req.length = 0, bRequest = %d\n",
+			   __func__, usb_ctrl->bRequest);
+		return;
+	}
+
+	setdma_rx(ep, req);
+}
+
+/*
+ * DATA_STATE_XMIT
+ */
+static int dwc2_ep0_write(struct dwc2_udc *dev)
+{
+	struct dwc2_request *req;
+	struct dwc2_ep *ep = &dev->ep[0];
+	int ret, need_zlp = 0;
+
+	if (list_empty(&ep->queue))
+		req = 0;
+	else
+		req = list_entry(ep->queue.next, struct dwc2_request, queue);
+
+	if (!req) {
+		debug_cond(DEBUG_EP0 != 0, "%s: NULL REQ\n", __func__);
+		return 0;
+	}
+
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+		   __func__, req, req->req.length, req->req.actual);
+
+	if (req->req.length - req->req.actual == ep0_fifo_size) {
+		/* Next write will end with the packet size, */
+		/* so we need Zero-length-packet */
+		need_zlp = 1;
+	}
+
+	ret = write_fifo_ep0(ep, req);
+
+	if ((ret == 1) && !need_zlp) {
+		/* Last packet */
+		dev->ep0state = WAIT_FOR_COMPLETE;
+		debug_cond(DEBUG_EP0 != 0,
+			   "%s: finished, waiting for status\n", __func__);
+
+	} else {
+		dev->ep0state = DATA_STATE_XMIT;
+		debug_cond(DEBUG_EP0 != 0,
+			   "%s: not finished\n", __func__);
+	}
+
+	return 1;
+}
+
+static int dwc2_udc_get_status(struct dwc2_udc *dev,
+		struct usb_ctrlrequest *crq)
+{
+	u8 ep_num = crq->wIndex & 0x7F;
+	u16 g_status = 0;
+	u32 ep_ctrl;
+
+	debug_cond(DEBUG_SETUP != 0,
+		   "%s: *** USB_REQ_GET_STATUS\n", __func__);
+	printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK);
+	switch (crq->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		g_status = 0;
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n",
+			   g_status);
+		break;
+
+	case USB_RECIP_DEVICE:
+		g_status = 0x1; /* Self powered */
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n",
+			   g_status);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		if (crq->wLength > 2) {
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tGET_STATUS:Not support EP or wLength\n");
+			return 1;
+		}
+
+		g_status = dev->ep[ep_num].stopped;
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n",
+			   g_status);
+
+		break;
+
+	default:
+		return 1;
+	}
+
+	memcpy(usb_ctrl, &g_status, sizeof(g_status));
+
+	flush_dcache_range((unsigned long) usb_ctrl,
+			   (unsigned long) usb_ctrl +
+			   ROUND(sizeof(g_status), CONFIG_SYS_CACHELINE_SIZE));
+
+	writel(phys_to_bus(usb_ctrl_dma_addr), &reg->in_endp[EP0_CON].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2),
+	       &reg->in_endp[EP0_CON].dieptsiz);
+
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->in_endp[EP0_CON].diepctl);
+	dev->ep0state = WAIT_FOR_NULL_COMPLETE;
+
+	return 0;
+}
+
+static void dwc2_udc_set_nak(struct dwc2_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+		ep_ctrl |= DEPCTL_SNAK;
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		debug("%s: set NAK, DIEPCTL%d = 0x%x\n",
+			__func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+		ep_ctrl |= DEPCTL_SNAK;
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		debug("%s: set NAK, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+
+static void dwc2_udc_ep_set_stall(struct dwc2_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+		/* set the disable and stall bits */
+		if (ep_ctrl & DEPCTL_EPENA)
+			ep_ctrl |= DEPCTL_EPDIS;
+
+		ep_ctrl |= DEPCTL_STALL;
+
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		debug("%s: set stall, DIEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+
+		/* set the stall bit */
+		ep_ctrl |= DEPCTL_STALL;
+
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		debug("%s: set stall, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+static void dwc2_udc_ep_clear_stall(struct dwc2_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+		/* clear stall bit */
+		ep_ctrl &= ~DEPCTL_STALL;
+
+		/*
+		 * USB Spec 9.4.5: For endpoints using data toggle, regardless
+		 * of whether an endpoint has the Halt feature set, a
+		 * ClearFeature(ENDPOINT_HALT) request always results in the
+		 * data toggle being reinitialized to DATA0.
+		 */
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+		    || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+			ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+		}
+
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		debug("%s: cleared stall, DIEPCTL%d = 0x%x\n",
+			__func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+
+		/* clear stall bit */
+		ep_ctrl &= ~DEPCTL_STALL;
+
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+		    || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+			ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+		}
+
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		debug("%s: cleared stall, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+static int dwc2_udc_set_halt(struct usb_ep *_ep, int value)
+{
+	struct dwc2_ep	*ep;
+	struct dwc2_udc	*dev;
+	unsigned long	flags = 0;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	ep_num = ep_index(ep);
+
+	if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON ||
+		     ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) {
+		debug("%s: %s bad ep or descriptor\n", __func__, ep->ep.name);
+		return -EINVAL;
+	}
+
+	/* Attempt to halt IN ep will fail if any transfer requests
+	 * are still queue */
+	if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+		debug("%s: %s queue not empty, req = %p\n",
+			__func__, ep->ep.name,
+			list_entry(ep->queue.next, struct dwc2_request, queue));
+
+		return -EAGAIN;
+	}
+
+	dev = ep->dev;
+	debug("%s: ep_num = %d, value = %d\n", __func__, ep_num, value);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (value == 0) {
+		ep->stopped = 0;
+		dwc2_udc_ep_clear_stall(ep);
+	} else {
+		if (ep_num == 0)
+			dev->ep0state = WAIT_FOR_SETUP;
+
+		ep->stopped = 1;
+		dwc2_udc_ep_set_stall(ep);
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+static void dwc2_udc_ep_activate(struct dwc2_ep *ep)
+{
+	u8 ep_num;
+	u32 ep_ctrl = 0, daintmsk = 0;
+
+	ep_num = ep_index(ep);
+
+	/* Read DEPCTLn register */
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+		daintmsk = 1 << ep_num;
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+		daintmsk = (1 << ep_num) << DAINT_OUT_BIT;
+	}
+
+	debug("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n",
+		__func__, ep_num, ep_ctrl, ep_is_in(ep));
+
+	/* If the EP is already active don't change the EP Control
+	 * register. */
+	if (!(ep_ctrl & DEPCTL_USBACTEP)) {
+		ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) |
+			(ep->bmAttributes << DEPCTL_TYPE_BIT);
+		ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) |
+			(ep->ep.maxpacket << DEPCTL_MPS_BIT);
+		ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK);
+
+		if (ep_is_in(ep)) {
+			writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+			debug("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n",
+			      __func__, ep_num, ep_num,
+			      readl(&reg->in_endp[ep_num].diepctl));
+		} else {
+			writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+			debug("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n",
+			      __func__, ep_num, ep_num,
+			      readl(&reg->out_endp[ep_num].doepctl));
+		}
+	}
+
+	/* Unmask EP Interrtupt */
+	writel(readl(&reg->daintmsk)|daintmsk, &reg->daintmsk);
+	debug("%s: DAINTMSK = 0x%x\n", __func__, readl(&reg->daintmsk));
+
+}
+
+static int dwc2_udc_clear_feature(struct usb_ep *_ep)
+{
+	struct dwc2_udc	*dev;
+	struct dwc2_ep	*ep;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	ep_num = ep_index(ep);
+
+	dev = ep->dev;
+	debug_cond(DEBUG_SETUP != 0,
+		   "%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n",
+		   __func__, ep_num, ep_is_in(ep), clear_feature_flag);
+
+	if (usb_ctrl->wLength != 0) {
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tCLEAR_FEATURE: wLength is not zero.....\n");
+		return 1;
+	}
+
+	switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (usb_ctrl->wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tOFF:USB_DEVICE_REMOTE_WAKEUP\n");
+			break;
+
+		case USB_DEVICE_TEST_MODE:
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n");
+			/** @todo Add CLEAR_FEATURE for TEST modes. */
+			break;
+		}
+
+		dwc2_udc_ep0_zlp(dev);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n",
+			   usb_ctrl->wValue);
+
+		if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+			if (ep_num == 0) {
+				dwc2_udc_ep0_set_stall(ep);
+				return 0;
+			}
+
+			dwc2_udc_ep0_zlp(dev);
+
+			dwc2_udc_ep_clear_stall(ep);
+			dwc2_udc_ep_activate(ep);
+			ep->stopped = 0;
+
+			clear_feature_num = ep_num;
+			clear_feature_flag = 1;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int dwc2_udc_set_feature(struct usb_ep *_ep)
+{
+	struct dwc2_udc	*dev;
+	struct dwc2_ep	*ep;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct dwc2_ep, ep);
+	ep_num = ep_index(ep);
+	dev = ep->dev;
+
+	debug_cond(DEBUG_SETUP != 0,
+		   "%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n",
+		    __func__, ep_num);
+
+	if (usb_ctrl->wLength != 0) {
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tSET_FEATURE: wLength is not zero.....\n");
+		return 1;
+	}
+
+	switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (usb_ctrl->wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n");
+			break;
+		case USB_DEVICE_B_HNP_ENABLE:
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+			break;
+
+		case USB_DEVICE_A_HNP_SUPPORT:
+			/* RH port supports HNP */
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n");
+			break;
+
+		case USB_DEVICE_A_ALT_HNP_SUPPORT:
+			/* other RH port does */
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+			break;
+		}
+
+		dwc2_udc_ep0_zlp(dev);
+		return 0;
+
+	case USB_RECIP_INTERFACE:
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tSET_FEATURE: USB_RECIP_INTERFACE\n");
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tSET_FEATURE: USB_RECIP_ENDPOINT\n");
+		if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+			if (ep_num == 0) {
+				dwc2_udc_ep0_set_stall(ep);
+				return 0;
+			}
+			ep->stopped = 1;
+			dwc2_udc_ep_set_stall(ep);
+		}
+
+		dwc2_udc_ep0_zlp(dev);
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * WAIT_FOR_SETUP (OUT_PKT_RDY)
+ */
+static void dwc2_ep0_setup(struct dwc2_udc *dev)
+{
+	struct dwc2_ep *ep = &dev->ep[0];
+	int i;
+	u8 ep_num;
+
+	/* Nuke all previous transfers */
+	nuke(ep, -EPROTO);
+
+	/* read control req from fifo (8 bytes) */
+	dwc2_fifo_read(ep, usb_ctrl, 8);
+
+	debug_cond(DEBUG_SETUP != 0,
+		   "%s: bRequestType = 0x%x(%s), bRequest = 0x%x"
+		   "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n",
+		   __func__, usb_ctrl->bRequestType,
+		   (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+		   usb_ctrl->bRequest,
+		   usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex);
+
+#ifdef DEBUG
+	{
+		int i, len = sizeof(*usb_ctrl);
+		char *p = (char *)usb_ctrl;
+
+		printf("pkt = ");
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)p)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+
+	if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST &&
+	    usb_ctrl->wLength != 1) {
+		debug_cond(DEBUG_SETUP != 0,
+			   "\t%s:GET_MAX_LUN_REQUEST:invalid",
+			   __func__);
+		debug_cond(DEBUG_SETUP != 0,
+			   "wLength = %d, setup returned\n",
+			   usb_ctrl->wLength);
+
+		dwc2_udc_ep0_set_stall(ep);
+		dev->ep0state = WAIT_FOR_SETUP;
+
+		return;
+	} else if (usb_ctrl->bRequest == BOT_RESET_REQUEST &&
+		 usb_ctrl->wLength != 0) {
+		/* Bulk-Only *mass storge reset of class-specific request */
+		debug_cond(DEBUG_SETUP != 0,
+			   "%s:BOT Rest:invalid wLength =%d, setup returned\n",
+			   __func__, usb_ctrl->wLength);
+
+		dwc2_udc_ep0_set_stall(ep);
+		dev->ep0state = WAIT_FOR_SETUP;
+
+		return;
+	}
+
+	/* Set direction of EP0 */
+	if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) {
+		ep->bEndpointAddress |= USB_DIR_IN;
+	} else {
+		ep->bEndpointAddress &= ~USB_DIR_IN;
+	}
+	/* cope with automagic for some standard requests. */
+	dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK)
+		== USB_TYPE_STANDARD;
+
+	dev->req_pending = 1;
+
+	/* Handle some SETUP packets ourselves */
+	if (dev->req_std) {
+		switch (usb_ctrl->bRequest) {
+		case USB_REQ_SET_ADDRESS:
+		debug_cond(DEBUG_SETUP != 0,
+			   "%s: *** USB_REQ_SET_ADDRESS (%d)\n",
+			   __func__, usb_ctrl->wValue);
+			if (usb_ctrl->bRequestType
+				!= (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+				break;
+
+			udc_set_address(dev, usb_ctrl->wValue);
+			return;
+
+		case USB_REQ_SET_CONFIGURATION:
+			debug_cond(DEBUG_SETUP != 0,
+				   "=====================================\n");
+			debug_cond(DEBUG_SETUP != 0,
+				   "%s: USB_REQ_SET_CONFIGURATION (%d)\n",
+				   __func__, usb_ctrl->wValue);
+
+			if (usb_ctrl->bRequestType == USB_RECIP_DEVICE)
+				reset_available = 1;
+
+			break;
+
+		case USB_REQ_GET_DESCRIPTOR:
+			debug_cond(DEBUG_SETUP != 0,
+				   "%s: *** USB_REQ_GET_DESCRIPTOR\n",
+				   __func__);
+			break;
+
+		case USB_REQ_SET_INTERFACE:
+			debug_cond(DEBUG_SETUP != 0,
+				   "%s: *** USB_REQ_SET_INTERFACE (%d)\n",
+				   __func__, usb_ctrl->wValue);
+
+			if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE)
+				reset_available = 1;
+
+			break;
+
+		case USB_REQ_GET_CONFIGURATION:
+			debug_cond(DEBUG_SETUP != 0,
+				   "%s: *** USB_REQ_GET_CONFIGURATION\n",
+				   __func__);
+			break;
+
+		case USB_REQ_GET_STATUS:
+			if (!dwc2_udc_get_status(dev, usb_ctrl))
+				return;
+
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			ep_num = usb_ctrl->wIndex & 0x7f;
+
+			if (!dwc2_udc_clear_feature(&dev->ep[ep_num].ep))
+				return;
+
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			ep_num = usb_ctrl->wIndex & 0x7f;
+
+			if (!dwc2_udc_set_feature(&dev->ep[ep_num].ep))
+				return;
+
+			break;
+
+		default:
+			debug_cond(DEBUG_SETUP != 0,
+				   "%s: *** Default of usb_ctrl->bRequest=0x%x"
+				   "happened.\n", __func__, usb_ctrl->bRequest);
+			break;
+		}
+	}
+
+
+	if (likely(dev->driver)) {
+		/* device-2-host (IN) or no data setup command,
+		 * process immediately */
+		debug_cond(DEBUG_SETUP != 0,
+			   "%s:usb_ctrlreq will be passed to fsg_setup()\n",
+			    __func__);
+
+		spin_unlock(&dev->lock);
+		i = dev->driver->setup(&dev->gadget, usb_ctrl);
+		spin_lock(&dev->lock);
+
+		if (i < 0) {
+			/* setup processing failed, force stall */
+			dwc2_udc_ep0_set_stall(ep);
+			dev->ep0state = WAIT_FOR_SETUP;
+
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tdev->driver->setup failed (%d),"
+				    " bRequest = %d\n",
+				i, usb_ctrl->bRequest);
+
+
+		} else if (dev->req_pending) {
+			dev->req_pending = 0;
+			debug_cond(DEBUG_SETUP != 0,
+				   "\tdev->req_pending...\n");
+		}
+
+		debug_cond(DEBUG_SETUP != 0,
+			   "\tep0state = %s\n", state_names[dev->ep0state]);
+
+	}
+}
+
+/*
+ * handle ep0 interrupt
+ */
+static void dwc2_handle_ep0(struct dwc2_udc *dev)
+{
+	if (dev->ep0state == WAIT_FOR_SETUP) {
+		debug_cond(DEBUG_OUT_EP != 0,
+			   "%s: WAIT_FOR_SETUP\n", __func__);
+		dwc2_ep0_setup(dev);
+
+	} else {
+		debug_cond(DEBUG_OUT_EP != 0,
+			   "%s: strange state!!(state = %s)\n",
+			__func__, state_names[dev->ep0state]);
+	}
+}
+
+static void dwc2_ep0_kick(struct dwc2_udc *dev, struct dwc2_ep *ep)
+{
+	debug_cond(DEBUG_EP0 != 0,
+		   "%s: ep_is_in = %d\n", __func__, ep_is_in(ep));
+	if (ep_is_in(ep)) {
+		dev->ep0state = DATA_STATE_XMIT;
+		dwc2_ep0_write(dev);
+
+	} else {
+		dev->ep0state = DATA_STATE_RECV;
+		dwc2_ep0_read(dev);
+	}
+}
diff --git a/roms/u-boot/drivers/usb/gadget/ep0.c b/roms/u-boot/drivers/usb/gadget/ep0.c
new file mode 100644
index 000000000..6624f61b7
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/ep0.c
@@ -0,0 +1,643 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, deckard@CodeHermit.ie
+ *
+ * Based on
+ * linux/drivers/usbd/ep0.c
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *	Stuart Lynne <sl@lineo.com>,
+ *	Tom Rushworth <tbr@lineo.com>,
+ *	Bruce Balden <balden@lineo.com>
+ */
+
+/*
+ * This is the builtin ep0 control function. It implements all required functionality
+ * for responding to control requests (SETUP packets).
+ *
+ * XXX
+ *
+ * Currently we do not pass any SETUP packets (or other) to the configured
+ * function driver. This may need to change.
+ *
+ * XXX
+ *
+ * As alluded to above, a simple callback cdc_recv_setup has been implemented
+ * in the usb_device data structure to facilicate passing
+ * Common Device Class packets to a function driver.
+ *
+ * XXX
+ */
+
+#include <common.h>
+#include <serial.h>
+#include <usbdevice.h>
+
+#if 0
+#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
+#else
+#define dbg_ep0(lvl,fmt,args...)
+#endif
+
+__maybe_unused static char *usbd_device_descriptors[] = {
+	"UNKNOWN",		/* 0 */
+	"DEVICE",		/* 1 */
+	"CONFIG",		/* 2 */
+	"STRING",		/* 3 */
+	"INTERFACE",		/* 4 */
+	"ENDPOINT",		/* 5 */
+	"DEVICE QUALIFIER",	/* 6 */
+	"OTHER SPEED",		/* 7 */
+	"INTERFACE POWER",	/* 8 */
+};
+
+#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
+		usbd_device_descriptors[x] : "UNKNOWN")
+
+__maybe_unused static char *usbd_device_states[] = {
+	"STATE_INIT",
+	"STATE_CREATED",
+	"STATE_ATTACHED",
+	"STATE_POWERED",
+	"STATE_DEFAULT",
+	"STATE_ADDRESSED",
+	"STATE_CONFIGURED",
+	"STATE_UNKNOWN",
+};
+
+#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
+
+__maybe_unused static char *usbd_device_requests[] = {
+	"GET STATUS",		/* 0 */
+	"CLEAR FEATURE",	/* 1 */
+	"RESERVED",		/* 2 */
+	"SET FEATURE",		/* 3 */
+	"RESERVED",		/* 4 */
+	"SET ADDRESS",		/* 5 */
+	"GET DESCRIPTOR",	/* 6 */
+	"SET DESCRIPTOR",	/* 7 */
+	"GET CONFIGURATION",	/* 8 */
+	"SET CONFIGURATION",	/* 9 */
+	"GET INTERFACE",	/* 10 */
+	"SET INTERFACE",	/* 11 */
+	"SYNC FRAME",		/* 12 */
+};
+
+#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
+
+/* EP0 Configuration Set ********************************************************************* */
+
+
+/**
+ * ep0_get_status - fill in URB data with appropriate status
+ * @device:
+ * @urb:
+ * @index:
+ * @requesttype:
+ *
+ */
+static int ep0_get_status (struct usb_device_instance *device,
+			   struct urb *urb, int index, int requesttype)
+{
+	char *cp;
+
+	urb->actual_length = 2;
+	cp = (char*)urb->buffer;
+	cp[0] = cp[1] = 0;
+
+	switch (requesttype) {
+	case USB_REQ_RECIPIENT_DEVICE:
+		cp[0] = USB_STATUS_SELFPOWERED;
+		break;
+	case USB_REQ_RECIPIENT_INTERFACE:
+		break;
+	case USB_REQ_RECIPIENT_ENDPOINT:
+		cp[0] = usbd_endpoint_halted (device, index);
+		break;
+	case USB_REQ_RECIPIENT_OTHER:
+		urb->actual_length = 0;
+	default:
+		break;
+	}
+	dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
+	return 0;
+}
+
+/**
+ * ep0_get_one
+ * @device:
+ * @urb:
+ * @result:
+ *
+ * Set a single byte value in the urb send buffer. Return non-zero to signal
+ * a request error.
+ */
+static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
+			__u8 result)
+{
+	urb->actual_length = 1;	/* XXX 2? */
+	((char *) urb->buffer)[0] = result;
+	return 0;
+}
+
+/**
+ * copy_config
+ * @urb: pointer to urb
+ * @data: pointer to configuration data
+ * @length: length of data
+ *
+ * Copy configuration data to urb transfer buffer if there is room for it.
+ */
+void copy_config (struct urb *urb, void *data, int max_length,
+			 int max_buf)
+{
+	int available;
+	int length;
+
+	/*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
+
+	if (!data) {
+		dbg_ep0 (1, "data is NULL");
+		return;
+	}
+	length = max_length;
+
+	if (length > max_length) {
+		dbg_ep0 (1, "length: %d >= max_length: %d", length,
+			 max_length);
+		return;
+	}
+	/*dbg_ep0(1, "   actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
+
+	if ((available =
+	     /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
+		return;
+	}
+	/*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+	if (length > available) {
+		length = available;
+	}
+	/*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+	memcpy (urb->buffer + urb->actual_length, data, length);
+	urb->actual_length += length;
+
+	dbg_ep0 (3,
+		 "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
+		 urb->actual_length, urb->buffer_length, max_buf, max_length,
+		 available);
+}
+
+/**
+ * ep0_get_descriptor
+ * @device:
+ * @urb:
+ * @max:
+ * @descriptor_type:
+ * @index:
+ *
+ * Called by ep0_rx_process for a get descriptor device command. Determine what
+ * descriptor is being requested, copy to send buffer. Return zero if ok to send,
+ * return non-zero to signal a request error.
+ */
+static int ep0_get_descriptor (struct usb_device_instance *device,
+			       struct urb *urb, int max, int descriptor_type,
+			       int index)
+{
+	int port = 0;		/* XXX compound device */
+
+	/*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
+
+	if (!urb || !urb->buffer || !urb->buffer_length
+	    || (urb->buffer_length < 255)) {
+		dbg_ep0 (2, "invalid urb %p", urb);
+		return -1L;
+	}
+
+	/* setup tx urb */
+	urb->actual_length = 0;
+
+	dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
+
+	switch (descriptor_type) {
+	case USB_DESCRIPTOR_TYPE_DEVICE:
+		{
+			struct usb_device_descriptor *device_descriptor;
+			if (!
+			    (device_descriptor =
+			     usbd_device_device_descriptor (device, port))) {
+				return -1;
+			}
+			/* copy descriptor for this device */
+			copy_config (urb, device_descriptor,
+				     sizeof (struct usb_device_descriptor),
+				     max);
+
+			/* correct the correct control endpoint 0 max packet size into the descriptor */
+			device_descriptor =
+				(struct usb_device_descriptor *) urb->buffer;
+
+		}
+		dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
+		break;
+
+	case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+		{
+			struct usb_configuration_descriptor
+				*configuration_descriptor;
+			struct usb_device_descriptor *device_descriptor;
+			if (!
+			    (device_descriptor =
+			     usbd_device_device_descriptor (device, port))) {
+				return -1;
+			}
+			/*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
+			if (index >= device_descriptor->bNumConfigurations) {
+				dbg_ep0 (0, "index too large: %d >= %d", index,
+					 device_descriptor->
+					 bNumConfigurations);
+				return -1;
+			}
+
+			if (!
+			    (configuration_descriptor =
+			     usbd_device_configuration_descriptor (device,
+								   port,
+								   index))) {
+				dbg_ep0 (0,
+					 "usbd_device_configuration_descriptor failed: %d",
+					 index);
+				return -1;
+			}
+			dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
+			copy_config (urb, configuration_descriptor,
+
+					cpu_to_le16(configuration_descriptor->wTotalLength),
+				     max);
+		}
+
+		break;
+
+	case USB_DESCRIPTOR_TYPE_STRING:
+		{
+			struct usb_string_descriptor *string_descriptor;
+			if (!(string_descriptor = usbd_get_string (index))) {
+				dbg_ep0(0, "Invalid string index %d\n", index);
+				return -1;
+			}
+			dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
+			copy_config (urb, string_descriptor, string_descriptor->bLength, max);
+		}
+		break;
+	case USB_DESCRIPTOR_TYPE_INTERFACE:
+		dbg_ep0(2, "USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
+		return -1;
+	case USB_DESCRIPTOR_TYPE_ENDPOINT:
+		dbg_ep0(2, "USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
+		return -1;
+	case USB_DESCRIPTOR_TYPE_HID:
+		{
+			dbg_ep0(2, "USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
+			return -1;	/* unsupported at this time */
+#if 0
+			int bNumInterface =
+				le16_to_cpu (urb->device_request.wIndex);
+			int bAlternateSetting = 0;
+			int class = 0;
+			struct usb_class_descriptor *class_descriptor;
+
+			if (!(class_descriptor =
+			      usbd_device_class_descriptor_index (device,
+								  port, 0,
+								  bNumInterface,
+								  bAlternateSetting,
+								  class))
+			    || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
+				dbg_ep0 (3, "[%d] interface is not HID",
+					 bNumInterface);
+				return -1;
+			}
+			/* copy descriptor for this class */
+			copy_config (urb, class_descriptor,
+				     class_descriptor->descriptor.hid.bLength,
+				     max);
+#endif
+		}
+		break;
+	case USB_DESCRIPTOR_TYPE_REPORT:
+		{
+			dbg_ep0(2, "USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
+			return -1;	/* unsupported at this time */
+#if 0
+			int bNumInterface =
+				le16_to_cpu (urb->device_request.wIndex);
+			int bAlternateSetting = 0;
+			int class = 0;
+			struct usb_class_report_descriptor *report_descriptor;
+
+			if (!(report_descriptor =
+			      usbd_device_class_report_descriptor_index
+			      (device, port, 0, bNumInterface,
+			       bAlternateSetting, class))
+			    || report_descriptor->bDescriptorType !=
+			    USB_DT_REPORT) {
+				dbg_ep0 (3, "[%d] descriptor is not REPORT",
+					 bNumInterface);
+				return -1;
+			}
+			/* copy report descriptor for this class */
+			/*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
+			if (max - urb->actual_length > 0) {
+				int length =
+					min(report_descriptor->wLength,
+					     max - urb->actual_length);
+				memcpy (urb->buffer + urb->actual_length,
+					&report_descriptor->bData[0], length);
+				urb->actual_length += length;
+			}
+#endif
+		}
+		break;
+	case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
+#if defined(CONFIG_USBD_HS)
+		{
+			struct usb_qualifier_descriptor *qualifier_descriptor =
+				device->qualifier_descriptor;
+
+			if (!qualifier_descriptor)
+				return -1;
+
+			/* copy descriptor for this device */
+			copy_config(urb, qualifier_descriptor,
+					sizeof(struct usb_qualifier_descriptor),
+					max);
+
+		}
+		dbg_ep0(3, "copied qualifier descriptor, actual_length: 0x%x",
+				urb->actual_length);
+#else
+		return -1;
+#endif
+		break;
+
+	default:
+		return -1;
+	}
+
+
+	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
+		 urb->buffer, urb->buffer_length, urb->actual_length,
+		 device->bus->endpoint_array[0].tx_packetSize);
+/*
+    if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
+	dbg_ep0(0, "adding null byte");
+	urb->buffer[urb->actual_length++] = 0;
+	dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
+		urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
+    }
+*/
+	return 0;
+
+}
+
+/**
+ * ep0_recv_setup - called to indicate URB has been received
+ * @urb: pointer to struct urb
+ *
+ * Check if this is a setup packet, process the device request, put results
+ * back into the urb and return zero or non-zero to indicate success (DATA)
+ * or failure (STALL).
+ *
+ */
+int ep0_recv_setup (struct urb *urb)
+{
+	/*struct usb_device_request *request = urb->buffer; */
+	/*struct usb_device_instance *device = urb->device; */
+
+	struct usb_device_request *request;
+	struct usb_device_instance *device;
+	int address;
+
+	dbg_ep0 (0, "entering ep0_recv_setup()");
+	if (!urb || !urb->device) {
+		dbg_ep0 (3, "invalid URB %p", urb);
+		return -1;
+	}
+
+	request = &urb->device_request;
+	device = urb->device;
+
+	dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
+
+
+	/*dbg_ep0(2, "-       -       -       -       -       -       -       -       -       -"); */
+
+	dbg_ep0 (2,
+		 "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
+		 request->bmRequestType, request->bRequest,
+		 le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
+		 le16_to_cpu (request->wLength),
+		 USBD_DEVICE_REQUESTS (request->bRequest));
+
+	/* handle USB Standard Request (c.f. USB Spec table 9-2) */
+	if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
+		if(device->device_state <= STATE_CONFIGURED){
+			/*	Attempt to handle a CDC specific request if we are
+			 *	in the configured state.
+			 */
+			return device->cdc_recv_setup(request,urb);
+		}
+		dbg_ep0 (1, "non standard request: %x",
+			 request->bmRequestType & USB_REQ_TYPE_MASK);
+		return -1;	/* Stall here */
+	}
+
+	switch (device->device_state) {
+	case STATE_CREATED:
+	case STATE_ATTACHED:
+	case STATE_POWERED:
+		/* It actually is important to allow requests in these states,
+		 * Windows will request descriptors before assigning an
+		 * address to the client.
+		 */
+
+		/*dbg_ep0 (1, "request %s not allowed in this state: %s", */
+		/*                USBD_DEVICE_REQUESTS(request->bRequest), */
+		/*                usbd_device_states[device->device_state]); */
+		/*return -1; */
+		break;
+
+	case STATE_INIT:
+	case STATE_DEFAULT:
+		switch (request->bRequest) {
+		case USB_REQ_GET_STATUS:
+		case USB_REQ_GET_INTERFACE:
+		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+		case USB_REQ_SET_DESCRIPTOR:
+			/* case USB_REQ_SET_CONFIGURATION: */
+		case USB_REQ_SET_INTERFACE:
+			dbg_ep0 (1,
+				 "request %s not allowed in DEFAULT state: %s",
+				 USBD_DEVICE_REQUESTS (request->bRequest),
+				 usbd_device_states[device->device_state]);
+			return -1;
+
+		case USB_REQ_SET_CONFIGURATION:
+		case USB_REQ_SET_ADDRESS:
+		case USB_REQ_GET_DESCRIPTOR:
+		case USB_REQ_GET_CONFIGURATION:
+			break;
+		}
+	case STATE_ADDRESSED:
+	case STATE_CONFIGURED:
+		break;
+	case STATE_UNKNOWN:
+		dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
+			 USBD_DEVICE_REQUESTS (request->bRequest),
+			 usbd_device_states[device->device_state]);
+		return -1;
+	}
+
+	/* handle all requests that return data (direction bit set on bm RequestType) */
+	if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
+
+		dbg_ep0 (3, "Device-to-Host");
+
+		switch (request->bRequest) {
+
+		case USB_REQ_GET_STATUS:
+			return ep0_get_status (device, urb, request->wIndex,
+					       request->bmRequestType &
+					       USB_REQ_RECIPIENT_MASK);
+
+		case USB_REQ_GET_DESCRIPTOR:
+			return ep0_get_descriptor (device, urb,
+						   le16_to_cpu (request->wLength),
+						   le16_to_cpu (request->wValue) >> 8,
+						   le16_to_cpu (request->wValue) & 0xff);
+
+		case USB_REQ_GET_CONFIGURATION:
+			dbg_ep0(2, "get config %d\n", device->configuration);
+			return ep0_get_one (device, urb,
+					    device->configuration);
+
+		case USB_REQ_GET_INTERFACE:
+			return ep0_get_one (device, urb, device->alternate);
+
+		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */
+			return -1;
+
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+		case USB_REQ_SET_ADDRESS:
+		case USB_REQ_SET_DESCRIPTOR:
+		case USB_REQ_SET_CONFIGURATION:
+		case USB_REQ_SET_INTERFACE:
+			return -1;
+		}
+	}
+	/* handle the requests that do not return data */
+	else {
+
+
+		/*dbg_ep0(3, "Host-to-Device"); */
+		switch (request->bRequest) {
+
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+			dbg_ep0 (0, "Host-to-Device");
+			switch (request->
+				bmRequestType & USB_REQ_RECIPIENT_MASK) {
+			case USB_REQ_RECIPIENT_DEVICE:
+				/* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
+				/* XXX fall through for now as we do not support either */
+			case USB_REQ_RECIPIENT_INTERFACE:
+			case USB_REQ_RECIPIENT_OTHER:
+				dbg_ep0 (0, "request %s not",
+					 USBD_DEVICE_REQUESTS (request->bRequest));
+			default:
+				return -1;
+
+			case USB_REQ_RECIPIENT_ENDPOINT:
+				dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
+				if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
+					/*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
+					/*                    request->bRequest == USB_REQ_SET_FEATURE); */
+					/* NEED TO IMPLEMENT THIS!!! */
+					return -1;
+				} else {
+					dbg_ep0 (1, "request %s bad wValue: %04x",
+						 USBD_DEVICE_REQUESTS
+						 (request->bRequest),
+						 le16_to_cpu (request->wValue));
+					return -1;
+				}
+			}
+
+		case USB_REQ_SET_ADDRESS:
+			/* check if this is a re-address, reset first if it is (this shouldn't be possible) */
+			if (device->device_state != STATE_DEFAULT) {
+				dbg_ep0 (1, "set_address: %02x state: %s",
+					 le16_to_cpu (request->wValue),
+					 usbd_device_states[device->device_state]);
+				return -1;
+			}
+			address = le16_to_cpu (request->wValue);
+			if ((address & 0x7f) != address) {
+				dbg_ep0 (1, "invalid address %04x %04x",
+					 address, address & 0x7f);
+				return -1;
+			}
+			device->address = address;
+
+			/*dbg_ep0(2, "address: %d %d %d", */
+			/*        request->wValue, le16_to_cpu(request->wValue), device->address); */
+
+			return 0;
+
+		case USB_REQ_SET_DESCRIPTOR:	/* XXX should we support this? */
+			dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
+			return -1;
+
+		case USB_REQ_SET_CONFIGURATION:
+			/* c.f. 9.4.7 - the top half of wValue is reserved */
+			device->configuration = le16_to_cpu(request->wValue) & 0xff;
+
+			/* reset interface and alternate settings */
+			device->interface = device->alternate = 0;
+
+			/*dbg_ep0(2, "set configuration: %d", device->configuration); */
+			/*dbg_ep0(2, "DEVICE_CONFIGURED.. event?\n"); */
+			return 0;
+
+		case USB_REQ_SET_INTERFACE:
+			device->interface = le16_to_cpu (request->wIndex);
+			device->alternate = le16_to_cpu (request->wValue);
+			/*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
+			dbg_ep0(2, "DEVICE_SET_INTERFACE.. event?\n");
+			return 0;
+
+		case USB_REQ_GET_STATUS:
+		case USB_REQ_GET_DESCRIPTOR:
+		case USB_REQ_GET_CONFIGURATION:
+		case USB_REQ_GET_INTERFACE:
+		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */
+			return -1;
+		}
+	}
+	return -1;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/ep0.h b/roms/u-boot/drivers/usb/gadget/ep0.h
new file mode 100644
index 000000000..976825ab9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/ep0.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/ep0.c
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *	Stuart Lynne <sl@lineo.com>,
+ *	Tom Rushworth <tbr@lineo.com>,
+ *	Bruce Balden <balden@lineo.com>
+ */
+
+#ifndef __USBDCORE_EP0_H__
+#define __USBDCORE_EP0_H__
+
+
+int ep0_recv_setup (struct urb *urb);
+
+
+#endif
diff --git a/roms/u-boot/drivers/usb/gadget/epautoconf.c b/roms/u-boot/drivers/usb/gadget/epautoconf.c
new file mode 100644
index 000000000..7da334f5d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/epautoconf.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
+ *
+ * Copyright (C) 2004 David Brownell
+ *
+ * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and
+ *                      Remy Bohmer <linux@bohmer.net>
+ */
+
+#include <common.h>
+#include <linux/usb/ch9.h>
+#include <linux/errno.h>
+#include <linux/usb/gadget.h>
+#include <asm/unaligned.h>
+#include "gadget_chips.h"
+
+#define isdigit(c)      ('0' <= (c) && (c) <= '9')
+
+/* we must assign addresses for configurable endpoints (like net2280) */
+static unsigned epnum;
+
+/* #define MANY_ENDPOINTS */
+#ifdef MANY_ENDPOINTS
+/* more than 15 configurable endpoints */
+static unsigned in_epnum;
+#endif
+
+
+/*
+ * This should work with endpoints from controller drivers sharing the
+ * same endpoint naming convention.  By example:
+ *
+ *	- ep1, ep2, ... address is fixed, not direction or type
+ *	- ep1in, ep2out, ... address and direction are fixed, not type
+ *	- ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
+ *	- ep1in-bulk, ep2out-iso, ... all three are fixed
+ *	- ep-* ... no functionality restrictions
+ *
+ * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
+ * Less common restrictions are implied by gadget_is_*().
+ *
+ * NOTE:  each endpoint is unidirectional, as specified by its USB
+ * descriptor; and isn't specific to a configuration or altsetting.
+ */
+static int ep_matches(
+	struct usb_gadget		*gadget,
+	struct usb_ep			*ep,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	u8		type;
+	const char	*tmp;
+	u16		max;
+
+	/* endpoint already claimed? */
+	if (NULL != ep->driver_data)
+		return 0;
+
+	/* only support ep0 for portable CONTROL traffic */
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	if (USB_ENDPOINT_XFER_CONTROL == type)
+		return 0;
+
+	/* some other naming convention */
+	if ('e' != ep->name[0])
+		return 0;
+
+	/* type-restriction:  "-iso", "-bulk", or "-int".
+	 * direction-restriction:  "in", "out".
+	 */
+	if ('-' != ep->name[2]) {
+		tmp = strrchr(ep->name, '-');
+		if (tmp) {
+			switch (type) {
+			case USB_ENDPOINT_XFER_INT:
+				/* bulk endpoints handle interrupt transfers,
+				 * except the toggle-quirky iso-synch kind
+				 */
+				if ('s' == tmp[2])	/* == "-iso" */
+					return 0;
+				/* for now, avoid PXA "interrupt-in";
+				 * it's documented as never using DATA1.
+				 */
+				if (gadget_is_pxa(gadget)
+						&& 'i' == tmp[1])
+					return 0;
+				break;
+			case USB_ENDPOINT_XFER_BULK:
+				if ('b' != tmp[1])	/* != "-bulk" */
+					return 0;
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				if ('s' != tmp[2])	/* != "-iso" */
+					return 0;
+			}
+		} else {
+			tmp = ep->name + strlen(ep->name);
+		}
+
+		/* direction-restriction:  "..in-..", "out-.." */
+		tmp--;
+		if (!isdigit(*tmp)) {
+			if (desc->bEndpointAddress & USB_DIR_IN) {
+				if ('n' != *tmp)
+					return 0;
+			} else {
+				if ('t' != *tmp)
+					return 0;
+			}
+		}
+	}
+
+	/* endpoint maxpacket size is an input parameter, except for bulk
+	 * where it's an output parameter representing the full speed limit.
+	 * the usb spec fixes high speed bulk maxpacket at 512 bytes.
+	 */
+	max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+	switch (type) {
+	case USB_ENDPOINT_XFER_INT:
+		/* INT:  limit 64 bytes full speed, 1024 high speed */
+		if (!gadget->is_dualspeed && max > 64)
+			return 0;
+		/* FALLTHROUGH */
+
+	case USB_ENDPOINT_XFER_ISOC:
+		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
+		if (ep->maxpacket < max)
+			return 0;
+		if (!gadget->is_dualspeed && max > 1023)
+			return 0;
+
+		/* BOTH:  "high bandwidth" works only at high speed */
+		if ((get_unaligned(&desc->wMaxPacketSize) &
+					__constant_cpu_to_le16(3<<11))) {
+			if (!gadget->is_dualspeed)
+				return 0;
+			/* configure your hardware with enough buffering!! */
+		}
+		break;
+	}
+
+	/* MATCH!! */
+
+	/* report address */
+	if (isdigit(ep->name[2])) {
+		u8	num = simple_strtoul(&ep->name[2], NULL, 10);
+		desc->bEndpointAddress |= num;
+#ifdef	MANY_ENDPOINTS
+	} else if (desc->bEndpointAddress & USB_DIR_IN) {
+		if (++in_epnum > 15)
+			return 0;
+		desc->bEndpointAddress = USB_DIR_IN | in_epnum;
+#endif
+	} else {
+		if (++epnum > 15)
+			return 0;
+		desc->bEndpointAddress |= epnum;
+	}
+
+	/* report (variable) full speed bulk maxpacket */
+	if (USB_ENDPOINT_XFER_BULK == type) {
+		int size = ep->maxpacket;
+
+		/* min() doesn't work on bitfields with gcc-3.5 */
+		if (size > 64)
+			size = 64;
+		put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
+	}
+
+	if (gadget->ops->ep_conf)
+		return gadget->ops->ep_conf(gadget, ep, desc);
+
+	return 1;
+}
+
+static struct usb_ep *
+find_ep(struct usb_gadget *gadget, const char *name)
+{
+	struct usb_ep	*ep;
+
+	list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+		if (0 == strcmp(ep->name, name))
+			return ep;
+	}
+	return NULL;
+}
+
+/**
+ * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.  For periodic transfers, the maximum packet
+ *	size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	struct usb_ep	*ep = NULL;
+	u8		type;
+
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	/* First, apply chip-specific "best usage" knowledge.
+	 * This might make a good usb_gadget_ops hook ...
+	 */
+	if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) {
+		/* ep-e, ep-f are PIO with only 64 byte fifos */
+		ep = find_ep(gadget, "ep-e");
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
+		ep = find_ep(gadget, "ep-f");
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
+
+	} else if (gadget_is_goku(gadget)) {
+		if (USB_ENDPOINT_XFER_INT == type) {
+			/* single buffering is enough */
+			ep = find_ep(gadget, "ep3-bulk");
+			if (ep && ep_matches(gadget, ep, desc))
+				return ep;
+		} else if (USB_ENDPOINT_XFER_BULK == type
+				&& (USB_DIR_IN & desc->bEndpointAddress)) {
+			/* DMA may be available */
+			ep = find_ep(gadget, "ep2-bulk");
+			if (ep && ep_matches(gadget, ep, desc))
+				return ep;
+		}
+
+	} else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) {
+		/* single buffering is enough; maybe 8 byte fifo is too */
+		ep = find_ep(gadget, "ep3in-bulk");
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
+
+	} else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) {
+		ep = find_ep(gadget, "ep1-bulk");
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
+#ifndef CONFIG_SPL_BUILD
+	} else if (gadget_is_dwc3(gadget)) {
+		const char *name = NULL;
+		/*
+		 * First try standard, common configuration: ep1in-bulk,
+		 * ep2out-bulk, ep3in-int to match other udc drivers to avoid
+		 * confusion in already deployed software (endpoint numbers
+		 * hardcoded in userspace software/drivers)
+		 */
+		if ((desc->bEndpointAddress & USB_DIR_IN) &&
+		    type == USB_ENDPOINT_XFER_BULK)
+			name = "ep1in";
+		else if ((desc->bEndpointAddress & USB_DIR_IN) == 0 &&
+			 type == USB_ENDPOINT_XFER_BULK)
+			name = "ep2out";
+		else if ((desc->bEndpointAddress & USB_DIR_IN) &&
+			 type == USB_ENDPOINT_XFER_INT)
+			name = "ep3in";
+
+		if (name)
+			ep = find_ep(gadget, name);
+		if (ep && ep_matches(gadget, ep, desc))
+			return ep;
+#endif
+	}
+
+	if (gadget->ops->match_ep)
+		ep = gadget->ops->match_ep(gadget, desc, NULL);
+
+	/* Second, look at endpoints until an unclaimed one looks usable */
+	list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+		if (ep_matches(gadget, ep, desc))
+			return ep;
+	}
+
+	/* Fail */
+	return NULL;
+}
+
+/**
+ * usb_ep_autoconfig_reset - reset endpoint autoconfig state
+ * @gadget: device for which autoconfig state will be reset
+ *
+ * Use this for devices where one configuration may need to assign
+ * endpoint resources very differently from the next one.  It clears
+ * state such as ep->driver_data and the record of assigned endpoints
+ * used by usb_ep_autoconfig().
+ */
+void usb_ep_autoconfig_reset(struct usb_gadget *gadget)
+{
+	struct usb_ep	*ep;
+
+	list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+		ep->driver_data = NULL;
+	}
+#ifdef	MANY_ENDPOINTS
+	in_epnum = 0;
+#endif
+	epnum = 0;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/ether.c b/roms/u-boot/drivers/usb/gadget/ether.c
new file mode 100644
index 000000000..16922ff15
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/ether.c
@@ -0,0 +1,2706 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ether.c -- Ethernet gadget driver, with CDC and non-CDC options
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ */
+
+#include <common.h>
+#include <console.h>
+#include <env.h>
+#include <log.h>
+#include <part.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/gadget.h>
+#include <net.h>
+#include <usb.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <linux/ctype.h>
+
+#include "gadget_chips.h"
+#include "rndis.h"
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <dm/device-internal.h>
+
+#define USB_NET_NAME "usb_ether"
+
+extern struct platform_data brd;
+
+
+unsigned packet_received, packet_sent;
+
+/*
+ * Ethernet gadget driver -- with CDC and non-CDC options
+ * Builds on hardware support for a full duplex link.
+ *
+ * CDC Ethernet is the standard USB solution for sending Ethernet frames
+ * using USB.  Real hardware tends to use the same framing protocol but look
+ * different for control features.  This driver strongly prefers to use
+ * this USB-IF standard as its open-systems interoperability solution;
+ * most host side USB stacks (except from Microsoft) support it.
+ *
+ * This is sometimes called "CDC ECM" (Ethernet Control Model) to support
+ * TLA-soup.  "CDC ACM" (Abstract Control Model) is for modems, and a new
+ * "CDC EEM" (Ethernet Emulation Model) is starting to spread.
+ *
+ * There's some hardware that can't talk CDC ECM.  We make that hardware
+ * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
+ *
+ * A third option is also in use.  Rather than CDC Ethernet, or something
+ * simpler, Microsoft pushes their own approach: RNDIS.  The published
+ * RNDIS specs are ambiguous and appear to be incomplete, and are also
+ * needlessly complex.  They borrow more from CDC ACM than CDC ECM.
+ */
+
+#define DRIVER_DESC		"Ethernet Gadget"
+/* Based on linux 2.6.27 version */
+#define DRIVER_VERSION		"May Day 2005"
+
+static const char driver_desc[] = DRIVER_DESC;
+
+#define RX_EXTRA	20		/* guard against rx overflows */
+
+#ifndef	CONFIG_USB_ETH_RNDIS
+#define rndis_uninit(x)		do {} while (0)
+#define rndis_deregister(c)	do {} while (0)
+#define rndis_exit()		do {} while (0)
+#endif
+
+/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
+#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
+			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
+			|USB_CDC_PACKET_TYPE_DIRECTED)
+
+#define USB_CONNECT_TIMEOUT (3 * CONFIG_SYS_HZ)
+
+/*-------------------------------------------------------------------------*/
+
+struct eth_dev {
+	struct usb_gadget	*gadget;
+	struct usb_request	*req;		/* for control responses */
+	struct usb_request	*stat_req;	/* for cdc & rndis status */
+
+	u8			config;
+	struct usb_ep		*in_ep, *out_ep, *status_ep;
+	const struct usb_endpoint_descriptor
+				*in, *out, *status;
+
+	struct usb_request	*tx_req, *rx_req;
+
+#ifndef CONFIG_DM_ETH
+	struct eth_device	*net;
+#else
+	struct udevice		*net;
+#endif
+	struct net_device_stats	stats;
+	unsigned int		tx_qlen;
+
+	unsigned		zlp:1;
+	unsigned		cdc:1;
+	unsigned		rndis:1;
+	unsigned		suspended:1;
+	unsigned		network_started:1;
+	u16			cdc_filter;
+	unsigned long		todo;
+	int			mtu;
+#define	WORK_RX_MEMORY		0
+	int			rndis_config;
+	u8			host_mac[ETH_ALEN];
+};
+
+/*
+ * This version autoconfigures as much as possible at run-time.
+ *
+ * It also ASSUMES a self-powered device, without remote wakeup,
+ * although remote wakeup support would make sense.
+ */
+
+/*-------------------------------------------------------------------------*/
+struct ether_priv {
+	struct eth_dev ethdev;
+#ifndef CONFIG_DM_ETH
+	struct eth_device netdev;
+#else
+	struct udevice *netdev;
+#endif
+	struct usb_gadget_driver eth_driver;
+};
+
+struct ether_priv eth_priv;
+struct ether_priv *l_priv = &eth_priv;
+
+/*-------------------------------------------------------------------------*/
+
+/* "main" config is either CDC, or its simple subset */
+static inline int is_cdc(struct eth_dev *dev)
+{
+#if	!defined(CONFIG_USB_ETH_SUBSET)
+	return 1;		/* only cdc possible */
+#elif	!defined(CONFIG_USB_ETH_CDC)
+	return 0;		/* only subset possible */
+#else
+	return dev->cdc;	/* depends on what hardware we found */
+#endif
+}
+
+/* "secondary" RNDIS config may sometimes be activated */
+static inline int rndis_active(struct eth_dev *dev)
+{
+#ifdef	CONFIG_USB_ETH_RNDIS
+	return dev->rndis;
+#else
+	return 0;
+#endif
+}
+
+#define	subset_active(dev)	(!is_cdc(dev) && !rndis_active(dev))
+#define	cdc_active(dev)		(is_cdc(dev) && !rndis_active(dev))
+
+#define DEFAULT_QLEN	2	/* double buffering by default */
+
+/* peak bulk transfer bits-per-second */
+#define	HS_BPS		(13 * 512 * 8 * 1000 * 8)
+#define	FS_BPS		(19 *  64 * 1 * 1000 * 8)
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+#define	DEVSPEED	USB_SPEED_HIGH
+
+#ifdef CONFIG_USB_ETH_QMULT
+#define qmult CONFIG_USB_ETH_QMULT
+#else
+#define qmult 5
+#endif
+
+/* for dual-speed hardware, use deeper queues at highspeed */
+#define qlen(gadget) \
+	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
+
+static inline int BITRATE(struct usb_gadget *g)
+{
+	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
+}
+
+#else	/* full speed (low speed doesn't do bulk) */
+
+#define qmult		1
+
+#define	DEVSPEED	USB_SPEED_FULL
+
+#define qlen(gadget) DEFAULT_QLEN
+
+static inline int BITRATE(struct usb_gadget *g)
+{
+	return FS_BPS;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only CDC Ethernet configurations.
+ */
+#define CDC_VENDOR_NUM		0x0525	/* NetChip */
+#define CDC_PRODUCT_NUM		0xa4a1	/* Linux-USB Ethernet Gadget */
+
+/*
+ * For hardware that can't talk CDC, we use the same vendor ID that
+ * ARM Linux has used for ethernet-over-usb, both with sa1100 and
+ * with pxa250.  We're protocol-compatible, if the host-side drivers
+ * use the endpoint descriptors.  bcdDevice (version) is nonzero, so
+ * drivers that need to hard-wire endpoint numbers have a hook.
+ *
+ * The protocol is a minimal subset of CDC Ether, which works on any bulk
+ * hardware that's not deeply broken ... even on hardware that can't talk
+ * RNDIS (like SA-1100, with no interrupt endpoint, or anything that
+ * doesn't handle control-OUT).
+ */
+#define	SIMPLE_VENDOR_NUM	0x049f	/* Compaq Computer Corp. */
+#define	SIMPLE_PRODUCT_NUM	0x505a	/* Linux-USB "CDC Subset" Device */
+
+/*
+ * For hardware that can talk RNDIS and either of the above protocols,
+ * use this ID ... the windows INF files will know it.  Unless it's
+ * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose
+ * the non-RNDIS configuration.
+ */
+#define RNDIS_VENDOR_NUM	0x0525	/* NetChip */
+#define RNDIS_PRODUCT_NUM	0xa4a2	/* Ethernet/RNDIS Gadget */
+
+/*
+ * Some systems will want different product identifers published in the
+ * device descriptor, either numbers or strings or both.  These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+/*
+ * Emulating them in eth_bind:
+ * static ushort idVendor;
+ * static ushort idProduct;
+ */
+
+#if defined(CONFIG_USB_GADGET_MANUFACTURER)
+static char *iManufacturer = CONFIG_USB_GADGET_MANUFACTURER;
+#else
+static char *iManufacturer = "U-Boot";
+#endif
+
+/* These probably need to be configurable. */
+static ushort bcdDevice;
+static char *iProduct;
+static char *iSerialNumber;
+
+static char dev_addr[18];
+
+static char host_addr[18];
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+ * ep0 implementation:  descriptors, config management, setup().
+ * also optional class-specific notification interrupt transfer.
+ */
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand.  For now we do either full CDC, or
+ * our simple subset, with RNDIS as an optional second configuration.
+ *
+ * RNDIS includes some CDC ACM descriptors ... like CDC Ethernet.  But
+ * the class descriptors match a modem (they're ignored; it's really just
+ * Ethernet functionality), they don't need the NOP altsetting, and the
+ * status transfer endpoint isn't optional.
+ */
+
+#define STRING_MANUFACTURER		1
+#define STRING_PRODUCT			2
+#define STRING_ETHADDR			3
+#define STRING_DATA			4
+#define STRING_CONTROL			5
+#define STRING_RNDIS_CONTROL		6
+#define STRING_CDC			7
+#define STRING_SUBSET			8
+#define STRING_RNDIS			9
+#define STRING_SERIALNUMBER		10
+
+/* holds our biggest descriptor (or RNDIS response) */
+#define USB_BUFSIZ	256
+
+/*
+ * This device advertises one configuration, eth_config, unless RNDIS
+ * is enabled (rndis_config) on hardware supporting at least two configs.
+ *
+ * NOTE:  Controllers like superh_udc should probably be able to use
+ * an RNDIS-only configuration.
+ *
+ * FIXME define some higher-powered configurations to make it easier
+ * to recharge batteries ...
+ */
+
+#define DEV_CONFIG_VALUE	1	/* cdc or subset */
+#define DEV_RNDIS_CONFIG_VALUE	2	/* rndis; optional */
+
+static struct usb_device_descriptor
+device_desc = {
+	.bLength =		sizeof device_desc,
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+
+	.bDeviceClass =		USB_CLASS_COMM,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
+
+	.idVendor =		__constant_cpu_to_le16(CDC_VENDOR_NUM),
+	.idProduct =		__constant_cpu_to_le16(CDC_PRODUCT_NUM),
+	.iManufacturer =	STRING_MANUFACTURER,
+	.iProduct =		STRING_PRODUCT,
+	.bNumConfigurations =	1,
+};
+
+static struct usb_otg_descriptor
+otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+
+	.bmAttributes =		USB_OTG_SRP,
+};
+
+static struct usb_config_descriptor
+eth_config = {
+	.bLength =		sizeof eth_config,
+	.bDescriptorType =	USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =	2,
+	.bConfigurationValue =	DEV_CONFIG_VALUE,
+	.iConfiguration =	STRING_CDC,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower =		1,
+};
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+static struct usb_config_descriptor
+rndis_config = {
+	.bLength =              sizeof rndis_config,
+	.bDescriptorType =      USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =       2,
+	.bConfigurationValue =  DEV_RNDIS_CONFIG_VALUE,
+	.iConfiguration =       STRING_RNDIS,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower =            1,
+};
+#endif
+
+/*
+ * Compared to the simple CDC subset, the full CDC Ethernet model adds
+ * three class descriptors, two interface descriptors, optional status
+ * endpoint.  Both have a "data" interface and two bulk endpoints.
+ * There are also differences in how control requests are handled.
+ *
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet.   We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+ * get those drivers from MCCI, or bundled with various products.
+ */
+
+#ifdef	CONFIG_USB_ETH_CDC
+static struct usb_interface_descriptor
+control_intf = {
+	.bLength =		sizeof control_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	0,
+	/* status endpoint is optional; this may be patched later */
+	.bNumEndpoints =	1,
+	.bInterfaceClass =	USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_ETHERNET,
+	.bInterfaceProtocol =	USB_CDC_PROTO_NONE,
+	.iInterface =		STRING_CONTROL,
+};
+#endif
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+static const struct usb_interface_descriptor
+rndis_control_intf = {
+	.bLength =              sizeof rndis_control_intf,
+	.bDescriptorType =      USB_DT_INTERFACE,
+
+	.bInterfaceNumber =     0,
+	.bNumEndpoints =        1,
+	.bInterfaceClass =      USB_CLASS_COMM,
+	.bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+	.bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
+	.iInterface =           STRING_RNDIS_CONTROL,
+};
+#endif
+
+static const struct usb_cdc_header_desc header_desc = {
+	.bLength =		sizeof header_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+
+	.bcdCDC =		__constant_cpu_to_le16(0x0110),
+};
+
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
+static const struct usb_cdc_union_desc union_desc = {
+	.bLength =		sizeof union_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+
+	.bMasterInterface0 =	0,	/* index of control interface */
+	.bSlaveInterface0 =	1,	/* index of DATA interface */
+};
+
+#endif	/* CDC || RNDIS */
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+
+static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
+	.bLength =		sizeof call_mgmt_descriptor,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+
+	.bmCapabilities =	0x00,
+	.bDataInterface =	0x01,
+};
+
+static const struct usb_cdc_acm_descriptor acm_descriptor = {
+	.bLength =		sizeof acm_descriptor,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+
+	.bmCapabilities =	0x00,
+};
+
+#endif
+
+#ifndef CONFIG_USB_ETH_CDC
+
+/*
+ * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways:  data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+	.bLength =		sizeof mdlm_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_MDLM_TYPE,
+
+	.bcdVersion =		__constant_cpu_to_le16(0x0100),
+	.bGUID = {
+		0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+		0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+	},
+};
+
+/*
+ * since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct.  All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+#ifdef CONFIG_USB_ETH_SUBSET
+static const u8 mdlm_detail_desc[] = {
+	6,
+	USB_DT_CS_INTERFACE,
+	USB_CDC_MDLM_DETAIL_TYPE,
+
+	0,	/* "SAFE" */
+	0,	/* network control capabilities (none) */
+	0,	/* network data capabilities ("raw" encapsulation) */
+};
+#endif
+
+#endif
+
+static const struct usb_cdc_ether_desc ether_desc = {
+	.bLength =		sizeof(ether_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ETHERNET_TYPE,
+
+	/* this descriptor actually adds value, surprise! */
+	.iMACAddress =		STRING_ETHADDR,
+	.bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
+	.wMaxSegmentSize =	__constant_cpu_to_le16(PKTSIZE_ALIGN),
+	.wNumberMCFilters =	__constant_cpu_to_le16(0),
+	.bNumberPowerFilters =	0,
+};
+
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
+/*
+ * include the status endpoint if we can, even where it's optional.
+ * use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+ * packet, to simplify cancellation; and a big transfer interval, to
+ * waste less bandwidth.
+ *
+ * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even
+ * if they ignore the connect/disconnect notifications that real aether
+ * can provide.  more advanced cdc configurations might want to support
+ * encapsulated commands (vendor-specific, using control-OUT).
+ *
+ * RNDIS requires the status endpoint, since it uses that encapsulation
+ * mechanism for its funky RPC scheme.
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
+#define STATUS_BYTECOUNT		16	/* 8 byte header + data */
+
+static struct usb_endpoint_descriptor
+fs_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+#endif
+
+#ifdef	CONFIG_USB_ETH_CDC
+
+/* the default data interface has no endpoints ... */
+
+static const struct usb_interface_descriptor
+data_nop_intf = {
+	.bLength =		sizeof data_nop_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	1,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	0,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+};
+
+/* ... but the "real" data interface has two bulk endpoints */
+
+static const struct usb_interface_descriptor
+data_intf = {
+	.bLength =		sizeof data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	1,
+	.bAlternateSetting =	1,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	.iInterface =		STRING_DATA,
+};
+
+#endif
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+
+/* RNDIS doesn't activate by changing to the "real" altsetting */
+
+static const struct usb_interface_descriptor
+rndis_data_intf = {
+	.bLength =		sizeof rndis_data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	1,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	.iInterface =		STRING_DATA,
+};
+
+#endif
+
+#ifdef CONFIG_USB_ETH_SUBSET
+
+/*
+ * "Simple" CDC-subset option is a simple vendor-neutral model that most
+ * full speed controllers can handle:  one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
+ */
+
+static const struct usb_interface_descriptor
+subset_data_intf = {
+	.bLength =		sizeof subset_data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	0,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =      USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_MDLM,
+	.bInterfaceProtocol =	0,
+	.iInterface =		STRING_DATA,
+};
+
+#endif	/* SUBSET */
+
+static struct usb_endpoint_descriptor
+fs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor
+fs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(64),
+};
+
+static const struct usb_descriptor_header *fs_eth_function[11] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+#ifdef CONFIG_USB_ETH_CDC
+	/* "cdc" mode descriptors */
+	(struct usb_descriptor_header *) &control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &union_desc,
+	(struct usb_descriptor_header *) &ether_desc,
+	/* NOTE: status endpoint may need to be removed */
+	(struct usb_descriptor_header *) &fs_status_desc,
+	/* data interface, with altsetting */
+	(struct usb_descriptor_header *) &data_nop_intf,
+	(struct usb_descriptor_header *) &data_intf,
+	(struct usb_descriptor_header *) &fs_source_desc,
+	(struct usb_descriptor_header *) &fs_sink_desc,
+	NULL,
+#endif /* CONFIG_USB_ETH_CDC */
+};
+
+static inline void fs_subset_descriptors(void)
+{
+#ifdef CONFIG_USB_ETH_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
+	fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+	fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+	fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+	fs_eth_function[8] = NULL;
+#else
+	fs_eth_function[1] = NULL;
+#endif
+}
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+static const struct usb_descriptor_header *fs_rndis_function[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &acm_descriptor,
+	(struct usb_descriptor_header *) &union_desc,
+	(struct usb_descriptor_header *) &fs_status_desc,
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_data_intf,
+	(struct usb_descriptor_header *) &fs_source_desc,
+	(struct usb_descriptor_header *) &fs_sink_desc,
+	NULL,
+};
+#endif
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+static struct usb_endpoint_descriptor
+hs_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+#endif /* CONFIG_USB_ETH_CDC */
+
+static struct usb_endpoint_descriptor
+hs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor
+hs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_qualifier_descriptor
+dev_qualifier = {
+	.bLength =		sizeof dev_qualifier,
+	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+	.bDeviceClass =		USB_CLASS_COMM,
+
+	.bNumConfigurations =	1,
+};
+
+static const struct usb_descriptor_header *hs_eth_function[11] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+#ifdef CONFIG_USB_ETH_CDC
+	/* "cdc" mode descriptors */
+	(struct usb_descriptor_header *) &control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &union_desc,
+	(struct usb_descriptor_header *) &ether_desc,
+	/* NOTE: status endpoint may need to be removed */
+	(struct usb_descriptor_header *) &hs_status_desc,
+	/* data interface, with altsetting */
+	(struct usb_descriptor_header *) &data_nop_intf,
+	(struct usb_descriptor_header *) &data_intf,
+	(struct usb_descriptor_header *) &hs_source_desc,
+	(struct usb_descriptor_header *) &hs_sink_desc,
+	NULL,
+#endif /* CONFIG_USB_ETH_CDC */
+};
+
+static inline void hs_subset_descriptors(void)
+{
+#ifdef CONFIG_USB_ETH_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
+	hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+	hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+	hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+	hs_eth_function[8] = NULL;
+#else
+	hs_eth_function[1] = NULL;
+#endif
+}
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+static const struct usb_descriptor_header *hs_rndis_function[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &acm_descriptor,
+	(struct usb_descriptor_header *) &union_desc,
+	(struct usb_descriptor_header *) &hs_status_desc,
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_data_intf,
+	(struct usb_descriptor_header *) &hs_source_desc,
+	(struct usb_descriptor_header *) &hs_sink_desc,
+	NULL,
+};
+#endif
+
+
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* descriptors that are built on-demand */
+
+static char manufacturer[50];
+static char product_desc[40] = DRIVER_DESC;
+static char serial_number[20];
+
+/* address that the host will use ... usually assigned at random */
+static char ethaddr[2 * ETH_ALEN + 1];
+
+/* static strings, in UTF-8 */
+static struct usb_string		strings[] = {
+	{ STRING_MANUFACTURER,	manufacturer, },
+	{ STRING_PRODUCT,	product_desc, },
+	{ STRING_SERIALNUMBER,	serial_number, },
+	{ STRING_DATA,		"Ethernet Data", },
+	{ STRING_ETHADDR,	ethaddr, },
+#ifdef	CONFIG_USB_ETH_CDC
+	{ STRING_CDC,		"CDC Ethernet", },
+	{ STRING_CONTROL,	"CDC Communications Control", },
+#endif
+#ifdef	CONFIG_USB_ETH_SUBSET
+	{ STRING_SUBSET,	"CDC Ethernet Subset", },
+#endif
+#ifdef	CONFIG_USB_ETH_RNDIS
+	{ STRING_RNDIS,		"RNDIS", },
+	{ STRING_RNDIS_CONTROL,	"RNDIS Communications Control", },
+#endif
+	{  }		/* end of list */
+};
+
+static struct usb_gadget_strings	stringtab = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings,
+};
+
+/*============================================================================*/
+DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ);
+
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT);
+#endif
+
+/*============================================================================*/
+
+/*
+ * one config, two interfaces:  control, data.
+ * complications: class descriptors, and an altsetting.
+ */
+static int
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
+{
+	int					len;
+	const struct usb_config_descriptor	*config;
+	const struct usb_descriptor_header	**function;
+	int					hs = 0;
+
+	if (gadget_is_dualspeed(g)) {
+		hs = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
+#define which_fn(t)	(hs ? hs_ ## t ## _function : fs_ ## t ## _function)
+
+	if (index >= device_desc.bNumConfigurations)
+		return -EINVAL;
+
+#ifdef	CONFIG_USB_ETH_RNDIS
+	/*
+	 * list the RNDIS config first, to make Microsoft's drivers
+	 * happy. DOCSIS 1.0 needs this too.
+	 */
+	if (device_desc.bNumConfigurations == 2 && index == 0) {
+		config = &rndis_config;
+		function = which_fn(rndis);
+	} else
+#endif
+	{
+		config = &eth_config;
+		function = which_fn(eth);
+	}
+
+	/* for now, don't advertise srp-only devices */
+	if (!is_otg)
+		function++;
+
+	len = usb_gadget_config_buf(config, buf, USB_BUFSIZ, function);
+	if (len < 0)
+		return len;
+	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+	return len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_start(struct eth_dev *dev, gfp_t gfp_flags);
+static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags);
+
+static int
+set_ether_config(struct eth_dev *dev, gfp_t gfp_flags)
+{
+	int					result = 0;
+	struct usb_gadget			*gadget = dev->gadget;
+
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+	/* status endpoint used for RNDIS and (optionally) CDC */
+	if (!subset_active(dev) && dev->status_ep) {
+		dev->status = ep_desc(gadget, &hs_status_desc,
+						&fs_status_desc);
+		dev->status_ep->driver_data = dev;
+
+		result = usb_ep_enable(dev->status_ep, dev->status);
+		if (result != 0) {
+			debug("enable %s --> %d\n",
+				dev->status_ep->name, result);
+			goto done;
+		}
+	}
+#endif
+
+	dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+	dev->in_ep->driver_data = dev;
+
+	dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+	dev->out_ep->driver_data = dev;
+
+	/*
+	 * With CDC,  the host isn't allowed to use these two data
+	 * endpoints in the default altsetting for the interface.
+	 * so we don't activate them yet.  Reset from SET_INTERFACE.
+	 *
+	 * Strictly speaking RNDIS should work the same: activation is
+	 * a side effect of setting a packet filter.  Deactivation is
+	 * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG.
+	 */
+	if (!cdc_active(dev)) {
+		result = usb_ep_enable(dev->in_ep, dev->in);
+		if (result != 0) {
+			debug("enable %s --> %d\n",
+				dev->in_ep->name, result);
+			goto done;
+		}
+
+		result = usb_ep_enable(dev->out_ep, dev->out);
+		if (result != 0) {
+			debug("enable %s --> %d\n",
+				dev->out_ep->name, result);
+			goto done;
+		}
+	}
+
+done:
+	if (result == 0)
+		result = alloc_requests(dev, qlen(gadget), gfp_flags);
+
+	/* on error, disable any endpoints  */
+	if (result < 0) {
+		if (!subset_active(dev) && dev->status_ep)
+			(void) usb_ep_disable(dev->status_ep);
+		dev->status = NULL;
+		(void) usb_ep_disable(dev->in_ep);
+		(void) usb_ep_disable(dev->out_ep);
+		dev->in = NULL;
+		dev->out = NULL;
+	} else if (!cdc_active(dev)) {
+		/*
+		 * activate non-CDC configs right away
+		 * this isn't strictly according to the RNDIS spec
+		 */
+		eth_start(dev, GFP_ATOMIC);
+	}
+
+	/* caller is responsible for cleanup on error */
+	return result;
+}
+
+static void eth_reset_config(struct eth_dev *dev)
+{
+	if (dev->config == 0)
+		return;
+
+	debug("%s\n", __func__);
+
+	rndis_uninit(dev->rndis_config);
+
+	/*
+	 * disable endpoints, forcing (synchronous) completion of
+	 * pending i/o.  then free the requests.
+	 */
+
+	if (dev->in) {
+		usb_ep_disable(dev->in_ep);
+		if (dev->tx_req) {
+			usb_ep_free_request(dev->in_ep, dev->tx_req);
+			dev->tx_req = NULL;
+		}
+	}
+	if (dev->out) {
+		usb_ep_disable(dev->out_ep);
+		if (dev->rx_req) {
+			usb_ep_free_request(dev->out_ep, dev->rx_req);
+			dev->rx_req = NULL;
+		}
+	}
+	if (dev->status)
+		usb_ep_disable(dev->status_ep);
+
+	dev->rndis = 0;
+	dev->cdc_filter = 0;
+	dev->config = 0;
+}
+
+/*
+ * change our operational config.  must agree with the code
+ * that returns config descriptors, and altsetting code.
+ */
+static int eth_set_config(struct eth_dev *dev, unsigned number,
+				gfp_t gfp_flags)
+{
+	int			result = 0;
+	struct usb_gadget	*gadget = dev->gadget;
+
+	if (gadget_is_sa1100(gadget)
+			&& dev->config
+			&& dev->tx_qlen != 0) {
+		/* tx fifo is full, but we can't clear it...*/
+		pr_err("can't change configurations");
+		return -ESPIPE;
+	}
+	eth_reset_config(dev);
+
+	switch (number) {
+	case DEV_CONFIG_VALUE:
+		result = set_ether_config(dev, gfp_flags);
+		break;
+#ifdef	CONFIG_USB_ETH_RNDIS
+	case DEV_RNDIS_CONFIG_VALUE:
+		dev->rndis = 1;
+		result = set_ether_config(dev, gfp_flags);
+		break;
+#endif
+	default:
+		result = -EINVAL;
+		/* FALL THROUGH */
+	case 0:
+		break;
+	}
+
+	if (result) {
+		if (number)
+			eth_reset_config(dev);
+		usb_gadget_vbus_draw(dev->gadget,
+				gadget_is_otg(dev->gadget) ? 8 : 100);
+	} else {
+		char *speed;
+		unsigned power;
+
+		power = 2 * eth_config.bMaxPower;
+		usb_gadget_vbus_draw(dev->gadget, power);
+
+		switch (gadget->speed) {
+		case USB_SPEED_FULL:
+			speed = "full"; break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+		case USB_SPEED_HIGH:
+			speed = "high"; break;
+#endif
+		default:
+			speed = "?"; break;
+		}
+
+		dev->config = number;
+		printf("%s speed config #%d: %d mA, %s, using %s\n",
+				speed, number, power, driver_desc,
+				rndis_active(dev)
+					? "RNDIS"
+					: (cdc_active(dev)
+						? "CDC Ethernet"
+						: "CDC Ethernet Subset"));
+	}
+	return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_USB_ETH_CDC
+
+/*
+ * The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
+ * only to notify the host about link status changes (which we support) or
+ * report completion of some encapsulated command (as used in RNDIS).  Since
+ * we want this CDC Ethernet code to be vendor-neutral, we don't use that
+ * command mechanism; and only one status request is ever queued.
+ */
+static void eth_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usb_cdc_notification	*event = req->buf;
+	int				value = req->status;
+	struct eth_dev			*dev = ep->driver_data;
+
+	/* issue the second notification if host reads the first */
+	if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION
+			&& value == 0) {
+		__le32	*data = req->buf + sizeof *event;
+
+		event->bmRequestType = 0xA1;
+		event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
+		event->wValue = __constant_cpu_to_le16(0);
+		event->wIndex = __constant_cpu_to_le16(1);
+		event->wLength = __constant_cpu_to_le16(8);
+
+		/* SPEED_CHANGE data is up/down speeds in bits/sec */
+		data[0] = data[1] = cpu_to_le32(BITRATE(dev->gadget));
+
+		req->length = STATUS_BYTECOUNT;
+		value = usb_ep_queue(ep, req, GFP_ATOMIC);
+		debug("send SPEED_CHANGE --> %d\n", value);
+		if (value == 0)
+			return;
+	} else if (value != -ECONNRESET) {
+		debug("event %02x --> %d\n",
+			event->bNotificationType, value);
+		if (event->bNotificationType ==
+				USB_CDC_NOTIFY_SPEED_CHANGE) {
+			dev->network_started = 1;
+			printf("USB network up!\n");
+		}
+	}
+	req->context = NULL;
+}
+
+static void issue_start_status(struct eth_dev *dev)
+{
+	struct usb_request		*req = dev->stat_req;
+	struct usb_cdc_notification	*event;
+	int				value;
+
+	/*
+	 * flush old status
+	 *
+	 * FIXME ugly idiom, maybe we'd be better with just
+	 * a "cancel the whole queue" primitive since any
+	 * unlink-one primitive has way too many error modes.
+	 * here, we "know" toggle is already clear...
+	 *
+	 * FIXME iff req->context != null just dequeue it
+	 */
+	usb_ep_disable(dev->status_ep);
+	usb_ep_enable(dev->status_ep, dev->status);
+
+	/*
+	 * 3.8.1 says to issue first NETWORK_CONNECTION, then
+	 * a SPEED_CHANGE.  could be useful in some configs.
+	 */
+	event = req->buf;
+	event->bmRequestType = 0xA1;
+	event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+	event->wValue = __constant_cpu_to_le16(1);	/* connected */
+	event->wIndex = __constant_cpu_to_le16(1);
+	event->wLength = 0;
+
+	req->length = sizeof *event;
+	req->complete = eth_status_complete;
+	req->context = dev;
+
+	value = usb_ep_queue(dev->status_ep, req, GFP_ATOMIC);
+	if (value < 0)
+		debug("status buf queue --> %d\n", value);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		debug("setup complete --> %d, %d/%d\n",
+				req->status, req->actual, req->length);
+}
+
+#ifdef CONFIG_USB_ETH_RNDIS
+
+static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		debug("rndis response complete --> %d, %d/%d\n",
+			req->status, req->actual, req->length);
+
+	/* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */
+}
+
+static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct eth_dev          *dev = ep->driver_data;
+	int			status;
+
+	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+	status = rndis_msg_parser(dev->rndis_config, (u8 *) req->buf);
+	if (status < 0)
+		pr_err("%s: rndis parse error %d", __func__, status);
+}
+
+#endif	/* RNDIS */
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down.  CDC has a number of less-common features:
+ *
+ *  - two interfaces:  control, and ethernet data
+ *  - Ethernet data interface has two altsettings:  default, and active
+ *  - class-specific descriptors for the control interface
+ *  - class-specific control requests
+ */
+static int
+eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct eth_dev		*dev = get_gadget_data(gadget);
+	struct usb_request	*req = dev->req;
+	int			value = -EOPNOTSUPP;
+	u16			wIndex = le16_to_cpu(ctrl->wIndex);
+	u16			wValue = le16_to_cpu(ctrl->wValue);
+	u16			wLength = le16_to_cpu(ctrl->wLength);
+
+	/*
+	 * descriptors just go into the pre-allocated ep0 buffer,
+	 * while config change events may enable network traffic.
+	 */
+
+	debug("%s\n", __func__);
+
+	req->complete = eth_setup_complete;
+	switch (ctrl->bRequest) {
+
+	case USB_REQ_GET_DESCRIPTOR:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			break;
+		switch (wValue >> 8) {
+
+		case USB_DT_DEVICE:
+			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+			value = min(wLength, (u16) sizeof device_desc);
+			memcpy(req->buf, &device_desc, value);
+			break;
+		case USB_DT_DEVICE_QUALIFIER:
+			if (!gadget_is_dualspeed(gadget))
+				break;
+			value = min(wLength, (u16) sizeof dev_qualifier);
+			memcpy(req->buf, &dev_qualifier, value);
+			break;
+
+		case USB_DT_OTHER_SPEED_CONFIG:
+			if (!gadget_is_dualspeed(gadget))
+				break;
+			/* FALLTHROUGH */
+		case USB_DT_CONFIG:
+			value = config_buf(gadget, req->buf,
+					wValue >> 8,
+					wValue & 0xff,
+					gadget_is_otg(gadget));
+			if (value >= 0)
+				value = min(wLength, (u16) value);
+			break;
+
+		case USB_DT_STRING:
+			value = usb_gadget_get_string(&stringtab,
+					wValue & 0xff, req->buf);
+
+			if (value >= 0)
+				value = min(wLength, (u16) value);
+
+			break;
+		}
+		break;
+
+	case USB_REQ_SET_CONFIGURATION:
+		if (ctrl->bRequestType != 0)
+			break;
+		if (gadget->a_hnp_support)
+			debug("HNP available\n");
+		else if (gadget->a_alt_hnp_support)
+			debug("HNP needs a different root port\n");
+		value = eth_set_config(dev, wValue, GFP_ATOMIC);
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			break;
+		*(u8 *)req->buf = dev->config;
+		value = min(wLength, (u16) 1);
+		break;
+
+	case USB_REQ_SET_INTERFACE:
+		if (ctrl->bRequestType != USB_RECIP_INTERFACE
+				|| !dev->config
+				|| wIndex > 1)
+			break;
+		if (!cdc_active(dev) && wIndex != 0)
+			break;
+
+		/*
+		 * PXA hardware partially handles SET_INTERFACE;
+		 * we need to kluge around that interference.
+		 */
+		if (gadget_is_pxa(gadget)) {
+			value = eth_set_config(dev, DEV_CONFIG_VALUE,
+						GFP_ATOMIC);
+			/*
+			 * PXA25x driver use non-CDC ethernet gadget.
+			 * But only _CDC and _RNDIS code can signalize
+			 * that network is working. So we signalize it
+			 * here.
+			 */
+			dev->network_started = 1;
+			debug("USB network up!\n");
+			goto done_set_intf;
+		}
+
+#ifdef CONFIG_USB_ETH_CDC
+		switch (wIndex) {
+		case 0:		/* control/master intf */
+			if (wValue != 0)
+				break;
+			if (dev->status) {
+				usb_ep_disable(dev->status_ep);
+				usb_ep_enable(dev->status_ep, dev->status);
+			}
+
+			value = 0;
+			break;
+		case 1:		/* data intf */
+			if (wValue > 1)
+				break;
+			usb_ep_disable(dev->in_ep);
+			usb_ep_disable(dev->out_ep);
+
+			/*
+			 * CDC requires the data transfers not be done from
+			 * the default interface setting ... also, setting
+			 * the non-default interface resets filters etc.
+			 */
+			if (wValue == 1) {
+				if (!cdc_active(dev))
+					break;
+				usb_ep_enable(dev->in_ep, dev->in);
+				usb_ep_enable(dev->out_ep, dev->out);
+				dev->cdc_filter = DEFAULT_FILTER;
+				if (dev->status)
+					issue_start_status(dev);
+				eth_start(dev, GFP_ATOMIC);
+			}
+			value = 0;
+			break;
+		}
+#else
+		/*
+		 * FIXME this is wrong, as is the assumption that
+		 * all non-PXA hardware talks real CDC ...
+		 */
+		debug("set_interface ignored!\n");
+#endif /* CONFIG_USB_ETH_CDC */
+
+done_set_intf:
+		break;
+	case USB_REQ_GET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+				|| !dev->config
+				|| wIndex > 1)
+			break;
+		if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0)
+			break;
+
+		/* for CDC, iff carrier is on, data interface is active. */
+		if (rndis_active(dev) || wIndex != 1)
+			*(u8 *)req->buf = 0;
+		else {
+			/* *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; */
+			/* carrier always ok ...*/
+			*(u8 *)req->buf = 1 ;
+		}
+		value = min(wLength, (u16) 1);
+		break;
+
+#ifdef CONFIG_USB_ETH_CDC
+	case USB_CDC_SET_ETHERNET_PACKET_FILTER:
+		/*
+		 * see 6.2.30: no data, wIndex = interface,
+		 * wValue = packet filter bitmap
+		 */
+		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+				|| !cdc_active(dev)
+				|| wLength != 0
+				|| wIndex > 1)
+			break;
+		debug("packet filter %02x\n", wValue);
+		dev->cdc_filter = wValue;
+		value = 0;
+		break;
+
+	/*
+	 * and potentially:
+	 * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+	 * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
+	 * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
+	 * case USB_CDC_GET_ETHERNET_STATISTIC:
+	 */
+
+#endif /* CONFIG_USB_ETH_CDC */
+
+#ifdef CONFIG_USB_ETH_RNDIS
+	/*
+	 * RNDIS uses the CDC command encapsulation mechanism to implement
+	 * an RPC scheme, with much getting/setting of attributes by OID.
+	 */
+	case USB_CDC_SEND_ENCAPSULATED_COMMAND:
+		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+				|| !rndis_active(dev)
+				|| wLength > USB_BUFSIZ
+				|| wValue
+				|| rndis_control_intf.bInterfaceNumber
+					!= wIndex)
+			break;
+		/* read the request, then process it */
+		value = wLength;
+		req->complete = rndis_command_complete;
+		/* later, rndis_control_ack () sends a notification */
+		break;
+
+	case USB_CDC_GET_ENCAPSULATED_RESPONSE:
+		if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+					== ctrl->bRequestType
+				&& rndis_active(dev)
+				/* && wLength >= 0x0400 */
+				&& !wValue
+				&& rndis_control_intf.bInterfaceNumber
+					== wIndex) {
+			u8 *buf;
+			u32 n;
+
+			/* return the result */
+			buf = rndis_get_next_response(dev->rndis_config, &n);
+			if (buf) {
+				memcpy(req->buf, buf, n);
+				req->complete = rndis_response_complete;
+				rndis_free_response(dev->rndis_config, buf);
+				value = n;
+			}
+			/* else stalls ... spec says to avoid that */
+		}
+		break;
+#endif	/* RNDIS */
+
+	default:
+		debug("unknown control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			wValue, wIndex, wLength);
+	}
+
+	/* respond with data transfer before status phase? */
+	if (value >= 0) {
+		debug("respond with data transfer before status phase\n");
+		req->length = value;
+		req->zero = value < wLength
+				&& (value % gadget->ep0->maxpacket) == 0;
+		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			debug("ep_queue --> %d\n", value);
+			req->status = 0;
+			eth_setup_complete(gadget->ep0, req);
+		}
+	}
+
+	/* host either stalls (value < 0) or reports success */
+	return value;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+
+static int rx_submit(struct eth_dev *dev, struct usb_request *req,
+				gfp_t gfp_flags)
+{
+	int			retval = -ENOMEM;
+	size_t			size;
+
+	/*
+	 * Padding up to RX_EXTRA handles minor disagreements with host.
+	 * Normally we use the USB "terminate on short read" convention;
+	 * so allow up to (N*maxpacket), since that memory is normally
+	 * already allocated.  Some hardware doesn't deal well with short
+	 * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
+	 * byte off the end (to force hardware errors on overflow).
+	 *
+	 * RNDIS uses internal framing, and explicitly allows senders to
+	 * pad to end-of-packet.  That's potentially nice for speed,
+	 * but means receivers can't recover synch on their own.
+	 */
+
+	debug("%s\n", __func__);
+	if (!req)
+		return -EINVAL;
+
+	size = (ETHER_HDR_SIZE + dev->mtu + RX_EXTRA);
+	size += dev->out_ep->maxpacket - 1;
+	if (rndis_active(dev))
+		size += sizeof(struct rndis_packet_msg_type);
+	size -= size % dev->out_ep->maxpacket;
+
+	/*
+	 * Some platforms perform better when IP packets are aligned,
+	 * but on at least one, checksumming fails otherwise.  Note:
+	 * RNDIS headers involve variable numbers of LE32 values.
+	 */
+
+	req->buf = (u8 *)net_rx_packets[0];
+	req->length = size;
+	req->complete = rx_complete;
+
+	retval = usb_ep_queue(dev->out_ep, req, gfp_flags);
+
+	if (retval)
+		pr_err("rx submit --> %d", retval);
+
+	return retval;
+}
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct eth_dev	*dev = ep->driver_data;
+
+	debug("%s: status %d\n", __func__, req->status);
+	switch (req->status) {
+	/* normal completion */
+	case 0:
+		if (rndis_active(dev)) {
+			/* we know MaxPacketsPerTransfer == 1 here */
+			int length = rndis_rm_hdr(req->buf, req->actual);
+			if (length < 0)
+				goto length_err;
+			req->length -= length;
+			req->actual -= length;
+		}
+		if (req->actual < ETH_HLEN || PKTSIZE_ALIGN < req->actual) {
+length_err:
+			dev->stats.rx_errors++;
+			dev->stats.rx_length_errors++;
+			debug("rx length %d\n", req->length);
+			break;
+		}
+
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += req->length;
+		break;
+
+	/* software-driven interface shutdown */
+	case -ECONNRESET:		/* unlink */
+	case -ESHUTDOWN:		/* disconnect etc */
+	/* for hardware automagic (such as pxa) */
+	case -ECONNABORTED:		/* endpoint reset */
+		break;
+
+	/* data overrun */
+	case -EOVERFLOW:
+		dev->stats.rx_over_errors++;
+		/* FALLTHROUGH */
+	default:
+		dev->stats.rx_errors++;
+		break;
+	}
+
+	packet_received = 1;
+}
+
+static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags)
+{
+
+	dev->tx_req = usb_ep_alloc_request(dev->in_ep, 0);
+
+	if (!dev->tx_req)
+		goto fail1;
+
+	dev->rx_req = usb_ep_alloc_request(dev->out_ep, 0);
+
+	if (!dev->rx_req)
+		goto fail2;
+
+	return 0;
+
+fail2:
+	usb_ep_free_request(dev->in_ep, dev->tx_req);
+fail1:
+	pr_err("can't alloc requests");
+	return -1;
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct eth_dev	*dev = ep->driver_data;
+
+	debug("%s: status %s\n", __func__, (req->status) ? "failed" : "ok");
+	switch (req->status) {
+	default:
+		dev->stats.tx_errors++;
+		debug("tx err %d\n", req->status);
+		/* FALLTHROUGH */
+	case -ECONNRESET:		/* unlink */
+	case -ESHUTDOWN:		/* disconnect etc */
+		break;
+	case 0:
+		dev->stats.tx_bytes += req->length;
+	}
+	dev->stats.tx_packets++;
+
+	packet_sent = 1;
+}
+
+static inline int eth_is_promisc(struct eth_dev *dev)
+{
+	/* no filters for the CDC subset; always promisc */
+	if (subset_active(dev))
+		return 1;
+	return dev->cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
+}
+
+#if 0
+static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
+{
+	struct eth_dev		*dev = netdev_priv(net);
+	int			length = skb->len;
+	int			retval;
+	struct usb_request	*req = NULL;
+	unsigned long		flags;
+
+	/* apply outgoing CDC or RNDIS filters */
+	if (!eth_is_promisc (dev)) {
+		u8		*dest = skb->data;
+
+		if (is_multicast_ethaddr(dest)) {
+			u16	type;
+
+			/* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
+			 * SET_ETHERNET_MULTICAST_FILTERS requests
+			 */
+			if (is_broadcast_ethaddr(dest))
+				type = USB_CDC_PACKET_TYPE_BROADCAST;
+			else
+				type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+			if (!(dev->cdc_filter & type)) {
+				dev_kfree_skb_any (skb);
+				return 0;
+			}
+		}
+		/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
+	}
+
+	spin_lock_irqsave(&dev->req_lock, flags);
+	/*
+	 * this freelist can be empty if an interrupt triggered disconnect()
+	 * and reconfigured the gadget (shutting down this queue) after the
+	 * network stack decided to xmit but before we got the spinlock.
+	 */
+	if (list_empty(&dev->tx_reqs)) {
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+		return 1;
+	}
+
+	req = container_of (dev->tx_reqs.next, struct usb_request, list);
+	list_del (&req->list);
+
+	/* temporarily stop TX queue when the freelist empties */
+	if (list_empty (&dev->tx_reqs))
+		netif_stop_queue (net);
+	spin_unlock_irqrestore(&dev->req_lock, flags);
+
+	/* no buffer copies needed, unless the network stack did it
+	 * or the hardware can't use skb buffers.
+	 * or there's not enough space for any RNDIS headers we need
+	 */
+	if (rndis_active(dev)) {
+		struct sk_buff	*skb_rndis;
+
+		skb_rndis = skb_realloc_headroom (skb,
+				sizeof (struct rndis_packet_msg_type));
+		if (!skb_rndis)
+			goto drop;
+
+		dev_kfree_skb_any (skb);
+		skb = skb_rndis;
+		rndis_add_hdr (skb);
+		length = skb->len;
+	}
+	req->buf = skb->data;
+	req->context = skb;
+	req->complete = tx_complete;
+
+	/* use zlp framing on tx for strict CDC-Ether conformance,
+	 * though any robust network rx path ignores extra padding.
+	 * and some hardware doesn't like to write zlps.
+	 */
+	req->zero = 1;
+	if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0)
+		length++;
+
+	req->length = length;
+
+	/* throttle highspeed IRQ rate back slightly */
+	if (gadget_is_dualspeed(dev->gadget))
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+			: 0;
+
+	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+	switch (retval) {
+	default:
+		DEBUG (dev, "tx queue err %d\n", retval);
+		break;
+	case 0:
+		net->trans_start = jiffies;
+		atomic_inc (&dev->tx_qlen);
+	}
+
+	if (retval) {
+drop:
+		dev->stats.tx_dropped++;
+		dev_kfree_skb_any (skb);
+		spin_lock_irqsave(&dev->req_lock, flags);
+		if (list_empty (&dev->tx_reqs))
+			netif_start_queue (net);
+		list_add (&req->list, &dev->tx_reqs);
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#endif
+
+static void eth_unbind(struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev = get_gadget_data(gadget);
+
+	debug("%s...\n", __func__);
+	rndis_deregister(dev->rndis_config);
+	rndis_exit();
+
+	/* we've already been disconnected ... no i/o is active */
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
+	if (dev->stat_req) {
+		usb_ep_free_request(dev->status_ep, dev->stat_req);
+		dev->stat_req = NULL;
+	}
+
+	if (dev->tx_req) {
+		usb_ep_free_request(dev->in_ep, dev->tx_req);
+		dev->tx_req = NULL;
+	}
+
+	if (dev->rx_req) {
+		usb_ep_free_request(dev->out_ep, dev->rx_req);
+		dev->rx_req = NULL;
+	}
+
+/*	unregister_netdev (dev->net);*/
+/*	free_netdev(dev->net);*/
+
+	dev->gadget = NULL;
+	set_gadget_data(gadget, NULL);
+}
+
+static void eth_disconnect(struct usb_gadget *gadget)
+{
+	eth_reset_config(get_gadget_data(gadget));
+	/* FIXME RNDIS should enter RNDIS_UNINITIALIZED */
+}
+
+static void eth_suspend(struct usb_gadget *gadget)
+{
+	/* Not used */
+}
+
+static void eth_resume(struct usb_gadget *gadget)
+{
+	/* Not used */
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_ETH_RNDIS
+
+/*
+ * The interrupt endpoint is used in RNDIS to notify the host when messages
+ * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT
+ * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even
+ * REMOTE_NDIS_KEEPALIVE_MSG.
+ *
+ * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and
+ * normally just one notification will be queued.
+ */
+
+static void rndis_control_ack_complete(struct usb_ep *ep,
+					struct usb_request *req)
+{
+	struct eth_dev          *dev = ep->driver_data;
+
+	debug("%s...\n", __func__);
+	if (req->status || req->actual != req->length)
+		debug("rndis control ack complete --> %d, %d/%d\n",
+			req->status, req->actual, req->length);
+
+	if (!dev->network_started) {
+		if (rndis_get_state(dev->rndis_config)
+				== RNDIS_DATA_INITIALIZED) {
+			dev->network_started = 1;
+			printf("USB RNDIS network up!\n");
+		}
+	}
+
+	req->context = NULL;
+
+	if (req != dev->stat_req)
+		usb_ep_free_request(ep, req);
+}
+
+static char rndis_resp_buf[8] __attribute__((aligned(sizeof(__le32))));
+
+#ifndef CONFIG_DM_ETH
+static int rndis_control_ack(struct eth_device *net)
+#else
+static int rndis_control_ack(struct udevice *net)
+#endif
+{
+	struct ether_priv *priv;
+	struct eth_dev *dev;
+	int length;
+	struct usb_request *resp;
+
+#ifndef CONFIG_DM_ETH
+	priv = (struct ether_priv *)net->priv;
+#else
+	priv = dev_get_priv(net);
+#endif
+	dev = &priv->ethdev;
+	resp = dev->stat_req;
+
+	/* in case RNDIS calls this after disconnect */
+	if (!dev->status) {
+		debug("status ENODEV\n");
+		return -ENODEV;
+	}
+
+	/* in case queue length > 1 */
+	if (resp->context) {
+		resp = usb_ep_alloc_request(dev->status_ep, GFP_ATOMIC);
+		if (!resp)
+			return -ENOMEM;
+		resp->buf = rndis_resp_buf;
+	}
+
+	/*
+	 * Send RNDIS RESPONSE_AVAILABLE notification;
+	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
+	 */
+	resp->length = 8;
+	resp->complete = rndis_control_ack_complete;
+	resp->context = dev;
+
+	*((__le32 *) resp->buf) = __constant_cpu_to_le32(1);
+	*((__le32 *) (resp->buf + 4)) = __constant_cpu_to_le32(0);
+
+	length = usb_ep_queue(dev->status_ep, resp, GFP_ATOMIC);
+	if (length < 0) {
+		resp->status = 0;
+		rndis_control_ack_complete(dev->status_ep, resp);
+	}
+
+	return 0;
+}
+
+#else
+
+#define	rndis_control_ack	NULL
+
+#endif	/* RNDIS */
+
+static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
+{
+	if (rndis_active(dev)) {
+		rndis_set_param_medium(dev->rndis_config,
+					NDIS_MEDIUM_802_3,
+					BITRATE(dev->gadget)/100);
+		rndis_signal_connect(dev->rndis_config);
+	}
+}
+
+static int eth_stop(struct eth_dev *dev)
+{
+#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
+	unsigned long ts;
+	unsigned long timeout = CONFIG_SYS_HZ; /* 1 sec to stop RNDIS */
+#endif
+
+	if (rndis_active(dev)) {
+		rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
+		rndis_signal_disconnect(dev->rndis_config);
+
+#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
+		/* Wait until host receives OID_GEN_MEDIA_CONNECT_STATUS */
+		ts = get_timer(0);
+		while (get_timer(ts) < timeout)
+			usb_gadget_handle_interrupts(0);
+#endif
+
+		rndis_uninit(dev->rndis_config);
+		dev->rndis = 0;
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int is_eth_addr_valid(char *str)
+{
+	if (strlen(str) == 17) {
+		int i;
+		char *p, *q;
+		uchar ea[6];
+
+		/* see if it looks like an ethernet address */
+
+		p = str;
+
+		for (i = 0; i < 6; i++) {
+			char term = (i == 5 ? '\0' : ':');
+
+			ea[i] = simple_strtol(p, &q, 16);
+
+			if ((q - p) != 2 || *q++ != term)
+				break;
+
+			p = q;
+		}
+
+		/* Now check the contents. */
+		return is_valid_ethaddr(ea);
+	}
+	return 0;
+}
+
+static u8 nibble(unsigned char c)
+{
+	if (likely(isdigit(c)))
+		return c - '0';
+	c = toupper(c);
+	if (likely(isxdigit(c)))
+		return 10 + c - 'A';
+	return 0;
+}
+
+static int get_ether_addr(const char *str, u8 *dev_addr)
+{
+	if (str) {
+		unsigned	i;
+
+		for (i = 0; i < 6; i++) {
+			unsigned char num;
+
+			if ((*str == '.') || (*str == ':'))
+				str++;
+			num = nibble(*str++) << 4;
+			num |= (nibble(*str++));
+			dev_addr[i] = num;
+		}
+		if (is_valid_ethaddr(dev_addr))
+			return 0;
+	}
+	return 1;
+}
+
+static int eth_bind(struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev = &l_priv->ethdev;
+	u8			cdc = 1, zlp = 1, rndis = 1;
+	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;
+	int			status = -ENOMEM;
+	int			gcnum;
+	u8			tmp[7];
+#ifdef CONFIG_DM_ETH
+	struct eth_pdata	*pdata = dev_get_plat(l_priv->netdev);
+#endif
+
+	/* these flags are only ever cleared; compiler take note */
+#ifndef	CONFIG_USB_ETH_CDC
+	cdc = 0;
+#endif
+#ifndef	CONFIG_USB_ETH_RNDIS
+	rndis = 0;
+#endif
+	/*
+	 * Because most host side USB stacks handle CDC Ethernet, that
+	 * standard protocol is _strongly_ preferred for interop purposes.
+	 * (By everyone except Microsoft.)
+	 */
+	if (gadget_is_pxa(gadget)) {
+		/* pxa doesn't support altsettings */
+		cdc = 0;
+	} else if (gadget_is_musbhdrc(gadget)) {
+		/* reduce tx dma overhead by avoiding special cases */
+		zlp = 0;
+	} else if (gadget_is_sh(gadget)) {
+		/* sh doesn't support multiple interfaces or configs */
+		cdc = 0;
+		rndis = 0;
+	} else if (gadget_is_sa1100(gadget)) {
+		/* hardware can't write zlps */
+		zlp = 0;
+		/*
+		 * sa1100 CAN do CDC, without status endpoint ... we use
+		 * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
+		 */
+		cdc = 0;
+	}
+
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16(0x0300 + gcnum);
+	else {
+		/*
+		 * can't assume CDC works.  don't want to default to
+		 * anything less functional on CDC-capable hardware,
+		 * so we fail in this case.
+		 */
+		pr_err("controller '%s' not recognized",
+			gadget->name);
+		return -ENODEV;
+	}
+
+	/*
+	 * If there's an RNDIS configuration, that's what Windows wants to
+	 * be using ... so use these product IDs here and in the "linux.inf"
+	 * needed to install MSFT drivers.  Current Linux kernels will use
+	 * the second configuration if it's CDC Ethernet, and need some help
+	 * to choose the right configuration otherwise.
+	 */
+	if (rndis) {
+#if defined(CONFIG_USB_GADGET_VENDOR_NUM) && defined(CONFIG_USB_GADGET_PRODUCT_NUM)
+		device_desc.idVendor =
+			__constant_cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM);
+		device_desc.idProduct =
+			__constant_cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM);
+#else
+		device_desc.idVendor =
+			__constant_cpu_to_le16(RNDIS_VENDOR_NUM);
+		device_desc.idProduct =
+			__constant_cpu_to_le16(RNDIS_PRODUCT_NUM);
+#endif
+		sprintf(product_desc, "RNDIS/%s", driver_desc);
+
+	/*
+	 * CDC subset ... recognized by Linux since 2.4.10, but Windows
+	 * drivers aren't widely available.  (That may be improved by
+	 * supporting one submode of the "SAFE" variant of MDLM.)
+	 */
+	} else {
+#if defined(CONFIG_USB_GADGET_VENDOR_NUM) && defined(CONFIG_USB_GADGET_PRODUCT_NUM)
+		device_desc.idVendor = cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM);
+		device_desc.idProduct = cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM);
+#else
+		if (!cdc) {
+			device_desc.idVendor =
+				__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
+			device_desc.idProduct =
+				__constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
+		}
+#endif
+	}
+	/* support optional vendor/distro customization */
+	if (bcdDevice)
+		device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+	if (iManufacturer)
+		strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
+	if (iProduct)
+		strlcpy(product_desc, iProduct, sizeof product_desc);
+	if (iSerialNumber) {
+		device_desc.iSerialNumber = STRING_SERIALNUMBER,
+		strlcpy(serial_number, iSerialNumber, sizeof serial_number);
+	}
+
+	/* all we really need is bulk IN/OUT */
+	usb_ep_autoconfig_reset(gadget);
+	in_ep = usb_ep_autoconfig(gadget, &fs_source_desc);
+	if (!in_ep) {
+autoconf_fail:
+		pr_err("can't autoconfigure on %s\n",
+			gadget->name);
+		return -ENODEV;
+	}
+	in_ep->driver_data = in_ep;	/* claim */
+
+	out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
+	if (!out_ep)
+		goto autoconf_fail;
+	out_ep->driver_data = out_ep;	/* claim */
+
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+	/*
+	 * CDC Ethernet control interface doesn't require a status endpoint.
+	 * Since some hosts expect one, try to allocate one anyway.
+	 */
+	if (cdc || rndis) {
+		status_ep = usb_ep_autoconfig(gadget, &fs_status_desc);
+		if (status_ep) {
+			status_ep->driver_data = status_ep;	/* claim */
+		} else if (rndis) {
+			pr_err("can't run RNDIS on %s", gadget->name);
+			return -ENODEV;
+#ifdef CONFIG_USB_ETH_CDC
+		} else if (cdc) {
+			control_intf.bNumEndpoints = 0;
+			/* FIXME remove endpoint from descriptor list */
+#endif
+		}
+	}
+#endif
+
+	/* one config:  cdc, else minimal subset */
+	if (!cdc) {
+		eth_config.bNumInterfaces = 1;
+		eth_config.iConfiguration = STRING_SUBSET;
+
+		/*
+		 * use functions to set these up, in case we're built to work
+		 * with multiple controllers and must override CDC Ethernet.
+		 */
+		fs_subset_descriptors();
+		hs_subset_descriptors();
+	}
+
+	usb_gadget_set_selfpowered(gadget);
+
+	/* For now RNDIS is always a second config */
+	if (rndis)
+		device_desc.bNumConfigurations = 2;
+
+	if (gadget_is_dualspeed(gadget)) {
+		if (rndis)
+			dev_qualifier.bNumConfigurations = 2;
+		else if (!cdc)
+			dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+
+		/* assumes ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+		if (status_ep)
+			hs_status_desc.bEndpointAddress =
+					fs_status_desc.bEndpointAddress;
+#endif
+	}
+
+	if (gadget_is_otg(gadget)) {
+		otg_descriptor.bmAttributes |= USB_OTG_HNP,
+		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		eth_config.bMaxPower = 4;
+#ifdef	CONFIG_USB_ETH_RNDIS
+		rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		rndis_config.bMaxPower = 4;
+#endif
+	}
+
+
+	/* network device setup */
+#ifndef CONFIG_DM_ETH
+	dev->net = &l_priv->netdev;
+#else
+	dev->net = l_priv->netdev;
+#endif
+
+	dev->cdc = cdc;
+	dev->zlp = zlp;
+
+	dev->in_ep = in_ep;
+	dev->out_ep = out_ep;
+	dev->status_ep = status_ep;
+
+	memset(tmp, 0, sizeof(tmp));
+	/*
+	 * Module params for these addresses should come from ID proms.
+	 * The host side address is used with CDC and RNDIS, and commonly
+	 * ends up in a persistent config database.  It's not clear if
+	 * host side code for the SAFE thing cares -- its original BLAN
+	 * thing didn't, Sharp never assigned those addresses on Zaurii.
+	 */
+#ifndef CONFIG_DM_ETH
+	get_ether_addr(dev_addr, dev->net->enetaddr);
+	memcpy(tmp, dev->net->enetaddr, sizeof(dev->net->enetaddr));
+#else
+	get_ether_addr(dev_addr, pdata->enetaddr);
+	memcpy(tmp, pdata->enetaddr, sizeof(pdata->enetaddr));
+#endif
+
+	get_ether_addr(host_addr, dev->host_mac);
+
+	sprintf(ethaddr, "%02X%02X%02X%02X%02X%02X",
+		dev->host_mac[0], dev->host_mac[1],
+			dev->host_mac[2], dev->host_mac[3],
+			dev->host_mac[4], dev->host_mac[5]);
+
+	if (rndis) {
+		status = rndis_init();
+		if (status < 0) {
+			pr_err("can't init RNDIS, %d", status);
+			goto fail;
+		}
+	}
+
+	/*
+	 * use PKTSIZE (or aligned... from u-boot) and set
+	 * wMaxSegmentSize accordingly
+	 */
+	dev->mtu = PKTSIZE_ALIGN; /* RNDIS does not like this, only 1514, TODO*/
+
+	/* preallocate control message data and buffer */
+	dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+	if (!dev->req)
+		goto fail;
+	dev->req->buf = control_req;
+	dev->req->complete = eth_setup_complete;
+
+	/* ... and maybe likewise for status transfer */
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+	if (dev->status_ep) {
+		dev->stat_req = usb_ep_alloc_request(dev->status_ep,
+							GFP_KERNEL);
+		if (!dev->stat_req) {
+			usb_ep_free_request(dev->status_ep, dev->req);
+
+			goto fail;
+		}
+		dev->stat_req->buf = status_req;
+		dev->stat_req->context = NULL;
+	}
+#endif
+
+	/* finish hookup to lower layer ... */
+	dev->gadget = gadget;
+	set_gadget_data(gadget, dev);
+	gadget->ep0->driver_data = dev;
+
+	/*
+	 * two kinds of host-initiated state changes:
+	 *  - iff DATA transfer is active, carrier is "on"
+	 *  - tx queueing enabled if open *and* carrier is "on"
+	 */
+
+	printf("using %s, OUT %s IN %s%s%s\n", gadget->name,
+		out_ep->name, in_ep->name,
+		status_ep ? " STATUS " : "",
+		status_ep ? status_ep->name : ""
+		);
+#ifndef CONFIG_DM_ETH
+	printf("MAC %pM\n", dev->net->enetaddr);
+#else
+	printf("MAC %pM\n", pdata->enetaddr);
+#endif
+
+	if (cdc || rndis)
+		printf("HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+			dev->host_mac[0], dev->host_mac[1],
+			dev->host_mac[2], dev->host_mac[3],
+			dev->host_mac[4], dev->host_mac[5]);
+
+	if (rndis) {
+		u32	vendorID = 0;
+
+		/* FIXME RNDIS vendor id == "vendor NIC code" == ? */
+
+		dev->rndis_config = rndis_register(rndis_control_ack);
+		if (dev->rndis_config < 0) {
+fail0:
+			eth_unbind(gadget);
+			debug("RNDIS setup failed\n");
+			status = -ENODEV;
+			goto fail;
+		}
+
+		/* these set up a lot of the OIDs that RNDIS needs */
+		rndis_set_host_mac(dev->rndis_config, dev->host_mac);
+		if (rndis_set_param_dev(dev->rndis_config, dev->net, dev->mtu,
+					&dev->stats, &dev->cdc_filter))
+			goto fail0;
+		if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+					manufacturer))
+			goto fail0;
+		if (rndis_set_param_medium(dev->rndis_config,
+					NDIS_MEDIUM_802_3, 0))
+			goto fail0;
+		printf("RNDIS ready\n");
+	}
+	return 0;
+
+fail:
+	pr_err("%s failed, status = %d", __func__, status);
+	eth_unbind(gadget);
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+static void _usb_eth_halt(struct ether_priv *priv);
+
+static int _usb_eth_init(struct ether_priv *priv)
+{
+	struct eth_dev *dev = &priv->ethdev;
+	struct usb_gadget *gadget;
+	unsigned long ts;
+	int ret;
+	unsigned long timeout = USB_CONNECT_TIMEOUT;
+
+	ret = usb_gadget_initialize(0);
+	if (ret)
+		return ret;
+
+	/* Configure default mac-addresses for the USB ethernet device */
+#ifdef CONFIG_USBNET_DEV_ADDR
+	strlcpy(dev_addr, CONFIG_USBNET_DEV_ADDR, sizeof(dev_addr));
+#endif
+#ifdef CONFIG_USBNET_HOST_ADDR
+	strlcpy(host_addr, CONFIG_USBNET_HOST_ADDR, sizeof(host_addr));
+#endif
+	/* Check if the user overruled the MAC addresses */
+	if (env_get("usbnet_devaddr"))
+		strlcpy(dev_addr, env_get("usbnet_devaddr"),
+			sizeof(dev_addr));
+
+	if (env_get("usbnet_hostaddr"))
+		strlcpy(host_addr, env_get("usbnet_hostaddr"),
+			sizeof(host_addr));
+
+	if (!is_eth_addr_valid(dev_addr)) {
+		pr_err("Need valid 'usbnet_devaddr' to be set");
+		goto fail;
+	}
+	if (!is_eth_addr_valid(host_addr)) {
+		pr_err("Need valid 'usbnet_hostaddr' to be set");
+		goto fail;
+	}
+
+	priv->eth_driver.speed		= DEVSPEED;
+	priv->eth_driver.bind		= eth_bind;
+	priv->eth_driver.unbind		= eth_unbind;
+	priv->eth_driver.setup		= eth_setup;
+	priv->eth_driver.reset		= eth_disconnect;
+	priv->eth_driver.disconnect	= eth_disconnect;
+	priv->eth_driver.suspend	= eth_suspend;
+	priv->eth_driver.resume		= eth_resume;
+	if (usb_gadget_register_driver(&priv->eth_driver) < 0)
+		goto fail;
+
+	dev->network_started = 0;
+
+	packet_received = 0;
+	packet_sent = 0;
+
+	gadget = dev->gadget;
+	usb_gadget_connect(gadget);
+
+	if (env_get("cdc_connect_timeout"))
+		timeout = simple_strtoul(env_get("cdc_connect_timeout"),
+						NULL, 10) * CONFIG_SYS_HZ;
+	ts = get_timer(0);
+	while (!dev->network_started) {
+		/* Handle control-c and timeouts */
+		if (ctrlc() || (get_timer(ts) > timeout)) {
+			pr_err("The remote end did not respond in time.");
+			goto fail;
+		}
+		usb_gadget_handle_interrupts(0);
+	}
+
+	packet_received = 0;
+	rx_submit(dev, dev->rx_req, 0);
+	return 0;
+fail:
+	_usb_eth_halt(priv);
+	return -1;
+}
+
+static int _usb_eth_send(struct ether_priv *priv, void *packet, int length)
+{
+	int			retval;
+	void			*rndis_pkt = NULL;
+	struct eth_dev		*dev = &priv->ethdev;
+	struct usb_request	*req = dev->tx_req;
+	unsigned long ts;
+	unsigned long timeout = USB_CONNECT_TIMEOUT;
+
+	debug("%s:...\n", __func__);
+
+	/* new buffer is needed to include RNDIS header */
+	if (rndis_active(dev)) {
+		rndis_pkt = malloc(length +
+					sizeof(struct rndis_packet_msg_type));
+		if (!rndis_pkt) {
+			pr_err("No memory to alloc RNDIS packet");
+			goto drop;
+		}
+		rndis_add_hdr(rndis_pkt, length);
+		memcpy(rndis_pkt + sizeof(struct rndis_packet_msg_type),
+				packet, length);
+		packet = rndis_pkt;
+		length += sizeof(struct rndis_packet_msg_type);
+	}
+	req->buf = packet;
+	req->context = NULL;
+	req->complete = tx_complete;
+
+	/*
+	 * use zlp framing on tx for strict CDC-Ether conformance,
+	 * though any robust network rx path ignores extra padding.
+	 * and some hardware doesn't like to write zlps.
+	 */
+	req->zero = 1;
+	if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0)
+		length++;
+
+	req->length = length;
+#if 0
+	/* throttle highspeed IRQ rate back slightly */
+	if (gadget_is_dualspeed(dev->gadget))
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+			? ((dev->tx_qlen % qmult) != 0) : 0;
+#endif
+	dev->tx_qlen = 1;
+	ts = get_timer(0);
+	packet_sent = 0;
+
+	retval = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
+
+	if (!retval)
+		debug("%s: packet queued\n", __func__);
+	while (!packet_sent) {
+		if (get_timer(ts) > timeout) {
+			printf("timeout sending packets to usb ethernet\n");
+			return -1;
+		}
+		usb_gadget_handle_interrupts(0);
+	}
+	free(rndis_pkt);
+
+	return 0;
+drop:
+	dev->stats.tx_dropped++;
+	return -ENOMEM;
+}
+
+static int _usb_eth_recv(struct ether_priv *priv)
+{
+	usb_gadget_handle_interrupts(0);
+
+	return 0;
+}
+
+static void _usb_eth_halt(struct ether_priv *priv)
+{
+	struct eth_dev *dev = &priv->ethdev;
+
+	/* If the gadget not registered, simple return */
+	if (!dev->gadget)
+		return;
+
+	/*
+	 * Some USB controllers may need additional deinitialization here
+	 * before dropping pull-up (also due to hardware issues).
+	 * For example: unhandled interrupt with status stage started may
+	 * bring the controller to fully broken state (until board reset).
+	 * There are some variants to debug and fix such cases:
+	 * 1) In the case of RNDIS connection eth_stop can perform additional
+	 * interrupt handling. See RNDIS_COMPLETE_SIGNAL_DISCONNECT definition.
+	 * 2) 'pullup' callback in your UDC driver can be improved to perform
+	 * this deinitialization.
+	 */
+	eth_stop(dev);
+
+	usb_gadget_disconnect(dev->gadget);
+
+	/* Clear pending interrupt */
+	if (dev->network_started) {
+		usb_gadget_handle_interrupts(0);
+		dev->network_started = 0;
+	}
+
+	usb_gadget_unregister_driver(&priv->eth_driver);
+	usb_gadget_release(0);
+}
+
+#ifndef CONFIG_DM_ETH
+static int usb_eth_init(struct eth_device *netdev, struct bd_info *bd)
+{
+	struct ether_priv *priv = (struct ether_priv *)netdev->priv;
+
+	return _usb_eth_init(priv);
+}
+
+static int usb_eth_send(struct eth_device *netdev, void *packet, int length)
+{
+	struct ether_priv	*priv = (struct ether_priv *)netdev->priv;
+
+	return _usb_eth_send(priv, packet, length);
+}
+
+static int usb_eth_recv(struct eth_device *netdev)
+{
+	struct ether_priv *priv = (struct ether_priv *)netdev->priv;
+	struct eth_dev *dev = &priv->ethdev;
+	int ret;
+
+	ret = _usb_eth_recv(priv);
+	if (ret) {
+		pr_err("error packet receive\n");
+		return ret;
+	}
+
+	if (!packet_received)
+		return 0;
+
+	if (dev->rx_req) {
+		net_process_received_packet(net_rx_packets[0],
+					    dev->rx_req->length);
+	} else {
+		pr_err("dev->rx_req invalid");
+	}
+	packet_received = 0;
+	rx_submit(dev, dev->rx_req, 0);
+
+	return 0;
+}
+
+void usb_eth_halt(struct eth_device *netdev)
+{
+	struct ether_priv *priv = (struct ether_priv *)netdev->priv;
+
+	_usb_eth_halt(priv);
+}
+
+int usb_eth_initialize(struct bd_info *bi)
+{
+	struct eth_device *netdev = &l_priv->netdev;
+
+	strlcpy(netdev->name, USB_NET_NAME, sizeof(netdev->name));
+
+	netdev->init = usb_eth_init;
+	netdev->send = usb_eth_send;
+	netdev->recv = usb_eth_recv;
+	netdev->halt = usb_eth_halt;
+	netdev->priv = l_priv;
+
+	eth_register(netdev);
+	return 0;
+}
+#else
+static int usb_eth_start(struct udevice *dev)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+
+	return _usb_eth_init(priv);
+}
+
+static int usb_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+
+	return _usb_eth_send(priv, packet, length);
+}
+
+static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+	struct eth_dev *ethdev = &priv->ethdev;
+	int ret;
+
+	ret = _usb_eth_recv(priv);
+	if (ret) {
+		pr_err("error packet receive\n");
+		return ret;
+	}
+
+	if (packet_received) {
+		if (ethdev->rx_req) {
+			*packetp = (uchar *)net_rx_packets[0];
+			return ethdev->rx_req->length;
+		} else {
+			pr_err("dev->rx_req invalid");
+			return -EFAULT;
+		}
+	}
+
+	return -EAGAIN;
+}
+
+static int usb_eth_free_pkt(struct udevice *dev, uchar *packet,
+				   int length)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+	struct eth_dev *ethdev = &priv->ethdev;
+
+	packet_received = 0;
+
+	return rx_submit(ethdev, ethdev->rx_req, 0);
+}
+
+static void usb_eth_stop(struct udevice *dev)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+
+	_usb_eth_halt(priv);
+}
+
+static int usb_eth_probe(struct udevice *dev)
+{
+	struct ether_priv *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_plat(dev);
+
+	priv->netdev = dev;
+	l_priv = priv;
+
+	get_ether_addr(CONFIG_USBNET_DEVADDR, pdata->enetaddr);
+	eth_env_set_enetaddr("usbnet_devaddr", pdata->enetaddr);
+
+	return 0;
+}
+
+static const struct eth_ops usb_eth_ops = {
+	.start		= usb_eth_start,
+	.send		= usb_eth_send,
+	.recv		= usb_eth_recv,
+	.free_pkt	= usb_eth_free_pkt,
+	.stop		= usb_eth_stop,
+};
+
+int usb_ether_init(void)
+{
+	struct udevice *dev;
+	struct udevice *usb_dev;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_USB_GADGET_GENERIC, &usb_dev);
+	if (!usb_dev || ret) {
+		pr_err("No USB device found\n");
+		return ret;
+	}
+
+	ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev);
+	if (!dev || ret) {
+		pr_err("usb - not able to bind usb_ether device\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(eth_usb) = {
+	.name	= "usb_ether",
+	.id	= UCLASS_ETH,
+	.probe	= usb_eth_probe,
+	.ops	= &usb_eth_ops,
+	.priv_auto	= sizeof(struct ether_priv),
+	.plat_auto	= sizeof(struct eth_pdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* CONFIG_DM_ETH */
diff --git a/roms/u-boot/drivers/usb/gadget/f_dfu.c b/roms/u-boot/drivers/usb/gadget/f_dfu.c
new file mode 100644
index 000000000..4bedc7d3a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_dfu.c
@@ -0,0 +1,844 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * f_dfu.c -- Device Firmware Update USB function
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *          Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * Based on OpenMoko u-boot: drivers/usb/usbdfu.c
+ * (C) 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * based on existing SAM7DFU code from OpenPCD:
+ * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de>
+ */
+
+#include <env.h>
+#include <errno.h>
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+
+#include <dfu.h>
+#include <g_dnl.h>
+#include "f_dfu.h"
+
+struct f_dfu {
+	struct usb_function		usb_function;
+
+	struct usb_descriptor_header	**function;
+	struct usb_string		*strings;
+
+	/* when configured, we have one config */
+	u8				config;
+	u8				altsetting;
+	enum dfu_state			dfu_state;
+	unsigned int			dfu_status;
+
+	/* Send/received block number is handy for data integrity check */
+	int                             blk_seq_num;
+	unsigned int                    poll_timeout;
+};
+
+struct dfu_entity *dfu_defer_flush;
+
+typedef int (*dfu_state_fn) (struct f_dfu *,
+			     const struct usb_ctrlrequest *,
+			     struct usb_gadget *,
+			     struct usb_request *);
+
+static inline struct f_dfu *func_to_dfu(struct usb_function *f)
+{
+	return container_of(f, struct f_dfu, usb_function);
+}
+
+static const struct dfu_function_descriptor dfu_func = {
+	.bLength =		sizeof dfu_func,
+	.bDescriptorType =	DFU_DT_FUNC,
+	.bmAttributes =		DFU_BIT_WILL_DETACH |
+				DFU_BIT_MANIFESTATION_TOLERANT |
+				DFU_BIT_CAN_UPLOAD |
+				DFU_BIT_CAN_DNLOAD,
+	.wDetachTimeOut =	0,
+	.wTransferSize =	DFU_USB_BUFSIZ,
+	.bcdDFUVersion =	__constant_cpu_to_le16(0x0110),
+};
+
+static struct usb_interface_descriptor dfu_intf_runtime = {
+	.bLength =		sizeof dfu_intf_runtime,
+	.bDescriptorType =	USB_DT_INTERFACE,
+	.bNumEndpoints =	0,
+	.bInterfaceClass =	USB_CLASS_APP_SPEC,
+	.bInterfaceSubClass =	1,
+	.bInterfaceProtocol =	1,
+	/* .iInterface = DYNAMIC */
+};
+
+static struct usb_descriptor_header *dfu_runtime_descs[] = {
+	(struct usb_descriptor_header *) &dfu_intf_runtime,
+	NULL,
+};
+
+static const char dfu_name[] = "Device Firmware Upgrade";
+
+/*
+ * static strings, in UTF-8
+ *
+ * dfu_generic configuration
+ */
+static struct usb_string strings_dfu_generic[] = {
+	[0].s = dfu_name,
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dfu_generic = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings_dfu_generic,
+};
+
+static struct usb_gadget_strings *dfu_generic_strings[] = {
+	&stringtab_dfu_generic,
+	NULL,
+};
+
+/*
+ * usb_function specific
+ */
+static struct usb_gadget_strings stringtab_dfu = {
+	.language	= 0x0409,	/* en-us */
+	/*
+	 * .strings
+	 *
+	 * assigned during initialization,
+	 * depends on number of flash entities
+	 *
+	 */
+};
+
+static struct usb_gadget_strings *dfu_strings[] = {
+	&stringtab_dfu,
+	NULL,
+};
+
+static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms)
+{
+	/*
+	 * The bwPollTimeout DFU_GETSTATUS request payload provides information
+	 * about minimum time, in milliseconds, that the host should wait before
+	 * sending a subsequent DFU_GETSTATUS request
+	 *
+	 * This permits the device to vary the delay depending on its need to
+	 * erase or program the memory
+	 *
+	 */
+
+	unsigned char *p = (unsigned char *)&ms;
+
+	if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) {
+		dstat->bwPollTimeout[0] = 0;
+		dstat->bwPollTimeout[1] = 0;
+		dstat->bwPollTimeout[2] = 0;
+
+		return;
+	}
+
+	dstat->bwPollTimeout[0] = *p++;
+	dstat->bwPollTimeout[1] = *p++;
+	dstat->bwPollTimeout[2] = *p;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_dfu *f_dfu = req->context;
+	int ret;
+
+	ret = dfu_write(dfu_get_entity(f_dfu->altsetting), req->buf,
+			req->actual, f_dfu->blk_seq_num);
+	if (ret) {
+		f_dfu->dfu_status = DFU_STATUS_errUNKNOWN;
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+	}
+}
+
+static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_dfu *f_dfu = req->context;
+	dfu_set_defer_flush(dfu_get_entity(f_dfu->altsetting));
+}
+
+static inline int dfu_get_manifest_timeout(struct dfu_entity *dfu)
+{
+	return dfu->poll_timeout ? dfu->poll_timeout(dfu) :
+		DFU_MANIFEST_POLL_TIMEOUT;
+}
+
+static int handle_getstatus(struct usb_request *req)
+{
+	struct dfu_status *dstat = (struct dfu_status *)req->buf;
+	struct f_dfu *f_dfu = req->context;
+	struct dfu_entity *dfu = dfu_get_entity(f_dfu->altsetting);
+
+	dfu_set_poll_timeout(dstat, 0);
+
+	switch (f_dfu->dfu_state) {
+	case DFU_STATE_dfuDNLOAD_SYNC:
+	case DFU_STATE_dfuDNBUSY:
+		f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
+		break;
+	case DFU_STATE_dfuMANIFEST_SYNC:
+		f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
+		break;
+	case DFU_STATE_dfuMANIFEST:
+		dfu_set_poll_timeout(dstat, dfu_get_manifest_timeout(dfu));
+		break;
+	default:
+		break;
+	}
+
+	if (f_dfu->poll_timeout)
+		if (!(f_dfu->blk_seq_num %
+		      (dfu_get_buf_size() / DFU_USB_BUFSIZ)))
+			dfu_set_poll_timeout(dstat, f_dfu->poll_timeout);
+
+	/* send status response */
+	dstat->bStatus = f_dfu->dfu_status;
+	dstat->bState = f_dfu->dfu_state;
+	dstat->iString = 0;
+
+	return sizeof(struct dfu_status);
+}
+
+static int handle_getstate(struct usb_request *req)
+{
+	struct f_dfu *f_dfu = req->context;
+
+	((u8 *)req->buf)[0] = f_dfu->dfu_state;
+	return sizeof(u8);
+}
+
+static inline void to_dfu_mode(struct f_dfu *f_dfu)
+{
+	f_dfu->usb_function.strings = dfu_strings;
+	f_dfu->usb_function.hs_descriptors = f_dfu->function;
+	f_dfu->usb_function.descriptors = f_dfu->function;
+	f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+}
+
+static inline void to_runtime_mode(struct f_dfu *f_dfu)
+{
+	f_dfu->usb_function.strings = NULL;
+	f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
+	f_dfu->usb_function.descriptors = dfu_runtime_descs;
+}
+
+static int handle_upload(struct usb_request *req, u16 len)
+{
+	struct f_dfu *f_dfu = req->context;
+
+	return dfu_read(dfu_get_entity(f_dfu->altsetting), req->buf,
+			req->length, f_dfu->blk_seq_num);
+}
+
+static int handle_dnload(struct usb_gadget *gadget, u16 len)
+{
+	struct usb_composite_dev *cdev = get_gadget_data(gadget);
+	struct usb_request *req = cdev->req;
+	struct f_dfu *f_dfu = req->context;
+
+	if (len == 0)
+		f_dfu->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
+
+	req->complete = dnload_request_complete;
+
+	return len;
+}
+
+/*-------------------------------------------------------------------------*/
+/* DFU state machine  */
+static int state_app_idle(struct f_dfu *f_dfu,
+			  const struct usb_ctrlrequest *ctrl,
+			  struct usb_gadget *gadget,
+			  struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	case USB_REQ_DFU_DETACH:
+		f_dfu->dfu_state = DFU_STATE_appDETACH;
+		to_dfu_mode(f_dfu);
+		value = RET_ZLP;
+		break;
+	default:
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_app_detach(struct f_dfu *f_dfu,
+			    const struct usb_ctrlrequest *ctrl,
+			    struct usb_gadget *gadget,
+			    struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_appIDLE;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_idle(struct f_dfu *f_dfu,
+			  const struct usb_ctrlrequest *ctrl,
+			  struct usb_gadget *gadget,
+			  struct usb_request *req)
+{
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	u16 len = le16_to_cpu(ctrl->wLength);
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_DNLOAD:
+		if (len == 0) {
+			f_dfu->dfu_state = DFU_STATE_dfuERROR;
+			value = RET_STALL;
+			break;
+		}
+		f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
+		f_dfu->blk_seq_num = w_value;
+		value = handle_dnload(gadget, len);
+		break;
+	case USB_REQ_DFU_UPLOAD:
+		f_dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
+		f_dfu->blk_seq_num = 0;
+		value = handle_upload(req, len);
+		break;
+	case USB_REQ_DFU_ABORT:
+		/* no zlp? */
+		value = RET_ZLP;
+		break;
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	case USB_REQ_DFU_DETACH:
+		/*
+		 * Proprietary extension: 'detach' from idle mode and
+		 * get back to runtime mode in case of USB Reset.  As
+		 * much as I dislike this, we just can't use every USB
+		 * bus reset to switch back to runtime mode, since at
+		 * least the Linux USB stack likes to send a number of
+		 * resets in a row :(
+		 */
+		f_dfu->dfu_state =
+			DFU_STATE_dfuMANIFEST_WAIT_RST;
+		to_runtime_mode(f_dfu);
+		f_dfu->dfu_state = DFU_STATE_appIDLE;
+
+		g_dnl_trigger_detach();
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_dnload_sync(struct f_dfu *f_dfu,
+				 const struct usb_ctrlrequest *ctrl,
+				 struct usb_gadget *gadget,
+				 struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_dnbusy(struct f_dfu *f_dfu,
+			    const struct usb_ctrlrequest *ctrl,
+			    struct usb_gadget *gadget,
+			    struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_dnload_idle(struct f_dfu *f_dfu,
+				 const struct usb_ctrlrequest *ctrl,
+				 struct usb_gadget *gadget,
+				 struct usb_request *req)
+{
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	u16 len = le16_to_cpu(ctrl->wLength);
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_DNLOAD:
+		f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
+		f_dfu->blk_seq_num = w_value;
+		value = handle_dnload(gadget, len);
+		break;
+	case USB_REQ_DFU_ABORT:
+		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+		value = RET_ZLP;
+		break;
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_manifest_sync(struct f_dfu *f_dfu,
+				   const struct usb_ctrlrequest *ctrl,
+				   struct usb_gadget *gadget,
+				   struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		/* We're MainfestationTolerant */
+		f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
+		value = handle_getstatus(req);
+		f_dfu->blk_seq_num = 0;
+		req->complete = dnload_request_flush;
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_manifest(struct f_dfu *f_dfu,
+			      const struct usb_ctrlrequest *ctrl,
+			      struct usb_gadget *gadget,
+			      struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		/* We're MainfestationTolerant */
+		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+		value = handle_getstatus(req);
+		f_dfu->blk_seq_num = 0;
+		puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+	return value;
+}
+
+static int state_dfu_upload_idle(struct f_dfu *f_dfu,
+				 const struct usb_ctrlrequest *ctrl,
+				 struct usb_gadget *gadget,
+				 struct usb_request *req)
+{
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	u16 len = le16_to_cpu(ctrl->wLength);
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_UPLOAD:
+		/* state transition if less data then requested */
+		f_dfu->blk_seq_num = w_value;
+		value = handle_upload(req, len);
+		if (value >= 0 && value < len)
+			f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+		break;
+	case USB_REQ_DFU_ABORT:
+		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+		/* no zlp? */
+		value = RET_ZLP;
+		break;
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static int state_dfu_error(struct f_dfu *f_dfu,
+				 const struct usb_ctrlrequest *ctrl,
+				 struct usb_gadget *gadget,
+				 struct usb_request *req)
+{
+	int value = 0;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_DFU_GETSTATUS:
+		value = handle_getstatus(req);
+		break;
+	case USB_REQ_DFU_GETSTATE:
+		value = handle_getstate(req);
+		break;
+	case USB_REQ_DFU_CLRSTATUS:
+		f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+		f_dfu->dfu_status = DFU_STATUS_OK;
+		/* no zlp? */
+		value = RET_ZLP;
+		break;
+	default:
+		f_dfu->dfu_state = DFU_STATE_dfuERROR;
+		value = RET_STALL;
+		break;
+	}
+
+	return value;
+}
+
+static dfu_state_fn dfu_state[] = {
+	state_app_idle,          /* DFU_STATE_appIDLE */
+	state_app_detach,        /* DFU_STATE_appDETACH */
+	state_dfu_idle,          /* DFU_STATE_dfuIDLE */
+	state_dfu_dnload_sync,   /* DFU_STATE_dfuDNLOAD_SYNC */
+	state_dfu_dnbusy,        /* DFU_STATE_dfuDNBUSY */
+	state_dfu_dnload_idle,   /* DFU_STATE_dfuDNLOAD_IDLE */
+	state_dfu_manifest_sync, /* DFU_STATE_dfuMANIFEST_SYNC */
+	state_dfu_manifest,	 /* DFU_STATE_dfuMANIFEST */
+	NULL,                    /* DFU_STATE_dfuMANIFEST_WAIT_RST */
+	state_dfu_upload_idle,   /* DFU_STATE_dfuUPLOAD_IDLE */
+	state_dfu_error          /* DFU_STATE_dfuERROR */
+};
+
+static int
+dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	struct usb_request *req = f->config->cdev->req;
+	struct f_dfu *f_dfu = f->config->cdev->req->context;
+	u16 len = le16_to_cpu(ctrl->wLength);
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	int value = 0;
+	u8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
+
+	debug("w_value: 0x%x len: 0x%x\n", w_value, len);
+	debug("req_type: 0x%x ctrl->bRequest: 0x%x f_dfu->dfu_state: 0x%x\n",
+	       req_type, ctrl->bRequest, f_dfu->dfu_state);
+
+#ifdef CONFIG_DFU_TIMEOUT
+	/* Forbid aborting by timeout. Next dfu command may update this */
+	dfu_set_timeout(0);
+#endif
+
+	if (req_type == USB_TYPE_STANDARD) {
+		if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR &&
+		    (w_value >> 8) == DFU_DT_FUNC) {
+			value = min(len, (u16) sizeof(dfu_func));
+			memcpy(req->buf, &dfu_func, value);
+		}
+	} else /* DFU specific request */
+		value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req);
+
+	if (value >= 0) {
+		req->length = value;
+		req->zero = value < len;
+		value = usb_ep_queue(gadget->ep0, req, 0);
+		if (value < 0) {
+			debug("ep_queue --> %d\n", value);
+			req->status = 0;
+		}
+	}
+
+	return value;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+dfu_prepare_strings(struct f_dfu *f_dfu, int n)
+{
+	struct dfu_entity *de = NULL;
+	int i = 0;
+
+	f_dfu->strings = calloc(sizeof(struct usb_string), n + 1);
+	if (!f_dfu->strings)
+		return -ENOMEM;
+
+	for (i = 0; i < n; ++i) {
+		de = dfu_get_entity(i);
+		f_dfu->strings[i].s = de->name;
+	}
+
+	f_dfu->strings[i].id = 0;
+	f_dfu->strings[i].s = NULL;
+
+	return 0;
+}
+
+static int dfu_prepare_function(struct f_dfu *f_dfu, int n)
+{
+	struct usb_interface_descriptor *d;
+	int i = 0;
+
+	f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 2);
+	if (!f_dfu->function)
+		goto enomem;
+
+	for (i = 0; i < n; ++i) {
+		d = calloc(sizeof(*d), 1);
+		if (!d)
+			goto enomem;
+
+		d->bLength =		sizeof(*d);
+		d->bDescriptorType =	USB_DT_INTERFACE;
+		d->bAlternateSetting =	i;
+		d->bNumEndpoints =	0;
+		d->bInterfaceClass =	USB_CLASS_APP_SPEC;
+		d->bInterfaceSubClass =	1;
+		d->bInterfaceProtocol =	2;
+
+		f_dfu->function[i] = (struct usb_descriptor_header *)d;
+	}
+
+	/* add DFU Functional Descriptor */
+	f_dfu->function[i] = calloc(sizeof(dfu_func), 1);
+	if (!f_dfu->function[i])
+		goto enomem;
+	memcpy(f_dfu->function[i], &dfu_func, sizeof(dfu_func));
+
+	i++;
+	f_dfu->function[i] = NULL;
+
+	return 0;
+
+enomem:
+	while (i) {
+		free(f_dfu->function[--i]);
+		f_dfu->function[i] = NULL;
+	}
+	free(f_dfu->function);
+
+	return -ENOMEM;
+}
+
+static int dfu_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_dfu *f_dfu = func_to_dfu(f);
+	const char *s;
+	int alt_num = dfu_get_alt_number();
+	int rv, id, i;
+
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	dfu_intf_runtime.bInterfaceNumber = id;
+
+	f_dfu->dfu_state = DFU_STATE_appIDLE;
+	f_dfu->dfu_status = DFU_STATUS_OK;
+
+	rv = dfu_prepare_function(f_dfu, alt_num);
+	if (rv)
+		goto error;
+
+	rv = dfu_prepare_strings(f_dfu, alt_num);
+	if (rv)
+		goto error;
+	for (i = 0; i < alt_num; i++) {
+		id = usb_string_id(cdev);
+		if (id < 0)
+			return id;
+		f_dfu->strings[i].id = id;
+		((struct usb_interface_descriptor *)f_dfu->function[i])
+			->iInterface = id;
+	}
+
+	to_dfu_mode(f_dfu);
+
+	stringtab_dfu.strings = f_dfu->strings;
+
+	cdev->req->context = f_dfu;
+
+	s = env_get("serial#");
+	if (s)
+		g_dnl_set_serialnumber((char *)s);
+
+error:
+	return rv;
+}
+
+static void dfu_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_dfu *f_dfu = func_to_dfu(f);
+	int alt_num = dfu_get_alt_number();
+	int i;
+
+	if (f_dfu->strings) {
+		i = alt_num;
+		while (i)
+			f_dfu->strings[--i].s = NULL;
+
+		free(f_dfu->strings);
+	}
+
+	if (f_dfu->function) {
+		i = alt_num;
+		i++; /* free DFU Functional Descriptor */
+		while (i) {
+			free(f_dfu->function[--i]);
+			f_dfu->function[i] = NULL;
+		}
+		free(f_dfu->function);
+	}
+
+	free(f_dfu);
+}
+
+static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_dfu *f_dfu = func_to_dfu(f);
+
+	debug("%s: intf:%d alt:%d\n", __func__, intf, alt);
+
+	f_dfu->altsetting = alt;
+	f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+	f_dfu->dfu_status = DFU_STATUS_OK;
+
+	return 0;
+}
+
+static int __dfu_get_alt(struct usb_function *f, unsigned intf)
+{
+	struct f_dfu *f_dfu = func_to_dfu(f);
+
+	return f_dfu->altsetting;
+}
+
+/* TODO: is this really what we need here? */
+static void dfu_disable(struct usb_function *f)
+{
+	struct f_dfu *f_dfu = func_to_dfu(f);
+	if (f_dfu->config == 0)
+		return;
+
+	debug("%s: reset config\n", __func__);
+
+	f_dfu->config = 0;
+}
+
+static int dfu_bind_config(struct usb_configuration *c)
+{
+	struct f_dfu *f_dfu;
+	int status;
+
+	f_dfu = calloc(sizeof(*f_dfu), 1);
+	if (!f_dfu)
+		return -ENOMEM;
+	f_dfu->usb_function.name = "dfu";
+	f_dfu->usb_function.hs_descriptors = dfu_runtime_descs;
+	f_dfu->usb_function.descriptors = dfu_runtime_descs;
+	f_dfu->usb_function.bind = dfu_bind;
+	f_dfu->usb_function.unbind = dfu_unbind;
+	f_dfu->usb_function.set_alt = dfu_set_alt;
+	f_dfu->usb_function.get_alt = __dfu_get_alt;
+	f_dfu->usb_function.disable = dfu_disable;
+	f_dfu->usb_function.strings = dfu_generic_strings;
+	f_dfu->usb_function.setup = dfu_handle;
+	f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT;
+
+	status = usb_add_function(c, &f_dfu->usb_function);
+	if (status)
+		free(f_dfu);
+
+	return status;
+}
+
+int dfu_add(struct usb_configuration *c)
+{
+	int id;
+
+	id = usb_string_id(c->cdev);
+	if (id < 0)
+		return id;
+	strings_dfu_generic[0].id = id;
+	dfu_intf_runtime.iInterface = id;
+
+	debug("%s: cdev: 0x%p gadget:0x%p gadget->ep0: 0x%p\n", __func__,
+	       c->cdev, c->cdev->gadget, c->cdev->gadget->ep0);
+
+	return dfu_bind_config(c);
+}
+
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_dfu, dfu_add);
diff --git a/roms/u-boot/drivers/usb/gadget/f_dfu.h b/roms/u-boot/drivers/usb/gadget/f_dfu.h
new file mode 100644
index 000000000..a175e3f13
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_dfu.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * f_dfu.h -- Device Firmware Update gadget
+ *
+ * Copyright (C) 2011-2012 Samsung Electronics
+ * author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ */
+
+#ifndef __F_DFU_H_
+#define __F_DFU_H_
+
+#include <linux/compiler.h>
+#include <linux/usb/composite.h>
+
+#define DFU_CONFIG_VAL			1
+#define DFU_DT_FUNC			0x21
+
+#define DFU_BIT_WILL_DETACH		(0x1 << 3)
+#define DFU_BIT_MANIFESTATION_TOLERANT	(0x1 << 2)
+#define DFU_BIT_CAN_UPLOAD		(0x1 << 1)
+#define DFU_BIT_CAN_DNLOAD		0x1
+
+/* big enough to hold our biggest descriptor */
+#define DFU_USB_BUFSIZ			4096
+
+#define USB_REQ_DFU_DETACH		0x00
+#define USB_REQ_DFU_DNLOAD		0x01
+#define USB_REQ_DFU_UPLOAD		0x02
+#define USB_REQ_DFU_GETSTATUS		0x03
+#define USB_REQ_DFU_CLRSTATUS		0x04
+#define USB_REQ_DFU_GETSTATE		0x05
+#define USB_REQ_DFU_ABORT		0x06
+
+#define DFU_STATUS_OK			0x00
+#define DFU_STATUS_errTARGET		0x01
+#define DFU_STATUS_errFILE		0x02
+#define DFU_STATUS_errWRITE		0x03
+#define DFU_STATUS_errERASE		0x04
+#define DFU_STATUS_errCHECK_ERASED	0x05
+#define DFU_STATUS_errPROG		0x06
+#define DFU_STATUS_errVERIFY		0x07
+#define DFU_STATUS_errADDRESS		0x08
+#define DFU_STATUS_errNOTDONE		0x09
+#define DFU_STATUS_errFIRMWARE		0x0a
+#define DFU_STATUS_errVENDOR		0x0b
+#define DFU_STATUS_errUSBR		0x0c
+#define DFU_STATUS_errPOR		0x0d
+#define DFU_STATUS_errUNKNOWN		0x0e
+#define DFU_STATUS_errSTALLEDPKT	0x0f
+
+#define RET_STALL			-1
+#define RET_ZLP				0
+
+enum dfu_state {
+	DFU_STATE_appIDLE		= 0,
+	DFU_STATE_appDETACH		= 1,
+	DFU_STATE_dfuIDLE		= 2,
+	DFU_STATE_dfuDNLOAD_SYNC	= 3,
+	DFU_STATE_dfuDNBUSY		= 4,
+	DFU_STATE_dfuDNLOAD_IDLE	= 5,
+	DFU_STATE_dfuMANIFEST_SYNC	= 6,
+	DFU_STATE_dfuMANIFEST		= 7,
+	DFU_STATE_dfuMANIFEST_WAIT_RST	= 8,
+	DFU_STATE_dfuUPLOAD_IDLE	= 9,
+	DFU_STATE_dfuERROR		= 10,
+};
+
+struct dfu_status {
+	__u8				bStatus;
+	__u8				bwPollTimeout[3];
+	__u8				bState;
+	__u8				iString;
+} __packed;
+
+struct dfu_function_descriptor {
+	__u8				bLength;
+	__u8				bDescriptorType;
+	__u8				bmAttributes;
+	__le16				wDetachTimeOut;
+	__le16				wTransferSize;
+	__le16				bcdDFUVersion;
+} __packed;
+
+#define DFU_POLL_TIMEOUT_MASK           (0xFFFFFFUL)
+#endif /* __F_DFU_H_ */
diff --git a/roms/u-boot/drivers/usb/gadget/f_fastboot.c b/roms/u-boot/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 000000000..8ba55aab9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ */
+#include <command.h>
+#include <config.h>
+#include <common.h>
+#include <env.h>
+#include <errno.h>
+#include <fastboot.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/compiler.h>
+#include <g_dnl.h>
+
+#define FASTBOOT_INTERFACE_CLASS	0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
+#define FASTBOOT_INTERFACE_PROTOCOL	0x03
+
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
+
+#define EP_BUFFER_SIZE			4096
+/*
+ * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
+ * (64 or 512 or 1024), else we break on certain controllers like DWC3
+ * that expect bulk OUT requests to be divisible by maxpacket size.
+ */
+
+struct f_fastboot {
+	struct usb_function usb_function;
+
+	/* IN/OUT EP's and corresponding requests */
+	struct usb_ep *in_ep, *out_ep;
+	struct usb_request *in_req, *out_req;
+};
+
+static char fb_ext_prop_name[] = "DeviceInterfaceGUID";
+static char fb_ext_prop_data[] = "{4866319A-F4D6-4374-93B9-DC2DEB361BA9}";
+
+static struct usb_os_desc_ext_prop fb_ext_prop = {
+	.type = 1,		/* NUL-terminated Unicode String (REG_SZ) */
+	.name = fb_ext_prop_name,
+	.data = fb_ext_prop_data,
+};
+
+/* 16 bytes of "Compatible ID" and "Subcompatible ID" */
+static char fb_cid[16] = {'W', 'I', 'N', 'U', 'S', 'B'};
+static struct usb_os_desc fb_os_desc = {
+	.ext_compat_id = fb_cid,
+};
+
+static struct usb_os_desc_table fb_os_desc_table = {
+	.os_desc = &fb_os_desc,
+};
+
+static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
+{
+	return container_of(f, struct f_fastboot, usb_function);
+}
+
+static struct f_fastboot *fastboot_func;
+
+static struct usb_endpoint_descriptor fs_ep_in = {
+	.bLength            = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    = USB_DT_ENDPOINT,
+	.bEndpointAddress   = USB_DIR_IN,
+	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     = cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor fs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor hs_ep_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(512),
+};
+
+static struct usb_interface_descriptor interface_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= 0x00,
+	.bAlternateSetting	= 0x00,
+	.bNumEndpoints		= 0x02,
+	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
+	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
+	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
+};
+
+static struct usb_descriptor_header *fb_fs_function[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&fs_ep_in,
+	(struct usb_descriptor_header *)&fs_ep_out,
+};
+
+static struct usb_descriptor_header *fb_hs_function[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&hs_ep_in,
+	(struct usb_descriptor_header *)&hs_ep_out,
+	NULL,
+};
+
+/* Super speed */
+static struct usb_endpoint_descriptor ss_ep_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fb_ss_bulk_comp_desc = {
+	.bLength =		sizeof(fb_ss_bulk_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *fb_ss_function[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&ss_ep_in,
+	(struct usb_descriptor_header *)&fb_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *)&ss_ep_out,
+	(struct usb_descriptor_header *)&fb_ss_bulk_comp_desc,
+	NULL,
+};
+
+static struct usb_endpoint_descriptor *
+fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+	    struct usb_endpoint_descriptor *hs,
+	    struct usb_endpoint_descriptor *ss)
+{
+	if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER)
+		return ss;
+
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+/*
+ * static strings, in UTF-8
+ */
+static const char fastboot_name[] = "Android Fastboot";
+
+static struct usb_string fastboot_string_defs[] = {
+	[0].s = fastboot_name,
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_fastboot = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= fastboot_string_defs,
+};
+
+static struct usb_gadget_strings *fastboot_strings[] = {
+	&stringtab_fastboot,
+	NULL,
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+	if (!status)
+		return;
+	printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+
+static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	int id;
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+	const char *s;
+
+	/* DYNAMIC interface numbers assignments */
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	interface_desc.bInterfaceNumber = id;
+
+	/* Enable OS and Extended Properties Feature Descriptor */
+	c->cdev->use_os_string = 1;
+	f->os_desc_table = &fb_os_desc_table;
+	f->os_desc_n = 1;
+	f->os_desc_table->if_id = id;
+	INIT_LIST_HEAD(&fb_os_desc.ext_prop);
+	fb_ext_prop.name_len = strlen(fb_ext_prop.name) * 2 + 2;
+	fb_os_desc.ext_prop_len = 10 + fb_ext_prop.name_len;
+	fb_os_desc.ext_prop_count = 1;
+	fb_ext_prop.data_len = strlen(fb_ext_prop.data) * 2 + 2;
+	fb_os_desc.ext_prop_len += fb_ext_prop.data_len + 4;
+	list_add_tail(&fb_ext_prop.entry, &fb_os_desc.ext_prop);
+
+	id = usb_string_id(c->cdev);
+	if (id < 0)
+		return id;
+	fastboot_string_defs[0].id = id;
+	interface_desc.iInterface = id;
+
+	f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
+	if (!f_fb->in_ep)
+		return -ENODEV;
+	f_fb->in_ep->driver_data = c->cdev;
+
+	f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
+	if (!f_fb->out_ep)
+		return -ENODEV;
+	f_fb->out_ep->driver_data = c->cdev;
+
+	f->descriptors = fb_fs_function;
+
+	if (gadget_is_dualspeed(gadget)) {
+		/* Assume endpoint addresses are the same for both speeds */
+		hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
+		hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+		/* copy HS descriptors */
+		f->hs_descriptors = fb_hs_function;
+	}
+
+	if (gadget_is_superspeed(gadget)) {
+		ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
+		ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+		f->ss_descriptors = fb_ss_function;
+	}
+
+	s = env_get("serial#");
+	if (s)
+		g_dnl_set_serialnumber((char *)s);
+
+	return 0;
+}
+
+static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	f->os_desc_table = NULL;
+	list_del(&fb_os_desc.ext_prop);
+	memset(fastboot_func, 0, sizeof(*fastboot_func));
+}
+
+static void fastboot_disable(struct usb_function *f)
+{
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+
+	usb_ep_disable(f_fb->out_ep);
+	usb_ep_disable(f_fb->in_ep);
+
+	if (f_fb->out_req) {
+		free(f_fb->out_req->buf);
+		usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
+		f_fb->out_req = NULL;
+	}
+	if (f_fb->in_req) {
+		free(f_fb->in_req->buf);
+		usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
+		f_fb->in_req = NULL;
+	}
+}
+
+static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req)
+		return NULL;
+
+	req->length = EP_BUFFER_SIZE;
+	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		return NULL;
+	}
+
+	memset(req->buf, 0, req->length);
+	return req;
+}
+
+static int fastboot_set_alt(struct usb_function *f,
+			    unsigned interface, unsigned alt)
+{
+	int ret;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct f_fastboot *f_fb = func_to_fastboot(f);
+	const struct usb_endpoint_descriptor *d;
+
+	debug("%s: func: %s intf: %d alt: %d\n",
+	      __func__, f->name, interface, alt);
+
+	d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out, &ss_ep_out);
+	ret = usb_ep_enable(f_fb->out_ep, d);
+	if (ret) {
+		puts("failed to enable out ep\n");
+		return ret;
+	}
+
+	f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
+	if (!f_fb->out_req) {
+		puts("failed to alloc out req\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	f_fb->out_req->complete = rx_handler_command;
+
+	d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in);
+	ret = usb_ep_enable(f_fb->in_ep, d);
+	if (ret) {
+		puts("failed to enable in ep\n");
+		goto err;
+	}
+
+	f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
+	if (!f_fb->in_req) {
+		puts("failed alloc req in\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	f_fb->in_req->complete = fastboot_complete;
+
+	ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	fastboot_disable(f);
+	return ret;
+}
+
+static int fastboot_add(struct usb_configuration *c)
+{
+	struct f_fastboot *f_fb = fastboot_func;
+	int status;
+
+	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+	if (!f_fb) {
+		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
+		if (!f_fb)
+			return -ENOMEM;
+
+		fastboot_func = f_fb;
+		memset(f_fb, 0, sizeof(*f_fb));
+	}
+
+	f_fb->usb_function.name = "f_fastboot";
+	f_fb->usb_function.bind = fastboot_bind;
+	f_fb->usb_function.unbind = fastboot_unbind;
+	f_fb->usb_function.set_alt = fastboot_set_alt;
+	f_fb->usb_function.disable = fastboot_disable;
+	f_fb->usb_function.strings = fastboot_strings;
+
+	status = usb_add_function(c, &f_fb->usb_function);
+	if (status) {
+		free(f_fb);
+		fastboot_func = NULL;
+	}
+
+	return status;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
+
+static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	struct usb_request *in_req = fastboot_func->in_req;
+	int ret;
+
+	memcpy(in_req->buf, buffer, buffer_size);
+	in_req->length = buffer_size;
+
+	usb_ep_dequeue(fastboot_func->in_ep, in_req);
+
+	ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
+	if (ret)
+		printf("Error %d on queue\n", ret);
+	return 0;
+}
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+	return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static unsigned int rx_bytes_expected(struct usb_ep *ep)
+{
+	int rx_remain = fastboot_data_remaining();
+	unsigned int rem;
+	unsigned int maxpacket = usb_endpoint_maxp(ep->desc);
+
+	if (rx_remain <= 0)
+		return 0;
+	else if (rx_remain > EP_BUFFER_SIZE)
+		return EP_BUFFER_SIZE;
+
+	/*
+	 * Some controllers e.g. DWC3 don't like OUT transfers to be
+	 * not ending in maxpacket boundary. So just make them happy by
+	 * always requesting for integral multiple of maxpackets.
+	 * This shouldn't bother controllers that don't care about it.
+	 */
+	rem = rx_remain % maxpacket;
+	if (rem > 0)
+		rx_remain = rx_remain + (maxpacket - rem);
+
+	return rx_remain;
+}
+
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[FASTBOOT_RESPONSE_LEN] = {0};
+	unsigned int transfer_size = fastboot_data_remaining();
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	if (req->status != 0) {
+		printf("Bad status: %d\n", req->status);
+		return;
+	}
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	fastboot_data_download(buffer, transfer_size, response);
+	if (response[0]) {
+		fastboot_tx_write_str(response);
+	} else if (!fastboot_data_remaining()) {
+		fastboot_data_complete(response);
+
+		/*
+		 * Reset global transfer variable
+		 */
+		req->complete = rx_handler_command;
+		req->length = EP_BUFFER_SIZE;
+
+		fastboot_tx_write_str(response);
+	} else {
+		req->length = rx_bytes_expected(ep);
+	}
+
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	g_dnl_trigger_detach();
+}
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	fastboot_boot();
+	do_exit_on_complete(ep, req);
+}
+
+#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
+static void do_acmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	/* When usb dequeue complete will be called
+	 *  Need status value before call run_command.
+	 * otherwise, host can't get last message.
+	 */
+	if (req->status == 0)
+		fastboot_acmd_complete();
+}
+#endif
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmdbuf = req->buf;
+	char response[FASTBOOT_RESPONSE_LEN] = {0};
+	int cmd = -1;
+
+	if (req->status != 0 || req->length == 0)
+		return;
+
+	if (req->actual < req->length) {
+		cmdbuf[req->actual] = '\0';
+		cmd = fastboot_handle_command(cmdbuf, response);
+	} else {
+		pr_err("buffer overflow");
+		fastboot_fail("buffer overflow", response);
+	}
+
+	if (!strncmp("DATA", response, 4)) {
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected(ep);
+	}
+
+	if (!strncmp("OKAY", response, 4)) {
+		switch (cmd) {
+		case FASTBOOT_COMMAND_BOOT:
+			fastboot_func->in_req->complete = do_bootm_on_complete;
+			break;
+
+		case FASTBOOT_COMMAND_CONTINUE:
+			fastboot_func->in_req->complete = do_exit_on_complete;
+			break;
+
+		case FASTBOOT_COMMAND_REBOOT:
+		case FASTBOOT_COMMAND_REBOOT_BOOTLOADER:
+		case FASTBOOT_COMMAND_REBOOT_FASTBOOTD:
+		case FASTBOOT_COMMAND_REBOOT_RECOVERY:
+			fastboot_func->in_req->complete = compl_do_reset;
+			break;
+#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
+		case FASTBOOT_COMMAND_ACMD:
+			fastboot_func->in_req->complete = do_acmd_complete;
+			break;
+#endif
+		}
+	}
+
+	fastboot_tx_write_str(response);
+
+	*cmdbuf = '\0';
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/f_mass_storage.c b/roms/u-boot/drivers/usb/gadget/f_mass_storage.c
new file mode 100644
index 000000000..45f0504b6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_mass_storage.c
@@ -0,0 +1,2777 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * f_mass_storage.c -- Mass Storage USB Composite Function
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyright (C) 2009 Samsung Electronics
+ *                    Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * All rights reserved.
+ */
+
+/*
+ * The Mass Storage Function acts as a USB Mass Storage device,
+ * appearing to the host as a disk drive or as a CD-ROM drive.  In
+ * addition to providing an example of a genuinely useful composite
+ * function for a USB device, it also illustrates a technique of
+ * double-buffering for increased throughput.
+ *
+ * Function supports multiple logical units (LUNs).  Backing storage
+ * for each LUN is provided by a regular file or a block device.
+ * Access for each LUN can be limited to read-only.  Moreover, the
+ * function can indicate that LUN is removable and/or CD-ROM.  (The
+ * later implies read-only access.)
+ *
+ * MSF is configured by specifying a fsg_config structure.  It has the
+ * following fields:
+ *
+ *	nluns		Number of LUNs function have (anywhere from 1
+ *				to FSG_MAX_LUNS which is 8).
+ *	luns		An array of LUN configuration values.  This
+ *				should be filled for each LUN that
+ *				function will include (ie. for "nluns"
+ *				LUNs).  Each element of the array has
+ *				the following fields:
+ *	->filename	The path to the backing file for the LUN.
+ *				Required if LUN is not marked as
+ *				removable.
+ *	->ro		Flag specifying access to the LUN shall be
+ *				read-only.  This is implied if CD-ROM
+ *				emulation is enabled as well as when
+ *				it was impossible to open "filename"
+ *				in R/W mode.
+ *	->removable	Flag specifying that LUN shall be indicated as
+ *				being removable.
+ *	->cdrom		Flag specifying that LUN shall be reported as
+ *				being a CD-ROM.
+ *
+ *	lun_name_format	A printf-like format for names of the LUN
+ *				devices.  This determines how the
+ *				directory in sysfs will be named.
+ *				Unless you are using several MSFs in
+ *				a single gadget (as opposed to single
+ *				MSF in many configurations) you may
+ *				leave it as NULL (in which case
+ *				"lun%d" will be used).  In the format
+ *				you can use "%d" to index LUNs for
+ *				MSF's with more than one LUN.  (Beware
+ *				that there is only one integer given
+ *				as an argument for the format and
+ *				specifying invalid format may cause
+ *				unspecified behaviour.)
+ *	thread_name	Name of the kernel thread process used by the
+ *				MSF.  You can safely set it to NULL
+ *				(in which case default "file-storage"
+ *				will be used).
+ *
+ *	vendor_name
+ *	product_name
+ *	release		Information used as a reply to INQUIRY
+ *				request.  To use default set to NULL,
+ *				NULL, 0xffff respectively.  The first
+ *				field should be 8 and the second 16
+ *				characters or less.
+ *
+ *	can_stall	Set to permit function to halt bulk endpoints.
+ *				Disabled on some USB devices known not
+ *				to work correctly.  You should set it
+ *				to true.
+ *
+ * If "removable" is not set for a LUN then a backing file must be
+ * specified.  If it is set, then NULL filename means the LUN's medium
+ * is not loaded (an empty string as "filename" in the fsg_config
+ * structure causes error).  The CD-ROM emulation includes a single
+ * data track and no audio tracks; hence there need be only one
+ * backing file per LUN.  Note also that the CD-ROM block length is
+ * set to 512 rather than the more common value 2048.
+ *
+ *
+ * MSF includes support for module parameters.  If gadget using it
+ * decides to use it, the following module parameters will be
+ * available:
+ *
+ *	file=filename[,filename...]
+ *			Names of the files or block devices used for
+ *				backing storage.
+ *	ro=b[,b...]	Default false, boolean for read-only access.
+ *	removable=b[,b...]
+ *			Default true, boolean for removable media.
+ *	cdrom=b[,b...]	Default false, boolean for whether to emulate
+ *				a CD-ROM drive.
+ *	luns=N		Default N = number of filenames, number of
+ *				LUNs to support.
+ *	stall		Default determined according to the type of
+ *				USB device controller (usually true),
+ *				boolean to permit the driver to halt
+ *				bulk endpoints.
+ *
+ * The module parameters may be prefixed with some string.  You need
+ * to consult gadget's documentation or source to verify whether it is
+ * using those module parameters and if it does what are the prefixes
+ * (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is
+ * the prefix).
+ *
+ *
+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
+ * needed.  The memory requirement amounts to two 16K buffers, size
+ * configurable by a parameter.  Support is included for both
+ * full-speed and high-speed operation.
+ *
+ * Note that the driver is slightly non-portable in that it assumes a
+ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
+ * interrupt-in endpoints.  With most device controllers this isn't an
+ * issue, but there may be some with hardware restrictions that prevent
+ * a buffer from being used by more than one endpoint.
+ *
+ *
+ * The pathnames of the backing files and the ro settings are
+ * available in the attribute files "file" and "ro" in the lun<n> (or
+ * to be more precise in a directory which name comes from
+ * "lun_name_format" option!) subdirectory of the gadget's sysfs
+ * directory.  If the "removable" option is set, writing to these
+ * files will simulate ejecting/loading the medium (writing an empty
+ * line means eject) and adjusting a write-enable tab.  Changes to the
+ * ro setting are not allowed when the medium is loaded or if CD-ROM
+ * emulation is being used.
+ *
+ * When a LUN receive an "eject" SCSI request (Start/Stop Unit),
+ * if the LUN is removable, the backing file is released to simulate
+ * ejection.
+ *
+ *
+ * This function is heavily based on "File-backed Storage Gadget" by
+ * Alan Stern which in turn is heavily based on "Gadget Zero" by David
+ * Brownell.  The driver's SCSI command interface was based on the
+ * "Information technology - Small Computer System Interface - 2"
+ * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93,
+ * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.
+ * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which
+ * was based on the "Universal Serial Bus Mass Storage Class UFI
+ * Command Specification" document, Revision 1.0, December 14, 1998,
+ * available at
+ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
+ */
+
+/*
+ *				Driver Design
+ *
+ * The MSF is fairly straightforward.  There is a main kernel
+ * thread that handles most of the work.  Interrupt routines field
+ * callbacks from the controller driver: bulk- and interrupt-request
+ * completion notifications, endpoint-0 events, and disconnect events.
+ * Completion events are passed to the main thread by wakeup calls.  Many
+ * ep0 requests are handled at interrupt time, but SetInterface,
+ * SetConfiguration, and device reset requests are forwarded to the
+ * thread in the form of "exceptions" using SIGUSR1 signals (since they
+ * should interrupt any ongoing file I/O operations).
+ *
+ * The thread's main routine implements the standard command/data/status
+ * parts of a SCSI interaction.  It and its subroutines are full of tests
+ * for pending signals/exceptions -- all this polling is necessary since
+ * the kernel has no setjmp/longjmp equivalents.  (Maybe this is an
+ * indication that the driver really wants to be running in userspace.)
+ * An important point is that so long as the thread is alive it keeps an
+ * open reference to the backing file.  This will prevent unmounting
+ * the backing file's underlying filesystem and could cause problems
+ * during system shutdown, for example.  To prevent such problems, the
+ * thread catches INT, TERM, and KILL signals and converts them into
+ * an EXIT exception.
+ *
+ * In normal operation the main thread is started during the gadget's
+ * fsg_bind() callback and stopped during fsg_unbind().  But it can
+ * also exit when it receives a signal, and there's no point leaving
+ * the gadget running when the thread is dead.  At of this moment, MSF
+ * provides no way to deregister the gadget when thread dies -- maybe
+ * a callback functions is needed.
+ *
+ * To provide maximum throughput, the driver uses a circular pipeline of
+ * buffer heads (struct fsg_buffhd).  In principle the pipeline can be
+ * arbitrarily long; in practice the benefits don't justify having more
+ * than 2 stages (i.e., double buffering).  But it helps to think of the
+ * pipeline as being a long one.  Each buffer head contains a bulk-in and
+ * a bulk-out request pointer (since the buffer can be used for both
+ * output and input -- directions always are given from the host's
+ * point of view) as well as a pointer to the buffer and various state
+ * variables.
+ *
+ * Use of the pipeline follows a simple protocol.  There is a variable
+ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
+ * At any time that buffer head may still be in use from an earlier
+ * request, so each buffer head has a state variable indicating whether
+ * it is EMPTY, FULL, or BUSY.  Typical use involves waiting for the
+ * buffer head to be EMPTY, filling the buffer either by file I/O or by
+ * USB I/O (during which the buffer head is BUSY), and marking the buffer
+ * head FULL when the I/O is complete.  Then the buffer will be emptied
+ * (again possibly by USB I/O, during which it is marked BUSY) and
+ * finally marked EMPTY again (possibly by a completion routine).
+ *
+ * A module parameter tells the driver to avoid stalling the bulk
+ * endpoints wherever the transport specification allows.  This is
+ * necessary for some UDCs like the SuperH, which cannot reliably clear a
+ * halt on a bulk endpoint.  However, under certain circumstances the
+ * Bulk-only specification requires a stall.  In such cases the driver
+ * will halt the endpoint and set a flag indicating that it should clear
+ * the halt in software during the next device reset.  Hopefully this
+ * will permit everything to work correctly.  Furthermore, although the
+ * specification allows the bulk-out endpoint to halt when the host sends
+ * too much data, implementing this would cause an unavoidable race.
+ * The driver will always use the "no-stall" approach for OUT transfers.
+ *
+ * One subtle point concerns sending status-stage responses for ep0
+ * requests.  Some of these requests, such as device reset, can involve
+ * interrupting an ongoing file I/O operation, which might take an
+ * arbitrarily long time.  During that delay the host might give up on
+ * the original ep0 request and issue a new one.  When that happens the
+ * driver should not notify the host about completion of the original
+ * request, as the host will no longer be waiting for it.  So the driver
+ * assigns to each ep0 request a unique tag, and it keeps track of the
+ * tag value of the request associated with a long-running exception
+ * (device-reset, interface-change, or configuration-change).  When the
+ * exception handler is finished, the status-stage response is submitted
+ * only if the current ep0 request tag is equal to the exception request
+ * tag.  Thus only the most recently received ep0 request will get a
+ * status-stage response.
+ *
+ * Warning: This driver source file is too long.  It ought to be split up
+ * into a header file plus about 3 separate .c files, to handle the details
+ * of the Gadget, USB Mass Storage, and SCSI protocols.
+ */
+
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
+
+#include <config.h>
+#include <hexdump.h>
+#include <log.h>
+#include <malloc.h>
+#include <common.h>
+#include <console.h>
+#include <g_dnl.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+
+#include <linux/err.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <usb_mass_storage.h>
+
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/bitmap.h>
+#include <g_dnl.h>
+
+/*------------------------------------------------------------------------*/
+
+#define FSG_DRIVER_DESC	"Mass Storage Function"
+#define FSG_DRIVER_VERSION	"2012/06/5"
+
+static const char fsg_string_interface[] = "Mass Storage";
+
+#define FSG_NO_INTR_EP 1
+#define FSG_NO_DEVICE_STRINGS    1
+#define FSG_NO_OTG               1
+#define FSG_NO_INTR_EP           1
+
+#include "storage_common.c"
+
+/*-------------------------------------------------------------------------*/
+
+#define GFP_ATOMIC ((gfp_t) 0)
+#define PAGE_CACHE_SHIFT	12
+#define PAGE_CACHE_SIZE		(1 << PAGE_CACHE_SHIFT)
+#define kthread_create(...)	__builtin_return_address(0)
+#define wait_for_completion(...) do {} while (0)
+
+struct kref {int x; };
+struct completion {int x; };
+
+struct fsg_dev;
+struct fsg_common;
+
+/* Data shared by all the FSG instances. */
+struct fsg_common {
+	struct usb_gadget	*gadget;
+	struct fsg_dev		*fsg, *new_fsg;
+
+	struct usb_ep		*ep0;		/* Copy of gadget->ep0 */
+	struct usb_request	*ep0req;	/* Copy of cdev->req */
+	unsigned int		ep0_req_tag;
+
+	struct fsg_buffhd	*next_buffhd_to_fill;
+	struct fsg_buffhd	*next_buffhd_to_drain;
+	struct fsg_buffhd	buffhds[FSG_NUM_BUFFERS];
+
+	int			cmnd_size;
+	u8			cmnd[MAX_COMMAND_SIZE];
+
+	unsigned int		nluns;
+	unsigned int		lun;
+	struct fsg_lun          luns[FSG_MAX_LUNS];
+
+	unsigned int		bulk_out_maxpacket;
+	enum fsg_state		state;		/* For exception handling */
+	unsigned int		exception_req_tag;
+
+	enum data_direction	data_dir;
+	u32			data_size;
+	u32			data_size_from_cmnd;
+	u32			tag;
+	u32			residue;
+	u32			usb_amount_left;
+
+	unsigned int		can_stall:1;
+	unsigned int		free_storage_on_release:1;
+	unsigned int		phase_error:1;
+	unsigned int		short_packet_received:1;
+	unsigned int		bad_lun_okay:1;
+	unsigned int		running:1;
+
+	int			thread_wakeup_needed;
+	struct completion	thread_notifier;
+	struct task_struct	*thread_task;
+
+	/* Callback functions. */
+	const struct fsg_operations	*ops;
+	/* Gadget's private data. */
+	void			*private_data;
+
+	const char *vendor_name;		/*  8 characters or less */
+	const char *product_name;		/* 16 characters or less */
+	u16 release;
+
+	/* Vendor (8 chars), product (16 chars), release (4
+	 * hexadecimal digits) and NUL byte */
+	char inquiry_string[8 + 16 + 4 + 1];
+
+	struct kref		ref;
+};
+
+struct fsg_config {
+	unsigned nluns;
+	struct fsg_lun_config {
+		const char *filename;
+		char ro;
+		char removable;
+		char cdrom;
+		char nofua;
+	} luns[FSG_MAX_LUNS];
+
+	/* Callback functions. */
+	const struct fsg_operations     *ops;
+	/* Gadget's private data. */
+	void			*private_data;
+
+	const char *vendor_name;		/*  8 characters or less */
+	const char *product_name;		/* 16 characters or less */
+
+	char			can_stall;
+};
+
+struct fsg_dev {
+	struct usb_function	function;
+	struct usb_gadget	*gadget;	/* Copy of cdev->gadget */
+	struct fsg_common	*common;
+
+	u16			interface_number;
+
+	unsigned int		bulk_in_enabled:1;
+	unsigned int		bulk_out_enabled:1;
+
+	unsigned long		atomic_bitflags;
+#define IGNORE_BULK_OUT		0
+
+	struct usb_ep		*bulk_in;
+	struct usb_ep		*bulk_out;
+};
+
+
+static inline int __fsg_is_set(struct fsg_common *common,
+			       const char *func, unsigned line)
+{
+	if (common->fsg)
+		return 1;
+	ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
+#ifdef __UBOOT__
+	assert_noisy(false);
+#else
+	WARN_ON(1);
+#endif
+	return 0;
+}
+
+#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
+
+
+static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
+{
+	return container_of(f, struct fsg_dev, function);
+}
+
+
+typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+static int exception_in_progress(struct fsg_common *common)
+{
+	return common->state > FSG_STATE_IDLE;
+}
+
+/* Make bulk-out requests be divisible by the maxpacket size */
+static void set_bulk_out_req_length(struct fsg_common *common,
+		struct fsg_buffhd *bh, unsigned int length)
+{
+	unsigned int	rem;
+
+	bh->bulk_out_intended_length = length;
+	rem = length % common->bulk_out_maxpacket;
+	if (rem > 0)
+		length += common->bulk_out_maxpacket - rem;
+	bh->outreq->length = length;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct ums *ums;
+static int ums_count;
+static struct fsg_common *the_fsg_common;
+static unsigned int controller_index;
+
+static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
+{
+	const char	*name;
+
+	if (ep == fsg->bulk_in)
+		name = "bulk-in";
+	else if (ep == fsg->bulk_out)
+		name = "bulk-out";
+	else
+		name = ep->name;
+	DBG(fsg, "%s set halt\n", name);
+	return usb_ep_set_halt(ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* These routines may be called in process context or in_irq */
+
+/* Caller must hold fsg->lock */
+static void wakeup_thread(struct fsg_common *common)
+{
+	common->thread_wakeup_needed = 1;
+}
+
+static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
+{
+	/* Do nothing if a higher-priority exception is already in progress.
+	 * If a lower-or-equal priority exception is in progress, preempt it
+	 * and notify the main thread by sending it a signal. */
+	if (common->state <= new_state) {
+		common->exception_req_tag = common->ep0_req_tag;
+		common->state = new_state;
+		common->thread_wakeup_needed = 1;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ep0_queue(struct fsg_common *common)
+{
+	int	rc;
+
+	rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC);
+	common->ep0->driver_data = common;
+	if (rc != 0 && rc != -ESHUTDOWN) {
+		/* We can't do much more than wait for a reset */
+		WARNING(common, "error in submission: %s --> %d\n",
+			common->ep0->name, rc);
+	}
+	return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Bulk and interrupt endpoint completion handlers.
+ * These always run in_irq. */
+
+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_common	*common = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
+
+	if (req->status || req->actual != req->length)
+		DBG(common, "%s --> %d, %u/%u\n", __func__,
+				req->status, req->actual, req->length);
+	if (req->status == -ECONNRESET)		/* Request was cancelled */
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	bh->inreq_busy = 0;
+	bh->state = BUF_STATE_EMPTY;
+	wakeup_thread(common);
+}
+
+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_common	*common = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
+
+	dump_msg(common, "bulk-out", req->buf, req->actual);
+	if (req->status || req->actual != bh->bulk_out_intended_length)
+		DBG(common, "%s --> %d, %u/%u\n", __func__,
+				req->status, req->actual,
+				bh->bulk_out_intended_length);
+	if (req->status == -ECONNRESET)		/* Request was cancelled */
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	bh->outreq_busy = 0;
+	bh->state = BUF_STATE_FULL;
+	wakeup_thread(common);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Ep0 class-specific handlers.  These always run in_irq. */
+
+static int fsg_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct fsg_dev		*fsg = fsg_from_func(f);
+	struct usb_request	*req = fsg->common->ep0req;
+	u16			w_index = get_unaligned_le16(&ctrl->wIndex);
+	u16			w_value = get_unaligned_le16(&ctrl->wValue);
+	u16			w_length = get_unaligned_le16(&ctrl->wLength);
+
+	if (!fsg_is_set(fsg->common))
+		return -EOPNOTSUPP;
+
+	switch (ctrl->bRequest) {
+
+	case USB_BULK_RESET_REQUEST:
+		if (ctrl->bRequestType !=
+		    (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+			break;
+		if (w_index != fsg->interface_number || w_value != 0)
+			return -EDOM;
+
+		/* Raise an exception to stop the current operation
+		 * and reinitialize our state. */
+		DBG(fsg, "bulk reset request\n");
+		raise_exception(fsg->common, FSG_STATE_RESET);
+		return DELAYED_STATUS;
+
+	case USB_BULK_GET_MAX_LUN_REQUEST:
+		if (ctrl->bRequestType !=
+		    (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+			break;
+		if (w_index != fsg->interface_number || w_value != 0)
+			return -EDOM;
+		VDBG(fsg, "get max LUN\n");
+		*(u8 *) req->buf = fsg->common->nluns - 1;
+
+		/* Respond with data/status */
+		req->length = min((u16)1, w_length);
+		return ep0_queue(fsg->common);
+	}
+
+	VDBG(fsg,
+	     "unknown class-specific control req "
+	     "%02x.%02x v%04x i%04x l%u\n",
+	     ctrl->bRequestType, ctrl->bRequest,
+	     get_unaligned_le16(&ctrl->wValue), w_index, w_length);
+	return -EOPNOTSUPP;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* All the following routines run in process context */
+
+/* Use this for bulk or interrupt transfers, not ep0 */
+static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
+		struct usb_request *req, int *pbusy,
+		enum fsg_buffer_state *state)
+{
+	int	rc;
+
+	if (ep == fsg->bulk_in)
+		dump_msg(fsg, "bulk-in", req->buf, req->length);
+
+	*pbusy = 1;
+	*state = BUF_STATE_BUSY;
+	rc = usb_ep_queue(ep, req, GFP_KERNEL);
+	if (rc != 0) {
+		*pbusy = 0;
+		*state = BUF_STATE_EMPTY;
+
+		/* We can't do much more than wait for a reset */
+
+		/* Note: currently the net2280 driver fails zero-length
+		 * submissions if DMA is enabled. */
+		if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
+						req->length == 0))
+			WARNING(fsg, "error in submission: %s --> %d\n",
+					ep->name, rc);
+	}
+}
+
+#define START_TRANSFER_OR(common, ep_name, req, pbusy, state)		\
+	if (fsg_is_set(common))						\
+		start_transfer((common)->fsg, (common)->fsg->ep_name,	\
+			       req, pbusy, state);			\
+	else
+
+#define START_TRANSFER(common, ep_name, req, pbusy, state)		\
+	START_TRANSFER_OR(common, ep_name, req, pbusy, state) (void)0
+
+static void busy_indicator(void)
+{
+	static int state;
+
+	switch (state) {
+	case 0:
+		puts("\r|"); break;
+	case 1:
+		puts("\r/"); break;
+	case 2:
+		puts("\r-"); break;
+	case 3:
+		puts("\r\\"); break;
+	case 4:
+		puts("\r|"); break;
+	case 5:
+		puts("\r/"); break;
+	case 6:
+		puts("\r-"); break;
+	case 7:
+		puts("\r\\"); break;
+	default:
+		state = 0;
+	}
+	if (state++ == 8)
+		state = 0;
+}
+
+static int sleep_thread(struct fsg_common *common)
+{
+	int	rc = 0;
+	int i = 0, k = 0;
+
+	/* Wait until a signal arrives or we are woken up */
+	for (;;) {
+		if (common->thread_wakeup_needed)
+			break;
+
+		if (++i == 20000) {
+			busy_indicator();
+			i = 0;
+			k++;
+		}
+
+		if (k == 10) {
+			/* Handle CTRL+C */
+			if (ctrlc())
+				return -EPIPE;
+
+			/* Check cable connection */
+			if (!g_dnl_board_usb_cable_connected())
+				return -EIO;
+
+			k = 0;
+		}
+
+		usb_gadget_handle_interrupts(controller_index);
+	}
+	common->thread_wakeup_needed = 0;
+	return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int do_read(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = &common->luns[common->lun];
+	u32			lba;
+	struct fsg_buffhd	*bh;
+	int			rc;
+	u32			amount_left;
+	loff_t			file_offset;
+	unsigned int		amount;
+	unsigned int		partial_page;
+	ssize_t			nread;
+
+	/* Get the starting Logical Block Address and check that it's
+	 * not too big */
+	if (common->cmnd[0] == SC_READ_6)
+		lba = get_unaligned_be24(&common->cmnd[1]);
+	else {
+		lba = get_unaligned_be32(&common->cmnd[2]);
+
+		/* We allow DPO (Disable Page Out = don't save data in the
+		 * cache) and FUA (Force Unit Access = don't read from the
+		 * cache), but we don't implement them. */
+		if ((common->cmnd[1] & ~0x18) != 0) {
+			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+	file_offset = ((loff_t) lba) << 9;
+
+	/* Carry out the file reads */
+	amount_left = common->data_size_from_cmnd;
+	if (unlikely(amount_left == 0))
+		return -EIO;		/* No default reply */
+
+	for (;;) {
+
+		/* Figure out how much we need to read:
+		 * Try to read the remaining amount.
+		 * But don't read more than the buffer size.
+		 * And don't try to read past the end of the file.
+		 * Finally, if we're not at a page boundary, don't read past
+		 *	the next page.
+		 * If this means reading 0 then we were asked to read past
+		 *	the end of file. */
+		amount = min(amount_left, FSG_BUFLEN);
+		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
+		if (partial_page > 0)
+			amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
+					partial_page);
+
+		/* Wait for the next buffer to become available */
+		bh = common->next_buffhd_to_fill;
+		while (bh->state != BUF_STATE_EMPTY) {
+			rc = sleep_thread(common);
+			if (rc)
+				return rc;
+		}
+
+		/* If we were asked to read past the end of file,
+		 * end with an empty buffer. */
+		if (amount == 0) {
+			curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+			curlun->info_valid = 1;
+			bh->inreq->length = 0;
+			bh->state = BUF_STATE_FULL;
+			break;
+		}
+
+		/* Perform the read */
+		rc = ums[common->lun].read_sector(&ums[common->lun],
+				      file_offset / SECTOR_SIZE,
+				      amount / SECTOR_SIZE,
+				      (char __user *)bh->buf);
+		if (!rc)
+			return -EIO;
+
+		nread = rc * SECTOR_SIZE;
+
+		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+				(unsigned long long) file_offset,
+				(int) nread);
+
+		if (nread < 0) {
+			LDBG(curlun, "error in file read: %d\n",
+					(int) nread);
+			nread = 0;
+		} else if (nread < amount) {
+			LDBG(curlun, "partial file read: %d/%u\n",
+					(int) nread, amount);
+			nread -= (nread & 511);	/* Round down to a block */
+		}
+		file_offset  += nread;
+		amount_left  -= nread;
+		common->residue -= nread;
+		bh->inreq->length = nread;
+		bh->state = BUF_STATE_FULL;
+
+		/* If an error occurred, report it and its position */
+		if (nread < amount) {
+			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+			curlun->info_valid = 1;
+			break;
+		}
+
+		if (amount_left == 0)
+			break;		/* No more left to read */
+
+		/* Send this buffer and go read some more */
+		bh->inreq->zero = 0;
+		START_TRANSFER_OR(common, bulk_in, bh->inreq,
+			       &bh->inreq_busy, &bh->state)
+			/* Don't know what to do if
+			 * common->fsg is NULL */
+			return -EIO;
+		common->next_buffhd_to_fill = bh->next;
+	}
+
+	return -EIO;		/* No default reply */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int do_write(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = &common->luns[common->lun];
+	u32			lba;
+	struct fsg_buffhd	*bh;
+	int			get_some_more;
+	u32			amount_left_to_req, amount_left_to_write;
+	loff_t			usb_offset, file_offset;
+	unsigned int		amount;
+	unsigned int		partial_page;
+	ssize_t			nwritten;
+	int			rc;
+
+	if (curlun->ro) {
+		curlun->sense_data = SS_WRITE_PROTECTED;
+		return -EINVAL;
+	}
+
+	/* Get the starting Logical Block Address and check that it's
+	 * not too big */
+	if (common->cmnd[0] == SC_WRITE_6)
+		lba = get_unaligned_be24(&common->cmnd[1]);
+	else {
+		lba = get_unaligned_be32(&common->cmnd[2]);
+
+		/* We allow DPO (Disable Page Out = don't save data in the
+		 * cache) and FUA (Force Unit Access = write directly to the
+		 * medium).  We don't implement DPO; we implement FUA by
+		 * performing synchronous output. */
+		if (common->cmnd[1] & ~0x18) {
+			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/* Carry out the file writes */
+	get_some_more = 1;
+	file_offset = usb_offset = ((loff_t) lba) << 9;
+	amount_left_to_req = common->data_size_from_cmnd;
+	amount_left_to_write = common->data_size_from_cmnd;
+
+	while (amount_left_to_write > 0) {
+
+		/* Queue a request for more data from the host */
+		bh = common->next_buffhd_to_fill;
+		if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+			/* Figure out how much we want to get:
+			 * Try to get the remaining amount.
+			 * But don't get more than the buffer size.
+			 * And don't try to go past the end of the file.
+			 * If we're not at a page boundary,
+			 *	don't go past the next page.
+			 * If this means getting 0, then we were asked
+			 *	to write past the end of file.
+			 * Finally, round down to a block boundary. */
+			amount = min(amount_left_to_req, FSG_BUFLEN);
+			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
+			if (partial_page > 0)
+				amount = min(amount,
+	(unsigned int) PAGE_CACHE_SIZE - partial_page);
+
+			if (amount == 0) {
+				get_some_more = 0;
+				curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+				curlun->info_valid = 1;
+				continue;
+			}
+			amount -= (amount & 511);
+			if (amount == 0) {
+
+				/* Why were we were asked to transfer a
+				 * partial block? */
+				get_some_more = 0;
+				continue;
+			}
+
+			/* Get the next buffer */
+			usb_offset += amount;
+			common->usb_amount_left -= amount;
+			amount_left_to_req -= amount;
+			if (amount_left_to_req == 0)
+				get_some_more = 0;
+
+			/* amount is always divisible by 512, hence by
+			 * the bulk-out maxpacket size */
+			bh->outreq->length = amount;
+			bh->bulk_out_intended_length = amount;
+			bh->outreq->short_not_ok = 1;
+			START_TRANSFER_OR(common, bulk_out, bh->outreq,
+					  &bh->outreq_busy, &bh->state)
+				/* Don't know what to do if
+				 * common->fsg is NULL */
+				return -EIO;
+			common->next_buffhd_to_fill = bh->next;
+			continue;
+		}
+
+		/* Write the received data to the backing file */
+		bh = common->next_buffhd_to_drain;
+		if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+			break;			/* We stopped early */
+		if (bh->state == BUF_STATE_FULL) {
+			common->next_buffhd_to_drain = bh->next;
+			bh->state = BUF_STATE_EMPTY;
+
+			/* Did something go wrong with the transfer? */
+			if (bh->outreq->status != 0) {
+				curlun->sense_data = SS_COMMUNICATION_FAILURE;
+				curlun->info_valid = 1;
+				break;
+			}
+
+			amount = bh->outreq->actual;
+
+			/* Perform the write */
+			rc = ums[common->lun].write_sector(&ums[common->lun],
+					       file_offset / SECTOR_SIZE,
+					       amount / SECTOR_SIZE,
+					       (char __user *)bh->buf);
+			if (!rc)
+				return -EIO;
+			nwritten = rc * SECTOR_SIZE;
+
+			VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
+					(unsigned long long) file_offset,
+					(int) nwritten);
+
+			if (nwritten < 0) {
+				LDBG(curlun, "error in file write: %d\n",
+						(int) nwritten);
+				nwritten = 0;
+			} else if (nwritten < amount) {
+				LDBG(curlun, "partial file write: %d/%u\n",
+						(int) nwritten, amount);
+				nwritten -= (nwritten & 511);
+				/* Round down to a block */
+			}
+			file_offset += nwritten;
+			amount_left_to_write -= nwritten;
+			common->residue -= nwritten;
+
+			/* If an error occurred, report it and its position */
+			if (nwritten < amount) {
+				printf("nwritten:%zd amount:%u\n", nwritten,
+				       amount);
+				curlun->sense_data = SS_WRITE_ERROR;
+				curlun->info_valid = 1;
+				break;
+			}
+
+			/* Did the host decide to stop early? */
+			if (bh->outreq->actual != bh->outreq->length) {
+				common->short_packet_received = 1;
+				break;
+			}
+			continue;
+		}
+
+		/* Wait for something to happen */
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	return -EIO;		/* No default reply */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int do_synchronize_cache(struct fsg_common *common)
+{
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int do_verify(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = &common->luns[common->lun];
+	u32			lba;
+	u32			verification_length;
+	struct fsg_buffhd	*bh = common->next_buffhd_to_fill;
+	loff_t			file_offset;
+	u32			amount_left;
+	unsigned int		amount;
+	ssize_t			nread;
+	int			rc;
+
+	/* Get the starting Logical Block Address and check that it's
+	 * not too big */
+	lba = get_unaligned_be32(&common->cmnd[2]);
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/* We allow DPO (Disable Page Out = don't save data in the
+	 * cache) but we don't implement it. */
+	if (common->cmnd[1] & ~0x10) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	verification_length = get_unaligned_be16(&common->cmnd[7]);
+	if (unlikely(verification_length == 0))
+		return -EIO;		/* No default reply */
+
+	/* Prepare to carry out the file verify */
+	amount_left = verification_length << 9;
+	file_offset = ((loff_t) lba) << 9;
+
+	/* Write out all the dirty buffers before invalidating them */
+
+	/* Just try to read the requested blocks */
+	while (amount_left > 0) {
+
+		/* Figure out how much we need to read:
+		 * Try to read the remaining amount, but not more than
+		 * the buffer size.
+		 * And don't try to read past the end of the file.
+		 * If this means reading 0 then we were asked to read
+		 * past the end of file. */
+		amount = min(amount_left, FSG_BUFLEN);
+		if (amount == 0) {
+			curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+			curlun->info_valid = 1;
+			break;
+		}
+
+		/* Perform the read */
+		rc = ums[common->lun].read_sector(&ums[common->lun],
+				      file_offset / SECTOR_SIZE,
+				      amount / SECTOR_SIZE,
+				      (char __user *)bh->buf);
+		if (!rc)
+			return -EIO;
+		nread = rc * SECTOR_SIZE;
+
+		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+				(unsigned long long) file_offset,
+				(int) nread);
+		if (nread < 0) {
+			LDBG(curlun, "error in file verify: %d\n",
+					(int) nread);
+			nread = 0;
+		} else if (nread < amount) {
+			LDBG(curlun, "partial file verify: %d/%u\n",
+					(int) nread, amount);
+			nread -= (nread & 511);	/* Round down to a sector */
+		}
+		if (nread == 0) {
+			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+			curlun->info_valid = 1;
+			break;
+		}
+		file_offset += nread;
+		amount_left -= nread;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun *curlun = &common->luns[common->lun];
+	static const char vendor_id[] = "Linux   ";
+	u8	*buf = (u8 *) bh->buf;
+
+	if (!curlun) {		/* Unsupported LUNs are okay */
+		common->bad_lun_okay = 1;
+		memset(buf, 0, 36);
+		buf[0] = 0x7f;		/* Unsupported, no device-type */
+		buf[4] = 31;		/* Additional length */
+		return 36;
+	}
+
+	memset(buf, 0, 8);
+	buf[0] = TYPE_DISK;
+	buf[1] = curlun->removable ? 0x80 : 0;
+	buf[2] = 2;		/* ANSI SCSI level 2 */
+	buf[3] = 2;		/* SCSI-2 INQUIRY data format */
+	buf[4] = 31;		/* Additional length */
+				/* No special options */
+	sprintf((char *) (buf + 8), "%-8s%-16s%04x", (char*) vendor_id ,
+			ums[common->lun].name, (u16) 0xffff);
+
+	return 36;
+}
+
+
+static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	u8		*buf = (u8 *) bh->buf;
+	u32		sd, sdinfo;
+	int		valid;
+
+	/*
+	 * From the SCSI-2 spec., section 7.9 (Unit attention condition):
+	 *
+	 * If a REQUEST SENSE command is received from an initiator
+	 * with a pending unit attention condition (before the target
+	 * generates the contingent allegiance condition), then the
+	 * target shall either:
+	 *   a) report any pending sense data and preserve the unit
+	 *	attention condition on the logical unit, or,
+	 *   b) report the unit attention condition, may discard any
+	 *	pending sense data, and clear the unit attention
+	 *	condition on the logical unit for that initiator.
+	 *
+	 * FSG normally uses option a); enable this code to use option b).
+	 */
+#if 0
+	if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
+		curlun->sense_data = curlun->unit_attention_data;
+		curlun->unit_attention_data = SS_NO_SENSE;
+	}
+#endif
+
+	if (!curlun) {		/* Unsupported LUNs are okay */
+		common->bad_lun_okay = 1;
+		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+		sdinfo = 0;
+		valid = 0;
+	} else {
+		sd = curlun->sense_data;
+		valid = curlun->info_valid << 7;
+		curlun->sense_data = SS_NO_SENSE;
+		curlun->info_valid = 0;
+	}
+
+	memset(buf, 0, 18);
+	buf[0] = valid | 0x70;			/* Valid, current error */
+	buf[2] = SK(sd);
+	put_unaligned_be32(sdinfo, &buf[3]);	/* Sense information */
+	buf[7] = 18 - 8;			/* Additional sense length */
+	buf[12] = ASC(sd);
+	buf[13] = ASCQ(sd);
+	return 18;
+}
+
+static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	u32		lba = get_unaligned_be32(&common->cmnd[2]);
+	int		pmi = common->cmnd[8];
+	u8		*buf = (u8 *) bh->buf;
+
+	/* Check the PMI and LBA fields */
+	if (pmi > 1 || (pmi == 0 && lba != 0)) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
+						/* Max logical block */
+	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	return 8;
+}
+
+static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	int		msf = common->cmnd[1] & 0x02;
+	u32		lba = get_unaligned_be32(&common->cmnd[2]);
+	u8		*buf = (u8 *) bh->buf;
+
+	if (common->cmnd[1] & ~0x02) {		/* Mask away MSF */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	memset(buf, 0, 8);
+	buf[0] = 0x01;		/* 2048 bytes of user data, rest is EC */
+	store_cdrom_address(&buf[4], msf, lba);
+	return 8;
+}
+
+
+static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	int		msf = common->cmnd[1] & 0x02;
+	int		start_track = common->cmnd[6];
+	u8		*buf = (u8 *) bh->buf;
+
+	if ((common->cmnd[1] & ~0x02) != 0 ||	/* Mask away MSF */
+			start_track > 1) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	memset(buf, 0, 20);
+	buf[1] = (20-2);		/* TOC data length */
+	buf[2] = 1;			/* First track number */
+	buf[3] = 1;			/* Last track number */
+	buf[5] = 0x16;			/* Data track, copying allowed */
+	buf[6] = 0x01;			/* Only track is number 1 */
+	store_cdrom_address(&buf[8], msf, 0);
+
+	buf[13] = 0x16;			/* Lead-out track is data */
+	buf[14] = 0xAA;			/* Lead-out track number */
+	store_cdrom_address(&buf[16], msf, curlun->num_sectors);
+
+	return 20;
+}
+
+static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	int		mscmnd = common->cmnd[0];
+	u8		*buf = (u8 *) bh->buf;
+	u8		*buf0 = buf;
+	int		pc, page_code;
+	int		changeable_values, all_pages;
+	int		valid_page = 0;
+	int		len, limit;
+
+	if ((common->cmnd[1] & ~0x08) != 0) {	/* Mask away DBD */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+	pc = common->cmnd[2] >> 6;
+	page_code = common->cmnd[2] & 0x3f;
+	if (pc == 3) {
+		curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
+		return -EINVAL;
+	}
+	changeable_values = (pc == 1);
+	all_pages = (page_code == 0x3f);
+
+	/* Write the mode parameter header.  Fixed values are: default
+	 * medium type, no cache control (DPOFUA), and no block descriptors.
+	 * The only variable value is the WriteProtect bit.  We will fill in
+	 * the mode data length later. */
+	memset(buf, 0, 8);
+	if (mscmnd == SC_MODE_SENSE_6) {
+		buf[2] = (curlun->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
+		buf += 4;
+		limit = 255;
+	} else {			/* SC_MODE_SENSE_10 */
+		buf[3] = (curlun->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
+		buf += 8;
+		limit = 65535;		/* Should really be FSG_BUFLEN */
+	}
+
+	/* No block descriptors */
+
+	/* The mode pages, in numerical order.  The only page we support
+	 * is the Caching page. */
+	if (page_code == 0x08 || all_pages) {
+		valid_page = 1;
+		buf[0] = 0x08;		/* Page code */
+		buf[1] = 10;		/* Page length */
+		memset(buf+2, 0, 10);	/* None of the fields are changeable */
+
+		if (!changeable_values) {
+			buf[2] = 0x04;	/* Write cache enable, */
+					/* Read cache not disabled */
+					/* No cache retention priorities */
+			put_unaligned_be16(0xffff, &buf[4]);
+					/* Don't disable prefetch */
+					/* Minimum prefetch = 0 */
+			put_unaligned_be16(0xffff, &buf[8]);
+					/* Maximum prefetch */
+			put_unaligned_be16(0xffff, &buf[10]);
+					/* Maximum prefetch ceiling */
+		}
+		buf += 12;
+	}
+
+	/* Check that a valid page was requested and the mode data length
+	 * isn't too long. */
+	len = buf - buf0;
+	if (!valid_page || len > limit) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	/*  Store the mode data length */
+	if (mscmnd == SC_MODE_SENSE_6)
+		buf0[0] = len - 1;
+	else
+		put_unaligned_be16(len - 2, buf0);
+	return len;
+}
+
+
+static int do_start_stop(struct fsg_common *common)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+
+	if (!curlun) {
+		return -EINVAL;
+	} else if (!curlun->removable) {
+		curlun->sense_data = SS_INVALID_COMMAND;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int do_prevent_allow(struct fsg_common *common)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	int		prevent;
+
+	if (!curlun->removable) {
+		curlun->sense_data = SS_INVALID_COMMAND;
+		return -EINVAL;
+	}
+
+	prevent = common->cmnd[4] & 0x01;
+	if ((common->cmnd[4] & ~0x01) != 0) {	/* Mask away Prevent */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	if (curlun->prevent_medium_removal && !prevent)
+		fsg_lun_fsync_sub(curlun);
+	curlun->prevent_medium_removal = prevent;
+	return 0;
+}
+
+
+static int do_read_format_capacities(struct fsg_common *common,
+			struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+	u8		*buf = (u8 *) bh->buf;
+
+	buf[0] = buf[1] = buf[2] = 0;
+	buf[3] = 8;	/* Only the Current/Maximum Capacity Descriptor */
+	buf += 4;
+
+	put_unaligned_be32(curlun->num_sectors, &buf[0]);
+						/* Number of blocks */
+	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	buf[4] = 0x02;				/* Current capacity */
+	return 12;
+}
+
+
+static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = &common->luns[common->lun];
+
+	/* We don't support MODE SELECT */
+	if (curlun)
+		curlun->sense_data = SS_INVALID_COMMAND;
+	return -EINVAL;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	rc = fsg_set_halt(fsg, fsg->bulk_in);
+	if (rc == -EAGAIN)
+		VDBG(fsg, "delayed bulk-in endpoint halt\n");
+	while (rc != 0) {
+		if (rc != -EAGAIN) {
+			WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
+			rc = 0;
+			break;
+		}
+
+		rc = usb_ep_set_halt(fsg->bulk_in);
+	}
+	return rc;
+}
+
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	DBG(fsg, "bulk-in set wedge\n");
+	rc = 0; /* usb_ep_set_wedge(fsg->bulk_in); */
+	if (rc == -EAGAIN)
+		VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+	while (rc != 0) {
+		if (rc != -EAGAIN) {
+			WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
+			rc = 0;
+			break;
+		}
+	}
+	return rc;
+}
+
+static int pad_with_zeros(struct fsg_dev *fsg)
+{
+	struct fsg_buffhd	*bh = fsg->common->next_buffhd_to_fill;
+	u32			nkeep = bh->inreq->length;
+	u32			nsend;
+	int			rc;
+
+	bh->state = BUF_STATE_EMPTY;		/* For the first iteration */
+	fsg->common->usb_amount_left = nkeep + fsg->common->residue;
+	while (fsg->common->usb_amount_left > 0) {
+
+		/* Wait for the next buffer to be free */
+		while (bh->state != BUF_STATE_EMPTY) {
+			rc = sleep_thread(fsg->common);
+			if (rc)
+				return rc;
+		}
+
+		nsend = min(fsg->common->usb_amount_left, FSG_BUFLEN);
+		memset(bh->buf + nkeep, 0, nsend - nkeep);
+		bh->inreq->length = nsend;
+		bh->inreq->zero = 0;
+		start_transfer(fsg, fsg->bulk_in, bh->inreq,
+				&bh->inreq_busy, &bh->state);
+		bh = fsg->common->next_buffhd_to_fill = bh->next;
+		fsg->common->usb_amount_left -= nsend;
+		nkeep = 0;
+	}
+	return 0;
+}
+
+static int throw_away_data(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh;
+	u32			amount;
+	int			rc;
+
+	for (bh = common->next_buffhd_to_drain;
+	     bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0;
+	     bh = common->next_buffhd_to_drain) {
+
+		/* Throw away the data in a filled buffer */
+		if (bh->state == BUF_STATE_FULL) {
+			bh->state = BUF_STATE_EMPTY;
+			common->next_buffhd_to_drain = bh->next;
+
+			/* A short packet or an error ends everything */
+			if (bh->outreq->actual != bh->outreq->length ||
+					bh->outreq->status != 0) {
+				raise_exception(common,
+						FSG_STATE_ABORT_BULK_OUT);
+				return -EINTR;
+			}
+			continue;
+		}
+
+		/* Try to submit another request if we need one */
+		bh = common->next_buffhd_to_fill;
+		if (bh->state == BUF_STATE_EMPTY
+		 && common->usb_amount_left > 0) {
+			amount = min(common->usb_amount_left, FSG_BUFLEN);
+
+			/* amount is always divisible by 512, hence by
+			 * the bulk-out maxpacket size */
+			bh->outreq->length = amount;
+			bh->bulk_out_intended_length = amount;
+			bh->outreq->short_not_ok = 1;
+			START_TRANSFER_OR(common, bulk_out, bh->outreq,
+					  &bh->outreq_busy, &bh->state)
+				/* Don't know what to do if
+				 * common->fsg is NULL */
+				return -EIO;
+			common->next_buffhd_to_fill = bh->next;
+			common->usb_amount_left -= amount;
+			continue;
+		}
+
+		/* Otherwise wait for something to happen */
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
+
+static int finish_reply(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh = common->next_buffhd_to_fill;
+	int			rc = 0;
+
+	switch (common->data_dir) {
+	case DATA_DIR_NONE:
+		break;			/* Nothing to send */
+
+	/* If we don't know whether the host wants to read or write,
+	 * this must be CB or CBI with an unknown command.  We mustn't
+	 * try to send or receive any data.  So stall both bulk pipes
+	 * if we can and wait for a reset. */
+	case DATA_DIR_UNKNOWN:
+		if (!common->can_stall) {
+			/* Nothing */
+		} else if (fsg_is_set(common)) {
+			fsg_set_halt(common->fsg, common->fsg->bulk_out);
+			rc = halt_bulk_in_endpoint(common->fsg);
+		} else {
+			/* Don't know what to do if common->fsg is NULL */
+			rc = -EIO;
+		}
+		break;
+
+	/* All but the last buffer of data must have already been sent */
+	case DATA_DIR_TO_HOST:
+		if (common->data_size == 0) {
+			/* Nothing to send */
+
+		/* If there's no residue, simply send the last buffer */
+		} else if (common->residue == 0) {
+			bh->inreq->zero = 0;
+			START_TRANSFER_OR(common, bulk_in, bh->inreq,
+					  &bh->inreq_busy, &bh->state)
+				return -EIO;
+			common->next_buffhd_to_fill = bh->next;
+
+		/* For Bulk-only, if we're allowed to stall then send the
+		 * short packet and halt the bulk-in endpoint.  If we can't
+		 * stall, pad out the remaining data with 0's. */
+		} else if (common->can_stall) {
+			bh->inreq->zero = 1;
+			START_TRANSFER_OR(common, bulk_in, bh->inreq,
+					  &bh->inreq_busy, &bh->state)
+				/* Don't know what to do if
+				 * common->fsg is NULL */
+				rc = -EIO;
+			common->next_buffhd_to_fill = bh->next;
+			if (common->fsg)
+				rc = halt_bulk_in_endpoint(common->fsg);
+		} else if (fsg_is_set(common)) {
+			rc = pad_with_zeros(common->fsg);
+		} else {
+			/* Don't know what to do if common->fsg is NULL */
+			rc = -EIO;
+		}
+		break;
+
+	/* We have processed all we want from the data the host has sent.
+	 * There may still be outstanding bulk-out requests. */
+	case DATA_DIR_FROM_HOST:
+		if (common->residue == 0) {
+			/* Nothing to receive */
+
+		/* Did the host stop sending unexpectedly early? */
+		} else if (common->short_packet_received) {
+			raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
+			rc = -EINTR;
+
+		/* We haven't processed all the incoming data.  Even though
+		 * we may be allowed to stall, doing so would cause a race.
+		 * The controller may already have ACK'ed all the remaining
+		 * bulk-out packets, in which case the host wouldn't see a
+		 * STALL.  Not realizing the endpoint was halted, it wouldn't
+		 * clear the halt -- leading to problems later on. */
+#if 0
+		} else if (common->can_stall) {
+			if (fsg_is_set(common))
+				fsg_set_halt(common->fsg,
+					     common->fsg->bulk_out);
+			raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
+			rc = -EINTR;
+#endif
+
+		/* We can't stall.  Read in the excess data and throw it
+		 * all away. */
+		} else {
+			rc = throw_away_data(common);
+		}
+		break;
+	}
+	return rc;
+}
+
+
+static int send_status(struct fsg_common *common)
+{
+	struct fsg_lun		*curlun = &common->luns[common->lun];
+	struct fsg_buffhd	*bh;
+	struct bulk_cs_wrap	*csw;
+	int			rc;
+	u8			status = USB_STATUS_PASS;
+	u32			sd, sdinfo = 0;
+
+	/* Wait for the next buffer to become available */
+	bh = common->next_buffhd_to_fill;
+	while (bh->state != BUF_STATE_EMPTY) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	if (curlun)
+		sd = curlun->sense_data;
+	else if (common->bad_lun_okay)
+		sd = SS_NO_SENSE;
+	else
+		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+	if (common->phase_error) {
+		DBG(common, "sending phase-error status\n");
+		status = USB_STATUS_PHASE_ERROR;
+		sd = SS_INVALID_COMMAND;
+	} else if (sd != SS_NO_SENSE) {
+		DBG(common, "sending command-failure status\n");
+		status = USB_STATUS_FAIL;
+		VDBG(common, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+			"  info x%x\n",
+			SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+	}
+
+	/* Store and send the Bulk-only CSW */
+	csw = (void *)bh->buf;
+
+	csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+	csw->Tag = common->tag;
+	csw->Residue = cpu_to_le32(common->residue);
+	csw->Status = status;
+
+	bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+	bh->inreq->zero = 0;
+	START_TRANSFER_OR(common, bulk_in, bh->inreq,
+			  &bh->inreq_busy, &bh->state)
+		/* Don't know what to do if common->fsg is NULL */
+		return -EIO;
+
+	common->next_buffhd_to_fill = bh->next;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Check whether the command is properly formed and whether its data size
+ * and direction agree with the values we already have. */
+static int check_command(struct fsg_common *common, int cmnd_size,
+		enum data_direction data_dir, unsigned int mask,
+		int needs_medium, const char *name)
+{
+	int			i;
+	int			lun = common->cmnd[1] >> 5;
+	static const char	dirletter[4] = {'u', 'o', 'i', 'n'};
+	char			hdlen[20];
+	struct fsg_lun		*curlun;
+
+	hdlen[0] = 0;
+	if (common->data_dir != DATA_DIR_UNKNOWN)
+		sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
+				common->data_size);
+	VDBG(common, "SCSI command: %s;  Dc=%d, D%c=%u;  Hc=%d%s\n",
+	     name, cmnd_size, dirletter[(int) data_dir],
+	     common->data_size_from_cmnd, common->cmnd_size, hdlen);
+
+	/* We can't reply at all until we know the correct data direction
+	 * and size. */
+	if (common->data_size_from_cmnd == 0)
+		data_dir = DATA_DIR_NONE;
+	if (common->data_size < common->data_size_from_cmnd) {
+		/* Host data size < Device data size is a phase error.
+		 * Carry out the command, but only transfer as much as
+		 * we are allowed. */
+		common->data_size_from_cmnd = common->data_size;
+		common->phase_error = 1;
+	}
+	common->residue = common->data_size;
+	common->usb_amount_left = common->data_size;
+
+	/* Conflicting data directions is a phase error */
+	if (common->data_dir != data_dir
+	 && common->data_size_from_cmnd > 0) {
+		common->phase_error = 1;
+		return -EINVAL;
+	}
+
+	/* Verify the length of the command itself */
+	if (cmnd_size != common->cmnd_size) {
+
+		/* Special case workaround: There are plenty of buggy SCSI
+		 * implementations. Many have issues with cbw->Length
+		 * field passing a wrong command size. For those cases we
+		 * always try to work around the problem by using the length
+		 * sent by the host side provided it is at least as large
+		 * as the correct command length.
+		 * Examples of such cases would be MS-Windows, which issues
+		 * REQUEST SENSE with cbw->Length == 12 where it should
+		 * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
+		 * REQUEST SENSE with cbw->Length == 10 where it should
+		 * be 6 as well.
+		 */
+		if (cmnd_size <= common->cmnd_size) {
+			DBG(common, "%s is buggy! Expected length %d "
+			    "but we got %d\n", name,
+			    cmnd_size, common->cmnd_size);
+			cmnd_size = common->cmnd_size;
+		} else {
+			common->phase_error = 1;
+			return -EINVAL;
+		}
+	}
+
+	/* Check that the LUN values are consistent */
+	if (common->lun != lun)
+		DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
+		    common->lun, lun);
+
+	/* Check the LUN */
+	if (common->lun < common->nluns) {
+		curlun = &common->luns[common->lun];
+		if (common->cmnd[0] != SC_REQUEST_SENSE) {
+			curlun->sense_data = SS_NO_SENSE;
+			curlun->info_valid = 0;
+		}
+	} else {
+		curlun = NULL;
+		common->bad_lun_okay = 0;
+
+		/* INQUIRY and REQUEST SENSE commands are explicitly allowed
+		 * to use unsupported LUNs; all others may not. */
+		if (common->cmnd[0] != SC_INQUIRY &&
+		    common->cmnd[0] != SC_REQUEST_SENSE) {
+			DBG(common, "unsupported LUN %d\n", common->lun);
+			return -EINVAL;
+		}
+	}
+#if 0
+	/* If a unit attention condition exists, only INQUIRY and
+	 * REQUEST SENSE commands are allowed; anything else must fail. */
+	if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
+			common->cmnd[0] != SC_INQUIRY &&
+			common->cmnd[0] != SC_REQUEST_SENSE) {
+		curlun->sense_data = curlun->unit_attention_data;
+		curlun->unit_attention_data = SS_NO_SENSE;
+		return -EINVAL;
+	}
+#endif
+	/* Check that only command bytes listed in the mask are non-zero */
+	common->cmnd[1] &= 0x1f;			/* Mask away the LUN */
+	for (i = 1; i < cmnd_size; ++i) {
+		if (common->cmnd[i] && !(mask & (1 << i))) {
+			if (curlun)
+				curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+
+static int do_scsi_command(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh;
+	int			rc;
+	int			reply = -EINVAL;
+	int			i;
+	static char		unknown[16];
+	struct fsg_lun		*curlun = &common->luns[common->lun];
+
+	dump_cdb(common);
+
+	/* Wait for the next buffer to become available for data or status */
+	bh = common->next_buffhd_to_fill;
+	common->next_buffhd_to_drain = bh;
+	while (bh->state != BUF_STATE_EMPTY) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+	common->phase_error = 0;
+	common->short_packet_received = 0;
+
+	down_read(&common->filesem);	/* We're using the backing file */
+	switch (common->cmnd[0]) {
+
+	case SC_INQUIRY:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (1<<4), 0,
+				      "INQUIRY");
+		if (reply == 0)
+			reply = do_inquiry(common, bh);
+		break;
+
+	case SC_MODE_SELECT_6:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+				      (1<<1) | (1<<4), 0,
+				      "MODE SELECT(6)");
+		if (reply == 0)
+			reply = do_mode_select(common, bh);
+		break;
+
+	case SC_MODE_SELECT_10:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+				      (1<<1) | (3<<7), 0,
+				      "MODE SELECT(10)");
+		if (reply == 0)
+			reply = do_mode_select(common, bh);
+		break;
+
+	case SC_MODE_SENSE_6:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (1<<1) | (1<<2) | (1<<4), 0,
+				      "MODE SENSE(6)");
+		if (reply == 0)
+			reply = do_mode_sense(common, bh);
+		break;
+
+	case SC_MODE_SENSE_10:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (1<<1) | (1<<2) | (3<<7), 0,
+				      "MODE SENSE(10)");
+		if (reply == 0)
+			reply = do_mode_sense(common, bh);
+		break;
+
+	case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 6, DATA_DIR_NONE,
+				      (1<<4), 0,
+				      "PREVENT-ALLOW MEDIUM REMOVAL");
+		if (reply == 0)
+			reply = do_prevent_allow(common);
+		break;
+
+	case SC_READ_6:
+		i = common->cmnd[4];
+		common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (7<<1) | (1<<4), 1,
+				      "READ(6)");
+		if (reply == 0)
+			reply = do_read(common);
+		break;
+
+	case SC_READ_10:
+		common->data_size_from_cmnd =
+				get_unaligned_be16(&common->cmnd[7]) << 9;
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (1<<1) | (0xf<<2) | (3<<7), 1,
+				      "READ(10)");
+		if (reply == 0)
+			reply = do_read(common);
+		break;
+
+	case SC_READ_12:
+		common->data_size_from_cmnd =
+				get_unaligned_be32(&common->cmnd[6]) << 9;
+		reply = check_command(common, 12, DATA_DIR_TO_HOST,
+				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
+				      "READ(12)");
+		if (reply == 0)
+			reply = do_read(common);
+		break;
+
+	case SC_READ_CAPACITY:
+		common->data_size_from_cmnd = 8;
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (0xf<<2) | (1<<8), 1,
+				      "READ CAPACITY");
+		if (reply == 0)
+			reply = do_read_capacity(common, bh);
+		break;
+
+	case SC_READ_HEADER:
+		if (!common->luns[common->lun].cdrom)
+			goto unknown_cmnd;
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (3<<7) | (0x1f<<1), 1,
+				      "READ HEADER");
+		if (reply == 0)
+			reply = do_read_header(common, bh);
+		break;
+
+	case SC_READ_TOC:
+		if (!common->luns[common->lun].cdrom)
+			goto unknown_cmnd;
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (7<<6) | (1<<1), 1,
+				      "READ TOC");
+		if (reply == 0)
+			reply = do_read_toc(common, bh);
+		break;
+
+	case SC_READ_FORMAT_CAPACITIES:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (3<<7), 1,
+				      "READ FORMAT CAPACITIES");
+		if (reply == 0)
+			reply = do_read_format_capacities(common, bh);
+		break;
+
+	case SC_REQUEST_SENSE:
+		common->data_size_from_cmnd = common->cmnd[4];
+		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+				      (1<<4), 0,
+				      "REQUEST SENSE");
+		if (reply == 0)
+			reply = do_request_sense(common, bh);
+		break;
+
+	case SC_START_STOP_UNIT:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 6, DATA_DIR_NONE,
+				      (1<<1) | (1<<4), 0,
+				      "START-STOP UNIT");
+		if (reply == 0)
+			reply = do_start_stop(common);
+		break;
+
+	case SC_SYNCHRONIZE_CACHE:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 10, DATA_DIR_NONE,
+				      (0xf<<2) | (3<<7), 1,
+				      "SYNCHRONIZE CACHE");
+		if (reply == 0)
+			reply = do_synchronize_cache(common);
+		break;
+
+	case SC_TEST_UNIT_READY:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 6, DATA_DIR_NONE,
+				0, 1,
+				"TEST UNIT READY");
+		break;
+
+	/* Although optional, this command is used by MS-Windows.  We
+	 * support a minimal version: BytChk must be 0. */
+	case SC_VERIFY:
+		common->data_size_from_cmnd = 0;
+		reply = check_command(common, 10, DATA_DIR_NONE,
+				      (1<<1) | (0xf<<2) | (3<<7), 1,
+				      "VERIFY");
+		if (reply == 0)
+			reply = do_verify(common);
+		break;
+
+	case SC_WRITE_6:
+		i = common->cmnd[4];
+		common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+				      (7<<1) | (1<<4), 1,
+				      "WRITE(6)");
+		if (reply == 0)
+			reply = do_write(common);
+		break;
+
+	case SC_WRITE_10:
+		common->data_size_from_cmnd =
+				get_unaligned_be16(&common->cmnd[7]) << 9;
+		reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+				      (1<<1) | (0xf<<2) | (3<<7), 1,
+				      "WRITE(10)");
+		if (reply == 0)
+			reply = do_write(common);
+		break;
+
+	case SC_WRITE_12:
+		common->data_size_from_cmnd =
+				get_unaligned_be32(&common->cmnd[6]) << 9;
+		reply = check_command(common, 12, DATA_DIR_FROM_HOST,
+				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
+				      "WRITE(12)");
+		if (reply == 0)
+			reply = do_write(common);
+		break;
+
+	/* Some mandatory commands that we recognize but don't implement.
+	 * They don't mean much in this setting.  It's left as an exercise
+	 * for anyone interested to implement RESERVE and RELEASE in terms
+	 * of Posix locks. */
+	case SC_FORMAT_UNIT:
+	case SC_RELEASE:
+	case SC_RESERVE:
+	case SC_SEND_DIAGNOSTIC:
+		/* Fall through */
+
+	default:
+unknown_cmnd:
+		common->data_size_from_cmnd = 0;
+		sprintf(unknown, "Unknown x%02x", common->cmnd[0]);
+		reply = check_command(common, common->cmnd_size,
+				      DATA_DIR_UNKNOWN, 0xff, 0, unknown);
+		if (reply == 0) {
+			curlun->sense_data = SS_INVALID_COMMAND;
+			reply = -EINVAL;
+		}
+		break;
+	}
+	up_read(&common->filesem);
+
+	if (reply == -EINTR)
+		return -EINTR;
+
+	/* Set up the single reply buffer for finish_reply() */
+	if (reply == -EINVAL)
+		reply = 0;		/* Error reply length */
+	if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
+		reply = min((u32) reply, common->data_size_from_cmnd);
+		bh->inreq->length = reply;
+		bh->state = BUF_STATE_FULL;
+		common->residue -= reply;
+	}				/* Otherwise it's already set */
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct usb_request	*req = bh->outreq;
+	struct fsg_bulk_cb_wrap	*cbw = req->buf;
+	struct fsg_common	*common = fsg->common;
+
+	/* Was this a real packet?  Should it be ignored? */
+	if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
+		return -EINVAL;
+
+	/* Is the CBW valid? */
+	if (req->actual != USB_BULK_CB_WRAP_LEN ||
+			cbw->Signature != cpu_to_le32(
+				USB_BULK_CB_SIG)) {
+		DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
+				req->actual,
+				le32_to_cpu(cbw->Signature));
+
+		/* The Bulk-only spec says we MUST stall the IN endpoint
+		 * (6.6.1), so it's unavoidable.  It also says we must
+		 * retain this state until the next reset, but there's
+		 * no way to tell the controller driver it should ignore
+		 * Clear-Feature(HALT) requests.
+		 *
+		 * We aren't required to halt the OUT endpoint; instead
+		 * we can simply accept and discard any data received
+		 * until the next reset. */
+		wedge_bulk_in_endpoint(fsg);
+		generic_set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+		return -EINVAL;
+	}
+
+	/* Is the CBW meaningful? */
+	if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
+		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
+				"cmdlen %u\n",
+				cbw->Lun, cbw->Flags, cbw->Length);
+
+		/* We can do anything we want here, so let's stall the
+		 * bulk pipes if we are allowed to. */
+		if (common->can_stall) {
+			fsg_set_halt(fsg, fsg->bulk_out);
+			halt_bulk_in_endpoint(fsg);
+		}
+		return -EINVAL;
+	}
+
+	/* Save the command for later */
+	common->cmnd_size = cbw->Length;
+	memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
+	if (cbw->Flags & USB_BULK_IN_FLAG)
+		common->data_dir = DATA_DIR_TO_HOST;
+	else
+		common->data_dir = DATA_DIR_FROM_HOST;
+	common->data_size = le32_to_cpu(cbw->DataTransferLength);
+	if (common->data_size == 0)
+		common->data_dir = DATA_DIR_NONE;
+	common->lun = cbw->Lun;
+	common->tag = cbw->Tag;
+	return 0;
+}
+
+
+static int get_next_command(struct fsg_common *common)
+{
+	struct fsg_buffhd	*bh;
+	int			rc = 0;
+
+	/* Wait for the next buffer to become available */
+	bh = common->next_buffhd_to_fill;
+	while (bh->state != BUF_STATE_EMPTY) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	/* Queue a request to read a Bulk-only CBW */
+	set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
+	bh->outreq->short_not_ok = 1;
+	START_TRANSFER_OR(common, bulk_out, bh->outreq,
+			  &bh->outreq_busy, &bh->state)
+		/* Don't know what to do if common->fsg is NULL */
+		return -EIO;
+
+	/* We will drain the buffer in software, which means we
+	 * can reuse it for the next filling.  No need to advance
+	 * next_buffhd_to_fill. */
+
+	/* Wait for the CBW to arrive */
+	while (bh->state != BUF_STATE_FULL) {
+		rc = sleep_thread(common);
+		if (rc)
+			return rc;
+	}
+
+	rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+	bh->state = BUF_STATE_EMPTY;
+
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *d)
+{
+	int	rc;
+
+	ep->driver_data = common;
+	rc = usb_ep_enable(ep, d);
+	if (rc)
+		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
+	return rc;
+}
+
+static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
+		struct usb_request **preq)
+{
+	*preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+	if (*preq)
+		return 0;
+	ERROR(common, "can't allocate request for %s\n", ep->name);
+	return -ENOMEM;
+}
+
+/* Reset interface setting and re-init endpoint state (toggle etc). */
+static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
+{
+	const struct usb_endpoint_descriptor *d;
+	struct fsg_dev *fsg;
+	int i, rc = 0;
+
+	if (common->running)
+		DBG(common, "reset interface\n");
+
+reset:
+	/* Deallocate the requests */
+	if (common->fsg) {
+		fsg = common->fsg;
+
+		for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+			struct fsg_buffhd *bh = &common->buffhds[i];
+
+			if (bh->inreq) {
+				usb_ep_free_request(fsg->bulk_in, bh->inreq);
+				bh->inreq = NULL;
+			}
+			if (bh->outreq) {
+				usb_ep_free_request(fsg->bulk_out, bh->outreq);
+				bh->outreq = NULL;
+			}
+		}
+
+		/* Disable the endpoints */
+		if (fsg->bulk_in_enabled) {
+			usb_ep_disable(fsg->bulk_in);
+			fsg->bulk_in_enabled = 0;
+		}
+		if (fsg->bulk_out_enabled) {
+			usb_ep_disable(fsg->bulk_out);
+			fsg->bulk_out_enabled = 0;
+		}
+
+		common->fsg = NULL;
+		/* wake_up(&common->fsg_wait); */
+	}
+
+	common->running = 0;
+	if (!new_fsg || rc)
+		return rc;
+
+	common->fsg = new_fsg;
+	fsg = common->fsg;
+
+	/* Enable the endpoints */
+	d = fsg_ep_desc(common->gadget,
+			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+	rc = enable_endpoint(common, fsg->bulk_in, d);
+	if (rc)
+		goto reset;
+	fsg->bulk_in_enabled = 1;
+
+	d = fsg_ep_desc(common->gadget,
+			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+	rc = enable_endpoint(common, fsg->bulk_out, d);
+	if (rc)
+		goto reset;
+	fsg->bulk_out_enabled = 1;
+	common->bulk_out_maxpacket =
+				le16_to_cpu(get_unaligned(&d->wMaxPacketSize));
+	generic_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+
+	/* Allocate the requests */
+	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+		struct fsg_buffhd	*bh = &common->buffhds[i];
+
+		rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
+		if (rc)
+			goto reset;
+		rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
+		if (rc)
+			goto reset;
+		bh->inreq->buf = bh->outreq->buf = bh->buf;
+		bh->inreq->context = bh->outreq->context = bh;
+		bh->inreq->complete = bulk_in_complete;
+		bh->outreq->complete = bulk_out_complete;
+	}
+
+	common->running = 1;
+
+	return rc;
+}
+
+
+/****************************** ALT CONFIGS ******************************/
+
+
+static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct fsg_dev *fsg = fsg_from_func(f);
+	fsg->common->new_fsg = fsg;
+	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+	return 0;
+}
+
+static void fsg_disable(struct usb_function *f)
+{
+	struct fsg_dev *fsg = fsg_from_func(f);
+	fsg->common->new_fsg = NULL;
+	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void handle_exception(struct fsg_common *common)
+{
+	int			i;
+	struct fsg_buffhd	*bh;
+	enum fsg_state		old_state;
+	struct fsg_lun		*curlun;
+	unsigned int		exception_req_tag;
+
+	/* Cancel all the pending transfers */
+	if (common->fsg) {
+		for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+			bh = &common->buffhds[i];
+			if (bh->inreq_busy)
+				usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
+			if (bh->outreq_busy)
+				usb_ep_dequeue(common->fsg->bulk_out,
+					       bh->outreq);
+		}
+
+		/* Wait until everything is idle */
+		for (;;) {
+			int num_active = 0;
+			for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+				bh = &common->buffhds[i];
+				num_active += bh->inreq_busy + bh->outreq_busy;
+			}
+			if (num_active == 0)
+				break;
+			if (sleep_thread(common))
+				return;
+		}
+
+		/* Clear out the controller's fifos */
+		if (common->fsg->bulk_in_enabled)
+			usb_ep_fifo_flush(common->fsg->bulk_in);
+		if (common->fsg->bulk_out_enabled)
+			usb_ep_fifo_flush(common->fsg->bulk_out);
+	}
+
+	/* Reset the I/O buffer states and pointers, the SCSI
+	 * state, and the exception.  Then invoke the handler. */
+
+	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+		bh = &common->buffhds[i];
+		bh->state = BUF_STATE_EMPTY;
+	}
+	common->next_buffhd_to_fill = &common->buffhds[0];
+	common->next_buffhd_to_drain = &common->buffhds[0];
+	exception_req_tag = common->exception_req_tag;
+	old_state = common->state;
+
+	if (old_state == FSG_STATE_ABORT_BULK_OUT)
+		common->state = FSG_STATE_STATUS_PHASE;
+	else {
+		for (i = 0; i < common->nluns; ++i) {
+			curlun = &common->luns[i];
+			curlun->sense_data = SS_NO_SENSE;
+			curlun->info_valid = 0;
+		}
+		common->state = FSG_STATE_IDLE;
+	}
+
+	/* Carry out any extra actions required for the exception */
+	switch (old_state) {
+	case FSG_STATE_ABORT_BULK_OUT:
+		send_status(common);
+
+		if (common->state == FSG_STATE_STATUS_PHASE)
+			common->state = FSG_STATE_IDLE;
+		break;
+
+	case FSG_STATE_RESET:
+		/* In case we were forced against our will to halt a
+		 * bulk endpoint, clear the halt now.  (The SuperH UDC
+		 * requires this.) */
+		if (!fsg_is_set(common))
+			break;
+		if (test_and_clear_bit(IGNORE_BULK_OUT,
+				       &common->fsg->atomic_bitflags))
+			usb_ep_clear_halt(common->fsg->bulk_in);
+
+		if (common->ep0_req_tag == exception_req_tag)
+			ep0_queue(common);	/* Complete the status stage */
+
+		break;
+
+	case FSG_STATE_CONFIG_CHANGE:
+		do_set_interface(common, common->new_fsg);
+		break;
+
+	case FSG_STATE_EXIT:
+	case FSG_STATE_TERMINATED:
+		do_set_interface(common, NULL);		/* Free resources */
+		common->state = FSG_STATE_TERMINATED;	/* Stop the thread */
+		break;
+
+	case FSG_STATE_INTERFACE_CHANGE:
+	case FSG_STATE_DISCONNECT:
+	case FSG_STATE_COMMAND_PHASE:
+	case FSG_STATE_DATA_PHASE:
+	case FSG_STATE_STATUS_PHASE:
+	case FSG_STATE_IDLE:
+		break;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+int fsg_main_thread(void *common_)
+{
+	int ret;
+	struct fsg_common	*common = the_fsg_common;
+	/* The main loop */
+	do {
+		if (exception_in_progress(common)) {
+			handle_exception(common);
+			continue;
+		}
+
+		if (!common->running) {
+			ret = sleep_thread(common);
+			if (ret)
+				return ret;
+
+			continue;
+		}
+
+		ret = get_next_command(common);
+		if (ret)
+			return ret;
+
+		if (!exception_in_progress(common))
+			common->state = FSG_STATE_DATA_PHASE;
+
+		if (do_scsi_command(common) || finish_reply(common))
+			continue;
+
+		if (!exception_in_progress(common))
+			common->state = FSG_STATE_STATUS_PHASE;
+
+		if (send_status(common))
+			continue;
+
+		if (!exception_in_progress(common))
+			common->state = FSG_STATE_IDLE;
+	} while (0);
+
+	common->thread_task = NULL;
+
+	return 0;
+}
+
+static void fsg_common_release(struct kref *ref);
+
+static struct fsg_common *fsg_common_init(struct fsg_common *common,
+					  struct usb_composite_dev *cdev)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+	struct fsg_buffhd *bh;
+	struct fsg_lun *curlun;
+	int nluns, i, rc;
+
+	/* Find out how many LUNs there should be */
+	nluns = ums_count;
+	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+		printf("invalid number of LUNs: %u\n", nluns);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Allocate? */
+	if (!common) {
+		common = calloc(sizeof(*common), 1);
+		if (!common)
+			return ERR_PTR(-ENOMEM);
+		common->free_storage_on_release = 1;
+	} else {
+		memset(common, 0, sizeof(*common));
+		common->free_storage_on_release = 0;
+	}
+
+	common->ops = NULL;
+	common->private_data = NULL;
+
+	common->gadget = gadget;
+	common->ep0 = gadget->ep0;
+	common->ep0req = cdev->req;
+
+	/* Maybe allocate device-global string IDs, and patch descriptors */
+	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+		rc = usb_string_id(cdev);
+		if (unlikely(rc < 0))
+			goto error_release;
+		fsg_strings[FSG_STRING_INTERFACE].id = rc;
+		fsg_intf_desc.iInterface = rc;
+	}
+
+	/* Create the LUNs, open their backing files, and register the
+	 * LUN devices in sysfs. */
+	curlun = calloc(nluns, sizeof *curlun);
+	if (!curlun) {
+		rc = -ENOMEM;
+		goto error_release;
+	}
+	common->nluns = nluns;
+
+	for (i = 0; i < nluns; i++) {
+		common->luns[i].removable = 1;
+
+		rc = fsg_lun_open(&common->luns[i], ums[i].num_sectors, "");
+		if (rc)
+			goto error_luns;
+	}
+	common->lun = 0;
+
+	/* Data buffers cyclic list */
+	bh = common->buffhds;
+
+	i = FSG_NUM_BUFFERS;
+	goto buffhds_first_it;
+	do {
+		bh->next = bh + 1;
+		++bh;
+buffhds_first_it:
+		bh->inreq_busy = 0;
+		bh->outreq_busy = 0;
+		bh->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, FSG_BUFLEN);
+		if (unlikely(!bh->buf)) {
+			rc = -ENOMEM;
+			goto error_release;
+		}
+	} while (--i);
+	bh->next = common->buffhds;
+
+	snprintf(common->inquiry_string, sizeof common->inquiry_string,
+		 "%-8s%-16s%04x",
+		 "Linux   ",
+		 "File-Store Gadget",
+		 0xffff);
+
+	/* Some peripheral controllers are known not to be able to
+	 * halt bulk endpoints correctly.  If one of them is present,
+	 * disable stalls.
+	 */
+
+	/* Tell the thread to start working */
+	common->thread_task =
+		kthread_create(fsg_main_thread, common,
+			       OR(cfg->thread_name, "file-storage"));
+	if (IS_ERR(common->thread_task)) {
+		rc = PTR_ERR(common->thread_task);
+		goto error_release;
+	}
+
+#undef OR
+	/* Information */
+	INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+	INFO(common, "Number of LUNs=%d\n", common->nluns);
+
+	return common;
+
+error_luns:
+	common->nluns = i + 1;
+error_release:
+	common->state = FSG_STATE_TERMINATED;	/* The thread is dead */
+	/* Call fsg_common_release() directly, ref might be not
+	 * initialised */
+	fsg_common_release(&common->ref);
+	return ERR_PTR(rc);
+}
+
+static void fsg_common_release(struct kref *ref)
+{
+	struct fsg_common *common = container_of(ref, struct fsg_common, ref);
+
+	/* If the thread isn't already dead, tell it to exit now */
+	if (common->state != FSG_STATE_TERMINATED) {
+		raise_exception(common, FSG_STATE_EXIT);
+		wait_for_completion(&common->thread_notifier);
+	}
+
+	if (likely(common->luns)) {
+		struct fsg_lun *lun = common->luns;
+		unsigned i = common->nluns;
+
+		/* In error recovery common->nluns may be zero. */
+		for (; i; --i, ++lun)
+			fsg_lun_close(lun);
+
+		kfree(common->luns);
+	}
+
+	{
+		struct fsg_buffhd *bh = common->buffhds;
+		unsigned i = FSG_NUM_BUFFERS;
+		do {
+			kfree(bh->buf);
+		} while (++bh, --i);
+	}
+
+	if (common->free_storage_on_release)
+		kfree(common);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_copy_descriptors - copy a vector of USB descriptors
+ * @src: null-terminated vector to copy
+ * Context: initialization code, which may sleep
+ *
+ * This makes a copy of a vector of USB descriptors.  Its primary use
+ * is to support usb_function objects which can have multiple copies,
+ * each needing different descriptors.  Functions may have static
+ * tables of descriptors, which are used as templates and customized
+ * with identifiers (for interfaces, strings, endpoints, and more)
+ * as needed by a given function instance.
+ */
+struct usb_descriptor_header **
+usb_copy_descriptors(struct usb_descriptor_header **src)
+{
+	struct usb_descriptor_header **tmp;
+	unsigned bytes;
+	unsigned n_desc;
+	void *mem;
+	struct usb_descriptor_header **ret;
+
+	/* count descriptors and their sizes; then add vector size */
+	for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
+		bytes += (*tmp)->bLength;
+	bytes += (n_desc + 1) * sizeof(*tmp);
+
+	mem = memalign(CONFIG_SYS_CACHELINE_SIZE, bytes);
+	if (!mem)
+		return NULL;
+
+	/* fill in pointers starting at "tmp",
+	 * to descriptors copied starting at "mem";
+	 * and return "ret"
+	 */
+	tmp = mem;
+	ret = mem;
+	mem += (n_desc + 1) * sizeof(*tmp);
+	while (*src) {
+		memcpy(mem, *src, (*src)->bLength);
+		*tmp = mem;
+		tmp++;
+		mem += (*src)->bLength;
+		src++;
+	}
+	*tmp = NULL;
+
+	return ret;
+}
+
+static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct fsg_dev		*fsg = fsg_from_func(f);
+
+	DBG(fsg, "unbind\n");
+	if (fsg->common->fsg == fsg) {
+		fsg->common->new_fsg = NULL;
+		raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+	}
+
+	free(fsg->function.descriptors);
+	free(fsg->function.hs_descriptors);
+	kfree(fsg);
+}
+
+static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct fsg_dev		*fsg = fsg_from_func(f);
+	struct usb_gadget	*gadget = c->cdev->gadget;
+	int			i;
+	struct usb_ep		*ep;
+	fsg->gadget = gadget;
+
+	/* New interface */
+	i = usb_interface_id(c, f);
+	if (i < 0)
+		return i;
+	fsg_intf_desc.bInterfaceNumber = i;
+	fsg->interface_number = i;
+
+	/* Find all the endpoints we will use */
+	ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+	if (!ep)
+		goto autoconf_fail;
+	ep->driver_data = fsg->common;	/* claim the endpoint */
+	fsg->bulk_in = ep;
+
+	ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
+	if (!ep)
+		goto autoconf_fail;
+	ep->driver_data = fsg->common;	/* claim the endpoint */
+	fsg->bulk_out = ep;
+
+	/* Copy descriptors */
+	f->descriptors = usb_copy_descriptors(fsg_fs_function);
+	if (unlikely(!f->descriptors))
+		return -ENOMEM;
+
+	if (gadget_is_dualspeed(gadget)) {
+		/* Assume endpoint addresses are the same for both speeds */
+		fsg_hs_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_hs_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
+		if (unlikely(!f->hs_descriptors)) {
+			free(f->descriptors);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+
+autoconf_fail:
+	ERROR(fsg, "unable to autoconfigure all endpoints\n");
+	return -ENOTSUPP;
+}
+
+
+/****************************** ADD FUNCTION ******************************/
+
+static struct usb_gadget_strings *fsg_strings_array[] = {
+	&fsg_stringtab,
+	NULL,
+};
+
+static int fsg_bind_config(struct usb_composite_dev *cdev,
+			   struct usb_configuration *c,
+			   struct fsg_common *common)
+{
+	struct fsg_dev *fsg;
+	int rc;
+
+	fsg = calloc(1, sizeof *fsg);
+	if (!fsg)
+		return -ENOMEM;
+	fsg->function.name        = FSG_DRIVER_DESC;
+	fsg->function.strings     = fsg_strings_array;
+	fsg->function.bind        = fsg_bind;
+	fsg->function.unbind      = fsg_unbind;
+	fsg->function.setup       = fsg_setup;
+	fsg->function.set_alt     = fsg_set_alt;
+	fsg->function.disable     = fsg_disable;
+
+	fsg->common               = common;
+	common->fsg               = fsg;
+	/* Our caller holds a reference to common structure so we
+	 * don't have to be worry about it being freed until we return
+	 * from this function.  So instead of incrementing counter now
+	 * and decrement in error recovery we increment it only when
+	 * call to usb_add_function() was successful. */
+
+	rc = usb_add_function(c, &fsg->function);
+
+	if (rc)
+		kfree(fsg);
+
+	return rc;
+}
+
+int fsg_add(struct usb_configuration *c)
+{
+	struct fsg_common *fsg_common;
+
+	fsg_common = fsg_common_init(NULL, c->cdev);
+
+	fsg_common->vendor_name = 0;
+	fsg_common->product_name = 0;
+	fsg_common->release = 0xffff;
+
+	fsg_common->ops = NULL;
+	fsg_common->private_data = NULL;
+
+	the_fsg_common = fsg_common;
+
+	return fsg_bind_config(c->cdev, c, fsg_common);
+}
+
+int fsg_init(struct ums *ums_devs, int count, unsigned int controller_idx)
+{
+	ums = ums_devs;
+	ums_count = count;
+	controller_index = controller_idx;
+
+	return 0;
+}
+
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_ums, fsg_add);
diff --git a/roms/u-boot/drivers/usb/gadget/f_rockusb.c b/roms/u-boot/drivers/usb/gadget/f_rockusb.c
new file mode 100644
index 000000000..bd846ce9a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_rockusb.c
@@ -0,0 +1,934 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017
+ *
+ * Eddie Cai <eddie.cai.linux@gmail.com>
+ */
+#include <command.h>
+#include <config.h>
+#include <common.h>
+#include <env.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <part.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/compiler.h>
+#include <version.h>
+#include <g_dnl.h>
+#include <asm/arch-rockchip/f_rockusb.h>
+
+static inline struct f_rockusb *func_to_rockusb(struct usb_function *f)
+{
+	return container_of(f, struct f_rockusb, usb_function);
+}
+
+static struct usb_endpoint_descriptor fs_ep_in = {
+	.bLength            = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    = USB_DT_ENDPOINT,
+	.bEndpointAddress   = USB_DIR_IN,
+	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     = cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor fs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor hs_ep_in = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= cpu_to_le16(512),
+};
+
+static struct usb_interface_descriptor interface_desc = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= 0x00,
+	.bAlternateSetting	= 0x00,
+	.bNumEndpoints		= 0x02,
+	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
+	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
+	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
+};
+
+static struct usb_descriptor_header *rkusb_fs_function[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&fs_ep_in,
+	(struct usb_descriptor_header *)&fs_ep_out,
+};
+
+static struct usb_descriptor_header *rkusb_hs_function[] = {
+	(struct usb_descriptor_header *)&interface_desc,
+	(struct usb_descriptor_header *)&hs_ep_in,
+	(struct usb_descriptor_header *)&hs_ep_out,
+	NULL,
+};
+
+static const char rkusb_name[] = "Rockchip Rockusb";
+
+static struct usb_string rkusb_string_defs[] = {
+	[0].s = rkusb_name,
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_rkusb = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= rkusb_string_defs,
+};
+
+static struct usb_gadget_strings *rkusb_strings[] = {
+	&stringtab_rkusb,
+	NULL,
+};
+
+static struct f_rockusb *rockusb_func;
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+static int rockusb_tx_write_csw(u32 tag, int residue, u8 status, int size);
+
+struct f_rockusb *get_rkusb(void)
+{
+	struct f_rockusb *f_rkusb = rockusb_func;
+
+	if (!f_rkusb) {
+		f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_rkusb));
+		if (!f_rkusb)
+			return NULL;
+
+		rockusb_func = f_rkusb;
+		memset(f_rkusb, 0, sizeof(*f_rkusb));
+	}
+
+	if (!f_rkusb->buf_head) {
+		f_rkusb->buf_head = memalign(CONFIG_SYS_CACHELINE_SIZE,
+					     RKUSB_BUF_SIZE);
+		if (!f_rkusb->buf_head)
+			return NULL;
+
+		f_rkusb->buf = f_rkusb->buf_head;
+		memset(f_rkusb->buf_head, 0, RKUSB_BUF_SIZE);
+	}
+	return f_rkusb;
+}
+
+static struct usb_endpoint_descriptor *rkusb_ep_desc(
+struct usb_gadget *g,
+struct usb_endpoint_descriptor *fs,
+struct usb_endpoint_descriptor *hs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+static void rockusb_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	if (!status)
+		return;
+	debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+
+/* config the rockusb device*/
+static int rockusb_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	int id;
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_rockusb *f_rkusb = func_to_rockusb(f);
+	const char *s;
+
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	interface_desc.bInterfaceNumber = id;
+
+	id = usb_string_id(c->cdev);
+	if (id < 0)
+		return id;
+
+	rkusb_string_defs[0].id = id;
+	interface_desc.iInterface = id;
+
+	f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
+	if (!f_rkusb->in_ep)
+		return -ENODEV;
+	f_rkusb->in_ep->driver_data = c->cdev;
+
+	f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
+	if (!f_rkusb->out_ep)
+		return -ENODEV;
+	f_rkusb->out_ep->driver_data = c->cdev;
+
+	f->descriptors = rkusb_fs_function;
+
+	if (gadget_is_dualspeed(gadget)) {
+		hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
+		hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+		f->hs_descriptors = rkusb_hs_function;
+	}
+
+	s = env_get("serial#");
+	if (s)
+		g_dnl_set_serialnumber((char *)s);
+
+	return 0;
+}
+
+static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	/* clear the configuration*/
+	memset(rockusb_func, 0, sizeof(*rockusb_func));
+}
+
+static void rockusb_disable(struct usb_function *f)
+{
+	struct f_rockusb *f_rkusb = func_to_rockusb(f);
+
+	usb_ep_disable(f_rkusb->out_ep);
+	usb_ep_disable(f_rkusb->in_ep);
+
+	if (f_rkusb->out_req) {
+		free(f_rkusb->out_req->buf);
+		usb_ep_free_request(f_rkusb->out_ep, f_rkusb->out_req);
+		f_rkusb->out_req = NULL;
+	}
+	if (f_rkusb->in_req) {
+		free(f_rkusb->in_req->buf);
+		usb_ep_free_request(f_rkusb->in_ep, f_rkusb->in_req);
+		f_rkusb->in_req = NULL;
+	}
+	if (f_rkusb->buf_head) {
+		free(f_rkusb->buf_head);
+		f_rkusb->buf_head = NULL;
+		f_rkusb->buf = NULL;
+	}
+}
+
+static struct usb_request *rockusb_start_ep(struct usb_ep *ep)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req)
+		return NULL;
+
+	req->length = EP_BUFFER_SIZE;
+	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		return NULL;
+	}
+	memset(req->buf, 0, req->length);
+
+	return req;
+}
+
+static int rockusb_set_alt(struct usb_function *f, unsigned int interface,
+			   unsigned int alt)
+{
+	int ret;
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct f_rockusb *f_rkusb = func_to_rockusb(f);
+	const struct usb_endpoint_descriptor *d;
+
+	debug("%s: func: %s intf: %d alt: %d\n",
+	      __func__, f->name, interface, alt);
+
+	d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
+	ret = usb_ep_enable(f_rkusb->out_ep, d);
+	if (ret) {
+		printf("failed to enable out ep\n");
+		return ret;
+	}
+
+	f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep);
+	if (!f_rkusb->out_req) {
+		printf("failed to alloc out req\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	f_rkusb->out_req->complete = rx_handler_command;
+
+	d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
+	ret = usb_ep_enable(f_rkusb->in_ep, d);
+	if (ret) {
+		printf("failed to enable in ep\n");
+		goto err;
+	}
+
+	f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep);
+	if (!f_rkusb->in_req) {
+		printf("failed alloc req in\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	f_rkusb->in_req->complete = rockusb_complete;
+
+	ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	rockusb_disable(f);
+	return ret;
+}
+
+static int rockusb_add(struct usb_configuration *c)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+	int status;
+
+	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+	f_rkusb->usb_function.name = "f_rockusb";
+	f_rkusb->usb_function.bind = rockusb_bind;
+	f_rkusb->usb_function.unbind = rockusb_unbind;
+	f_rkusb->usb_function.set_alt = rockusb_set_alt;
+	f_rkusb->usb_function.disable = rockusb_disable;
+	f_rkusb->usb_function.strings = rkusb_strings;
+
+	status = usb_add_function(c, &f_rkusb->usb_function);
+	if (status) {
+		free(f_rkusb->buf_head);
+		free(f_rkusb);
+		rockusb_func = NULL;
+	}
+	return status;
+}
+
+void rockusb_dev_init(char *dev_type, int dev_index)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+
+	f_rkusb->dev_type = dev_type;
+	f_rkusb->dev_index = dev_index;
+}
+
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add);
+
+static int rockusb_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	struct usb_request *in_req = rockusb_func->in_req;
+	int ret;
+
+	memcpy(in_req->buf, buffer, buffer_size);
+	in_req->length = buffer_size;
+	debug("Transferring 0x%x bytes\n", buffer_size);
+	usb_ep_dequeue(rockusb_func->in_ep, in_req);
+	ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
+	if (ret)
+		printf("Error %d on queue\n", ret);
+	return 0;
+}
+
+static int rockusb_tx_write_str(const char *buffer)
+{
+	return rockusb_tx_write(buffer, strlen(buffer));
+}
+
+#ifdef DEBUG
+static void printcbw(char *buf)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+
+	memcpy((char *)cbw, buf, USB_BULK_CB_WRAP_LEN);
+
+	debug("cbw: signature:%x\n", cbw->signature);
+	debug("cbw: tag=%x\n", cbw->tag);
+	debug("cbw: data_transfer_length=%d\n", cbw->data_transfer_length);
+	debug("cbw: flags=%x\n", cbw->flags);
+	debug("cbw: lun=%d\n", cbw->lun);
+	debug("cbw: length=%d\n", cbw->length);
+	debug("cbw: ucOperCode=%x\n", cbw->CDB[0]);
+	debug("cbw: ucReserved=%x\n", cbw->CDB[1]);
+	debug("cbw: dwAddress:%x %x %x %x\n", cbw->CDB[5], cbw->CDB[4],
+	      cbw->CDB[3], cbw->CDB[2]);
+	debug("cbw: ucReserved2=%x\n", cbw->CDB[6]);
+	debug("cbw: uslength:%x %x\n", cbw->CDB[8], cbw->CDB[7]);
+}
+
+static void printcsw(char *buf)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct bulk_cs_wrap, csw,
+				 sizeof(struct bulk_cs_wrap));
+	memcpy((char *)csw, buf, USB_BULK_CS_WRAP_LEN);
+	debug("csw: signature:%x\n", csw->signature);
+	debug("csw: tag:%x\n", csw->tag);
+	debug("csw: residue:%x\n", csw->residue);
+	debug("csw: status:%x\n", csw->status);
+}
+#endif
+
+static int rockusb_tx_write_csw(u32 tag, int residue, u8 status, int size)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct bulk_cs_wrap, csw,
+				 sizeof(struct bulk_cs_wrap));
+	csw->signature = cpu_to_le32(USB_BULK_CS_SIG);
+	csw->tag = tag;
+	csw->residue = cpu_to_be32(residue);
+	csw->status = status;
+#ifdef DEBUG
+	printcsw((char *)csw);
+#endif
+	return rockusb_tx_write((char *)csw, size);
+}
+
+static void tx_handler_send_csw(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+	int status = req->status;
+
+	if (status)
+		debug("status: %d ep '%s' trans: %d\n",
+		      status, ep->name, req->actual);
+
+	/* Return back to default in_req complete function after sending CSW */
+	req->complete = rockusb_complete;
+	rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+
+static unsigned int rx_bytes_expected(struct usb_ep *ep)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+	int rx_remain = f_rkusb->dl_size - f_rkusb->dl_bytes;
+	unsigned int rem;
+	unsigned int maxpacket = ep->maxpacket;
+
+	if (rx_remain <= 0)
+		return 0;
+	else if (rx_remain > EP_BUFFER_SIZE)
+		return EP_BUFFER_SIZE;
+
+	rem = rx_remain % maxpacket;
+	if (rem > 0)
+		rx_remain = rx_remain + (maxpacket - rem);
+
+	return rx_remain;
+}
+
+/* usb_request complete call back to handle upload image */
+static void tx_handler_ul_image(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(char, rbuffer, RKBLOCK_BUF_SIZE);
+	struct f_rockusb *f_rkusb = get_rkusb();
+	struct usb_request *in_req = rockusb_func->in_req;
+	int ret;
+
+	/* Print error status of previous transfer */
+	if (req->status)
+		debug("status: %d ep '%s' trans: %d len %d\n", req->status,
+		      ep->name, req->actual, req->length);
+
+	/* On transfer complete reset in_req and feedback host with CSW_GOOD */
+	if (f_rkusb->ul_bytes >= f_rkusb->ul_size) {
+		in_req->length = 0;
+		in_req->complete = rockusb_complete;
+
+		rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD,
+				     USB_BULK_CS_WRAP_LEN);
+		return;
+	}
+
+	/* Proceed with current chunk */
+	unsigned int transfer_size = f_rkusb->ul_size - f_rkusb->ul_bytes;
+
+	if (transfer_size > RKBLOCK_BUF_SIZE)
+		transfer_size = RKBLOCK_BUF_SIZE;
+	/* Read at least one block */
+	unsigned int blkcount = (transfer_size + f_rkusb->desc->blksz - 1) /
+				f_rkusb->desc->blksz;
+
+	debug("ul %x bytes, %x blks, read lba %x, ul_size:%x, ul_bytes:%x, ",
+	      transfer_size, blkcount, f_rkusb->lba,
+	      f_rkusb->ul_size, f_rkusb->ul_bytes);
+
+	int blks = blk_dread(f_rkusb->desc, f_rkusb->lba, blkcount, rbuffer);
+
+	if (blks != blkcount) {
+		printf("failed reading from device %s: %d\n",
+		       f_rkusb->dev_type, f_rkusb->dev_index);
+		rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL,
+				     USB_BULK_CS_WRAP_LEN);
+		return;
+	}
+	f_rkusb->lba += blkcount;
+	f_rkusb->ul_bytes += transfer_size;
+
+	/* Proceed with USB request */
+	memcpy(in_req->buf, rbuffer, transfer_size);
+	in_req->length = transfer_size;
+	in_req->complete = tx_handler_ul_image;
+	debug("Uploading 0x%x bytes\n", transfer_size);
+	usb_ep_dequeue(rockusb_func->in_ep, in_req);
+	ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
+	if (ret)
+		printf("Error %d on queue\n", ret);
+}
+
+/* usb_request complete call back to handle down load image */
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+	unsigned int transfer_size = 0;
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	transfer_size = f_rkusb->dl_size - f_rkusb->dl_bytes;
+
+	if (req->status != 0) {
+		printf("Bad status: %d\n", req->status);
+		rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL,
+				     USB_BULK_CS_WRAP_LEN);
+		return;
+	}
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	memcpy((void *)f_rkusb->buf, buffer, transfer_size);
+	f_rkusb->dl_bytes += transfer_size;
+	int blks = 0, blkcnt = transfer_size  / f_rkusb->desc->blksz;
+
+	debug("dl %x bytes, %x blks, write lba %x, dl_size:%x, dl_bytes:%x, ",
+	      transfer_size, blkcnt, f_rkusb->lba, f_rkusb->dl_size,
+	      f_rkusb->dl_bytes);
+	blks = blk_dwrite(f_rkusb->desc, f_rkusb->lba, blkcnt, f_rkusb->buf);
+	if (blks != blkcnt) {
+		printf("failed writing to device %s: %d\n", f_rkusb->dev_type,
+		       f_rkusb->dev_index);
+		rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL,
+				     USB_BULK_CS_WRAP_LEN);
+		return;
+	}
+	f_rkusb->lba += blkcnt;
+
+	/* Check if transfer is done */
+	if (f_rkusb->dl_bytes >= f_rkusb->dl_size) {
+		req->complete = rx_handler_command;
+		req->length = EP_BUFFER_SIZE;
+		f_rkusb->buf = f_rkusb->buf_head;
+		debug("transfer 0x%x bytes done\n", f_rkusb->dl_size);
+		f_rkusb->dl_size = 0;
+		rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD,
+				     USB_BULK_CS_WRAP_LEN);
+	} else {
+		req->length = rx_bytes_expected(ep);
+		if (f_rkusb->buf == f_rkusb->buf_head)
+			f_rkusb->buf = f_rkusb->buf_head + EP_BUFFER_SIZE;
+		else
+			f_rkusb->buf = f_rkusb->buf_head;
+
+		debug("remain %x bytes, %lx sectors\n", req->length,
+		      req->length / f_rkusb->desc->blksz);
+	}
+
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+
+	rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length,
+			     CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+
+static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	struct f_rockusb *f_rkusb = get_rkusb();
+	char emmc_id[] = "EMMC ";
+
+	printf("read storage id\n");
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+
+	/* Prepare for sending subsequent CSW_GOOD */
+	f_rkusb->tag = cbw->tag;
+	f_rkusb->in_req->complete = tx_handler_send_csw;
+
+	rockusb_tx_write_str(emmc_id);
+}
+
+int __weak rk_get_bootrom_chip_version(unsigned int *chip_info, int size)
+{
+	return 0;
+}
+
+static void cb_get_chip_version(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	struct f_rockusb *f_rkusb = get_rkusb();
+	unsigned int chip_info[4], i;
+
+	memset(chip_info, 0, sizeof(chip_info));
+	rk_get_bootrom_chip_version(chip_info, 4);
+
+	/*
+	 * Chip Version is a string saved in BOOTROM address space Little Endian
+	 *
+	 * Ex for rk3288: 0x33323041 0x32303134 0x30383133 0x56323030
+	 * which brings:  320A20140813V200
+	 *
+	 * Note that memory version do invert MSB/LSB so printing the char
+	 * buffer will show: A02341023180002V
+	 */
+	printf("read chip version: ");
+	for (i = 0; i < 4; i++) {
+		printf("%c%c%c%c",
+		       (chip_info[i] >> 24) & 0xFF,
+		       (chip_info[i] >> 16) & 0xFF,
+		       (chip_info[i] >>  8) & 0xFF,
+		       (chip_info[i] >>  0) & 0xFF);
+	}
+	printf("\n");
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+
+	/* Prepare for sending subsequent CSW_GOOD */
+	f_rkusb->tag = cbw->tag;
+	f_rkusb->in_req->complete = tx_handler_send_csw;
+
+	rockusb_tx_write((char *)chip_info, sizeof(chip_info));
+}
+
+static void cb_read_lba(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	struct f_rockusb *f_rkusb = get_rkusb();
+	int sector_count;
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+	sector_count = (int)get_unaligned_be16(&cbw->CDB[7]);
+	f_rkusb->tag = cbw->tag;
+
+	if (!f_rkusb->desc) {
+		char *type = f_rkusb->dev_type;
+		int index = f_rkusb->dev_index;
+
+		f_rkusb->desc = blk_get_dev(type, index);
+		if (!f_rkusb->desc ||
+		    f_rkusb->desc->type == DEV_TYPE_UNKNOWN) {
+			printf("invalid device \"%s\", %d\n", type, index);
+			rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL,
+					     USB_BULK_CS_WRAP_LEN);
+			return;
+		}
+	}
+
+	f_rkusb->lba = get_unaligned_be32(&cbw->CDB[2]);
+	f_rkusb->ul_size = sector_count * f_rkusb->desc->blksz;
+	f_rkusb->ul_bytes = 0;
+
+	debug("require read %x bytes, %x sectors from lba %x\n",
+	      f_rkusb->ul_size, sector_count, f_rkusb->lba);
+
+	if (f_rkusb->ul_size == 0)  {
+		rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length,
+				     CSW_FAIL, USB_BULK_CS_WRAP_LEN);
+		return;
+	}
+
+	/* Start right now sending first chunk */
+	tx_handler_ul_image(ep, req);
+}
+
+static void cb_write_lba(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	struct f_rockusb *f_rkusb = get_rkusb();
+	int sector_count;
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+	sector_count = (int)get_unaligned_be16(&cbw->CDB[7]);
+	f_rkusb->tag = cbw->tag;
+
+	if (!f_rkusb->desc) {
+		char *type = f_rkusb->dev_type;
+		int index = f_rkusb->dev_index;
+
+		f_rkusb->desc = blk_get_dev(type, index);
+		if (!f_rkusb->desc ||
+		    f_rkusb->desc->type == DEV_TYPE_UNKNOWN) {
+			printf("invalid device \"%s\", %d\n", type, index);
+			rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL,
+					     USB_BULK_CS_WRAP_LEN);
+			return;
+		}
+	}
+
+	f_rkusb->lba = get_unaligned_be32(&cbw->CDB[2]);
+	f_rkusb->dl_size = sector_count * f_rkusb->desc->blksz;
+	f_rkusb->dl_bytes = 0;
+
+	debug("require write %x bytes, %x sectors to lba %x\n",
+	      f_rkusb->dl_size, sector_count, f_rkusb->lba);
+
+	if (f_rkusb->dl_size == 0)  {
+		rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length,
+				     CSW_FAIL, USB_BULK_CS_WRAP_LEN);
+	} else {
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected(ep);
+	}
+}
+
+static void cb_erase_lba(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	struct f_rockusb *f_rkusb = get_rkusb();
+	int sector_count, lba, blks;
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+	sector_count = (int)get_unaligned_be16(&cbw->CDB[7]);
+	f_rkusb->tag = cbw->tag;
+
+	if (!f_rkusb->desc) {
+		char *type = f_rkusb->dev_type;
+		int index = f_rkusb->dev_index;
+
+		f_rkusb->desc = blk_get_dev(type, index);
+		if (!f_rkusb->desc ||
+		    f_rkusb->desc->type == DEV_TYPE_UNKNOWN) {
+			printf("invalid device \"%s\", %d\n", type, index);
+			rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL,
+					     USB_BULK_CS_WRAP_LEN);
+			return;
+		}
+	}
+
+	lba = get_unaligned_be32(&cbw->CDB[2]);
+
+	debug("require erase %x sectors from lba %x\n",
+	      sector_count, lba);
+
+	blks = blk_derase(f_rkusb->desc, lba, sector_count);
+	if (blks != sector_count) {
+		printf("failed erasing device %s: %d\n", f_rkusb->dev_type,
+		       f_rkusb->dev_index);
+		rockusb_tx_write_csw(f_rkusb->tag,
+				     cbw->data_transfer_length, CSW_FAIL,
+				     USB_BULK_CS_WRAP_LEN);
+		return;
+	}
+
+	rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD,
+			     USB_BULK_CS_WRAP_LEN);
+}
+
+void __weak rkusb_set_reboot_flag(int flag)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+
+	printf("rockkusb set reboot flag: %d\n", f_rkusb->reboot_flag);
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_rockusb *f_rkusb = get_rkusb();
+
+	rkusb_set_reboot_flag(f_rkusb->reboot_flag);
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	struct f_rockusb *f_rkusb = get_rkusb();
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+	f_rkusb->reboot_flag = cbw->CDB[1];
+	rockusb_func->in_req->complete = compl_do_reset;
+	rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD,
+			     USB_BULK_CS_WRAP_LEN);
+}
+
+static void cb_not_support(struct usb_ep *ep, struct usb_request *req)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+	printf("Rockusb command %x not support yet\n", cbw->CDB[0]);
+	rockusb_tx_write_csw(cbw->tag, 0, CSW_FAIL, USB_BULK_CS_WRAP_LEN);
+}
+
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
+	{
+		.cmd = K_FW_TEST_UNIT_READY,
+		.cb = cb_test_unit_ready,
+	},
+	{
+		.cmd = K_FW_READ_FLASH_ID,
+		.cb = cb_read_storage_id,
+	},
+	{
+		.cmd = K_FW_SET_DEVICE_ID,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_TEST_BAD_BLOCK,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_READ_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_WRITE_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_ERASE_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_WRITE_SPARE,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_READ_SPARE,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_ERASE_10_FORCE,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_GET_VERSION,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_LBA_READ_10,
+		.cb = cb_read_lba,
+	},
+	{
+		.cmd = K_FW_LBA_WRITE_10,
+		.cb = cb_write_lba,
+	},
+	{
+		.cmd = K_FW_ERASE_SYS_DISK,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_SDRAM_READ_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_SDRAM_WRITE_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_SDRAM_EXECUTE,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_READ_FLASH_INFO,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_GET_CHIP_VER,
+		.cb = cb_get_chip_version,
+	},
+	{
+		.cmd = K_FW_LOW_FORMAT,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_SET_RESET_FLAG,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_SPI_READ_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_SPI_WRITE_10,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_LBA_ERASE_10,
+		.cb = cb_erase_lba,
+	},
+	{
+		.cmd = K_FW_SESSION,
+		.cb = cb_not_support,
+	},
+	{
+		.cmd = K_FW_RESET,
+		.cb = cb_reboot,
+	},
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+
+	ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw,
+				 sizeof(struct fsg_bulk_cb_wrap));
+	char *cmdbuf = req->buf;
+	int i;
+
+	if (req->status || req->length == 0)
+		return;
+
+	memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN);
+#ifdef DEBUG
+	printcbw(req->buf);
+#endif
+
+	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+		if (cmd_dispatch_info[i].cmd == cbw->CDB[0]) {
+			func_cb = cmd_dispatch_info[i].cb;
+			break;
+		}
+	}
+
+	if (!func_cb) {
+		printf("unknown command: %s\n", (char *)req->buf);
+		rockusb_tx_write_str("FAILunknown command");
+	} else {
+		if (req->actual < req->length) {
+			u8 *buf = (u8 *)req->buf;
+
+			buf[req->actual] = 0;
+			func_cb(ep, req);
+		} else {
+			puts("buffer overflow\n");
+			rockusb_tx_write_str("FAILbuffer overflow");
+		}
+	}
+
+	*cmdbuf = '\0';
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/f_sdp.c b/roms/u-boot/drivers/usb/gadget/f_sdp.c
new file mode 100644
index 000000000..e48aa2f90
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_sdp.c
@@ -0,0 +1,956 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * f_sdp.c -- USB HID Serial Download Protocol
+ *
+ * Copyright (C) 2017 Toradex
+ * Author: Stefan Agner <stefan.agner@toradex.com>
+ *
+ * This file implements the Serial Download Protocol (SDP) as specified in
+ * the i.MX 6 Reference Manual. The SDP is a USB HID based protocol and
+ * allows to download images directly to memory. The implementation
+ * works with the imx_loader (imx_usb) USB client software on host side.
+ *
+ * Not all commands are implemented, e.g. WRITE_REGISTER, DCD_WRITE and
+ * SKIP_DCD_HEADER are only stubs.
+ *
+ * Parts of the implementation are based on f_dfu and f_thor.
+ */
+
+#include <errno.h>
+#include <common.h>
+#include <console.h>
+#include <env.h>
+#include <log.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+
+#include <asm/io.h>
+#include <g_dnl.h>
+#include <sdp.h>
+#include <spl.h>
+#include <image.h>
+#include <imximage.h>
+#include <watchdog.h>
+
+#define HID_REPORT_ID_MASK	0x000000ff
+
+/*
+ * HID class requests
+ */
+#define HID_REQ_GET_REPORT		0x01
+#define HID_REQ_GET_IDLE		0x02
+#define HID_REQ_GET_PROTOCOL		0x03
+#define HID_REQ_SET_REPORT		0x09
+#define HID_REQ_SET_IDLE		0x0A
+#define HID_REQ_SET_PROTOCOL		0x0B
+
+#define HID_USAGE_PAGE_LEN		76
+
+struct hid_report {
+	u8 usage_page[HID_USAGE_PAGE_LEN];
+} __packed;
+
+#define SDP_READ_REGISTER	0x0101
+#define SDP_WRITE_REGISTER	0x0202
+#define SDP_WRITE_FILE		0x0404
+#define SDP_ERROR_STATUS	0x0505
+#define SDP_DCD_WRITE		0x0a0a
+#define SDP_JUMP_ADDRESS	0x0b0b
+#define SDP_SKIP_DCD_HEADER	0x0c0c
+
+#define SDP_SECURITY_CLOSED		0x12343412
+#define SDP_SECURITY_OPEN		0x56787856
+
+#define SDP_WRITE_FILE_COMPLETE		0x88888888
+#define SDP_WRITE_REGISTER_COMPLETE	0x128A8A12
+#define SDP_SKIP_DCD_HEADER_COMPLETE	0x900DD009
+#define SDP_ERROR_IMXHEADER		0x000a0533
+
+#define SDP_COMMAND_LEN		16
+
+#define SDP_HID_PACKET_SIZE_EP1 1024
+
+#define SDP_EXIT 1
+
+struct sdp_command {
+	u16 cmd;
+	u32 addr;
+	u8 format;
+	u32 cnt;
+	u32 data;
+	u8 rsvd;
+} __packed;
+
+enum sdp_state {
+	SDP_STATE_IDLE,
+	SDP_STATE_RX_CMD,
+	SDP_STATE_RX_DCD_DATA,
+	SDP_STATE_RX_FILE_DATA,
+	SDP_STATE_RX_FILE_DATA_BUSY,
+	SDP_STATE_TX_SEC_CONF,
+	SDP_STATE_TX_SEC_CONF_BUSY,
+	SDP_STATE_TX_REGISTER,
+	SDP_STATE_TX_REGISTER_BUSY,
+	SDP_STATE_TX_STATUS,
+	SDP_STATE_TX_STATUS_BUSY,
+	SDP_STATE_JUMP,
+};
+
+struct f_sdp {
+	struct usb_function		usb_function;
+
+	struct usb_descriptor_header	**function;
+
+	u8				altsetting;
+	enum sdp_state			state;
+	enum sdp_state			next_state;
+	u32				dnl_address;
+	u32				dnl_bytes;
+	u32				dnl_bytes_remaining;
+	u32				jmp_address;
+	bool				always_send_status;
+	u32				error_status;
+
+	/* EP0 request */
+	struct usb_request		*req;
+
+	/* EP1 IN */
+	struct usb_ep			*in_ep;
+	struct usb_request		*in_req;
+	/* EP1 OUT */
+	struct usb_ep			*out_ep;
+	struct usb_request		*out_req;
+
+	bool				configuration_done;
+	bool				ep_int_enable;
+};
+
+static struct f_sdp *sdp_func;
+
+static inline struct f_sdp *func_to_sdp(struct usb_function *f)
+{
+	return container_of(f, struct f_sdp, usb_function);
+}
+
+static struct usb_interface_descriptor sdp_intf_runtime = {
+	.bLength =		sizeof(sdp_intf_runtime),
+	.bDescriptorType =	USB_DT_INTERFACE,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_HID,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	/* .iInterface = DYNAMIC */
+};
+
+/* HID configuration */
+static struct usb_class_hid_descriptor sdp_hid_desc = {
+	.bLength =		sizeof(sdp_hid_desc),
+	.bDescriptorType =	USB_DT_CS_DEVICE,
+
+	.bcdCDC =		__constant_cpu_to_le16(0x0110),
+	.bCountryCode =		0,
+	.bNumDescriptors =	1,
+
+	.bDescriptorType0	= USB_DT_HID_REPORT,
+	.wDescriptorLength0	= HID_USAGE_PAGE_LEN,
+};
+
+static struct usb_endpoint_descriptor in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+	.bEndpointAddress =	1 | USB_DIR_IN,
+	.bmAttributes =	USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	64,
+	.bInterval =		1,
+};
+
+static struct usb_endpoint_descriptor out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+	.bEndpointAddress =	1 | USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	64,
+	.bInterval =		1,
+};
+
+static struct usb_endpoint_descriptor in_hs_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+	.bEndpointAddress =	1 | USB_DIR_IN,
+	.bmAttributes =	USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	512,
+	.bInterval =		3,
+};
+
+static struct usb_endpoint_descriptor out_hs_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+	.bEndpointAddress =	1 | USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	SDP_HID_PACKET_SIZE_EP1,
+	.bInterval =		3,
+};
+
+static struct usb_descriptor_header *sdp_runtime_descs[] = {
+	(struct usb_descriptor_header *)&sdp_intf_runtime,
+	(struct usb_descriptor_header *)&sdp_hid_desc,
+	(struct usb_descriptor_header *)&in_desc,
+	(struct usb_descriptor_header *)&out_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *sdp_runtime_hs_descs[] = {
+	(struct usb_descriptor_header *)&sdp_intf_runtime,
+	(struct usb_descriptor_header *)&sdp_hid_desc,
+	(struct usb_descriptor_header *)&in_hs_desc,
+	(struct usb_descriptor_header *)&out_hs_desc,
+	NULL,
+};
+
+/* This is synchronized with what the SoC implementation reports */
+static struct hid_report sdp_hid_report = {
+	.usage_page = {
+		0x06, 0x00, 0xff, /* Usage Page */
+		0x09, 0x01, /* Usage (Pointer?) */
+		0xa1, 0x01, /* Collection */
+
+		0x85, 0x01, /* Report ID */
+		0x19, 0x01, /* Usage Minimum */
+		0x29, 0x01, /* Usage Maximum */
+		0x15, 0x00, /* Local Minimum */
+		0x26, 0xFF, 0x00, /* Local Maximum? */
+		0x75, 0x08, /* Report Size */
+		0x95, 0x10, /* Report Count */
+		0x91, 0x02, /* Output Data */
+
+		0x85, 0x02, /* Report ID */
+		0x19, 0x01, /* Usage Minimum */
+		0x29, 0x01, /* Usage Maximum */
+		0x15, 0x00, /* Local Minimum */
+		0x26, 0xFF, 0x00, /* Local Maximum? */
+		0x75, 0x80, /* Report Size 128 */
+		0x95, 0x40, /* Report Count */
+		0x91, 0x02, /* Output Data */
+
+		0x85, 0x03, /* Report ID */
+		0x19, 0x01, /* Usage Minimum */
+		0x29, 0x01, /* Usage Maximum */
+		0x15, 0x00, /* Local Minimum */
+		0x26, 0xFF, 0x00, /* Local Maximum? */
+		0x75, 0x08, /* Report Size 8 */
+		0x95, 0x04, /* Report Count */
+		0x81, 0x02, /* Input Data */
+
+		0x85, 0x04, /* Report ID */
+		0x19, 0x01, /* Usage Minimum */
+		0x29, 0x01, /* Usage Maximum */
+		0x15, 0x00, /* Local Minimum */
+		0x26, 0xFF, 0x00, /* Local Maximum? */
+		0x75, 0x08, /* Report Size 8 */
+		0x95, 0x40, /* Report Count */
+		0x81, 0x02, /* Input Data */
+		0xc0
+	},
+};
+
+static const char sdp_name[] = "Serial Downloader Protocol";
+
+/*
+ * static strings, in UTF-8
+ */
+static struct usb_string strings_sdp_generic[] = {
+	[0].s = sdp_name,
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_sdp_generic = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings_sdp_generic,
+};
+
+static struct usb_gadget_strings *sdp_generic_strings[] = {
+	&stringtab_sdp_generic,
+	NULL,
+};
+
+static inline void *sdp_ptr(u32 val)
+{
+	return (void *)(uintptr_t)val;
+}
+
+static void sdp_rx_command_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_sdp *sdp = req->context;
+	int status = req->status;
+	u8 *data = req->buf;
+	u8 report = data[0];
+
+	if (status != 0) {
+		pr_err("Status: %d\n", status);
+		return;
+	}
+
+	if (report != 1) {
+		pr_err("Unexpected report %d\n", report);
+		return;
+	}
+
+	struct sdp_command *cmd = req->buf + 1;
+
+	debug("%s: command: %04x, addr: %08x, cnt: %u\n",
+	      __func__, be16_to_cpu(cmd->cmd),
+	      be32_to_cpu(cmd->addr), be32_to_cpu(cmd->cnt));
+
+	switch (be16_to_cpu(cmd->cmd)) {
+	case SDP_READ_REGISTER:
+		sdp->always_send_status = false;
+		sdp->error_status = 0x0;
+
+		sdp->state = SDP_STATE_TX_SEC_CONF;
+		sdp->dnl_address = be32_to_cpu(cmd->addr);
+		sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+		sdp->next_state = SDP_STATE_TX_REGISTER;
+		printf("Reading %d registers at 0x%08x... ",
+		       sdp->dnl_bytes_remaining, sdp->dnl_address);
+		break;
+	case SDP_WRITE_FILE:
+		sdp->always_send_status = true;
+		sdp->error_status = SDP_WRITE_FILE_COMPLETE;
+
+		sdp->state = SDP_STATE_RX_FILE_DATA;
+		sdp->dnl_address = cmd->addr ? be32_to_cpu(cmd->addr) : CONFIG_SDP_LOADADDR;
+		sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+		sdp->dnl_bytes = sdp->dnl_bytes_remaining;
+		sdp->next_state = SDP_STATE_IDLE;
+
+		printf("Downloading file of size %d to 0x%08x... ",
+		       sdp->dnl_bytes_remaining, sdp->dnl_address);
+
+		break;
+	case SDP_ERROR_STATUS:
+		sdp->always_send_status = true;
+		sdp->error_status = 0;
+
+		sdp->state = SDP_STATE_TX_SEC_CONF;
+		sdp->next_state = SDP_STATE_IDLE;
+		break;
+	case SDP_DCD_WRITE:
+		sdp->always_send_status = true;
+		sdp->error_status = SDP_WRITE_REGISTER_COMPLETE;
+
+		sdp->state = SDP_STATE_RX_DCD_DATA;
+		sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+		sdp->next_state = SDP_STATE_IDLE;
+		break;
+	case SDP_JUMP_ADDRESS:
+		sdp->always_send_status = false;
+		sdp->error_status = 0;
+
+		sdp->jmp_address = cmd->addr ? be32_to_cpu(cmd->addr) : CONFIG_SDP_LOADADDR;
+		sdp->state = SDP_STATE_TX_SEC_CONF;
+		sdp->next_state = SDP_STATE_JUMP;
+		break;
+	case SDP_SKIP_DCD_HEADER:
+		sdp->always_send_status = true;
+		sdp->error_status = SDP_SKIP_DCD_HEADER_COMPLETE;
+
+		/* Ignore command, DCD not supported anyway */
+		sdp->state = SDP_STATE_TX_SEC_CONF;
+		sdp->next_state = SDP_STATE_IDLE;
+		break;
+	default:
+		pr_err("Unknown command: %04x\n", be16_to_cpu(cmd->cmd));
+	}
+}
+
+static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_sdp *sdp = req->context;
+	int status = req->status;
+	u8 *data = req->buf;
+	u8 report = data[0];
+	int datalen = req->actual - 1;
+
+	if (status != 0) {
+		pr_err("Status: %d\n", status);
+		return;
+	}
+
+	if (report != 2) {
+		pr_err("Unexpected report %d\n", report);
+		return;
+	}
+
+	if (sdp->dnl_bytes_remaining < datalen) {
+		/*
+		 * Some USB stacks require to send a complete buffer as
+		 * specified in the HID descriptor. This leads to longer
+		 * transfers than the file length, no problem for us.
+		 */
+		sdp->dnl_bytes_remaining = 0;
+	} else {
+		sdp->dnl_bytes_remaining -= datalen;
+	}
+
+	if (sdp->state == SDP_STATE_RX_FILE_DATA_BUSY) {
+		memcpy(sdp_ptr(sdp->dnl_address), req->buf + 1, datalen);
+		sdp->dnl_address += datalen;
+	}
+
+	if (sdp->dnl_bytes_remaining) {
+		sdp->state = SDP_STATE_RX_FILE_DATA;
+		return;
+	}
+
+#ifndef CONFIG_SPL_BUILD
+	env_set_hex("filesize", sdp->dnl_bytes);
+#endif
+	printf("done\n");
+
+	switch (sdp->state) {
+	case SDP_STATE_RX_FILE_DATA_BUSY:
+		sdp->state = SDP_STATE_TX_SEC_CONF;
+		break;
+	case SDP_STATE_RX_DCD_DATA:
+		sdp->state = SDP_STATE_TX_SEC_CONF;
+		break;
+	default:
+		pr_err("Invalid state: %d\n", sdp->state);
+	}
+}
+
+static void sdp_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_sdp *sdp = req->context;
+	int status = req->status;
+
+	if (status != 0) {
+		pr_err("Status: %d\n", status);
+		return;
+	}
+
+	switch (sdp->state) {
+	case SDP_STATE_TX_SEC_CONF_BUSY:
+		/* Not all commands require status report */
+		if (sdp->always_send_status || sdp->error_status)
+			sdp->state = SDP_STATE_TX_STATUS;
+		else
+			sdp->state = sdp->next_state;
+
+		break;
+	case SDP_STATE_TX_STATUS_BUSY:
+		sdp->state = sdp->next_state;
+		break;
+	case SDP_STATE_TX_REGISTER_BUSY:
+		if (sdp->dnl_bytes_remaining)
+			sdp->state = SDP_STATE_TX_REGISTER;
+		else
+			sdp->state = SDP_STATE_IDLE;
+		break;
+	default:
+		pr_err("Wrong State: %d\n", sdp->state);
+		sdp->state = SDP_STATE_IDLE;
+		break;
+	}
+	debug("%s complete --> %d, %d/%d\n", ep->name,
+	      status, req->actual, req->length);
+}
+
+static int sdp_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	struct usb_request *req = f->config->cdev->req;
+	struct f_sdp *sdp = f->config->cdev->req->context;
+	u16 len = le16_to_cpu(ctrl->wLength);
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	int value = 0;
+	u8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
+
+	debug("w_value: 0x%04x len: 0x%04x\n", w_value, len);
+	debug("req_type: 0x%02x ctrl->bRequest: 0x%02x sdp->state: %d\n",
+	      req_type, ctrl->bRequest, sdp->state);
+
+	if (req_type == USB_TYPE_STANDARD) {
+		if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR) {
+			/* Send HID report descriptor */
+			value = min(len, (u16) sizeof(sdp_hid_report));
+			memcpy(req->buf, &sdp_hid_report, value);
+			sdp->configuration_done = true;
+		}
+	}
+
+	if (req_type == USB_TYPE_CLASS) {
+		int report = w_value & HID_REPORT_ID_MASK;
+
+		/* HID (SDP) request */
+		switch (ctrl->bRequest) {
+		case HID_REQ_SET_REPORT:
+			switch (report) {
+			case 1:
+				value = SDP_COMMAND_LEN + 1;
+				req->complete = sdp_rx_command_complete;
+				sdp_func->ep_int_enable = false;
+				break;
+			case 2:
+				value = len;
+				req->complete = sdp_rx_data_complete;
+				sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
+				break;
+			}
+		}
+	}
+
+	if (value >= 0) {
+		req->length = value;
+		req->zero = value < len;
+		value = usb_ep_queue(gadget->ep0, req, 0);
+		if (value < 0) {
+			debug("ep_queue --> %d\n", value);
+			req->status = 0;
+		}
+	}
+
+	return value;
+}
+
+static int sdp_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_sdp *sdp = func_to_sdp(f);
+	int rv = 0, id;
+
+	id = usb_interface_id(c, f);
+	if (id < 0)
+		return id;
+	sdp_intf_runtime.bInterfaceNumber = id;
+
+	struct usb_ep *ep_in, *ep_out;
+
+	/* allocate instance-specific endpoints */
+	ep_in = usb_ep_autoconfig(gadget, &in_desc);
+	if (!ep_in) {
+		rv = -ENODEV;
+		goto error;
+	}
+
+	ep_out = usb_ep_autoconfig(gadget, &out_desc);
+	if (!ep_out) {
+		rv = -ENODEV;
+		goto error;
+	}
+
+	if (gadget_is_dualspeed(gadget)) {
+		/* Assume endpoint addresses are the same for both speeds */
+		in_hs_desc.bEndpointAddress = in_desc.bEndpointAddress;
+		out_hs_desc.bEndpointAddress = out_desc.bEndpointAddress;
+	}
+
+	sdp->in_ep = ep_in; /* Store IN EP for enabling @ setup */
+	sdp->out_ep = ep_out;
+
+	cdev->req->context = sdp;
+
+error:
+	return rv;
+}
+
+static void sdp_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	free(sdp_func);
+	sdp_func = NULL;
+}
+
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req)
+		return req;
+
+	req->length = length;
+	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		req = NULL;
+	}
+
+	return req;
+}
+
+
+static struct usb_request *sdp_start_ep(struct usb_ep *ep, bool in)
+{
+	struct usb_request *req;
+
+	if (in)
+		req = alloc_ep_req(ep, 65);
+	else
+		req = alloc_ep_req(ep, 2048);
+/*
+ * OUT endpoint request length should be an integral multiple of
+ * maxpacket size 1024, else we break on certain controllers like
+ * DWC3 that expect bulk OUT requests to be divisible by maxpacket size.
+ */
+	debug("%s: ep:%p req:%p\n", __func__, ep, req);
+
+	if (!req)
+		return NULL;
+
+	memset(req->buf, 0, req->length);
+	if (in)
+		req->complete = sdp_tx_complete;
+	else
+		req->complete = sdp_rx_command_complete;
+
+	return req;
+}
+static int sdp_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_sdp *sdp = func_to_sdp(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	int result;
+
+	debug("%s: intf: %d alt: %d\n", __func__, intf, alt);
+
+	if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) {
+		result = usb_ep_enable(sdp->in_ep, &in_hs_desc);
+		result |= usb_ep_enable(sdp->out_ep, &out_hs_desc);
+	} else {
+		result = usb_ep_enable(sdp->in_ep, &in_desc);
+		result |= usb_ep_enable(sdp->out_ep, &out_desc);
+	}
+	if (result)
+		return result;
+
+	sdp->in_req = sdp_start_ep(sdp->in_ep, true);
+	sdp->in_req->context = sdp;
+	sdp->out_req = sdp_start_ep(sdp->out_ep, false);
+	sdp->out_req->context = sdp;
+
+	sdp->in_ep->driver_data = cdev; /* claim */
+	sdp->out_ep->driver_data = cdev; /* claim */
+
+	sdp->altsetting = alt;
+	sdp->state = SDP_STATE_IDLE;
+	sdp->ep_int_enable = true;
+
+	return 0;
+}
+
+static int sdp_get_alt(struct usb_function *f, unsigned intf)
+{
+	struct f_sdp *sdp = func_to_sdp(f);
+
+	return sdp->altsetting;
+}
+
+static void sdp_disable(struct usb_function *f)
+{
+	struct f_sdp *sdp = func_to_sdp(f);
+
+	usb_ep_disable(sdp->in_ep);
+	usb_ep_disable(sdp->out_ep);
+
+	if (sdp->in_req) {
+		free(sdp->in_req->buf);
+		usb_ep_free_request(sdp->in_ep, sdp->in_req);
+		sdp->in_req = NULL;
+	}
+	if (sdp->out_req) {
+		free(sdp->out_req->buf);
+		usb_ep_free_request(sdp->out_ep, sdp->out_req);
+		sdp->out_req = NULL;
+	}
+}
+
+static int sdp_bind_config(struct usb_configuration *c)
+{
+	int status;
+
+	if (!sdp_func) {
+		sdp_func = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*sdp_func));
+		if (!sdp_func)
+			return -ENOMEM;
+	}
+
+	memset(sdp_func, 0, sizeof(*sdp_func));
+
+	sdp_func->usb_function.name = "sdp";
+	sdp_func->usb_function.hs_descriptors = sdp_runtime_hs_descs;
+	sdp_func->usb_function.descriptors = sdp_runtime_descs;
+	sdp_func->usb_function.bind = sdp_bind;
+	sdp_func->usb_function.unbind = sdp_unbind;
+	sdp_func->usb_function.set_alt = sdp_set_alt;
+	sdp_func->usb_function.get_alt = sdp_get_alt;
+	sdp_func->usb_function.disable = sdp_disable;
+	sdp_func->usb_function.strings = sdp_generic_strings;
+	sdp_func->usb_function.setup = sdp_setup;
+
+	status = usb_add_function(c, &sdp_func->usb_function);
+
+	return status;
+}
+
+int sdp_init(int controller_index)
+{
+	printf("SDP: initialize...\n");
+	while (!sdp_func->configuration_done) {
+		if (ctrlc()) {
+			puts("\rCTRL+C - Operation aborted.\n");
+			return 1;
+		}
+
+		WATCHDOG_RESET();
+		usb_gadget_handle_interrupts(controller_index);
+	}
+
+	return 0;
+}
+
+static u32 sdp_jump_imxheader(void *address)
+{
+	flash_header_v2_t *headerv2 = address;
+	ulong (*entry)(void);
+
+	if (headerv2->header.tag != IVT_HEADER_TAG) {
+		printf("Header Tag is not an IMX image\n");
+		return SDP_ERROR_IMXHEADER;
+	}
+
+	printf("Jumping to 0x%08x\n", headerv2->entry);
+	entry = sdp_ptr(headerv2->entry);
+	entry();
+
+	/* The image probably never returns hence we won't reach that point */
+	return 0;
+}
+
+#ifdef CONFIG_SPL_BUILD
+static ulong sdp_load_read(struct spl_load_info *load, ulong sector,
+			   ulong count, void *buf)
+{
+	debug("%s: sector %lx, count %lx, buf %lx\n",
+	      __func__, sector, count, (ulong)buf);
+	memcpy(buf, (void *)(load->dev + sector), count);
+	return count;
+}
+
+static ulong search_fit_header(ulong p, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i += 4) {
+		if (genimg_get_format((const void *)(p + i)) == IMAGE_FORMAT_FIT)
+			return p + i;
+	}
+
+	return 0;
+}
+
+static ulong search_container_header(ulong p, int size)
+{
+	int i;
+	u8 *hdr;
+
+	for (i = 0; i < size; i += 4) {
+		hdr = (u8 *)(p + i);
+		if (*(hdr + 3) == 0x87 && *hdr == 0)
+			if (*(hdr + 1) != 0 || *(hdr + 2) != 0)
+				return p + i;
+	}
+	return 0;
+}
+#endif
+
+static int sdp_handle_in_ep(struct spl_image_info *spl_image)
+{
+	u8 *data = sdp_func->in_req->buf;
+	u32 status;
+	int datalen;
+
+	switch (sdp_func->state) {
+	case SDP_STATE_TX_SEC_CONF:
+		debug("Report 3: HAB security\n");
+		data[0] = 3;
+
+		status = SDP_SECURITY_OPEN;
+		memcpy(&data[1], &status, 4);
+		sdp_func->in_req->length = 5;
+		usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0);
+		sdp_func->state = SDP_STATE_TX_SEC_CONF_BUSY;
+		break;
+
+	case SDP_STATE_TX_STATUS:
+		debug("Report 4: Status\n");
+		data[0] = 4;
+
+		memcpy(&data[1], &sdp_func->error_status, 4);
+		sdp_func->in_req->length = 65;
+		usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0);
+		sdp_func->state = SDP_STATE_TX_STATUS_BUSY;
+		break;
+	case SDP_STATE_TX_REGISTER:
+		debug("Report 4: Register Values\n");
+		data[0] = 4;
+
+		datalen = sdp_func->dnl_bytes_remaining;
+
+		if (datalen > 64)
+			datalen = 64;
+
+		memcpy(&data[1], sdp_ptr(sdp_func->dnl_address), datalen);
+		sdp_func->in_req->length = 65;
+
+		sdp_func->dnl_bytes_remaining -= datalen;
+		sdp_func->dnl_address += datalen;
+
+		usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0);
+		sdp_func->state = SDP_STATE_TX_REGISTER_BUSY;
+		break;
+	case SDP_STATE_JUMP:
+		printf("Jumping to header at 0x%08x\n", sdp_func->jmp_address);
+		status = sdp_jump_imxheader(sdp_ptr(sdp_func->jmp_address));
+
+		/* If imx header fails, try some U-Boot specific headers */
+		if (status) {
+#ifdef CONFIG_SPL_BUILD
+			if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER))
+				sdp_func->jmp_address = (u32)search_container_header((ulong)sdp_func->jmp_address, sdp_func->dnl_bytes);
+			else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT))
+				sdp_func->jmp_address = (u32)search_fit_header((ulong)sdp_func->jmp_address, sdp_func->dnl_bytes);
+			if (sdp_func->jmp_address == 0)
+				panic("Error in search header, failed to jump\n");
+
+			printf("Found header at 0x%08x\n", sdp_func->jmp_address);
+
+			image_header_t *header =
+				sdp_ptr(sdp_func->jmp_address);
+#ifdef CONFIG_SPL_LOAD_FIT
+			if (image_get_magic(header) == FDT_MAGIC) {
+				struct spl_load_info load;
+
+				debug("Found FIT\n");
+				load.dev = header;
+				load.bl_len = 1;
+				load.read = sdp_load_read;
+				spl_load_simple_fit(spl_image, &load, 0,
+						    header);
+
+				return SDP_EXIT;
+			}
+#endif
+			if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
+				struct spl_load_info load;
+
+				load.dev = header;
+				load.bl_len = 1;
+				load.read = sdp_load_read;
+				spl_load_imx_container(spl_image, &load, 0);
+				return SDP_EXIT;
+			}
+
+			/* In SPL, allow jumps to U-Boot images */
+			struct spl_image_info spl_image = {};
+			spl_parse_image_header(&spl_image, header);
+			jump_to_image_no_args(&spl_image);
+#else
+			/* In U-Boot, allow jumps to scripts */
+			image_source_script(sdp_func->jmp_address, "script@1");
+#endif
+		}
+
+		sdp_func->next_state = SDP_STATE_IDLE;
+		sdp_func->error_status = status;
+
+		/* Only send Report 4 if there was an error */
+		if (status)
+			sdp_func->state = SDP_STATE_TX_STATUS;
+		else
+			sdp_func->state = SDP_STATE_IDLE;
+		break;
+	default:
+		break;
+	};
+
+	return 0;
+}
+
+static void sdp_handle_out_ep(void)
+{
+	int rc;
+
+	if (sdp_func->state == SDP_STATE_IDLE) {
+		sdp_func->out_req->complete = sdp_rx_command_complete;
+		rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
+		if (rc)
+			printf("error in submission: %s\n",
+			       sdp_func->out_ep->name);
+		sdp_func->state = SDP_STATE_RX_CMD;
+	} else if (sdp_func->state == SDP_STATE_RX_FILE_DATA) {
+		sdp_func->out_req->complete = sdp_rx_data_complete;
+		rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
+		if (rc)
+			printf("error in submission: %s\n",
+			       sdp_func->out_ep->name);
+		sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
+	}
+}
+
+#ifndef CONFIG_SPL_BUILD
+int sdp_handle(int controller_index)
+#else
+int spl_sdp_handle(int controller_index, struct spl_image_info *spl_image)
+#endif
+{
+	int flag = 0;
+	printf("SDP: handle requests...\n");
+	while (1) {
+		if (ctrlc()) {
+			puts("\rCTRL+C - Operation aborted.\n");
+			return -EINVAL;
+		}
+
+		if (flag == SDP_EXIT)
+			return 0;
+
+		WATCHDOG_RESET();
+		usb_gadget_handle_interrupts(controller_index);
+
+#ifdef CONFIG_SPL_BUILD
+		flag = sdp_handle_in_ep(spl_image);
+#else
+		flag = sdp_handle_in_ep(NULL);
+#endif
+		if (sdp_func->ep_int_enable)
+			sdp_handle_out_ep();
+	}
+}
+
+int sdp_add(struct usb_configuration *c)
+{
+	int id;
+
+	id = usb_string_id(c->cdev);
+	if (id < 0)
+		return id;
+	strings_sdp_generic[0].id = id;
+	sdp_intf_runtime.iInterface = id;
+
+	debug("%s: cdev: %p gadget: %p gadget->ep0: %p\n", __func__,
+	      c->cdev, c->cdev->gadget, c->cdev->gadget->ep0);
+
+	return sdp_bind_config(c);
+}
+
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_sdp, sdp_add);
diff --git a/roms/u-boot/drivers/usb/gadget/f_thor.c b/roms/u-boot/drivers/usb/gadget/f_thor.c
new file mode 100644
index 000000000..47ef55b2f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_thor.c
@@ -0,0 +1,1034 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * f_thor.c -- USB TIZEN THOR Downloader gadget function
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * Based on code from:
+ * git://review.tizen.org/kernel/u-boot
+ *
+ * Developed by:
+ * Copyright (C) 2009 Samsung Electronics
+ * Minkyu Kang <mk7.kang@samsung.com>
+ * Sanghee Kim <sh0130.kim@samsung.com>
+ */
+
+#include <command.h>
+#include <errno.h>
+#include <common.h>
+#include <console.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <version.h>
+#include <linux/delay.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+#include <g_dnl.h>
+#include <dfu.h>
+#include <thor.h>
+
+#include "f_thor.h"
+
+static void thor_tx_data(unsigned char *data, int len);
+static void thor_set_dma(void *addr, int len);
+static int thor_rx_data(void);
+
+static struct f_thor *thor_func;
+static inline struct f_thor *func_to_thor(struct usb_function *f)
+{
+	return container_of(f, struct f_thor, usb_function);
+}
+
+DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_tx_data_buf,
+			  sizeof(struct rsp_box));
+DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_rx_data_buf,
+			  sizeof(struct rqt_box));
+
+/* ********************************************************** */
+/*         THOR protocol - transmission handling	      */
+/* ********************************************************** */
+DEFINE_CACHE_ALIGN_BUFFER(char, f_name, F_NAME_BUF_SIZE + 1);
+static unsigned long long int thor_file_size;
+static int alt_setting_num;
+
+static void send_rsp(const struct rsp_box *rsp)
+{
+	memcpy(thor_tx_data_buf, rsp, sizeof(struct rsp_box));
+	thor_tx_data(thor_tx_data_buf, sizeof(struct rsp_box));
+
+	debug("-RSP: %d, %d\n", rsp->rsp, rsp->rsp_data);
+}
+
+static void send_data_rsp(s32 ack, s32 count)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct data_rsp_box, rsp,
+				 sizeof(struct data_rsp_box));
+
+	rsp->ack = ack;
+	rsp->count = count;
+
+	memcpy(thor_tx_data_buf, rsp, sizeof(struct data_rsp_box));
+	thor_tx_data(thor_tx_data_buf, sizeof(struct data_rsp_box));
+
+	debug("-DATA RSP: %d, %d\n", ack, count);
+}
+
+static int process_rqt_info(const struct rqt_box *rqt)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
+	memset(rsp, 0, sizeof(struct rsp_box));
+
+	rsp->rsp = rqt->rqt;
+	rsp->rsp_data = rqt->rqt_data;
+
+	switch (rqt->rqt_data) {
+	case RQT_INFO_VER_PROTOCOL:
+		rsp->int_data[0] = VER_PROTOCOL_MAJOR;
+		rsp->int_data[1] = VER_PROTOCOL_MINOR;
+		break;
+	case RQT_INIT_VER_HW:
+		snprintf(rsp->str_data[0], sizeof(rsp->str_data[0]),
+			 "%x", checkboard());
+		break;
+	case RQT_INIT_VER_BOOT:
+		sprintf(rsp->str_data[0], "%s", U_BOOT_VERSION);
+		break;
+	case RQT_INIT_VER_KERNEL:
+		sprintf(rsp->str_data[0], "%s", "k unknown");
+		break;
+	case RQT_INIT_VER_PLATFORM:
+		sprintf(rsp->str_data[0], "%s", "p unknown");
+		break;
+	case RQT_INIT_VER_CSC:
+		sprintf(rsp->str_data[0], "%s", "c unknown");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	send_rsp(rsp);
+	return true;
+}
+
+static int process_rqt_cmd(const struct rqt_box *rqt)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
+	memset(rsp, 0, sizeof(struct rsp_box));
+
+	rsp->rsp = rqt->rqt;
+	rsp->rsp_data = rqt->rqt_data;
+
+	switch (rqt->rqt_data) {
+	case RQT_CMD_REBOOT:
+		debug("TARGET RESET\n");
+		send_rsp(rsp);
+		g_dnl_unregister();
+		dfu_free_entities();
+#ifdef CONFIG_THOR_RESET_OFF
+		return RESET_DONE;
+#endif
+		run_command("reset", 0);
+		break;
+	case RQT_CMD_POWEROFF:
+	case RQT_CMD_EFSCLEAR:
+		send_rsp(rsp);
+	default:
+		printf("Command not supported -> cmd: %d\n", rqt->rqt_data);
+		return -EINVAL;
+	}
+
+	return true;
+}
+
+static long long int download_head(unsigned long long total,
+				   unsigned int packet_size,
+				   long long int *left,
+				   int *cnt)
+{
+	long long int rcv_cnt = 0, left_to_rcv, ret_rcv;
+	struct dfu_entity *dfu_entity = dfu_get_entity(alt_setting_num);
+	void *transfer_buffer = dfu_get_buf(dfu_entity);
+	void *buf = transfer_buffer;
+	int usb_pkt_cnt = 0, ret;
+
+	/*
+	 * Files smaller than THOR_STORE_UNIT_SIZE (now 32 MiB) are stored on
+	 * the medium.
+	 * The packet response is sent on the purpose after successful data
+	 * chunk write. There is a room for improvement when asynchronous write
+	 * is performed.
+	 */
+	while (total - rcv_cnt >= packet_size) {
+		thor_set_dma(buf, packet_size);
+		buf += packet_size;
+		ret_rcv = thor_rx_data();
+		if (ret_rcv < 0)
+			return ret_rcv;
+		rcv_cnt += ret_rcv;
+		debug("%d: RCV data count: %llu cnt: %d\n", usb_pkt_cnt,
+		      rcv_cnt, *cnt);
+
+		if ((rcv_cnt % THOR_STORE_UNIT_SIZE) == 0) {
+			ret = dfu_write(dfu_get_entity(alt_setting_num),
+					transfer_buffer, THOR_STORE_UNIT_SIZE,
+					(*cnt)++);
+			if (ret) {
+				pr_err("DFU write failed [%d] cnt: %d\n",
+				      ret, *cnt);
+				return ret;
+			}
+			buf = transfer_buffer;
+		}
+		send_data_rsp(0, ++usb_pkt_cnt);
+	}
+
+	/* Calculate the amount of data to arrive from PC (in bytes) */
+	left_to_rcv = total - rcv_cnt;
+
+	/*
+	 * Calculate number of data already received. but not yet stored
+	 * on the medium (they are smaller than THOR_STORE_UNIT_SIZE)
+	 */
+	*left = left_to_rcv + buf - transfer_buffer;
+	debug("%s: left: %llu left_to_rcv: %llu buf: 0x%p\n", __func__,
+	      *left, left_to_rcv, buf);
+
+	if (left_to_rcv) {
+		thor_set_dma(buf, packet_size);
+		ret_rcv = thor_rx_data();
+		if (ret_rcv < 0)
+			return ret_rcv;
+		rcv_cnt += ret_rcv;
+		send_data_rsp(0, ++usb_pkt_cnt);
+	}
+
+	debug("%s: %llu total: %llu cnt: %d\n", __func__, rcv_cnt, total, *cnt);
+
+	return rcv_cnt;
+}
+
+static int download_tail(long long int left, int cnt)
+{
+	struct dfu_entity *dfu_entity;
+	void *transfer_buffer;
+	int ret;
+
+	debug("%s: left: %llu cnt: %d\n", __func__, left, cnt);
+
+	dfu_entity = dfu_get_entity(alt_setting_num);
+	if (!dfu_entity) {
+		pr_err("Alt setting: %d entity not found!\n", alt_setting_num);
+		return -ENOENT;
+	}
+
+	transfer_buffer = dfu_get_buf(dfu_entity);
+	if (!transfer_buffer) {
+		pr_err("Transfer buffer not allocated!\n");
+		return -ENXIO;
+	}
+
+	if (left) {
+		ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++);
+		if (ret) {
+			pr_err("DFU write failed[%d]: left: %llu\n", ret, left);
+			return ret;
+		}
+	}
+
+	/*
+	 * To store last "packet" or write file from buffer to filesystem
+	 * DFU storage backend requires dfu_flush
+	 *
+	 * This also frees memory malloc'ed by dfu_get_buf(), so no explicit
+	 * need fo call dfu_free_buf() is needed.
+	 */
+	ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt);
+	if (ret)
+		pr_err("DFU flush failed!\n");
+
+	return ret;
+}
+
+static long long int process_rqt_download(const struct rqt_box *rqt)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box));
+	static long long int left, ret_head;
+	int file_type, ret = 0;
+	static int cnt;
+
+	memset(rsp, 0, sizeof(struct rsp_box));
+	rsp->rsp = rqt->rqt;
+	rsp->rsp_data = rqt->rqt_data;
+
+	switch (rqt->rqt_data) {
+	case RQT_DL_INIT:
+		thor_file_size = (uint64_t)(uint32_t)rqt->int_data[0] +
+				 (((uint64_t)(uint32_t)rqt->int_data[1])
+				  << 32);
+		debug("INIT: total %llu bytes\n", thor_file_size);
+		break;
+	case RQT_DL_FILE_INFO:
+		file_type = rqt->int_data[0];
+		if (file_type == FILE_TYPE_PIT) {
+			puts("PIT table file - not supported\n");
+			rsp->ack = -ENOTSUPP;
+			ret = rsp->ack;
+			break;
+		}
+
+		thor_file_size = (uint64_t)(uint32_t)rqt->int_data[1] +
+				 (((uint64_t)(uint32_t)rqt->int_data[2])
+				  << 32);
+		memcpy(f_name, rqt->str_data[0], F_NAME_BUF_SIZE);
+		f_name[F_NAME_BUF_SIZE] = '\0';
+
+		debug("INFO: name(%s, %d), size(%llu), type(%d)\n",
+		      f_name, 0, thor_file_size, file_type);
+
+		rsp->int_data[0] = THOR_PACKET_SIZE;
+
+		alt_setting_num = dfu_get_alt(f_name);
+		if (alt_setting_num < 0) {
+			pr_err("Alt setting [%d] to write not found!\n",
+			      alt_setting_num);
+			rsp->ack = -ENODEV;
+			ret = rsp->ack;
+		}
+		break;
+	case RQT_DL_FILE_START:
+		send_rsp(rsp);
+		ret_head = download_head(thor_file_size, THOR_PACKET_SIZE,
+					 &left, &cnt);
+		if (ret_head < 0) {
+			left = 0;
+			cnt = 0;
+		}
+		return ret_head;
+	case RQT_DL_FILE_END:
+		debug("DL FILE_END\n");
+		rsp->ack = download_tail(left, cnt);
+		ret = rsp->ack;
+		left = 0;
+		cnt = 0;
+		break;
+	case RQT_DL_EXIT:
+		debug("DL EXIT\n");
+		break;
+	default:
+		pr_err("Operation not supported: %d\n", rqt->rqt_data);
+		ret = -ENOTSUPP;
+	}
+
+	send_rsp(rsp);
+	return ret;
+}
+
+static int process_data(void)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct rqt_box, rqt, sizeof(struct rqt_box));
+	int ret = -EINVAL;
+
+	memcpy(rqt, thor_rx_data_buf, sizeof(struct rqt_box));
+
+	debug("+RQT: %d, %d\n", rqt->rqt, rqt->rqt_data);
+
+	switch (rqt->rqt) {
+	case RQT_INFO:
+		ret = process_rqt_info(rqt);
+		break;
+	case RQT_CMD:
+		ret = process_rqt_cmd(rqt);
+		break;
+	case RQT_DL:
+		ret = (int) process_rqt_download(rqt);
+		break;
+	case RQT_UL:
+		puts("RQT: UPLOAD not supported!\n");
+		break;
+	default:
+		pr_err("unknown request (%d)\n", rqt->rqt);
+	}
+
+	return ret;
+}
+
+/* ********************************************************** */
+/*         THOR USB Function				      */
+/* ********************************************************** */
+
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+	struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+static struct usb_interface_descriptor thor_downloader_intf_data = {
+	.bLength =		sizeof(thor_downloader_intf_data),
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+};
+
+static struct usb_endpoint_descriptor fs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =	USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor fs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =	USB_ENDPOINT_XFER_BULK,
+};
+
+/* CDC configuration */
+static struct usb_interface_descriptor thor_downloader_intf_int = {
+	.bLength =		sizeof(thor_downloader_intf_int),
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	1,
+	.bInterfaceClass =	USB_CLASS_COMM,
+	 /* 0x02 Abstract Line Control Model */
+	.bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+	/* 0x01 Common AT commands */
+	.bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
+};
+
+static struct usb_cdc_header_desc thor_downloader_cdc_header = {
+	.bLength         =    sizeof(thor_downloader_cdc_header),
+	.bDescriptorType =    0x24, /* CS_INTERFACE */
+	.bDescriptorSubType = 0x00,
+	.bcdCDC =             0x0110,
+};
+
+static struct usb_cdc_call_mgmt_descriptor thor_downloader_cdc_call = {
+	.bLength         =    sizeof(thor_downloader_cdc_call),
+	.bDescriptorType =    0x24, /* CS_INTERFACE */
+	.bDescriptorSubType = 0x01,
+	.bmCapabilities =     0x00,
+	.bDataInterface =     0x01,
+};
+
+static struct usb_cdc_acm_descriptor thor_downloader_cdc_abstract = {
+	.bLength         =    sizeof(thor_downloader_cdc_abstract),
+	.bDescriptorType =    0x24, /* CS_INTERFACE */
+	.bDescriptorSubType = 0x02,
+	.bmCapabilities =     0x00,
+};
+
+static struct usb_cdc_union_desc thor_downloader_cdc_union = {
+	.bLength         =     sizeof(thor_downloader_cdc_union),
+	.bDescriptorType =     0x24, /* CS_INTERFACE */
+	.bDescriptorSubType =  USB_CDC_UNION_TYPE,
+};
+
+static struct usb_endpoint_descriptor fs_int_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = 3 | USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize = __constant_cpu_to_le16(16),
+
+	.bInterval = 0x9,
+};
+
+static struct usb_interface_assoc_descriptor
+thor_iad_descriptor = {
+	.bLength =		sizeof(thor_iad_descriptor),
+	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
+
+	.bFirstInterface =	0,
+	.bInterfaceCount =	2,	/* control + data */
+	.bFunctionClass =	USB_CLASS_COMM,
+	.bFunctionSubClass =	USB_CDC_SUBCLASS_ACM,
+	.bFunctionProtocol =	USB_CDC_PROTO_NONE,
+};
+
+static struct usb_endpoint_descriptor hs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_int_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bmAttributes = USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize = __constant_cpu_to_le16(16),
+
+	.bInterval = 0x9,
+};
+
+/*
+ * This attribute vendor descriptor is necessary for correct operation with
+ * Windows version of THOR download program
+ *
+ * It prevents windows driver from sending zero lenght packet (ZLP) after
+ * each THOR_PACKET_SIZE. This assures consistent behaviour with libusb
+ */
+static struct usb_cdc_attribute_vendor_descriptor thor_downloader_cdc_av = {
+	.bLength =              sizeof(thor_downloader_cdc_av),
+	.bDescriptorType =      0x24,
+	.bDescriptorSubType =   0x80,
+	.DAUType =              0x0002,
+	.DAULength =            0x0001,
+	.DAUValue =             0x00,
+};
+
+static const struct usb_descriptor_header *hs_thor_downloader_function[] = {
+	(struct usb_descriptor_header *)&thor_iad_descriptor,
+
+	(struct usb_descriptor_header *)&thor_downloader_intf_int,
+	(struct usb_descriptor_header *)&thor_downloader_cdc_header,
+	(struct usb_descriptor_header *)&thor_downloader_cdc_call,
+	(struct usb_descriptor_header *)&thor_downloader_cdc_abstract,
+	(struct usb_descriptor_header *)&thor_downloader_cdc_union,
+	(struct usb_descriptor_header *)&hs_int_desc,
+
+	(struct usb_descriptor_header *)&thor_downloader_intf_data,
+	(struct usb_descriptor_header *)&thor_downloader_cdc_av,
+	(struct usb_descriptor_header *)&hs_in_desc,
+	(struct usb_descriptor_header *)&hs_out_desc,
+	NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req)
+		return req;
+
+	req->length = length;
+	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length);
+	if (!req->buf) {
+		usb_ep_free_request(ep, req);
+		req = NULL;
+	}
+
+	return req;
+}
+
+static int thor_rx_data(void)
+{
+	struct thor_dev *dev = thor_func->dev;
+	int data_to_rx, tmp, status;
+
+	data_to_rx = dev->out_req->length;
+	tmp = data_to_rx;
+	do {
+		dev->out_req->length = data_to_rx;
+		debug("dev->out_req->length:%d dev->rxdata:%d\n",
+		      dev->out_req->length, dev->rxdata);
+
+		status = usb_ep_queue(dev->out_ep, dev->out_req, 0);
+		if (status) {
+			pr_err("kill %s:  resubmit %d bytes --> %d\n",
+			      dev->out_ep->name, dev->out_req->length, status);
+			usb_ep_set_halt(dev->out_ep);
+			return -EAGAIN;
+		}
+
+		while (!dev->rxdata) {
+			usb_gadget_handle_interrupts(0);
+			if (ctrlc())
+				return -1;
+		}
+		dev->rxdata = 0;
+		data_to_rx -= dev->out_req->actual;
+	} while (data_to_rx);
+
+	return tmp;
+}
+
+static void thor_tx_data(unsigned char *data, int len)
+{
+	struct thor_dev *dev = thor_func->dev;
+	unsigned char *ptr = dev->in_req->buf;
+	int status;
+
+	memset(ptr, 0, len);
+	memcpy(ptr, data, len);
+
+	dev->in_req->length = len;
+
+	debug("%s: dev->in_req->length:%d to_cpy:%zd\n", __func__,
+	      dev->in_req->length, sizeof(data));
+
+	status = usb_ep_queue(dev->in_ep, dev->in_req, 0);
+	if (status) {
+		pr_err("kill %s:  resubmit %d bytes --> %d\n",
+		      dev->in_ep->name, dev->in_req->length, status);
+		usb_ep_set_halt(dev->in_ep);
+	}
+
+	/* Wait until tx interrupt received */
+	while (!dev->txdata)
+		usb_gadget_handle_interrupts(0);
+
+	dev->txdata = 0;
+}
+
+static void thor_rx_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct thor_dev *dev = thor_func->dev;
+	int status = req->status;
+
+	debug("%s: ep_ptr:%p, req_ptr:%p\n", __func__, ep, req);
+	switch (status) {
+	case 0:
+		if (ep == dev->out_ep)
+			dev->rxdata = 1;
+		else
+			dev->txdata = 1;
+
+		break;
+
+	/* this endpoint is normally active while we're configured */
+	case -ECONNABORTED:		/* hardware forced ep reset */
+	case -ECONNRESET:		/* request dequeued */
+	case -ESHUTDOWN:		/* disconnect from host */
+	case -EREMOTEIO:                /* short read */
+	case -EOVERFLOW:
+		pr_err("ERROR:%d\n", status);
+		break;
+	}
+
+	debug("%s complete --> %d, %d/%d\n", ep->name,
+	      status, req->actual, req->length);
+}
+
+static void thor_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		debug("setup complete --> %d, %d/%d\n",
+		      req->status, req->actual, req->length);
+}
+
+static int
+thor_func_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct thor_dev *dev = thor_func->dev;
+	struct usb_request *req = dev->req;
+	struct usb_gadget *gadget = dev->gadget;
+	int value = 0;
+
+	u16 len = le16_to_cpu(ctrl->wLength);
+
+	debug("Req_Type: 0x%x Req: 0x%x wValue: 0x%x wIndex: 0x%x wLen: 0x%x\n",
+	      ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex,
+	      ctrl->wLength);
+
+	switch (ctrl->bRequest) {
+	case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+		value = 0;
+		break;
+	case USB_CDC_REQ_SET_LINE_CODING:
+		value = len;
+		/* Line Coding set done = configuration done */
+		thor_func->dev->configuration_done = 1;
+		break;
+
+	default:
+		pr_err("thor_setup: unknown request: %d\n", ctrl->bRequest);
+	}
+
+	if (value >= 0) {
+		req->length = value;
+		req->zero = value < len;
+		value = usb_ep_queue(gadget->ep0, req, 0);
+		if (value < 0) {
+			debug("%s: ep_queue: %d\n", __func__, value);
+			req->status = 0;
+		}
+	}
+
+	return value;
+}
+
+/* Specific to the THOR protocol */
+static void thor_set_dma(void *addr, int len)
+{
+	struct thor_dev *dev = thor_func->dev;
+
+	debug("in_req:%p, out_req:%p\n", dev->in_req, dev->out_req);
+	debug("addr:%p, len:%d\n", addr, len);
+
+	dev->out_req->buf = addr;
+	dev->out_req->length = len;
+}
+
+int thor_init(void)
+{
+	struct thor_dev *dev = thor_func->dev;
+
+	/* Wait for a device enumeration and configuration settings */
+	debug("THOR enumeration/configuration setting....\n");
+	while (!dev->configuration_done)
+		usb_gadget_handle_interrupts(0);
+
+	thor_set_dma(thor_rx_data_buf, strlen("THOR"));
+	/* detect the download request from Host PC */
+	if (thor_rx_data() < 0) {
+		printf("%s: Data not received!\n", __func__);
+		return -1;
+	}
+
+	if (!strncmp((char *)thor_rx_data_buf, "THOR", strlen("THOR"))) {
+		puts("Download request from the Host PC\n");
+		udelay(30 * 1000); /* 30 ms */
+
+		strcpy((char *)thor_tx_data_buf, "ROHT");
+		thor_tx_data(thor_tx_data_buf, strlen("ROHT"));
+	} else {
+		puts("Wrong reply information\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int thor_handle(void)
+{
+	int ret;
+
+	/* receive the data from Host PC */
+	while (1) {
+		thor_set_dma(thor_rx_data_buf, sizeof(struct rqt_box));
+		ret = thor_rx_data();
+
+		if (ret > 0) {
+			ret = process_data();
+#ifdef CONFIG_THOR_RESET_OFF
+			if (ret == RESET_DONE)
+				break;
+#endif
+			if (ret < 0)
+				return ret;
+		} else {
+			printf("%s: No data received!\n", __func__);
+			break;
+		}
+		if (dfu_reinit_needed)
+			return THOR_DFU_REINIT_NEEDED;
+	}
+
+	return 0;
+}
+
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->buf)
+		free(req->buf);
+	usb_ep_free_request(ep, req);
+}
+
+static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_thor *f_thor = func_to_thor(f);
+	struct thor_dev *dev;
+	struct usb_ep *ep;
+	int status;
+
+	thor_func = f_thor;
+	dev = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*dev));
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(*dev));
+	dev->gadget = gadget;
+	f_thor->dev = dev;
+
+	debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n",
+	      __func__, c, f);
+	debug("f_thor: 0x%p thor: 0x%p\n", f_thor, dev);
+
+	/* EP0  */
+	/* preallocate control response and buffer */
+	dev->req = usb_ep_alloc_request(gadget->ep0, 0);
+	if (!dev->req) {
+		status = -ENOMEM;
+		goto fail;
+	}
+	dev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
+				 THOR_PACKET_SIZE);
+	if (!dev->req->buf) {
+		status = -ENOMEM;
+		goto fail;
+	}
+
+	dev->req->complete = thor_setup_complete;
+
+	/* DYNAMIC interface numbers assignments */
+	status = usb_interface_id(c, f);
+
+	if (status < 0)
+		goto fail;
+
+	thor_downloader_intf_int.bInterfaceNumber = status;
+	thor_downloader_cdc_union.bMasterInterface0 = status;
+
+	status = usb_interface_id(c, f);
+
+	if (status < 0)
+		goto fail;
+
+	thor_downloader_intf_data.bInterfaceNumber = status;
+	thor_downloader_cdc_union.bSlaveInterface0 = status;
+
+	/* allocate instance-specific endpoints */
+	ep = usb_ep_autoconfig(gadget, &fs_in_desc);
+	if (!ep) {
+		status = -ENODEV;
+		goto fail;
+	}
+
+	if (gadget_is_dualspeed(gadget)) {
+		hs_in_desc.bEndpointAddress =
+				fs_in_desc.bEndpointAddress;
+	}
+
+	dev->in_ep = ep; /* Store IN EP for enabling @ setup */
+	ep->driver_data = dev;
+
+	ep = usb_ep_autoconfig(gadget, &fs_out_desc);
+	if (!ep) {
+		status = -ENODEV;
+		goto fail;
+	}
+
+	if (gadget_is_dualspeed(gadget))
+		hs_out_desc.bEndpointAddress =
+				fs_out_desc.bEndpointAddress;
+
+	dev->out_ep = ep; /* Store OUT EP for enabling @ setup */
+	ep->driver_data = dev;
+
+	ep = usb_ep_autoconfig(gadget, &fs_int_desc);
+	if (!ep) {
+		status = -ENODEV;
+		goto fail;
+	}
+
+	dev->int_ep = ep;
+	ep->driver_data = dev;
+
+	if (gadget_is_dualspeed(gadget)) {
+		hs_int_desc.bEndpointAddress =
+				fs_int_desc.bEndpointAddress;
+
+		f->hs_descriptors = (struct usb_descriptor_header **)
+			&hs_thor_downloader_function;
+
+		if (!f->hs_descriptors)
+			goto fail;
+	}
+
+	debug("%s: out_ep:%p out_req:%p\n", __func__,
+	      dev->out_ep, dev->out_req);
+
+	return 0;
+
+ fail:
+	if (dev->req)
+		free_ep_req(gadget->ep0, dev->req);
+	free(dev);
+	return status;
+}
+
+static void thor_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_thor *f_thor = func_to_thor(f);
+	struct thor_dev *dev = f_thor->dev;
+
+	free_ep_req(dev->gadget->ep0, dev->req);
+	free(dev);
+	memset(thor_func, 0, sizeof(*thor_func));
+	thor_func = NULL;
+}
+
+static void thor_func_disable(struct usb_function *f)
+{
+	struct f_thor *f_thor = func_to_thor(f);
+	struct thor_dev *dev = f_thor->dev;
+
+	debug("%s:\n", __func__);
+
+	/* Avoid freeing memory when ep is still claimed */
+	if (dev->in_ep->driver_data) {
+		usb_ep_disable(dev->in_ep);
+		free_ep_req(dev->in_ep, dev->in_req);
+		dev->in_ep->driver_data = NULL;
+	}
+
+	if (dev->out_ep->driver_data) {
+		usb_ep_disable(dev->out_ep);
+		usb_ep_free_request(dev->out_ep, dev->out_req);
+		dev->out_ep->driver_data = NULL;
+	}
+
+	if (dev->int_ep->driver_data) {
+		usb_ep_disable(dev->int_ep);
+		dev->int_ep->driver_data = NULL;
+	}
+}
+
+static int thor_eps_setup(struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct thor_dev *dev = thor_func->dev;
+	struct usb_endpoint_descriptor *d;
+	struct usb_request *req;
+	struct usb_ep *ep;
+	int result;
+
+	ep = dev->in_ep;
+	d = ep_desc(gadget, &hs_in_desc, &fs_in_desc);
+	debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
+
+	result = usb_ep_enable(ep, d);
+	if (result)
+		goto err;
+
+	ep->driver_data = cdev; /* claim */
+	req = alloc_ep_req(ep, THOR_PACKET_SIZE);
+	if (!req) {
+		result = -EIO;
+		goto err_disable_in_ep;
+	}
+
+	memset(req->buf, 0, req->length);
+	req->complete = thor_rx_tx_complete;
+	dev->in_req = req;
+	ep = dev->out_ep;
+	d = ep_desc(gadget, &hs_out_desc, &fs_out_desc);
+	debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
+
+	result = usb_ep_enable(ep, d);
+	if (result)
+		goto err_free_in_req;
+
+	ep->driver_data = cdev; /* claim */
+	req = usb_ep_alloc_request(ep, 0);
+	if (!req) {
+		result = -EIO;
+		goto err_disable_out_ep;
+	}
+
+	req->complete = thor_rx_tx_complete;
+	dev->out_req = req;
+	/* ACM control EP */
+	ep = dev->int_ep;
+	d = ep_desc(gadget, &hs_int_desc, &fs_int_desc);
+	debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
+
+	result = usb_ep_enable(ep, d);
+	if (result)
+		goto err;
+
+	ep->driver_data = cdev;	/* claim */
+
+	return 0;
+
+ err_disable_out_ep:
+	usb_ep_disable(dev->out_ep);
+
+ err_free_in_req:
+	free_ep_req(dev->in_ep, dev->in_req);
+	dev->in_req = NULL;
+
+ err_disable_in_ep:
+	usb_ep_disable(dev->in_ep);
+
+ err:
+	return result;
+}
+
+static int thor_func_set_alt(struct usb_function *f,
+			     unsigned intf, unsigned alt)
+{
+	struct thor_dev *dev = thor_func->dev;
+	int result;
+
+	debug("%s: func: %s intf: %d alt: %d\n",
+	      __func__, f->name, intf, alt);
+
+	switch (intf) {
+	case 0:
+		debug("ACM INTR interface\n");
+		break;
+	case 1:
+		debug("Communication Data interface\n");
+		result = thor_eps_setup(f);
+		if (result)
+			pr_err("%s: EPs setup failed!\n", __func__);
+		dev->configuration_done = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static int thor_func_init(struct usb_configuration *c)
+{
+	struct f_thor *f_thor;
+	int status;
+
+	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+	f_thor = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_thor));
+	if (!f_thor)
+		return -ENOMEM;
+
+	memset(f_thor, 0, sizeof(*f_thor));
+
+	f_thor->usb_function.name = "f_thor";
+	f_thor->usb_function.bind = thor_func_bind;
+	f_thor->usb_function.unbind = thor_unbind;
+	f_thor->usb_function.setup = thor_func_setup;
+	f_thor->usb_function.set_alt = thor_func_set_alt;
+	f_thor->usb_function.disable = thor_func_disable;
+
+	status = usb_add_function(c, &f_thor->usb_function);
+	if (status)
+		free(f_thor);
+
+	return status;
+}
+
+int thor_add(struct usb_configuration *c)
+{
+	debug("%s:\n", __func__);
+	return thor_func_init(c);
+}
+
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_thor, thor_add);
diff --git a/roms/u-boot/drivers/usb/gadget/f_thor.h b/roms/u-boot/drivers/usb/gadget/f_thor.h
new file mode 100644
index 000000000..8ba3fa21b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/f_thor.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * f_thor.h - USB TIZEN THOR - internal gadget definitions
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Lukasz Majewski  <l.majewski@samsung.com>
+ */
+
+#ifndef _USB_THOR_H_
+#define _USB_THOR_H_
+
+#include <linux/compiler.h>
+#include <linux/sizes.h>
+
+/* THOR Composite Gadget */
+#define STRING_MANUFACTURER_IDX	0
+#define STRING_PRODUCT_IDX		1
+#define STRING_SERIAL_IDX		2
+
+/* ********************************************************** */
+/*                   THOR protocol definitions		      */
+/* ********************************************************** */
+
+/*
+ * Attribute Vendor descriptor - necessary to prevent ZLP transmission
+ * from Windows XP HOST PC
+ */
+struct usb_cdc_attribute_vendor_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubType;
+	__u16 DAUType;
+	__u16 DAULength;
+	__u8 DAUValue;
+} __packed;
+
+#define VER_PROTOCOL_MAJOR	5
+#define VER_PROTOCOL_MINOR	0
+
+enum rqt {
+	RQT_INFO = 200,
+	RQT_CMD,
+	RQT_DL,
+	RQT_UL,
+};
+
+enum rqt_data {
+	/* RQT_INFO */
+	RQT_INFO_VER_PROTOCOL = 1,
+	RQT_INIT_VER_HW,
+	RQT_INIT_VER_BOOT,
+	RQT_INIT_VER_KERNEL,
+	RQT_INIT_VER_PLATFORM,
+	RQT_INIT_VER_CSC,
+
+	/* RQT_CMD */
+	RQT_CMD_REBOOT = 1,
+	RQT_CMD_POWEROFF,
+	RQT_CMD_EFSCLEAR,
+
+	/* RQT_DL */
+	RQT_DL_INIT = 1,
+	RQT_DL_FILE_INFO,
+	RQT_DL_FILE_START,
+	RQT_DL_FILE_END,
+	RQT_DL_EXIT,
+
+	/* RQT_UL */
+	RQT_UL_INIT = 1,
+	RQT_UL_START,
+	RQT_UL_END,
+	RQT_UL_EXIT,
+};
+
+struct rqt_box {		/* total: 256B */
+	s32 rqt;		/* request id */
+	s32 rqt_data;		/* request data id */
+	s32 int_data[14];	/* int data */
+	char str_data[5][32];	/* string data */
+	char md5[32];		/* md5 checksum */
+} __packed;
+
+struct rsp_box {		/* total: 128B */
+	s32 rsp;		/* response id (= request id) */
+	s32 rsp_data;		/* response data id */
+	s32 ack;		/* ack */
+	s32 int_data[5];	/* int data */
+	char str_data[3][32];	/* string data */
+} __packed;
+
+struct data_rsp_box {		/* total: 8B */
+	s32 ack;		/* response id (= request id) */
+	s32 count;		/* response data id */
+} __packed;
+
+enum {
+	FILE_TYPE_NORMAL,
+	FILE_TYPE_PIT,
+};
+
+struct thor_dev {
+	struct usb_gadget *gadget;
+	struct usb_request *req; /* EP0 -> control responses */
+
+	/* IN/OUT EP's and correspoinding requests */
+	struct usb_ep *in_ep, *out_ep, *int_ep;
+	struct usb_request *in_req, *out_req;
+
+	/* Control flow variables */
+	unsigned char configuration_done;
+	unsigned char rxdata;
+	unsigned char txdata;
+};
+
+struct f_thor {
+	struct usb_function usb_function;
+	struct thor_dev *dev;
+};
+
+#define F_NAME_BUF_SIZE 32
+#define THOR_PACKET_SIZE SZ_1M      /* 1 MiB */
+#define THOR_STORE_UNIT_SIZE SZ_32M /* 32 MiB */
+#ifdef CONFIG_THOR_RESET_OFF
+#define RESET_DONE 0xFFFFFFFF
+#endif
+#endif /* _USB_THOR_H_ */
diff --git a/roms/u-boot/drivers/usb/gadget/fotg210.c b/roms/u-boot/drivers/usb/gadget/fotg210.c
new file mode 100644
index 000000000..af43433d8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,964 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id & 0x03) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) & 0x03);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(0, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable all interrupts */
+	writel(IMR_MASK, &regs->imr);
+	writel(GIMR_MASK, &regs->gimr);
+	writel(GIMR0_MASK, &regs->gimr0);
+	writel(GIMR1_MASK, &regs->gimr1);
+	writel(GIMR2_MASK, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(ISR_MASK, &regs->isr);
+	writel(0, &regs->gisr);
+	writel(0, &regs->gisr0);
+	writel(0, &regs->gisr1);
+	writel(0, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	mdelay(10);
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	mdelay(10);
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		mdelay(10);
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, &regs->imr);
+	writel(ISR_MASK, &regs->isr);
+	/* disable EP0 IN/OUT interrupt */
+	writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(GIMR1_MASK, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+		| GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	int fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & DMACTRL_START)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((ulong)buf, (ulong)buf + len);
+	else
+		invalidate_dcache_range((ulong)buf, (ulong)buf + len);
+
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx/ep0 fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			udelay(1);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until epx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				/* SOF mask timer = 1100 ticks */
+				writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				/* SOF mask timer = 10000 ticks */
+				writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue & DEVADDR_ADDR_MASK;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return SOFFNR_FNR(readl(&regs->sof_fnr));
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name  = "ep0",
+			.ops   = &fotg210_ep_ops,
+		},
+		.desc      = &ep0_desc,
+		.chip      = &controller,
+		.maxpacket = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name  = "ep1",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name  = "ep2",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name  = "ep3",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name  = "ep4",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(int index)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		/*
+		 * Write 1 and then 0 works for both W1C & RW.
+		 *
+		 * HW v1.11.0+: It's a W1C register (write 1 clear)
+		 * HW v1.10.0-: It's a R/W register (write 0 clear)
+		 */
+		writel(st & GISR0_CXABORT, &regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		/*
+		 * Write 1 and then 0 works for both W1C & RW.
+		 *
+		 * HW v1.11.0+: It's a W1C register (write 1 clear)
+		 * HW v1.10.0-: It's a R/W register (write 0 clear)
+		 */
+		writel(st, &regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/g_dnl.c b/roms/u-boot/drivers/usb/gadget/g_dnl.c
new file mode 100644
index 000000000..afb7b74f3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/g_dnl.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * g_dnl.c -- USB Downloader Gadget
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski  <l.majewski@samsung.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+
+#include <mmc.h>
+#include <part.h>
+#include <usb.h>
+
+#include <g_dnl.h>
+#include <usb_mass_storage.h>
+#include <dfu.h>
+#include <thor.h>
+
+#include <env_callback.h>
+
+#include "gadget_chips.h"
+#include "composite.c"
+
+/*
+ * One needs to define the following:
+ * CONFIG_USB_GADGET_VENDOR_NUM
+ * CONFIG_USB_GADGET_PRODUCT_NUM
+ * CONFIG_USB_GADGET_MANUFACTURER
+ * at e.g. ./configs/<board>_defconfig
+ */
+
+#define STRING_MANUFACTURER 25
+#define STRING_PRODUCT 2
+/* Index of String Descriptor describing this configuration */
+#define STRING_USBDOWN 2
+/* Index of String serial */
+#define STRING_SERIAL  3
+#define MAX_STRING_SERIAL	256
+/* Number of supported configurations */
+#define CONFIGURATION_NUMBER 1
+
+#define DRIVER_VERSION		"usb_dnl 2.0"
+
+static const char product[] = "USB download gadget";
+static char g_dnl_serial[MAX_STRING_SERIAL];
+static const char manufacturer[] = CONFIG_USB_GADGET_MANUFACTURER;
+
+void g_dnl_set_serialnumber(char *s)
+{
+	memset(g_dnl_serial, 0, MAX_STRING_SERIAL);
+	strncpy(g_dnl_serial, s, MAX_STRING_SERIAL - 1);
+}
+
+static struct usb_device_descriptor device_desc = {
+	.bLength = sizeof device_desc,
+	.bDescriptorType = USB_DT_DEVICE,
+
+	.bcdUSB = __constant_cpu_to_le16(0x0200),
+	.bDeviceClass = USB_CLASS_PER_INTERFACE,
+	.bDeviceSubClass = 0, /*0x02:CDC-modem , 0x00:CDC-serial*/
+
+	.idVendor = __constant_cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM),
+	.idProduct = __constant_cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM),
+	/* .iProduct = DYNAMIC */
+	/* .iSerialNumber = DYNAMIC */
+	.bNumConfigurations = 1,
+};
+
+/*
+ * static strings, in UTF-8
+ * IDs for those strings are assigned dynamically at g_dnl_bind()
+ */
+static struct usb_string g_dnl_string_defs[] = {
+	{.s = manufacturer},
+	{.s = product},
+	{.s = g_dnl_serial},
+	{ }		/* end of list */
+};
+
+static struct usb_gadget_strings g_dnl_string_tab = {
+	.language = 0x0409, /* en-us */
+	.strings = g_dnl_string_defs,
+};
+
+static struct usb_gadget_strings *g_dnl_composite_strings[] = {
+	&g_dnl_string_tab,
+	NULL,
+};
+
+void g_dnl_set_product(const char *s)
+{
+	if (s)
+		g_dnl_string_defs[1].s = s;
+	else
+		g_dnl_string_defs[1].s = product;
+}
+
+static int g_dnl_unbind(struct usb_composite_dev *cdev)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+
+	debug("%s: calling usb_gadget_disconnect for "
+			"controller '%s'\n", __func__, gadget->name);
+	usb_gadget_disconnect(gadget);
+
+	return 0;
+}
+
+static inline struct g_dnl_bind_callback *g_dnl_bind_callback_first(void)
+{
+	return ll_entry_start(struct g_dnl_bind_callback,
+				g_dnl_bind_callbacks);
+}
+
+static inline struct g_dnl_bind_callback *g_dnl_bind_callback_end(void)
+{
+	return ll_entry_end(struct g_dnl_bind_callback,
+				g_dnl_bind_callbacks);
+}
+
+static int g_dnl_do_config(struct usb_configuration *c)
+{
+	const char *s = c->cdev->driver->name;
+	struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();
+
+	debug("%s: configuration: 0x%p composite dev: 0x%p\n",
+	      __func__, c, c->cdev);
+
+	for (; callback != g_dnl_bind_callback_end(); callback++)
+		if (!strcmp(s, callback->usb_function_name))
+			return callback->fptr(c);
+	return -ENODEV;
+}
+
+static int g_dnl_config_register(struct usb_composite_dev *cdev)
+{
+	struct usb_configuration *config;
+	const char *name = "usb_dnload";
+
+	config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config));
+	if (!config)
+		return -ENOMEM;
+
+	memset(config, 0, sizeof(*config));
+
+	config->label = name;
+	config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
+	config->bConfigurationValue = CONFIGURATION_NUMBER;
+	config->iConfiguration = STRING_USBDOWN;
+	config->bind = g_dnl_do_config;
+
+	return usb_add_config(cdev, config);
+}
+
+__weak
+int board_usb_init(int index, enum usb_init_type init)
+{
+	return 0;
+}
+
+__weak
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+	return 0;
+}
+
+__weak
+int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
+{
+	return 0;
+}
+
+__weak int g_dnl_get_board_bcd_device_number(int gcnum)
+{
+	return gcnum;
+}
+
+__weak int g_dnl_board_usb_cable_connected(void)
+{
+	return -EOPNOTSUPP;
+}
+
+static bool g_dnl_detach_request;
+
+bool g_dnl_detach(void)
+{
+	return g_dnl_detach_request;
+}
+
+void g_dnl_trigger_detach(void)
+{
+	g_dnl_detach_request = true;
+}
+
+void g_dnl_clear_detach(void)
+{
+	g_dnl_detach_request = false;
+}
+
+static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+	int gcnum;
+
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum > 0)
+		gcnum += 0x200;
+
+	return g_dnl_get_board_bcd_device_number(gcnum);
+}
+
+/**
+ * Update internal serial number variable when the "serial#" env var changes.
+ *
+ * Handle all cases, even when flags == H_PROGRAMMATIC or op == env_op_delete.
+ */
+static int on_serialno(const char *name, const char *value, enum env_op op,
+		int flags)
+{
+	g_dnl_set_serialnumber((char *)value);
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(serialno, on_serialno);
+
+static int g_dnl_bind(struct usb_composite_dev *cdev)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+	int id, ret;
+	int gcnum;
+
+	debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev);
+
+	id = usb_string_id(cdev);
+
+	if (id < 0)
+		return id;
+	g_dnl_string_defs[0].id = id;
+	device_desc.iManufacturer = id;
+
+	id = usb_string_id(cdev);
+	if (id < 0)
+		return id;
+
+	g_dnl_string_defs[1].id = id;
+	device_desc.iProduct = id;
+
+	g_dnl_bind_fixup(&device_desc, cdev->driver->name);
+
+	if (strlen(g_dnl_serial)) {
+		id = usb_string_id(cdev);
+		if (id < 0)
+			return id;
+
+		g_dnl_string_defs[2].id = id;
+		device_desc.iSerialNumber = id;
+	}
+
+	ret = g_dnl_config_register(cdev);
+	if (ret)
+		goto error;
+
+	gcnum = g_dnl_get_bcd_device_number(cdev);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16(gcnum);
+	else {
+		debug("%s: controller '%s' not recognized\n",
+			__func__, gadget->name);
+		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+	}
+
+	debug("%s: calling usb_gadget_connect for "
+			"controller '%s'\n", __func__, gadget->name);
+	usb_gadget_connect(gadget);
+
+	return 0;
+
+ error:
+	g_dnl_unbind(cdev);
+	return -ENOMEM;
+}
+
+static struct usb_composite_driver g_dnl_driver = {
+	.name = NULL,
+	.dev = &device_desc,
+	.strings = g_dnl_composite_strings,
+	.max_speed = USB_SPEED_SUPER,
+
+	.bind = g_dnl_bind,
+	.unbind = g_dnl_unbind,
+};
+
+/*
+ * NOTICE:
+ * Registering via USB function name won't be necessary after rewriting
+ * g_dnl to support multiple USB functions.
+ */
+int g_dnl_register(const char *name)
+{
+	int ret;
+
+	debug("%s: g_dnl_driver.name = %s\n", __func__, name);
+	g_dnl_driver.name = name;
+
+	ret = usb_composite_register(&g_dnl_driver);
+	if (ret) {
+		printf("%s: failed!, error: %d\n", __func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+void g_dnl_unregister(void)
+{
+	usb_composite_unregister(&g_dnl_driver);
+}
diff --git a/roms/u-boot/drivers/usb/gadget/gadget_chips.h b/roms/u-boot/drivers/usb/gadget/gadget_chips.h
new file mode 100644
index 000000000..0cdf47c2d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/gadget_chips.h
@@ -0,0 +1,236 @@
+/*
+ * USB device controllers have lots of quirks.  Use these macros in
+ * gadget drivers or other code that needs to deal with them, and which
+ * autoconfigures instead of using early binding to the hardware.
+ *
+ * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
+ * some config file that gets updated as new hardware is supported.
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
+ *
+ * NOTE:  some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
+ *
+ * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and
+ *                      Remy Bohmer <linux@bohmer.net>
+ */
+#ifdef CONFIG_USB_GADGET_NET2280
+#define	gadget_is_net2280(g)	(!strcmp("net2280", (g)->name))
+#else
+#define	gadget_is_net2280(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define	gadget_is_amd5536udc(g)	(!strcmp("amd5536udc", (g)->name))
+#else
+#define	gadget_is_amd5536udc(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_DUMMY_HCD
+#define	gadget_is_dummy(g)	(!strcmp("dummy_udc", (g)->name))
+#else
+#define	gadget_is_dummy(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA2XX
+#define	gadget_is_pxa(g)	(!strcmp("pxa2xx_udc", (g)->name))
+#else
+#define	gadget_is_pxa(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_GOKU
+#define	gadget_is_goku(g)	(!strcmp("goku_udc", (g)->name))
+#else
+#define	gadget_is_goku(g)	0
+#endif
+
+/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
+#ifdef CONFIG_USB_GADGET_SUPERH
+#define	gadget_is_sh(g)		(!strcmp("sh_udc", (g)->name))
+#else
+#define	gadget_is_sh(g)		0
+#endif
+
+/* not yet stable on 2.6 (would help "original Zaurus") */
+#ifdef CONFIG_USB_GADGET_SA1100
+#define	gadget_is_sa1100(g)	(!strcmp("sa1100_udc", (g)->name))
+#else
+#define	gadget_is_sa1100(g)	0
+#endif
+
+/* handhelds.org tree (?) */
+#ifdef CONFIG_USB_GADGET_MQ11XX
+#define	gadget_is_mq11xx(g)	(!strcmp("mq11xx_udc", (g)->name))
+#else
+#define	gadget_is_mq11xx(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_OMAP
+#define	gadget_is_omap(g)	(!strcmp("omap_udc", (g)->name))
+#else
+#define	gadget_is_omap(g)	0
+#endif
+
+/* not yet ported 2.4 --> 2.6 */
+#ifdef CONFIG_USB_GADGET_N9604
+#define	gadget_is_n9604(g)	(!strcmp("n9604_udc", (g)->name))
+#else
+#define	gadget_is_n9604(g)	0
+#endif
+
+/* various unstable versions available */
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define	gadget_is_pxa27x(g)	(!strcmp("pxa27x_udc", (g)->name))
+#else
+#define	gadget_is_pxa27x(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+#define gadget_is_atmel_usba(g)	(!strcmp("atmel_usba_udc", (g)->name))
+#else
+#define gadget_is_atmel_usba(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_AT91
+#define gadget_is_at91(g)	(!strcmp("at91_udc", (g)->name))
+#else
+#define gadget_is_at91(g)	0
+#endif
+
+/* status unclear */
+#ifdef CONFIG_USB_GADGET_IMX
+#define gadget_is_imx(g)	(!strcmp("imx_udc", (g)->name))
+#else
+#define gadget_is_imx(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_FSL_USB2
+#define gadget_is_fsl_usb2(g)	(!strcmp("fsl-usb2-udc", (g)->name))
+#else
+#define gadget_is_fsl_usb2(g)	0
+#endif
+
+/* Mentor high speed function controller */
+/* from Montavista kernel (?) */
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define gadget_is_musbhsfc(g)	(!strcmp("musbhsfc_udc", (g)->name))
+#else
+#define gadget_is_musbhsfc(g)	0
+#endif
+
+/* Mentor high speed "dual role" controller, in peripheral role */
+#ifdef CONFIG_USB_MUSB_GADGET
+#define gadget_is_musbhdrc(g)	(!strcmp("musb-hdrc", (g)->name))
+#else
+#define gadget_is_musbhdrc(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_M66592
+#define	gadget_is_m66592(g)	(!strcmp("m66592_udc", (g)->name))
+#else
+#define	gadget_is_m66592(g)	0
+#endif
+
+#ifdef CONFIG_CI_UDC
+#define gadget_is_ci(g)        (!strcmp("ci_udc", (g)->name))
+#else
+#define gadget_is_ci(g)        0
+#endif
+
+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
+#ifdef CONFIG_USB_DWC3_GADGET
+#define gadget_is_dwc3(g)        (!strcmp("dwc3-gadget", (g)->name))
+#else
+#define gadget_is_dwc3(g)        0
+#endif
+
+#ifdef CONFIG_USB_CDNS3_GADGET
+#define gadget_is_cdns3(g)        (!strcmp("cdns3-gadget", (g)->name))
+#else
+#define gadget_is_cdns3(g)        0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MAX3420
+#define gadget_is_max3420(g)        (!strcmp("max3420-udc", (g)->name))
+#else
+#define gadget_is_max3420(g)        0
+#endif
+
+#ifdef CONFIG_USB_MTU3_GADGET
+#define gadget_is_mtu3(g)        (!strcmp("mtu3-gadget", (g)->name))
+#else
+#define gadget_is_mtu3(g)        0
+#endif
+
+/**
+ * usb_gadget_controller_number - support bcdDevice id convention
+ * @gadget: the controller being driven
+ *
+ * Return a 2-digit BCD value associated with the peripheral controller,
+ * suitable for use as part of a bcdDevice value, or a negative error code.
+ *
+ * NOTE:  this convention is purely optional, and has no meaning in terms of
+ * any USB specification.  If you want to use a different convention in your
+ * gadget driver firmware -- maybe a more formal revision ID -- feel free.
+ *
+ * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
+ * to change their behavior accordingly.  For example it might help avoiding
+ * some chip bug.
+ */
+static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+{
+	if (gadget_is_net2280(gadget))
+		return 0x01;
+	else if (gadget_is_dummy(gadget))
+		return 0x02;
+	else if (gadget_is_pxa(gadget))
+		return 0x03;
+	else if (gadget_is_sh(gadget))
+		return 0x04;
+	else if (gadget_is_sa1100(gadget))
+		return 0x05;
+	else if (gadget_is_goku(gadget))
+		return 0x06;
+	else if (gadget_is_mq11xx(gadget))
+		return 0x07;
+	else if (gadget_is_omap(gadget))
+		return 0x08;
+	else if (gadget_is_n9604(gadget))
+		return 0x09;
+	else if (gadget_is_pxa27x(gadget))
+		return 0x10;
+	else if (gadget_is_at91(gadget))
+		return 0x12;
+	else if (gadget_is_imx(gadget))
+		return 0x13;
+	else if (gadget_is_musbhsfc(gadget))
+		return 0x14;
+	else if (gadget_is_musbhdrc(gadget))
+		return 0x15;
+	else if (gadget_is_atmel_usba(gadget))
+		return 0x17;
+	else if (gadget_is_fsl_usb2(gadget))
+		return 0x18;
+	else if (gadget_is_amd5536udc(gadget))
+		return 0x19;
+	else if (gadget_is_m66592(gadget))
+		return 0x20;
+	else if (gadget_is_ci(gadget))
+		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
+	else if (gadget_is_dwc3(gadget))
+		return 0x23;
+	else if (gadget_is_cdns3(gadget))
+		return 0x24;
+	else if (gadget_is_max3420(gadget))
+		return 0x25;
+	else if (gadget_is_mtu3(gadget))
+		return 0x26;
+	return -ENOENT;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/max3420_udc.c b/roms/u-boot/drivers/usb/gadget/max3420_udc.c
new file mode 100644
index 000000000..a16095f89
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/max3420_udc.c
@@ -0,0 +1,875 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+#include <linux/list.h>
+#include <linux/bitfield.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <spi.h>
+#include <dm.h>
+#include <g_dnl.h>
+
+#define MAX3420_MAX_EPS		4
+#define EP_MAX_PACKET		64  /* Same for all Endpoints */
+#define EPNAME_SIZE		16  /* Buffer size for endpoint name */
+
+#define MAX3420_SPI_DIR_RD	0	/* read register from MAX3420 */
+#define MAX3420_SPI_DIR_WR	1	/* write register to MAX3420 */
+
+/* SPI commands: */
+#define MAX3420_SPI_ACK_MASK BIT(0)
+#define MAX3420_SPI_DIR_MASK BIT(1)
+#define MAX3420_SPI_REG_MASK GENMASK(7, 3)
+
+#define MAX3420_REG_EP0FIFO	0
+#define MAX3420_REG_EP1FIFO	1
+#define MAX3420_REG_EP2FIFO	2
+#define MAX3420_REG_EP3FIFO	3
+#define MAX3420_REG_SUDFIFO	4
+#define MAX3420_REG_EP0BC	5
+#define MAX3420_REG_EP1BC	6
+#define MAX3420_REG_EP2BC	7
+#define MAX3420_REG_EP3BC	8
+
+#define MAX3420_REG_EPSTALLS	9
+	#define bACKSTAT	BIT(6)
+	#define bSTLSTAT	BIT(5)
+	#define bSTLEP3IN	BIT(4)
+	#define bSTLEP2IN	BIT(3)
+	#define bSTLEP1OUT	BIT(2)
+	#define bSTLEP0OUT	BIT(1)
+	#define bSTLEP0IN	BIT(0)
+
+#define MAX3420_REG_CLRTOGS	10
+	#define bEP3DISAB	BIT(7)
+	#define bEP2DISAB	BIT(6)
+	#define bEP1DISAB	BIT(5)
+	#define bCTGEP3IN	BIT(4)
+	#define bCTGEP2IN	BIT(3)
+	#define bCTGEP1OUT	BIT(2)
+
+#define MAX3420_REG_EPIRQ	11
+#define MAX3420_REG_EPIEN	12
+	#define bSUDAVIRQ	BIT(5)
+	#define bIN3BAVIRQ	BIT(4)
+	#define bIN2BAVIRQ	BIT(3)
+	#define bOUT1DAVIRQ	BIT(2)
+	#define bOUT0DAVIRQ	BIT(1)
+	#define bIN0BAVIRQ	BIT(0)
+
+#define MAX3420_REG_USBIRQ	13
+#define MAX3420_REG_USBIEN	14
+	#define bOSCOKIRQ	BIT(0)
+	#define bRWUDNIRQ	BIT(1)
+	#define bBUSACTIRQ	BIT(2)
+	#define bURESIRQ	BIT(3)
+	#define bSUSPIRQ	BIT(4)
+	#define bNOVBUSIRQ	BIT(5)
+	#define bVBUSIRQ	BIT(6)
+	#define bURESDNIRQ	BIT(7)
+
+#define MAX3420_REG_USBCTL	15
+	#define bHOSCSTEN	BIT(7)
+	#define bVBGATE		BIT(6)
+	#define bCHIPRES	BIT(5)
+	#define bPWRDOWN	BIT(4)
+	#define bCONNECT	BIT(3)
+	#define bSIGRWU		BIT(2)
+
+#define MAX3420_REG_CPUCTL	16
+	#define bIE		BIT(0)
+
+#define MAX3420_REG_PINCTL	17
+	#define bEP3INAK	BIT(7)
+	#define bEP2INAK	BIT(6)
+	#define bEP0INAK	BIT(5)
+	#define bFDUPSPI	BIT(4)
+	#define bINTLEVEL	BIT(3)
+	#define bPOSINT		BIT(2)
+	#define bGPXB		BIT(1)
+	#define bGPXA		BIT(0)
+
+#define MAX3420_REG_REVISION	18
+
+#define MAX3420_REG_FNADDR	19
+	#define FNADDR_MASK	0x7f
+
+#define MAX3420_REG_IOPINS	20
+#define MAX3420_REG_IOPINS2	21
+#define MAX3420_REG_GPINIRQ	22
+#define MAX3420_REG_GPINIEN	23
+#define MAX3420_REG_GPINPOL	24
+#define MAX3420_REG_HIRQ	25
+#define MAX3420_REG_HIEN	26
+#define MAX3420_REG_MODE	27
+#define MAX3420_REG_PERADDR	28
+#define MAX3420_REG_HCTL	29
+#define MAX3420_REG_HXFR	30
+#define MAX3420_REG_HRSL	31
+
+struct max3420_req {
+	struct usb_request usb_req;
+	struct list_head queue;
+	struct max3420_ep *ep;
+};
+
+struct max3420_ep {
+	struct max3420_udc *udc;
+	struct list_head queue;
+	char name[EPNAME_SIZE];
+	unsigned int maxpacket;
+	struct usb_ep ep_usb;
+	int halted;
+	int id;
+};
+
+struct max3420_udc {
+	struct max3420_ep ep[MAX3420_MAX_EPS];
+	struct usb_gadget_driver *driver;
+	bool softconnect;
+	struct usb_ctrlrequest setup;
+	struct max3420_req ep0req;
+	struct usb_gadget gadget;
+	struct spi_slave *slave;
+	struct udevice *dev;
+	u8 ep0buf[64];
+	int remote_wkp;
+	bool suspended;
+};
+
+#define to_max3420_req(r)	container_of((r), struct max3420_req, usb_req)
+#define to_max3420_ep(e)	container_of((e), struct max3420_ep, ep_usb)
+#define to_udc(g)		container_of((g), struct max3420_udc, gadget)
+
+static void spi_ack_ctrl(struct max3420_udc *udc)
+{
+	struct spi_slave *slave = udc->slave;
+	u8 txdata[1];
+
+	txdata[0] = FIELD_PREP(MAX3420_SPI_ACK_MASK, 1);
+	spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE);
+}
+
+static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int ackstat)
+{
+	struct spi_slave *slave = udc->slave;
+	u8 txdata[2], rxdata[2];
+
+	txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
+			FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD) |
+			FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0);
+
+	rxdata[0] = 0;
+	rxdata[1] = 0;
+	spi_xfer(slave, sizeof(txdata), txdata, rxdata, SPI_XFER_ONCE);
+
+	return rxdata[1];
+}
+
+static u8 spi_rd8(struct max3420_udc *udc, u8 reg)
+{
+	return spi_rd8_ack(udc, reg, 0);
+}
+
+static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int ackstat)
+{
+	struct spi_slave *slave = udc->slave;
+	u8 txdata[2];
+
+	txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
+			FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR) |
+			FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0);
+	txdata[1] = val;
+
+	spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE);
+}
+
+static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val)
+{
+	spi_wr8_ack(udc, reg, val, 0);
+}
+
+static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
+{
+	struct spi_slave *slave = udc->slave;
+	u8 txdata[1];
+
+	txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
+			FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD);
+
+	spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN);
+	spi_xfer(slave, len * 8, NULL, buf, SPI_XFER_END);
+}
+
+static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
+{
+	struct spi_slave *slave = udc->slave;
+	u8 txdata[1];
+
+	txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
+			FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR);
+
+	spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN);
+	spi_xfer(slave, len * 8, buf, NULL, SPI_XFER_END);
+}
+
+/* 0 if not-connected */
+int g_dnl_board_usb_cable_connected(void)
+{
+	return 1;
+}
+
+static void spi_max3420_enable(struct max3420_ep *ep, int enable)
+{
+	struct max3420_udc *udc = ep->udc;
+	u8 epdis, epien;
+
+	if (ep->id == 0)
+		return;
+
+	epien = spi_rd8(udc, MAX3420_REG_EPIEN);
+	epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS);
+
+	if (enable) {
+		epdis &= ~BIT(ep->id + 4);
+		epien |= BIT(ep->id + 1);
+	} else {
+		epdis |= BIT(ep->id + 4);
+		epien &= ~BIT(ep->id + 1);
+	}
+
+	spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis);
+	spi_wr8(udc, MAX3420_REG_EPIEN, epien);
+}
+
+static int
+max3420_ep_enable(struct usb_ep *_ep,
+		  const struct usb_endpoint_descriptor *desc)
+{
+	struct max3420_ep *ep = to_max3420_ep(_ep);
+
+	_ep->desc = desc;
+	_ep->maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
+
+	spi_max3420_enable(ep, 1);
+
+	return 0;
+}
+
+static void max3420_req_done(struct max3420_req *req, int status)
+{
+	struct max3420_ep *ep = req->ep;
+
+	if (req->usb_req.status == -EINPROGRESS)
+		req->usb_req.status = status;
+	else
+		status = req->usb_req.status;
+
+	if (status && status != -ESHUTDOWN)
+		dev_err(ep->udc->dev, "%s done %p, status %d\n",
+			ep->ep_usb.name, req, status);
+
+	if (req->usb_req.complete)
+		req->usb_req.complete(&ep->ep_usb, &req->usb_req);
+}
+
+static void max3420_ep_nuke(struct max3420_ep *ep, int status)
+{
+	struct max3420_req *req, *r;
+
+	list_for_each_entry_safe(req, r, &ep->queue, queue) {
+		list_del_init(&req->queue);
+		max3420_req_done(req, status);
+	}
+}
+
+static int max3420_ep_disable(struct usb_ep *_ep)
+{
+	struct max3420_ep *ep = to_max3420_ep(_ep);
+
+	_ep->desc = NULL;
+	max3420_ep_nuke(ep, -ESHUTDOWN);
+	spi_max3420_enable(ep, 0);
+
+	return 0;
+}
+
+static struct usb_request *
+max3420_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct max3420_ep *ep = to_max3420_ep(_ep);
+	struct max3420_req *req = kzalloc(sizeof(*req), gfp_flags);
+
+	if (!req)
+		return NULL;
+
+	req->ep = ep;
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->usb_req;
+}
+
+static void
+max3420_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	kfree(to_max3420_req(_req));
+}
+
+static int
+max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct max3420_req *req = to_max3420_req(_req);
+	struct max3420_ep *ep = to_max3420_ep(_ep);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+	list_add_tail(&req->queue, &ep->queue);
+
+	return 0;
+}
+
+static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct max3420_req *req = to_max3420_req(_req);
+
+	list_del_init(&req->queue);
+	max3420_req_done(req, -ECONNRESET);
+
+	return 0;
+}
+
+static int max3420_ep_set_halt(struct usb_ep *_ep, int halt)
+{
+	struct max3420_ep *ep = to_max3420_ep(_ep);
+	struct max3420_udc *udc = ep->udc;
+	u8 epstalls;
+
+	if (ep->id == 0) /* can't stall EP0 */
+		return 0;
+
+	epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS);
+	if (halt) {
+		ep->halted = 1;
+		epstalls |= BIT(ep->id + 1);
+	} else {
+		u8 clrtogs;
+
+		ep->halted = 0;
+		epstalls &= ~BIT(ep->id + 1);
+		clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS);
+		clrtogs |= BIT(ep->id + 1);
+		spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs);
+	}
+	spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | bACKSTAT);
+
+	return 0;
+}
+
+static const struct usb_ep_ops max3420_ep_ops = {
+	.enable		= max3420_ep_enable,
+	.disable	= max3420_ep_disable,
+	.alloc_request	= max3420_ep_alloc_request,
+	.free_request	= max3420_ep_free_request,
+	.queue		= max3420_ep_queue,
+	.dequeue	= max3420_ep_dequeue,
+	.set_halt	= max3420_ep_set_halt,
+};
+
+static void __max3420_stop(struct max3420_udc *udc)
+{
+	u8 val;
+
+	/* Disable IRQ to CPU */
+	spi_wr8(udc, MAX3420_REG_CPUCTL, 0);
+
+	val = spi_rd8(udc, MAX3420_REG_USBCTL);
+	val |= bPWRDOWN;
+	val |= bHOSCSTEN;
+	spi_wr8(udc, MAX3420_REG_USBCTL, val);
+}
+
+static void __max3420_start(struct max3420_udc *udc)
+{
+	u8 val;
+
+	/* configure SPI */
+	spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI);
+
+	/* Chip Reset */
+	spi_wr8(udc, MAX3420_REG_USBCTL, bCHIPRES);
+	mdelay(5);
+	spi_wr8(udc, MAX3420_REG_USBCTL, 0);
+
+	/* Poll for OSC to stabilize */
+	while (1) {
+		val = spi_rd8(udc, MAX3420_REG_USBIRQ);
+		if (val & bOSCOKIRQ)
+			break;
+		cond_resched();
+	}
+
+	/* Enable PULL-UP only when Vbus detected */
+	val = spi_rd8(udc, MAX3420_REG_USBCTL);
+	val |= bVBGATE | bCONNECT;
+	spi_wr8(udc, MAX3420_REG_USBCTL, val);
+
+	val = bURESDNIRQ | bURESIRQ;
+	spi_wr8(udc, MAX3420_REG_USBIEN, val);
+
+	/* Enable only EP0 interrupts */
+	val = bIN0BAVIRQ | bOUT0DAVIRQ | bSUDAVIRQ;
+	spi_wr8(udc, MAX3420_REG_EPIEN, val);
+
+	/* Enable IRQ to CPU */
+	spi_wr8(udc, MAX3420_REG_CPUCTL, bIE);
+}
+
+static int max3420_udc_start(struct usb_gadget *gadget,
+			     struct usb_gadget_driver *driver)
+{
+	struct max3420_udc *udc = to_udc(gadget);
+
+	udc->driver = driver;
+	udc->remote_wkp = 0;
+	udc->softconnect = true;
+
+	__max3420_start(udc);
+
+	return 0;
+}
+
+static int max3420_udc_stop(struct usb_gadget *gadget)
+{
+	struct max3420_udc *udc = to_udc(gadget);
+
+	udc->driver = NULL;
+	udc->softconnect = false;
+
+	__max3420_stop(udc);
+
+	return 0;
+}
+
+static int max3420_wakeup(struct usb_gadget *gadget)
+{
+	struct max3420_udc *udc = to_udc(gadget);
+	u8 usbctl;
+
+	/* Only if wakeup allowed by host */
+	if (!udc->remote_wkp || !udc->suspended)
+		return 0;
+
+	/* Set Remote-Wakeup Signal*/
+	usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
+	usbctl |= bSIGRWU;
+	spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
+
+	mdelay(5);
+
+	/* Clear Remote-WkUp Signal*/
+	usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
+	usbctl &= ~bSIGRWU;
+	spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
+
+	udc->suspended = false;
+
+	return 0;
+}
+
+static const struct usb_gadget_ops max3420_udc_ops = {
+	.udc_start	= max3420_udc_start,
+	.udc_stop	= max3420_udc_stop,
+	.wakeup		= max3420_wakeup,
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_OUT,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET),
+};
+
+static void max3420_getstatus(struct max3420_udc *udc)
+{
+	struct max3420_ep *ep;
+	u16 status = 0;
+
+	switch (udc->setup.bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		/* Get device status */
+		status = 0 << USB_DEVICE_SELF_POWERED;
+		status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP);
+		break;
+	case USB_RECIP_INTERFACE:
+		if (udc->driver->setup(&udc->gadget, &udc->setup) < 0)
+			goto stall;
+		break;
+	case USB_RECIP_ENDPOINT:
+		ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];
+		if (ep->halted)
+			status = 1 << USB_ENDPOINT_HALT;
+		break;
+	default:
+		goto stall;
+	}
+
+	status = cpu_to_le16(status);
+	spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2);
+	spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1);
+	return;
+stall:
+	dev_err(udc->dev, "Can't respond to getstatus request\n");
+	spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
+}
+
+static void max3420_set_clear_feature(struct max3420_udc *udc)
+{
+	int set = udc->setup.bRequest == USB_REQ_SET_FEATURE;
+	struct max3420_ep *ep;
+	int id;
+
+	switch (udc->setup.bRequestType) {
+	case USB_RECIP_DEVICE:
+		if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP)
+			break;
+
+		if (udc->setup.bRequest == USB_REQ_SET_FEATURE)
+			udc->remote_wkp = 1;
+		else
+			udc->remote_wkp = 0;
+
+		return spi_ack_ctrl(udc);
+
+	case USB_RECIP_ENDPOINT:
+		if (udc->setup.wValue != USB_ENDPOINT_HALT)
+			break;
+
+		id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[id];
+
+		max3420_ep_set_halt(&ep->ep_usb, set);
+		return;
+	default:
+		break;
+	}
+
+	dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n");
+	spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
+}
+
+static void max3420_handle_setup(struct max3420_udc *udc)
+{
+	struct usb_ctrlrequest setup;
+	u8 addr;
+
+	spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8);
+
+	udc->setup = setup;
+	udc->setup.wValue = cpu_to_le16(setup.wValue);
+	udc->setup.wIndex = cpu_to_le16(setup.wIndex);
+	udc->setup.wLength = cpu_to_le16(setup.wLength);
+
+	switch (udc->setup.bRequest) {
+	case USB_REQ_GET_STATUS:
+		/* Data+Status phase form udc */
+		if ((udc->setup.bRequestType &
+				(USB_DIR_IN | USB_TYPE_MASK)) !=
+				(USB_DIR_IN | USB_TYPE_STANDARD)) {
+			break;
+		}
+		return max3420_getstatus(udc);
+	case USB_REQ_SET_ADDRESS:
+		/* Status phase from udc */
+		if (udc->setup.bRequestType != (USB_DIR_OUT |
+				USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+			break;
+		addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1);
+		dev_dbg(udc->dev, "Assigned Address=%d/%d\n",
+			udc->setup.wValue, addr);
+		return;
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		/* Requests with no data phase, status phase from udc */
+		if ((udc->setup.bRequestType & USB_TYPE_MASK)
+				!= USB_TYPE_STANDARD)
+			break;
+		return max3420_set_clear_feature(udc);
+	default:
+		break;
+	}
+
+	if (udc->driver->setup(&udc->gadget, &setup) < 0) {
+		/* Stall EP0 */
+		spi_wr8(udc, MAX3420_REG_EPSTALLS,
+			bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
+	}
+}
+
+static int do_data(struct max3420_udc *udc, int ep_id, int in)
+{
+	struct max3420_ep *ep = &udc->ep[ep_id];
+	struct max3420_req *req;
+	int done, length, psz;
+	void *buf;
+
+	if (list_empty(&ep->queue))
+		return 0;
+
+	req = list_first_entry(&ep->queue, struct max3420_req, queue);
+	buf = req->usb_req.buf + req->usb_req.actual;
+
+	psz = ep->ep_usb.maxpacket;
+	length = req->usb_req.length - req->usb_req.actual;
+	length = min(length, psz);
+
+	if (length == 0) {
+		done = 1;
+		goto xfer_done;
+	}
+
+	done = 0;
+	if (in) {
+		spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
+		spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length);
+		if (length < psz)
+			done = 1;
+	} else {
+		psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id);
+		length = min(length, psz);
+		spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
+		if (length < ep->ep_usb.maxpacket)
+			done = 1;
+	}
+
+	req->usb_req.actual += length;
+
+	if (req->usb_req.actual == req->usb_req.length)
+		done = 1;
+
+xfer_done:
+	if (done) {
+		list_del_init(&req->queue);
+
+		if (ep_id == 0)
+			spi_ack_ctrl(udc);
+
+		max3420_req_done(req, 0);
+	}
+
+	return 1;
+}
+
+static int max3420_handle_irqs(struct max3420_udc *udc)
+{
+	u8 epien, epirq, usbirq, usbien, reg[4];
+	int ret = 0;
+
+	spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4);
+	epirq = reg[0];
+	epien = reg[1];
+	usbirq = reg[2];
+	usbien = reg[3];
+
+	usbirq &= usbien;
+	epirq &= epien;
+
+	if (epirq & bSUDAVIRQ) {
+		spi_wr8(udc, MAX3420_REG_EPIRQ, bSUDAVIRQ);
+		max3420_handle_setup(udc);
+		return 1;
+	}
+
+	if (usbirq & bVBUSIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bVBUSIRQ);
+		dev_dbg(udc->dev, "Cable plugged in\n");
+		g_dnl_clear_detach();
+		return 1;
+	}
+
+	if (usbirq & bNOVBUSIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bNOVBUSIRQ);
+		dev_dbg(udc->dev, "Cable pulled out\n");
+		g_dnl_trigger_detach();
+		return 1;
+	}
+
+	if (usbirq & bURESIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bURESIRQ);
+		return 1;
+	}
+
+	if (usbirq & bURESDNIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bURESDNIRQ);
+		spi_wr8(udc, MAX3420_REG_USBIEN, bURESDNIRQ | bURESIRQ);
+		spi_wr8(udc, MAX3420_REG_EPIEN, bSUDAVIRQ
+			| bIN0BAVIRQ | bOUT0DAVIRQ);
+		return 1;
+	}
+
+	if (usbirq & bSUSPIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bSUSPIRQ);
+		dev_dbg(udc->dev, "USB Suspend - Enter\n");
+		udc->suspended = true;
+		return 1;
+	}
+
+	if (usbirq & bBUSACTIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bBUSACTIRQ);
+		dev_dbg(udc->dev, "USB Suspend - Exit\n");
+		udc->suspended = false;
+		return 1;
+	}
+
+	if (usbirq & bRWUDNIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bRWUDNIRQ);
+		dev_dbg(udc->dev, "Asked Host to wakeup\n");
+		return 1;
+	}
+
+	if (usbirq & bOSCOKIRQ) {
+		spi_wr8(udc, MAX3420_REG_USBIRQ, bOSCOKIRQ);
+		dev_dbg(udc->dev, "Osc stabilized, start work\n");
+		return 1;
+	}
+
+	if (epirq & bOUT0DAVIRQ && do_data(udc, 0, 0)) {
+		spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT0DAVIRQ, 1);
+		ret = 1;
+	}
+
+	if (epirq & bIN0BAVIRQ && do_data(udc, 0, 1))
+		ret = 1;
+
+	if (epirq & bOUT1DAVIRQ && do_data(udc, 1, 0)) {
+		spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT1DAVIRQ, 1);
+		ret = 1;
+	}
+
+	if (epirq & bIN2BAVIRQ && do_data(udc, 2, 1))
+		ret = 1;
+
+	if (epirq & bIN3BAVIRQ && do_data(udc, 3, 1))
+		ret = 1;
+
+	return ret;
+}
+
+static int max3420_irq(struct max3420_udc *udc)
+{
+	do_data(udc, 0, 1); /* get done with the EP0 ZLP */
+
+	return max3420_handle_irqs(udc);
+}
+
+static void max3420_setup_eps(struct max3420_udc *udc)
+{
+	int i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->ep[0].ep_usb.ep_list);
+
+	for (i = 0; i < MAX3420_MAX_EPS; i++) {
+		struct max3420_ep *ep = &udc->ep[i];
+
+		INIT_LIST_HEAD(&ep->queue);
+
+		ep->id = i;
+		ep->udc = udc;
+		ep->ep_usb.ops = &max3420_ep_ops;
+		ep->ep_usb.name = ep->name;
+		ep->ep_usb.maxpacket = EP_MAX_PACKET;
+
+		if (i == 0) {
+			ep->ep_usb.desc = &ep0_desc;
+			snprintf(ep->name, EPNAME_SIZE, "ep0");
+			continue;
+		}
+
+		list_add_tail(&ep->ep_usb.ep_list, &udc->gadget.ep_list);
+
+		if (i == 1)
+			snprintf(ep->name, EPNAME_SIZE, "ep1out-bulk");
+		else
+			snprintf(ep->name, EPNAME_SIZE, "ep%din-bulk", i);
+	};
+}
+
+static void max3420_setup_spi(struct max3420_udc *udc)
+{
+	u8 reg[8];
+
+	spi_claim_bus(udc->slave);
+	spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
+	/* configure SPI */
+	spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI);
+}
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct max3420_udc *udc = dev_get_priv(dev);
+
+	return max3420_irq(udc);
+}
+
+static int max3420_udc_probe(struct udevice *dev)
+{
+	struct max3420_udc *udc = dev_get_priv(dev);
+	struct dm_spi_slave_plat *slave_pdata;
+	struct udevice *bus = dev->parent;
+	int busnum = dev_seq(bus);
+	unsigned int cs;
+	uint speed, mode;
+	struct udevice *spid;
+
+	slave_pdata = dev_get_parent_plat(dev);
+	cs = slave_pdata->cs;
+	speed = slave_pdata->max_hz;
+	mode = slave_pdata->mode;
+	spi_get_bus_and_cs(busnum, cs, speed, mode, "spi_generic_drv",
+			   NULL, &spid, &udc->slave);
+
+	udc->dev = dev;
+	udc->gadget.ep0 = &udc->ep[0].ep_usb;
+	udc->gadget.max_speed = USB_SPEED_FULL;
+	udc->gadget.speed = USB_SPEED_FULL;
+	udc->gadget.is_dualspeed = 0;
+	udc->gadget.ops = &max3420_udc_ops;
+	udc->gadget.name = "max3420-udc";
+
+	max3420_setup_eps(udc);
+	max3420_setup_spi(udc);
+
+	usb_add_gadget_udc((struct device *)dev, &udc->gadget);
+
+	return 0;
+}
+
+static int max3420_udc_remove(struct udevice *dev)
+{
+	struct max3420_udc *udc = dev_get_priv(dev);
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	spi_release_bus(udc->slave);
+
+	return 0;
+}
+
+static const struct udevice_id max3420_ids[] = {
+	{ .compatible = "maxim,max3421-udc" },
+	{ }
+};
+
+U_BOOT_DRIVER(max3420_generic_udc) = {
+	.name = "max3420-udc",
+	.id = UCLASS_USB_GADGET_GENERIC,
+	.of_match = max3420_ids,
+	.probe = max3420_udc_probe,
+	.remove = max3420_udc_remove,
+	.priv_auto	= sizeof(struct max3420_udc),
+};
diff --git a/roms/u-boot/drivers/usb/gadget/ndis.h b/roms/u-boot/drivers/usb/gadget/ndis.h
new file mode 100644
index 000000000..753838f79
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/ndis.h
@@ -0,0 +1,217 @@
+/*
+ * ndis.h
+ *
+ * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
+ *
+ * Thanks to the cygwin development team,
+ * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef _USBGADGET_NDIS_H
+#define _USBGADGET_NDIS_H
+
+
+#define NDIS_STATUS_MULTICAST_FULL        0xC0010009
+#define NDIS_STATUS_MULTICAST_EXISTS      0xC001000A
+#define NDIS_STATUS_MULTICAST_NOT_FOUND   0xC001000B
+
+enum NDIS_DEVICE_POWER_STATE {
+	NdisDeviceStateUnspecified = 0,
+	NdisDeviceStateD0,
+	NdisDeviceStateD1,
+	NdisDeviceStateD2,
+	NdisDeviceStateD3,
+	NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES {
+	enum NDIS_DEVICE_POWER_STATE  MinMagicPacketWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinPatternWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinLinkChangeWakeUp;
+};
+
+/* NDIS_PNP_CAPABILITIES.Flags constants */
+#define NDIS_DEVICE_WAKE_UP_ENABLE                0x00000001
+#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE  0x00000002
+#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE   0x00000004
+
+struct NDIS_PNP_CAPABILITIES {
+	__le32					Flags;
+	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
+};
+
+struct NDIS_PM_PACKET_PATTERN {
+	__le32	Priority;
+	__le32	Reserved;
+	__le32	MaskSize;
+	__le32	PatternOffset;
+	__le32	PatternSize;
+	__le32	PatternFlags;
+};
+
+
+/* Required Object IDs (OIDs) */
+#define OID_GEN_SUPPORTED_LIST            0x00010101
+#define OID_GEN_HARDWARE_STATUS           0x00010102
+#define OID_GEN_MEDIA_SUPPORTED           0x00010103
+#define OID_GEN_MEDIA_IN_USE              0x00010104
+#define OID_GEN_MAXIMUM_LOOKAHEAD         0x00010105
+#define OID_GEN_MAXIMUM_FRAME_SIZE        0x00010106
+#define OID_GEN_LINK_SPEED                0x00010107
+#define OID_GEN_TRANSMIT_BUFFER_SPACE     0x00010108
+#define OID_GEN_RECEIVE_BUFFER_SPACE      0x00010109
+#define OID_GEN_TRANSMIT_BLOCK_SIZE       0x0001010A
+#define OID_GEN_RECEIVE_BLOCK_SIZE        0x0001010B
+#define OID_GEN_VENDOR_ID                 0x0001010C
+#define OID_GEN_VENDOR_DESCRIPTION        0x0001010D
+#define OID_GEN_CURRENT_PACKET_FILTER     0x0001010E
+#define OID_GEN_CURRENT_LOOKAHEAD         0x0001010F
+#define OID_GEN_DRIVER_VERSION            0x00010110
+#define OID_GEN_MAXIMUM_TOTAL_SIZE        0x00010111
+#define OID_GEN_PROTOCOL_OPTIONS          0x00010112
+#define OID_GEN_MAC_OPTIONS               0x00010113
+#define OID_GEN_MEDIA_CONNECT_STATUS      0x00010114
+#define OID_GEN_MAXIMUM_SEND_PACKETS      0x00010115
+#define OID_GEN_VENDOR_DRIVER_VERSION     0x00010116
+#define OID_GEN_SUPPORTED_GUIDS           0x00010117
+#define OID_GEN_NETWORK_LAYER_ADDRESSES   0x00010118
+#define OID_GEN_TRANSPORT_HEADER_OFFSET   0x00010119
+#define OID_GEN_MACHINE_NAME              0x0001021A
+#define OID_GEN_RNDIS_CONFIG_PARAMETER    0x0001021B
+#define OID_GEN_VLAN_ID                   0x0001021C
+
+/* Optional OIDs */
+#define OID_GEN_MEDIA_CAPABILITIES        0x00010201
+#define OID_GEN_PHYSICAL_MEDIUM           0x00010202
+
+/* Required statistics OIDs */
+#define OID_GEN_XMIT_OK                   0x00020101
+#define OID_GEN_RCV_OK                    0x00020102
+#define OID_GEN_XMIT_ERROR                0x00020103
+#define OID_GEN_RCV_ERROR                 0x00020104
+#define OID_GEN_RCV_NO_BUFFER             0x00020105
+
+/* Optional statistics OIDs */
+#define OID_GEN_DIRECTED_BYTES_XMIT       0x00020201
+#define OID_GEN_DIRECTED_FRAMES_XMIT      0x00020202
+#define OID_GEN_MULTICAST_BYTES_XMIT      0x00020203
+#define OID_GEN_MULTICAST_FRAMES_XMIT     0x00020204
+#define OID_GEN_BROADCAST_BYTES_XMIT      0x00020205
+#define OID_GEN_BROADCAST_FRAMES_XMIT     0x00020206
+#define OID_GEN_DIRECTED_BYTES_RCV        0x00020207
+#define OID_GEN_DIRECTED_FRAMES_RCV       0x00020208
+#define OID_GEN_MULTICAST_BYTES_RCV       0x00020209
+#define OID_GEN_MULTICAST_FRAMES_RCV      0x0002020A
+#define OID_GEN_BROADCAST_BYTES_RCV       0x0002020B
+#define OID_GEN_BROADCAST_FRAMES_RCV      0x0002020C
+#define OID_GEN_RCV_CRC_ERROR             0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH     0x0002020E
+#define OID_GEN_GET_TIME_CAPS             0x0002020F
+#define OID_GEN_GET_NETCARD_TIME          0x00020210
+#define OID_GEN_NETCARD_LOAD              0x00020211
+#define OID_GEN_DEVICE_PROFILE            0x00020212
+#define OID_GEN_INIT_TIME_MS              0x00020213
+#define OID_GEN_RESET_COUNTS              0x00020214
+#define OID_GEN_MEDIA_SENSE_COUNTS        0x00020215
+#define OID_GEN_FRIENDLY_NAME             0x00020216
+#define OID_GEN_MINIPORT_INFO             0x00020217
+#define OID_GEN_RESET_VERIFY_PARAMETERS   0x00020218
+
+/* IEEE 802.3 (Ethernet) OIDs */
+#define NDIS_802_3_MAC_OPTION_PRIORITY    0x00000001
+
+#define OID_802_3_PERMANENT_ADDRESS       0x01010101
+#define OID_802_3_CURRENT_ADDRESS         0x01010102
+#define OID_802_3_MULTICAST_LIST          0x01010103
+#define OID_802_3_MAXIMUM_LIST_SIZE       0x01010104
+#define OID_802_3_MAC_OPTIONS             0x01010105
+#define OID_802_3_RCV_ERROR_ALIGNMENT     0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION      0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS    0x01020103
+#define OID_802_3_XMIT_DEFERRED           0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS     0x01020202
+#define OID_802_3_RCV_OVERRUN             0x01020203
+#define OID_802_3_XMIT_UNDERRUN           0x01020204
+#define OID_802_3_XMIT_HEARTBEAT_FAILURE  0x01020205
+#define OID_802_3_XMIT_TIMES_CRS_LOST     0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS    0x01020207
+
+/* OID_GEN_MINIPORT_INFO constants */
+#define NDIS_MINIPORT_BUS_MASTER                      0x00000001
+#define NDIS_MINIPORT_WDM_DRIVER                      0x00000002
+#define NDIS_MINIPORT_SG_LIST                         0x00000004
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY            0x00000008
+#define NDIS_MINIPORT_INDICATES_PACKETS               0x00000010
+#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE             0x00000020
+#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE            0x00000040
+#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS        0x00000080
+#define NDIS_MINIPORT_INTERMEDIATE_DRIVER             0x00000100
+#define NDIS_MINIPORT_IS_NDIS_5                       0x00000200
+#define NDIS_MINIPORT_IS_CO                           0x00000400
+#define NDIS_MINIPORT_DESERIALIZE                     0x00000800
+#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING          0x00001000
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE            0x00002000
+#define NDIS_MINIPORT_NETBOOT_CARD                    0x00004000
+#define NDIS_MINIPORT_PM_SUPPORTED                    0x00008000
+#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE  0x00010000
+#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS           0x00020000
+#define NDIS_MINIPORT_HIDDEN                          0x00040000
+#define NDIS_MINIPORT_SWENUM                          0x00080000
+#define NDIS_MINIPORT_SURPRISE_REMOVE_OK              0x00100000
+#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND              0x00200000
+#define NDIS_MINIPORT_HARDWARE_DEVICE                 0x00400000
+#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS    0x00800000
+#define NDIS_MINIPORT_64BITS_DMA                      0x01000000
+
+#define NDIS_MEDIUM_802_3		0x00000000
+#define NDIS_MEDIUM_802_5		0x00000001
+#define NDIS_MEDIUM_FDDI		0x00000002
+#define NDIS_MEDIUM_WAN			0x00000003
+#define NDIS_MEDIUM_LOCAL_TALK		0x00000004
+#define NDIS_MEDIUM_DIX			0x00000005
+#define NDIS_MEDIUM_ARCENT_RAW		0x00000006
+#define NDIS_MEDIUM_ARCENT_878_2	0x00000007
+#define NDIS_MEDIUM_ATM			0x00000008
+#define NDIS_MEDIUM_WIRELESS_LAN	0x00000009
+#define NDIS_MEDIUM_IRDA		0x0000000A
+#define NDIS_MEDIUM_BPC			0x0000000B
+#define NDIS_MEDIUM_CO_WAN		0x0000000C
+#define NDIS_MEDIUM_1394		0x0000000D
+
+#define NDIS_PACKET_TYPE_DIRECTED	0x00000001
+#define NDIS_PACKET_TYPE_MULTICAST	0x00000002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST	0x00000004
+#define NDIS_PACKET_TYPE_BROADCAST	0x00000008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING	0x00000010
+#define NDIS_PACKET_TYPE_PROMISCUOUS	0x00000020
+#define NDIS_PACKET_TYPE_SMT		0x00000040
+#define NDIS_PACKET_TYPE_ALL_LOCAL	0x00000080
+#define NDIS_PACKET_TYPE_GROUP		0x00000100
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL	0x00000200
+#define NDIS_PACKET_TYPE_FUNCTIONAL	0x00000400
+#define NDIS_PACKET_TYPE_MAC_FRAME	0x00000800
+
+#define NDIS_MEDIA_STATE_CONNECTED	0x00000000
+#define NDIS_MEDIA_STATE_DISCONNECTED	0x00000001
+
+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA     0x00000001
+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED      0x00000002
+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND      0x00000004
+#define NDIS_MAC_OPTION_NO_LOOPBACK             0x00000008
+#define NDIS_MAC_OPTION_FULL_DUPLEX             0x00000010
+#define NDIS_MAC_OPTION_EOTX_INDICATION         0x00000020
+#define NDIS_MAC_OPTION_8021P_PRIORITY          0x00000040
+#define NDIS_MAC_OPTION_RESERVED                0x80000000
+
+#endif /* _USBGADGET_NDIS_H */
diff --git a/roms/u-boot/drivers/usb/gadget/pxa25x_udc.c b/roms/u-boot/drivers/usb/gadget/pxa25x_udc.c
new file mode 100644
index 000000000..d19ac1d03
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/pxa25x_udc.c
@@ -0,0 +1,2049 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
+ * Copyright (C) 2003 Robert Schwebel, Pengutronix
+ * Copyright (C) 2003 Benedikt Spranger, Pengutronix
+ * Copyright (C) 2003 David Brownell
+ * Copyright (C) 2003 Joshua Wise
+ * Copyright (C) 2012 Lukasz Dalek <luk0104@gmail.com>
+ *
+ * MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");
+ */
+
+#define CONFIG_USB_PXA25X_SMALL
+#define DRIVER_NAME "pxa25x_udc_linux"
+#define ARCH_HAS_PREFETCH
+
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <asm/unaligned.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/compat.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/arch/pxa.h>
+#include <linux/delay.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "pxa25x_udc.h"
+
+/*
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
+ * series processors.  The UDC for the IXP 4xx series is very similar.
+ * There are fifteen endpoints, in addition to ep0.
+ *
+ * Such controller drivers work with a gadget driver.  The gadget driver
+ * returns descriptors, implements configuration and data protocols used
+ * by the host to interact with this device, and allocates endpoints to
+ * the different protocol interfaces.  The controller driver virtualizes
+ * usb hardware so that the gadget drivers will be more portable.
+ *
+ * This UDC hardware wants to implement a bit too much USB protocol, so
+ * it constrains the sorts of USB configuration change events that work.
+ * The errata for these chips are misleading; some "fixed" bugs from
+ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
+ *
+ * Note that the UDC hardware supports DMA (except on IXP) but that's
+ * not used here.  IN-DMA (to host) is simple enough, when the data is
+ * suitably aligned (16 bytes) ... the network stack doesn't do that,
+ * other software can.  OUT-DMA is buggy in most chip versions, as well
+ * as poorly designed (data toggle not automatic).  So this driver won't
+ * bother using DMA.  (Mostly-working IN-DMA support was available in
+ * kernels before 2.6.23, but was never enabled or well tested.)
+ */
+
+#define DRIVER_VERSION	"18-August-2012"
+#define DRIVER_DESC	"PXA 25x USB Device Controller driver"
+
+static const char driver_name[] = "pxa25x_udc";
+static const char ep0name[] = "ep0";
+
+/* Watchdog */
+static inline void start_watchdog(struct pxa25x_udc *udc)
+{
+	debug("Started watchdog\n");
+	udc->watchdog.base = get_timer(0);
+	udc->watchdog.running = 1;
+}
+
+static inline void stop_watchdog(struct pxa25x_udc *udc)
+{
+	udc->watchdog.running = 0;
+	debug("Stopped watchdog\n");
+}
+
+static inline void test_watchdog(struct pxa25x_udc *udc)
+{
+	if (!udc->watchdog.running)
+		return;
+
+	debug("watchdog %ld %ld\n", get_timer(udc->watchdog.base),
+		udc->watchdog.period);
+
+	if (get_timer(udc->watchdog.base) >= udc->watchdog.period) {
+		stop_watchdog(udc);
+		udc->watchdog.function(udc);
+	}
+}
+
+static void udc_watchdog(struct pxa25x_udc *dev)
+{
+	uint32_t udccs0 = readl(&dev->regs->udccs[0]);
+
+	debug("Fired up udc_watchdog\n");
+
+	local_irq_disable();
+	if (dev->ep0state == EP0_STALL
+			&& (udccs0 & UDCCS0_FST) == 0
+			&& (udccs0 & UDCCS0_SST) == 0) {
+		writel(UDCCS0_FST|UDCCS0_FTF, &dev->regs->udccs[0]);
+		debug("ep0 re-stall\n");
+		start_watchdog(dev);
+	}
+	local_irq_enable();
+}
+
+#ifdef DEBUG
+
+static const char * const state_name[] = {
+	"EP0_IDLE",
+	"EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
+	"EP0_END_XFER", "EP0_STALL"
+};
+
+static void
+dump_udccr(const char *label)
+{
+	u32 udccr = readl(&UDC_REGS->udccr);
+	debug("%s %02X =%s%s%s%s%s%s%s%s\n",
+		label, udccr,
+		(udccr & UDCCR_REM) ? " rem" : "",
+		(udccr & UDCCR_RSTIR) ? " rstir" : "",
+		(udccr & UDCCR_SRM) ? " srm" : "",
+		(udccr & UDCCR_SUSIR) ? " susir" : "",
+		(udccr & UDCCR_RESIR) ? " resir" : "",
+		(udccr & UDCCR_RSM) ? " rsm" : "",
+		(udccr & UDCCR_UDA) ? " uda" : "",
+		(udccr & UDCCR_UDE) ? " ude" : "");
+}
+
+static void
+dump_udccs0(const char *label)
+{
+	u32 udccs0 = readl(&UDC_REGS->udccs[0]);
+
+	debug("%s %s %02X =%s%s%s%s%s%s%s%s\n",
+		label, state_name[the_controller->ep0state], udccs0,
+		(udccs0 & UDCCS0_SA) ? " sa" : "",
+		(udccs0 & UDCCS0_RNE) ? " rne" : "",
+		(udccs0 & UDCCS0_FST) ? " fst" : "",
+		(udccs0 & UDCCS0_SST) ? " sst" : "",
+		(udccs0 & UDCCS0_DRWF) ? " dwrf" : "",
+		(udccs0 & UDCCS0_FTF) ? " ftf" : "",
+		(udccs0 & UDCCS0_IPR) ? " ipr" : "",
+		(udccs0 & UDCCS0_OPR) ? " opr" : "");
+}
+
+static void
+dump_state(struct pxa25x_udc *dev)
+{
+	u32 tmp;
+	unsigned i;
+
+	debug("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+		state_name[dev->ep0state],
+		readl(&UDC_REGS->uicr1), readl(&UDC_REGS->uicr0),
+		readl(&UDC_REGS->usir1), readl(&UDC_REGS->usir0),
+		readl(&UDC_REGS->ufnrh), readl(&UDC_REGS->ufnrl));
+	dump_udccr("udccr");
+	if (dev->has_cfr) {
+		tmp = readl(&UDC_REGS->udccfr);
+		debug("udccfr %02X =%s%s\n", tmp,
+			(tmp & UDCCFR_AREN) ? " aren" : "",
+			(tmp & UDCCFR_ACM) ? " acm" : "");
+	}
+
+	if (!dev->driver) {
+		debug("no gadget driver bound\n");
+		return;
+	} else
+		debug("ep0 driver '%s'\n", "ether");
+
+	dump_udccs0("udccs0");
+	debug("ep0 IN %lu/%lu, OUT %lu/%lu\n",
+		dev->stats.write.bytes, dev->stats.write.ops,
+		dev->stats.read.bytes, dev->stats.read.ops);
+
+	for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+		if (dev->ep[i].desc == NULL)
+			continue;
+		debug("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
+	}
+}
+
+#else /* DEBUG */
+
+static inline void dump_udccr(const char *label) { }
+static inline void dump_udccs0(const char *label) { }
+static inline void dump_state(struct pxa25x_udc *dev) { }
+
+#endif /* DEBUG */
+
+/*
+ * ---------------------------------------------------------------------------
+ *	endpoint related parts of the api to the usb controller hardware,
+ *	used by gadget driver; and the inner talker-to-hardware core.
+ * ---------------------------------------------------------------------------
+ */
+
+static void pxa25x_ep_fifo_flush(struct usb_ep *ep);
+static void nuke(struct pxa25x_ep *, int status);
+
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static void pullup_off(void)
+{
+	struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+	if (mach->udc_command)
+		mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+static void pullup_on(void)
+{
+	struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+	if (mach->udc_command)
+		mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
+static void pio_irq_enable(int bEndpointAddress)
+{
+	bEndpointAddress &= 0xf;
+	if (bEndpointAddress < 8) {
+		clrbits_le32(&the_controller->regs->uicr0,
+			1 << bEndpointAddress);
+	} else {
+		bEndpointAddress -= 8;
+		clrbits_le32(&the_controller->regs->uicr1,
+			1 << bEndpointAddress);
+	}
+}
+
+static void pio_irq_disable(int bEndpointAddress)
+{
+	bEndpointAddress &= 0xf;
+	if (bEndpointAddress < 8) {
+		setbits_le32(&the_controller->regs->uicr0,
+			1 << bEndpointAddress);
+	} else {
+		bEndpointAddress -= 8;
+		setbits_le32(&the_controller->regs->uicr1,
+			1 << bEndpointAddress);
+	}
+}
+
+static inline void udc_set_mask_UDCCR(int mask)
+{
+	/*
+	 * The UDCCR reg contains mask and interrupt status bits,
+	 * so using '|=' isn't safe as it may ack an interrupt.
+	 */
+	const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE;
+
+	mask &= mask_bits;
+	clrsetbits_le32(&the_controller->regs->udccr, ~mask_bits, mask);
+}
+
+static inline void udc_clear_mask_UDCCR(int mask)
+{
+	const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE;
+
+	mask = ~mask & mask_bits;
+	clrbits_le32(&the_controller->regs->udccr, ~mask);
+}
+
+static inline void udc_ack_int_UDCCR(int mask)
+{
+	const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE;
+
+	mask &= ~mask_bits;
+	clrsetbits_le32(&the_controller->regs->udccr, ~mask_bits, mask);
+}
+
+/*
+ * endpoint enable/disable
+ *
+ * we need to verify the descriptors used to enable endpoints.  since pxa25x
+ * endpoint configurations are fixed, and are pretty much always enabled,
+ * there's not a lot to manage here.
+ *
+ * because pxa25x can't selectively initialize bulk (or interrupt) endpoints,
+ * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except
+ * for a single interface (with only the default altsetting) and for gadget
+ * drivers that don't halt endpoints (not reset by set_interface).  that also
+ * means that if you use ISO, you must violate the USB spec rule that all
+ * iso endpoints must be in non-default altsettings.
+ */
+static int pxa25x_ep_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct pxa25x_ep *ep;
+	struct pxa25x_udc *dev;
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| ep->bEndpointAddress != desc->bEndpointAddress
+			|| ep->fifo_size <
+			   le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) {
+		printf("%s, bad ep or descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	/* xfer types must match, except that interrupt ~= bulk */
+	if (ep->bmAttributes != desc->bmAttributes
+			&& ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+			&& desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+		printf("%s, %s type mismatch\n", __func__, _ep->name);
+		return -EINVAL;
+	}
+
+	/* hardware _could_ do smaller, but driver doesn't */
+	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+			&& le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))
+						!= BULK_FIFO_SIZE)
+			|| !get_unaligned(&desc->wMaxPacketSize)) {
+		printf("%s, bad %s maxpacket\n", __func__, _ep->name);
+		return -ERANGE;
+	}
+
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+		printf("%s, bogus device state\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+	ep->pio_irqs = 0;
+	ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+
+	/* flush fifo (mostly for OUT buffers) */
+	pxa25x_ep_fifo_flush(_ep);
+
+	/* ... reset halt state too, if we could ... */
+
+	debug("enabled %s\n", _ep->name);
+	return 0;
+}
+
+static int pxa25x_ep_disable(struct usb_ep *_ep)
+{
+	struct pxa25x_ep *ep;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (!_ep || !ep->desc) {
+		printf("%s, %s not enabled\n", __func__,
+			_ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+	local_irq_save(flags);
+
+	nuke(ep, -ESHUTDOWN);
+
+	/* flush fifo (mostly for IN buffers) */
+	pxa25x_ep_fifo_flush(_ep);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	local_irq_restore(flags);
+	debug("%s disabled\n", _ep->name);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * for the pxa25x, these can just wrap kmalloc/kfree.  gadget drivers
+ * must still pass correctly initialized endpoints, since other controller
+ * drivers may care about how it's currently set up (dma issues etc).
+ */
+
+/*
+ *	pxa25x_ep_alloc_request - allocate a request data structure
+ */
+static struct usb_request *
+pxa25x_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct pxa25x_request *req;
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+
+/*
+ *	pxa25x_ep_free_request - deallocate a request data structure
+ */
+static void
+pxa25x_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct pxa25x_request	*req;
+
+	req = container_of(_req, struct pxa25x_request, req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ *	done - retire a request; caller blocked irqs
+ */
+static void done(struct pxa25x_ep *ep, struct pxa25x_request *req, int status)
+{
+	unsigned stopped = ep->stopped;
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	if (status && status != -ESHUTDOWN)
+		debug("complete %s req %p stat %d len %u/%u\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->stopped = stopped;
+}
+
+
+static inline void ep0_idle(struct pxa25x_udc *dev)
+{
+	dev->ep0state = EP0_IDLE;
+}
+
+static int
+write_packet(u32 *uddr, struct pxa25x_request *req, unsigned max)
+{
+	u8 *buf;
+	unsigned length, count;
+
+	debug("%s(): uddr %p\n", __func__, uddr);
+
+	buf = req->req.buf + req->req.actual;
+	prefetch(buf);
+
+	/* how big will this packet be? */
+	length = min(req->req.length - req->req.actual, max);
+	req->req.actual += length;
+
+	count = length;
+	while (likely(count--))
+		writeb(*buf++, uddr);
+
+	return length;
+}
+
+/*
+ * write to an IN endpoint fifo, as many packets as possible.
+ * irqs will use this to write the rest later.
+ * caller guarantees at least one packet buffer is ready (or a zlp).
+ */
+static int
+write_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req)
+{
+	unsigned max;
+
+	max = le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize));
+	do {
+		unsigned count;
+		int is_last, is_short;
+
+		count = write_packet(ep->reg_uddr, req, max);
+
+		/* last packet is usually short (or a zlp) */
+		if (unlikely(count != max))
+			is_last = is_short = 1;
+		else {
+			if (likely(req->req.length != req->req.actual)
+					|| req->req.zero)
+				is_last = 0;
+			else
+				is_last = 1;
+			/* interrupt/iso maxpacket may not fill the fifo */
+			is_short = unlikely(max < ep->fifo_size);
+		}
+
+		debug_cond(NOISY, "wrote %s %d bytes%s%s %d left %p\n",
+			ep->ep.name, count,
+			is_last ? "/L" : "", is_short ? "/S" : "",
+			req->req.length - req->req.actual, req);
+
+		/*
+		 * let loose that packet. maybe try writing another one,
+		 * double buffering might work.  TSP, TPC, and TFS
+		 * bit values are the same for all normal IN endpoints.
+		 */
+		writel(UDCCS_BI_TPC, ep->reg_udccs);
+		if (is_short)
+			writel(UDCCS_BI_TSP, ep->reg_udccs);
+
+		/* requests complete when all IN data is in the FIFO */
+		if (is_last) {
+			done(ep, req, 0);
+			if (list_empty(&ep->queue))
+				pio_irq_disable(ep->bEndpointAddress);
+			return 1;
+		}
+
+		/*
+		 * TODO experiment: how robust can fifo mode tweaking be?
+		 * double buffering is off in the default fifo mode, which
+		 * prevents TFS from being set here.
+		 */
+
+	} while (readl(ep->reg_udccs) & UDCCS_BI_TFS);
+	return 0;
+}
+
+/*
+ * caller asserts req->pending (ep0 irq status nyet cleared); starts
+ * ep0 data stage.  these chips want very simple state transitions.
+ */
+static inline
+void ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag)
+{
+	writel(flags|UDCCS0_SA|UDCCS0_OPR, &dev->regs->udccs[0]);
+	writel(USIR0_IR0, &dev->regs->usir0);
+	dev->req_pending = 0;
+	debug_cond(NOISY, "%s() %s, udccs0: %02x/%02x usir: %X.%X\n",
+		__func__, tag, readl(&dev->regs->udccs[0]), flags,
+		readl(&dev->regs->usir1), readl(&dev->regs->usir0));
+}
+
+static int
+write_ep0_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req)
+{
+	unsigned count;
+	int is_short;
+
+	count = write_packet(&ep->dev->regs->uddr0, req, EP0_FIFO_SIZE);
+	ep->dev->stats.write.bytes += count;
+
+	/* last packet "must be" short (or a zlp) */
+	is_short = (count != EP0_FIFO_SIZE);
+
+	debug_cond(NOISY, "ep0in %d bytes %d left %p\n", count,
+		req->req.length - req->req.actual, req);
+
+	if (unlikely(is_short)) {
+		if (ep->dev->req_pending)
+			ep0start(ep->dev, UDCCS0_IPR, "short IN");
+		else
+			writel(UDCCS0_IPR, &ep->dev->regs->udccs[0]);
+
+		count = req->req.length;
+		done(ep, req, 0);
+		ep0_idle(ep->dev);
+
+		/*
+		 * This seems to get rid of lost status irqs in some cases:
+		 * host responds quickly, or next request involves config
+		 * change automagic, or should have been hidden, or ...
+		 *
+		 * FIXME get rid of all udelays possible...
+		 */
+		if (count >= EP0_FIFO_SIZE) {
+			count = 100;
+			do {
+				if ((readl(&ep->dev->regs->udccs[0]) &
+				     UDCCS0_OPR) != 0) {
+					/* clear OPR, generate ack */
+					writel(UDCCS0_OPR,
+						&ep->dev->regs->udccs[0]);
+					break;
+				}
+				count--;
+				udelay(1);
+			} while (count);
+		}
+	} else if (ep->dev->req_pending)
+		ep0start(ep->dev, 0, "IN");
+
+	return is_short;
+}
+
+
+/*
+ * read_fifo -  unload packet(s) from the fifo we use for usb OUT
+ * transfers and put them into the request.  caller should have made
+ * sure there's at least one packet ready.
+ *
+ * returns true if the request completed because of short packet or the
+ * request buffer having filled (and maybe overran till end-of-packet).
+ */
+static int
+read_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req)
+{
+	u32 udccs;
+	u8 *buf;
+	unsigned bufferspace, count, is_short;
+
+	for (;;) {
+		/*
+		 * make sure there's a packet in the FIFO.
+		 * UDCCS_{BO,IO}_RPC are all the same bit value.
+		 * UDCCS_{BO,IO}_RNE are all the same bit value.
+		 */
+		udccs = readl(ep->reg_udccs);
+		if (unlikely((udccs & UDCCS_BO_RPC) == 0))
+			break;
+		buf = req->req.buf + req->req.actual;
+		prefetchw(buf);
+		bufferspace = req->req.length - req->req.actual;
+
+		/* read all bytes from this packet */
+		if (likely(udccs & UDCCS_BO_RNE)) {
+			count = 1 + (0x0ff & readl(ep->reg_ubcr));
+			req->req.actual += min(count, bufferspace);
+		} else /* zlp */
+			count = 0;
+		is_short = (count < ep->ep.maxpacket);
+		debug_cond(NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n",
+			ep->ep.name, udccs, count,
+			is_short ? "/S" : "",
+			req, req->req.actual, req->req.length);
+		while (likely(count-- != 0)) {
+			u8 byte = readb(ep->reg_uddr);
+
+			if (unlikely(bufferspace == 0)) {
+				/*
+				 * this happens when the driver's buffer
+				 * is smaller than what the host sent.
+				 * discard the extra data.
+				 */
+				if (req->req.status != -EOVERFLOW)
+					printf("%s overflow %d\n",
+						ep->ep.name, count);
+				req->req.status = -EOVERFLOW;
+			} else {
+				*buf++ = byte;
+				bufferspace--;
+			}
+		}
+		writel(UDCCS_BO_RPC, ep->reg_udccs);
+		/* RPC/RSP/RNE could now reflect the other packet buffer */
+
+		/* iso is one request per packet */
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+			if (udccs & UDCCS_IO_ROF)
+				req->req.status = -EHOSTUNREACH;
+			/* more like "is_done" */
+			is_short = 1;
+		}
+
+		/* completion */
+		if (is_short || req->req.actual == req->req.length) {
+			done(ep, req, 0);
+			if (list_empty(&ep->queue))
+				pio_irq_disable(ep->bEndpointAddress);
+			return 1;
+		}
+
+		/* finished that packet.  the next one may be waiting... */
+	}
+	return 0;
+}
+
+/*
+ * special ep0 version of the above.  no UBCR0 or double buffering; status
+ * handshaking is magic.  most device protocols don't need control-OUT.
+ * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other
+ * protocols do use them.
+ */
+static int
+read_ep0_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req)
+{
+	u8 *buf, byte;
+	unsigned bufferspace;
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+
+	while (readl(&ep->dev->regs->udccs[0]) & UDCCS0_RNE) {
+		byte = (u8)readb(&ep->dev->regs->uddr0);
+
+		if (unlikely(bufferspace == 0)) {
+			/*
+			 * this happens when the driver's buffer
+			 * is smaller than what the host sent.
+			 * discard the extra data.
+			 */
+			if (req->req.status != -EOVERFLOW)
+				printf("%s overflow\n", ep->ep.name);
+			req->req.status = -EOVERFLOW;
+		} else {
+			*buf++ = byte;
+			req->req.actual++;
+			bufferspace--;
+		}
+	}
+
+	writel(UDCCS0_OPR | UDCCS0_IPR, &ep->dev->regs->udccs[0]);
+
+	/* completion */
+	if (req->req.actual >= req->req.length)
+		return 1;
+
+	/* finished that packet.  the next one may be waiting... */
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct pxa25x_request *req;
+	struct pxa25x_ep *ep;
+	struct pxa25x_udc *dev;
+	unsigned long flags;
+
+	req = container_of(_req, struct pxa25x_request, req);
+	if (unlikely(!_req || !_req->complete || !_req->buf
+			|| !list_empty(&req->queue))) {
+		printf("%s, bad params\n", __func__);
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		printf("%s, bad ep\n", __func__);
+		return -EINVAL;
+	}
+
+	dev = ep->dev;
+	if (unlikely(!dev->driver
+			|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+		printf("%s, bogus device state\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	/*
+	 * iso is always one packet per request, that's the only way
+	 * we can report per-packet status.  that also helps with dma.
+	 */
+	if (unlikely(ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
+			&& req->req.length >
+			le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize))))
+		return -EMSGSIZE;
+
+	debug_cond(NOISY, "%s queue req %p, len %d buf %p\n",
+		_ep->name, _req, _req->length, _req->buf);
+
+	local_irq_save(flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* kickstart this i/o queue? */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		if (ep->desc == NULL/* ep0 */) {
+			unsigned length = _req->length;
+
+			switch (dev->ep0state) {
+			case EP0_IN_DATA_PHASE:
+				dev->stats.write.ops++;
+				if (write_ep0_fifo(ep, req))
+					req = NULL;
+				break;
+
+			case EP0_OUT_DATA_PHASE:
+				dev->stats.read.ops++;
+				/* messy ... */
+				if (dev->req_config) {
+					debug("ep0 config ack%s\n",
+						dev->has_cfr ?  "" : " raced");
+					if (dev->has_cfr)
+						writel(UDCCFR_AREN|UDCCFR_ACM
+							|UDCCFR_MB1,
+							&ep->dev->regs->udccfr);
+					done(ep, req, 0);
+					dev->ep0state = EP0_END_XFER;
+					local_irq_restore(flags);
+					return 0;
+				}
+				if (dev->req_pending)
+					ep0start(dev, UDCCS0_IPR, "OUT");
+				if (length == 0 ||
+						((readl(
+						&ep->dev->regs->udccs[0])
+						& UDCCS0_RNE) != 0
+						&& read_ep0_fifo(ep, req))) {
+					ep0_idle(dev);
+					done(ep, req, 0);
+					req = NULL;
+				}
+				break;
+
+			default:
+				printf("ep0 i/o, odd state %d\n",
+					dev->ep0state);
+				local_irq_restore(flags);
+				return -EL2HLT;
+			}
+		/* can the FIFO can satisfy the request immediately? */
+		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+			if ((readl(ep->reg_udccs) & UDCCS_BI_TFS) != 0
+					&& write_fifo(ep, req))
+				req = NULL;
+		} else if ((readl(ep->reg_udccs) & UDCCS_BO_RFS) != 0
+				&& read_fifo(ep, req)) {
+			req = NULL;
+		}
+
+		if (likely(req && ep->desc))
+			pio_irq_enable(ep->bEndpointAddress);
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely(req != NULL))
+		list_add_tail(&req->queue, &ep->queue);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+
+/*
+ *	nuke - dequeue ALL requests
+ */
+static void nuke(struct pxa25x_ep *ep, int status)
+{
+	struct pxa25x_request *req;
+
+	/* called with irqs blocked */
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+				struct pxa25x_request,
+				queue);
+		done(ep, req, status);
+	}
+	if (ep->desc)
+		pio_irq_disable(ep->bEndpointAddress);
+}
+
+
+/* dequeue JUST ONE request */
+static int pxa25x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct pxa25x_ep *ep;
+	struct pxa25x_request *req;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		local_irq_restore(flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct pxa25x_ep *ep;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (unlikely(!_ep
+			|| (!ep->desc && ep->ep.name != ep0name))
+			|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+		printf("%s, bad ep\n", __func__);
+		return -EINVAL;
+	}
+	if (value == 0) {
+		/*
+		 * this path (reset toggle+halt) is needed to implement
+		 * SET_INTERFACE on normal hardware.  but it can't be
+		 * done from software on the PXA UDC, and the hardware
+		 * forgets to do it as part of SET_INTERFACE automagic.
+		 */
+		printf("only host can clear %s halt\n", _ep->name);
+		return -EROFS;
+	}
+
+	local_irq_save(flags);
+
+	if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+			&& ((readl(ep->reg_udccs) & UDCCS_BI_TFS) == 0
+			   || !list_empty(&ep->queue))) {
+		local_irq_restore(flags);
+		return -EAGAIN;
+	}
+
+	/* FST bit is the same for control, bulk in, bulk out, interrupt in */
+	writel(UDCCS_BI_FST|UDCCS_BI_FTF, ep->reg_udccs);
+
+	/* ep0 needs special care */
+	if (!ep->desc) {
+		start_watchdog(ep->dev);
+		ep->dev->req_pending = 0;
+		ep->dev->ep0state = EP0_STALL;
+
+	/* and bulk/intr endpoints like dropping stalls too */
+	} else {
+		unsigned i;
+		for (i = 0; i < 1000; i += 20) {
+			if (readl(ep->reg_udccs) & UDCCS_BI_SST)
+				break;
+			udelay(20);
+		}
+	}
+	local_irq_restore(flags);
+
+	debug("%s halt\n", _ep->name);
+	return 0;
+}
+
+static int pxa25x_ep_fifo_status(struct usb_ep *_ep)
+{
+	struct pxa25x_ep        *ep;
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (!_ep) {
+		printf("%s, bad ep\n", __func__);
+		return -ENODEV;
+	}
+	/* pxa can't report unclaimed bytes from IN fifos */
+	if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
+		return -EOPNOTSUPP;
+	if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN
+			|| (readl(ep->reg_udccs) & UDCCS_BO_RFS) == 0)
+		return 0;
+	else
+		return (readl(ep->reg_ubcr) & 0xfff) + 1;
+}
+
+static void pxa25x_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct pxa25x_ep        *ep;
+
+	ep = container_of(_ep, struct pxa25x_ep, ep);
+	if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) {
+		printf("%s, bad ep\n", __func__);
+		return;
+	}
+
+	/* toggle and halt bits stay unchanged */
+
+	/* for OUT, just read and discard the FIFO contents. */
+	if ((ep->bEndpointAddress & USB_DIR_IN) == 0) {
+		while (((readl(ep->reg_udccs)) & UDCCS_BO_RNE) != 0)
+			(void)readb(ep->reg_uddr);
+		return;
+	}
+
+	/* most IN status is the same, but ISO can't stall */
+	writel(UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR
+		| (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
+			? 0 : UDCCS_BI_SST), ep->reg_udccs);
+}
+
+
+static struct usb_ep_ops pxa25x_ep_ops = {
+	.enable		= pxa25x_ep_enable,
+	.disable	= pxa25x_ep_disable,
+
+	.alloc_request	= pxa25x_ep_alloc_request,
+	.free_request	= pxa25x_ep_free_request,
+
+	.queue		= pxa25x_ep_queue,
+	.dequeue	= pxa25x_ep_dequeue,
+
+	.set_halt	= pxa25x_ep_set_halt,
+	.fifo_status	= pxa25x_ep_fifo_status,
+	.fifo_flush	= pxa25x_ep_fifo_flush,
+};
+
+
+/* ---------------------------------------------------------------------------
+ *	device-scoped parts of the api to the usb controller hardware
+ * ---------------------------------------------------------------------------
+ */
+
+static int pxa25x_udc_get_frame(struct usb_gadget *_gadget)
+{
+	return ((readl(&the_controller->regs->ufnrh) & 0x07) << 8) |
+		(readl(&the_controller->regs->ufnrl) & 0xff);
+}
+
+static int pxa25x_udc_wakeup(struct usb_gadget *_gadget)
+{
+	/* host may not have enabled remote wakeup */
+	if ((readl(&the_controller->regs->udccs[0]) & UDCCS0_DRWF) == 0)
+		return -EHOSTUNREACH;
+	udc_set_mask_UDCCR(UDCCR_RSM);
+	return 0;
+}
+
+static void stop_activity(struct pxa25x_udc *, struct usb_gadget_driver *);
+static void udc_enable(struct pxa25x_udc *);
+static void udc_disable(struct pxa25x_udc *);
+
+/*
+ * We disable the UDC -- and its 48 MHz clock -- whenever it's not
+ * in active use.
+ */
+static int pullup(struct pxa25x_udc *udc)
+{
+	if (udc->pullup)
+		pullup_on();
+	else
+		pullup_off();
+
+
+	int is_active = udc->pullup;
+	if (is_active) {
+		if (!udc->active) {
+			udc->active = 1;
+			udc_enable(udc);
+		}
+	} else {
+		if (udc->active) {
+			if (udc->gadget.speed != USB_SPEED_UNKNOWN)
+				stop_activity(udc, udc->driver);
+			udc_disable(udc);
+			udc->active = 0;
+		}
+
+	}
+	return 0;
+}
+
+/* VBUS reporting logically comes from a transceiver */
+static int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct pxa25x_udc *udc;
+
+	udc = container_of(_gadget, struct pxa25x_udc, gadget);
+	printf("vbus %s\n", is_active ? "supplied" : "inactive");
+	pullup(udc);
+	return 0;
+}
+
+/* drivers may have software control over D+ pullup */
+static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)
+{
+	struct pxa25x_udc	*udc;
+
+	udc = container_of(_gadget, struct pxa25x_udc, gadget);
+
+	/* not all boards support pullup control */
+	if (!udc->mach->udc_command)
+		return -EOPNOTSUPP;
+
+	udc->pullup = (is_active != 0);
+	pullup(udc);
+	return 0;
+}
+
+/*
+ * boards may consume current from VBUS, up to 100-500mA based on config.
+ * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs
+ * violate USB specs.
+ */
+static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct usb_gadget_ops pxa25x_udc_ops = {
+	.get_frame	= pxa25x_udc_get_frame,
+	.wakeup		= pxa25x_udc_wakeup,
+	.vbus_session	= pxa25x_udc_vbus_session,
+	.pullup		= pxa25x_udc_pullup,
+	.vbus_draw	= pxa25x_udc_vbus_draw,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ *	udc_disable - disable USB device controller
+ */
+static void udc_disable(struct pxa25x_udc *dev)
+{
+	/* block all irqs */
+	udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM);
+	writel(0xff, &dev->regs->uicr0);
+	writel(0xff, &dev->regs->uicr1);
+	writel(UFNRH_SIM, &dev->regs->ufnrh);
+
+	/* if hardware supports it, disconnect from usb */
+	pullup_off();
+
+	udc_clear_mask_UDCCR(UDCCR_UDE);
+
+	ep0_idle(dev);
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ *	udc_reinit - initialize software state
+ */
+static void udc_reinit(struct pxa25x_udc *dev)
+{
+	u32 i;
+
+	/* device/ep0 records init */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+	dev->ep0state = EP0_IDLE;
+
+	/* basic endpoint records init */
+	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+		struct pxa25x_ep *ep = &dev->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+		ep->desc = NULL;
+		ep->stopped = 0;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->pio_irqs = 0;
+	}
+
+	/* the rest was statically initialized, and is read-only */
+}
+
+/*
+ * until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static void udc_enable(struct pxa25x_udc *dev)
+{
+	debug("udc: enabling udc\n");
+
+	udc_clear_mask_UDCCR(UDCCR_UDE);
+
+	/*
+	 * Try to clear these bits before we enable the udc.
+	 * Do not touch reset ack bit, we would take care of it in
+	 * interrupt handle routine
+	 */
+	udc_ack_int_UDCCR(UDCCR_SUSIR|UDCCR_RESIR);
+
+	ep0_idle(dev);
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	dev->stats.irqs = 0;
+
+	/*
+	 * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual:
+	 * - enable UDC
+	 * - if RESET is already in progress, ack interrupt
+	 * - unmask reset interrupt
+	 */
+	udc_set_mask_UDCCR(UDCCR_UDE);
+	if (!(readl(&dev->regs->udccr) & UDCCR_UDA))
+		udc_ack_int_UDCCR(UDCCR_RSTIR);
+
+	if (dev->has_cfr /* UDC_RES2 is defined */) {
+		/*
+		 * pxa255 (a0+) can avoid a set_config race that could
+		 * prevent gadget drivers from configuring correctly
+		 */
+		writel(UDCCFR_ACM | UDCCFR_MB1, &dev->regs->udccfr);
+	}
+
+	/* enable suspend/resume and reset irqs */
+	udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
+
+	/* enable ep0 irqs */
+	clrbits_le32(&dev->regs->uicr0, UICR0_IM0);
+
+	/* if hardware supports it, pullup D+ and wait for reset */
+	pullup_on();
+}
+
+static inline void clear_ep_state(struct pxa25x_udc *dev)
+{
+	unsigned i;
+
+	/*
+	 * hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
+	 * fifos, and pending transactions mustn't be continued in any case.
+	 */
+	for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++)
+		nuke(&dev->ep[i], -ECONNABORTED);
+}
+
+static void handle_ep0(struct pxa25x_udc *dev)
+{
+	u32 udccs0 = readl(&dev->regs->udccs[0]);
+	struct pxa25x_ep *ep = &dev->ep[0];
+	struct pxa25x_request *req;
+	union {
+		struct usb_ctrlrequest	r;
+		u8			raw[8];
+		u32			word[2];
+	} u;
+
+	if (list_empty(&ep->queue))
+		req = NULL;
+	else
+		req = list_entry(ep->queue.next, struct pxa25x_request, queue);
+
+	/* clear stall status */
+	if (udccs0 & UDCCS0_SST) {
+		nuke(ep, -EPIPE);
+		writel(UDCCS0_SST, &dev->regs->udccs[0]);
+		stop_watchdog(dev);
+		ep0_idle(dev);
+	}
+
+	/* previous request unfinished?  non-error iff back-to-back ... */
+	if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) {
+		nuke(ep, 0);
+		stop_watchdog(dev);
+		ep0_idle(dev);
+	}
+
+	switch (dev->ep0state) {
+	case EP0_IDLE:
+		/* late-breaking status? */
+		udccs0 = readl(&dev->regs->udccs[0]);
+
+		/* start control request? */
+		if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))
+				== (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) {
+			int i;
+
+			nuke(ep, -EPROTO);
+
+			/* read SETUP packet */
+			for (i = 0; i < 8; i++) {
+				if (unlikely(!(readl(&dev->regs->udccs[0]) &
+						UDCCS0_RNE))) {
+bad_setup:
+					debug("SETUP %d!\n", i);
+					goto stall;
+				}
+				u.raw[i] = (u8)readb(&dev->regs->uddr0);
+			}
+			if (unlikely((readl(&dev->regs->udccs[0]) &
+					UDCCS0_RNE) != 0))
+				goto bad_setup;
+
+got_setup:
+			debug("SETUP %02x.%02x v%04x i%04x l%04x\n",
+				u.r.bRequestType, u.r.bRequest,
+				le16_to_cpu(u.r.wValue),
+				le16_to_cpu(u.r.wIndex),
+				le16_to_cpu(u.r.wLength));
+
+			/* cope with automagic for some standard requests. */
+			dev->req_std = (u.r.bRequestType & USB_TYPE_MASK)
+						== USB_TYPE_STANDARD;
+			dev->req_config = 0;
+			dev->req_pending = 1;
+			switch (u.r.bRequest) {
+			/* hardware restricts gadget drivers here! */
+			case USB_REQ_SET_CONFIGURATION:
+				debug("GOT SET_CONFIGURATION\n");
+				if (u.r.bRequestType == USB_RECIP_DEVICE) {
+					/*
+					 * reflect hardware's automagic
+					 * up to the gadget driver.
+					 */
+config_change:
+					dev->req_config = 1;
+					clear_ep_state(dev);
+					/*
+					 * if !has_cfr, there's no synch
+					 * else use AREN (later) not SA|OPR
+					 * USIR0_IR0 acts edge sensitive
+					 */
+				}
+				break;
+			/* ... and here, even more ... */
+			case USB_REQ_SET_INTERFACE:
+				if (u.r.bRequestType == USB_RECIP_INTERFACE) {
+					/*
+					 * udc hardware is broken by design:
+					 *  - altsetting may only be zero;
+					 *  - hw resets all interfaces' eps;
+					 *  - ep reset doesn't include halt(?).
+					 */
+					printf("broken set_interface (%d/%d)\n",
+						le16_to_cpu(u.r.wIndex),
+						le16_to_cpu(u.r.wValue));
+					goto config_change;
+				}
+				break;
+			/* hardware was supposed to hide this */
+			case USB_REQ_SET_ADDRESS:
+				debug("GOT SET ADDRESS\n");
+				if (u.r.bRequestType == USB_RECIP_DEVICE) {
+					ep0start(dev, 0, "address");
+					return;
+				}
+				break;
+			}
+
+			if (u.r.bRequestType & USB_DIR_IN)
+				dev->ep0state = EP0_IN_DATA_PHASE;
+			else
+				dev->ep0state = EP0_OUT_DATA_PHASE;
+
+			i = dev->driver->setup(&dev->gadget, &u.r);
+			if (i < 0) {
+				/* hardware automagic preventing STALL... */
+				if (dev->req_config) {
+					/*
+					 * hardware sometimes neglects to tell
+					 * tell us about config change events,
+					 * so later ones may fail...
+					 */
+					printf("config change %02x fail %d?\n",
+						u.r.bRequest, i);
+					return;
+					/*
+					 * TODO experiment:  if has_cfr,
+					 * hardware didn't ACK; maybe we
+					 * could actually STALL!
+					 */
+				}
+				if (0) {
+stall:
+					/* uninitialized when goto stall */
+					i = 0;
+				}
+				debug("protocol STALL, "
+					"%02x err %d\n",
+					readl(&dev->regs->udccs[0]), i);
+
+				/*
+				 * the watchdog timer helps deal with cases
+				 * where udc seems to clear FST wrongly, and
+				 * then NAKs instead of STALLing.
+				 */
+				ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall");
+				start_watchdog(dev);
+				dev->ep0state = EP0_STALL;
+
+			/* deferred i/o == no response yet */
+			} else if (dev->req_pending) {
+				if (likely(dev->ep0state == EP0_IN_DATA_PHASE
+						|| dev->req_std || u.r.wLength))
+					ep0start(dev, 0, "defer");
+				else
+					ep0start(dev, UDCCS0_IPR, "defer/IPR");
+			}
+
+			/* expect at least one data or status stage irq */
+			return;
+
+		} else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA))
+				== (UDCCS0_OPR|UDCCS0_SA))) {
+			unsigned i;
+
+			/*
+			 * pxa210/250 erratum 131 for B0/B1 says RNE lies.
+			 * still observed on a pxa255 a0.
+			 */
+			debug("e131\n");
+			nuke(ep, -EPROTO);
+
+			/* read SETUP data, but don't trust it too much */
+			for (i = 0; i < 8; i++)
+				u.raw[i] = (u8)readb(&dev->regs->uddr0);
+			if ((u.r.bRequestType & USB_RECIP_MASK)
+					> USB_RECIP_OTHER)
+				goto stall;
+			if (u.word[0] == 0 && u.word[1] == 0)
+				goto stall;
+			goto got_setup;
+		} else {
+			/*
+			 * some random early IRQ:
+			 * - we acked FST
+			 * - IPR cleared
+			 * - OPR got set, without SA (likely status stage)
+			 */
+			debug("random IRQ %X %X\n", udccs0,
+				readl(&dev->regs->udccs[0]));
+			writel(udccs0 & (UDCCS0_SA|UDCCS0_OPR),
+				&dev->regs->udccs[0]);
+		}
+		break;
+	case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR etc */
+		if (udccs0 & UDCCS0_OPR) {
+			debug("ep0in premature status\n");
+			if (req)
+				done(ep, req, 0);
+			ep0_idle(dev);
+		} else /* irq was IPR clearing */ {
+			if (req) {
+				debug("next ep0 in packet\n");
+				/* this IN packet might finish the request */
+				(void) write_ep0_fifo(ep, req);
+			} /* else IN token before response was written */
+		}
+		break;
+	case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR etc */
+		if (udccs0 & UDCCS0_OPR) {
+			if (req) {
+				/* this OUT packet might finish the request */
+				if (read_ep0_fifo(ep, req))
+					done(ep, req, 0);
+				/* else more OUT packets expected */
+			} /* else OUT token before read was issued */
+		} else /* irq was IPR clearing */ {
+			debug("ep0out premature status\n");
+			if (req)
+				done(ep, req, 0);
+			ep0_idle(dev);
+		}
+		break;
+	case EP0_END_XFER:
+		if (req)
+			done(ep, req, 0);
+		/*
+		 * ack control-IN status (maybe in-zlp was skipped)
+		 * also appears after some config change events.
+		 */
+		if (udccs0 & UDCCS0_OPR)
+			writel(UDCCS0_OPR, &dev->regs->udccs[0]);
+		ep0_idle(dev);
+		break;
+	case EP0_STALL:
+		writel(UDCCS0_FST, &dev->regs->udccs[0]);
+		break;
+	}
+
+	writel(USIR0_IR0, &dev->regs->usir0);
+}
+
+static void handle_ep(struct pxa25x_ep *ep)
+{
+	struct pxa25x_request	*req;
+	int			is_in = ep->bEndpointAddress & USB_DIR_IN;
+	int			completed;
+	u32			udccs, tmp;
+
+	do {
+		completed = 0;
+		if (likely(!list_empty(&ep->queue)))
+			req = list_entry(ep->queue.next,
+					struct pxa25x_request, queue);
+		else
+			req = NULL;
+
+		/* TODO check FST handling */
+
+		udccs = readl(ep->reg_udccs);
+		if (unlikely(is_in)) {	/* irq from TPC, SST, or (ISO) TUR */
+			tmp = UDCCS_BI_TUR;
+			if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
+				tmp |= UDCCS_BI_SST;
+			tmp &= udccs;
+			if (likely(tmp))
+				writel(tmp, ep->reg_udccs);
+			if (req && likely((udccs & UDCCS_BI_TFS) != 0))
+				completed = write_fifo(ep, req);
+
+		} else {	/* irq from RPC (or for ISO, ROF) */
+			if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
+				tmp = UDCCS_BO_SST | UDCCS_BO_DME;
+			else
+				tmp = UDCCS_IO_ROF | UDCCS_IO_DME;
+			tmp &= udccs;
+			if (likely(tmp))
+				writel(tmp, ep->reg_udccs);
+
+			/* fifos can hold packets, ready for reading... */
+			if (likely(req))
+				completed = read_fifo(ep, req);
+			else
+				pio_irq_disable(ep->bEndpointAddress);
+		}
+		ep->pio_irqs++;
+	} while (completed);
+}
+
+/*
+ *	pxa25x_udc_irq - interrupt handler
+ *
+ * avoid delays in ep0 processing. the control handshaking isn't always
+ * under software control (pxa250c0 and the pxa255 are better), and delays
+ * could cause usb protocol errors.
+ */
+static struct pxa25x_udc memory;
+static int
+pxa25x_udc_irq(void)
+{
+	struct pxa25x_udc *dev = &memory;
+	int handled;
+
+	test_watchdog(dev);
+
+	dev->stats.irqs++;
+	do {
+		u32 udccr = readl(&dev->regs->udccr);
+
+		handled = 0;
+
+		/* SUSpend Interrupt Request */
+		if (unlikely(udccr & UDCCR_SUSIR)) {
+			udc_ack_int_UDCCR(UDCCR_SUSIR);
+			handled = 1;
+			debug("USB suspend\n");
+
+			if (dev->gadget.speed != USB_SPEED_UNKNOWN
+					&& dev->driver
+					&& dev->driver->suspend)
+				dev->driver->suspend(&dev->gadget);
+			ep0_idle(dev);
+		}
+
+		/* RESume Interrupt Request */
+		if (unlikely(udccr & UDCCR_RESIR)) {
+			udc_ack_int_UDCCR(UDCCR_RESIR);
+			handled = 1;
+			debug("USB resume\n");
+
+			if (dev->gadget.speed != USB_SPEED_UNKNOWN
+					&& dev->driver
+					&& dev->driver->resume)
+				dev->driver->resume(&dev->gadget);
+		}
+
+		/* ReSeT Interrupt Request - USB reset */
+		if (unlikely(udccr & UDCCR_RSTIR)) {
+			udc_ack_int_UDCCR(UDCCR_RSTIR);
+			handled = 1;
+
+			if ((readl(&dev->regs->udccr) & UDCCR_UDA) == 0) {
+				debug("USB reset start\n");
+
+				/*
+				 * reset driver and endpoints,
+				 * in case that's not yet done
+				 */
+				stop_activity(dev, dev->driver);
+
+			} else {
+				debug("USB reset end\n");
+				dev->gadget.speed = USB_SPEED_FULL;
+				memset(&dev->stats, 0, sizeof dev->stats);
+				/* driver and endpoints are still reset */
+			}
+
+		} else {
+			u32 uicr0 = readl(&dev->regs->uicr0);
+			u32 uicr1 = readl(&dev->regs->uicr1);
+			u32 usir0 = readl(&dev->regs->usir0);
+			u32 usir1 = readl(&dev->regs->usir1);
+
+			usir0 = usir0 & ~uicr0;
+			usir1 = usir1 & ~uicr1;
+			int i;
+
+			if (unlikely(!usir0 && !usir1))
+				continue;
+
+			debug_cond(NOISY, "irq %02x.%02x\n", usir1, usir0);
+
+			/* control traffic */
+			if (usir0 & USIR0_IR0) {
+				dev->ep[0].pio_irqs++;
+				handle_ep0(dev);
+				handled = 1;
+			}
+
+			/* endpoint data transfers */
+			for (i = 0; i < 8; i++) {
+				u32	tmp = 1 << i;
+
+				if (i && (usir0 & tmp)) {
+					handle_ep(&dev->ep[i]);
+					setbits_le32(&dev->regs->usir0, tmp);
+					handled = 1;
+				}
+#ifndef	CONFIG_USB_PXA25X_SMALL
+				if (usir1 & tmp) {
+					handle_ep(&dev->ep[i+8]);
+					setbits_le32(&dev->regs->usir1, tmp);
+					handled = 1;
+				}
+#endif
+			}
+		}
+
+		/* we could also ask for 1 msec SOF (SIR) interrupts */
+
+	} while (handled);
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * this uses load-time allocation and initialization (instead of
+ * doing it at run-time) to save code, eliminate fault paths, and
+ * be more obviously correct.
+ */
+static struct pxa25x_udc memory = {
+	.regs = UDC_REGS,
+
+	.gadget = {
+		.ops		= &pxa25x_udc_ops,
+		.ep0		= &memory.ep[0].ep,
+		.name		= driver_name,
+	},
+
+	/* control endpoint */
+	.ep[0] = {
+		.ep = {
+			.name		= ep0name,
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= EP0_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.reg_udccs	= &UDC_REGS->udccs[0],
+		.reg_uddr	= &UDC_REGS->uddr0,
+	},
+
+	/* first group of endpoints */
+	.ep[1] = {
+		.ep = {
+			.name		= "ep1in-bulk",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= BULK_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 1,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+		.reg_udccs	= &UDC_REGS->udccs[1],
+		.reg_uddr	= &UDC_REGS->uddr1,
+	},
+	.ep[2] = {
+		.ep = {
+			.name		= "ep2out-bulk",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= BULK_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
+		.bEndpointAddress = 2,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+		.reg_udccs	= &UDC_REGS->udccs[2],
+		.reg_ubcr	= &UDC_REGS->ubcr2,
+		.reg_uddr	= &UDC_REGS->uddr2,
+	},
+#ifndef CONFIG_USB_PXA25X_SMALL
+	.ep[3] = {
+		.ep = {
+			.name		= "ep3in-iso",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= ISO_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 3,
+		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
+		.reg_udccs	= &UDC_REGS->udccs[3],
+		.reg_uddr	= &UDC_REGS->uddr3,
+	},
+	.ep[4] = {
+		.ep = {
+			.name		= "ep4out-iso",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= ISO_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
+		.bEndpointAddress = 4,
+		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
+		.reg_udccs	= &UDC_REGS->udccs[4],
+		.reg_ubcr	= &UDC_REGS->ubcr4,
+		.reg_uddr	= &UDC_REGS->uddr4,
+	},
+	.ep[5] = {
+		.ep = {
+			.name		= "ep5in-int",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= INT_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= INT_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 5,
+		.bmAttributes	= USB_ENDPOINT_XFER_INT,
+		.reg_udccs	= &UDC_REGS->udccs[5],
+		.reg_uddr	= &UDC_REGS->uddr5,
+	},
+
+	/* second group of endpoints */
+	.ep[6] = {
+		.ep = {
+			.name		= "ep6in-bulk",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= BULK_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 6,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+		.reg_udccs	= &UDC_REGS->udccs[6],
+		.reg_uddr	= &UDC_REGS->uddr6,
+	},
+	.ep[7] = {
+		.ep = {
+			.name		= "ep7out-bulk",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= BULK_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
+		.bEndpointAddress = 7,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+		.reg_udccs	= &UDC_REGS->udccs[7],
+		.reg_ubcr	= &UDC_REGS->ubcr7,
+		.reg_uddr	= &UDC_REGS->uddr7,
+	},
+	.ep[8] = {
+		.ep = {
+			.name		= "ep8in-iso",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= ISO_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 8,
+		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
+		.reg_udccs	= &UDC_REGS->udccs[8],
+		.reg_uddr	= &UDC_REGS->uddr8,
+	},
+	.ep[9] = {
+		.ep = {
+			.name		= "ep9out-iso",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= ISO_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
+		.bEndpointAddress = 9,
+		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
+		.reg_udccs	= &UDC_REGS->udccs[9],
+		.reg_ubcr	= &UDC_REGS->ubcr9,
+		.reg_uddr	= &UDC_REGS->uddr9,
+	},
+	.ep[10] = {
+		.ep = {
+			.name		= "ep10in-int",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= INT_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= INT_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 10,
+		.bmAttributes	= USB_ENDPOINT_XFER_INT,
+		.reg_udccs	= &UDC_REGS->udccs[10],
+		.reg_uddr	= &UDC_REGS->uddr10,
+	},
+
+	/* third group of endpoints */
+	.ep[11] = {
+		.ep = {
+			.name		= "ep11in-bulk",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= BULK_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 11,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+		.reg_udccs	= &UDC_REGS->udccs[11],
+		.reg_uddr	= &UDC_REGS->uddr11,
+	},
+	.ep[12] = {
+		.ep = {
+			.name		= "ep12out-bulk",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= BULK_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
+		.bEndpointAddress = 12,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+		.reg_udccs	= &UDC_REGS->udccs[12],
+		.reg_ubcr	= &UDC_REGS->ubcr12,
+		.reg_uddr	= &UDC_REGS->uddr12,
+	},
+	.ep[13] = {
+		.ep = {
+			.name		= "ep13in-iso",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= ISO_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 13,
+		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
+		.reg_udccs	= &UDC_REGS->udccs[13],
+		.reg_uddr	= &UDC_REGS->uddr13,
+	},
+	.ep[14] = {
+		.ep = {
+			.name		= "ep14out-iso",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= ISO_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
+		.bEndpointAddress = 14,
+		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
+		.reg_udccs	= &UDC_REGS->udccs[14],
+		.reg_ubcr	= &UDC_REGS->ubcr14,
+		.reg_uddr	= &UDC_REGS->uddr14,
+	},
+	.ep[15] = {
+		.ep = {
+			.name		= "ep15in-int",
+			.ops		= &pxa25x_ep_ops,
+			.maxpacket	= INT_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= INT_FIFO_SIZE,
+		.bEndpointAddress = USB_DIR_IN | 15,
+		.bmAttributes	= USB_ENDPOINT_XFER_INT,
+		.reg_udccs	= &UDC_REGS->udccs[15],
+		.reg_uddr	= &UDC_REGS->uddr15,
+	},
+#endif /* !CONFIG_USB_PXA25X_SMALL */
+};
+
+static void udc_command(int cmd)
+{
+	switch (cmd) {
+	case PXA2XX_UDC_CMD_CONNECT:
+		setbits_le32(GPDR(CONFIG_USB_DEV_PULLUP_GPIO),
+			GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO));
+
+		/* enable pullup */
+		writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO),
+			GPCR(CONFIG_USB_DEV_PULLUP_GPIO));
+
+		debug("Connected to USB\n");
+		break;
+
+	case PXA2XX_UDC_CMD_DISCONNECT:
+		/* disable pullup resistor */
+		writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO),
+			GPSR(CONFIG_USB_DEV_PULLUP_GPIO));
+
+		/* setup pin as input, line will float */
+		clrbits_le32(GPDR(CONFIG_USB_DEV_PULLUP_GPIO),
+			GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO));
+
+		debug("Disconnected from USB\n");
+		break;
+	}
+}
+
+static struct pxa2xx_udc_mach_info mach_info = {
+	.udc_command = udc_command,
+};
+
+/*
+ * when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests.  then usb traffic follows until a
+ * disconnect is reported.  then a host may connect again, or
+ * the driver might get unbound.
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct pxa25x_udc *dev = &memory;
+	int retval;
+	uint32_t chiprev;
+
+	if (!driver
+			|| driver->speed < USB_SPEED_FULL
+			|| !driver->disconnect
+			|| !driver->setup)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	/* Enable clock for usb controller */
+	setbits_le32(CKEN, CKEN11_USB);
+
+	/* first hook up the driver ... */
+	dev->driver = driver;
+	dev->pullup = 1;
+
+	/* trigger chiprev-specific logic */
+	switch ((chiprev = pxa_get_cpu_revision())) {
+	case PXA255_A0:
+		dev->has_cfr = 1;
+		break;
+	case PXA250_A0:
+	case PXA250_A1:
+		/* A0/A1 "not released"; ep 13, 15 unusable */
+		/* fall through */
+	case PXA250_B2: case PXA210_B2:
+	case PXA250_B1: case PXA210_B1:
+	case PXA250_B0: case PXA210_B0:
+		/* OUT-DMA is broken ... */
+		/* fall through */
+	case PXA250_C0: case PXA210_C0:
+		break;
+	default:
+		printf("%s: unrecognized processor: %08x\n",
+			DRIVER_NAME, chiprev);
+		return -ENODEV;
+	}
+
+	the_controller = dev;
+
+	/* prepare watchdog timer */
+	dev->watchdog.running = 0;
+	dev->watchdog.period = 5000 * CONFIG_SYS_HZ / 1000000; /* 5 ms */
+	dev->watchdog.function = udc_watchdog;
+
+	dev->mach = &mach_info;
+
+	udc_disable(dev);
+	udc_reinit(dev);
+
+	dev->gadget.name = "pxa2xx_udc";
+	retval = driver->bind(&dev->gadget);
+	if (retval) {
+		printf("bind to driver %s --> error %d\n",
+				DRIVER_NAME, retval);
+		dev->driver = NULL;
+		return retval;
+	}
+
+	/*
+	 * ... then enable host detection and ep0; and we're ready
+	 * for set_configuration as well as eventual disconnect.
+	 */
+	printf("registered gadget driver '%s'\n", DRIVER_NAME);
+
+	pullup(dev);
+	dump_state(dev);
+	return 0;
+}
+
+static void
+stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
+{
+	int i;
+
+	/* don't disconnect drivers more than once */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* prevent new request submissions, kill any outstanding requests  */
+	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+		struct pxa25x_ep *ep = &dev->ep[i];
+
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	stop_watchdog(dev);
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver)
+		driver->disconnect(&dev->gadget);
+
+	/* re-init driver-visible data structures */
+	udc_reinit(dev);
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct pxa25x_udc	*dev = the_controller;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver || !driver->unbind)
+		return -EINVAL;
+
+	local_irq_disable();
+	dev->pullup = 0;
+	pullup(dev);
+	stop_activity(dev, driver);
+	local_irq_enable();
+
+	driver->unbind(&dev->gadget);
+	dev->driver = NULL;
+
+	printf("unregistered gadget driver '%s'\n", DRIVER_NAME);
+	dump_state(dev);
+
+	the_controller = NULL;
+
+	clrbits_le32(CKEN, CKEN11_USB);
+
+	return 0;
+}
+
+extern void udc_disconnect(void)
+{
+	setbits_le32(CKEN, CKEN11_USB);
+	udc_clear_mask_UDCCR(UDCCR_UDE);
+	udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+	clrbits_le32(CKEN, CKEN11_USB);
+}
+
+/*-------------------------------------------------------------------------*/
+
+extern int
+usb_gadget_handle_interrupts(int index)
+{
+	return pxa25x_udc_irq();
+}
diff --git a/roms/u-boot/drivers/usb/gadget/pxa25x_udc.h b/roms/u-boot/drivers/usb/gadget/pxa25x_udc.h
new file mode 100644
index 000000000..7c3882aa1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/pxa25x_udc.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Intel PXA25x on-chip full speed USB device controller
+ *
+ * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
+ * Copyright (C) 2003 David Brownell
+ * Copyright (C) 2012 Lukasz Dalek <luk0104@gmail.com>
+ */
+
+#ifndef __LINUX_USB_GADGET_PXA25X_H
+#define __LINUX_USB_GADGET_PXA25X_H
+
+#include <linux/types.h>
+#include <asm/arch/regs-usb.h>
+
+/*
+ * Prefetching support - only ARMv5.
+ */
+
+#ifdef ARCH_HAS_PREFETCH
+static inline void prefetch(const void *ptr)
+{
+	__asm__ __volatile__(
+		"pld\t%a0"
+		:
+		: "p" (ptr)
+		: "cc");
+}
+
+#define prefetchw(ptr)	prefetch(ptr)
+#endif /* ARCH_HAS_PREFETCH */
+
+/*-------------------------------------------------------------------------*/
+
+#define UDC_REGS	((struct pxa25x_udc_regs *)PXA25X_UDC_BASE)
+
+/*-------------------------------------------------------------------------*/
+
+struct pxa2xx_udc_mach_info {
+	int  (*udc_is_connected)(void);		/* do we see host? */
+	void (*udc_command)(int cmd);
+#define	PXA2XX_UDC_CMD_CONNECT		0	/* let host see us */
+#define	PXA2XX_UDC_CMD_DISCONNECT	1	/* so host won't see us */
+};
+
+struct pxa25x_udc;
+
+struct pxa25x_ep {
+	struct usb_ep				ep;
+	struct pxa25x_udc			*dev;
+
+	const struct usb_endpoint_descriptor	*desc;
+	struct list_head			queue;
+	unsigned long				pio_irqs;
+
+	unsigned short				fifo_size;
+	u8					bEndpointAddress;
+	u8					bmAttributes;
+
+	unsigned				stopped:1;
+
+	/* UDCCS = UDC Control/Status for this EP
+	 * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
+	 * UDDR = UDC Endpoint Data Register (the fifo)
+	 * DRCM = DMA Request Channel Map
+	 */
+	u32					*reg_udccs;
+	u32					*reg_ubcr;
+	u32					*reg_uddr;
+};
+
+struct pxa25x_request {
+	struct usb_request			req;
+	struct list_head			queue;
+};
+
+enum ep0_state {
+	EP0_IDLE,
+	EP0_IN_DATA_PHASE,
+	EP0_OUT_DATA_PHASE,
+	EP0_END_XFER,
+	EP0_STALL,
+};
+
+#define EP0_FIFO_SIZE	16U
+#define BULK_FIFO_SIZE	64U
+#define ISO_FIFO_SIZE	256U
+#define INT_FIFO_SIZE	8U
+
+struct udc_stats {
+	struct ep0stats {
+		unsigned long		ops;
+		unsigned long		bytes;
+	} read, write;
+	unsigned long			irqs;
+};
+
+#ifdef CONFIG_USB_PXA25X_SMALL
+/* when memory's tight, SMALL config saves code+data.  */
+#define	PXA_UDC_NUM_ENDPOINTS	3
+#endif
+
+#ifndef	PXA_UDC_NUM_ENDPOINTS
+#define	PXA_UDC_NUM_ENDPOINTS	16
+#endif
+
+struct pxa25x_watchdog {
+	unsigned				running:1;
+	ulong					period;
+	ulong					base;
+	struct pxa25x_udc			*udc;
+
+	void (*function)(struct pxa25x_udc *udc);
+};
+
+struct pxa25x_udc {
+	struct usb_gadget			gadget;
+	struct usb_gadget_driver		*driver;
+	struct pxa25x_udc_regs			*regs;
+
+	enum ep0_state				ep0state;
+	struct udc_stats			stats;
+	unsigned				got_irq:1,
+						pullup:1,
+						has_cfr:1,
+						req_pending:1,
+						req_std:1,
+						req_config:1,
+						active:1;
+
+	struct clk				*clk;
+	struct pxa2xx_udc_mach_info		*mach;
+	u64					dma_mask;
+	struct pxa25x_ep			ep[PXA_UDC_NUM_ENDPOINTS];
+
+	struct pxa25x_watchdog			watchdog;
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct pxa25x_udc *the_controller;
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+# define NOISY 0
+#endif
+
+#endif /* __LINUX_USB_GADGET_PXA25X_H */
diff --git a/roms/u-boot/drivers/usb/gadget/pxa27x_udc.c b/roms/u-boot/drivers/usb/gadget/pxa27x_udc.c
new file mode 100644
index 000000000..ba362b8f2
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/pxa27x_udc.c
@@ -0,0 +1,703 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PXA27x USB device driver for u-boot.
+ *
+ * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2007 Eurotech S.p.A.  <info@eurotech.it>
+ * Copyright (C) 2008 Vivek Kutal      <vivek.kutal@azingo.com>
+ */
+
+
+#include <common.h>
+#include <asm/arch/hardware.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <usbdevice.h>
+#include <linux/delay.h>
+#include <usb/pxa27x_udc.h>
+#include <usb/udc.h>
+
+#include "ep0.h"
+
+/* number of endpoints on this UDC */
+#define UDC_MAX_ENDPOINTS	24
+
+static struct urb *ep0_urb;
+static struct usb_device_instance *udc_device;
+static int ep0state = EP0_IDLE;
+
+#ifdef USBDDBG
+static void udc_dump_buffer(char *name, u8 *buf, int len)
+{
+	usbdbg("%s - buf %p, len %d", name, buf, len);
+	print_buffer(0, buf, 1, len, 0);
+}
+#else
+#define udc_dump_buffer(name, buf, len)		/* void */
+#endif
+
+static inline void udc_ack_int_UDCCR(int mask)
+{
+	writel(readl(USIR1) | mask, USIR1);
+}
+
+/*
+ * If the endpoint has an active tx_urb, then the next packet of data from the
+ * URB is written to the tx FIFO.
+ * The total amount of data in the urb is given by urb->actual_length.
+ * The maximum amount of data that can be sent in any one packet is given by
+ * endpoint->tx_packetSize.
+ * The number of data bytes from this URB that have already been transmitted
+ * is given by endpoint->sent.
+ * endpoint->last is updated by this routine with the number of data bytes
+ * transmitted in this packet.
+ */
+static int udc_write_urb(struct usb_endpoint_instance *endpoint)
+{
+	struct urb *urb = endpoint->tx_urb;
+	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+	u32 *data32 = (u32 *) urb->buffer;
+	u8  *data8 = (u8 *) urb->buffer;
+	unsigned int i, n, w, b, is_short;
+	int timeout = 2000;	/* 2ms */
+
+	if (!urb || !urb->actual_length)
+		return -1;
+
+	n = min_t(unsigned int, urb->actual_length - endpoint->sent,
+		  endpoint->tx_packetSize);
+	if (n <= 0)
+		return -1;
+
+	usbdbg("write urb on ep %d", ep_num);
+#if defined(USBDDBG) && defined(USBDPARANOIA)
+	usbdbg("urb: buf %p, buf_len %d, actual_len %d",
+		urb->buffer, urb->buffer_length, urb->actual_length);
+	usbdbg("endpoint: sent %d, tx_packetSize %d, last %d",
+		endpoint->sent, endpoint->tx_packetSize, endpoint->last);
+#endif
+
+	is_short = n != endpoint->tx_packetSize;
+	w = n / 4;
+	b = n % 4;
+	usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b);
+	udc_dump_buffer("urb write", data8 + endpoint->sent, n);
+
+	/* Prepare for data send */
+	if (ep_num)
+		writel(UDCCSR_PC ,UDCCSN(ep_num));
+
+	for (i = 0; i < w; i++)
+		  writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num));
+
+	for (i = 0; i < b; i++)
+		  writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num));
+
+	/* Set "Packet Complete" if less data then tx_packetSize */
+	if (is_short)
+		writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num));
+
+	/* Wait for data sent */
+	if (ep_num) {
+		while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) {
+			if (timeout-- == 0)
+				return -1;
+			else
+				udelay(1);
+		}
+	}
+
+	endpoint->last = n;
+
+	if (ep_num) {
+		usbd_tx_complete(endpoint);
+	} else {
+		endpoint->sent += n;
+		endpoint->last -= n;
+	}
+
+	if (endpoint->sent >= urb->actual_length) {
+		urb->actual_length = 0;
+		endpoint->sent = 0;
+		endpoint->last = 0;
+	}
+
+	if ((endpoint->sent >= urb->actual_length) && (!ep_num)) {
+		usbdbg("ep0 IN stage done");
+		if (is_short)
+			ep0state = EP0_IDLE;
+		else
+			ep0state = EP0_XFER_COMPLETE;
+	}
+
+	return 0;
+}
+
+static int udc_read_urb(struct usb_endpoint_instance *endpoint)
+{
+	struct urb *urb = endpoint->rcv_urb;
+	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+	u32 *data32 = (u32 *) urb->buffer;
+	unsigned int i, n;
+
+	usbdbg("read urb on ep %d", ep_num);
+#if defined(USBDDBG) && defined(USBDPARANOIA)
+	usbdbg("urb: buf %p, buf_len %d, actual_len %d",
+		urb->buffer, urb->buffer_length, urb->actual_length);
+	usbdbg("endpoint: rcv_packetSize %d",
+		endpoint->rcv_packetSize);
+#endif
+
+	if (readl(UDCCSN(ep_num)) & UDCCSR_BNE)
+		n = readl(UDCBCN(ep_num)) & 0x3ff;
+	else /* zlp */
+		n = 0;
+
+	usbdbg("n %d%s", n, n != endpoint->rcv_packetSize ? "-s" : "");
+	for (i = 0; i < n; i += 4)
+		data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num));
+
+	udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n);
+	usbd_rcv_complete(endpoint, n, 0);
+
+	return 0;
+}
+
+static int udc_read_urb_ep0(void)
+{
+	u32 *data32 = (u32 *) ep0_urb->buffer;
+	u8 *data8 = (u8 *) ep0_urb->buffer;
+	unsigned int i, n, w, b;
+
+	usbdbg("read urb on ep 0");
+#if defined(USBDDBG) && defined(USBDPARANOIA)
+	usbdbg("urb: buf %p, buf_len %d, actual_len %d",
+		ep0_urb->buffer, ep0_urb->buffer_length, ep0_urb->actual_length);
+#endif
+
+	n = readl(UDCBCR0);
+	w = n / 4;
+	b = n % 4;
+
+	for (i = 0; i < w; i++) {
+		data32[ep0_urb->actual_length / 4 + i] = readl(UDCDN(0));
+		/* ep0_urb->actual_length += 4; */
+	}
+
+	for (i = 0; i < b; i++) {
+		data8[ep0_urb->actual_length + w * 4 + i] = readb(UDCDN(0));
+		/* ep0_urb->actual_length++; */
+	}
+
+	ep0_urb->actual_length += n;
+
+	udc_dump_buffer("urb read", (u8 *) data32, ep0_urb->actual_length);
+
+	writel(UDCCSR0_OPC | UDCCSR0_IPR, UDCCSR0);
+	if (ep0_urb->actual_length == ep0_urb->device_request.wLength)
+		return 1;
+
+	return 0;
+}
+
+static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
+{
+	u32 udccsr0 = readl(UDCCSR0);
+	u32 *data = (u32 *) &ep0_urb->device_request;
+	int i;
+
+	usbdbg("udccsr0 %x", udccsr0);
+
+	/* Clear stall status */
+	if (udccsr0 & UDCCSR0_SST) {
+		usberr("clear stall status");
+		writel(UDCCSR0_SST, UDCCSR0);
+		ep0state = EP0_IDLE;
+	}
+
+	/* previous request unfinished?  non-error iff back-to-back ... */
+	if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE)
+		ep0state = EP0_IDLE;
+
+	switch (ep0state) {
+
+	case EP0_IDLE:
+		udccsr0 = readl(UDCCSR0);
+		/* Start control request? */
+		if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE))
+			== (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) {
+
+			/* Read SETUP packet.
+			 * SETUP packet size is 8 bytes (aka 2 words)
+			 */
+			usbdbg("try reading SETUP packet");
+			for (i = 0; i < 2; i++) {
+				if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) {
+					usberr("setup packet too short:%d", i);
+					goto stall;
+				}
+				data[i] = readl(UDCDR0);
+			}
+
+			writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0);
+			if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) {
+				usberr("setup packet too long");
+				goto stall;
+			}
+
+			udc_dump_buffer("ep0 setup read", (u8 *) data, 8);
+
+			if (ep0_urb->device_request.wLength == 0) {
+				usbdbg("Zero Data control Packet\n");
+				if (ep0_recv_setup(ep0_urb)) {
+					usberr("Invalid Setup Packet\n");
+					udc_dump_buffer("ep0 setup read",
+								(u8 *)data, 8);
+					goto stall;
+				}
+				writel(UDCCSR0_IPR, UDCCSR0);
+				ep0state = EP0_IDLE;
+			} else {
+				/* Check direction */
+				if ((ep0_urb->device_request.bmRequestType &
+						USB_REQ_DIRECTION_MASK)
+						== USB_REQ_HOST2DEVICE) {
+					ep0state = EP0_OUT_DATA;
+					ep0_urb->buffer =
+						(u8 *)ep0_urb->buffer_data;
+					ep0_urb->buffer_length =
+						sizeof(ep0_urb->buffer_data);
+					ep0_urb->actual_length = 0;
+					writel(UDCCSR0_IPR, UDCCSR0);
+				} else {
+					/* The ep0_recv_setup function has
+					 * already placed our response packet
+					 * data in ep0_urb->buffer and the
+					 * packet length in
+					 * ep0_urb->actual_length.
+					 */
+					if (ep0_recv_setup(ep0_urb)) {
+stall:
+						usberr("Invalid setup packet");
+						udc_dump_buffer("ep0 setup read"
+							, (u8 *) data, 8);
+						ep0state = EP0_IDLE;
+
+						writel(UDCCSR0_SA |
+						UDCCSR0_OPC | UDCCSR0_FST |
+						UDCCS0_FTF, UDCCSR0);
+
+						return;
+					}
+
+					endpoint->tx_urb = ep0_urb;
+					endpoint->sent = 0;
+					usbdbg("EP0_IN_DATA");
+					ep0state = EP0_IN_DATA;
+					if (udc_write_urb(endpoint) < 0)
+						goto stall;
+
+				}
+			}
+			return;
+		} else if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA))
+			== (UDCCSR0_OPC|UDCCSR0_SA)) {
+			usberr("Setup Active but no data. Stalling ....\n");
+			goto stall;
+		} else {
+			usbdbg("random early IRQs");
+			/* Some random early IRQs:
+			 * - we acked FST
+			 * - IPR cleared
+			 * - OPC got set, without SA (likely status stage)
+			 */
+			writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0);
+		}
+		break;
+
+	case EP0_OUT_DATA:
+
+		if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) {
+			if (udc_read_urb_ep0()) {
+read_complete:
+				ep0state = EP0_IDLE;
+				if (ep0_recv_setup(ep0_urb)) {
+					/* Not a setup packet, stall next
+					 * EP0 transaction
+					 */
+					udc_dump_buffer("ep0 setup read",
+							(u8 *) data, 8);
+					usberr("can't parse setup packet\n");
+					goto stall;
+				}
+			}
+		} else if (!(udccsr0 & UDCCSR0_OPC) &&
+				!(udccsr0 & UDCCSR0_IPR)) {
+			if (ep0_urb->device_request.wLength ==
+				ep0_urb->actual_length)
+				goto read_complete;
+
+			usberr("Premature Status\n");
+			ep0state = EP0_IDLE;
+		}
+		break;
+
+	case EP0_IN_DATA:
+		/* GET_DESCRIPTOR etc */
+		if (udccsr0 & UDCCSR0_OPC) {
+			writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0);
+			usberr("ep0in premature status");
+			ep0state = EP0_IDLE;
+		} else {
+			/* irq was IPR clearing */
+			if (udc_write_urb(endpoint) < 0) {
+				usberr("ep0_write_error\n");
+				goto stall;
+			}
+		}
+		break;
+
+	case EP0_XFER_COMPLETE:
+		writel(UDCCSR0_IPR, UDCCSR0);
+		ep0state = EP0_IDLE;
+		break;
+
+	default:
+		usbdbg("Default\n");
+	}
+	writel(USIR0_IR0, USIR0);
+}
+
+static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
+{
+	int ep_addr = endpoint->endpoint_address;
+	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
+
+	u32 flags = readl(UDCCSN(ep_num)) & (UDCCSR_SST | UDCCSR_TRN);
+	if (flags)
+		writel(flags, UDCCSN(ep_num));
+
+	if (ep_isout)
+		udc_read_urb(endpoint);
+	else
+		udc_write_urb(endpoint);
+
+	writel(UDCCSR_PC, UDCCSN(ep_num));
+}
+
+static void udc_state_changed(void)
+{
+
+	writel(readl(UDCCR) | UDCCR_SMAC, UDCCR);
+
+	usbdbg("New UDC settings are: conf %d - inter %d - alter %d",
+	       (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S,
+	       (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S,
+	       (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S);
+
+	usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+	writel(UDCISR1_IRCC, UDCISR1);
+}
+
+void udc_irq(void)
+{
+	int handled;
+	struct usb_endpoint_instance *endpoint;
+	int ep_num, i;
+	u32 udcisr0;
+
+	do {
+		handled = 0;
+		/* Suspend Interrupt Request */
+		if (readl(USIR1) & UDCCR_SUSIR) {
+			usbdbg("Suspend\n");
+			udc_ack_int_UDCCR(UDCCR_SUSIR);
+			handled = 1;
+			ep0state = EP0_IDLE;
+		}
+
+		/* Resume Interrupt Request */
+		if (readl(USIR1) & UDCCR_RESIR) {
+			udc_ack_int_UDCCR(UDCCR_RESIR);
+			handled = 1;
+			usbdbg("USB resume\n");
+		}
+
+		if (readl(USIR1) & (1<<31)) {
+			handled = 1;
+			udc_state_changed();
+		}
+
+		/* Reset Interrupt Request */
+		if (readl(USIR1) & UDCCR_RSTIR) {
+			udc_ack_int_UDCCR(UDCCR_RSTIR);
+			handled = 1;
+			usbdbg("Reset\n");
+			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+		} else {
+			if (readl(USIR0))
+				usbdbg("UISR0: %x \n", readl(USIR0));
+
+			if (readl(USIR0) & 0x2)
+				writel(0x2, USIR0);
+
+			/* Control traffic */
+			if (readl(USIR0)  & USIR0_IR0) {
+				handled = 1;
+				writel(USIR0_IR0, USIR0);
+				udc_handle_ep0(udc_device->bus->endpoint_array);
+			}
+
+			endpoint = udc_device->bus->endpoint_array;
+			for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+				ep_num = (endpoint[i].endpoint_address) &
+						USB_ENDPOINT_NUMBER_MASK;
+				if (!ep_num)
+					continue;
+				udcisr0 = readl(UDCISR0);
+				if (udcisr0 &
+					UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) {
+					writel(UDCISR_INT(ep_num, UDC_INT_PACKETCMP),
+					       UDCISR0);
+					udc_handle_ep(&endpoint[i]);
+				}
+			}
+		}
+
+	} while (handled);
+}
+
+/* The UDCCR reg contains mask and interrupt status bits,
+ * so using '|=' isn't safe as it may ack an interrupt.
+ */
+#define UDCCR_OEN		(1 << 31)   /* On-the-Go Enable */
+#define UDCCR_MASK_BITS     	(UDCCR_OEN | UDCCR_UDE)
+
+static inline void udc_set_mask_UDCCR(int mask)
+{
+    writel((readl(UDCCR) & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR);
+}
+
+static inline void udc_clear_mask_UDCCR(int mask)
+{
+    writel((readl(UDCCR) & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR);
+}
+
+static void pio_irq_enable(int ep_num)
+{
+	if (ep_num < 16)
+		writel(readl(UDCICR0) | 3 << (ep_num * 2), UDCICR0);
+	else {
+		ep_num -= 16;
+		writel(readl(UDCICR1) | 3 << (ep_num * 2), UDCICR1);
+	}
+}
+
+/*
+ * udc_set_nak
+ *
+ * Allow upper layers to signal lower layers should not accept more RX data
+ */
+void udc_set_nak(int ep_num)
+{
+	/* TODO */
+}
+
+/*
+ * udc_unset_nak
+ *
+ * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint.
+ * Switch off NAKing on this endpoint to accept more data output from host.
+ */
+void udc_unset_nak(int ep_num)
+{
+	/* TODO */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+	return udc_write_urb(endpoint);
+}
+
+/* Associate a physical endpoint with endpoint instance */
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+				struct usb_endpoint_instance *endpoint)
+{
+	int ep_num, ep_addr, ep_isout, ep_type, ep_size;
+	int config, interface, alternate;
+	u32 tmp;
+
+	usbdbg("setting up endpoint id %d", id);
+
+	if (!endpoint) {
+		usberr("endpoint void!");
+		return;
+	}
+
+	ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+	if (ep_num >= UDC_MAX_ENDPOINTS) {
+		usberr("unable to setup ep %d!", ep_num);
+		return;
+	}
+
+	pio_irq_enable(ep_num);
+	if (ep_num == 0) {
+		/* Done for ep0 */
+		return;
+	}
+
+	config = 1;
+	interface = 0;
+	alternate = 0;
+
+	usbdbg("config %d - interface %d - alternate %d",
+		config, interface, alternate);
+
+	ep_addr = endpoint->endpoint_address;
+	ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
+	ep_type = ep_isout ? endpoint->rcv_attributes : endpoint->tx_attributes;
+	ep_size = ep_isout ? endpoint->rcv_packetSize : endpoint->tx_packetSize;
+
+	usbdbg("addr %x, num %d, dir %s, type %s, packet size %d",
+		ep_addr, ep_num,
+		ep_isout ? "out" : "in",
+		ep_type == USB_ENDPOINT_XFER_ISOC ? "isoc" :
+		ep_type == USB_ENDPOINT_XFER_BULK ? "bulk" :
+		ep_type == USB_ENDPOINT_XFER_INT ? "int" : "???",
+		ep_size
+		);
+
+	/* Configure UDCCRx */
+	tmp = 0;
+	tmp |= (config << UDCCONR_CN_S) & UDCCONR_CN;
+	tmp |= (interface << UDCCONR_IN_S) & UDCCONR_IN;
+	tmp |= (alternate << UDCCONR_AISN_S) & UDCCONR_AISN;
+	tmp |= (ep_num << UDCCONR_EN_S) & UDCCONR_EN;
+	tmp |= (ep_type << UDCCONR_ET_S) & UDCCONR_ET;
+	tmp |= ep_isout ? 0 : UDCCONR_ED;
+	tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS;
+	tmp |= UDCCONR_EE;
+
+	writel(tmp, UDCCN(ep_num));
+
+	usbdbg("UDCCR%c = %x", 'A' + ep_num-1, readl(UDCCN(ep_num)));
+	usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, readl(UDCCSN(ep_num)));
+}
+
+/* Connect the USB device to the bus */
+void udc_connect(void)
+{
+	usbdbg("UDC connect");
+
+#ifdef CONFIG_USB_DEV_PULLUP_GPIO
+	/* Turn on the USB connection by enabling the pullup resistor */
+	writel(readl(GPDR(CONFIG_USB_DEV_PULLUP_GPIO))
+		     | GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO),
+	       GPDR(CONFIG_USB_DEV_PULLUP_GPIO));
+	writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPSR(CONFIG_USB_DEV_PULLUP_GPIO));
+#else
+	/* Host port 2 transceiver D+ pull up enable */
+	writel(readl(UP2OCR) | UP2OCR_DPPUE, UP2OCR);
+#endif
+}
+
+/* Disconnect the USB device to the bus */
+void udc_disconnect(void)
+{
+	usbdbg("UDC disconnect");
+
+#ifdef CONFIG_USB_DEV_PULLUP_GPIO
+	/* Turn off the USB connection by disabling the pullup resistor */
+	writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPCR(CONFIG_USB_DEV_PULLUP_GPIO));
+#else
+	/* Host port 2 transceiver D+ pull up disable */
+	writel(readl(UP2OCR) & ~UP2OCR_DPPUE, UP2OCR);
+#endif
+}
+
+/* Switch on the UDC */
+void udc_enable(struct usb_device_instance *device)
+{
+
+	ep0state = EP0_IDLE;
+
+	/* enable endpoint 0, A, B's Packet Complete Interrupt. */
+	writel(0xffffffff, UDCICR0);
+	writel(0xa8000000, UDCICR1);
+
+	/* clear the interrupt status/control registers */
+	writel(0xffffffff, UDCISR0);
+	writel(0xffffffff, UDCISR1);
+
+	/* set UDC-enable */
+	udc_set_mask_UDCCR(UDCCR_UDE);
+
+	udc_device = device;
+	if (!ep0_urb)
+		ep0_urb = usbd_alloc_urb(udc_device,
+				udc_device->bus->endpoint_array);
+	else
+		usbinfo("ep0_urb %p already allocated", ep0_urb);
+
+	usbdbg("UDC Enabled\n");
+}
+
+/* Need to check this again */
+void udc_disable(void)
+{
+	usbdbg("disable UDC");
+
+	udc_clear_mask_UDCCR(UDCCR_UDE);
+
+	/* Disable clock for USB device */
+	writel(readl(CKEN) & ~CKEN11_USB, CKEN);
+
+	/* Free ep0 URB */
+	if (ep0_urb) {
+		usbd_dealloc_urb(ep0_urb);
+		ep0_urb = NULL;
+	}
+
+	/* Reset device pointer */
+	udc_device = NULL;
+}
+
+/* Allow udc code to do any additional startup */
+void udc_startup_events(struct usb_device_instance *device)
+{
+	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT */
+	usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+	/* The DEVICE_CREATE event puts the USB device in the state
+	 * STATE_ATTACHED */
+	usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+	/* Some USB controller driver implementations signal
+	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+	 * DEVICE_HUB_CONFIGURED causes a transition to the state
+	 * STATE_POWERED, and DEVICE_RESET causes a transition to
+	 * the state STATE_DEFAULT.
+	 */
+	udc_enable(device);
+}
+
+/* Initialize h/w stuff */
+int udc_init(void)
+{
+	udc_device = NULL;
+	usbdbg("PXA27x usbd start");
+
+	/* Enable clock for USB device */
+	writel(readl(CKEN) | CKEN11_USB, CKEN);
+
+	/* Disable the UDC */
+	udc_clear_mask_UDCCR(UDCCR_UDE);
+
+	/* Disable IRQs: we don't use them */
+	writel(0, UDCICR0);
+	writel(0, UDCICR1);
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/gadget/rndis.c b/roms/u-boot/drivers/usb/gadget/rndis.c
new file mode 100644
index 000000000..13c327ea3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/rndis.c
@@ -0,0 +1,1314 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RNDIS MSG parser
+ *
+ * Authors:	Benedikt Spranger, Pengutronix
+ *		Robert Schwebel, Pengutronix
+ *
+ *		This software was originally developed in conformance with
+ *		Microsoft's Remote NDIS Specification License Agreement.
+ *
+ * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
+ *		Fixed message length bug in init_response
+ *
+ * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
+ *		Fixed rndis_rm_hdr length bug.
+ *
+ * Copyright (C) 2004 by David Brownell
+ *		updates to merge with Linux 2.6, better match RNDIS spec
+ */
+
+#include <common.h>
+#include <log.h>
+#include <net.h>
+#include <malloc.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+
+#undef	RNDIS_PM
+#undef	RNDIS_WAKEUP
+#undef	VERBOSE
+
+#include "rndis.h"
+
+/*
+ * The driver for your USB chip needs to support ep0 OUT to work with
+ * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
+ *
+ * Windows hosts need an INF file like Documentation/usb/linux.inf
+ * and will be happier if you provide the host_addr module parameter.
+ */
+
+#define RNDIS_MAX_CONFIGS	1
+
+static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
+
+/* Driver Version */
+static const __le32 rndis_driver_version = __constant_cpu_to_le32(1);
+
+/* Function Prototypes */
+static rndis_resp_t *rndis_add_response(int configNr, u32 length);
+
+
+/* supported OIDs */
+static const u32 oid_supported_list[] = {
+	/* the general stuff */
+	OID_GEN_SUPPORTED_LIST,
+	OID_GEN_HARDWARE_STATUS,
+	OID_GEN_MEDIA_SUPPORTED,
+	OID_GEN_MEDIA_IN_USE,
+	OID_GEN_MAXIMUM_FRAME_SIZE,
+	OID_GEN_LINK_SPEED,
+	OID_GEN_TRANSMIT_BLOCK_SIZE,
+	OID_GEN_RECEIVE_BLOCK_SIZE,
+	OID_GEN_VENDOR_ID,
+	OID_GEN_VENDOR_DESCRIPTION,
+	OID_GEN_VENDOR_DRIVER_VERSION,
+	OID_GEN_CURRENT_PACKET_FILTER,
+	OID_GEN_MAXIMUM_TOTAL_SIZE,
+	OID_GEN_MEDIA_CONNECT_STATUS,
+	OID_GEN_PHYSICAL_MEDIUM,
+#if 0
+	OID_GEN_RNDIS_CONFIG_PARAMETER,
+#endif
+
+	/* the statistical stuff */
+	OID_GEN_XMIT_OK,
+	OID_GEN_RCV_OK,
+	OID_GEN_XMIT_ERROR,
+	OID_GEN_RCV_ERROR,
+	OID_GEN_RCV_NO_BUFFER,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_GEN_DIRECTED_BYTES_XMIT,
+	OID_GEN_DIRECTED_FRAMES_XMIT,
+	OID_GEN_MULTICAST_BYTES_XMIT,
+	OID_GEN_MULTICAST_FRAMES_XMIT,
+	OID_GEN_BROADCAST_BYTES_XMIT,
+	OID_GEN_BROADCAST_FRAMES_XMIT,
+	OID_GEN_DIRECTED_BYTES_RCV,
+	OID_GEN_DIRECTED_FRAMES_RCV,
+	OID_GEN_MULTICAST_BYTES_RCV,
+	OID_GEN_MULTICAST_FRAMES_RCV,
+	OID_GEN_BROADCAST_BYTES_RCV,
+	OID_GEN_BROADCAST_FRAMES_RCV,
+	OID_GEN_RCV_CRC_ERROR,
+	OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+	/* mandatory 802.3 */
+	/* the general stuff */
+	OID_802_3_PERMANENT_ADDRESS,
+	OID_802_3_CURRENT_ADDRESS,
+	OID_802_3_MULTICAST_LIST,
+	OID_802_3_MAC_OPTIONS,
+	OID_802_3_MAXIMUM_LIST_SIZE,
+
+	/* the statistical stuff */
+	OID_802_3_RCV_ERROR_ALIGNMENT,
+	OID_802_3_XMIT_ONE_COLLISION,
+	OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_802_3_XMIT_DEFERRED,
+	OID_802_3_XMIT_MAX_COLLISIONS,
+	OID_802_3_RCV_OVERRUN,
+	OID_802_3_XMIT_UNDERRUN,
+	OID_802_3_XMIT_HEARTBEAT_FAILURE,
+	OID_802_3_XMIT_TIMES_CRS_LOST,
+	OID_802_3_XMIT_LATE_COLLISIONS,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* PM and wakeup are mandatory for USB: */
+
+	/* power management */
+	OID_PNP_CAPABILITIES,
+	OID_PNP_QUERY_POWER,
+	OID_PNP_SET_POWER,
+
+#ifdef	RNDIS_WAKEUP
+	/* wake up host */
+	OID_PNP_ENABLE_WAKE_UP,
+	OID_PNP_ADD_WAKE_UP_PATTERN,
+	OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif	/* RNDIS_WAKEUP */
+#endif	/* RNDIS_PM */
+};
+
+
+/* NDIS Functions */
+static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
+				unsigned buf_len, rndis_resp_t *r)
+{
+	int				retval = -ENOTSUPP;
+	u32				length = 4;	/* usually */
+	__le32				*outbuf;
+	int				i, count;
+	rndis_query_cmplt_type		*resp;
+	rndis_params			*params;
+
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_query_cmplt_type *) r->buf;
+
+	if (!resp)
+		return -ENOMEM;
+
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+	if (buf_len) {
+		debug("query OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			debug("%03d: %08x %08x %08x %08x\n", i,
+				get_unaligned_le32(&buf[i]),
+				get_unaligned_le32(&buf[i + 4]),
+				get_unaligned_le32(&buf[i + 8]),
+				get_unaligned_le32(&buf[i + 12]));
+		}
+	}
+#endif
+
+	/* response goes here, right after the header */
+	outbuf = (__le32 *) &resp[1];
+	resp->InformationBufferOffset = __constant_cpu_to_le32(16);
+
+	params = &rndis_per_dev_params[configNr];
+	switch (OID) {
+
+	/* general oids (table 4-1) */
+
+	/* mandatory */
+	case OID_GEN_SUPPORTED_LIST:
+		debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__);
+		length = sizeof(oid_supported_list);
+		count  = length / sizeof(u32);
+		for (i = 0; i < count; i++)
+			outbuf[i] = cpu_to_le32(oid_supported_list[i]);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_HARDWARE_STATUS:
+		debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__);
+		/*
+		 * Bogus question!
+		 * Hardware must be ready to receive high level protocols.
+		 * BTW:
+		 * reddite ergo quae sunt Caesaris Caesari
+		 * et quae sunt Dei Deo!
+		 */
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_MEDIA_SUPPORTED:
+		debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__);
+		*outbuf = cpu_to_le32(params->medium);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_MEDIA_IN_USE:
+		debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__);
+		/* one medium, one transport... (maybe you do it better) */
+		*outbuf = cpu_to_le32(params->medium);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_MAXIMUM_FRAME_SIZE:
+		debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
+		if (params->dev) {
+			*outbuf = cpu_to_le32(params->mtu);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_LINK_SPEED:
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: OID_GEN_LINK_SPEED\n", __func__);
+#endif
+		if (params->media_state == NDIS_MEDIA_STATE_DISCONNECTED)
+			*outbuf = __constant_cpu_to_le32(0);
+		else
+			*outbuf = cpu_to_le32(params->speed);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_TRANSMIT_BLOCK_SIZE:
+		debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
+		if (params->dev) {
+			*outbuf = cpu_to_le32(params->mtu);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_RECEIVE_BLOCK_SIZE:
+		debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
+		if (params->dev) {
+			*outbuf = cpu_to_le32(params->mtu);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_VENDOR_ID:
+		debug("%s: OID_GEN_VENDOR_ID\n", __func__);
+		*outbuf = cpu_to_le32(params->vendorID);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_VENDOR_DESCRIPTION:
+		debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
+		length = strlen(params->vendorDescr);
+		memcpy(outbuf, params->vendorDescr, length);
+		retval = 0;
+		break;
+
+	case OID_GEN_VENDOR_DRIVER_VERSION:
+		debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
+		/* Created as LE */
+		*outbuf = rndis_driver_version;
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_CURRENT_PACKET_FILTER:
+		debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
+		*outbuf = cpu_to_le32(*params->filter);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_MAXIMUM_TOTAL_SIZE:
+		debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
+		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_GEN_MEDIA_CONNECT_STATUS:
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
+#endif
+		*outbuf = cpu_to_le32(params->media_state);
+		retval = 0;
+		break;
+
+	case OID_GEN_PHYSICAL_MEDIUM:
+		debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__);
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/*
+	 * The RNDIS specification is incomplete/wrong.   Some versions
+	 * of MS-Windows expect OIDs that aren't specified there.  Other
+	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
+	 */
+	case OID_GEN_MAC_OPTIONS:		/* from WinME */
+		debug("%s: OID_GEN_MAC_OPTIONS\n", __func__);
+		*outbuf = __constant_cpu_to_le32(
+				  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+				| NDIS_MAC_OPTION_FULL_DUPLEX);
+		retval = 0;
+		break;
+
+	/* statistics OIDs (table 4-2) */
+
+	/* mandatory */
+	case OID_GEN_XMIT_OK:
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: OID_GEN_XMIT_OK\n", __func__);
+#endif
+		if (params->stats) {
+			*outbuf = cpu_to_le32(
+					params->stats->tx_packets -
+					params->stats->tx_errors -
+					params->stats->tx_dropped);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_RCV_OK:
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: OID_GEN_RCV_OK\n", __func__);
+#endif
+		if (params->stats) {
+			*outbuf = cpu_to_le32(
+					params->stats->rx_packets -
+					params->stats->rx_errors -
+					params->stats->rx_dropped);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_XMIT_ERROR:
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: OID_GEN_XMIT_ERROR\n", __func__);
+#endif
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->tx_errors);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_RCV_ERROR:
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: OID_GEN_RCV_ERROR\n", __func__);
+#endif
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->rx_errors);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_GEN_RCV_NO_BUFFER:
+		debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->rx_dropped);
+			retval = 0;
+		}
+		break;
+
+#ifdef	RNDIS_OPTIONAL_STATS
+	case OID_GEN_DIRECTED_BYTES_XMIT:
+		debug("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__);
+		/*
+		 * Aunt Tilly's size of shoes
+		 * minus antarctica count of penguins
+		 * divided by weight of Alpha Centauri
+		 */
+		if (params->stats) {
+			*outbuf = cpu_to_le32(
+					(params->stats->tx_packets -
+					 params->stats->tx_errors -
+					 params->stats->tx_dropped)
+					* 123);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_DIRECTED_FRAMES_XMIT:
+		debug("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__);
+		/* dito */
+		if (params->stats) {
+			*outbuf = cpu_to_le32(
+					(params->stats->tx_packets -
+					 params->stats->tx_errors -
+					 params->stats->tx_dropped)
+					/ 123);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_MULTICAST_BYTES_XMIT:
+		debug("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->multicast * 1234);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_MULTICAST_FRAMES_XMIT:
+		debug("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->multicast);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_BROADCAST_BYTES_XMIT:
+		debug("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->tx_packets/42*255);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_BROADCAST_FRAMES_XMIT:
+		debug("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->tx_packets / 42);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_DIRECTED_BYTES_RCV:
+		debug("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__);
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	case OID_GEN_DIRECTED_FRAMES_RCV:
+		debug("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__);
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	case OID_GEN_MULTICAST_BYTES_RCV:
+		debug("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->multicast * 1111);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_MULTICAST_FRAMES_RCV:
+		debug("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->multicast);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_BROADCAST_BYTES_RCV:
+		debug("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->rx_packets/42*255);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_BROADCAST_FRAMES_RCV:
+		debug("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->rx_packets / 42);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_RCV_CRC_ERROR:
+		debug("%s: OID_GEN_RCV_CRC_ERROR\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->rx_crc_errors);
+			retval = 0;
+		}
+		break;
+
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+		debug("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__);
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+	/* ieee802.3 OIDs (table 4-3) */
+
+	/* mandatory */
+	case OID_802_3_PERMANENT_ADDRESS:
+		debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__);
+		if (params->dev) {
+			length = ETH_ALEN;
+			memcpy(outbuf, params->host_mac, length);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_802_3_CURRENT_ADDRESS:
+		debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__);
+		if (params->dev) {
+			length = ETH_ALEN;
+			memcpy(outbuf, params->host_mac, length);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_802_3_MULTICAST_LIST:
+		debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
+		/* Multicast base address only */
+		*outbuf = __constant_cpu_to_le32(0xE0000000);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_802_3_MAXIMUM_LIST_SIZE:
+		debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
+		/* Multicast base address only */
+		*outbuf = __constant_cpu_to_le32(1);
+		retval = 0;
+		break;
+
+	case OID_802_3_MAC_OPTIONS:
+		debug("%s: OID_802_3_MAC_OPTIONS\n", __func__);
+		break;
+
+	/* ieee802.3 statistics OIDs (table 4-4) */
+
+	/* mandatory */
+	case OID_802_3_RCV_ERROR_ALIGNMENT:
+		debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
+		if (params->stats) {
+			*outbuf = cpu_to_le32(params->stats->rx_frame_errors);
+			retval = 0;
+		}
+		break;
+
+	/* mandatory */
+	case OID_802_3_XMIT_ONE_COLLISION:
+		debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__);
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+
+	/* mandatory */
+	case OID_802_3_XMIT_MORE_COLLISIONS:
+		debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
+		*outbuf = __constant_cpu_to_le32(0);
+		retval = 0;
+		break;
+
+#ifdef	RNDIS_OPTIONAL_STATS
+	case OID_802_3_XMIT_DEFERRED:
+		debug("%s: OID_802_3_XMIT_DEFERRED\n", __func__);
+		/* TODO */
+		break;
+
+	case OID_802_3_XMIT_MAX_COLLISIONS:
+		debug("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__);
+		/* TODO */
+		break;
+
+	case OID_802_3_RCV_OVERRUN:
+		debug("%s: OID_802_3_RCV_OVERRUN\n", __func__);
+		/* TODO */
+		break;
+
+	case OID_802_3_XMIT_UNDERRUN:
+		debug("%s: OID_802_3_XMIT_UNDERRUN\n", __func__);
+		/* TODO */
+		break;
+
+	case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+		debug("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__);
+		/* TODO */
+		break;
+
+	case OID_802_3_XMIT_TIMES_CRS_LOST:
+		debug("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__);
+		/* TODO */
+		break;
+
+	case OID_802_3_XMIT_LATE_COLLISIONS:
+		debug("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__);
+		/* TODO */
+		break;
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* power management OIDs (table 4-5) */
+	case OID_PNP_CAPABILITIES:
+		debug("%s: OID_PNP_CAPABILITIES\n", __func__);
+
+		/* for now, no wakeup capabilities */
+		length = sizeof(struct NDIS_PNP_CAPABILITIES);
+		memset(outbuf, 0, length);
+		retval = 0;
+		break;
+	case OID_PNP_QUERY_POWER:
+		debug("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
+				get_unaligned_le32(buf) - 1);
+		/*
+		 * only suspend is a real power state, and
+		 * it can't be entered by OID_PNP_SET_POWER...
+		 */
+		length = 0;
+		retval = 0;
+		break;
+#endif
+
+	default:
+		debug("%s: query unknown OID 0x%08X\n", __func__, OID);
+	}
+	if (retval < 0)
+		length = 0;
+
+	resp->InformationBufferLength = cpu_to_le32(length);
+	r->length = length + sizeof *resp;
+	resp->MessageLength = cpu_to_le32(r->length);
+	return retval;
+}
+
+static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
+				rndis_resp_t *r)
+{
+	rndis_set_cmplt_type		*resp;
+	int				retval = -ENOTSUPP;
+	struct rndis_params		*params;
+#if (defined(DEBUG) && defined(DEBUG_VERBOSE)) || defined(RNDIS_PM)
+	int				i;
+#endif
+
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_set_cmplt_type *) r->buf;
+	if (!resp)
+		return -ENOMEM;
+
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+	if (buf_len) {
+		debug("set OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			debug("%03d: %08x %08x %08x %08x\n", i,
+				get_unaligned_le32(&buf[i]),
+				get_unaligned_le32(&buf[i + 4]),
+				get_unaligned_le32(&buf[i + 8]),
+				get_unaligned_le32(&buf[i + 12]));
+		}
+	}
+#endif
+
+	params = &rndis_per_dev_params[configNr];
+	switch (OID) {
+	case OID_GEN_CURRENT_PACKET_FILTER:
+
+		/*
+		 * these NDIS_PACKET_TYPE_* bitflags are shared with
+		 * cdc_filter; it's not RNDIS-specific
+		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
+		 *	PROMISCUOUS, DIRECTED,
+		 *	MULTICAST, ALL_MULTICAST, BROADCAST
+		 */
+		*params->filter = (u16) get_unaligned_le32(buf);
+		debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
+			__func__, *params->filter);
+
+		/*
+		 * this call has a significant side effect:  it's
+		 * what makes the packet flow start and stop, like
+		 * activating the CDC Ethernet altsetting.
+		 */
+#ifdef	RNDIS_PM
+update_linkstate:
+#endif
+		retval = 0;
+		if (*params->filter)
+			params->state = RNDIS_DATA_INITIALIZED;
+		else
+			params->state = RNDIS_INITIALIZED;
+		break;
+
+	case OID_802_3_MULTICAST_LIST:
+		/* I think we can ignore this */
+		debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
+		retval = 0;
+		break;
+#if 0
+	case OID_GEN_RNDIS_CONFIG_PARAMETER:
+		{
+		struct rndis_config_parameter	*param;
+		param = (struct rndis_config_parameter *) buf;
+		debug("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
+			__func__,
+			min(cpu_to_le32(param->ParameterNameLength), 80),
+			buf + param->ParameterNameOffset);
+		retval = 0;
+		}
+		break;
+#endif
+
+#ifdef	RNDIS_PM
+	case OID_PNP_SET_POWER:
+		/*
+		 * The only real power state is USB suspend, and RNDIS requests
+		 * can't enter it; this one isn't really about power.  After
+		 * resuming, Windows forces a reset, and then SET_POWER D0.
+		 * FIXME ... then things go batty; Windows wedges itself.
+		 */
+		i = get_unaligned_le32(buf);
+		debug("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
+		switch (i) {
+		case NdisDeviceStateD0:
+			*params->filter = params->saved_filter;
+			goto update_linkstate;
+		case NdisDeviceStateD3:
+		case NdisDeviceStateD2:
+		case NdisDeviceStateD1:
+			params->saved_filter = *params->filter;
+			retval = 0;
+			break;
+		}
+		break;
+
+#ifdef	RNDIS_WAKEUP
+	/*
+	 * no wakeup support advertised, so wakeup OIDs always fail:
+	 *  - OID_PNP_ENABLE_WAKE_UP
+	 *  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
+	 */
+#endif
+
+#endif	/* RNDIS_PM */
+
+	default:
+		debug("%s: set unknown OID 0x%08X, size %d\n",
+			__func__, OID, buf_len);
+	}
+
+	return retval;
+}
+
+/*
+ * Response Functions
+ */
+
+static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
+{
+	rndis_init_cmplt_type	*resp;
+	rndis_resp_t            *r;
+
+	if (!rndis_per_dev_params[configNr].dev)
+		return -ENOTSUPP;
+
+	r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_init_cmplt_type *) r->buf;
+
+	resp->MessageType = __constant_cpu_to_le32(
+			REMOTE_NDIS_INITIALIZE_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32(52);
+	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
+	resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
+	resp->MajorVersion = __constant_cpu_to_le32(RNDIS_MAJOR_VERSION);
+	resp->MinorVersion = __constant_cpu_to_le32(RNDIS_MINOR_VERSION);
+	resp->DeviceFlags = __constant_cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
+	resp->Medium = __constant_cpu_to_le32(RNDIS_MEDIUM_802_3);
+	resp->MaxPacketsPerTransfer = __constant_cpu_to_le32(1);
+	resp->MaxTransferSize = cpu_to_le32(
+		  rndis_per_dev_params[configNr].mtu
+		+ ETHER_HDR_SIZE
+		+ sizeof(struct rndis_packet_msg_type)
+		+ 22);
+	resp->PacketAlignmentFactor = __constant_cpu_to_le32(0);
+	resp->AFListOffset = __constant_cpu_to_le32(0);
+	resp->AFListSize = __constant_cpu_to_le32(0);
+
+	if (rndis_per_dev_params[configNr].ack)
+		rndis_per_dev_params[configNr].ack(
+			rndis_per_dev_params[configNr].dev);
+
+	return 0;
+}
+
+static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
+{
+	rndis_query_cmplt_type *resp;
+	rndis_resp_t            *r;
+
+	debug("%s: OID = %08X\n", __func__, get_unaligned_le32(&buf->OID));
+	if (!rndis_per_dev_params[configNr].dev)
+		return -ENOTSUPP;
+
+	/*
+	 * we need more memory:
+	 * gen_ndis_query_resp expects enough space for
+	 * rndis_query_cmplt_type followed by data.
+	 * oid_supported_list is the largest data reply
+	 */
+	r = rndis_add_response(configNr,
+		sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_query_cmplt_type *) r->buf;
+
+	resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT);
+	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
+
+	if (gen_ndis_query_resp(configNr, get_unaligned_le32(&buf->OID),
+			get_unaligned_le32(&buf->InformationBufferOffset)
+					+ 8 + (u8 *) buf,
+			get_unaligned_le32(&buf->InformationBufferLength),
+			r)) {
+		/* OID not supported */
+		resp->Status = __constant_cpu_to_le32(
+						RNDIS_STATUS_NOT_SUPPORTED);
+		resp->MessageLength = __constant_cpu_to_le32(sizeof *resp);
+		resp->InformationBufferLength = __constant_cpu_to_le32(0);
+		resp->InformationBufferOffset = __constant_cpu_to_le32(0);
+	} else
+		resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+	if (rndis_per_dev_params[configNr].ack)
+		rndis_per_dev_params[configNr].ack(
+			rndis_per_dev_params[configNr].dev);
+	return 0;
+}
+
+static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
+{
+	u32			BufLength, BufOffset;
+	rndis_set_cmplt_type	*resp;
+	rndis_resp_t		*r;
+
+	r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_set_cmplt_type *) r->buf;
+
+	BufLength = get_unaligned_le32(&buf->InformationBufferLength);
+	BufOffset = get_unaligned_le32(&buf->InformationBufferOffset);
+
+#ifdef	VERBOSE
+	debug("%s: Length: %d\n", __func__, BufLength);
+	debug("%s: Offset: %d\n", __func__, BufOffset);
+	debug("%s: InfoBuffer: ", __func__);
+
+	for (i = 0; i < BufLength; i++)
+		debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
+
+	debug("\n");
+#endif
+
+	resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_SET_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32(16);
+	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
+	if (gen_ndis_set_resp(configNr, get_unaligned_le32(&buf->OID),
+			((u8 *) buf) + 8 + BufOffset, BufLength, r))
+		resp->Status = __constant_cpu_to_le32(
+						RNDIS_STATUS_NOT_SUPPORTED);
+	else
+		resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+	if (rndis_per_dev_params[configNr].ack)
+		rndis_per_dev_params[configNr].ack(
+			rndis_per_dev_params[configNr].dev);
+
+	return 0;
+}
+
+static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
+{
+	rndis_reset_cmplt_type	*resp;
+	rndis_resp_t		*r;
+
+	r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_reset_cmplt_type *) r->buf;
+
+	resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_RESET_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32(16);
+	resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
+	/* resent information */
+	resp->AddressingReset = __constant_cpu_to_le32(1);
+
+	if (rndis_per_dev_params[configNr].ack)
+		rndis_per_dev_params[configNr].ack(
+			rndis_per_dev_params[configNr].dev);
+
+	return 0;
+}
+
+static int rndis_keepalive_response(int configNr,
+					rndis_keepalive_msg_type *buf)
+{
+	rndis_keepalive_cmplt_type	*resp;
+	rndis_resp_t			*r;
+
+	/* host "should" check only in RNDIS_DATA_INITIALIZED state */
+
+	r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_keepalive_cmplt_type *) r->buf;
+
+	resp->MessageType = __constant_cpu_to_le32(
+			REMOTE_NDIS_KEEPALIVE_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32(16);
+	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
+	resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+	if (rndis_per_dev_params[configNr].ack)
+		rndis_per_dev_params[configNr].ack(
+			rndis_per_dev_params[configNr].dev);
+
+	return 0;
+}
+
+
+/*
+ * Device to Host Comunication
+ */
+static int rndis_indicate_status_msg(int configNr, u32 status)
+{
+	rndis_indicate_status_msg_type	*resp;
+	rndis_resp_t			*r;
+
+	if (rndis_per_dev_params[configNr].state == RNDIS_UNINITIALIZED)
+		return -ENOTSUPP;
+
+	r = rndis_add_response(configNr,
+				sizeof(rndis_indicate_status_msg_type));
+	if (!r)
+		return -ENOMEM;
+	resp = (rndis_indicate_status_msg_type *) r->buf;
+
+	resp->MessageType = __constant_cpu_to_le32(
+			REMOTE_NDIS_INDICATE_STATUS_MSG);
+	resp->MessageLength = __constant_cpu_to_le32(20);
+	resp->Status = cpu_to_le32(status);
+	resp->StatusBufferLength = __constant_cpu_to_le32(0);
+	resp->StatusBufferOffset = __constant_cpu_to_le32(0);
+
+	if (rndis_per_dev_params[configNr].ack)
+		rndis_per_dev_params[configNr].ack(
+			rndis_per_dev_params[configNr].dev);
+	return 0;
+}
+
+int rndis_signal_connect(int configNr)
+{
+	rndis_per_dev_params[configNr].media_state
+			= NDIS_MEDIA_STATE_CONNECTED;
+	return rndis_indicate_status_msg(configNr,
+					  RNDIS_STATUS_MEDIA_CONNECT);
+}
+
+int rndis_signal_disconnect(int configNr)
+{
+	rndis_per_dev_params[configNr].media_state
+			= NDIS_MEDIA_STATE_DISCONNECTED;
+
+#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
+	return rndis_indicate_status_msg(configNr,
+					  RNDIS_STATUS_MEDIA_DISCONNECT);
+#else
+	return 0;
+#endif
+}
+
+void rndis_uninit(int configNr)
+{
+	u8 *buf;
+	u32 length;
+
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return;
+	rndis_per_dev_params[configNr].used = 0;
+	rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
+
+	/* drain the response queue */
+	while ((buf = rndis_get_next_response(configNr, &length)))
+		rndis_free_response(configNr, buf);
+}
+
+void rndis_set_host_mac(int configNr, const u8 *addr)
+{
+	rndis_per_dev_params[configNr].host_mac = addr;
+}
+
+enum rndis_state rndis_get_state(int configNr)
+{
+	if (configNr >= RNDIS_MAX_CONFIGS || configNr < 0)
+		return -ENOTSUPP;
+	return rndis_per_dev_params[configNr].state;
+}
+
+/*
+ * Message Parser
+ */
+int rndis_msg_parser(u8 configNr, u8 *buf)
+{
+	u32				MsgType, MsgLength;
+	__le32				*tmp;
+	struct rndis_params		*params;
+
+	debug("%s: configNr = %d, %p\n", __func__, configNr, buf);
+
+	if (!buf)
+		return -ENOMEM;
+
+	tmp = (__le32 *) buf;
+	MsgType   = get_unaligned_le32(tmp++);
+	MsgLength = get_unaligned_le32(tmp++);
+
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return -ENOTSUPP;
+	params = &rndis_per_dev_params[configNr];
+
+	/*
+	 * NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+	 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+	 * and normal HC level polling to see if there's any IN traffic.
+	 */
+
+	/* For USB: responses may take up to 10 seconds */
+	switch (MsgType) {
+	case REMOTE_NDIS_INITIALIZE_MSG:
+		debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __func__);
+		params->state = RNDIS_INITIALIZED;
+		return  rndis_init_response(configNr,
+					(rndis_init_msg_type *) buf);
+
+	case REMOTE_NDIS_HALT_MSG:
+		debug("%s: REMOTE_NDIS_HALT_MSG\n", __func__);
+		params->state = RNDIS_UNINITIALIZED;
+		return 0;
+
+	case REMOTE_NDIS_QUERY_MSG:
+		return rndis_query_response(configNr,
+					(rndis_query_msg_type *) buf);
+
+	case REMOTE_NDIS_SET_MSG:
+		return rndis_set_response(configNr,
+					(rndis_set_msg_type *) buf);
+
+	case REMOTE_NDIS_RESET_MSG:
+		debug("%s: REMOTE_NDIS_RESET_MSG\n", __func__);
+		return rndis_reset_response(configNr,
+					(rndis_reset_msg_type *) buf);
+
+	case REMOTE_NDIS_KEEPALIVE_MSG:
+		/* For USB: host does this every 5 seconds */
+#if defined(DEBUG) && defined(DEBUG_VERBOSE)
+		debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __func__);
+#endif
+		return rndis_keepalive_response(configNr,
+					(rndis_keepalive_msg_type *) buf);
+
+	default:
+		/*
+		 * At least Windows XP emits some undefined RNDIS messages.
+		 * In one case those messages seemed to relate to the host
+		 * suspending itself.
+		 */
+		debug("%s: unknown RNDIS message 0x%08X len %d\n",
+			__func__ , MsgType, MsgLength);
+		{
+			unsigned i;
+			for (i = 0; i < MsgLength; i += 16) {
+				debug("%03d: "
+					" %02x %02x %02x %02x"
+					" %02x %02x %02x %02x"
+					" %02x %02x %02x %02x"
+					" %02x %02x %02x %02x"
+					"\n",
+					i,
+					buf[i], buf[i+1],
+						buf[i+2], buf[i+3],
+					buf[i+4], buf[i+5],
+						buf[i+6], buf[i+7],
+					buf[i+8], buf[i+9],
+						buf[i+10], buf[i+11],
+					buf[i+12], buf[i+13],
+						buf[i+14], buf[i+15]);
+			}
+		}
+		break;
+	}
+
+	return -ENOTSUPP;
+}
+
+#ifndef CONFIG_DM_ETH
+int rndis_register(int (*rndis_control_ack)(struct eth_device *))
+#else
+int rndis_register(int (*rndis_control_ack)(struct udevice *))
+#endif
+{
+	u8 i;
+
+	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+		if (!rndis_per_dev_params[i].used) {
+			rndis_per_dev_params[i].used = 1;
+			rndis_per_dev_params[i].ack = rndis_control_ack;
+			debug("%s: configNr = %d\n", __func__, i);
+			return i;
+		}
+	}
+	debug("%s failed\n", __func__);
+
+	return -1;
+}
+
+void rndis_deregister(int configNr)
+{
+	debug("%s: configNr = %d\n", __func__, configNr);
+
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return;
+	rndis_per_dev_params[configNr].used = 0;
+
+	return;
+}
+
+#ifndef CONFIG_DM_ETH
+int  rndis_set_param_dev(u8 configNr, struct eth_device *dev, int mtu,
+			 struct net_device_stats *stats, u16 *cdc_filter)
+#else
+int  rndis_set_param_dev(u8 configNr, struct udevice *dev, int mtu,
+			 struct net_device_stats *stats, u16 *cdc_filter)
+#endif
+{
+	debug("%s: configNr = %d\n", __func__, configNr);
+	if (!dev || !stats)
+		return -1;
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return -1;
+
+	rndis_per_dev_params[configNr].dev = dev;
+	rndis_per_dev_params[configNr].stats = stats;
+	rndis_per_dev_params[configNr].mtu = mtu;
+	rndis_per_dev_params[configNr].filter = cdc_filter;
+
+	return 0;
+}
+
+int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
+{
+	debug("%s: configNr = %d\n", __func__, configNr);
+	if (!vendorDescr)
+		return -1;
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return -1;
+
+	rndis_per_dev_params[configNr].vendorID = vendorID;
+	rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
+
+	return 0;
+}
+
+int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
+{
+	debug("%s: configNr = %d, %u %u\n", __func__, configNr, medium, speed);
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return -1;
+
+	rndis_per_dev_params[configNr].medium = medium;
+	rndis_per_dev_params[configNr].speed = speed;
+
+	return 0;
+}
+
+void rndis_add_hdr(void *buf, int length)
+{
+	struct rndis_packet_msg_type	*header;
+
+	header = buf;
+	memset(header, 0, sizeof *header);
+	header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
+	header->MessageLength = cpu_to_le32(length + sizeof *header);
+	header->DataOffset = __constant_cpu_to_le32(36);
+	header->DataLength = cpu_to_le32(length);
+}
+
+void rndis_free_response(int configNr, u8 *buf)
+{
+	rndis_resp_t		*r;
+	struct list_head	*act, *tmp;
+
+	list_for_each_safe(act, tmp,
+			&(rndis_per_dev_params[configNr].resp_queue))
+	{
+		r = list_entry(act, rndis_resp_t, list);
+		if (r && r->buf == buf) {
+			list_del(&r->list);
+			free(r);
+		}
+	}
+}
+
+u8 *rndis_get_next_response(int configNr, u32 *length)
+{
+	rndis_resp_t		*r;
+	struct list_head	*act, *tmp;
+
+	if (!length)
+		return NULL;
+
+	list_for_each_safe(act, tmp,
+			&(rndis_per_dev_params[configNr].resp_queue))
+	{
+		r = list_entry(act, rndis_resp_t, list);
+		if (!r->send) {
+			r->send = 1;
+			*length = r->length;
+			return r->buf;
+		}
+	}
+
+	return NULL;
+}
+
+static rndis_resp_t *rndis_add_response(int configNr, u32 length)
+{
+	rndis_resp_t	*r;
+
+	/* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
+	r = malloc(sizeof(rndis_resp_t) + length);
+	if (!r)
+		return NULL;
+
+	r->buf = (u8 *) (r + 1);
+	r->length = length;
+	r->send = 0;
+
+	list_add_tail(&r->list,
+		&(rndis_per_dev_params[configNr].resp_queue));
+	return r;
+}
+
+int rndis_rm_hdr(void *buf, int length)
+{
+	/* tmp points to a struct rndis_packet_msg_type */
+	__le32		*tmp = buf;
+	int		offs, len;
+
+	/* MessageType, MessageLength */
+	if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
+			!= get_unaligned(tmp++))
+		return -EINVAL;
+	tmp++;
+
+	/* DataOffset, DataLength */
+	offs = get_unaligned_le32(tmp++) + 8 /* offset of DataOffset */;
+	if (offs != sizeof(struct rndis_packet_msg_type))
+		debug("%s: unexpected DataOffset: %d\n", __func__, offs);
+	if (offs >= length)
+		return -EOVERFLOW;
+
+	len = get_unaligned_le32(tmp++);
+	if (len + sizeof(struct rndis_packet_msg_type) != length)
+		debug("%s: unexpected DataLength: %d, packet length=%d\n",
+				__func__, len, length);
+
+	memmove(buf, buf + offs, len);
+
+	return offs;
+}
+
+int rndis_init(void)
+{
+	u8 i;
+
+	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+		rndis_per_dev_params[i].confignr = i;
+		rndis_per_dev_params[i].used = 0;
+		rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
+		rndis_per_dev_params[i].media_state
+				= NDIS_MEDIA_STATE_DISCONNECTED;
+		INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
+	}
+
+	return 0;
+}
+
+void rndis_exit(void)
+{
+	/* Nothing to do */
+}
diff --git a/roms/u-boot/drivers/usb/gadget/rndis.h b/roms/u-boot/drivers/usb/gadget/rndis.h
new file mode 100644
index 000000000..e827af0be
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/rndis.h
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RNDIS	Definitions for Remote NDIS
+ *
+ * Authors:	Benedikt Spranger, Pengutronix
+ *		Robert Schwebel, Pengutronix
+ *
+ *		This software was originally developed in conformance with
+ *		Microsoft's Remote NDIS Specification License Agreement.
+ */
+
+#ifndef _USBGADGET_RNDIS_H
+#define _USBGADGET_RNDIS_H
+
+#include "ndis.h"
+
+/*
+ * By default rndis_signal_disconnect does not send status message about
+ * RNDIS disconnection to USB host (indicated as cable disconnected).
+ * Define RNDIS_COMPLETE_SIGNAL_DISCONNECT to send it.
+ * However, this will cause 1 sec delay on Ethernet device halt.
+ * Usually you do not need to define it. Mostly usable for debugging.
+ */
+
+#define RNDIS_MAXIMUM_FRAME_SIZE	1518
+#define RNDIS_MAX_TOTAL_SIZE		1558
+
+/* Remote NDIS Versions */
+#define RNDIS_MAJOR_VERSION		1
+#define RNDIS_MINOR_VERSION		0
+
+/* Status Values */
+#define RNDIS_STATUS_SUCCESS		0x00000000U	/* Success           */
+#define RNDIS_STATUS_FAILURE		0xC0000001U	/* Unspecified error */
+#define RNDIS_STATUS_INVALID_DATA	0xC0010015U	/* Invalid data      */
+#define RNDIS_STATUS_NOT_SUPPORTED	0xC00000BBU	/* Unsupported request */
+#define RNDIS_STATUS_MEDIA_CONNECT	0x4001000BU	/* Device connected  */
+#define RNDIS_STATUS_MEDIA_DISCONNECT	0x4001000CU	/* Device disconnected */
+/*
+ * For all not specified status messages:
+ * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx
+ */
+
+/* Message Set for Connectionless (802.3) Devices */
+#define REMOTE_NDIS_PACKET_MSG		0x00000001U
+#define REMOTE_NDIS_INITIALIZE_MSG	0x00000002U	/* Initialize device */
+#define REMOTE_NDIS_HALT_MSG		0x00000003U
+#define REMOTE_NDIS_QUERY_MSG		0x00000004U
+#define REMOTE_NDIS_SET_MSG		0x00000005U
+#define REMOTE_NDIS_RESET_MSG		0x00000006U
+#define REMOTE_NDIS_INDICATE_STATUS_MSG	0x00000007U
+#define REMOTE_NDIS_KEEPALIVE_MSG	0x00000008U
+
+/* Message completion */
+#define REMOTE_NDIS_INITIALIZE_CMPLT	0x80000002U
+#define REMOTE_NDIS_QUERY_CMPLT		0x80000004U
+#define REMOTE_NDIS_SET_CMPLT		0x80000005U
+#define REMOTE_NDIS_RESET_CMPLT		0x80000006U
+#define REMOTE_NDIS_KEEPALIVE_CMPLT	0x80000008U
+
+/* Device Flags */
+#define RNDIS_DF_CONNECTIONLESS		0x00000001U
+#define RNDIS_DF_CONNECTION_ORIENTED	0x00000002U
+
+#define RNDIS_MEDIUM_802_3		0x00000000U
+
+/* from drivers/net/sk98lin/h/skgepnmi.h */
+#define OID_PNP_CAPABILITIES			0xFD010100
+#define OID_PNP_SET_POWER			0xFD010101
+#define OID_PNP_QUERY_POWER			0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN		0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN		0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP			0xFD010106
+
+
+typedef struct rndis_init_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	MajorVersion;
+	__le32	MinorVersion;
+	__le32	MaxTransferSize;
+} rndis_init_msg_type;
+
+typedef struct rndis_init_cmplt_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+	__le32	MajorVersion;
+	__le32	MinorVersion;
+	__le32	DeviceFlags;
+	__le32	Medium;
+	__le32	MaxPacketsPerTransfer;
+	__le32	MaxTransferSize;
+	__le32	PacketAlignmentFactor;
+	__le32	AFListOffset;
+	__le32	AFListSize;
+} rndis_init_cmplt_type;
+
+typedef struct rndis_halt_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+} rndis_halt_msg_type;
+
+typedef struct rndis_query_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	OID;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+	__le32	DeviceVcHandle;
+} rndis_query_msg_type;
+
+typedef struct rndis_query_cmplt_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+} rndis_query_cmplt_type;
+
+typedef struct rndis_set_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	OID;
+	__le32	InformationBufferLength;
+	__le32	InformationBufferOffset;
+	__le32	DeviceVcHandle;
+} rndis_set_msg_type;
+
+typedef struct rndis_set_cmplt_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+} rndis_set_cmplt_type;
+
+typedef struct rndis_reset_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Reserved;
+} rndis_reset_msg_type;
+
+typedef struct rndis_reset_cmplt_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Status;
+	__le32	AddressingReset;
+} rndis_reset_cmplt_type;
+
+typedef struct rndis_indicate_status_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	Status;
+	__le32	StatusBufferLength;
+	__le32	StatusBufferOffset;
+} rndis_indicate_status_msg_type;
+
+typedef struct rndis_keepalive_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+} rndis_keepalive_msg_type;
+
+typedef struct rndis_keepalive_cmplt_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	RequestID;
+	__le32	Status;
+} rndis_keepalive_cmplt_type;
+
+struct rndis_packet_msg_type {
+	__le32	MessageType;
+	__le32	MessageLength;
+	__le32	DataOffset;
+	__le32	DataLength;
+	__le32	OOBDataOffset;
+	__le32	OOBDataLength;
+	__le32	NumOOBDataElements;
+	__le32	PerPacketInfoOffset;
+	__le32	PerPacketInfoLength;
+	__le32	VcHandle;
+	__le32	Reserved;
+} __attribute__ ((packed));
+
+struct rndis_config_parameter {
+	__le32	ParameterNameOffset;
+	__le32	ParameterNameLength;
+	__le32	ParameterType;
+	__le32	ParameterValueOffset;
+	__le32	ParameterValueLength;
+};
+
+/* implementation specific */
+enum rndis_state {
+	RNDIS_UNINITIALIZED,
+	RNDIS_INITIALIZED,
+	RNDIS_DATA_INITIALIZED,
+};
+
+typedef struct rndis_resp_t {
+	struct list_head	list;
+	u8			*buf;
+	u32			length;
+	int			send;
+} rndis_resp_t;
+
+typedef struct rndis_params {
+	u8			confignr;
+	u8			used;
+	u16			saved_filter;
+	enum rndis_state	state;
+	u32			medium;
+	u32			speed;
+	u32			media_state;
+
+	const u8		*host_mac;
+	u16			*filter;
+	struct net_device_stats *stats;
+	int			mtu;
+
+	u32			vendorID;
+	const char		*vendorDescr;
+#ifndef CONFIG_DM_ETH
+	struct eth_device	*dev;
+	int (*ack)(struct eth_device *);
+#else
+	struct udevice		*dev;
+	int (*ack)(struct udevice *);
+#endif
+	struct list_head	resp_queue;
+} rndis_params;
+
+/* RNDIS Message parser and other useless functions */
+int  rndis_msg_parser(u8 configNr, u8 *buf);
+enum rndis_state rndis_get_state(int configNr);
+void rndis_deregister(int configNr);
+#ifndef CONFIG_DM_ETH
+int  rndis_register(int (*rndis_control_ack)(struct eth_device *));
+int  rndis_set_param_dev(u8 configNr, struct eth_device *dev, int mtu,
+			 struct net_device_stats *stats, u16 *cdc_filter);
+#else
+int  rndis_register(int (*rndis_control_ack)(struct udevice *));
+int  rndis_set_param_dev(u8 configNr, struct udevice *dev, int mtu,
+			 struct net_device_stats *stats, u16 *cdc_filter);
+#endif
+int  rndis_set_param_vendor(u8 configNr, u32 vendorID,
+			    const char *vendorDescr);
+int  rndis_set_param_medium(u8 configNr, u32 medium, u32 speed);
+void rndis_add_hdr(void *bug, int length);
+int rndis_rm_hdr(void *bug, int length);
+u8   *rndis_get_next_response(int configNr, u32 *length);
+void rndis_free_response(int configNr, u8 *buf);
+
+void rndis_uninit(int configNr);
+int  rndis_signal_connect(int configNr);
+int  rndis_signal_disconnect(int configNr);
+extern void rndis_set_host_mac(int configNr, const u8 *addr);
+
+int rndis_init(void);
+void rndis_exit(void);
+
+#endif  /* _USBGADGET_RNDIS_H */
diff --git a/roms/u-boot/drivers/usb/gadget/storage_common.c b/roms/u-boot/drivers/usb/gadget/storage_common.c
new file mode 100644
index 000000000..5674e8fe4
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/storage_common.c
@@ -0,0 +1,617 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * storage_common.c -- Common definitions for mass storage functionality
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyeight (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ *
+ * Ported to u-boot:
+ * Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * Code refactoring & cleanup:
+ * Łukasz Majewski <l.majewski@samsung.com>
+ */
+
+
+/*
+ * This file requires the following identifiers used in USB strings to
+ * be defined (each of type pointer to char):
+ *  - fsg_string_manufacturer -- name of the manufacturer
+ *  - fsg_string_product      -- name of the product
+ *  - fsg_string_serial       -- product's serial
+ *  - fsg_string_config       -- name of the configuration
+ *  - fsg_string_interface    -- name of the interface
+ * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
+ * macro is defined prior to including this file.
+ */
+
+/*
+ * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
+ * fsg_hs_intr_in_desc objects as well as
+ * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
+ * macros are not defined.
+ *
+ * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
+ * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
+ * defined (as well as corresponding entries in string tables are
+ * missing) and FSG_STRING_INTERFACE has value of zero.
+ *
+ * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
+ */
+
+/*
+ * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
+ * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
+ * characters rather then a pointer to void.
+ */
+
+
+/* #include <asm/unaligned.h> */
+
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define FSG_VENDOR_ID	0x0525	/* NetChip */
+#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#undef VERBOSE_DEBUG
+#undef DUMP_MSGS
+#endif /* !DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#define VLDBG	LDBG
+#else
+#define VLDBG(lun, fmt, args...) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+/*
+#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args)
+#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
+#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args)
+#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)
+*/
+
+#define LDBG(lun, fmt, args...) do { } while (0)
+#define LERROR(lun, fmt, args...) do { } while (0)
+#define LWARN(lun, fmt, args...) do { } while (0)
+#define LINFO(lun, fmt, args...) do { } while (0)
+
+/*
+ * Keep those macros in sync with those in
+ * include/linux/usb/composite.h or else GCC will complain.  If they
+ * are identical (the same names of arguments, white spaces in the
+ * same places) GCC will allow redefinition otherwise (even if some
+ * white space is removed or added) warning will be issued.
+ *
+ * Those macros are needed here because File Storage Gadget does not
+ * include the composite.h header.  For composite gadgets those macros
+ * are redundant since composite.h is included any way.
+ *
+ * One could check whether those macros are already defined (which
+ * would indicate composite.h had been included) or not (which would
+ * indicate we were in FSG) but this is not done because a warning is
+ * desired if definitions here differ from the ones in composite.h.
+ *
+ * We want the definitions to match and be the same in File Storage
+ * Gadget as well as Mass Storage Function (and so composite gadgets
+ * using MSF).  If someone changes them in composite.h it will produce
+ * a warning in this file when building MSF.
+ */
+
+#define DBG(d, fmt, args...)     debug(fmt , ## args)
+#define VDBG(d, fmt, args...)    debug(fmt , ## args)
+/* #define ERROR(d, fmt, args...)   printf(fmt , ## args) */
+/* #define WARNING(d, fmt, args...) printf(fmt , ## args) */
+/* #define INFO(d, fmt, args...)    printf(fmt , ## args) */
+
+/* #define DBG(d, fmt, args...)     do { } while (0) */
+/* #define VDBG(d, fmt, args...)    do { } while (0) */
+#define ERROR(d, fmt, args...)   do { } while (0)
+#define WARNING(d, fmt, args...) do { } while (0)
+#define INFO(d, fmt, args...)    do { } while (0)
+
+#ifdef DUMP_MSGS
+
+/* dump_msg(fsg, const char * label, const u8 * buf, unsigned length); */
+# define dump_msg(fsg, label, buf, length) do {                         \
+	if (length < 512) {						\
+		DBG(fsg, "%s, length %u:\n", label, length);		\
+		print_hex_dump("", DUMP_PREFIX_OFFSET,	\
+			       16, 1, buf, length, 0);			\
+	}								\
+} while (0)
+
+#  define dump_cdb(fsg) do { } while (0)
+
+#else
+
+#  define dump_msg(fsg, /* const char * */ label, \
+		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
+
+#  ifdef VERBOSE_DEBUG
+
+#    define dump_cdb(fsg)						\
+	print_hex_dump("SCSI CDB: ", DUMP_PREFIX_NONE,	\
+		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\
+
+#  else
+
+#    define dump_cdb(fsg) do { } while (0)
+
+#  endif /* VERBOSE_DEBUG */
+
+#endif /* DUMP_MSGS */
+
+/*-------------------------------------------------------------------------*/
+
+/* SCSI device types */
+#define TYPE_DISK	0x00
+#define TYPE_CDROM	0x05
+
+/* USB protocol value = the transport method */
+#define USB_PR_CBI	0x00		/* Control/Bulk/Interrupt */
+#define USB_PR_CB	0x01		/* Control/Bulk w/o interrupt */
+#define USB_PR_BULK	0x50		/* Bulk-only */
+
+/* USB subclass value = the protocol encapsulation */
+#define USB_SC_RBC	0x01		/* Reduced Block Commands (flash) */
+#define USB_SC_8020	0x02		/* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
+#define USB_SC_QIC	0x03		/* QIC-157 (tape) */
+#define USB_SC_UFI	0x04		/* UFI (floppy) */
+#define USB_SC_8070	0x05		/* SFF-8070i (removable) */
+#define USB_SC_SCSI	0x06		/* Transparent SCSI */
+
+/* Bulk-only data structures */
+
+/* Command Block Wrapper */
+struct fsg_bulk_cb_wrap {
+	__le32	Signature;		/* Contains 'USBC' */
+	u32	Tag;			/* Unique per command id */
+	__le32	DataTransferLength;	/* Size of the data */
+	u8	Flags;			/* Direction in bit 7 */
+	u8	Lun;			/* LUN (normally 0) */
+	u8	Length;			/* Of the CDB, <= MAX_COMMAND_SIZE */
+	u8	CDB[16];		/* Command Data Block */
+};
+
+#define USB_BULK_CB_WRAP_LEN	31
+#define USB_BULK_CB_SIG		0x43425355	/* Spells out USBC */
+#define USB_BULK_IN_FLAG	0x80
+
+/* Command Status Wrapper */
+struct bulk_cs_wrap {
+	__le32	Signature;		/* Should = 'USBS' */
+	u32	Tag;			/* Same as original command */
+	__le32	Residue;		/* Amount not transferred */
+	u8	Status;			/* See below */
+};
+
+#define USB_BULK_CS_WRAP_LEN	13
+#define USB_BULK_CS_SIG		0x53425355	/* Spells out 'USBS' */
+#define USB_STATUS_PASS		0
+#define USB_STATUS_FAIL		1
+#define USB_STATUS_PHASE_ERROR	2
+
+/* Bulk-only class specific requests */
+#define USB_BULK_RESET_REQUEST		0xff
+#define USB_BULK_GET_MAX_LUN_REQUEST	0xfe
+
+/* CBI Interrupt data structure */
+struct interrupt_data {
+	u8	bType;
+	u8	bValue;
+};
+
+#define CBI_INTERRUPT_DATA_LEN		2
+
+/* CBI Accept Device-Specific Command request */
+#define USB_CBI_ADSC_REQUEST		0x00
+
+/* Length of a SCSI Command Data Block */
+#define MAX_COMMAND_SIZE	16
+
+/* SCSI commands that we recognize */
+#define SC_FORMAT_UNIT			0x04
+#define SC_INQUIRY			0x12
+#define SC_MODE_SELECT_6		0x15
+#define SC_MODE_SELECT_10		0x55
+#define SC_MODE_SENSE_6			0x1a
+#define SC_MODE_SENSE_10		0x5a
+#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL	0x1e
+#define SC_READ_6			0x08
+#define SC_READ_10			0x28
+#define SC_READ_12			0xa8
+#define SC_READ_CAPACITY		0x25
+#define SC_READ_FORMAT_CAPACITIES	0x23
+#define SC_READ_HEADER			0x44
+#define SC_READ_TOC			0x43
+#define SC_RELEASE			0x17
+#define SC_REQUEST_SENSE		0x03
+#define SC_RESERVE			0x16
+#define SC_SEND_DIAGNOSTIC		0x1d
+#define SC_START_STOP_UNIT		0x1b
+#define SC_SYNCHRONIZE_CACHE		0x35
+#define SC_TEST_UNIT_READY		0x00
+#define SC_VERIFY			0x2f
+#define SC_WRITE_6			0x0a
+#define SC_WRITE_10			0x2a
+#define SC_WRITE_12			0xaa
+
+/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
+#define SS_NO_SENSE				0
+#define SS_COMMUNICATION_FAILURE		0x040800
+#define SS_INVALID_COMMAND			0x052000
+#define SS_INVALID_FIELD_IN_CDB			0x052400
+#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100
+#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500
+#define SS_MEDIUM_NOT_PRESENT			0x023a00
+#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302
+#define SS_NOT_READY_TO_READY_TRANSITION	0x062800
+#define SS_RESET_OCCURRED			0x062900
+#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900
+#define SS_UNRECOVERED_READ_ERROR		0x031100
+#define SS_WRITE_ERROR				0x030c02
+#define SS_WRITE_PROTECTED			0x072700
+
+#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */
+#define ASC(x)		((u8) ((x) >> 8))
+#define ASCQ(x)		((u8) (x))
+
+struct device_attribute { int i; };
+#define ETOOSMALL	525
+
+#include <log.h>
+#include <usb_mass_storage.h>
+#include <dm/device_compat.h>
+
+/*-------------------------------------------------------------------------*/
+
+struct fsg_lun {
+	loff_t		file_length;
+	loff_t		num_sectors;
+
+	unsigned int	initially_ro:1;
+	unsigned int	ro:1;
+	unsigned int	removable:1;
+	unsigned int	cdrom:1;
+	unsigned int	prevent_medium_removal:1;
+	unsigned int	registered:1;
+	unsigned int	info_valid:1;
+	unsigned int	nofua:1;
+
+	u32		sense_data;
+	u32		sense_data_info;
+	u32		unit_attention_data;
+
+	struct device	dev;
+};
+
+#define fsg_lun_is_open(curlun)	((curlun)->filp != NULL)
+#if 0
+static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
+{
+	return container_of(dev, struct fsg_lun, dev);
+}
+#endif
+
+/* Big enough to hold our biggest descriptor */
+#define EP0_BUFSIZE	256
+#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */
+
+/* Number of buffers we will use.  2 is enough for double-buffering */
+#define FSG_NUM_BUFFERS	2
+
+/* Default size of buffer length. */
+#define FSG_BUFLEN	((u32)131072)
+
+/* Maximal number of LUNs supported in mass storage function */
+#define FSG_MAX_LUNS	8
+
+enum fsg_buffer_state {
+	BUF_STATE_EMPTY = 0,
+	BUF_STATE_FULL,
+	BUF_STATE_BUSY
+};
+
+struct fsg_buffhd {
+#ifdef FSG_BUFFHD_STATIC_BUFFER
+	char				buf[FSG_BUFLEN];
+#else
+	void				*buf;
+#endif
+	enum fsg_buffer_state		state;
+	struct fsg_buffhd		*next;
+
+	/*
+	 * The NetChip 2280 is faster, and handles some protocol faults
+	 * better, if we don't submit any short bulk-out read requests.
+	 * So we will record the intended request length here.
+	 */
+	unsigned int			bulk_out_intended_length;
+
+	struct usb_request		*inreq;
+	int				inreq_busy;
+	struct usb_request		*outreq;
+	int				outreq_busy;
+};
+
+enum fsg_state {
+	/* This one isn't used anywhere */
+	FSG_STATE_COMMAND_PHASE = -10,
+	FSG_STATE_DATA_PHASE,
+	FSG_STATE_STATUS_PHASE,
+
+	FSG_STATE_IDLE = 0,
+	FSG_STATE_ABORT_BULK_OUT,
+	FSG_STATE_RESET,
+	FSG_STATE_INTERFACE_CHANGE,
+	FSG_STATE_CONFIG_CHANGE,
+	FSG_STATE_DISCONNECT,
+	FSG_STATE_EXIT,
+	FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+	DATA_DIR_UNKNOWN = 0,
+	DATA_DIR_FROM_HOST,
+	DATA_DIR_TO_HOST,
+	DATA_DIR_NONE
+};
+
+/*-------------------------------------------------------------------------*/
+
+static inline u32 get_unaligned_be24(u8 *buf)
+{
+	return 0xffffff & (u32) get_unaligned_be32(buf - 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+enum {
+#ifndef FSG_NO_DEVICE_STRINGS
+	FSG_STRING_MANUFACTURER	= 1,
+	FSG_STRING_PRODUCT,
+	FSG_STRING_SERIAL,
+	FSG_STRING_CONFIG,
+#endif
+	FSG_STRING_INTERFACE
+};
+
+#ifndef FSG_NO_OTG
+static struct usb_otg_descriptor
+fsg_otg_desc = {
+	.bLength =		sizeof fsg_otg_desc,
+	.bDescriptorType =	USB_DT_OTG,
+
+	.bmAttributes =		USB_OTG_SRP,
+};
+#endif
+
+/* There is only one interface. */
+
+static struct usb_interface_descriptor
+fsg_intf_desc = {
+	.bLength =		sizeof fsg_intf_desc,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
+	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
+	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
+	.iInterface =		FSG_STRING_INTERFACE,
+};
+
+/*
+ * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
+ * interrupt-in.
+ */
+
+static struct usb_endpoint_descriptor
+fsg_fs_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	/* wMaxPacketSize set by autoconfiguration */
+};
+
+static struct usb_endpoint_descriptor
+fsg_fs_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	/* wMaxPacketSize set by autoconfiguration */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_fs_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(2),
+	.bInterval =		32,	/* frames -> 32 ms */
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	2
+#else
+#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	1
+#endif
+
+#endif
+
+static struct usb_descriptor_header *fsg_fs_function[] = {
+#ifndef FSG_NO_OTG
+	(struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+	(struct usb_descriptor_header *) &fsg_intf_desc,
+	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
+	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
+#ifndef FSG_NO_INTR_EP
+	(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
+#endif
+	NULL,
+};
+
+/*
+ * USB 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ *
+ * That means alternate endpoint descriptors (bigger packets)
+ * and a "device qualifier" ... plus more construction options
+ * for the configuration descriptor.
+ */
+static struct usb_endpoint_descriptor
+fsg_hs_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor
+fsg_hs_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+	.bInterval =		1,	/* NAK every 1 uframe */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_hs_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(2),
+	.bInterval =		9,	/* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	2
+#else
+#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	1
+#endif
+
+#endif
+
+static struct usb_descriptor_header *fsg_hs_function[] = {
+#ifndef FSG_NO_OTG
+	(struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+	(struct usb_descriptor_header *) &fsg_intf_desc,
+	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
+	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
+#ifndef FSG_NO_INTR_EP
+	(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
+#endif
+	NULL,
+};
+
+/* Maxpacket and other transfer characteristics vary by speed. */
+static struct usb_endpoint_descriptor *
+fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+		struct usb_endpoint_descriptor *hs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
+static struct usb_string		fsg_strings[] = {
+#ifndef FSG_NO_DEVICE_STRINGS
+	{FSG_STRING_MANUFACTURER,	fsg_string_manufacturer},
+	{FSG_STRING_PRODUCT,		fsg_string_product},
+	{FSG_STRING_SERIAL,		fsg_string_serial},
+	{FSG_STRING_CONFIG,		fsg_string_config},
+#endif
+	{FSG_STRING_INTERFACE,		fsg_string_interface},
+	{}
+};
+
+static struct usb_gadget_strings	fsg_stringtab = {
+	.language	= 0x0409,		/* en-us */
+	.strings	= fsg_strings,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * If the next two routines are called while the gadget is registered,
+ * the caller must own fsg->filesem for writing.
+ */
+
+static int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors,
+			const char *filename)
+{
+	int				ro;
+
+	/* R/W if we can, R/O if we must */
+	ro = curlun->initially_ro;
+
+	curlun->ro = ro;
+	curlun->file_length = num_sectors << 9;
+	curlun->num_sectors = num_sectors;
+	debug("open backing file: %s\n", filename);
+
+	return 0;
+}
+
+static void fsg_lun_close(struct fsg_lun *curlun)
+{
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sync the file data, don't bother with the metadata.
+ * This code was copied from fs/buffer.c:sys_fdatasync().
+ */
+static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
+{
+	return 0;
+}
+
+static void store_cdrom_address(u8 *dest, int msf, u32 addr)
+{
+	if (msf) {
+		/* Convert to Minutes-Seconds-Frames */
+		addr >>= 2;		/* Convert to 2048-byte frames */
+		addr += 2*75;		/* Lead-in occupies 2 seconds */
+		dest[3] = addr % 75;	/* Frames */
+		addr /= 75;
+		dest[2] = addr % 60;	/* Seconds */
+		addr /= 60;
+		dest[1] = addr;		/* Minutes */
+		dest[0] = 0;		/* Reserved */
+	} else {
+		/* Absolute sector */
+		put_unaligned_be32(addr, dest);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
diff --git a/roms/u-boot/drivers/usb/gadget/u_os_desc.h b/roms/u-boot/drivers/usb/gadget/u_os_desc.h
new file mode 100644
index 000000000..4dab4814a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/u_os_desc.h
@@ -0,0 +1,123 @@
+/*
+ * u_os_desc.h
+ *
+ * Utility definitions for "OS Descriptors" support
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __U_OS_DESC_H__
+#define __U_OS_DESC_H__
+
+#include <linux/utf.h>
+
+#define USB_EXT_PROP_DW_SIZE			0
+#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE	4
+#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH	8
+#define USB_EXT_PROP_B_PROPERTY_NAME		10
+#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH	10
+#define USB_EXT_PROP_B_PROPERTY_DATA		14
+
+#define USB_EXT_PROP_RESERVED			0
+#define USB_EXT_PROP_UNICODE			1
+#define USB_EXT_PROP_UNICODE_ENV		2
+#define USB_EXT_PROP_BINARY			3
+#define USB_EXT_PROP_LE32			4
+#define USB_EXT_PROP_BE32			5
+#define USB_EXT_PROP_UNICODE_LINK		6
+#define USB_EXT_PROP_UNICODE_MULTI		7
+
+static inline u8 *__usb_ext_prop_ptr(u8 *buf, size_t offset)
+{
+	return buf + offset;
+}
+
+static inline u8 *usb_ext_prop_size_ptr(u8 *buf)
+{
+	return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_SIZE);
+}
+
+static inline u8 *usb_ext_prop_type_ptr(u8 *buf)
+{
+	return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_TYPE);
+}
+
+static inline u8 *usb_ext_prop_name_len_ptr(u8 *buf)
+{
+	return __usb_ext_prop_ptr(buf, USB_EXT_PROP_W_PROPERTY_NAME_LENGTH);
+}
+
+static inline u8 *usb_ext_prop_name_ptr(u8 *buf)
+{
+	return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_NAME);
+}
+
+static inline u8 *usb_ext_prop_data_len_ptr(u8 *buf, size_t off)
+{
+	return __usb_ext_prop_ptr(buf,
+				  USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + off);
+}
+
+static inline u8 *usb_ext_prop_data_ptr(u8 *buf, size_t off)
+{
+	return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_DATA + off);
+}
+
+static inline void usb_ext_prop_put_size(u8 *buf, int dw_size)
+{
+	put_unaligned_le32(dw_size, usb_ext_prop_size_ptr(buf));
+}
+
+static inline void usb_ext_prop_put_type(u8 *buf, int type)
+{
+	put_unaligned_le32(type, usb_ext_prop_type_ptr(buf));
+}
+
+static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl)
+{
+	int result;
+
+	put_unaligned_le16(pnl, usb_ext_prop_name_len_ptr(buf));
+	memset(usb_ext_prop_name_ptr(buf), 0, 2 * strlen(name));
+	result = utf8_to_utf16le(name, (__le16 *)usb_ext_prop_name_ptr(buf),
+				 strlen(name));
+	if (result < 0)
+		return result;
+
+	put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl - 2]);
+
+	return pnl;
+}
+
+static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const char *data,
+					   int data_len)
+{
+	put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
+	memcpy(usb_ext_prop_data_ptr(buf, pnl), data, data_len);
+}
+
+static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string,
+					   int data_len)
+{
+	int result;
+	put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
+	memset(usb_ext_prop_data_ptr(buf, pnl), 0, 2 * (data_len >> 1));
+	result = utf8_to_utf16le(string, (__le16 *) usb_ext_prop_data_ptr(buf, pnl),
+				 data_len >> 1);
+	if (result < 0)
+		return result;
+
+	put_unaligned_le16(0,
+		&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len - 2]);
+
+	return data_len;
+}
+
+#endif /* __U_OS_DESC_H__ */
diff --git a/roms/u-boot/drivers/usb/gadget/udc/Makefile b/roms/u-boot/drivers/usb/gadget/udc/Makefile
new file mode 100644
index 000000000..95dbf0c82
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/udc/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# USB peripheral controller drivers
+
+ifndef CONFIG_$(SPL_)DM_USB_GADGET
+obj-$(CONFIG_USB_DWC3_GADGET)	+= udc-core.o
+endif
+
+obj-$(CONFIG_$(SPL_)DM_USB_GADGET)	+= udc-core.o
+obj-$(CONFIG_$(SPL_)DM) += udc-uclass.o
diff --git a/roms/u-boot/drivers/usb/gadget/udc/udc-core.c b/roms/u-boot/drivers/usb/gadget/udc/udc-core.c
new file mode 100644
index 000000000..7f73926cb
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/udc/udc-core.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * udc-core.c - Core UDC Framework
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * Taken from Linux Kernel v3.19-rc1 (drivers/usb/gadget/udc-core.c) and ported
+ * to uboot.
+ *
+ * commit 02e8c96627 : usb: gadget: udc: core: prepend udc_attach_driver with
+ *		       usb_
+ */
+
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/compat.h>
+#include <malloc.h>
+#include <asm/cache.h>
+#include <linux/dma-mapping.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/**
+ * struct usb_udc - describes one usb device controller
+ * @driver - the gadget driver pointer. For use by the class code
+ * @dev - the child device to the actual controller
+ * @gadget - the gadget. For use by the class code
+ * @list - for use by the udc class driver
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_udc {
+	struct usb_gadget_driver	*driver;
+	struct usb_gadget		*gadget;
+	struct device			dev;
+	struct list_head		list;
+};
+
+static struct class *udc_class;
+static LIST_HEAD(udc_list);
+DEFINE_MUTEX(udc_lock);
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_map_request(struct usb_gadget *gadget,
+		struct usb_request *req, int is_in)
+{
+	if (req->length == 0)
+		return 0;
+
+	req->dma = dma_map_single(req->buf, req->length,
+				  is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_map_request);
+
+void usb_gadget_unmap_request(struct usb_gadget *gadget,
+		struct usb_request *req, int is_in)
+{
+	if (req->length == 0)
+		return;
+
+	dma_unmap_single(req->dma, req->length,
+			 is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_giveback_request - give the request back to the gadget layer
+ * Context: in_interrupt()
+ *
+ * This is called by device controller drivers in order to return the
+ * completed request back to the gadget layer.
+ */
+void usb_gadget_giveback_request(struct usb_ep *ep,
+		struct usb_request *req)
+{
+	req->complete(ep, req);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
+
+/* ------------------------------------------------------------------------- */
+
+void usb_gadget_set_state(struct usb_gadget *gadget,
+		enum usb_device_state state)
+{
+	gadget->state = state;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_udc_reset - notifies the udc core that bus reset occurs
+ * @gadget: The gadget which bus reset occurs
+ * @driver: The gadget driver we want to notify
+ *
+ * If the udc driver has bus reset handler, it needs to call this when the bus
+ * reset occurs, it notifies the gadget driver that the bus reset occurs as
+ * well as updates gadget state.
+ */
+void usb_gadget_udc_reset(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	driver->reset(gadget);
+	usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
+
+/**
+ * usb_gadget_udc_start - tells usb device controller to start up
+ * @udc: The UDC to be started
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_udc_start(struct usb_udc *udc)
+{
+	return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
+}
+
+/**
+ * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_udc_stop(struct usb_udc *udc)
+{
+	udc->gadget->ops->udc_stop(udc->gadget);
+}
+
+/**
+ * usb_udc_release - release the usb_udc struct
+ * @dev: the dev member within usb_udc
+ *
+ * This is called by driver's core in order to free memory once the last
+ * reference is released.
+ */
+static void usb_udc_release(struct device *dev)
+{
+	struct usb_udc *udc;
+
+	udc = container_of(dev, struct usb_udc, dev);
+	kfree(udc);
+}
+
+/**
+ * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller driver's
+ * device.
+ * @gadget: the gadget to be added to the list.
+ * @release: a gadget release function.
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+		void (*release)(struct device *dev))
+{
+	struct usb_udc		*udc;
+	int			ret = -ENOMEM;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		goto err1;
+
+	dev_set_name(&gadget->dev, "gadget");
+	gadget->dev.parent = parent;
+
+	udc->dev.release = usb_udc_release;
+	udc->dev.class = udc_class;
+	udc->dev.parent = parent;
+
+	udc->gadget = gadget;
+
+	mutex_lock(&udc_lock);
+	list_add_tail(&udc->list, &udc_list);
+
+	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+
+err1:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
+
+static void usb_gadget_remove_driver(struct usb_udc *udc)
+{
+	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
+			udc->driver->function);
+
+	usb_gadget_disconnect(udc->gadget);
+	udc->driver->disconnect(udc->gadget);
+	udc->driver->unbind(udc->gadget);
+	usb_gadget_udc_stop(udc);
+
+	udc->driver = NULL;
+}
+
+/**
+ * usb_del_gadget_udc - deletes @udc from udc_list
+ * @gadget: the gadget to be removed.
+ *
+ * This, will call usb_gadget_unregister_driver() if
+ * the @udc is still busy.
+ */
+void usb_del_gadget_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc = NULL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			goto found;
+
+	dev_err(gadget->dev.parent, "gadget not registered.\n");
+	mutex_unlock(&udc_lock);
+
+	return;
+
+found:
+	dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
+
+	list_del(&udc->list);
+	mutex_unlock(&udc_lock);
+
+	if (udc->driver)
+		usb_gadget_remove_driver(udc);
+}
+EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_udc_set_speed - tells usb device controller speed supported by
+ *    current driver
+ * @udc: The device we want to set maximum speed
+ * @speed: The maximum speed to allowed to run
+ *
+ * This call is issued by the UDC Class driver before calling
+ * usb_gadget_udc_start() in order to make sure that we don't try to
+ * connect on speeds the gadget driver doesn't support.
+ */
+static inline void usb_gadget_udc_set_speed(struct usb_udc *udc,
+					    enum usb_device_speed speed)
+{
+	if (udc->gadget->ops->udc_set_speed) {
+		enum usb_device_speed s;
+
+		s = min(speed, udc->gadget->max_speed);
+		udc->gadget->ops->udc_set_speed(udc->gadget, s);
+	}
+}
+
+static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
+{
+	int ret;
+
+	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+			driver->function);
+
+	udc->driver = driver;
+
+	usb_gadget_udc_set_speed(udc, driver->speed);
+
+	ret = driver->bind(udc->gadget);
+	if (ret)
+		goto err1;
+	ret = usb_gadget_udc_start(udc);
+	if (ret) {
+		driver->unbind(udc->gadget);
+		goto err1;
+	}
+	usb_gadget_connect(udc->gadget);
+
+	return 0;
+err1:
+	if (ret != -EISNAM)
+		dev_err(&udc->dev, "failed to start %s: %d\n",
+			udc->driver->function, ret);
+	udc->driver = NULL;
+	return ret;
+}
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_udc		*udc = NULL;
+	int			ret;
+
+	if (!driver || !driver->bind || !driver->setup)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list) {
+		/* For now we take the first one */
+		if (!udc->driver)
+			goto found;
+	}
+
+	printf("couldn't find an available UDC\n");
+	mutex_unlock(&udc_lock);
+	return -ENODEV;
+found:
+	ret = udc_bind_to_driver(udc, driver);
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	return usb_gadget_probe_driver(driver);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_udc		*udc = NULL;
+	int			ret = -ENODEV;
+
+	if (!driver || !driver->unbind)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->driver == driver) {
+			usb_gadget_remove_driver(udc);
+			usb_gadget_set_state(udc->gadget,
+					USB_STATE_NOTATTACHED);
+			ret = 0;
+			break;
+		}
+
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
+
+MODULE_DESCRIPTION("UDC Framework");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/roms/u-boot/drivers/usb/gadget/udc/udc-uclass.c b/roms/u-boot/drivers/usb/gadget/udc/udc-uclass.c
new file mode 100644
index 000000000..dbc354e84
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/udc/udc-uclass.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <linux/usb/gadget.h>
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+#define MAX_UDC_DEVICES 4
+static struct udevice *dev_array[MAX_UDC_DEVICES];
+int usb_gadget_initialize(int index)
+{
+	int ret;
+	struct udevice *dev = NULL;
+
+	if (index < 0 || index >= ARRAY_SIZE(dev_array))
+		return -EINVAL;
+	if (dev_array[index])
+		return 0;
+	ret = uclass_get_device_by_seq(UCLASS_USB_GADGET_GENERIC, index, &dev);
+	if (!dev || ret) {
+		ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, index, &dev);
+		if (!dev || ret) {
+			pr_err("No USB device found\n");
+			return -ENODEV;
+		}
+	}
+	dev_array[index] = dev;
+	return 0;
+}
+
+int usb_gadget_release(int index)
+{
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+	int ret;
+	if (index < 0 || index >= ARRAY_SIZE(dev_array))
+		return -EINVAL;
+
+	ret = device_remove(dev_array[index], DM_REMOVE_NORMAL);
+	if (!ret)
+		dev_array[index] = NULL;
+	return ret;
+#else
+	return -ENOSYS;
+#endif
+}
+
+int usb_gadget_handle_interrupts(int index)
+{
+	if (index < 0 || index >= ARRAY_SIZE(dev_array))
+		return -EINVAL;
+	return dm_usb_gadget_handle_interrupts(dev_array[index]);
+}
+#endif
+
+UCLASS_DRIVER(usb_gadget_generic) = {
+	.id		= UCLASS_USB_GADGET_GENERIC,
+	.name		= "usb",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+};
diff --git a/roms/u-boot/drivers/usb/gadget/usbstring.c b/roms/u-boot/drivers/usb/gadget/usbstring.c
new file mode 100644
index 000000000..e2464ad92
--- /dev/null
+++ b/roms/u-boot/drivers/usb/gadget/usbstring.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and
+ *                      Remy Bohmer <linux@bohmer.net>
+ */
+
+#include <common.h>
+#include <linux/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/utf.h>
+
+/**
+ * usb_gadget_get_string - fill out a string descriptor
+ * @table: of c strings encoded using UTF-8
+ * @id: string id, from low byte of wValue in get string descriptor
+ * @buf: at least 256 bytes
+ *
+ * Finds the UTF-8 string matching the ID, and converts it into a
+ * string descriptor in utf16-le.
+ * Returns length of descriptor (always even) or negative errno
+ *
+ * If your driver needs stings in multiple languages, you'll probably
+ * "switch (wIndex) { ... }"  in your ep0 string descriptor logic,
+ * using this routine after choosing which set of UTF-8 strings to use.
+ * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
+ * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
+ * characters (which are also widely used in C strings).
+ */
+int
+usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf)
+{
+	struct usb_string	*s;
+	int			len;
+
+	if (!table)
+		return -EINVAL;
+
+	/* descriptor 0 has the language id */
+	if (id == 0) {
+		buf[0] = 4;
+		buf[1] = USB_DT_STRING;
+		buf[2] = (u8) table->language;
+		buf[3] = (u8) (table->language >> 8);
+		return 4;
+	}
+	for (s = table->strings; s && s->s; s++)
+		if (s->id == id)
+			break;
+
+	/* unrecognized: stall. */
+	if (!s || !s->s)
+		return -EINVAL;
+
+	/* string descriptors have length, tag, then UTF16-LE text */
+	len = min((size_t) 126, strlen(s->s));
+	memset(buf + 2, 0, 2 * len);	/* zero all the bytes */
+	len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
+	if (len < 0)
+		return -EINVAL;
+	buf[0] = (len + 1) * 2;
+	buf[1] = USB_DT_STRING;
+	return buf[0];
+}
diff --git a/roms/u-boot/drivers/usb/host/Kconfig b/roms/u-boot/drivers/usb/host/Kconfig
new file mode 100644
index 000000000..f34cba239
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/Kconfig
@@ -0,0 +1,319 @@
+#
+# USB Host Controller Drivers
+#
+comment "USB Host Controller Drivers"
+
+config USB_HOST
+	bool
+
+config USB_XHCI_HCD
+	bool "xHCI HCD (USB 3.0) support"
+	select USB_HOST
+	---help---
+	  The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
+	  "SuperSpeed" host controller hardware.
+
+if USB_XHCI_HCD
+
+config USB_XHCI_DWC3
+	bool "DesignWare USB3 DRD Core Support"
+	help
+	  Say Y or if your system has a Dual Role SuperSpeed
+	  USB controller based on the DesignWare USB3 IP Core.
+
+config USB_XHCI_DWC3_OF_SIMPLE
+	bool "DesignWare USB3 DRD Generic OF Simple Glue Layer"
+	depends on DM_USB
+	default y if ARCH_ROCKCHIP
+	default y if DRA7XX
+	help
+	  Support USB2/3 functionality in simple SoC integrations with
+	  USB controller based on the DesignWare USB3 IP Core.
+
+config USB_XHCI_MTK
+	bool "Support for MediaTek on-chip xHCI USB controller"
+	depends on ARCH_MEDIATEK
+	help
+	  Enables support for the on-chip xHCI controller on MediaTek SoCs.
+
+config USB_XHCI_MVEBU
+	bool "MVEBU USB 3.0 support"
+	default y
+	depends on ARCH_MVEBU
+	select DM_REGULATOR
+	help
+	  Choose this option to add support for USB 3.0 driver on mvebu
+	  SoCs, which includes Armada8K, Armada3700 and other Armada
+	  family SoCs.
+
+config USB_XHCI_OCTEON
+	bool "Support for Marvell Octeon family on-chip xHCI USB controller"
+	depends on ARCH_OCTEON
+	default y
+	help
+	  Enables support for the on-chip xHCI controller on Marvell Octeon
+	  family SoCs. This is a driver for the dwc3 to provide the glue logic
+	  to configure the controller.
+
+config USB_XHCI_PCI
+	bool "Support for PCI-based xHCI USB controller"
+	depends on DM_USB
+	default y if X86
+	help
+	  Enables support for the PCI-based xHCI controller.
+
+config USB_XHCI_RCAR
+	bool "Renesas RCar USB 3.0 support"
+	default y
+	depends on ARCH_RMOBILE
+	help
+	  Choose this option to add support for USB 3.0 driver on Renesas
+	  RCar Gen3 SoCs.
+
+config USB_XHCI_STI
+	bool "Support for STMicroelectronics STiH407 family on-chip xHCI USB controller"
+	depends on ARCH_STI
+	default y
+	help
+	  Enables support for the on-chip xHCI controller on STMicroelectronics
+	  STiH407 family SoCs. This is a driver for the dwc3 to provide the glue logic
+	  to configure the controller.
+
+config USB_XHCI_DRA7XX_INDEX
+	int "DRA7XX xHCI USB index"
+	range 0 1
+	default 0
+	depends on DRA7XX
+	help
+	  Select the DRA7XX xHCI USB index.
+	  Current supported values: 0, 1.
+
+config USB_XHCI_FSL
+	bool "Support for NXP Layerscape on-chip xHCI USB controller"
+	default y if ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2
+	depends on !SPL_NO_USB
+	help
+	  Enables support for the on-chip xHCI controller on NXP Layerscape SoCs.
+
+config USB_XHCI_BRCM
+	bool "Broadcom USB3 Host XHCI controller"
+	depends on DM_USB
+	help
+	  USB controller based on the Broadcom USB3 IP Core.
+	  Supports USB2/3 functionality.
+
+endif # USB_XHCI_HCD
+
+config USB_EHCI_HCD
+	bool "EHCI HCD (USB 2.0) support"
+	default y if ARCH_MX5 || ARCH_MX6
+	select USB_HOST
+	---help---
+	  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
+	  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
+	  If your USB host controller supports USB 2.0, you will likely want to
+	  configure this Host Controller Driver.
+
+	  EHCI controllers are packaged with "companion" host controllers (OHCI
+	  or UHCI) to handle USB 1.1 devices connected to root hub ports.  Ports
+	  will connect to EHCI if the device is high speed, otherwise they
+	  connect to a companion controller.  If you configure EHCI, you should
+	  probably configure the OHCI (for NEC and some other vendors) USB Host
+	  Controller Driver or UHCI (for Via motherboards) Host Controller
+	  Driver too.
+
+	  You may want to read <file:Documentation/usb/ehci.txt>.
+
+if USB_EHCI_HCD
+
+config USB_EHCI_ATMEL
+	bool  "Support for Atmel on-chip EHCI USB controller"
+	depends on ARCH_AT91
+	default y
+	---help---
+	  Enables support for the on-chip EHCI controller on Atmel chips.
+
+config USB_EHCI_MARVELL
+	bool "Support for Marvell on-chip EHCI USB controller"
+	depends on ARCH_MVEBU || ARCH_KIRKWOOD || ARCH_ORION5X
+	default y
+	---help---
+	  Enables support for the on-chip EHCI controller on MVEBU SoCs.
+
+config USB_EHCI_MX5
+	bool "Support for i.MX5 on-chip EHCI USB controller"
+	depends on ARCH_MX5
+	default n
+	help
+	  Enables support for the on-chip EHCI controller on i.MX5 SoCs.
+
+config USB_EHCI_MX6
+	bool "Support for i.MX6/i.MX7ULP on-chip EHCI USB controller"
+	depends on ARCH_MX6 || ARCH_MX7ULP || ARCH_IMXRT
+	default y
+	---help---
+	  Enables support for the on-chip EHCI controller on i.MX6 SoCs.
+
+config USB_EHCI_MX7
+	bool "Support for i.MX7 on-chip EHCI USB controller"
+	depends on ARCH_MX7 || IMX8M
+	select PHY if IMX8M
+	select NOP_PHY if IMX8M
+	default y
+	---help---
+	  Enables support for the on-chip EHCI controller on i.MX7 SoCs.
+
+config USB_EHCI_OMAP
+	bool "Support for OMAP3+ on-chip EHCI USB controller"
+	depends on ARCH_OMAP2PLUS
+	default y
+	---help---
+	  Enables support for the on-chip EHCI controller on OMAP3 and later
+	  SoCs.
+
+config USB_EHCI_VF
+	bool "Support for Vybrid on-chip EHCI USB controller"
+	depends on ARCH_VF610
+	default y
+	help
+	  Enables support for the on-chip EHCI controller on Vybrid SoCs.
+
+if USB_EHCI_MX6 || USB_EHCI_MX7
+
+config MXC_USB_OTG_HACTIVE
+	bool "USB Power pin high active"
+	---help---
+	  Set the USB Power pin polarity to be high active (PWR_POL)
+
+endif
+
+config USB_EHCI_MSM
+	bool "Support for Qualcomm on-chip EHCI USB controller"
+	depends on DM_USB
+	select USB_ULPI_VIEWPORT
+	select MSM8916_USB_PHY
+	default n
+	---help---
+	  Enables support for the on-chip EHCI controller on Qualcomm
+	  Snapdragon SoCs.
+
+config USB_EHCI_PCI
+	bool "Support for PCI-based EHCI USB controller"
+	default y if X86
+	help
+	  Enables support for the PCI-based EHCI controller.
+
+config USB_EHCI_TEGRA
+	bool "Support for NVIDIA Tegra on-chip EHCI USB controller"
+	depends on ARCH_TEGRA
+	---help---
+	  Enable support for Tegra on-chip EHCI USB controller
+
+config USB_EHCI_ZYNQ
+	bool "Support for Xilinx Zynq on-chip EHCI USB controller"
+	default y if ARCH_ZYNQ
+	---help---
+	  Enable support for Zynq on-chip EHCI USB controller
+
+config USB_EHCI_GENERIC
+	bool "Support for generic EHCI USB controller"
+	depends on OF_CONTROL
+	depends on DM_USB
+	default ARCH_SUNXI
+	default n
+	---help---
+	  Enables support for generic EHCI controller.
+
+config USB_EHCI_FSL
+	bool  "Support for FSL on-chip EHCI USB controller"
+	default n
+	select  CONFIG_EHCI_HCD_INIT_AFTER_RESET
+	---help---
+	  Enables support for the on-chip EHCI controller on FSL chips.
+endif # USB_EHCI_HCD
+
+config USB_OHCI_HCD
+	bool "OHCI HCD (USB 1.1) support"
+	---help---
+	  The Open Host Controller Interface (OHCI) is a standard for accessing
+	  USB 1.1 host controller hardware.  It does more in hardware than Intel's
+	  UHCI specification.  If your USB host controller follows the OHCI spec,
+	  say Y.  On most non-x86 systems, and on x86 hardware that's not using a
+	  USB controller from Intel or VIA, this is appropriate.  If your host
+	  controller doesn't use PCI, this is probably appropriate.  For a PCI
+	  based system where you're not sure, the "lspci -v" entry will list the
+	  right "prog-if" for your USB controller(s):  EHCI, OHCI, or UHCI.
+
+config USB_OHCI_PCI
+	bool "Support for PCI-based OHCI USB controller"
+	depends on DM_USB
+	default n
+	help
+	  Enables support for the PCI-based OHCI controller.
+
+if USB_OHCI_HCD
+
+config USB_OHCI_GENERIC
+	bool "Support for generic OHCI USB controller"
+	depends on OF_CONTROL
+	depends on DM_USB
+	default ARCH_SUNXI
+	select USB_HOST
+	---help---
+	  Enables support for generic OHCI controller.
+
+config USB_OHCI_DA8XX
+	bool "Support for da850 OHCI USB controller"
+	help
+	  Enable support for the da850 USB controller.
+
+endif # USB_OHCI_HCD
+
+config USB_UHCI_HCD
+	bool "UHCI HCD (most Intel and VIA) support"
+	select USB_HOST
+	---help---
+	  The Universal Host Controller Interface is a standard by Intel for
+	  accessing the USB hardware in the PC (which is also called the USB
+	  host controller). If your USB host controller conforms to this
+	  standard, you may want to say Y, but see below. All recent boards
+	  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
+	  i810, i820) conform to this standard. Also all VIA PCI chipsets
+	  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
+	  133) and LEON/GRLIB SoCs with the GRUSBHC controller.
+	  If unsure, say Y.
+
+if USB_UHCI_HCD
+
+endif # USB_UHCI_HCD
+
+config USB_DWC2
+	bool "DesignWare USB2 Core support"
+	select USB_HOST
+	---help---
+	  The DesignWare USB 2.0 controller is compliant with the
+	  USB-Implementers Forum (USB-IF) USB 2.0 specifications.
+	  Hi-Speed (480 Mbps), Full-Speed (12 Mbps), and Low-Speed (1.5 Mbps)
+	  operation is compliant to the controller Supplement. If you want to
+	  enable this controller in host mode, say Y.
+
+if USB_DWC2
+config USB_DWC2_BUFFER_SIZE
+	int "Data buffer size in kB"
+	default 64
+	---help---
+	  By default 64 kB buffer is used but if amount of RAM avaialble on
+	  the target is not enough to accommodate allocation of buffer of
+	  that size it is possible to shrink it. Smaller sizes should be fine
+	  because larger transactions could be split in smaller ones.
+
+endif # USB_DWC2
+
+config USB_R8A66597_HCD
+	bool "Renesas R8A66597 USB Core support"
+	depends on OF_CONTROL
+	depends on DM_USB
+	select USB_HOST
+	---help---
+	  This enables support for the on-chip Renesas R8A66597 USB 2.0
+	  controller, present in various RZ and SH SoCs.
diff --git a/roms/u-boot/drivers/usb/host/Makefile b/roms/u-boot/drivers/usb/host/Makefile
new file mode 100644
index 000000000..a12e8f270
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/Makefile
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+ifdef CONFIG_$(SPL_)DM_USB
+obj-y += usb-uclass.o
+obj-$(CONFIG_SANDBOX) += usb-sandbox.o
+endif
+
+# ohci
+obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
+obj-$(CONFIG_USB_ATMEL) += ohci-at91.o
+obj-$(CONFIG_USB_OHCI_DA8XX) += ohci-da8xx.o
+obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+obj-$(CONFIG_USB_SL811HS) += sl811-hcd.o
+obj-$(CONFIG_USB_OHCI_EP93XX) += ohci-ep93xx.o
+obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o
+obj-$(CONFIG_USB_OHCI_PCI) += ohci-pci.o
+obj-$(CONFIG_USB_OHCI_GENERIC) += ohci-generic.o
+
+# echi
+obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
+obj-$(CONFIG_USB_EHCI_ARMADA100) += ehci-armada100.o utmi-armada100.o
+obj-$(CONFIG_USB_EHCI_ATMEL) += ehci-atmel.o
+obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
+obj-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
+obj-$(CONFIG_USB_EHCI_GENERIC) += ehci-generic.o
+obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
+obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
+obj-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
+obj-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o
+obj-$(CONFIG_USB_EHCI_MX6) += ehci-mx6.o
+obj-$(CONFIG_USB_EHCI_MX7) += ehci-mx6.o
+obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
+obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
+obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o
+obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
+obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
+obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
+obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
+obj-$(CONFIG_USB_EHCI_VF) += ehci-vf.o
+obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
+obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
+
+# xhci
+obj-$(CONFIG_USB_XHCI_BRCM) += xhci-brcm.o
+obj-$(CONFIG_USB_XHCI_HCD) += xhci.o xhci-mem.o xhci-ring.o
+obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o
+obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
+obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
+obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o
+obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
+obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
+obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
+obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
+obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o
+obj-$(CONFIG_USB_XHCI_STI) += dwc3-sti-glue.o
+obj-$(CONFIG_USB_XHCI_OCTEON) += dwc3-octeon-glue.o
+
+# designware
+obj-$(CONFIG_USB_DWC2) += dwc2.o
diff --git a/roms/u-boot/drivers/usb/host/dwc2.c b/roms/u-boot/drivers/usb/host/dwc2.c
new file mode 100644
index 000000000..43cc2e043
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/dwc2.c
@@ -0,0 +1,1490 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <phys2bus.h>
+#include <usb.h>
+#include <usbroothubdes.h>
+#include <wait_bit.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/usb/otg.h>
+#include <power/regulator.h>
+#include <reset.h>
+
+#include "dwc2.h"
+
+/* Use only HC channel 0. */
+#define DWC2_HC_CHANNEL			0
+
+#define DWC2_STATUS_BUF_SIZE		64
+#define DWC2_DATA_BUF_SIZE		(CONFIG_USB_DWC2_BUFFER_SIZE * 1024)
+
+#define MAX_DEVICE			16
+#define MAX_ENDPOINT			16
+
+struct dwc2_priv {
+#if CONFIG_IS_ENABLED(DM_USB)
+	uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
+	uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
+#ifdef CONFIG_DM_REGULATOR
+	struct udevice *vbus_supply;
+#endif
+	struct phy phy;
+	struct clk_bulk clks;
+#else
+	uint8_t *aligned_buffer;
+	uint8_t *status_buffer;
+#endif
+	u8 in_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+	u8 out_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+	struct dwc2_core_regs *regs;
+	int root_hub_devnum;
+	bool ext_vbus;
+	/*
+	 * The hnp/srp capability must be disabled if the platform
+	 * does't support hnp/srp. Otherwise the force mode can't work.
+	 */
+	bool hnp_srp_disable;
+	bool oc_disable;
+
+	struct reset_ctl_bulk	resets;
+};
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+/* We need cacheline-aligned buffers for DMA transfers and dcache support */
+DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE,
+		ARCH_DMA_MINALIGN);
+DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE,
+		ARCH_DMA_MINALIGN);
+
+static struct dwc2_priv local;
+#endif
+
+/*
+ * DWC2 IP interface
+ */
+
+/*
+ * Initializes the FSLSPClkSel field of the HCFG register
+ * depending on the PHY type.
+ */
+static void init_fslspclksel(struct dwc2_core_regs *regs)
+{
+	uint32_t phyclk;
+
+#if (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
+	phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
+#else
+	/* High speed PHY running at full speed or high speed */
+	phyclk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ;
+#endif
+
+#ifdef CONFIG_DWC2_ULPI_FS_LS
+	uint32_t hwcfg2 = readl(&regs->ghwcfg2);
+	uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
+			DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
+	uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
+			DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
+
+	if (hval == 2 && fval == 1)
+		phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
+#endif
+
+	clrsetbits_le32(&regs->host_regs.hcfg,
+			DWC2_HCFG_FSLSPCLKSEL_MASK,
+			phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET);
+}
+
+/*
+ * Flush a Tx FIFO.
+ *
+ * @param regs Programming view of DWC_otg controller.
+ * @param num Tx FIFO to flush.
+ */
+static void dwc_otg_flush_tx_fifo(struct udevice *dev,
+				  struct dwc2_core_regs *regs, const int num)
+{
+	int ret;
+
+	writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET),
+	       &regs->grstctl);
+	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_TXFFLSH,
+				false, 1000, false);
+	if (ret)
+		dev_info(dev, "%s: Timeout!\n", __func__);
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/*
+ * Flush Rx FIFO.
+ *
+ * @param regs Programming view of DWC_otg controller.
+ */
+static void dwc_otg_flush_rx_fifo(struct udevice *dev,
+				  struct dwc2_core_regs *regs)
+{
+	int ret;
+
+	writel(DWC2_GRSTCTL_RXFFLSH, &regs->grstctl);
+	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_RXFFLSH,
+				false, 1000, false);
+	if (ret)
+		dev_info(dev, "%s: Timeout!\n", __func__);
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/*
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+static void dwc_otg_core_reset(struct udevice *dev,
+			       struct dwc2_core_regs *regs)
+{
+	int ret;
+
+	/* Wait for AHB master IDLE state. */
+	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
+				true, 1000, false);
+	if (ret)
+		dev_info(dev, "%s: Timeout!\n", __func__);
+
+	/* Core Soft Reset */
+	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
+	ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
+				false, 1000, false);
+	if (ret)
+		dev_info(dev, "%s: Timeout!\n", __func__);
+
+	/*
+	 * Wait for core to come out of reset.
+	 * NOTE: This long sleep is _very_ important, otherwise the core will
+	 *       not stay in host mode after a connector ID change!
+	 */
+	mdelay(100);
+}
+
+#if CONFIG_IS_ENABLED(DM_USB) && defined(CONFIG_DM_REGULATOR)
+static int dwc_vbus_supply_init(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &priv->vbus_supply);
+	if (ret) {
+		debug("%s: No vbus supply\n", dev->name);
+		return 0;
+	}
+
+	ret = regulator_set_enable(priv->vbus_supply, true);
+	if (ret) {
+		dev_err(dev, "Error enabling vbus supply\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc_vbus_supply_exit(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (priv->vbus_supply) {
+		ret = regulator_set_enable(priv->vbus_supply, false);
+		if (ret) {
+			dev_err(dev, "Error disabling vbus supply\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+#else
+static int dwc_vbus_supply_init(struct udevice *dev)
+{
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int dwc_vbus_supply_exit(struct udevice *dev)
+{
+	return 0;
+}
+#endif
+#endif
+
+/*
+ * This function initializes the DWC_otg controller registers for
+ * host mode.
+ *
+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ *
+ * @param dev USB Device (NULL if driver model is not being used)
+ * @param regs Programming view of DWC_otg controller
+ *
+ */
+static void dwc_otg_core_host_init(struct udevice *dev,
+				   struct dwc2_core_regs *regs)
+{
+	uint32_t nptxfifosize = 0;
+	uint32_t ptxfifosize = 0;
+	uint32_t hprt0 = 0;
+	int i, ret, num_channels;
+
+	/* Restart the Phy Clock */
+	writel(0, &regs->pcgcctl);
+
+	/* Initialize Host Configuration Register */
+	init_fslspclksel(regs);
+#ifdef CONFIG_DWC2_DFLT_SPEED_FULL
+	setbits_le32(&regs->host_regs.hcfg, DWC2_HCFG_FSLSSUPP);
+#endif
+
+	/* Configure data FIFO sizes */
+#ifdef CONFIG_DWC2_ENABLE_DYNAMIC_FIFO
+	if (readl(&regs->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
+		/* Rx FIFO */
+		writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, &regs->grxfsiz);
+
+		/* Non-periodic Tx FIFO */
+		nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
+				DWC2_FIFOSIZE_DEPTH_OFFSET;
+		nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
+				DWC2_FIFOSIZE_STARTADDR_OFFSET;
+		writel(nptxfifosize, &regs->gnptxfsiz);
+
+		/* Periodic Tx FIFO */
+		ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
+				DWC2_FIFOSIZE_DEPTH_OFFSET;
+		ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
+				CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
+				DWC2_FIFOSIZE_STARTADDR_OFFSET;
+		writel(ptxfifosize, &regs->hptxfsiz);
+	}
+#endif
+
+	/* Clear Host Set HNP Enable in the OTG Control Register */
+	clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
+
+	/* Make sure the FIFOs are flushed. */
+	dwc_otg_flush_tx_fifo(dev, regs, 0x10);	/* All Tx FIFOs */
+	dwc_otg_flush_rx_fifo(dev, regs);
+
+	/* Flush out any leftover queued requests. */
+	num_channels = readl(&regs->ghwcfg2);
+	num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK;
+	num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET;
+	num_channels += 1;
+
+	for (i = 0; i < num_channels; i++)
+		clrsetbits_le32(&regs->hc_regs[i].hcchar,
+				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR,
+				DWC2_HCCHAR_CHDIS);
+
+	/* Halt all channels to put them into a known state. */
+	for (i = 0; i < num_channels; i++) {
+		clrsetbits_le32(&regs->hc_regs[i].hcchar,
+				DWC2_HCCHAR_EPDIR,
+				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
+		ret = wait_for_bit_le32(&regs->hc_regs[i].hcchar,
+					DWC2_HCCHAR_CHEN, false, 1000, false);
+		if (ret)
+			dev_info(dev, "%s: Timeout!\n", __func__);
+	}
+
+	/* Turn on the vbus power. */
+	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
+		hprt0 = readl(&regs->hprt0);
+		hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET);
+		hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG);
+		if (!(hprt0 & DWC2_HPRT0_PRTPWR)) {
+			hprt0 |= DWC2_HPRT0_PRTPWR;
+			writel(hprt0, &regs->hprt0);
+		}
+	}
+
+	if (dev)
+		dwc_vbus_supply_init(dev);
+}
+
+/*
+ * This function initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation.
+ *
+ * @param regs Programming view of the DWC_otg controller
+ */
+static void dwc_otg_core_init(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	struct dwc2_core_regs *regs = priv->regs;
+	uint32_t ahbcfg = 0;
+	uint32_t usbcfg = 0;
+	uint8_t brst_sz = CONFIG_DWC2_DMA_BURST_SIZE;
+
+	/* Common Initialization */
+	usbcfg = readl(&regs->gusbcfg);
+
+	/* Program the ULPI External VBUS bit if needed */
+	if (priv->ext_vbus) {
+		usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
+		if (!priv->oc_disable) {
+			usbcfg |= DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR |
+				  DWC2_GUSBCFG_INDICATOR_PASSTHROUGH;
+		}
+	} else {
+		usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
+	}
+
+	/* Set external TS Dline pulsing */
+#ifdef CONFIG_DWC2_TS_DLINE
+	usbcfg |= DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
+#else
+	usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
+#endif
+	writel(usbcfg, &regs->gusbcfg);
+
+	/* Reset the Controller */
+	dwc_otg_core_reset(dev, regs);
+
+	/*
+	 * This programming sequence needs to happen in FS mode before
+	 * any other programming occurs
+	 */
+#if defined(CONFIG_DWC2_DFLT_SPEED_FULL) && \
+	(CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
+	/* If FS mode with FS PHY */
+	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_PHYSEL);
+
+	/* Reset after a PHY select */
+	dwc_otg_core_reset(dev, regs);
+
+	/*
+	 * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
+	 * Also do this on HNP Dev/Host mode switches (done in dev_init
+	 * and host_init).
+	 */
+	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
+		init_fslspclksel(regs);
+
+#ifdef CONFIG_DWC2_I2C_ENABLE
+	/* Program GUSBCFG.OtgUtmifsSel to I2C */
+	setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL);
+
+	/* Program GI2CCTL.I2CEn */
+	clrsetbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN |
+			DWC2_GI2CCTL_I2CDEVADDR_MASK,
+			1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET);
+	setbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN);
+#endif
+
+#else
+	/* High speed PHY. */
+
+	/*
+	 * HS PHY parameters. These parameters are preserved during
+	 * soft reset so only program the first time. Do a soft reset
+	 * immediately after setting phyif.
+	 */
+	usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF);
+	usbcfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET;
+
+	if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) {	/* ULPI interface */
+#ifdef CONFIG_DWC2_PHY_ULPI_DDR
+		usbcfg |= DWC2_GUSBCFG_DDRSEL;
+#else
+		usbcfg &= ~DWC2_GUSBCFG_DDRSEL;
+#endif
+	} else {	/* UTMI+ interface */
+#if (CONFIG_DWC2_UTMI_WIDTH == 16)
+		usbcfg |= DWC2_GUSBCFG_PHYIF;
+#endif
+	}
+
+	writel(usbcfg, &regs->gusbcfg);
+
+	/* Reset after setting the PHY parameters */
+	dwc_otg_core_reset(dev, regs);
+#endif
+
+	usbcfg = readl(&regs->gusbcfg);
+	usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M);
+#ifdef CONFIG_DWC2_ULPI_FS_LS
+	uint32_t hwcfg2 = readl(&regs->ghwcfg2);
+	uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
+			DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
+	uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
+			DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
+	if (hval == 2 && fval == 1) {
+		usbcfg |= DWC2_GUSBCFG_ULPI_FSLS;
+		usbcfg |= DWC2_GUSBCFG_ULPI_CLK_SUS_M;
+	}
+#endif
+	if (priv->hnp_srp_disable)
+		usbcfg |= DWC2_GUSBCFG_FORCEHOSTMODE;
+
+	writel(usbcfg, &regs->gusbcfg);
+
+	/* Program the GAHBCFG Register. */
+	switch (readl(&regs->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) {
+	case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY:
+		break;
+	case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA:
+		while (brst_sz > 1) {
+			ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET);
+			ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK;
+			brst_sz >>= 1;
+		}
+
+#ifdef CONFIG_DWC2_DMA_ENABLE
+		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
+#endif
+		break;
+
+	case DWC2_HWCFG2_ARCHITECTURE_INT_DMA:
+		ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4;
+#ifdef CONFIG_DWC2_DMA_ENABLE
+		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
+#endif
+		break;
+	}
+
+	writel(ahbcfg, &regs->gahbcfg);
+
+	/* Program the capabilities in GUSBCFG Register */
+	usbcfg = 0;
+
+	if (!priv->hnp_srp_disable)
+		usbcfg |= DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP;
+#ifdef CONFIG_DWC2_IC_USB_CAP
+	usbcfg |= DWC2_GUSBCFG_IC_USB_CAP;
+#endif
+
+	setbits_le32(&regs->gusbcfg, usbcfg);
+}
+
+/*
+ * Prepares a host channel for transferring packets to/from a specific
+ * endpoint. The HCCHARn register is set up with the characteristics specified
+ * in _hc. Host channel interrupts that may need to be serviced while this
+ * transfer is in progress are enabled.
+ *
+ * @param regs Programming view of DWC_otg controller
+ * @param hc Information needed to initialize the host channel
+ */
+static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
+		struct usb_device *dev, uint8_t dev_addr, uint8_t ep_num,
+		uint8_t ep_is_in, uint8_t ep_type, uint16_t max_packet)
+{
+	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[hc_num];
+	uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) |
+			  (ep_num << DWC2_HCCHAR_EPNUM_OFFSET) |
+			  (ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) |
+			  (ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) |
+			  (max_packet << DWC2_HCCHAR_MPS_OFFSET);
+
+	if (dev->speed == USB_SPEED_LOW)
+		hcchar |= DWC2_HCCHAR_LSPDDEV;
+
+	/*
+	 * Program the HCCHARn register with the endpoint characteristics
+	 * for the current transfer.
+	 */
+	writel(hcchar, &hc_regs->hcchar);
+
+	/* Program the HCSPLIT register, default to no SPLIT */
+	writel(0, &hc_regs->hcsplt);
+}
+
+static void dwc_otg_hc_init_split(struct dwc2_hc_regs *hc_regs,
+				  uint8_t hub_devnum, uint8_t hub_port)
+{
+	uint32_t hcsplt = 0;
+
+	hcsplt = DWC2_HCSPLT_SPLTENA;
+	hcsplt |= hub_devnum << DWC2_HCSPLT_HUBADDR_OFFSET;
+	hcsplt |= hub_port << DWC2_HCSPLT_PRTADDR_OFFSET;
+
+	/* Program the HCSPLIT register for SPLITs */
+	writel(hcsplt, &hc_regs->hcsplt);
+}
+
+/*
+ * DWC2 to USB API interface
+ */
+/* Direction: In ; Request: Status */
+static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs,
+					   struct usb_device *dev, void *buffer,
+					   int txlen, struct devrequest *cmd)
+{
+	uint32_t hprt0 = 0;
+	uint32_t port_status = 0;
+	uint32_t port_change = 0;
+	int len = 0;
+	int stat = 0;
+
+	switch (cmd->requesttype & ~USB_DIR_IN) {
+	case 0:
+		*(uint16_t *)buffer = cpu_to_le16(1);
+		len = 2;
+		break;
+	case USB_RECIP_INTERFACE:
+	case USB_RECIP_ENDPOINT:
+		*(uint16_t *)buffer = cpu_to_le16(0);
+		len = 2;
+		break;
+	case USB_TYPE_CLASS:
+		*(uint32_t *)buffer = cpu_to_le32(0);
+		len = 4;
+		break;
+	case USB_RECIP_OTHER | USB_TYPE_CLASS:
+		hprt0 = readl(&regs->hprt0);
+		if (hprt0 & DWC2_HPRT0_PRTCONNSTS)
+			port_status |= USB_PORT_STAT_CONNECTION;
+		if (hprt0 & DWC2_HPRT0_PRTENA)
+			port_status |= USB_PORT_STAT_ENABLE;
+		if (hprt0 & DWC2_HPRT0_PRTSUSP)
+			port_status |= USB_PORT_STAT_SUSPEND;
+		if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT)
+			port_status |= USB_PORT_STAT_OVERCURRENT;
+		if (hprt0 & DWC2_HPRT0_PRTRST)
+			port_status |= USB_PORT_STAT_RESET;
+		if (hprt0 & DWC2_HPRT0_PRTPWR)
+			port_status |= USB_PORT_STAT_POWER;
+
+		if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == DWC2_HPRT0_PRTSPD_LOW)
+			port_status |= USB_PORT_STAT_LOW_SPEED;
+		else if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) ==
+			 DWC2_HPRT0_PRTSPD_HIGH)
+			port_status |= USB_PORT_STAT_HIGH_SPEED;
+
+		if (hprt0 & DWC2_HPRT0_PRTENCHNG)
+			port_change |= USB_PORT_STAT_C_ENABLE;
+		if (hprt0 & DWC2_HPRT0_PRTCONNDET)
+			port_change |= USB_PORT_STAT_C_CONNECTION;
+		if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG)
+			port_change |= USB_PORT_STAT_C_OVERCURRENT;
+
+		*(uint32_t *)buffer = cpu_to_le32(port_status |
+					(port_change << 16));
+		len = 4;
+		break;
+	default:
+		puts("unsupported root hub command\n");
+		stat = USB_ST_STALLED;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = stat;
+
+	return stat;
+}
+
+/* Direction: In ; Request: Descriptor */
+static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
+					       void *buffer, int txlen,
+					       struct devrequest *cmd)
+{
+	unsigned char data[32];
+	uint32_t dsc;
+	int len = 0;
+	int stat = 0;
+	uint16_t wValue = cpu_to_le16(cmd->value);
+	uint16_t wLength = cpu_to_le16(cmd->length);
+
+	switch (cmd->requesttype & ~USB_DIR_IN) {
+	case 0:
+		switch (wValue & 0xff00) {
+		case 0x0100:	/* device descriptor */
+			len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
+			memcpy(buffer, root_hub_dev_des, len);
+			break;
+		case 0x0200:	/* configuration descriptor */
+			len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
+			memcpy(buffer, root_hub_config_des, len);
+			break;
+		case 0x0300:	/* string descriptors */
+			switch (wValue & 0xff) {
+			case 0x00:
+				len = min3(txlen, (int)sizeof(root_hub_str_index0),
+					   (int)wLength);
+				memcpy(buffer, root_hub_str_index0, len);
+				break;
+			case 0x01:
+				len = min3(txlen, (int)sizeof(root_hub_str_index1),
+					   (int)wLength);
+				memcpy(buffer, root_hub_str_index1, len);
+				break;
+			}
+			break;
+		default:
+			stat = USB_ST_STALLED;
+		}
+		break;
+
+	case USB_TYPE_CLASS:
+		/* Root port config, set 1 port and nothing else. */
+		dsc = 0x00000001;
+
+		data[0] = 9;		/* min length; */
+		data[1] = 0x29;
+		data[2] = dsc & RH_A_NDP;
+		data[3] = 0;
+		if (dsc & RH_A_PSM)
+			data[3] |= 0x1;
+		if (dsc & RH_A_NOCP)
+			data[3] |= 0x10;
+		else if (dsc & RH_A_OCPM)
+			data[3] |= 0x8;
+
+		/* corresponds to data[4-7] */
+		data[5] = (dsc & RH_A_POTPGT) >> 24;
+		data[7] = dsc & RH_B_DR;
+		if (data[2] < 7) {
+			data[8] = 0xff;
+		} else {
+			data[0] += 2;
+			data[8] = (dsc & RH_B_DR) >> 8;
+			data[9] = 0xff;
+			data[10] = data[9];
+		}
+
+		len = min3(txlen, (int)data[0], (int)wLength);
+		memcpy(buffer, data, len);
+		break;
+	default:
+		puts("unsupported root hub command\n");
+		stat = USB_ST_STALLED;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = stat;
+
+	return stat;
+}
+
+/* Direction: In ; Request: Configuration */
+static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
+						  void *buffer, int txlen,
+						  struct devrequest *cmd)
+{
+	int len = 0;
+	int stat = 0;
+
+	switch (cmd->requesttype & ~USB_DIR_IN) {
+	case 0:
+		*(uint8_t *)buffer = 0x01;
+		len = 1;
+		break;
+	default:
+		puts("unsupported root hub command\n");
+		stat = USB_ST_STALLED;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = stat;
+
+	return stat;
+}
+
+/* Direction: In */
+static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv,
+				    struct usb_device *dev, void *buffer,
+				    int txlen, struct devrequest *cmd)
+{
+	switch (cmd->request) {
+	case USB_REQ_GET_STATUS:
+		return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer,
+						       txlen, cmd);
+	case USB_REQ_GET_DESCRIPTOR:
+		return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
+							   txlen, cmd);
+	case USB_REQ_GET_CONFIGURATION:
+		return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
+							      txlen, cmd);
+	default:
+		puts("unsupported root hub command\n");
+		return USB_ST_STALLED;
+	}
+}
+
+/* Direction: Out */
+static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv,
+				     struct usb_device *dev,
+				     void *buffer, int txlen,
+				     struct devrequest *cmd)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	int len = 0;
+	int stat = 0;
+	uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
+	uint16_t wValue = cpu_to_le16(cmd->value);
+
+	switch (bmrtype_breq & ~USB_DIR_IN) {
+	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
+	case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
+		break;
+
+	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		switch (wValue) {
+		case USB_PORT_FEAT_C_CONNECTION:
+			setbits_le32(&regs->hprt0, DWC2_HPRT0_PRTCONNDET);
+			break;
+		}
+		break;
+
+	case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			break;
+
+		case USB_PORT_FEAT_RESET:
+			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+					DWC2_HPRT0_PRTCONNDET |
+					DWC2_HPRT0_PRTENCHNG |
+					DWC2_HPRT0_PRTOVRCURRCHNG,
+					DWC2_HPRT0_PRTRST);
+			mdelay(50);
+			clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTRST);
+			break;
+
+		case USB_PORT_FEAT_POWER:
+			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+					DWC2_HPRT0_PRTCONNDET |
+					DWC2_HPRT0_PRTENCHNG |
+					DWC2_HPRT0_PRTOVRCURRCHNG,
+					DWC2_HPRT0_PRTRST);
+			break;
+
+		case USB_PORT_FEAT_ENABLE:
+			break;
+		}
+		break;
+	case (USB_REQ_SET_ADDRESS << 8):
+		priv->root_hub_devnum = wValue;
+		break;
+	case (USB_REQ_SET_CONFIGURATION << 8):
+		break;
+	default:
+		puts("unsupported root hub command\n");
+		stat = USB_ST_STALLED;
+	}
+
+	len = min(len, txlen);
+
+	dev->act_len = len;
+	dev->status = stat;
+
+	return stat;
+}
+
+static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev,
+				 unsigned long pipe, void *buffer, int txlen,
+				 struct devrequest *cmd)
+{
+	int stat = 0;
+
+	if (usb_pipeint(pipe)) {
+		puts("Root-Hub submit IRQ: NOT implemented\n");
+		return 0;
+	}
+
+	if (cmd->requesttype & USB_DIR_IN)
+		stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd);
+	else
+		stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd);
+
+	mdelay(1);
+
+	return stat;
+}
+
+int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle)
+{
+	int ret;
+	uint32_t hcint, hctsiz;
+
+	ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true,
+				2000, false);
+	if (ret)
+		return ret;
+
+	hcint = readl(&hc_regs->hcint);
+	hctsiz = readl(&hc_regs->hctsiz);
+	*sub = (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK) >>
+		DWC2_HCTSIZ_XFERSIZE_OFFSET;
+	*toggle = (hctsiz & DWC2_HCTSIZ_PID_MASK) >> DWC2_HCTSIZ_PID_OFFSET;
+
+	debug("%s: HCINT=%08x sub=%u toggle=%d\n", __func__, hcint, *sub,
+	      *toggle);
+
+	if (hcint & DWC2_HCINT_XFERCOMP)
+		return 0;
+
+	if (hcint & (DWC2_HCINT_NAK | DWC2_HCINT_FRMOVRUN))
+		return -EAGAIN;
+
+	debug("%s: Error (HCINT=%08x)\n", __func__, hcint);
+	return -EINVAL;
+}
+
+static int dwc2_eptype[] = {
+	DWC2_HCCHAR_EPTYPE_ISOC,
+	DWC2_HCCHAR_EPTYPE_INTR,
+	DWC2_HCCHAR_EPTYPE_CONTROL,
+	DWC2_HCCHAR_EPTYPE_BULK,
+};
+
+static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer,
+			  u8 *pid, int in, void *buffer, int num_packets,
+			  int xfer_len, int *actual_len, int odd_frame)
+{
+	int ret = 0;
+	uint32_t sub;
+
+	debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__,
+	      *pid, xfer_len, num_packets);
+
+	writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
+	       (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
+	       (*pid << DWC2_HCTSIZ_PID_OFFSET),
+	       &hc_regs->hctsiz);
+
+	if (xfer_len) {
+		if (in) {
+			invalidate_dcache_range(
+					(uintptr_t)aligned_buffer,
+					(uintptr_t)aligned_buffer +
+					roundup(xfer_len, ARCH_DMA_MINALIGN));
+		} else {
+			memcpy(aligned_buffer, buffer, xfer_len);
+			flush_dcache_range(
+					(uintptr_t)aligned_buffer,
+					(uintptr_t)aligned_buffer +
+					roundup(xfer_len, ARCH_DMA_MINALIGN));
+		}
+	}
+
+	writel(phys_to_bus((unsigned long)aligned_buffer), &hc_regs->hcdma);
+
+	/* Clear old interrupt conditions for this host channel. */
+	writel(0x3fff, &hc_regs->hcint);
+
+	/* Set host channel enable after all other setup is complete. */
+	clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
+			DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS |
+			DWC2_HCCHAR_ODDFRM,
+			(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
+			(odd_frame << DWC2_HCCHAR_ODDFRM_OFFSET) |
+			DWC2_HCCHAR_CHEN);
+
+	ret = wait_for_chhltd(hc_regs, &sub, pid);
+	if (ret < 0)
+		return ret;
+
+	if (in) {
+		xfer_len -= sub;
+
+		invalidate_dcache_range((unsigned long)aligned_buffer,
+					(unsigned long)aligned_buffer +
+					roundup(xfer_len, ARCH_DMA_MINALIGN));
+
+		memcpy(buffer, aligned_buffer, xfer_len);
+	}
+	*actual_len = xfer_len;
+
+	return ret;
+}
+
+int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
+	      unsigned long pipe, u8 *pid, int in, void *buffer, int len)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
+	struct dwc2_host_regs *host_regs = &regs->host_regs;
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	int max = usb_maxpacket(dev, pipe);
+	int eptype = dwc2_eptype[usb_pipetype(pipe)];
+	int done = 0;
+	int ret = 0;
+	int do_split = 0;
+	int complete_split = 0;
+	uint32_t xfer_len;
+	uint32_t num_packets;
+	int stop_transfer = 0;
+	uint32_t max_xfer_len;
+	int ssplit_frame_num = 0;
+
+	debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid,
+	      in, len);
+
+	max_xfer_len = CONFIG_DWC2_MAX_PACKET_COUNT * max;
+	if (max_xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE)
+		max_xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE;
+	if (max_xfer_len > DWC2_DATA_BUF_SIZE)
+		max_xfer_len = DWC2_DATA_BUF_SIZE;
+
+	/* Make sure that max_xfer_len is a multiple of max packet size. */
+	num_packets = max_xfer_len / max;
+	max_xfer_len = num_packets * max;
+
+	/* Initialize channel */
+	dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in,
+			eptype, max);
+
+	/* Check if the target is a FS/LS device behind a HS hub */
+	if (dev->speed != USB_SPEED_HIGH) {
+		uint8_t hub_addr;
+		uint8_t hub_port;
+		uint32_t hprt0 = readl(&regs->hprt0);
+		if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) ==
+		     DWC2_HPRT0_PRTSPD_HIGH) {
+			usb_find_usb2_hub_address_port(dev, &hub_addr,
+						       &hub_port);
+			dwc_otg_hc_init_split(hc_regs, hub_addr, hub_port);
+
+			do_split = 1;
+			num_packets = 1;
+			max_xfer_len = max;
+		}
+	}
+
+	do {
+		int actual_len = 0;
+		uint32_t hcint;
+		int odd_frame = 0;
+		xfer_len = len - done;
+
+		if (xfer_len > max_xfer_len)
+			xfer_len = max_xfer_len;
+		else if (xfer_len > max)
+			num_packets = (xfer_len + max - 1) / max;
+		else
+			num_packets = 1;
+
+		if (complete_split)
+			setbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT);
+		else if (do_split)
+			clrbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT);
+
+		if (eptype == DWC2_HCCHAR_EPTYPE_INTR) {
+			int uframe_num = readl(&host_regs->hfnum);
+			if (!(uframe_num & 0x1))
+				odd_frame = 1;
+		}
+
+		ret = transfer_chunk(hc_regs, priv->aligned_buffer, pid,
+				     in, (char *)buffer + done, num_packets,
+				     xfer_len, &actual_len, odd_frame);
+
+		hcint = readl(&hc_regs->hcint);
+		if (complete_split) {
+			stop_transfer = 0;
+			if (hcint & DWC2_HCINT_NYET) {
+				ret = 0;
+				int frame_num = DWC2_HFNUM_MAX_FRNUM &
+						readl(&host_regs->hfnum);
+				if (((frame_num - ssplit_frame_num) &
+				    DWC2_HFNUM_MAX_FRNUM) > 4)
+					ret = -EAGAIN;
+			} else
+				complete_split = 0;
+		} else if (do_split) {
+			if (hcint & DWC2_HCINT_ACK) {
+				ssplit_frame_num = DWC2_HFNUM_MAX_FRNUM &
+						   readl(&host_regs->hfnum);
+				ret = 0;
+				complete_split = 1;
+			}
+		}
+
+		if (ret)
+			break;
+
+		if (actual_len < xfer_len)
+			stop_transfer = 1;
+
+		done += actual_len;
+
+	/* Transactions are done when when either all data is transferred or
+	 * there is a short transfer. In case of a SPLIT make sure the CSPLIT
+	 * is executed.
+	 */
+	} while (((done < len) && !stop_transfer) || complete_split);
+
+	writel(0, &hc_regs->hcintmsk);
+	writel(0xFFFFFFFF, &hc_regs->hcint);
+
+	dev->status = 0;
+	dev->act_len = done;
+
+	return ret;
+}
+
+/* U-Boot USB transmission interface */
+int _submit_bulk_msg(struct dwc2_priv *priv, struct usb_device *dev,
+		     unsigned long pipe, void *buffer, int len)
+{
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	u8* pid;
+
+	if ((devnum >= MAX_DEVICE) || (devnum == priv->root_hub_devnum)) {
+		dev->status = 0;
+		return -EINVAL;
+	}
+
+	if (usb_pipein(pipe))
+		pid = &priv->in_data_toggle[devnum][ep];
+	else
+		pid = &priv->out_data_toggle[devnum][ep];
+
+	return chunk_msg(priv, dev, pipe, pid, usb_pipein(pipe), buffer, len);
+}
+
+static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev,
+			       unsigned long pipe, void *buffer, int len,
+			       struct devrequest *setup)
+{
+	int devnum = usb_pipedevice(pipe);
+	int ret, act_len;
+	u8 pid;
+	/* For CONTROL endpoint pid should start with DATA1 */
+	int status_direction;
+
+	if (devnum == priv->root_hub_devnum) {
+		dev->status = 0;
+		dev->speed = USB_SPEED_HIGH;
+		return dwc_otg_submit_rh_msg(priv, dev, pipe, buffer, len,
+					     setup);
+	}
+
+	/* SETUP stage */
+	pid = DWC2_HC_PID_SETUP;
+	do {
+		ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8);
+	} while (ret == -EAGAIN);
+	if (ret)
+		return ret;
+
+	/* DATA stage */
+	act_len = 0;
+	if (buffer) {
+		pid = DWC2_HC_PID_DATA1;
+		do {
+			ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe),
+					buffer, len);
+			act_len += dev->act_len;
+			buffer += dev->act_len;
+			len -= dev->act_len;
+		} while (ret == -EAGAIN);
+		if (ret)
+			return ret;
+		status_direction = usb_pipeout(pipe);
+	} else {
+		/* No-data CONTROL always ends with an IN transaction */
+		status_direction = 1;
+	}
+
+	/* STATUS stage */
+	pid = DWC2_HC_PID_DATA1;
+	do {
+		ret = chunk_msg(priv, dev, pipe, &pid, status_direction,
+				priv->status_buffer, 0);
+	} while (ret == -EAGAIN);
+	if (ret)
+		return ret;
+
+	dev->act_len = act_len;
+
+	return 0;
+}
+
+int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
+		    unsigned long pipe, void *buffer, int len, int interval,
+		    bool nonblock)
+{
+	unsigned long timeout;
+	int ret;
+
+	/* FIXME: what is interval? */
+
+	timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
+	for (;;) {
+		if (get_timer(0) > timeout) {
+#if CONFIG_IS_ENABLED(DM_USB)
+			dev_err(dev->dev,
+				"Timeout poll on interrupt endpoint\n");
+#else
+			log_err("Timeout poll on interrupt endpoint\n");
+#endif
+			return -ETIMEDOUT;
+		}
+		ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
+		if ((ret != -EAGAIN) || nonblock)
+			return ret;
+	}
+}
+
+static int dwc2_reset(struct udevice *dev)
+{
+	int ret;
+	struct dwc2_priv *priv = dev_get_priv(dev);
+
+	ret = reset_get_bulk(dev, &priv->resets);
+	if (ret) {
+		dev_warn(dev, "Can't get reset: %d\n", ret);
+		/* Return 0 if error due to !CONFIG_DM_RESET and reset
+		 * DT property is not present.
+		 */
+		if (ret == -ENOENT || ret == -ENOTSUPP)
+			return 0;
+		else
+			return ret;
+	}
+
+	/* force reset to clear all IP register */
+	reset_assert_bulk(&priv->resets);
+	ret = reset_deassert_bulk(&priv->resets);
+	if (ret) {
+		reset_release_bulk(&priv->resets);
+		dev_err(dev, "Failed to reset: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	uint32_t snpsid;
+	int i, j;
+	int ret;
+
+	ret = dwc2_reset(dev);
+	if (ret)
+		return ret;
+
+	snpsid = readl(&regs->gsnpsid);
+	dev_info(dev, "Core Release: %x.%03x\n",
+		 snpsid >> 12 & 0xf, snpsid & 0xfff);
+
+	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
+	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
+		dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
+			 snpsid);
+		return -ENODEV;
+	}
+
+#ifdef CONFIG_DWC2_PHY_ULPI_EXT_VBUS
+	priv->ext_vbus = 1;
+#else
+	priv->ext_vbus = 0;
+#endif
+
+	dwc_otg_core_init(dev);
+
+	if (usb_get_dr_mode(dev_ofnode(dev)) == USB_DR_MODE_PERIPHERAL) {
+		dev_dbg(dev, "USB device %s dr_mode set to %d. Skipping host_init.\n",
+			dev->name, usb_get_dr_mode(dev_ofnode(dev)));
+	} else {
+		dwc_otg_core_host_init(dev, regs);
+	}
+
+	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
+			DWC2_HPRT0_PRTOVRCURRCHNG,
+			DWC2_HPRT0_PRTRST);
+	mdelay(50);
+	clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET |
+		     DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG |
+		     DWC2_HPRT0_PRTRST);
+
+	for (i = 0; i < MAX_DEVICE; i++) {
+		for (j = 0; j < MAX_ENDPOINT; j++) {
+			priv->in_data_toggle[i][j] = DWC2_HC_PID_DATA0;
+			priv->out_data_toggle[i][j] = DWC2_HC_PID_DATA0;
+		}
+	}
+
+	/*
+	 * Add a 1 second delay here. This gives the host controller
+	 * a bit time before the comminucation with the USB devices
+	 * is started (the bus is scanned) and  fixes the USB detection
+	 * problems with some problematic USB keys.
+	 */
+	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
+		mdelay(1000);
+
+	printf("USB DWC2\n");
+
+	return 0;
+}
+
+static void dwc2_uninit_common(struct dwc2_core_regs *regs)
+{
+	/* Put everything in reset. */
+	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
+			DWC2_HPRT0_PRTOVRCURRCHNG,
+			DWC2_HPRT0_PRTRST);
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		       int len, struct devrequest *setup)
+{
+	return _submit_control_msg(&local, dev, pipe, buffer, len, setup);
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		    int len)
+{
+	return _submit_bulk_msg(&local, dev, pipe, buffer, len);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int len, int interval, bool nonblock)
+{
+	return _submit_int_msg(&local, dev, pipe, buffer, len, interval,
+			       nonblock);
+}
+
+/* U-Boot USB control interface */
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	struct dwc2_priv *priv = &local;
+
+	memset(priv, '\0', sizeof(*priv));
+	priv->root_hub_devnum = 0;
+	priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
+	priv->aligned_buffer = aligned_buffer_addr;
+	priv->status_buffer = status_buffer_addr;
+
+	/* board-dependant init */
+	if (board_usb_init(index, USB_INIT_HOST))
+		return -1;
+
+	return dwc2_init_common(NULL, priv);
+}
+
+int usb_lowlevel_stop(int index)
+{
+	dwc2_uninit_common(local.regs);
+
+	return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+
+	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+	      dev->name, udev, udev->dev->name, udev->portnr);
+
+	return _submit_control_msg(priv, udev, pipe, buffer, length, setup);
+}
+
+static int dwc2_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+
+	return _submit_bulk_msg(priv, udev, pipe, buffer, length);
+}
+
+static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval, bool nonblock)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+
+	return _submit_int_msg(priv, udev, pipe, buffer, length, interval,
+			       nonblock);
+}
+
+static int dwc2_usb_of_to_plat(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+
+	priv->regs = dev_read_addr_ptr(dev);
+	if (!priv->regs)
+		return -EINVAL;
+
+	priv->oc_disable = dev_read_bool(dev, "disable-over-current");
+	priv->hnp_srp_disable = dev_read_bool(dev, "hnp-srp-disable");
+
+	return 0;
+}
+
+static int dwc2_setup_phy(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = generic_phy_get_by_index(dev, 0, &priv->phy);
+	if (ret) {
+		if (ret == -ENOENT)
+			return 0; /* no PHY, nothing to do */
+		dev_err(dev, "Failed to get USB PHY: %d.\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_init(&priv->phy);
+	if (ret) {
+		dev_dbg(dev, "Failed to init USB PHY: %d.\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_power_on(&priv->phy);
+	if (ret) {
+		dev_dbg(dev, "Failed to power on USB PHY: %d.\n", ret);
+		generic_phy_exit(&priv->phy);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc2_shutdown_phy(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	/* PHY is not valid when generic_phy_get_by_index() = -ENOENT */
+	if (!generic_phy_valid(&priv->phy))
+		return 0; /* no PHY, nothing to do */
+
+	ret = generic_phy_power_off(&priv->phy);
+	if (ret) {
+		dev_dbg(dev, "Failed to power off USB PHY: %d.\n", ret);
+		return ret;
+	}
+
+	ret = generic_phy_exit(&priv->phy);
+	if (ret) {
+		dev_dbg(dev, "Failed to power off USB PHY: %d.\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc2_clk_init(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = clk_get_bulk(dev, &priv->clks);
+	if (ret == -ENOSYS || ret == -ENOENT)
+		return 0;
+	if (ret)
+		return ret;
+
+	ret = clk_enable_bulk(&priv->clks);
+	if (ret) {
+		clk_release_bulk(&priv->clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc2_usb_probe(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
+	int ret;
+
+	bus_priv->desc_before_addr = true;
+
+	ret = dwc2_clk_init(dev);
+	if (ret)
+		return ret;
+
+	ret = dwc2_setup_phy(dev);
+	if (ret)
+		return ret;
+
+	return dwc2_init_common(dev, priv);
+}
+
+static int dwc2_usb_remove(struct udevice *dev)
+{
+	struct dwc2_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = dwc_vbus_supply_exit(dev);
+	if (ret)
+		return ret;
+
+	ret = dwc2_shutdown_phy(dev);
+	if (ret) {
+		dev_dbg(dev, "Failed to shutdown USB PHY: %d.\n", ret);
+		return ret;
+	}
+
+	dwc2_uninit_common(priv->regs);
+
+	reset_release_bulk(&priv->resets);
+	clk_disable_bulk(&priv->clks);
+	clk_release_bulk(&priv->clks);
+
+	return 0;
+}
+
+struct dm_usb_ops dwc2_usb_ops = {
+	.control = dwc2_submit_control_msg,
+	.bulk = dwc2_submit_bulk_msg,
+	.interrupt = dwc2_submit_int_msg,
+};
+
+static const struct udevice_id dwc2_usb_ids[] = {
+	{ .compatible = "brcm,bcm2835-usb" },
+	{ .compatible = "brcm,bcm2708-usb" },
+	{ .compatible = "snps,dwc2" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_dwc2) = {
+	.name	= "dwc2_usb",
+	.id	= UCLASS_USB,
+	.of_match = dwc2_usb_ids,
+	.of_to_plat = dwc2_usb_of_to_plat,
+	.probe	= dwc2_usb_probe,
+	.remove = dwc2_usb_remove,
+	.ops	= &dwc2_usb_ops,
+	.priv_auto	= sizeof(struct dwc2_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/host/dwc2.h b/roms/u-boot/drivers/usb/host/dwc2.h
new file mode 100644
index 000000000..97a06c48f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/dwc2.h
@@ -0,0 +1,790 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ */
+
+#ifndef __DWC2_H__
+#define __DWC2_H__
+
+struct dwc2_hc_regs {
+	u32			hcchar;		/* 0x00 */
+	u32			hcsplt;
+	u32			hcint;
+	u32			hcintmsk;
+	u32			hctsiz;		/* 0x10 */
+	u32			hcdma;
+	u32			reserved;
+	u32			hcdmab;
+};
+
+struct dwc2_host_regs {
+	u32			hcfg;		/* 0x00 */
+	u32			hfir;
+	u32			hfnum;
+	u32			_pad_0x40c;
+	u32			hptxsts;	/* 0x10 */
+	u32			haint;
+	u32			haintmsk;
+	u32			hflbaddr;
+};
+
+struct dwc2_core_regs {
+	u32			gotgctl;	/* 0x000 */
+	u32			gotgint;
+	u32			gahbcfg;
+	u32			gusbcfg;
+	u32			grstctl;	/* 0x010 */
+	u32			gintsts;
+	u32			gintmsk;
+	u32			grxstsr;
+	u32			grxstsp;	/* 0x020 */
+	u32			grxfsiz;
+	u32			gnptxfsiz;
+	u32			gnptxsts;
+	u32			gi2cctl;	/* 0x030 */
+	u32			gpvndctl;
+	u32			ggpio;
+	u32			guid;
+	u32			gsnpsid;	/* 0x040 */
+	u32			ghwcfg1;
+	u32			ghwcfg2;
+	u32			ghwcfg3;
+	u32			ghwcfg4;	/* 0x050 */
+	u32			glpmcfg;
+	u32			_pad_0x58_0x9c[42];
+	u32			hptxfsiz;	/* 0x100 */
+	u32			dptxfsiz_dieptxf[15];
+	u32			_pad_0x140_0x3fc[176];
+	struct dwc2_host_regs	host_regs;	/* 0x400 */
+	u32			_pad_0x420_0x43c[8];
+	u32			hprt0;		/* 0x440 */
+	u32			_pad_0x444_0x4fc[47];
+	struct dwc2_hc_regs	hc_regs[16];	/* 0x500 */
+	u32			_pad_0x700_0xe00[448];
+	u32			pcgcctl;	/* 0xe00 */
+};
+
+#define DWC2_GOTGCTL_SESREQSCS				(1 << 0)
+#define DWC2_GOTGCTL_SESREQSCS_OFFSET			0
+#define DWC2_GOTGCTL_SESREQ				(1 << 1)
+#define DWC2_GOTGCTL_SESREQ_OFFSET			1
+#define DWC2_GOTGCTL_HSTNEGSCS				(1 << 8)
+#define DWC2_GOTGCTL_HSTNEGSCS_OFFSET			8
+#define DWC2_GOTGCTL_HNPREQ				(1 << 9)
+#define DWC2_GOTGCTL_HNPREQ_OFFSET			9
+#define DWC2_GOTGCTL_HSTSETHNPEN			(1 << 10)
+#define DWC2_GOTGCTL_HSTSETHNPEN_OFFSET			10
+#define DWC2_GOTGCTL_DEVHNPEN				(1 << 11)
+#define DWC2_GOTGCTL_DEVHNPEN_OFFSET			11
+#define DWC2_GOTGCTL_CONIDSTS				(1 << 16)
+#define DWC2_GOTGCTL_CONIDSTS_OFFSET			16
+#define DWC2_GOTGCTL_DBNCTIME				(1 << 17)
+#define DWC2_GOTGCTL_DBNCTIME_OFFSET			17
+#define DWC2_GOTGCTL_ASESVLD				(1 << 18)
+#define DWC2_GOTGCTL_ASESVLD_OFFSET			18
+#define DWC2_GOTGCTL_BSESVLD				(1 << 19)
+#define DWC2_GOTGCTL_BSESVLD_OFFSET			19
+#define DWC2_GOTGCTL_OTGVER				(1 << 20)
+#define DWC2_GOTGCTL_OTGVER_OFFSET			20
+#define DWC2_GOTGINT_SESENDDET				(1 << 2)
+#define DWC2_GOTGINT_SESENDDET_OFFSET			2
+#define DWC2_GOTGINT_SESREQSUCSTSCHNG			(1 << 8)
+#define DWC2_GOTGINT_SESREQSUCSTSCHNG_OFFSET		8
+#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG			(1 << 9)
+#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG_OFFSET		9
+#define DWC2_GOTGINT_RESERVER10_16_MASK			(0x7F << 10)
+#define DWC2_GOTGINT_RESERVER10_16_OFFSET		10
+#define DWC2_GOTGINT_HSTNEGDET				(1 << 17)
+#define DWC2_GOTGINT_HSTNEGDET_OFFSET			17
+#define DWC2_GOTGINT_ADEVTOUTCHNG			(1 << 18)
+#define DWC2_GOTGINT_ADEVTOUTCHNG_OFFSET		18
+#define DWC2_GOTGINT_DEBDONE				(1 << 19)
+#define DWC2_GOTGINT_DEBDONE_OFFSET			19
+#define DWC2_GAHBCFG_GLBLINTRMSK			(1 << 0)
+#define DWC2_GAHBCFG_GLBLINTRMSK_OFFSET			0
+#define DWC2_GAHBCFG_HBURSTLEN_SINGLE			(0 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR			(1 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR4			(3 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR8			(5 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR16			(7 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_MASK			(0xF << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_OFFSET			1
+#define DWC2_GAHBCFG_DMAENABLE				(1 << 5)
+#define DWC2_GAHBCFG_DMAENABLE_OFFSET			5
+#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL		(1 << 7)
+#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL_OFFSET	7
+#define DWC2_GAHBCFG_PTXFEMPLVL				(1 << 8)
+#define DWC2_GAHBCFG_PTXFEMPLVL_OFFSET			8
+#define DWC2_GUSBCFG_TOUTCAL_MASK			(0x7 << 0)
+#define DWC2_GUSBCFG_TOUTCAL_OFFSET			0
+#define DWC2_GUSBCFG_PHYIF				(1 << 3)
+#define DWC2_GUSBCFG_PHYIF_OFFSET			3
+#define DWC2_GUSBCFG_ULPI_UTMI_SEL			(1 << 4)
+#define DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET		4
+#define DWC2_GUSBCFG_FSINTF				(1 << 5)
+#define DWC2_GUSBCFG_FSINTF_OFFSET			5
+#define DWC2_GUSBCFG_PHYSEL				(1 << 6)
+#define DWC2_GUSBCFG_PHYSEL_OFFSET			6
+#define DWC2_GUSBCFG_DDRSEL				(1 << 7)
+#define DWC2_GUSBCFG_DDRSEL_OFFSET			7
+#define DWC2_GUSBCFG_SRPCAP				(1 << 8)
+#define DWC2_GUSBCFG_SRPCAP_OFFSET			8
+#define DWC2_GUSBCFG_HNPCAP				(1 << 9)
+#define DWC2_GUSBCFG_HNPCAP_OFFSET			9
+#define DWC2_GUSBCFG_USBTRDTIM_MASK			(0xF << 10)
+#define DWC2_GUSBCFG_USBTRDTIM_OFFSET			10
+#define DWC2_GUSBCFG_NPTXFRWNDEN			(1 << 14)
+#define DWC2_GUSBCFG_NPTXFRWNDEN_OFFSET			14
+#define DWC2_GUSBCFG_PHYLPWRCLKSEL			(1 << 15)
+#define DWC2_GUSBCFG_PHYLPWRCLKSEL_OFFSET		15
+#define DWC2_GUSBCFG_OTGUTMIFSSEL			(1 << 16)
+#define DWC2_GUSBCFG_OTGUTMIFSSEL_OFFSET		16
+#define DWC2_GUSBCFG_ULPI_FSLS				(1 << 17)
+#define DWC2_GUSBCFG_ULPI_FSLS_OFFSET			17
+#define DWC2_GUSBCFG_ULPI_AUTO_RES			(1 << 18)
+#define DWC2_GUSBCFG_ULPI_AUTO_RES_OFFSET		18
+#define DWC2_GUSBCFG_ULPI_CLK_SUS_M			(1 << 19)
+#define DWC2_GUSBCFG_ULPI_CLK_SUS_M_OFFSET		19
+#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV			(1 << 20)
+#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV_OFFSET		20
+#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR		(1 << 21)
+#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR_OFFSET	21
+#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE			(1 << 22)
+#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE_OFFSET		22
+#define DWC2_GUSBCFG_INDICATOR_PASSTHROUGH		(1 << 24)
+#define DWC2_GUSBCFG_INDICATOR_PASSTHROUGH_OFFSET	24
+#define DWC2_GUSBCFG_IC_USB_CAP				(1 << 26)
+#define DWC2_GUSBCFG_IC_USB_CAP_OFFSET			26
+#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE		(1 << 27)
+#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE_OFFSET	27
+#define DWC2_GUSBCFG_TX_END_DELAY			(1 << 28)
+#define DWC2_GUSBCFG_TX_END_DELAY_OFFSET		28
+#define DWC2_GUSBCFG_FORCEHOSTMODE			(1 << 29)
+#define DWC2_GUSBCFG_FORCEHOSTMODE_OFFSET		29
+#define DWC2_GUSBCFG_FORCEDEVMODE			(1 << 30)
+#define DWC2_GUSBCFG_FORCEDEVMODE_OFFSET		30
+#define DWC2_GLPMCTL_LPM_CAP_EN				(1 << 0)
+#define DWC2_GLPMCTL_LPM_CAP_EN_OFFSET			0
+#define DWC2_GLPMCTL_APPL_RESP				(1 << 1)
+#define DWC2_GLPMCTL_APPL_RESP_OFFSET			1
+#define DWC2_GLPMCTL_HIRD_MASK				(0xF << 2)
+#define DWC2_GLPMCTL_HIRD_OFFSET			2
+#define DWC2_GLPMCTL_REM_WKUP_EN			(1 << 6)
+#define DWC2_GLPMCTL_REM_WKUP_EN_OFFSET			6
+#define DWC2_GLPMCTL_EN_UTMI_SLEEP			(1 << 7)
+#define DWC2_GLPMCTL_EN_UTMI_SLEEP_OFFSET		7
+#define DWC2_GLPMCTL_HIRD_THRES_MASK			(0x1F << 8)
+#define DWC2_GLPMCTL_HIRD_THRES_OFFSET			8
+#define DWC2_GLPMCTL_LPM_RESP_MASK			(0x3 << 13)
+#define DWC2_GLPMCTL_LPM_RESP_OFFSET			13
+#define DWC2_GLPMCTL_PRT_SLEEP_STS			(1 << 15)
+#define DWC2_GLPMCTL_PRT_SLEEP_STS_OFFSET		15
+#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK		(1 << 16)
+#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK_OFFSET	16
+#define DWC2_GLPMCTL_LPM_CHAN_INDEX_MASK		(0xF << 17)
+#define DWC2_GLPMCTL_LPM_CHAN_INDEX_OFFSET		17
+#define DWC2_GLPMCTL_RETRY_COUNT_MASK			(0x7 << 21)
+#define DWC2_GLPMCTL_RETRY_COUNT_OFFSET			21
+#define DWC2_GLPMCTL_SEND_LPM				(1 << 24)
+#define DWC2_GLPMCTL_SEND_LPM_OFFSET			24
+#define DWC2_GLPMCTL_RETRY_COUNT_STS_MASK		(0x7 << 25)
+#define DWC2_GLPMCTL_RETRY_COUNT_STS_OFFSET		25
+#define DWC2_GLPMCTL_HSIC_CONNECT			(1 << 30)
+#define DWC2_GLPMCTL_HSIC_CONNECT_OFFSET		30
+#define DWC2_GLPMCTL_INV_SEL_HSIC			(1 << 31)
+#define DWC2_GLPMCTL_INV_SEL_HSIC_OFFSET		31
+#define DWC2_GRSTCTL_CSFTRST				(1 << 0)
+#define DWC2_GRSTCTL_CSFTRST_OFFSET			0
+#define DWC2_GRSTCTL_HSFTRST				(1 << 1)
+#define DWC2_GRSTCTL_HSFTRST_OFFSET			1
+#define DWC2_GRSTCTL_HSTFRM				(1 << 2)
+#define DWC2_GRSTCTL_HSTFRM_OFFSET			2
+#define DWC2_GRSTCTL_INTKNQFLSH				(1 << 3)
+#define DWC2_GRSTCTL_INTKNQFLSH_OFFSET			3
+#define DWC2_GRSTCTL_RXFFLSH				(1 << 4)
+#define DWC2_GRSTCTL_RXFFLSH_OFFSET			4
+#define DWC2_GRSTCTL_TXFFLSH				(1 << 5)
+#define DWC2_GRSTCTL_TXFFLSH_OFFSET			5
+#define DWC2_GRSTCTL_TXFNUM_MASK			(0x1F << 6)
+#define DWC2_GRSTCTL_TXFNUM_OFFSET			6
+#define DWC2_GRSTCTL_DMAREQ				(1 << 30)
+#define DWC2_GRSTCTL_DMAREQ_OFFSET			30
+#define DWC2_GRSTCTL_AHBIDLE				(1 << 31)
+#define DWC2_GRSTCTL_AHBIDLE_OFFSET			31
+#define DWC2_GINTMSK_MODEMISMATCH			(1 << 1)
+#define DWC2_GINTMSK_MODEMISMATCH_OFFSET		1
+#define DWC2_GINTMSK_OTGINTR				(1 << 2)
+#define DWC2_GINTMSK_OTGINTR_OFFSET			2
+#define DWC2_GINTMSK_SOFINTR				(1 << 3)
+#define DWC2_GINTMSK_SOFINTR_OFFSET			3
+#define DWC2_GINTMSK_RXSTSQLVL				(1 << 4)
+#define DWC2_GINTMSK_RXSTSQLVL_OFFSET			4
+#define DWC2_GINTMSK_NPTXFEMPTY				(1 << 5)
+#define DWC2_GINTMSK_NPTXFEMPTY_OFFSET			5
+#define DWC2_GINTMSK_GINNAKEFF				(1 << 6)
+#define DWC2_GINTMSK_GINNAKEFF_OFFSET			6
+#define DWC2_GINTMSK_GOUTNAKEFF				(1 << 7)
+#define DWC2_GINTMSK_GOUTNAKEFF_OFFSET			7
+#define DWC2_GINTMSK_I2CINTR				(1 << 9)
+#define DWC2_GINTMSK_I2CINTR_OFFSET			9
+#define DWC2_GINTMSK_ERLYSUSPEND			(1 << 10)
+#define DWC2_GINTMSK_ERLYSUSPEND_OFFSET			10
+#define DWC2_GINTMSK_USBSUSPEND				(1 << 11)
+#define DWC2_GINTMSK_USBSUSPEND_OFFSET			11
+#define DWC2_GINTMSK_USBRESET				(1 << 12)
+#define DWC2_GINTMSK_USBRESET_OFFSET			12
+#define DWC2_GINTMSK_ENUMDONE				(1 << 13)
+#define DWC2_GINTMSK_ENUMDONE_OFFSET			13
+#define DWC2_GINTMSK_ISOOUTDROP				(1 << 14)
+#define DWC2_GINTMSK_ISOOUTDROP_OFFSET			14
+#define DWC2_GINTMSK_EOPFRAME				(1 << 15)
+#define DWC2_GINTMSK_EOPFRAME_OFFSET			15
+#define DWC2_GINTMSK_EPMISMATCH				(1 << 17)
+#define DWC2_GINTMSK_EPMISMATCH_OFFSET			17
+#define DWC2_GINTMSK_INEPINTR				(1 << 18)
+#define DWC2_GINTMSK_INEPINTR_OFFSET			18
+#define DWC2_GINTMSK_OUTEPINTR				(1 << 19)
+#define DWC2_GINTMSK_OUTEPINTR_OFFSET			19
+#define DWC2_GINTMSK_INCOMPLISOIN			(1 << 20)
+#define DWC2_GINTMSK_INCOMPLISOIN_OFFSET		20
+#define DWC2_GINTMSK_INCOMPLISOOUT			(1 << 21)
+#define DWC2_GINTMSK_INCOMPLISOOUT_OFFSET		21
+#define DWC2_GINTMSK_PORTINTR				(1 << 24)
+#define DWC2_GINTMSK_PORTINTR_OFFSET			24
+#define DWC2_GINTMSK_HCINTR				(1 << 25)
+#define DWC2_GINTMSK_HCINTR_OFFSET			25
+#define DWC2_GINTMSK_PTXFEMPTY				(1 << 26)
+#define DWC2_GINTMSK_PTXFEMPTY_OFFSET			26
+#define DWC2_GINTMSK_LPMTRANRCVD			(1 << 27)
+#define DWC2_GINTMSK_LPMTRANRCVD_OFFSET			27
+#define DWC2_GINTMSK_CONIDSTSCHNG			(1 << 28)
+#define DWC2_GINTMSK_CONIDSTSCHNG_OFFSET		28
+#define DWC2_GINTMSK_DISCONNECT				(1 << 29)
+#define DWC2_GINTMSK_DISCONNECT_OFFSET			29
+#define DWC2_GINTMSK_SESSREQINTR			(1 << 30)
+#define DWC2_GINTMSK_SESSREQINTR_OFFSET			30
+#define DWC2_GINTMSK_WKUPINTR				(1 << 31)
+#define DWC2_GINTMSK_WKUPINTR_OFFSET			31
+#define DWC2_GINTSTS_CURMODE_DEVICE			(0 << 0)
+#define DWC2_GINTSTS_CURMODE_HOST			(1 << 0)
+#define DWC2_GINTSTS_CURMODE				(1 << 0)
+#define DWC2_GINTSTS_CURMODE_OFFSET			0
+#define DWC2_GINTSTS_MODEMISMATCH			(1 << 1)
+#define DWC2_GINTSTS_MODEMISMATCH_OFFSET		1
+#define DWC2_GINTSTS_OTGINTR				(1 << 2)
+#define DWC2_GINTSTS_OTGINTR_OFFSET			2
+#define DWC2_GINTSTS_SOFINTR				(1 << 3)
+#define DWC2_GINTSTS_SOFINTR_OFFSET			3
+#define DWC2_GINTSTS_RXSTSQLVL				(1 << 4)
+#define DWC2_GINTSTS_RXSTSQLVL_OFFSET			4
+#define DWC2_GINTSTS_NPTXFEMPTY				(1 << 5)
+#define DWC2_GINTSTS_NPTXFEMPTY_OFFSET			5
+#define DWC2_GINTSTS_GINNAKEFF				(1 << 6)
+#define DWC2_GINTSTS_GINNAKEFF_OFFSET			6
+#define DWC2_GINTSTS_GOUTNAKEFF				(1 << 7)
+#define DWC2_GINTSTS_GOUTNAKEFF_OFFSET			7
+#define DWC2_GINTSTS_I2CINTR				(1 << 9)
+#define DWC2_GINTSTS_I2CINTR_OFFSET			9
+#define DWC2_GINTSTS_ERLYSUSPEND			(1 << 10)
+#define DWC2_GINTSTS_ERLYSUSPEND_OFFSET			10
+#define DWC2_GINTSTS_USBSUSPEND				(1 << 11)
+#define DWC2_GINTSTS_USBSUSPEND_OFFSET			11
+#define DWC2_GINTSTS_USBRESET				(1 << 12)
+#define DWC2_GINTSTS_USBRESET_OFFSET			12
+#define DWC2_GINTSTS_ENUMDONE				(1 << 13)
+#define DWC2_GINTSTS_ENUMDONE_OFFSET			13
+#define DWC2_GINTSTS_ISOOUTDROP				(1 << 14)
+#define DWC2_GINTSTS_ISOOUTDROP_OFFSET			14
+#define DWC2_GINTSTS_EOPFRAME				(1 << 15)
+#define DWC2_GINTSTS_EOPFRAME_OFFSET			15
+#define DWC2_GINTSTS_INTOKENRX				(1 << 16)
+#define DWC2_GINTSTS_INTOKENRX_OFFSET			16
+#define DWC2_GINTSTS_EPMISMATCH				(1 << 17)
+#define DWC2_GINTSTS_EPMISMATCH_OFFSET			17
+#define DWC2_GINTSTS_INEPINT				(1 << 18)
+#define DWC2_GINTSTS_INEPINT_OFFSET			18
+#define DWC2_GINTSTS_OUTEPINTR				(1 << 19)
+#define DWC2_GINTSTS_OUTEPINTR_OFFSET			19
+#define DWC2_GINTSTS_INCOMPLISOIN			(1 << 20)
+#define DWC2_GINTSTS_INCOMPLISOIN_OFFSET		20
+#define DWC2_GINTSTS_INCOMPLISOOUT			(1 << 21)
+#define DWC2_GINTSTS_INCOMPLISOOUT_OFFSET		21
+#define DWC2_GINTSTS_PORTINTR				(1 << 24)
+#define DWC2_GINTSTS_PORTINTR_OFFSET			24
+#define DWC2_GINTSTS_HCINTR				(1 << 25)
+#define DWC2_GINTSTS_HCINTR_OFFSET			25
+#define DWC2_GINTSTS_PTXFEMPTY				(1 << 26)
+#define DWC2_GINTSTS_PTXFEMPTY_OFFSET			26
+#define DWC2_GINTSTS_LPMTRANRCVD			(1 << 27)
+#define DWC2_GINTSTS_LPMTRANRCVD_OFFSET			27
+#define DWC2_GINTSTS_CONIDSTSCHNG			(1 << 28)
+#define DWC2_GINTSTS_CONIDSTSCHNG_OFFSET		28
+#define DWC2_GINTSTS_DISCONNECT				(1 << 29)
+#define DWC2_GINTSTS_DISCONNECT_OFFSET			29
+#define DWC2_GINTSTS_SESSREQINTR			(1 << 30)
+#define DWC2_GINTSTS_SESSREQINTR_OFFSET			30
+#define DWC2_GINTSTS_WKUPINTR				(1 << 31)
+#define DWC2_GINTSTS_WKUPINTR_OFFSET			31
+#define DWC2_GRXSTS_EPNUM_MASK				(0xF << 0)
+#define DWC2_GRXSTS_EPNUM_OFFSET			0
+#define DWC2_GRXSTS_BCNT_MASK				(0x7FF << 4)
+#define DWC2_GRXSTS_BCNT_OFFSET				4
+#define DWC2_GRXSTS_DPID_MASK				(0x3 << 15)
+#define DWC2_GRXSTS_DPID_OFFSET				15
+#define DWC2_GRXSTS_PKTSTS_MASK				(0xF << 17)
+#define DWC2_GRXSTS_PKTSTS_OFFSET			17
+#define DWC2_GRXSTS_FN_MASK				(0xF << 21)
+#define DWC2_GRXSTS_FN_OFFSET				21
+#define DWC2_FIFOSIZE_STARTADDR_MASK			(0xFFFF << 0)
+#define DWC2_FIFOSIZE_STARTADDR_OFFSET			0
+#define DWC2_FIFOSIZE_DEPTH_MASK			(0xFFFF << 16)
+#define DWC2_FIFOSIZE_DEPTH_OFFSET			16
+#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_MASK		(0xFFFF << 0)
+#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_OFFSET		0
+#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_MASK		(0xFF << 16)
+#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_OFFSET		16
+#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE		(1 << 24)
+#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE_OFFSET		24
+#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_MASK		(0x3 << 25)
+#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_OFFSET		25
+#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_MASK		(0xF << 27)
+#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_OFFSET		27
+#define DWC2_DTXFSTS_TXFSPCAVAIL_MASK			(0xFFFF << 0)
+#define DWC2_DTXFSTS_TXFSPCAVAIL_OFFSET			0
+#define DWC2_GI2CCTL_RWDATA_MASK			(0xFF << 0)
+#define DWC2_GI2CCTL_RWDATA_OFFSET			0
+#define DWC2_GI2CCTL_REGADDR_MASK			(0xFF << 8)
+#define DWC2_GI2CCTL_REGADDR_OFFSET			8
+#define DWC2_GI2CCTL_ADDR_MASK				(0x7F << 16)
+#define DWC2_GI2CCTL_ADDR_OFFSET			16
+#define DWC2_GI2CCTL_I2CEN				(1 << 23)
+#define DWC2_GI2CCTL_I2CEN_OFFSET			23
+#define DWC2_GI2CCTL_ACK				(1 << 24)
+#define DWC2_GI2CCTL_ACK_OFFSET				24
+#define DWC2_GI2CCTL_I2CSUSPCTL				(1 << 25)
+#define DWC2_GI2CCTL_I2CSUSPCTL_OFFSET			25
+#define DWC2_GI2CCTL_I2CDEVADDR_MASK			(0x3 << 26)
+#define DWC2_GI2CCTL_I2CDEVADDR_OFFSET			26
+#define DWC2_GI2CCTL_RW					(1 << 30)
+#define DWC2_GI2CCTL_RW_OFFSET				30
+#define DWC2_GI2CCTL_BSYDNE				(1 << 31)
+#define DWC2_GI2CCTL_BSYDNE_OFFSET			31
+#define DWC2_HWCFG1_EP_DIR0_MASK			(0x3 << 0)
+#define DWC2_HWCFG1_EP_DIR0_OFFSET			0
+#define DWC2_HWCFG1_EP_DIR1_MASK			(0x3 << 2)
+#define DWC2_HWCFG1_EP_DIR1_OFFSET			2
+#define DWC2_HWCFG1_EP_DIR2_MASK			(0x3 << 4)
+#define DWC2_HWCFG1_EP_DIR2_OFFSET			4
+#define DWC2_HWCFG1_EP_DIR3_MASK			(0x3 << 6)
+#define DWC2_HWCFG1_EP_DIR3_OFFSET			6
+#define DWC2_HWCFG1_EP_DIR4_MASK			(0x3 << 8)
+#define DWC2_HWCFG1_EP_DIR4_OFFSET			8
+#define DWC2_HWCFG1_EP_DIR5_MASK			(0x3 << 10)
+#define DWC2_HWCFG1_EP_DIR5_OFFSET			10
+#define DWC2_HWCFG1_EP_DIR6_MASK			(0x3 << 12)
+#define DWC2_HWCFG1_EP_DIR6_OFFSET			12
+#define DWC2_HWCFG1_EP_DIR7_MASK			(0x3 << 14)
+#define DWC2_HWCFG1_EP_DIR7_OFFSET			14
+#define DWC2_HWCFG1_EP_DIR8_MASK			(0x3 << 16)
+#define DWC2_HWCFG1_EP_DIR8_OFFSET			16
+#define DWC2_HWCFG1_EP_DIR9_MASK			(0x3 << 18)
+#define DWC2_HWCFG1_EP_DIR9_OFFSET			18
+#define DWC2_HWCFG1_EP_DIR10_MASK			(0x3 << 20)
+#define DWC2_HWCFG1_EP_DIR10_OFFSET			20
+#define DWC2_HWCFG1_EP_DIR11_MASK			(0x3 << 22)
+#define DWC2_HWCFG1_EP_DIR11_OFFSET			22
+#define DWC2_HWCFG1_EP_DIR12_MASK			(0x3 << 24)
+#define DWC2_HWCFG1_EP_DIR12_OFFSET			24
+#define DWC2_HWCFG1_EP_DIR13_MASK			(0x3 << 26)
+#define DWC2_HWCFG1_EP_DIR13_OFFSET			26
+#define DWC2_HWCFG1_EP_DIR14_MASK			(0x3 << 28)
+#define DWC2_HWCFG1_EP_DIR14_OFFSET			28
+#define DWC2_HWCFG1_EP_DIR15_MASK			(0x3 << 30)
+#define DWC2_HWCFG1_EP_DIR15_OFFSET			30
+#define DWC2_HWCFG2_OP_MODE_MASK			(0x7 << 0)
+#define DWC2_HWCFG2_OP_MODE_OFFSET			0
+#define DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY		(0x0 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_EXT_DMA		(0x1 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_INT_DMA		(0x2 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_MASK			(0x3 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_OFFSET			3
+#define DWC2_HWCFG2_POINT2POINT				(1 << 5)
+#define DWC2_HWCFG2_POINT2POINT_OFFSET			5
+#define DWC2_HWCFG2_HS_PHY_TYPE_MASK			(0x3 << 6)
+#define DWC2_HWCFG2_HS_PHY_TYPE_OFFSET			6
+#define DWC2_HWCFG2_FS_PHY_TYPE_MASK			(0x3 << 8)
+#define DWC2_HWCFG2_FS_PHY_TYPE_OFFSET			8
+#define DWC2_HWCFG2_NUM_DEV_EP_MASK			(0xF << 10)
+#define DWC2_HWCFG2_NUM_DEV_EP_OFFSET			10
+#define DWC2_HWCFG2_NUM_HOST_CHAN_MASK			(0xF << 14)
+#define DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET		14
+#define DWC2_HWCFG2_PERIO_EP_SUPPORTED			(1 << 18)
+#define DWC2_HWCFG2_PERIO_EP_SUPPORTED_OFFSET		18
+#define DWC2_HWCFG2_DYNAMIC_FIFO			(1 << 19)
+#define DWC2_HWCFG2_DYNAMIC_FIFO_OFFSET			19
+#define DWC2_HWCFG2_MULTI_PROC_INT			(1 << 20)
+#define DWC2_HWCFG2_MULTI_PROC_INT_OFFSET		20
+#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_MASK		(0x3 << 22)
+#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_OFFSET		22
+#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK		(0x3 << 24)
+#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_OFFSET	24
+#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_MASK		(0x1F << 26)
+#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_OFFSET		26
+#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_MASK		(0xF << 0)
+#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_OFFSET		0
+#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK		(0x7 << 4)
+#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_OFFSET	4
+#define DWC2_HWCFG3_OTG_FUNC				(1 << 7)
+#define DWC2_HWCFG3_OTG_FUNC_OFFSET			7
+#define DWC2_HWCFG3_I2C					(1 << 8)
+#define DWC2_HWCFG3_I2C_OFFSET				8
+#define DWC2_HWCFG3_VENDOR_CTRL_IF			(1 << 9)
+#define DWC2_HWCFG3_VENDOR_CTRL_IF_OFFSET		9
+#define DWC2_HWCFG3_OPTIONAL_FEATURES			(1 << 10)
+#define DWC2_HWCFG3_OPTIONAL_FEATURES_OFFSET		10
+#define DWC2_HWCFG3_SYNCH_RESET_TYPE			(1 << 11)
+#define DWC2_HWCFG3_SYNCH_RESET_TYPE_OFFSET		11
+#define DWC2_HWCFG3_OTG_ENABLE_IC_USB			(1 << 12)
+#define DWC2_HWCFG3_OTG_ENABLE_IC_USB_OFFSET		12
+#define DWC2_HWCFG3_OTG_ENABLE_HSIC			(1 << 13)
+#define DWC2_HWCFG3_OTG_ENABLE_HSIC_OFFSET		13
+#define DWC2_HWCFG3_OTG_LPM_EN				(1 << 15)
+#define DWC2_HWCFG3_OTG_LPM_EN_OFFSET			15
+#define DWC2_HWCFG3_DFIFO_DEPTH_MASK			(0xFFFF << 16)
+#define DWC2_HWCFG3_DFIFO_DEPTH_OFFSET			16
+#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_MASK		(0xF << 0)
+#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_OFFSET		0
+#define DWC2_HWCFG4_POWER_OPTIMIZ			(1 << 4)
+#define DWC2_HWCFG4_POWER_OPTIMIZ_OFFSET		4
+#define DWC2_HWCFG4_MIN_AHB_FREQ_MASK			(0x1FF << 5)
+#define DWC2_HWCFG4_MIN_AHB_FREQ_OFFSET			5
+#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_MASK		(0x3 << 14)
+#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_OFFSET		14
+#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_MASK		(0xF << 16)
+#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_OFFSET		16
+#define DWC2_HWCFG4_IDDIG_FILT_EN			(1 << 20)
+#define DWC2_HWCFG4_IDDIG_FILT_EN_OFFSET		20
+#define DWC2_HWCFG4_VBUS_VALID_FILT_EN			(1 << 21)
+#define DWC2_HWCFG4_VBUS_VALID_FILT_EN_OFFSET		21
+#define DWC2_HWCFG4_A_VALID_FILT_EN			(1 << 22)
+#define DWC2_HWCFG4_A_VALID_FILT_EN_OFFSET		22
+#define DWC2_HWCFG4_B_VALID_FILT_EN			(1 << 23)
+#define DWC2_HWCFG4_B_VALID_FILT_EN_OFFSET		23
+#define DWC2_HWCFG4_SESSION_END_FILT_EN			(1 << 24)
+#define DWC2_HWCFG4_SESSION_END_FILT_EN_OFFSET		24
+#define DWC2_HWCFG4_DED_FIFO_EN				(1 << 25)
+#define DWC2_HWCFG4_DED_FIFO_EN_OFFSET			25
+#define DWC2_HWCFG4_NUM_IN_EPS_MASK			(0xF << 26)
+#define DWC2_HWCFG4_NUM_IN_EPS_OFFSET			26
+#define DWC2_HWCFG4_DESC_DMA				(1 << 30)
+#define DWC2_HWCFG4_DESC_DMA_OFFSET			30
+#define DWC2_HWCFG4_DESC_DMA_DYN			(1 << 31)
+#define DWC2_HWCFG4_DESC_DMA_DYN_OFFSET			31
+#define DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ			0
+#define DWC2_HCFG_FSLSPCLKSEL_48_MHZ			1
+#define DWC2_HCFG_FSLSPCLKSEL_6_MHZ			2
+#define DWC2_HCFG_FSLSPCLKSEL_MASK			(0x3 << 0)
+#define DWC2_HCFG_FSLSPCLKSEL_OFFSET			0
+#define DWC2_HCFG_FSLSSUPP				(1 << 2)
+#define DWC2_HCFG_FSLSSUPP_OFFSET			2
+#define DWC2_HCFG_DESCDMA				(1 << 23)
+#define DWC2_HCFG_DESCDMA_OFFSET			23
+#define DWC2_HCFG_FRLISTEN_MASK				(0x3 << 24)
+#define DWC2_HCFG_FRLISTEN_OFFSET			24
+#define DWC2_HCFG_PERSCHEDENA				(1 << 26)
+#define DWC2_HCFG_PERSCHEDENA_OFFSET			26
+#define DWC2_HCFG_PERSCHEDSTAT				(1 << 27)
+#define DWC2_HCFG_PERSCHEDSTAT_OFFSET			27
+#define DWC2_HFIR_FRINT_MASK				(0xFFFF << 0)
+#define DWC2_HFIR_FRINT_OFFSET				0
+#define DWC2_HFNUM_FRNUM_MASK				(0xFFFF << 0)
+#define DWC2_HFNUM_FRNUM_OFFSET				0
+#define DWC2_HFNUM_FRREM_MASK				(0xFFFF << 16)
+#define DWC2_HFNUM_FRREM_OFFSET				16
+#define DWC2_HFNUM_MAX_FRNUM				0x3FFF
+#define DWC2_HPTXSTS_PTXFSPCAVAIL_MASK			(0xFFFF << 0)
+#define DWC2_HPTXSTS_PTXFSPCAVAIL_OFFSET		0
+#define DWC2_HPTXSTS_PTXQSPCAVAIL_MASK			(0xFF << 16)
+#define DWC2_HPTXSTS_PTXQSPCAVAIL_OFFSET		16
+#define DWC2_HPTXSTS_PTXQTOP_TERMINATE			(1 << 24)
+#define DWC2_HPTXSTS_PTXQTOP_TERMINATE_OFFSET		24
+#define DWC2_HPTXSTS_PTXQTOP_TOKEN_MASK			(0x3 << 25)
+#define DWC2_HPTXSTS_PTXQTOP_TOKEN_OFFSET		25
+#define DWC2_HPTXSTS_PTXQTOP_CHNUM_MASK			(0xF << 27)
+#define DWC2_HPTXSTS_PTXQTOP_CHNUM_OFFSET		27
+#define DWC2_HPTXSTS_PTXQTOP_ODD			(1 << 31)
+#define DWC2_HPTXSTS_PTXQTOP_ODD_OFFSET			31
+#define DWC2_HPRT0_PRTCONNSTS				(1 << 0)
+#define DWC2_HPRT0_PRTCONNSTS_OFFSET			0
+#define DWC2_HPRT0_PRTCONNDET				(1 << 1)
+#define DWC2_HPRT0_PRTCONNDET_OFFSET			1
+#define DWC2_HPRT0_PRTENA				(1 << 2)
+#define DWC2_HPRT0_PRTENA_OFFSET			2
+#define DWC2_HPRT0_PRTENCHNG				(1 << 3)
+#define DWC2_HPRT0_PRTENCHNG_OFFSET			3
+#define DWC2_HPRT0_PRTOVRCURRACT			(1 << 4)
+#define DWC2_HPRT0_PRTOVRCURRACT_OFFSET			4
+#define DWC2_HPRT0_PRTOVRCURRCHNG			(1 << 5)
+#define DWC2_HPRT0_PRTOVRCURRCHNG_OFFSET		5
+#define DWC2_HPRT0_PRTRES				(1 << 6)
+#define DWC2_HPRT0_PRTRES_OFFSET			6
+#define DWC2_HPRT0_PRTSUSP				(1 << 7)
+#define DWC2_HPRT0_PRTSUSP_OFFSET			7
+#define DWC2_HPRT0_PRTRST				(1 << 8)
+#define DWC2_HPRT0_PRTRST_OFFSET			8
+#define DWC2_HPRT0_PRTLNSTS_MASK			(0x3 << 10)
+#define DWC2_HPRT0_PRTLNSTS_OFFSET			10
+#define DWC2_HPRT0_PRTPWR				(1 << 12)
+#define DWC2_HPRT0_PRTPWR_OFFSET			12
+#define DWC2_HPRT0_PRTTSTCTL_MASK			(0xF << 13)
+#define DWC2_HPRT0_PRTTSTCTL_OFFSET			13
+#define DWC2_HPRT0_PRTSPD_HIGH				(0 << 17)
+#define DWC2_HPRT0_PRTSPD_FULL				(1 << 17)
+#define DWC2_HPRT0_PRTSPD_LOW				(2 << 17)
+#define DWC2_HPRT0_PRTSPD_MASK				(0x3 << 17)
+#define DWC2_HPRT0_PRTSPD_OFFSET			17
+#define DWC2_HAINT_CH0					(1 << 0)
+#define DWC2_HAINT_CH0_OFFSET				0
+#define DWC2_HAINT_CH1					(1 << 1)
+#define DWC2_HAINT_CH1_OFFSET				1
+#define DWC2_HAINT_CH2					(1 << 2)
+#define DWC2_HAINT_CH2_OFFSET				2
+#define DWC2_HAINT_CH3					(1 << 3)
+#define DWC2_HAINT_CH3_OFFSET				3
+#define DWC2_HAINT_CH4					(1 << 4)
+#define DWC2_HAINT_CH4_OFFSET				4
+#define DWC2_HAINT_CH5					(1 << 5)
+#define DWC2_HAINT_CH5_OFFSET				5
+#define DWC2_HAINT_CH6					(1 << 6)
+#define DWC2_HAINT_CH6_OFFSET				6
+#define DWC2_HAINT_CH7					(1 << 7)
+#define DWC2_HAINT_CH7_OFFSET				7
+#define DWC2_HAINT_CH8					(1 << 8)
+#define DWC2_HAINT_CH8_OFFSET				8
+#define DWC2_HAINT_CH9					(1 << 9)
+#define DWC2_HAINT_CH9_OFFSET				9
+#define DWC2_HAINT_CH10					(1 << 10)
+#define DWC2_HAINT_CH10_OFFSET				10
+#define DWC2_HAINT_CH11					(1 << 11)
+#define DWC2_HAINT_CH11_OFFSET				11
+#define DWC2_HAINT_CH12					(1 << 12)
+#define DWC2_HAINT_CH12_OFFSET				12
+#define DWC2_HAINT_CH13					(1 << 13)
+#define DWC2_HAINT_CH13_OFFSET				13
+#define DWC2_HAINT_CH14					(1 << 14)
+#define DWC2_HAINT_CH14_OFFSET				14
+#define DWC2_HAINT_CH15					(1 << 15)
+#define DWC2_HAINT_CH15_OFFSET				15
+#define DWC2_HAINT_CHINT_MASK				0xffff
+#define DWC2_HAINT_CHINT_OFFSET				0
+#define DWC2_HAINTMSK_CH0				(1 << 0)
+#define DWC2_HAINTMSK_CH0_OFFSET			0
+#define DWC2_HAINTMSK_CH1				(1 << 1)
+#define DWC2_HAINTMSK_CH1_OFFSET			1
+#define DWC2_HAINTMSK_CH2				(1 << 2)
+#define DWC2_HAINTMSK_CH2_OFFSET			2
+#define DWC2_HAINTMSK_CH3				(1 << 3)
+#define DWC2_HAINTMSK_CH3_OFFSET			3
+#define DWC2_HAINTMSK_CH4				(1 << 4)
+#define DWC2_HAINTMSK_CH4_OFFSET			4
+#define DWC2_HAINTMSK_CH5				(1 << 5)
+#define DWC2_HAINTMSK_CH5_OFFSET			5
+#define DWC2_HAINTMSK_CH6				(1 << 6)
+#define DWC2_HAINTMSK_CH6_OFFSET			6
+#define DWC2_HAINTMSK_CH7				(1 << 7)
+#define DWC2_HAINTMSK_CH7_OFFSET			7
+#define DWC2_HAINTMSK_CH8				(1 << 8)
+#define DWC2_HAINTMSK_CH8_OFFSET			8
+#define DWC2_HAINTMSK_CH9				(1 << 9)
+#define DWC2_HAINTMSK_CH9_OFFSET			9
+#define DWC2_HAINTMSK_CH10				(1 << 10)
+#define DWC2_HAINTMSK_CH10_OFFSET			10
+#define DWC2_HAINTMSK_CH11				(1 << 11)
+#define DWC2_HAINTMSK_CH11_OFFSET			11
+#define DWC2_HAINTMSK_CH12				(1 << 12)
+#define DWC2_HAINTMSK_CH12_OFFSET			12
+#define DWC2_HAINTMSK_CH13				(1 << 13)
+#define DWC2_HAINTMSK_CH13_OFFSET			13
+#define DWC2_HAINTMSK_CH14				(1 << 14)
+#define DWC2_HAINTMSK_CH14_OFFSET			14
+#define DWC2_HAINTMSK_CH15				(1 << 15)
+#define DWC2_HAINTMSK_CH15_OFFSET			15
+#define DWC2_HAINTMSK_CHINT_MASK			0xffff
+#define DWC2_HAINTMSK_CHINT_OFFSET			0
+#define DWC2_HCCHAR_MPS_MASK				(0x7FF << 0)
+#define DWC2_HCCHAR_MPS_OFFSET				0
+#define DWC2_HCCHAR_EPNUM_MASK				(0xF << 11)
+#define DWC2_HCCHAR_EPNUM_OFFSET			11
+#define DWC2_HCCHAR_EPDIR				(1 << 15)
+#define DWC2_HCCHAR_EPDIR_OFFSET			15
+#define DWC2_HCCHAR_LSPDDEV				(1 << 17)
+#define DWC2_HCCHAR_LSPDDEV_OFFSET			17
+#define DWC2_HCCHAR_EPTYPE_CONTROL			0
+#define DWC2_HCCHAR_EPTYPE_ISOC				1
+#define DWC2_HCCHAR_EPTYPE_BULK				2
+#define DWC2_HCCHAR_EPTYPE_INTR				3
+#define DWC2_HCCHAR_EPTYPE_MASK				(0x3 << 18)
+#define DWC2_HCCHAR_EPTYPE_OFFSET			18
+#define DWC2_HCCHAR_MULTICNT_MASK			(0x3 << 20)
+#define DWC2_HCCHAR_MULTICNT_OFFSET			20
+#define DWC2_HCCHAR_DEVADDR_MASK			(0x7F << 22)
+#define DWC2_HCCHAR_DEVADDR_OFFSET			22
+#define DWC2_HCCHAR_ODDFRM				(1 << 29)
+#define DWC2_HCCHAR_ODDFRM_OFFSET			29
+#define DWC2_HCCHAR_CHDIS				(1 << 30)
+#define DWC2_HCCHAR_CHDIS_OFFSET			30
+#define DWC2_HCCHAR_CHEN				(1 << 31)
+#define DWC2_HCCHAR_CHEN_OFFSET				31
+#define DWC2_HCSPLT_PRTADDR_MASK			(0x7F << 0)
+#define DWC2_HCSPLT_PRTADDR_OFFSET			0
+#define DWC2_HCSPLT_HUBADDR_MASK			(0x7F << 7)
+#define DWC2_HCSPLT_HUBADDR_OFFSET			7
+#define DWC2_HCSPLT_XACTPOS_MASK			(0x3 << 14)
+#define DWC2_HCSPLT_XACTPOS_OFFSET			14
+#define DWC2_HCSPLT_COMPSPLT				(1 << 16)
+#define DWC2_HCSPLT_COMPSPLT_OFFSET			16
+#define DWC2_HCSPLT_SPLTENA				(1 << 31)
+#define DWC2_HCSPLT_SPLTENA_OFFSET			31
+#define DWC2_HCINT_XFERCOMP				(1 << 0)
+#define DWC2_HCINT_XFERCOMP_OFFSET			0
+#define DWC2_HCINT_CHHLTD				(1 << 1)
+#define DWC2_HCINT_CHHLTD_OFFSET			1
+#define DWC2_HCINT_AHBERR				(1 << 2)
+#define DWC2_HCINT_AHBERR_OFFSET			2
+#define DWC2_HCINT_STALL				(1 << 3)
+#define DWC2_HCINT_STALL_OFFSET				3
+#define DWC2_HCINT_NAK					(1 << 4)
+#define DWC2_HCINT_NAK_OFFSET				4
+#define DWC2_HCINT_ACK					(1 << 5)
+#define DWC2_HCINT_ACK_OFFSET				5
+#define DWC2_HCINT_NYET					(1 << 6)
+#define DWC2_HCINT_NYET_OFFSET				6
+#define DWC2_HCINT_XACTERR				(1 << 7)
+#define DWC2_HCINT_XACTERR_OFFSET			7
+#define DWC2_HCINT_BBLERR				(1 << 8)
+#define DWC2_HCINT_BBLERR_OFFSET			8
+#define DWC2_HCINT_FRMOVRUN				(1 << 9)
+#define DWC2_HCINT_FRMOVRUN_OFFSET			9
+#define DWC2_HCINT_DATATGLERR				(1 << 10)
+#define DWC2_HCINT_DATATGLERR_OFFSET			10
+#define DWC2_HCINT_BNA					(1 << 11)
+#define DWC2_HCINT_BNA_OFFSET				11
+#define DWC2_HCINT_XCS_XACT				(1 << 12)
+#define DWC2_HCINT_XCS_XACT_OFFSET			12
+#define DWC2_HCINT_FRM_LIST_ROLL			(1 << 13)
+#define DWC2_HCINT_FRM_LIST_ROLL_OFFSET			13
+#define DWC2_HCINTMSK_XFERCOMPL				(1 << 0)
+#define DWC2_HCINTMSK_XFERCOMPL_OFFSET			0
+#define DWC2_HCINTMSK_CHHLTD				(1 << 1)
+#define DWC2_HCINTMSK_CHHLTD_OFFSET			1
+#define DWC2_HCINTMSK_AHBERR				(1 << 2)
+#define DWC2_HCINTMSK_AHBERR_OFFSET			2
+#define DWC2_HCINTMSK_STALL				(1 << 3)
+#define DWC2_HCINTMSK_STALL_OFFSET			3
+#define DWC2_HCINTMSK_NAK				(1 << 4)
+#define DWC2_HCINTMSK_NAK_OFFSET			4
+#define DWC2_HCINTMSK_ACK				(1 << 5)
+#define DWC2_HCINTMSK_ACK_OFFSET			5
+#define DWC2_HCINTMSK_NYET				(1 << 6)
+#define DWC2_HCINTMSK_NYET_OFFSET			6
+#define DWC2_HCINTMSK_XACTERR				(1 << 7)
+#define DWC2_HCINTMSK_XACTERR_OFFSET			7
+#define DWC2_HCINTMSK_BBLERR				(1 << 8)
+#define DWC2_HCINTMSK_BBLERR_OFFSET			8
+#define DWC2_HCINTMSK_FRMOVRUN				(1 << 9)
+#define DWC2_HCINTMSK_FRMOVRUN_OFFSET			9
+#define DWC2_HCINTMSK_DATATGLERR			(1 << 10)
+#define DWC2_HCINTMSK_DATATGLERR_OFFSET			10
+#define DWC2_HCINTMSK_BNA				(1 << 11)
+#define DWC2_HCINTMSK_BNA_OFFSET			11
+#define DWC2_HCINTMSK_XCS_XACT				(1 << 12)
+#define DWC2_HCINTMSK_XCS_XACT_OFFSET			12
+#define DWC2_HCINTMSK_FRM_LIST_ROLL			(1 << 13)
+#define DWC2_HCINTMSK_FRM_LIST_ROLL_OFFSET		13
+#define DWC2_HCTSIZ_XFERSIZE_MASK			0x7ffff
+#define DWC2_HCTSIZ_XFERSIZE_OFFSET			0
+#define DWC2_HCTSIZ_SCHINFO_MASK			0xff
+#define DWC2_HCTSIZ_SCHINFO_OFFSET			0
+#define DWC2_HCTSIZ_NTD_MASK				(0xff << 8)
+#define DWC2_HCTSIZ_NTD_OFFSET				8
+#define DWC2_HCTSIZ_PKTCNT_MASK				(0x3ff << 19)
+#define DWC2_HCTSIZ_PKTCNT_OFFSET			19
+#define DWC2_HCTSIZ_PID_MASK				(0x3 << 29)
+#define DWC2_HCTSIZ_PID_OFFSET				29
+#define DWC2_HCTSIZ_DOPNG				(1 << 31)
+#define DWC2_HCTSIZ_DOPNG_OFFSET			31
+#define DWC2_HCDMA_CTD_MASK				(0xFF << 3)
+#define DWC2_HCDMA_CTD_OFFSET				3
+#define DWC2_HCDMA_DMA_ADDR_MASK			(0x1FFFFF << 11)
+#define DWC2_HCDMA_DMA_ADDR_OFFSET			11
+#define DWC2_PCGCCTL_STOPPCLK				(1 << 0)
+#define DWC2_PCGCCTL_STOPPCLK_OFFSET			0
+#define DWC2_PCGCCTL_GATEHCLK				(1 << 1)
+#define DWC2_PCGCCTL_GATEHCLK_OFFSET			1
+#define DWC2_PCGCCTL_PWRCLMP				(1 << 2)
+#define DWC2_PCGCCTL_PWRCLMP_OFFSET			2
+#define DWC2_PCGCCTL_RSTPDWNMODULE			(1 << 3)
+#define DWC2_PCGCCTL_RSTPDWNMODULE_OFFSET		3
+#define DWC2_PCGCCTL_PHYSUSPENDED			(1 << 4)
+#define DWC2_PCGCCTL_PHYSUSPENDED_OFFSET		4
+#define DWC2_PCGCCTL_ENBL_SLEEP_GATING			(1 << 5)
+#define DWC2_PCGCCTL_ENBL_SLEEP_GATING_OFFSET		5
+#define DWC2_PCGCCTL_PHY_IN_SLEEP			(1 << 6)
+#define DWC2_PCGCCTL_PHY_IN_SLEEP_OFFSET		6
+#define DWC2_PCGCCTL_DEEP_SLEEP				(1 << 7)
+#define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET			7
+#define DWC2_SNPSID_DEVID_VER_2xx			(0x4f542 << 12)
+#define DWC2_SNPSID_DEVID_VER_3xx			(0x4f543 << 12)
+#define DWC2_SNPSID_DEVID_MASK				(0xfffff << 12)
+#define DWC2_SNPSID_DEVID_OFFSET			12
+
+/* Host controller specific */
+#define DWC2_HC_PID_DATA0		0
+#define DWC2_HC_PID_DATA2		1
+#define DWC2_HC_PID_DATA1		2
+#define DWC2_HC_PID_MDATA		3
+#define DWC2_HC_PID_SETUP		3
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)	/* number of downstream ports */
+#define RH_A_PSM	(1 << 8)	/* power switching mode */
+#define RH_A_NPS	(1 << 9)	/* no power switching */
+#define RH_A_DT		(1 << 10)	/* device type (mbz) */
+#define RH_A_OCPM	(1 << 11)	/* over current protection mode */
+#define RH_A_NOCP	(1 << 12)	/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)	/* power on to power good time */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff	/* device removable flags */
+#define RH_B_PPCM	0xffff0000	/* port power control mask */
+
+/* Default driver configuration */
+#define CONFIG_DWC2_DMA_ENABLE
+#define CONFIG_DWC2_DMA_BURST_SIZE		32	/* DMA burst len */
+#undef CONFIG_DWC2_DFLT_SPEED_FULL		/* Do not force DWC2 to FS */
+#define CONFIG_DWC2_ENABLE_DYNAMIC_FIFO		/* Runtime FIFO size detect */
+#define CONFIG_DWC2_MAX_CHANNELS		16	/* Max # of EPs */
+#define CONFIG_DWC2_HOST_RX_FIFO_SIZE		(516 + CONFIG_DWC2_MAX_CHANNELS)
+#define CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE	0x100	/* nPeriodic TX FIFO */
+#define CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE	0x200	/* Periodic TX FIFO */
+#define CONFIG_DWC2_MAX_TRANSFER_SIZE		65535
+#define CONFIG_DWC2_MAX_PACKET_COUNT		511
+
+#define DWC2_PHY_TYPE_FS		0
+#define DWC2_PHY_TYPE_UTMI		1
+#define DWC2_PHY_TYPE_ULPI		2
+#define CONFIG_DWC2_PHY_TYPE		DWC2_PHY_TYPE_UTMI	/* PHY type */
+#ifndef CONFIG_DWC2_UTMI_WIDTH
+#define CONFIG_DWC2_UTMI_WIDTH		8	/* UTMI bus width (8/16) */
+#endif
+
+#undef CONFIG_DWC2_PHY_ULPI_DDR			/* ULPI PHY uses DDR mode */
+#define CONFIG_DWC2_PHY_ULPI_EXT_VBUS		/* ULPI PHY controls VBUS */
+#undef CONFIG_DWC2_I2C_ENABLE			/* Enable I2C */
+#undef CONFIG_DWC2_ULPI_FS_LS			/* ULPI is FS/LS */
+#undef CONFIG_DWC2_TS_DLINE			/* External DLine pulsing */
+#undef CONFIG_DWC2_THR_CTL			/* Threshold control */
+#define CONFIG_DWC2_TX_THR_LENGTH		64
+#undef CONFIG_DWC2_IC_USB_CAP			/* IC Cap */
+
+#endif	/* __DWC2_H__ */
diff --git a/roms/u-boot/drivers/usb/host/dwc3-octeon-glue.c b/roms/u-boot/drivers/usb/host/dwc3-octeon-glue.c
new file mode 100644
index 000000000..975f375e1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/dwc3-octeon-glue.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Octeon family DWC3 specific glue layer
+ *
+ * Copyright (C) 2020 Stefan Roese <sr@denx.de>
+ *
+ * The low-level init code is based on the Linux driver octeon-usb.c by
+ * David Daney <david.daney@cavium.com>, which is:
+ * Copyright (C) 2010-2017 Cavium Networks
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <usb.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/of_access.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/usb/dwc3.h>
+#include <linux/usb/otg.h>
+#include <mach/octeon-model.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CVMX_GPIO_BIT_CFGX(i)	(0x0001070000000900ull + ((i) * 8))
+#define CVMX_GPIO_XBIT_CFGX(i)	(0x0001070000000900ull + \
+				 ((i) & 31) * 8 - 8 * 16)
+
+#define GPIO_BIT_CFG_TX_OE		BIT_ULL(0)
+#define GPIO_BIT_CFG_OUTPUT_SEL		GENMASK_ULL(20, 16)
+
+#define UCTL_CTL_UCTL_RST		BIT_ULL(0)
+#define UCTL_CTL_UAHC_RST		BIT_ULL(1)
+#define UCTL_CTL_UPHY_RST		BIT_ULL(2)
+#define UCTL_CTL_DRD_MODE		BIT_ULL(3)
+#define UCTL_CTL_SCLK_EN		BIT_ULL(4)
+#define UCTL_CTL_HS_POWER_EN		BIT_ULL(12)
+#define UCTL_CTL_SS_POWER_EN		BIT_ULL(14)
+#define UCTL_CTL_H_CLKDIV_SEL		GENMASK_ULL(26, 24)
+#define UCTL_CTL_H_CLKDIV_RST		BIT_ULL(28)
+#define UCTL_CTL_H_CLK_EN		BIT_ULL(30)
+#define UCTL_CTL_REF_CLK_FSEL		GENMASK_ULL(37, 32)
+#define UCTL_CTL_REF_CLK_DIV2		BIT_ULL(38)
+#define UCTL_CTL_REF_SSP_EN		BIT_ULL(39)
+#define UCTL_CTL_MPLL_MULTIPLIER	GENMASK_ULL(46, 40)
+#define UCTL_CTL_SSC_EN			BIT_ULL(59)
+#define UCTL_CTL_REF_CLK_SEL		GENMASK_ULL(61, 60)
+
+#define UCTL_HOST_CFG			0xe0
+#define UCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN BIT_ULL(24)
+#define UCTL_HOST_CFG_PPC_EN		BIT_ULL(25)
+
+#define UCTL_SHIM_CFG			0xe8
+#define UCTL_SHIM_CFG_CSR_ENDIAN_MODE	GENMASK_ULL(1, 0)
+#define UCTL_SHIM_CFG_DMA_ENDIAN_MODE	GENMASK_ULL(9, 8)
+
+#define OCTEON_H_CLKDIV_SEL		8
+#define OCTEON_MIN_H_CLK_RATE		150000000
+#define OCTEON_MAX_H_CLK_RATE		300000000
+
+#define CLOCK_50MHZ			50000000
+#define CLOCK_100MHZ			100000000
+#define CLOCK_125MHZ			125000000
+
+static u8 clk_div[OCTEON_H_CLKDIV_SEL] = {1, 2, 4, 6, 8, 16, 24, 32};
+
+static int dwc3_octeon_config_power(struct udevice *dev, void __iomem *base)
+{
+	u64 uctl_host_cfg;
+	u64 gpio_bit;
+	u32 gpio_pwr[3];
+	int gpio, len, power_active_low;
+	const struct device_node *node = dev_np(dev);
+	int index = ((u64)base >> 24) & 1;
+	void __iomem *gpio_bit_cfg;
+
+	if (of_find_property(node, "power", &len)) {
+		if (len == 12) {
+			dev_read_u32_array(dev, "power", gpio_pwr, 3);
+			power_active_low = gpio_pwr[2] & 0x01;
+			gpio = gpio_pwr[1];
+		} else if (len == 8) {
+			dev_read_u32_array(dev, "power", gpio_pwr, 2);
+			power_active_low = 0;
+			gpio = gpio_pwr[1];
+		} else {
+			printf("dwc3 controller clock init failure\n");
+			return -EINVAL;
+		}
+
+		gpio_bit_cfg = ioremap(CVMX_GPIO_BIT_CFGX(gpio), 0);
+
+		if ((OCTEON_IS_MODEL(OCTEON_CN73XX) ||
+		     OCTEON_IS_MODEL(OCTEON_CNF75XX)) && gpio <= 31) {
+			gpio_bit = ioread64(gpio_bit_cfg);
+			gpio_bit |= GPIO_BIT_CFG_TX_OE;
+			gpio_bit &= ~GPIO_BIT_CFG_OUTPUT_SEL;
+			gpio_bit |= FIELD_PREP(GPIO_BIT_CFG_OUTPUT_SEL,
+					       index == 0 ? 0x14 : 0x15);
+			iowrite64(gpio_bit, gpio_bit_cfg);
+		} else if (gpio <= 15) {
+			gpio_bit = ioread64(gpio_bit_cfg);
+			gpio_bit |= GPIO_BIT_CFG_TX_OE;
+			gpio_bit &= ~GPIO_BIT_CFG_OUTPUT_SEL;
+			gpio_bit |= FIELD_PREP(GPIO_BIT_CFG_OUTPUT_SEL,
+					       index == 0 ? 0x14 : 0x19);
+			iowrite64(gpio_bit, gpio_bit_cfg);
+		} else {
+			gpio_bit_cfg = ioremap(CVMX_GPIO_XBIT_CFGX(gpio), 0);
+
+			gpio_bit = ioread64(gpio_bit_cfg);
+			gpio_bit |= GPIO_BIT_CFG_TX_OE;
+			gpio_bit &= ~GPIO_BIT_CFG_OUTPUT_SEL;
+			gpio_bit |= FIELD_PREP(GPIO_BIT_CFG_OUTPUT_SEL,
+					       index == 0 ? 0x14 : 0x19);
+			iowrite64(gpio_bit, gpio_bit_cfg);
+		}
+
+		/* Enable XHCI power control and set if active high or low. */
+		uctl_host_cfg = ioread64(base + UCTL_HOST_CFG);
+		uctl_host_cfg |= UCTL_HOST_CFG_PPC_EN;
+		if (power_active_low)
+			uctl_host_cfg &= ~UCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN;
+		else
+			uctl_host_cfg |= UCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN;
+		iowrite64(uctl_host_cfg, base + UCTL_HOST_CFG);
+
+		/* Wait for power to stabilize */
+		mdelay(10);
+	} else {
+		/* Disable XHCI power control and set if active high. */
+		uctl_host_cfg = ioread64(base + UCTL_HOST_CFG);
+		uctl_host_cfg &= ~UCTL_HOST_CFG_PPC_EN;
+		uctl_host_cfg &= ~UCTL_HOST_CFG_PPC_ACTIVE_HIGH_EN;
+		iowrite64(uctl_host_cfg, base + UCTL_HOST_CFG);
+		dev_warn(dev, "dwc3 controller clock init failure.\n");
+	}
+
+	return 0;
+}
+
+static int dwc3_octeon_clocks_start(struct udevice *dev, void __iomem *base)
+{
+	u64 uctl_ctl;
+	int ref_clk_sel = 2;
+	u64 div;
+	u32 clock_rate;
+	int mpll_mul;
+	int i;
+	u64 h_clk_rate;
+	void __iomem *uctl_ctl_reg = base;
+	const char *ss_clock_type;
+	const char *hs_clock_type;
+
+	i = dev_read_u32(dev, "refclk-frequency", &clock_rate);
+	if (i) {
+		printf("No UCTL \"refclk-frequency\"\n");
+		return -EINVAL;
+	}
+
+	ss_clock_type = dev_read_string(dev, "refclk-type-ss");
+	if (!ss_clock_type) {
+		printf("No UCTL \"refclk-type-ss\"\n");
+		return -EINVAL;
+	}
+
+	hs_clock_type = dev_read_string(dev, "refclk-type-hs");
+	if (!hs_clock_type) {
+		printf("No UCTL \"refclk-type-hs\"\n");
+		return -EINVAL;
+	}
+
+	if (strcmp("dlmc_ref_clk0", ss_clock_type) == 0) {
+		if (strcmp(hs_clock_type, "dlmc_ref_clk0") == 0) {
+			ref_clk_sel = 0;
+		} else if (strcmp(hs_clock_type, "pll_ref_clk") == 0) {
+			ref_clk_sel = 2;
+		} else {
+			printf("Invalid HS clock type %s, using pll_ref_clk\n",
+			       hs_clock_type);
+		}
+	} else if (strcmp(ss_clock_type, "dlmc_ref_clk1") == 0) {
+		if (strcmp(hs_clock_type, "dlmc_ref_clk1") == 0) {
+			ref_clk_sel = 1;
+		} else if (strcmp(hs_clock_type, "pll_ref_clk") == 0) {
+			ref_clk_sel = 3;
+		} else {
+			printf("Invalid HS clock type %s, using pll_ref_clk\n",
+			       hs_clock_type);
+			ref_clk_sel = 3;
+		}
+	} else {
+		printf("Invalid SS clock type %s, using dlmc_ref_clk0\n",
+		       ss_clock_type);
+	}
+
+	if ((ref_clk_sel == 0 || ref_clk_sel == 1) &&
+	    clock_rate != CLOCK_100MHZ)
+		printf("Invalid UCTL clock rate of %u\n", clock_rate);
+
+	/*
+	 * Step 1: Wait for all voltages to be stable...that surely
+	 *         happened before this driver is started. SKIP
+	 */
+
+	/* Step 2: Select GPIO for overcurrent indication, if desired. SKIP */
+
+	/* Step 3: Assert all resets. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl |= UCTL_CTL_UCTL_RST | UCTL_CTL_UAHC_RST | UCTL_CTL_UPHY_RST;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 4a: Reset the clock dividers. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl |= UCTL_CTL_H_CLKDIV_RST;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 4b: Select controller clock frequency. */
+	for (div = ARRAY_SIZE(clk_div) - 1; div >= 0; div--) {
+		h_clk_rate = gd->bus_clk / clk_div[div];
+		if (h_clk_rate <= OCTEON_MAX_H_CLK_RATE &&
+		    h_clk_rate >= OCTEON_MIN_H_CLK_RATE)
+			break;
+	}
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl &= ~UCTL_CTL_H_CLKDIV_SEL;
+	uctl_ctl |= FIELD_PREP(UCTL_CTL_H_CLKDIV_SEL, div);
+	uctl_ctl |= UCTL_CTL_H_CLK_EN;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	if (div != FIELD_GET(UCTL_CTL_H_CLKDIV_SEL, uctl_ctl) ||
+	    !(uctl_ctl & UCTL_CTL_H_CLK_EN)) {
+		printf("dwc3 controller clock init failure\n");
+		return -EINVAL;
+	}
+
+	/* Step 4c: Deassert the controller clock divider reset. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl &= ~UCTL_CTL_H_CLKDIV_RST;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 5a: Reference clock configuration. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl &= ~UCTL_CTL_REF_CLK_SEL;
+	uctl_ctl |= FIELD_PREP(UCTL_CTL_REF_CLK_SEL, ref_clk_sel);
+	uctl_ctl &= ~UCTL_CTL_REF_CLK_FSEL;
+	uctl_ctl |= FIELD_PREP(UCTL_CTL_REF_CLK_FSEL, 0x07);
+	uctl_ctl &= ~UCTL_CTL_REF_CLK_DIV2;
+
+	switch (clock_rate) {
+	default:
+		printf("Invalid ref_clk %u, using %u instead\n", CLOCK_100MHZ,
+		       clock_rate);
+		fallthrough;
+	case CLOCK_100MHZ:
+		mpll_mul = 0x19;
+		if (ref_clk_sel < 2) {
+			uctl_ctl &= ~UCTL_CTL_REF_CLK_FSEL;
+			uctl_ctl |= FIELD_PREP(UCTL_CTL_REF_CLK_FSEL, 0x27);
+		}
+		break;
+	case CLOCK_50MHZ:
+		mpll_mul = 0x32;
+		break;
+	case CLOCK_125MHZ:
+		mpll_mul = 0x28;
+		break;
+	}
+	uctl_ctl &= ~UCTL_CTL_MPLL_MULTIPLIER;
+	uctl_ctl |= FIELD_PREP(UCTL_CTL_MPLL_MULTIPLIER, mpll_mul);
+
+	/* Step 5b: Configure and enable spread-spectrum for SuperSpeed. */
+	uctl_ctl |= UCTL_CTL_SSC_EN;
+
+	/* Step 5c: Enable SuperSpeed. */
+	uctl_ctl |= UCTL_CTL_REF_SSP_EN;
+
+	/* Step 5d: Configure PHYs. SKIP */
+
+	/* Step 6a & 6b: Power up PHYs. */
+	uctl_ctl |= UCTL_CTL_HS_POWER_EN;
+	uctl_ctl |= UCTL_CTL_SS_POWER_EN;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 7: Wait 10 controller-clock cycles to take effect. */
+	udelay(10);
+
+	/* Step 8a: Deassert UCTL reset signal. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl &= ~UCTL_CTL_UCTL_RST;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 8b: Wait 10 controller-clock cycles. */
+	udelay(10);
+
+	/* Step 8c: Setup power-power control. */
+	if (dwc3_octeon_config_power(dev, base)) {
+		printf("Error configuring power\n");
+		return -EINVAL;
+	}
+
+	/* Step 8d: Deassert UAHC reset signal. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl &= ~UCTL_CTL_UAHC_RST;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 8e: Wait 10 controller-clock cycles. */
+	udelay(10);
+
+	/* Step 9: Enable conditional coprocessor clock of UCTL. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl |= UCTL_CTL_SCLK_EN;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	/* Step 10: Set for host mode only. */
+	uctl_ctl = ioread64(uctl_ctl_reg);
+	uctl_ctl &= ~UCTL_CTL_DRD_MODE;
+	iowrite64(uctl_ctl, uctl_ctl_reg);
+
+	return 0;
+}
+
+static void dwc3_octeon_set_endian_mode(void __iomem *base)
+{
+	u64 shim_cfg;
+
+	shim_cfg = ioread64(base + UCTL_SHIM_CFG);
+	shim_cfg &= ~UCTL_SHIM_CFG_CSR_ENDIAN_MODE;
+	shim_cfg |= FIELD_PREP(UCTL_SHIM_CFG_CSR_ENDIAN_MODE, 1);
+	shim_cfg &= ~UCTL_SHIM_CFG_DMA_ENDIAN_MODE;
+	shim_cfg |= FIELD_PREP(UCTL_SHIM_CFG_DMA_ENDIAN_MODE, 1);
+	iowrite64(shim_cfg, base + UCTL_SHIM_CFG);
+}
+
+static void dwc3_octeon_phy_reset(void __iomem *base)
+{
+	u64 uctl_ctl;
+
+	uctl_ctl = ioread64(base);
+	uctl_ctl &= ~UCTL_CTL_UPHY_RST;
+	iowrite64(uctl_ctl, base);
+}
+
+static int octeon_dwc3_glue_probe(struct udevice *dev)
+{
+	void __iomem *base;
+
+	base = dev_remap_addr(dev);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	dwc3_octeon_clocks_start(dev, base);
+	dwc3_octeon_set_endian_mode(base);
+	dwc3_octeon_phy_reset(base);
+
+	return 0;
+}
+
+static int octeon_dwc3_glue_bind(struct udevice *dev)
+{
+	ofnode node, dwc3_node;
+
+	/* Find snps,dwc3 node from subnode */
+	dwc3_node = ofnode_null();
+	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+		if (ofnode_device_is_compatible(node, "snps,dwc3"))
+			dwc3_node = node;
+	}
+
+	if (!ofnode_valid(dwc3_node)) {
+		printf("Can't find dwc3 subnode for %s\n", dev->name);
+		return -ENODEV;
+	}
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id octeon_dwc3_glue_ids[] = {
+	{ .compatible = "cavium,octeon-7130-usb-uctl" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_octeon_glue) = {
+	.name = "dwc3_octeon_glue",
+	.id = UCLASS_NOP,
+	.of_match = octeon_dwc3_glue_ids,
+	.probe = octeon_dwc3_glue_probe,
+	.bind = octeon_dwc3_glue_bind,
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/dwc3-of-simple.c b/roms/u-boot/drivers/usb/host/dwc3-of-simple.c
new file mode 100644
index 000000000..66b3e96b0
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/dwc3-of-simple.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * dwc3-of-simple.c - OF glue layer for simple integrations
+ *
+ * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstron@baylibre.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset.h>
+#include <clk.h>
+
+struct dwc3_of_simple {
+	struct clk_bulk		clks;
+	struct reset_ctl_bulk	resets;
+};
+
+static int dwc3_of_simple_reset_init(struct udevice *dev,
+				     struct dwc3_of_simple *simple)
+{
+	int ret;
+
+	ret = reset_get_bulk(dev, &simple->resets);
+	if (ret == -ENOTSUPP)
+		return 0;
+	else if (ret)
+		return ret;
+
+	ret = reset_deassert_bulk(&simple->resets);
+	if (ret) {
+		reset_release_bulk(&simple->resets);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dwc3_of_simple_clk_init(struct udevice *dev,
+				   struct dwc3_of_simple *simple)
+{
+	int ret;
+
+	ret = clk_get_bulk(dev, &simple->clks);
+	if (ret == -ENOSYS)
+		return 0;
+	if (ret)
+		return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_enable_bulk(&simple->clks);
+	if (ret) {
+		clk_release_bulk(&simple->clks);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static int dwc3_of_simple_probe(struct udevice *dev)
+{
+	struct dwc3_of_simple *simple = dev_get_plat(dev);
+	int ret;
+
+	ret = dwc3_of_simple_clk_init(dev, simple);
+	if (ret)
+		return ret;
+
+	ret = dwc3_of_simple_reset_init(dev, simple);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int dwc3_of_simple_remove(struct udevice *dev)
+{
+	struct dwc3_of_simple *simple = dev_get_plat(dev);
+
+	reset_release_bulk(&simple->resets);
+
+	clk_release_bulk(&simple->clks);
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id dwc3_of_simple_ids[] = {
+	{ .compatible = "amlogic,meson-gxl-dwc3" },
+	{ .compatible = "rockchip,rk3399-dwc3" },
+	{ .compatible = "ti,dwc3" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_of_simple) = {
+	.name = "dwc3-of-simple",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = dwc3_of_simple_ids,
+	.probe = dwc3_of_simple_probe,
+	.remove = dwc3_of_simple_remove,
+	.plat_auto	= sizeof(struct dwc3_of_simple),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/dwc3-sti-glue.c b/roms/u-boot/drivers/usb/host/dwc3-sti-glue.c
new file mode 100644
index 000000000..239b671ac
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/dwc3-sti-glue.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * STiH407 family DWC3 specific Glue layer
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <regmap.h>
+#include <reset-uclass.h>
+#include <syscon.h>
+#include <usb.h>
+
+#include <linux/usb/dwc3.h>
+#include <linux/usb/otg.h>
+#include <dwc3-sti-glue.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct sti_dwc3_glue_plat - dwc3 STi glue driver private structure
+ * @syscfg_base:	addr for the glue syscfg
+ * @glue_base:		addr for the glue registers
+ * @syscfg_offset:	usb syscfg control offset
+ * @powerdown_ctl:	rest controller for powerdown signal
+ * @softreset_ctl:	reset controller for softreset signal
+ * @mode:		drd static host/device config
+ */
+struct sti_dwc3_glue_plat {
+	phys_addr_t syscfg_base;
+	phys_addr_t glue_base;
+	phys_addr_t syscfg_offset;
+	struct reset_ctl powerdown_ctl;
+	struct reset_ctl softreset_ctl;
+	enum usb_dr_mode mode;
+};
+
+static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_plat *plat)
+{
+	unsigned long val;
+
+	val = readl(plat->syscfg_base + plat->syscfg_offset);
+
+	val &= USB3_CONTROL_MASK;
+
+	switch (plat->mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		val &= ~(USB3_DELAY_VBUSVALID
+			| USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
+			| USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
+			| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
+
+		val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID;
+		break;
+
+	case USB_DR_MODE_HOST:
+		val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID
+			| USB3_SEL_FORCE_OPMODE	| USB3_FORCE_OPMODE(0x3)
+			| USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
+			| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
+
+		val |= USB3_DELAY_VBUSVALID;
+		break;
+
+	default:
+		pr_err("Unsupported mode of operation %d\n", plat->mode);
+		return -EINVAL;
+	}
+	writel(val, plat->syscfg_base + plat->syscfg_offset);
+
+	return 0;
+}
+
+static void sti_dwc3_glue_init(struct sti_dwc3_glue_plat *plat)
+{
+	unsigned long reg;
+
+	reg = readl(plat->glue_base + CLKRST_CTRL);
+
+	reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION;
+	reg &= ~SW_PIPEW_RESET_N;
+
+	writel(reg, plat->glue_base + CLKRST_CTRL);
+
+	/* configure mux for vbus, powerpresent and bvalid signals */
+	reg = readl(plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
+
+	reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
+	       SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
+	       SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG);
+
+	writel(reg, plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
+
+	setbits_le32(plat->glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
+}
+
+static int sti_dwc3_glue_of_to_plat(struct udevice *dev)
+{
+	struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
+	struct udevice *syscon;
+	struct regmap *regmap;
+	int ret;
+	u32 reg[4];
+
+	ret = ofnode_read_u32_array(dev_ofnode(dev), "reg", reg,
+				    ARRAY_SIZE(reg));
+	if (ret) {
+		pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret);
+		return ret;
+	}
+
+	plat->glue_base = reg[0];
+	plat->syscfg_offset = reg[2];
+
+	/* get corresponding syscon phandle */
+	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg",
+					   &syscon);
+	if (ret) {
+		pr_err("unable to find syscon device (%d)\n", ret);
+		return ret;
+	}
+
+	/* get syscfg-reg base address */
+	regmap = syscon_get_regmap(syscon);
+	if (!regmap) {
+		pr_err("unable to find regmap\n");
+		return -ENODEV;
+	}
+	plat->syscfg_base = regmap->ranges[0].start;
+
+	/* get powerdown reset */
+	ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl);
+	if (ret) {
+		pr_err("can't get powerdown reset for %s (%d)", dev->name, ret);
+		return ret;
+	}
+
+	/* get softreset reset */
+	ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl);
+	if (ret)
+		pr_err("can't get soft reset for %s (%d)", dev->name, ret);
+
+	return ret;
+};
+
+static int sti_dwc3_glue_bind(struct udevice *dev)
+{
+	struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
+	ofnode node, dwc3_node;
+
+	/* Find snps,dwc3 node from subnode */
+	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+		if (ofnode_device_is_compatible(node, "snps,dwc3"))
+			dwc3_node = node;
+	}
+
+	if (!ofnode_valid(dwc3_node)) {
+		pr_err("Can't find dwc3 subnode for %s\n", dev->name);
+		return -ENODEV;
+	}
+
+	/* retrieve the DWC3 dual role mode */
+	plat->mode = usb_get_dr_mode(dwc3_node);
+	if (plat->mode == USB_DR_MODE_UNKNOWN)
+		/* by default set dual role mode to HOST */
+		plat->mode = USB_DR_MODE_HOST;
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static int sti_dwc3_glue_probe(struct udevice *dev)
+{
+	struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	/* deassert both powerdown and softreset */
+	ret = reset_deassert(&plat->powerdown_ctl);
+	if (ret < 0) {
+		pr_err("DWC3 powerdown reset deassert failed: %d", ret);
+		return ret;
+	}
+
+	ret = reset_deassert(&plat->softreset_ctl);
+	if (ret < 0) {
+		pr_err("DWC3 soft reset deassert failed: %d", ret);
+		goto softreset_err;
+	}
+
+	ret = sti_dwc3_glue_drd_init(plat);
+	if (ret)
+		goto init_err;
+
+	sti_dwc3_glue_init(plat);
+
+	return 0;
+
+init_err:
+	ret = reset_assert(&plat->softreset_ctl);
+	if (ret < 0) {
+		pr_err("DWC3 soft reset deassert failed: %d", ret);
+		return ret;
+	}
+
+softreset_err:
+	ret = reset_assert(&plat->powerdown_ctl);
+	if (ret < 0)
+		pr_err("DWC3 powerdown reset deassert failed: %d", ret);
+
+	return ret;
+}
+
+static int sti_dwc3_glue_remove(struct udevice *dev)
+{
+	struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	/* assert both powerdown and softreset */
+	ret = reset_assert(&plat->powerdown_ctl);
+	if (ret < 0) {
+		pr_err("DWC3 powerdown reset deassert failed: %d", ret);
+		return ret;
+	}
+
+	ret = reset_assert(&plat->softreset_ctl);
+	if (ret < 0)
+		pr_err("DWC3 soft reset deassert failed: %d", ret);
+
+	return ret;
+}
+
+static const struct udevice_id sti_dwc3_glue_ids[] = {
+	{ .compatible = "st,stih407-dwc3" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_sti_glue) = {
+	.name = "dwc3_sti_glue",
+	.id = UCLASS_NOP,
+	.of_match = sti_dwc3_glue_ids,
+	.of_to_plat = sti_dwc3_glue_of_to_plat,
+	.probe = sti_dwc3_glue_probe,
+	.remove = sti_dwc3_glue_remove,
+	.bind = sti_dwc3_glue_bind,
+	.plat_auto	= sizeof(struct sti_dwc3_glue_plat),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ehci-armada100.c b/roms/u-boot/drivers/usb/host/ehci-armada100.c
new file mode 100644
index 000000000..2ce9f27b8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-armada100.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <contact@8051projects.net>
+ *
+ * This driver is based on Kirkwood echi driver
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <usb.h>
+#include "ehci.h"
+#include <asm/arch/cpu.h>
+#include <asm/arch/armada100.h>
+#include <asm/arch/utmi-armada100.h>
+
+/*
+ * EHCI host controller init
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	if (utmi_init() < 0)
+		return -1;
+
+	*hccr = (struct ehci_hccr *)(ARMD1_USB_HOST_BASE + 0x100);
+	*hcor = (struct ehci_hcor *)((uint32_t) *hccr
+			+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	debug("armada100-ehci: init hccr %x and hcor %x hc_length %d\n",
+		(uint32_t)*hccr, (uint32_t)*hcor,
+		(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	return 0;
+}
+
+/*
+ * EHCI host controller stop
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-atmel.c b/roms/u-boot/drivers/usb/host/ehci-atmel.c
new file mode 100644
index 000000000..fba3595e1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-atmel.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012
+ * Atmel Semiconductor <www.atmel.com>
+ * Written-by: Bo Shen <voice.shen@atmel.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+
+#include "ehci.h"
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	/* Enable UTMI PLL */
+	if (at91_upll_clk_enable())
+		return -1;
+
+	/* Enable USB Host clock */
+	at91_periph_clk_enable(ATMEL_ID_UHPHS);
+
+	*hccr = (struct ehci_hccr *)ATMEL_BASE_EHCI;
+	*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	/* Disable USB Host Clock */
+	at91_periph_clk_disable(ATMEL_ID_UHPHS);
+
+	/* Disable UTMI PLL */
+	if (at91_upll_clk_disable())
+		return -1;
+
+	return 0;
+}
+
+#else
+
+struct ehci_atmel_priv {
+	struct ehci_ctrl ehci;
+};
+
+static int ehci_atmel_enable_clk(struct udevice *dev)
+{
+	struct clk clk;
+	int ret;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(&clk);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 1, &clk);
+	if (ret)
+		return -EINVAL;
+
+	ret = clk_enable(&clk);
+	if (ret)
+		return ret;
+
+	clk_free(&clk);
+
+	return 0;
+}
+
+static int ehci_atmel_probe(struct udevice *dev)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	fdt_addr_t hcd_base;
+	int ret;
+
+	ret = ehci_atmel_enable_clk(dev);
+	if (ret) {
+		debug("Failed to enable USB Host clock\n");
+		return ret;
+	}
+
+	/*
+	 * Get the base address for EHCI controller from the device node
+	 */
+	hcd_base = dev_read_addr(dev);
+	if (hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the EHCI register base address\n");
+		return -ENXIO;
+	}
+
+	hccr = (struct ehci_hccr *)hcd_base;
+	hcor = (struct ehci_hcor *)
+		((u32)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	debug("echi-atmel: init hccr %x and hcor %x hc_length %d\n",
+	      (u32)hccr, (u32)hcor,
+	      (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "atmel,at91sam9g45-ehci", },
+	{ }
+};
+
+U_BOOT_DRIVER(ehci_atmel) = {
+	.name		= "ehci_atmel",
+	.id		= UCLASS_USB,
+	.of_match	= ehci_usb_ids,
+	.probe		= ehci_atmel_probe,
+	.remove		= ehci_deregister,
+	.ops		= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_atmel_priv),
+	.flags		= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ehci-exynos.c b/roms/u-boot/drivers/usb/host/ehci-exynos.c
new file mode 100644
index 000000000..c1cdd4b08
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-exynos.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SAMSUNG EXYNOS USB HOST EHCI Controller
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *	Vivek Gautam <gautam.vivek@samsung.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+#include <linux/libfdt.h>
+#include <malloc.h>
+#include <usb.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/ehci.h>
+#include <asm/arch/system.h>
+#include <asm/arch/power.h>
+#include <asm/gpio.h>
+#include <linux/errno.h>
+#include <linux/compat.h>
+#include "ehci.h"
+
+/* Declare global data pointer */
+DECLARE_GLOBAL_DATA_PTR;
+
+struct exynos_ehci_plat {
+	struct usb_plat usb_plat;
+	fdt_addr_t hcd_base;
+	fdt_addr_t phy_base;
+	struct gpio_desc vbus_gpio;
+};
+
+/**
+ * Contains pointers to register base addresses
+ * for the usb controller.
+ */
+struct exynos_ehci {
+	struct ehci_ctrl ctrl;
+	struct exynos_usb_phy *usb;
+	struct ehci_hccr *hcd;
+};
+
+static int ehci_usb_of_to_plat(struct udevice *dev)
+{
+	struct exynos_ehci_plat *plat = dev_get_plat(dev);
+	const void *blob = gd->fdt_blob;
+	unsigned int node;
+	int depth;
+
+	/*
+	 * Get the base address for XHCI controller from the device node
+	 */
+	plat->hcd_base = dev_read_addr(dev);
+	if (plat->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the XHCI register base address\n");
+		return -ENXIO;
+	}
+
+	depth = 0;
+	node = fdtdec_next_compatible_subnode(blob, dev_of_offset(dev),
+				COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
+	if (node <= 0) {
+		debug("XHCI: Can't get device node for usb3-phy controller\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Get the base address for usbphy from the device node
+	 */
+	plat->phy_base = fdtdec_get_addr(blob, node, "reg");
+	if (plat->phy_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the usbphy register address\n");
+		return -ENXIO;
+	}
+
+	/* Vbus gpio */
+	gpio_request_by_name(dev, "samsung,vbus-gpio", 0,
+			     &plat->vbus_gpio, GPIOD_IS_OUT);
+
+	return 0;
+}
+
+static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb)
+{
+	u32 hsic_ctrl;
+
+	clrbits_le32(&usb->usbphyctrl0,
+			HOST_CTRL0_FSEL_MASK |
+			HOST_CTRL0_COMMONON_N |
+			/* HOST Phy setting */
+			HOST_CTRL0_PHYSWRST |
+			HOST_CTRL0_PHYSWRSTALL |
+			HOST_CTRL0_SIDDQ |
+			HOST_CTRL0_FORCESUSPEND |
+			HOST_CTRL0_FORCESLEEP);
+
+	setbits_le32(&usb->usbphyctrl0,
+			/* Setting up the ref freq */
+			(CLK_24MHZ << 16) |
+			/* HOST Phy setting */
+			HOST_CTRL0_LINKSWRST |
+			HOST_CTRL0_UTMISWRST);
+	udelay(10);
+	clrbits_le32(&usb->usbphyctrl0,
+			HOST_CTRL0_LINKSWRST |
+			HOST_CTRL0_UTMISWRST);
+
+	/* HSIC Phy Setting */
+	hsic_ctrl = (HSIC_CTRL_FORCESUSPEND |
+			HSIC_CTRL_FORCESLEEP |
+			HSIC_CTRL_SIDDQ);
+
+	clrbits_le32(&usb->hsicphyctrl1, hsic_ctrl);
+	clrbits_le32(&usb->hsicphyctrl2, hsic_ctrl);
+
+	hsic_ctrl = (((HSIC_CTRL_REFCLKDIV_12 & HSIC_CTRL_REFCLKDIV_MASK)
+				<< HSIC_CTRL_REFCLKDIV_SHIFT)
+			| ((HSIC_CTRL_REFCLKSEL & HSIC_CTRL_REFCLKSEL_MASK)
+				<< HSIC_CTRL_REFCLKSEL_SHIFT)
+			| HSIC_CTRL_UTMISWRST);
+
+	setbits_le32(&usb->hsicphyctrl1, hsic_ctrl);
+	setbits_le32(&usb->hsicphyctrl2, hsic_ctrl);
+
+	udelay(10);
+
+	clrbits_le32(&usb->hsicphyctrl1, HSIC_CTRL_PHYSWRST |
+					HSIC_CTRL_UTMISWRST);
+
+	clrbits_le32(&usb->hsicphyctrl2, HSIC_CTRL_PHYSWRST |
+					HSIC_CTRL_UTMISWRST);
+
+	udelay(20);
+
+	/* EHCI Ctrl setting */
+	setbits_le32(&usb->ehcictrl,
+			EHCICTRL_ENAINCRXALIGN |
+			EHCICTRL_ENAINCR4 |
+			EHCICTRL_ENAINCR8 |
+			EHCICTRL_ENAINCR16);
+}
+
+static void exynos4412_setup_usb_phy(struct exynos4412_usb_phy *usb)
+{
+	writel(CLK_24MHZ, &usb->usbphyclk);
+
+	clrbits_le32(&usb->usbphyctrl, (PHYPWR_NORMAL_MASK_HSIC0 |
+		PHYPWR_NORMAL_MASK_HSIC1 | PHYPWR_NORMAL_MASK_PHY1 |
+		PHYPWR_NORMAL_MASK_PHY0));
+
+	setbits_le32(&usb->usbphyrstcon, (RSTCON_HOSTPHY_SWRST | RSTCON_SWRST));
+	udelay(10);
+	clrbits_le32(&usb->usbphyrstcon, (RSTCON_HOSTPHY_SWRST | RSTCON_SWRST));
+}
+
+static void setup_usb_phy(struct exynos_usb_phy *usb)
+{
+	set_usbhost_mode(USB20_PHY_CFG_HOST_LINK_EN);
+
+	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_EN);
+
+	if (cpu_is_exynos5())
+		exynos5_setup_usb_phy(usb);
+	else if (cpu_is_exynos4())
+		if (proid_is_exynos4412())
+			exynos4412_setup_usb_phy((struct exynos4412_usb_phy *)
+						 usb);
+}
+
+static void exynos5_reset_usb_phy(struct exynos_usb_phy *usb)
+{
+	u32 hsic_ctrl;
+
+	/* HOST_PHY reset */
+	setbits_le32(&usb->usbphyctrl0,
+			HOST_CTRL0_PHYSWRST |
+			HOST_CTRL0_PHYSWRSTALL |
+			HOST_CTRL0_SIDDQ |
+			HOST_CTRL0_FORCESUSPEND |
+			HOST_CTRL0_FORCESLEEP);
+
+	/* HSIC Phy reset */
+	hsic_ctrl = (HSIC_CTRL_FORCESUSPEND |
+			HSIC_CTRL_FORCESLEEP |
+			HSIC_CTRL_SIDDQ |
+			HSIC_CTRL_PHYSWRST);
+
+	setbits_le32(&usb->hsicphyctrl1, hsic_ctrl);
+	setbits_le32(&usb->hsicphyctrl2, hsic_ctrl);
+}
+
+static void exynos4412_reset_usb_phy(struct exynos4412_usb_phy *usb)
+{
+	setbits_le32(&usb->usbphyctrl, (PHYPWR_NORMAL_MASK_HSIC0 |
+		PHYPWR_NORMAL_MASK_HSIC1 | PHYPWR_NORMAL_MASK_PHY1 |
+		PHYPWR_NORMAL_MASK_PHY0));
+}
+
+/* Reset the EHCI host controller. */
+static void reset_usb_phy(struct exynos_usb_phy *usb)
+{
+	if (cpu_is_exynos5())
+		exynos5_reset_usb_phy(usb);
+	else if (cpu_is_exynos4())
+		if (proid_is_exynos4412())
+			exynos4412_reset_usb_phy((struct exynos4412_usb_phy *)
+						 usb);
+
+	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct exynos_ehci_plat *plat = dev_get_plat(dev);
+	struct exynos_ehci *ctx = dev_get_priv(dev);
+	struct ehci_hcor *hcor;
+
+	ctx->hcd = (struct ehci_hccr *)plat->hcd_base;
+	ctx->usb = (struct exynos_usb_phy *)plat->phy_base;
+
+	/* setup the Vbus gpio here */
+	if (dm_gpio_is_valid(&plat->vbus_gpio))
+		dm_gpio_set_value(&plat->vbus_gpio, 1);
+
+	setup_usb_phy(ctx->usb);
+	hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd +
+			HC_LENGTH(ehci_readl(&ctx->hcd->cr_capbase)));
+
+	return ehci_register(dev, ctx->hcd, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+	struct exynos_ehci *ctx = dev_get_priv(dev);
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+	reset_usb_phy(ctx->usb);
+
+	return 0;
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "samsung,exynos-ehci" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_exynos",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.of_to_plat = ehci_usb_of_to_plat,
+	.probe = ehci_usb_probe,
+	.remove = ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.priv_auto	= sizeof(struct exynos_ehci),
+	.plat_auto	= sizeof(struct exynos_ehci_plat),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ehci-faraday.c b/roms/u-boot/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 000000000..b61b5382d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+void faraday_ehci_set_usbmode(struct ehci_ctrl *ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int faraday_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+{
+	int spd, ret = PORTSC_PSPD_HS;
+	union ehci_faraday_regs *regs;
+
+	ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		ret = PORTSC_PSPD_FS;
+		break;
+	case 1:    /* low  speed */
+		ret = PORTSC_PSPD_LS;
+		break;
+	case 2:    /* high speed */
+		ret = PORTSC_PSPD_HS;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+uint32_t *faraday_ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port) {
+		/* Printing the message would cause a scan failure! */
+		debug("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
+}
+
+static const struct ehci_ops faraday_ehci_ops = {
+	.set_usb_mode		= faraday_ehci_set_usbmode,
+	.get_port_speed		= faraday_ehci_get_port_speed,
+	.get_portsc_register	= faraday_ehci_get_portsc_register,
+};
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	ehci_set_controller_priv(index, NULL, &faraday_ehci_ops);
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-fsl.c b/roms/u-boot/drivers/usb/host/ehci-fsl.c
new file mode 100644
index 000000000..cf1f88244
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-fsl.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009, 2011, 2016 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
+ *
+ * Author: Tor Krill tor@excito.com
+ */
+
+#include <common.h>
+#include <env.h>
+#include <log.h>
+#include <pci.h>
+#include <usb.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <usb/ehci-ci.h>
+#include <hwconfig.h>
+#include <fsl_usb.h>
+#include <fdt_support.h>
+#include <dm.h>
+
+#include "ehci.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+struct ehci_fsl_priv {
+	struct ehci_ctrl ehci;
+	fdt_addr_t hcd_base;
+	char *phy_type;
+};
+#endif
+
+static void set_txfifothresh(struct usb_ehci *, u32);
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci,
+		  struct ehci_hccr *hccr, struct ehci_hcor *hcor);
+#else
+static int ehci_fsl_init(int index, struct usb_ehci *ehci,
+			 struct ehci_hccr *hccr, struct ehci_hcor *hcor);
+#endif
+
+/* Check USB PHY clock valid */
+static int usb_phy_clk_valid(struct usb_ehci *ehci)
+{
+	if (!((in_be32(&ehci->control) & PHY_CLK_VALID) ||
+			in_be32(&ehci->prictrl))) {
+		printf("USB PHY clock invalid!\n");
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ehci_fsl_of_to_plat(struct udevice *dev)
+{
+	struct ehci_fsl_priv *priv = dev_get_priv(dev);
+	const void *prop;
+
+	prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy_type",
+			   NULL);
+	if (prop) {
+		priv->phy_type = (char *)prop;
+		debug("phy_type %s\n", priv->phy_type);
+	}
+
+	return 0;
+}
+
+static int ehci_fsl_init_after_reset(struct ehci_ctrl *ctrl)
+{
+	struct usb_ehci *ehci = NULL;
+	struct ehci_fsl_priv *priv = container_of(ctrl, struct ehci_fsl_priv,
+						   ehci);
+#ifdef CONFIG_PPC
+	ehci = (struct usb_ehci *)lower_32_bits(priv->hcd_base);
+#else
+	ehci = (struct usb_ehci *)priv->hcd_base;
+#endif
+
+	if (ehci_fsl_init(priv, ehci, priv->ehci.hccr, priv->ehci.hcor) < 0)
+		return -ENXIO;
+
+	return 0;
+}
+
+static const struct ehci_ops fsl_ehci_ops = {
+	.init_after_reset = ehci_fsl_init_after_reset,
+};
+
+static int ehci_fsl_probe(struct udevice *dev)
+{
+	struct ehci_fsl_priv *priv = dev_get_priv(dev);
+	struct usb_ehci *ehci = NULL;
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	struct ehci_ctrl *ehci_ctrl = &priv->ehci;
+
+	/*
+	 * Get the base address for EHCI controller from the device node
+	 */
+	priv->hcd_base = dev_read_addr(dev);
+	if (priv->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the EHCI register base address\n");
+		return -ENXIO;
+	}
+#ifdef CONFIG_PPC
+	ehci = (struct usb_ehci *)lower_32_bits(priv->hcd_base);
+#else
+	ehci = (struct usb_ehci *)priv->hcd_base;
+#endif
+	hccr = (struct ehci_hccr *)(&ehci->caplength);
+	hcor = (struct ehci_hcor *)
+		((void *)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	ehci_ctrl->has_fsl_erratum_a005275 = has_erratum_a005275();
+
+	if (ehci_fsl_init(priv, ehci, hccr, hcor) < 0)
+		return -ENXIO;
+
+	debug("ehci-fsl: init hccr %p and hcor %p hc_length %d\n",
+	      (void *)hccr, (void *)hcor,
+	      HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	return ehci_register(dev, hccr, hcor, &fsl_ehci_ops, 0, USB_INIT_HOST);
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "fsl-usb2-mph", },
+	{ .compatible = "fsl-usb2-dr", },
+	{ }
+};
+
+U_BOOT_DRIVER(ehci_fsl) = {
+	.name	= "ehci_fsl",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.of_to_plat = ehci_fsl_of_to_plat,
+	.probe = ehci_fsl_probe,
+	.remove = ehci_deregister,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_fsl_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#else
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ *
+ * Excerpts from linux ehci fsl driver.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	struct ehci_ctrl *ehci_ctrl = container_of(hccr,
+					struct ehci_ctrl, hccr);
+	struct usb_ehci *ehci = NULL;
+
+	switch (index) {
+	case 0:
+		ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR;
+		break;
+	case 1:
+		ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB2_ADDR;
+		break;
+	default:
+		printf("ERROR: wrong controller index!!\n");
+		return -EINVAL;
+	};
+
+	*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	ehci_ctrl->has_fsl_erratum_a005275 = has_erratum_a005275();
+
+	return ehci_fsl_init(index, ehci, *hccr, *hcor);
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci,
+		  struct ehci_hccr *hccr, struct ehci_hcor *hcor)
+#else
+static int ehci_fsl_init(int index, struct usb_ehci *ehci,
+			 struct ehci_hccr *hccr, struct ehci_hcor *hcor)
+#endif
+{
+	const char *phy_type = NULL;
+#if !CONFIG_IS_ENABLED(DM_USB)
+	size_t len;
+	char current_usb_controller[5];
+#endif
+#ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY
+	char usb_phy[5];
+
+	usb_phy[0] = '\0';
+#endif
+	if (has_erratum_a007075()) {
+		/*
+		 * A 5ms delay is needed after applying soft-reset to the
+		 * controller to let external ULPI phy come out of reset.
+		 * This delay needs to be added before re-initializing
+		 * the controller after soft-resetting completes
+		 */
+		mdelay(5);
+	}
+
+	/* Set to Host mode */
+	setbits_le32(&ehci->usbmode, CM_HOST);
+
+	out_be32(&ehci->snoop1, SNOOP_SIZE_2GB);
+	out_be32(&ehci->snoop2, 0x80000000 | SNOOP_SIZE_2GB);
+
+	/* Init phy */
+#if CONFIG_IS_ENABLED(DM_USB)
+	if (priv->phy_type)
+		phy_type = priv->phy_type;
+#else
+	memset(current_usb_controller, '\0', 5);
+	snprintf(current_usb_controller, sizeof(current_usb_controller),
+		 "usb%d", index+1);
+
+	if (hwconfig_sub(current_usb_controller, "phy_type"))
+		phy_type = hwconfig_subarg(current_usb_controller,
+				"phy_type", &len);
+#endif
+	else
+		phy_type = env_get("usb_phy_type");
+
+	if (!phy_type) {
+#ifdef CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY
+		/* if none specified assume internal UTMI */
+		strcpy(usb_phy, "utmi");
+		phy_type = usb_phy;
+#else
+		printf("WARNING: USB phy type not defined !!\n");
+		return -1;
+#endif
+	}
+
+	if (!strncmp(phy_type, "utmi", 4)) {
+#if defined(CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY)
+		clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+				PHY_CLK_SEL_UTMI);
+		clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+				UTMI_PHY_EN);
+		udelay(1000); /* delay required for PHY Clk to appear */
+#endif
+		out_le32(&(hcor)->or_portsc[0], PORT_PTS_UTMI);
+		clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+				USB_EN);
+	} else {
+		clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+				PHY_CLK_SEL_ULPI);
+		clrsetbits_be32(&ehci->control, UTMI_PHY_EN |
+				CONTROL_REGISTER_W1C_MASK, USB_EN);
+		udelay(1000); /* delay required for PHY Clk to appear */
+		if (!usb_phy_clk_valid(ehci))
+			return -EINVAL;
+		out_le32(&(hcor)->or_portsc[0], PORT_PTS_ULPI);
+	}
+
+	out_be32(&ehci->prictrl, 0x0000000c);
+	out_be32(&ehci->age_cnt_limit, 0x00000040);
+	out_be32(&ehci->sictrl, 0x00000001);
+
+	in_le32(&ehci->usbmode);
+
+	if (has_erratum_a007798())
+		set_txfifothresh(ehci, TXFIFOTHRESH);
+
+	if (has_erratum_a004477()) {
+		/*
+		 * When reset is issued while any ULPI transaction is ongoing
+		 * then it may result to corruption of ULPI Function Control
+		 * Register which eventually causes phy clock to enter low
+		 * power mode which stops the clock. Thus delay is required
+		 * before reset to let ongoing ULPI transaction complete.
+		 */
+		udelay(1);
+	}
+	return 0;
+}
+
+/*
+ * Setting the value of TXFIFO_THRESH field in TXFILLTUNING register
+ * to counter DDR latencies in writing data into Tx buffer.
+ * This prevents Tx buffer from getting underrun
+ */
+static void set_txfifothresh(struct usb_ehci *ehci, u32 txfifo_thresh)
+{
+	u32 cmd;
+	cmd = ehci_readl(&ehci->txfilltuning);
+	cmd &= ~TXFIFO_THRESH_MASK;
+	cmd |= TXFIFO_THRESH(txfifo_thresh);
+	ehci_writel(&ehci->txfilltuning, cmd);
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-generic.c b/roms/u-boot/drivers/usb/host/ehci-generic.c
new file mode 100644
index 000000000..4c28a69b9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-generic.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/ofnode.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm.h>
+#include "ehci.h"
+#include <power/regulator.h>
+
+/*
+ * Even though here we don't explicitly use "struct ehci_ctrl"
+ * ehci_register() expects it to be the first thing that resides in
+ * device's private data.
+ */
+struct generic_ehci {
+	struct ehci_ctrl ctrl;
+	struct clk *clocks;
+	struct reset_ctl *resets;
+	struct phy phy;
+#ifdef CONFIG_DM_REGULATOR
+	struct udevice *vbus_supply;
+#endif
+	int clock_count;
+	int reset_count;
+};
+
+#ifdef CONFIG_DM_REGULATOR
+static int ehci_enable_vbus_supply(struct udevice *dev)
+{
+	struct generic_ehci *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &priv->vbus_supply);
+	if (ret && ret != -ENOENT)
+		return ret;
+
+	if (priv->vbus_supply) {
+		ret = regulator_set_enable(priv->vbus_supply, true);
+		if (ret) {
+			dev_err(dev, "Error enabling VBUS supply\n");
+			return ret;
+		}
+	} else {
+		dev_dbg(dev, "No vbus supply\n");
+	}
+
+	return 0;
+}
+
+static int ehci_disable_vbus_supply(struct generic_ehci *priv)
+{
+	if (priv->vbus_supply)
+		return regulator_set_enable(priv->vbus_supply, false);
+	else
+		return 0;
+}
+#else
+static int ehci_enable_vbus_supply(struct udevice *dev)
+{
+	return 0;
+}
+
+static int ehci_disable_vbus_supply(struct generic_ehci *priv)
+{
+	return 0;
+}
+#endif
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct generic_ehci *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int i, err, ret, clock_nb, reset_nb;
+
+	err = 0;
+	priv->clock_count = 0;
+	clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
+						  "#clock-cells", 0);
+	if (clock_nb > 0) {
+		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
+					    GFP_KERNEL);
+		if (!priv->clocks)
+			return -ENOMEM;
+
+		for (i = 0; i < clock_nb; i++) {
+			err = clk_get_by_index(dev, i, &priv->clocks[i]);
+
+			if (err < 0)
+				break;
+			err = clk_enable(&priv->clocks[i]);
+			if (err && err != -ENOSYS) {
+				dev_err(dev, "failed to enable clock %d\n", i);
+				clk_free(&priv->clocks[i]);
+				goto clk_err;
+			}
+			priv->clock_count++;
+		}
+	} else {
+		if (clock_nb != -ENOENT) {
+			dev_err(dev, "failed to get clock phandle(%d)\n",
+				clock_nb);
+			return clock_nb;
+		}
+	}
+
+	priv->reset_count = 0;
+	reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
+						  "#reset-cells", 0);
+	if (reset_nb > 0) {
+		priv->resets = devm_kcalloc(dev, reset_nb,
+					    sizeof(struct reset_ctl),
+					    GFP_KERNEL);
+		if (!priv->resets)
+			return -ENOMEM;
+
+		for (i = 0; i < reset_nb; i++) {
+			err = reset_get_by_index(dev, i, &priv->resets[i]);
+			if (err < 0)
+				break;
+
+			if (reset_deassert(&priv->resets[i])) {
+				dev_err(dev, "failed to deassert reset %d\n",
+					i);
+				reset_free(&priv->resets[i]);
+				goto reset_err;
+			}
+			priv->reset_count++;
+		}
+	} else {
+		if (reset_nb != -ENOENT) {
+			dev_err(dev, "failed to get reset phandle(%d)\n",
+				reset_nb);
+			goto clk_err;
+		}
+	}
+
+	err = ehci_enable_vbus_supply(dev);
+	if (err)
+		goto reset_err;
+
+	err = ehci_setup_phy(dev, &priv->phy, 0);
+	if (err)
+		goto regulator_err;
+
+	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
+	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
+				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+	if (err)
+		goto phy_err;
+
+	return 0;
+
+phy_err:
+	ret = ehci_shutdown_phy(dev, &priv->phy);
+	if (ret)
+		dev_err(dev, "failed to shutdown usb phy\n");
+
+regulator_err:
+	ret = ehci_disable_vbus_supply(priv);
+	if (ret)
+		dev_err(dev, "failed to disable VBUS supply\n");
+
+reset_err:
+	ret = reset_release_all(priv->resets, priv->reset_count);
+	if (ret)
+		dev_err(dev, "failed to assert all resets\n");
+clk_err:
+	ret = clk_release_all(priv->clocks, priv->clock_count);
+	if (ret)
+		dev_err(dev, "failed to disable all clocks\n");
+
+	return err;
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+	struct generic_ehci *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	ret = ehci_shutdown_phy(dev, &priv->phy);
+	if (ret)
+		return ret;
+
+	ret = ehci_disable_vbus_supply(priv);
+	if (ret)
+		return ret;
+
+	ret =  reset_release_all(priv->resets, priv->reset_count);
+	if (ret)
+		return ret;
+
+	return clk_release_all(priv->clocks, priv->clock_count);
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "generic-ehci" },
+	{ }
+};
+
+U_BOOT_DRIVER(ehci_generic) = {
+	.name	= "ehci_generic",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.probe = ehci_usb_probe,
+	.remove = ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.priv_auto	= sizeof(struct generic_ehci),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ehci-hcd.c b/roms/u-boot/drivers/usb/host/ehci-hcd.c
new file mode 100644
index 000000000..ba75c27d0
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-hcd.c
@@ -0,0 +1,1839 @@
+// SPDX-License-Identifier: GPL-2.0
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Excito Elektronik i Skåne AB
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * All rights reserved.
+ */
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/byteorder.h>
+#include <asm/cache.h>
+#include <asm/unaligned.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <watchdog.h>
+#include <dm/device_compat.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+/*
+ * EHCI spec page 20 says that the HC may take up to 16 uFrames (= 4ms) to halt.
+ * Let's time out after 8 to have a little safety margin on top of that.
+ */
+#define HCHALT_TIMEOUT (8 * 1000)
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
+
+#define ALIGN_END_ADDR(type, ptr, size)			\
+	((unsigned long)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN))
+
+static struct descriptor {
+	struct usb_hub_descriptor hub;
+	struct usb_device_descriptor device;
+	struct usb_linux_config_descriptor config;
+	struct usb_linux_interface_descriptor interface;
+	struct usb_endpoint_descriptor endpoint;
+}  __attribute__ ((packed)) descriptor = {
+	{
+		0x8,		/* bDescLength */
+		0x29,		/* bDescriptorType: hub descriptor */
+		2,		/* bNrPorts -- runtime modified */
+		0,		/* wHubCharacteristics */
+		10,		/* bPwrOn2PwrGood */
+		0,		/* bHubCntrCurrent */
+		{		/* Device removable */
+		}		/* at most 7 ports! XXX */
+	},
+	{
+		0x12,		/* bLength */
+		1,		/* bDescriptorType: UDESC_DEVICE */
+		cpu_to_le16(0x0200), /* bcdUSB: v2.0 */
+		9,		/* bDeviceClass: UDCLASS_HUB */
+		0,		/* bDeviceSubClass: UDSUBCLASS_HUB */
+		1,		/* bDeviceProtocol: UDPROTO_HSHUBSTT */
+		64,		/* bMaxPacketSize: 64 bytes */
+		0x0000,		/* idVendor */
+		0x0000,		/* idProduct */
+		cpu_to_le16(0x0100), /* bcdDevice */
+		1,		/* iManufacturer */
+		2,		/* iProduct */
+		0,		/* iSerialNumber */
+		1		/* bNumConfigurations: 1 */
+	},
+	{
+		0x9,
+		2,		/* bDescriptorType: UDESC_CONFIG */
+		cpu_to_le16(0x19),
+		1,		/* bNumInterface */
+		1,		/* bConfigurationValue */
+		0,		/* iConfiguration */
+		0x40,		/* bmAttributes: UC_SELF_POWER */
+		0		/* bMaxPower */
+	},
+	{
+		0x9,		/* bLength */
+		4,		/* bDescriptorType: UDESC_INTERFACE */
+		0,		/* bInterfaceNumber */
+		0,		/* bAlternateSetting */
+		1,		/* bNumEndpoints */
+		9,		/* bInterfaceClass: UICLASS_HUB */
+		0,		/* bInterfaceSubClass: UISUBCLASS_HUB */
+		0,		/* bInterfaceProtocol: UIPROTO_HSHUBSTT */
+		0		/* iInterface */
+	},
+	{
+		0x7,		/* bLength */
+		5,		/* bDescriptorType: UDESC_ENDPOINT */
+		0x81,		/* bEndpointAddress:
+				 * UE_DIR_IN | EHCI_INTR_ENDPT
+				 */
+		3,		/* bmAttributes: UE_INTERRUPT */
+		8,		/* wMaxPacketSize */
+		255		/* bInterval */
+	},
+};
+
+#if defined(CONFIG_EHCI_IS_TDI)
+#define ehci_is_TDI()	(1)
+#else
+#define ehci_is_TDI()	(0)
+#endif
+
+static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
+{
+#if CONFIG_IS_ENABLED(DM_USB)
+	return dev_get_priv(usb_get_bus(udev->dev));
+#else
+	return udev->controller;
+#endif
+}
+
+static int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+{
+	return PORTSC_PSPD(reg);
+}
+
+static void ehci_set_usbmode(struct ehci_ctrl *ctrl)
+{
+	uint32_t tmp;
+	uint32_t *reg_ptr;
+
+	reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd + USBMODE);
+	tmp = ehci_readl(reg_ptr);
+	tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+	tmp |= USBMODE_BE;
+#else
+	tmp &= ~USBMODE_BE;
+#endif
+	ehci_writel(reg_ptr, tmp);
+}
+
+static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			       uint32_t *reg)
+{
+	mdelay(50);
+}
+
+static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+{
+	int max_ports = HCS_N_PORTS(ehci_readl(&ctrl->hccr->cr_hcsparams));
+
+	if (port < 0 || port >= max_ports) {
+		/* Printing the message would cause a scan failure! */
+		debug("The request port(%u) exceeds maximum port number\n",
+		      port);
+		return NULL;
+	}
+
+	return (uint32_t *)&ctrl->hcor->or_portsc[port];
+}
+
+static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
+{
+	uint32_t result;
+	do {
+		result = ehci_readl(ptr);
+		udelay(5);
+		if (result == ~(uint32_t)0)
+			return -1;
+		result &= mask;
+		if (result == done)
+			return 0;
+		usec--;
+	} while (usec > 0);
+	return -1;
+}
+
+static int ehci_reset(struct ehci_ctrl *ctrl)
+{
+	uint32_t cmd;
+	int ret = 0;
+
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	cmd = (cmd & ~CMD_RUN) | CMD_RESET;
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+	ret = handshake((uint32_t *)&ctrl->hcor->or_usbcmd,
+			CMD_RESET, 0, 250 * 1000);
+	if (ret < 0) {
+		printf("EHCI fail to reset\n");
+		goto out;
+	}
+
+	if (ehci_is_TDI())
+		ctrl->ops.set_usb_mode(ctrl);
+
+#ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
+	cmd = ehci_readl(&ctrl->hcor->or_txfilltuning);
+	cmd &= ~TXFIFO_THRESH_MASK;
+	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
+	ehci_writel(&ctrl->hcor->or_txfilltuning, cmd);
+#endif
+out:
+	return ret;
+}
+
+static int ehci_shutdown(struct ehci_ctrl *ctrl)
+{
+	int i, ret = 0;
+	uint32_t cmd, reg;
+	int max_ports = HCS_N_PORTS(ehci_readl(&ctrl->hccr->cr_hcsparams));
+
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	/* If not run, directly return */
+	if (!(cmd & CMD_RUN))
+		return 0;
+	cmd &= ~(CMD_PSE | CMD_ASE);
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+	ret = handshake(&ctrl->hcor->or_usbsts, STS_ASS | STS_PSS, 0,
+		100 * 1000);
+
+	if (!ret) {
+		for (i = 0; i < max_ports; i++) {
+			reg = ehci_readl(&ctrl->hcor->or_portsc[i]);
+			reg |= EHCI_PS_SUSP;
+			ehci_writel(&ctrl->hcor->or_portsc[i], reg);
+		}
+
+		cmd &= ~CMD_RUN;
+		ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+		ret = handshake(&ctrl->hcor->or_usbsts, STS_HALT, STS_HALT,
+			HCHALT_TIMEOUT);
+	}
+
+	if (ret)
+		puts("EHCI failed to shut down host controller.\n");
+
+	return ret;
+}
+
+static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
+{
+	uint32_t delta, next;
+	unsigned long addr = (unsigned long)buf;
+	int idx;
+
+	if (addr != ALIGN(addr, ARCH_DMA_MINALIGN))
+		debug("EHCI-HCD: Misaligned buffer address (%p)\n", buf);
+
+	flush_dcache_range(addr, ALIGN(addr + sz, ARCH_DMA_MINALIGN));
+
+	idx = 0;
+	while (idx < QT_BUFFER_CNT) {
+		td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr));
+		td->qt_buffer_hi[idx] = 0;
+		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);
+		delta = next - addr;
+		if (delta >= sz)
+			break;
+		sz -= delta;
+		addr = next;
+		idx++;
+	}
+
+	if (idx == QT_BUFFER_CNT) {
+		printf("out of buffer pointers (%zu bytes left)\n", sz);
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline u8 ehci_encode_speed(enum usb_device_speed speed)
+{
+	#define QH_HIGH_SPEED	2
+	#define QH_FULL_SPEED	0
+	#define QH_LOW_SPEED	1
+	if (speed == USB_SPEED_HIGH)
+		return QH_HIGH_SPEED;
+	if (speed == USB_SPEED_LOW)
+		return QH_LOW_SPEED;
+	return QH_FULL_SPEED;
+}
+
+static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
+					  struct QH *qh)
+{
+	uint8_t portnr = 0;
+	uint8_t hubaddr = 0;
+
+	if (udev->speed != USB_SPEED_LOW && udev->speed != USB_SPEED_FULL)
+		return;
+
+	usb_find_usb2_hub_address_port(udev, &hubaddr, &portnr);
+
+	qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(portnr) |
+				     QH_ENDPT2_HUBADDR(hubaddr));
+}
+
+static int ehci_enable_async(struct ehci_ctrl *ctrl)
+{
+	u32 cmd;
+	int ret;
+
+	/* Enable async. schedule. */
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	if (cmd & CMD_ASE)
+		return 0;
+
+	cmd |= CMD_ASE;
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+
+	ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS,
+			100 * 1000);
+	if (ret < 0)
+		printf("EHCI fail timeout STS_ASS set\n");
+
+	return ret;
+}
+
+static int ehci_disable_async(struct ehci_ctrl *ctrl)
+{
+	u32 cmd;
+	int ret;
+
+	if (ctrl->async_locked)
+		return 0;
+
+	/* Disable async schedule. */
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	if (!(cmd & CMD_ASE))
+		return 0;
+
+	cmd &= ~CMD_ASE;
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+
+	ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, 0,
+			100 * 1000);
+	if (ret < 0)
+		printf("EHCI fail timeout STS_ASS reset\n");
+
+	return ret;
+}
+
+static int ehci_iaa_cycle(struct ehci_ctrl *ctrl)
+{
+	u32 cmd, status;
+	int ret;
+
+	/* Enable Interrupt on Async Advance Doorbell. */
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	cmd |= CMD_IAAD;
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+
+	ret = handshake(&ctrl->hcor->or_usbsts, STS_IAA, STS_IAA,
+			10 * 1000); /* 10ms timeout */
+	if (ret < 0)
+		printf("EHCI fail timeout STS_IAA set\n");
+
+	status = ehci_readl(&ctrl->hcor->or_usbsts);
+	if (status & STS_IAA)
+		ehci_writel(&ctrl->hcor->or_usbsts, STS_IAA);
+
+	return ret;
+}
+
+static int
+ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int length, struct devrequest *req)
+{
+	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
+	struct qTD *qtd;
+	int qtd_count = 0;
+	int qtd_counter = 0;
+	volatile struct qTD *vtd;
+	unsigned long ts;
+	uint32_t *tdp;
+	uint32_t endpt, maxpacket, token, usbsts, qhtoken;
+	uint32_t c, toggle;
+	int timeout;
+	int ret = 0;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+
+	debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
+	      buffer, length, req);
+	if (req != NULL)
+		debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
+		      req->request, req->request,
+		      req->requesttype, req->requesttype,
+		      le16_to_cpu(req->value), le16_to_cpu(req->value),
+		      le16_to_cpu(req->index));
+
+#define PKT_ALIGN	512
+	/*
+	 * The USB transfer is split into qTD transfers. Eeach qTD transfer is
+	 * described by a transfer descriptor (the qTD). The qTDs form a linked
+	 * list with a queue head (QH).
+	 *
+	 * Each qTD transfer starts with a new USB packet, i.e. a packet cannot
+	 * have its beginning in a qTD transfer and its end in the following
+	 * one, so the qTD transfer lengths have to be chosen accordingly.
+	 *
+	 * Each qTD transfer uses up to QT_BUFFER_CNT data buffers, mapped to
+	 * single pages. The first data buffer can start at any offset within a
+	 * page (not considering the cache-line alignment issues), while the
+	 * following buffers must be page-aligned. There is no alignment
+	 * constraint on the size of a qTD transfer.
+	 */
+	if (req != NULL)
+		/* 1 qTD will be needed for SETUP, and 1 for ACK. */
+		qtd_count += 1 + 1;
+	if (length > 0 || req == NULL) {
+		/*
+		 * Determine the qTD transfer size that will be used for the
+		 * data payload (not considering the first qTD transfer, which
+		 * may be longer or shorter, and the final one, which may be
+		 * shorter).
+		 *
+		 * In order to keep each packet within a qTD transfer, the qTD
+		 * transfer size is aligned to PKT_ALIGN, which is a multiple of
+		 * wMaxPacketSize (except in some cases for interrupt transfers,
+		 * see comment in submit_int_msg()).
+		 *
+		 * By default, i.e. if the input buffer is aligned to PKT_ALIGN,
+		 * QT_BUFFER_CNT full pages will be used.
+		 */
+		int xfr_sz = QT_BUFFER_CNT;
+		/*
+		 * However, if the input buffer is not aligned to PKT_ALIGN, the
+		 * qTD transfer size will be one page shorter, and the first qTD
+		 * data buffer of each transfer will be page-unaligned.
+		 */
+		if ((unsigned long)buffer & (PKT_ALIGN - 1))
+			xfr_sz--;
+		/* Convert the qTD transfer size to bytes. */
+		xfr_sz *= EHCI_PAGE_SIZE;
+		/*
+		 * Approximate by excess the number of qTDs that will be
+		 * required for the data payload. The exact formula is way more
+		 * complicated and saves at most 2 qTDs, i.e. a total of 128
+		 * bytes.
+		 */
+		qtd_count += 2 + length / xfr_sz;
+	}
+/*
+ * Threshold value based on the worst-case total size of the allocated qTDs for
+ * a mass-storage transfer of 65535 blocks of 512 bytes.
+ */
+#if CONFIG_SYS_MALLOC_LEN <= 64 + 128 * 1024
+#warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI
+#endif
+	qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD));
+	if (qtd == NULL) {
+		printf("unable to allocate TDs\n");
+		return -1;
+	}
+
+	memset(qh, 0, sizeof(struct QH));
+	memset(qtd, 0, qtd_count * sizeof(*qtd));
+
+	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+	/*
+	 * Setup QH (3.6 in ehci-r10.pdf)
+	 *
+	 *   qh_link ................. 03-00 H
+	 *   qh_endpt1 ............... 07-04 H
+	 *   qh_endpt2 ............... 0B-08 H
+	 * - qh_curtd
+	 *   qh_overlay.qt_next ...... 13-10 H
+	 * - qh_overlay.qt_altnext
+	 */
+	qh->qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH);
+	c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe);
+	maxpacket = usb_maxpacket(dev, pipe);
+	endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) |
+		QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) |
+		QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) |
+		QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) |
+		QH_ENDPT1_DEVADDR(usb_pipedevice(pipe));
+
+	/* Force FS for fsl HS quirk */
+	if (!ctrl->has_fsl_erratum_a005275)
+		endpt |= QH_ENDPT1_EPS(ehci_encode_speed(dev->speed));
+	else
+		endpt |= QH_ENDPT1_EPS(ehci_encode_speed(QH_FULL_SPEED));
+
+	qh->qh_endpt1 = cpu_to_hc32(endpt);
+	endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0);
+	qh->qh_endpt2 = cpu_to_hc32(endpt);
+	ehci_update_endpt2_dev_n_port(dev, qh);
+	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+	qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+
+	tdp = &qh->qh_overlay.qt_next;
+	if (req != NULL) {
+		/*
+		 * Setup request qTD (3.5 in ehci-r10.pdf)
+		 *
+		 *   qt_next ................ 03-00 H
+		 *   qt_altnext ............. 07-04 H
+		 *   qt_token ............... 0B-08 H
+		 *
+		 *   [ buffer, buffer_hi ] loaded with "req".
+		 */
+		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		token = QT_TOKEN_DT(0) | QT_TOKEN_TOTALBYTES(sizeof(*req)) |
+			QT_TOKEN_IOC(0) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |
+			QT_TOKEN_PID(QT_TOKEN_PID_SETUP) |
+			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
+		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
+		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req))) {
+			printf("unable to construct SETUP TD\n");
+			goto fail;
+		}
+		/* Update previous qTD! */
+		*tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
+		tdp = &qtd[qtd_counter++].qt_next;
+		toggle = 1;
+	}
+
+	if (length > 0 || req == NULL) {
+		uint8_t *buf_ptr = buffer;
+		int left_length = length;
+
+		do {
+			/*
+			 * Determine the size of this qTD transfer. By default,
+			 * QT_BUFFER_CNT full pages can be used.
+			 */
+			int xfr_bytes = QT_BUFFER_CNT * EHCI_PAGE_SIZE;
+			/*
+			 * However, if the input buffer is not page-aligned, the
+			 * portion of the first page before the buffer start
+			 * offset within that page is unusable.
+			 */
+			xfr_bytes -= (unsigned long)buf_ptr & (EHCI_PAGE_SIZE - 1);
+			/*
+			 * In order to keep each packet within a qTD transfer,
+			 * align the qTD transfer size to PKT_ALIGN.
+			 */
+			xfr_bytes &= ~(PKT_ALIGN - 1);
+			/*
+			 * This transfer may be shorter than the available qTD
+			 * transfer size that has just been computed.
+			 */
+			xfr_bytes = min(xfr_bytes, left_length);
+
+			/*
+			 * Setup request qTD (3.5 in ehci-r10.pdf)
+			 *
+			 *   qt_next ................ 03-00 H
+			 *   qt_altnext ............. 07-04 H
+			 *   qt_token ............... 0B-08 H
+			 *
+			 *   [ buffer, buffer_hi ] loaded with "buffer".
+			 */
+			qtd[qtd_counter].qt_next =
+					cpu_to_hc32(QT_NEXT_TERMINATE);
+			qtd[qtd_counter].qt_altnext =
+					cpu_to_hc32(QT_NEXT_TERMINATE);
+			token = QT_TOKEN_DT(toggle) |
+				QT_TOKEN_TOTALBYTES(xfr_bytes) |
+				QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) |
+				QT_TOKEN_CERR(3) |
+				QT_TOKEN_PID(usb_pipein(pipe) ?
+					QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) |
+				QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
+			qtd[qtd_counter].qt_token = cpu_to_hc32(token);
+			if (ehci_td_buffer(&qtd[qtd_counter], buf_ptr,
+						xfr_bytes)) {
+				printf("unable to construct DATA TD\n");
+				goto fail;
+			}
+			/* Update previous qTD! */
+			*tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
+			tdp = &qtd[qtd_counter++].qt_next;
+			/*
+			 * Data toggle has to be adjusted since the qTD transfer
+			 * size is not always an even multiple of
+			 * wMaxPacketSize.
+			 */
+			if ((xfr_bytes / maxpacket) & 1)
+				toggle ^= 1;
+			buf_ptr += xfr_bytes;
+			left_length -= xfr_bytes;
+		} while (left_length > 0);
+	}
+
+	if (req != NULL) {
+		/*
+		 * Setup request qTD (3.5 in ehci-r10.pdf)
+		 *
+		 *   qt_next ................ 03-00 H
+		 *   qt_altnext ............. 07-04 H
+		 *   qt_token ............... 0B-08 H
+		 */
+		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		token = QT_TOKEN_DT(1) | QT_TOKEN_TOTALBYTES(0) |
+			QT_TOKEN_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |
+			QT_TOKEN_PID(usb_pipein(pipe) ?
+				QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) |
+			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
+		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
+		/* Update previous qTD! */
+		*tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter]));
+		tdp = &qtd[qtd_counter++].qt_next;
+	}
+
+	ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(qh) | QH_LINK_TYPE_QH);
+
+	/* Flush dcache */
+	flush_dcache_range((unsigned long)&ctrl->qh_list,
+		ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
+	flush_dcache_range((unsigned long)qh, ALIGN_END_ADDR(struct QH, qh, 1));
+	flush_dcache_range((unsigned long)qtd,
+			   ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
+
+	usbsts = ehci_readl(&ctrl->hcor->or_usbsts);
+	ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f));
+
+	ret = ehci_enable_async(ctrl);
+	if (ret)
+		goto fail;
+
+	/* Wait for TDs to be processed. */
+	ts = get_timer(0);
+	vtd = &qtd[qtd_counter - 1];
+	timeout = USB_TIMEOUT_MS(pipe);
+	do {
+		/* Invalidate dcache */
+		invalidate_dcache_range((unsigned long)&ctrl->qh_list,
+			ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
+		invalidate_dcache_range((unsigned long)qh,
+			ALIGN_END_ADDR(struct QH, qh, 1));
+		invalidate_dcache_range((unsigned long)qtd,
+			ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
+
+		token = hc32_to_cpu(vtd->qt_token);
+		if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE))
+			break;
+		WATCHDOG_RESET();
+	} while (get_timer(ts) < timeout);
+	qhtoken = hc32_to_cpu(qh->qh_overlay.qt_token);
+
+	ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH);
+	flush_dcache_range((unsigned long)&ctrl->qh_list,
+		ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
+
+	/* Set IAAD, poll IAA */
+	ret = ehci_iaa_cycle(ctrl);
+	if (ret)
+		goto fail;
+
+	/*
+	 * Invalidate the memory area occupied by buffer
+	 * Don't try to fix the buffer alignment, if it isn't properly
+	 * aligned it's upper layer's fault so let invalidate_dcache_range()
+	 * vow about it. But we have to fix the length as it's actual
+	 * transfer length and can be unaligned. This is potentially
+	 * dangerous operation, it's responsibility of the calling
+	 * code to make sure enough space is reserved.
+	 */
+	if (buffer != NULL && length > 0)
+		invalidate_dcache_range((unsigned long)buffer,
+			ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));
+
+	/* Check that the TD processing happened */
+	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
+		printf("EHCI timed out on TD - token=%#x\n", token);
+
+	ret = ehci_disable_async(ctrl);
+	if (ret)
+		goto fail;
+
+	if (!(QT_TOKEN_GET_STATUS(qhtoken) & QT_TOKEN_STATUS_ACTIVE)) {
+		debug("TOKEN=%#x\n", qhtoken);
+		switch (QT_TOKEN_GET_STATUS(qhtoken) &
+			~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) {
+		case 0:
+			toggle = QT_TOKEN_GET_DT(qhtoken);
+			usb_settoggle(dev, usb_pipeendpoint(pipe),
+				       usb_pipeout(pipe), toggle);
+			dev->status = 0;
+			break;
+		case QT_TOKEN_STATUS_HALTED:
+			dev->status = USB_ST_STALLED;
+			break;
+		case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR:
+		case QT_TOKEN_STATUS_DATBUFERR:
+			dev->status = USB_ST_BUF_ERR;
+			break;
+		case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET:
+		case QT_TOKEN_STATUS_BABBLEDET:
+			dev->status = USB_ST_BABBLE_DET;
+			break;
+		default:
+			dev->status = USB_ST_CRC_ERR;
+			if (QT_TOKEN_GET_STATUS(qhtoken) & QT_TOKEN_STATUS_HALTED)
+				dev->status |= USB_ST_STALLED;
+			break;
+		}
+		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(qhtoken);
+	} else {
+		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
+		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
+		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
+		      ehci_readl(&ctrl->hcor->or_portsc[0]),
+		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
+	}
+
+	free(qtd);
+	return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
+
+fail:
+	free(qtd);
+	return -1;
+}
+
+static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length, struct devrequest *req)
+{
+	uint8_t tmpbuf[4];
+	u16 typeReq;
+	void *srcptr = NULL;
+	int len, srclen;
+	uint32_t reg;
+	uint32_t *status_reg;
+	int port = le16_to_cpu(req->index) & 0xff;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+
+	srclen = 0;
+
+	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
+	      req->request, req->request,
+	      req->requesttype, req->requesttype,
+	      le16_to_cpu(req->value), le16_to_cpu(req->index));
+
+	typeReq = req->request | req->requesttype << 8;
+
+	switch (typeReq) {
+	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+		status_reg = ctrl->ops.get_portsc_register(ctrl, port - 1);
+		if (!status_reg)
+			return -1;
+		break;
+	default:
+		status_reg = NULL;
+		break;
+	}
+
+	switch (typeReq) {
+	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+		switch (le16_to_cpu(req->value) >> 8) {
+		case USB_DT_DEVICE:
+			debug("USB_DT_DEVICE request\n");
+			srcptr = &descriptor.device;
+			srclen = descriptor.device.bLength;
+			break;
+		case USB_DT_CONFIG:
+			debug("USB_DT_CONFIG config\n");
+			srcptr = &descriptor.config;
+			srclen = descriptor.config.bLength +
+					descriptor.interface.bLength +
+					descriptor.endpoint.bLength;
+			break;
+		case USB_DT_STRING:
+			debug("USB_DT_STRING config\n");
+			switch (le16_to_cpu(req->value) & 0xff) {
+			case 0:	/* Language */
+				srcptr = "\4\3\1\0";
+				srclen = 4;
+				break;
+			case 1:	/* Vendor */
+				srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
+				srclen = 14;
+				break;
+			case 2:	/* Product */
+				srcptr = "\52\3E\0H\0C\0I\0 "
+					 "\0H\0o\0s\0t\0 "
+					 "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
+				srclen = 42;
+				break;
+			default:
+				debug("unknown value DT_STRING %x\n",
+					le16_to_cpu(req->value));
+				goto unknown;
+			}
+			break;
+		default:
+			debug("unknown value %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		break;
+	case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
+		switch (le16_to_cpu(req->value) >> 8) {
+		case USB_DT_HUB:
+			debug("USB_DT_HUB config\n");
+			srcptr = &descriptor.hub;
+			srclen = descriptor.hub.bLength;
+			break;
+		default:
+			debug("unknown value %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		break;
+	case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
+		debug("USB_REQ_SET_ADDRESS\n");
+		ctrl->rootdev = le16_to_cpu(req->value);
+		break;
+	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+		debug("USB_REQ_SET_CONFIGURATION\n");
+		/* Nothing to do */
+		break;
+	case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
+		tmpbuf[0] = 1;	/* USB_STATUS_SELFPOWERED */
+		tmpbuf[1] = 0;
+		srcptr = tmpbuf;
+		srclen = 2;
+		break;
+	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+		memset(tmpbuf, 0, 4);
+		reg = ehci_readl(status_reg);
+		if (reg & EHCI_PS_CS)
+			tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
+		if (reg & EHCI_PS_PE)
+			tmpbuf[0] |= USB_PORT_STAT_ENABLE;
+		if (reg & EHCI_PS_SUSP)
+			tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
+		if (reg & EHCI_PS_OCA)
+			tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
+		if (reg & EHCI_PS_PR)
+			tmpbuf[0] |= USB_PORT_STAT_RESET;
+		if (reg & EHCI_PS_PP)
+			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
+
+		if (ehci_is_TDI()) {
+			switch (ctrl->ops.get_port_speed(ctrl, reg)) {
+			case PORTSC_PSPD_FS:
+				break;
+			case PORTSC_PSPD_LS:
+				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
+				break;
+			case PORTSC_PSPD_HS:
+			default:
+				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+				break;
+			}
+		} else {
+			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+		}
+
+		if (reg & EHCI_PS_CSC)
+			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
+		if (reg & EHCI_PS_PEC)
+			tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
+		if (reg & EHCI_PS_OCC)
+			tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
+		if (ctrl->portreset & (1 << port))
+			tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+
+		srcptr = tmpbuf;
+		srclen = 4;
+		break;
+	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+		reg = ehci_readl(status_reg);
+		reg &= ~EHCI_PS_CLEAR;
+		switch (le16_to_cpu(req->value)) {
+		case USB_PORT_FEAT_ENABLE:
+			reg |= EHCI_PS_PE;
+			ehci_writel(status_reg, reg);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) {
+				reg |= EHCI_PS_PP;
+				ehci_writel(status_reg, reg);
+			}
+			break;
+		case USB_PORT_FEAT_RESET:
+			if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
+			    !ehci_is_TDI() &&
+			    EHCI_PS_IS_LOWSPEED(reg)) {
+				/* Low speed device, give up ownership. */
+				debug("port %d low speed --> companion\n",
+				      port - 1);
+				reg |= EHCI_PS_PO;
+				ehci_writel(status_reg, reg);
+				return -ENXIO;
+			} else {
+				int ret;
+
+				/* Disable chirp for HS erratum */
+				if (ctrl->has_fsl_erratum_a005275)
+					reg |= PORTSC_FSL_PFSC;
+
+				reg |= EHCI_PS_PR;
+				reg &= ~EHCI_PS_PE;
+				ehci_writel(status_reg, reg);
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 specification say 50 ms resets on
+				 * root
+				 */
+				ctrl->ops.powerup_fixup(ctrl, status_reg, &reg);
+
+				ehci_writel(status_reg, reg & ~EHCI_PS_PR);
+				/*
+				 * A host controller must terminate the reset
+				 * and stabilize the state of the port within
+				 * 2 milliseconds
+				 */
+				ret = handshake(status_reg, EHCI_PS_PR, 0,
+						2 * 1000);
+				if (!ret) {
+					reg = ehci_readl(status_reg);
+					if ((reg & (EHCI_PS_PE | EHCI_PS_CS))
+					    == EHCI_PS_CS && !ehci_is_TDI()) {
+						debug("port %d full speed --> companion\n", port - 1);
+						reg &= ~EHCI_PS_CLEAR;
+						reg |= EHCI_PS_PO;
+						ehci_writel(status_reg, reg);
+						return -ENXIO;
+					} else {
+						ctrl->portreset |= 1 << port;
+					}
+				} else {
+					printf("port(%d) reset error\n",
+					       port - 1);
+				}
+			}
+			break;
+		case USB_PORT_FEAT_TEST:
+			ehci_shutdown(ctrl);
+			reg &= ~(0xf << 16);
+			reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16;
+			ehci_writel(status_reg, reg);
+			break;
+		default:
+			debug("unknown feature %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		/* unblock posted writes */
+		(void) ehci_readl(&ctrl->hcor->or_usbcmd);
+		break;
+	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+		reg = ehci_readl(status_reg);
+		reg &= ~EHCI_PS_CLEAR;
+		switch (le16_to_cpu(req->value)) {
+		case USB_PORT_FEAT_ENABLE:
+			reg &= ~EHCI_PS_PE;
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			reg |= EHCI_PS_PE;
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams)))
+				reg &= ~EHCI_PS_PP;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			reg |= EHCI_PS_CSC;
+			break;
+		case USB_PORT_FEAT_OVER_CURRENT:
+			reg |= EHCI_PS_OCC;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			ctrl->portreset &= ~(1 << port);
+			break;
+		default:
+			debug("unknown feature %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		ehci_writel(status_reg, reg);
+		/* unblock posted write */
+		(void) ehci_readl(&ctrl->hcor->or_usbcmd);
+		break;
+	default:
+		debug("Unknown request\n");
+		goto unknown;
+	}
+
+	mdelay(1);
+	len = min3(srclen, (int)le16_to_cpu(req->length), length);
+	if (srcptr != NULL && len > 0)
+		memcpy(buffer, srcptr, len);
+	else
+		debug("Len is 0\n");
+
+	dev->act_len = len;
+	dev->status = 0;
+	return 0;
+
+unknown:
+	debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n",
+	      req->requesttype, req->request, le16_to_cpu(req->value),
+	      le16_to_cpu(req->index), le16_to_cpu(req->length));
+
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+	return -1;
+}
+
+static const struct ehci_ops default_ehci_ops = {
+	.set_usb_mode		= ehci_set_usbmode,
+	.get_port_speed		= ehci_get_port_speed,
+	.powerup_fixup		= ehci_powerup_fixup,
+	.get_portsc_register	= ehci_get_portsc_register,
+};
+
+static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops)
+{
+	if (!ops) {
+		ctrl->ops = default_ehci_ops;
+	} else {
+		ctrl->ops = *ops;
+		if (!ctrl->ops.set_usb_mode)
+			ctrl->ops.set_usb_mode = ehci_set_usbmode;
+		if (!ctrl->ops.get_port_speed)
+			ctrl->ops.get_port_speed = ehci_get_port_speed;
+		if (!ctrl->ops.powerup_fixup)
+			ctrl->ops.powerup_fixup = ehci_powerup_fixup;
+		if (!ctrl->ops.get_portsc_register)
+			ctrl->ops.get_portsc_register =
+					ehci_get_portsc_register;
+	}
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops)
+{
+	struct ehci_ctrl *ctrl = &ehcic[index];
+
+	ctrl->priv = priv;
+	ehci_setup_ops(ctrl, ops);
+}
+
+void *ehci_get_controller_priv(int index)
+{
+	return ehcic[index].priv;
+}
+#endif
+
+static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
+{
+	struct QH *qh_list;
+	struct QH *periodic;
+	uint32_t reg;
+	uint32_t cmd;
+	int i;
+
+	/* Set the high address word (aka segment) for 64-bit controller */
+	if (ehci_readl(&ctrl->hccr->cr_hccparams) & 1)
+		ehci_writel(&ctrl->hcor->or_ctrldssegment, 0);
+
+	qh_list = &ctrl->qh_list;
+
+	/* Set head of reclaim list */
+	memset(qh_list, 0, sizeof(*qh_list));
+	qh_list->qh_link = cpu_to_hc32(virt_to_phys(qh_list) | QH_LINK_TYPE_QH);
+	qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) |
+						QH_ENDPT1_EPS(USB_SPEED_HIGH));
+	qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+	qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+	qh_list->qh_overlay.qt_token =
+			cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
+
+	flush_dcache_range((unsigned long)qh_list,
+			   ALIGN_END_ADDR(struct QH, qh_list, 1));
+
+	/* Set async. queue head pointer. */
+	ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(qh_list));
+
+	/*
+	 * Set up periodic list
+	 * Step 1: Parent QH for all periodic transfers.
+	 */
+	ctrl->periodic_schedules = 0;
+	periodic = &ctrl->periodic_queue;
+	memset(periodic, 0, sizeof(*periodic));
+	periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
+	periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+	periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+
+	flush_dcache_range((unsigned long)periodic,
+			   ALIGN_END_ADDR(struct QH, periodic, 1));
+
+	/*
+	 * Step 2: Setup frame-list: Every microframe, USB tries the same list.
+	 *         In particular, device specifications on polling frequency
+	 *         are disregarded. Keyboards seem to send NAK/NYet reliably
+	 *         when polled with an empty buffer.
+	 *
+	 *         Split Transactions will be spread across microframes using
+	 *         S-mask and C-mask.
+	 */
+	if (ctrl->periodic_list == NULL)
+		ctrl->periodic_list = memalign(4096, 1024 * 4);
+
+	if (!ctrl->periodic_list)
+		return -ENOMEM;
+	for (i = 0; i < 1024; i++) {
+		ctrl->periodic_list[i] = cpu_to_hc32((unsigned long)periodic
+						| QH_LINK_TYPE_QH);
+	}
+
+	flush_dcache_range((unsigned long)ctrl->periodic_list,
+			   ALIGN_END_ADDR(uint32_t, ctrl->periodic_list,
+					  1024));
+
+	/* Set periodic list base address */
+	ehci_writel(&ctrl->hcor->or_periodiclistbase,
+		(unsigned long)ctrl->periodic_list);
+
+	reg = ehci_readl(&ctrl->hccr->cr_hcsparams);
+	descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
+	debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
+	/* Port Indicators */
+	if (HCS_INDICATOR(reg))
+		put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
+				| 0x80, &descriptor.hub.wHubCharacteristics);
+	/* Port Power Control */
+	if (HCS_PPC(reg))
+		put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
+				| 0x01, &descriptor.hub.wHubCharacteristics);
+
+	/* Start the host controller. */
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	/*
+	 * Philips, Intel, and maybe others need CMD_RUN before the
+	 * root hub will detect new devices (why?); NEC doesn't
+	 */
+	cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+	cmd |= CMD_RUN;
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+
+	if (!(tweaks & EHCI_TWEAK_NO_INIT_CF)) {
+		/* take control over the ports */
+		cmd = ehci_readl(&ctrl->hcor->or_configflag);
+		cmd |= FLAG_CF;
+		ehci_writel(&ctrl->hcor->or_configflag, cmd);
+	}
+
+	/* unblock posted write */
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+	mdelay(5);
+	reg = HC_VERSION(ehci_readl(&ctrl->hccr->cr_capbase));
+	printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int usb_lowlevel_stop(int index)
+{
+	ehci_shutdown(&ehcic[index]);
+	return ehci_hcd_stop(index);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	struct ehci_ctrl *ctrl = &ehcic[index];
+	uint tweaks = 0;
+	int rc;
+
+	/**
+	 * Set ops to default_ehci_ops, ehci_hcd_init should call
+	 * ehci_set_controller_priv to change any of these function pointers.
+	 */
+	ctrl->ops = default_ehci_ops;
+
+	rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
+	if (rc)
+		return rc;
+	if (!ctrl->hccr || !ctrl->hcor)
+		return -1;
+	if (init == USB_INIT_DEVICE)
+		goto done;
+
+	/* EHCI spec section 4.1 */
+	if (ehci_reset(ctrl))
+		return -1;
+
+#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
+	rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
+	if (rc)
+		return rc;
+#endif
+#ifdef CONFIG_USB_EHCI_FARADAY
+	tweaks |= EHCI_TWEAK_NO_INIT_CF;
+#endif
+	rc = ehci_common_init(ctrl, tweaks);
+	if (rc)
+		return rc;
+
+	ctrl->rootdev = 0;
+done:
+	*controller = &ehcic[index];
+	return 0;
+}
+#endif
+
+static int _ehci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+				 void *buffer, int length)
+{
+
+	if (usb_pipetype(pipe) != PIPE_BULK) {
+		debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
+		return -1;
+	}
+	return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
+				    void *buffer, int length,
+				    struct devrequest *setup)
+{
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+
+	if (usb_pipetype(pipe) != PIPE_CONTROL) {
+		debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
+		return -1;
+	}
+
+	if (usb_pipedevice(pipe) == ctrl->rootdev) {
+		if (!ctrl->rootdev)
+			dev->speed = USB_SPEED_HIGH;
+		return ehci_submit_root(dev, pipe, buffer, length, setup);
+	}
+	return ehci_submit_async(dev, pipe, buffer, length, setup);
+}
+
+struct int_queue {
+	int elementsize;
+	unsigned long pipe;
+	struct QH *first;
+	struct QH *current;
+	struct QH *last;
+	struct qTD *tds;
+};
+
+#define NEXT_QH(qh) (struct QH *)((unsigned long)hc32_to_cpu((qh)->qh_link) & ~0x1f)
+
+static int
+enable_periodic(struct ehci_ctrl *ctrl)
+{
+	uint32_t cmd;
+	struct ehci_hcor *hcor = ctrl->hcor;
+	int ret;
+
+	cmd = ehci_readl(&hcor->or_usbcmd);
+	cmd |= CMD_PSE;
+	ehci_writel(&hcor->or_usbcmd, cmd);
+
+	ret = handshake((uint32_t *)&hcor->or_usbsts,
+			STS_PSS, STS_PSS, 100 * 1000);
+	if (ret < 0) {
+		printf("EHCI failed: timeout when enabling periodic list\n");
+		return -ETIMEDOUT;
+	}
+	udelay(1000);
+	return 0;
+}
+
+static int
+disable_periodic(struct ehci_ctrl *ctrl)
+{
+	uint32_t cmd;
+	struct ehci_hcor *hcor = ctrl->hcor;
+	int ret;
+
+	cmd = ehci_readl(&hcor->or_usbcmd);
+	cmd &= ~CMD_PSE;
+	ehci_writel(&hcor->or_usbcmd, cmd);
+
+	ret = handshake((uint32_t *)&hcor->or_usbsts,
+			STS_PSS, 0, 100 * 1000);
+	if (ret < 0) {
+		printf("EHCI failed: timeout when disabling periodic list\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
+			unsigned long pipe, int queuesize, int elementsize,
+			void *buffer, int interval)
+{
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+	struct int_queue *result = NULL;
+	uint32_t i, toggle;
+
+	/*
+	 * Interrupt transfers requiring several transactions are not supported
+	 * because bInterval is ignored.
+	 *
+	 * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2
+	 * <= PKT_ALIGN if several qTDs are required, while the USB
+	 * specification does not constrain this for interrupt transfers. That
+	 * means that ehci_submit_async() would support interrupt transfers
+	 * requiring several transactions only as long as the transfer size does
+	 * not require more than a single qTD.
+	 */
+	if (elementsize > usb_maxpacket(dev, pipe)) {
+		printf("%s: xfers requiring several transactions are not supported.\n",
+		       __func__);
+		return NULL;
+	}
+
+	debug("Enter create_int_queue\n");
+	if (usb_pipetype(pipe) != PIPE_INTERRUPT) {
+		debug("non-interrupt pipe (type=%lu)", usb_pipetype(pipe));
+		return NULL;
+	}
+
+	/* limit to 4 full pages worth of data -
+	 * we can safely fit them in a single TD,
+	 * no matter the alignment
+	 */
+	if (elementsize >= 16384) {
+		debug("too large elements for interrupt transfers\n");
+		return NULL;
+	}
+
+	result = malloc(sizeof(*result));
+	if (!result) {
+		debug("ehci intr queue: out of memory\n");
+		goto fail1;
+	}
+	result->elementsize = elementsize;
+	result->pipe = pipe;
+	result->first = memalign(USB_DMA_MINALIGN,
+				 sizeof(struct QH) * queuesize);
+	if (!result->first) {
+		debug("ehci intr queue: out of memory\n");
+		goto fail2;
+	}
+	result->current = result->first;
+	result->last = result->first + queuesize - 1;
+	result->tds = memalign(USB_DMA_MINALIGN,
+			       sizeof(struct qTD) * queuesize);
+	if (!result->tds) {
+		debug("ehci intr queue: out of memory\n");
+		goto fail3;
+	}
+	memset(result->first, 0, sizeof(struct QH) * queuesize);
+	memset(result->tds, 0, sizeof(struct qTD) * queuesize);
+
+	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+	for (i = 0; i < queuesize; i++) {
+		struct QH *qh = result->first + i;
+		struct qTD *td = result->tds + i;
+		void **buf = &qh->buffer;
+
+		qh->qh_link = cpu_to_hc32((unsigned long)(qh+1) | QH_LINK_TYPE_QH);
+		if (i == queuesize - 1)
+			qh->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
+
+		qh->qh_overlay.qt_next = cpu_to_hc32((unsigned long)td);
+		qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		qh->qh_endpt1 =
+			cpu_to_hc32((0 << 28) | /* No NAK reload (ehci 4.9) */
+			(usb_maxpacket(dev, pipe) << 16) | /* MPS */
+			(1 << 14) |
+			QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) |
+			(usb_pipeendpoint(pipe) << 8) | /* Endpoint Number */
+			(usb_pipedevice(pipe) << 0));
+		qh->qh_endpt2 = cpu_to_hc32((1 << 30) | /* 1 Tx per mframe */
+			(1 << 0)); /* S-mask: microframe 0 */
+		if (dev->speed == USB_SPEED_LOW ||
+				dev->speed == USB_SPEED_FULL) {
+			/* C-mask: microframes 2-4 */
+			qh->qh_endpt2 |= cpu_to_hc32((0x1c << 8));
+		}
+		ehci_update_endpt2_dev_n_port(dev, qh);
+
+		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+		debug("communication direction is '%s'\n",
+		      usb_pipein(pipe) ? "in" : "out");
+		td->qt_token = cpu_to_hc32(
+			QT_TOKEN_DT(toggle) |
+			(elementsize << 16) |
+			((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
+			0x80); /* active */
+		td->qt_buffer[0] =
+		    cpu_to_hc32((unsigned long)buffer + i * elementsize);
+		td->qt_buffer[1] =
+		    cpu_to_hc32((td->qt_buffer[0] + 0x1000) & ~0xfff);
+		td->qt_buffer[2] =
+		    cpu_to_hc32((td->qt_buffer[0] + 0x2000) & ~0xfff);
+		td->qt_buffer[3] =
+		    cpu_to_hc32((td->qt_buffer[0] + 0x3000) & ~0xfff);
+		td->qt_buffer[4] =
+		    cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff);
+
+		*buf = buffer + i * elementsize;
+		toggle ^= 1;
+	}
+
+	flush_dcache_range((unsigned long)buffer,
+			   ALIGN_END_ADDR(char, buffer,
+					  queuesize * elementsize));
+	flush_dcache_range((unsigned long)result->first,
+			   ALIGN_END_ADDR(struct QH, result->first,
+					  queuesize));
+	flush_dcache_range((unsigned long)result->tds,
+			   ALIGN_END_ADDR(struct qTD, result->tds,
+					  queuesize));
+
+	if (ctrl->periodic_schedules > 0) {
+		if (disable_periodic(ctrl) < 0) {
+			debug("FATAL: periodic should never fail, but did");
+			goto fail3;
+		}
+	}
+
+	/* hook up to periodic list */
+	struct QH *list = &ctrl->periodic_queue;
+	result->last->qh_link = list->qh_link;
+	list->qh_link = cpu_to_hc32((unsigned long)result->first | QH_LINK_TYPE_QH);
+
+	flush_dcache_range((unsigned long)result->last,
+			   ALIGN_END_ADDR(struct QH, result->last, 1));
+	flush_dcache_range((unsigned long)list,
+			   ALIGN_END_ADDR(struct QH, list, 1));
+
+	if (enable_periodic(ctrl) < 0) {
+		debug("FATAL: periodic should never fail, but did");
+		goto fail3;
+	}
+	ctrl->periodic_schedules++;
+
+	debug("Exit create_int_queue\n");
+	return result;
+fail3:
+	free(result->tds);
+fail2:
+	free(result->first);
+	free(result);
+fail1:
+	return NULL;
+}
+
+static void *_ehci_poll_int_queue(struct usb_device *dev,
+				  struct int_queue *queue)
+{
+	struct QH *cur = queue->current;
+	struct qTD *cur_td;
+	uint32_t token, toggle;
+	unsigned long pipe = queue->pipe;
+
+	/* depleted queue */
+	if (cur == NULL) {
+		debug("Exit poll_int_queue with completed queue\n");
+		return NULL;
+	}
+	/* still active */
+	cur_td = &queue->tds[queue->current - queue->first];
+	invalidate_dcache_range((unsigned long)cur_td,
+				ALIGN_END_ADDR(struct qTD, cur_td, 1));
+	token = hc32_to_cpu(cur_td->qt_token);
+	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) {
+		debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token);
+		return NULL;
+	}
+
+	toggle = QT_TOKEN_GET_DT(token);
+	usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle);
+
+	if (!(cur->qh_link & QH_LINK_TERMINATE))
+		queue->current++;
+	else
+		queue->current = NULL;
+
+	invalidate_dcache_range((unsigned long)cur->buffer,
+				ALIGN_END_ADDR(char, cur->buffer,
+					       queue->elementsize));
+
+	debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
+	      token, cur, queue->first);
+	return cur->buffer;
+}
+
+/* Do not free buffers associated with QHs, they're owned by someone else */
+static int _ehci_destroy_int_queue(struct usb_device *dev,
+				   struct int_queue *queue)
+{
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+	int result = -1;
+	unsigned long timeout;
+
+	if (disable_periodic(ctrl) < 0) {
+		debug("FATAL: periodic should never fail, but did");
+		goto out;
+	}
+	ctrl->periodic_schedules--;
+
+	struct QH *cur = &ctrl->periodic_queue;
+	timeout = get_timer(0) + 500; /* abort after 500ms */
+	while (!(cur->qh_link & cpu_to_hc32(QH_LINK_TERMINATE))) {
+		debug("considering %p, with qh_link %x\n", cur, cur->qh_link);
+		if (NEXT_QH(cur) == queue->first) {
+			debug("found candidate. removing from chain\n");
+			cur->qh_link = queue->last->qh_link;
+			flush_dcache_range((unsigned long)cur,
+					   ALIGN_END_ADDR(struct QH, cur, 1));
+			result = 0;
+			break;
+		}
+		cur = NEXT_QH(cur);
+		if (get_timer(0) > timeout) {
+			printf("Timeout destroying interrupt endpoint queue\n");
+			result = -1;
+			goto out;
+		}
+	}
+
+	if (ctrl->periodic_schedules > 0) {
+		result = enable_periodic(ctrl);
+		if (result < 0)
+			debug("FATAL: periodic should never fail, but did");
+	}
+
+out:
+	free(queue->tds);
+	free(queue->first);
+	free(queue);
+
+	return result;
+}
+
+static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+				void *buffer, int length, int interval,
+				bool nonblock)
+{
+	void *backbuffer;
+	struct int_queue *queue;
+	unsigned long timeout;
+	int result = 0, ret;
+
+	debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
+	      dev, pipe, buffer, length, interval);
+
+	queue = _ehci_create_int_queue(dev, pipe, 1, length, buffer, interval);
+	if (!queue)
+		return -1;
+
+	timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
+	while ((backbuffer = _ehci_poll_int_queue(dev, queue)) == NULL)
+		if (get_timer(0) > timeout) {
+			printf("Timeout poll on interrupt endpoint\n");
+			result = -ETIMEDOUT;
+			break;
+		}
+
+	if (backbuffer != buffer) {
+		debug("got wrong buffer back (%p instead of %p)\n",
+		      backbuffer, buffer);
+		return -EINVAL;
+	}
+
+	ret = _ehci_destroy_int_queue(dev, queue);
+	if (ret < 0)
+		return ret;
+
+	/* everything worked out fine */
+	return result;
+}
+
+static int _ehci_lock_async(struct ehci_ctrl *ctrl, int lock)
+{
+	ctrl->async_locked = lock;
+
+	if (lock)
+		return 0;
+
+	return ehci_disable_async(ctrl);
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length)
+{
+	return _ehci_submit_bulk_msg(dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int length, struct devrequest *setup)
+{
+	return _ehci_submit_control_msg(dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+		   void *buffer, int length, int interval, bool nonblock)
+{
+	return _ehci_submit_int_msg(dev, pipe, buffer, length, interval,
+				    nonblock);
+}
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+		unsigned long pipe, int queuesize, int elementsize,
+		void *buffer, int interval)
+{
+	return _ehci_create_int_queue(dev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _ehci_poll_int_queue(dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _ehci_destroy_int_queue(dev, queue);
+}
+
+int usb_lock_async(struct usb_device *dev, int lock)
+{
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+
+	return _ehci_lock_async(ctrl, lock);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ehci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+	      dev->name, udev, udev->dev->name, udev->portnr);
+
+	return _ehci_submit_control_msg(udev, pipe, buffer, length, setup);
+}
+
+static int ehci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+static int ehci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval, bool nonblock)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_submit_int_msg(udev, pipe, buffer, length, interval,
+				    nonblock);
+}
+
+static struct int_queue *ehci_create_int_queue(struct udevice *dev,
+		struct usb_device *udev, unsigned long pipe, int queuesize,
+		int elementsize, void *buffer, int interval)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_create_int_queue(udev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+static void *ehci_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+				 struct int_queue *queue)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_poll_int_queue(udev, queue);
+}
+
+static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+				  struct int_queue *queue)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_destroy_int_queue(udev, queue);
+}
+
+static int ehci_get_max_xfer_size(struct udevice *dev, size_t *size)
+{
+	/*
+	 * EHCD can handle any transfer length as long as there is enough
+	 * free heap space left, hence set the theoretical max number here.
+	 */
+	*size = SIZE_MAX;
+
+	return 0;
+}
+
+static int ehci_lock_async(struct udevice *dev, int lock)
+{
+	struct ehci_ctrl *ctrl = dev_get_priv(dev);
+
+	return _ehci_lock_async(ctrl, lock);
+}
+
+int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
+		  struct ehci_hcor *hcor, const struct ehci_ops *ops,
+		  uint tweaks, enum usb_init_type init)
+{
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	struct ehci_ctrl *ctrl = dev_get_priv(dev);
+	int ret = -1;
+
+	debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__,
+	      dev->name, ctrl, hccr, hcor, init);
+
+	if (!ctrl || !hccr || !hcor)
+		goto err;
+
+	priv->desc_before_addr = true;
+
+	ehci_setup_ops(ctrl, ops);
+	ctrl->hccr = hccr;
+	ctrl->hcor = hcor;
+	ctrl->priv = ctrl;
+
+	ctrl->init = init;
+	if (ctrl->init == USB_INIT_DEVICE)
+		goto done;
+
+	ret = ehci_reset(ctrl);
+	if (ret)
+		goto err;
+
+	if (ctrl->ops.init_after_reset) {
+		ret = ctrl->ops.init_after_reset(ctrl);
+		if (ret)
+			goto err;
+	}
+
+	ret = ehci_common_init(ctrl, tweaks);
+	if (ret)
+		goto err;
+done:
+	return 0;
+err:
+	free(ctrl);
+	debug("%s: failed, ret=%d\n", __func__, ret);
+	return ret;
+}
+
+int ehci_deregister(struct udevice *dev)
+{
+	struct ehci_ctrl *ctrl = dev_get_priv(dev);
+
+	if (ctrl->init == USB_INIT_DEVICE)
+		return 0;
+
+	ehci_shutdown(ctrl);
+
+	return 0;
+}
+
+struct dm_usb_ops ehci_usb_ops = {
+	.control = ehci_submit_control_msg,
+	.bulk = ehci_submit_bulk_msg,
+	.interrupt = ehci_submit_int_msg,
+	.create_int_queue = ehci_create_int_queue,
+	.poll_int_queue = ehci_poll_int_queue,
+	.destroy_int_queue = ehci_destroy_int_queue,
+	.get_max_xfer_size  = ehci_get_max_xfer_size,
+	.lock_async = ehci_lock_async,
+};
+
+#endif
+
+#ifdef CONFIG_PHY
+int ehci_setup_phy(struct udevice *dev, struct phy *phy, int index)
+{
+	int ret;
+
+	if (!phy)
+		return 0;
+
+	ret = generic_phy_get_by_index(dev, index, phy);
+	if (ret) {
+		if (ret != -ENOENT) {
+			dev_err(dev, "failed to get usb phy\n");
+			return ret;
+		}
+	} else {
+		ret = generic_phy_init(phy);
+		if (ret) {
+			dev_dbg(dev, "failed to init usb phy\n");
+			return ret;
+		}
+
+		ret = generic_phy_power_on(phy);
+		if (ret) {
+			dev_dbg(dev, "failed to power on usb phy\n");
+			return generic_phy_exit(phy);
+		}
+	}
+
+	return 0;
+}
+
+int ehci_shutdown_phy(struct udevice *dev, struct phy *phy)
+{
+	int ret = 0;
+
+	if (!phy)
+		return 0;
+
+	if (generic_phy_valid(phy)) {
+		ret = generic_phy_power_off(phy);
+		if (ret) {
+			dev_dbg(dev, "failed to power off usb phy\n");
+			return ret;
+		}
+
+		ret = generic_phy_exit(phy);
+		if (ret) {
+			dev_dbg(dev, "failed to power off usb phy\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+#else
+int ehci_setup_phy(struct udevice *dev, struct phy *phy, int index)
+{
+	return 0;
+}
+
+int ehci_shutdown_phy(struct udevice *dev, struct phy *phy)
+{
+	return 0;
+}
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ehci-marvell.c b/roms/u-boot/drivers/usb/host/ehci-marvell.c
new file mode 100644
index 000000000..5420bb977
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-marvell.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include "ehci.h"
+#include <linux/mbus.h>
+#include <asm/arch/cpu.h>
+#include <dm.h>
+
+#if defined(CONFIG_ARCH_KIRKWOOD)
+#include <asm/arch/soc.h>
+#elif defined(CONFIG_ARCH_ORION5X)
+#include <asm/arch/orion5x.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define USB_WINDOW_CTRL(i)	(0x320 + ((i) << 4))
+#define USB_WINDOW_BASE(i)	(0x324 + ((i) << 4))
+#define USB_TARGET_DRAM		0x0
+
+#define USB2_SBUSCFG_OFF	0x90
+
+#define USB_SBUSCFG_BAWR_OFF	0x6
+#define USB_SBUSCFG_BARD_OFF	0x3
+#define USB_SBUSCFG_AHBBRST_OFF	0x0
+
+#define USB_SBUSCFG_BAWR_ALIGN_64B	0x4
+#define USB_SBUSCFG_BARD_ALIGN_64B	0x4
+#define USB_SBUSCFG_AHBBRST_INCR16	0x7
+
+/*
+ * USB 2.0 Bridge Address Decoding registers setup
+ */
+#if CONFIG_IS_ENABLED(DM_USB)
+
+struct ehci_mvebu_priv {
+	struct ehci_ctrl ehci;
+	fdt_addr_t hcd_base;
+};
+
+/*
+ * Once all the older Marvell SoC's (Orion, Kirkwood) are converted
+ * to the common mvebu archticture including the mbus setup, this
+ * will be the only function needed to configure the access windows
+ */
+static void usb_brg_adrdec_setup(void *base)
+{
+	const struct mbus_dram_target_info *dram;
+	int i;
+
+	dram = mvebu_mbus_dram_info();
+
+	for (i = 0; i < 4; i++) {
+		writel(0, base + USB_WINDOW_CTRL(i));
+		writel(0, base + USB_WINDOW_BASE(i));
+	}
+
+	for (i = 0; i < dram->num_cs; i++) {
+		const struct mbus_dram_window *cs = dram->cs + i;
+
+		/* Write size, attributes and target id to control register */
+		writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
+		       (dram->mbus_dram_target_id << 4) | 1,
+		       base + USB_WINDOW_CTRL(i));
+
+		/* Write base address to base register */
+		writel(cs->base, base + USB_WINDOW_BASE(i));
+	}
+}
+
+static void marvell_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
+				       uint32_t *status_reg, uint32_t *reg)
+{
+	struct ehci_mvebu_priv *priv = ctrl->priv;
+
+	/*
+	 * Set default value for reg SBUSCFG, which is Control for the AMBA
+	 * system bus interface:
+	 * BAWR = BARD = 4 : Align rd/wr bursts packets larger than 64 bytes
+	 * AHBBRST = 7     : Align AHB burst for packets larger than 64 bytes
+	 */
+	writel((USB_SBUSCFG_BAWR_ALIGN_64B << USB_SBUSCFG_BAWR_OFF) |
+	       (USB_SBUSCFG_BARD_ALIGN_64B << USB_SBUSCFG_BARD_OFF) |
+	       (USB_SBUSCFG_AHBBRST_INCR16 << USB_SBUSCFG_AHBBRST_OFF),
+	       priv->hcd_base + USB2_SBUSCFG_OFF);
+
+	mdelay(50);
+}
+
+static struct ehci_ops marvell_ehci_ops = {
+	.powerup_fixup	= NULL,
+};
+
+static int ehci_mvebu_probe(struct udevice *dev)
+{
+	struct ehci_mvebu_priv *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+
+	/*
+	 * Get the base address for EHCI controller from the device node
+	 */
+	priv->hcd_base = dev_read_addr(dev);
+	if (priv->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the EHCI register base address\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * For SoCs without hlock like Armada3700 we need to program the sbuscfg
+	 * reg to guarantee AHB master's burst will not overrun or underrun
+	 * the FIFO. Otherwise all USB2 write option will fail.
+	 * Also, the address decoder doesn't need to get setup with this
+	 * SoC, so don't call usb_brg_adrdec_setup().
+	 */
+	if (device_is_compatible(dev, "marvell,armada3700-ehci"))
+		marvell_ehci_ops.powerup_fixup = marvell_ehci_powerup_fixup;
+	else
+		usb_brg_adrdec_setup((void *)priv->hcd_base);
+
+	hccr = (struct ehci_hccr *)(priv->hcd_base + 0x100);
+	hcor = (struct ehci_hcor *)
+		((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	debug("ehci-marvell: init hccr %lx and hcor %lx hc_length %ld\n",
+	      (uintptr_t)hccr, (uintptr_t)hcor,
+	      (uintptr_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	return ehci_register(dev, hccr, hcor, &marvell_ehci_ops, 0,
+			     USB_INIT_HOST);
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "marvell,orion-ehci", },
+	{ .compatible = "marvell,armada3700-ehci", },
+	{ }
+};
+
+U_BOOT_DRIVER(ehci_mvebu) = {
+	.name	= "ehci_mvebu",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.probe = ehci_mvebu_probe,
+	.remove = ehci_deregister,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_mvebu_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+#else
+#define MVUSB_BASE(port)	MVUSB0_BASE
+
+static void usb_brg_adrdec_setup(int index)
+{
+	int i;
+	u32 size, base, attrib;
+
+	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+
+		/* Enable DRAM bank */
+		switch (i) {
+		case 0:
+			attrib = MVUSB0_CPU_ATTR_DRAM_CS0;
+			break;
+		case 1:
+			attrib = MVUSB0_CPU_ATTR_DRAM_CS1;
+			break;
+		case 2:
+			attrib = MVUSB0_CPU_ATTR_DRAM_CS2;
+			break;
+		case 3:
+			attrib = MVUSB0_CPU_ATTR_DRAM_CS3;
+			break;
+		default:
+			/* invalide bank, disable access */
+			attrib = 0;
+			break;
+		}
+
+		size = gd->bd->bi_dram[i].size;
+		base = gd->bd->bi_dram[i].start;
+		if ((size) && (attrib))
+			writel(MVCPU_WIN_CTRL_DATA(size, USB_TARGET_DRAM,
+						   attrib, MVCPU_WIN_ENABLE),
+				MVUSB0_BASE + USB_WINDOW_CTRL(i));
+		else
+			writel(MVCPU_WIN_DISABLE,
+			       MVUSB0_BASE + USB_WINDOW_CTRL(i));
+
+		writel(base, MVUSB0_BASE + USB_WINDOW_BASE(i));
+	}
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	usb_brg_adrdec_setup(index);
+
+	*hccr = (struct ehci_hccr *)(MVUSB_BASE(index) + 0x100);
+	*hcor = (struct ehci_hcor *)((uint32_t) *hccr
+			+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	debug("ehci-marvell: init hccr %x and hcor %x hc_length %d\n",
+		(uint32_t)*hccr, (uint32_t)*hcor,
+		(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+#endif /* CONFIG_IS_ENABLED(DM_USB) */
diff --git a/roms/u-boot/drivers/usb/host/ehci-msm.c b/roms/u-boot/drivers/usb/host/ehci-msm.c
new file mode 100644
index 000000000..d160cf019
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-msm.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm EHCI driver
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * Based on Linux driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <usb.h>
+#include <usb/ehci-ci.h>
+#include <usb/ulpi.h>
+#include <wait_bit.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/compat.h>
+#include "ehci.h"
+
+struct msm_ehci_priv {
+	struct ehci_ctrl ctrl; /* Needed by EHCI */
+	struct usb_ehci *ehci; /* Start of IP core*/
+	struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
+	struct phy phy;
+};
+
+static int msm_init_after_reset(struct ehci_ctrl *dev)
+{
+	struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
+	struct usb_ehci *ehci = p->ehci;
+
+	generic_phy_reset(&p->phy);
+
+	/* set mode to host controller */
+	writel(CM_HOST, &ehci->usbmode);
+
+	return 0;
+}
+
+static const struct ehci_ops msm_ehci_ops = {
+	.init_after_reset = msm_init_after_reset
+};
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct msm_ehci_priv *p = dev_get_priv(dev);
+	struct usb_ehci *ehci = p->ehci;
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int ret;
+
+	hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
+	hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
+			HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
+
+	ret = ehci_setup_phy(dev, &p->phy, 0);
+	if (ret)
+		return ret;
+
+	ret = board_usb_init(0, plat->init_type);
+	if (ret < 0)
+		return ret;
+
+	return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
+			     plat->init_type);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+	struct msm_ehci_priv *p = dev_get_priv(dev);
+	struct usb_ehci *ehci = p->ehci;
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	/* Stop controller. */
+	clrbits_le32(&ehci->usbcmd, CMD_RUN);
+
+	ret = ehci_shutdown_phy(dev, &p->phy);
+	if (ret)
+		return ret;
+
+	ret = board_usb_init(0, USB_INIT_DEVICE); /* Board specific hook */
+	if (ret < 0)
+		return ret;
+
+	/* Reset controller */
+	setbits_le32(&ehci->usbcmd, CMD_RESET);
+
+	/* Wait for reset */
+	if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
+		printf("Stuck on USB reset.\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int ehci_usb_of_to_plat(struct udevice *dev)
+{
+	struct msm_ehci_priv *priv = dev_get_priv(dev);
+
+	priv->ulpi_vp.port_num = 0;
+	priv->ehci = dev_read_addr_ptr(dev);
+
+	if (priv->ehci == (void *)FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	/* Warning: this will not work if viewport address is > 64 bit due to
+	 * ULPI design.
+	 */
+	priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
+
+	return 0;
+}
+
+#if defined(CONFIG_CI_UDC)
+/* Little quirk that MSM needs with Chipidea controller
+ * Must reinit phy after reset
+ */
+void ci_init_after_reset(struct ehci_ctrl *ctrl)
+{
+	struct msm_ehci_priv *p = ctrl->priv;
+
+	generic_phy_reset(&p->phy);
+}
+#endif
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "qcom,ehci-host", },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_msm",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.of_to_plat = ehci_usb_of_to_plat,
+	.probe = ehci_usb_probe,
+	.remove = ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.priv_auto	= sizeof(struct msm_ehci_priv),
+	.plat_auto	= sizeof(struct usb_plat),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ehci-mx5.c b/roms/u-boot/drivers/usb/host/ehci-mx5.c
new file mode 100644
index 000000000..ab863f41b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-mx5.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <usb.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <usb/ehci-ci.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+#include <dm.h>
+#include <power/regulator.h>
+
+#include "ehci.h"
+
+#define MX5_USBOTHER_REGS_OFFSET 0x800
+
+
+#define MXC_OTG_OFFSET			0
+#define MXC_H1_OFFSET			0x200
+#define MXC_H2_OFFSET			0x400
+#define MXC_H3_OFFSET			0x600
+
+#define MXC_USBCTRL_OFFSET		0
+#define MXC_USB_PHY_CTR_FUNC_OFFSET	0x8
+#define MXC_USB_PHY_CTR_FUNC2_OFFSET	0xc
+#define MXC_USB_CTRL_1_OFFSET		0x10
+#define MXC_USBH2CTRL_OFFSET		0x14
+#define MXC_USBH3CTRL_OFFSET		0x18
+
+/* USB_CTRL */
+/* OTG wakeup intr enable */
+#define MXC_OTG_UCTRL_OWIE_BIT		(1 << 27)
+/* OTG power mask */
+#define MXC_OTG_UCTRL_OPM_BIT		(1 << 24)
+/* OTG power pin polarity */
+#define MXC_OTG_UCTRL_O_PWR_POL_BIT	(1 << 24)
+/* Host1 ULPI interrupt enable */
+#define MXC_H1_UCTRL_H1UIE_BIT		(1 << 12)
+/* HOST1 wakeup intr enable */
+#define MXC_H1_UCTRL_H1WIE_BIT		(1 << 11)
+/* HOST1 power mask */
+#define MXC_H1_UCTRL_H1PM_BIT		(1 << 8)
+/* HOST1 power pin polarity */
+#define MXC_H1_UCTRL_H1_PWR_POL_BIT	(1 << 8)
+
+/* USB_PHY_CTRL_FUNC */
+/* OTG Polarity of Overcurrent */
+#define MXC_OTG_PHYCTRL_OC_POL_BIT	(1 << 9)
+/* OTG Disable Overcurrent Event */
+#define MXC_OTG_PHYCTRL_OC_DIS_BIT	(1 << 8)
+/* UH1 Polarity of Overcurrent */
+#define MXC_H1_OC_POL_BIT		(1 << 6)
+/* UH1 Disable Overcurrent Event */
+#define MXC_H1_OC_DIS_BIT		(1 << 5)
+/* OTG Power Pin Polarity */
+#define MXC_OTG_PHYCTRL_PWR_POL_BIT	(1 << 3)
+
+/* USBH2CTRL */
+#define MXC_H2_UCTRL_H2_OC_POL_BIT	(1 << 31)
+#define MXC_H2_UCTRL_H2_OC_DIS_BIT	(1 << 30)
+#define MXC_H2_UCTRL_H2UIE_BIT		(1 << 8)
+#define MXC_H2_UCTRL_H2WIE_BIT		(1 << 7)
+#define MXC_H2_UCTRL_H2PM_BIT		(1 << 4)
+#define MXC_H2_UCTRL_H2_PWR_POL_BIT	(1 << 4)
+
+/* USBH3CTRL */
+#define MXC_H3_UCTRL_H3_OC_POL_BIT	(1 << 31)
+#define MXC_H3_UCTRL_H3_OC_DIS_BIT	(1 << 30)
+#define MXC_H3_UCTRL_H3UIE_BIT		(1 << 8)
+#define MXC_H3_UCTRL_H3WIE_BIT		(1 << 7)
+#define MXC_H3_UCTRL_H3_PWR_POL_BIT	(1 << 4)
+
+/* USB_CTRL_1 */
+#define MXC_USB_CTRL_UH1_EXT_CLK_EN	(1 << 25)
+
+int mxc_set_usbcontrol(int port, unsigned int flags)
+{
+	unsigned int v;
+	void __iomem *usb_base = (void __iomem *)OTG_BASE_ADDR;
+	void __iomem *usbother_base;
+	int ret = 0;
+
+	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+	switch (port) {
+	case 0:	/* OTG port */
+		if (flags & MXC_EHCI_INTERNAL_PHY) {
+			v = __raw_readl(usbother_base +
+					MXC_USB_PHY_CTR_FUNC_OFFSET);
+			if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+				v |= MXC_OTG_PHYCTRL_OC_POL_BIT;
+			else
+				v &= ~MXC_OTG_PHYCTRL_OC_POL_BIT;
+			if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+				/* OC/USBPWR is used */
+				v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
+			else
+				/* OC/USBPWR is not used */
+				v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
+#ifdef CONFIG_MX51
+			if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+				v |= MXC_OTG_PHYCTRL_PWR_POL_BIT;
+			else
+				v &= ~MXC_OTG_PHYCTRL_PWR_POL_BIT;
+#endif
+			__raw_writel(v, usbother_base +
+					MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+			v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+#ifdef CONFIG_MX51
+			if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+				v &= ~MXC_OTG_UCTRL_OPM_BIT;
+			else
+				v |= MXC_OTG_UCTRL_OPM_BIT;
+#endif
+#ifdef CONFIG_MX53
+			if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+				v |= MXC_OTG_UCTRL_O_PWR_POL_BIT;
+			else
+				v &= ~MXC_OTG_UCTRL_O_PWR_POL_BIT;
+#endif
+			__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+		}
+		break;
+	case 1:	/* Host 1 ULPI */
+#ifdef CONFIG_MX51
+		/* The clock for the USBH1 ULPI port will come externally
+		   from the PHY. */
+		v = __raw_readl(usbother_base + MXC_USB_CTRL_1_OFFSET);
+		__raw_writel(v | MXC_USB_CTRL_UH1_EXT_CLK_EN, usbother_base +
+				MXC_USB_CTRL_1_OFFSET);
+#endif
+
+		v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+#ifdef CONFIG_MX51
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H1_UCTRL_H1PM_BIT; /* H1 power mask unused */
+		else
+			v |= MXC_H1_UCTRL_H1PM_BIT; /* H1 power mask used */
+#endif
+#ifdef CONFIG_MX53
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MXC_H1_UCTRL_H1_PWR_POL_BIT;
+		else
+			v &= ~MXC_H1_UCTRL_H1_PWR_POL_BIT;
+#endif
+		__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+
+		v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+		if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+			v |= MXC_H1_OC_POL_BIT;
+		else
+			v &= ~MXC_H1_OC_POL_BIT;
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
+		else
+			v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
+		__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+		break;
+	case 2: /* Host 2 ULPI */
+		v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET);
+#ifdef CONFIG_MX51
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H2_UCTRL_H2PM_BIT; /* H2 power mask unused */
+		else
+			v |= MXC_H2_UCTRL_H2PM_BIT; /* H2 power mask used */
+#endif
+#ifdef CONFIG_MX53
+		if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+			v |= MXC_H2_UCTRL_H2_OC_POL_BIT;
+		else
+			v &= ~MXC_H2_UCTRL_H2_OC_POL_BIT;
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H2_UCTRL_H2_OC_DIS_BIT; /* OC is used */
+		else
+			v |= MXC_H2_UCTRL_H2_OC_DIS_BIT; /* OC is not used */
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MXC_H2_UCTRL_H2_PWR_POL_BIT;
+		else
+			v &= ~MXC_H2_UCTRL_H2_PWR_POL_BIT;
+#endif
+		__raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
+		break;
+#ifdef CONFIG_MX53
+	case 3: /* Host 3 ULPI */
+		v = __raw_readl(usbother_base + MXC_USBH3CTRL_OFFSET);
+		if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+			v |= MXC_H3_UCTRL_H3_OC_POL_BIT;
+		else
+			v &= ~MXC_H3_UCTRL_H3_OC_POL_BIT;
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H3_UCTRL_H3_OC_DIS_BIT; /* OC is used */
+		else
+			v |= MXC_H3_UCTRL_H3_OC_DIS_BIT; /* OC is not used */
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MXC_H3_UCTRL_H3_PWR_POL_BIT;
+		else
+			v &= ~MXC_H3_UCTRL_H3_PWR_POL_BIT;
+		__raw_writel(v, usbother_base + MXC_USBH3CTRL_OFFSET);
+		break;
+#endif
+	}
+
+	return ret;
+}
+
+int __weak board_ehci_hcd_init(int port)
+{
+	return 0;
+}
+
+void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+{
+}
+
+__weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+				   uint32_t *reg)
+{
+	mdelay(50);
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+static const struct ehci_ops mx5_ehci_ops = {
+	.powerup_fixup		= mx5_ehci_powerup_fixup,
+};
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	struct usb_ehci *ehci;
+
+	/* The only user for this is efikamx-usb */
+	ehci_set_controller_priv(index, NULL, &mx5_ehci_ops);
+	set_usboh3_clk();
+	enable_usboh3_clk(true);
+	set_usb_phy_clk();
+	enable_usb_phy1_clk(true);
+	enable_usb_phy2_clk(true);
+	mdelay(1);
+
+	/* Do board specific initialization */
+	board_ehci_hcd_init(CONFIG_MXC_USB_PORT);
+
+	ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
+		(0x200 * CONFIG_MXC_USB_PORT));
+	*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+	setbits_le32(&ehci->usbmode, CM_HOST);
+
+	__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS);
+	mdelay(10);
+
+	/* Do board specific post-initialization */
+	board_ehci_hcd_postinit(ehci, CONFIG_MXC_USB_PORT);
+
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+#else /* CONFIG_IS_ENABLED(DM_USB) */
+struct ehci_mx5_priv_data {
+	struct ehci_ctrl ctrl;
+	struct usb_ehci *ehci;
+	struct udevice *vbus_supply;
+	enum usb_init_type init_type;
+	int portnr;
+};
+
+static const struct ehci_ops mx5_ehci_ops = {
+	.powerup_fixup		= mx5_ehci_powerup_fixup,
+};
+
+static int ehci_usb_of_to_plat(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	const char *mode;
+
+	mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL);
+	if (mode) {
+		if (strcmp(mode, "peripheral") == 0)
+			plat->init_type = USB_INIT_DEVICE;
+		else if (strcmp(mode, "host") == 0)
+			plat->init_type = USB_INIT_HOST;
+		else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct usb_ehci *ehci = dev_read_addr_ptr(dev);
+	struct ehci_mx5_priv_data *priv = dev_get_priv(dev);
+	enum usb_init_type type = plat->init_type;
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int ret;
+
+	set_usboh3_clk();
+	enable_usboh3_clk(true);
+	set_usb_phy_clk();
+	enable_usb_phy1_clk(true);
+	enable_usb_phy2_clk(true);
+	mdelay(1);
+
+	priv->ehci = ehci;
+	priv->portnr = dev_seq(dev);
+	priv->init_type = type;
+
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &priv->vbus_supply);
+	if (ret)
+		debug("%s: No vbus supply\n", dev->name);
+
+	if (!ret && priv->vbus_supply) {
+		ret = regulator_set_enable(priv->vbus_supply,
+					   (type == USB_INIT_DEVICE) ?
+					   false : true);
+		if (ret) {
+			puts("Error enabling VBUS supply\n");
+			return ret;
+		}
+	}
+
+	hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	hcor = (struct ehci_hcor *)((uint32_t)hccr +
+			HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
+	setbits_le32(&ehci->usbmode, CM_HOST);
+
+	__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mxc_set_usbcontrol(priv->portnr, CONFIG_MXC_USB_FLAGS);
+	mdelay(10);
+
+	return ehci_register(dev, hccr, hcor, &mx5_ehci_ops, 0,
+			     priv->init_type);
+}
+
+static const struct udevice_id mx5_usb_ids[] = {
+	{ .compatible = "fsl,imx53-usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_mx5) = {
+	.name	= "ehci_mx5",
+	.id	= UCLASS_USB,
+	.of_match = mx5_usb_ids,
+	.of_to_plat = ehci_usb_of_to_plat,
+	.probe	= ehci_usb_probe,
+	.remove = ehci_deregister,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_mx5_priv_data),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* !CONFIG_IS_ENABLED(DM_USB) */
diff --git a/roms/u-boot/drivers/usb/host/ehci-mx6.c b/roms/u-boot/drivers/usb/host/ehci-mx6.c
new file mode 100644
index 000000000..c3e417051
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-mx6.c
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <log.h>
+#include <usb.h>
+#include <errno.h>
+#include <wait_bit.h>
+#include <asm/global_data.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <usb/ehci-ci.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/sys_proto.h>
+#include <dm.h>
+#include <asm/mach-types.h>
+#include <power/regulator.h>
+#include <linux/usb/otg.h>
+
+#include "ehci.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define USB_OTGREGS_OFFSET	0x000
+#define USB_H1REGS_OFFSET	0x200
+#define USB_H2REGS_OFFSET	0x400
+#define USB_H3REGS_OFFSET	0x600
+#define USB_OTHERREGS_OFFSET	0x800
+
+#define USB_H1_CTRL_OFFSET	0x04
+
+#define USBPHY_CTRL				0x00000030
+#define USBPHY_CTRL_SET				0x00000034
+#define USBPHY_CTRL_CLR				0x00000038
+#define USBPHY_CTRL_TOG				0x0000003c
+
+#define USBPHY_PWD				0x00000000
+#define USBPHY_CTRL_SFTRST			0x80000000
+#define USBPHY_CTRL_CLKGATE			0x40000000
+#define USBPHY_CTRL_ENUTMILEVEL3		0x00008000
+#define USBPHY_CTRL_ENUTMILEVEL2		0x00004000
+#define USBPHY_CTRL_OTG_ID			0x08000000
+
+#define ANADIG_USB2_CHRG_DETECT_EN_B		0x00100000
+#define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B	0x00080000
+
+#define ANADIG_USB2_PLL_480_CTRL_BYPASS		0x00010000
+#define ANADIG_USB2_PLL_480_CTRL_ENABLE		0x00002000
+#define ANADIG_USB2_PLL_480_CTRL_POWER		0x00001000
+#define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS	0x00000040
+
+#define USBNC_OFFSET		0x200
+#define USBNC_PHY_STATUS_OFFSET	0x23C
+#define USBNC_PHYSTATUS_ID_DIG	(1 << 4) /* otg_id status */
+#define USBNC_PHYCFG2_ACAENB	(1 << 4) /* otg_id detection enable */
+#define UCTRL_PWR_POL		(1 << 9) /* OTG Polarity of Power Pin */
+#define UCTRL_OVER_CUR_POL	(1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS	(1 << 7) /* Disable OTG Overcurrent Detection */
+
+/* USBCMD */
+#define UCMD_RUN_STOP           (1 << 0) /* controller run/stop */
+#define UCMD_RESET		(1 << 1) /* controller reset */
+
+/* If this is not defined, assume MX6/MX7/MX8M SoC default */
+#ifndef CONFIG_MXC_USB_PORTSC
+#define CONFIG_MXC_USB_PORTSC	(PORT_PTS_UTMI | PORT_PTS_PTW)
+#endif
+
+/* Base address for this IP block is 0x02184800 */
+struct usbnc_regs {
+	u32 ctrl[4]; /* otg/host1-3 */
+	u32 uh2_hsic_ctrl;
+	u32 uh3_hsic_ctrl;
+	u32 otg_phy_ctrl_0;
+	u32 uh1_phy_ctrl_0;
+	u32 reserve1[4];
+	u32 phy_cfg1;
+	u32 phy_cfg2;
+	u32 reserve2;
+	u32 phy_status;
+	u32 reserve3[4];
+	u32 adp_cfg1;
+	u32 adp_cfg2;
+	u32 adp_status;
+};
+
+#if defined(CONFIG_MX6) && !defined(CONFIG_PHY)
+static void usb_power_config_mx6(struct anatop_regs __iomem *anatop,
+				 int anatop_bits_index)
+{
+	void __iomem *chrg_detect;
+	void __iomem *pll_480_ctrl_clr;
+	void __iomem *pll_480_ctrl_set;
+
+	if (!is_mx6())
+		return;
+
+	switch (anatop_bits_index) {
+	case 0:
+		chrg_detect = &anatop->usb1_chrg_detect;
+		pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr;
+		pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set;
+		break;
+	case 1:
+		chrg_detect = &anatop->usb2_chrg_detect;
+		pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr;
+		pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set;
+		break;
+	default:
+		return;
+	}
+	/*
+	 * Some phy and power's special controls
+	 * 1. The external charger detector needs to be disabled
+	 * or the signal at DP will be poor
+	 * 2. The PLL's power and output to usb
+	 * is totally controlled by IC, so the Software only needs
+	 * to enable them at initializtion.
+	 */
+	writel(ANADIG_USB2_CHRG_DETECT_EN_B |
+		     ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
+		     chrg_detect);
+
+	writel(ANADIG_USB2_PLL_480_CTRL_BYPASS,
+		     pll_480_ctrl_clr);
+
+	writel(ANADIG_USB2_PLL_480_CTRL_ENABLE |
+		     ANADIG_USB2_PLL_480_CTRL_POWER |
+		     ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
+		     pll_480_ctrl_set);
+}
+#else
+static void __maybe_unused
+usb_power_config_mx6(void *anatop, int anatop_bits_index) { }
+#endif
+
+#if defined(CONFIG_MX7) && !defined(CONFIG_PHY)
+static void usb_power_config_mx7(struct usbnc_regs *usbnc)
+{
+	void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2);
+
+	if (!is_mx7())
+		return;
+
+	/*
+	 * Clear the ACAENB to enable usb_otg_id detection,
+	 * otherwise it is the ACA detection enabled.
+	 */
+	clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB);
+}
+#else
+static void __maybe_unused
+usb_power_config_mx7(void *usbnc) { }
+#endif
+
+#if defined(CONFIG_MX7ULP) && !defined(CONFIG_PHY)
+static void usb_power_config_mx7ulp(struct usbphy_regs __iomem *usbphy)
+{
+	if (!is_mx7ulp())
+		return;
+
+	writel(ANADIG_USB2_CHRG_DETECT_EN_B |
+	       ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
+	       &usbphy->usb1_chrg_detect);
+
+	scg_enable_usb_pll(true);
+}
+#else
+static void __maybe_unused
+usb_power_config_mx7ulp(void *usbphy) { }
+#endif
+
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT)
+static const unsigned phy_bases[] = {
+	USB_PHY0_BASE_ADDR,
+#if defined(USB_PHY1_BASE_ADDR)
+	USB_PHY1_BASE_ADDR,
+#endif
+};
+
+#if !defined(CONFIG_PHY)
+static void usb_internal_phy_clock_gate(void __iomem *phy_reg, int on)
+{
+	phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
+	writel(USBPHY_CTRL_CLKGATE, phy_reg);
+}
+
+/* Return 0 : host node, <>0 : device mode */
+static int usb_phy_enable(struct usb_ehci *ehci, void __iomem *phy_reg)
+{
+	void __iomem *phy_ctrl;
+	void __iomem *usb_cmd;
+	int ret;
+
+	phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
+	usb_cmd = (void __iomem *)&ehci->usbcmd;
+
+	/* Stop then Reset */
+	clrbits_le32(usb_cmd, UCMD_RUN_STOP);
+	ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false);
+	if (ret)
+		return ret;
+
+	setbits_le32(usb_cmd, UCMD_RESET);
+	ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false);
+	if (ret)
+		return ret;
+
+	/* Reset USBPHY module */
+	setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST);
+	udelay(10);
+
+	/* Remove CLKGATE and SFTRST */
+	clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
+	udelay(10);
+
+	/* Power up the PHY */
+	writel(0, phy_reg + USBPHY_PWD);
+	/* enable FS/LS device */
+	setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 |
+			USBPHY_CTRL_ENUTMILEVEL3);
+
+	return 0;
+}
+#endif
+
+int usb_phy_mode(int port)
+{
+	void __iomem *phy_reg;
+	void __iomem *phy_ctrl;
+	u32 val;
+
+	phy_reg = (void __iomem *)phy_bases[port];
+	phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
+
+	val = readl(phy_ctrl);
+
+	if (val & USBPHY_CTRL_OTG_ID)
+		return USB_INIT_DEVICE;
+	else
+		return USB_INIT_HOST;
+}
+
+#elif defined(CONFIG_MX7)
+int usb_phy_mode(int port)
+{
+	struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
+			(0x10000 * port) + USBNC_OFFSET);
+	void __iomem *status = (void __iomem *)(&usbnc->phy_status);
+	u32 val;
+
+	val = readl(status);
+
+	if (val & USBNC_PHYSTATUS_ID_DIG)
+		return USB_INIT_DEVICE;
+	else
+		return USB_INIT_HOST;
+}
+#endif
+
+#if !defined(CONFIG_PHY)
+/* Should be done in the MXS PHY driver */
+static void usb_oc_config(struct usbnc_regs *usbnc, int index)
+{
+	void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]);
+
+#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
+	/* mx6qarm2 seems to required a different setting*/
+	clrbits_le32(ctrl, UCTRL_OVER_CUR_POL);
+#else
+	setbits_le32(ctrl, UCTRL_OVER_CUR_POL);
+#endif
+
+	setbits_le32(ctrl, UCTRL_OVER_CUR_DIS);
+
+	/* Set power polarity to high active */
+#ifdef CONFIG_MXC_USB_OTG_HACTIVE
+	setbits_le32(ctrl, UCTRL_PWR_POL);
+#else
+	clrbits_le32(ctrl, UCTRL_PWR_POL);
+#endif
+}
+#endif
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+/**
+ * board_usb_phy_mode - override usb phy mode
+ * @port:	usb host/otg port
+ *
+ * Target board specific, override usb_phy_mode.
+ * When usb-otg is used as usb host port, iomux pad usb_otg_id can be
+ * left disconnected in this case usb_phy_mode will not be able to identify
+ * the phy mode that usb port is used.
+ * Machine file overrides board_usb_phy_mode.
+ *
+ * Return: USB_INIT_DEVICE or USB_INIT_HOST
+ */
+int __weak board_usb_phy_mode(int port)
+{
+	return usb_phy_mode(port);
+}
+
+/**
+ * board_ehci_hcd_init - set usb vbus voltage
+ * @port:      usb otg port
+ *
+ * Target board specific, setup iomux pad to setup supply vbus voltage
+ * for usb otg port. Machine board file overrides board_ehci_hcd_init
+ *
+ * Return: 0 Success
+ */
+int __weak board_ehci_hcd_init(int port)
+{
+	return 0;
+}
+
+/**
+ * board_ehci_power - enables/disables usb vbus voltage
+ * @port:      usb otg port
+ * @on:        on/off vbus voltage
+ *
+ * Enables/disables supply vbus voltage for usb otg port.
+ * Machine board file overrides board_ehci_power
+ *
+ * Return: 0 Success
+ */
+int __weak board_ehci_power(int port, int on)
+{
+	return 0;
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	enum usb_init_type type;
+#if defined(CONFIG_MX6) || defined(CONFIG_IMXRT)
+	u32 controller_spacing = 0x200;
+	struct anatop_regs __iomem *anatop =
+		(struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
+	struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
+			USB_OTHERREGS_OFFSET);
+#elif defined(CONFIG_MX7)
+	u32 controller_spacing = 0x10000;
+	struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
+			(0x10000 * index) + USBNC_OFFSET);
+#elif defined(CONFIG_MX7ULP)
+	u32 controller_spacing = 0x10000;
+	struct usbphy_regs __iomem *usbphy =
+		(struct usbphy_regs __iomem *)USB_PHY0_BASE_ADDR;
+	struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
+			(0x10000 * index) + USBNC_OFFSET);
+#endif
+	struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR +
+		(controller_spacing * index));
+	int ret;
+
+	if (index > 3)
+		return -EINVAL;
+
+	if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) {
+		if (usb_fused((ulong)ehci)) {
+			printf("SoC fuse indicates USB@0x%lx is unavailable.\n",
+			       (ulong)ehci);
+			return	-ENODEV;
+		}
+	}
+
+	enable_usboh3_clk(1);
+	mdelay(1);
+
+	/* Do board specific initialization */
+	ret = board_ehci_hcd_init(index);
+	if (ret) {
+		enable_usboh3_clk(0);
+		return ret;
+	}
+
+#if defined(CONFIG_MX6) || defined(CONFIG_IMXRT)
+	usb_power_config_mx6(anatop, index);
+#elif defined (CONFIG_MX7)
+	usb_power_config_mx7(usbnc);
+#elif defined (CONFIG_MX7ULP)
+	usb_power_config_mx7ulp(usbphy);
+#endif
+
+	usb_oc_config(usbnc, index);
+
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT)
+	if (index < ARRAY_SIZE(phy_bases)) {
+		usb_internal_phy_clock_gate((void __iomem *)phy_bases[index], 1);
+		usb_phy_enable(ehci, (void __iomem *)phy_bases[index]);
+	}
+#endif
+
+	type = board_usb_phy_mode(index);
+
+	if (hccr && hcor) {
+		*hccr = (struct ehci_hccr *)((uintptr_t)&ehci->caplength);
+		*hcor = (struct ehci_hcor *)((uintptr_t)*hccr +
+				HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+	}
+
+	if ((type == init) || (type == USB_INIT_DEVICE))
+		board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1);
+	if (type != init)
+		return -ENODEV;
+	if (type == USB_INIT_DEVICE)
+		return 0;
+
+	setbits_le32(&ehci->usbmode, CM_HOST);
+	writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mdelay(10);
+
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+#else
+struct ehci_mx6_priv_data {
+	struct ehci_ctrl ctrl;
+	struct usb_ehci *ehci;
+	struct udevice *vbus_supply;
+	struct clk clk;
+	struct phy phy;
+	enum usb_init_type init_type;
+#if !defined(CONFIG_PHY)
+	int portnr;
+	void __iomem *phy_addr;
+	void __iomem *misc_addr;
+	void __iomem *anatop_addr;
+#endif
+};
+
+static int mx6_init_after_reset(struct ehci_ctrl *dev)
+{
+	struct ehci_mx6_priv_data *priv = dev->priv;
+	enum usb_init_type type = priv->init_type;
+	struct usb_ehci *ehci = priv->ehci;
+
+#if !defined(CONFIG_PHY)
+	usb_power_config_mx6(priv->anatop_addr, priv->portnr);
+	usb_power_config_mx7(priv->misc_addr);
+	usb_power_config_mx7ulp(priv->phy_addr);
+
+	usb_oc_config(priv->misc_addr, priv->portnr);
+
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
+	usb_internal_phy_clock_gate(priv->phy_addr, 1);
+	usb_phy_enable(ehci, priv->phy_addr);
+#endif
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	if (priv->vbus_supply) {
+		int ret;
+		ret = regulator_set_enable(priv->vbus_supply,
+					   (type == USB_INIT_DEVICE) ?
+					   false : true);
+		if (ret && ret != -ENOSYS) {
+			printf("Error enabling VBUS supply (ret=%i)\n", ret);
+			return ret;
+		}
+	}
+#endif
+
+	if (type == USB_INIT_DEVICE)
+		return 0;
+
+	setbits_le32(&ehci->usbmode, CM_HOST);
+	writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mdelay(10);
+
+	return 0;
+}
+
+static const struct ehci_ops mx6_ehci_ops = {
+	.init_after_reset = mx6_init_after_reset
+};
+
+static int ehci_usb_phy_mode(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	void *__iomem addr = dev_read_addr_ptr(dev);
+	void *__iomem phy_ctrl, *__iomem phy_status;
+	const void *blob = gd->fdt_blob;
+	int offset = dev_of_offset(dev), phy_off;
+	u32 val;
+
+	/*
+	 * About fsl,usbphy, Refer to
+	 * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt.
+	 */
+	if (is_mx6() || is_mx7ulp() || is_imxrt()) {
+		phy_off = fdtdec_lookup_phandle(blob,
+						offset,
+						"fsl,usbphy");
+		if (phy_off < 0)
+			return -EINVAL;
+
+		addr = (void __iomem *)fdtdec_get_addr(blob, phy_off,
+						       "reg");
+		if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
+			return -EINVAL;
+
+		phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL);
+		val = readl(phy_ctrl);
+
+		if (val & USBPHY_CTRL_OTG_ID)
+			plat->init_type = USB_INIT_DEVICE;
+		else
+			plat->init_type = USB_INIT_HOST;
+	} else if (is_mx7()) {
+		phy_status = (void __iomem *)(addr +
+					      USBNC_PHY_STATUS_OFFSET);
+		val = readl(phy_status);
+
+		if (val & USBNC_PHYSTATUS_ID_DIG)
+			plat->init_type = USB_INIT_DEVICE;
+		else
+			plat->init_type = USB_INIT_HOST;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ehci_usb_of_to_plat(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	enum usb_dr_mode dr_mode;
+
+	dr_mode = usb_get_dr_mode(dev_ofnode(dev));
+
+	switch (dr_mode) {
+	case USB_DR_MODE_HOST:
+		plat->init_type = USB_INIT_HOST;
+		break;
+	case USB_DR_MODE_PERIPHERAL:
+		plat->init_type = USB_INIT_DEVICE;
+		break;
+	case USB_DR_MODE_OTG:
+	case USB_DR_MODE_UNKNOWN:
+		return ehci_usb_phy_mode(dev);
+	};
+
+	return 0;
+}
+
+static int mx6_parse_dt_addrs(struct udevice *dev)
+{
+#if !defined(CONFIG_PHY)
+	struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
+	int phy_off, misc_off;
+	const void *blob = gd->fdt_blob;
+	int offset = dev_of_offset(dev);
+	void *__iomem addr;
+
+	phy_off = fdtdec_lookup_phandle(blob, offset, "fsl,usbphy");
+	if (phy_off < 0) {
+		phy_off = fdtdec_lookup_phandle(blob, offset, "phys");
+		if (phy_off < 0)
+			return -EINVAL;
+	}
+
+	misc_off = fdtdec_lookup_phandle(blob, offset, "fsl,usbmisc");
+	if (misc_off < 0)
+		return -EINVAL;
+
+	addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, "reg");
+	if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
+		addr = NULL;
+
+	priv->phy_addr = addr;
+
+	addr = (void __iomem *)fdtdec_get_addr(blob, misc_off, "reg");
+	if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->misc_addr = addr;
+
+#if defined(CONFIG_MX6)
+	int anatop_off, ret, devnump;
+
+	ret = fdtdec_get_alias_seq(blob, dev->uclass->uc_drv->name,
+				   phy_off, &devnump);
+	if (ret < 0)
+		return ret;
+	priv->portnr = devnump;
+
+	/* Resolve ANATOP offset through USB PHY node */
+	anatop_off = fdtdec_lookup_phandle(blob, phy_off, "fsl,anatop");
+	if (anatop_off < 0)
+		return -EINVAL;
+
+	addr = (void __iomem *)fdtdec_get_addr(blob, anatop_off, "reg");
+	if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->anatop_addr = addr;
+#endif
+#endif
+	return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct usb_ehci *ehci = dev_read_addr_ptr(dev);
+	struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
+	enum usb_init_type type = plat->init_type;
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int ret;
+
+	if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) {
+		if (usb_fused((ulong)ehci)) {
+			printf("SoC fuse indicates USB@0x%lx is unavailable.\n",
+			       (ulong)ehci);
+			return -ENODEV;
+		}
+	}
+
+	ret = mx6_parse_dt_addrs(dev);
+	if (ret)
+		return ret;
+
+	priv->ehci = ehci;
+	priv->init_type = type;
+
+#if CONFIG_IS_ENABLED(CLK)
+	ret = clk_get_by_index(dev, 0, &priv->clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_enable(&priv->clk);
+	if (ret)
+		return ret;
+#else
+	/* Compatibility with DM_USB and !CLK */
+	enable_usboh3_clk(1);
+	mdelay(1);
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &priv->vbus_supply);
+	if (ret)
+		debug("%s: No vbus supply\n", dev->name);
+#endif
+
+#if !defined(CONFIG_PHY)
+	usb_power_config_mx6(priv->anatop_addr, priv->portnr);
+	usb_power_config_mx7(priv->misc_addr);
+	usb_power_config_mx7ulp(priv->phy_addr);
+
+	usb_oc_config(priv->misc_addr, priv->portnr);
+
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT)
+	usb_internal_phy_clock_gate(priv->phy_addr, 1);
+	usb_phy_enable(ehci, priv->phy_addr);
+#endif
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	if (priv->vbus_supply) {
+		ret = regulator_set_enable(priv->vbus_supply,
+					   (type == USB_INIT_DEVICE) ?
+					   false : true);
+		if (ret && ret != -ENOSYS) {
+			printf("Error enabling VBUS supply (ret=%i)\n", ret);
+			goto err_clk;
+		}
+	}
+#endif
+
+	if (priv->init_type == USB_INIT_HOST) {
+		setbits_le32(&ehci->usbmode, CM_HOST);
+		writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+		setbits_le32(&ehci->portsc, USB_EN);
+	}
+
+	mdelay(10);
+
+#if defined(CONFIG_PHY)
+	ret = ehci_setup_phy(dev, &priv->phy, 0);
+	if (ret)
+		goto err_regulator;
+#endif
+
+	hccr = (struct ehci_hccr *)((uintptr_t)&ehci->caplength);
+	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
+			HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
+
+	ret = ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type);
+	if (ret)
+		goto err_phy;
+
+	return ret;
+
+err_phy:
+#if defined(CONFIG_PHY)
+	ehci_shutdown_phy(dev, &priv->phy);
+err_regulator:
+#endif
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	if (priv->vbus_supply)
+		regulator_set_enable(priv->vbus_supply, false);
+err_clk:
+#endif
+#if CONFIG_IS_ENABLED(CLK)
+	clk_disable(&priv->clk);
+#else
+	/* Compatibility with DM_USB and !CLK */
+	enable_usboh3_clk(0);
+#endif
+	return ret;
+}
+
+int ehci_usb_remove(struct udevice *dev)
+{
+	struct ehci_mx6_priv_data *priv __maybe_unused = dev_get_priv(dev);
+
+	ehci_deregister(dev);
+
+#if defined(CONFIG_PHY)
+	ehci_shutdown_phy(dev, &priv->phy);
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	if (priv->vbus_supply)
+		regulator_set_enable(priv->vbus_supply, false);
+#endif
+
+#if CONFIG_IS_ENABLED(CLK)
+	clk_disable(&priv->clk);
+#endif
+
+	return 0;
+}
+
+static const struct udevice_id mx6_usb_ids[] = {
+	{ .compatible = "fsl,imx27-usb" },
+	{ .compatible = "fsl,imx7d-usb" },
+	{ .compatible = "fsl,imxrt-usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_mx6) = {
+	.name	= "ehci_mx6",
+	.id	= UCLASS_USB,
+	.of_match = mx6_usb_ids,
+	.of_to_plat = ehci_usb_of_to_plat,
+	.probe	= ehci_usb_probe,
+	.remove = ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_mx6_priv_data),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ehci-mxc.c b/roms/u-boot/drivers/usb/host/ehci-mxc.c
new file mode 100644
index 000000000..d0b7ac512
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-mxc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ */
+
+
+#include <common.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <linux/delay.h>
+#include <usb/ehci-ci.h>
+#include <errno.h>
+
+#include "ehci.h"
+
+#define USBCTRL_OTGBASE_OFFSET	0x600
+
+#define MX25_OTG_SIC_SHIFT	29
+#define MX25_OTG_SIC_MASK	(0x3 << MX25_OTG_SIC_SHIFT)
+#define MX25_OTG_PM_BIT		(1 << 24)
+#define MX25_OTG_PP_BIT		(1 << 11)
+#define MX25_OTG_OCPOL_BIT	(1 << 3)
+
+#define MX25_H1_SIC_SHIFT	21
+#define MX25_H1_SIC_MASK	(0x3 << MX25_H1_SIC_SHIFT)
+#define MX25_H1_PP_BIT		(1 << 18)
+#define MX25_H1_PM_BIT		(1 << 16)
+#define MX25_H1_IPPUE_UP_BIT	(1 << 7)
+#define MX25_H1_IPPUE_DOWN_BIT	(1 << 6)
+#define MX25_H1_TLL_BIT		(1 << 5)
+#define MX25_H1_USBTE_BIT	(1 << 4)
+#define MX25_H1_OCPOL_BIT	(1 << 2)
+
+#define MX31_OTG_SIC_SHIFT	29
+#define MX31_OTG_SIC_MASK	(0x3 << MX31_OTG_SIC_SHIFT)
+#define MX31_OTG_PM_BIT		(1 << 24)
+
+#define MX31_H2_SIC_SHIFT	21
+#define MX31_H2_SIC_MASK	(0x3 << MX31_H2_SIC_SHIFT)
+#define MX31_H2_PM_BIT		(1 << 16)
+#define MX31_H2_DT_BIT		(1 << 5)
+
+#define MX31_H1_SIC_SHIFT	13
+#define MX31_H1_SIC_MASK	(0x3 << MX31_H1_SIC_SHIFT)
+#define MX31_H1_PM_BIT		(1 << 8)
+#define MX31_H1_DT_BIT		(1 << 4)
+
+#define MX35_OTG_SIC_SHIFT	29
+#define MX35_OTG_SIC_MASK	(0x3 << MX35_OTG_SIC_SHIFT)
+#define MX35_OTG_PM_BIT		(1 << 24)
+#define MX35_OTG_PP_BIT		(1 << 11)
+#define MX35_OTG_OCPOL_BIT	(1 << 3)
+
+#define MX35_H1_SIC_SHIFT	21
+#define MX35_H1_SIC_MASK	(0x3 << MX35_H1_SIC_SHIFT)
+#define MX35_H1_PP_BIT		(1 << 18)
+#define MX35_H1_PM_BIT		(1 << 16)
+#define MX35_H1_IPPUE_UP_BIT	(1 << 7)
+#define MX35_H1_IPPUE_DOWN_BIT	(1 << 6)
+#define MX35_H1_TLL_BIT		(1 << 5)
+#define MX35_H1_USBTE_BIT	(1 << 4)
+#define MX35_H1_OCPOL_BIT	(1 << 2)
+
+static int mxc_set_usbcontrol(int port, unsigned int flags)
+{
+	unsigned int v;
+
+	v = readl(IMX_USB_BASE + USBCTRL_OTGBASE_OFFSET);
+#if defined(CONFIG_MX25)
+	switch (port) {
+	case 0:	/* OTG port */
+		v &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PM_BIT | MX25_OTG_PP_BIT |
+				MX25_OTG_OCPOL_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX25_OTG_PM_BIT;
+
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MX25_OTG_PP_BIT;
+
+		if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+			v |= MX25_OTG_OCPOL_BIT;
+
+		break;
+	case 1: /* H1 port */
+		v &= ~(MX25_H1_SIC_MASK | MX25_H1_PM_BIT | MX25_H1_PP_BIT |
+				MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
+				MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT |
+				MX25_H1_IPPUE_UP_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX25_H1_PM_BIT;
+
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MX25_H1_PP_BIT;
+
+		if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+			v |= MX25_H1_OCPOL_BIT;
+
+		if (!(flags & MXC_EHCI_TTL_ENABLED))
+			v |= MX25_H1_TLL_BIT;
+
+		if (flags & MXC_EHCI_INTERNAL_PHY)
+			v |= MX25_H1_USBTE_BIT;
+
+		if (flags & MXC_EHCI_IPPUE_DOWN)
+			v |= MX25_H1_IPPUE_DOWN_BIT;
+
+		if (flags & MXC_EHCI_IPPUE_UP)
+			v |= MX25_H1_IPPUE_UP_BIT;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+#elif defined(CONFIG_MX31)
+	switch (port) {
+	case 0:	/* OTG port */
+		v &= ~(MX31_OTG_SIC_MASK | MX31_OTG_PM_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_OTG_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX31_OTG_PM_BIT;
+
+		break;
+	case 1: /* H1 port */
+		v &= ~(MX31_H1_SIC_MASK | MX31_H1_PM_BIT | MX31_H1_DT_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_H1_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX31_H1_PM_BIT;
+
+		if (!(flags & MXC_EHCI_TTL_ENABLED))
+			v |= MX31_H1_DT_BIT;
+
+		break;
+	case 2:	/* H2 port */
+		v &= ~(MX31_H2_SIC_MASK | MX31_H2_PM_BIT | MX31_H2_DT_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_H2_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX31_H2_PM_BIT;
+
+		if (!(flags & MXC_EHCI_TTL_ENABLED))
+			v |= MX31_H2_DT_BIT;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+#elif defined(CONFIG_MX35)
+	switch (port) {
+	case 0:	/* OTG port */
+		v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT | MX35_OTG_PP_BIT |
+				MX35_OTG_OCPOL_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_OTG_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX35_OTG_PM_BIT;
+
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MX35_OTG_PP_BIT;
+
+		if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+			v |= MX35_OTG_OCPOL_BIT;
+
+		break;
+	case 1: /* H1 port */
+		v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_PP_BIT |
+				MX35_H1_OCPOL_BIT | MX35_H1_TLL_BIT |
+				MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT |
+				MX35_H1_IPPUE_UP_BIT);
+		v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_H1_SIC_SHIFT;
+
+		if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+			v |= MX35_H1_PM_BIT;
+
+		if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+			v |= MX35_H1_PP_BIT;
+
+		if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+			v |= MX35_H1_OCPOL_BIT;
+
+		if (!(flags & MXC_EHCI_TTL_ENABLED))
+			v |= MX35_H1_TLL_BIT;
+
+		if (flags & MXC_EHCI_INTERNAL_PHY)
+			v |= MX35_H1_USBTE_BIT;
+
+		if (flags & MXC_EHCI_IPPUE_DOWN)
+			v |= MX35_H1_IPPUE_DOWN_BIT;
+
+		if (flags & MXC_EHCI_IPPUE_UP)
+			v |= MX35_H1_IPPUE_UP_BIT;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+#else
+#error MXC EHCI USB driver not supported on this platform
+#endif
+	writel(v, IMX_USB_BASE + USBCTRL_OTGBASE_OFFSET);
+
+	return 0;
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	struct usb_ehci *ehci;
+#ifdef CONFIG_MX31
+	struct clock_control_regs *sc_regs =
+		(struct clock_control_regs *)CCM_BASE;
+
+	__raw_readl(&sc_regs->ccmr);
+	__raw_writel(__raw_readl(&sc_regs->ccmr) | (1 << 9), &sc_regs->ccmr) ;
+#endif
+
+	udelay(80);
+
+	ehci = (struct usb_ehci *)(IMX_USB_BASE +
+			IMX_USB_PORT_OFFSET * CONFIG_MXC_USB_PORT);
+	*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+	setbits_le32(&ehci->usbmode, CM_HOST);
+	__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS);
+#ifdef CONFIG_MX35
+	/* Workaround for ENGcm11601 */
+	__raw_writel(0, &ehci->sbuscfg);
+#endif
+
+	udelay(10000);
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-mxs.c b/roms/u-boot/drivers/usb/host/ehci-mxs.c
new file mode 100644
index 000000000..824c620e6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-mxs.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale i.MX28 USB Host driver
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <errno.h>
+#include <linux/delay.h>
+
+#include "ehci.h"
+
+/* This DIGCTL register ungates clock to USB */
+#define	HW_DIGCTL_CTRL			0x8001c000
+#define	HW_DIGCTL_CTRL_USB0_CLKGATE	(1 << 2)
+#define	HW_DIGCTL_CTRL_USB1_CLKGATE	(1 << 16)
+
+struct ehci_mxs_port {
+	uint32_t		usb_regs;
+	struct mxs_usbphy_regs	*phy_regs;
+
+	struct mxs_register_32	*pll;
+	uint32_t		pll_en_bits;
+	uint32_t		pll_dis_bits;
+	uint32_t		gate_bits;
+};
+
+static const struct ehci_mxs_port mxs_port[] = {
+#ifdef CONFIG_EHCI_MXS_PORT0
+	{
+		MXS_USBCTRL0_BASE,
+		(struct mxs_usbphy_regs *)MXS_USBPHY0_BASE,
+		(struct mxs_register_32 *)(MXS_CLKCTRL_BASE +
+			offsetof(struct mxs_clkctrl_regs,
+			hw_clkctrl_pll0ctrl0_reg)),
+		CLKCTRL_PLL0CTRL0_EN_USB_CLKS | CLKCTRL_PLL0CTRL0_POWER,
+		CLKCTRL_PLL0CTRL0_EN_USB_CLKS,
+		HW_DIGCTL_CTRL_USB0_CLKGATE,
+	},
+#endif
+#ifdef CONFIG_EHCI_MXS_PORT1
+	{
+		MXS_USBCTRL1_BASE,
+		(struct mxs_usbphy_regs *)MXS_USBPHY1_BASE,
+		(struct mxs_register_32 *)(MXS_CLKCTRL_BASE +
+			offsetof(struct mxs_clkctrl_regs,
+			hw_clkctrl_pll1ctrl0_reg)),
+		CLKCTRL_PLL1CTRL0_EN_USB_CLKS | CLKCTRL_PLL1CTRL0_POWER,
+		CLKCTRL_PLL1CTRL0_EN_USB_CLKS,
+		HW_DIGCTL_CTRL_USB1_CLKGATE,
+	},
+#endif
+};
+
+static int ehci_mxs_toggle_clock(const struct ehci_mxs_port *port, int enable)
+{
+	struct mxs_register_32 *digctl_ctrl =
+		(struct mxs_register_32 *)HW_DIGCTL_CTRL;
+	int pll_offset, dig_offset;
+
+	if (enable) {
+		pll_offset = offsetof(struct mxs_register_32, reg_set);
+		dig_offset = offsetof(struct mxs_register_32, reg_clr);
+		writel(port->gate_bits, (u32)&digctl_ctrl->reg + dig_offset);
+		writel(port->pll_en_bits, (u32)port->pll + pll_offset);
+	} else {
+		pll_offset = offsetof(struct mxs_register_32, reg_clr);
+		dig_offset = offsetof(struct mxs_register_32, reg_set);
+		writel(port->pll_dis_bits, (u32)port->pll + pll_offset);
+		writel(port->gate_bits, (u32)&digctl_ctrl->reg + dig_offset);
+	}
+
+	return 0;
+}
+
+int __weak board_ehci_hcd_init(int port)
+{
+	return 0;
+}
+
+int __weak board_ehci_hcd_exit(int port)
+{
+	return 0;
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+
+	int ret;
+	uint32_t usb_base, cap_base;
+	const struct ehci_mxs_port *port;
+
+	if ((index < 0) || (index >= ARRAY_SIZE(mxs_port))) {
+		printf("Invalid port index (index = %d)!\n", index);
+		return -EINVAL;
+	}
+
+	ret = board_ehci_hcd_init(index);
+	if (ret)
+		return ret;
+
+	port = &mxs_port[index];
+
+	/* Reset the PHY block */
+	writel(USBPHY_CTRL_SFTRST, &port->phy_regs->hw_usbphy_ctrl_set);
+	udelay(10);
+	writel(USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE,
+		&port->phy_regs->hw_usbphy_ctrl_clr);
+
+	/* Enable USB clock */
+	ret = ehci_mxs_toggle_clock(port, 1);
+	if (ret)
+		return ret;
+
+	/* Start USB PHY */
+	writel(0, &port->phy_regs->hw_usbphy_pwd);
+
+	/* Enable UTMI+ Level 2 and Level 3 compatibility */
+	writel(USBPHY_CTRL_ENUTMILEVEL3 | USBPHY_CTRL_ENUTMILEVEL2 | 1,
+		&port->phy_regs->hw_usbphy_ctrl_set);
+
+	usb_base = port->usb_regs + 0x100;
+	*hccr = (struct ehci_hccr *)usb_base;
+
+	cap_base = ehci_readl(&(*hccr)->cr_capbase);
+	*hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base));
+
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	int ret;
+	uint32_t usb_base, cap_base, tmp;
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	const struct ehci_mxs_port *port;
+
+	if ((index < 0) || (index >= ARRAY_SIZE(mxs_port))) {
+		printf("Invalid port index (index = %d)!\n", index);
+		return -EINVAL;
+	}
+
+	port = &mxs_port[index];
+
+	/* Stop the USB port */
+	usb_base = port->usb_regs + 0x100;
+	hccr = (struct ehci_hccr *)usb_base;
+	cap_base = ehci_readl(&hccr->cr_capbase);
+	hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base));
+
+	tmp = ehci_readl(&hcor->or_usbcmd);
+	tmp &= ~CMD_RUN;
+	ehci_writel(&hcor->or_usbcmd, tmp);
+
+	/* Disable the PHY */
+	tmp = USBPHY_PWD_RXPWDRX | USBPHY_PWD_RXPWDDIFF |
+		USBPHY_PWD_RXPWD1PT1 | USBPHY_PWD_RXPWDENV |
+		USBPHY_PWD_TXPWDV2I | USBPHY_PWD_TXPWDIBIAS |
+		USBPHY_PWD_TXPWDFS;
+	writel(tmp, &port->phy_regs->hw_usbphy_pwd);
+
+	/* Disable USB clock */
+	ret = ehci_mxs_toggle_clock(port, 0);
+
+	board_ehci_hcd_exit(index);
+
+	return ret;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-omap.c b/roms/u-boot/drivers/usb/host/ehci-omap.c
new file mode 100644
index 000000000..12c422d81
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-omap.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011 Ilya Yanok, Emcraft Systems
+ * (C) Copyright 2004-2008
+ * Texas Instruments, <www.ti.com>
+ *
+ * Derived from Beagle Board code by
+ *	Sunil Kumar <sunilsaini05@gmail.com>
+ *	Shashi Ranjan <shashiranjanmca05@gmail.com>
+ *
+ */
+
+#include <common.h>
+#include <log.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include <usb/ulpi.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/ehci.h>
+#include <asm/ehci-omap.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <power/regulator.h>
+
+#include "ehci.h"
+
+static struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE;
+static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE;
+static struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
+
+static int omap_uhh_reset(void)
+{
+	int timeout = 0;
+	u32 rev;
+
+	rev = readl(&uhh->rev);
+
+	/* Soft RESET */
+	writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
+
+	switch (rev) {
+	case OMAP_USBHS_REV1:
+		/* Wait for soft RESET to complete */
+		while (!(readl(&uhh->syss) & 0x1)) {
+			if (timeout > 100) {
+				printf("%s: RESET timeout\n", __func__);
+				return -1;
+			}
+			udelay(10);
+			timeout++;
+		}
+
+		/* Set No-Idle, No-Standby */
+		writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
+		break;
+
+	default:	/* Rev. 2 onwards */
+
+		udelay(2); /* Need to wait before accessing SYSCONFIG back */
+
+		/* Wait for soft RESET to complete */
+		while ((readl(&uhh->sysc) & 0x1)) {
+			if (timeout > 100) {
+				printf("%s: RESET timeout\n", __func__);
+				return -1;
+			}
+			udelay(10);
+			timeout++;
+		}
+
+		writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
+		break;
+	}
+
+	return 0;
+}
+
+static int omap_ehci_tll_reset(void)
+{
+	unsigned long init = get_timer(0);
+
+	/* perform TLL soft reset, and wait until reset is complete */
+	writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET, &usbtll->sysc);
+
+	/* Wait for TLL reset to complete */
+	while (!(readl(&usbtll->syss) & OMAP_USBTLL_SYSSTATUS_RESETDONE))
+		if (get_timer(init) > CONFIG_SYS_HZ) {
+			debug("OMAP EHCI error: timeout resetting TLL\n");
+			return -EL3RST;
+	}
+
+	return 0;
+}
+
+static void omap_usbhs_hsic_init(int port)
+{
+	unsigned int reg;
+
+	/* Enable channels now */
+	reg = readl(&usbtll->channel_conf + port);
+
+	setbits_le32(&reg, (OMAP_TLL_CHANNEL_CONF_CHANMODE_TRANSPARENT_UTMI
+		| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
+		| OMAP_TLL_CHANNEL_CONF_DRVVBUS
+		| OMAP_TLL_CHANNEL_CONF_CHRGVBUS
+		| OMAP_TLL_CHANNEL_CONF_CHANEN));
+
+	writel(reg, &usbtll->channel_conf + port);
+}
+
+#ifdef CONFIG_USB_ULPI
+static void omap_ehci_soft_phy_reset(int port)
+{
+	struct ulpi_viewport ulpi_vp;
+
+	ulpi_vp.viewport_addr = (u32)&ehci->insreg05_utmi_ulpi;
+	ulpi_vp.port_num = port;
+
+	ulpi_reset(&ulpi_vp);
+}
+#else
+static void omap_ehci_soft_phy_reset(int port)
+{
+	return;
+}
+#endif
+
+#if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \
+	defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) || \
+	defined(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO)
+/* controls PHY(s) reset signal(s) */
+static inline void omap_ehci_phy_reset(int on, int delay)
+{
+	/*
+	 * Refer ISSUE1:
+	 * Hold the PHY in RESET for enough time till
+	 * PHY is settled and ready
+	 */
+	if (delay && !on)
+		udelay(delay);
+#ifdef CONFIG_OMAP_EHCI_PHY1_RESET_GPIO
+	gpio_request(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, "USB PHY1 reset");
+	gpio_direction_output(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, !on);
+#endif
+#ifdef CONFIG_OMAP_EHCI_PHY2_RESET_GPIO
+	gpio_request(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, "USB PHY2 reset");
+	gpio_direction_output(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, !on);
+#endif
+#ifdef CONFIG_OMAP_EHCI_PHY3_RESET_GPIO
+	gpio_request(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, "USB PHY3 reset");
+	gpio_direction_output(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, !on);
+#endif
+
+	/* Hold the PHY in RESET for enough time till DIR is high */
+	/* Refer: ISSUE1 */
+	if (delay && on)
+		udelay(delay);
+}
+#else
+#define omap_ehci_phy_reset(on, delay)	do {} while (0)
+#endif
+
+/* Reset is needed otherwise the kernel-driver will throw an error. */
+int omap_ehci_hcd_stop(void)
+{
+	debug("Resetting OMAP EHCI\n");
+	omap_ehci_phy_reset(1, 0);
+
+	if (omap_uhh_reset() < 0)
+		return -1;
+
+	if (omap_ehci_tll_reset() < 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Initialize the OMAP EHCI controller and PHY.
+ * Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1
+ * See there for additional Copyrights.
+ */
+#if !CONFIG_IS_ENABLED(DM_USB) || !CONFIG_IS_ENABLED(OF_CONTROL)
+
+int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata,
+		       struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	*hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
+	*hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10);
+#else
+int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata)
+{
+#endif
+	int ret;
+	unsigned int i, reg = 0, rev = 0;
+
+	debug("Initializing OMAP EHCI\n");
+
+	ret = board_usb_init(index, USB_INIT_HOST);
+	if (ret < 0)
+		return ret;
+
+	/* Put the PHY in RESET */
+	omap_ehci_phy_reset(1, 10);
+
+	ret = omap_uhh_reset();
+	if (ret < 0)
+		return ret;
+
+	ret = omap_ehci_tll_reset();
+	if (ret)
+		return ret;
+
+	writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
+		OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
+		OMAP_USBTLL_SYSCONFIG_CACTIVITY, &usbtll->sysc);
+
+	/* Put UHH in NoIdle/NoStandby mode */
+	writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
+
+	/* setup ULPI bypass and burst configurations */
+	clrsetbits_le32(&reg, OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN,
+		(OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
+		OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN |
+		OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN));
+
+	rev = readl(&uhh->rev);
+	if (rev == OMAP_USBHS_REV1) {
+		if (is_ehci_phy_mode(usbhs_pdata->port_mode[0]))
+			clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
+		else
+			setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS);
+
+		if (is_ehci_phy_mode(usbhs_pdata->port_mode[1]))
+			clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
+		else
+			setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS);
+
+		if (is_ehci_phy_mode(usbhs_pdata->port_mode[2]))
+			clrbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
+		else
+			setbits_le32(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
+	} else if (rev == OMAP_USBHS_REV2) {
+
+		clrsetbits_le32(&reg, (OMAP_P1_MODE_CLEAR | OMAP_P2_MODE_CLEAR),
+					OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
+
+		/* Clear port mode fields for PHY mode */
+
+		if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
+			setbits_le32(&reg, OMAP_P1_MODE_HSIC);
+
+		if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
+			setbits_le32(&reg, OMAP_P2_MODE_HSIC);
+
+	} else if (rev == OMAP_USBHS_REV2_1) {
+
+		clrsetbits_le32(&reg,
+				(OMAP_P1_MODE_CLEAR |
+				 OMAP_P2_MODE_CLEAR |
+				 OMAP_P3_MODE_CLEAR),
+				OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
+
+		/* Clear port mode fields for PHY mode */
+
+		if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
+			setbits_le32(&reg, OMAP_P1_MODE_HSIC);
+
+		if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
+			setbits_le32(&reg, OMAP_P2_MODE_HSIC);
+
+		if (is_ehci_hsic_mode(usbhs_pdata->port_mode[2]))
+			setbits_le32(&reg, OMAP_P3_MODE_HSIC);
+	}
+
+	debug("OMAP UHH_REVISION 0x%x\n", rev);
+	writel(reg, &uhh->hostconfig);
+
+	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
+		if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i]))
+			omap_usbhs_hsic_init(i);
+
+	omap_ehci_phy_reset(0, 10);
+
+	/*
+	 * An undocumented "feature" in the OMAP3 EHCI controller,
+	 * causes suspended ports to be taken out of suspend when
+	 * the USBCMD.Run/Stop bit is cleared (for example when
+	 * we do ehci_bus_suspend).
+	 * This breaks suspend-resume if the root-hub is allowed
+	 * to suspend. Writing 1 to this undocumented register bit
+	 * disables this feature and restores normal behavior.
+	 */
+	writel(EHCI_INSNREG04_DISABLE_UNSUSPEND, &ehci->insreg04);
+
+	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
+		if (is_ehci_phy_mode(usbhs_pdata->port_mode[i]))
+			omap_ehci_soft_phy_reset(i);
+
+	debug("OMAP EHCI init done\n");
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+
+static struct omap_usbhs_board_data usbhs_bdata = {
+	.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
+	.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
+	.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
+};
+
+static void omap_usbhs_set_mode(u8 index, const char *mode)
+{
+	if (!strcmp(mode, "ehci-phy"))
+		usbhs_bdata.port_mode[index] = OMAP_EHCI_PORT_MODE_PHY;
+	else if (!strcmp(mode, "ehci-tll"))
+		usbhs_bdata.port_mode[index] = OMAP_EHCI_PORT_MODE_TLL;
+	else if (!strcmp(mode, "ehci-hsic"))
+		usbhs_bdata.port_mode[index] = OMAP_EHCI_PORT_MODE_HSIC;
+}
+
+static int omap_usbhs_probe(struct udevice *dev)
+{
+	u8 i;
+	const char *mode;
+	char prop[11];
+
+	/* Go through each port portX-mode to determing phy mode */
+	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
+		snprintf(prop, sizeof(prop), "port%d-mode", i + 1);
+		mode = dev_read_string(dev, prop);
+
+		/* If the portX-mode exists, set the mode */
+		if (mode)
+			omap_usbhs_set_mode(i, mode);
+	}
+
+	return omap_ehci_hcd_init(0, &usbhs_bdata);
+}
+
+static const struct udevice_id omap_usbhs_dt_ids[] = {
+	{ .compatible = "ti,usbhs-host" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_omaphs_host) = {
+	.name	= "usbhs-host",
+	.id	= UCLASS_SIMPLE_BUS,
+	.of_match = omap_usbhs_dt_ids,
+	.probe	= omap_usbhs_probe,
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+struct ehci_omap_priv_data {
+	struct ehci_ctrl ctrl;
+	struct omap_ehci *ehci;
+#ifdef CONFIG_DM_REGULATOR
+	struct udevice *vbus_supply;
+#endif
+	enum usb_init_type init_type;
+	int portnr;
+	struct phy phy[OMAP_HS_USB_PORTS];
+	int nports;
+};
+
+static int ehci_usb_of_to_plat(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+
+	plat->init_type = USB_INIT_HOST;
+
+	return 0;
+}
+
+static int omap_ehci_probe(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct ehci_omap_priv_data *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+
+	priv->ehci = dev_read_addr_ptr(dev);
+	priv->portnr = dev_seq(dev);
+	priv->init_type = plat->init_type;
+
+	hccr = (struct ehci_hccr *)&priv->ehci->hccapbase;
+	hcor = (struct ehci_hcor *)&priv->ehci->usbcmd;
+
+	return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static const struct udevice_id omap_ehci_dt_ids[] = {
+	{ .compatible = "ti,ehci-omap" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_omap_ehci) = {
+	.name	= "omap-ehci",
+	.id	= UCLASS_USB,
+	.of_match = omap_ehci_dt_ids,
+	.probe = omap_ehci_probe,
+	.of_to_plat = ehci_usb_of_to_plat,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_omap_priv_data),
+	.remove = ehci_deregister,
+	.ops	= &ehci_usb_ops,
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ehci-pci.c b/roms/u-boot/drivers/usb/host/ehci-pci.c
new file mode 100644
index 000000000..4f711de7d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-pci.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * All rights reserved.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <pci.h>
+#include <usb.h>
+#include <asm/io.h>
+
+#include "ehci.h"
+
+/* Information about a USB port */
+struct ehci_pci_priv {
+	struct ehci_ctrl ehci;
+	struct phy phy;
+};
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ehci_pci_init(struct udevice *dev, struct ehci_hccr **ret_hccr,
+			  struct ehci_hcor **ret_hcor)
+{
+	struct ehci_pci_priv *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int ret;
+	u32 cmd;
+
+	ret = ehci_setup_phy(dev, &priv->phy, 0);
+	if (ret)
+		return ret;
+
+	hccr = (struct ehci_hccr *)dm_pci_map_bar(dev,
+			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	hcor = (struct ehci_hcor *)((uintptr_t) hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	debug("EHCI-PCI init hccr %#lx and hcor %#lx hc_length %d\n",
+	      (ulong)hccr, (ulong)hcor,
+	      (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	/* enable busmaster */
+	dm_pci_read_config32(dev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	dm_pci_write_config32(dev, PCI_COMMAND, cmd);
+
+	return 0;
+}
+
+#else
+
+#ifdef CONFIG_PCI_EHCI_DEVICE
+static struct pci_device_id ehci_pci_ids[] = {
+	/* Please add supported PCI EHCI controller ids here */
+	{0x1033, 0x00E0},	/* NEC */
+	{0x10B9, 0x5239},	/* ULI1575 PCI EHCI module ids */
+	{0x12D8, 0x400F},	/* Pericom */
+	{0, 0}
+};
+#endif
+
+static void ehci_pci_legacy_init(pci_dev_t pdev, struct ehci_hccr **ret_hccr,
+				 struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	u32 cmd;
+
+	hccr = (struct ehci_hccr *)pci_map_bar(pdev,
+			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	hcor = (struct ehci_hcor *)((uintptr_t) hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
+	      (u32)hccr, (u32)hcor,
+	      (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	/* enable busmaster */
+	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	pci_write_config_dword(pdev, PCI_COMMAND, cmd);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
+{
+	pci_dev_t pdev;
+
+#ifdef CONFIG_PCI_EHCI_DEVICE
+	pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
+#else
+	pdev = pci_find_class(PCI_CLASS_SERIAL_USB_EHCI, index);
+#endif
+	if (pdev < 0) {
+		printf("EHCI host controller not found\n");
+		return -1;
+	}
+	ehci_pci_legacy_init(pdev, ret_hccr, ret_hcor);
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+#endif /* !CONFIG_IS_ENABLED(DM_USB) */
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ehci_pci_probe(struct udevice *dev)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int ret;
+
+	ret = ehci_pci_init(dev, &hccr, &hcor);
+	if (ret)
+		return ret;
+
+	return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_pci_remove(struct udevice *dev)
+{
+	struct ehci_pci_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	return ehci_shutdown_phy(dev, &priv->phy);
+}
+
+static const struct udevice_id ehci_pci_ids[] = {
+	{ .compatible = "ehci-pci" },
+	{ }
+};
+
+U_BOOT_DRIVER(ehci_pci) = {
+	.name	= "ehci_pci",
+	.id	= UCLASS_USB,
+	.probe = ehci_pci_probe,
+	.remove = ehci_pci_remove,
+	.of_match = ehci_pci_ids,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_pci_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static struct pci_device_id ehci_pci_supported[] = {
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(ehci_pci, ehci_pci_supported);
+
+#endif /* CONFIG_IS_ENABLED(DM_USB) */
diff --git a/roms/u-boot/drivers/usb/host/ehci-rmobile.c b/roms/u-boot/drivers/usb/host/ehci-rmobile.c
new file mode 100644
index 000000000..130b73dfe
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-rmobile.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  EHCI HCD (Host Controller Driver) for USB.
+ *
+ *  Copyright (C) 2013,2014 Renesas Electronics Corporation
+ *  Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/ehci-rmobile.h>
+#include <linux/delay.h>
+#include "ehci.h"
+
+#if defined(CONFIG_R8A7740)
+static u32 usb_base_address[] = {
+	0xC6700000
+};
+#elif defined(CONFIG_R8A7790)
+static u32 usb_base_address[] = {
+	0xEE080000,	/* USB0 (EHCI) */
+	0xEE0A0000,	/* USB1 */
+	0xEE0C0000,	/* USB2 */
+};
+#elif defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \
+	defined(CONFIG_R8A7794)
+static u32 usb_base_address[] = {
+	0xEE080000,	/* USB0 (EHCI) */
+	0xEE0C0000,	/* USB1 */
+};
+#else
+#error rmobile EHCI USB driver not supported on this platform
+#endif
+
+int ehci_hcd_stop(int index)
+{
+	int i;
+	u32 base;
+	struct ahbcom_pci_bridge *ahbcom_pci;
+
+	base = usb_base_address[index];
+	ahbcom_pci = (struct ahbcom_pci_bridge *)(base + AHBPCI_OFFSET);
+	writel(0, &ahbcom_pci->ahb_bus_ctr);
+
+	/* reset ehci */
+	setbits_le32(base + EHCI_USBCMD, CMD_RESET);
+	for (i = 100; i > 0; i--) {
+		if (!(readl(base + EHCI_USBCMD) & CMD_RESET))
+			break;
+		udelay(100);
+	}
+
+	if (!i)
+		printf("error : ehci(%d) reset failed.\n", index);
+
+	if (index == (ARRAY_SIZE(usb_base_address) - 1))
+		setbits_le32(SMSTPCR7, SMSTPCR703);
+
+	return 0;
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+	struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	u32 base;
+	u32 phys_base;
+	struct rmobile_ehci_reg *rehci;
+	struct ahbcom_pci_bridge *ahbcom_pci;
+	struct ahbconf_pci_bridge *ahbconf_pci;
+	struct ahb_pciconf *ahb_pciconf_ohci;
+	struct ahb_pciconf *ahb_pciconf_ehci;
+	uint32_t cap_base;
+
+	base = usb_base_address[index];
+	phys_base = base;
+	if (index == 0)
+		clrbits_le32(SMSTPCR7, SMSTPCR703);
+
+	rehci = (struct rmobile_ehci_reg *)(base + EHCI_OFFSET);
+	ahbcom_pci = (struct ahbcom_pci_bridge *)(base + AHBPCI_OFFSET);
+	ahbconf_pci =
+		(struct ahbconf_pci_bridge *)(base + PCI_CONF_AHBPCI_OFFSET);
+	ahb_pciconf_ohci = (struct ahb_pciconf *)(base + PCI_CONF_OHCI_OFFSET);
+	ahb_pciconf_ehci = (struct ahb_pciconf *)(base + PCI_CONF_EHCI_OFFSET);
+
+	/* Clock & Reset & Direct Power Down */
+	clrsetbits_le32(&ahbcom_pci->usbctr,
+			(DIRPD | PCICLK_MASK | USBH_RST), USBCTR_WIN_SIZE_1GB);
+	clrbits_le32(&ahbcom_pci->usbctr, PLL_RST);
+
+	/* AHB-PCI Bridge Communication Registers */
+	writel(AHB_BUS_CTR_INIT, &ahbcom_pci->ahb_bus_ctr);
+	writel((CONFIG_SYS_SDRAM_BASE & 0xf0000000) | PCIAHB_WIN_PREFETCH,
+	       &ahbcom_pci->pciahb_win1_ctr);
+	writel(0xf0000000 | PCIAHB_WIN_PREFETCH,
+	       &ahbcom_pci->pciahb_win2_ctr);
+	writel(phys_base | PCIWIN2_PCICMD, &ahbcom_pci->ahbpci_win2_ctr);
+
+	setbits_le32(&ahbcom_pci->pci_arbiter_ctr,
+		     PCIBP_MODE | PCIREQ1 | PCIREQ0);
+
+	/* PCI Configuration Registers for AHBPCI */
+	writel(PCIWIN1_PCICMD | AHB_CFG_AHBPCI,
+	       &ahbcom_pci->ahbpci_win1_ctr);
+	writel(phys_base + AHBPCI_OFFSET, &ahbconf_pci->basead);
+	writel(CONFIG_SYS_SDRAM_BASE & 0xf0000000, &ahbconf_pci->win1_basead);
+	writel(0xf0000000, &ahbconf_pci->win2_basead);
+	writel(SERREN | PERREN | MASTEREN | MEMEN,
+	       &ahbconf_pci->cmnd_sts);
+
+	/* PCI Configuration Registers for EHCI */
+	writel(PCIWIN1_PCICMD | AHB_CFG_HOST, &ahbcom_pci->ahbpci_win1_ctr);
+	writel(phys_base + OHCI_OFFSET, &ahb_pciconf_ohci->basead);
+	writel(phys_base + EHCI_OFFSET, &ahb_pciconf_ehci->basead);
+	writel(SERREN | PERREN | MASTEREN | MEMEN,
+	       &ahb_pciconf_ohci->cmnd_sts);
+	writel(SERREN | PERREN | MASTEREN | MEMEN,
+	       &ahb_pciconf_ehci->cmnd_sts);
+
+	/* Enable PCI interrupt */
+	setbits_le32(&ahbcom_pci->pci_int_enable,
+		     USBH_PMEEN | USBH_INTBEN | USBH_INTAEN);
+
+	*hccr = (struct ehci_hccr *)((uint32_t)&rehci->hciversion);
+	cap_base = ehci_readl(&(*hccr)->cr_capbase);
+	*hcor = (struct ehci_hcor *)((uint32_t)*hccr + HC_LENGTH(cap_base));
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-spear.c b/roms/u-boot/drivers/usb/host/ehci-spear.c
new file mode 100644
index 000000000..3e87e0c7f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-spear.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Armando Visconti, ST Micoelectronics, <armando.visconti@st.com>.
+ *
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include "ehci.h"
+#include <asm/arch/hardware.h>
+#include <asm/arch/spr_misc.h>
+
+static void spear6xx_usbh_stop(void)
+{
+	struct misc_regs *const misc_p =
+	    (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
+	u32 periph1_rst = readl(misc_p->periph1_rst);
+
+	periph1_rst |= PERIPH_USBH1 | PERIPH_USBH2;
+	writel(periph1_rst, misc_p->periph1_rst);
+
+	udelay(1000);
+	periph1_rst &= ~(PERIPH_USBH1 | PERIPH_USBH2);
+	writel(periph1_rst, misc_p->periph1_rst);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	u32 ehci = 0;
+
+	switch (index) {
+	case 0:
+		ehci = CONFIG_SYS_UHC0_EHCI_BASE;
+		break;
+	case 1:
+		ehci = CONFIG_SYS_UHC1_EHCI_BASE;
+		break;
+	default:
+		printf("ERROR: wrong controller index!\n");
+		break;
+	};
+
+	*hccr = (struct ehci_hccr *)(ehci + 0x100);
+	*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	debug("SPEAr-ehci: init hccr %x and hcor %x hc_length %d\n",
+		(uint32_t)*hccr, (uint32_t)*hcor,
+		(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+#if defined(CONFIG_SPEAR600)
+	spear6xx_usbh_stop();
+#endif
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-tegra.c b/roms/u-boot/drivers/usb/host/ehci-tegra.c
new file mode 100644
index 000000000..b02ee89c3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-tegra.c
@@ -0,0 +1,871 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (c) 2009-2015 NVIDIA Corporation
+ * Copyright (c) 2013 Lucas Stach
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/usb.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <usb.h>
+#include <usb/ulpi.h>
+#include <linux/libfdt.h>
+
+#include "ehci.h"
+
+#define USB1_ADDR_MASK	0xFFFF0000
+
+#define HOSTPC1_DEVLC	0x84
+#define HOSTPC1_PSPD(x)		(((x) >> 25) & 0x3)
+
+#ifdef CONFIG_USB_ULPI
+	#ifndef CONFIG_USB_ULPI_VIEWPORT
+	#error	"To use CONFIG_USB_ULPI on Tegra Boards you have to also \
+		define CONFIG_USB_ULPI_VIEWPORT"
+	#endif
+#endif
+
+/* Parameters we need for USB */
+enum {
+	PARAM_DIVN,                     /* PLL FEEDBACK DIVIDer */
+	PARAM_DIVM,                     /* PLL INPUT DIVIDER */
+	PARAM_DIVP,                     /* POST DIVIDER (2^N) */
+	PARAM_CPCON,                    /* BASE PLLC CHARGE Pump setup ctrl */
+	PARAM_LFCON,                    /* BASE PLLC LOOP FILter setup ctrl */
+	PARAM_ENABLE_DELAY_COUNT,       /* PLL-U Enable Delay Count */
+	PARAM_STABLE_COUNT,             /* PLL-U STABLE count */
+	PARAM_ACTIVE_DELAY_COUNT,       /* PLL-U Active delay count */
+	PARAM_XTAL_FREQ_COUNT,          /* PLL-U XTAL frequency count */
+	PARAM_DEBOUNCE_A_TIME,          /* 10MS DELAY for BIAS_DEBOUNCE_A */
+	PARAM_BIAS_TIME,                /* 20US DELAY AFter bias cell op */
+
+	PARAM_COUNT
+};
+
+/* Possible port types (dual role mode) */
+enum dr_mode {
+	DR_MODE_NONE = 0,
+	DR_MODE_HOST,		/* supports host operation */
+	DR_MODE_DEVICE,		/* supports device operation */
+	DR_MODE_OTG,		/* supports both */
+};
+
+enum usb_ctlr_type {
+	USB_CTLR_T20,
+	USB_CTLR_T30,
+	USB_CTLR_T114,
+	USB_CTLR_T210,
+
+	USB_CTRL_COUNT,
+};
+
+/* Information about a USB port */
+struct fdt_usb {
+	struct ehci_ctrl ehci;
+	struct usb_ctlr *reg;	/* address of registers in physical memory */
+	unsigned utmi:1;	/* 1 if port has external tranceiver, else 0 */
+	unsigned ulpi:1;	/* 1 if port has external ULPI transceiver */
+	unsigned enabled:1;	/* 1 to enable, 0 to disable */
+	unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
+	enum usb_ctlr_type type;
+	enum usb_init_type init_type;
+	enum dr_mode dr_mode;	/* dual role mode */
+	enum periph_id periph_id;/* peripheral id */
+	struct gpio_desc vbus_gpio;	/* GPIO for vbus enable */
+	struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
+};
+
+/*
+ * This table has USB timing parameters for each Oscillator frequency we
+ * support. There are four sets of values:
+ *
+ * 1. PLLU configuration information (reference clock is osc/clk_m and
+ * PLLU-FOs are fixed at 12MHz/60MHz/480MHz).
+ *
+ *  Reference frequency     13.0MHz      19.2MHz      12.0MHz      26.0MHz
+ *  ----------------------------------------------------------------------
+ *      DIVN                960 (0x3c0)  200 (0c8)    960 (3c0h)   960 (3c0)
+ *      DIVM                13 (0d)      4 (04)       12 (0c)      26 (1a)
+ * Filter frequency (MHz)   1            4.8          6            2
+ * CPCON                    1100b        0011b        1100b        1100b
+ * LFCON0                   0            0            0            0
+ *
+ * 2. PLL CONFIGURATION & PARAMETERS for different clock generators:
+ *
+ * Reference frequency     13.0MHz         19.2MHz         12.0MHz     26.0MHz
+ * ---------------------------------------------------------------------------
+ * PLLU_ENABLE_DLY_COUNT   02 (0x02)       03 (03)         02 (02)     04 (04)
+ * PLLU_STABLE_COUNT       51 (33)         75 (4B)         47 (2F)    102 (66)
+ * PLL_ACTIVE_DLY_COUNT    05 (05)         06 (06)         04 (04)     09 (09)
+ * XTAL_FREQ_COUNT        127 (7F)        187 (BB)        118 (76)    254 (FE)
+ *
+ * 3. Debounce values IdDig, Avalid, Bvalid, VbusValid, VbusWakeUp, and
+ * SessEnd. Each of these signals have their own debouncer and for each of
+ * those one out of two debouncing times can be chosen (BIAS_DEBOUNCE_A or
+ * BIAS_DEBOUNCE_B).
+ *
+ * The values of DEBOUNCE_A and DEBOUNCE_B are calculated as follows:
+ *    0xffff -> No debouncing at all
+ *    <n> ms = <n> *1000 / (1/19.2MHz) / 4
+ *
+ * So to program a 1 ms debounce for BIAS_DEBOUNCE_A, we have:
+ * BIAS_DEBOUNCE_A[15:0] = 1000 * 19.2 / 4  = 4800 = 0x12c0
+ *
+ * We need to use only DebounceA for BOOTROM. We don't need the DebounceB
+ * values, so we can keep those to default.
+ *
+ * 4. The 20 microsecond delay after bias cell operation.
+ */
+static const unsigned T20_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
+	{ 0x3C0, 0x0D, 0x00, 0xC,   0,  0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   0,  0x02, 0x2F, 0x04, 0x76, 0x7530, 5 },
+	{ 0x3C0, 0x1A, 0x00, 0xC,   0,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 }
+};
+
+static const unsigned T30_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
+	{ 0x3C0, 0x0D, 0x00, 0xC,   1,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 5 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 7 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   1,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
+	{ 0x3C0, 0x1A, 0x00, 0xC,   1,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 }
+};
+
+static const unsigned T114_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
+	{ 0x3C0, 0x0D, 0x00, 0xC,   2,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 6 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   2,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 8 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   2,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
+	{ 0x3C0, 0x1A, 0x00, 0xC,   2,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 11 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 },
+	{ 0x000, 0x00, 0x00, 0x0,   0,  0x00, 0x00, 0x00, 0x00, 0x0000, 0 }
+};
+
+/* NOTE: 13/26MHz settings are N/A for T210, so dupe 12MHz settings for now */
+static const unsigned T210_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+	/* DivN, DivM, DivP, KCP,   KVCO,  Delays              Debounce, Bias */
+	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  32500,  5 },
+	{ 0x019, 0x01, 0x01, 0x0,   0,  0x03, 0x4B, 0x0C, 0xBB,  48000,  8 },
+	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  30000,  5 },
+	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  65000,  5 },
+	{ 0x019, 0x02, 0x01, 0x0,   0,  0x05, 0x96, 0x18, 0x177, 96000, 15 },
+	{ 0x028, 0x04, 0x01, 0x0,   0,  0x04, 0x66, 0x09, 0xFE, 120000, 20 }
+};
+
+/* UTMIP Idle Wait Delay */
+static const u8 utmip_idle_wait_delay = 17;
+
+/* UTMIP Elastic limit */
+static const u8 utmip_elastic_limit = 16;
+
+/* UTMIP High Speed Sync Start Delay */
+static const u8 utmip_hs_sync_start_delay = 9;
+
+struct fdt_usb_controller {
+	/* flag to determine whether controller supports hostpc register */
+	u32 has_hostpc:1;
+	const unsigned *pll_parameter;
+};
+
+static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
+	{
+		.has_hostpc	= 0,
+		.pll_parameter	= (const unsigned *)T20_usb_pll,
+	},
+	{
+		.has_hostpc	= 1,
+		.pll_parameter	= (const unsigned *)T30_usb_pll,
+	},
+	{
+		.has_hostpc	= 1,
+		.pll_parameter	= (const unsigned *)T114_usb_pll,
+	},
+	{
+		.has_hostpc	= 1,
+		.pll_parameter	= (const unsigned *)T210_usb_pll,
+	},
+};
+
+/*
+ * A known hardware issue where Connect Status Change bit of PORTSC register
+ * of USB1 controller will be set after Port Reset.
+ * We have to clear it in order for later device enumeration to proceed.
+ */
+static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
+				     uint32_t *status_reg, uint32_t *reg)
+{
+	struct fdt_usb *config = ctrl->priv;
+	struct fdt_usb_controller *controller;
+
+	controller = &fdt_usb_controllers[config->type];
+	mdelay(50);
+	/* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */
+	if (controller->has_hostpc)
+		*reg |= EHCI_PS_PE;
+
+	if (!config->has_legacy_mode)
+		return;
+	/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */
+	if (ehci_readl(status_reg) & EHCI_PS_CSC)
+		*reg |= EHCI_PS_CSC;
+}
+
+static void tegra_ehci_set_usbmode(struct ehci_ctrl *ctrl)
+{
+	struct fdt_usb *config = ctrl->priv;
+	struct usb_ctlr *usbctlr;
+	uint32_t tmp;
+
+	usbctlr = config->reg;
+
+	tmp = ehci_readl(&usbctlr->usb_mode);
+	tmp |= USBMODE_CM_HC;
+	ehci_writel(&usbctlr->usb_mode, tmp);
+}
+
+static int tegra_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+{
+	struct fdt_usb *config = ctrl->priv;
+	struct fdt_usb_controller *controller;
+	uint32_t tmp;
+	uint32_t *reg_ptr;
+
+	controller = &fdt_usb_controllers[config->type];
+	if (controller->has_hostpc) {
+		reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd +
+				HOSTPC1_DEVLC);
+		tmp = ehci_readl(reg_ptr);
+		return HOSTPC1_PSPD(tmp);
+	} else
+		return PORTSC_PSPD(reg);
+}
+
+/* Set up VBUS for host/device mode */
+static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
+{
+	/*
+	 * If we are an OTG port initializing in host mode,
+	 * check if remote host is driving VBus and bail out in this case.
+	 */
+	if (init == USB_INIT_HOST &&
+	    config->dr_mode == DR_MODE_OTG &&
+	    (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS)) {
+		printf("tegrausb: VBUS input active; not enabling as host\n");
+		return;
+	}
+
+	if (dm_gpio_is_valid(&config->vbus_gpio)) {
+		int vbus_value;
+
+		vbus_value = (init == USB_INIT_HOST);
+		dm_gpio_set_value(&config->vbus_gpio, vbus_value);
+
+		debug("set_up_vbus: GPIO %d %d\n",
+		      gpio_get_number(&config->vbus_gpio), vbus_value);
+	}
+}
+
+static void usbf_reset_controller(struct fdt_usb *config,
+				  struct usb_ctlr *usbctlr)
+{
+	/* Reset the USB controller with 2us delay */
+	reset_periph(config->periph_id, 2);
+
+	/*
+	 * Set USB1_NO_LEGACY_MODE to 1, Registers are accessible under
+	 * base address
+	 */
+	if (config->has_legacy_mode)
+		setbits_le32(&usbctlr->usb1_legacy_ctrl, USB1_NO_LEGACY_MODE);
+
+	/* Put UTMIP1/3 in reset */
+	setbits_le32(&usbctlr->susp_ctrl, UTMIP_RESET);
+
+	/* Enable the UTMIP PHY */
+	if (config->utmi)
+		setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB);
+}
+
+static const unsigned *get_pll_timing(struct fdt_usb_controller *controller)
+{
+	const unsigned *timing;
+
+	timing = controller->pll_parameter +
+		clock_get_osc_freq() * PARAM_COUNT;
+
+	return timing;
+}
+
+/* select the PHY to use with a USB controller */
+static void init_phy_mux(struct fdt_usb *config, uint pts,
+			 enum usb_init_type init)
+{
+	struct usb_ctlr *usbctlr = config->reg;
+
+#if defined(CONFIG_TEGRA20)
+	if (config->periph_id == PERIPH_ID_USBD) {
+		clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
+				pts << PTS1_SHIFT);
+		clrbits_le32(&usbctlr->port_sc1, STS1);
+	} else {
+		clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
+				pts << PTS_SHIFT);
+		clrbits_le32(&usbctlr->port_sc1, STS);
+	}
+#else
+	/* Set to Host mode (if applicable) after Controller Reset was done */
+	clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC,
+			(init == USB_INIT_HOST) ? USBMODE_CM_HC : 0);
+	/*
+	 * Select PHY interface after setting host mode.
+	 * For device mode, the ordering requirement is not an issue, since
+	 * only the first USB controller supports device mode, and that USB
+	 * controller can only talk to a UTMI PHY, so the PHY selection is
+	 * already made at reset time, so this write is a no-op.
+	 */
+	clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
+			pts << PTS_SHIFT);
+	clrbits_le32(&usbctlr->hostpc1_devlc, STS);
+#endif
+}
+
+/* set up the UTMI USB controller with the parameters provided */
+static int init_utmi_usb_controller(struct fdt_usb *config,
+				    enum usb_init_type init)
+{
+	struct fdt_usb_controller *controller;
+	u32 b_sess_valid_mask, val;
+	int loop_count;
+	const unsigned *timing;
+	struct usb_ctlr *usbctlr = config->reg;
+	struct clk_rst_ctlr *clkrst;
+	struct usb_ctlr *usb1ctlr;
+
+	clock_enable(config->periph_id);
+
+	/* Reset the usb controller */
+	usbf_reset_controller(config, usbctlr);
+
+	/* Stop crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN low */
+	clrbits_le32(&usbctlr->utmip_misc_cfg1, UTMIP_PHY_XTAL_CLOCKEN);
+
+	/* Follow the crystal clock disable by >100ns delay */
+	udelay(1);
+
+	b_sess_valid_mask = (VBUS_B_SESS_VLD_SW_VALUE | VBUS_B_SESS_VLD_SW_EN);
+	clrsetbits_le32(&usbctlr->phy_vbus_sensors, b_sess_valid_mask,
+			(init == USB_INIT_DEVICE) ? b_sess_valid_mask : 0);
+
+	/*
+	 * To Use the A Session Valid for cable detection logic, VBUS_WAKEUP
+	 * mux must be switched to actually use a_sess_vld threshold.
+	 */
+	if (config->dr_mode == DR_MODE_OTG &&
+	    dm_gpio_is_valid(&config->vbus_gpio))
+		clrsetbits_le32(&usbctlr->usb1_legacy_ctrl,
+			VBUS_SENSE_CTL_MASK,
+			VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
+
+	controller = &fdt_usb_controllers[config->type];
+	debug("controller=%p, type=%d\n", controller, config->type);
+
+	/*
+	 * PLL Delay CONFIGURATION settings. The following parameters control
+	 * the bring up of the plls.
+	 */
+	timing = get_pll_timing(controller);
+
+	if (!controller->has_hostpc) {
+		val = readl(&usbctlr->utmip_misc_cfg1);
+		clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK,
+				timing[PARAM_STABLE_COUNT] <<
+				UTMIP_PLLU_STABLE_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK,
+				timing[PARAM_ACTIVE_DELAY_COUNT] <<
+				UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT);
+		writel(val, &usbctlr->utmip_misc_cfg1);
+
+		/* Set PLL enable delay count and crystal frequency count */
+		val = readl(&usbctlr->utmip_pll_cfg1);
+		clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK,
+				timing[PARAM_ENABLE_DELAY_COUNT] <<
+				UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK,
+				timing[PARAM_XTAL_FREQ_COUNT] <<
+				UTMIP_XTAL_FREQ_COUNT_SHIFT);
+		writel(val, &usbctlr->utmip_pll_cfg1);
+	} else {
+		clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+		val = readl(&clkrst->crc_utmip_pll_cfg2);
+		clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK,
+				timing[PARAM_STABLE_COUNT] <<
+				UTMIP_PLLU_STABLE_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK,
+				timing[PARAM_ACTIVE_DELAY_COUNT] <<
+				UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT);
+		writel(val, &clkrst->crc_utmip_pll_cfg2);
+
+		/* Set PLL enable delay count and crystal frequency count */
+		val = readl(&clkrst->crc_utmip_pll_cfg1);
+		clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK,
+				timing[PARAM_ENABLE_DELAY_COUNT] <<
+				UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK,
+				timing[PARAM_XTAL_FREQ_COUNT] <<
+				UTMIP_XTAL_FREQ_COUNT_SHIFT);
+		writel(val, &clkrst->crc_utmip_pll_cfg1);
+
+		/* Disable Power Down state for PLL */
+		clrbits_le32(&clkrst->crc_utmip_pll_cfg1,
+			     PLLU_POWERDOWN | PLL_ENABLE_POWERDOWN |
+			     PLL_ACTIVE_POWERDOWN);
+
+		/* Recommended PHY settings for EYE diagram */
+		val = readl(&usbctlr->utmip_xcvr_cfg0);
+		clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MASK,
+				0x4 << UTMIP_XCVR_SETUP_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB_MASK,
+				0x3 << UTMIP_XCVR_SETUP_MSB_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB_MASK,
+				0x8 << UTMIP_XCVR_HSSLEW_MSB_SHIFT);
+		writel(val, &usbctlr->utmip_xcvr_cfg0);
+		clrsetbits_le32(&usbctlr->utmip_xcvr_cfg1,
+				UTMIP_XCVR_TERM_RANGE_ADJ_MASK,
+				0x7 << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT);
+
+		/* Some registers can be controlled from USB1 only. */
+		if (config->periph_id != PERIPH_ID_USBD) {
+			clock_enable(PERIPH_ID_USBD);
+			/* Disable Reset if in Reset state */
+			reset_set_enable(PERIPH_ID_USBD, 0);
+		}
+		usb1ctlr = (struct usb_ctlr *)
+			((unsigned long)config->reg & USB1_ADDR_MASK);
+		val = readl(&usb1ctlr->utmip_bias_cfg0);
+		setbits_le32(&val, UTMIP_HSDISCON_LEVEL_MSB);
+		clrsetbits_le32(&val, UTMIP_HSDISCON_LEVEL_MASK,
+				0x1 << UTMIP_HSDISCON_LEVEL_SHIFT);
+		clrsetbits_le32(&val, UTMIP_HSSQUELCH_LEVEL_MASK,
+				0x2 << UTMIP_HSSQUELCH_LEVEL_SHIFT);
+		writel(val, &usb1ctlr->utmip_bias_cfg0);
+
+		/* Miscellaneous setting mentioned in Programming Guide */
+		clrbits_le32(&usbctlr->utmip_misc_cfg0,
+			     UTMIP_SUSPEND_EXIT_ON_EDGE);
+	}
+
+	/* Setting the tracking length time */
+	clrsetbits_le32(&usbctlr->utmip_bias_cfg1,
+		UTMIP_BIAS_PDTRK_COUNT_MASK,
+		timing[PARAM_BIAS_TIME] << UTMIP_BIAS_PDTRK_COUNT_SHIFT);
+
+	/* Program debounce time for VBUS to become valid */
+	clrsetbits_le32(&usbctlr->utmip_debounce_cfg0,
+		UTMIP_DEBOUNCE_CFG0_MASK,
+		timing[PARAM_DEBOUNCE_A_TIME] << UTMIP_DEBOUNCE_CFG0_SHIFT);
+
+	if (timing[PARAM_DEBOUNCE_A_TIME] > 0xFFFF) {
+		clrsetbits_le32(&usbctlr->utmip_debounce_cfg0,
+				UTMIP_DEBOUNCE_CFG0_MASK,
+				(timing[PARAM_DEBOUNCE_A_TIME] >> 1)
+				<< UTMIP_DEBOUNCE_CFG0_SHIFT);
+		clrsetbits_le32(&usbctlr->utmip_bias_cfg1,
+				UTMIP_BIAS_DEBOUNCE_TIMESCALE_MASK,
+				1 << UTMIP_BIAS_DEBOUNCE_TIMESCALE_SHIFT);
+	}
+
+	setbits_le32(&usbctlr->utmip_tx_cfg0, UTMIP_FS_PREAMBLE_J);
+
+	/* Disable battery charge enabling bit */
+	setbits_le32(&usbctlr->utmip_bat_chrg_cfg0, UTMIP_PD_CHRG);
+
+	clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_XCVR_LSBIAS_SE);
+	setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
+
+	/*
+	 * Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT
+	 * Setting these fields, together with default values of the
+	 * other fields, results in programming the registers below as
+	 * follows:
+	 *         UTMIP_HSRX_CFG0 = 0x9168c000
+	 *         UTMIP_HSRX_CFG1 = 0x13
+	 */
+
+	/* Set PLL enable delay count and Crystal frequency count */
+	val = readl(&usbctlr->utmip_hsrx_cfg0);
+	clrsetbits_le32(&val, UTMIP_IDLE_WAIT_MASK,
+		utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
+	clrsetbits_le32(&val, UTMIP_ELASTIC_LIMIT_MASK,
+		utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
+	writel(val, &usbctlr->utmip_hsrx_cfg0);
+
+	/* Configure the UTMIP_HS_SYNC_START_DLY */
+	clrsetbits_le32(&usbctlr->utmip_hsrx_cfg1,
+		UTMIP_HS_SYNC_START_DLY_MASK,
+		utmip_hs_sync_start_delay << UTMIP_HS_SYNC_START_DLY_SHIFT);
+
+	/* Preceed the crystal clock disable by >100ns delay. */
+	udelay(1);
+
+	/* Resuscitate crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN */
+	setbits_le32(&usbctlr->utmip_misc_cfg1, UTMIP_PHY_XTAL_CLOCKEN);
+
+	if (controller->has_hostpc) {
+		if (config->periph_id == PERIPH_ID_USBD)
+			clrbits_le32(&clkrst->crc_utmip_pll_cfg2,
+				     UTMIP_FORCE_PD_SAMP_A_POWERDOWN);
+		if (config->periph_id == PERIPH_ID_USB2)
+			clrbits_le32(&clkrst->crc_utmip_pll_cfg2,
+				     UTMIP_FORCE_PD_SAMP_B_POWERDOWN);
+		if (config->periph_id == PERIPH_ID_USB3)
+			clrbits_le32(&clkrst->crc_utmip_pll_cfg2,
+				     UTMIP_FORCE_PD_SAMP_C_POWERDOWN);
+	}
+	/* Finished the per-controller init. */
+
+	/* De-assert UTMIP_RESET to bring out of reset. */
+	clrbits_le32(&usbctlr->susp_ctrl, UTMIP_RESET);
+
+	/* Wait for the phy clock to become valid in 100 ms */
+	for (loop_count = 100000; loop_count != 0; loop_count--) {
+		if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID)
+			break;
+		udelay(1);
+	}
+	if (!loop_count)
+		return -ETIMEDOUT;
+
+	/* Disable ICUSB FS/LS transceiver */
+	clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
+
+	/* Select UTMI parallel interface */
+	init_phy_mux(config, PTS_UTMI, init);
+
+	/* Deassert power down state */
+	clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN |
+		UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN);
+	clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN |
+		UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN);
+
+	if (controller->has_hostpc) {
+		/*
+		 * BIAS Pad Power Down is common among all 3 USB
+		 * controllers and can be controlled from USB1 only.
+		 */
+		usb1ctlr = (struct usb_ctlr *)
+			((unsigned long)config->reg & USB1_ADDR_MASK);
+		clrbits_le32(&usb1ctlr->utmip_bias_cfg0, UTMIP_BIASPD);
+		udelay(25);
+		clrbits_le32(&usb1ctlr->utmip_bias_cfg1,
+			     UTMIP_FORCE_PDTRK_POWERDOWN);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_USB_ULPI
+/* if board file does not set a ULPI reference frequency we default to 24MHz */
+#ifndef CONFIG_ULPI_REF_CLK
+#define CONFIG_ULPI_REF_CLK 24000000
+#endif
+
+/* set up the ULPI USB controller with the parameters provided */
+static int init_ulpi_usb_controller(struct fdt_usb *config,
+				    enum usb_init_type init)
+{
+	u32 val;
+	int loop_count;
+	struct ulpi_viewport ulpi_vp;
+	struct usb_ctlr *usbctlr = config->reg;
+	int ret;
+
+	/* set up ULPI reference clock on pllp_out4 */
+	clock_enable(PERIPH_ID_DEV2_OUT);
+	clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK);
+
+	/* reset ULPI phy */
+	if (dm_gpio_is_valid(&config->phy_reset_gpio)) {
+		/*
+		 * This GPIO is typically active-low, and marked as such in
+		 * device tree. dm_gpio_set_value() takes this into account
+		 * and inverts the value we pass here if required. In other
+		 * words, this first call logically asserts the reset signal,
+		 * which typically results in driving the physical GPIO low,
+		 * and the second call logically de-asserts the reset signal,
+		 * which typically results in driver the GPIO high.
+		 */
+		dm_gpio_set_value(&config->phy_reset_gpio, 1);
+		mdelay(5);
+		dm_gpio_set_value(&config->phy_reset_gpio, 0);
+	}
+
+	/* Reset the usb controller */
+	clock_enable(config->periph_id);
+	usbf_reset_controller(config, usbctlr);
+
+	/* enable pinmux bypass */
+	setbits_le32(&usbctlr->ulpi_timing_ctrl_0,
+			ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP);
+
+	/* Select ULPI parallel interface */
+	init_phy_mux(config, PTS_ULPI, init);
+
+	/* enable ULPI transceiver */
+	setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB);
+
+	/* configure ULPI transceiver timings */
+	val = 0;
+	writel(val, &usbctlr->ulpi_timing_ctrl_1);
+
+	val |= ULPI_DATA_TRIMMER_SEL(4);
+	val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
+	val |= ULPI_DIR_TRIMMER_SEL(4);
+	writel(val, &usbctlr->ulpi_timing_ctrl_1);
+	udelay(10);
+
+	val |= ULPI_DATA_TRIMMER_LOAD;
+	val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+	val |= ULPI_DIR_TRIMMER_LOAD;
+	writel(val, &usbctlr->ulpi_timing_ctrl_1);
+
+	/* set up phy for host operation with external vbus supply */
+	ulpi_vp.port_num = 0;
+	ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport;
+
+	ret = ulpi_init(&ulpi_vp);
+	if (ret) {
+		printf("Tegra ULPI viewport init failed\n");
+		return ret;
+	}
+
+	ulpi_set_vbus(&ulpi_vp, 1, 1);
+	ulpi_set_vbus_indicator(&ulpi_vp, 1, 1, 0);
+
+	/* enable wakeup events */
+	setbits_le32(&usbctlr->port_sc1, WKCN | WKDS | WKOC);
+
+	/* Enable and wait for the phy clock to become valid in 100 ms */
+	setbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
+	for (loop_count = 100000; loop_count != 0; loop_count--) {
+		if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID)
+			break;
+		udelay(1);
+	}
+	if (!loop_count)
+		return -ETIMEDOUT;
+	clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
+
+	return 0;
+}
+#else
+static int init_ulpi_usb_controller(struct fdt_usb *config,
+				    enum usb_init_type init)
+{
+	printf("No code to set up ULPI controller, please enable"
+			"CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
+	return -ENOSYS;
+}
+#endif
+
+static void config_clock(const u32 timing[])
+{
+	debug("%s: DIVM = %d, DIVN = %d, DIVP = %d, cpcon/lfcon = %d/%d\n",
+	      __func__, timing[PARAM_DIVM], timing[PARAM_DIVN],
+	      timing[PARAM_DIVP], timing[PARAM_CPCON], timing[PARAM_LFCON]);
+
+	clock_start_pll(CLOCK_ID_USB,
+		timing[PARAM_DIVM], timing[PARAM_DIVN], timing[PARAM_DIVP],
+		timing[PARAM_CPCON], timing[PARAM_LFCON]);
+}
+
+static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config)
+{
+	const char *phy, *mode;
+
+	config->reg = (struct usb_ctlr *)dev_read_addr(dev);
+	debug("reg=%p\n", config->reg);
+	mode = dev_read_string(dev, "dr_mode");
+	if (mode) {
+		if (0 == strcmp(mode, "host"))
+			config->dr_mode = DR_MODE_HOST;
+		else if (0 == strcmp(mode, "peripheral"))
+			config->dr_mode = DR_MODE_DEVICE;
+		else if (0 == strcmp(mode, "otg"))
+			config->dr_mode = DR_MODE_OTG;
+		else {
+			debug("%s: Cannot decode dr_mode '%s'\n", __func__,
+			      mode);
+			return -EINVAL;
+		}
+	} else {
+		config->dr_mode = DR_MODE_HOST;
+	}
+
+	phy = dev_read_string(dev, "phy_type");
+	config->utmi = phy && 0 == strcmp("utmi", phy);
+	config->ulpi = phy && 0 == strcmp("ulpi", phy);
+	config->has_legacy_mode = dev_read_bool(dev, "nvidia,has-legacy-mode");
+	config->periph_id = clock_decode_periph_id(dev);
+	if (config->periph_id == PERIPH_ID_NONE) {
+		debug("%s: Missing/invalid peripheral ID\n", __func__);
+		return -EINVAL;
+	}
+	gpio_request_by_name(dev, "nvidia,vbus-gpio", 0, &config->vbus_gpio,
+			     GPIOD_IS_OUT);
+	gpio_request_by_name(dev, "nvidia,phy-reset-gpio", 0,
+			     &config->phy_reset_gpio, GPIOD_IS_OUT);
+	debug("legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, vbus=%d, phy_reset=%d, dr_mode=%d, reg=%p\n",
+	      config->has_legacy_mode, config->utmi, config->ulpi,
+	      config->periph_id, gpio_get_number(&config->vbus_gpio),
+	      gpio_get_number(&config->phy_reset_gpio), config->dr_mode,
+	      config->reg);
+
+	return 0;
+}
+
+int usb_common_init(struct fdt_usb *config, enum usb_init_type init)
+{
+	int ret = 0;
+
+	switch (init) {
+	case USB_INIT_HOST:
+		switch (config->dr_mode) {
+		case DR_MODE_HOST:
+		case DR_MODE_OTG:
+			break;
+		default:
+			printf("tegrausb: Invalid dr_mode %d for host mode\n",
+			       config->dr_mode);
+			return -1;
+		}
+		break;
+	case USB_INIT_DEVICE:
+		if (config->periph_id != PERIPH_ID_USBD) {
+			printf("tegrausb: Device mode only supported on first USB controller\n");
+			return -1;
+		}
+		if (!config->utmi) {
+			printf("tegrausb: Device mode only supported with UTMI PHY\n");
+			return -1;
+		}
+		switch (config->dr_mode) {
+		case DR_MODE_DEVICE:
+		case DR_MODE_OTG:
+			break;
+		default:
+			printf("tegrausb: Invalid dr_mode %d for device mode\n",
+			       config->dr_mode);
+			return -1;
+		}
+		break;
+	default:
+		printf("tegrausb: Unknown USB_INIT_* %d\n", init);
+		return -1;
+	}
+
+	debug("%d, %d\n", config->utmi, config->ulpi);
+	if (config->utmi)
+		ret = init_utmi_usb_controller(config, init);
+	else if (config->ulpi)
+		ret = init_ulpi_usb_controller(config, init);
+	if (ret)
+		return ret;
+
+	set_up_vbus(config, init);
+
+	config->init_type = init;
+
+	return 0;
+}
+
+void usb_common_uninit(struct fdt_usb *priv)
+{
+	struct usb_ctlr *usbctlr;
+
+	usbctlr = priv->reg;
+
+	/* Stop controller */
+	writel(0, &usbctlr->usb_cmd);
+	udelay(1000);
+
+	/* Initiate controller reset */
+	writel(2, &usbctlr->usb_cmd);
+	udelay(1000);
+}
+
+static const struct ehci_ops tegra_ehci_ops = {
+	.set_usb_mode		= tegra_ehci_set_usbmode,
+	.get_port_speed		= tegra_ehci_get_port_speed,
+	.powerup_fixup		= tegra_ehci_powerup_fixup,
+};
+
+static int ehci_usb_of_to_plat(struct udevice *dev)
+{
+	struct fdt_usb *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = fdt_decode_usb(dev, priv);
+	if (ret)
+		return ret;
+
+	priv->type = dev_get_driver_data(dev);
+
+	return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct fdt_usb *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	static bool clk_done;
+	int ret;
+
+	ret = usb_common_init(priv, plat->init_type);
+	if (ret)
+		return ret;
+	hccr = (struct ehci_hccr *)&priv->reg->cap_length;
+	hcor = (struct ehci_hcor *)&priv->reg->usb_cmd;
+	if (!clk_done) {
+		config_clock(get_pll_timing(&fdt_usb_controllers[priv->type]));
+		clk_done = true;
+	}
+
+	return ehci_register(dev, hccr, hcor, &tegra_ehci_ops, 0,
+			     plat->init_type);
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+	{ .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+	{ .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+	{ .compatible = "nvidia,tegra210-ehci", .data = USB_CTLR_T210 },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_tegra",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.of_to_plat = ehci_usb_of_to_plat,
+	.probe = ehci_usb_probe,
+	.remove = ehci_deregister,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct fdt_usb),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ehci-vct.c b/roms/u-boot/drivers/usb/host/ehci-vct.c
new file mode 100644
index 000000000..7167f82b4
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-vct.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ */
+
+#include <common.h>
+#include <usb.h>
+
+#include "ehci.h"
+
+int vct_ehci_hcd_init(u32 *hccr, u32 *hcor);
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	int ret;
+	u32 vct_hccr;
+	u32 vct_hcor;
+
+	/*
+	 * Init VCT specific stuff
+	 */
+	ret = vct_ehci_hcd_init(&vct_hccr, &vct_hcor);
+	if (ret)
+		return ret;
+
+	*hccr = (struct ehci_hccr *)vct_hccr;
+	*hcor = (struct ehci_hcor *)vct_hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/host/ehci-vf.c b/roms/u-boot/drivers/usb/host/ehci-vf.c
new file mode 100644
index 000000000..648e13644
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-vf.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Sanchayan Maity <sanchayan.maity@toradex.com>
+ * Copyright (C) 2015 Toradex AG
+ *
+ * Based on ehci-mx6 driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <errno.h>
+#include <asm/global_data.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/regs-usbphy.h>
+#include <linux/delay.h>
+#include <usb/ehci-ci.h>
+#include <linux/libfdt.h>
+#include <fdtdec.h>
+
+#include "ehci.h"
+
+#define USB_NC_REG_OFFSET				0x00000800
+
+#define ANADIG_PLL_CTRL_EN_USB_CLKS		(1 << 6)
+
+#define UCTRL_OVER_CUR_POL	(1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS	(1 << 7) /* Disable OTG Overcurrent Detection */
+
+/* USBCMD */
+#define UCMD_RUN_STOP		(1 << 0) /* controller run/stop */
+#define UCMD_RESET			(1 << 1) /* controller reset */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const unsigned phy_bases[] = {
+	USB_PHY0_BASE_ADDR,
+	USB_PHY1_BASE_ADDR,
+};
+
+static const unsigned nc_reg_bases[] = {
+	USBC0_BASE_ADDR,
+	USBC1_BASE_ADDR,
+};
+
+static void usb_internal_phy_clock_gate(int index)
+{
+	void __iomem *phy_reg;
+
+	phy_reg = (void __iomem *)phy_bases[index];
+	clrbits_le32(phy_reg + USBPHY_CTRL, USBPHY_CTRL_CLKGATE);
+}
+
+static void usb_power_config(int index)
+{
+	struct anadig_reg __iomem *anadig =
+		(struct anadig_reg __iomem *)ANADIG_BASE_ADDR;
+	void __iomem *pll_ctrl;
+
+	switch (index) {
+	case 0:
+		pll_ctrl = &anadig->pll3_ctrl;
+		clrbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_BYPASS);
+		setbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_ENABLE
+			 | ANADIG_PLL3_CTRL_POWERDOWN
+			 | ANADIG_PLL_CTRL_EN_USB_CLKS);
+		break;
+	case 1:
+		pll_ctrl = &anadig->pll7_ctrl;
+		clrbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_BYPASS);
+		setbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_ENABLE
+			 | ANADIG_PLL7_CTRL_POWERDOWN
+			 | ANADIG_PLL_CTRL_EN_USB_CLKS);
+		break;
+	default:
+		return;
+	}
+}
+
+static void usb_phy_enable(int index, struct usb_ehci *ehci)
+{
+	void __iomem *phy_reg;
+	void __iomem *phy_ctrl;
+	void __iomem *usb_cmd;
+
+	phy_reg = (void __iomem *)phy_bases[index];
+	phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
+	usb_cmd = (void __iomem *)&ehci->usbcmd;
+
+	/* Stop then Reset */
+	clrbits_le32(usb_cmd, UCMD_RUN_STOP);
+	while (readl(usb_cmd) & UCMD_RUN_STOP)
+		;
+
+	setbits_le32(usb_cmd, UCMD_RESET);
+	while (readl(usb_cmd) & UCMD_RESET)
+		;
+
+	/* Reset USBPHY module */
+	setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST);
+	udelay(10);
+
+	/* Remove CLKGATE and SFTRST */
+	clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
+	udelay(10);
+
+	/* Power up the PHY */
+	writel(0, phy_reg + USBPHY_PWD);
+
+	/* Enable FS/LS device */
+	setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 |
+		 USBPHY_CTRL_ENUTMILEVEL3);
+}
+
+static void usb_oc_config(int index)
+{
+	void __iomem *ctrl;
+
+	ctrl = (void __iomem *)(nc_reg_bases[index] + USB_NC_REG_OFFSET);
+
+	setbits_le32(ctrl, UCTRL_OVER_CUR_POL);
+	setbits_le32(ctrl, UCTRL_OVER_CUR_DIS);
+}
+
+int __weak board_usb_phy_mode(int port)
+{
+	return 0;
+}
+
+int __weak board_ehci_hcd_init(int port)
+{
+	return 0;
+}
+
+int ehci_vf_common_init(struct usb_ehci *ehci, int index)
+{
+	int ret;
+
+	/* Do board specific initialisation */
+	ret = board_ehci_hcd_init(index);
+	if (ret)
+		return ret;
+
+	usb_power_config(index);
+	usb_oc_config(index);
+	usb_internal_phy_clock_gate(index);
+	usb_phy_enable(index, ehci);
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	struct usb_ehci *ehci;
+	enum usb_init_type type;
+	int ret;
+
+	if (index >= ARRAY_SIZE(nc_reg_bases))
+		return -EINVAL;
+
+	ehci = (struct usb_ehci *)nc_reg_bases[index];
+
+	ret = ehci_vf_common_init(index);
+	if (ret)
+		return ret;
+
+	*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	type = board_usb_phy_mode(index);
+	if (type != init)
+		return -ENODEV;
+
+	if (init == USB_INIT_DEVICE) {
+		setbits_le32(&ehci->usbmode, CM_DEVICE);
+		writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc);
+		setbits_le32(&ehci->portsc, USB_EN);
+	} else if (init == USB_INIT_HOST) {
+		setbits_le32(&ehci->usbmode, CM_HOST);
+		writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc);
+		setbits_le32(&ehci->portsc, USB_EN);
+	}
+
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+#else
+/* Possible port types (dual role mode) */
+enum dr_mode {
+	DR_MODE_NONE = 0,
+	DR_MODE_HOST,		/* supports host operation */
+	DR_MODE_DEVICE,		/* supports device operation */
+	DR_MODE_OTG,		/* supports both */
+};
+
+struct ehci_vf_priv_data {
+	struct ehci_ctrl ctrl;
+	struct usb_ehci *ehci;
+	struct gpio_desc cdet_gpio;
+	enum usb_init_type init_type;
+	enum dr_mode dr_mode;
+	u32 portnr;
+};
+
+static int vf_usb_of_to_plat(struct udevice *dev)
+{
+	struct ehci_vf_priv_data *priv = dev_get_priv(dev);
+	const void *dt_blob = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	const char *mode;
+
+	priv->portnr = dev_seq(dev);
+
+	priv->ehci = dev_read_addr_ptr(dev);
+	mode = fdt_getprop(dt_blob, node, "dr_mode", NULL);
+	if (mode) {
+		if (0 == strcmp(mode, "host")) {
+			priv->dr_mode = DR_MODE_HOST;
+			priv->init_type = USB_INIT_HOST;
+		} else if (0 == strcmp(mode, "peripheral")) {
+			priv->dr_mode = DR_MODE_DEVICE;
+			priv->init_type = USB_INIT_DEVICE;
+		} else if (0 == strcmp(mode, "otg")) {
+			priv->dr_mode = DR_MODE_OTG;
+			/*
+			 * We set init_type to device by default when OTG
+			 * mode is requested. If a valid gpio is provided
+			 * we will switch the init_type based on the state
+			 * of the gpio pin.
+			 */
+			priv->init_type = USB_INIT_DEVICE;
+		} else {
+			debug("%s: Cannot decode dr_mode '%s'\n",
+			      __func__, mode);
+			return -EINVAL;
+		}
+	} else {
+		priv->dr_mode = DR_MODE_HOST;
+		priv->init_type = USB_INIT_HOST;
+	}
+
+	if (priv->dr_mode == DR_MODE_OTG) {
+		gpio_request_by_name_nodev(offset_to_ofnode(node),
+					   "fsl,cdet-gpio", 0, &priv->cdet_gpio,
+					   GPIOD_IS_IN);
+		if (dm_gpio_is_valid(&priv->cdet_gpio)) {
+			if (dm_gpio_get_value(&priv->cdet_gpio))
+				priv->init_type = USB_INIT_DEVICE;
+			else
+				priv->init_type = USB_INIT_HOST;
+		}
+	}
+
+	return 0;
+}
+
+static int vf_init_after_reset(struct ehci_ctrl *dev)
+{
+	struct ehci_vf_priv_data *priv = dev->priv;
+	enum usb_init_type type = priv->init_type;
+	struct usb_ehci *ehci = priv->ehci;
+	int ret;
+
+	ret = ehci_vf_common_init(priv->ehci, priv->portnr);
+	if (ret)
+		return ret;
+
+	if (type == USB_INIT_DEVICE)
+		return 0;
+
+	setbits_le32(&ehci->usbmode, CM_HOST);
+	writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mdelay(10);
+
+	return 0;
+}
+
+static const struct ehci_ops vf_ehci_ops = {
+	.init_after_reset = vf_init_after_reset
+};
+
+static int vf_usb_bind(struct udevice *dev)
+{
+	/*
+	 * Without this hack, if we return ENODEV for USB Controller 0, on
+	 * probe for the next controller, USB Controller 1 will be given a
+	 * sequence number of 0. This conflicts with our requirement of
+	 * sequence numbers while initialising the peripherals.
+	 *
+	 * FIXME: Check that this still works OK with the new sequence numbers
+	 */
+
+	return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct ehci_vf_priv_data *priv = dev_get_priv(dev);
+	struct usb_ehci *ehci = priv->ehci;
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	int ret;
+
+	ret = ehci_vf_common_init(ehci, priv->portnr);
+	if (ret)
+		return ret;
+
+	if (priv->init_type != plat->init_type)
+		return -ENODEV;
+
+	if (priv->init_type == USB_INIT_HOST) {
+		setbits_le32(&ehci->usbmode, CM_HOST);
+		writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc);
+		setbits_le32(&ehci->portsc, USB_EN);
+	}
+
+	mdelay(10);
+
+	hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	hcor = (struct ehci_hcor *)((uint32_t)hccr +
+				HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	return ehci_register(dev, hccr, hcor, &vf_ehci_ops, 0, priv->init_type);
+}
+
+static const struct udevice_id vf_usb_ids[] = {
+	{ .compatible = "fsl,vf610-usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name = "ehci_vf",
+	.id = UCLASS_USB,
+	.of_match = vf_usb_ids,
+	.bind = vf_usb_bind,
+	.probe = ehci_usb_probe,
+	.remove = ehci_deregister,
+	.ops = &ehci_usb_ops,
+	.of_to_plat = vf_usb_of_to_plat,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ehci_vf_priv_data),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ehci-zynq.c b/roms/u-boot/drivers/usb/host/ehci-zynq.c
new file mode 100644
index 000000000..f7e458cb1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci-zynq.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014, Xilinx, Inc
+ *
+ * USB Low level initialization(Specific to zynq)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <usb/ehci-ci.h>
+#include <usb/ulpi.h>
+
+#include "ehci.h"
+
+struct zynq_ehci_priv {
+	struct ehci_ctrl ehcictrl;
+	struct usb_ehci *ehci;
+};
+
+static int ehci_zynq_of_to_plat(struct udevice *dev)
+{
+	struct zynq_ehci_priv *priv = dev_get_priv(dev);
+
+	priv->ehci = dev_read_addr_ptr(dev);
+	if (!priv->ehci)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ehci_zynq_probe(struct udevice *dev)
+{
+	struct usb_plat *plat = dev_get_plat(dev);
+	struct zynq_ehci_priv *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	struct ulpi_viewport ulpi_vp;
+	/* Used for writing the ULPI data address */
+	struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+	int ret;
+
+	hccr = (struct ehci_hccr *)((uint32_t)&priv->ehci->caplength);
+	hcor = (struct ehci_hcor *)((uint32_t) hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	ulpi_vp.viewport_addr = (u32)&priv->ehci->ulpi_viewpoint;
+	ulpi_vp.port_num = 0;
+
+	ret = ulpi_init(&ulpi_vp);
+	if (ret) {
+		puts("zynq ULPI viewport init failed\n");
+		return -1;
+	}
+
+	/* ULPI set flags */
+	ulpi_write(&ulpi_vp, &ulpi->otg_ctrl,
+		   ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN |
+		   ULPI_OTG_EXTVBUSIND);
+	ulpi_write(&ulpi_vp, &ulpi->function_ctrl,
+		   ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL |
+		   ULPI_FC_SUSPENDM);
+	ulpi_write(&ulpi_vp, &ulpi->iface_ctrl, 0);
+
+	/* Set VBus */
+	ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set,
+		   ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+
+	return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type);
+}
+
+static const struct udevice_id ehci_zynq_ids[] = {
+	{ .compatible = "xlnx,zynq-usb-2.20a" },
+	{ }
+};
+
+U_BOOT_DRIVER(ehci_zynq) = {
+	.name	= "ehci_zynq",
+	.id	= UCLASS_USB,
+	.of_match = ehci_zynq_ids,
+	.of_to_plat = ehci_zynq_of_to_plat,
+	.probe = ehci_zynq_probe,
+	.remove = ehci_deregister,
+	.ops	= &ehci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct zynq_ehci_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ehci.h b/roms/u-boot/drivers/usb/host/ehci.h
new file mode 100644
index 000000000..e9e6f2a55
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ehci.h
@@ -0,0 +1,303 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ * All rights reserved.
+ */
+
+#ifndef USB_EHCI_H
+#define USB_EHCI_H
+
+#include <stdbool.h>
+#include <usb.h>
+#include <generic-phy.h>
+
+/* Section 2.2.3 - N_PORTS */
+#define MAX_HC_PORTS		15
+
+/*
+ * Register Space.
+ */
+struct ehci_hccr {
+	uint32_t cr_capbase;
+#define HC_LENGTH(p)		(((p) >> 0) & 0x00ff)
+#define HC_VERSION(p)		(((p) >> 16) & 0xffff)
+	uint32_t cr_hcsparams;
+#define HCS_PPC(p)		((p) & (1 << 4))
+#define HCS_INDICATOR(p)	((p) & (1 << 16)) /* Port indicators */
+#define HCS_N_PORTS(p)		(((p) >> 0) & 0xf)
+	uint32_t cr_hccparams;
+	uint8_t cr_hcsp_portrt[8];
+} __attribute__ ((packed, aligned(4)));
+
+struct ehci_hcor {
+	uint32_t or_usbcmd;
+#define CMD_PARK	(1 << 11)		/* enable "park" */
+#define CMD_PARK_CNT(c)	(((c) >> 8) & 3)	/* how many transfers to park */
+#define CMD_LRESET	(1 << 7)		/* partial reset */
+#define CMD_IAAD	(1 << 6)		/* "doorbell" interrupt */
+#define CMD_ASE		(1 << 5)		/* async schedule enable */
+#define CMD_PSE		(1 << 4)		/* periodic schedule enable */
+#define CMD_RESET	(1 << 1)		/* reset HC not bus */
+#define CMD_RUN		(1 << 0)		/* start/stop HC */
+	uint32_t or_usbsts;
+#define STS_ASS		(1 << 15)
+#define	STS_PSS		(1 << 14)
+#define STS_HALT	(1 << 12)
+#define STS_IAA		(1 << 5)
+	uint32_t or_usbintr;
+#define INTR_UE         (1 << 0)                /* USB interrupt enable */
+#define INTR_UEE        (1 << 1)                /* USB error interrupt enable */
+#define INTR_PCE        (1 << 2)                /* Port change detect enable */
+#define INTR_SEE        (1 << 4)                /* system error enable */
+#define INTR_AAE        (1 << 5)                /* Interrupt on async adavance enable */
+	uint32_t or_frindex;
+	uint32_t or_ctrldssegment;
+	uint32_t or_periodiclistbase;
+	uint32_t or_asynclistaddr;
+	uint32_t _reserved_0_;
+	uint32_t or_burstsize;
+	uint32_t or_txfilltuning;
+#define TXFIFO_THRESH_MASK		(0x3f << 16)
+#define TXFIFO_THRESH(p)		((p & 0x3f) << 16)
+	uint32_t _reserved_1_[6];
+	uint32_t or_configflag;
+#define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */
+	uint32_t or_portsc[MAX_HC_PORTS];
+#define PORTSC_PSPD(x)		(((x) >> 26) & 0x3)
+#define PORTSC_PSPD_FS			0x0
+#define PORTSC_PSPD_LS			0x1
+#define PORTSC_PSPD_HS			0x2
+#define PORTSC_FSL_PFSC		BIT(24) /* PFSC bit to disable HS chirping */
+
+	uint32_t or_systune;
+} __attribute__ ((packed, aligned(4)));
+
+#define USBMODE		0x68		/* USB Device mode */
+#define USBMODE_SDIS	(1 << 3)	/* Stream disable */
+#define USBMODE_BE	(1 << 2)	/* BE/LE endiannes select */
+#define USBMODE_CM_HC	(3 << 0)	/* host controller mode */
+#define USBMODE_CM_IDLE	(0 << 0)	/* idle state */
+
+/* Interface descriptor */
+struct usb_linux_interface_descriptor {
+	unsigned char	bLength;
+	unsigned char	bDescriptorType;
+	unsigned char	bInterfaceNumber;
+	unsigned char	bAlternateSetting;
+	unsigned char	bNumEndpoints;
+	unsigned char	bInterfaceClass;
+	unsigned char	bInterfaceSubClass;
+	unsigned char	bInterfaceProtocol;
+	unsigned char	iInterface;
+} __attribute__ ((packed));
+
+/* Configuration descriptor information.. */
+struct usb_linux_config_descriptor {
+	unsigned char	bLength;
+	unsigned char	bDescriptorType;
+	unsigned short	wTotalLength;
+	unsigned char	bNumInterfaces;
+	unsigned char	bConfigurationValue;
+	unsigned char	iConfiguration;
+	unsigned char	bmAttributes;
+	unsigned char	MaxPower;
+} __attribute__ ((packed));
+
+#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
+#define ehci_readl(x)		be32_to_cpu(__raw_readl(x))
+#define ehci_writel(a, b)	__raw_writel(cpu_to_be32(b), a)
+#else
+#define ehci_readl(x)		readl(x)
+#define ehci_writel(a, b)	writel(b, a)
+#endif
+
+#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
+#define hc32_to_cpu(x)		be32_to_cpu((x))
+#define cpu_to_hc32(x)		cpu_to_be32((x))
+#else
+#define hc32_to_cpu(x)		le32_to_cpu((x))
+#define cpu_to_hc32(x)		cpu_to_le32((x))
+#endif
+
+#define EHCI_PS_WKOC_E		(1 << 22)	/* RW wake on over current */
+#define EHCI_PS_WKDSCNNT_E	(1 << 21)	/* RW wake on disconnect */
+#define EHCI_PS_WKCNNT_E	(1 << 20)	/* RW wake on connect */
+#define EHCI_PS_PO		(1 << 13)	/* RW port owner */
+#define EHCI_PS_PP		(1 << 12)	/* RW,RO port power */
+#define EHCI_PS_LS		(3 << 10)	/* RO line status */
+#define EHCI_PS_PR		(1 << 8)	/* RW port reset */
+#define EHCI_PS_SUSP		(1 << 7)	/* RW suspend */
+#define EHCI_PS_FPR		(1 << 6)	/* RW force port resume */
+#define EHCI_PS_OCC		(1 << 5)	/* RWC over current change */
+#define EHCI_PS_OCA		(1 << 4)	/* RO over current active */
+#define EHCI_PS_PEC		(1 << 3)	/* RWC port enable change */
+#define EHCI_PS_PE		(1 << 2)	/* RW port enable */
+#define EHCI_PS_CSC		(1 << 1)	/* RWC connect status change */
+#define EHCI_PS_CS		(1 << 0)	/* RO connect status */
+#define EHCI_PS_CLEAR		(EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
+
+#define EHCI_PS_IS_LOWSPEED(x)	(((x) & EHCI_PS_LS) == (1 << 10))
+
+/*
+ * Schedule Interface Space.
+ *
+ * IMPORTANT: Software must ensure that no interface data structure
+ * reachable by the EHCI host controller spans a 4K page boundary!
+ *
+ * Periodic transfers (i.e. isochronous and interrupt transfers) are
+ * not supported.
+ */
+
+/* Queue Element Transfer Descriptor (qTD). */
+struct qTD {
+	/* this part defined by EHCI spec */
+	uint32_t qt_next;			/* see EHCI 3.5.1 */
+#define	QT_NEXT_TERMINATE	1
+	uint32_t qt_altnext;			/* see EHCI 3.5.2 */
+	uint32_t qt_token;			/* see EHCI 3.5.3 */
+#define QT_TOKEN_DT(x)		(((x) & 0x1) << 31)	/* Data Toggle */
+#define QT_TOKEN_GET_DT(x)		(((x) >> 31) & 0x1)
+#define QT_TOKEN_TOTALBYTES(x)	(((x) & 0x7fff) << 16)	/* Total Bytes to Transfer */
+#define QT_TOKEN_GET_TOTALBYTES(x)	(((x) >> 16) & 0x7fff)
+#define QT_TOKEN_IOC(x)		(((x) & 0x1) << 15)	/* Interrupt On Complete */
+#define QT_TOKEN_CPAGE(x)	(((x) & 0x7) << 12)	/* Current Page */
+#define QT_TOKEN_CERR(x)	(((x) & 0x3) << 10)	/* Error Counter */
+#define QT_TOKEN_PID(x)		(((x) & 0x3) << 8)	/* PID Code */
+#define QT_TOKEN_PID_OUT		0x0
+#define QT_TOKEN_PID_IN			0x1
+#define QT_TOKEN_PID_SETUP		0x2
+#define QT_TOKEN_STATUS(x)	(((x) & 0xff) << 0)	/* Status */
+#define QT_TOKEN_GET_STATUS(x)		(((x) >> 0) & 0xff)
+#define QT_TOKEN_STATUS_ACTIVE		0x80
+#define QT_TOKEN_STATUS_HALTED		0x40
+#define QT_TOKEN_STATUS_DATBUFERR	0x20
+#define QT_TOKEN_STATUS_BABBLEDET	0x10
+#define QT_TOKEN_STATUS_XACTERR		0x08
+#define QT_TOKEN_STATUS_MISSEDUFRAME	0x04
+#define QT_TOKEN_STATUS_SPLITXSTATE	0x02
+#define QT_TOKEN_STATUS_PERR		0x01
+#define QT_BUFFER_CNT		5
+	uint32_t qt_buffer[QT_BUFFER_CNT];	/* see EHCI 3.5.4 */
+	uint32_t qt_buffer_hi[QT_BUFFER_CNT];	/* Appendix B */
+	/* pad struct for 32 byte alignment */
+	uint32_t unused[3];
+};
+
+#define EHCI_PAGE_SIZE		4096
+
+/* Queue Head (QH). */
+struct QH {
+	uint32_t qh_link;
+#define	QH_LINK_TERMINATE	1
+#define	QH_LINK_TYPE_ITD	0
+#define	QH_LINK_TYPE_QH		2
+#define	QH_LINK_TYPE_SITD	4
+#define	QH_LINK_TYPE_FSTN	6
+	uint32_t qh_endpt1;
+#define QH_ENDPT1_RL(x)		(((x) & 0xf) << 28)	/* NAK Count Reload */
+#define QH_ENDPT1_C(x)		(((x) & 0x1) << 27)	/* Control Endpoint Flag */
+#define QH_ENDPT1_MAXPKTLEN(x)	(((x) & 0x7ff) << 16)	/* Maximum Packet Length */
+#define QH_ENDPT1_H(x)		(((x) & 0x1) << 15)	/* Head of Reclamation List Flag */
+#define QH_ENDPT1_DTC(x)	(((x) & 0x1) << 14)	/* Data Toggle Control */
+#define QH_ENDPT1_DTC_IGNORE_QTD_TD	0x0
+#define QH_ENDPT1_DTC_DT_FROM_QTD	0x1
+#define QH_ENDPT1_EPS(x)	(((x) & 0x3) << 12)	/* Endpoint Speed */
+#define QH_ENDPT1_EPS_FS		0x0
+#define QH_ENDPT1_EPS_LS		0x1
+#define QH_ENDPT1_EPS_HS		0x2
+#define QH_ENDPT1_ENDPT(x)	(((x) & 0xf) << 8)	/* Endpoint Number */
+#define QH_ENDPT1_I(x)		(((x) & 0x1) << 7)	/* Inactivate on Next Transaction */
+#define QH_ENDPT1_DEVADDR(x)	(((x) & 0x7f) << 0)	/* Device Address */
+	uint32_t qh_endpt2;
+#define QH_ENDPT2_MULT(x)	(((x) & 0x3) << 30)	/* High-Bandwidth Pipe Multiplier */
+#define QH_ENDPT2_PORTNUM(x)	(((x) & 0x7f) << 23)	/* Port Number */
+#define QH_ENDPT2_HUBADDR(x)	(((x) & 0x7f) << 16)	/* Hub Address */
+#define QH_ENDPT2_UFCMASK(x)	(((x) & 0xff) << 8)	/* Split Completion Mask */
+#define QH_ENDPT2_UFSMASK(x)	(((x) & 0xff) << 0)	/* Interrupt Schedule Mask */
+	uint32_t qh_curtd;
+	struct qTD qh_overlay;
+	/*
+	 * Add dummy fill value to make the size of this struct
+	 * aligned to 32 bytes
+	 */
+	union {
+		uint32_t fill[4];
+		void *buffer;
+	};
+};
+
+/* Tweak flags for EHCI, used to control operation */
+enum {
+	/* don't use or_configflag in init */
+	EHCI_TWEAK_NO_INIT_CF		= 1 << 0,
+};
+
+struct ehci_ctrl;
+
+struct ehci_ops {
+	void (*set_usb_mode)(struct ehci_ctrl *ctrl);
+	int (*get_port_speed)(struct ehci_ctrl *ctrl, uint32_t reg);
+	void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			      uint32_t *reg);
+	uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port);
+	int (*init_after_reset)(struct ehci_ctrl *ctrl);
+};
+
+struct ehci_ctrl {
+	enum usb_init_type init;
+	struct ehci_hccr *hccr;	/* R/O registers, not need for volatile */
+	struct ehci_hcor *hcor;
+	int rootdev;
+	uint16_t portreset;
+	struct QH qh_list __aligned(USB_DMA_MINALIGN);
+	struct QH periodic_queue __aligned(USB_DMA_MINALIGN);
+	uint32_t *periodic_list;
+	int periodic_schedules;
+	int ntds;
+	bool has_fsl_erratum_a005275;	/* Freescale HS silicon quirk */
+	bool async_locked;
+	struct ehci_ops ops;
+	void *priv;	/* client's private data */
+};
+
+/**
+ * ehci_set_controller_info() - Set up private data for the controller
+ *
+ * This function can be called in ehci_hcd_init() to tell the EHCI layer
+ * about the controller's private data pointer. Then in the above functions
+ * this can be accessed given the struct ehci_ctrl pointer. Also special
+ * EHCI operation methods can be provided if required
+ *
+ * @index:	Controller number to set
+ * @priv:	Controller pointer
+ * @ops:	Controller operations, or NULL to use default
+ */
+void ehci_set_controller_priv(int index, void *priv,
+			      const struct ehci_ops *ops);
+
+/**
+ * ehci_get_controller_priv() - Get controller private data
+ *
+ * @index	Controller number to get
+ * @return controller pointer for this index
+ */
+void *ehci_get_controller_priv(int index);
+
+/* Low level init functions */
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor);
+int ehci_hcd_stop(int index);
+
+int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
+		  struct ehci_hcor *hcor, const struct ehci_ops *ops,
+		  uint tweaks, enum usb_init_type init);
+int ehci_deregister(struct udevice *dev);
+extern struct dm_usb_ops ehci_usb_ops;
+
+/* EHCI PHY functions */
+int ehci_setup_phy(struct udevice *dev, struct phy *phy, int index);
+int ehci_shutdown_phy(struct udevice *dev, struct phy *phy);
+
+#include <linux/bitops.h>
+#endif /* USB_EHCI_H */
diff --git a/roms/u-boot/drivers/usb/host/ohci-at91.c b/roms/u-boot/drivers/usb/host/ohci-at91.c
new file mode 100644
index 000000000..8ceabaf45
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-at91.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2006
+ * DENX Software Engineering <mk@denx.de>
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+
+#include <asm/arch/clk.h>
+
+int usb_cpu_init(void)
+{
+#ifdef CONFIG_USB_ATMEL_CLK_SEL_PLLB
+	if (at91_pllb_clk_enable(get_pllb_init()))
+		return -1;
+
+#ifdef CONFIG_AT91SAM9N12
+	at91_usb_clk_init(AT91_PMC_USBS_USB_PLLB | AT91_PMC_USB_DIV_2);
+#endif
+#elif defined(CONFIG_USB_ATMEL_CLK_SEL_UPLL)
+	if (at91_upll_clk_enable())
+		return -1;
+
+	at91_usb_clk_init(AT91_PMC_USBS_USB_UPLL | AT91_PMC_USBDIV_10);
+#endif
+
+	at91_periph_clk_enable(ATMEL_ID_UHP);
+
+	at91_system_clk_enable(ATMEL_PMC_UHP);
+#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)
+	at91_system_clk_enable(AT91_PMC_HCK0);
+#endif
+
+	return 0;
+}
+
+int usb_cpu_stop(void)
+{
+	at91_periph_clk_disable(ATMEL_ID_UHP);
+
+	at91_system_clk_disable(ATMEL_PMC_UHP);
+#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)
+	at91_system_clk_disable(AT91_PMC_HCK0);
+#endif
+
+#ifdef CONFIG_USB_ATMEL_CLK_SEL_PLLB
+#ifdef CONFIG_AT91SAM9N12
+	at91_usb_clk_init(0);
+#endif
+
+	if (at91_pllb_clk_disable())
+		return -1;
+
+#elif defined(CONFIG_USB_ATMEL_CLK_SEL_UPLL)
+	if (at91_upll_clk_disable())
+		return -1;
+#endif
+
+	return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+	return usb_cpu_stop();
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
diff --git a/roms/u-boot/drivers/usb/host/ohci-da8xx.c b/roms/u-boot/drivers/usb/host/ohci-da8xx.c
new file mode 100644
index 000000000..33c4a911a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-da8xx.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Sughosh Ganu <urwithsughosh@gmail.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/ofnode.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include "ohci.h"
+#include <asm/arch/da8xx-usb.h>
+
+struct da8xx_ohci {
+	ohci_t ohci;
+	struct clk *clocks;	/* clock list */
+	struct phy phy;
+	int clock_count;	/* number of clock in clock list */
+};
+
+static int usb_phy_on(void)
+{
+	unsigned long timeout;
+
+	clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
+			(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN |
+			CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE |
+			CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX),
+			(CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN |
+			CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ |
+			CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM));
+
+	/* wait until the usb phy pll locks */
+	timeout = get_timer(0);
+	while (get_timer(timeout) < 10) {
+		if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
+			return 1;
+	}
+
+	/* USB phy was not turned on */
+	return 0;
+}
+
+static void usb_phy_off(void)
+{
+	/* Power down the on-chip PHY. */
+	clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
+			CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM,
+			CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
+			CFGCHIP2_RESET);
+}
+
+int usb_cpu_init(void)
+{
+	/* enable psc for usb2.0 */
+	lpsc_on(DAVINCI_LPSC_USB20);
+
+	/* enable psc for usb1.0 */
+	lpsc_on(DAVINCI_LPSC_USB11);
+
+	/* start the on-chip usb phy and its pll */
+	if (usb_phy_on())
+		return 0;
+
+	return 1;
+}
+
+int usb_cpu_stop(void)
+{
+	usb_phy_off();
+
+	/* turn off the usb clock and assert the module reset */
+	lpsc_disable(DAVINCI_LPSC_USB11);
+	lpsc_disable(DAVINCI_LPSC_USB20);
+
+	return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+	return usb_cpu_stop();
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ohci_da8xx_probe(struct udevice *dev)
+{
+	struct ohci_regs *regs = dev_read_addr_ptr(dev);
+	struct da8xx_ohci *priv = dev_get_priv(dev);
+	int i, err, ret, clock_nb;
+
+	err = 0;
+	priv->clock_count = 0;
+	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells",
+					       0);
+
+	if (clock_nb < 0)
+		return clock_nb;
+
+	if (clock_nb > 0) {
+		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
+					    GFP_KERNEL);
+		if (!priv->clocks)
+			return -ENOMEM;
+
+		for (i = 0; i < clock_nb; i++) {
+			err = clk_get_by_index(dev, i, &priv->clocks[i]);
+			if (err < 0)
+				break;
+
+			err = clk_enable(&priv->clocks[i]);
+			if (err) {
+				dev_err(dev, "failed to enable clock %d\n", i);
+				clk_free(&priv->clocks[i]);
+				goto clk_err;
+			}
+			priv->clock_count++;
+		}
+	}
+
+	err = usb_cpu_init();
+
+	if (err)
+		goto clk_err;
+
+	err = ohci_register(dev, regs);
+	if (err)
+		goto phy_err;
+
+	return 0;
+
+phy_err:
+	ret = usb_cpu_stop();
+	if (ret)
+		dev_err(dev, "failed to shutdown usb phy\n");
+
+clk_err:
+	ret = clk_release_all(priv->clocks, priv->clock_count);
+	if (ret)
+		dev_err(dev, "failed to disable all clocks\n");
+
+	return err;
+}
+
+static int ohci_da8xx_remove(struct udevice *dev)
+{
+	struct da8xx_ohci *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = ohci_deregister(dev);
+	if (ret)
+		return ret;
+
+	ret = usb_cpu_stop();
+	if (ret)
+		return ret;
+
+	return clk_release_all(priv->clocks, priv->clock_count);
+}
+
+static const struct udevice_id da8xx_ohci_ids[] = {
+	{ .compatible = "ti,da830-ohci" },
+	{ }
+};
+
+U_BOOT_DRIVER(ohci_generic) = {
+	.name	= "ohci-da8xx",
+	.id	= UCLASS_USB,
+	.of_match = da8xx_ohci_ids,
+	.probe = ohci_da8xx_probe,
+	.remove = ohci_da8xx_remove,
+	.ops	= &ohci_usb_ops,
+	.priv_auto	= sizeof(struct da8xx_ohci),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ohci-ep93xx.c b/roms/u-boot/drivers/usb/host/ohci-ep93xx.c
new file mode 100644
index 000000000..9654fa299
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-ep93xx.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2013
+ * Sergey Kostanbaev < sergey.kostanbaev <at> fairwaves.ru >
+ */
+
+#include <config.h>
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+#include <asm/io.h>
+#include <asm/arch/ep93xx.h>
+
+int usb_cpu_init(void)
+{
+	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
+	unsigned long pwr = readl(&syscon->pwrcnt);
+	writel(pwr | SYSCON_PWRCNT_USH_EN, &syscon->pwrcnt);
+
+	return 0;
+}
+
+int usb_cpu_stop(void)
+{
+	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
+	unsigned long pwr = readl(&syscon->pwrcnt);
+	writel(pwr &  ~SYSCON_PWRCNT_USH_EN, &syscon->pwrcnt);
+
+	return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+	return usb_cpu_stop();
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
diff --git a/roms/u-boot/drivers/usb/host/ohci-generic.c b/roms/u-boot/drivers/usb/host/ohci-generic.c
new file mode 100644
index 000000000..163f0ef17
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-generic.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/ofnode.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include "ohci.h"
+
+#if !defined(CONFIG_USB_OHCI_NEW)
+# error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW"
+#endif
+
+struct generic_ohci {
+	ohci_t ohci;
+	struct clk *clocks;	/* clock list */
+	struct reset_ctl *resets; /* reset list */
+	struct phy phy;
+	int clock_count;	/* number of clock in clock list */
+	int reset_count;	/* number of reset in reset list */
+};
+
+static int ohci_setup_phy(struct udevice *dev, int index)
+{
+	struct generic_ohci *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = generic_phy_get_by_index(dev, index, &priv->phy);
+	if (ret) {
+		if (ret != -ENOENT) {
+			dev_err(dev, "failed to get usb phy\n");
+			return ret;
+		}
+	} else {
+		ret = generic_phy_init(&priv->phy);
+		if (ret) {
+			dev_dbg(dev, "failed to init usb phy\n");
+			return ret;
+		}
+
+		ret = generic_phy_power_on(&priv->phy);
+		if (ret) {
+			dev_dbg(dev, "failed to power on usb phy\n");
+			return generic_phy_exit(&priv->phy);
+		}
+	}
+
+	return 0;
+}
+
+static int ohci_shutdown_phy(struct udevice *dev)
+{
+	struct generic_ohci *priv = dev_get_priv(dev);
+	int ret = 0;
+
+	if (generic_phy_valid(&priv->phy)) {
+		ret = generic_phy_power_off(&priv->phy);
+		if (ret) {
+			dev_dbg(dev, "failed to power off usb phy\n");
+			return ret;
+		}
+
+		ret = generic_phy_exit(&priv->phy);
+		if (ret) {
+			dev_dbg(dev, "failed to power off usb phy\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int ohci_usb_probe(struct udevice *dev)
+{
+	struct ohci_regs *regs = dev_read_addr_ptr(dev);
+	struct generic_ohci *priv = dev_get_priv(dev);
+	int i, err, ret, clock_nb, reset_nb;
+
+	err = 0;
+	priv->clock_count = 0;
+	clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells",
+					       0);
+	if (clock_nb > 0) {
+		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
+					    GFP_KERNEL);
+		if (!priv->clocks)
+			return -ENOMEM;
+
+		for (i = 0; i < clock_nb; i++) {
+			err = clk_get_by_index(dev, i, &priv->clocks[i]);
+			if (err < 0)
+				break;
+
+			err = clk_enable(&priv->clocks[i]);
+			if (err && err != -ENOSYS) {
+				dev_err(dev, "failed to enable clock %d\n", i);
+				clk_free(&priv->clocks[i]);
+				goto clk_err;
+			}
+			priv->clock_count++;
+		}
+	} else if (clock_nb != -ENOENT) {
+		dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb);
+		return clock_nb;
+	}
+
+	priv->reset_count = 0;
+	reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells",
+					       0);
+	if (reset_nb > 0) {
+		priv->resets = devm_kcalloc(dev, reset_nb,
+					    sizeof(struct reset_ctl),
+					    GFP_KERNEL);
+		if (!priv->resets)
+			return -ENOMEM;
+
+		for (i = 0; i < reset_nb; i++) {
+			err = reset_get_by_index(dev, i, &priv->resets[i]);
+			if (err < 0)
+				break;
+
+			err = reset_deassert(&priv->resets[i]);
+			if (err) {
+				dev_err(dev, "failed to deassert reset %d\n", i);
+				reset_free(&priv->resets[i]);
+				goto reset_err;
+			}
+			priv->reset_count++;
+		}
+	} else if (reset_nb != -ENOENT) {
+		dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb);
+		goto clk_err;
+	}
+
+	err = ohci_setup_phy(dev, 0);
+	if (err)
+		goto reset_err;
+
+	err = ohci_register(dev, regs);
+	if (err)
+		goto phy_err;
+
+	return 0;
+
+phy_err:
+	ret = ohci_shutdown_phy(dev);
+	if (ret)
+		dev_err(dev, "failed to shutdown usb phy\n");
+
+reset_err:
+	ret = reset_release_all(priv->resets, priv->reset_count);
+	if (ret)
+		dev_err(dev, "failed to assert all resets\n");
+clk_err:
+	ret = clk_release_all(priv->clocks, priv->clock_count);
+	if (ret)
+		dev_err(dev, "failed to disable all clocks\n");
+
+	return err;
+}
+
+static int ohci_usb_remove(struct udevice *dev)
+{
+	struct generic_ohci *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = ohci_deregister(dev);
+	if (ret)
+		return ret;
+
+	ret = ohci_shutdown_phy(dev);
+	if (ret)
+		return ret;
+
+	ret = reset_release_all(priv->resets, priv->reset_count);
+	if (ret)
+		return ret;
+
+	return clk_release_all(priv->clocks, priv->clock_count);
+}
+
+static const struct udevice_id ohci_usb_ids[] = {
+	{ .compatible = "generic-ohci" },
+	{ }
+};
+
+U_BOOT_DRIVER(ohci_generic) = {
+	.name	= "ohci_generic",
+	.id	= UCLASS_USB,
+	.of_match = ohci_usb_ids,
+	.probe = ohci_usb_probe,
+	.remove = ohci_usb_remove,
+	.ops	= &ohci_usb_ops,
+	.priv_auto	= sizeof(struct generic_ohci),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/ohci-hcd.c b/roms/u-boot/drivers/usb/host/ohci-hcd.c
new file mode 100644
index 000000000..c62d8feec
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-hcd.c
@@ -0,0 +1,2243 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
+ *
+ * Interrupt support is added. Now, it has been tested
+ * on ULI1575 chip and works well with USB keyboard.
+ *
+ * (C) Copyright 2007
+ * Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang@freescale.com>
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
+ * ebenard@eukrea.com - based on s3c24x0's driver
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - Read doc/README.generic_usb_ohci
+ * 2 - this driver is intended for use with USB Mass Storage Devices
+ *     (BBB) and USB keyboard. There is NO support for Isochronous pipes!
+ * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
+ *     to activate workaround for bug #41 or this driver will NOT work!
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <asm/byteorder.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/cache.h>
+#include <linux/delay.h>
+
+#if defined(CONFIG_PCI_OHCI)
+# include <pci.h>
+#if !defined(CONFIG_PCI_OHCI_DEVNO)
+#define CONFIG_PCI_OHCI_DEVNO	0
+#endif
+#endif
+
+#include <malloc.h>
+#include <memalign.h>
+#include <usb.h>
+
+#include "ohci.h"
+
+#ifdef CONFIG_AT91RM9200
+#include <asm/arch/hardware.h>	/* needed for AT91_USB_HOST_BASE */
+#endif
+
+#if defined(CONFIG_CPU_ARM920T) || \
+	defined(CONFIG_PCI_OHCI) || \
+	defined(CONFIG_DM_PCI) || \
+	defined(CONFIG_SYS_OHCI_USE_NPS)
+# define OHCI_USE_NPS		/* force NoPowerSwitching mode */
+#endif
+
+#undef OHCI_VERBOSE_DEBUG	/* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+#ifdef CONFIG_PCI_OHCI
+static struct pci_device_id ohci_pci_ids[] = {
+	{0x10b9, 0x5237},	/* ULI1575 PCI OHCI module ids */
+	{0x1033, 0x0035},	/* NEC PCI OHCI module ids */
+	{0x1131, 0x1561},	/* Philips 1561 PCI OHCI module ids */
+	/* Please add supported PCI OHCI controller ids here */
+	{0, 0}
+};
+#endif
+#endif
+
+#ifdef CONFIG_PCI_EHCI_DEVNO
+static struct pci_device_id ehci_pci_ids[] = {
+	{0x1131, 0x1562},	/* Philips 1562 PCI EHCI module ids */
+	/* Please add supported PCI EHCI controller ids here */
+	{0, 0}
+};
+#endif
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while (0)
+#endif
+
+#ifdef CONFIG_SYS_OHCI_BE_CONTROLLER
+# define m16_swap(x) cpu_to_be16(x)
+# define m32_swap(x) cpu_to_be32(x)
+#else
+# define m16_swap(x) cpu_to_le16(x)
+# define m32_swap(x) cpu_to_le32(x)
+#endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
+
+/* We really should do proper cache flushing everywhere */
+#define flush_dcache_buffer(addr, size) \
+	flush_dcache_range((unsigned long)(addr), \
+		ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
+#define invalidate_dcache_buffer(addr, size) \
+	invalidate_dcache_range((unsigned long)(addr), \
+		ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
+
+/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */
+#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16)
+#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16)
+#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32)
+#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256)
+#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16)
+#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16)
+#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32)
+#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256)
+
+#if CONFIG_IS_ENABLED(DM_USB)
+/*
+ * The various ohci_mdelay(1) calls in the code seem unnecessary. We keep
+ * them around when building for older boards not yet converted to the dm
+ * just in case (to avoid regressions), for dm this turns them into nops.
+ */
+#define ohci_mdelay(x)
+#else
+#define ohci_mdelay(x) mdelay(x)
+#endif
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+#endif
+
+/* mapping of the OHCI CC status to error codes */
+static int cc_to_error[16] = {
+	/* No  Error  */	       0,
+	/* CRC Error  */	       USB_ST_CRC_ERR,
+	/* Bit Stuff  */	       USB_ST_BIT_ERR,
+	/* Data Togg  */	       USB_ST_CRC_ERR,
+	/* Stall      */	       USB_ST_STALLED,
+	/* DevNotResp */	       -1,
+	/* PIDCheck   */	       USB_ST_BIT_ERR,
+	/* UnExpPID   */	       USB_ST_BIT_ERR,
+	/* DataOver   */	       USB_ST_BUF_ERR,
+	/* DataUnder  */	       USB_ST_BUF_ERR,
+	/* reservd    */	       -1,
+	/* reservd    */	       -1,
+	/* BufferOver */	       USB_ST_BUF_ERR,
+	/* BuffUnder  */	       USB_ST_BUF_ERR,
+	/* Not Access */	       -1,
+	/* Not Access */	       -1
+};
+
+static const char *cc_to_string[16] = {
+	"No Error",
+	"CRC: Last data packet from endpoint contained a CRC error.",
+	"BITSTUFFING: Last data packet from endpoint contained a bit " \
+		     "stuffing violation",
+	"DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
+		     "that did not match the expected value.",
+	"STALL: TD was moved to the Done Queue because the endpoint returned" \
+		     " a STALL PID",
+	"DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
+		     "not provide a handshake (OUT)",
+	"PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
+		     "(IN) or handshake (OUT)",
+	"UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
+		     "value is not defined.",
+	"DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
+		     "either the size of the maximum data packet allowed\n" \
+		     "from the endpoint (found in MaximumPacketSize field\n" \
+		     "of ED) or the remaining buffer size.",
+	"DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
+		     "and that amount was not sufficient to fill the\n" \
+		     "specified buffer",
+	"reserved1",
+	"reserved2",
+	"BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
+		     "than it could be written to system memory",
+	"BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
+		     "system memory fast enough to keep up with data USB " \
+		     "data rate.",
+	"NOT ACCESSED: This code is set by software before the TD is placed" \
+		     "on a list to be processed by the HC.(1)",
+	"NOT ACCESSED: This code is set by software before the TD is placed" \
+		     "on a list to be processed by the HC.(2)",
+};
+
+static inline u32 roothub_a(struct ohci *hc)
+	{ return ohci_readl(&hc->regs->roothub.a); }
+static inline u32 roothub_b(struct ohci *hc)
+	{ return ohci_readl(&hc->regs->roothub.b); }
+static inline u32 roothub_status(struct ohci *hc)
+	{ return ohci_readl(&hc->regs->roothub.status); }
+static inline u32 roothub_portstatus(struct ohci *hc, int i)
+	{ return ohci_readl(&hc->regs->roothub.portstatus[i]); }
+
+/* forward declaration */
+static int hc_interrupt(ohci_t *ohci);
+static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
+			  unsigned long pipe, void *buffer, int transfer_len,
+			  struct devrequest *setup, urb_priv_t *urb,
+			  int interval);
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
+		       unsigned long pipe, int interval, int load);
+
+/*-------------------------------------------------------------------------*/
+
+/* TDs ... */
+static struct td *td_alloc(ohci_dev_t *ohci_dev, struct usb_device *usb_dev)
+{
+	int i;
+	struct td *td;
+
+	td = NULL;
+	for (i = 0; i < NUM_TD; i++)
+	{
+		if (ohci_dev->tds[i].usb_dev == NULL)
+		{
+			td = &ohci_dev->tds[i];
+			td->usb_dev = usb_dev;
+			break;
+		}
+	}
+
+	return td;
+}
+
+static inline void ed_free(struct ed *ed)
+{
+	ed->usb_dev = NULL;
+}
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv(urb_priv_t *urb)
+{
+	int		i;
+	int		last;
+	struct td	*td;
+
+	last = urb->length - 1;
+	if (last >= 0) {
+		for (i = 0; i <= last; i++) {
+			td = urb->td[i];
+			if (td) {
+				td->usb_dev = NULL;
+				urb->td[i] = NULL;
+			}
+		}
+	}
+	free(urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number(ohci_t *ohci);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print(ohci_t *ohci, urb_priv_t *purb, struct usb_device *dev,
+		      unsigned long pipe, void *buffer, int transfer_len,
+		      struct devrequest *setup, char *str, int small)
+{
+	dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
+			str,
+			sohci_get_current_frame_number(ohci),
+			usb_pipedevice(pipe),
+			usb_pipeendpoint(pipe),
+			usb_pipeout(pipe)? 'O': 'I',
+			usb_pipetype(pipe) < 2 ? \
+				(usb_pipeint(pipe)? "INTR": "ISOC"): \
+				(usb_pipecontrol(pipe)? "CTRL": "BULK"),
+			(purb ? purb->actual_length : 0),
+			transfer_len, dev->status);
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol(pipe)) {
+			printf(__FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++)
+				printf(" %02x", ((__u8 *) setup) [i]);
+			printf("\n");
+		}
+		if (transfer_len > 0 && buffer) {
+			printf(__FILE__ ": data(%d/%d):",
+				(purb ? purb->actual_length : 0),
+				transfer_len);
+			len = usb_pipeout(pipe)? transfer_len:
+					(purb ? purb->actual_length : 0);
+			for (i = 0; i < 16 && i < len; i++)
+				printf(" %02x", ((__u8 *) buffer) [i]);
+			printf("%s\n", i < len? "...": "");
+		}
+	}
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree
+ * inclusive iso eds */
+void ep_print_int_eds(ohci_t *ohci, char *str)
+{
+	int i, j;
+	 __u32 *ed_p;
+	for (i = 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		invalidate_dcache_ed(ed_p);
+		printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+		while (*ed_p != 0 && j--) {
+			ed_t *ed = (ed_t *)m32_swap(ed_p);
+			invalidate_dcache_ed(ed);
+			printf(" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printf("\n");
+	}
+}
+
+static void ohci_dump_intr_mask(char *label, __u32 mask)
+{
+	dbg("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds(char *label, __u32 value)
+{
+	ed_t *edp = (ed_t *)value;
+
+	if (value) {
+		dbg("%s %08x", label, value);
+		invalidate_dcache_ed(edp);
+		dbg("%08x", edp->hwINFO);
+		dbg("%08x", edp->hwTailP);
+		dbg("%08x", edp->hwHeadP);
+		dbg("%08x", edp->hwNextED);
+	}
+}
+
+static char *hcfs2string(int state)
+{
+	switch (state) {
+	case OHCI_USB_RESET:	return "reset";
+	case OHCI_USB_RESUME:	return "resume";
+	case OHCI_USB_OPER:	return "operational";
+	case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status(ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = ohci_readl(&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = ohci_readl(&regs->control);
+	dbg("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string(temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = ohci_readl(&regs->cmdstatus);
+	dbg("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask("intrstatus", ohci_readl(&regs->intrstatus));
+	ohci_dump_intr_mask("intrenable", ohci_readl(&regs->intrenable));
+
+	maybe_print_eds("ed_periodcurrent",
+			ohci_readl(&regs->ed_periodcurrent));
+
+	maybe_print_eds("ed_controlhead", ohci_readl(&regs->ed_controlhead));
+	maybe_print_eds("ed_controlcurrent",
+			ohci_readl(&regs->ed_controlcurrent));
+
+	maybe_print_eds("ed_bulkhead", ohci_readl(&regs->ed_bulkhead));
+	maybe_print_eds("ed_bulkcurrent", ohci_readl(&regs->ed_bulkcurrent));
+
+	maybe_print_eds("donehead", ohci_readl(&regs->donehead));
+}
+
+static void ohci_dump_roothub(ohci_t *controller, int verbose)
+{
+	__u32			temp, ndp, i;
+
+	temp = roothub_a(controller);
+	ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+	ndp = (ndp == 2) ? 1:0;
+#endif
+	if (verbose) {
+		dbg("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = roothub_b(controller);
+		dbg("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status(controller);
+		dbg("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus(controller, i);
+		dbg("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump(ohci_t *controller, int verbose)
+{
+	dbg("OHCI controller usb-%s state", controller->slot_name);
+
+	/* dumps some of the state we know about */
+	ohci_dump_status(controller);
+	if (verbose)
+		ep_print_int_eds(controller, "hcca");
+	invalidate_dcache_hcca(controller->hcca);
+	dbg("hcca frame #%04x", controller->hcca->frame_no);
+	ohci_dump_roothub(controller, 1);
+}
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(ohci_t *ohci, ohci_dev_t *ohci_dev, urb_priv_t *urb,
+		     struct devrequest *setup)
+{
+	ed_t *ed;
+	urb_priv_t *purb_priv = urb;
+	int i, size = 0;
+	struct usb_device *dev = urb->dev;
+	unsigned long pipe = urb->pipe;
+	void *buffer = urb->transfer_buffer;
+	int transfer_len = urb->transfer_buffer_length;
+	int interval = urb->interval;
+
+	/* when controller's hung, permit only roothub cleanup attempts
+	 * such as powering down ports */
+	if (ohci->disabled) {
+		err("sohci_submit_job: EPIPE");
+		return -1;
+	}
+
+	/* we're about to begin a new transaction here so mark the
+	 * URB unfinished */
+	urb->finished = 0;
+
+	/* every endpoint has a ed, locate and fill it */
+	ed = ep_add_ed(ohci_dev, dev, pipe, interval, 1);
+	if (!ed) {
+		err("sohci_submit_job: ENOMEM");
+		return -1;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype(pipe)) {
+	case PIPE_BULK: /* one TD for every 4096 Byte */
+		size = (transfer_len - 1) / 4096 + 1;
+		break;
+	case PIPE_CONTROL:/* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+		size = (transfer_len == 0)? 2:
+					(transfer_len - 1) / 4096 + 3;
+		break;
+	case PIPE_INTERRUPT: /* 1 TD */
+		size = 1;
+		break;
+	}
+
+	ed->purb = urb;
+
+	if (size >= (N_URB_TD - 1)) {
+		err("need %d TDs, only have %d", size, N_URB_TD);
+		return -1;
+	}
+	purb_priv->pipe = pipe;
+
+	/* fill the private part of the URB */
+	purb_priv->length = size;
+	purb_priv->ed = ed;
+	purb_priv->actual_length = 0;
+
+	/* allocate the TDs */
+	/* note that td[0] was allocated in ep_add_ed */
+	for (i = 0; i < size; i++) {
+		purb_priv->td[i] = td_alloc(ohci_dev, dev);
+		if (!purb_priv->td[i]) {
+			purb_priv->length = i;
+			urb_free_priv(purb_priv);
+			err("sohci_submit_job: ENOMEM");
+			return -1;
+		}
+	}
+
+	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_free_priv(purb_priv);
+		err("sohci_submit_job: EINVAL");
+		return -1;
+	}
+
+	/* link the ed into a chain if is not already */
+	if (ed->state != ED_OPER)
+		ep_link(ohci, ed);
+
+	/* fill the TDs and link it to the ed */
+	td_submit_job(ohci, dev, pipe, buffer, transfer_len,
+		      setup, purb_priv, interval);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+static int sohci_get_current_frame_number(ohci_t *ohci)
+{
+	invalidate_dcache_hcca(ohci->hcca);
+	return m16_swap(ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* search for the right branch to insert an interrupt ed into the int tree
+ * do some load ballancing;
+ * returns the branch and
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance(ohci_t *ohci, int interval, int load)
+{
+	int i, branch = 0;
+
+	/* search for the least loaded interrupt endpoint
+	 * branch of all 32 branches
+	 */
+	for (i = 0; i < 32; i++)
+		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+			branch = i;
+
+	branch = branch % interval;
+	for (i = branch; i < 32; i += interval)
+		ohci->ohci_int_load [i] += load;
+
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+static int ep_2_n_interval(int inter)
+{
+	int i;
+	for (i = 0; ((inter >> i) > 1) && (i < 5); i++);
+	return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree
+ * in order to process it sequentially the indexes of the branches have to
+ * be mapped the mapping reverses the bits of a word of num_bits length */
+static int ep_rev(int num_bits, int word)
+{
+	int i, wout = 0;
+
+	for (i = 0; i < num_bits; i++)
+		wout |= (((word >> i) & 1) << (num_bits - i - 1));
+	return wout;
+}
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link(ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+	int int_branch;
+	int i;
+	int inter;
+	int interval;
+	int load;
+	__u32 *ed_p;
+
+	ed->state = ED_OPER;
+	ed->int_interval = 0;
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+		flush_dcache_ed(ed);
+		if (ohci->ed_controltail == NULL)
+			ohci_writel((uintptr_t)ed, &ohci->regs->ed_controlhead);
+		else
+			ohci->ed_controltail->hwNextED =
+						   m32_swap((unsigned long)ed);
+
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			ohci_writel(ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_controltail = edi;
+		break;
+
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+		flush_dcache_ed(ed);
+		if (ohci->ed_bulktail == NULL)
+			ohci_writel((uintptr_t)ed, &ohci->regs->ed_bulkhead);
+		else
+			ohci->ed_bulktail->hwNextED =
+						   m32_swap((unsigned long)ed);
+
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			ohci_writel(ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_bulktail = edi;
+		break;
+
+	case PIPE_INTERRUPT:
+		load = ed->int_load;
+		interval = ep_2_n_interval(ed->int_period);
+		ed->int_interval = interval;
+		int_branch = ep_int_ballance(ohci, interval, load);
+		ed->int_branch = int_branch;
+
+		for (i = 0; i < ep_rev(6, interval); i += inter) {
+			inter = 1;
+			for (ed_p = &(ohci->hcca->int_table[\
+						ep_rev(5, i) + int_branch]);
+				(*ed_p != 0) &&
+				(((ed_t *)ed_p)->int_interval >= interval);
+				ed_p = &(((ed_t *)ed_p)->hwNextED))
+					inter = ep_rev(6,
+						 ((ed_t *)ed_p)->int_interval);
+			ed->hwNextED = *ed_p;
+			flush_dcache_ed(ed);
+			*ed_p = m32_swap((unsigned long)ed);
+			flush_dcache_hcca(ohci->hcca);
+		}
+		break;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
+			    unsigned index, unsigned period)
+{
+	__maybe_unused unsigned long aligned_ed_p;
+
+	for (; index < NUM_INTS; index += period) {
+		__u32	*ed_p = &ohci->hcca->int_table [index];
+
+		/* ED might have been unlinked through another path */
+		while (*ed_p != 0) {
+			if (((struct ed *)(uintptr_t)
+					m32_swap((unsigned long)ed_p)) == ed) {
+				*ed_p = ed->hwNextED;
+				aligned_ed_p = (unsigned long)ed_p;
+				aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1);
+				flush_dcache_range(aligned_ed_p,
+					aligned_ed_p + ARCH_DMA_MINALIGN);
+				break;
+			}
+			ed_p = &(((struct ed *)(uintptr_t)
+				     m32_swap((unsigned long)ed_p))->hwNextED);
+		}
+	}
+}
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink(ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+	int i;
+
+	ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
+	flush_dcache_ed(ed);
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				ohci_writel(ohci->hc_control,
+					    &ohci->regs->control);
+			}
+			ohci_writel(m32_swap(*((__u32 *)&ed->hwNextED)),
+				&ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+			flush_dcache_ed(ed->ed_prev);
+		}
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			((ed_t *)(uintptr_t)m32_swap(
+			    *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				ohci_writel(ohci->hc_control,
+					    &ohci->regs->control);
+			}
+			ohci_writel(m32_swap(*((__u32 *)&ed->hwNextED)),
+			       &ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+			flush_dcache_ed(ed->ed_prev);
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			((ed_t *)(uintptr_t)m32_swap(
+			     *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		periodic_unlink(ohci, ed, 0, 1);
+		for (i = ed->int_branch; i < 32; i += ed->int_interval)
+		    ohci->ohci_int_load[i] -= ed->int_load;
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the
+ * usb_set_configuration command, but the USB stack is a little bit
+ * stateless so we do it at every transaction if the state of the ed
+ * is ED_NEW then a dummy td is added and the state is changed to
+ * ED_UNLINK in all other cases the state is left unchanged the ed
+ * info fields are setted anyway even though most of them should not
+ * change
+ */
+static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
+		       unsigned long pipe, int interval, int load)
+{
+	td_t *td;
+	ed_t *ed_ret;
+	volatile ed_t *ed;
+
+	ed = ed_ret = &ohci_dev->ed[(usb_pipeendpoint(pipe) << 1) |
+			(usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+		err("ep_add_ed: pending delete");
+		/* pending delete request */
+		return NULL;
+	}
+
+	if (ed->state == ED_NEW) {
+		/* dummy td; end of td list for ed */
+		td = td_alloc(ohci_dev, usb_dev);
+		ed->hwTailP = m32_swap((unsigned long)td);
+		ed->hwHeadP = ed->hwTailP;
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype(pipe);
+		ohci_dev->ed_cnt++;
+	}
+
+	ed->hwINFO = m32_swap(usb_pipedevice(pipe)
+			| usb_pipeendpoint(pipe) << 7
+			| (usb_pipeisoc(pipe)? 0x8000: 0)
+			| (usb_pipecontrol(pipe)? 0: \
+					   (usb_pipeout(pipe)? 0x800: 0x1000))
+			| (usb_dev->speed == USB_SPEED_LOW) << 13
+			| usb_maxpacket(usb_dev, pipe) << 16);
+
+	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+		ed->int_period = interval;
+		ed->int_load = load;
+	}
+
+	flush_dcache_ed(ed);
+
+	return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill(ohci_t *ohci, unsigned int info,
+	void *data, int len,
+	struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+	volatile td_t  *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+	int i;
+#endif
+
+	if (index > urb_priv->length) {
+		err("index > length");
+		return;
+	}
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+	flush_dcache_td(td_pt);
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] =
+			     (td_t *)(uintptr_t)
+			     (m32_swap(urb_priv->ed->hwTailP) & ~0xf);
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->data = (uintptr_t)data;
+#ifdef OHCI_FILL_TRACE
+	if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
+		for (i = 0; i < len; i++)
+		printf("td->data[%d] %#2x ", i, ((unsigned char *)td->data)[i]);
+		printf("\n");
+	}
+#endif
+	if (!len)
+		data = 0;
+
+	td->hwINFO = m32_swap(info);
+	td->hwCBP = m32_swap((unsigned long)data);
+	if (data)
+		td->hwBE = m32_swap((unsigned long)(data + len - 1));
+	else
+		td->hwBE = 0;
+
+	td->hwNextTD = m32_swap((unsigned long)td_pt);
+	flush_dcache_td(td);
+
+	/* append to queue */
+	td->ed->hwTailP = td->hwNextTD;
+	flush_dcache_ed(td->ed);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
+			  unsigned long pipe, void *buffer, int transfer_len,
+			  struct devrequest *setup, urb_priv_t *urb,
+			  int interval)
+{
+	int data_len = transfer_len;
+	void *data;
+	int cnt = 0;
+	__u32 info = 0;
+	unsigned int toggle = 0;
+
+	flush_dcache_buffer(buffer, data_len);
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle
+	 * bits for resetting */
+	if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+		toggle = TD_T_TOGGLE;
+	} else {
+		toggle = TD_T_DATA0;
+		usb_settoggle(dev, usb_pipeendpoint(pipe),
+				usb_pipeout(pipe), 1);
+	}
+	urb->td_cnt = 0;
+	if (data_len)
+		data = buffer;
+	else
+		data = 0;
+
+	switch (usb_pipetype(pipe)) {
+	case PIPE_BULK:
+		info = usb_pipeout(pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+		while (data_len > 4096) {
+			td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle),
+				data, 4096, dev, cnt, urb);
+			data += 4096; data_len -= 4096; cnt++;
+		}
+		info = usb_pipeout(pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+		td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle), data,
+			data_len, dev, cnt, urb);
+		cnt++;
+
+		if (!ohci->sleeping) {
+			/* start bulk list */
+			ohci_writel(OHCI_BLF, &ohci->regs->cmdstatus);
+		}
+		break;
+
+	case PIPE_CONTROL:
+		/* Setup phase */
+		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		flush_dcache_buffer(setup, 8);
+		td_fill(ohci, info, setup, 8, dev, cnt++, urb);
+
+		/* Optional Data phase */
+		if (data_len > 0) {
+			info = usb_pipeout(pipe)?
+				TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 :
+				TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+			/* NOTE:  mishandles transfers >8K, some >4K */
+			td_fill(ohci, info, data, data_len, dev, cnt++, urb);
+		}
+
+		/* Status phase */
+		info = (usb_pipeout(pipe) || data_len == 0) ?
+			TD_CC | TD_DP_IN | TD_T_DATA1:
+			TD_CC | TD_DP_OUT | TD_T_DATA1;
+		td_fill(ohci, info, data, 0, dev, cnt++, urb);
+
+		if (!ohci->sleeping) {
+			/* start Control list */
+			ohci_writel(OHCI_CLF, &ohci->regs->cmdstatus);
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		info = usb_pipeout(urb->pipe)?
+			TD_CC | TD_DP_OUT | toggle:
+			TD_CC | TD_R | TD_DP_IN | toggle;
+		td_fill(ohci, info, data, data_len, dev, cnt++, urb);
+		break;
+	}
+	if (urb->length != cnt)
+		dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t *td)
+{
+	__u32 tdBE, tdCBP;
+	urb_priv_t *lurb_priv = td->ed->purb;
+
+	tdBE   = m32_swap(td->hwBE);
+	tdCBP  = m32_swap(td->hwCBP);
+
+	if (!(usb_pipecontrol(lurb_priv->pipe) &&
+	    ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+		if (tdBE != 0) {
+			if (td->hwCBP == 0)
+				lurb_priv->actual_length += tdBE - td->data + 1;
+			else
+				lurb_priv->actual_length += tdCBP - td->data;
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+static void check_status(td_t *td_list)
+{
+	urb_priv_t *lurb_priv = td_list->ed->purb;
+	int	   urb_len    = lurb_priv->length;
+	__u32      *phwHeadP  = &td_list->ed->hwHeadP;
+	int	   cc;
+
+	cc = TD_CC_GET(m32_swap(td_list->hwINFO));
+	if (cc) {
+		err(" USB-error: %s (%x)", cc_to_string[cc], cc);
+
+		invalidate_dcache_ed(td_list->ed);
+		if (*phwHeadP & m32_swap(0x1)) {
+			if (lurb_priv &&
+			    ((td_list->index + 1) < urb_len)) {
+				*phwHeadP =
+					(lurb_priv->td[urb_len - 1]->hwNextTD &\
+							m32_swap(0xfffffff0)) |
+						   (*phwHeadP & m32_swap(0x2));
+
+				lurb_priv->td_cnt += urb_len -
+						     td_list->index - 1;
+			} else
+				*phwHeadP &= m32_swap(0xfffffff2);
+			flush_dcache_ed(td_list->ed);
+		}
+	}
+}
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+static td_t *dl_reverse_done_list(ohci_t *ohci)
+{
+	uintptr_t td_list_hc;
+	td_t *td_rev = NULL;
+	td_t *td_list = NULL;
+
+	invalidate_dcache_hcca(ohci->hcca);
+	td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
+	flush_dcache_hcca(ohci->hcca);
+
+	while (td_list_hc) {
+		td_list = (td_t *)td_list_hc;
+		invalidate_dcache_td(td_list);
+		check_status(td_list);
+		td_list->next_dl_td = td_rev;
+		td_rev = td_list;
+		td_list_hc = m32_swap(td_list->hwNextTD) & 0xfffffff0;
+	}
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+
+static void finish_urb(ohci_t *ohci, urb_priv_t *urb, int status)
+{
+	if ((status & (ED_OPER | ED_UNLINK)) && (urb->state != URB_DEL))
+		urb->finished = 1;
+	else
+		dbg("finish_urb: strange.., ED state %x, \n", status);
+}
+
+/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static int takeback_td(ohci_t *ohci, td_t *td_list)
+{
+	ed_t *ed;
+	int cc;
+	int stat = 0;
+	/* urb_t *urb; */
+	urb_priv_t *lurb_priv;
+	__u32 tdINFO, edHeadP, edTailP;
+
+	invalidate_dcache_td(td_list);
+	tdINFO = m32_swap(td_list->hwINFO);
+
+	ed = td_list->ed;
+	lurb_priv = ed->purb;
+
+	dl_transfer_length(td_list);
+
+	lurb_priv->td_cnt++;
+
+	/* error code of transfer */
+	cc = TD_CC_GET(tdINFO);
+	if (cc) {
+		err("USB-error: %s (%x)", cc_to_string[cc], cc);
+		stat = cc_to_error[cc];
+	}
+
+	/* see if this done list makes for all TD's of current URB,
+	* and mark the URB finished if so */
+	if (lurb_priv->td_cnt == lurb_priv->length)
+		finish_urb(ohci, lurb_priv, ed->state);
+
+	dbg("dl_done_list: processing TD %x, len %x\n",
+		lurb_priv->td_cnt, lurb_priv->length);
+
+	if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
+		invalidate_dcache_ed(ed);
+		edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
+		edTailP = m32_swap(ed->hwTailP);
+
+		/* unlink eds if they are not busy */
+		if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+			ep_unlink(ohci, ed);
+	}
+	return stat;
+}
+
+static int dl_done_list(ohci_t *ohci)
+{
+	int stat = 0;
+	td_t	*td_list = dl_reverse_done_list(ohci);
+
+	while (td_list) {
+		td_t	*td_next = td_list->next_dl_td;
+		stat = takeback_td(ohci, td_list);
+		td_list = td_next;
+	}
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+#include <usbroothubdes.h>
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x)			len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x)		{info("WR:status %#8x", (x)); ohci_writel((x), \
+						&ohci->regs->roothub.status); }
+#define WR_RH_PORTSTAT(x)	{info("WR:portstatus[%d] %#8x", wIndex-1, \
+	(x)); ohci_writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); }
+#else
+#define WR_RH_STAT(x)		ohci_writel((x), &ohci->regs->roothub.status)
+#define WR_RH_PORTSTAT(x)	ohci_writel((x), \
+				    &ohci->regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT		roothub_status(ohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(ohci, wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+	__u32 temp, ndp, i;
+	int res;
+
+	res = -1;
+	temp = roothub_a(controller);
+	ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+	ndp = (ndp == 2) ? 1:0;
+#endif
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus(controller, i);
+		/* check for a device disconnect */
+		if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+			(RH_PS_PESC | RH_PS_CSC)) &&
+			((temp & RH_PS_CCS) == 0)) {
+			res = i;
+			break;
+		}
+	}
+	return res;
+}
+
+static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev,
+	unsigned long pipe, void *buffer, int transfer_len,
+	struct devrequest *cmd)
+{
+	void *data = buffer;
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+	ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32));
+
+#ifdef DEBUG
+pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
+	  cmd, "SUB(rh)", usb_pipein(pipe));
+#else
+	ohci_mdelay(1);
+#endif
+	if (usb_pipeint(pipe)) {
+		info("Root-Hub submit IRQ: NOT implemented");
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+	wValue	      = le16_to_cpu(cmd->value);
+	wIndex	      = le16_to_cpu(cmd->index);
+	wLength	      = le16_to_cpu(cmd->length);
+
+	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device,
+	   RH_INTERFACE: interface,
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here,
+	   RH_OTHER | RH_CLASS	almost ever means HUB_PORT here
+	*/
+
+	case RH_GET_STATUS:
+		*(u16 *)databuf = cpu_to_le16(1);
+		OK(2);
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(u16 *)databuf = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(u16 *)databuf = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_CLASS:
+		*(u32 *)databuf = cpu_to_le32(
+				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+		OK(4);
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		*(u32 *)databuf = cpu_to_le32(RD_RH_PORTSTAT);
+		OK(4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK(0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			OK(0);
+		case (RH_C_HUB_OVER_CURRENT):
+			WR_RH_STAT(RH_HS_OCIC);
+			OK(0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):        WR_RH_PORTSTAT(RH_PS_CCS);  OK(0);
+		case (RH_PORT_SUSPEND):       WR_RH_PORTSTAT(RH_PS_POCI); OK(0);
+		case (RH_PORT_POWER):         WR_RH_PORTSTAT(RH_PS_LSDA); OK(0);
+		case (RH_C_PORT_CONNECTION):  WR_RH_PORTSTAT(RH_PS_CSC);  OK(0);
+		case (RH_C_PORT_ENABLE):      WR_RH_PORTSTAT(RH_PS_PESC); OK(0);
+		case (RH_C_PORT_SUSPEND):     WR_RH_PORTSTAT(RH_PS_PSSC); OK(0);
+		case (RH_C_PORT_OVER_CURRENT):WR_RH_PORTSTAT(RH_PS_OCIC); OK(0);
+		case (RH_C_PORT_RESET):       WR_RH_PORTSTAT(RH_PS_PRSC); OK(0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			WR_RH_PORTSTAT(RH_PS_PSS);  OK(0);
+		case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+			if (RD_RH_PORTSTAT & RH_PS_CCS)
+				WR_RH_PORTSTAT(RH_PS_PRS);
+			OK(0);
+		case (RH_PORT_POWER):
+			WR_RH_PORTSTAT(RH_PS_PPS);
+			OK(0);
+		case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+			if (RD_RH_PORTSTAT & RH_PS_CCS)
+				WR_RH_PORTSTAT(RH_PS_PES);
+			OK(0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		ohci->rh.devnum = wValue;
+		OK(0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01): /* device descriptor */
+			len = min_t(unsigned int,
+					leni,
+					min_t(unsigned int,
+					sizeof(root_hub_dev_des),
+					wLength));
+			databuf = root_hub_dev_des; OK(len);
+		case (0x02): /* configuration descriptor */
+			len = min_t(unsigned int,
+					leni,
+					min_t(unsigned int,
+					sizeof(root_hub_config_des),
+					wLength));
+			databuf = root_hub_config_des; OK(len);
+		case (0x03): /* string descriptors */
+			if (wValue == 0x0300) {
+				len = min_t(unsigned int,
+						leni,
+						min_t(unsigned int,
+						sizeof(root_hub_str_index0),
+						wLength));
+				databuf = root_hub_str_index0;
+				OK(len);
+			}
+			if (wValue == 0x0301) {
+				len = min_t(unsigned int,
+						leni,
+						min_t(unsigned int,
+						sizeof(root_hub_str_index1),
+						wLength));
+				databuf = root_hub_str_index1;
+				OK(len);
+		}
+		default:
+			stat = USB_ST_STALLED;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+	{
+		__u32 temp = roothub_a(ohci);
+
+		databuf[0] = 9;		/* min length; */
+		databuf[1] = 0x29;
+		databuf[2] = temp & RH_A_NDP;
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+		databuf[2] = (databuf[2] == 2) ? 1 : 0;
+#endif
+		databuf[3] = 0;
+		if (temp & RH_A_PSM)	/* per-port power switching? */
+			databuf[3] |= 0x1;
+		if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+			databuf[3] |= 0x10;
+		else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
+			databuf[3] |= 0x8;
+
+		databuf[4] = 0;
+		databuf[5] = (temp & RH_A_POTPGT) >> 24;
+		databuf[6] = 0;
+		temp = roothub_b(ohci);
+		databuf[7] = temp & RH_B_DR;
+		if (databuf[2] < 7) {
+			databuf[8] = 0xff;
+		} else {
+			databuf[0] += 2;
+			databuf[8] = (temp & RH_B_DR) >> 8;
+			databuf[10] = databuf[9] = 0xff;
+		}
+
+		len = min_t(unsigned int, leni,
+			    min_t(unsigned int, databuf[0], wLength));
+		OK(len);
+	}
+
+	case RH_GET_CONFIGURATION:
+		databuf[0] = 0x01;
+		OK(1);
+
+	case RH_SET_CONFIGURATION:
+		WR_RH_STAT(0x10000);
+		OK(0);
+
+	default:
+		dbg("unsupported root hub command");
+		stat = USB_ST_STALLED;
+	}
+
+#ifdef	DEBUG
+	ohci_dump_roothub(ohci, 1);
+#else
+	ohci_mdelay(1);
+#endif
+
+	len = min_t(int, len, leni);
+	if (data != databuf)
+		memcpy(data, databuf, len);
+	dev->act_len = len;
+	dev->status = stat;
+
+#ifdef DEBUG
+	pkt_print(ohci, NULL, dev, pipe, buffer,
+		  transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#else
+	ohci_mdelay(1);
+#endif
+
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ohci_dev_t *ohci_get_ohci_dev(ohci_t *ohci, int devnum, int intr)
+{
+	int i;
+
+	if (!intr)
+		return &ohci->ohci_dev;
+
+	/* First see if we already have an ohci_dev for this dev. */
+	for (i = 0; i < NUM_INT_DEVS; i++) {
+		if (ohci->int_dev[i].devnum == devnum)
+			return &ohci->int_dev[i];
+	}
+
+	/* If not then find a free one. */
+	for (i = 0; i < NUM_INT_DEVS; i++) {
+		if (ohci->int_dev[i].devnum == -1) {
+			ohci->int_dev[i].devnum = devnum;
+			return &ohci->int_dev[i];
+		}
+	}
+
+	printf("ohci: Error out of ohci_devs for interrupt endpoints\n");
+	return NULL;
+}
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+static urb_priv_t *ohci_alloc_urb(struct usb_device *dev, unsigned long pipe,
+		void *buffer, int transfer_len, int interval)
+{
+	urb_priv_t *urb;
+
+	urb = calloc(1, sizeof(urb_priv_t));
+	if (!urb) {
+		printf("ohci: Error out of memory allocating urb\n");
+		return NULL;
+	}
+
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->transfer_buffer = buffer;
+	urb->transfer_buffer_length = transfer_len;
+	urb->interval = interval;
+
+	return urb;
+}
+
+static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
+		unsigned long pipe, void *buffer, int transfer_len,
+		struct devrequest *setup, int interval)
+{
+	int stat = 0;
+	int maxsize = usb_maxpacket(dev, pipe);
+	int timeout;
+	urb_priv_t *urb;
+	ohci_dev_t *ohci_dev;
+
+	urb = ohci_alloc_urb(dev, pipe, buffer, transfer_len, interval);
+	if (!urb)
+		return -ENOMEM;
+
+#ifdef DEBUG
+	urb->actual_length = 0;
+	pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
+		  setup, "SUB", usb_pipein(pipe));
+#else
+	ohci_mdelay(1);
+#endif
+	if (!maxsize) {
+		err("submit_common_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+
+	ohci_dev = ohci_get_ohci_dev(ohci, dev->devnum, usb_pipeint(pipe));
+	if (!ohci_dev)
+		return -ENOMEM;
+
+	if (sohci_submit_job(ohci, ohci_dev, urb, setup) < 0) {
+		err("sohci_submit_job failed");
+		return -1;
+	}
+
+	mdelay(10);
+	/* ohci_dump_status(ohci); */
+
+	timeout = USB_TIMEOUT_MS(pipe);
+
+	/* wait for it to complete */
+	for (;;) {
+		/* check whether the controller is done */
+		stat = hc_interrupt(ohci);
+		if (stat < 0) {
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+
+		/* NOTE: since we are not interrupt driven in U-Boot and always
+		 * handle only one URB at a time, we cannot assume the
+		 * transaction finished on the first successful return from
+		 * hc_interrupt().. unless the flag for current URB is set,
+		 * meaning that all TD's to/from device got actually
+		 * transferred and processed. If the current URB is not
+		 * finished we need to re-iterate this loop so as
+		 * hc_interrupt() gets called again as there needs to be some
+		 * more TD's to process still */
+		if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
+			/* 0xff is returned for an SF-interrupt */
+			break;
+		}
+
+		if (--timeout) {
+			mdelay(1);
+			if (!urb->finished)
+				dbg("*");
+
+		} else {
+			if (!usb_pipeint(pipe))
+				err("CTL:TIMEOUT ");
+			dbg("submit_common_msg: TO status %x\n", stat);
+			urb->finished = 1;
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+	}
+
+	dev->status = stat;
+	dev->act_len = urb->actual_length;
+
+	if (usb_pipein(pipe) && dev->status == 0 && dev->act_len)
+		invalidate_dcache_buffer(buffer, dev->act_len);
+
+#ifdef DEBUG
+	pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
+		  setup, "RET(ctlr)", usb_pipein(pipe));
+#else
+	ohci_mdelay(1);
+#endif
+	urb_free_priv(urb);
+	return 0;
+}
+
+#define MAX_INT_QUEUESIZE 8
+
+struct int_queue {
+	int queuesize;
+	int curr_urb;
+	urb_priv_t *urb[MAX_INT_QUEUESIZE];
+};
+
+static struct int_queue *_ohci_create_int_queue(ohci_t *ohci,
+		struct usb_device *udev, unsigned long pipe, int queuesize,
+		int elementsize, void *buffer, int interval)
+{
+	struct int_queue *queue;
+	ohci_dev_t *ohci_dev;
+	int i;
+
+	if (queuesize > MAX_INT_QUEUESIZE)
+		return NULL;
+
+	ohci_dev = ohci_get_ohci_dev(ohci, udev->devnum, 1);
+	if (!ohci_dev)
+		return NULL;
+
+	queue = malloc(sizeof(*queue));
+	if (!queue) {
+		printf("ohci: Error out of memory allocating int queue\n");
+		return NULL;
+	}
+
+	for (i = 0; i < queuesize; i++) {
+		queue->urb[i] = ohci_alloc_urb(udev, pipe,
+					       buffer + i * elementsize,
+					       elementsize, interval);
+		if (!queue->urb[i])
+			break;
+
+		if (sohci_submit_job(ohci, ohci_dev, queue->urb[i], NULL)) {
+			printf("ohci: Error submitting int queue job\n");
+			urb_free_priv(queue->urb[i]);
+			break;
+		}
+	}
+	if (i == 0) {
+		/* We did not succeed in submitting even 1 urb */
+		free(queue);
+		return NULL;
+	}
+
+	queue->queuesize = i;
+	queue->curr_urb = 0;
+
+	return queue;
+}
+
+static void *_ohci_poll_int_queue(ohci_t *ohci, struct usb_device *udev,
+				  struct int_queue *queue)
+{
+	if (queue->curr_urb == queue->queuesize)
+		return NULL; /* Queue depleted */
+
+	if (hc_interrupt(ohci) < 0)
+		return NULL;
+
+	if (queue->urb[queue->curr_urb]->finished) {
+		void *ret = queue->urb[queue->curr_urb]->transfer_buffer;
+		queue->curr_urb++;
+		return ret;
+	}
+
+	return NULL;
+}
+
+static int _ohci_destroy_int_queue(ohci_t *ohci, struct usb_device *dev,
+				   struct int_queue *queue)
+{
+	int i;
+
+	for (i = 0; i < queue->queuesize; i++)
+		urb_free_priv(queue->urb[i]);
+
+	free(queue);
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len)
+{
+	info("submit_bulk_msg");
+	return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len,
+				 NULL, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, int interval, bool nonblock)
+{
+	info("submit_int_msg");
+	return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL,
+			interval);
+}
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+		unsigned long pipe, int queuesize, int elementsize,
+		void *buffer, int interval)
+{
+	return _ohci_create_int_queue(&gohci, dev, pipe, queuesize,
+				      elementsize, buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _ohci_poll_int_queue(&gohci, dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _ohci_destroy_int_queue(&gohci, dev, queue);
+}
+#endif
+
+static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev,
+	unsigned long pipe, void *buffer, int transfer_len,
+	struct devrequest *setup)
+{
+	int maxsize = usb_maxpacket(dev, pipe);
+
+	info("submit_control_msg");
+#ifdef DEBUG
+	pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
+		  setup, "SUB", usb_pipein(pipe));
+#else
+	ohci_mdelay(1);
+#endif
+	if (!maxsize) {
+		err("submit_control_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+	if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) {
+		ohci->rh.dev = dev;
+		/* root hub - redirect */
+		return ohci_submit_rh_msg(ohci, dev, pipe, buffer,
+					  transfer_len, setup);
+	}
+
+	return submit_common_msg(ohci, dev, pipe, buffer, transfer_len,
+				 setup, 0);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset(ohci_t *ohci)
+{
+#ifdef CONFIG_PCI_EHCI_DEVNO
+	pci_dev_t pdev;
+#endif
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+
+	dbg("%s\n", __FUNCTION__);
+
+#ifdef CONFIG_PCI_EHCI_DEVNO
+	/*
+	 *  Some multi-function controllers (e.g. ISP1562) allow root hub
+	 * resetting via EHCI registers only.
+	 */
+	pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVNO);
+	if (pdev != -1) {
+		u32 base;
+		int timeout = 1000;
+
+		pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+		base += EHCI_USBCMD_OFF;
+		ohci_writel(ohci_readl(base) | EHCI_USBCMD_HCRESET, base);
+
+		while (ohci_readl(base) & EHCI_USBCMD_HCRESET) {
+			if (timeout-- <= 0) {
+				printf("USB RootHub reset timed out!");
+				break;
+			}
+			udelay(1);
+		}
+	} else
+		printf("No EHCI func at %d index!\n", CONFIG_PCI_EHCI_DEVNO);
+#endif
+	if (ohci_readl(&ohci->regs->control) & OHCI_CTRL_IR) {
+		/* SMM owns the HC, request ownership */
+		ohci_writel(OHCI_OCR, &ohci->regs->cmdstatus);
+		info("USB HC TakeOver from SMM");
+		while (ohci_readl(&ohci->regs->control) & OHCI_CTRL_IR) {
+			mdelay(10);
+			if (--smm_timeout == 0) {
+				err("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}
+
+	/* Disable HC interrupts */
+	ohci_writel(OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
+		ohci->slot_name,
+		ohci_readl(&ohci->regs->control));
+
+	/* Reset USB (needed by some controllers) */
+	ohci->hc_control = 0;
+	ohci_writel(ohci->hc_control, &ohci->regs->control);
+
+	/* HC Reset requires max 10 us delay */
+	ohci_writel(OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((ohci_readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err("USB HC reset timed out!");
+			return -1;
+		}
+		udelay(1);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start(ohci_t *ohci)
+{
+	__u32 mask;
+	unsigned int fminterval;
+	int i;
+
+	ohci->disabled = 1;
+	for (i = 0; i < NUM_INT_DEVS; i++)
+		ohci->int_dev[i].devnum = -1;
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+
+	ohci_writel(0, &ohci->regs->ed_controlhead);
+	ohci_writel(0, &ohci->regs->ed_bulkhead);
+
+	ohci_writel((uintptr_t)ohci->hcca,
+		    &ohci->regs->hcca); /* reset clears this */
+
+	fminterval = 0x2edf;
+	ohci_writel((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+	ohci_writel(fminterval, &ohci->regs->fminterval);
+	ohci_writel(0x628, &ohci->regs->lsthresh);
+
+	/* start controller operations */
+	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ohci->disabled = 0;
+	ohci_writel(ohci->hc_control, &ohci->regs->control);
+
+	/* disable all interrupts */
+	mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+			OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+			OHCI_INTR_OC | OHCI_INTR_MIE);
+	ohci_writel(mask, &ohci->regs->intrdisable);
+	/* clear all interrupts */
+	mask &= ~OHCI_INTR_MIE;
+	ohci_writel(mask, &ohci->regs->intrstatus);
+	/* Choose the interrupts we care about now  - but w/o MIE */
+	mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	ohci_writel(mask, &ohci->regs->intrenable);
+
+#ifdef	OHCI_USE_NPS
+	/* required for AMD-756 and some Mac platforms */
+	ohci_writel((roothub_a(ohci) | RH_A_NPS) & ~RH_A_PSM,
+		&ohci->regs->roothub.a);
+	ohci_writel(RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif	/* OHCI_USE_NPS */
+
+	/* connect the virtual root hub */
+	ohci->rh.devnum = 0;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int hc_interrupt(ohci_t *ohci)
+{
+	struct ohci_regs *regs = ohci->regs;
+	int ints;
+	int stat = -1;
+
+	invalidate_dcache_hcca(ohci->hcca);
+
+	if ((ohci->hcca->done_head != 0) &&
+				!(m32_swap(ohci->hcca->done_head) & 0x01)) {
+		ints =  OHCI_INTR_WDH;
+	} else {
+		ints = ohci_readl(&regs->intrstatus);
+		if (ints == ~(u32)0) {
+			ohci->disabled++;
+			err("%s device removed!", ohci->slot_name);
+			return -1;
+		} else {
+			ints &= ohci_readl(&regs->intrenable);
+			if (ints == 0) {
+				dbg("hc_interrupt: returning..\n");
+				return 0xff;
+			}
+		}
+	}
+
+	/* dbg("Interrupt: %x frame: %x", ints,
+					le16_to_cpu(ohci->hcca->frame_no)); */
+
+	if (ints & OHCI_INTR_RHSC)
+		stat = 0xff;
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err("OHCI Unrecoverable Error, controller usb-%s disabled",
+			ohci->slot_name);
+		/* e.g. due to PCI Master/Target Abort */
+
+#ifdef	DEBUG
+		ohci_dump(ohci, 1);
+#else
+		ohci_mdelay(1);
+#endif
+		/* FIXME: be optimistic, hope that bug won't repeat often. */
+		/* Make some non-interrupt context restart the controller. */
+		/* Count and limit the retries though; either hardware or */
+		/* software errors can go forever... */
+		hc_reset(ohci);
+		return -1;
+	}
+
+	if (ints & OHCI_INTR_WDH) {
+		ohci_mdelay(1);
+		ohci_writel(OHCI_INTR_WDH, &regs->intrdisable);
+		(void)ohci_readl(&regs->intrdisable); /* flush */
+		stat = dl_done_list(ohci);
+		ohci_writel(OHCI_INTR_WDH, &regs->intrenable);
+		(void)ohci_readl(&regs->intrdisable); /* flush */
+	}
+
+	if (ints & OHCI_INTR_SO) {
+		dbg("USB Schedule overrun\n");
+		ohci_writel(OHCI_INTR_SO, &regs->intrenable);
+		stat = -1;
+	}
+
+	/* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
+	if (ints & OHCI_INTR_SF) {
+		unsigned int frame = m16_swap(ohci->hcca->frame_no) & 1;
+		mdelay(1);
+		ohci_writel(OHCI_INTR_SF, &regs->intrdisable);
+		if (ohci->ed_rm_list[frame] != NULL)
+			ohci_writel(OHCI_INTR_SF, &regs->intrenable);
+		stat = 0xff;
+	}
+
+	ohci_writel(ints, &regs->intrstatus);
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci(ohci_t *ohci)
+{
+	dbg("USB HC release ohci usb-%s", ohci->slot_name);
+
+	if (!ohci->disabled)
+		hc_reset(ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+#ifdef CONFIG_PCI_OHCI
+	pci_dev_t pdev;
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+	/* cpu dependant init */
+	if (usb_cpu_init())
+		return -1;
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+	/*  board dependant init */
+	if (board_usb_init(index, USB_INIT_HOST))
+		return -1;
+#endif
+	memset(&gohci, 0, sizeof(ohci_t));
+
+	/* align the storage */
+	if ((__u32)&ghcca[0] & 0xff) {
+		err("HCCA not aligned!!");
+		return -1;
+	}
+	gohci.hcca = &ghcca[0];
+	info("aligned ghcca %p", gohci.hcca);
+	memset(gohci.hcca, 0, sizeof(struct ohci_hcca));
+
+	gohci.disabled = 1;
+	gohci.sleeping = 0;
+	gohci.irq = -1;
+#ifdef CONFIG_PCI_OHCI
+	pdev = pci_find_devices(ohci_pci_ids, CONFIG_PCI_OHCI_DEVNO);
+
+	if (pdev != -1) {
+		u16 vid, did;
+		u32 base;
+		pci_read_config_word(pdev, PCI_VENDOR_ID, &vid);
+		pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
+		printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n",
+				vid, did, (pdev >> 16) & 0xff,
+				(pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
+		pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+		printf("OHCI regs address 0x%08x\n", base);
+		gohci.regs = (struct ohci_regs *)base;
+	} else {
+		printf("%s: OHCI devnr: %d not found\n", __func__,
+		       CONFIG_PCI_OHCI_DEVNO);
+		return -1;
+	}
+#else
+	gohci.regs = (struct ohci_regs *)CONFIG_SYS_USB_OHCI_REGS_BASE;
+#endif
+
+	gohci.flags = 0;
+	gohci.slot_name = CONFIG_SYS_USB_OHCI_SLOT_NAME;
+
+	if (hc_reset (&gohci) < 0) {
+		hc_release_ohci (&gohci);
+		err ("can't reset usb-%s", gohci.slot_name);
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+		/* board dependant cleanup */
+		board_usb_cleanup(index, USB_INIT_HOST);
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+		/* cpu dependant cleanup */
+		usb_cpu_init_fail();
+#endif
+		return -1;
+	}
+
+	if (hc_start(&gohci) < 0) {
+		err("can't start usb-%s", gohci.slot_name);
+		hc_release_ohci(&gohci);
+		/* Initialization failed */
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+		/* board dependant cleanup */
+		usb_board_stop();
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+		/* cpu dependant cleanup */
+		usb_cpu_stop();
+#endif
+		return -1;
+	}
+
+#ifdef	DEBUG
+	ohci_dump(&gohci, 1);
+#else
+	ohci_mdelay(1);
+#endif
+	ohci_inited = 1;
+	return 0;
+}
+
+int usb_lowlevel_stop(int index)
+{
+	/* this gets called really early - before the controller has */
+	/* even been initialized! */
+	if (!ohci_inited)
+		return 0;
+	/* TODO release any interrupts, etc. */
+	/* call hc_release_ohci() here ? */
+	hc_reset(&gohci);
+
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+	/* board dependant cleanup */
+	if (usb_board_stop())
+		return -1;
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+	/* cpu dependant cleanup */
+	if (usb_cpu_stop())
+		return -1;
+#endif
+	/* This driver is no longer initialised. It needs a new low-level
+	 * init (board/cpu) before it can be used again. */
+	ohci_inited = 0;
+	return 0;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+	void *buffer, int transfer_len, struct devrequest *setup)
+{
+	return _ohci_submit_control_msg(&gohci, dev, pipe, buffer,
+					transfer_len, setup);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int ohci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+	return _ohci_submit_control_msg(ohci, udev, pipe, buffer,
+					length, setup);
+}
+
+static int ohci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+	return submit_common_msg(ohci, udev, pipe, buffer, length, NULL, 0);
+}
+
+static int ohci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval, bool nonblock)
+{
+	ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+	return submit_common_msg(ohci, udev, pipe, buffer, length,
+				 NULL, interval);
+}
+
+static struct int_queue *ohci_create_int_queue(struct udevice *dev,
+		struct usb_device *udev, unsigned long pipe, int queuesize,
+		int elementsize, void *buffer, int interval)
+{
+	ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+	return _ohci_create_int_queue(ohci, udev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+static void *ohci_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+				 struct int_queue *queue)
+{
+	ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+	return _ohci_poll_int_queue(ohci, udev, queue);
+}
+
+static int ohci_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+				  struct int_queue *queue)
+{
+	ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+	return _ohci_destroy_int_queue(ohci, udev, queue);
+}
+
+int ohci_register(struct udevice *dev, struct ohci_regs *regs)
+{
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	ohci_t *ohci = dev_get_priv(dev);
+	u32 reg;
+
+	priv->desc_before_addr = true;
+
+	ohci->regs = regs;
+	ohci->hcca = memalign(256, sizeof(struct ohci_hcca));
+	if (!ohci->hcca)
+		return -ENOMEM;
+	memset(ohci->hcca, 0, sizeof(struct ohci_hcca));
+	flush_dcache_hcca(ohci->hcca);
+
+	if (hc_reset(ohci) < 0)
+		return -EIO;
+
+	if (hc_start(ohci) < 0)
+		return -EIO;
+
+	reg = ohci_readl(&regs->revision);
+	printf("USB OHCI %x.%x\n", (reg >> 4) & 0xf, reg & 0xf);
+
+	return 0;
+}
+
+int ohci_deregister(struct udevice *dev)
+{
+	ohci_t *ohci = dev_get_priv(dev);
+
+	if (hc_reset(ohci) < 0)
+		return -EIO;
+
+	free(ohci->hcca);
+
+	return 0;
+}
+
+struct dm_usb_ops ohci_usb_ops = {
+	.control = ohci_submit_control_msg,
+	.bulk = ohci_submit_bulk_msg,
+	.interrupt = ohci_submit_int_msg,
+	.create_int_queue = ohci_create_int_queue,
+	.poll_int_queue = ohci_poll_int_queue,
+	.destroy_int_queue = ohci_destroy_int_queue,
+};
+
+#endif
diff --git a/roms/u-boot/drivers/usb/host/ohci-lpc32xx.c b/roms/u-boot/drivers/usb/host/ohci-lpc32xx.c
new file mode 100644
index 000000000..3be0b311a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-lpc32xx.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008 by NXP Semiconductors
+ * @Author: Based on code by Kevin Wells
+ * @Descr: USB driver - Embedded Artists LPC3250 OEM Board support functions
+ *
+ * Copyright (c) 2015 Tyco Fire Protection Products.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/i2c.h>
+#include <usb.h>
+#include <i2c.h>
+
+/* OTG I2C controller module register structures */
+struct otgi2c_regs {
+	u32 otg_i2c_txrx;   /* OTG I2C Tx/Rx Data FIFO */
+	u32 otg_i2c_stat;   /* OTG I2C Status Register */
+	u32 otg_i2c_ctrl;   /* OTG I2C Control Register */
+	u32 otg_i2c_clk_hi; /* OTG I2C Clock Divider high */
+	u32 otg_i2c_clk_lo; /* OTG I2C Clock Divider low */
+};
+
+/* OTG controller module register structures */
+struct otg_regs {
+	u32 reserved1[64];
+	u32 otg_int_sts;    /* OTG int status register */
+	u32 otg_int_enab;   /* OTG int enable register */
+	u32 otg_int_set;    /* OTG int set register */
+	u32 otg_int_clr;    /* OTG int clear register */
+	u32 otg_sts_ctrl;   /* OTG status/control register */
+	u32 otg_timer;      /* OTG timer register */
+	u32 reserved2[122];
+	struct otgi2c_regs otg_i2c;
+	u32 reserved3[824];
+	u32 otg_clk_ctrl;   /* OTG clock control reg */
+	u32 otg_clk_sts;    /* OTG clock status reg */
+};
+
+/* otg_sts_ctrl register definitions */
+#define OTG_HOST_EN			(1 << 0) /* Enable host mode */
+
+/* otg_clk_ctrl and otg_clk_sts register definitions */
+#define OTG_CLK_AHB_EN			(1 << 4) /* Enable AHB clock */
+#define OTG_CLK_OTG_EN			(1 << 3) /* Enable OTG clock */
+#define OTG_CLK_I2C_EN			(1 << 2) /* Enable I2C clock */
+#define OTG_CLK_HOST_EN			(1 << 0) /* Enable host clock */
+
+/* ISP1301 USB transceiver I2C registers */
+#define MC1_SPEED_REG			(1 << 0)
+#define MC1_DAT_SE0			(1 << 2)
+#define MC1_UART_EN			(1 << 6)
+
+#define MC2_SPD_SUSP_CTRL		(1 << 1)
+#define MC2_BI_DI			(1 << 2)
+#define MC2_PSW_EN			(1 << 6)
+
+#define OTG1_DP_PULLUP			(1 << 0)
+#define OTG1_DM_PULLUP			(1 << 1)
+#define OTG1_DP_PULLDOWN		(1 << 2)
+#define OTG1_DM_PULLDOWN		(1 << 3)
+#define OTG1_VBUS_DRV			(1 << 5)
+
+#define ISP1301_I2C_ADDR		CONFIG_USB_ISP1301_I2C_ADDR
+
+#define ISP1301_I2C_MODE_CONTROL_1_SET		0x04
+#define ISP1301_I2C_MODE_CONTROL_1_CLR		0x05
+#define ISP1301_I2C_MODE_CONTROL_2_SET		0x12
+#define ISP1301_I2C_MODE_CONTROL_2_CLR		0x13
+#define ISP1301_I2C_OTG_CONTROL_1_SET		0x06
+#define ISP1301_I2C_OTG_CONTROL_1_CLR		0x07
+#define ISP1301_I2C_INTERRUPT_LATCH_CLR		0x0B
+#define ISP1301_I2C_INTERRUPT_FALLING_CLR	0x0D
+#define ISP1301_I2C_INTERRUPT_RISING_CLR	0x0F
+
+static struct otg_regs *otg = (struct otg_regs *)USB_BASE;
+static struct clk_pm_regs *clk_pwr = (struct clk_pm_regs *)CLK_PM_BASE;
+
+static int isp1301_set_value(struct udevice *dev, int reg, u8 value)
+{
+#if !CONFIG_IS_ENABLED(DM_I2C)
+	return i2c_write(ISP1301_I2C_ADDR, reg, 1, &value, 1);
+#else
+	return dm_i2c_write(dev, reg, &value, 1);
+#endif
+}
+
+static void isp1301_configure(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(DM_I2C)
+	i2c_set_bus_num(I2C_2);
+#endif
+
+	/*
+	 * LPC32XX only supports DAT_SE0 USB mode
+	 * This sequence is important
+	 */
+
+	/* Disable transparent UART mode first */
+	isp1301_set_value(dev, ISP1301_I2C_MODE_CONTROL_1_CLR, MC1_UART_EN);
+
+	isp1301_set_value(dev, ISP1301_I2C_MODE_CONTROL_1_CLR, ~MC1_SPEED_REG);
+	isp1301_set_value(dev, ISP1301_I2C_MODE_CONTROL_1_SET, MC1_SPEED_REG);
+	isp1301_set_value(dev, ISP1301_I2C_MODE_CONTROL_2_CLR, ~0);
+	isp1301_set_value(dev, ISP1301_I2C_MODE_CONTROL_2_SET,
+			  MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL);
+
+	isp1301_set_value(dev, ISP1301_I2C_OTG_CONTROL_1_CLR, ~0);
+	isp1301_set_value(dev, ISP1301_I2C_MODE_CONTROL_1_SET, MC1_DAT_SE0);
+	isp1301_set_value(dev, ISP1301_I2C_OTG_CONTROL_1_SET,
+			  OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+	isp1301_set_value(dev, ISP1301_I2C_OTG_CONTROL_1_CLR,
+			  OTG1_DM_PULLUP | OTG1_DP_PULLUP);
+	isp1301_set_value(dev, ISP1301_I2C_INTERRUPT_LATCH_CLR, ~0);
+	isp1301_set_value(dev, ISP1301_I2C_INTERRUPT_FALLING_CLR, ~0);
+	isp1301_set_value(dev, ISP1301_I2C_INTERRUPT_RISING_CLR, ~0);
+
+	/* Enable usb_need_clk clock after transceiver is initialized */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_USBDVND_EN);
+}
+
+static int usbpll_setup(void)
+{
+	u32 ret;
+
+	/* make sure clocks are disabled */
+	clrbits_le32(&clk_pwr->usb_ctrl,
+		     CLK_USBCTRL_CLK_EN1 | CLK_USBCTRL_CLK_EN2);
+
+	/* start PLL clock input */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN1);
+
+	/* Setup PLL. */
+	setbits_le32(&clk_pwr->usb_ctrl,
+		     CLK_USBCTRL_FDBK_PLUS1(192 - 1));
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_POSTDIV_2POW(0x01));
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_PWRUP);
+
+	ret = wait_for_bit_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_STS,
+				true, CONFIG_SYS_HZ, false);
+	if (ret)
+		return ret;
+
+	/* enable PLL output */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN2);
+
+	return 0;
+}
+
+int usb_cpu_init(void)
+{
+	u32 ret;
+	struct udevice *dev = NULL;
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+	ret = i2c_get_chip_for_busnum(I2C_2, ISP1301_I2C_ADDR, 1, &dev);
+	if (ret) {
+		debug("%s: No bus %d\n", __func__, I2C_2);
+		return ret;
+	}
+#endif
+
+	/*
+	 * USB pins routing setup is done by "lpc32xx_usb_init()" and should
+	 * be call by board "board_init()" or "misc_init_r()" functions.
+	 */
+
+	/* enable AHB slave USB clock */
+	setbits_le32(&clk_pwr->usb_ctrl,
+		     CLK_USBCTRL_HCLK_EN | CLK_USBCTRL_BUS_KEEPER);
+
+	/* enable I2C clock */
+	writel(OTG_CLK_I2C_EN, &otg->otg_clk_ctrl);
+	ret = wait_for_bit_le32(&otg->otg_clk_sts, OTG_CLK_I2C_EN, true,
+				CONFIG_SYS_HZ, false);
+	if (ret)
+		return ret;
+
+	/* Configure ISP1301 */
+	isp1301_configure(dev);
+
+	/* setup USB clocks and PLL */
+	ret = usbpll_setup();
+	if (ret)
+		return ret;
+
+	/* enable usb_host_need_clk */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_USBHSTND_EN);
+
+	/* enable all needed USB clocks */
+	const u32 mask = OTG_CLK_AHB_EN | OTG_CLK_OTG_EN |
+			 OTG_CLK_I2C_EN | OTG_CLK_HOST_EN;
+	writel(mask, &otg->otg_clk_ctrl);
+
+	ret = wait_for_bit_le32(&otg->otg_clk_sts, mask, true,
+				CONFIG_SYS_HZ, false);
+	if (ret)
+		return ret;
+
+	setbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
+	isp1301_set_value(dev, ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
+
+	return 0;
+}
+
+int usb_cpu_stop(void)
+{
+	struct udevice *dev = NULL;
+	int ret = 0;
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+	ret = i2c_get_chip_for_busnum(I2C_2, ISP1301_I2C_ADDR, 1, &dev);
+	if (ret) {
+		debug("%s: No bus %d\n", __func__, I2C_2);
+		return ret;
+	}
+#endif
+
+	/* vbus off */
+	isp1301_set_value(dev, ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
+
+	clrbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
+
+	clrbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_HCLK_EN);
+
+	return ret;
+}
+
+int usb_cpu_init_fail(void)
+{
+	return usb_cpu_stop();
+}
diff --git a/roms/u-boot/drivers/usb/host/ohci-pci.c b/roms/u-boot/drivers/usb/host/ohci-pci.c
new file mode 100644
index 000000000..6ddc9da70
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci-pci.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <usb.h>
+#include <asm/io.h>
+
+#include "ohci.h"
+
+static int ohci_pci_probe(struct udevice *dev)
+{
+	struct ohci_regs *regs;
+
+	regs = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	return ohci_register(dev, regs);
+}
+
+static int ohci_pci_remove(struct udevice *dev)
+{
+	return ohci_deregister(dev);
+}
+
+static const struct udevice_id ohci_pci_ids[] = {
+	{ .compatible = "ohci-pci" },
+	{ }
+};
+
+U_BOOT_DRIVER(ohci_pci) = {
+	.name	= "ohci_pci",
+	.id	= UCLASS_USB,
+	.probe = ohci_pci_probe,
+	.remove = ohci_pci_remove,
+	.of_match = ohci_pci_ids,
+	.ops	= &ohci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(ohci_t),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static struct pci_device_id ohci_pci_supported[] = {
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(ohci_pci, ohci_pci_supported);
diff --git a/roms/u-boot/drivers/usb/host/ohci.h b/roms/u-boot/drivers/usb/host/ohci.h
new file mode 100644
index 000000000..a38cd25eb
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/ohci.h
@@ -0,0 +1,415 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+/*
+ * e.g. PCI controllers need this
+ */
+
+#include <asm/cache.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SYS_OHCI_SWAP_REG_ACCESS
+# define ohci_readl(a) __swap_32(in_be32((u32 *)a))
+# define ohci_writel(a, b) out_be32((u32 *)b, __swap_32(a))
+#else
+# define ohci_readl(a) readl(a)
+# define ohci_writel(v, a) writel(v, a)
+#endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
+
+#if ARCH_DMA_MINALIGN > 16
+#define ED_ALIGNMENT ARCH_DMA_MINALIGN
+#else
+#define ED_ALIGNMENT 16
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB) && ARCH_DMA_MINALIGN > 32
+#define TD_ALIGNMENT ARCH_DMA_MINALIGN
+#else
+#define TD_ALIGNMENT 32
+#endif
+
+/* functions for doing board or CPU specific setup/cleanup */
+int usb_board_stop(void);
+
+int usb_cpu_init(void);
+int usb_cpu_stop(void);
+int usb_cpu_init_fail(void);
+
+/* ED States */
+#define ED_NEW		0x00
+#define ED_UNLINK	0x01
+#define ED_OPER		0x02
+#define ED_DEL		0x04
+#define ED_URB_DEL	0x08
+
+/* usb_ohci_ed */
+struct ed {
+	__u32 hwINFO;
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed *ed_prev;
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load;
+	__u8 int_interval;
+	__u8 state;
+	__u8 type;
+	__u16 last_iso;
+	struct ed *ed_rm_list;
+
+	struct usb_device *usb_dev;
+	void *purb;
+	__u32 unused[2];
+} __attribute__((aligned(ED_ALIGNMENT)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC	    0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC	    0x0C000000
+#define TD_T	    0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R	    0x00040000
+#define TD_DI	    0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP	    0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO	    0x00010000
+#define TD_DEL	    0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR	   0x00
+#define TD_CC_CRC	   0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL	   0x04
+#define TD_DEVNOTRESP	   0x05
+#define TD_PIDCHECKFAIL	   0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN	   0x08
+#define TD_DATAUNDERRUN	   0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED	   0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+	__u32 hwINFO;
+	__u32 hwCBP;		/* Current Buffer Pointer */
+	__u32 hwNextTD;		/* Next TD Pointer */
+	__u32 hwBE;		/* Memory Buffer End Pointer */
+
+	__u16 hwPSW[MAXPSW];
+	__u8 unused;
+	__u8 index;
+	struct ed *ed;
+	struct td *next_dl_td;
+	struct usb_device *usb_dev;
+	int transfer_len;
+	__u32 data;
+
+	__u32 unused2[2];
+} __attribute__((aligned(TD_ALIGNMENT)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute__((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#ifndef CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS
+# error "CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS undefined!"
+#endif
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.	You must use the ohci_readl() and
+ * ohci_writel() macros defined in this file to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS];
+	} roothub;
+} __attribute__((aligned(32)));
+
+/* Some EHCI controls */
+#define EHCI_USBCMD_OFF		0x20
+#define EHCI_USBCMD_HCRESET	(1 << 1)
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF	(1 << 1)	/* control list filled */
+#define OHCI_BLF	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR	(1 << 3)	/* ownership change request */
+#define OHCI_SOC	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int devnum; /* Address of Root Hub endpoint */
+	void *dev;  /* was urb */
+	void *int_addr;
+	int send;
+	int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE		   0x01
+#define RH_ENDPOINT		   0x02
+#define RH_OTHER		   0x03
+
+#define RH_CLASS		   0x20
+#define RH_VENDOR		   0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	   0x00
+#define RH_PORT_ENABLE		   0x01
+#define RH_PORT_SUSPEND		   0x02
+#define RH_PORT_OVER_CURRENT	   0x03
+#define RH_PORT_RESET		   0x04
+#define RH_PORT_POWER		   0x08
+#define RH_PORT_LOW_SPEED	   0x09
+
+#define RH_C_PORT_CONNECTION	   0x10
+#define RH_C_PORT_ENABLE	   0x11
+#define RH_C_PORT_SUSPEND	   0x12
+#define RH_C_PORT_OVER_CURRENT	   0x13
+#define RH_C_PORT_RESET		   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	   0x00
+#define RH_C_HUB_OVER_CURRENT	   0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	   0x00
+#define RH_ENDPOINT_STALL	   0x01
+
+#define RH_ACK			   0x01
+#define RH_REQ_ERR		   -1
+#define RH_NACK			   0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS	     0x00000001		/* current connect status */
+#define RH_PS_PES	     0x00000002		/* port enable status*/
+#define RH_PS_PSS	     0x00000004		/* port suspend status */
+#define RH_PS_POCI	     0x00000008		/* port over current indicator */
+#define RH_PS_PRS	     0x00000010		/* port reset status */
+#define RH_PS_PPS	     0x00000100		/* port power status */
+#define RH_PS_LSDA	     0x00000200		/* low speed device attached */
+#define RH_PS_CSC	     0x00010000		/* connect status change */
+#define RH_PS_PESC	     0x00020000		/* port enable status change */
+#define RH_PS_PSSC	     0x00040000		/* port suspend status change */
+#define RH_PS_OCIC	     0x00080000		/* over current indicator change */
+#define RH_PS_PRSC	     0x00100000		/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001		/* local power status */
+#define RH_HS_OCI	     0x00000002		/* over current indicator */
+#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000		/* local power status change */
+#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff		/* device removable flags */
+#define RH_B_PPCM	0xffff0000		/* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)		/* number of downstream ports */
+#define RH_A_PSM	(1 << 8)		/* power switching mode */
+#define RH_A_NPS	(1 << 9)		/* no power switching */
+#define RH_A_DT		(1 << 10)		/* device type (mbz) */
+#define RH_A_OCPM	(1 << 11)		/* over current protection mode */
+#define RH_A_NOCP	(1 << 12)		/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+	ed_t *ed;
+	__u16 length;	/* number of tds associated with this request */
+	__u16 td_cnt;	/* number of tds already serviced */
+	struct usb_device *dev;
+	int   state;
+	unsigned long pipe;
+	void *transfer_buffer;
+	int transfer_buffer_length;
+	int interval;
+	int actual_length;
+	int finished;
+	td_t *td[N_URB_TD];	/* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+#define NUM_EDS 32		/* num of preallocated endpoint descriptors */
+
+#define NUM_TD 64		/* we need more TDs than EDs */
+
+#define NUM_INT_DEVS 8		/* num of ohci_dev structs for int endpoints */
+
+typedef struct ohci_device {
+	ed_t ed[NUM_EDS] __aligned(ED_ALIGNMENT);
+	td_t tds[NUM_TD] __aligned(TD_ALIGNMENT);
+	int ed_cnt;
+	int devnum;
+} ohci_dev_t;
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+	/* this allocates EDs for all possible endpoints */
+	struct ohci_device ohci_dev __aligned(TD_ALIGNMENT);
+	struct ohci_device int_dev[NUM_INT_DEVS] __aligned(TD_ALIGNMENT);
+	struct ohci_hcca *hcca;		/* hcca */
+	/*dma_addr_t hcca_dma;*/
+
+	int irq;
+	int disabled;			/* e.g. got a UE, we're hung */
+	int sleeping;
+	unsigned long flags;		/* for HC bugs */
+
+	struct ohci_regs *regs; /* OHCI controller's memory */
+
+	int ohci_int_load[32];	 /* load of the 32 Interrupt Chains (for load balancing)*/
+	ed_t *ed_rm_list[2];	 /* lists of all endpoints to be removed */
+	ed_t *ed_bulktail;	 /* last endpoint of bulk list */
+	ed_t *ed_controltail;	 /* last endpoint of control list */
+	int intrstatus;
+	__u32 hc_control;		/* copy of the hc control reg */
+	struct usb_device *dev[32];
+	struct virt_root_hub rh;
+
+	const char	*slot_name;
+} ohci_t;
+
+#if CONFIG_IS_ENABLED(DM_USB)
+extern struct dm_usb_ops ohci_usb_ops;
+
+int ohci_register(struct udevice *dev, struct ohci_regs *regs);
+int ohci_deregister(struct udevice *dev);
+#endif
diff --git a/roms/u-boot/drivers/usb/host/r8a66597-hcd.c b/roms/u-boot/drivers/usb/host/r8a66597-hcd.c
new file mode 100644
index 000000000..f1fc93f3d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/r8a66597-hcd.c
@@ -0,0 +1,899 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R8A66597 HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ */
+
+#include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <power/regulator.h>
+
+#include "r8a66597.h"
+
+#ifdef R8A66597_DEBUG
+#define R8A66597_DPRINT		printf
+#else
+#define R8A66597_DPRINT(...)
+#endif
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
+{
+	struct udevice *parent = udev->dev->parent;
+
+	/*
+	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
+	 * to the parent udevice, not the actual udevice belonging to the
+	 * udev as the device is not instantiated yet.
+	 *
+	 * If dev is an usb-bus, then we are called from usb_scan_device() for
+	 * an usb-device plugged directly into the root port, return NULL.
+	 */
+	if (device_get_uclass_id(udev->dev) == UCLASS_USB)
+		return NULL;
+
+	/*
+	 * If these 2 are not the same we are being called from
+	 * usb_scan_device() and udev itself is the parent.
+	 */
+	if (dev_get_parent_priv(udev->dev) != udev)
+		return udev;
+
+	/* We are being called normally, use the parent pointer */
+	if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
+		return dev_get_parent_priv(parent);
+
+	return NULL;
+}
+
+static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport)
+{
+	struct usb_device *parent = usb_dev_get_parent(dev);
+
+	*hub_devnum = 0;
+	*hubport = 0;
+
+	/* check a device connected to root_hub */
+	if ((parent && parent->devnum == 1) ||
+	    dev->devnum == 1)
+		return;
+
+	*hub_devnum = (u8)parent->devnum;
+	*hubport = parent->portnr - 1;
+}
+
+static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address,
+		       struct usb_device *dev, int port)
+{
+	u16 val, usbspd, upphub, hubport;
+	unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
+
+	get_hub_data(dev, &upphub, &hubport);
+	usbspd = r8a66597->speed;
+	val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
+	r8a66597_write(r8a66597, val, devadd_reg);
+}
+
+static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
+{
+	u16 tmp;
+	int i = 0;
+
+	do {
+		r8a66597_write(r8a66597, USBE, SYSCFG0);
+		tmp = r8a66597_read(r8a66597, SYSCFG0);
+		if (i++ > 1000) {
+			printf("register access fail.\n");
+			return -1;
+		}
+	} while ((tmp & USBE) != USBE);
+	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+	/*
+	 * RZ/A Only:
+	 * Bits XTAL(UCKSEL) and UPLLE in SYSCFG0 for USB0 controls both USB0
+	 * and USB1, so we must always set the USB0 register
+	 */
+#if (CONFIG_R8A66597_XTAL == 1)
+	r8a66597_bset(r8a66597, XTAL, SYSCFG0);
+#endif
+	mdelay(1);
+	r8a66597_bset(r8a66597, UPLLE, SYSCFG0);
+	mdelay(1);
+	r8a66597_bset(r8a66597, SUSPM, SUSPMODE0);
+
+	return 0;
+}
+
+static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
+{
+	r8a66597_bclr(r8a66597, SUSPM, SUSPMODE0);
+
+	r8a66597_bclr(r8a66597, UPLLE, SYSCFG0);
+	mdelay(1);
+	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+	mdelay(1);
+}
+
+static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
+{
+	u16 val;
+
+	val = port ? DRPD : DCFM | DRPD;
+	r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
+	r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+}
+
+static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
+{
+	u16 val, tmp;
+
+	r8a66597_write(r8a66597, 0, get_intenb_reg(port));
+	r8a66597_write(r8a66597, 0, get_intsts_reg(port));
+
+	r8a66597_port_power(r8a66597, port, 0);
+
+	do {
+		tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
+		udelay(640);
+	} while (tmp == EDGESTS);
+
+	val = port ? DRPD : DCFM | DRPD;
+	r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
+	r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+	int ret, port;
+
+	ret = r8a66597_clock_enable(r8a66597);
+	if (ret < 0)
+		return ret;
+
+	r8a66597_bset(r8a66597, USBE, SYSCFG0);
+
+	r8a66597_bset(r8a66597, INTL, SOFCFG);
+	r8a66597_write(r8a66597, 0, INTENB0);
+	for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+		r8a66597_write(r8a66597, 0, get_intenb_reg(port));
+
+	r8a66597_bclr(r8a66597, BIGEND, CFIFOSEL);
+	r8a66597_bclr(r8a66597, BIGEND, D0FIFOSEL);
+	r8a66597_bclr(r8a66597, BIGEND, D1FIFOSEL);
+	r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
+
+	for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+		r8a66597_enable_port(r8a66597, port);
+
+	return 0;
+}
+
+static void disable_controller(struct r8a66597 *r8a66597)
+{
+	int i;
+
+	if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE))
+		return;
+
+	r8a66597_write(r8a66597, 0, INTENB0);
+	r8a66597_write(r8a66597, 0, INTSTS0);
+
+	r8a66597_write(r8a66597, 0, D0FIFOSEL);
+	r8a66597_write(r8a66597, 0, D1FIFOSEL);
+	r8a66597_write(r8a66597, 0, DCPCFG);
+	r8a66597_write(r8a66597, 0x40, DCPMAXP);
+	r8a66597_write(r8a66597, 0, DCPCTR);
+
+	for (i = 0; i <= 10; i++)
+		r8a66597_write(r8a66597, 0, get_devadd_addr(i));
+	for (i = 1; i <= 5; i++) {
+		r8a66597_write(r8a66597, 0, get_pipetre_addr(i));
+		r8a66597_write(r8a66597, 0, get_pipetrn_addr(i));
+	}
+	for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) {
+		r8a66597_write(r8a66597, 0, get_pipectr_addr(i));
+		r8a66597_write(r8a66597, i, PIPESEL);
+		r8a66597_write(r8a66597, 0, PIPECFG);
+		r8a66597_write(r8a66597, 0, PIPEBUF);
+		r8a66597_write(r8a66597, 0, PIPEMAXP);
+		r8a66597_write(r8a66597, 0, PIPEPERI);
+	}
+
+	for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++)
+		r8a66597_disable_port(r8a66597, i);
+
+	r8a66597_clock_disable(r8a66597);
+}
+
+static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
+			      u16 mask, u16 loop)
+{
+	u16 tmp;
+	int i = 0;
+
+	do {
+		tmp = r8a66597_read(r8a66597, reg);
+		if (i++ > 1000000) {
+			printf("register%lx, loop %x is timeout\n", reg, loop);
+			break;
+		}
+	} while ((tmp & mask) != loop);
+}
+
+static void pipe_buffer_setting(struct r8a66597 *r8a66597,
+				struct usb_device *dev, unsigned long pipe)
+{
+	u16 val = 0;
+	u16 pipenum, bufnum, maxpacket;
+
+	if (usb_pipein(pipe)) {
+		pipenum = BULK_IN_PIPENUM;
+		bufnum = BULK_IN_BUFNUM;
+		maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
+	} else {
+		pipenum = BULK_OUT_PIPENUM;
+		bufnum = BULK_OUT_BUFNUM;
+		maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
+	}
+
+	if (r8a66597->pipe_config & (1 << pipenum))
+		return;
+	r8a66597->pipe_config |= (1 << pipenum);
+
+	r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum));
+	r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum));
+	r8a66597_write(r8a66597, pipenum, PIPESEL);
+
+	/* FIXME: This driver support bulk transfer only. */
+	if (!usb_pipein(pipe))
+		val |= R8A66597_DIR;
+	else
+		val |= R8A66597_SHTNAK;
+	val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe);
+	r8a66597_write(r8a66597, val, PIPECFG);
+
+	r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF);
+	r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) |
+				 maxpacket, PIPEMAXP);
+	r8a66597_write(r8a66597, 0, PIPEPERI);
+	r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum));
+}
+
+static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
+			     struct devrequest *setup)
+{
+	int i;
+	unsigned short *p = (unsigned short *)setup;
+	unsigned long setup_addr = USBREQ;
+	u16 intsts1;
+	int timeout = 3000;
+	u16 dcpctr;
+	u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum;
+
+	r8a66597_write(r8a66597, make_devsel(devsel) |
+				 (8 << dev->maxpacketsize), DCPMAXP);
+	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
+
+	dcpctr = r8a66597_read(r8a66597, DCPCTR);
+	if ((dcpctr & PID) == PID_BUF) {
+		if (readw_poll_timeout(r8a66597->reg + DCPCTR, dcpctr,
+				       dcpctr & BSTS, 1000) < 0) {
+			printf("DCPCTR BSTS timeout!\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
+		setup_addr += 2;
+	}
+	r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
+	r8a66597_write(r8a66597, SUREQ, DCPCTR);
+
+	while (1) {
+		intsts1 = r8a66597_read(r8a66597, INTSTS1);
+		if (intsts1 & SACK)
+			break;
+		if (intsts1 & SIGN) {
+			printf("setup packet send error\n");
+			return -1;
+		}
+		if (timeout-- < 0) {
+			printf("setup packet timeout\n");
+			return -1;
+		}
+		udelay(500);
+	}
+
+	return 0;
+}
+
+static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
+			    unsigned long pipe, void *buffer, int transfer_len)
+{
+	u16 tmp, bufsize;
+	u16 *buf;
+	size_t size;
+
+	R8A66597_DPRINT("%s\n", __func__);
+
+	r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM,
+		      MBW | CURPIPE, CFIFOSEL);
+	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM);
+	tmp = r8a66597_read(r8a66597, CFIFOCTR);
+	if ((tmp & FRDY) == 0) {
+		printf("%s FRDY is not set (%x)\n", __func__, tmp);
+		return -1;
+	}
+
+	/* prepare parameters */
+	bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
+	buf = (u16 *)(buffer + dev->act_len);
+	size = min((int)bufsize, transfer_len - dev->act_len);
+
+	/* write fifo */
+	r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
+	if (buffer) {
+		r8a66597_write_fifo(r8a66597, CFIFO, buf, size);
+		r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+	}
+
+	/* update parameters */
+	dev->act_len += size;
+
+	r8a66597_mdfy(r8a66597, PID_BUF, PID,
+		      get_pipectr_addr(BULK_OUT_PIPENUM));
+
+	while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM)))
+		if (ctrlc())
+			return -1;
+	r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
+
+	if (dev->act_len >= transfer_len)
+		r8a66597_mdfy(r8a66597, PID_NAK, PID,
+			      get_pipectr_addr(BULK_OUT_PIPENUM));
+
+	return 0;
+}
+
+static int receive_bulk_packet(struct r8a66597 *r8a66597,
+			       struct usb_device *dev,
+			       unsigned long pipe,
+			       void *buffer, int transfer_len)
+{
+	u16 tmp;
+	u16 *buf;
+	const u16 pipenum = BULK_IN_PIPENUM;
+	int rcv_len;
+	int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
+
+	R8A66597_DPRINT("%s\n", __func__);
+
+	/* prepare */
+	if (dev->act_len == 0) {
+		r8a66597_mdfy(r8a66597, PID_NAK, PID,
+			      get_pipectr_addr(pipenum));
+		r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+
+		r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum));
+		r8a66597_write(r8a66597,
+			       (transfer_len + maxpacket - 1) / maxpacket,
+				get_pipetrn_addr(pipenum));
+		r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum));
+
+		r8a66597_mdfy(r8a66597, PID_BUF, PID,
+			      get_pipectr_addr(pipenum));
+	}
+
+	r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
+
+	while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum)))
+		if (ctrlc())
+			return -1;
+	r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+
+	tmp = r8a66597_read(r8a66597, CFIFOCTR);
+	if ((tmp & FRDY) == 0) {
+		printf("%s FRDY is not set. (%x)\n", __func__, tmp);
+		return -1;
+	}
+
+	buf = (u16 *)(buffer + dev->act_len);
+	rcv_len = tmp & DTLN;
+	dev->act_len += rcv_len;
+
+	if (buffer) {
+		if (rcv_len == 0)
+			r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+		else
+			r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len);
+	}
+
+	return 0;
+}
+
+static int receive_control_packet(struct r8a66597 *r8a66597,
+				  struct usb_device *dev,
+				  void *buffer, int transfer_len)
+{
+	u16 tmp;
+	int rcv_len;
+
+	/* FIXME: limit transfer size : 64byte or less */
+
+	r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+	r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+	r8a66597_bset(r8a66597, SQSET, DCPCTR);
+	r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+	r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
+
+	while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001))
+		if (ctrlc())
+			return -1;
+	r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
+
+	r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL);
+	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+
+	tmp = r8a66597_read(r8a66597, CFIFOCTR);
+	if ((tmp & FRDY) == 0) {
+		printf("%s FRDY is not set. (%x)\n", __func__, tmp);
+		return -1;
+	}
+
+	rcv_len = tmp & DTLN;
+	dev->act_len += rcv_len;
+
+	r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
+
+	if (buffer) {
+		if (rcv_len == 0)
+			r8a66597_write(r8a66597, BCLR, DCPCTR);
+		else
+			r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len);
+	}
+
+	return 0;
+}
+
+static int send_status_packet(struct r8a66597 *r8a66597,
+			      unsigned long pipe)
+{
+	r8a66597_bset(r8a66597, SQSET, DCPCTR);
+	r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
+
+	if (usb_pipein(pipe)) {
+		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+		r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+		r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
+	} else {
+		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+	}
+	r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
+
+	while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001))
+		if (ctrlc())
+			return -1;
+
+	return 0;
+}
+
+static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port)
+{
+	int count = R8A66597_MAX_SAMPLING;
+	unsigned short syssts, old_syssts;
+
+	R8A66597_DPRINT("%s\n", __func__);
+
+	old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
+	while (count > 0) {
+		mdelay(R8A66597_RH_POLL_TIME);
+
+		syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
+		if (syssts == old_syssts) {
+			count--;
+		} else {
+			count = R8A66597_MAX_SAMPLING;
+			old_syssts = syssts;
+		}
+	}
+}
+
+static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port)
+{
+	mdelay(10);
+	r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port));
+	mdelay(50);
+	r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port));
+	mdelay(50);
+}
+
+static int check_usb_device_connecting(struct r8a66597 *r8a66597)
+{
+	int timeout = 10000;	/* 100usec * 10000 = 1sec */
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		/* check a usb cable connect */
+		while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) {
+			if (timeout-- < 0) {
+				printf("%s timeout.\n", __func__);
+				return -1;
+			}
+			udelay(100);
+		}
+
+		/* check a data line */
+		r8a66597_check_syssts(r8a66597, 0);
+
+		r8a66597_bus_reset(r8a66597, 0);
+		r8a66597->speed = get_rh_usb_speed(r8a66597, 0);
+
+		if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) {
+			r8a66597->port_change = USB_PORT_STAT_C_CONNECTION;
+			r8a66597->port_status = USB_PORT_STAT_CONNECTION |
+						USB_PORT_STAT_ENABLE;
+			return 0;	/* success */
+		}
+
+		R8A66597_DPRINT("USB device has detached. retry = %d\n", i);
+		r8a66597_write(r8a66597, ~DTCH, INTSTS1);
+	}
+
+	return -1;	/* fail */
+}
+
+/* Virtual Root Hub */
+
+#include <usbroothubdes.h>
+
+static int r8a66597_submit_rh_msg(struct udevice *udev, struct usb_device *dev,
+				  unsigned long pipe, void *buffer,
+				  int transfer_len, struct devrequest *cmd)
+{
+	struct r8a66597 *r8a66597 = dev_get_priv(udev);
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wLength;
+	unsigned char data[32];
+
+	R8A66597_DPRINT("%s\n", __func__);
+
+	if (usb_pipeint(pipe)) {
+		printf("Root-Hub submit IRQ: NOT implemented");
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+	wValue	      = cpu_to_le16 (cmd->value);
+	wLength	      = cpu_to_le16 (cmd->length);
+
+	switch (bmRType_bReq) {
+	case RH_GET_STATUS:
+		*(__u16 *)buffer = cpu_to_le16(1);
+		len = 2;
+		break;
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *)buffer = cpu_to_le16(0);
+		len = 2;
+		break;
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *)buffer = cpu_to_le16(0);
+		len = 2;
+		break;
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *)buffer = cpu_to_le32(0);
+		len = 4;
+		break;
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		*(__u32 *)buffer = cpu_to_le32(r8a66597->port_status |
+						(r8a66597->port_change << 16));
+		len = 4;
+		break;
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_C_PORT_CONNECTION:
+			r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION;
+			break;
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			break;
+		case (RH_PORT_RESET):
+			r8a66597_bus_reset(r8a66597, 0);
+			break;
+		case (RH_PORT_POWER):
+			break;
+		case (RH_PORT_ENABLE):
+			break;
+		}
+		break;
+	case RH_SET_ADDRESS:
+		r8a66597->rh_devnum = wValue;
+		break;
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01): /* device descriptor */
+			len = min_t(unsigned int,
+				    leni,
+				  min_t(unsigned int,
+					sizeof(root_hub_dev_des),
+				      wLength));
+			memcpy(buffer, root_hub_dev_des, len);
+			break;
+		case (0x02): /* configuration descriptor */
+			len = min_t(unsigned int,
+				    leni,
+				  min_t(unsigned int,
+					sizeof(root_hub_config_des),
+				      wLength));
+			memcpy(buffer, root_hub_config_des, len);
+			break;
+		case (0x03): /* string descriptors */
+			if (wValue == 0x0300) {
+				len = min_t(unsigned int,
+					    leni,
+					  min_t(unsigned int,
+						sizeof(root_hub_str_index0),
+					      wLength));
+				memcpy(buffer, root_hub_str_index0, len);
+			}
+			if (wValue == 0x0301) {
+				len = min_t(unsigned int,
+					    leni,
+					  min_t(unsigned int,
+						sizeof(root_hub_str_index1),
+					      wLength));
+				memcpy(buffer, root_hub_str_index1, len);
+			}
+			break;
+		default:
+			stat = USB_ST_STALLED;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+	{
+		__u32 temp = 0x00000001;
+
+		data[0] = 9;		/* min length; */
+		data[1] = 0x29;
+		data[2] = temp & RH_A_NDP;
+		data[3] = 0;
+		if (temp & RH_A_PSM)
+			data[3] |= 0x1;
+		if (temp & RH_A_NOCP)
+			data[3] |= 0x10;
+		else if (temp & RH_A_OCPM)
+			data[3] |= 0x8;
+
+		/* corresponds to data[4-7] */
+		data[5] = (temp & RH_A_POTPGT) >> 24;
+		data[7] = temp & RH_B_DR;
+		if (data[2] < 7) {
+			data[8] = 0xff;
+		} else {
+			data[0] += 2;
+			data[8] = (temp & RH_B_DR) >> 8;
+			data[9] = 0xff;
+			data[10] = 0xff;
+		}
+
+		len = min_t(unsigned int, leni,
+			    min_t(unsigned int, data[0], wLength));
+		memcpy(buffer, data, len);
+		break;
+	}
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *)buffer = 0x01;
+		len = 1;
+		break;
+	case RH_SET_CONFIGURATION:
+		break;
+	default:
+		R8A66597_DPRINT("unsupported root hub command");
+		stat = USB_ST_STALLED;
+	}
+
+	mdelay(1);
+
+	len = min_t(int, len, leni);
+
+	dev->act_len = len;
+	dev->status = stat;
+
+	return stat;
+}
+
+static int r8a66597_submit_control_msg(struct udevice *udev,
+				       struct usb_device *dev,
+				       unsigned long pipe, void *buffer,
+				       int length, struct devrequest *setup)
+{
+	struct r8a66597 *r8a66597 = dev_get_priv(udev);
+	u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ?
+					0 : dev->devnum;
+
+	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+	      udev->name, dev, dev->dev->name, dev->portnr);
+
+	R8A66597_DPRINT("%s\n", __func__);
+	if (usb_pipedevice(pipe) == r8a66597->rh_devnum)
+		return r8a66597_submit_rh_msg(udev, dev, pipe, buffer,
+					      length, setup);
+
+	R8A66597_DPRINT("%s: setup\n", __func__);
+	set_devadd(r8a66597, r8a66597_address, dev, 0);
+
+	if (send_setup_packet(r8a66597, dev, setup) < 0) {
+		printf("setup packet send error\n");
+		return -1;
+	}
+
+	dev->act_len = 0;
+	if (usb_pipein(pipe))
+		if (receive_control_packet(r8a66597, dev, buffer,
+					   length) < 0)
+			return -1;
+
+	if (send_status_packet(r8a66597, pipe) < 0)
+		return -1;
+
+	dev->status = 0;
+
+	return 0;
+}
+
+static int r8a66597_submit_bulk_msg(struct udevice *udev,
+				    struct usb_device *dev, unsigned long pipe,
+				    void *buffer, int length)
+{
+	struct r8a66597 *r8a66597 = dev_get_priv(udev);
+	int ret = 0;
+
+	debug("%s: dev='%s', udev=%p\n", __func__, udev->name, dev);
+
+	R8A66597_DPRINT("%s\n", __func__);
+	R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n",
+			pipe, buffer, length, dev->devnum);
+
+	set_devadd(r8a66597, dev->devnum, dev, 0);
+
+	pipe_buffer_setting(r8a66597, dev, pipe);
+
+	dev->act_len = 0;
+	while (dev->act_len < length && ret == 0) {
+		if (ctrlc())
+			return -1;
+
+		if (usb_pipein(pipe))
+			ret = receive_bulk_packet(r8a66597, dev, pipe, buffer,
+						  length);
+		else
+			ret = send_bulk_packet(r8a66597, dev, pipe, buffer,
+					       length);
+	}
+
+	if (ret == 0)
+		dev->status = 0;
+
+	return ret;
+}
+
+static int r8a66597_usb_of_to_plat(struct udevice *dev)
+{
+	struct r8a66597 *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+
+	addr = dev_read_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->reg = addr;
+
+	return 0;
+}
+
+static int r8a66597_usb_probe(struct udevice *dev)
+{
+	struct r8a66597 *priv = dev_get_priv(dev);
+	struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
+	int ret;
+
+	bus_priv->desc_before_addr = true;
+
+	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+		ret = device_get_supply_regulator(dev, "vbus-supply",
+						  &priv->vbus_supply);
+		if (ret) {
+			dev_err(dev,
+				"can't get VBUS supply\n");
+			return ret;
+		}
+
+		ret = regulator_set_enable(priv->vbus_supply, true);
+		if (ret) {
+			dev_err(dev,
+				"can't enable VBUS supply\n");
+			return ret;
+		}
+	}
+
+	disable_controller(priv);
+	mdelay(100);
+
+	enable_controller(priv);
+	r8a66597_port_power(priv, 0, 1);
+
+	/* check usb device */
+	check_usb_device_connecting(priv);
+
+	mdelay(50);
+
+	return 0;
+}
+
+static int r8a66597_usb_remove(struct udevice *dev)
+{
+	struct r8a66597 *priv = dev_get_priv(dev);
+	int ret;
+
+	disable_controller(priv);
+
+	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+		ret = regulator_set_enable(priv->vbus_supply, false);
+		if (ret) {
+			dev_err(dev,
+				"can't disable VBUS supply\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+struct dm_usb_ops r8a66597_usb_ops = {
+	.control = r8a66597_submit_control_msg,
+	.bulk = r8a66597_submit_bulk_msg,
+};
+
+static const struct udevice_id r8a66597_usb_ids[] = {
+	{ .compatible = "renesas,rza1-usbhs" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_r8a66597) = {
+	.name	= "r8a66597_usb",
+	.id	= UCLASS_USB,
+	.of_match = r8a66597_usb_ids,
+	.of_to_plat = r8a66597_usb_of_to_plat,
+	.probe	= r8a66597_usb_probe,
+	.remove = r8a66597_usb_remove,
+	.ops	= &r8a66597_usb_ops,
+	.priv_auto	= sizeof(struct r8a66597),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/r8a66597.h b/roms/u-boot/drivers/usb/host/r8a66597.h
new file mode 100644
index 000000000..625d4938c
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/r8a66597.h
@@ -0,0 +1,617 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * R8A66597 HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ */
+
+#ifndef __R8A66597_H__
+#define __R8A66597_H__
+
+#include <linux/bitops.h>
+#define SYSCFG0		0x00
+#define SYSCFG1		0x02
+#define SYSSTS0		0x04
+#define SYSSTS1		0x06
+#define DVSTCTR0	0x08
+#define DVSTCTR1	0x0A
+#define TESTMODE	0x0C
+#define PINCFG		0x0E
+#define DMA0CFG		0x10
+#define DMA1CFG		0x12
+#define CFIFO		0x14
+#define D0FIFO		0x18
+#define D1FIFO		0x1C
+#define CFIFOSEL	0x20
+#define CFIFOCTR	0x22
+#define CFIFOSIE	0x24
+#define D0FIFOSEL	0x28
+#define D0FIFOCTR	0x2A
+#define D1FIFOSEL	0x2C
+#define D1FIFOCTR	0x2E
+#define INTENB0		0x30
+#define INTENB1		0x32
+#define INTENB2		0x34
+#define BRDYENB		0x36
+#define NRDYENB		0x38
+#define BEMPENB		0x3A
+#define SOFCFG		0x3C
+#define INTSTS0		0x40
+#define INTSTS1		0x42
+#define INTSTS2		0x44
+#define BRDYSTS		0x46
+#define NRDYSTS		0x48
+#define BEMPSTS		0x4A
+#define FRMNUM		0x4C
+#define UFRMNUM		0x4E
+#define USBADDR		0x50
+#define USBREQ		0x54
+#define USBVAL		0x56
+#define USBINDX		0x58
+#define USBLENG		0x5A
+#define DCPCFG		0x5C
+#define DCPMAXP		0x5E
+#define DCPCTR		0x60
+#define PIPESEL		0x64
+#define PIPECFG		0x68
+#define PIPEBUF		0x6A
+#define PIPEMAXP	0x6C
+#define PIPEPERI	0x6E
+#define PIPE1CTR	0x70
+#define PIPE2CTR	0x72
+#define PIPE3CTR	0x74
+#define PIPE4CTR	0x76
+#define PIPE5CTR	0x78
+#define PIPE6CTR	0x7A
+#define PIPE7CTR	0x7C
+#define PIPE8CTR	0x7E
+#define PIPE9CTR	0x80
+#define PIPE1TRE	0x90
+#define PIPE1TRN	0x92
+#define PIPE2TRE	0x94
+#define PIPE2TRN	0x96
+#define PIPE3TRE	0x98
+#define PIPE3TRN	0x9A
+#define PIPE4TRE	0x9C
+#define PIPE4TRN	0x9E
+#define PIPE5TRE	0xA0
+#define PIPE5TRN	0xA2
+#define DEVADD0		0xD0
+#define DEVADD1		0xD2
+#define DEVADD2		0xD4
+#define DEVADD3		0xD6
+#define DEVADD4		0xD8
+#define DEVADD5		0xDA
+#define DEVADD6		0xDC
+#define DEVADD7		0xDE
+#define DEVADD8		0xE0
+#define DEVADD9		0xE2
+#define DEVADDA		0xE4
+#define SUSPMODE0	0x102	/* RZ/A only */
+
+/* System Configuration Control Register */
+#define HSE		0x0080	/* b7: Hi-speed enable */
+#define DCFM		0x0040	/* b6: Controller function select  */
+#define DRPD		0x0020	/* b5: D+/- pull down control */
+#define DPRPU		0x0010	/* b4: D+ pull up control */
+#define XTAL		0x0004	/* b2: Crystal selection */
+#define XTAL12		0x0004	/* 12MHz */
+#define XTAL48		0x0000	/* 48MHz */
+#define UPLLE		0x0002	/* b1: internal PLL control */
+#define USBE		0x0001	/* b0: USB module operation enable */
+
+/* System Configuration Status Register */
+#define OVCBIT		0x8000	/* b15-14: Over-current bit */
+#define OVCMON		0xC000	/* b15-14: Over-current monitor */
+#define SOFEA		0x0020	/* b5: SOF monitor */
+#define IDMON		0x0004	/* b3: ID-pin monitor */
+#define LNST		0x0003	/* b1-0: D+, D- line status */
+#define SE1		0x0003	/* SE1 */
+#define FS_KSTS		0x0002	/* Full-Speed K State */
+#define FS_JSTS		0x0001	/* Full-Speed J State */
+#define LS_JSTS		0x0002	/* Low-Speed J State */
+#define LS_KSTS		0x0001	/* Low-Speed K State */
+#define SE0		0x0000	/* SE0 */
+
+/* Device State Control Register */
+#define EXTLP0		0x0400	/* b10: External port */
+#define VBOUT		0x0200	/* b9: VBUS output */
+#define WKUP		0x0100	/* b8: Remote wakeup */
+#define RWUPE		0x0080	/* b7: Remote wakeup sense */
+#define USBRST		0x0040	/* b6: USB reset enable */
+#define RESUME		0x0020	/* b5: Resume enable */
+#define UACT		0x0010	/* b4: USB bus enable */
+#define RHST		0x0007	/* b1-0: Reset handshake status */
+#define HSPROC		0x0004	/* HS handshake is processing */
+#define HSMODE		0x0003	/* Hi-Speed mode */
+#define FSMODE		0x0002	/* Full-Speed mode */
+#define LSMODE		0x0001	/* Low-Speed mode */
+#define UNDECID		0x0000	/* Undecided */
+
+/* Test Mode Register */
+#define UTST		0x000F	/* b3-0: Test select */
+#define H_TST_PACKET	0x000C	/* HOST TEST Packet */
+#define H_TST_SE0_NAK	0x000B	/* HOST TEST SE0 NAK */
+#define H_TST_K		0x000A	/* HOST TEST K */
+#define H_TST_J		0x0009	/* HOST TEST J */
+#define H_TST_NORMAL	0x0000	/* HOST Normal Mode */
+#define P_TST_PACKET	0x0004	/* PERI TEST Packet */
+#define P_TST_SE0_NAK	0x0003	/* PERI TEST SE0 NAK */
+#define P_TST_K		0x0002	/* PERI TEST K */
+#define P_TST_J		0x0001	/* PERI TEST J */
+#define P_TST_NORMAL	0x0000	/* PERI Normal Mode */
+
+/* Data Pin Configuration Register */
+#define LDRV		0x8000	/* b15: Drive Current Adjust */
+#define VIF1		0x0000	/* VIF = 1.8V */
+#define VIF3		0x8000	/* VIF = 3.3V */
+#define INTA		0x0001	/* b1: USB INT-pin active */
+
+/* DMAx Pin Configuration Register */
+#define DREQA		0x4000	/* b14: Dreq active select */
+#define BURST		0x2000	/* b13: Burst mode */
+#define DACKA		0x0400	/* b10: Dack active select */
+#define DFORM		0x0380	/* b9-7: DMA mode select */
+#define CPU_ADR_RD_WR	0x0000	/* Address + RD/WR mode (CPU bus) */
+#define CPU_DACK_RD_WR	0x0100	/* DACK + RD/WR mode (CPU bus) */
+#define CPU_DACK_ONLY	0x0180	/* DACK only mode (CPU bus) */
+#define SPLIT_DACK_ONLY	0x0200	/* DACK only mode (SPLIT bus) */
+#define DENDA		0x0040	/* b6: Dend active select */
+#define PKTM		0x0020	/* b5: Packet mode */
+#define DENDE		0x0010	/* b4: Dend enable */
+#define OBUS		0x0004	/* b2: OUTbus mode */
+
+/* CFIFO/DxFIFO Port Select Register */
+#define RCNT		0x8000	/* b15: Read count mode */
+#define REW		0x4000	/* b14: Buffer rewind */
+#define DCLRM		0x2000	/* b13: DMA buffer clear mode */
+#define DREQE		0x1000	/* b12: DREQ output enable */
+#define MBW		0x0800	/* b10: Maximum bit width for FIFO access */
+#define MBW_8		0x0000	/*  8bit */
+#define MBW_16		0x0400	/* 16bit */
+#define MBW_32		0x0800	/* 32bit */
+#define BIGEND		0x0100	/* b8: Big endian mode */
+#define BYTE_LITTLE	0x0000	/* little dendian */
+#define BYTE_BIG	0x0100	/* big endifan */
+#define ISEL		0x0020	/* b5: DCP FIFO port direction select */
+#define CURPIPE		0x000F	/* b2-0: PIPE select */
+
+/* CFIFO/DxFIFO Port Control Register */
+#define BVAL		0x8000	/* b15: Buffer valid flag */
+#define BCLR		0x4000	/* b14: Buffer clear */
+#define FRDY		0x2000	/* b13: FIFO ready */
+#define DTLN		0x0FFF	/* b11-0: FIFO received data length */
+
+/* Interrupt Enable Register 0 */
+#define VBSE	0x8000	/* b15: VBUS interrupt */
+#define RSME	0x4000	/* b14: Resume interrupt */
+#define SOFE	0x2000	/* b13: Frame update interrupt */
+#define DVSE	0x1000	/* b12: Device state transition interrupt */
+#define CTRE	0x0800	/* b11: Control transfer stage transition interrupt */
+#define BEMPE	0x0400	/* b10: Buffer empty interrupt */
+#define NRDYE	0x0200	/* b9: Buffer not ready interrupt */
+#define BRDYE	0x0100	/* b8: Buffer ready interrupt */
+
+/* Interrupt Enable Register 1 */
+#define OVRCRE		0x8000	/* b15: Over-current interrupt */
+#define BCHGE		0x4000	/* b14: USB us chenge interrupt */
+#define DTCHE		0x1000	/* b12: Detach sense interrupt */
+#define ATTCHE		0x0800	/* b11: Attach sense interrupt */
+#define EOFERRE		0x0040	/* b6: EOF error interrupt */
+#define SIGNE		0x0020	/* b5: SETUP IGNORE interrupt */
+#define SACKE		0x0010	/* b4: SETUP ACK interrupt */
+
+/* BRDY Interrupt Enable/Status Register */
+#define BRDY9		0x0200	/* b9: PIPE9 */
+#define BRDY8		0x0100	/* b8: PIPE8 */
+#define BRDY7		0x0080	/* b7: PIPE7 */
+#define BRDY6		0x0040	/* b6: PIPE6 */
+#define BRDY5		0x0020	/* b5: PIPE5 */
+#define BRDY4		0x0010	/* b4: PIPE4 */
+#define BRDY3		0x0008	/* b3: PIPE3 */
+#define BRDY2		0x0004	/* b2: PIPE2 */
+#define BRDY1		0x0002	/* b1: PIPE1 */
+#define BRDY0		0x0001	/* b1: PIPE0 */
+
+/* NRDY Interrupt Enable/Status Register */
+#define NRDY9		0x0200	/* b9: PIPE9 */
+#define NRDY8		0x0100	/* b8: PIPE8 */
+#define NRDY7		0x0080	/* b7: PIPE7 */
+#define NRDY6		0x0040	/* b6: PIPE6 */
+#define NRDY5		0x0020	/* b5: PIPE5 */
+#define NRDY4		0x0010	/* b4: PIPE4 */
+#define NRDY3		0x0008	/* b3: PIPE3 */
+#define NRDY2		0x0004	/* b2: PIPE2 */
+#define NRDY1		0x0002	/* b1: PIPE1 */
+#define NRDY0		0x0001	/* b1: PIPE0 */
+
+/* BEMP Interrupt Enable/Status Register */
+#define BEMP9		0x0200	/* b9: PIPE9 */
+#define BEMP8		0x0100	/* b8: PIPE8 */
+#define BEMP7		0x0080	/* b7: PIPE7 */
+#define BEMP6		0x0040	/* b6: PIPE6 */
+#define BEMP5		0x0020	/* b5: PIPE5 */
+#define BEMP4		0x0010	/* b4: PIPE4 */
+#define BEMP3		0x0008	/* b3: PIPE3 */
+#define BEMP2		0x0004	/* b2: PIPE2 */
+#define BEMP1		0x0002	/* b1: PIPE1 */
+#define BEMP0		0x0001	/* b0: PIPE0 */
+
+/* SOF Pin Configuration Register */
+#define TRNENSEL	0x0100	/* b8: Select transaction enable period */
+#define BRDYM		0x0040	/* b6: BRDY clear timing */
+#define INTL		0x0020	/* b5: Interrupt sense select */
+#define EDGESTS		0x0010	/* b4:  */
+#define SOFMODE		0x000C	/* b3-2: SOF pin select */
+#define SOF_125US	0x0008	/* SOF OUT 125us Frame Signal */
+#define SOF_1MS		0x0004	/* SOF OUT 1ms Frame Signal */
+#define SOF_DISABLE	0x0000	/* SOF OUT Disable */
+
+/* Interrupt Status Register 0 */
+#define VBINT	0x8000	/* b15: VBUS interrupt */
+#define RESM	0x4000	/* b14: Resume interrupt */
+#define SOFR	0x2000	/* b13: SOF frame update interrupt */
+#define DVST	0x1000	/* b12: Device state transition interrupt */
+#define CTRT	0x0800	/* b11: Control transfer stage transition interrupt */
+#define BEMP	0x0400	/* b10: Buffer empty interrupt */
+#define NRDY	0x0200	/* b9: Buffer not ready interrupt */
+#define BRDY	0x0100	/* b8: Buffer ready interrupt */
+#define VBSTS	0x0080	/* b7: VBUS input port */
+#define DVSQ	0x0070	/* b6-4: Device state */
+#define DS_SPD_CNFG	0x0070	/* Suspend Configured */
+#define DS_SPD_ADDR	0x0060	/* Suspend Address */
+#define DS_SPD_DFLT	0x0050	/* Suspend Default */
+#define DS_SPD_POWR	0x0040	/* Suspend Powered */
+#define DS_SUSP		0x0040	/* Suspend */
+#define DS_CNFG		0x0030	/* Configured */
+#define DS_ADDS		0x0020	/* Address */
+#define DS_DFLT		0x0010	/* Default */
+#define DS_POWR		0x0000	/* Powered */
+#define DVSQS		0x0030	/* b5-4: Device state */
+#define VALID		0x0008	/* b3: Setup packet detected flag */
+#define CTSQ		0x0007	/* b2-0: Control transfer stage */
+#define CS_SQER		0x0006	/* Sequence error */
+#define CS_WRND		0x0005	/* Control write nodata status stage */
+#define CS_WRSS		0x0004	/* Control write status stage */
+#define CS_WRDS		0x0003	/* Control write data stage */
+#define CS_RDSS		0x0002	/* Control read status stage */
+#define CS_RDDS		0x0001	/* Control read data stage */
+#define CS_IDST		0x0000	/* Idle or setup stage */
+
+/* Interrupt Status Register 1 */
+#define OVRCR		0x8000	/* b15: Over-current interrupt */
+#define BCHG		0x4000	/* b14: USB bus chenge interrupt */
+#define DTCH		0x1000	/* b12: Detach sense interrupt */
+#define ATTCH		0x0800	/* b11: Attach sense interrupt */
+#define EOFERR		0x0040	/* b6: EOF-error interrupt */
+#define SIGN		0x0020	/* b5: Setup ignore interrupt */
+#define SACK		0x0010	/* b4: Setup acknowledge interrupt */
+
+/* Frame Number Register */
+#define OVRN		0x8000	/* b15: Overrun error */
+#define CRCE		0x4000	/* b14: Received data error */
+#define FRNM		0x07FF	/* b10-0: Frame number */
+
+/* Micro Frame Number Register */
+#define UFRNM		0x0007	/* b2-0: Micro frame number */
+
+/* Default Control Pipe Maxpacket Size Register */
+/* Pipe Maxpacket Size Register */
+#define DEVSEL	0xF000	/* b15-14: Device address select */
+#define MAXP	0x007F	/* b6-0: Maxpacket size of default control pipe */
+
+/* Default Control Pipe Control Register */
+#define BSTS		0x8000	/* b15: Buffer status */
+#define SUREQ		0x4000	/* b14: Send USB request  */
+#define CSCLR		0x2000	/* b13: complete-split status clear */
+#define CSSTS		0x1000	/* b12: complete-split status */
+#define SUREQCLR	0x0800	/* b11: stop setup request */
+#define SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define PBUSY		0x0020	/* b5: pipe busy */
+#define PINGE		0x0010	/* b4: ping enable */
+#define CCPL		0x0004	/* b2: Enable control transfer complete */
+#define PID		0x0003	/* b1-0: Response PID */
+#define PID_STALL11	0x0003	/* STALL */
+#define PID_STALL	0x0002	/* STALL */
+#define PID_BUF		0x0001	/* BUF */
+#define PID_NAK		0x0000	/* NAK */
+
+/* Pipe Window Select Register */
+#define PIPENM		0x0007	/* b2-0: Pipe select */
+
+/* Pipe Configuration Register */
+#define R8A66597_TYP	0xC000	/* b15-14: Transfer type */
+#define R8A66597_ISO	0xC000	/* Isochronous */
+#define R8A66597_INT	0x8000	/* Interrupt */
+#define R8A66597_BULK	0x4000	/* Bulk */
+#define R8A66597_BFRE	0x0400	/* b10: Buffer ready interrupt mode select */
+#define R8A66597_DBLB	0x0200	/* b9: Double buffer mode select */
+#define R8A66597_CNTMD	0x0100	/* b8: Continuous transfer mode select */
+#define R8A66597_SHTNAK	0x0080	/* b7: Transfer end NAK */
+#define R8A66597_DIR	0x0010	/* b4: Transfer direction select */
+#define R8A66597_EPNUM	0x000F	/* b3-0: Eendpoint number select */
+
+/* Pipe Buffer Configuration Register */
+#define BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
+#define BUFNMB		0x007F	/* b6-0: Pipe buffer number */
+#define PIPE0BUF	256
+#define PIPExBUF	64
+
+/* Pipe Maxpacket Size Register */
+#define MXPS	0x07FF	/* b10-0: Maxpacket size */
+
+/* Pipe Cycle Configuration Register */
+#define IFIS	0x1000	/* b12: Isochronous in-buffer flush mode select */
+#define IITV	0x0007	/* b2-0: Isochronous interval */
+
+/* Pipex Control Register */
+#define BSTS	0x8000	/* b15: Buffer status */
+#define INBUFM	0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define CSCLR	0x2000	/* b13: complete-split status clear */
+#define CSSTS	0x1000	/* b12: complete-split status */
+#define ATREPM	0x0400	/* b10: Auto repeat mode */
+#define ACLRM	0x0200	/* b9: Out buffer auto clear mode */
+#define SQCLR	0x0100	/* b8: Sequence toggle bit clear */
+#define SQSET	0x0080	/* b7: Sequence toggle bit set */
+#define SQMON	0x0040	/* b6: Sequence toggle bit monitor */
+#define PBUSY	0x0020	/* b5: pipe busy */
+#define PID	0x0003	/* b1-0: Response PID */
+
+/* PIPExTRE */
+#define TRENB		0x0200	/* b9: Transaction counter enable */
+#define TRCLR		0x0100	/* b8: Transaction counter clear */
+
+/* PIPExTRN */
+#define TRNCNT		0xFFFF	/* b15-0: Transaction counter */
+
+/* DEVADDx */
+#define UPPHUB		0x7800
+#define HUBPORT		0x0700
+#define USBSPD		0x00C0
+#define RTPORT		0x0001
+
+/* Suspend Mode Register */
+#define SUSPM		0x4000	/* b14: Suspend */
+
+#define R8A66597_MAX_NUM_PIPE		10
+#define R8A66597_BUF_BSIZE		8
+#define R8A66597_MAX_DEVICE		10
+#define R8A66597_MAX_ROOT_HUB		2
+#define R8A66597_MAX_SAMPLING		5
+#define R8A66597_RH_POLL_TIME		10
+
+#define BULK_IN_PIPENUM		3
+#define BULK_IN_BUFNUM		8
+
+#define BULK_OUT_PIPENUM	4
+#define BULK_OUT_BUFNUM		40
+
+#define make_devsel(addr)		((addr) << 12)
+
+struct r8a66597 {
+	unsigned long reg;
+	unsigned short pipe_config;	/* bit field */
+	unsigned short port_status;
+	unsigned short port_change;
+	u16 speed;	/* HSMODE or FSMODE or LSMODE */
+	unsigned char rh_devnum;
+	struct udevice *vbus_supply;
+};
+
+static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
+{
+	return readw(r8a66597->reg + offset);
+}
+
+static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
+				      unsigned long offset, void *buf,
+				      int len)
+{
+	int i;
+	unsigned long fifoaddr = r8a66597->reg + offset;
+	unsigned long count;
+	unsigned long *p = buf;
+
+	count = len / 4;
+	for (i = 0; i < count; i++)
+		p[i] = readl(r8a66597->reg + offset);
+
+	if (len & 0x00000003) {
+		unsigned long tmp = readl(fifoaddr);
+
+		memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+	}
+}
+
+static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
+				  unsigned long offset)
+{
+	writew(val, r8a66597->reg + offset);
+}
+
+static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
+				       unsigned long offset, void *buf,
+				       int len)
+{
+	int i;
+	unsigned long fifoaddr = r8a66597->reg + offset;
+	unsigned long count;
+	unsigned char *pb;
+	unsigned long *p = buf;
+
+	count = len / 4;
+	for (i = 0; i < count; i++)
+		writel(p[i], fifoaddr);
+
+	if (len & 0x00000003) {
+		pb = (unsigned char *)buf + count * 4;
+		for (i = 0; i < (len & 0x00000003); i++) {
+			if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+				writeb(pb[i], fifoaddr + i);
+			else
+				writeb(pb[i], fifoaddr + 3 - i);
+		}
+	}
+}
+
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+				 u16 val, u16 pat, unsigned long offset)
+{
+	u16 tmp;
+
+	tmp = r8a66597_read(r8a66597, offset);
+	tmp = tmp & (~pat);
+	tmp = tmp | val;
+	r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset)	\
+			r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset)	\
+			r8a66597_mdfy(r8a66597, val, 0, offset)
+
+static inline unsigned long get_syscfg_reg(int port)
+{
+	return port == 0 ? SYSCFG0 : SYSCFG1;
+}
+
+static inline unsigned long get_syssts_reg(int port)
+{
+	return port == 0 ? SYSSTS0 : SYSSTS1;
+}
+
+static inline unsigned long get_dvstctr_reg(int port)
+{
+	return port == 0 ? DVSTCTR0 : DVSTCTR1;
+}
+
+static inline unsigned long get_dmacfg_reg(int port)
+{
+	return port == 0 ? DMA0CFG : DMA1CFG;
+}
+
+static inline unsigned long get_intenb_reg(int port)
+{
+	return port == 0 ? INTENB1 : INTENB2;
+}
+
+static inline unsigned long get_intsts_reg(int port)
+{
+	return port == 0 ? INTSTS1 : INTSTS2;
+}
+
+static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
+{
+	unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+	return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
+}
+
+static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
+				       int power)
+{
+	unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+	if (power)
+		r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
+	else
+		r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+}
+
+#define get_pipectr_addr(pipenum)	(PIPE1CTR + (pipenum - 1) * 2)
+#define get_pipetre_addr(pipenum)	(PIPE1TRE + (pipenum - 1) * 4)
+#define get_pipetrn_addr(pipenum)	(PIPE1TRN + (pipenum - 1) * 4)
+#define get_devadd_addr(address)	(DEVADD0 + address * 2)
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h, based on usb_ohci.h) */
+
+/* destination of request */
+#define RH_INTERFACE		   0x01
+#define RH_ENDPOINT		   0x02
+#define RH_OTHER		   0x03
+
+#define RH_CLASS		   0x20
+#define RH_VENDOR		   0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	   0x00
+#define RH_PORT_ENABLE		   0x01
+#define RH_PORT_SUSPEND		   0x02
+#define RH_PORT_OVER_CURRENT	   0x03
+#define RH_PORT_RESET		   0x04
+#define RH_PORT_POWER		   0x08
+#define RH_PORT_LOW_SPEED	   0x09
+
+#define RH_C_PORT_CONNECTION	   0x10
+#define RH_C_PORT_ENABLE	   0x11
+#define RH_C_PORT_SUSPEND	   0x12
+#define RH_C_PORT_OVER_CURRENT	   0x13
+#define RH_C_PORT_RESET		   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	   0x00
+#define RH_C_HUB_OVER_CURRENT	   0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	   0x00
+#define RH_ENDPOINT_STALL	   0x01
+
+#define RH_ACK			   0x01
+#define RH_REQ_ERR		   -1
+#define RH_NACK			   0x00
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS	0x00000001	/* current connect status */
+#define RH_PS_PES	0x00000002	/* port enable status*/
+#define RH_PS_PSS	0x00000004	/* port suspend status */
+#define RH_PS_POCI	0x00000008	/* port over current indicator */
+#define RH_PS_PRS	0x00000010	/* port reset status */
+#define RH_PS_PPS	0x00000100	/* port power status */
+#define RH_PS_LSDA	0x00000200	/* low speed device attached */
+#define RH_PS_CSC	0x00010000	/* connect status change */
+#define RH_PS_PESC	0x00020000	/* port enable status change */
+#define RH_PS_PSSC	0x00040000	/* port suspend status change */
+#define RH_PS_OCIC	0x00080000	/* over current indicator change */
+#define RH_PS_PRSC	0x00100000	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	0x00000001	/* local power status */
+#define RH_HS_OCI	0x00000002	/* over current indicator */
+#define RH_HS_DRWE	0x00008000	/* device remote wakeup enable */
+#define RH_HS_LPSC	0x00010000	/* local power status change */
+#define RH_HS_OCIC	0x00020000	/* over current indicator change */
+#define RH_HS_CRWE	0x80000000	/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff	/* device removable flags */
+#define RH_B_PPCM	0xffff0000	/* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)	/* number of downstream ports */
+#define RH_A_PSM	BIT(8)	/* power switching mode */
+#define RH_A_NPS	BIT(9)	/* no power switching */
+#define RH_A_DT		BIT(10)	/* device type (mbz) */
+#define RH_A_OCPM	BIT(11)	/* over current protection mode */
+#define RH_A_NOCP	BIT(12)	/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)	/* power on to power good time */
+
+#endif	/* __R8A66597_H__ */
diff --git a/roms/u-boot/drivers/usb/host/sl811-hcd.c b/roms/u-boot/drivers/usb/host/sl811-hcd.c
new file mode 100644
index 000000000..7c823f241
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/sl811-hcd.c
@@ -0,0 +1,714 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This code is based on linux driver for sl811hs chip, source at
+ * drivers/usb/host/sl811.c:
+ *
+ * SL811 Host Controller Interface driver for USB.
+ *
+ * Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ * Based on:
+ *	1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ *	  Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ *	  Adam Richter, Gregory P. Smith;
+ *	2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ *	3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include "sl811.h"
+
+#include "../../../board/kup/common/kup.h"
+
+#ifdef __PPC__
+# define EIEIO		__asm__ volatile ("eieio")
+#else
+# define EIEIO		/* nothing */
+#endif
+
+#define	 SL811_ADR (0x50000000)
+#define	 SL811_DAT (0x50000001)
+
+#ifdef SL811_DEBUG
+static int debug = 9;
+#endif
+
+static int root_hub_devnum = 0;
+static struct usb_port_status rh_status = { 0 };/* root hub port status */
+
+static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
+			       void *data, int buf_len, struct devrequest *cmd);
+
+static void sl811_write (__u8 index, __u8 data)
+{
+	*(volatile unsigned char *) (SL811_ADR) = index;
+	EIEIO;
+	*(volatile unsigned char *) (SL811_DAT) = data;
+	EIEIO;
+}
+
+static __u8 sl811_read (__u8 index)
+{
+	__u8 data;
+
+	*(volatile unsigned char *) (SL811_ADR) = index;
+	EIEIO;
+	data = *(volatile unsigned char *) (SL811_DAT);
+	EIEIO;
+	return (data);
+}
+
+/*
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ */
+static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
+{
+	*(volatile unsigned char *) (SL811_ADR) = offset;
+	EIEIO;
+	while (size--) {
+		*buf++ = *(volatile unsigned char *) (SL811_DAT);
+		EIEIO;
+	}
+}
+
+/*
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ */
+static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
+{
+	*(volatile unsigned char *) (SL811_ADR) = offset;
+	EIEIO;
+	while (size--) {
+		*(volatile unsigned char *) (SL811_DAT) = *buf++;
+		EIEIO;
+	}
+}
+
+int usb_init_kup4x (void)
+{
+	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+	volatile memctl8xx_t *memctl = &immap->im_memctl;
+	int i;
+	unsigned char tmp;
+
+	memctl = &immap->im_memctl;
+	memctl->memc_or7 = 0xFFFF8726;
+	memctl->memc_br7 = 0x50000401;	/* start at 0x50000000 */
+	/* BP 14 low = USB ON */
+	immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
+	/* PB 14 nomal port */
+	immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
+	/* output */
+	immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
+
+	puts ("USB:   ");
+
+	for (i = 0x10; i < 0xff; i++) {
+		sl811_write(i, i);
+		tmp = (sl811_read(i));
+		if (tmp != i) {
+			printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
+			return (-1);
+		}
+	}
+	printf ("SL811 ready\n");
+	return (0);
+}
+
+/*
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device
+ *
+ * Return: 0 = no device attached; 1 = USB device attached
+ */
+static int sl811_hc_reset(void)
+{
+	int status ;
+
+	sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
+	sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+
+	mdelay(20);
+
+	/* Disable hardware SOF generation, clear all irq status. */
+	sl811_write(SL811_CTRL1, 0);
+	mdelay(2);
+	sl811_write(SL811_INTRSTS, 0xff);
+	status = sl811_read(SL811_INTRSTS);
+
+	if (status & SL811_INTR_NOTPRESENT) {
+		/* Device is not present */
+		PDEBUG(0, "Device not present\n");
+		rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
+		rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
+		sl811_write(SL811_INTR, SL811_INTR_INSRMV);
+		return 0;
+	}
+
+	/* Send SOF to address 0, endpoint 0. */
+	sl811_write(SL811_LEN_B, 0);
+	sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
+	sl811_write(SL811_DEV_B, 0x00);
+	sl811_write(SL811_SOFLOW, SL811_12M_LOW);
+
+	if (status & SL811_INTR_SPEED_FULL) {
+		/* full speed device connect directly to root hub */
+		PDEBUG (0, "Full speed Device attached\n");
+
+		sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+		mdelay(20);
+		sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
+		sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
+
+		/* start the SOF or EOP */
+		sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
+		rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
+		rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+		mdelay(2);
+		sl811_write(SL811_INTRSTS, 0xff);
+	} else {
+		/* slow speed device connect directly to root-hub */
+		PDEBUG(0, "Low speed Device attached\n");
+
+		sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+		mdelay(20);
+		sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
+		sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
+
+		/* start the SOF or EOP */
+		sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
+		rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
+		mdelay(2);
+		sl811_write(SL811_INTRSTS, 0xff);
+	}
+
+	rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
+	sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
+
+	return 1;
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	root_hub_devnum = 0;
+	sl811_hc_reset();
+	return 0;
+}
+
+int usb_lowlevel_stop(int index)
+{
+	sl811_hc_reset();
+	return 0;
+}
+
+static int calc_needed_buswidth(int bytes, int need_preamble)
+{
+	return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
+}
+
+static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
+{
+	__u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
+	__u16 status = 0;
+	int err = 0, time_start = get_timer(0);
+	int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
+		(dev->speed == USB_SPEED_LOW);
+
+	if (len > 239)
+		return -1;
+
+	if (usb_pipeout(pipe))
+		ctrl |= SL811_USB_CTRL_DIR_OUT;
+	if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
+		ctrl |= SL811_USB_CTRL_TOGGLE_1;
+	if (need_preamble)
+		ctrl |= SL811_USB_CTRL_PREAMBLE;
+
+	sl811_write(SL811_INTRSTS, 0xff);
+
+	while (err < 3) {
+		sl811_write(SL811_ADDR_A, 0x10);
+		sl811_write(SL811_LEN_A, len);
+		if (usb_pipeout(pipe) && len)
+			sl811_write_buf(0x10, buffer, len);
+
+		if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
+		    sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
+			ctrl |= SL811_USB_CTRL_SOF;
+		else
+			ctrl &= ~SL811_USB_CTRL_SOF;
+
+		sl811_write(SL811_CTRL_A, ctrl);
+		while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
+			if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
+				printf("USB transmit timed out\n");
+				return -USB_ST_CRC_ERR;
+			}
+		}
+
+		sl811_write(SL811_INTRSTS, 0xff);
+		status = sl811_read(SL811_STS_A);
+
+		if (status & SL811_USB_STS_ACK) {
+			int remainder = sl811_read(SL811_CNT_A);
+			if (remainder) {
+				PDEBUG(0, "usb transfer remainder = %d\n", remainder);
+				len -= remainder;
+			}
+			if (usb_pipein(pipe) && len)
+				sl811_read_buf(0x10, buffer, len);
+			return len;
+		}
+
+		if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
+			continue;
+
+		PDEBUG(0, "usb transfer error %#x\n", (int)status);
+		err++;
+	}
+
+	err = 0;
+
+	if (status & SL811_USB_STS_ERROR)
+		err |= USB_ST_BUF_ERR;
+	if (status & SL811_USB_STS_TIMEOUT)
+		err |= USB_ST_CRC_ERR;
+	if (status & SL811_USB_STS_STALL)
+		err |= USB_ST_STALLED;
+
+	return -err;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		    int len)
+{
+	int dir_out = usb_pipeout(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	int max = usb_maxpacket(dev, pipe);
+	int done = 0;
+
+	PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
+	       usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
+
+	dev->status = 0;
+
+	sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
+	sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
+	while (done < len) {
+		int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
+					    max > len - done ? len - done : max);
+		if (res < 0) {
+			dev->status = -res;
+			return res;
+		}
+
+		if (!dir_out && res < max) /* short packet */
+			break;
+
+		done += res;
+		usb_dotoggle(dev, ep, dir_out);
+	}
+
+	dev->act_len = done;
+
+	return 0;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		       int len,struct devrequest *setup)
+{
+	int done = 0;
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+
+	dev->status = 0;
+
+	if (devnum == root_hub_devnum)
+		return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
+
+	PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
+	       devnum, ep, buffer, len, (int)setup->requesttype,
+	       (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
+
+	sl811_write(SL811_DEV_A, devnum);
+	sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
+	/* setup phase */
+	usb_settoggle(dev, ep, 1, 0);
+	if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
+			      (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
+		int dir_in = usb_pipein(pipe);
+		int max = usb_maxpacket(dev, pipe);
+
+		/* data phase */
+		sl811_write(SL811_PIDEP_A,
+			    PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
+		usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
+		while (done < len) {
+			int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
+						    max > len - done ? len - done : max);
+			if (res < 0) {
+				PDEBUG(0, "status data failed!\n");
+				dev->status = -res;
+				return 0;
+			}
+			done += res;
+			usb_dotoggle(dev, ep, usb_pipeout(pipe));
+			if (dir_in && res < max) /* short packet */
+				break;
+		}
+
+		/* status phase */
+		sl811_write(SL811_PIDEP_A,
+			    PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
+		usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
+		if (sl811_send_packet(dev,
+				      !dir_in ? usb_rcvctrlpipe(dev, ep) :
+				      usb_sndctrlpipe(dev, ep),
+				      0, 0) < 0) {
+			PDEBUG(0, "status phase failed!\n");
+			dev->status = -1;
+		}
+	} else {
+		PDEBUG(0, "setup phase failed!\n");
+		dev->status = -1;
+	}
+
+	dev->act_len = done;
+
+	return done;
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int len, int interval, bool nonblock)
+{
+	PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
+	       buffer, len, interval);
+	return -1;
+}
+
+/*
+ * SL811 Virtual Root Hub
+ */
+
+/* Device descriptor */
+static __u8 sl811_rh_dev_des[] =
+{
+	0x12,	    /*	__u8  bLength; */
+	0x01,	    /*	__u8  bDescriptorType; Device */
+	0x10,	    /*	__u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*	__u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  bDeviceSubClass; */
+	0x00,	    /*	__u8  bDeviceProtocol; */
+	0x08,	    /*	__u8  bMaxPacketSize0; 8 Bytes */
+	0x00,	    /*	__u16 idVendor; */
+	0x00,
+	0x00,	    /*	__u16 idProduct; */
+	0x00,
+	0x00,	    /*	__u16 bcdDevice; */
+	0x00,
+	0x00,	    /*	__u8  iManufacturer; */
+	0x02,	    /*	__u8  iProduct; */
+	0x01,	    /*	__u8  iSerialNumber; */
+	0x01	    /*	__u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 sl811_rh_config_des[] =
+{
+	0x09,	    /*	__u8  bLength; */
+	0x02,	    /*	__u8  bDescriptorType; Configuration */
+	0x19,	    /*	__u16 wTotalLength; */
+	0x00,
+	0x01,	    /*	__u8  bNumInterfaces; */
+	0x01,	    /*	__u8  bConfigurationValue; */
+	0x00,	    /*	__u8  iConfiguration; */
+	0x40,	    /*	__u8  bmAttributes;
+		    Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
+		    4..0: resvd */
+	0x00,	    /*	__u8  MaxPower; */
+
+	/* interface */
+	0x09,	    /*	__u8  if_bLength; */
+	0x04,	    /*	__u8  if_bDescriptorType; Interface */
+	0x00,	    /*	__u8  if_bInterfaceNumber; */
+	0x00,	    /*	__u8  if_bAlternateSetting; */
+	0x01,	    /*	__u8  if_bNumEndpoints; */
+	0x09,	    /*	__u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  if_bInterfaceSubClass; */
+	0x00,	    /*	__u8  if_bInterfaceProtocol; */
+	0x00,	    /*	__u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,	    /*	__u8  ep_bLength; */
+	0x05,	    /*	__u8  ep_bDescriptorType; Endpoint */
+	0x81,	    /*	__u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,	    /*	__u8  ep_bmAttributes; Interrupt */
+	0x08,	    /*	__u16 ep_wMaxPacketSize; */
+	0x00,
+	0xff	    /*	__u8  ep_bInterval; 255 ms */
+};
+
+/* root hub class descriptor*/
+static __u8 sl811_rh_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x01,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x50,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0xfc,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *s, u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *s++;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+/*
+ * root_hub_string is used by each host controller's root hub code,
+ * so that they're identified consistently throughout the system.
+ */
+static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+	char buf [30];
+
+	/* assert (len > (2 * (sizeof (buf) + 1)));
+	   assert (strlen (type) <= 8);*/
+
+	/* language ids */
+	if (id == 0) {
+		*data++ = 4; *data++ = 3;	/* 4 bytes data */
+		*data++ = 0; *data++ = 0;	/* some language id */
+		return 4;
+
+	/* serial number */
+	} else if (id == 1) {
+		sprintf (buf, "%#x", serial);
+
+	/* product description */
+	} else if (id == 2) {
+		sprintf (buf, "USB %s Root Hub", type);
+
+	/* id 3 == vendor description */
+
+	/* unsupported IDs --> "stall" */
+	} else
+	    return 0;
+
+	ascii2utf (buf, data + 2, len - 2);
+	data [0] = 2 + strlen(buf) * 2;
+	data [1] = 3;
+	return data [0];
+}
+
+/* helper macro */
+#define OK(x)	len = (x); break
+
+/*
+ * This function handles all USB request to the the virtual root hub
+ */
+static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
+			       void *data, int buf_len, struct devrequest *cmd)
+{
+	__u8 data_buf[16];
+	__u8 *bufp = data_buf;
+	int len = 0;
+	int status = 0;
+	__u16 bmRType_bReq;
+	__u16 wValue  = le16_to_cpu (cmd->value);
+	__u16 wLength = le16_to_cpu (cmd->length);
+#ifdef SL811_DEBUG
+	__u16 wIndex  = le16_to_cpu (cmd->index);
+#endif
+
+	if (usb_pipeint(pipe)) {
+		PDEBUG(0, "interrupt transfer unimplemented!\n");
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+
+	PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
+	       bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
+
+	/* Request Destination:
+		   without flags: Device,
+		   USB_RECIP_INTERFACE: interface,
+		   USB_RECIP_ENDPOINT: endpoint,
+		   USB_TYPE_CLASS means HUB here,
+		   USB_RECIP_OTHER | USB_TYPE_CLASS  almost ever means HUB_PORT here
+	*/
+	switch (bmRType_bReq) {
+	case RH_GET_STATUS:
+		*(__u16 *)bufp = cpu_to_le16(1);
+		OK(2);
+
+	case RH_GET_STATUS | USB_RECIP_INTERFACE:
+		*(__u16 *)bufp = cpu_to_le16(0);
+		OK(2);
+
+	case RH_GET_STATUS | USB_RECIP_ENDPOINT:
+		*(__u16 *)bufp = cpu_to_le16(0);
+		OK(2);
+
+	case RH_GET_STATUS | USB_TYPE_CLASS:
+		*(__u32 *)bufp = cpu_to_le32(0);
+		OK(4);
+
+	case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		*(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
+		OK(4);
+
+	case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
+		switch (wValue) {
+		case 1:
+			OK(0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+			OK(0);
+
+		case C_HUB_OVER_CURRENT:
+			OK(0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
+			OK(0);
+
+		case USB_PORT_FEAT_SUSPEND:
+			rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
+			OK(0);
+
+		case USB_PORT_FEAT_POWER:
+			rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
+			OK(0);
+
+		case USB_PORT_FEAT_C_CONNECTION:
+			rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
+			OK(0);
+
+		case USB_PORT_FEAT_C_ENABLE:
+			rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
+			OK(0);
+
+		case USB_PORT_FEAT_C_SUSPEND:
+			rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
+			OK(0);
+
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
+			OK(0);
+
+		case USB_PORT_FEAT_C_RESET:
+			rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
+			OK(0);
+		}
+		break;
+
+	case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
+			OK(0);
+
+		case USB_PORT_FEAT_RESET:
+			rh_status.wPortStatus |= USB_PORT_STAT_RESET;
+			rh_status.wPortChange = 0;
+			rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
+			rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
+			rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
+			OK(0);
+
+		case USB_PORT_FEAT_POWER:
+			rh_status.wPortStatus |= USB_PORT_STAT_POWER;
+			OK(0);
+
+		case USB_PORT_FEAT_ENABLE:
+			rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
+			OK(0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		root_hub_devnum = wValue;
+		OK(0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case USB_DT_DEVICE:
+			len = sizeof(sl811_rh_dev_des);
+			bufp = sl811_rh_dev_des;
+			OK(len);
+
+		case USB_DT_CONFIG:
+			len = sizeof(sl811_rh_config_des);
+			bufp = sl811_rh_config_des;
+			OK(len);
+
+		case USB_DT_STRING:
+			len = usb_root_hub_string(wValue & 0xff, (int)(long)0,	"SL811HS", data, wLength);
+			if (len > 0) {
+				bufp = data;
+				OK(len);
+			}
+
+		default:
+			status = -32;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
+		len = sizeof(sl811_rh_hub_des);
+		bufp = sl811_rh_hub_des;
+		OK(len);
+
+	case RH_GET_CONFIGURATION:
+		bufp[0] = 0x01;
+		OK(1);
+
+	case RH_SET_CONFIGURATION:
+		OK(0);
+
+	default:
+		PDEBUG(1, "unsupported root hub command\n");
+		status = -32;
+	}
+
+	len = min(len, buf_len);
+	if (data != bufp)
+		memcpy(data, bufp, len);
+
+	PDEBUG(5, "len = %d, status = %d\n", len, status);
+
+	usb_dev->status = status;
+	usb_dev->act_len = len;
+
+	return status == 0 ? len : status;
+}
diff --git a/roms/u-boot/drivers/usb/host/sl811.h b/roms/u-boot/drivers/usb/host/sl811.h
new file mode 100644
index 000000000..c1f9f013b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/sl811.h
@@ -0,0 +1,104 @@
+#ifndef __UBOOT_SL811_H
+#define __UBOOT_SL811_H
+
+#undef SL811_DEBUG
+
+#ifdef SL811_DEBUG
+	#define PDEBUG(level, fmt, args...) \
+		if (debug >= (level)) printf("[%s:%d] " fmt, \
+		__PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+	#define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* Sl811 host control register */
+#define	SL811_CTRL_A		0x00
+#define	SL811_ADDR_A		0x01
+#define	SL811_LEN_A		0x02
+#define	SL811_STS_A		0x03	/* read	*/
+#define	SL811_PIDEP_A		0x03	/* write */
+#define	SL811_CNT_A		0x04	/* read	*/
+#define	SL811_DEV_A		0x04	/* write */
+#define	SL811_CTRL1		0x05
+#define	SL811_INTR		0x06
+#define	SL811_CTRL_B		0x08
+#define	SL811_ADDR_B		0x09
+#define	SL811_LEN_B		0x0A
+#define	SL811_STS_B		0x0B	/* read	*/
+#define	SL811_PIDEP_B		0x0B	/* write */
+#define	SL811_CNT_B		0x0C	/* read	*/
+#define	SL811_DEV_B		0x0C	/* write */
+#define	SL811_INTRSTS		0x0D	/* write clears	bitwise	*/
+#define	SL811_HWREV		0x0E	/* read	*/
+#define	SL811_SOFLOW		0x0E	/* write */
+#define	SL811_SOFCNTDIV		0x0F	/* read	*/
+#define	SL811_CTRL2		0x0F	/* write */
+
+/* USB control register bits (addr 0x00 and addr 0x08) */
+#define	SL811_USB_CTRL_ARM	0x01
+#define	SL811_USB_CTRL_ENABLE	0x02
+#define	SL811_USB_CTRL_DIR_OUT	0x04
+#define	SL811_USB_CTRL_ISO	0x10
+#define	SL811_USB_CTRL_SOF	0x20
+#define	SL811_USB_CTRL_TOGGLE_1	0x40
+#define	SL811_USB_CTRL_PREAMBLE	0x80
+
+/* USB status register bits (addr 0x03 and addr 0x0B) */
+#define	SL811_USB_STS_ACK	0x01
+#define	SL811_USB_STS_ERROR	0x02
+#define	SL811_USB_STS_TIMEOUT	0x04
+#define	SL811_USB_STS_TOGGLE_1	0x08
+#define	SL811_USB_STS_SETUP	0x10
+#define	SL811_USB_STS_OVERFLOW	0x20
+#define	SL811_USB_STS_NAK	0x40
+#define	SL811_USB_STS_STALL	0x80
+
+/* Control register 1 bits (addr 0x05) */
+#define	SL811_CTRL1_SOF		0x01
+#define	SL811_CTRL1_RESET	0x08
+#define	SL811_CTRL1_JKSTATE	0x10
+#define	SL811_CTRL1_SPEED_LOW	0x20
+#define	SL811_CTRL1_SUSPEND	0x40
+
+/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
+#define	SL811_INTR_DONE_A	0x01
+#define	SL811_INTR_DONE_B	0x02
+#define	SL811_INTR_SOF		0x10
+#define	SL811_INTR_INSRMV	0x20
+#define	SL811_INTR_DETECT	0x40
+#define	SL811_INTR_NOTPRESENT	0x40
+#define	SL811_INTR_SPEED_FULL	0x80    /* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0x0E) */
+#define	SL811_HWR_HWREV		0xF0
+
+/* SOF counter and control reg 2 (addr 0x0F) */
+#define	SL811_CTL2_SOFHI	0x3F
+#define	SL811_CTL2_DSWAP	0x40
+#define	SL811_CTL2_HOST		0x80
+
+/* Set up for 1-ms SOF time. */
+#define SL811_12M_LOW		0xE0
+#define SL811_12M_HI		0x2E
+
+#define SL811_DATA_START	0x10
+#define SL811_DATA_LIMIT	240
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+
+
+#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
+
+#endif	/* __UBOOT_SL811_H */
diff --git a/roms/u-boot/drivers/usb/host/usb-sandbox.c b/roms/u-boot/drivers/usb/host/usb-sandbox.c
new file mode 100644
index 000000000..d7cc92aa5
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/usb-sandbox.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <usb.h>
+#include <dm/root.h>
+
+struct sandbox_usb_ctrl {
+	int rootdev;
+};
+
+static void usbmon_trace(struct udevice *bus, ulong pipe,
+			 struct devrequest *setup, struct udevice *emul)
+{
+	static const char types[] = "ZICB";
+	int type;
+
+	type = (pipe & USB_PIPE_TYPE_MASK) >> USB_PIPE_TYPE_SHIFT;
+	debug("0 0 S %c%c:%d:%03ld:%ld", types[type],
+	      pipe & USB_DIR_IN ? 'i' : 'o',
+	      dev_seq(bus),
+	      (pipe & USB_PIPE_DEV_MASK) >> USB_PIPE_DEV_SHIFT,
+	      (pipe & USB_PIPE_EP_MASK) >> USB_PIPE_EP_SHIFT);
+	if (setup) {
+		debug(" s %02x %02x %04x %04x %04x", setup->requesttype,
+		      setup->request, setup->value, setup->index,
+		      setup->length);
+	}
+	debug(" %s", emul ? emul->name : "(no emul found)");
+
+	debug("\n");
+}
+
+static int sandbox_submit_control(struct udevice *bus,
+				      struct usb_device *udev,
+				      unsigned long pipe,
+				      void *buffer, int length,
+				      struct devrequest *setup)
+{
+	struct sandbox_usb_ctrl *ctrl = dev_get_priv(bus);
+	struct udevice *emul;
+	int ret;
+
+	/* Just use child of dev as emulator? */
+	debug("%s: bus=%s\n", __func__, bus->name);
+	ret = usb_emul_find(bus, pipe, udev->portnr, &emul);
+	usbmon_trace(bus, pipe, setup, emul);
+	if (ret)
+		return ret;
+
+	if (usb_pipedevice(pipe) == ctrl->rootdev) {
+		if (setup->request == USB_REQ_SET_ADDRESS) {
+			debug("%s: Set root hub's USB address\n", __func__);
+			ctrl->rootdev = le16_to_cpu(setup->value);
+		}
+	}
+
+	ret = usb_emul_control(emul, udev, pipe, buffer, length, setup);
+	if (ret < 0) {
+		debug("ret=%d\n", ret);
+		udev->status = ret;
+		udev->act_len = 0;
+	} else {
+		udev->status = 0;
+		udev->act_len = ret;
+	}
+
+	return ret;
+}
+
+static int sandbox_submit_bulk(struct udevice *bus, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length)
+{
+	struct udevice *emul;
+	int ret;
+
+	/* Just use child of dev as emulator? */
+	debug("%s: bus=%s\n", __func__, bus->name);
+	ret = usb_emul_find(bus, pipe, udev->portnr, &emul);
+	usbmon_trace(bus, pipe, NULL, emul);
+	if (ret)
+		return ret;
+	ret = usb_emul_bulk(emul, udev, pipe, buffer, length);
+	if (ret < 0) {
+		debug("ret=%d\n", ret);
+		udev->status = ret;
+		udev->act_len = 0;
+	} else {
+		udev->status = 0;
+		udev->act_len = ret;
+	}
+
+	return ret;
+}
+
+static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev,
+			      unsigned long pipe, void *buffer, int length,
+			      int interval, bool nonblock)
+{
+	struct udevice *emul;
+	int ret;
+
+	/* Just use child of dev as emulator? */
+	debug("%s: bus=%s\n", __func__, bus->name);
+	ret = usb_emul_find(bus, pipe, udev->portnr, &emul);
+	usbmon_trace(bus, pipe, NULL, emul);
+	if (ret)
+		return ret;
+	ret = usb_emul_int(emul, udev, pipe, buffer, length, interval,
+			   nonblock);
+
+	return ret;
+}
+
+static int sandbox_alloc_device(struct udevice *dev, struct usb_device *udev)
+{
+	struct sandbox_usb_ctrl *ctrl = dev_get_priv(dev);
+
+	/*
+	 * Root hub will be the first device to be initailized.
+	 * If this device is a root hub, initialize its device speed
+	 * to high speed as we are a USB 2.0 controller.
+	 */
+	if (ctrl->rootdev == 0)
+		udev->speed = USB_SPEED_HIGH;
+
+	return 0;
+}
+
+static int sandbox_usb_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct dm_usb_ops sandbox_usb_ops = {
+	.control	= sandbox_submit_control,
+	.bulk		= sandbox_submit_bulk,
+	.interrupt	= sandbox_submit_int,
+	.alloc_device	= sandbox_alloc_device,
+};
+
+static const struct udevice_id sandbox_usb_ids[] = {
+	{ .compatible = "sandbox,usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_sandbox) = {
+	.name	= "usb_sandbox",
+	.id	= UCLASS_USB,
+	.of_match = sandbox_usb_ids,
+	.probe = sandbox_usb_probe,
+	.ops	= &sandbox_usb_ops,
+	.priv_auto	= sizeof(struct sandbox_usb_ctrl),
+};
diff --git a/roms/u-boot/drivers/usb/host/usb-uclass.c b/roms/u-boot/drivers/usb/host/usb-uclass.c
new file mode 100644
index 000000000..e3b616c32
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/usb-uclass.c
@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * usb_match_device() modified from Linux kernel v4.0.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <memalign.h>
+#include <usb.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+
+extern bool usb_started; /* flag for the started/stopped USB status */
+static bool asynch_allowed;
+
+struct usb_uclass_priv {
+	int companion_device_count;
+};
+
+int usb_lock_async(struct usb_device *udev, int lock)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->lock_async)
+		return -ENOSYS;
+
+	return ops->lock_async(bus, lock);
+}
+
+int usb_disable_asynch(int disable)
+{
+	int old_value = asynch_allowed;
+
+	asynch_allowed = !disable;
+	return old_value;
+}
+
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+		   int length, int interval, bool nonblock)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->interrupt)
+		return -ENOSYS;
+
+	return ops->interrupt(bus, udev, pipe, buffer, length, interval,
+			      nonblock);
+}
+
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
+		       void *buffer, int length, struct devrequest *setup)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+	struct usb_uclass_priv *uc_priv = uclass_get_priv(bus->uclass);
+	int err;
+
+	if (!ops->control)
+		return -ENOSYS;
+
+	err = ops->control(bus, udev, pipe, buffer, length, setup);
+	if (setup->request == USB_REQ_SET_FEATURE &&
+	    setup->requesttype == USB_RT_PORT &&
+	    setup->value == cpu_to_le16(USB_PORT_FEAT_RESET) &&
+	    err == -ENXIO) {
+		/* Device handed over to companion after port reset */
+		uc_priv->companion_device_count++;
+	}
+
+	return err;
+}
+
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+		    int length)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->bulk)
+		return -ENOSYS;
+
+	return ops->bulk(bus, udev, pipe, buffer, length);
+}
+
+struct int_queue *create_int_queue(struct usb_device *udev,
+		unsigned long pipe, int queuesize, int elementsize,
+		void *buffer, int interval)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->create_int_queue)
+		return NULL;
+
+	return ops->create_int_queue(bus, udev, pipe, queuesize, elementsize,
+				     buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *udev, struct int_queue *queue)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->poll_int_queue)
+		return NULL;
+
+	return ops->poll_int_queue(bus, udev, queue);
+}
+
+int destroy_int_queue(struct usb_device *udev, struct int_queue *queue)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->destroy_int_queue)
+		return -ENOSYS;
+
+	return ops->destroy_int_queue(bus, udev, queue);
+}
+
+int usb_alloc_device(struct usb_device *udev)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	/* This is only requird by some controllers - current XHCI */
+	if (!ops->alloc_device)
+		return 0;
+
+	return ops->alloc_device(bus, udev);
+}
+
+int usb_reset_root_port(struct usb_device *udev)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->reset_root_port)
+		return -ENOSYS;
+
+	return ops->reset_root_port(bus, udev);
+}
+
+int usb_update_hub_device(struct usb_device *udev)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->update_hub_device)
+		return -ENOSYS;
+
+	return ops->update_hub_device(bus, udev);
+}
+
+int usb_get_max_xfer_size(struct usb_device *udev, size_t *size)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->get_max_xfer_size)
+		return -ENOSYS;
+
+	return ops->get_max_xfer_size(bus, size);
+}
+
+int usb_stop(void)
+{
+	struct udevice *bus;
+	struct udevice *rh;
+	struct uclass *uc;
+	struct usb_uclass_priv *uc_priv;
+	int err = 0, ret;
+
+	/* De-activate any devices that have been activated */
+	ret = uclass_get(UCLASS_USB, &uc);
+	if (ret)
+		return ret;
+
+	uc_priv = uclass_get_priv(uc);
+
+	uclass_foreach_dev(bus, uc) {
+		ret = device_remove(bus, DM_REMOVE_NORMAL);
+		if (ret && !err)
+			err = ret;
+
+		/* Locate root hub device */
+		device_find_first_child(bus, &rh);
+		if (rh) {
+			/*
+			 * All USB devices are children of root hub.
+			 * Unbinding root hub will unbind all of its children.
+			 */
+			ret = device_unbind(rh);
+			if (ret && !err)
+				err = ret;
+		}
+	}
+
+#ifdef CONFIG_USB_STORAGE
+	usb_stor_reset();
+#endif
+	uc_priv->companion_device_count = 0;
+	usb_started = 0;
+
+	return err;
+}
+
+static void usb_scan_bus(struct udevice *bus, bool recurse)
+{
+	struct usb_bus_priv *priv;
+	struct udevice *dev;
+	int ret;
+
+	priv = dev_get_uclass_priv(bus);
+
+	assert(recurse);	/* TODO: Support non-recusive */
+
+	printf("scanning bus %s for devices... ", bus->name);
+	debug("\n");
+	ret = usb_scan_device(bus, 0, USB_SPEED_FULL, &dev);
+	if (ret)
+		printf("failed, error %d\n", ret);
+	else if (priv->next_addr == 0)
+		printf("No USB Device found\n");
+	else
+		printf("%d USB Device(s) found\n", priv->next_addr);
+}
+
+static void remove_inactive_children(struct uclass *uc, struct udevice *bus)
+{
+	uclass_foreach_dev(bus, uc) {
+		struct udevice *dev, *next;
+
+		if (!device_active(bus))
+			continue;
+		device_foreach_child_safe(dev, next, bus) {
+			if (!device_active(dev))
+				device_unbind(dev);
+		}
+	}
+}
+
+int usb_init(void)
+{
+	int controllers_initialized = 0;
+	struct usb_uclass_priv *uc_priv;
+	struct usb_bus_priv *priv;
+	struct udevice *bus;
+	struct uclass *uc;
+	int ret;
+
+	asynch_allowed = 1;
+
+	ret = uclass_get(UCLASS_USB, &uc);
+	if (ret)
+		return ret;
+
+	uc_priv = uclass_get_priv(uc);
+
+	uclass_foreach_dev(bus, uc) {
+		/* init low_level USB */
+		printf("Bus %s: ", bus->name);
+
+#ifdef CONFIG_SANDBOX
+		/*
+		 * For Sandbox, we need scan the device tree each time when we
+		 * start the USB stack, in order to re-create the emulated USB
+		 * devices and bind drivers for them before we actually do the
+		 * driver probe.
+		 */
+		ret = dm_scan_fdt_dev(bus);
+		if (ret) {
+			printf("Sandbox USB device scan failed (%d)\n", ret);
+			continue;
+		}
+#endif
+
+		ret = device_probe(bus);
+		if (ret == -ENODEV) {	/* No such device. */
+			puts("Port not available.\n");
+			controllers_initialized++;
+			continue;
+		}
+
+		if (ret) {		/* Other error. */
+			printf("probe failed, error %d\n", ret);
+			continue;
+		}
+		controllers_initialized++;
+		usb_started = true;
+	}
+
+	/*
+	 * lowlevel init done, now scan the bus for devices i.e. search HUBs
+	 * and configure them, first scan primary controllers.
+	 */
+	uclass_foreach_dev(bus, uc) {
+		if (!device_active(bus))
+			continue;
+
+		priv = dev_get_uclass_priv(bus);
+		if (!priv->companion)
+			usb_scan_bus(bus, true);
+	}
+
+	/*
+	 * Now that the primary controllers have been scanned and have handed
+	 * over any devices they do not understand to their companions, scan
+	 * the companions if necessary.
+	 */
+	if (uc_priv->companion_device_count) {
+		uclass_foreach_dev(bus, uc) {
+			if (!device_active(bus))
+				continue;
+
+			priv = dev_get_uclass_priv(bus);
+			if (priv->companion)
+				usb_scan_bus(bus, true);
+		}
+	}
+
+	debug("scan end\n");
+
+	/* Remove any devices that were not found on this scan */
+	remove_inactive_children(uc, bus);
+
+	ret = uclass_get(UCLASS_USB_HUB, &uc);
+	if (ret)
+		return ret;
+	remove_inactive_children(uc, bus);
+
+	/* if we were not able to find at least one working bus, bail out */
+	if (controllers_initialized == 0)
+		printf("No working controllers found\n");
+
+	return usb_started ? 0 : -1;
+}
+
+/*
+ * TODO(sjg@chromium.org): Remove this legacy function. At present it is needed
+ * to support boards which use driver model for USB but not Ethernet, and want
+ * to use USB Ethernet.
+ *
+ * The #if clause is here to ensure that remains the only case.
+ */
+#if !defined(CONFIG_DM_ETH) && defined(CONFIG_USB_HOST_ETHER)
+static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
+{
+	struct usb_device *udev;
+	struct udevice *dev;
+
+	if (!device_active(parent))
+		return NULL;
+	udev = dev_get_parent_priv(parent);
+	if (udev->devnum == devnum)
+		return udev;
+
+	for (device_find_first_child(parent, &dev);
+	     dev;
+	     device_find_next_child(&dev)) {
+		udev = find_child_devnum(dev, devnum);
+		if (udev)
+			return udev;
+	}
+
+	return NULL;
+}
+
+struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
+{
+	struct udevice *dev;
+	int devnum = index + 1; /* Addresses are allocated from 1 on USB */
+
+	device_find_first_child(bus, &dev);
+	if (!dev)
+		return NULL;
+
+	return find_child_devnum(dev, devnum);
+}
+#endif
+
+int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
+{
+	struct usb_plat *plat;
+	struct udevice *dev;
+	int ret;
+
+	/* Find the old device and remove it */
+	ret = uclass_find_device_by_seq(UCLASS_USB, 0, &dev);
+	if (ret)
+		return ret;
+	ret = device_remove(dev, DM_REMOVE_NORMAL);
+	if (ret)
+		return ret;
+
+	plat = dev_get_plat(dev);
+	plat->init_type = USB_INIT_DEVICE;
+	ret = device_probe(dev);
+	if (ret)
+		return ret;
+	*ctlrp = dev_get_priv(dev);
+
+	return 0;
+}
+
+int usb_remove_ehci_gadget(struct ehci_ctrl **ctlrp)
+{
+	struct udevice *dev;
+	int ret;
+
+	/* Find the old device and remove it */
+	ret = uclass_find_device_by_seq(UCLASS_USB, 0, &dev);
+	if (ret)
+		return ret;
+	ret = device_remove(dev, DM_REMOVE_NORMAL);
+	if (ret)
+		return ret;
+
+	*ctlrp = NULL;
+
+	return 0;
+}
+
+/* returns 0 if no match, 1 if match */
+static int usb_match_device(const struct usb_device_descriptor *desc,
+			    const struct usb_device_id *id)
+{
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+	    id->idVendor != desc->idVendor)
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+	    id->idProduct != desc->idProduct)
+		return 0;
+
+	/* No need to test id->bcdDevice_lo != 0, since 0 is never
+	   greater than any unsigned number. */
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+	    (id->bcdDevice_lo > desc->bcdDevice))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+	    (id->bcdDevice_hi < desc->bcdDevice))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+	    (id->bDeviceClass != desc->bDeviceClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+	    (id->bDeviceSubClass != desc->bDeviceSubClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+	    (id->bDeviceProtocol != desc->bDeviceProtocol))
+		return 0;
+
+	return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+static int usb_match_one_id_intf(const struct usb_device_descriptor *desc,
+			const struct usb_interface_descriptor *int_desc,
+			const struct usb_device_id *id)
+{
+	/* The interface class, subclass, protocol and number should never be
+	 * checked for a match if the device class is Vendor Specific,
+	 * unless the match record specifies the Vendor ID. */
+	if (desc->bDeviceClass == USB_CLASS_VENDOR_SPEC &&
+	    !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+	    (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
+				USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+				USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+				USB_DEVICE_ID_MATCH_INT_NUMBER)))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+	    (id->bInterfaceClass != int_desc->bInterfaceClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+	    (id->bInterfaceSubClass != int_desc->bInterfaceSubClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+	    (id->bInterfaceProtocol != int_desc->bInterfaceProtocol))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+	    (id->bInterfaceNumber != int_desc->bInterfaceNumber))
+		return 0;
+
+	return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+static int usb_match_one_id(struct usb_device_descriptor *desc,
+			    struct usb_interface_descriptor *int_desc,
+			    const struct usb_device_id *id)
+{
+	if (!usb_match_device(desc, id))
+		return 0;
+
+	return usb_match_one_id_intf(desc, int_desc, id);
+}
+
+static ofnode usb_get_ofnode(struct udevice *hub, int port)
+{
+	ofnode node;
+	u32 reg;
+
+	if (!dev_has_ofnode(hub))
+		return ofnode_null();
+
+	/*
+	 * The USB controller and its USB hub are two different udevices,
+	 * but the device tree has only one node for both. Thus we are
+	 * assigning this node to both udevices.
+	 * If port is zero, the controller scans its root hub, thus we
+	 * are using the same ofnode as the controller here.
+	 */
+	if (!port)
+		return dev_ofnode(hub);
+
+	ofnode_for_each_subnode(node, dev_ofnode(hub)) {
+		if (ofnode_read_u32(node, "reg", &reg))
+			continue;
+
+		if (reg == port)
+			return node;
+	}
+
+	return ofnode_null();
+}
+
+/**
+ * usb_find_and_bind_driver() - Find and bind the right USB driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+static int usb_find_and_bind_driver(struct udevice *parent,
+				    struct usb_device_descriptor *desc,
+				    struct usb_interface_descriptor *iface,
+				    int bus_seq, int devnum, int port,
+				    struct udevice **devp)
+{
+	struct usb_driver_entry *start, *entry;
+	int n_ents;
+	int ret;
+	char name[30], *str;
+	ofnode node = usb_get_ofnode(parent, port);
+
+	*devp = NULL;
+	debug("%s: Searching for driver\n", __func__);
+	start = ll_entry_start(struct usb_driver_entry, usb_driver_entry);
+	n_ents = ll_entry_count(struct usb_driver_entry, usb_driver_entry);
+	for (entry = start; entry != start + n_ents; entry++) {
+		const struct usb_device_id *id;
+		struct udevice *dev;
+		const struct driver *drv;
+		struct usb_dev_plat *plat;
+
+		for (id = entry->match; id->match_flags; id++) {
+			if (!usb_match_one_id(desc, iface, id))
+				continue;
+
+			drv = entry->driver;
+			/*
+			 * We could pass the descriptor to the driver as
+			 * plat (instead of NULL) and allow its bind()
+			 * method to return -ENOENT if it doesn't support this
+			 * device. That way we could continue the search to
+			 * find another driver. For now this doesn't seem
+			 * necesssary, so just bind the first match.
+			 */
+			ret = device_bind(parent, drv, drv->name, NULL, node,
+					  &dev);
+			if (ret)
+				goto error;
+			debug("%s: Match found: %s\n", __func__, drv->name);
+			dev->driver_data = id->driver_info;
+			plat = dev_get_parent_plat(dev);
+			plat->id = *id;
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	/* Bind a generic driver so that the device can be used */
+	snprintf(name, sizeof(name), "generic_bus_%x_dev_%x", bus_seq, devnum);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	ret = device_bind_driver(parent, "usb_dev_generic_drv", str, devp);
+
+error:
+	debug("%s: No match found: %d\n", __func__, ret);
+	return ret;
+}
+
+/**
+ * usb_find_child() - Find an existing device which matches our needs
+ *
+ *
+ */
+static int usb_find_child(struct udevice *parent,
+			  struct usb_device_descriptor *desc,
+			  struct usb_interface_descriptor *iface,
+			  struct udevice **devp)
+{
+	struct udevice *dev;
+
+	*devp = NULL;
+	for (device_find_first_child(parent, &dev);
+	     dev;
+	     device_find_next_child(&dev)) {
+		struct usb_dev_plat *plat = dev_get_parent_plat(dev);
+
+		/* If this device is already in use, skip it */
+		if (device_active(dev))
+			continue;
+		debug("   %s: name='%s', plat=%d, desc=%d\n", __func__,
+		      dev->name, plat->id.bDeviceClass, desc->bDeviceClass);
+		if (usb_match_one_id(desc, iface, &plat->id)) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+int usb_scan_device(struct udevice *parent, int port,
+		    enum usb_device_speed speed, struct udevice **devp)
+{
+	struct udevice *dev;
+	bool created = false;
+	struct usb_dev_plat *plat;
+	struct usb_bus_priv *priv;
+	struct usb_device *parent_udev;
+	int ret;
+	ALLOC_CACHE_ALIGN_BUFFER(struct usb_device, udev, 1);
+	struct usb_interface_descriptor *iface = &udev->config.if_desc[0].desc;
+
+	*devp = NULL;
+	memset(udev, '\0', sizeof(*udev));
+	udev->controller_dev = usb_get_bus(parent);
+	priv = dev_get_uclass_priv(udev->controller_dev);
+
+	/*
+	 * Somewhat nasty, this. We create a local device and use the normal
+	 * USB stack to read its descriptor. Then we know what type of device
+	 * to create for real.
+	 *
+	 * udev->dev is set to the parent, since we don't have a real device
+	 * yet. The USB stack should not access udev.dev anyway, except perhaps
+	 * to find the controller, and the controller will either be @parent,
+	 * or some parent of @parent.
+	 *
+	 * Another option might be to create the device as a generic USB
+	 * device, then morph it into the correct one when we know what it
+	 * should be. This means that a generic USB device would morph into
+	 * a network controller, or a USB flash stick, for example. However,
+	 * we don't support such morphing and it isn't clear that it would
+	 * be easy to do.
+	 *
+	 * Yet another option is to split out the USB stack parts of udev
+	 * into something like a 'struct urb' (as Linux does) which can exist
+	 * independently of any device. This feels cleaner, but calls for quite
+	 * a big change to the USB stack.
+	 *
+	 * For now, the approach is to set up an empty udev, read its
+	 * descriptor and assign it an address, then bind a real device and
+	 * stash the resulting information into the device's parent
+	 * platform data. Then when we probe it, usb_child_pre_probe() is called
+	 * and it will pull the information out of the stash.
+	 */
+	udev->dev = parent;
+	udev->speed = speed;
+	udev->devnum = priv->next_addr + 1;
+	udev->portnr = port;
+	debug("Calling usb_setup_device(), portnr=%d\n", udev->portnr);
+	parent_udev = device_get_uclass_id(parent) == UCLASS_USB_HUB ?
+		dev_get_parent_priv(parent) : NULL;
+	ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev);
+	debug("read_descriptor for '%s': ret=%d\n", parent->name, ret);
+	if (ret)
+		return ret;
+	ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
+	debug("** usb_find_child returns %d\n", ret);
+	if (ret) {
+		if (ret != -ENOENT)
+			return ret;
+		ret = usb_find_and_bind_driver(parent, &udev->descriptor,
+					       iface,
+					       dev_seq(udev->controller_dev),
+					       udev->devnum, port, &dev);
+		if (ret)
+			return ret;
+		created = true;
+	}
+	plat = dev_get_parent_plat(dev);
+	debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat);
+	plat->devnum = udev->devnum;
+	plat->udev = udev;
+	priv->next_addr++;
+	ret = device_probe(dev);
+	if (ret) {
+		debug("%s: Device '%s' probe failed\n", __func__, dev->name);
+		priv->next_addr--;
+		if (created)
+			device_unbind(dev);
+		return ret;
+	}
+	*devp = dev;
+
+	return 0;
+}
+
+/*
+ * Detect if a USB device has been plugged or unplugged.
+ */
+int usb_detect_change(void)
+{
+	struct udevice *hub;
+	struct uclass *uc;
+	int change = 0;
+	int ret;
+
+	ret = uclass_get(UCLASS_USB_HUB, &uc);
+	if (ret)
+		return ret;
+
+	uclass_foreach_dev(hub, uc) {
+		struct usb_device *udev;
+		struct udevice *dev;
+
+		if (!device_active(hub))
+			continue;
+		for (device_find_first_child(hub, &dev);
+		     dev;
+		     device_find_next_child(&dev)) {
+			struct usb_port_status status;
+
+			if (!device_active(dev))
+				continue;
+
+			udev = dev_get_parent_priv(dev);
+			if (usb_get_port_status(udev, udev->portnr, &status)
+					< 0)
+				/* USB request failed */
+				continue;
+
+			if (le16_to_cpu(status.wPortChange) &
+			    USB_PORT_STAT_C_CONNECTION)
+				change++;
+		}
+	}
+
+	return change;
+}
+
+static int usb_child_post_bind(struct udevice *dev)
+{
+	struct usb_dev_plat *plat = dev_get_parent_plat(dev);
+	int val;
+
+	if (!dev_has_ofnode(dev))
+		return 0;
+
+	/* We only support matching a few things */
+	val = dev_read_u32_default(dev, "usb,device-class", -1);
+	if (val != -1) {
+		plat->id.match_flags |= USB_DEVICE_ID_MATCH_DEV_CLASS;
+		plat->id.bDeviceClass = val;
+	}
+	val = dev_read_u32_default(dev, "usb,interface-class", -1);
+	if (val != -1) {
+		plat->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+		plat->id.bInterfaceClass = val;
+	}
+
+	return 0;
+}
+
+struct udevice *usb_get_bus(struct udevice *dev)
+{
+	struct udevice *bus;
+
+	for (bus = dev; bus && device_get_uclass_id(bus) != UCLASS_USB; )
+		bus = bus->parent;
+	if (!bus) {
+		/* By design this cannot happen */
+		assert(bus);
+		debug("USB HUB '%s' does not have a controller\n", dev->name);
+	}
+
+	return bus;
+}
+
+int usb_child_pre_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parent_priv(dev);
+	struct usb_dev_plat *plat = dev_get_parent_plat(dev);
+	int ret;
+
+	if (plat->udev) {
+		/*
+		 * Copy over all the values set in the on stack struct
+		 * usb_device in usb_scan_device() to our final struct
+		 * usb_device for this dev.
+		 */
+		*udev = *(plat->udev);
+		/* And clear plat->udev as it will not be valid for long */
+		plat->udev = NULL;
+		udev->dev = dev;
+	} else {
+		/*
+		 * This happens with devices which are explicitly bound
+		 * instead of being discovered through usb_scan_device()
+		 * such as sandbox emul devices.
+		 */
+		udev->dev = dev;
+		udev->controller_dev = usb_get_bus(dev);
+		udev->devnum = plat->devnum;
+
+		/*
+		 * udev did not go through usb_scan_device(), so we need to
+		 * select the config and read the config descriptors.
+		 */
+		ret = usb_select_config(udev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+UCLASS_DRIVER(usb) = {
+	.id		= UCLASS_USB,
+	.name		= "usb",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.post_bind	= dm_scan_fdt_dev,
+	.priv_auto	= sizeof(struct usb_uclass_priv),
+	.per_child_auto	= sizeof(struct usb_device),
+	.per_device_auto	= sizeof(struct usb_bus_priv),
+	.child_post_bind = usb_child_post_bind,
+	.child_pre_probe = usb_child_pre_probe,
+	.per_child_plat_auto	= sizeof(struct usb_dev_plat),
+};
+
+UCLASS_DRIVER(usb_dev_generic) = {
+	.id		= UCLASS_USB_DEV_GENERIC,
+	.name		= "usb_dev_generic",
+};
+
+U_BOOT_DRIVER(usb_dev_generic_drv) = {
+	.id		= UCLASS_USB_DEV_GENERIC,
+	.name		= "usb_dev_generic_drv",
+};
diff --git a/roms/u-boot/drivers/usb/host/utmi-armada100.c b/roms/u-boot/drivers/usb/host/utmi-armada100.c
new file mode 100644
index 000000000..5d66e5881
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/utmi-armada100.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <contact@8051projects.net>
+ *
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/armada100.h>
+#include <asm/arch/utmi-armada100.h>
+#include <linux/delay.h>
+
+static int utmi_phy_init(void)
+{
+	struct armd1usb_phy_reg *phy_regs =
+		(struct armd1usb_phy_reg *)UTMI_PHY_BASE;
+	int timeout;
+
+	setbits_le32(&phy_regs->utmi_ctrl, INPKT_DELAY_SOF | PLL_PWR_UP);
+	udelay(1000);
+	setbits_le32(&phy_regs->utmi_ctrl, PHY_PWR_UP);
+
+	clrbits_le32(&phy_regs->utmi_pll, PLL_FBDIV_MASK | PLL_REFDIV_MASK);
+	setbits_le32(&phy_regs->utmi_pll, N_DIVIDER << PLL_FBDIV | M_DIVIDER);
+
+	setbits_le32(&phy_regs->utmi_tx, PHSEL_VAL << CK60_PHSEL);
+
+	/* Calibrate pll */
+	timeout = 10000;
+	while (--timeout && ((readl(&phy_regs->utmi_pll) & PLL_READY) == 0))
+		;
+	if (!timeout)
+		return -1;
+
+	udelay(200);
+	setbits_le32(&phy_regs->utmi_pll, VCOCAL_START);
+	udelay(400);
+	clrbits_le32(&phy_regs->utmi_pll, VCOCAL_START);
+
+	udelay(200);
+	setbits_le32(&phy_regs->utmi_tx, RCAL_START);
+	udelay(400);
+	clrbits_le32(&phy_regs->utmi_tx, RCAL_START);
+
+	timeout = 10000;
+	while (--timeout && ((readl(&phy_regs->utmi_pll) & PLL_READY) == 0))
+		;
+	if (!timeout)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Initialize USB host controller's UTMI Physical interface
+ */
+int utmi_init(void)
+{
+	struct armd1mpmu_registers *mpmu_regs =
+		(struct armd1mpmu_registers *)ARMD1_MPMU_BASE;
+
+	struct armd1apmu_registers *apmu_regs =
+		(struct armd1apmu_registers *)ARMD1_APMU_BASE;
+
+	/* Turn on 26Mhz ref clock for UTMI PLL */
+	setbits_le32(&mpmu_regs->acgr, APB2_26M_EN | AP_26M);
+
+	/* USB Clock reset */
+	writel(USB_SPH_AXICLK_EN, &apmu_regs->usbcrc);
+	writel(USB_SPH_AXICLK_EN | USB_SPH_AXI_RST, &apmu_regs->usbcrc);
+
+	/* Initialize UTMI transceiver */
+	return utmi_phy_init();
+}
diff --git a/roms/u-boot/drivers/usb/host/xhci-brcm.c b/roms/u-boot/drivers/usb/host/xhci-brcm.c
new file mode 100644
index 000000000..27c4bbfcb
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-brcm.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Broadcom.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <usb/xhci.h>
+
+#define DRD2U3H_XHC_REGS_AXIWRA	0xC08
+#define DRD2U3H_XHC_REGS_AXIRDA	0xC0C
+
+#define USBAXI_CACHE		0xF
+#define USBAXI_PROT		0x8
+#define USBAXI_SA_MASK		0x1FF
+#define USBAXI_UA_MASK		(0x1FF << 16)
+#define USBAXI_SA_VAL		((USBAXI_CACHE << 4) | USBAXI_PROT)
+#define USBAXI_UA_VAL		(USBAXI_SA_VAL << 16)
+#define USBAXI_SA_UA_MASK	(USBAXI_UA_MASK | USBAXI_SA_MASK)
+#define USBAXI_SA_UA_VAL	(USBAXI_UA_VAL | USBAXI_SA_VAL)
+
+struct brcm_xhci_plat {
+	unsigned int arcache;
+	unsigned int awcache;
+	void __iomem *hc_base;
+};
+
+static int xhci_brcm_probe(struct udevice *dev)
+{
+	struct brcm_xhci_plat *plat = dev_get_plat(dev);
+	struct xhci_hcor *hcor;
+	struct xhci_hccr *hcd;
+	int len, ret = 0;
+
+	if (!plat) {
+		dev_err(dev, "Can't get xHCI Plat data\n");
+		return -ENOMEM;
+	}
+
+	hcd = dev_read_addr_ptr(dev);
+	if (!hcd) {
+		dev_err(dev, "Can't get the xHCI register base address\n");
+		return -ENXIO;
+	}
+
+	plat->hc_base = hcd;
+	len = HC_LENGTH(xhci_readl(&hcd->cr_capbase));
+	hcor = (struct xhci_hcor *)(plat->hc_base + len);
+
+	/* Save the default values of AXI read and write attributes */
+	plat->awcache = readl(plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA);
+	plat->arcache = readl(plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA);
+
+	/* Enable AXI write attributes */
+	clrsetbits_le32(plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA,
+			USBAXI_SA_UA_MASK, USBAXI_SA_UA_VAL);
+
+	/* Enable AXI read attributes */
+	clrsetbits_le32(plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA,
+			USBAXI_SA_UA_MASK, USBAXI_SA_UA_VAL);
+
+	ret = xhci_register(dev, hcd, hcor);
+	if (ret)
+		dev_err(dev, "Failed to register xHCI\n");
+
+	return ret;
+}
+
+static int xhci_brcm_deregister(struct udevice *dev)
+{
+	struct brcm_xhci_plat *plat = dev_get_plat(dev);
+
+	/* Restore the default values for AXI read and write attributes */
+	writel(plat->awcache, plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA);
+	writel(plat->arcache, plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA);
+
+	return xhci_deregister(dev);
+}
+
+static const struct udevice_id xhci_brcm_ids[] = {
+	{ .compatible = "brcm,generic-xhci" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name				= "xhci_brcm",
+	.id				= UCLASS_USB,
+	.probe				= xhci_brcm_probe,
+	.remove				= xhci_brcm_deregister,
+	.ops				= &xhci_usb_ops,
+	.of_match			= xhci_brcm_ids,
+	.plat_auto	= sizeof(struct brcm_xhci_plat),
+	.priv_auto		= sizeof(struct xhci_ctrl),
+	.flags				= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/xhci-dwc3.c b/roms/u-boot/drivers/usb/host/xhci-dwc3.c
new file mode 100644
index 000000000..3e0ae80ce
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-dwc3.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * DWC3 controller driver
+ *
+ * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <usb.h>
+#include <dwc3-uboot.h>
+#include <linux/delay.h>
+
+#include <usb/xhci.h>
+#include <asm/io.h>
+#include <linux/usb/dwc3.h>
+#include <linux/usb/otg.h>
+
+struct xhci_dwc3_plat {
+	struct phy_bulk phys;
+};
+
+void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
+{
+	clrsetbits_le32(&dwc3_reg->g_ctl,
+			DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
+			DWC3_GCTL_PRTCAPDIR(mode));
+}
+
+static void dwc3_phy_reset(struct dwc3 *dwc3_reg)
+{
+	/* Assert USB3 PHY reset */
+	setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
+
+	/* Assert USB2 PHY reset */
+	setbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
+
+	mdelay(100);
+
+	/* Clear USB3 PHY reset */
+	clrbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
+
+	/* Clear USB2 PHY reset */
+	clrbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
+}
+
+void dwc3_core_soft_reset(struct dwc3 *dwc3_reg)
+{
+	/* Before Resetting PHY, put Core in Reset */
+	setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
+
+	/* reset USB3 phy - if required */
+	dwc3_phy_reset(dwc3_reg);
+
+	mdelay(100);
+
+	/* After PHYs are stable we can take Core out of reset state */
+	clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
+}
+
+int dwc3_core_init(struct dwc3 *dwc3_reg)
+{
+	u32 reg;
+	u32 revision;
+	unsigned int dwc3_hwparams1;
+
+	revision = readl(&dwc3_reg->g_snpsid);
+	/* This should read as U3 followed by revision number */
+	if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) {
+		puts("this is not a DesignWare USB3 DRD Core\n");
+		return -1;
+	}
+
+	dwc3_core_soft_reset(dwc3_reg);
+
+	dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1);
+
+	reg = readl(&dwc3_reg->g_ctl);
+	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
+	reg &= ~DWC3_GCTL_DISSCRAMBLE;
+	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		break;
+	default:
+		debug("No power optimization available\n");
+	}
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.90a have a bug
+	 * where the device can fail to connect at SuperSpeed
+	 * and falls back to high-speed mode which causes
+	 * the device to enter a Connect/Disconnect loop
+	 */
+	if ((revision & DWC3_REVISION_MASK) < 0x190a)
+		reg |= DWC3_GCTL_U2RSTECN;
+
+	writel(reg, &dwc3_reg->g_ctl);
+
+	return 0;
+}
+
+void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val)
+{
+	setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL |
+			GFLADJ_30MHZ(val));
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int xhci_dwc3_probe(struct udevice *dev)
+{
+	struct xhci_hcor *hcor;
+	struct xhci_hccr *hccr;
+	struct dwc3 *dwc3_reg;
+	enum usb_dr_mode dr_mode;
+	struct xhci_dwc3_plat *plat = dev_get_plat(dev);
+	const char *phy;
+	u32 reg;
+	int ret;
+
+	hccr = (struct xhci_hccr *)((uintptr_t)dev_remap_addr(dev));
+	hcor = (struct xhci_hcor *)((uintptr_t)hccr +
+			HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
+
+	ret = dwc3_setup_phy(dev, &plat->phys);
+	if (ret && (ret != -ENOTSUPP))
+		return ret;
+
+	dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
+
+	dwc3_core_init(dwc3_reg);
+
+	/* Set dwc3 usb2 phy config */
+	reg = readl(&dwc3_reg->g_usb2phycfg[0]);
+
+	phy = dev_read_string(dev, "phy_type");
+	if (phy && strcmp(phy, "utmi_wide") == 0) {
+		reg |= DWC3_GUSB2PHYCFG_PHYIF;
+		reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK;
+		reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT;
+	}
+
+	if (dev_read_bool(dev, "snps,dis_enblslpm-quirk"))
+		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+	if (dev_read_bool(dev, "snps,dis-u2-freeclk-exists-quirk"))
+		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
+	if (dev_read_bool(dev, "snps,dis_u2_susphy_quirk"))
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+	writel(reg, &dwc3_reg->g_usb2phycfg[0]);
+
+	dr_mode = usb_get_dr_mode(dev_ofnode(dev));
+	if (dr_mode == USB_DR_MODE_UNKNOWN)
+		/* by default set dual role mode to HOST */
+		dr_mode = USB_DR_MODE_HOST;
+
+	dwc3_set_mode(dwc3_reg, dr_mode);
+
+	return xhci_register(dev, hccr, hcor);
+}
+
+static int xhci_dwc3_remove(struct udevice *dev)
+{
+	struct xhci_dwc3_plat *plat = dev_get_plat(dev);
+
+	dwc3_shutdown_phy(dev, &plat->phys);
+
+	return xhci_deregister(dev);
+}
+
+static const struct udevice_id xhci_dwc3_ids[] = {
+	{ .compatible = "snps,dwc3" },
+	{ }
+};
+
+U_BOOT_DRIVER(xhci_dwc3) = {
+	.name = "xhci-dwc3",
+	.id = UCLASS_USB,
+	.of_match = xhci_dwc3_ids,
+	.probe = xhci_dwc3_probe,
+	.remove = xhci_dwc3_remove,
+	.ops = &xhci_usb_ops,
+	.priv_auto	= sizeof(struct xhci_ctrl),
+	.plat_auto	= sizeof(struct xhci_dwc3_plat),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/host/xhci-exynos5.c b/roms/u-boot/drivers/usb/host/xhci-exynos5.c
new file mode 100644
index 000000000..270be934e
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-exynos5.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SAMSUNG EXYNOS5 USB HOST XHCI Controller
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *	Vivek Gautam <gautam.vivek@samsung.com>
+ *	Vikas Sajjan <vikas.sajjan@samsung.com>
+ */
+
+/*
+ * This file is a conglomeration for DWC3-init sequence and further
+ * exynos5 specific PHY-init sequence.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+#include <linux/libfdt.h>
+#include <malloc.h>
+#include <usb.h>
+#include <watchdog.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include <asm/arch/xhci-exynos.h>
+#include <asm/gpio.h>
+#include <linux/errno.h>
+#include <linux/compat.h>
+#include <linux/usb/dwc3.h>
+
+#include <usb/xhci.h>
+
+/* Declare global data pointer */
+DECLARE_GLOBAL_DATA_PTR;
+
+struct exynos_xhci_plat {
+	fdt_addr_t hcd_base;
+	fdt_addr_t phy_base;
+	struct gpio_desc vbus_gpio;
+};
+
+/**
+ * Contains pointers to register base addresses
+ * for the usb controller.
+ */
+struct exynos_xhci {
+	struct usb_plat usb_plat;
+	struct xhci_ctrl ctrl;
+	struct exynos_usb3_phy *usb3_phy;
+	struct xhci_hccr *hcd;
+	struct dwc3 *dwc3_reg;
+};
+
+static int xhci_usb_of_to_plat(struct udevice *dev)
+{
+	struct exynos_xhci_plat *plat = dev_get_plat(dev);
+	const void *blob = gd->fdt_blob;
+	unsigned int node;
+	int depth;
+
+	/*
+	 * Get the base address for XHCI controller from the device node
+	 */
+	plat->hcd_base = dev_read_addr(dev);
+	if (plat->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the XHCI register base address\n");
+		return -ENXIO;
+	}
+
+	depth = 0;
+	node = fdtdec_next_compatible_subnode(blob, dev_of_offset(dev),
+				COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth);
+	if (node <= 0) {
+		debug("XHCI: Can't get device node for usb3-phy controller\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Get the base address for usbphy from the device node
+	 */
+	plat->phy_base = fdtdec_get_addr(blob, node, "reg");
+	if (plat->phy_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the usbphy register address\n");
+		return -ENXIO;
+	}
+
+	/* Vbus gpio */
+	gpio_request_by_name(dev, "samsung,vbus-gpio", 0,
+			     &plat->vbus_gpio, GPIOD_IS_OUT);
+
+	return 0;
+}
+
+static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
+{
+	u32 reg;
+
+	/* enabling usb_drd phy */
+	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
+
+	/* Reset USB 3.0 PHY */
+	writel(0x0, &phy->phy_reg0);
+
+	clrbits_le32(&phy->phy_param0,
+			/* Select PHY CLK source */
+			PHYPARAM0_REF_USE_PAD |
+			/* Set Loss-of-Signal Detector sensitivity */
+			PHYPARAM0_REF_LOSLEVEL_MASK);
+	setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
+
+	writel(0x0, &phy->phy_resume);
+
+	/*
+	 * Setting the Frame length Adj value[6:1] to default 0x20
+	 * See xHCI 1.0 spec, 5.2.4
+	 */
+	setbits_le32(&phy->link_system,
+			LINKSYSTEM_XHCI_VERSION_CONTROL |
+			LINKSYSTEM_FLADJ(0x20));
+
+	/* Set Tx De-Emphasis level */
+	clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
+	setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
+
+	setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
+
+	/* PHYTEST POWERDOWN Control */
+	clrbits_le32(&phy->phy_test,
+			PHYTEST_POWERDOWN_SSP |
+			PHYTEST_POWERDOWN_HSP);
+
+	/* UTMI Power Control */
+	writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
+
+		/* Use core clock from main PLL */
+	reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+		/* Default 24Mhz crystal clock */
+		PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
+		PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+		PHYCLKRST_SSC_REFCLKSEL(0x88) |
+		/* Force PortReset of PHY */
+		PHYCLKRST_PORTRESET |
+		/* Digital power supply in normal operating mode */
+		PHYCLKRST_RETENABLEN |
+		/* Enable ref clock for SS function */
+		PHYCLKRST_REF_SSP_EN |
+		/* Enable spread spectrum */
+		PHYCLKRST_SSC_EN |
+		/* Power down HS Bias and PLL blocks in suspend mode */
+		PHYCLKRST_COMMONONN;
+
+	writel(reg, &phy->phy_clk_rst);
+
+	/* giving time to Phy clock to settle before resetting */
+	udelay(10);
+
+	reg &= ~PHYCLKRST_PORTRESET;
+	writel(reg, &phy->phy_clk_rst);
+}
+
+static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy)
+{
+	setbits_le32(&phy->phy_utmi,
+			PHYUTMI_OTGDISABLE |
+			PHYUTMI_FORCESUSPEND |
+			PHYUTMI_FORCESLEEP);
+
+	clrbits_le32(&phy->phy_clk_rst,
+			PHYCLKRST_REF_SSP_EN |
+			PHYCLKRST_SSC_EN |
+			PHYCLKRST_COMMONONN);
+
+	/* PHYTEST POWERDOWN Control to remove leakage current */
+	setbits_le32(&phy->phy_test,
+			PHYTEST_POWERDOWN_SSP |
+			PHYTEST_POWERDOWN_HSP);
+
+	/* disabling usb_drd phy */
+	set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE);
+}
+
+static int exynos_xhci_core_init(struct exynos_xhci *exynos)
+{
+	int ret;
+
+	exynos5_usb3_phy_init(exynos->usb3_phy);
+
+	ret = dwc3_core_init(exynos->dwc3_reg);
+	if (ret) {
+		debug("failed to initialize core\n");
+		return -EINVAL;
+	}
+
+	/* We are hard-coding DWC3 core to Host Mode */
+	dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
+
+	return 0;
+}
+
+static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
+{
+	exynos5_usb3_phy_exit(exynos->usb3_phy);
+}
+
+static int xhci_usb_probe(struct udevice *dev)
+{
+	struct exynos_xhci_plat *plat = dev_get_plat(dev);
+	struct exynos_xhci *ctx = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int ret;
+
+	ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
+	ctx->usb3_phy = (struct exynos_usb3_phy *)plat->phy_base;
+	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
+	hcor = (struct xhci_hcor *)((uint32_t)ctx->hcd +
+			HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)));
+
+	/* setup the Vbus gpio here */
+	if (dm_gpio_is_valid(&plat->vbus_gpio))
+		dm_gpio_set_value(&plat->vbus_gpio, 1);
+
+	ret = exynos_xhci_core_init(ctx);
+	if (ret) {
+		puts("XHCI: failed to initialize controller\n");
+		return -EINVAL;
+	}
+
+	return xhci_register(dev, ctx->hcd, hcor);
+}
+
+static int xhci_usb_remove(struct udevice *dev)
+{
+	struct exynos_xhci *ctx = dev_get_priv(dev);
+	int ret;
+
+	ret = xhci_deregister(dev);
+	if (ret)
+		return ret;
+	exynos_xhci_core_exit(ctx);
+
+	return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+	{ .compatible = "samsung,exynos5250-xhci" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name	= "xhci_exynos",
+	.id	= UCLASS_USB,
+	.of_match = xhci_usb_ids,
+	.of_to_plat = xhci_usb_of_to_plat,
+	.probe = xhci_usb_probe,
+	.remove = xhci_usb_remove,
+	.ops	= &xhci_usb_ops,
+	.plat_auto	= sizeof(struct exynos_xhci_plat),
+	.priv_auto	= sizeof(struct exynos_xhci),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/xhci-fsl.c b/roms/u-boot/drivers/usb/host/xhci-fsl.c
new file mode 100644
index 000000000..f062f12ad
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-fsl.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015,2016 Freescale Semiconductor, Inc.
+ *
+ * FSL USB HOST xHCI Controller
+ *
+ * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <usb.h>
+#include <linux/errno.h>
+#include <linux/compat.h>
+#include <linux/usb/xhci-fsl.h>
+#include <linux/usb/dwc3.h>
+#include <usb/xhci.h>
+#include <fsl_errata.h>
+#include <fsl_usb.h>
+#include <dm.h>
+
+/* Declare global data pointer */
+#if !CONFIG_IS_ENABLED(DM_USB)
+static struct fsl_xhci fsl_xhci;
+unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR;
+#else
+struct xhci_fsl_priv {
+	struct xhci_ctrl xhci;
+	fdt_addr_t hcd_base;
+	struct fsl_xhci ctx;
+};
+#endif
+
+__weak int __board_usb_init(int index, enum usb_init_type init)
+{
+	return 0;
+}
+
+static int erratum_a008751(void)
+{
+#if defined(CONFIG_TARGET_LS2080AQDS) || defined(CONFIG_TARGET_LS2080ARDB) ||\
+					defined(CONFIG_TARGET_LS2080AQDS)
+	u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
+	writel(SCFG_USB3PRM1CR_INIT, scfg + SCFG_USB3PRM1CR / 4);
+	return 0;
+#endif
+	return 1;
+}
+
+static void fsl_apply_xhci_errata(void)
+{
+	int ret;
+	if (has_erratum_a008751()) {
+		ret = erratum_a008751();
+		if (ret != 0)
+			puts("Failed to apply erratum a008751\n");
+	}
+}
+
+static void fsl_xhci_set_beat_burst_length(struct dwc3 *dwc3_reg)
+{
+	clrsetbits_le32(&dwc3_reg->g_sbuscfg0, USB3_ENABLE_BEAT_BURST_MASK,
+			USB3_ENABLE_BEAT_BURST);
+	setbits_le32(&dwc3_reg->g_sbuscfg1, USB3_SET_BEAT_BURST_LIMIT);
+}
+
+static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci)
+{
+	int ret = 0;
+
+	ret = dwc3_core_init(fsl_xhci->dwc3_reg);
+	if (ret) {
+		debug("%s:failed to initialize core\n", __func__);
+		return ret;
+	}
+
+	/* We are hard-coding DWC3 core to Host Mode */
+	dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
+
+	/* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */
+	dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT);
+
+	/* Change beat burst and outstanding pipelined transfers requests */
+	fsl_xhci_set_beat_burst_length(fsl_xhci->dwc3_reg);
+
+	/*
+	 * A-010151: The dwc3 phy TSMC 28-nm HPM 0.9/1.8 V does not
+	 * reliably support Rx Detect in P3 mode(P3 is the default
+	 * setting). Therefore, some USB3.0 devices may not be detected
+	 * reliably in Super Speed mode. So, USB controller to configure
+	 * USB in P2 mode whenever the Receive Detect feature is required.
+	 * whenever the Receive Detect feature is required.
+	 */
+	if (has_erratum_a010151())
+		clrsetbits_le32(&fsl_xhci->dwc3_reg->g_usb3pipectl[0],
+				DWC3_GUSB3PIPECTL_DISRXDETP3,
+				DWC3_GUSB3PIPECTL_DISRXDETP3);
+
+	return ret;
+}
+
+static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci)
+{
+	/*
+	 * Currently fsl socs do not support PHY shutdown from
+	 * sw. But this support may be added in future socs.
+	 */
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int xhci_fsl_probe(struct udevice *dev)
+{
+	struct xhci_fsl_priv *priv = dev_get_priv(dev);
+	struct xhci_hccr *hccr;
+	struct xhci_hcor *hcor;
+
+	int ret = 0;
+
+	/*
+	 * Get the base address for XHCI controller from the device node
+	 */
+	priv->hcd_base = dev_read_addr(dev);
+	if (priv->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the XHCI register base address\n");
+		return -ENXIO;
+	}
+	priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base;
+	priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) +
+			  DWC3_REG_OFFSET);
+
+	fsl_apply_xhci_errata();
+
+	ret = fsl_xhci_core_init(&priv->ctx);
+	if (ret < 0) {
+		puts("Failed to initialize xhci\n");
+		return ret;
+	}
+
+	hccr = (struct xhci_hccr *)(priv->ctx.hcd);
+	hcor = (struct xhci_hcor *)((uintptr_t) hccr
+				+ HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
+
+	debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n",
+	      (uintptr_t)hccr, (uintptr_t)hcor,
+	      (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
+
+	return xhci_register(dev, hccr, hcor);
+}
+
+static int xhci_fsl_remove(struct udevice *dev)
+{
+	struct xhci_fsl_priv *priv = dev_get_priv(dev);
+
+	fsl_xhci_core_exit(&priv->ctx);
+
+	return xhci_deregister(dev);
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+	{ .compatible = "fsl,layerscape-dwc3", },
+	{ }
+};
+
+U_BOOT_DRIVER(xhci_fsl) = {
+	.name	= "xhci_fsl",
+	.id	= UCLASS_USB,
+	.of_match = xhci_usb_ids,
+	.probe = xhci_fsl_probe,
+	.remove = xhci_fsl_remove,
+	.ops	= &xhci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct xhci_fsl_priv),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#else
+int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
+{
+	struct fsl_xhci *ctx = &fsl_xhci;
+	int ret = 0;
+
+	ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
+	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
+
+	ret = board_usb_init(index, USB_INIT_HOST);
+	if (ret != 0) {
+		puts("Failed to initialize board for USB\n");
+		return ret;
+	}
+
+	fsl_apply_xhci_errata();
+
+	ret = fsl_xhci_core_init(ctx);
+	if (ret < 0) {
+		puts("Failed to initialize xhci\n");
+		return ret;
+	}
+
+	*hccr = (struct xhci_hccr *)ctx->hcd;
+	*hcor = (struct xhci_hcor *)((uintptr_t) *hccr
+				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
+
+	debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n",
+	      (uintptr_t)*hccr, (uintptr_t)*hcor,
+	      (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
+
+	return ret;
+}
+
+void xhci_hcd_stop(int index)
+{
+	struct fsl_xhci *ctx = &fsl_xhci;
+
+	fsl_xhci_core_exit(ctx);
+}
+#endif
diff --git a/roms/u-boot/drivers/usb/host/xhci-mem.c b/roms/u-boot/drivers/usb/host/xhci-mem.c
new file mode 100644
index 000000000..1c11c2e7e
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-mem.c
@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * USB HOST XHCI Controller stack
+ *
+ * Based on xHCI host controller driver in linux-kernel
+ * by Sarah Sharp.
+ *
+ * Copyright (C) 2008 Intel Corp.
+ * Author: Sarah Sharp
+ *
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors: Vivek Gautam <gautam.vivek@samsung.com>
+ *	    Vikas Sajjan <vikas.sajjan@samsung.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/byteorder.h>
+#include <usb.h>
+#include <malloc.h>
+#include <asm/cache.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+
+#include <usb/xhci.h>
+
+#define CACHELINE_SIZE		CONFIG_SYS_CACHELINE_SIZE
+/**
+ * flushes the address passed till the length
+ *
+ * @param addr	pointer to memory region to be flushed
+ * @param len	the length of the cache line to be flushed
+ * @return none
+ */
+void xhci_flush_cache(uintptr_t addr, u32 len)
+{
+	BUG_ON((void *)addr == NULL || len == 0);
+
+	flush_dcache_range(addr & ~(CACHELINE_SIZE - 1),
+				ALIGN(addr + len, CACHELINE_SIZE));
+}
+
+/**
+ * invalidates the address passed till the length
+ *
+ * @param addr	pointer to memory region to be invalidates
+ * @param len	the length of the cache line to be invalidated
+ * @return none
+ */
+void xhci_inval_cache(uintptr_t addr, u32 len)
+{
+	BUG_ON((void *)addr == NULL || len == 0);
+
+	invalidate_dcache_range(addr & ~(CACHELINE_SIZE - 1),
+				ALIGN(addr + len, CACHELINE_SIZE));
+}
+
+
+/**
+ * frees the "segment" pointer passed
+ *
+ * @param ptr	pointer to "segement" to be freed
+ * @return none
+ */
+static void xhci_segment_free(struct xhci_segment *seg)
+{
+	free(seg->trbs);
+	seg->trbs = NULL;
+
+	free(seg);
+}
+
+/**
+ * frees the "ring" pointer passed
+ *
+ * @param ptr	pointer to "ring" to be freed
+ * @return none
+ */
+static void xhci_ring_free(struct xhci_ring *ring)
+{
+	struct xhci_segment *seg;
+	struct xhci_segment *first_seg;
+
+	BUG_ON(!ring);
+
+	first_seg = ring->first_seg;
+	seg = first_seg->next;
+	while (seg != first_seg) {
+		struct xhci_segment *next = seg->next;
+		xhci_segment_free(seg);
+		seg = next;
+	}
+	xhci_segment_free(first_seg);
+
+	free(ring);
+}
+
+/**
+ * Free the scratchpad buffer array and scratchpad buffers
+ *
+ * @ctrl	host controller data structure
+ * @return	none
+ */
+static void xhci_scratchpad_free(struct xhci_ctrl *ctrl)
+{
+	if (!ctrl->scratchpad)
+		return;
+
+	ctrl->dcbaa->dev_context_ptrs[0] = 0;
+
+	free(xhci_bus_to_virt(ctrl, le64_to_cpu(ctrl->scratchpad->sp_array[0])));
+	free(ctrl->scratchpad->sp_array);
+	free(ctrl->scratchpad);
+	ctrl->scratchpad = NULL;
+}
+
+/**
+ * frees the "xhci_container_ctx" pointer passed
+ *
+ * @param ptr	pointer to "xhci_container_ctx" to be freed
+ * @return none
+ */
+static void xhci_free_container_ctx(struct xhci_container_ctx *ctx)
+{
+	free(ctx->bytes);
+	free(ctx);
+}
+
+/**
+ * frees the virtual devices for "xhci_ctrl" pointer passed
+ *
+ * @param ptr	pointer to "xhci_ctrl" whose virtual devices are to be freed
+ * @return none
+ */
+static void xhci_free_virt_devices(struct xhci_ctrl *ctrl)
+{
+	int i;
+	int slot_id;
+	struct xhci_virt_device *virt_dev;
+
+	/*
+	 * refactored here to loop through all virt_dev
+	 * Slot ID 0 is reserved
+	 */
+	for (slot_id = 0; slot_id < MAX_HC_SLOTS; slot_id++) {
+		virt_dev = ctrl->devs[slot_id];
+		if (!virt_dev)
+			continue;
+
+		ctrl->dcbaa->dev_context_ptrs[slot_id] = 0;
+
+		for (i = 0; i < 31; ++i)
+			if (virt_dev->eps[i].ring)
+				xhci_ring_free(virt_dev->eps[i].ring);
+
+		if (virt_dev->in_ctx)
+			xhci_free_container_ctx(virt_dev->in_ctx);
+		if (virt_dev->out_ctx)
+			xhci_free_container_ctx(virt_dev->out_ctx);
+
+		free(virt_dev);
+		/* make sure we are pointing to NULL */
+		ctrl->devs[slot_id] = NULL;
+	}
+}
+
+/**
+ * frees all the memory allocated
+ *
+ * @param ptr	pointer to "xhci_ctrl" to be cleaned up
+ * @return none
+ */
+void xhci_cleanup(struct xhci_ctrl *ctrl)
+{
+	xhci_ring_free(ctrl->event_ring);
+	xhci_ring_free(ctrl->cmd_ring);
+	xhci_scratchpad_free(ctrl);
+	xhci_free_virt_devices(ctrl);
+	free(ctrl->erst.entries);
+	free(ctrl->dcbaa);
+	if (reset_valid(&ctrl->reset))
+		reset_free(&ctrl->reset);
+	memset(ctrl, '\0', sizeof(struct xhci_ctrl));
+}
+
+/**
+ * Malloc the aligned memory
+ *
+ * @param size	size of memory to be allocated
+ * @return allocates the memory and returns the aligned pointer
+ */
+static void *xhci_malloc(unsigned int size)
+{
+	void *ptr;
+	size_t cacheline_size = max(XHCI_ALIGNMENT, CACHELINE_SIZE);
+
+	ptr = memalign(cacheline_size, ALIGN(size, cacheline_size));
+	BUG_ON(!ptr);
+	memset(ptr, '\0', size);
+
+	xhci_flush_cache((uintptr_t)ptr, size);
+
+	return ptr;
+}
+
+/**
+ * Make the prev segment point to the next segment.
+ * Change the last TRB in the prev segment to be a Link TRB which points to the
+ * address of the next segment.  The caller needs to set any Link TRB
+ * related flags, such as End TRB, Toggle Cycle, and no snoop.
+ *
+ * @param prev	pointer to the previous segment
+ * @param next	pointer to the next segment
+ * @param link_trbs	flag to indicate whether to link the trbs or NOT
+ * @return none
+ */
+static void xhci_link_segments(struct xhci_ctrl *ctrl, struct xhci_segment *prev,
+			       struct xhci_segment *next, bool link_trbs)
+{
+	u32 val;
+	u64 val_64 = 0;
+
+	if (!prev || !next)
+		return;
+	prev->next = next;
+	if (link_trbs) {
+		val_64 = xhci_virt_to_bus(ctrl, next->trbs);
+		prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
+			cpu_to_le64(val_64);
+
+		/*
+		 * Set the last TRB in the segment to
+		 * have a TRB type ID of Link TRB
+		 */
+		val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
+		val &= ~TRB_TYPE_BITMASK;
+		val |= TRB_TYPE(TRB_LINK);
+		prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
+	}
+}
+
+/**
+ * Initialises the Ring's enqueue,dequeue,enq_seg pointers
+ *
+ * @param ring	pointer to the RING to be intialised
+ * @return none
+ */
+static void xhci_initialize_ring_info(struct xhci_ring *ring)
+{
+	/*
+	 * The ring is empty, so the enqueue pointer == dequeue pointer
+	 */
+	ring->enqueue = ring->first_seg->trbs;
+	ring->enq_seg = ring->first_seg;
+	ring->dequeue = ring->enqueue;
+	ring->deq_seg = ring->first_seg;
+
+	/*
+	 * The ring is initialized to 0. The producer must write 1 to the
+	 * cycle bit to handover ownership of the TRB, so PCS = 1.
+	 * The consumer must compare CCS to the cycle bit to
+	 * check ownership, so CCS = 1.
+	 */
+	ring->cycle_state = 1;
+}
+
+/**
+ * Allocates a generic ring segment from the ring pool, sets the dma address,
+ * initializes the segment to zero, and sets the private next pointer to NULL.
+ * Section 4.11.1.1:
+ * "All components of all Command and Transfer TRBs shall be initialized to '0'"
+ *
+ * @param	none
+ * @return pointer to the newly allocated SEGMENT
+ */
+static struct xhci_segment *xhci_segment_alloc(void)
+{
+	struct xhci_segment *seg;
+
+	seg = malloc(sizeof(struct xhci_segment));
+	BUG_ON(!seg);
+
+	seg->trbs = xhci_malloc(SEGMENT_SIZE);
+
+	seg->next = NULL;
+
+	return seg;
+}
+
+/**
+ * Create a new ring with zero or more segments.
+ * TODO: current code only uses one-time-allocated single-segment rings
+ * of 1KB anyway, so we might as well get rid of all the segment and
+ * linking code (and maybe increase the size a bit, e.g. 4KB).
+ *
+ *
+ * Link each segment together into a ring.
+ * Set the end flag and the cycle toggle bit on the last segment.
+ * See section 4.9.2 and figures 15 and 16 of XHCI spec rev1.0.
+ *
+ * @param num_segs	number of segments in the ring
+ * @param link_trbs	flag to indicate whether to link the trbs or NOT
+ * @return pointer to the newly created RING
+ */
+struct xhci_ring *xhci_ring_alloc(struct xhci_ctrl *ctrl, unsigned int num_segs,
+				  bool link_trbs)
+{
+	struct xhci_ring *ring;
+	struct xhci_segment *prev;
+
+	ring = malloc(sizeof(struct xhci_ring));
+	BUG_ON(!ring);
+
+	if (num_segs == 0)
+		return ring;
+
+	ring->first_seg = xhci_segment_alloc();
+	BUG_ON(!ring->first_seg);
+
+	num_segs--;
+
+	prev = ring->first_seg;
+	while (num_segs > 0) {
+		struct xhci_segment *next;
+
+		next = xhci_segment_alloc();
+		BUG_ON(!next);
+
+		xhci_link_segments(ctrl, prev, next, link_trbs);
+
+		prev = next;
+		num_segs--;
+	}
+	xhci_link_segments(ctrl, prev, ring->first_seg, link_trbs);
+	if (link_trbs) {
+		/* See section 4.9.2.1 and 6.4.4.1 */
+		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
+					cpu_to_le32(LINK_TOGGLE);
+	}
+	xhci_initialize_ring_info(ring);
+
+	return ring;
+}
+
+/**
+ * Set up the scratchpad buffer array and scratchpad buffers
+ *
+ * @ctrl	host controller data structure
+ * @return	-ENOMEM if buffer allocation fails, 0 on success
+ */
+static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
+{
+	struct xhci_hccr *hccr = ctrl->hccr;
+	struct xhci_hcor *hcor = ctrl->hcor;
+	struct xhci_scratchpad *scratchpad;
+	uint64_t val_64;
+	int num_sp;
+	uint32_t page_size;
+	void *buf;
+	int i;
+
+	num_sp = HCS_MAX_SCRATCHPAD(xhci_readl(&hccr->cr_hcsparams2));
+	if (!num_sp)
+		return 0;
+
+	scratchpad = malloc(sizeof(*scratchpad));
+	if (!scratchpad)
+		goto fail_sp;
+	ctrl->scratchpad = scratchpad;
+
+	scratchpad->sp_array = xhci_malloc(num_sp * sizeof(u64));
+	if (!scratchpad->sp_array)
+		goto fail_sp2;
+
+	val_64 = xhci_virt_to_bus(ctrl, scratchpad->sp_array);
+	ctrl->dcbaa->dev_context_ptrs[0] = cpu_to_le64(val_64);
+
+	xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[0],
+		sizeof(ctrl->dcbaa->dev_context_ptrs[0]));
+
+	page_size = xhci_readl(&hcor->or_pagesize) & 0xffff;
+	for (i = 0; i < 16; i++) {
+		if ((0x1 & page_size) != 0)
+			break;
+		page_size = page_size >> 1;
+	}
+	BUG_ON(i == 16);
+
+	page_size = 1 << (i + 12);
+	buf = memalign(page_size, num_sp * page_size);
+	if (!buf)
+		goto fail_sp3;
+	memset(buf, '\0', num_sp * page_size);
+	xhci_flush_cache((uintptr_t)buf, num_sp * page_size);
+
+	for (i = 0; i < num_sp; i++) {
+		val_64 = xhci_virt_to_bus(ctrl, buf + i * page_size);
+		scratchpad->sp_array[i] = cpu_to_le64(val_64);
+	}
+
+	xhci_flush_cache((uintptr_t)scratchpad->sp_array,
+			 sizeof(u64) * num_sp);
+
+	return 0;
+
+fail_sp3:
+	free(scratchpad->sp_array);
+
+fail_sp2:
+	free(scratchpad);
+	ctrl->scratchpad = NULL;
+
+fail_sp:
+	return -ENOMEM;
+}
+
+/**
+ * Allocates the Container context
+ *
+ * @param ctrl	Host controller data structure
+ * @param type type of XHCI Container Context
+ * @return NULL if failed else pointer to the context on success
+ */
+static struct xhci_container_ctx
+		*xhci_alloc_container_ctx(struct xhci_ctrl *ctrl, int type)
+{
+	struct xhci_container_ctx *ctx;
+
+	ctx = malloc(sizeof(struct xhci_container_ctx));
+	BUG_ON(!ctx);
+
+	BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
+	ctx->type = type;
+	ctx->size = (MAX_EP_CTX_NUM + 1) *
+			CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams));
+	if (type == XHCI_CTX_TYPE_INPUT)
+		ctx->size += CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams));
+
+	ctx->bytes = xhci_malloc(ctx->size);
+
+	return ctx;
+}
+
+/**
+ * Allocating virtual device
+ *
+ * @param udev	pointer to USB deivce structure
+ * @return 0 on success else -1 on failure
+ */
+int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
+{
+	u64 byte_64 = 0;
+	struct xhci_virt_device *virt_dev;
+
+	/* Slot ID 0 is reserved */
+	if (ctrl->devs[slot_id]) {
+		printf("Virt dev for slot[%d] already allocated\n", slot_id);
+		return -EEXIST;
+	}
+
+	ctrl->devs[slot_id] = malloc(sizeof(struct xhci_virt_device));
+
+	if (!ctrl->devs[slot_id]) {
+		puts("Failed to allocate virtual device\n");
+		return -ENOMEM;
+	}
+
+	memset(ctrl->devs[slot_id], 0, sizeof(struct xhci_virt_device));
+	virt_dev = ctrl->devs[slot_id];
+
+	/* Allocate the (output) device context that will be used in the HC. */
+	virt_dev->out_ctx = xhci_alloc_container_ctx(ctrl,
+					XHCI_CTX_TYPE_DEVICE);
+	if (!virt_dev->out_ctx) {
+		puts("Failed to allocate out context for virt dev\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate the (input) device context for address device command */
+	virt_dev->in_ctx = xhci_alloc_container_ctx(ctrl,
+					XHCI_CTX_TYPE_INPUT);
+	if (!virt_dev->in_ctx) {
+		puts("Failed to allocate in context for virt dev\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate endpoint 0 ring */
+	virt_dev->eps[0].ring = xhci_ring_alloc(ctrl, 1, true);
+
+	byte_64 = xhci_virt_to_bus(ctrl, virt_dev->out_ctx->bytes);
+
+	/* Point to output device context in dcbaa. */
+	ctrl->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(byte_64);
+
+	xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[slot_id],
+			 sizeof(__le64));
+	return 0;
+}
+
+/**
+ * Allocates the necessary data structures
+ * for XHCI host controller
+ *
+ * @param ctrl	Host controller data structure
+ * @param hccr	pointer to HOST Controller Control Registers
+ * @param hcor	pointer to HOST Controller Operational Registers
+ * @return 0 if successful else -1 on failure
+ */
+int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
+					struct xhci_hcor *hcor)
+{
+	uint64_t val_64;
+	uint64_t trb_64;
+	uint32_t val;
+	uint64_t deq;
+	int i;
+	struct xhci_segment *seg;
+
+	/* DCBAA initialization */
+	ctrl->dcbaa = xhci_malloc(sizeof(struct xhci_device_context_array));
+	if (ctrl->dcbaa == NULL) {
+		puts("unable to allocate DCBA\n");
+		return -ENOMEM;
+	}
+
+	val_64 = xhci_virt_to_bus(ctrl, ctrl->dcbaa);
+	/* Set the pointer in DCBAA register */
+	xhci_writeq(&hcor->or_dcbaap, val_64);
+
+	/* Command ring control pointer register initialization */
+	ctrl->cmd_ring = xhci_ring_alloc(ctrl, 1, true);
+
+	/* Set the address in the Command Ring Control register */
+	trb_64 = xhci_virt_to_bus(ctrl, ctrl->cmd_ring->first_seg->trbs);
+	val_64 = xhci_readq(&hcor->or_crcr);
+	val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+		(trb_64 & (u64) ~CMD_RING_RSVD_BITS) |
+		ctrl->cmd_ring->cycle_state;
+	xhci_writeq(&hcor->or_crcr, val_64);
+
+	/* write the address of db register */
+	val = xhci_readl(&hccr->cr_dboff);
+	val &= DBOFF_MASK;
+	ctrl->dba = (struct xhci_doorbell_array *)((char *)hccr + val);
+
+	/* write the address of runtime register */
+	val = xhci_readl(&hccr->cr_rtsoff);
+	val &= RTSOFF_MASK;
+	ctrl->run_regs = (struct xhci_run_regs *)((char *)hccr + val);
+
+	/* writting the address of ir_set structure */
+	ctrl->ir_set = &ctrl->run_regs->ir_set[0];
+
+	/* Event ring does not maintain link TRB */
+	ctrl->event_ring = xhci_ring_alloc(ctrl, ERST_NUM_SEGS, false);
+	ctrl->erst.entries = xhci_malloc(sizeof(struct xhci_erst_entry) *
+					 ERST_NUM_SEGS);
+
+	ctrl->erst.num_entries = ERST_NUM_SEGS;
+
+	for (val = 0, seg = ctrl->event_ring->first_seg;
+			val < ERST_NUM_SEGS;
+			val++) {
+		struct xhci_erst_entry *entry = &ctrl->erst.entries[val];
+		trb_64 = xhci_virt_to_bus(ctrl, seg->trbs);
+		entry->seg_addr = cpu_to_le64(trb_64);
+		entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
+		entry->rsvd = 0;
+		seg = seg->next;
+	}
+	xhci_flush_cache((uintptr_t)ctrl->erst.entries,
+			 ERST_NUM_SEGS * sizeof(struct xhci_erst_entry));
+
+	deq = xhci_virt_to_bus(ctrl, ctrl->event_ring->dequeue);
+
+	/* Update HC event ring dequeue pointer */
+	xhci_writeq(&ctrl->ir_set->erst_dequeue,
+				(u64)deq & (u64)~ERST_PTR_MASK);
+
+	/* set ERST count with the number of entries in the segment table */
+	val = xhci_readl(&ctrl->ir_set->erst_size);
+	val &= ERST_SIZE_MASK;
+	val |= ERST_NUM_SEGS;
+	xhci_writel(&ctrl->ir_set->erst_size, val);
+
+	/* this is the event ring segment table pointer */
+	val_64 = xhci_readq(&ctrl->ir_set->erst_base);
+	val_64 &= ERST_PTR_MASK;
+	val_64 |= xhci_virt_to_bus(ctrl, ctrl->erst.entries) & ~ERST_PTR_MASK;
+
+	xhci_writeq(&ctrl->ir_set->erst_base, val_64);
+
+	/* set up the scratchpad buffer array and scratchpad buffers */
+	xhci_scratchpad_alloc(ctrl);
+
+	/* initializing the virtual devices to NULL */
+	for (i = 0; i < MAX_HC_SLOTS; ++i)
+		ctrl->devs[i] = NULL;
+
+	/*
+	 * Just Zero'ing this register completely,
+	 * or some spurious Device Notification Events
+	 * might screw things here.
+	 */
+	xhci_writel(&hcor->or_dnctrl, 0x0);
+
+	return 0;
+}
+
+/**
+ * Give the input control context for the passed container context
+ *
+ * @param ctx	pointer to the context
+ * @return pointer to the Input control context data
+ */
+struct xhci_input_control_ctx
+		*xhci_get_input_control_ctx(struct xhci_container_ctx *ctx)
+{
+	BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT);
+	return (struct xhci_input_control_ctx *)ctx->bytes;
+}
+
+/**
+ * Give the slot context for the passed container context
+ *
+ * @param ctrl	Host controller data structure
+ * @param ctx	pointer to the context
+ * @return pointer to the slot control context data
+ */
+struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctrl *ctrl,
+				struct xhci_container_ctx *ctx)
+{
+	if (ctx->type == XHCI_CTX_TYPE_DEVICE)
+		return (struct xhci_slot_ctx *)ctx->bytes;
+
+	return (struct xhci_slot_ctx *)
+		(ctx->bytes + CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams)));
+}
+
+/**
+ * Gets the EP context from based on the ep_index
+ *
+ * @param ctrl	Host controller data structure
+ * @param ctx	context container
+ * @param ep_index	index of the endpoint
+ * @return pointer to the End point context
+ */
+struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctrl *ctrl,
+				    struct xhci_container_ctx *ctx,
+				    unsigned int ep_index)
+{
+	/* increment ep index by offset of start of ep ctx array */
+	ep_index++;
+	if (ctx->type == XHCI_CTX_TYPE_INPUT)
+		ep_index++;
+
+	return (struct xhci_ep_ctx *)
+		(ctx->bytes +
+		(ep_index * CTX_SIZE(xhci_readl(&ctrl->hccr->cr_hccparams))));
+}
+
+/**
+ * Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
+ * Useful when you want to change one particular aspect of the endpoint
+ * and then issue a configure endpoint command.
+ *
+ * @param ctrl	Host controller data structure
+ * @param in_ctx contains the input context
+ * @param out_ctx contains the input context
+ * @param ep_index index of the end point
+ * @return none
+ */
+void xhci_endpoint_copy(struct xhci_ctrl *ctrl,
+			struct xhci_container_ctx *in_ctx,
+			struct xhci_container_ctx *out_ctx,
+			unsigned int ep_index)
+{
+	struct xhci_ep_ctx *out_ep_ctx;
+	struct xhci_ep_ctx *in_ep_ctx;
+
+	out_ep_ctx = xhci_get_ep_ctx(ctrl, out_ctx, ep_index);
+	in_ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
+
+	in_ep_ctx->ep_info = out_ep_ctx->ep_info;
+	in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2;
+	in_ep_ctx->deq = out_ep_ctx->deq;
+	in_ep_ctx->tx_info = out_ep_ctx->tx_info;
+}
+
+/**
+ * Copy output xhci_slot_ctx to the input xhci_slot_ctx.
+ * Useful when you want to change one particular aspect of the endpoint
+ * and then issue a configure endpoint command.
+ * Only the context entries field matters, but
+ * we'll copy the whole thing anyway.
+ *
+ * @param ctrl	Host controller data structure
+ * @param in_ctx contains the inpout context
+ * @param out_ctx contains the inpout context
+ * @return none
+ */
+void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx,
+					struct xhci_container_ctx *out_ctx)
+{
+	struct xhci_slot_ctx *in_slot_ctx;
+	struct xhci_slot_ctx *out_slot_ctx;
+
+	in_slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
+	out_slot_ctx = xhci_get_slot_ctx(ctrl, out_ctx);
+
+	in_slot_ctx->dev_info = out_slot_ctx->dev_info;
+	in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2;
+	in_slot_ctx->tt_info = out_slot_ctx->tt_info;
+	in_slot_ctx->dev_state = out_slot_ctx->dev_state;
+}
+
+/**
+ * Setup an xHCI virtual device for a Set Address command
+ *
+ * @param udev pointer to the Device Data Structure
+ * @return returns negative value on failure else 0 on success
+ */
+void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
+				     struct usb_device *udev, int hop_portnr)
+{
+	struct xhci_virt_device *virt_dev;
+	struct xhci_ep_ctx *ep0_ctx;
+	struct xhci_slot_ctx *slot_ctx;
+	u32 port_num = 0;
+	u64 trb_64 = 0;
+	int slot_id = udev->slot_id;
+	int speed = udev->speed;
+	int route = 0;
+#if CONFIG_IS_ENABLED(DM_USB)
+	struct usb_device *dev = udev;
+	struct usb_hub_device *hub;
+#endif
+
+	virt_dev = ctrl->devs[slot_id];
+
+	BUG_ON(!virt_dev);
+
+	/* Extract the EP0 and Slot Ctrl */
+	ep0_ctx = xhci_get_ep_ctx(ctrl, virt_dev->in_ctx, 0);
+	slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->in_ctx);
+
+	/* Only the control endpoint is valid - one endpoint context */
+	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1));
+
+#if CONFIG_IS_ENABLED(DM_USB)
+	/* Calculate the route string for this device */
+	port_num = dev->portnr;
+	while (!usb_hub_is_root_hub(dev->dev)) {
+		hub = dev_get_uclass_priv(dev->dev);
+		/*
+		 * Each hub in the topology is expected to have no more than
+		 * 15 ports in order for the route string of a device to be
+		 * unique. SuperSpeed hubs are restricted to only having 15
+		 * ports, but FS/LS/HS hubs are not. The xHCI specification
+		 * says that if the port number the device is greater than 15,
+		 * that portion of the route string shall be set to 15.
+		 */
+		if (port_num > 15)
+			port_num = 15;
+		route |= port_num << (hub->hub_depth * 4);
+		dev = dev_get_parent_priv(dev->dev);
+		port_num = dev->portnr;
+		dev = dev_get_parent_priv(dev->dev->parent);
+	}
+
+	debug("route string %x\n", route);
+#endif
+	slot_ctx->dev_info |= cpu_to_le32(route);
+
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
+		break;
+	case USB_SPEED_HIGH:
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS);
+		break;
+	case USB_SPEED_FULL:
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS);
+		break;
+	case USB_SPEED_LOW:
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS);
+		break;
+	default:
+		/* Speed was set earlier, this shouldn't happen. */
+		BUG();
+	}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+	/* Set up TT fields to support FS/LS devices */
+	if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
+		struct udevice *parent = udev->dev;
+
+		dev = udev;
+		do {
+			port_num = dev->portnr;
+			dev = dev_get_parent_priv(parent);
+			if (usb_hub_is_root_hub(dev->dev))
+				break;
+			parent = dev->dev->parent;
+		} while (dev->speed != USB_SPEED_HIGH);
+
+		if (!usb_hub_is_root_hub(dev->dev)) {
+			hub = dev_get_uclass_priv(dev->dev);
+			if (hub->tt.multi)
+				slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
+			slot_ctx->tt_info |= cpu_to_le32(TT_PORT(port_num));
+			slot_ctx->tt_info |= cpu_to_le32(TT_SLOT(dev->slot_id));
+		}
+	}
+#endif
+
+	port_num = hop_portnr;
+	debug("port_num = %d\n", port_num);
+
+	slot_ctx->dev_info2 |=
+			cpu_to_le32(((port_num & ROOT_HUB_PORT_MASK) <<
+				ROOT_HUB_PORT_SHIFT));
+
+	/* Step 4 - ring already allocated */
+	/* Step 5 */
+	ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP));
+	debug("SPEED = %d\n", speed);
+
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512));
+		debug("Setting Packet size = 512bytes\n");
+		break;
+	case USB_SPEED_HIGH:
+	/* USB core guesses at a 64-byte max packet first for FS devices */
+	case USB_SPEED_FULL:
+		ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64));
+		debug("Setting Packet size = 64bytes\n");
+		break;
+	case USB_SPEED_LOW:
+		ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8));
+		debug("Setting Packet size = 8bytes\n");
+		break;
+	default:
+		/* New speed? */
+		BUG();
+	}
+
+	/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
+	ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
+
+	trb_64 = xhci_virt_to_bus(ctrl, virt_dev->eps[0].ring->first_seg->trbs);
+	ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
+
+	/*
+	 * xHCI spec 6.2.3:
+	 * software shall set 'Average TRB Length' to 8 for control endpoints.
+	 */
+	ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8));
+
+	/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
+
+	xhci_flush_cache((uintptr_t)ep0_ctx, sizeof(struct xhci_ep_ctx));
+	xhci_flush_cache((uintptr_t)slot_ctx, sizeof(struct xhci_slot_ctx));
+}
diff --git a/roms/u-boot/drivers/usb/host/xhci-mtk.c b/roms/u-boot/drivers/usb/host/xhci-mtk.c
new file mode 100644
index 000000000..18b4f55d8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-mtk.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 MediaTek, Inc.
+ * Authors: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <generic-phy.h>
+#include <malloc.h>
+#include <power/regulator.h>
+#include <usb.h>
+#include <usb/xhci.h>
+#include <linux/errno.h>
+#include <linux/compat.h>
+#include <linux/iopoll.h>
+
+/* IPPC (IP Port Control) registers */
+#define IPPC_IP_PW_CTRL0		0x00
+#define CTRL0_IP_SW_RST			BIT(0)
+
+#define IPPC_IP_PW_CTRL1		0x04
+#define CTRL1_IP_HOST_PDN		BIT(0)
+
+#define IPPC_IP_PW_STS1			0x10
+#define STS1_IP_SLEEP_STS		BIT(30)
+#define STS1_U3_MAC_RST			BIT(16)
+#define STS1_XHCI_RST			BIT(11)
+#define STS1_SYS125_RST			BIT(10)
+#define STS1_REF_RST			BIT(8)
+#define STS1_SYSPLL_STABLE		BIT(0)
+
+#define IPPC_IP_XHCI_CAP		0x24
+#define CAP_U3_PORT_NUM(p)		((p) & 0xff)
+#define CAP_U2_PORT_NUM(p)		(((p) >> 8) & 0xff)
+
+#define IPPC_U3_CTRL_0P			0x30
+#define CTRL_U3_PORT_HOST_SEL		BIT(2)
+#define CTRL_U3_PORT_PDN		BIT(1)
+#define CTRL_U3_PORT_DIS		BIT(0)
+
+#define IPPC_U2_CTRL_0P			0x50
+#define CTRL_U2_PORT_HOST_SEL		BIT(2)
+#define CTRL_U2_PORT_PDN		BIT(1)
+#define CTRL_U2_PORT_DIS		BIT(0)
+
+#define IPPC_U3_CTRL(p)	(IPPC_U3_CTRL_0P + ((p) * 0x08))
+#define IPPC_U2_CTRL(p)	(IPPC_U2_CTRL_0P + ((p) * 0x08))
+
+struct mtk_xhci {
+	struct xhci_ctrl ctrl;	/* Needs to come first in this struct! */
+	struct xhci_hccr *hcd;
+	void __iomem *ippc;
+	struct udevice *dev;
+	struct udevice *vusb33_supply;
+	struct udevice *vbus_supply;
+	struct clk_bulk clks;
+	struct phy_bulk phys;
+	int num_u2ports;
+	int num_u3ports;
+	u32 u3p_dis_msk;
+	u32 u2p_dis_msk;
+};
+
+static int xhci_mtk_host_enable(struct mtk_xhci *mtk)
+{
+	int u3_ports_disabed = 0;
+	u32 value;
+	u32 check_val;
+	int ret;
+	int i;
+
+	/* power on host ip */
+	clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN);
+
+	/* power on and enable u3 ports except skipped ones */
+	for (i = 0; i < mtk->num_u3ports; i++) {
+		if (BIT(i) & mtk->u3p_dis_msk) {
+			u3_ports_disabed++;
+			continue;
+		}
+
+		clrsetbits_le32(mtk->ippc + IPPC_U3_CTRL(i),
+				CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS,
+				CTRL_U3_PORT_HOST_SEL);
+	}
+
+	/* power on and enable u2 ports except skipped ones */
+	for (i = 0; i < mtk->num_u2ports; i++) {
+		if (BIT(i) & mtk->u2p_dis_msk)
+			continue;
+
+		clrsetbits_le32(mtk->ippc + IPPC_U2_CTRL(i),
+				CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS,
+				CTRL_U2_PORT_HOST_SEL);
+	}
+
+	/*
+	 * wait for clocks to be stable, and clock domains reset to
+	 * be inactive after power on and enable ports
+	 */
+	check_val = STS1_SYSPLL_STABLE | STS1_REF_RST |
+			STS1_SYS125_RST | STS1_XHCI_RST;
+
+	if (mtk->num_u3ports > u3_ports_disabed)
+		check_val |= STS1_U3_MAC_RST;
+
+	ret = readl_poll_timeout(mtk->ippc + IPPC_IP_PW_STS1, value,
+				 (check_val == (value & check_val)), 20000);
+	if (ret)
+		dev_err(mtk->dev, "clocks are not stable 0x%x!\n", value);
+
+	return ret;
+}
+
+static int xhci_mtk_host_disable(struct mtk_xhci *mtk)
+{
+	int i;
+
+	/* power down all u3 ports */
+	for (i = 0; i < mtk->num_u3ports; i++)
+		setbits_le32(mtk->ippc + IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN);
+
+	/* power down all u2 ports */
+	for (i = 0; i < mtk->num_u2ports; i++)
+		setbits_le32(mtk->ippc + IPPC_U2_CTRL(i), CTRL_U2_PORT_PDN);
+
+	/* power down host ip */
+	setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN);
+
+	return 0;
+}
+
+static int xhci_mtk_ssusb_init(struct mtk_xhci *mtk)
+{
+	u32 value;
+
+	/* reset whole ip */
+	setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST);
+	udelay(1);
+	clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST);
+
+	value = readl(mtk->ippc + IPPC_IP_XHCI_CAP);
+	mtk->num_u3ports = CAP_U3_PORT_NUM(value);
+	mtk->num_u2ports = CAP_U2_PORT_NUM(value);
+	dev_info(mtk->dev, "u2p:%d, u3p:%d\n",
+		 mtk->num_u2ports, mtk->num_u3ports);
+
+	return xhci_mtk_host_enable(mtk);
+}
+
+static int xhci_mtk_ofdata_get(struct mtk_xhci *mtk)
+{
+	struct udevice *dev = mtk->dev;
+	int ret = 0;
+
+	mtk->hcd = devfdt_remap_addr_name(dev, "mac");
+	if (!mtk->hcd) {
+		dev_err(dev, "failed to get xHCI base address\n");
+		return -ENXIO;
+	}
+
+	mtk->ippc = devfdt_remap_addr_name(dev, "ippc");
+	if (!mtk->ippc) {
+		dev_err(dev, "failed to get IPPC base address\n");
+		return -ENXIO;
+	}
+
+	dev_info(dev, "hcd: 0x%p, ippc: 0x%p\n", mtk->hcd, mtk->ippc);
+
+	ret = clk_get_bulk(dev, &mtk->clks);
+	if (ret) {
+		dev_err(dev, "failed to get clocks %d!\n", ret);
+		return ret;
+	}
+
+	ret = device_get_supply_regulator(dev, "vusb33-supply",
+					  &mtk->vusb33_supply);
+	if (ret)
+		debug("can't get vusb33 regulator %d!\n", ret);
+
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &mtk->vbus_supply);
+	if (ret)
+		debug("can't get vbus regulator %d!\n", ret);
+
+	/* optional properties to disable ports, ignore the error */
+	dev_read_u32(dev, "mediatek,u3p-dis-msk", &mtk->u3p_dis_msk);
+	dev_read_u32(dev, "mediatek,u2p-dis-msk", &mtk->u2p_dis_msk);
+	dev_info(dev, "ports disabled mask: u3p-0x%x, u2p-0x%x\n",
+		 mtk->u3p_dis_msk, mtk->u2p_dis_msk);
+
+	return 0;
+}
+
+static int xhci_mtk_ldos_enable(struct mtk_xhci *mtk)
+{
+	int ret;
+
+	ret = regulator_set_enable(mtk->vusb33_supply, true);
+	if (ret < 0 && ret != -ENOSYS) {
+		dev_err(mtk->dev, "failed to enable vusb33 %d!\n", ret);
+		return ret;
+	}
+
+	ret = regulator_set_enable(mtk->vbus_supply, true);
+	if (ret < 0 && ret != -ENOSYS) {
+		dev_err(mtk->dev, "failed to enable vbus %d!\n", ret);
+		regulator_set_enable(mtk->vusb33_supply, false);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void xhci_mtk_ldos_disable(struct mtk_xhci *mtk)
+{
+	regulator_set_enable(mtk->vbus_supply, false);
+	regulator_set_enable(mtk->vusb33_supply, false);
+}
+
+static int xhci_mtk_phy_setup(struct mtk_xhci *mtk)
+{
+	struct udevice *dev = mtk->dev;
+	struct phy_bulk *phys = &mtk->phys;
+	int ret;
+
+	ret = generic_phy_get_bulk(dev, phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_init_bulk(phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on_bulk(phys);
+	if (ret)
+		generic_phy_exit_bulk(phys);
+
+	return ret;
+}
+
+static void xhci_mtk_phy_shutdown(struct mtk_xhci *mtk)
+{
+	generic_phy_power_off_bulk(&mtk->phys);
+	generic_phy_exit_bulk(&mtk->phys);
+}
+
+static int xhci_mtk_probe(struct udevice *dev)
+{
+	struct mtk_xhci *mtk = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int ret;
+
+	mtk->dev = dev;
+	ret = xhci_mtk_ofdata_get(mtk);
+	if (ret)
+		return ret;
+
+	ret = xhci_mtk_ldos_enable(mtk);
+	if (ret)
+		goto ldos_err;
+
+	ret = clk_enable_bulk(&mtk->clks);
+	if (ret)
+		goto clks_err;
+
+	ret = xhci_mtk_phy_setup(mtk);
+	if (ret)
+		goto phys_err;
+
+	ret = xhci_mtk_ssusb_init(mtk);
+	if (ret)
+		goto ssusb_init_err;
+
+	mtk->ctrl.quirks = XHCI_MTK_HOST;
+	hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd +
+			HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase)));
+
+	return xhci_register(dev, mtk->hcd, hcor);
+
+ssusb_init_err:
+	xhci_mtk_phy_shutdown(mtk);
+phys_err:
+	clk_disable_bulk(&mtk->clks);
+clks_err:
+	xhci_mtk_ldos_disable(mtk);
+ldos_err:
+	return ret;
+}
+
+static int xhci_mtk_remove(struct udevice *dev)
+{
+	struct mtk_xhci *mtk = dev_get_priv(dev);
+
+	xhci_deregister(dev);
+	xhci_mtk_host_disable(mtk);
+	xhci_mtk_ldos_disable(mtk);
+	clk_disable_bulk(&mtk->clks);
+
+	return 0;
+}
+
+static const struct udevice_id xhci_mtk_ids[] = {
+	{ .compatible = "mediatek,mtk-xhci" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name = "xhci-mtk",
+	.id = UCLASS_USB,
+	.of_match = xhci_mtk_ids,
+	.probe = xhci_mtk_probe,
+	.remove = xhci_mtk_remove,
+	.ops = &xhci_usb_ops,
+	.bind = dm_scan_fdt_dev,
+	.priv_auto	= sizeof(struct mtk_xhci),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/xhci-mvebu.c b/roms/u-boot/drivers/usb/host/xhci-mvebu.c
new file mode 100644
index 000000000..46b89de85
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-mvebu.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Marvell International Ltd.
+ *
+ * MVEBU USB HOST xHCI Controller
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <usb.h>
+#include <power/regulator.h>
+#include <asm/gpio.h>
+
+#include <usb/xhci.h>
+
+struct mvebu_xhci_plat {
+	fdt_addr_t hcd_base;
+};
+
+/**
+ * Contains pointers to register base addresses
+ * for the usb controller.
+ */
+struct mvebu_xhci {
+	struct xhci_ctrl ctrl;	/* Needs to come first in this struct! */
+	struct usb_plat usb_plat;
+	struct xhci_hccr *hcd;
+};
+
+/*
+ * Dummy implementation that can be overwritten by a board
+ * specific function
+ */
+__weak int board_xhci_enable(fdt_addr_t base)
+{
+	return 0;
+}
+
+static int xhci_usb_probe(struct udevice *dev)
+{
+	struct mvebu_xhci_plat *plat = dev_get_plat(dev);
+	struct mvebu_xhci *ctx = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int len, ret;
+	struct udevice *regulator;
+
+	ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
+	len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
+	hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
+
+	ret = device_get_supply_regulator(dev, "vbus-supply", &regulator);
+	if (!ret) {
+		ret = regulator_set_enable(regulator, true);
+		if (ret) {
+			printf("Failed to turn ON the VBUS regulator\n");
+			return ret;
+		}
+	}
+
+	/* Enable USB xHCI (VBUS, reset etc) in board specific code */
+	board_xhci_enable(devfdt_get_addr_index(dev, 1));
+
+	return xhci_register(dev, ctx->hcd, hcor);
+}
+
+static int xhci_usb_of_to_plat(struct udevice *dev)
+{
+	struct mvebu_xhci_plat *plat = dev_get_plat(dev);
+
+	/*
+	 * Get the base address for XHCI controller from the device node
+	 */
+	plat->hcd_base = dev_read_addr(dev);
+	if (plat->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the XHCI register base address\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+	{ .compatible = "marvell,armada3700-xhci" },
+	{ .compatible = "marvell,armada-380-xhci" },
+	{ .compatible = "marvell,armada-8k-xhci" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name	= "xhci_mvebu",
+	.id	= UCLASS_USB,
+	.of_match = xhci_usb_ids,
+	.of_to_plat = xhci_usb_of_to_plat,
+	.probe = xhci_usb_probe,
+	.remove = xhci_deregister,
+	.ops	= &xhci_usb_ops,
+	.plat_auto	= sizeof(struct mvebu_xhci_plat),
+	.priv_auto	= sizeof(struct mvebu_xhci),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/xhci-omap.c b/roms/u-boot/drivers/usb/host/xhci-omap.c
new file mode 100644
index 000000000..501129d76
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-omap.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP USB HOST xHCI Controller
+ *
+ * (C) Copyright 2013
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <usb.h>
+#include <linux/errno.h>
+#include <asm/omap_common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/sys_proto.h>
+
+#include <linux/compat.h>
+#include <linux/usb/dwc3.h>
+#include <linux/usb/xhci-omap.h>
+
+#include <usb/xhci.h>
+
+/* Declare global data pointer */
+static struct omap_xhci omap;
+
+static int omap_xhci_core_init(struct omap_xhci *omap)
+{
+	int ret = 0;
+
+	usb_phy_power(1);
+	omap_enable_phy(omap);
+
+	ret = dwc3_core_init(omap->dwc3_reg);
+	if (ret) {
+		debug("%s:failed to initialize core\n", __func__);
+		return ret;
+	}
+
+	/* We are hard-coding DWC3 core to Host Mode */
+	dwc3_set_mode(omap->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
+
+	return ret;
+}
+
+static void omap_xhci_core_exit(struct omap_xhci *omap)
+{
+	usb_phy_power(0);
+}
+
+int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
+{
+	struct omap_xhci *ctx = &omap;
+	int ret = 0;
+
+	ctx->hcd = (struct xhci_hccr *)OMAP_XHCI_BASE;
+	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
+	ctx->usb3_phy = (struct omap_usb3_phy *)OMAP_OCP1_SCP_BASE;
+	ctx->otg_wrapper = (struct omap_dwc_wrapper *)OMAP_OTG_WRAPPER_BASE;
+
+	ret = board_usb_init(index, USB_INIT_HOST);
+	if (ret != 0) {
+		puts("Failed to initialize board for USB\n");
+		return ret;
+	}
+
+	ret = omap_xhci_core_init(ctx);
+	if (ret < 0) {
+		puts("Failed to initialize xhci\n");
+		return ret;
+	}
+
+	*hccr = (struct xhci_hccr *)(OMAP_XHCI_BASE);
+	*hcor = (struct xhci_hcor *)((uint32_t) *hccr
+				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
+
+	debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n",
+	      (uint32_t)*hccr, (uint32_t)*hcor,
+	      (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
+
+	return ret;
+}
+
+void xhci_hcd_stop(int index)
+{
+	struct omap_xhci *ctx = &omap;
+
+	omap_xhci_core_exit(ctx);
+	board_usb_cleanup(index, USB_INIT_HOST);
+}
diff --git a/roms/u-boot/drivers/usb/host/xhci-pci.c b/roms/u-boot/drivers/usb/host/xhci-pci.c
new file mode 100644
index 000000000..aaa243f29
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-pci.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015, Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * All rights reserved.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <pci.h>
+#include <usb.h>
+#include <usb/xhci.h>
+
+static int xhci_pci_init(struct udevice *dev, struct xhci_hccr **ret_hccr,
+			 struct xhci_hcor **ret_hcor)
+{
+	struct xhci_hccr *hccr;
+	struct xhci_hcor *hcor;
+	u32 cmd;
+
+	hccr = (struct xhci_hccr *)dm_pci_map_bar(dev,
+			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	if (!hccr) {
+		printf("xhci-pci init cannot map PCI mem bar\n");
+		return -EIO;
+	}
+
+	hcor = (struct xhci_hcor *)((uintptr_t) hccr +
+			HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
+
+	debug("XHCI-PCI init hccr %p and hcor %p hc_length %d\n",
+	      hccr, hcor, (u32)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	/* enable busmaster */
+	dm_pci_read_config32(dev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER;
+	dm_pci_write_config32(dev, PCI_COMMAND, cmd);
+	return 0;
+}
+
+static int xhci_pci_probe(struct udevice *dev)
+{
+	struct xhci_hccr *hccr;
+	struct xhci_hcor *hcor;
+	int ret;
+
+	ret = xhci_pci_init(dev, &hccr, &hcor);
+	if (ret)
+		return ret;
+
+	return xhci_register(dev, hccr, hcor);
+}
+
+static const struct udevice_id xhci_pci_ids[] = {
+	{ .compatible = "xhci-pci" },
+	{ }
+};
+
+U_BOOT_DRIVER(xhci_pci) = {
+	.name	= "xhci_pci",
+	.id	= UCLASS_USB,
+	.probe = xhci_pci_probe,
+	.remove = xhci_deregister,
+	.of_match = xhci_pci_ids,
+	.ops	= &xhci_usb_ops,
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct xhci_ctrl),
+	.flags	= DM_FLAG_OS_PREPARE | DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static struct pci_device_id xhci_pci_supported[] = {
+	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(xhci_pci, xhci_pci_supported);
diff --git a/roms/u-boot/drivers/usb/host/xhci-rcar-r8a779x_usb3_v3.h b/roms/u-boot/drivers/usb/host/xhci-rcar-r8a779x_usb3_v3.h
new file mode 100644
index 000000000..f0f48a335
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-rcar-r8a779x_usb3_v3.h
@@ -0,0 +1,643 @@
+/*
+ * Renesas RCar xHCI controller firmware version 3
+ *
+ * Copyright (c) 2014, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in binary form, without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistribution in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 2. The name of Renesas Electronics Corporation may not be used to endorse or
+ *    promote products derived from this software without specific prior written
+ *    permission.
+ * 3. Reverse engineering, decompilation, or disassembly of this software is
+ *    not permitted.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS ELECTRONICS CORPORATION DISCLAIMS
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND
+ * NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL RENESAS ELECTRONICS
+ * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is generated from the firmware blob r8a779x_usb3_v3.dlmem
+ * with associated license file LICENCE.r8a779x_usb3, both taken from
+ * linux-firmware.git [1] as of:
+ *
+ *     commit 7c3dfc0bb21bf717dc19a6b677a866aef8b70c35
+ *     Author: Yoshihiro Shimoda
+ *     Date:   Wed Aug 10 19:56:39 2016 +0900
+ *
+ *         usb: host: xhci-rcar: update firmware for R-Car H3 and M3-W
+ *
+ * To generate the content of the array below, use ie. the following command:
+ * $ hexdump -v -e '/4 "0x%08x, "' r8a779x_usb3_v3.dlmem | \
+ * 	sed "s@\(.\{47\}\) @\1\n@g"
+ *
+ * [1] git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git
+ */
+
+#ifndef __FIRMWARE_R8A779X_USB3_V3__
+#define __FIRMWARE_R8A779X_USB3_V3__
+
+static const u32 firmware_r8a779x_usb3_v3[] = {
+	0xf4c455aa, 0x00d20014, 0x00000000, 0x23dc00e8,
+	0x00000000, 0x1a5c2007, 0x0001ff63, 0x001eff80,
+	0x0001ff23, 0x007f1a44, 0xff631a5c, 0xff800001,
+	0xff2301e2, 0x1a440001, 0x0780007f, 0x06250061,
+	0x00021e74, 0x40002e05, 0x40002e05, 0x8000f625,
+	0xdc90062a, 0x556f0000, 0xdd14062a, 0x17040000,
+	0x5573d612, 0x15ea062a, 0x57650000, 0x16c285d5,
+	0x060200f0, 0x1deaffe0, 0xe4251724, 0x05d9128d,
+	0x10001620, 0xe4251764, 0xd6151724, 0x1db1129f,
+	0x8625ef25, 0x0088063f, 0x32010002, 0x3200007d,
+	0x0392ffbe, 0x05e251e0, 0xffbe3200, 0x51e003e4,
+	0x520005ba, 0xef2515f5, 0x063f8625, 0x000200ae,
+	0x007d3200, 0xd6151724, 0x05b9129d, 0x0d8cffbe,
+	0xd61417c4, 0xd6179e24, 0x000037d3, 0x4ad0ffbe,
+	0x06405201, 0x26e6007f, 0x0f9a0631, 0x063f0000,
+	0x00000e64, 0x0782007f, 0x8f250061, 0xee248019,
+	0x30030000, 0x00f4063f, 0x00710002, 0x80158725,
+	0x00d00626, 0x3a010002, 0x0108063f, 0x00700002,
+	0x0505f01d, 0x7e3d0501, 0x7d030008, 0x80001640,
+	0x150d1511, 0xf6241509, 0x0509fd00, 0x1503121f,
+	0x801d7725, 0x00013723, 0x1764121e, 0x063f5c11,
+	0x0002013e, 0x0642006e, 0x0780007f, 0xe8060061,
+	0x0d0cffbe, 0x0001577d, 0x007f0640, 0x0d0a07be,
+	0x17201624, 0x9c00062a, 0x118a03ff, 0x17210764,
+	0xffec0602, 0xf6240d89, 0x35011720, 0x12820503,
+	0x1505125d, 0x1724007f, 0x11461721, 0xf6241db2,
+	0x55021720, 0x12c2100a, 0x3f6211c4, 0x160a172d,
+	0x15030001, 0x17295724, 0x05bb51e2, 0x17250764,
+	0x17251724, 0xeeee062a, 0x12c2eeee, 0x576211c4,
+	0x007f172d, 0x00610780, 0xe8060086, 0x17e0ffbe,
+	0x5c591724, 0x1281580a, 0xe9e00db1, 0x17240d92,
+	0x129dd605, 0x172405d9, 0x129dd605, 0x500bfdd1,
+	0x007f0640, 0x3bd60631, 0x063f0000, 0x00000e64,
+	0x0780007f, 0x06250061, 0x00021e74, 0x40002e05,
+	0x40002e05, 0x0dd00744, 0x17441201, 0xef840dd1,
+	0xea610dd1, 0x0dc205e1, 0x0dd1ea63, 0x15b50df2,
+	0x0046ff80, 0x1de251e0, 0x14b6ff80, 0xff800df5,
+	0x0dc50116, 0x023aff80, 0xff8005b5, 0xff800360,
+	0x05c514be, 0xffbe3201, 0x3f841702, 0x39fd0dd1,
+	0x0622ddf2, 0xaaaa1100, 0x32013902, 0x16d8ffbe,
+	0x0640d5f5, 0x0780007f, 0xffbe0061, 0x51e00398,
+	0x320105ca, 0x00eeffbe, 0x1c3affbe, 0x0386ffbe,
+	0x05ca51e0, 0xffbe3201, 0xff8000dc, 0xff800438,
+	0x321f04a2, 0xfebcffbf, 0x036affbe, 0x05ca51e0,
+	0xffbe3201, 0x172400c0, 0x1282d60d, 0xffbe15e9,
+	0xf62442ce, 0x1500d600, 0xf1ff5620, 0x1501114a,
+	0xd6051724, 0x05d9128d, 0xd6019e24, 0x000087d3,
+	0xd6b91724, 0x08f01764, 0x032affbe, 0x05ca51e0,
+	0xffbe3201, 0xef250080, 0x063f8625, 0x000202fc,
+	0x007d3201, 0x030effbe, 0x05ca51e0, 0xffbe3201,
+	0xff800064, 0x062604d6, 0x000224ac, 0x1de8ffbe,
+	0x15f251e0, 0x02eeffbe, 0x05ca51e0, 0xffbe3201,
+	0xef250044, 0x063f8625, 0x00020338, 0x007d3200,
+	0x016087e0, 0xffbe3201, 0x52011578, 0x0dd05744,
+	0x007f0640, 0x30e10780, 0xd6051724, 0x128dd200,
+	0x172415a9, 0x1282d60d, 0x172405d1, 0x1285d605,
+	0x9e240da1, 0x17d3d600, 0xffbe0000, 0xff80440a,
+	0x6dd500e2, 0x481affbe, 0xd7e91724, 0x15d11284,
+	0xd60d1724, 0x15911282, 0x1e26ffbe, 0xd6011724,
+	0x05b91298, 0xd602bfc4, 0xd6051724, 0x05d9129b,
+	0x04001640, 0xd6051764, 0xd7e91724, 0x05a91284,
+	0x1724d201, 0x128dd605, 0x17240d91, 0x1282d60d,
+	0xd1e005d9, 0xffbe05ba, 0xef251eda, 0x063f82b1,
+	0x000203de, 0x1724007d, 0x1282d60d, 0xd1e035a9,
+	0x172435ea, 0x1281d6b9, 0x178425f9, 0x11e008f3,
+	0xea0125ba, 0x80001625, 0x00c4de02, 0x301d15d5,
+	0xffbe0086, 0x51e0d8a6, 0x372a0de2, 0xe73b0001,
+	0x063f0001, 0x00020422, 0x51e0007c, 0x87c405ca,
+	0x0da5d6b8, 0x1724ea41, 0x52025c59, 0x05a91281,
+	0xe9ea5201, 0x1201e5d7, 0x08f91744, 0xd60c8fc4,
+	0x05dad1e0, 0x205affbe, 0x03caff80, 0x30ff0640,
+	0x00610780, 0x8625ef25, 0x046a063f, 0x32010002,
+	0xffbe007d, 0xffbe1572, 0x064015de, 0x0780007f,
+	0x17a40061, 0x12610dd1, 0x178415ba, 0x11e0e459,
+	0xffbe0df2, 0xef2542f2, 0x063f806d, 0x0002049a,
+	0x9e24007d, 0x1fd3d60f, 0x07440000, 0x17240dd1,
+	0x1285d605, 0x27c405e9, 0xff80d6b2, 0x45d50092,
+	0x82b9ef25, 0x04c4063f, 0x007d0002, 0x05c251e0,
+	0x181effbe, 0x17243da5, 0x1282e421, 0x32000dd9,
+	0x13deffbe, 0x82c1ef25, 0x04e8063f, 0x007d0002,
+	0x0dd00744, 0x17242da5, 0x1288e421, 0xffbe05b9,
+	0x17242250, 0x1289e425, 0xffbe05b9, 0x1724224c,
+	0x128ae425, 0xffbe05b9, 0xffbe24d6, 0x51e000f8,
+	0x320105ca, 0xfe4effbd, 0xe4211724, 0x0dd91281,
+	0x0dd117a4, 0x05da1261, 0xd60f9e24, 0x00001fd3,
+	0xd60c9fc4, 0x0026ff80, 0x007f0640, 0x00610780,
+	0x8625ef25, 0x0556063f, 0x32000002, 0xffbe007d,
+	0xffbe1562, 0x0640166e, 0x0782007f, 0xef250061,
+	0x063f8019, 0x00020574, 0x007d3003, 0x8625ef25,
+	0x0582063f, 0x32000002, 0xffbe007d, 0xffbe168c,
+	0x372316b4, 0xef250001, 0x063f801d, 0x0002059a,
+	0xffbe007d, 0x06421724, 0x0780007f, 0x172400e1,
+	0x1281e421, 0x17240d81, 0x1284e439, 0xff8005c1,
+	0x45c50090, 0x82b9ef25, 0x05c8063f, 0x007d0002,
+	0x05c251e0, 0x188affbe, 0xef253d95, 0x063f82d5,
+	0x000205e0, 0x007d3200, 0x8311ef25, 0x05ec063f,
+	0x007d0002, 0x08f717a4, 0x05ba11e0, 0x0450ff80,
+	0x02bcff80, 0x08f71784, 0x25821262, 0x08f717a4,
+	0x1dca11e0, 0x456cffbe, 0xffbee00a, 0xef25313e,
+	0x063f82e1, 0x00020622, 0xef25007d, 0x063f82f1,
+	0x0002062e, 0xffbe007d, 0xe1e0327a, 0xffbe05f2,
+	0x51e04542, 0xffbe05ba, 0x06402cf4, 0x078200ff,
+	0xef250061, 0x063f8019, 0x00020658, 0x007d3003,
+	0x8625ef25, 0x0666063f, 0x32010002, 0x1724007d,
+	0x1281ea01, 0x07c405b1, 0xffbeea00, 0xf62416da,
+	0x1558d600, 0x00105640, 0x1559110a, 0x171affbe,
+	0x00013723, 0x801def25, 0x0698063f, 0x007d0002,
+	0x85adef25, 0x06a4063f, 0x007d0002, 0x8019ef25,
+	0x06b2063f, 0x30030002, 0xffbe007d, 0x3723174e,
+	0xef250001, 0x063f801d, 0x000206c6, 0x0642007d,
+	0x0780007f, 0x121f0061, 0x5c00f624, 0x15091507,
+	0x150d150b, 0xfd00f624, 0x15031505, 0xe900f624,
+	0x15071505, 0xd600f624, 0x15061505, 0x0d911282,
+	0x1764121f, 0x0000d605, 0x00000000, 0x00000000,
+	0x8001ef25, 0x0714063f, 0x007d0002, 0x8015ef25,
+	0x01ec0626, 0x3a020002, 0x0728063f, 0x007d0002,
+	0x8021ef25, 0x0734063f, 0x007d0002, 0x007f0640,
+	0x00210780, 0xfbccffbd, 0x07d01620, 0x0fb8f624,
+	0x56801480, 0x5481ffff, 0x14835482, 0x001c1620,
+	0x0818f624, 0x520413b0, 0x120353b1, 0x13b313b2,
+	0x5bb45a01, 0x5c8153b5, 0x00c85620, 0x5e205482,
+	0x5c830190, 0x00645e20, 0x54855c84, 0x04870486,
+	0x00fa5620, 0x5e205488, 0x5c89012c, 0x5e20548a,
+	0x5c8b0014, 0x03c05620, 0x5205548c, 0x539b539a,
+	0x639c6206, 0x6b9d6a09, 0x539f5b9e, 0x63a153a0,
+	0x5ba25a0a, 0x00105e20, 0x5a025ba3, 0x5ba55ba4,
+	0x13a713a6, 0x5ba913a8, 0x13ab5baa, 0x13ad13ac,
+	0x5baf53ae, 0x003f0640, 0x00610780, 0xe000f624,
+	0x96201544, 0x9e24f0ff, 0x1152fb75, 0x03001682,
+	0xafd31545, 0xffbe0000, 0x27c41806, 0xef25d6b2,
+	0x063f834d, 0x00020812, 0xffbe007d, 0x064018a0,
+	0x0782007f, 0xef250061, 0x063f8019, 0x0002082c,
+	0x007d3003, 0x08f317a4, 0x1d8a1261, 0xd6051724,
+	0x15c9129c, 0x08001640, 0xd6051764, 0x00001200,
+	0x00000000, 0x00000000, 0x12671241, 0x1724fd96,
+	0x129cd605, 0x074405b1, 0xffbe08f3, 0x51e02500,
+	0xffbe1dc2, 0x37232554, 0xef250001, 0x063f801d,
+	0x0002087e, 0x1724007d, 0x5640d605, 0x114a0300,
+	0xffbe15c2, 0x17241a1e, 0x1282fd05, 0x17240de1,
+	0x1285d605, 0x0d95fd91, 0x00013723, 0x801def25,
+	0x08b0063f, 0x007d0002, 0x007f0642, 0x00610782,
+	0x8019ef25, 0x08c6063f, 0x30030002, 0xffbe007d,
+	0x51e02650, 0xffbe05da, 0xffbe26d6, 0x37232710,
+	0xef250001, 0x063f801d, 0x000208e6, 0x0642007d,
+	0x0780007f, 0xffbe0021, 0x51e02906, 0xffbe05b2,
+	0x06402acc, 0x0780003f, 0xef250061, 0x063f8631,
+	0x0002090e, 0x51e0007d, 0xffbe05ba, 0x0640325c,
+	0x0780007f, 0xd20070e1, 0x17441201, 0x16250855,
+	0xce028000, 0xde020330, 0x17240334, 0xe802eab5,
+	0xea9aeaca, 0x003f16c2, 0x35c2e9e2, 0x001f16dd,
+	0x000c36e2, 0x170631c4, 0x362694b4, 0x12d894b0,
+	0x1261129c, 0x05d21df1, 0x0da11263, 0x1da515c2,
+	0x0001e739, 0x0974063f, 0x007c0002, 0xe73b15d5,
+	0x063f0001, 0x00020982, 0x06aa007c, 0x0dc2ffff,
+	0x0da5d201, 0x0009e73b, 0x0998063f, 0x007c0002,
+	0xff8005b5, 0xea41003e, 0x003f56dd, 0xeab65744,
+	0x1640c5d5, 0xf6240001, 0x1503ea00, 0xe802155a,
+	0xea9aeaca, 0x003f16c2, 0xbd8ae9e2, 0x05fad261,
+	0x8339ef25, 0x09d4063f, 0x007d0002, 0x70ff0640,
+	0x00610780, 0x5864f006, 0x5ad81303, 0x12d85a9c,
+	0x0dba1299, 0x80011724, 0x30005640, 0x25d2114a,
+	0x80011724, 0x129a12ca, 0x52c25002, 0x572a51c4,
+	0x66408001, 0x514c8000, 0x060b1d82, 0x15d1fff0,
+	0x57eb5201, 0x5f2400c0, 0x514be435, 0x38020de2,
+	0x000c16e2, 0x854def25, 0x47e211c4, 0x32440fc9,
+	0x0a40063f, 0x007d0002, 0x007f0640, 0x00e10780,
+	0x2200063c, 0xf624aaaa, 0xe86000a4, 0xea610384,
+	0x0d8205e1, 0x0d91ea63, 0x0dd50db2, 0x4292ffbe,
+	0xff800dd5, 0x0da50034, 0x0076ff80, 0xffbe05f5,
+	0x05c542de, 0xffbe3202, 0x3f840ed2, 0x39fd00a5,
+	0x391c05d2, 0xffbe3202, 0x17840eae, 0x11e000a9,
+	0x0640ddba, 0x078000ff, 0xefa40061, 0xea6100a5,
+	0x159205e1, 0x05e1ea63, 0x0da50d82, 0x430effbe,
+	0xffbe0da5, 0x05f543bc, 0x4406ffbe, 0x320305c5,
+	0x0e88ffbe, 0x00a53fa4, 0x0d8239fd, 0x33000622,
+	0x3902aaaa, 0xffbe3204, 0x06400e5e, 0x0780007f,
+	0xef8400e1, 0xe7a400a7, 0x101d00a7, 0xffed0602,
+	0x00424de1, 0x00160013, 0x001c0019, 0x0022001f,
+	0x00280025, 0x002e002b, 0x00340031, 0x003a0037,
+	0x0040003d, 0x00490043, 0xffbe0046, 0x3da543ea,
+	0x4488ffbe, 0xffbe35f5, 0x35c5448a, 0x0098ff80,
+	0xff803595, 0x2de500d4, 0x0114ff80, 0xff802db5,
+	0x2d8501a8, 0x01e0ff80, 0xff8025d5, 0x25a502fe,
+	0x05b0ff80, 0xff801df5, 0x1dc505d4, 0x694effbe,
+	0xffbe1d95, 0x15e56a22, 0x0604ff80, 0xff8015b5,
+	0x1585061e, 0x6c9effbe, 0xffbe0dd5, 0x0da56cea,
+	0x6d96ffbe, 0xffbe05f5, 0x05c56e5e, 0xffbe3204,
+	0x3f840dba, 0x39fd00a7, 0x06220d82, 0xaaaa4400,
+	0x32083902, 0x0d90ffbe, 0x00a73fa4, 0x0d9239fc,
+	0x55000622, 0x3902aaaa, 0x00103620, 0x0d78ffbe,
+	0x00ff0640, 0x00a717a4, 0x1dab1269, 0x000a0042,
+	0x001b000c, 0x0010000e, 0x0012001b, 0x001b0014,
+	0x07be0016, 0x07be4470, 0x07be4522, 0x07be458e,
+	0x07be45ae, 0x07be461a, 0x07be463a, 0x32054696,
+	0x0d4807be, 0x17a4007f, 0x126900a7, 0x00421dcb,
+	0x001d000a, 0x0010000c, 0x0016000e, 0x00140012,
+	0x0018001d, 0x46fc07be, 0x47d607be, 0x494407be,
+	0x487207be, 0x4a3607be, 0x4a8a07be, 0x497a07be,
+	0x4b7407be, 0x07be3206, 0x007f0d02, 0x00a717a4,
+	0xffe70602, 0x004245d1, 0x00460019, 0x001d001b,
+	0x0021001f, 0x00250023, 0x00290027, 0x002d002b,
+	0x0031002f, 0x00350033, 0x00370046, 0x003b0039,
+	0x0046003d, 0x0046003f, 0x07be0041, 0x07be4b80,
+	0x07be4c5e, 0x07be4d0c, 0x07be4d72, 0x07be4dd2,
+	0x07be4e8c, 0x07be4f12, 0x07be504c, 0x07be50f6,
+	0x07be512c, 0x07be51c6, 0x07be5212, 0x07be5320,
+	0x07be5462, 0x07be54d0, 0x07be55fa, 0x07be562e,
+	0x07be5698, 0x07be56d0, 0x07be582c, 0x3207599c,
+	0x0c6807be, 0x17a4007f, 0x126900a7, 0x00421d8b,
+	0x0019000a, 0x000e000c, 0x00100019, 0x00120019,
+	0x00140019, 0x5a3e07be, 0x5abc07be, 0x5b5407be,
+	0x5bba07be, 0x5c2207be, 0x5d3c07be, 0x07be3208,
+	0x007f0c2a, 0x00a717a4, 0x0d811261, 0x12631582,
+	0x0dd205f1, 0x05e21264, 0x07be05f5, 0x07805d24,
+	0x07be0010, 0x32095f2c, 0x0c0007be, 0x0786007f,
+	0x378470e1, 0x16240811, 0xe8068284, 0xe9c2eac5,
+	0xe4391724, 0xd200e200, 0x07a4de24, 0x05e91283,
+	0x07b337a4, 0x6cb6ffbe, 0xffbe65e5, 0x171da9f6,
+	0x12d90001, 0x1264129d, 0xf7dd0d9a, 0x05e20006,
+	0x0007e79d, 0xe2d8d201, 0x17bbe29f, 0x3784000d,
+	0xcf250811, 0x063f83cd, 0x00020dbc, 0x129f12de,
+	0x00793802, 0xf6241201, 0x139c00ac, 0xd1e0039d,
+	0xe1e02582, 0x171d0dda, 0xf6240015, 0x12ddeb54,
+	0x12c3129e, 0x121ff1c2, 0x15031501, 0x120115a5,
+	0x00acf624, 0x571d139c, 0x56ca000b, 0x5241001f,
+	0x00c017ea, 0x139d125f, 0x07b4f624, 0x05030501,
+	0x0e5497c4, 0x0e540fc4, 0x000d3f3b, 0x0e5407c4,
+	0x17441203, 0x300700a7, 0x3acb3298, 0x3ac63a9b,
+	0x08e0ffbe, 0x00ac3624, 0x00401620, 0x1501f003,
+	0x17250503, 0x3e24839d, 0x400a0e54, 0x1505480b,
+	0x05ccffbe, 0x70ff0646, 0x00210780, 0x00a717a4,
+	0x0d911261, 0x126415f2, 0x15f22591, 0x1d811266,
+	0x1d950de2, 0x003aff80, 0xfd191724, 0x129512c5,
+	0x16c21242, 0x17440003, 0x15851714, 0x0132ff80,
+	0xffbe0dd5, 0x0da55f18, 0x01a6ff80, 0xffbe05f5,
+	0x05c560f8, 0xffbe320a, 0x06400ab2, 0x0780003f,
+	0x5f2400e1, 0xee2407b1, 0x662407a4, 0x100b8000,
+	0x50021298, 0x51cc52c2, 0x0da211e0, 0xffdf0602,
+	0x172a05f1, 0x56400001, 0x51428000, 0x320b05ba,
+	0x56405dc5, 0x51423000, 0x36c255e2, 0x100b00ff,
+	0xe72512cb, 0x129b841d, 0x063f3802, 0x00020efa,
+	0x5744007c, 0x008a0810, 0x060d680a, 0x05baff01,
+	0x45b53205, 0x100d6ac5, 0x172211c4, 0x16c28299,
+	0x12610007, 0x12633df2, 0x100a35ea, 0x66c21285,
+	0x16ca0003, 0x5a01001f, 0x00c05fe2, 0x17196764,
+	0x100c62c2, 0x172211c4, 0x5f64ea49, 0x114b171d,
+	0x17241dea, 0x12c5fd19, 0x12421295, 0x000376c2,
+	0xfd191724, 0x129512c5, 0x000316c2, 0xfd9a11ee,
+	0x172d69c4, 0x16c28299, 0x12610007, 0x126315b2,
+	0x61c40daa, 0xea49172c, 0x05d25942, 0x17441206,
+	0x15c500a7, 0x00133620, 0x000f3fbd, 0x6b0effbe,
+	0xef250dd5, 0x063f8625, 0x00020fa8, 0x007d3201,
+	0xf6241201, 0x138400a4, 0x06401383, 0x172400ff,
+	0x5e24e421, 0x128107a4, 0x172405d9, 0x1283e439,
+	0x37ab05d9, 0x07be000f, 0x17846a64, 0x12c50811,
+	0x172211c4, 0x16c28299, 0x12630007, 0xf62405f2,
+	0x038300a4, 0x13841201, 0x172425a5, 0x57241719,
+	0x12c2171d, 0x172211c4, 0x5142ea49, 0xfd191724,
+	0x129512c5, 0x05f251e0, 0x16c21242, 0x17440003,
+	0x0dd51714, 0x17155784, 0x000316c2, 0x05fa11ea,
+	0x000f3fab, 0x00133620, 0x6a7207be, 0x0788007f,
+	0x67240021, 0x62d2eab1, 0x160c629a, 0x1261ffff,
+	0x126315b3, 0x12691592, 0x126b0df2, 0x126d0dd2,
+	0x06020db2, 0x0d82ffef, 0xffed1602, 0x05c31261,
+	0x12611259, 0x57844d9b, 0x5e240811, 0x100a8284,
+	0x11cb12c5, 0x05b26261, 0x0dba6262, 0x51c452c2,
+	0x8085572a, 0x05d9528e, 0x07635200, 0x05f50001,
+	0xeb6d5724, 0x00015763, 0xeb715724, 0x5503f003,
+	0x1b005640, 0x05075505, 0x56ca530d, 0x568a0003,
+	0x538d0080, 0x57225b0e, 0x5ecb0001, 0x6eca00e0,
+	0x590d001f, 0x52d45b8e, 0x538f5299, 0xffff560c,
+	0x05e35261, 0x05c25269, 0xffef060a, 0x3f8205ea,
+	0x3ec7000d, 0x05d5000f, 0xeab13f24, 0x3a9c3acc,
+	0xffbe3003, 0x12050436, 0x00a71744, 0x003f0648,
+	0x00a717a4, 0x0d811261, 0x12631582, 0x0dd205f1,
+	0x05e21264, 0x07be05f5, 0x07be5eac, 0x07be5fc4,
+	0x320b6022, 0x082407be, 0x17a4007f, 0x126900a7,
+	0x00421dab, 0x000c000a, 0x000e001b, 0x001b0010,
+	0x00140012, 0x0016001b, 0x603607be, 0x613a07be,
+	0x61a607be, 0x61c607be, 0x623207be, 0x625207be,
+	0x62d007be, 0x07be320c, 0x007f07e2, 0x00a717a4,
+	0x05d11261, 0x12620db2, 0x05d505c2, 0x643807be,
+	0x655407be, 0x07be320d, 0x007f07c2, 0x00a717a4,
+	0x05d11261, 0x126205e2, 0x05f505e2, 0x654007be,
+	0x65fe07be, 0x666607be, 0x07be320e, 0x0780079e,
+	0x008610e1, 0xeac5e806, 0x077de9c4, 0x077d8289,
+	0x077d828d, 0x077d8291, 0x077d8295, 0x077d8299,
+	0x077d829d, 0xe00682a1, 0xd8070087, 0x6b06ffbe,
+	0x8285171d, 0x301c381b, 0x129d12d9, 0x05ca1264,
+	0x6c54ffbe, 0xffbe05b5, 0x06406c86, 0x078010ff,
+	0xd80770e1, 0xd008009b, 0xc809009a, 0x009ce006,
+	0xeac5e81c, 0x82841624, 0x301de9c2, 0x46203a00,
+	0xffbe0020, 0x301c062a, 0x401a381b, 0xffbe4819,
+	0x301c6cba, 0x0001171d, 0x401a381b, 0x12d94819,
+	0x1264129d, 0xffbe158a, 0xf7dd6e9e, 0x48190006,
+	0x381b401a, 0x05ca301c, 0x6f1affbe, 0xffbe05e5,
+	0x05b56f4e, 0x6f54ffbe, 0x70ff0640, 0x10e10780,
+	0xe8060086, 0xe9c4eac5, 0x0087e006, 0xffbed807,
+	0x171d7016, 0xee3d8285, 0x301c8284, 0x12d9381b,
+	0x1264129d, 0xffbe0dea, 0xf7dd7012, 0x381b0006,
+	0x05ca301c, 0x7064ffbe, 0xffbe05e5, 0x05b570c6,
+	0x70f8ffbe, 0x10ff0640, 0x00610780, 0xe8060086,
+	0x1624eac4, 0xe9c205a4, 0x00051728, 0x008b5807,
+	0x30025002, 0x529852d0, 0x00013e0a, 0x32900087,
+	0x2da25a61, 0x1dc25a63, 0x35aa5a64, 0x129d12da,
+	0x05e21261, 0x0d821263, 0x0da21265, 0x30080dd5,
+	0x8512ffbe, 0x300825f5, 0x85f4ffbe, 0x300825b5,
+	0x86d6ffbe, 0x30081df5, 0x879cffbe, 0x12da1db5,
+	0x1261129d, 0x126505b2, 0xffbe05ca, 0x15a58858,
+	0x8862ffbe, 0x12da0df5, 0x1261129d, 0x126505b2,
+	0xffbe05ca, 0x05e58860, 0x8886ffbe, 0xffbe05b5,
+	0x577d88ac, 0x06400001, 0x0780007f, 0x00860061,
+	0xeac4e806, 0x05a41624, 0xefc7e9c2, 0x30070004,
+	0xffbe05ca, 0x05b588c4, 0x8976ffbe, 0x0005577d,
+	0x007f0640, 0xffe1078a, 0x00bc3620, 0x8cbcffbe,
+	0xffbea00a, 0x57638cbe, 0xffbe0002, 0x57638cb6,
+	0xffbe0004, 0x57638cb4, 0x36200006, 0xffbe00bc,
+	0x57638cae, 0x36200008, 0xffbe00bc, 0x57638caa,
+	0xffbe000a, 0x57638cdc, 0xffbe000c, 0x57638cd4,
+	0xffbe000e, 0x57638cd2, 0x36200010, 0xffbe00bc,
+	0x57638ccc, 0xaa000012, 0xb200ba00, 0xe815ca00,
+	0x1624eac3, 0xe9c204a4, 0xd860f01d, 0xe063c067,
+	0x0220dff4, 0xffbe3018, 0xf01d8c42, 0xe7ea1061,
+	0x57e30220, 0x5fe30003, 0x17ea0005, 0x50650220,
+	0x57ebe1db, 0x11dc0220, 0x5fe351c2, 0x10640007,
+	0x022017eb, 0x11cad862, 0x000957e3, 0xdfeae066,
+	0x30180220, 0xffbed9c2, 0xe7ea8c16, 0xf01d0220,
+	0xd060e1db, 0x000b17e3, 0xd8633018, 0x0220d7e2,
+	0x8c04ffbe, 0x1061f01d, 0x0220dfea, 0x000d57e3,
+	0x000f5fe3, 0x022017ea, 0xd9da5065, 0x022057eb,
+	0x51c211db, 0x00115fe3, 0x17eb1064, 0xd0620220,
+	0x57e311ca, 0xd8660013, 0x0220d7ea, 0xd1c23018,
+	0x8c0affbe, 0x0220dfea, 0xb9fcd9da, 0xb81c05a9,
+	0x05a9b1fb, 0xee1db01b, 0xca410040, 0xca640099,
+	0x10159dc1, 0x500212c2, 0xbf6a51c4, 0x11c403bd,
+	0x03ddb762, 0x0095aa41, 0x85f1aa68, 0xffff064a,
+	0x00210780, 0x00041706, 0x12da0087, 0x16c2129d,
+	0x3a610003, 0x2dc255b1, 0x3dd13a63, 0x3a6415e2,
+	0x12614dda, 0x0de205e1, 0x05e11263, 0x45e50d82,
+	0xa402ffbe, 0xffbe45c5, 0x4595a464, 0xa546ffbe,
+	0xffbe3de5, 0x3db5a602, 0x05e11261, 0x12630de2,
+	0x0d8205e1, 0xffbe35b5, 0x3595a3b8, 0xa41affbe,
+	0xffbe2de5, 0x2db5a4d2, 0xa58effbe, 0x12612d85,
+	0x0de205e1, 0x05e11263, 0x25850d82, 0xa35cffbe,
+	0xffbe1de5, 0x1db5a3d0, 0xa47cffbe, 0xffbe1d85,
+	0x15d5a538, 0x05e11261, 0x12630de2, 0x0d8205e1,
+	0xffbe0dd5, 0x0db5a31c, 0xa3a6ffbe, 0xffbe0d85,
+	0x05d5a428, 0xa50effbe, 0x520105a5, 0x003f0640,
+	0x00210780, 0x0fc11784, 0x05f211e0, 0x0fb8f624,
+	0x03883069, 0xabf4ffbe, 0xfd111724, 0x05b11284,
+	0xfd081fc4, 0x003f0640, 0xf0e10780, 0x8625ef25,
+	0x3201d200, 0x15e4063f, 0x007d0002, 0x5c591724,
+	0x1281c00a, 0x0000e7e9, 0x80001625, 0x00c0ce02,
+	0x301c1db5, 0xffbe0086, 0xe80ac6b2, 0x15b2e9e0,
+	0xff80301d, 0x373d00a0, 0xdf390001, 0x063f0001,
+	0x0002161e, 0x5261007b, 0xcfdd05c2, 0x05b20003,
+	0x0d95d201, 0x1724e241, 0x12815c59, 0x000017e9,
+	0xe587e1e2, 0x8625ef25, 0x164a063f, 0x30180002,
+	0x501a007d, 0xf0ff0640, 0x10e10780, 0x5c591724,
+	0x1281ea02, 0xea0105a9, 0x80001625, 0x00c0de02,
+	0x301d15e5, 0xffbe0086, 0xe00ac642, 0x0de2e1e0,
+	0xff80301c, 0x373c0030, 0xe73b0001, 0x063f0001,
+	0x0002168e, 0x5261007c, 0xea410db2, 0x5c591724,
+	0x12815202, 0x520105a9, 0xe5c7e9ea, 0x06405200,
+	0x1a5c10ff, 0x00011726, 0x0001062a, 0x17630012,
+	0x12cb0001, 0x114a128b, 0x00125640, 0x0dea11ea,
+	0x17461202, 0x00000002, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x1a440000, 0xf624007f,
+	0x03800d24, 0x00dc1620, 0x12021381, 0x03831382,
+	0x0d290764, 0x12011388, 0x007f1389, 0x00e10780,
+	0x09e1ef84, 0x09e1e7a4, 0x1267101d, 0x0042259b,
+	0x000b0008, 0x0011000e, 0x00170014, 0x001d001a,
+	0x006eff80, 0xff8015d5, 0x15a501c2, 0xd03cffbe,
+	0xffbe0df5, 0x0dc5d088, 0xd0f8ffbe, 0xff800d95,
+	0x05e501f8, 0xd1f6ffbe, 0xffbe05b5, 0x3f84d2f4,
+	0x39fd09e1, 0x06220d92, 0xaaaa6600, 0x36203902,
+	0xffbe0020, 0x3fa401d2, 0x39fc09e1, 0x06220d92,
+	0xaaaa7700, 0x36203902, 0xffbe0040, 0x178401ba,
+	0x11e009e1, 0xff8005b2, 0x0640066c, 0x078000ff,
+	0x17a40021, 0x126109e1, 0x05f205d1, 0x0d821263,
+	0xff800d95, 0x05e5002c, 0x0056ff80, 0xffbe05b5,
+	0xffbecdd4, 0x5784d2a8, 0x17a409e1, 0x51e209e3,
+	0xf62405d2, 0x13a409bc, 0x064003a5, 0x0780003f,
+	0xffbe0061, 0x1724cc88, 0x12815c59, 0xef250df1,
+	0x063f8625, 0x000217f4, 0x007d3201, 0x8625ef25,
+	0x1802063f, 0x300a0002, 0x0640007d, 0x0788007f,
+	0x17240061, 0x12815c59, 0x17246de1, 0x5640c0a1,
+	0x114a8000, 0x17240d9a, 0x129cd621, 0x962405d1,
+	0x1fd2d623, 0x17240000, 0x5640c0a1, 0x114a8000,
+	0x12035da2, 0xc000f624, 0x15501531, 0x55b2114a,
+	0x8625ef25, 0x1856063f, 0x32010002, 0x1724007d,
+	0x128efb75, 0x178415c9, 0x06025c61, 0xfdc2ffdf,
+	0x5c611784, 0xffde0602, 0x172405ea, 0x06c2fb9d,
+	0xf5fa000c, 0xfb759624, 0x0000afd2, 0xc0648fc4,
+	0xd6239624, 0x00009fd2, 0x0dd11784, 0x05fa1262,
+	0x3a013200, 0x4a024200, 0x3224ffbe, 0x17441202,
+	0x172409e1, 0x1282c061, 0x074405c9, 0x1db509e1,
+	0xc000f624, 0x35583d5a, 0xffbd4210, 0x1624fdf4,
+	0xf00308fc, 0x16201501, 0x150300c0, 0x20001620,
+	0x17251505, 0x362481ad, 0x400a09bc, 0x1507480b,
+	0xfad6ffbd, 0x007f0648, 0x00210780, 0x09e117a4,
+	0x05e211e0, 0x05f21264, 0x0d821265, 0xffbe0d95,
+	0x05e5ccac, 0xccf2ffbe, 0xffbe05b5, 0xffbecd76,
+	0x5784d14c, 0x17a409e1, 0x51e209e3, 0x12640db2,
+	0x9e2405da, 0x07d3c049, 0xf6240000, 0x13a409bc,
+	0x064003a5, 0x0780003f, 0xffbe0061, 0x1784cf60,
+	0x126609e1, 0xef250dda, 0x063f824d, 0x0002195a,
+	0xef25007d, 0x063f8251, 0x00021966, 0x0640007d,
+	0x0780007f, 0xffbe0021, 0x1784d2a0, 0x12610a15,
+	0x05d20de1, 0x05e11263, 0x0d950d82, 0xd30cffbe,
+	0xffbe05e5, 0x05b5d3da, 0xd4b4ffbe, 0x003f0640,
+	0x00210780, 0x0a0d1724, 0x00ff062b, 0x5200ffff,
+	0x1262114b, 0x96400da2, 0x11f20030, 0x96400d92,
+	0x11f20031, 0x0d950d82, 0xd518ffbe, 0xffbe05e5,
+	0x05b5d5f8, 0xd60effbe, 0x003f0640, 0x00210780,
+	0x0a0d1724, 0x5ec25200, 0x060b00ff, 0x15eaff80,
+	0x12611298, 0x05f215b1, 0x0d811263, 0x126f0da2,
+	0x0dc50db2, 0xd63cffbe, 0xffbe0d95, 0x05e5d64c,
+	0xd65cffbe, 0xffbe05b5, 0x0640d662, 0x17a4003f,
+	0x12610a0f, 0x05f21581, 0x05f11263, 0x126f0d82,
+	0x0d950d82, 0xd65a07be, 0xd68007be, 0xd6a607be,
+	0xd6c007be, 0x0780007f, 0x17840021, 0x52000a0d,
+	0xff800602, 0x05e20df9, 0xff7e0602, 0x0d8205e9,
+	0xffbe0d95, 0x05e5d6f6, 0xd706ffbe, 0xffbe05b5,
+	0x0640d720, 0x1784003f, 0x06020a0d, 0x05baff80,
+	0xd74607be, 0xff7f0602, 0x07be05ba, 0x07bed768,
+	0x0780d76e, 0x17240021, 0x062b0a0d, 0xffff00ff,
+	0x114b5200, 0x0da21262, 0x00309640, 0x0d9211f2,
+	0x00319640, 0x0d8211f2, 0xffbe0d95, 0x05e5d822,
+	0xd8d4ffbe, 0xffbe05b5, 0x0640d8ec, 0x1784003f,
+	0x520109e1, 0x05ba1266, 0xd91a07be, 0x1784007f,
+	0x520109e1, 0x05ba1266, 0xd98007be, 0x0780007f,
+	0xee240061, 0x301dc500, 0xd9d6ffbe, 0x0009361d,
+	0xd9e8ffbe, 0x0012361d, 0xffbe3a00, 0x361dda00,
+	0x3a000019, 0xda2cffbe, 0x001f361d, 0xffbe3a01,
+	0x361dd9ec, 0x3a010026, 0xda18ffbe, 0x007f0640,
+	0x00610780, 0xc500ee24, 0xffbe301d, 0x361dda12,
+	0xffbe0005, 0x0640da1a, 0x0780007f, 0x170400e1,
+	0x16c2097c, 0x12610007, 0x126305b2, 0xffbe05ba,
+	0x1724db90, 0x1285c0a1, 0x063c2dd1, 0xaaaa8800,
+	0x0b71efa4, 0x0b700744, 0x0d91ea61, 0xea630db2,
+	0xea650dc2, 0xea660dd2, 0x0df50de2, 0xdce8ffbe,
+	0xffbe0dc5, 0x0d95dd3a, 0xdddcffbe, 0xffbe05e5,
+	0x05b5de32, 0x00a6ff80, 0x0b713fa4, 0x05e239fd,
+	0x3620391c, 0xffbd0080, 0x1784fd8e, 0x11e00b71,
+	0x0640dd8a, 0x078000ff, 0x170400e1, 0x16c2093c,
+	0x12610007, 0x126305b2, 0xffbe05ba, 0xffbedbb8,
+	0x51e0eba0, 0x17243592, 0x1285c0a1, 0x063c2dd1,
+	0xaaaacc00, 0x0c57efa4, 0x0c560744, 0x0d91ea61,
+	0xea630db2, 0xea650dc2, 0xea660dd2, 0x0df50de2,
+	0xe2dcffbe, 0xffbe0dc5, 0x0d95e32e, 0xe3e8ffbe,
+	0xffbe05e5, 0x05b5e47c, 0x00feff80, 0x0c573fa4,
+	0x05e239fd, 0x3620391c, 0xffbd0400, 0x1784fd0a,
+	0x11e00c57, 0x0640dd8a, 0x078000ff, 0xef840061,
+	0x101d0b73, 0x359b126b, 0x000c0042, 0x0012000f,
+	0x00180015, 0x001e001b, 0x00240021, 0x002a0027,
+	0xffbe002d, 0x2595dd88, 0x005cff80, 0xffbe1de5,
+	0x1db5de12, 0xde3effbe, 0xffbe1d85, 0x15d5de94,
+	0xde9cffbe, 0xffbe15a5, 0x0df5dea4, 0xdf38ffbe,
+	0xffbe0dc5, 0x0d95dfaa, 0xdfe0ffbe, 0xffbe05e5,
+	0x05b5dff6, 0xe054ffbe, 0x0b733f84, 0x0d9239fd,
+	0x99000622, 0x3902aaaa, 0x01003620, 0xfc78ffbd,
+	0x007f0640, 0x00610780, 0x0b73efa4, 0x0d81ea61,
+	0xea630da2, 0x0dd20db1, 0x0de2ea65, 0xffbe0df5,
+	0x0dc5e036, 0xe05cffbe, 0xffbe0d95, 0x05e5e098,
+	0xe0e8ffbe, 0xffbe05b5, 0x3fa4e198, 0x39fd0b73,
+	0x06220d92, 0xaaaabb00, 0x36203902, 0xffbd0200,
+	0x0640fc26, 0x0780007f, 0xef840061, 0x101d0c59,
+	0x359b126b, 0x000c0042, 0x0012000f, 0x00180015,
+	0x001e001b, 0x00240021, 0x002a0027, 0xffbe002d,
+	0x2595e3c8, 0x005cff80, 0xffbe1de5, 0x1db5e41c,
+	0xe47affbe, 0xffbe1d85, 0x15d5e4e0, 0xe508ffbe,
+	0xffbe15a5, 0x0df5e530, 0xe544ffbe, 0xffbe0dc5,
+	0x0d95e61e, 0xe680ffbe, 0xffbe05e5, 0x05b5e696,
+	0xe728ffbe, 0x0c593f84, 0x0d9239fd, 0xdd000622,
+	0x3902aaaa, 0x08003620, 0xfb9cffbd, 0x007f0640,
+	0x00610780, 0x0c59efa4, 0x0d81ea61, 0xea630dd2,
+	0x05f20de1, 0x0de2ea65, 0xffbe0df5, 0x0dc5e70a,
+	0xe734ffbe, 0xffbe0d95, 0x05e5e840, 0xe890ffbe,
+	0xffbe05b5, 0x3fa4e8c4, 0x39fd0c59, 0x06220d92,
+	0xaaaaee00, 0x36203902, 0xffbd1000, 0x0640fb4a,
+	0x0780007f, 0x17240061, 0x1286c061, 0x16200d99,
+	0x17640020, 0x3202c061, 0xffbe3a00, 0xefa4ef1c,
+	0x07440cd5, 0xea610cd9, 0x0db20d91, 0x15c1ea63,
+	0xea650db2, 0x0de20dc1, 0xffbe0df5, 0x0dc5eb38,
+	0xeb5effbe, 0xffbe0d95, 0x05e5ebe6, 0xec4affbe,
+	0xffbe05b5, 0x3fa4ecc8, 0x39fd0cd5, 0x06220d92,
+	0xaaaaff00, 0x36203902, 0xffbd2000, 0x17a4fada,
+	0x11e00cd9, 0x0640d5da, 0x0000007f, 0x000200de,
+	0x0000102c, 0x00001064, 0x0000109e, 0x0000111c,
+	0x0000115a, 0x00020142, 0x00020154, 0x000011a6,
+	0x000011ee, 0x000012a6, 0x00001250, 0x000012f4,
+	0x00001376, 0x0000ccc8, 0x0000ccfc, 0x0000cd72,
+	0x0000cda8, 0x0000ce0a, 0x0000cecc, 0x000215d0,
+	0x0000cfc4, 0x0000d018, 0x0000d062, 0x00021650,
+	0x0000d12e, 0x0000d1a8, 0x0000d204, 0x0000d274,
+	0x0000d2d0, 0x0000d334, 0x0000d3fe, 0x0000d462,
+	0x0000d4e8, 0x0000d54a, 0x0000d5d0, 0x0000d632,
+	0x0000d67a, 0x0000d6e2, 0x0000d73a, 0x0000d7b4,
+	0x0000d84c, 0x0000d8c4, 0x0000d916, 0x0000d968,
+	0x0000d9e4, 0x0000da36, 0x0000dab2, 0x0000db04,
+	0x0000db5a, 0x0000db84, 0x0000dba4, 0x0000dbd8,
+	0x0000dc22, 0x0000dc50, 0x0000dc90, 0x0000dcc6,
+	0x0000dd14, 0x0000dd62, 0x0000dd86, 0x0000dda2,
+	0x0000ddba, 0x0000ddce, 0x0000dde2, 0x0000ddf8,
+	0x0000de12, 0x0000de28, 0x0000de3e, 0x0000de84,
+	0x0000defe, 0x0000dfb2, 0x0000dfe6, 0x0000e01a,
+	0x0000e050, 0x0000e086, 0x0000e0bc, 0x0000e0f2,
+	0x0000e150, 0x0000e19c, 0x0000e1d0, 0x0000e212,
+	0x0000e304, 0x0000e27a, 0x0000e318, 0x0000e3a4,
+	0x0000e42a, 0x0000c608, 0x0000c6d8, 0x0000c74e,
+	0x0000c76a, 0x0000c786, 0x0000c7d6, 0x0000c866,
+	0x0000c930, 0x0000c960, 0x0000c98e, 0x0000c9c8,
+	0x0000c9de, 0x0000c9fc, 0x0000ca28, 0x0000ca6c,
+	0x0000ca90, 0x0000caa2, 0x0000cae4, 0x0000cb88,
+	0x0000cc30, 0x0000cc52, 0x0000e578, 0x0000ea76,
+	0x0000eae6, 0x0000eb6a, 0x0002196a, 0x00021998,
+	0x0000eff6, 0x0000f018, 0x000219d4, 0x00021a16,
+	0x0000f11e, 0x0000f146, 0x00021a3e, 0x00021a6e,
+	0x0000f23e, 0x0000f268, 0x0000f29e, 0x00021a8a,
+	0x0000f3c8, 0x0000f3e8, 0x00021ac6, 0x00021ad6,
+	0x0000f48a, 0x00021ae6, 0x00021b28, 0x0000f57e,
+	0x0000f60c, 0x0000f660, 0x0000f68a, 0x0000f6a2,
+	0x0000f6b2, 0x0000f6dc, 0x00021b42, 0x00021bbe,
+	0x0000f940, 0x0000f9b6, 0x0000fe5e, 0x0000ffbc,
+	0x00010084, 0x000105e0, 0x000106ee, 0x00010722,
+	0x00010762, 0x0001078a, 0x000107f8, 0x0001085c,
+	0x0001089e, 0x000109e8, 0x00010be0, 0x00010c84,
+	0x00010cf4, 0x00010d82, 0x00010da0, 0x00010e0e,
+	0x00010e60, 0x00010eb4, 0x00010f18, 0x00010f66,
+	0x00010f6e, 0x00010f76, 0x00010fb6, 0x00010fd4,
+	0x00001ed6, 0x00002164, 0x000022bc, 0x000023ec,
+	0x00002328, 0x00002530, 0x00000000, 0x000025d4,
+	0x0000274c, 0x000208ea, 0x000034b4, 0x000035ca,
+	0x000036ae, 0x0000372e, 0x0000382e, 0x0000385e,
+	0x00003910, 0x00003960, 0x0000398e, 0x000039fc,
+	0x00003a68, 0x00003a98, 0x00003ace, 0x00003b0e,
+	0x00003b2e, 0x00003b60, 0x00003b6a, 0x000208fe,
+	0x00003bb4, 0x00003cba, 0x00003d48, 0x00003dd4,
+	0x00003e80, 0x00003f26, 0x0002091a, 0x00004030,
+	0x0000408a, 0x00004116, 0x00004144, 0x000041e4,
+	0x00004328, 0x00004416, 0x0000450a, 0x00004572,
+	0x000045a8, 0x000045fc, 0x00004650, 0x0000468c,
+	0x000046de, 0x00004790, 0x0000488c, 0x00004a8c,
+	0x000048ac, 0x00004ab0, 0x00000000, 0x00000000,
+	0x00000000, 0x00004c18, 0x00004ae0, 0x000022f2,
+	0x00004e64, 0x00006e08, 0x00006c0e, 0x00007a08,
+	0x00007a48, 0x00007aba, 0x00007ada, 0x00007af8,
+	0x00007b82, 0x00007bd2, 0x00007c40, 0x00007cae,
+	0x000211b6, 0x00021206, 0x00021274, 0x00008484,
+	0x0000851c, 0x0000857a, 0x000085ca, 0x0000865e,
+	0x00008758, 0x000087ec, 0x000088a2, 0x00008948,
+	0x00008a54, 0x00008ac8, 0x00008b58, 0x00008bdc,
+	0x00008bf2, 0x00008c4c, 0x00008cb4, 0x00008d5e,
+	0x00008de6, 0x00008e6c, 0x00008f34, 0x00008f5e,
+	0x00008ff4, 0x00009046, 0x000090da, 0x0000911c,
+	0x00009146, 0x0000918e, 0x000091ae, 0x000091fa,
+	0x000092e4, 0x000093a0, 0x000093e2, 0x00009424,
+	0x00009458, 0x00009488, 0x000094ca, 0x0000950c,
+	0x00009540, 0x00009586, 0x000096ac, 0x000097f6,
+	0x000212c0, 0x00009bb2, 0x00009bde, 0x00009c12,
+	0x00021362, 0x00009daa, 0x00009e20, 0x00009e7a,
+	0x00009eb4, 0x00009f1a, 0x00009f7e, 0x00009fd6,
+	0x0000a00a, 0x0002138c, 0x0000a0cc, 0x0000a110,
+	0x0000a156, 0x0000a192, 0x0000a1e2, 0x0000a28e,
+	0x0000a3ec, 0x0000a4ac, 0x0000a4d6, 0x0000a52a,
+	0x0000a62c, 0x0000a662, 0x0000a77c, 0x0000a7be,
+	0x0000a7e4, 0x0000a820, 0x0000a87a, 0x0000a914,
+	0x0000a972, 0x0000aa32, 0x0000aaa2, 0x0000abf8,
+	0x0000ad28, 0x0000ad48, 0x0000adb0, 0x0000ae52,
+	0x0000ae8c, 0x0000af88, 0x0000b002, 0x0000b0ae,
+	0x0000b1aa, 0x0000b2f0, 0x0000b3b0, 0x0000b442,
+	0x0000b470, 0x0000b51a, 0x0000b550, 0x0000b578,
+	0x0000b59a, 0x0000b5cc, 0x0000b5f6, 0x0000b648,
+	0x0000b78e, 0x0000b7e6, 0x0000b894, 0x000214e8,
+	0x0000bb76, 0x0000bce2, 0x0000bd04, 0x0000bd94,
+	0x0000be98, 0x0000bfb0, 0x0000bfb2, 0x0000bff2,
+	0x0000c060, 0x0000c0d8, 0x0000c158, 0x0000c1c6,
+	0x0000c30e, 0x000215a8, 0x0000c388, 0x0000c4d0,
+	0x0000c50e, 0x0000c548, 0x0000c588, 0x0000c5c8,
+	0x000013e4, 0x00001436, 0x0000147e, 0x000014a6,
+	0x000014de, 0x000014f2, 0x00001546, 0x000015c4,
+	0x000015ea, 0x0000164c, 0x00001660, 0x0000168e,
+	0x000016ca, 0x000016f0, 0x0000171e, 0x0000175e,
+	0x00001798, 0x000017be, 0x000017e4, 0x0000183a,
+	0x0000186a, 0x000018cc, 0x0000193a, 0x0002017e,
+	0x00001966, 0x0000198e, 0x0000a1ca, 0x0000c2b4,
+	0x000201bc, 0x0000cc74, 0x00011014, 0x00011076,
+	0x000032dc, 0x000079cf
+};
+
+#endif /* __FIRMWARE_R8A779X_USB3_V3__ */
diff --git a/roms/u-boot/drivers/usb/host/xhci-rcar.c b/roms/u-boot/drivers/usb/host/xhci-rcar.c
new file mode 100644
index 000000000..5fc7afb7d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-rcar.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Renesas RCar USB HOST xHCI Controller
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <usb.h>
+#include <wait_bit.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+
+#include <usb/xhci.h>
+#include "xhci-rcar-r8a779x_usb3_v3.h"
+
+/* Register Offset */
+#define RCAR_USB3_DL_CTRL	0x250	/* FW Download Control & Status */
+#define RCAR_USB3_FW_DATA0	0x258	/* FW Data0 */
+
+/* Register Settings */
+/* FW Download Control & Status */
+#define RCAR_USB3_DL_CTRL_ENABLE	BIT(0)
+#define RCAR_USB3_DL_CTRL_FW_SUCCESS	BIT(4)
+#define RCAR_USB3_DL_CTRL_FW_SET_DATA0	BIT(8)
+
+struct rcar_xhci_plat {
+	fdt_addr_t	hcd_base;
+	struct clk	clk;
+};
+
+/**
+ * Contains pointers to register base addresses
+ * for the usb controller.
+ */
+struct rcar_xhci {
+	struct xhci_ctrl ctrl;	/* Needs to come first in this struct! */
+	struct usb_plat usb_plat;
+	struct xhci_hccr *hcd;
+};
+
+static int xhci_rcar_download_fw(struct rcar_xhci *ctx, const u32 *fw_data,
+				 const size_t fw_array_size)
+{
+	void __iomem *regs = (void __iomem *)ctx->hcd;
+	int i, ret;
+
+	/* Download R-Car USB3.0 firmware */
+	setbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE);
+
+	for (i = 0; i < fw_array_size; i++) {
+		writel(fw_data[i], regs + RCAR_USB3_FW_DATA0);
+		setbits_le32(regs + RCAR_USB3_DL_CTRL,
+			     RCAR_USB3_DL_CTRL_FW_SET_DATA0);
+
+		ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL,
+					RCAR_USB3_DL_CTRL_FW_SET_DATA0, false,
+					10, false);
+		if (ret)
+			break;
+	}
+
+	clrbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE);
+
+	ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL,
+				RCAR_USB3_DL_CTRL_FW_SUCCESS, true,
+				10, false);
+
+	return ret;
+}
+
+static int xhci_rcar_probe(struct udevice *dev)
+{
+	struct rcar_xhci_plat *plat = dev_get_plat(dev);
+	struct rcar_xhci *ctx = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int len, ret;
+
+	ret = clk_get_by_index(dev, 0, &plat->clk);
+	if (ret < 0) {
+		dev_err(dev, "Failed to get USB3 clock\n");
+		return ret;
+	}
+
+	ret = clk_enable(&plat->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable USB3 clock\n");
+		goto err_clk;
+	}
+
+	ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
+	len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
+	hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
+
+	ret = xhci_rcar_download_fw(ctx, firmware_r8a779x_usb3_v3,
+				    ARRAY_SIZE(firmware_r8a779x_usb3_v3));
+	if (ret) {
+		dev_err(dev, "Failed to download firmware\n");
+		goto err_fw;
+	}
+
+	ret = xhci_register(dev, ctx->hcd, hcor);
+	if (ret) {
+		dev_err(dev, "Failed to register xHCI\n");
+		goto err_fw;
+	}
+
+	return 0;
+
+err_fw:
+	clk_disable(&plat->clk);
+err_clk:
+	clk_free(&plat->clk);
+	return ret;
+}
+
+static int xhci_rcar_deregister(struct udevice *dev)
+{
+	int ret;
+	struct rcar_xhci_plat *plat = dev_get_plat(dev);
+
+	ret = xhci_deregister(dev);
+
+	clk_disable(&plat->clk);
+	clk_free(&plat->clk);
+
+	return ret;
+}
+
+static int xhci_rcar_of_to_plat(struct udevice *dev)
+{
+	struct rcar_xhci_plat *plat = dev_get_plat(dev);
+
+	plat->hcd_base = dev_read_addr(dev);
+	if (plat->hcd_base == FDT_ADDR_T_NONE) {
+		debug("Can't get the XHCI register base address\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id xhci_rcar_ids[] = {
+	{ .compatible = "renesas,rcar-gen3-xhci" },
+	{ .compatible = "renesas,xhci-r8a7795" },
+	{ .compatible = "renesas,xhci-r8a7796" },
+	{ .compatible = "renesas,xhci-r8a77965" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+	.name		= "xhci_rcar",
+	.id		= UCLASS_USB,
+	.probe		= xhci_rcar_probe,
+	.remove		= xhci_rcar_deregister,
+	.ops		= &xhci_usb_ops,
+	.of_match	= xhci_rcar_ids,
+	.of_to_plat = xhci_rcar_of_to_plat,
+	.plat_auto	= sizeof(struct rcar_xhci_plat),
+	.priv_auto	= sizeof(struct rcar_xhci),
+	.flags		= DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/roms/u-boot/drivers/usb/host/xhci-ring.c b/roms/u-boot/drivers/usb/host/xhci-ring.c
new file mode 100644
index 000000000..35bd5cd29
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci-ring.c
@@ -0,0 +1,955 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * USB HOST XHCI Controller stack
+ *
+ * Based on xHCI host controller driver in linux-kernel
+ * by Sarah Sharp.
+ *
+ * Copyright (C) 2008 Intel Corp.
+ * Author: Sarah Sharp
+ *
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors: Vivek Gautam <gautam.vivek@samsung.com>
+ *	    Vikas Sajjan <vikas.sajjan@samsung.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <asm/byteorder.h>
+#include <usb.h>
+#include <asm/unaligned.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+
+#include <usb/xhci.h>
+
+/**
+ * Is this TRB a link TRB or was the last TRB the last TRB in this event ring
+ * segment?  I.e. would the updated event TRB pointer step off the end of the
+ * event seg ?
+ *
+ * @param ctrl	Host controller data structure
+ * @param ring	pointer to the ring
+ * @param seg	poniter to the segment to which TRB belongs
+ * @param trb	poniter to the ring trb
+ * @return 1 if this TRB a link TRB else 0
+ */
+static int last_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
+			struct xhci_segment *seg, union xhci_trb *trb)
+{
+	if (ring == ctrl->event_ring)
+		return trb == &seg->trbs[TRBS_PER_SEGMENT];
+	else
+		return TRB_TYPE_LINK_LE32(trb->link.control);
+}
+
+/**
+ * Does this link TRB point to the first segment in a ring,
+ * or was the previous TRB the last TRB on the last segment in the ERST?
+ *
+ * @param ctrl	Host controller data structure
+ * @param ring	pointer to the ring
+ * @param seg	poniter to the segment to which TRB belongs
+ * @param trb	poniter to the ring trb
+ * @return 1 if this TRB is the last TRB on the last segment else 0
+ */
+static bool last_trb_on_last_seg(struct xhci_ctrl *ctrl,
+				 struct xhci_ring *ring,
+				 struct xhci_segment *seg,
+				 union xhci_trb *trb)
+{
+	if (ring == ctrl->event_ring)
+		return ((trb == &seg->trbs[TRBS_PER_SEGMENT]) &&
+			(seg->next == ring->first_seg));
+	else
+		return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
+}
+
+/**
+ * See Cycle bit rules. SW is the consumer for the event ring only.
+ * Don't make a ring full of link TRBs.  That would be dumb and this would loop.
+ *
+ * If we've just enqueued a TRB that is in the middle of a TD (meaning the
+ * chain bit is set), then set the chain bit in all the following link TRBs.
+ * If we've enqueued the last TRB in a TD, make sure the following link TRBs
+ * have their chain bit cleared (so that each Link TRB is a separate TD).
+ *
+ * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
+ * set, but other sections talk about dealing with the chain bit set.  This was
+ * fixed in the 0.96 specification errata, but we have to assume that all 0.95
+ * xHCI hardware can't handle the chain bit being cleared on a link TRB.
+ *
+ * @param ctrl	Host controller data structure
+ * @param ring	pointer to the ring
+ * @param more_trbs_coming	flag to indicate whether more trbs
+ *				are expected or NOT.
+ *				Will you enqueue more TRBs before calling
+ *				prepare_ring()?
+ * @return none
+ */
+static void inc_enq(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
+						bool more_trbs_coming)
+{
+	u32 chain;
+	union xhci_trb *next;
+
+	chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
+	next = ++(ring->enqueue);
+
+	/*
+	 * Update the dequeue pointer further if that was a link TRB or we're at
+	 * the end of an event ring segment (which doesn't have link TRBS)
+	 */
+	while (last_trb(ctrl, ring, ring->enq_seg, next)) {
+		if (ring != ctrl->event_ring) {
+			/*
+			 * If the caller doesn't plan on enqueueing more
+			 * TDs before ringing the doorbell, then we
+			 * don't want to give the link TRB to the
+			 * hardware just yet.  We'll give the link TRB
+			 * back in prepare_ring() just before we enqueue
+			 * the TD at the top of the ring.
+			 */
+			if (!chain && !more_trbs_coming)
+				break;
+
+			/*
+			 * If we're not dealing with 0.95 hardware or
+			 * isoc rings on AMD 0.96 host,
+			 * carry over the chain bit of the previous TRB
+			 * (which may mean the chain bit is cleared).
+			 */
+			next->link.control &= cpu_to_le32(~TRB_CHAIN);
+			next->link.control |= cpu_to_le32(chain);
+
+			next->link.control ^= cpu_to_le32(TRB_CYCLE);
+			xhci_flush_cache((uintptr_t)next,
+					 sizeof(union xhci_trb));
+		}
+		/* Toggle the cycle bit after the last ring segment. */
+		if (last_trb_on_last_seg(ctrl, ring,
+					ring->enq_seg, next))
+			ring->cycle_state = (ring->cycle_state ? 0 : 1);
+
+		ring->enq_seg = ring->enq_seg->next;
+		ring->enqueue = ring->enq_seg->trbs;
+		next = ring->enqueue;
+	}
+}
+
+/**
+ * See Cycle bit rules. SW is the consumer for the event ring only.
+ * Don't make a ring full of link TRBs.  That would be dumb and this would loop.
+ *
+ * @param ctrl	Host controller data structure
+ * @param ring	Ring whose Dequeue TRB pointer needs to be incremented.
+ * return none
+ */
+static void inc_deq(struct xhci_ctrl *ctrl, struct xhci_ring *ring)
+{
+	do {
+		/*
+		 * Update the dequeue pointer further if that was a link TRB or
+		 * we're at the end of an event ring segment (which doesn't have
+		 * link TRBS)
+		 */
+		if (last_trb(ctrl, ring, ring->deq_seg, ring->dequeue)) {
+			if (ring == ctrl->event_ring &&
+					last_trb_on_last_seg(ctrl, ring,
+						ring->deq_seg, ring->dequeue)) {
+				ring->cycle_state = (ring->cycle_state ? 0 : 1);
+			}
+			ring->deq_seg = ring->deq_seg->next;
+			ring->dequeue = ring->deq_seg->trbs;
+		} else {
+			ring->dequeue++;
+		}
+	} while (last_trb(ctrl, ring, ring->deq_seg, ring->dequeue));
+}
+
+/**
+ * Generic function for queueing a TRB on a ring.
+ * The caller must have checked to make sure there's room on the ring.
+ *
+ * @param	more_trbs_coming:   Will you enqueue more TRBs before calling
+ *				prepare_ring()?
+ * @param ctrl	Host controller data structure
+ * @param ring	pointer to the ring
+ * @param more_trbs_coming	flag to indicate whether more trbs
+ * @param trb_fields	pointer to trb field array containing TRB contents
+ * @return pointer to the enqueued trb
+ */
+static struct xhci_generic_trb *queue_trb(struct xhci_ctrl *ctrl,
+					  struct xhci_ring *ring,
+					  bool more_trbs_coming,
+					  unsigned int *trb_fields)
+{
+	struct xhci_generic_trb *trb;
+	int i;
+
+	trb = &ring->enqueue->generic;
+
+	for (i = 0; i < 4; i++)
+		trb->field[i] = cpu_to_le32(trb_fields[i]);
+
+	xhci_flush_cache((uintptr_t)trb, sizeof(struct xhci_generic_trb));
+
+	inc_enq(ctrl, ring, more_trbs_coming);
+
+	return trb;
+}
+
+/**
+ * Does various checks on the endpoint ring, and makes it ready
+ * to queue num_trbs.
+ *
+ * @param ctrl		Host controller data structure
+ * @param ep_ring	pointer to the EP Transfer Ring
+ * @param ep_state	State of the End Point
+ * @return error code in case of invalid ep_state, 0 on success
+ */
+static int prepare_ring(struct xhci_ctrl *ctrl, struct xhci_ring *ep_ring,
+							u32 ep_state)
+{
+	union xhci_trb *next = ep_ring->enqueue;
+
+	/* Make sure the endpoint has been added to xHC schedule */
+	switch (ep_state) {
+	case EP_STATE_DISABLED:
+		/*
+		 * USB core changed config/interfaces without notifying us,
+		 * or hardware is reporting the wrong state.
+		 */
+		puts("WARN urb submitted to disabled ep\n");
+		return -ENOENT;
+	case EP_STATE_ERROR:
+		puts("WARN waiting for error on ep to be cleared\n");
+		return -EINVAL;
+	case EP_STATE_HALTED:
+		puts("WARN halted endpoint, queueing URB anyway.\n");
+	case EP_STATE_STOPPED:
+	case EP_STATE_RUNNING:
+		debug("EP STATE RUNNING.\n");
+		break;
+	default:
+		puts("ERROR unknown endpoint state for ep\n");
+		return -EINVAL;
+	}
+
+	while (last_trb(ctrl, ep_ring, ep_ring->enq_seg, next)) {
+		/*
+		 * If we're not dealing with 0.95 hardware or isoc rings
+		 * on AMD 0.96 host, clear the chain bit.
+		 */
+		next->link.control &= cpu_to_le32(~TRB_CHAIN);
+
+		next->link.control ^= cpu_to_le32(TRB_CYCLE);
+
+		xhci_flush_cache((uintptr_t)next, sizeof(union xhci_trb));
+
+		/* Toggle the cycle bit after the last ring segment. */
+		if (last_trb_on_last_seg(ctrl, ep_ring,
+					ep_ring->enq_seg, next))
+			ep_ring->cycle_state = (ep_ring->cycle_state ? 0 : 1);
+		ep_ring->enq_seg = ep_ring->enq_seg->next;
+		ep_ring->enqueue = ep_ring->enq_seg->trbs;
+		next = ep_ring->enqueue;
+	}
+
+	return 0;
+}
+
+/**
+ * Generic function for queueing a command TRB on the command ring.
+ * Check to make sure there's room on the command ring for one command TRB.
+ *
+ * @param ctrl		Host controller data structure
+ * @param ptr		Pointer address to write in the first two fields (opt.)
+ * @param slot_id	Slot ID to encode in the flags field (opt.)
+ * @param ep_index	Endpoint index to encode in the flags field (opt.)
+ * @param cmd		Command type to enqueue
+ * @return none
+ */
+void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id,
+			u32 ep_index, trb_type cmd)
+{
+	u32 fields[4];
+	u64 val_64 = 0;
+
+	BUG_ON(prepare_ring(ctrl, ctrl->cmd_ring, EP_STATE_RUNNING));
+
+	if (ptr)
+		val_64 = xhci_virt_to_bus(ctrl, ptr);
+
+	fields[0] = lower_32_bits(val_64);
+	fields[1] = upper_32_bits(val_64);
+	fields[2] = 0;
+	fields[3] = TRB_TYPE(cmd) | SLOT_ID_FOR_TRB(slot_id) |
+		    ctrl->cmd_ring->cycle_state;
+
+	/*
+	 * Only 'reset endpoint', 'stop endpoint' and 'set TR dequeue pointer'
+	 * commands need endpoint id encoded.
+	 */
+	if (cmd >= TRB_RESET_EP && cmd <= TRB_SET_DEQ)
+		fields[3] |= EP_ID_FOR_TRB(ep_index);
+
+	queue_trb(ctrl, ctrl->cmd_ring, false, fields);
+
+	/* Ring the command ring doorbell */
+	xhci_writel(&ctrl->dba->doorbell[0], DB_VALUE_HOST);
+}
+
+/*
+ * For xHCI 1.0 host controllers, TD size is the number of max packet sized
+ * packets remaining in the TD (*not* including this TRB).
+ *
+ * Total TD packet count = total_packet_count =
+ *     DIV_ROUND_UP(TD size in bytes / wMaxPacketSize)
+ *
+ * Packets transferred up to and including this TRB = packets_transferred =
+ *     rounddown(total bytes transferred including this TRB / wMaxPacketSize)
+ *
+ * TD size = total_packet_count - packets_transferred
+ *
+ * For xHCI 0.96 and older, TD size field should be the remaining bytes
+ * including this TRB, right shifted by 10
+ *
+ * For all hosts it must fit in bits 21:17, so it can't be bigger than 31.
+ * This is taken care of in the TRB_TD_SIZE() macro
+ *
+ * The last TRB in a TD must have the TD size set to zero.
+ *
+ * @param ctrl	host controller data structure
+ * @param transferred	total size sent so far
+ * @param trb_buff_len	length of the TRB Buffer
+ * @param td_total_len	total packet count
+ * @param maxp	max packet size of current pipe
+ * @param more_trbs_coming	indicate last trb in TD
+ * @return remainder
+ */
+static u32 xhci_td_remainder(struct xhci_ctrl *ctrl, int transferred,
+			     int trb_buff_len, unsigned int td_total_len,
+			     int maxp, bool more_trbs_coming)
+{
+	u32 total_packet_count;
+
+	/* MTK xHCI 0.96 contains some features from 1.0 */
+	if (ctrl->hci_version < 0x100 && !(ctrl->quirks & XHCI_MTK_HOST))
+		return ((td_total_len - transferred) >> 10);
+
+	/* One TRB with a zero-length data packet. */
+	if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
+	    trb_buff_len == td_total_len)
+		return 0;
+
+	/* for MTK xHCI 0.96, TD size include this TRB, but not in 1.x */
+	if ((ctrl->quirks & XHCI_MTK_HOST) && (ctrl->hci_version < 0x100))
+		trb_buff_len = 0;
+
+	total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
+
+	/* Queueing functions don't count the current TRB into transferred */
+	return (total_packet_count - ((transferred + trb_buff_len) / maxp));
+}
+
+/**
+ * Ring the doorbell of the End Point
+ *
+ * @param udev		pointer to the USB device structure
+ * @param ep_index	index of the endpoint
+ * @param start_cycle	cycle flag of the first TRB
+ * @param start_trb	pionter to the first TRB
+ * @return none
+ */
+static void giveback_first_trb(struct usb_device *udev, int ep_index,
+				int start_cycle,
+				struct xhci_generic_trb *start_trb)
+{
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+
+	/*
+	 * Pass all the TRBs to the hardware at once and make sure this write
+	 * isn't reordered.
+	 */
+	if (start_cycle)
+		start_trb->field[3] |= cpu_to_le32(start_cycle);
+	else
+		start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
+
+	xhci_flush_cache((uintptr_t)start_trb, sizeof(struct xhci_generic_trb));
+
+	/* Ringing EP doorbell here */
+	xhci_writel(&ctrl->dba->doorbell[udev->slot_id],
+				DB_VALUE(ep_index, 0));
+
+	return;
+}
+
+/**** POLLING mechanism for XHCI ****/
+
+/**
+ * Finalizes a handled event TRB by advancing our dequeue pointer and giving
+ * the TRB back to the hardware for recycling. Must call this exactly once at
+ * the end of each event handler, and not touch the TRB again afterwards.
+ *
+ * @param ctrl	Host controller data structure
+ * @return none
+ */
+void xhci_acknowledge_event(struct xhci_ctrl *ctrl)
+{
+	/* Advance our dequeue pointer to the next event */
+	inc_deq(ctrl, ctrl->event_ring);
+
+	/* Inform the hardware */
+	xhci_writeq(&ctrl->ir_set->erst_dequeue,
+		    xhci_virt_to_bus(ctrl, ctrl->event_ring->dequeue) | ERST_EHB);
+}
+
+/**
+ * Checks if there is a new event to handle on the event ring.
+ *
+ * @param ctrl	Host controller data structure
+ * @return 0 if failure else 1 on success
+ */
+static int event_ready(struct xhci_ctrl *ctrl)
+{
+	union xhci_trb *event;
+
+	xhci_inval_cache((uintptr_t)ctrl->event_ring->dequeue,
+			 sizeof(union xhci_trb));
+
+	event = ctrl->event_ring->dequeue;
+
+	/* Does the HC or OS own the TRB? */
+	if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
+		ctrl->event_ring->cycle_state)
+		return 0;
+
+	return 1;
+}
+
+/**
+ * Waits for a specific type of event and returns it. Discards unexpected
+ * events. Caller *must* call xhci_acknowledge_event() after it is finished
+ * processing the event, and must not access the returned pointer afterwards.
+ *
+ * @param ctrl		Host controller data structure
+ * @param expected	TRB type expected from Event TRB
+ * @return pointer to event trb
+ */
+union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
+{
+	trb_type type;
+	unsigned long ts = get_timer(0);
+
+	do {
+		union xhci_trb *event = ctrl->event_ring->dequeue;
+
+		if (!event_ready(ctrl))
+			continue;
+
+		type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
+		if (type == expected)
+			return event;
+
+		if (type == TRB_PORT_STATUS)
+		/* TODO: remove this once enumeration has been reworked */
+			/*
+			 * Port status change events always have a
+			 * successful completion code
+			 */
+			BUG_ON(GET_COMP_CODE(
+				le32_to_cpu(event->generic.field[2])) !=
+								COMP_SUCCESS);
+		else
+			printf("Unexpected XHCI event TRB, skipping... "
+				"(%08x %08x %08x %08x)\n",
+				le32_to_cpu(event->generic.field[0]),
+				le32_to_cpu(event->generic.field[1]),
+				le32_to_cpu(event->generic.field[2]),
+				le32_to_cpu(event->generic.field[3]));
+
+		xhci_acknowledge_event(ctrl);
+	} while (get_timer(ts) < XHCI_TIMEOUT);
+
+	if (expected == TRB_TRANSFER)
+		return NULL;
+
+	printf("XHCI timeout on event type %d... cannot recover.\n", expected);
+	BUG();
+}
+
+/*
+ * Stops transfer processing for an endpoint and throws away all unprocessed
+ * TRBs by setting the xHC's dequeue pointer to our enqueue pointer. The next
+ * xhci_bulk_tx/xhci_ctrl_tx on this enpoint will add new transfers there and
+ * ring the doorbell, causing this endpoint to start working again.
+ * (Careful: This will BUG() when there was no transfer in progress. Shouldn't
+ * happen in practice for current uses and is too complicated to fix right now.)
+ */
+static void abort_td(struct usb_device *udev, int ep_index)
+{
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	struct xhci_ring *ring =  ctrl->devs[udev->slot_id]->eps[ep_index].ring;
+	union xhci_trb *event;
+	u32 field;
+
+	xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_STOP_RING);
+
+	event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+	field = le32_to_cpu(event->trans_event.flags);
+	BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
+	BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+	BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
+		!= COMP_STOP)));
+	xhci_acknowledge_event(ctrl);
+
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+		!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
+		event->event_cmd.status)) != COMP_SUCCESS);
+	xhci_acknowledge_event(ctrl);
+
+	xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
+		ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+		!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
+		event->event_cmd.status)) != COMP_SUCCESS);
+	xhci_acknowledge_event(ctrl);
+}
+
+static void record_transfer_result(struct usb_device *udev,
+				   union xhci_trb *event, int length)
+{
+	udev->act_len = min(length, length -
+		(int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len)));
+
+	switch (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))) {
+	case COMP_SUCCESS:
+		BUG_ON(udev->act_len != length);
+		/* fallthrough */
+	case COMP_SHORT_TX:
+		udev->status = 0;
+		break;
+	case COMP_STALL:
+		udev->status = USB_ST_STALLED;
+		break;
+	case COMP_DB_ERR:
+	case COMP_TRB_ERR:
+		udev->status = USB_ST_BUF_ERR;
+		break;
+	case COMP_BABBLE:
+		udev->status = USB_ST_BABBLE_DET;
+		break;
+	default:
+		udev->status = 0x80;  /* USB_ST_TOO_LAZY_TO_MAKE_A_NEW_MACRO */
+	}
+}
+
+/**** Bulk and Control transfer methods ****/
+/**
+ * Queues up the BULK Request
+ *
+ * @param udev		pointer to the USB device structure
+ * @param pipe		contains the DIR_IN or OUT , devnum
+ * @param length	length of the buffer
+ * @param buffer	buffer to be read/written based on the request
+ * @return returns 0 if successful else -1 on failure
+ */
+int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
+			int length, void *buffer)
+{
+	int num_trbs = 0;
+	struct xhci_generic_trb *start_trb;
+	bool first_trb = false;
+	int start_cycle;
+	u32 field = 0;
+	u32 length_field = 0;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	int slot_id = udev->slot_id;
+	int ep_index;
+	struct xhci_virt_device *virt_dev;
+	struct xhci_ep_ctx *ep_ctx;
+	struct xhci_ring *ring;		/* EP transfer ring */
+	union xhci_trb *event;
+
+	int running_total, trb_buff_len;
+	bool more_trbs_coming = true;
+	int maxpacketsize;
+	u64 addr;
+	int ret;
+	u32 trb_fields[4];
+	u64 val_64 = xhci_virt_to_bus(ctrl, buffer);
+	void *last_transfer_trb_addr;
+	int available_length;
+
+	debug("dev=%p, pipe=%lx, buffer=%p, length=%d\n",
+		udev, pipe, buffer, length);
+
+	available_length = length;
+	ep_index = usb_pipe_ep_index(pipe);
+	virt_dev = ctrl->devs[slot_id];
+
+	xhci_inval_cache((uintptr_t)virt_dev->out_ctx->bytes,
+			 virt_dev->out_ctx->size);
+
+	ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
+
+	ring = virt_dev->eps[ep_index].ring;
+	/*
+	 * How much data is (potentially) left before the 64KB boundary?
+	 * XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec)
+	 * that the buffer should not span 64KB boundary. if so
+	 * we send request in more than 1 TRB by chaining them.
+	 */
+	running_total = TRB_MAX_BUFF_SIZE -
+			(lower_32_bits(val_64) & (TRB_MAX_BUFF_SIZE - 1));
+	trb_buff_len = running_total;
+	running_total &= TRB_MAX_BUFF_SIZE - 1;
+
+	/*
+	 * If there's some data on this 64KB chunk, or we have to send a
+	 * zero-length transfer, we need at least one TRB
+	 */
+	if (running_total != 0 || length == 0)
+		num_trbs++;
+
+	/* How many more 64KB chunks to transfer, how many more TRBs? */
+	while (running_total < length) {
+		num_trbs++;
+		running_total += TRB_MAX_BUFF_SIZE;
+	}
+
+	/*
+	 * XXX: Calling routine prepare_ring() called in place of
+	 * prepare_trasfer() as there in 'Linux' since we are not
+	 * maintaining multiple TDs/transfer at the same time.
+	 */
+	ret = prepare_ring(ctrl, ring,
+			   le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Don't give the first TRB to the hardware (by toggling the cycle bit)
+	 * until we've finished creating all the other TRBs.  The ring's cycle
+	 * state may change as we enqueue the other TRBs, so save it too.
+	 */
+	start_trb = &ring->enqueue->generic;
+	start_cycle = ring->cycle_state;
+
+	running_total = 0;
+	maxpacketsize = usb_maxpacket(udev, pipe);
+
+	/* How much data is in the first TRB? */
+	/*
+	 * How much data is (potentially) left before the 64KB boundary?
+	 * XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec)
+	 * that the buffer should not span 64KB boundary. if so
+	 * we send request in more than 1 TRB by chaining them.
+	 */
+	addr = val_64;
+
+	if (trb_buff_len > length)
+		trb_buff_len = length;
+
+	first_trb = true;
+
+	/* flush the buffer before use */
+	xhci_flush_cache((uintptr_t)buffer, length);
+
+	/* Queue the first TRB, even if it's zero-length */
+	do {
+		u32 remainder = 0;
+		field = 0;
+		/* Don't change the cycle bit of the first TRB until later */
+		if (first_trb) {
+			first_trb = false;
+			if (start_cycle == 0)
+				field |= TRB_CYCLE;
+		} else {
+			field |= ring->cycle_state;
+		}
+
+		/*
+		 * Chain all the TRBs together; clear the chain bit in the last
+		 * TRB to indicate it's the last TRB in the chain.
+		 */
+		if (num_trbs > 1) {
+			field |= TRB_CHAIN;
+		} else {
+			field |= TRB_IOC;
+			more_trbs_coming = false;
+		}
+
+		/* Only set interrupt on short packet for IN endpoints */
+		if (usb_pipein(pipe))
+			field |= TRB_ISP;
+
+		/* Set the TRB length, TD size, and interrupter fields. */
+		remainder = xhci_td_remainder(ctrl, running_total, trb_buff_len,
+					      length, maxpacketsize,
+					      more_trbs_coming);
+
+		length_field = (TRB_LEN(trb_buff_len) |
+				TRB_TD_SIZE(remainder) |
+				TRB_INTR_TARGET(0));
+
+		trb_fields[0] = lower_32_bits(addr);
+		trb_fields[1] = upper_32_bits(addr);
+		trb_fields[2] = length_field;
+		trb_fields[3] = field | TRB_TYPE(TRB_NORMAL);
+
+		last_transfer_trb_addr = queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
+
+		--num_trbs;
+
+		running_total += trb_buff_len;
+
+		/* Calculate length for next transfer */
+		addr += trb_buff_len;
+		trb_buff_len = min((length - running_total), TRB_MAX_BUFF_SIZE);
+	} while (running_total < length);
+
+	giveback_first_trb(udev, ep_index, start_cycle, start_trb);
+
+again:
+	event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+	if (!event) {
+		debug("XHCI bulk transfer timed out, aborting...\n");
+		abort_td(udev, ep_index);
+		udev->status = USB_ST_NAK_REC;  /* closest thing to a timeout */
+		udev->act_len = 0;
+		return -ETIMEDOUT;
+	}
+
+	if ((uintptr_t)(le64_to_cpu(event->trans_event.buffer)) !=
+	    (uintptr_t)xhci_virt_to_bus(ctrl, last_transfer_trb_addr)) {
+		available_length -=
+			(int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len));
+		xhci_acknowledge_event(ctrl);
+		goto again;
+	}
+
+	field = le32_to_cpu(event->trans_event.flags);
+	BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
+	BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+
+	record_transfer_result(udev, event, available_length);
+	xhci_acknowledge_event(ctrl);
+	xhci_inval_cache((uintptr_t)buffer, length);
+
+	return (udev->status != USB_ST_NOT_PROC) ? 0 : -1;
+}
+
+/**
+ * Queues up the Control Transfer Request
+ *
+ * @param udev	pointer to the USB device structure
+ * @param pipe		contains the DIR_IN or OUT , devnum
+ * @param req		request type
+ * @param length	length of the buffer
+ * @param buffer	buffer to be read/written based on the request
+ * @return returns 0 if successful else error code on failure
+ */
+int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
+			struct devrequest *req,	int length,
+			void *buffer)
+{
+	int ret;
+	int start_cycle;
+	int num_trbs;
+	u32 field;
+	u32 length_field;
+	u64 buf_64 = 0;
+	struct xhci_generic_trb *start_trb;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	int slot_id = udev->slot_id;
+	int ep_index;
+	u32 trb_fields[4];
+	struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
+	struct xhci_ring *ep_ring;
+	union xhci_trb *event;
+	u32 remainder;
+
+	debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
+		req->request, req->request,
+		req->requesttype, req->requesttype,
+		le16_to_cpu(req->value), le16_to_cpu(req->value),
+		le16_to_cpu(req->index));
+
+	ep_index = usb_pipe_ep_index(pipe);
+
+	ep_ring = virt_dev->eps[ep_index].ring;
+
+	/*
+	 * Check to see if the max packet size for the default control
+	 * endpoint changed during FS device enumeration
+	 */
+	if (udev->speed == USB_SPEED_FULL) {
+		ret = xhci_check_maxpacket(udev);
+		if (ret < 0)
+			return ret;
+	}
+
+	xhci_inval_cache((uintptr_t)virt_dev->out_ctx->bytes,
+			 virt_dev->out_ctx->size);
+
+	struct xhci_ep_ctx *ep_ctx = NULL;
+	ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
+
+	/* 1 TRB for setup, 1 for status */
+	num_trbs = 2;
+	/*
+	 * Don't need to check if we need additional event data and normal TRBs,
+	 * since data in control transfers will never get bigger than 16MB
+	 * XXX: can we get a buffer that crosses 64KB boundaries?
+	 */
+
+	if (length > 0)
+		num_trbs++;
+	/*
+	 * XXX: Calling routine prepare_ring() called in place of
+	 * prepare_trasfer() as there in 'Linux' since we are not
+	 * maintaining multiple TDs/transfer at the same time.
+	 */
+	ret = prepare_ring(ctrl, ep_ring,
+				le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
+
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Don't give the first TRB to the hardware (by toggling the cycle bit)
+	 * until we've finished creating all the other TRBs.  The ring's cycle
+	 * state may change as we enqueue the other TRBs, so save it too.
+	 */
+	start_trb = &ep_ring->enqueue->generic;
+	start_cycle = ep_ring->cycle_state;
+
+	debug("start_trb %p, start_cycle %d\n", start_trb, start_cycle);
+
+	/* Queue setup TRB - see section 6.4.1.2.1 */
+	/* FIXME better way to translate setup_packet into two u32 fields? */
+	field = 0;
+	field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
+	if (start_cycle == 0)
+		field |= 0x1;
+
+	/* xHCI 1.0 6.4.1.2.1: Transfer Type field */
+	if (ctrl->hci_version >= 0x100 || ctrl->quirks & XHCI_MTK_HOST) {
+		if (length > 0) {
+			if (req->requesttype & USB_DIR_IN)
+				field |= TRB_TX_TYPE(TRB_DATA_IN);
+			else
+				field |= TRB_TX_TYPE(TRB_DATA_OUT);
+		}
+	}
+
+	debug("req->requesttype = %d, req->request = %d, req->value = %d, req->index = %d, req->length = %d\n",
+	      req->requesttype, req->request, le16_to_cpu(req->value),
+	      le16_to_cpu(req->index), le16_to_cpu(req->length));
+
+	trb_fields[0] = req->requesttype | req->request << 8 |
+				le16_to_cpu(req->value) << 16;
+	trb_fields[1] = le16_to_cpu(req->index) |
+			le16_to_cpu(req->length) << 16;
+	/* TRB_LEN | (TRB_INTR_TARGET) */
+	trb_fields[2] = (TRB_LEN(8) | TRB_INTR_TARGET(0));
+	/* Immediate data in pointer */
+	trb_fields[3] = field;
+	queue_trb(ctrl, ep_ring, true, trb_fields);
+
+	/* Re-initializing field to zero */
+	field = 0;
+	/* If there's data, queue data TRBs */
+	/* Only set interrupt on short packet for IN endpoints */
+	if (usb_pipein(pipe))
+		field = TRB_ISP | TRB_TYPE(TRB_DATA);
+	else
+		field = TRB_TYPE(TRB_DATA);
+
+	remainder = xhci_td_remainder(ctrl, 0, length, length,
+				      usb_maxpacket(udev, pipe), true);
+	length_field = TRB_LEN(length) | TRB_TD_SIZE(remainder) |
+		       TRB_INTR_TARGET(0);
+	debug("length_field = %d, length = %d,"
+		"xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n",
+		length_field, TRB_LEN(length),
+		TRB_TD_SIZE(remainder), 0);
+
+	if (length > 0) {
+		if (req->requesttype & USB_DIR_IN)
+			field |= TRB_DIR_IN;
+		buf_64 = xhci_virt_to_bus(ctrl, buffer);
+
+		trb_fields[0] = lower_32_bits(buf_64);
+		trb_fields[1] = upper_32_bits(buf_64);
+		trb_fields[2] = length_field;
+		trb_fields[3] = field | ep_ring->cycle_state;
+
+		xhci_flush_cache((uintptr_t)buffer, length);
+		queue_trb(ctrl, ep_ring, true, trb_fields);
+	}
+
+	/*
+	 * Queue status TRB -
+	 * see Table 7 and sections 4.11.2.2 and 6.4.1.2.3
+	 */
+
+	/* If the device sent data, the status stage is an OUT transfer */
+	field = 0;
+	if (length > 0 && req->requesttype & USB_DIR_IN)
+		field = 0;
+	else
+		field = TRB_DIR_IN;
+
+	trb_fields[0] = 0;
+	trb_fields[1] = 0;
+	trb_fields[2] = TRB_INTR_TARGET(0);
+		/* Event on completion */
+	trb_fields[3] = field | TRB_IOC |
+			TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
+
+	queue_trb(ctrl, ep_ring, false, trb_fields);
+
+	giveback_first_trb(udev, ep_index, start_cycle, start_trb);
+
+	event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+	if (!event)
+		goto abort;
+	field = le32_to_cpu(event->trans_event.flags);
+
+	BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
+	BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+
+	record_transfer_result(udev, event, length);
+	xhci_acknowledge_event(ctrl);
+
+	/* Invalidate buffer to make it available to usb-core */
+	if (length > 0)
+		xhci_inval_cache((uintptr_t)buffer, length);
+
+	if (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))
+			== COMP_SHORT_TX) {
+		/* Short data stage, clear up additional status stage event */
+		event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
+		if (!event)
+			goto abort;
+		BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
+		BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+		xhci_acknowledge_event(ctrl);
+	}
+
+	return (udev->status != USB_ST_NOT_PROC) ? 0 : -1;
+
+abort:
+	debug("XHCI control transfer timed out, aborting...\n");
+	abort_td(udev, ep_index);
+	udev->status = USB_ST_NAK_REC;
+	udev->act_len = 0;
+	return -ETIMEDOUT;
+}
diff --git a/roms/u-boot/drivers/usb/host/xhci.c b/roms/u-boot/drivers/usb/host/xhci.c
new file mode 100644
index 000000000..d27ac01c8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/host/xhci.c
@@ -0,0 +1,1585 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * USB HOST XHCI Controller stack
+ *
+ * Based on xHCI host controller driver in linux-kernel
+ * by Sarah Sharp.
+ *
+ * Copyright (C) 2008 Intel Corp.
+ * Author: Sarah Sharp
+ *
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors: Vivek Gautam <gautam.vivek@samsung.com>
+ *	    Vikas Sajjan <vikas.sajjan@samsung.com>
+ */
+
+/**
+ * This file gives the xhci stack for usb3.0 looking into
+ * xhci specification Rev1.0 (5/21/10).
+ * The quirk devices support hasn't been given yet.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <log.h>
+#include <malloc.h>
+#include <usb.h>
+#include <usb/xhci.h>
+#include <watchdog.h>
+#include <asm/byteorder.h>
+#include <asm/cache.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/iopoll.h>
+
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+static struct descriptor {
+	struct usb_hub_descriptor hub;
+	struct usb_device_descriptor device;
+	struct usb_config_descriptor config;
+	struct usb_interface_descriptor interface;
+	struct usb_endpoint_descriptor endpoint;
+	struct usb_ss_ep_comp_descriptor ep_companion;
+} __attribute__ ((packed)) descriptor = {
+	{
+		0xc,		/* bDescLength */
+		0x2a,		/* bDescriptorType: hub descriptor */
+		2,		/* bNrPorts -- runtime modified */
+		cpu_to_le16(0x8), /* wHubCharacteristics */
+		10,		/* bPwrOn2PwrGood */
+		0,		/* bHubCntrCurrent */
+		{		/* Device removable */
+		}		/* at most 7 ports! XXX */
+	},
+	{
+		0x12,		/* bLength */
+		1,		/* bDescriptorType: UDESC_DEVICE */
+		cpu_to_le16(0x0300), /* bcdUSB: v3.0 */
+		9,		/* bDeviceClass: UDCLASS_HUB */
+		0,		/* bDeviceSubClass: UDSUBCLASS_HUB */
+		3,		/* bDeviceProtocol: UDPROTO_SSHUBSTT */
+		9,		/* bMaxPacketSize: 512 bytes  2^9 */
+		0x0000,		/* idVendor */
+		0x0000,		/* idProduct */
+		cpu_to_le16(0x0100), /* bcdDevice */
+		1,		/* iManufacturer */
+		2,		/* iProduct */
+		0,		/* iSerialNumber */
+		1		/* bNumConfigurations: 1 */
+	},
+	{
+		0x9,
+		2,		/* bDescriptorType: UDESC_CONFIG */
+		cpu_to_le16(0x1f), /* includes SS endpoint descriptor */
+		1,		/* bNumInterface */
+		1,		/* bConfigurationValue */
+		0,		/* iConfiguration */
+		0x40,		/* bmAttributes: UC_SELF_POWER */
+		0		/* bMaxPower */
+	},
+	{
+		0x9,		/* bLength */
+		4,		/* bDescriptorType: UDESC_INTERFACE */
+		0,		/* bInterfaceNumber */
+		0,		/* bAlternateSetting */
+		1,		/* bNumEndpoints */
+		9,		/* bInterfaceClass: UICLASS_HUB */
+		0,		/* bInterfaceSubClass: UISUBCLASS_HUB */
+		0,		/* bInterfaceProtocol: UIPROTO_HSHUBSTT */
+		0		/* iInterface */
+	},
+	{
+		0x7,		/* bLength */
+		5,		/* bDescriptorType: UDESC_ENDPOINT */
+		0x81,		/* bEndpointAddress: IN endpoint 1 */
+		3,		/* bmAttributes: UE_INTERRUPT */
+		8,		/* wMaxPacketSize */
+		255		/* bInterval */
+	},
+	{
+		0x06,		/* ss_bLength */
+		0x30,		/* ss_bDescriptorType: SS EP Companion */
+		0x00,		/* ss_bMaxBurst: allows 1 TX between ACKs */
+		/* ss_bmAttributes: 1 packet per service interval */
+		0x00,
+		/* ss_wBytesPerInterval: 15 bits for max 15 ports */
+		cpu_to_le16(0x02),
+	},
+};
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
+
+struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev)
+{
+#if CONFIG_IS_ENABLED(DM_USB)
+	struct udevice *dev;
+
+	/* Find the USB controller */
+	for (dev = udev->dev;
+	     device_get_uclass_id(dev) != UCLASS_USB;
+	     dev = dev->parent)
+		;
+	return dev_get_priv(dev);
+#else
+	return udev->controller;
+#endif
+}
+
+/**
+ * Waits for as per specified amount of time
+ * for the "result" to match with "done"
+ *
+ * @param ptr	pointer to the register to be read
+ * @param mask	mask for the value read
+ * @param done	value to be campared with result
+ * @param usec	time to wait till
+ * @return 0 if handshake is success else < 0 on failure
+ */
+static int
+handshake(uint32_t volatile *ptr, uint32_t mask, uint32_t done, int usec)
+{
+	uint32_t result;
+	int ret;
+
+	ret = readx_poll_sleep_timeout(xhci_readl, ptr, result,
+				 (result & mask) == done || result == U32_MAX,
+				 1, usec);
+	if (result == U32_MAX)		/* card removed */
+		return -ENODEV;
+
+	return ret;
+}
+
+/**
+ * Set the run bit and wait for the host to be running.
+ *
+ * @param hcor	pointer to host controller operation registers
+ * @return status of the Handshake
+ */
+static int xhci_start(struct xhci_hcor *hcor)
+{
+	u32 temp;
+	int ret;
+
+	puts("Starting the controller\n");
+	temp = xhci_readl(&hcor->or_usbcmd);
+	temp |= (CMD_RUN);
+	xhci_writel(&hcor->or_usbcmd, temp);
+
+	/*
+	 * Wait for the HCHalted Status bit to be 0 to indicate the host is
+	 * running.
+	 */
+	ret = handshake(&hcor->or_usbsts, STS_HALT, 0, XHCI_MAX_HALT_USEC);
+	if (ret)
+		debug("Host took too long to start, "
+				"waited %u microseconds.\n",
+				XHCI_MAX_HALT_USEC);
+	return ret;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+/**
+ * Resets XHCI Hardware
+ *
+ * @param ctrl	pointer to host controller
+ * @return 0 if OK, or a negative error code.
+ */
+static int xhci_reset_hw(struct xhci_ctrl *ctrl)
+{
+	int ret;
+
+	ret = reset_get_by_index(ctrl->dev, 0, &ctrl->reset);
+	if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
+		dev_err(ctrl->dev, "failed to get reset\n");
+		return ret;
+	}
+
+	if (reset_valid(&ctrl->reset)) {
+		ret = reset_assert(&ctrl->reset);
+		if (ret)
+			return ret;
+
+		ret = reset_deassert(&ctrl->reset);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
+/**
+ * Resets the XHCI Controller
+ *
+ * @param hcor	pointer to host controller operation registers
+ * @return -EBUSY if XHCI Controller is not halted else status of handshake
+ */
+static int xhci_reset(struct xhci_hcor *hcor)
+{
+	u32 cmd;
+	u32 state;
+	int ret;
+
+	/* Halting the Host first */
+	debug("// Halt the HC: %p\n", hcor);
+	state = xhci_readl(&hcor->or_usbsts) & STS_HALT;
+	if (!state) {
+		cmd = xhci_readl(&hcor->or_usbcmd);
+		cmd &= ~CMD_RUN;
+		xhci_writel(&hcor->or_usbcmd, cmd);
+	}
+
+	ret = handshake(&hcor->or_usbsts,
+			STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
+	if (ret) {
+		printf("Host not halted after %u microseconds.\n",
+				XHCI_MAX_HALT_USEC);
+		return -EBUSY;
+	}
+
+	debug("// Reset the HC\n");
+	cmd = xhci_readl(&hcor->or_usbcmd);
+	cmd |= CMD_RESET;
+	xhci_writel(&hcor->or_usbcmd, cmd);
+
+	ret = handshake(&hcor->or_usbcmd, CMD_RESET, 0, XHCI_MAX_RESET_USEC);
+	if (ret)
+		return ret;
+
+	/*
+	 * xHCI cannot write to any doorbells or operational registers other
+	 * than status until the "Controller Not Ready" flag is cleared.
+	 */
+	return handshake(&hcor->or_usbsts, STS_CNR, 0, XHCI_MAX_RESET_USEC);
+}
+
+/**
+ * Used for passing endpoint bitmasks between the core and HCDs.
+ * Find the index for an endpoint given its descriptor.
+ * Use the return value to right shift 1 for the bitmask.
+ *
+ * Index  = (epnum * 2) + direction - 1,
+ * where direction = 0 for OUT, 1 for IN.
+ * For control endpoints, the IN index is used (OUT index is unused), so
+ * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2)
+ *
+ * @param desc	USB enpdoint Descriptor
+ * @return index of the Endpoint
+ */
+static unsigned int xhci_get_ep_index(struct usb_endpoint_descriptor *desc)
+{
+	unsigned int index;
+
+	if (usb_endpoint_xfer_control(desc))
+		index = (unsigned int)(usb_endpoint_num(desc) * 2);
+	else
+		index = (unsigned int)((usb_endpoint_num(desc) * 2) -
+				(usb_endpoint_dir_in(desc) ? 0 : 1));
+
+	return index;
+}
+
+/*
+ * Convert bInterval expressed in microframes (in 1-255 range) to exponent of
+ * microframes, rounded down to nearest power of 2.
+ */
+static unsigned int xhci_microframes_to_exponent(unsigned int desc_interval,
+						 unsigned int min_exponent,
+						 unsigned int max_exponent)
+{
+	unsigned int interval;
+
+	interval = fls(desc_interval) - 1;
+	interval = clamp_val(interval, min_exponent, max_exponent);
+	if ((1 << interval) != desc_interval)
+		debug("rounding interval to %d microframes, "\
+		      "ep desc says %d microframes\n",
+		      1 << interval, desc_interval);
+
+	return interval;
+}
+
+static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc)
+{
+	if (endpt_desc->bInterval == 0)
+		return 0;
+
+	return xhci_microframes_to_exponent(endpt_desc->bInterval, 0, 15);
+}
+
+static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc)
+{
+	return xhci_microframes_to_exponent(endpt_desc->bInterval * 8, 3, 10);
+}
+
+/*
+ * Convert interval expressed as 2^(bInterval - 1) == interval into
+ * straight exponent value 2^n == interval.
+ */
+static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc)
+{
+	unsigned int interval;
+
+	interval = clamp_val(endpt_desc->bInterval, 1, 16) - 1;
+	if (interval != endpt_desc->bInterval - 1)
+		debug("ep %#x - rounding interval to %d %sframes\n",
+		      endpt_desc->bEndpointAddress, 1 << interval,
+		      udev->speed == USB_SPEED_FULL ? "" : "micro");
+
+	if (udev->speed == USB_SPEED_FULL) {
+		/*
+		 * Full speed isoc endpoints specify interval in frames,
+		 * not microframes. We are using microframes everywhere,
+		 * so adjust accordingly.
+		 */
+		interval += 3;	/* 1 frame = 2^3 uframes */
+	}
+
+	return interval;
+}
+
+/*
+ * Return the polling or NAK interval.
+ *
+ * The polling interval is expressed in "microframes". If xHCI's Interval field
+ * is set to N, it will service the endpoint every 2^(Interval)*125us.
+ *
+ * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
+ * is set to 0.
+ */
+static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc)
+{
+	unsigned int interval = 0;
+
+	switch (udev->speed) {
+	case USB_SPEED_HIGH:
+		/* Max NAK rate */
+		if (usb_endpoint_xfer_control(endpt_desc) ||
+		    usb_endpoint_xfer_bulk(endpt_desc)) {
+			interval = xhci_parse_microframe_interval(udev,
+								  endpt_desc);
+			break;
+		}
+		/* Fall through - SS and HS isoc/int have same decoding */
+
+	case USB_SPEED_SUPER:
+		if (usb_endpoint_xfer_int(endpt_desc) ||
+		    usb_endpoint_xfer_isoc(endpt_desc)) {
+			interval = xhci_parse_exponent_interval(udev,
+								endpt_desc);
+		}
+		break;
+
+	case USB_SPEED_FULL:
+		if (usb_endpoint_xfer_isoc(endpt_desc)) {
+			interval = xhci_parse_exponent_interval(udev,
+								endpt_desc);
+			break;
+		}
+		/*
+		 * Fall through for interrupt endpoint interval decoding
+		 * since it uses the same rules as low speed interrupt
+		 * endpoints.
+		 */
+
+	case USB_SPEED_LOW:
+		if (usb_endpoint_xfer_int(endpt_desc) ||
+		    usb_endpoint_xfer_isoc(endpt_desc)) {
+			interval = xhci_parse_frame_interval(udev, endpt_desc);
+		}
+		break;
+
+	default:
+		BUG();
+	}
+
+	return interval;
+}
+
+/*
+ * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
+ * High speed endpoint descriptors can define "the number of additional
+ * transaction opportunities per microframe", but that goes in the Max Burst
+ * endpoint context field.
+ */
+static u32 xhci_get_endpoint_mult(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc,
+	struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)
+{
+	if (udev->speed < USB_SPEED_SUPER ||
+	    !usb_endpoint_xfer_isoc(endpt_desc))
+		return 0;
+
+	return ss_ep_comp_desc->bmAttributes;
+}
+
+static u32 xhci_get_endpoint_max_burst(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc,
+	struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)
+{
+	/* Super speed and Plus have max burst in ep companion desc */
+	if (udev->speed >= USB_SPEED_SUPER)
+		return ss_ep_comp_desc->bMaxBurst;
+
+	if (udev->speed == USB_SPEED_HIGH &&
+	    (usb_endpoint_xfer_isoc(endpt_desc) ||
+	     usb_endpoint_xfer_int(endpt_desc)))
+		return usb_endpoint_maxp_mult(endpt_desc) - 1;
+
+	return 0;
+}
+
+/*
+ * Return the maximum endpoint service interval time (ESIT) payload.
+ * Basically, this is the maxpacket size, multiplied by the burst size
+ * and mult size.
+ */
+static u32 xhci_get_max_esit_payload(struct usb_device *udev,
+	struct usb_endpoint_descriptor *endpt_desc,
+	struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)
+{
+	int max_burst;
+	int max_packet;
+
+	/* Only applies for interrupt or isochronous endpoints */
+	if (usb_endpoint_xfer_control(endpt_desc) ||
+	    usb_endpoint_xfer_bulk(endpt_desc))
+		return 0;
+
+	/* SuperSpeed Isoc ep with less than 48k per esit */
+	if (udev->speed >= USB_SPEED_SUPER)
+		return le16_to_cpu(ss_ep_comp_desc->wBytesPerInterval);
+
+	max_packet = usb_endpoint_maxp(endpt_desc);
+	max_burst = usb_endpoint_maxp_mult(endpt_desc);
+
+	/* A 0 in max burst means 1 transfer per ESIT */
+	return max_packet * max_burst;
+}
+
+/**
+ * Issue a configure endpoint command or evaluate context command
+ * and wait for it to finish.
+ *
+ * @param udev	pointer to the Device Data Structure
+ * @param ctx_change	flag to indicate the Context has changed or NOT
+ * @return 0 on success, -1 on failure
+ */
+static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change)
+{
+	struct xhci_container_ctx *in_ctx;
+	struct xhci_virt_device *virt_dev;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	union xhci_trb *event;
+
+	virt_dev = ctrl->devs[udev->slot_id];
+	in_ctx = virt_dev->in_ctx;
+
+	xhci_flush_cache((uintptr_t)in_ctx->bytes, in_ctx->size);
+	xhci_queue_command(ctrl, in_ctx->bytes, udev->slot_id, 0,
+			   ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+		!= udev->slot_id);
+
+	switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) {
+	case COMP_SUCCESS:
+		debug("Successful %s command\n",
+			ctx_change ? "Evaluate Context" : "Configure Endpoint");
+		break;
+	default:
+		printf("ERROR: %s command returned completion code %d.\n",
+			ctx_change ? "Evaluate Context" : "Configure Endpoint",
+			GET_COMP_CODE(le32_to_cpu(event->event_cmd.status)));
+		return -EINVAL;
+	}
+
+	xhci_acknowledge_event(ctrl);
+
+	return 0;
+}
+
+/**
+ * Configure the endpoint, programming the device contexts.
+ *
+ * @param udev	pointer to the USB device structure
+ * @return returns the status of the xhci_configure_endpoints
+ */
+static int xhci_set_configuration(struct usb_device *udev)
+{
+	struct xhci_container_ctx *in_ctx;
+	struct xhci_container_ctx *out_ctx;
+	struct xhci_input_control_ctx *ctrl_ctx;
+	struct xhci_slot_ctx *slot_ctx;
+	struct xhci_ep_ctx *ep_ctx[MAX_EP_CTX_NUM];
+	int cur_ep;
+	int max_ep_flag = 0;
+	int ep_index;
+	unsigned int dir;
+	unsigned int ep_type;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	int num_of_ep;
+	int ep_flag = 0;
+	u64 trb_64 = 0;
+	int slot_id = udev->slot_id;
+	struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
+	struct usb_interface *ifdesc;
+	u32 max_esit_payload;
+	unsigned int interval;
+	unsigned int mult;
+	unsigned int max_burst;
+	unsigned int avg_trb_len;
+	unsigned int err_count = 0;
+
+	out_ctx = virt_dev->out_ctx;
+	in_ctx = virt_dev->in_ctx;
+
+	num_of_ep = udev->config.if_desc[0].no_of_ep;
+	ifdesc = &udev->config.if_desc[0];
+
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
+	/* Initialize the input context control */
+	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
+	ctrl_ctx->drop_flags = 0;
+
+	/* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */
+	for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {
+		ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]);
+		ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1));
+		if (max_ep_flag < ep_flag)
+			max_ep_flag = ep_flag;
+	}
+
+	xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
+
+	/* slot context */
+	xhci_slot_copy(ctrl, in_ctx, out_ctx);
+	slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
+	slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK));
+	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0);
+
+	xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0);
+
+	/* filling up ep contexts */
+	for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {
+		struct usb_endpoint_descriptor *endpt_desc = NULL;
+		struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL;
+
+		endpt_desc = &ifdesc->ep_desc[cur_ep];
+		ss_ep_comp_desc = &ifdesc->ss_ep_comp_desc[cur_ep];
+		trb_64 = 0;
+
+		/*
+		 * Get values to fill the endpoint context, mostly from ep
+		 * descriptor. The average TRB buffer lengt for bulk endpoints
+		 * is unclear as we have no clue on scatter gather list entry
+		 * size. For Isoc and Int, set it to max available.
+		 * See xHCI 1.1 spec 4.14.1.1 for details.
+		 */
+		max_esit_payload = xhci_get_max_esit_payload(udev, endpt_desc,
+							     ss_ep_comp_desc);
+		interval = xhci_get_endpoint_interval(udev, endpt_desc);
+		mult = xhci_get_endpoint_mult(udev, endpt_desc,
+					      ss_ep_comp_desc);
+		max_burst = xhci_get_endpoint_max_burst(udev, endpt_desc,
+							ss_ep_comp_desc);
+		avg_trb_len = max_esit_payload;
+
+		ep_index = xhci_get_ep_index(endpt_desc);
+		ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
+
+		/* Allocate the ep rings */
+		virt_dev->eps[ep_index].ring = xhci_ring_alloc(ctrl, 1, true);
+		if (!virt_dev->eps[ep_index].ring)
+			return -ENOMEM;
+
+		/*NOTE: ep_desc[0] actually represents EP1 and so on */
+		dir = (((endpt_desc->bEndpointAddress) & (0x80)) >> 7);
+		ep_type = (((endpt_desc->bmAttributes) & (0x3)) | (dir << 2));
+
+		ep_ctx[ep_index]->ep_info =
+			cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
+			EP_INTERVAL(interval) | EP_MULT(mult));
+
+		ep_ctx[ep_index]->ep_info2 = cpu_to_le32(EP_TYPE(ep_type));
+		ep_ctx[ep_index]->ep_info2 |=
+			cpu_to_le32(MAX_PACKET
+			(get_unaligned(&endpt_desc->wMaxPacketSize)));
+
+		/* Allow 3 retries for everything but isoc, set CErr = 3 */
+		if (!usb_endpoint_xfer_isoc(endpt_desc))
+			err_count = 3;
+		ep_ctx[ep_index]->ep_info2 |=
+			cpu_to_le32(MAX_BURST(max_burst) |
+			ERROR_COUNT(err_count));
+
+		trb_64 = xhci_virt_to_bus(ctrl, virt_dev->eps[ep_index].ring->enqueue);
+		ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 |
+				virt_dev->eps[ep_index].ring->cycle_state);
+
+		/*
+		 * xHCI spec 6.2.3:
+		 * 'Average TRB Length' should be 8 for control endpoints.
+		 */
+		if (usb_endpoint_xfer_control(endpt_desc))
+			avg_trb_len = 8;
+		ep_ctx[ep_index]->tx_info =
+			cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
+			EP_AVG_TRB_LENGTH(avg_trb_len));
+
+		/*
+		 * The MediaTek xHCI defines some extra SW parameters which
+		 * are put into reserved DWs in Slot and Endpoint Contexts
+		 * for synchronous endpoints.
+		 */
+		if (ctrl->quirks & XHCI_MTK_HOST) {
+			ep_ctx[ep_index]->reserved[0] =
+				cpu_to_le32(EP_BPKTS(1) | EP_BBM(1));
+		}
+	}
+
+	return xhci_configure_endpoints(udev, false);
+}
+
+/**
+ * Issue an Address Device command (which will issue a SetAddress request to
+ * the device).
+ *
+ * @param udev pointer to the Device Data Structure
+ * @return 0 if successful else error code on failure
+ */
+static int xhci_address_device(struct usb_device *udev, int root_portnr)
+{
+	int ret = 0;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	struct xhci_slot_ctx *slot_ctx;
+	struct xhci_input_control_ctx *ctrl_ctx;
+	struct xhci_virt_device *virt_dev;
+	int slot_id = udev->slot_id;
+	union xhci_trb *event;
+
+	virt_dev = ctrl->devs[slot_id];
+
+	/*
+	 * This is the first Set Address since device plug-in
+	 * so setting up the slot context.
+	 */
+	debug("Setting up addressable devices %p\n", ctrl->dcbaa);
+	xhci_setup_addressable_virt_dev(ctrl, udev, root_portnr);
+
+	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
+	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
+	ctrl_ctx->drop_flags = 0;
+
+	xhci_queue_command(ctrl, (void *)ctrl_ctx, slot_id, 0, TRB_ADDR_DEV);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != slot_id);
+
+	switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) {
+	case COMP_CTX_STATE:
+	case COMP_EBADSLT:
+		printf("Setup ERROR: address device command for slot %d.\n",
+								slot_id);
+		ret = -EINVAL;
+		break;
+	case COMP_TX_ERR:
+		puts("Device not responding to set address.\n");
+		ret = -EPROTO;
+		break;
+	case COMP_DEV_ERR:
+		puts("ERROR: Incompatible device"
+					"for address device command.\n");
+		ret = -ENODEV;
+		break;
+	case COMP_SUCCESS:
+		debug("Successful Address Device command\n");
+		udev->status = 0;
+		break;
+	default:
+		printf("ERROR: unexpected command completion code 0x%x.\n",
+			GET_COMP_CODE(le32_to_cpu(event->event_cmd.status)));
+		ret = -EINVAL;
+		break;
+	}
+
+	xhci_acknowledge_event(ctrl);
+
+	if (ret < 0)
+		/*
+		 * TODO: Unsuccessful Address Device command shall leave the
+		 * slot in default state. So, issue Disable Slot command now.
+		 */
+		return ret;
+
+	xhci_inval_cache((uintptr_t)virt_dev->out_ctx->bytes,
+			 virt_dev->out_ctx->size);
+	slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->out_ctx);
+
+	debug("xHC internal address is: %d\n",
+		le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);
+
+	return 0;
+}
+
+/**
+ * Issue Enable slot command to the controller to allocate
+ * device slot and assign the slot id. It fails if the xHC
+ * ran out of device slots, the Enable Slot command timed out,
+ * or allocating memory failed.
+ *
+ * @param udev	pointer to the Device Data Structure
+ * @return Returns 0 on succes else return error code on failure
+ */
+static int _xhci_alloc_device(struct usb_device *udev)
+{
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	union xhci_trb *event;
+	int ret;
+
+	/*
+	 * Root hub will be first device to be initailized.
+	 * If this device is root-hub, don't do any xHC related
+	 * stuff.
+	 */
+	if (ctrl->rootdev == 0) {
+		udev->speed = USB_SPEED_SUPER;
+		return 0;
+	}
+
+	xhci_queue_command(ctrl, NULL, 0, 0, TRB_ENABLE_SLOT);
+	event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+	BUG_ON(GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))
+		!= COMP_SUCCESS);
+
+	udev->slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags));
+
+	xhci_acknowledge_event(ctrl);
+
+	ret = xhci_alloc_virt_device(ctrl, udev->slot_id);
+	if (ret < 0) {
+		/*
+		 * TODO: Unsuccessful Address Device command shall leave
+		 * the slot in default. So, issue Disable Slot command now.
+		 */
+		puts("Could not allocate xHCI USB device data structures\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int usb_alloc_device(struct usb_device *udev)
+{
+	return _xhci_alloc_device(udev);
+}
+#endif
+
+/*
+ * Full speed devices may have a max packet size greater than 8 bytes, but the
+ * USB core doesn't know that until it reads the first 8 bytes of the
+ * descriptor.  If the usb_device's max packet size changes after that point,
+ * we need to issue an evaluate context command and wait on it.
+ *
+ * @param udev	pointer to the Device Data Structure
+ * @return returns the status of the xhci_configure_endpoints
+ */
+int xhci_check_maxpacket(struct usb_device *udev)
+{
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	unsigned int slot_id = udev->slot_id;
+	int ep_index = 0;	/* control endpoint */
+	struct xhci_container_ctx *in_ctx;
+	struct xhci_container_ctx *out_ctx;
+	struct xhci_input_control_ctx *ctrl_ctx;
+	struct xhci_ep_ctx *ep_ctx;
+	int max_packet_size;
+	int hw_max_packet_size;
+	int ret = 0;
+
+	out_ctx = ctrl->devs[slot_id]->out_ctx;
+	xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
+
+	ep_ctx = xhci_get_ep_ctx(ctrl, out_ctx, ep_index);
+	hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
+	max_packet_size = udev->epmaxpacketin[0];
+	if (hw_max_packet_size != max_packet_size) {
+		debug("Max Packet Size for ep 0 changed.\n");
+		debug("Max packet size in usb_device = %d\n", max_packet_size);
+		debug("Max packet size in xHCI HW = %d\n", hw_max_packet_size);
+		debug("Issuing evaluate context command.\n");
+
+		/* Set up the modified control endpoint 0 */
+		xhci_endpoint_copy(ctrl, ctrl->devs[slot_id]->in_ctx,
+				ctrl->devs[slot_id]->out_ctx, ep_index);
+		in_ctx = ctrl->devs[slot_id]->in_ctx;
+		ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
+		ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET(MAX_PACKET_MASK));
+		ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
+
+		/*
+		 * Set up the input context flags for the command
+		 * FIXME: This won't work if a non-default control endpoint
+		 * changes max packet sizes.
+		 */
+		ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
+		ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG);
+		ctrl_ctx->drop_flags = 0;
+
+		ret = xhci_configure_endpoints(udev, true);
+	}
+	return ret;
+}
+
+/**
+ * Clears the Change bits of the Port Status Register
+ *
+ * @param wValue	request value
+ * @param wIndex	request index
+ * @param addr		address of posrt status register
+ * @param port_status	state of port status register
+ * @return none
+ */
+static void xhci_clear_port_change_bit(u16 wValue,
+		u16 wIndex, volatile uint32_t *addr, u32 port_status)
+{
+	char *port_change_bit;
+	u32 status;
+
+	switch (wValue) {
+	case USB_PORT_FEAT_C_RESET:
+		status = PORT_RC;
+		port_change_bit = "reset";
+		break;
+	case USB_PORT_FEAT_C_CONNECTION:
+		status = PORT_CSC;
+		port_change_bit = "connect";
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		status = PORT_OCC;
+		port_change_bit = "over-current";
+		break;
+	case USB_PORT_FEAT_C_ENABLE:
+		status = PORT_PEC;
+		port_change_bit = "enable/disable";
+		break;
+	case USB_PORT_FEAT_C_SUSPEND:
+		status = PORT_PLC;
+		port_change_bit = "suspend/resume";
+		break;
+	default:
+		/* Should never happen */
+		return;
+	}
+
+	/* Change bits are all write 1 to clear */
+	xhci_writel(addr, port_status | status);
+
+	port_status = xhci_readl(addr);
+	debug("clear port %s change, actual port %d status  = 0x%x\n",
+			port_change_bit, wIndex, port_status);
+}
+
+/**
+ * Save Read Only (RO) bits and save read/write bits where
+ * writing a 0 clears the bit and writing a 1 sets the bit (RWS).
+ * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
+ *
+ * @param state	state of the Port Status and Control Regsiter
+ * @return a value that would result in the port being in the
+ *	   same state, if the value was written to the port
+ *	   status control register.
+ */
+static u32 xhci_port_state_to_neutral(u32 state)
+{
+	/* Save read-only status and port state */
+	return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
+}
+
+/**
+ * Submits the Requests to the XHCI Host Controller
+ *
+ * @param udev pointer to the USB device structure
+ * @param pipe contains the DIR_IN or OUT , devnum
+ * @param buffer buffer to be read/written based on the request
+ * @return returns 0 if successful else -1 on failure
+ */
+static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
+			void *buffer, struct devrequest *req)
+{
+	uint8_t tmpbuf[4];
+	u16 typeReq;
+	void *srcptr = NULL;
+	int len, srclen;
+	uint32_t reg;
+	volatile uint32_t *status_reg;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	struct xhci_hccr *hccr = ctrl->hccr;
+	struct xhci_hcor *hcor = ctrl->hcor;
+	int max_ports = HCS_MAX_PORTS(xhci_readl(&hccr->cr_hcsparams1));
+
+	if ((req->requesttype & USB_RT_PORT) &&
+	    le16_to_cpu(req->index) > max_ports) {
+		printf("The request port(%d) exceeds maximum port number\n",
+		       le16_to_cpu(req->index) - 1);
+		return -EINVAL;
+	}
+
+	status_reg = (volatile uint32_t *)
+		     (&hcor->portregs[le16_to_cpu(req->index) - 1].or_portsc);
+	srclen = 0;
+
+	typeReq = req->request | req->requesttype << 8;
+
+	switch (typeReq) {
+	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+		switch (le16_to_cpu(req->value) >> 8) {
+		case USB_DT_DEVICE:
+			debug("USB_DT_DEVICE request\n");
+			srcptr = &descriptor.device;
+			srclen = 0x12;
+			break;
+		case USB_DT_CONFIG:
+			debug("USB_DT_CONFIG config\n");
+			srcptr = &descriptor.config;
+			srclen = 0x19;
+			break;
+		case USB_DT_STRING:
+			debug("USB_DT_STRING config\n");
+			switch (le16_to_cpu(req->value) & 0xff) {
+			case 0:	/* Language */
+				srcptr = "\4\3\11\4";
+				srclen = 4;
+				break;
+			case 1:	/* Vendor String  */
+				srcptr = "\16\3U\0-\0B\0o\0o\0t\0";
+				srclen = 14;
+				break;
+			case 2:	/* Product Name */
+				srcptr = "\52\3X\0H\0C\0I\0 "
+					 "\0H\0o\0s\0t\0 "
+					 "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
+				srclen = 42;
+				break;
+			default:
+				printf("unknown value DT_STRING %x\n",
+					le16_to_cpu(req->value));
+				goto unknown;
+			}
+			break;
+		default:
+			printf("unknown value %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		break;
+	case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
+		switch (le16_to_cpu(req->value) >> 8) {
+		case USB_DT_HUB:
+		case USB_DT_SS_HUB:
+			debug("USB_DT_HUB config\n");
+			srcptr = &descriptor.hub;
+			srclen = 0x8;
+			break;
+		default:
+			printf("unknown value %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		break;
+	case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
+		debug("USB_REQ_SET_ADDRESS\n");
+		ctrl->rootdev = le16_to_cpu(req->value);
+		break;
+	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+		/* Do nothing */
+		break;
+	case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
+		tmpbuf[0] = 1;	/* USB_STATUS_SELFPOWERED */
+		tmpbuf[1] = 0;
+		srcptr = tmpbuf;
+		srclen = 2;
+		break;
+	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+		memset(tmpbuf, 0, 4);
+		reg = xhci_readl(status_reg);
+		if (reg & PORT_CONNECT) {
+			tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
+			switch (reg & DEV_SPEED_MASK) {
+			case XDEV_FS:
+				debug("SPEED = FULLSPEED\n");
+				break;
+			case XDEV_LS:
+				debug("SPEED = LOWSPEED\n");
+				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
+				break;
+			case XDEV_HS:
+				debug("SPEED = HIGHSPEED\n");
+				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+				break;
+			case XDEV_SS:
+				debug("SPEED = SUPERSPEED\n");
+				tmpbuf[1] |= USB_PORT_STAT_SUPER_SPEED >> 8;
+				break;
+			}
+		}
+		if (reg & PORT_PE)
+			tmpbuf[0] |= USB_PORT_STAT_ENABLE;
+		if ((reg & PORT_PLS_MASK) == XDEV_U3)
+			tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
+		if (reg & PORT_OC)
+			tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
+		if (reg & PORT_RESET)
+			tmpbuf[0] |= USB_PORT_STAT_RESET;
+		if (reg & PORT_POWER)
+			/*
+			 * XXX: This Port power bit (for USB 3.0 hub)
+			 * we are faking in USB 2.0 hub port status;
+			 * since there's a change in bit positions in
+			 * two:
+			 * USB 2.0 port status PP is at position[8]
+			 * USB 3.0 port status PP is at position[9]
+			 * So, we are still keeping it at position [8]
+			 */
+			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
+		if (reg & PORT_CSC)
+			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
+		if (reg & PORT_PEC)
+			tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
+		if (reg & PORT_OCC)
+			tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
+		if (reg & PORT_RC)
+			tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+
+		srcptr = tmpbuf;
+		srclen = 4;
+		break;
+	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+		reg = xhci_readl(status_reg);
+		reg = xhci_port_state_to_neutral(reg);
+		switch (le16_to_cpu(req->value)) {
+		case USB_PORT_FEAT_ENABLE:
+			reg |= PORT_PE;
+			xhci_writel(status_reg, reg);
+			break;
+		case USB_PORT_FEAT_POWER:
+			reg |= PORT_POWER;
+			xhci_writel(status_reg, reg);
+			break;
+		case USB_PORT_FEAT_RESET:
+			reg |= PORT_RESET;
+			xhci_writel(status_reg, reg);
+			break;
+		default:
+			printf("unknown feature %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		break;
+	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+		reg = xhci_readl(status_reg);
+		reg = xhci_port_state_to_neutral(reg);
+		switch (le16_to_cpu(req->value)) {
+		case USB_PORT_FEAT_ENABLE:
+			reg &= ~PORT_PE;
+			break;
+		case USB_PORT_FEAT_POWER:
+			reg &= ~PORT_POWER;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+		case USB_PORT_FEAT_C_CONNECTION:
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+		case USB_PORT_FEAT_C_ENABLE:
+			xhci_clear_port_change_bit((le16_to_cpu(req->value)),
+							le16_to_cpu(req->index),
+							status_reg, reg);
+			break;
+		default:
+			printf("unknown feature %x\n", le16_to_cpu(req->value));
+			goto unknown;
+		}
+		xhci_writel(status_reg, reg);
+		break;
+	default:
+		puts("Unknown request\n");
+		goto unknown;
+	}
+
+	debug("scrlen = %d\n req->length = %d\n",
+		srclen, le16_to_cpu(req->length));
+
+	len = min(srclen, (int)le16_to_cpu(req->length));
+
+	if (srcptr != NULL && len > 0)
+		memcpy(buffer, srcptr, len);
+	else
+		debug("Len is 0\n");
+
+	udev->act_len = len;
+	udev->status = 0;
+
+	return 0;
+
+unknown:
+	udev->act_len = 0;
+	udev->status = USB_ST_STALLED;
+
+	return -ENODEV;
+}
+
+/**
+ * Submits the INT request to XHCI Host cotroller
+ *
+ * @param udev	pointer to the USB device
+ * @param pipe		contains the DIR_IN or OUT , devnum
+ * @param buffer	buffer to be read/written based on the request
+ * @param length	length of the buffer
+ * @param interval	interval of the interrupt
+ * @return 0
+ */
+static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
+				void *buffer, int length, int interval,
+				bool nonblock)
+{
+	if (usb_pipetype(pipe) != PIPE_INTERRUPT) {
+		printf("non-interrupt pipe (type=%lu)", usb_pipetype(pipe));
+		return -EINVAL;
+	}
+
+	/*
+	 * xHCI uses normal TRBs for both bulk and interrupt. When the
+	 * interrupt endpoint is to be serviced, the xHC will consume
+	 * (at most) one TD. A TD (comprised of sg list entries) can
+	 * take several service intervals to transmit.
+	 */
+	return xhci_bulk_tx(udev, pipe, length, buffer);
+}
+
+/**
+ * submit the BULK type of request to the USB Device
+ *
+ * @param udev	pointer to the USB device
+ * @param pipe		contains the DIR_IN or OUT , devnum
+ * @param buffer	buffer to be read/written based on the request
+ * @param length	length of the buffer
+ * @return returns 0 if successful else -1 on failure
+ */
+static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
+				 void *buffer, int length)
+{
+	if (usb_pipetype(pipe) != PIPE_BULK) {
+		printf("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
+		return -EINVAL;
+	}
+
+	return xhci_bulk_tx(udev, pipe, length, buffer);
+}
+
+/**
+ * submit the control type of request to the Root hub/Device based on the devnum
+ *
+ * @param udev	pointer to the USB device
+ * @param pipe		contains the DIR_IN or OUT , devnum
+ * @param buffer	buffer to be read/written based on the request
+ * @param length	length of the buffer
+ * @param setup		Request type
+ * @param root_portnr	Root port number that this device is on
+ * @return returns 0 if successful else -1 on failure
+ */
+static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe,
+				    void *buffer, int length,
+				    struct devrequest *setup, int root_portnr)
+{
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	int ret = 0;
+
+	if (usb_pipetype(pipe) != PIPE_CONTROL) {
+		printf("non-control pipe (type=%lu)", usb_pipetype(pipe));
+		return -EINVAL;
+	}
+
+	if (usb_pipedevice(pipe) == ctrl->rootdev)
+		return xhci_submit_root(udev, pipe, buffer, setup);
+
+	if (setup->request == USB_REQ_SET_ADDRESS &&
+	   (setup->requesttype & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		return xhci_address_device(udev, root_portnr);
+
+	if (setup->request == USB_REQ_SET_CONFIGURATION &&
+	   (setup->requesttype & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		ret = xhci_set_configuration(udev);
+		if (ret) {
+			puts("Failed to configure xHCI endpoint\n");
+			return ret;
+		}
+	}
+
+	return xhci_ctrl_tx(udev, pipe, setup, length, buffer);
+}
+
+static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
+{
+	struct xhci_hccr *hccr;
+	struct xhci_hcor *hcor;
+	uint32_t val;
+	uint32_t val2;
+	uint32_t reg;
+
+	hccr = ctrl->hccr;
+	hcor = ctrl->hcor;
+	/*
+	 * Program the Number of Device Slots Enabled field in the CONFIG
+	 * register with the max value of slots the HC can handle.
+	 */
+	val = (xhci_readl(&hccr->cr_hcsparams1) & HCS_SLOTS_MASK);
+	val2 = xhci_readl(&hcor->or_config);
+	val |= (val2 & ~HCS_SLOTS_MASK);
+	xhci_writel(&hcor->or_config, val);
+
+	/* initializing xhci data structures */
+	if (xhci_mem_init(ctrl, hccr, hcor) < 0)
+		return -ENOMEM;
+
+	reg = xhci_readl(&hccr->cr_hcsparams1);
+	descriptor.hub.bNbrPorts = HCS_MAX_PORTS(reg);
+	printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
+
+	/* Port Indicators */
+	reg = xhci_readl(&hccr->cr_hccparams);
+	if (HCS_INDICATOR(reg))
+		put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
+				| 0x80, &descriptor.hub.wHubCharacteristics);
+
+	/* Port Power Control */
+	if (HCC_PPC(reg))
+		put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
+				| 0x01, &descriptor.hub.wHubCharacteristics);
+
+	if (xhci_start(hcor)) {
+		xhci_reset(hcor);
+		return -ENODEV;
+	}
+
+	/* Zero'ing IRQ control register and IRQ pending register */
+	xhci_writel(&ctrl->ir_set->irq_control, 0x0);
+	xhci_writel(&ctrl->ir_set->irq_pending, 0x0);
+
+	reg = HC_VERSION(xhci_readl(&hccr->cr_capbase));
+	printf("USB XHCI %x.%02x\n", reg >> 8, reg & 0xff);
+	ctrl->hci_version = reg;
+
+	return 0;
+}
+
+static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl)
+{
+	u32 temp;
+
+	xhci_reset(ctrl->hcor);
+
+	debug("// Disabling event ring interrupts\n");
+	temp = xhci_readl(&ctrl->hcor->or_usbsts);
+	xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT);
+	temp = xhci_readl(&ctrl->ir_set->irq_pending);
+	xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp));
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
+		       void *buffer, int length, struct devrequest *setup)
+{
+	struct usb_device *hop = udev;
+
+	if (hop->parent)
+		while (hop->parent->parent)
+			hop = hop->parent;
+
+	return _xhci_submit_control_msg(udev, pipe, buffer, length, setup,
+					hop->portnr);
+}
+
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+		    int length)
+{
+	return _xhci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+		   int length, int interval, bool nonblock)
+{
+	return _xhci_submit_int_msg(udev, pipe, buffer, length, interval,
+				    nonblock);
+}
+
+/**
+ * Intialises the XHCI host controller
+ * and allocates the necessary data structures
+ *
+ * @param index	index to the host controller data structure
+ * @return pointer to the intialised controller
+ */
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	struct xhci_hccr *hccr;
+	struct xhci_hcor *hcor;
+	struct xhci_ctrl *ctrl;
+	int ret;
+
+	*controller = NULL;
+
+	if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0)
+		return -ENODEV;
+
+	if (xhci_reset(hcor) != 0)
+		return -ENODEV;
+
+	ctrl = &xhcic[index];
+
+	ctrl->hccr = hccr;
+	ctrl->hcor = hcor;
+
+	ret = xhci_lowlevel_init(ctrl);
+
+	if (ret) {
+		ctrl->hccr = NULL;
+		ctrl->hcor = NULL;
+	} else {
+		*controller = &xhcic[index];
+	}
+
+	return ret;
+}
+
+/**
+ * Stops the XHCI host controller
+ * and cleans up all the related data structures
+ *
+ * @param index	index to the host controller data structure
+ * @return none
+ */
+int usb_lowlevel_stop(int index)
+{
+	struct xhci_ctrl *ctrl = (xhcic + index);
+
+	if (ctrl->hcor) {
+		xhci_lowlevel_stop(ctrl);
+		xhci_hcd_stop(index);
+		xhci_cleanup(ctrl);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IS_ENABLED(DM_USB) */
+
+#if CONFIG_IS_ENABLED(DM_USB)
+
+static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	struct usb_device *uhop;
+	struct udevice *hub;
+	int root_portnr = 0;
+
+	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+	      dev->name, udev, udev->dev->name, udev->portnr);
+	hub = udev->dev;
+	if (device_get_uclass_id(hub) == UCLASS_USB_HUB) {
+		/* Figure out our port number on the root hub */
+		if (usb_hub_is_root_hub(hub)) {
+			root_portnr = udev->portnr;
+		} else {
+			while (!usb_hub_is_root_hub(hub->parent))
+				hub = hub->parent;
+			uhop = dev_get_parent_priv(hub);
+			root_portnr = uhop->portnr;
+		}
+	}
+/*
+	struct usb_device *hop = udev;
+
+	if (hop->parent)
+		while (hop->parent->parent)
+			hop = hop->parent;
+*/
+	return _xhci_submit_control_msg(udev, pipe, buffer, length, setup,
+					root_portnr);
+}
+
+static int xhci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _xhci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+static int xhci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval, bool nonblock)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _xhci_submit_int_msg(udev, pipe, buffer, length, interval,
+				    nonblock);
+}
+
+static int xhci_alloc_device(struct udevice *dev, struct usb_device *udev)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _xhci_alloc_device(udev);
+}
+
+static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev)
+{
+	struct xhci_ctrl *ctrl = dev_get_priv(dev);
+	struct usb_hub_device *hub = dev_get_uclass_priv(udev->dev);
+	struct xhci_virt_device *virt_dev;
+	struct xhci_input_control_ctx *ctrl_ctx;
+	struct xhci_container_ctx *out_ctx;
+	struct xhci_container_ctx *in_ctx;
+	struct xhci_slot_ctx *slot_ctx;
+	int slot_id = udev->slot_id;
+	unsigned think_time;
+
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+
+	/* Ignore root hubs */
+	if (usb_hub_is_root_hub(udev->dev))
+		return 0;
+
+	virt_dev = ctrl->devs[slot_id];
+	BUG_ON(!virt_dev);
+
+	out_ctx = virt_dev->out_ctx;
+	in_ctx = virt_dev->in_ctx;
+
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
+	/* Initialize the input context control */
+	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
+	ctrl_ctx->drop_flags = 0;
+
+	xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
+
+	/* slot context */
+	xhci_slot_copy(ctrl, in_ctx, out_ctx);
+	slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
+
+	/* Update hub related fields */
+	slot_ctx->dev_info |= cpu_to_le32(DEV_HUB);
+	/*
+	 * refer to section 6.2.2: MTT should be 0 for full speed hub,
+	 * but it may be already set to 1 when setup an xHCI virtual
+	 * device, so clear it anyway.
+	 */
+	if (hub->tt.multi)
+		slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
+	else if (udev->speed == USB_SPEED_FULL)
+		slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT);
+	slot_ctx->dev_info2 |= cpu_to_le32(XHCI_MAX_PORTS(udev->maxchild));
+	/*
+	 * Set TT think time - convert from ns to FS bit times.
+	 * Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns
+	 *
+	 * 0 =  8 FS bit times, 1 = 16 FS bit times,
+	 * 2 = 24 FS bit times, 3 = 32 FS bit times.
+	 *
+	 * This field shall be 0 if the device is not a high-spped hub.
+	 */
+	think_time = hub->tt.think_time;
+	if (think_time != 0)
+		think_time = (think_time / 666) - 1;
+	if (udev->speed == USB_SPEED_HIGH)
+		slot_ctx->tt_info |= cpu_to_le32(TT_THINK_TIME(think_time));
+	slot_ctx->dev_state = 0;
+
+	return xhci_configure_endpoints(udev, false);
+}
+
+static int xhci_get_max_xfer_size(struct udevice *dev, size_t *size)
+{
+	/*
+	 * xHCD allocates one segment which includes 64 TRBs for each endpoint
+	 * and the last TRB in this segment is configured as a link TRB to form
+	 * a TRB ring. Each TRB can transfer up to 64K bytes, however data
+	 * buffers referenced by transfer TRBs shall not span 64KB boundaries.
+	 * Hence the maximum number of TRBs we can use in one transfer is 62.
+	 */
+	*size = (TRBS_PER_SEGMENT - 2) * TRB_MAX_BUFF_SIZE;
+
+	return 0;
+}
+
+int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
+		  struct xhci_hcor *hcor)
+{
+	struct xhci_ctrl *ctrl = dev_get_priv(dev);
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	int ret;
+
+	debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p\n", __func__, dev->name,
+	      ctrl, hccr, hcor);
+
+	ctrl->dev = dev;
+
+	ret = xhci_reset_hw(ctrl);
+	if (ret)
+		goto err;
+
+	/*
+	 * XHCI needs to issue a Address device command to setup
+	 * proper device context structures, before it can interact
+	 * with the device. So a get_descriptor will fail before any
+	 * of that is done for XHCI unlike EHCI.
+	 */
+	priv->desc_before_addr = false;
+
+	ret = xhci_reset(hcor);
+	if (ret)
+		goto err;
+
+	ctrl->hccr = hccr;
+	ctrl->hcor = hcor;
+	ret = xhci_lowlevel_init(ctrl);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	free(ctrl);
+	debug("%s: failed, ret=%d\n", __func__, ret);
+	return ret;
+}
+
+int xhci_deregister(struct udevice *dev)
+{
+	struct xhci_ctrl *ctrl = dev_get_priv(dev);
+
+	xhci_lowlevel_stop(ctrl);
+	xhci_cleanup(ctrl);
+
+	return 0;
+}
+
+struct dm_usb_ops xhci_usb_ops = {
+	.control = xhci_submit_control_msg,
+	.bulk = xhci_submit_bulk_msg,
+	.interrupt = xhci_submit_int_msg,
+	.alloc_device = xhci_alloc_device,
+	.update_hub_device = xhci_update_hub_device,
+	.get_max_xfer_size  = xhci_get_max_xfer_size,
+};
+
+#endif
diff --git a/roms/u-boot/drivers/usb/mtu3/Kconfig b/roms/u-boot/drivers/usb/mtu3/Kconfig
new file mode 100644
index 000000000..a2a599171
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/Kconfig
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# For MTK USB3.0 IP
+
+config USB_MTU3
+	bool "MediaTek USB3 Dual Role controller"
+	depends on USB_HOST || USB_GADGET
+	depends on ARCH_MEDIATEK
+	help
+	  Say Y here if your system runs on MediaTek SoCs with
+	  Dual Role SuperSpeed USB controller. You can select usb
+	  mode as peripheral role or host role.
+
+	  If you don't know what this is, please say N.
+
+if USB_MTU3
+choice
+	bool "MTU3 Mode Selection"
+	default USB_MTU3_GADGET if USB_GADGET
+	default USB_MTU3_HOST if (USB_HOST && !USB_GADGET)
+
+config USB_MTU3_HOST
+	bool "Host only mode"
+	depends on USB_XHCI_HCD
+	help
+	  Select this when you want to use MTU3 in host mode only,
+	  thereby the gadget feature will be regressed.
+
+config USB_MTU3_GADGET
+	bool "Gadget only mode"
+	depends on USB_GADGET
+	select USB_GADGET_DUALSPEED
+	help
+	  Select this when you want to use MTU3 in gadget mode only,
+	  thereby the host feature will be regressed.
+
+endchoice
+
+config USB_MTU3_DEBUG
+	bool "Enable Debugging Messages"
+	help
+	  Say Y here to enable debugging messages in the MTU3 Driver.
+
+endif
diff --git a/roms/u-boot/drivers/usb/mtu3/Makefile b/roms/u-boot/drivers/usb/mtu3/Makefile
new file mode 100644
index 000000000..234f3a380
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-$(CONFIG_USB_MTU3_DEBUG)	+= -DDEBUG
+
+obj-$(CONFIG_USB_MTU3)	+= mtu3.o
+
+mtu3-y	:= mtu3_plat.o
+
+obj-$(CONFIG_USB_MTU3_GADGET)	+= mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o
+obj-$(CONFIG_USB_MTU3_GADGET)	+= mtu3_qmu.o
+obj-$(CONFIG_USB_MTU3_HOST)	+= mtu3_host.o
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3.h b/roms/u-boot/drivers/usb/mtu3/mtu3.h
new file mode 100644
index 000000000..8a7ae83ee
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3.h
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3.h - MediaTek USB3 DRD header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTU3_H__
+#define __MTU3_H__
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <generic-phy.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <power/regulator.h>
+#include <usb/xhci.h>
+
+struct mtu3;
+struct mtu3_ep;
+struct mtu3_request;
+struct mtu3_host;
+
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+#define MU3D_EP_TXCR0(epnum)	(U3D_TX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR1(epnum)	(U3D_TX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR2(epnum)	(U3D_TX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define MU3D_EP_RXCR0(epnum)	(U3D_RX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR1(epnum)	(U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR2(epnum)	(U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_RQCSR(epnum)	(U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQSAR(epnum)	(U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQCPR(epnum)	(U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_TQCSR(epnum)	(U3D_TXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQSAR(epnum)	(U3D_TXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQCPR(epnum)	(U3D_TXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define SSUSB_U3_CTRL(p)	(U3D_SSUSB_U3_CTRL_0P + ((p) * 0x08))
+#define SSUSB_U2_CTRL(p)	(U3D_SSUSB_U2_CTRL_0P + ((p) * 0x08))
+
+#define MTU3_DRIVER_NAME	"mtu3-gadget"
+#define DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+#define MTU3_EP_ENABLED		BIT(0)
+#define MTU3_EP_STALL		BIT(1)
+#define MTU3_EP_WEDGE		BIT(2)
+#define MTU3_EP_BUSY		BIT(3)
+
+/* should be set as 1 */
+#define MTU3_U2_IP_SLOT_DEFAULT 1
+#define MTU3_U3_IP_SLOT_DEFAULT (MTU3_U2_IP_SLOT_DEFAULT)
+
+/**
+ * IP TRUNK version
+ * from 0x1003 version, USB3 Gen2 is supported, two changes affect driver:
+ * 1. MAXPKT and MULTI bits layout of TXCSR1 and RXCSR1 are adjusted,
+ *    but not backward compatible
+ * 2. QMU extend buffer length supported
+ */
+#define MTU3_TRUNK_VERS_1003	0x1003
+
+/**
+ * Normally the device works on HS or SS, to simplify fifo management,
+ * devide fifo into some 2*maxp parts, use bitmap to manage it; And
+ * 32 bits size of bitmap is large enough, that means it can manage
+ * up to 32KB/64KB fifo size.
+ * NOTE: MTU3_U2/3IP_EP_FIFO_UNIT should be power of two;
+ *	FIFO size is allocated according to @slot which is 1 by default
+ */
+#define USB_HS_MAXP	512
+#define USB_SS_MAXP	1024
+#define MTU3_U2IP_EP_FIFO_UNIT	\
+	((USB_HS_MAXP) * ((MTU3_U2_IP_SLOT_DEFAULT) + 1))
+#define MTU3_U3IP_EP_FIFO_UNIT	\
+	((USB_SS_MAXP) * ((MTU3_U3_IP_SLOT_DEFAULT) + 1))
+
+#define MTU3_FIFO_BIT_SIZE		32
+#define MTU3_U2_IP_EP0_FIFO_SIZE	64
+
+/**
+ * Maximum size of ep0 response buffer for ch9 requests,
+ * the SET_SEL request uses 6 so far, and GET_STATUS is 2
+ */
+#define EP0_RESPONSE_BUF  6
+
+/* device operated link and speed got from DEVICE_CONF register */
+enum mtu3_speed {
+	MTU3_SPEED_INACTIVE = 0,
+	MTU3_SPEED_FULL = 1,
+	MTU3_SPEED_HIGH = 3,
+	MTU3_SPEED_SUPER = 4,
+	MTU3_SPEED_SUPER_PLUS = 5,
+};
+
+/**
+ * @MU3D_EP0_STATE_SETUP: waits for SETUP or received a SETUP
+ *		without data stage.
+ * @MU3D_EP0_STATE_TX: IN data stage
+ * @MU3D_EP0_STATE_RX: OUT data stage
+ * @MU3D_EP0_STATE_TX_END: the last IN data is transferred, and
+ *		waits for its completion interrupt
+ * @MU3D_EP0_STATE_STALL: ep0 is in stall status, will be auto-cleared
+ *		after receives a SETUP.
+ */
+enum mtu3_g_ep0_state {
+	MU3D_EP0_STATE_SETUP = 1,
+	MU3D_EP0_STATE_TX,
+	MU3D_EP0_STATE_RX,
+	MU3D_EP0_STATE_TX_END,
+	MU3D_EP0_STATE_STALL,
+};
+
+/**
+ * MTU3_DR_FORCE_NONE: automatically switch host and peripheral mode
+ *		by IDPIN signal.
+ * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
+ *		IDPIN signal.
+ * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
+ */
+enum mtu3_dr_force_mode {
+	MTU3_DR_FORCE_NONE = 0,
+	MTU3_DR_FORCE_HOST,
+	MTU3_DR_FORCE_DEVICE,
+};
+
+/**
+ * @mac_base: register base address of MAC, include xHCI and device
+ * @ippc_base: register base address of IP Power and Clock interface (IPPC)
+ * @vusb33_supply: usb3.3V shared by device/host IP
+ * @vbus_supply: vbus 5v of OTG port
+ * @clks: optional clocks, include "sys_ck", "ref_ck", "mcu_ck",
+ *		"dma_ck" and "xhci_ck"
+ * @phys: phys used
+ * @dr_mode: works in which mode:
+ *		host only, device only or dual-role mode
+ */
+struct ssusb_mtk {
+	struct udevice *dev;
+	struct mtu3 *u3d;
+	struct mtu3_host *u3h;
+	void __iomem *mac_base;
+	void __iomem *ippc_base;
+	/* common power & clock */
+	struct udevice *vusb33_supply;
+	struct udevice *vbus_supply;
+	struct clk_bulk clks;
+	struct phy_bulk phys;
+	/* otg */
+	enum usb_dr_mode dr_mode;
+};
+
+/**
+ * @ctrl: xHCI controller, needs to come first in this struct!
+ * @hcd: xHCI's register base address
+ * @u2_ports: number of usb2 host ports
+ * @u3_ports: number of usb3 host ports
+ * @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
+ *		disable u3port0, bit1==1 to disable u3port1,... etc
+ */
+struct mtu3_host {
+	struct xhci_ctrl ctrl;
+	struct xhci_hccr *hcd;
+	void __iomem *ippc_base;
+	struct ssusb_mtk *ssusb;
+	struct udevice *dev;
+	u32 u2_ports;
+	u32 u3_ports;
+	u32 u3p_dis_msk;
+};
+
+/**
+ * @base: the base address of fifo
+ * @limit: the bitmap size in bits
+ * @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
+ */
+struct mtu3_fifo_info {
+	u32 base;
+	u32 limit;
+	DECLARE_BITMAP(bitmap, MTU3_FIFO_BIT_SIZE);
+};
+
+/**
+ * General Purpose Descriptor (GPD):
+ *	The format of TX GPD is a little different from RX one.
+ *	And the size of GPD is 16 bytes.
+ *
+ * @flag:
+ *	bit0: Hardware Own (HWO)
+ *	bit1: Buffer Descriptor Present (BDP), always 0, BD is not supported
+ *	bit2: Bypass (BPS), 1: HW skips this GPD if HWO = 1
+ *	bit7: Interrupt On Completion (IOC)
+ * @chksum: This is used to validate the contents of this GPD;
+ *	If TXQ_CS_EN / RXQ_CS_EN bit is set, an interrupt is issued
+ *	when checksum validation fails;
+ *	Checksum value is calculated over the 16 bytes of the GPD by default;
+ * @data_buf_len (RX ONLY): This value indicates the length of
+ *	the assigned data buffer
+ * @next_gpd: Physical address of the next GPD
+ * @buffer: Physical address of the data buffer
+ * @buf_len:
+ *	(TX): This value indicates the length of the assigned data buffer
+ *	(RX): The total length of data received
+ * @ext_len: reserved
+ * @ext_flag:
+ *	bit5 (TX ONLY): Zero Length Packet (ZLP),
+ */
+struct qmu_gpd {
+	__u8 flag;
+	__u8 chksum;
+	__le16 data_buf_len;
+	__le32 next_gpd;
+	__le32 buffer;
+	__le16 buf_len;
+	__u8 ext_len;
+	__u8 ext_flag;
+} __packed;
+
+/**
+ * dma: physical base address of GPD segment
+ * start: virtual base address of GPD segment
+ * end: the last GPD element
+ * enqueue: the first empty GPD to use
+ * dequeue: the first completed GPD serviced by ISR
+ * NOTE: the size of GPD ring should be >= 2
+ */
+struct mtu3_gpd_ring {
+	dma_addr_t dma;
+	struct qmu_gpd *start;
+	struct qmu_gpd *end;
+	struct qmu_gpd *enqueue;
+	struct qmu_gpd *dequeue;
+};
+
+/**
+ * @fifo_size: it is (@slot + 1) * @fifo_seg_size
+ * @fifo_seg_size: it is roundup_pow_of_two(@maxp)
+ */
+struct mtu3_ep {
+	struct usb_ep ep;
+	char name[12];
+	struct mtu3 *mtu;
+	u8 epnum;
+	u8 type;
+	u8 is_in;
+	u16 maxp;
+	int slot;
+	u32 fifo_size;
+	u32 fifo_addr;
+	u32 fifo_seg_size;
+	struct mtu3_fifo_info *fifo;
+
+	struct list_head req_list;
+	struct mtu3_gpd_ring gpd_ring;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	const struct usb_endpoint_descriptor *desc;
+
+	int flags;
+};
+
+struct mtu3_request {
+	struct usb_request request;
+	struct list_head list;
+	struct mtu3_ep *mep;
+	struct mtu3 *mtu;
+	struct qmu_gpd *gpd;
+	int epnum;
+};
+
+static inline struct ssusb_mtk *dev_to_ssusb(struct udevice *dev)
+{
+	return dev_get_priv(dev);
+}
+
+/**
+ * struct mtu3 - device driver instance data.
+ * @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP only,
+ *		MTU3_U3_IP_SLOT_DEFAULT for U3 IP
+ * @may_wakeup: means device's remote wakeup is enabled
+ * @is_self_powered: is reported in device status and the config descriptor
+ * @delayed_status: true when function drivers ask for delayed status
+ * @gen2cp: compatible with USB3 Gen2 IP
+ * @ep0_req: dummy request used while handling standard USB requests
+ *		for GET_STATUS and SET_SEL
+ * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests
+ */
+struct mtu3 {
+	spinlock_t lock;
+	struct ssusb_mtk *ssusb;
+	struct udevice *dev;
+	void __iomem *mac_base;
+	void __iomem *ippc_base;
+	int irq;
+
+	struct mtu3_fifo_info tx_fifo;
+	struct mtu3_fifo_info rx_fifo;
+
+	struct mtu3_ep *ep_array;
+	struct mtu3_ep *in_eps;
+	struct mtu3_ep *out_eps;
+	struct mtu3_ep *ep0;
+	int num_eps;
+	int slot;
+	int active_ep;
+
+	enum mtu3_g_ep0_state ep0_state;
+	struct usb_gadget g;	/* the gadget */
+	struct usb_gadget_driver *gadget_driver;
+	struct mtu3_request ep0_req;
+	u8 setup_buf[EP0_RESPONSE_BUF];
+	enum usb_device_speed max_speed;
+	enum usb_device_speed speed;
+
+	unsigned is_active:1;
+	unsigned may_wakeup:1;
+	unsigned is_self_powered:1;
+	unsigned test_mode:1;
+	unsigned softconnect:1;
+	unsigned u1_enable:1;
+	unsigned u2_enable:1;
+	unsigned is_u3_ip:1;
+	unsigned delayed_status:1;
+	unsigned gen2cp:1;
+	unsigned force_vbus:1;
+
+	u8 address;
+	u8 test_mode_nr;
+	u32 hw_version;
+};
+
+static inline struct mtu3 *gadget_to_mtu3(struct usb_gadget *g)
+{
+	return container_of(g, struct mtu3, g);
+}
+
+static inline int is_first_entry(const struct list_head *list,
+				 const struct list_head *head)
+{
+	return list_is_last(head, list);
+}
+
+static inline struct mtu3_request *to_mtu3_request(struct usb_request *req)
+{
+	return req ? container_of(req, struct mtu3_request, request) : NULL;
+}
+
+static inline struct mtu3_ep *to_mtu3_ep(struct usb_ep *ep)
+{
+	return ep ? container_of(ep, struct mtu3_ep, ep) : NULL;
+}
+
+static inline struct mtu3_request *next_request(struct mtu3_ep *mep)
+{
+	if (list_empty(&mep->req_list))
+		return NULL;
+
+	return list_first_entry(&mep->req_list, struct mtu3_request, list);
+}
+
+static inline void mtu3_writel(void __iomem *base, u32 offset, u32 data)
+{
+	writel(data, base + offset);
+}
+
+static inline u32 mtu3_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void mtu3_setbits(void __iomem *base, u32 offset, u32 bits)
+{
+	void __iomem *addr = base + offset;
+	u32 tmp = readl(addr);
+
+	writel((tmp | (bits)), addr);
+}
+
+static inline void mtu3_clrbits(void __iomem *base, u32 offset, u32 bits)
+{
+	void __iomem *addr = base + offset;
+	u32 tmp = readl(addr);
+
+	writel((tmp & ~(bits)), addr);
+}
+
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks);
+struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+void mtu3_free_request(struct usb_ep *ep, struct usb_request *req);
+void mtu3_req_complete(struct mtu3_ep *mep,
+		       struct usb_request *req, int status);
+
+int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+		   int interval, int burst, int mult);
+void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep);
+void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set);
+void mtu3_ep0_setup(struct mtu3 *mtu);
+void mtu3_start(struct mtu3 *mtu);
+void mtu3_stop(struct mtu3 *mtu);
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on);
+void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed);
+
+int mtu3_gadget_setup(struct mtu3 *mtu);
+void mtu3_gadget_cleanup(struct mtu3 *mtu);
+void mtu3_gadget_reset(struct mtu3 *mtu);
+void mtu3_gadget_suspend(struct mtu3 *mtu);
+void mtu3_gadget_resume(struct mtu3 *mtu);
+void mtu3_gadget_disconnect(struct mtu3 *mtu);
+
+irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu);
+extern const struct usb_ep_ops mtu3_ep0_ops;
+
+#endif
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_core.c b/roms/u-boot/drivers/usb/mtu3/mtu3_core.c
new file mode 100644
index 000000000..2f5cc9b14
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_core.c
@@ -0,0 +1,838 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_core.c - hardware access layer and gadget init/exit of
+ *                     MediaTek usb3 Dual-Role Controller Driver
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/log2.h>
+#include <linux/bitmap.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size)
+{
+	struct mtu3_fifo_info *fifo = mep->fifo;
+	struct mtu3 *mtu = mep->mtu;
+	u32 fz_bit;
+
+	mep->fifo_seg_size = mtu->is_u3_ip ? USB_SS_MAXP : USB_HS_MAXP;
+
+	fz_bit = find_first_zero_bit(fifo->bitmap, fifo->limit);
+	if (fz_bit >= fifo->limit)
+		return -EOVERFLOW;
+
+	mep->fifo_size = mep->fifo_seg_size * (mep->slot + 1);
+	mep->fifo_addr = fifo->base + mep->fifo_size * fz_bit;
+	generic_set_bit(fz_bit, fifo->bitmap);
+
+	dev_dbg(mep->mtu->dev, "%s fifo:%#x/%#x, bit: %d\n",
+		__func__, mep->fifo_seg_size, mep->fifo_size, fz_bit);
+
+	return mep->fifo_addr;
+}
+
+static void ep_fifo_free(struct mtu3_ep *mep)
+{
+	struct mtu3_fifo_info *fifo = mep->fifo;
+	u32 addr = mep->fifo_addr;
+	u32 bit;
+
+	if (unlikely(addr < fifo->base))
+		return;
+
+	bit = (addr - fifo->base) / mep->fifo_size;
+	generic_clear_bit(bit, fifo->bitmap);
+	mep->fifo_size = 0;
+	mep->fifo_seg_size = 0;
+
+	dev_dbg(mep->mtu->dev, "%s size:%#x/%#x, bit: %d\n",
+		__func__, mep->fifo_seg_size, mep->fifo_size, bit);
+}
+
+/* enable/disable U3D SS function */
+static inline void mtu3_ss_func_set(struct mtu3 *mtu, bool enable)
+{
+	/* If usb3_en==0, LTSSM will go to SS.Disable state */
+	if (enable)
+		mtu3_setbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+	else
+		mtu3_clrbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+
+	dev_dbg(mtu->dev, "USB3_EN = %d\n", !!enable);
+}
+
+/* set/clear U3D HS device soft connect */
+static inline void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable)
+{
+	if (enable) {
+		mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
+			     SOFT_CONN | SUSPENDM_ENABLE);
+	} else {
+		mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
+			     SOFT_CONN | SUSPENDM_ENABLE);
+	}
+	dev_dbg(mtu->dev, "SOFTCONN = %d\n", !!enable);
+}
+
+/* only port0 of U2/U3 supports device mode */
+static int mtu3_device_enable(struct mtu3 *mtu)
+{
+	void __iomem *ibase = mtu->ippc_base;
+	u32 check_clk = 0;
+
+	mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+
+	if (mtu->is_u3_ip) {
+		check_clk = SSUSB_U3_MAC_RST_B_STS;
+		mtu3_clrbits(ibase, SSUSB_U3_CTRL(0),
+			     (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN |
+			      SSUSB_U3_PORT_HOST_SEL));
+	}
+	mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
+		     (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
+		      SSUSB_U2_PORT_HOST_SEL));
+
+	return ssusb_check_clocks(mtu->ssusb, check_clk);
+}
+
+static void mtu3_device_disable(struct mtu3 *mtu)
+{
+	void __iomem *ibase = mtu->ippc_base;
+
+	if (mtu->is_u3_ip)
+		mtu3_setbits(ibase, SSUSB_U3_CTRL(0),
+			     (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN));
+
+	mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
+		     SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
+
+	mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+}
+
+/* reset U3D's device module. */
+static void mtu3_device_reset(struct mtu3 *mtu)
+{
+	void __iomem *ibase = mtu->ippc_base;
+
+	mtu3_setbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST);
+	udelay(1);
+	mtu3_clrbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST);
+}
+
+static void mtu3_intr_status_clear(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	/* Clear EP0 and Tx/Rx EPn interrupts status */
+	mtu3_writel(mbase, U3D_EPISR, ~0x0);
+	/* Clear U2 USB common interrupts status */
+	mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);
+	/* Clear U3 LTSSM interrupts status */
+	mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);
+	/* Clear speed change interrupt status */
+	mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
+	/* Clear QMU interrupt status */
+	mtu3_writel(mbase, U3D_QISAR0, ~0x0);
+}
+
+/* disable all interrupts */
+static void mtu3_intr_disable(struct mtu3 *mtu)
+{
+	/* Disable level 1 interrupts */
+	mtu3_writel(mtu->mac_base, U3D_LV1IECR, ~0x0);
+	/* Disable endpoint interrupts */
+	mtu3_writel(mtu->mac_base, U3D_EPIECR, ~0x0);
+	mtu3_intr_status_clear(mtu);
+}
+
+/* enable system global interrupt */
+static void mtu3_intr_enable(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 value;
+
+	/*Enable level 1 interrupts (BMU, QMU, MAC3, DMA, MAC2, EPCTL) */
+	value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR;
+	mtu3_writel(mbase, U3D_LV1IESR, value);
+
+	/* Enable U2 common USB interrupts */
+	value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
+	mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value);
+
+	if (mtu->is_u3_ip) {
+		/* Enable U3 LTSSM interrupts */
+		value = HOT_RST_INTR | WARM_RST_INTR |
+			ENTER_U3_INTR | EXIT_U3_INTR;
+		mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value);
+	}
+
+	/* Enable QMU interrupts. */
+	value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT |
+			RXQ_LENERR_INT | RXQ_ZLPERR_INT;
+	mtu3_writel(mbase, U3D_QIESR1, value);
+
+	/* Enable speed change interrupt */
+	mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR);
+}
+
+void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	if (speed > mtu->max_speed)
+		speed = mtu->max_speed;
+
+	switch (speed) {
+	case USB_SPEED_FULL:
+		/* disable U3 SS function */
+		mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+		/* disable HS function */
+		mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+		break;
+	case USB_SPEED_HIGH:
+		mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+		/* HS/FS detected by HW */
+		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+		break;
+	case USB_SPEED_SUPER:
+		mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+			     SSUSB_U3_PORT_SSP_SPEED);
+		break;
+	case USB_SPEED_SUPER_PLUS:
+		mtu3_setbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+			     SSUSB_U3_PORT_SSP_SPEED);
+		break;
+	default:
+		dev_err(mtu->dev, "invalid speed: %d\n", speed);
+		return;
+	}
+
+	mtu->speed = speed;
+	dev_dbg(mtu->dev, "set speed: %s\n", usb_speed_string(mtu->speed));
+}
+
+/* reset: u2 - data toggle, u3 - SeqN, flow control status etc */
+static void mtu3_ep_reset(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	u32 rst_bit = EP_RST(mep->is_in, mep->epnum);
+
+	mtu3_setbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+	mtu3_clrbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+}
+
+/* set/clear the stall and toggle bits for non-ep0 */
+void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	u8 epnum = mep->epnum;
+	u32 csr;
+
+	if (mep->is_in) {	/* TX */
+		csr = mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)) & TX_W1C_BITS;
+		if (set)
+			csr |= TX_SENDSTALL;
+		else
+			csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL;
+		mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr);
+	} else {	/* RX */
+		csr = mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)) & RX_W1C_BITS;
+		if (set)
+			csr |= RX_SENDSTALL;
+		else
+			csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL;
+		mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr);
+	}
+
+	if (!set) {
+		mtu3_ep_reset(mep);
+		mep->flags &= ~MTU3_EP_STALL;
+	} else {
+		mep->flags |= MTU3_EP_STALL;
+	}
+
+	dev_dbg(mtu->dev, "%s: %s\n", mep->name,
+		set ? "SEND STALL" : "CLEAR STALL, with EP RESET");
+}
+
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
+{
+	if (mtu->is_u3_ip && mtu->speed >= USB_SPEED_SUPER)
+		mtu3_ss_func_set(mtu, is_on);
+	else
+		mtu3_hs_softconn_set(mtu, is_on);
+
+	dev_info(mtu->dev, "gadget (%s) pullup D%s\n",
+		 usb_speed_string(mtu->speed), is_on ? "+" : "-");
+}
+
+void mtu3_start(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	dev_dbg(mtu->dev, "%s devctl 0x%x\n", __func__,
+		mtu3_readl(mbase, U3D_DEVICE_CONTROL));
+
+	/* Initialize the default interrupts */
+	mtu3_intr_enable(mtu);
+	mtu->is_active = 1;
+
+	if (mtu->softconnect)
+		mtu3_dev_on_off(mtu, 1);
+}
+
+void mtu3_stop(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	mtu3_intr_disable(mtu);
+
+	if (mtu->softconnect)
+		mtu3_dev_on_off(mtu, 0);
+
+	mtu->is_active = 0;
+}
+
+/* for non-ep0 */
+int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+		   int interval, int burst, int mult)
+{
+	void __iomem *mbase = mtu->mac_base;
+	bool gen2cp = mtu->gen2cp;
+	int epnum = mep->epnum;
+	u32 csr0, csr1, csr2;
+	int fifo_sgsz, fifo_addr;
+	int num_pkts;
+
+	fifo_addr = ep_fifo_alloc(mep, mep->maxp);
+	if (fifo_addr < 0) {
+		dev_err(mtu->dev, "alloc ep fifo failed(%d)\n", mep->maxp);
+		return -ENOMEM;
+	}
+	fifo_sgsz = ilog2(mep->fifo_seg_size);
+	dev_dbg(mtu->dev, "%s fifosz: %x(%x/%x)\n", __func__, fifo_sgsz,
+		mep->fifo_seg_size, mep->fifo_size);
+
+	if (mep->is_in) {
+		csr0 = TX_TXMAXPKTSZ(mep->maxp);
+		csr0 |= TX_DMAREQEN;
+
+		num_pkts = (burst + 1) * (mult + 1) - 1;
+		csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot);
+		csr1 |= TX_MAX_PKT(gen2cp, num_pkts) | TX_MULT(gen2cp, mult);
+
+		csr2 = TX_FIFOADDR(fifo_addr >> 4);
+		csr2 |= TX_FIFOSEGSIZE(fifo_sgsz);
+
+		switch (mep->type) {
+		case USB_ENDPOINT_XFER_BULK:
+			csr1 |= TX_TYPE(TYPE_BULK);
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			csr1 |= TX_TYPE(TYPE_ISO);
+			csr2 |= TX_BINTERVAL(interval);
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			csr1 |= TX_TYPE(TYPE_INT);
+			csr2 |= TX_BINTERVAL(interval);
+			break;
+		}
+
+		/* Enable QMU Done interrupt */
+		mtu3_setbits(mbase, U3D_QIESR0, QMU_TX_DONE_INT(epnum));
+
+		mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr0);
+		mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), csr1);
+		mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), csr2);
+
+		dev_dbg(mtu->dev, "U3D_TX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n",
+			epnum, mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)),
+			mtu3_readl(mbase, MU3D_EP_TXCR1(epnum)),
+			mtu3_readl(mbase, MU3D_EP_TXCR2(epnum)));
+	} else {
+		csr0 = RX_RXMAXPKTSZ(mep->maxp);
+		csr0 |= RX_DMAREQEN;
+
+		num_pkts = (burst + 1) * (mult + 1) - 1;
+		csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot);
+		csr1 |= RX_MAX_PKT(gen2cp, num_pkts) | RX_MULT(gen2cp, mult);
+
+		csr2 = RX_FIFOADDR(fifo_addr >> 4);
+		csr2 |= RX_FIFOSEGSIZE(fifo_sgsz);
+
+		switch (mep->type) {
+		case USB_ENDPOINT_XFER_BULK:
+			csr1 |= RX_TYPE(TYPE_BULK);
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			csr1 |= RX_TYPE(TYPE_ISO);
+			csr2 |= RX_BINTERVAL(interval);
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			csr1 |= RX_TYPE(TYPE_INT);
+			csr2 |= RX_BINTERVAL(interval);
+			break;
+		}
+
+		/*Enable QMU Done interrupt */
+		mtu3_setbits(mbase, U3D_QIESR0, QMU_RX_DONE_INT(epnum));
+
+		mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr0);
+		mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), csr1);
+		mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), csr2);
+
+		dev_dbg(mtu->dev, "U3D_RX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n",
+			epnum, mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)),
+			mtu3_readl(mbase, MU3D_EP_RXCR1(epnum)),
+			mtu3_readl(mbase, MU3D_EP_RXCR2(epnum)));
+	}
+
+	dev_dbg(mtu->dev, "csr0:%#x, csr1:%#x, csr2:%#x\n", csr0, csr1, csr2);
+	dev_dbg(mtu->dev, "%s: %s, fifo-addr:%#x, fifo-size:%#x(%#x/%#x)\n",
+		__func__, mep->name, mep->fifo_addr, mep->fifo_size,
+		fifo_sgsz, mep->fifo_seg_size);
+
+	return 0;
+}
+
+/* for non-ep0 */
+void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep)
+{
+	void __iomem *mbase = mtu->mac_base;
+	int epnum = mep->epnum;
+
+	if (mep->is_in) {
+		mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), 0);
+		mtu3_setbits(mbase, U3D_QIECR0, QMU_TX_DONE_INT(epnum));
+	} else {
+		mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), 0);
+		mtu3_setbits(mbase, U3D_QIECR0, QMU_RX_DONE_INT(epnum));
+	}
+
+	mtu3_ep_reset(mep);
+	ep_fifo_free(mep);
+
+	dev_dbg(mtu->dev, "%s: %s\n", __func__, mep->name);
+}
+
+/*
+ * Two scenarios:
+ * 1. when device IP supports SS, the fifo of EP0, TX EPs, RX EPs
+ *	are separated;
+ * 2. when supports only HS, the fifo is shared for all EPs, and
+ *	the capability registers of @EPNTXFFSZ or @EPNRXFFSZ indicate
+ *	the total fifo size of non-ep0, and ep0's is fixed to 64B,
+ *	so the total fifo size is 64B + @EPNTXFFSZ;
+ *	Due to the first 64B should be reserved for EP0, non-ep0's fifo
+ *	starts from offset 64 and are divided into two equal parts for
+ *	TX or RX EPs for simplification.
+ */
+static void get_ep_fifo_config(struct mtu3 *mtu)
+{
+	struct mtu3_fifo_info *tx_fifo;
+	struct mtu3_fifo_info *rx_fifo;
+	u32 fifosize;
+
+	if (mtu->is_u3_ip) {
+		fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+		tx_fifo = &mtu->tx_fifo;
+		tx_fifo->base = 0;
+		tx_fifo->limit = fifosize / MTU3_U3IP_EP_FIFO_UNIT;
+		bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+		fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNRXFFSZ);
+		rx_fifo = &mtu->rx_fifo;
+		rx_fifo->base = 0;
+		rx_fifo->limit = fifosize / MTU3_U3IP_EP_FIFO_UNIT;
+		bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+		mtu->slot = MTU3_U3_IP_SLOT_DEFAULT;
+	} else {
+		fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+		tx_fifo = &mtu->tx_fifo;
+		tx_fifo->base = MTU3_U2_IP_EP0_FIFO_SIZE;
+		tx_fifo->limit = (fifosize / MTU3_U2IP_EP_FIFO_UNIT) >> 1;
+		bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+		rx_fifo = &mtu->rx_fifo;
+		rx_fifo->base = tx_fifo->base +
+				tx_fifo->limit * MTU3_U2IP_EP_FIFO_UNIT;
+		rx_fifo->limit = tx_fifo->limit;
+		bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+		mtu->slot = MTU3_U2_IP_SLOT_DEFAULT;
+	}
+
+	dev_dbg(mtu->dev, "%s, TX: base-%d, limit-%d; RX: base-%d, limit-%d\n",
+		__func__, tx_fifo->base, tx_fifo->limit,
+		rx_fifo->base, rx_fifo->limit);
+}
+
+void mtu3_ep0_setup(struct mtu3 *mtu)
+{
+	u32 maxpacket = mtu->g.ep0->maxpacket;
+	u32 csr;
+
+	dev_dbg(mtu->dev, "%s maxpacket: %d\n", __func__, maxpacket);
+
+	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR);
+	csr &= ~EP0_MAXPKTSZ_MSK;
+	csr |= EP0_MAXPKTSZ(maxpacket);
+	csr &= EP0_W1C_BITS;
+	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
+
+	/* Enable EP0 interrupt */
+	mtu3_writel(mtu->mac_base, U3D_EPIESR, EP0ISR | SETUPENDISR);
+}
+
+static int mtu3_mem_alloc(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	struct mtu3_ep *ep_array;
+	int in_ep_num, out_ep_num;
+	u32 cap_epinfo;
+	int i;
+
+	cap_epinfo = mtu3_readl(mbase, U3D_CAP_EPINFO);
+	in_ep_num = CAP_TX_EP_NUM(cap_epinfo);
+	out_ep_num = CAP_RX_EP_NUM(cap_epinfo);
+
+	dev_info(mtu->dev, "fifosz/epnum: Tx=%#x/%d, Rx=%#x/%d\n",
+		 mtu3_readl(mbase, U3D_CAP_EPNTXFFSZ), in_ep_num,
+		 mtu3_readl(mbase, U3D_CAP_EPNRXFFSZ), out_ep_num);
+
+	/* one for ep0, another is reserved */
+	mtu->num_eps = min(in_ep_num, out_ep_num) + 1;
+	ep_array = kcalloc(mtu->num_eps * 2, sizeof(*ep_array), GFP_KERNEL);
+	if (!ep_array)
+		return -ENOMEM;
+
+	mtu->ep_array = ep_array;
+	mtu->in_eps = ep_array;
+	mtu->out_eps = &ep_array[mtu->num_eps];
+	/* ep0 uses in_eps[0], out_eps[0] is reserved */
+	mtu->ep0 = mtu->in_eps;
+	mtu->ep0->mtu = mtu;
+	mtu->ep0->epnum = 0;
+
+	for (i = 1; i < mtu->num_eps; i++) {
+		struct mtu3_ep *mep = mtu->in_eps + i;
+
+		mep->fifo = &mtu->tx_fifo;
+		mep = mtu->out_eps + i;
+		mep->fifo = &mtu->rx_fifo;
+	}
+
+	get_ep_fifo_config(mtu);
+	mtu3_qmu_init(mtu);
+
+	return 0;
+}
+
+static void mtu3_mem_free(struct mtu3 *mtu)
+{
+	mtu3_qmu_exit(mtu);
+	kfree(mtu->ep_array);
+}
+
+static void mtu3_regs_init(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	/* be sure interrupts are disabled before registration of ISR */
+	mtu3_intr_disable(mtu);
+
+	if (mtu->is_u3_ip) {
+		/* disable LGO_U1/U2 by default */
+		mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL,
+			     SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE);
+		/* enable accept LGO_U1/U2 link command from host */
+		mtu3_setbits(mbase, U3D_LINK_POWER_CONTROL,
+			     SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE);
+		/* device responses to u3_exit from host automatically */
+		mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN);
+		/* automatically build U2 link when U3 detect fail */
+		mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH);
+		/* auto clear SOFT_CONN when clear USB3_EN if work as HS */
+		mtu3_setbits(mbase, U3D_U3U2_SWITCH_CTRL, SOFTCON_CLR_AUTO_EN);
+	}
+
+	/* delay about 0.1us from detecting reset to send chirp-K */
+	mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
+	/* U2/U3 detected by HW */
+	mtu3_writel(mbase, U3D_DEVICE_CONF, 0);
+	/* enable automatical HWRW from L1 */
+	mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE);
+
+	mtu3_set_speed(mtu, mtu->max_speed);
+	ssusb_set_force_mode(mtu->ssusb, MTU3_DR_FORCE_DEVICE);
+
+	if (mtu->force_vbus)
+		mtu3_setbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
+	else	/* vbus detected by HW */
+		mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
+}
+
+static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	enum usb_device_speed udev_speed;
+	u32 maxpkt = 64;
+	u32 link;
+	u32 speed;
+
+	link = mtu3_readl(mbase, U3D_DEV_LINK_INTR);
+	link &= mtu3_readl(mbase, U3D_DEV_LINK_INTR_ENABLE);
+	mtu3_writel(mbase, U3D_DEV_LINK_INTR, link); /* W1C */
+	dev_dbg(mtu->dev, "=== LINK[%x] ===\n", link);
+
+	if (!(link & SSUSB_DEV_SPEED_CHG_INTR))
+		return IRQ_NONE;
+
+	speed = SSUSB_DEV_SPEED(mtu3_readl(mbase, U3D_DEVICE_CONF));
+
+	switch (speed) {
+	case MTU3_SPEED_FULL:
+		udev_speed = USB_SPEED_FULL;
+		/*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */
+		mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf)
+			    | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa));
+		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
+			     LPM_BESL_STALL | LPM_BESLD_STALL);
+		break;
+	case MTU3_SPEED_HIGH:
+		udev_speed = USB_SPEED_HIGH;
+		/*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */
+		mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf)
+			    | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa));
+		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
+			     LPM_BESL_STALL | LPM_BESLD_STALL);
+		break;
+	case MTU3_SPEED_SUPER:
+		udev_speed = USB_SPEED_SUPER;
+		maxpkt = 512;
+		break;
+	case MTU3_SPEED_SUPER_PLUS:
+		udev_speed = USB_SPEED_SUPER_PLUS;
+		maxpkt = 512;
+		break;
+	default:
+		udev_speed = USB_SPEED_UNKNOWN;
+		break;
+	}
+	dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed));
+
+	mtu->g.speed = udev_speed;
+	mtu->g.ep0->maxpacket = maxpkt;
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+	if (udev_speed == USB_SPEED_UNKNOWN)
+		mtu3_gadget_disconnect(mtu);
+	else
+		mtu3_ep0_setup(mtu);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 ltssm;
+
+	ltssm = mtu3_readl(mbase, U3D_LTSSM_INTR);
+	ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE);
+	mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */
+	dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm);
+
+	if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
+		mtu3_gadget_reset(mtu);
+
+	if (ltssm & VBUS_FALL_INTR) {
+		mtu3_ss_func_set(mtu, false);
+		mtu3_gadget_reset(mtu);
+	}
+
+	if (ltssm & VBUS_RISE_INTR)
+		mtu3_ss_func_set(mtu, true);
+
+	if (ltssm & EXIT_U3_INTR)
+		mtu3_gadget_resume(mtu);
+
+	if (ltssm & ENTER_U3_INTR)
+		mtu3_gadget_suspend(mtu);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 u2comm;
+
+	u2comm = mtu3_readl(mbase, U3D_COMMON_USB_INTR);
+	u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE);
+	mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */
+	dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm);
+
+	if (u2comm & SUSPEND_INTR)
+		mtu3_gadget_suspend(mtu);
+
+	if (u2comm & RESUME_INTR)
+		mtu3_gadget_resume(mtu);
+
+	if (u2comm & RESET_INTR)
+		mtu3_gadget_reset(mtu);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t mtu3_irq(int irq, void *data)
+{
+	struct mtu3 *mtu = (struct mtu3 *)data;
+	unsigned long flags;
+	u32 level1;
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	/* U3D_LV1ISR is RU */
+	level1 = mtu3_readl(mtu->mac_base, U3D_LV1ISR);
+	level1 &= mtu3_readl(mtu->mac_base, U3D_LV1IER);
+
+	if (level1 & EP_CTRL_INTR)
+		mtu3_link_isr(mtu);
+
+	if (level1 & MAC2_INTR)
+		mtu3_u2_common_isr(mtu);
+
+	if (level1 & MAC3_INTR)
+		mtu3_u3_ltssm_isr(mtu);
+
+	if (level1 & BMU_INTR)
+		mtu3_ep0_isr(mtu);
+
+	if (level1 & QMU_INTR)
+		mtu3_qmu_isr(mtu);
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void mtu3_check_params(struct mtu3 *mtu)
+{
+	/* check the max_speed parameter */
+	switch (mtu->max_speed) {
+	case USB_SPEED_FULL:
+	case USB_SPEED_HIGH:
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		break;
+	default:
+		dev_err(mtu->dev, "invalid max_speed: %d\n", mtu->max_speed);
+		/* fall through */
+	case USB_SPEED_UNKNOWN:
+		/* default as SS */
+		mtu->max_speed = USB_SPEED_SUPER;
+		break;
+	}
+
+	if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH))
+		mtu->max_speed = USB_SPEED_HIGH;
+
+	mtu->speed = mtu->max_speed;
+
+	dev_info(mtu->dev, "max_speed: %s\n", usb_speed_string(mtu->speed));
+}
+
+static int mtu3_hw_init(struct mtu3 *mtu)
+{
+	u32 value;
+	int ret;
+
+	value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_TRUNK_VERS);
+	mtu->hw_version = IP_TRUNK_VERS(value);
+	mtu->gen2cp = !!(mtu->hw_version >= MTU3_TRUNK_VERS_1003);
+
+	value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
+	mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value);
+
+	dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version,
+		 mtu->is_u3_ip ? "U3" : "U2");
+
+	mtu3_check_params(mtu);
+
+	mtu3_device_reset(mtu);
+
+	ret = mtu3_device_enable(mtu);
+	if (ret) {
+		dev_err(mtu->dev, "device enable failed %d\n", ret);
+		return ret;
+	}
+
+	ret = mtu3_mem_alloc(mtu);
+	if (ret)
+		return ret;
+
+	mtu3_regs_init(mtu);
+
+	return 0;
+}
+
+static void mtu3_hw_exit(struct mtu3 *mtu)
+{
+	mtu3_device_disable(mtu);
+	mtu3_mem_free(mtu);
+}
+
+int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+	struct mtu3 *mtu = ssusb->u3d;
+	struct udevice *dev = mtu->dev;
+	int ret = -ENOMEM;
+
+	spin_lock_init(&mtu->lock);
+	mtu->ippc_base = ssusb->ippc_base;
+	mtu->mac_base = ssusb->mac_base;
+	mtu->ssusb = ssusb;
+	mtu->max_speed = usb_get_maximum_speed(dev_ofnode(dev));
+	mtu->force_vbus = dev_read_bool(dev, "mediatek,force-vbus");
+
+	ret = mtu3_hw_init(mtu);
+	if (ret) {
+		dev_err(dev, "mtu3 hw init failed:%d\n", ret);
+		return ret;
+	}
+
+	ret = mtu3_gadget_setup(mtu);
+	if (ret) {
+		dev_err(dev, "mtu3 gadget init failed:%d\n", ret);
+		goto gadget_err;
+	}
+
+	dev_info(dev, "%s() done...\n", __func__);
+
+	return 0;
+
+gadget_err:
+	mtu3_hw_exit(mtu);
+	ssusb->u3d = NULL;
+	dev_err(dev, "%s() fail...\n", __func__);
+
+	return ret;
+}
+
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{
+	struct mtu3 *mtu = ssusb->u3d;
+
+	mtu3_gadget_cleanup(mtu);
+	mtu3_hw_exit(mtu);
+}
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_dr.h b/roms/u-boot/drivers/usb/mtu3/mtu3_dr.h
new file mode 100644
index 000000000..ec0e50c04
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_dr.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_dr.h - dual role switch and host glue layer header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef _MTU3_DR_H_
+#define _MTU3_DR_H_
+
+#if IS_ENABLED(CONFIG_USB_MTU3_HOST)
+
+int ssusb_host_init(struct ssusb_mtk *ssusb);
+void ssusb_host_exit(struct ssusb_mtk *ssusb);
+
+#else
+
+static inline int ssusb_host_init(struct ssusb_mtk *ssusb)
+{
+	return 0;
+}
+
+static inline void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{}
+
+#endif
+
+#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
+int ssusb_gadget_init(struct ssusb_mtk *ssusb);
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
+irqreturn_t mtu3_irq(int irq, void *data);
+#else
+static inline int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+	return 0;
+}
+
+static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{}
+
+static inline irqreturn_t mtu3_irq(int irq, void *data)
+{
+	return IRQ_NONE;
+}
+#endif
+
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+			  enum mtu3_dr_force_mode mode);
+
+#endif		/* _MTU3_DR_H_ */
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_gadget.c b/roms/u-boot/drivers/usb/mtu3/mtu3_gadget.c
new file mode 100644
index 000000000..027b7e611
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_gadget.c
@@ -0,0 +1,686 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_gadget.c - MediaTek usb3 DRD peripheral support
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include "mtu3.h"
+
+void mtu3_req_complete(struct mtu3_ep *mep,
+		       struct usb_request *req, int status)
+__releases(mep->mtu->lock)
+__acquires(mep->mtu->lock)
+{
+	struct mtu3_request *mreq = to_mtu3_request(req);
+	struct mtu3 *mtu = mreq->mtu;
+
+	list_del(&mreq->list);
+	if (req->status == -EINPROGRESS)
+		req->status = status;
+
+	spin_unlock(&mtu->lock);
+
+	/* ep0 makes use of PIO, needn't unmap it */
+	if (mep->epnum)
+		usb_gadget_unmap_request(&mtu->g, req, mep->is_in);
+
+	dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n",
+		mep->name, req, req->status, req->actual, req->length);
+
+	usb_gadget_giveback_request(&mep->ep, req);
+	spin_lock(&mtu->lock);
+}
+
+static void nuke(struct mtu3_ep *mep, const int status)
+{
+	struct mtu3_request *mreq = NULL;
+
+	if (list_empty(&mep->req_list))
+		return;
+
+	dev_dbg(mep->mtu->dev, "abort %s's req: sts %d\n", mep->name, status);
+
+	/* exclude EP0 */
+	if (mep->epnum)
+		mtu3_qmu_flush(mep);
+
+	while (!list_empty(&mep->req_list)) {
+		mreq = list_first_entry(&mep->req_list,
+					struct mtu3_request, list);
+		mtu3_req_complete(mep, &mreq->request, status);
+	}
+}
+
+static int mtu3_ep_enable(struct mtu3_ep *mep)
+{
+	const struct usb_endpoint_descriptor *desc;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	struct mtu3 *mtu = mep->mtu;
+	u32 interval = 0;
+	u32 mult = 0;
+	u32 burst = 0;
+	int max_packet;
+	int ret;
+
+	desc = mep->desc;
+	comp_desc = mep->comp_desc;
+	mep->type = usb_endpoint_type(desc);
+	max_packet = usb_endpoint_maxp(desc);
+	mep->maxp = max_packet & GENMASK(10, 0);
+
+	switch (mtu->g.speed) {
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		if (usb_endpoint_xfer_int(desc) ||
+		    usb_endpoint_xfer_isoc(desc)) {
+			interval = desc->bInterval;
+			interval = clamp_val(interval, 1, 16) - 1;
+			if (usb_endpoint_xfer_isoc(desc) && comp_desc)
+				mult = comp_desc->bmAttributes;
+		}
+		if (comp_desc)
+			burst = comp_desc->bMaxBurst;
+
+		break;
+	case USB_SPEED_HIGH:
+		if (usb_endpoint_xfer_isoc(desc) ||
+		    usb_endpoint_xfer_int(desc)) {
+			interval = desc->bInterval;
+			interval = clamp_val(interval, 1, 16) - 1;
+			burst = (max_packet & GENMASK(12, 11)) >> 11;
+		}
+		break;
+	default:
+		break; /*others are ignored */
+	}
+
+	dev_dbg(mtu->dev, "%s maxp:%d, interval:%d, burst:%d, mult:%d\n",
+		__func__, mep->maxp, interval, burst, mult);
+
+	mep->ep.maxpacket = mep->maxp;
+	mep->ep.desc = desc;
+	mep->ep.comp_desc = comp_desc;
+	mep->slot = mtu->slot;
+
+	ret = mtu3_config_ep(mtu, mep, interval, burst, mult);
+	if (ret < 0)
+		return ret;
+
+	ret = mtu3_gpd_ring_alloc(mep);
+	if (ret < 0) {
+		mtu3_deconfig_ep(mtu, mep);
+		return ret;
+	}
+
+	mtu3_qmu_start(mep);
+
+	return 0;
+}
+
+static int mtu3_ep_disable(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+
+	mtu3_qmu_stop(mep);
+
+	/* abort all pending requests */
+	nuke(mep, -ESHUTDOWN);
+	mtu3_deconfig_ep(mtu, mep);
+	mtu3_gpd_ring_free(mep);
+
+	mep->desc = NULL;
+	mep->ep.desc = NULL;
+	mep->comp_desc = NULL;
+	mep->type = 0;
+	mep->flags = 0;
+
+	return 0;
+}
+
+static int mtu3_gadget_ep_enable(struct usb_ep *ep,
+				 const struct usb_endpoint_descriptor *desc)
+{
+	struct mtu3_ep *mep;
+	struct mtu3 *mtu;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+		pr_debug("%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!desc->wMaxPacketSize) {
+		pr_debug("%s missing wMaxPacketSize\n", __func__);
+		return -EINVAL;
+	}
+	mep = to_mtu3_ep(ep);
+	mtu = mep->mtu;
+
+	/* check ep number and direction against endpoint */
+	if (usb_endpoint_num(desc) != mep->epnum)
+		return -EINVAL;
+
+	if (!!usb_endpoint_dir_in(desc) ^ !!mep->is_in)
+		return -EINVAL;
+
+	dev_dbg(mtu->dev, "%s %s\n", __func__, ep->name);
+
+	if (mep->flags & MTU3_EP_ENABLED) {
+		dev_warn(mtu->dev, "%s is already enabled\n", mep->name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	mep->desc = desc;
+	mep->comp_desc = ep->comp_desc;
+
+	ret = mtu3_ep_enable(mep);
+	if (ret)
+		goto error;
+
+	mep->flags = MTU3_EP_ENABLED;
+	mtu->active_ep++;
+
+error:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep);
+
+	return ret;
+}
+
+static int mtu3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3 *mtu = mep->mtu;
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name);
+
+	if (!(mep->flags & MTU3_EP_ENABLED)) {
+		dev_warn(mtu->dev, "%s is already disabled\n", mep->name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	mtu3_ep_disable(mep);
+	mep->flags = 0;
+	mtu->active_ep--;
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	dev_dbg(mtu->dev, "%s active_ep=%d, mtu3 is_active=%d\n",
+		__func__, mtu->active_ep, mtu->is_active);
+
+	return 0;
+}
+
+struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3_request *mreq;
+
+	mreq = kzalloc(sizeof(*mreq), gfp_flags);
+	if (!mreq)
+		return NULL;
+
+	mreq->request.dma = DMA_ADDR_INVALID;
+	mreq->epnum = mep->epnum;
+	mreq->mep = mep;
+
+	return &mreq->request;
+}
+
+void mtu3_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mtu3_request *mreq = to_mtu3_request(req);
+
+	kfree(mreq);
+}
+
+static int mtu3_gadget_queue(struct usb_ep *ep,
+			     struct usb_request *req, gfp_t gfp_flags)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3_request *mreq = to_mtu3_request(req);
+	struct mtu3 *mtu = mep->mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!req->buf)
+		return -ENODATA;
+
+	if (mreq->mep != mep)
+		return -EINVAL;
+
+	dev_dbg(mtu->dev, "%s %s EP%d(%s), req=%p, maxp=%d, len#%d\n",
+		__func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name,
+		mreq, ep->maxpacket, mreq->request.length);
+
+	if (req->length > GPD_BUF_SIZE) {
+		dev_warn(mtu->dev,
+			 "req length > supported MAX:%d requested:%d\n",
+			 GPD_BUF_SIZE, req->length);
+		return -EOPNOTSUPP;
+	}
+
+	/* don't queue if the ep is down */
+	if (!mep->desc) {
+		dev_dbg(mtu->dev, "req=%p queued to %s while it's disabled\n",
+			req, ep->name);
+		return -ESHUTDOWN;
+	}
+
+	mreq->mtu = mtu;
+	mreq->request.actual = 0;
+	mreq->request.status = -EINPROGRESS;
+
+	ret = usb_gadget_map_request(&mtu->g, req, mep->is_in);
+	if (ret) {
+		dev_err(mtu->dev, "dma mapping failed\n");
+		return ret;
+	}
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	if (mtu3_prepare_transfer(mep)) {
+		ret = -EAGAIN;
+		goto error;
+	}
+
+	list_add_tail(&mreq->list, &mep->req_list);
+	mtu3_insert_gpd(mep, mreq);
+	mtu3_qmu_resume(mep);
+
+error:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+
+static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3_request *mreq = to_mtu3_request(req);
+	struct mtu3_request *r;
+	struct mtu3 *mtu = mep->mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (mreq->mep != mep)
+		return -EINVAL;
+
+	dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	list_for_each_entry(r, &mep->req_list, list) {
+		if (r == mreq)
+			break;
+	}
+	if (r != mreq) {
+		dev_dbg(mtu->dev, "req=%p not queued to %s\n", req, ep->name);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mtu3_qmu_flush(mep);  /* REVISIT: set BPS ?? */
+	mtu3_req_complete(mep, req, -ECONNRESET);
+	mtu3_qmu_start(mep);
+
+done:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+
+/*
+ * Set or clear the halt bit of an EP.
+ * A halted EP won't TX/RX any data but will queue requests.
+ */
+static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3 *mtu = mep->mtu;
+	struct mtu3_request *mreq;
+	unsigned long flags = 0;
+	int ret = 0;
+
+	dev_dbg(mtu->dev, "%s : %s...", __func__, ep->name);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	if (mep->type == USB_ENDPOINT_XFER_ISOC) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mreq = next_request(mep);
+	if (value) {
+		/*
+		 * If there is not request for TX-EP, QMU will not transfer
+		 * data to TX-FIFO, so no need check whether TX-FIFO
+		 * holds bytes or not here
+		 */
+		if (mreq) {
+			dev_dbg(mtu->dev, "req in progress, cannot halt %s\n",
+				ep->name);
+			ret = -EAGAIN;
+			goto done;
+		}
+	} else {
+		mep->flags &= ~MTU3_EP_WEDGE;
+	}
+
+	dev_dbg(mtu->dev, "%s %s stall\n", ep->name, value ? "set" : "clear");
+
+	mtu3_ep_stall_set(mep, value);
+
+done:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+
+/* Sets the halt feature with the clear requests ignored */
+static int mtu3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+
+	mep->flags |= MTU3_EP_WEDGE;
+
+	return usb_ep_set_halt(ep);
+}
+
+static const struct usb_ep_ops mtu3_ep_ops = {
+	.enable = mtu3_gadget_ep_enable,
+	.disable = mtu3_gadget_ep_disable,
+	.alloc_request = mtu3_alloc_request,
+	.free_request = mtu3_free_request,
+	.queue = mtu3_gadget_queue,
+	.dequeue = mtu3_gadget_dequeue,
+	.set_halt = mtu3_gadget_ep_set_halt,
+	.set_wedge = mtu3_gadget_ep_set_wedge,
+};
+
+static int mtu3_gadget_get_frame(struct usb_gadget *gadget)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+
+	return (int)mtu3_readl(mtu->mac_base, U3D_USB20_FRAME_NUM);
+}
+
+static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	/* remote wakeup feature is not enabled by host */
+	if (!mtu->may_wakeup)
+		return  -EOPNOTSUPP;
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	if (mtu->g.speed >= USB_SPEED_SUPER) {
+		mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
+	} else {
+		mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+		spin_unlock_irqrestore(&mtu->lock, flags);
+		mdelay(10);
+		spin_lock_irqsave(&mtu->lock, flags);
+		mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+	}
+	spin_unlock_irqrestore(&mtu->lock, flags);
+	return 0;
+}
+
+static int mtu3_gadget_set_self_powered(struct usb_gadget *gadget,
+					int is_selfpowered)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+
+	mtu->is_self_powered = !!is_selfpowered;
+	return 0;
+}
+
+static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s (%s) for %sactive device\n", __func__,
+		is_on ? "on" : "off", mtu->is_active ? "" : "in");
+
+	/* we'd rather not pullup unless the device is active. */
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	is_on = !!is_on;
+	if (!mtu->is_active) {
+		/* save it for mtu3_start() to process the request */
+		mtu->softconnect = is_on;
+	} else if (is_on != mtu->softconnect) {
+		mtu->softconnect = is_on;
+		mtu3_dev_on_off(mtu, is_on);
+	}
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return 0;
+}
+
+static int mtu3_gadget_start(struct usb_gadget *gadget,
+			     struct usb_gadget_driver *driver)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+	unsigned long flags;
+
+	if (mtu->gadget_driver) {
+		dev_err(mtu->dev, "%s is already bound to %s\n",
+			mtu->g.name, mtu->gadget_driver->function);
+		return -EBUSY;
+	}
+
+	dev_dbg(mtu->dev, "bind driver %s\n", driver->function);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	mtu->softconnect = 0;
+	mtu->gadget_driver = driver;
+	mtu3_start(mtu);
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return 0;
+}
+
+static void stop_activity(struct mtu3 *mtu)
+{
+	int i;
+
+	mtu->g.speed = USB_SPEED_UNKNOWN;
+
+	/* deactivate the hardware */
+	if (mtu->softconnect) {
+		mtu->softconnect = 0;
+		mtu3_dev_on_off(mtu, 0);
+	}
+
+	/*
+	 * killing any outstanding requests will quiesce the driver;
+	 * then report disconnect
+	 */
+	nuke(mtu->ep0, -ESHUTDOWN);
+	for (i = 1; i < mtu->num_eps; i++) {
+		nuke(mtu->in_eps + i, -ESHUTDOWN);
+		nuke(mtu->out_eps + i, -ESHUTDOWN);
+	}
+}
+
+static int mtu3_gadget_stop(struct usb_gadget *g)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(g);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	stop_activity(mtu);
+	mtu->gadget_driver = NULL;
+	mtu3_stop(mtu);
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return 0;
+}
+
+static void
+mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(g);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s %d\n", __func__, speed);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	mtu3_set_speed(mtu, speed);
+	spin_unlock_irqrestore(&mtu->lock, flags);
+}
+
+static const struct usb_gadget_ops mtu3_gadget_ops = {
+	.get_frame = mtu3_gadget_get_frame,
+	.wakeup = mtu3_gadget_wakeup,
+	.set_selfpowered = mtu3_gadget_set_self_powered,
+	.pullup = mtu3_gadget_pullup,
+	.udc_start = mtu3_gadget_start,
+	.udc_stop = mtu3_gadget_stop,
+	.udc_set_speed = mtu3_gadget_set_speed,
+};
+
+static void mtu3_state_reset(struct mtu3 *mtu)
+{
+	mtu->address = 0;
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+	mtu->may_wakeup = 0;
+	mtu->u1_enable = 0;
+	mtu->u2_enable = 0;
+	mtu->delayed_status = false;
+	mtu->test_mode = false;
+}
+
+static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+		       u32 epnum, u32 is_in)
+{
+	mep->epnum = epnum;
+	mep->mtu = mtu;
+	mep->is_in = is_in;
+
+	INIT_LIST_HEAD(&mep->req_list);
+
+	sprintf(mep->name, "ep%d%s", epnum,
+		!epnum ? "" : (is_in ? "in" : "out"));
+
+	mep->ep.name = mep->name;
+	INIT_LIST_HEAD(&mep->ep.ep_list);
+
+	/* initialize maxpacket as SS */
+	if (!epnum) {
+		usb_ep_set_maxpacket_limit(&mep->ep, USB_HS_MAXP);
+		mep->ep.ops = &mtu3_ep0_ops;
+		mtu->g.ep0 = &mep->ep;
+	} else {
+		usb_ep_set_maxpacket_limit(&mep->ep, USB_SS_MAXP);
+		mep->ep.ops = &mtu3_ep_ops;
+		list_add_tail(&mep->ep.ep_list, &mtu->g.ep_list);
+	}
+
+	dev_dbg(mtu->dev, "%s, name=%s, maxp=%d\n", __func__, mep->ep.name,
+		mep->ep.maxpacket);
+}
+
+static void mtu3_gadget_init_eps(struct mtu3 *mtu)
+{
+	u8 epnum;
+
+	/* initialize endpoint list just once */
+	INIT_LIST_HEAD(&mtu->g.ep_list);
+
+	dev_dbg(mtu->dev, "%s num_eps(1 for a pair of tx&rx ep)=%d\n",
+		__func__, mtu->num_eps);
+
+	init_hw_ep(mtu, mtu->ep0, 0, 0);
+	for (epnum = 1; epnum < mtu->num_eps; epnum++) {
+		init_hw_ep(mtu, mtu->in_eps + epnum, epnum, 1);
+		init_hw_ep(mtu, mtu->out_eps + epnum, epnum, 0);
+	}
+}
+
+int mtu3_gadget_setup(struct mtu3 *mtu)
+{
+	mtu->g.ops = &mtu3_gadget_ops;
+	mtu->g.max_speed = mtu->max_speed;
+	mtu->g.speed = USB_SPEED_UNKNOWN;
+	mtu->g.is_dualspeed = 1;
+	mtu->g.name = MTU3_DRIVER_NAME;
+	mtu->is_active = 0;
+	mtu->delayed_status = false;
+
+	mtu3_gadget_init_eps(mtu);
+
+	return usb_add_gadget_udc((struct device *)mtu->dev, &mtu->g);
+}
+
+void mtu3_gadget_cleanup(struct mtu3 *mtu)
+{
+	usb_del_gadget_udc(&mtu->g);
+}
+
+void mtu3_gadget_resume(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget RESUME\n");
+	if (mtu->gadget_driver && mtu->gadget_driver->resume) {
+		spin_unlock(&mtu->lock);
+		mtu->gadget_driver->resume(&mtu->g);
+		spin_lock(&mtu->lock);
+	}
+}
+
+/* called when SOF packets stop for 3+ msec or enters U3 */
+void mtu3_gadget_suspend(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget SUSPEND\n");
+	if (mtu->gadget_driver && mtu->gadget_driver->suspend) {
+		spin_unlock(&mtu->lock);
+		mtu->gadget_driver->suspend(&mtu->g);
+		spin_lock(&mtu->lock);
+	}
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void mtu3_gadget_disconnect(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget DISCONNECT\n");
+	if (mtu->gadget_driver && mtu->gadget_driver->disconnect) {
+		spin_unlock(&mtu->lock);
+		mtu->gadget_driver->disconnect(&mtu->g);
+		spin_lock(&mtu->lock);
+	}
+
+	mtu3_state_reset(mtu);
+	usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED);
+}
+
+void mtu3_gadget_reset(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget RESET\n");
+
+	/* report disconnect, if we didn't flush EP state */
+	if (mtu->g.speed != USB_SPEED_UNKNOWN)
+		mtu3_gadget_disconnect(mtu);
+	else
+		mtu3_state_reset(mtu);
+}
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_gadget_ep0.c b/roms/u-boot/drivers/usb/mtu3/mtu3_gadget_ep0.c
new file mode 100644
index 000000000..4b0bc5f02
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -0,0 +1,933 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Author:  Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/iopoll.h>
+#include <linux/usb/composite.h>
+
+#include "mtu3.h"
+
+/* ep0 is always mtu3->in_eps[0] */
+#define	next_ep0_request(mtu)	next_request((mtu)->ep0)
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 mtu3_test_packet[53] = {
+	/* implicit SYNC then DATA0 to start */
+
+	/* JKJKJKJK x9 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* JJKKJJKK x8 */
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	/* JJJJKKKK x8 */
+	0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+	/* JJJJJJJKKKKKKK x8 */
+	0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	/* JJJJJJJK x8 */
+	0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+	/* JKKKKKKK x10, JK */
+	0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e,
+	/* implicit CRC16 then EOP to end */
+};
+
+static char *decode_ep0_state(struct mtu3 *mtu)
+{
+	switch (mtu->ep0_state) {
+	case MU3D_EP0_STATE_SETUP:
+		return "SETUP";
+	case MU3D_EP0_STATE_TX:
+		return "IN";
+	case MU3D_EP0_STATE_RX:
+		return "OUT";
+	case MU3D_EP0_STATE_TX_END:
+		return "TX-END";
+	case MU3D_EP0_STATE_STALL:
+		return "STALL";
+	default:
+		return "??";
+	}
+}
+
+static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req)
+{
+	mtu3_req_complete(mtu->ep0, req, 0);
+}
+
+static int
+forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
+__releases(mtu->lock)
+__acquires(mtu->lock)
+{
+	int ret;
+
+	if (!mtu->gadget_driver)
+		return -EOPNOTSUPP;
+
+	spin_unlock(&mtu->lock);
+	ret = mtu->gadget_driver->setup(&mtu->g, setup);
+	spin_lock(&mtu->lock);
+
+	dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret);
+	return ret;
+}
+
+static inline void writel_rep(volatile void *addr, const void *buffer,
+			      unsigned int count)
+{
+	if (count) {
+		const u32 *buf = buffer;
+
+		do {
+			writel(*buf++, addr);
+		} while (--count);
+	}
+}
+
+static inline void readl_rep(const volatile void *addr, void *buffer,
+			     unsigned int count)
+{
+	if (count) {
+		u32 *buf = buffer;
+
+		do {
+			u32 x = readl(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+
+static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len)
+{
+	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
+	u16 index = 0;
+
+	dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n",
+		__func__, mep->epnum, len, src);
+
+	if (len >= 4) {
+		writel_rep(fifo, src, len >> 2);
+		index = len & ~0x03;
+	}
+	if (len & 0x02) {
+		writew(*(u16 *)&src[index], fifo);
+		index += 2;
+	}
+	if (len & 0x01)
+		writeb(src[index], fifo);
+}
+
+static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len)
+{
+	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
+	u32 value;
+	u16 index = 0;
+
+	dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n",
+		__func__, mep->epnum, len, dst);
+
+	if (len >= 4) {
+		readl_rep(fifo, dst, len >> 2);
+		index = len & ~0x03;
+	}
+	if (len & 0x3) {
+		value = readl(fifo);
+		memcpy(&dst[index], &value, len & 0x3);
+	}
+}
+
+static void ep0_load_test_packet(struct mtu3 *mtu)
+{
+	/*
+	 * because the length of test packet is less than max packet of HS ep0,
+	 * write it into fifo directly.
+	 */
+	ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet));
+}
+
+/*
+ * A. send STALL for setup transfer without data stage:
+ *		set SENDSTALL and SETUPPKTRDY at the same time;
+ * B. send STALL for other cases:
+ *		set SENDSTALL only.
+ */
+static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
+{
+	struct mtu3 *mtu = mep0->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	u32 csr;
+
+	/* EP0_SENTSTALL is W1C */
+	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+	if (set)
+		csr |= EP0_SENDSTALL | pktrdy;
+	else
+		csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
+	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
+
+	mtu->delayed_status = false;
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+	dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n",
+		set ? "SEND" : "CLEAR", decode_ep0_state(mtu));
+}
+
+static void ep0_do_status_stage(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 value;
+
+	value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+	mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
+}
+
+static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq);
+
+static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
+{}
+
+static void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mtu3_request *mreq;
+	struct mtu3 *mtu;
+	struct usb_set_sel_req sel;
+
+	memcpy(&sel, req->buf, sizeof(sel));
+
+	mreq = to_mtu3_request(req);
+	mtu = mreq->mtu;
+	dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n",
+		sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel);
+}
+
+/* queue data stage to handle 6 byte SET_SEL request */
+static int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+	int ret;
+	u16 length = le16_to_cpu(setup->wLength);
+
+	if (unlikely(length != 6)) {
+		dev_err(mtu->dev, "%s wrong wLength:%d\n",
+			__func__, length);
+		return -EINVAL;
+	}
+
+	mtu->ep0_req.mep = mtu->ep0;
+	mtu->ep0_req.request.length = 6;
+	mtu->ep0_req.request.buf = mtu->setup_buf;
+	mtu->ep0_req.request.complete = ep0_set_sel_complete;
+	ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+
+	return ret < 0 ? ret : 1;
+}
+
+static int
+ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
+{
+	struct mtu3_ep *mep = NULL;
+	int handled = 1;
+	u8 result[2] = {0, 0};
+	u8 epnum = 0;
+	int is_in;
+
+	switch (setup->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
+		result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+
+		if (mtu->g.speed >= USB_SPEED_SUPER) {
+			result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
+			result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
+		}
+
+		dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__,
+			result[0], mtu->u1_enable, mtu->u2_enable);
+
+		break;
+	case USB_RECIP_INTERFACE:
+		break;
+	case USB_RECIP_ENDPOINT:
+		epnum = (u8)le16_to_cpu(setup->wIndex);
+		is_in = epnum & USB_DIR_IN;
+		epnum &= USB_ENDPOINT_NUMBER_MASK;
+
+		if (epnum >= mtu->num_eps) {
+			handled = -EINVAL;
+			break;
+		}
+		if (!epnum)
+			break;
+
+		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
+		if (!mep->desc) {
+			handled = -EINVAL;
+			break;
+		}
+		if (mep->flags & MTU3_EP_STALL)
+			result[0] |= 1 << USB_ENDPOINT_HALT;
+
+		break;
+	default:
+		/* class, vendor, etc ... delegate */
+		handled = 0;
+		break;
+	}
+
+	if (handled > 0) {
+		int ret;
+
+		/* prepare a data stage for GET_STATUS */
+		dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result);
+		memcpy(mtu->setup_buf, result, sizeof(result));
+		mtu->ep0_req.mep = mtu->ep0;
+		mtu->ep0_req.request.length = 2;
+		mtu->ep0_req.request.buf = &mtu->setup_buf;
+		mtu->ep0_req.request.complete = ep0_dummy_complete;
+		ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+		if (ret < 0)
+			handled = ret;
+	}
+	return handled;
+}
+
+static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+	void __iomem *mbase = mtu->mac_base;
+	int handled = 1;
+	u32 value = 0;
+
+	switch (le16_to_cpu(setup->wIndex) >> 8) {
+	case TEST_J:
+		dev_dbg(mtu->dev, "TEST_J\n");
+		mtu->test_mode_nr = TEST_J_MODE;
+		break;
+	case TEST_K:
+		dev_dbg(mtu->dev, "TEST_K\n");
+		mtu->test_mode_nr = TEST_K_MODE;
+		break;
+	case TEST_SE0_NAK:
+		dev_dbg(mtu->dev, "TEST_SE0_NAK\n");
+		mtu->test_mode_nr = TEST_SE0_NAK_MODE;
+		break;
+	case TEST_PACKET:
+		dev_dbg(mtu->dev, "TEST_PACKET\n");
+		mtu->test_mode_nr = TEST_PACKET_MODE;
+		break;
+	default:
+		handled = -EINVAL;
+		goto out;
+	}
+
+	mtu->test_mode = true;
+
+	/* no TX completion interrupt, and need restart platform after test */
+	if (mtu->test_mode_nr == TEST_PACKET_MODE)
+		ep0_load_test_packet(mtu);
+
+	/* send status before entering test mode. */
+	ep0_do_status_stage(mtu);
+
+	/* wait for ACK status sent by host */
+	readl_poll_timeout(mbase + U3D_EP0CSR, value,
+			   !(value & EP0_DATAEND), 5000);
+
+	mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr);
+
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+out:
+	return handled;
+}
+
+static int ep0_handle_feature_dev(struct mtu3 *mtu,
+				  struct usb_ctrlrequest *setup, bool set)
+{
+	void __iomem *mbase = mtu->mac_base;
+	int handled = -EINVAL;
+	u32 lpc;
+
+	switch (le16_to_cpu(setup->wValue)) {
+	case USB_DEVICE_REMOTE_WAKEUP:
+		mtu->may_wakeup = !!set;
+		handled = 1;
+		break;
+	case USB_DEVICE_TEST_MODE:
+		if (!set || (mtu->g.speed != USB_SPEED_HIGH) ||
+		    (le16_to_cpu(setup->wIndex) & 0xff))
+			break;
+
+		handled = handle_test_mode(mtu, setup);
+		break;
+	case USB_DEVICE_U1_ENABLE:
+		if (mtu->g.speed < USB_SPEED_SUPER ||
+		    mtu->g.state != USB_STATE_CONFIGURED)
+			break;
+
+		lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+		if (set)
+			lpc |= SW_U1_REQUEST_ENABLE;
+		else
+			lpc &= ~SW_U1_REQUEST_ENABLE;
+		mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+		mtu->u1_enable = !!set;
+		handled = 1;
+		break;
+	case USB_DEVICE_U2_ENABLE:
+		if (mtu->g.speed < USB_SPEED_SUPER ||
+		    mtu->g.state != USB_STATE_CONFIGURED)
+			break;
+
+		lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+		if (set)
+			lpc |= SW_U2_REQUEST_ENABLE;
+		else
+			lpc &= ~SW_U2_REQUEST_ENABLE;
+		mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+		mtu->u2_enable = !!set;
+		handled = 1;
+		break;
+	default:
+		handled = -EINVAL;
+		break;
+	}
+	return handled;
+}
+
+static int ep0_handle_feature(struct mtu3 *mtu,
+			      struct usb_ctrlrequest *setup, bool set)
+{
+	struct mtu3_ep *mep;
+	int handled = -EINVAL;
+	int is_in;
+	u16 value;
+	u16 index;
+	u8 epnum;
+
+	value = le16_to_cpu(setup->wValue);
+	index = le16_to_cpu(setup->wIndex);
+
+	switch (setup->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		handled = ep0_handle_feature_dev(mtu, setup, set);
+		break;
+	case USB_RECIP_INTERFACE:
+		/* superspeed only */
+		if (value == USB_INTRF_FUNC_SUSPEND &&
+		    mtu->g.speed >= USB_SPEED_SUPER) {
+			/*
+			 * forward the request because function drivers
+			 * should handle it
+			 */
+			handled = 0;
+		}
+		break;
+	case USB_RECIP_ENDPOINT:
+		epnum = index & USB_ENDPOINT_NUMBER_MASK;
+		if (epnum == 0 || epnum >= mtu->num_eps ||
+		    value != USB_ENDPOINT_HALT)
+			break;
+
+		is_in = index & USB_DIR_IN;
+		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
+		if (!mep->desc)
+			break;
+
+		handled = 1;
+		/* ignore request if endpoint is wedged */
+		if (mep->flags & MTU3_EP_WEDGE)
+			break;
+
+		mtu3_ep_stall_set(mep, set);
+		break;
+	default:
+		/* class, vendor, etc ... delegate */
+		handled = 0;
+		break;
+	}
+	return handled;
+}
+
+/*
+ * handle all control requests can be handled
+ * returns:
+ *	negative errno - error happened
+ *	zero - need delegate SETUP to gadget driver
+ *	positive - already handled
+ */
+static int handle_standard_request(struct mtu3 *mtu,
+				   struct usb_ctrlrequest *setup)
+{
+	void __iomem *mbase = mtu->mac_base;
+	enum usb_device_state state = mtu->g.state;
+	int handled = -EINVAL;
+	u32 dev_conf;
+	u16 value;
+
+	value = le16_to_cpu(setup->wValue);
+
+	/* the gadget driver handles everything except what we must handle */
+	switch (setup->bRequest) {
+	case USB_REQ_SET_ADDRESS:
+		/* change it after the status stage */
+		mtu->address = (u8)(value & 0x7f);
+		dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address);
+
+		dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF);
+		dev_conf &= ~DEV_ADDR_MSK;
+		dev_conf |= DEV_ADDR(mtu->address);
+		mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf);
+
+		if (mtu->address)
+			usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS);
+		else
+			usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT);
+
+		handled = 1;
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		if (state == USB_STATE_ADDRESS) {
+			usb_gadget_set_state(&mtu->g,
+					     USB_STATE_CONFIGURED);
+		} else if (state == USB_STATE_CONFIGURED) {
+			/*
+			 * USB2 spec sec 9.4.7, if wValue is 0 then dev
+			 * is moved to addressed state
+			 */
+			if (!value)
+				usb_gadget_set_state(&mtu->g,
+						     USB_STATE_ADDRESS);
+		}
+		handled = 0;
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		handled = ep0_handle_feature(mtu, setup, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		handled = ep0_handle_feature(mtu, setup, 1);
+		break;
+	case USB_REQ_GET_STATUS:
+		handled = ep0_get_status(mtu, setup);
+		break;
+	case USB_REQ_SET_SEL:
+		handled = ep0_set_sel(mtu, setup);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		handled = 1;
+		break;
+	default:
+		/* delegate SET_CONFIGURATION, etc */
+		handled = 0;
+	}
+
+	return handled;
+}
+
+/* receive an data packet (OUT) */
+static void ep0_rx_state(struct mtu3 *mtu)
+{
+	struct mtu3_request *mreq;
+	struct usb_request *req;
+	void __iomem *mbase = mtu->mac_base;
+	u32 maxp;
+	u32 csr;
+	u16 count = 0;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+	mreq = next_ep0_request(mtu);
+	req = &mreq->request;
+
+	/* read packet and ack; or stall because of gadget driver bug */
+	if (req) {
+		void *buf = req->buf + req->actual;
+		unsigned int len = req->length - req->actual;
+
+		/* read the buffer */
+		count = mtu3_readl(mbase, U3D_RXCOUNT0);
+		if (count > len) {
+			req->status = -EOVERFLOW;
+			count = len;
+		}
+		ep0_read_fifo(mtu->ep0, buf, count);
+		req->actual += count;
+		csr |= EP0_RXPKTRDY;
+
+		maxp = mtu->g.ep0->maxpacket;
+		if (count < maxp || req->actual == req->length) {
+			mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+			dev_dbg(mtu->dev, "ep0 state: %s\n",
+				decode_ep0_state(mtu));
+
+			csr |= EP0_DATAEND;
+		} else {
+			req = NULL;
+		}
+	} else {
+		csr |= EP0_RXPKTRDY | EP0_SENDSTALL;
+		dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__);
+	}
+
+	mtu3_writel(mbase, U3D_EP0CSR, csr);
+
+	/* give back the request if have received all data */
+	if (req)
+		ep0_req_giveback(mtu, req);
+}
+
+/* transmitting to the host (IN) */
+static void ep0_tx_state(struct mtu3 *mtu)
+{
+	struct mtu3_request *mreq = next_ep0_request(mtu);
+	struct usb_request *req;
+	u32 csr;
+	u8 *src;
+	u32 count;
+	u32 maxp;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	if (!mreq)
+		return;
+
+	maxp = mtu->g.ep0->maxpacket;
+	req = &mreq->request;
+
+	/* load the data */
+	src = (u8 *)req->buf + req->actual;
+	count = min(maxp, req->length - req->actual);
+	if (count)
+		ep0_write_fifo(mtu->ep0, src, count);
+
+	dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n",
+		__func__, req->actual, req->length, count, maxp, req->zero);
+
+	req->actual += count;
+
+	if ((count < maxp) ||
+	    ((req->actual == req->length) && !req->zero))
+		mtu->ep0_state = MU3D_EP0_STATE_TX_END;
+
+	/* send it out, triggering a "txpktrdy cleared" irq */
+	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
+	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY);
+
+	dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__,
+		mtu3_readl(mtu->mac_base, U3D_EP0CSR));
+}
+
+static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+	struct mtu3_request *mreq;
+	u32 count;
+	u32 csr;
+
+	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
+	count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0);
+
+	ep0_read_fifo(mtu->ep0, (u8 *)setup, count);
+
+	dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n",
+		setup->bRequestType, setup->bRequest,
+		le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex),
+		le16_to_cpu(setup->wLength));
+
+	/* clean up any leftover transfers */
+	mreq = next_ep0_request(mtu);
+	if (mreq)
+		ep0_req_giveback(mtu, &mreq->request);
+
+	if (le16_to_cpu(setup->wLength) == 0) {
+		;	/* no data stage, nothing to do */
+	} else if (setup->bRequestType & USB_DIR_IN) {
+		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
+			    csr | EP0_SETUPPKTRDY | EP0_DPHTX);
+		mtu->ep0_state = MU3D_EP0_STATE_TX;
+	} else {
+		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
+			    (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX));
+		mtu->ep0_state = MU3D_EP0_STATE_RX;
+	}
+}
+
+static int ep0_handle_setup(struct mtu3 *mtu)
+__releases(mtu->lock)
+__acquires(mtu->lock)
+{
+	struct usb_ctrlrequest setup;
+	struct mtu3_request *mreq;
+	int handled = 0;
+
+	ep0_read_setup(mtu, &setup);
+
+	if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		handled = handle_standard_request(mtu, &setup);
+
+	dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n",
+		handled, decode_ep0_state(mtu));
+
+	if (handled < 0)
+		goto stall;
+	else if (handled > 0)
+		goto finish;
+
+	handled = forward_to_driver(mtu, &setup);
+	if (handled < 0) {
+stall:
+		dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled);
+
+		ep0_stall_set(mtu->ep0, true,
+			      le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY);
+
+		return 0;
+	}
+
+finish:
+	if (mtu->test_mode) {
+		;	/* nothing to do */
+	} else if (handled == USB_GADGET_DELAYED_STATUS) {
+
+		mreq = next_ep0_request(mtu);
+		if (mreq) {
+			/* already asked us to continue delayed status */
+			ep0_do_status_stage(mtu);
+			ep0_req_giveback(mtu, &mreq->request);
+		} else {
+			/* do delayed STATUS stage till receive ep0_queue */
+			mtu->delayed_status = true;
+		}
+	} else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
+
+		ep0_do_status_stage(mtu);
+		/* complete zlp request directly */
+		mreq = next_ep0_request(mtu);
+		if (mreq && !mreq->request.length)
+			ep0_req_giveback(mtu, &mreq->request);
+	}
+
+	return 0;
+}
+
+irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	struct mtu3_request *mreq;
+	u32 int_status;
+	irqreturn_t ret = IRQ_NONE;
+	u32 csr;
+	u32 len;
+
+	int_status = mtu3_readl(mbase, U3D_EPISR);
+	int_status &= mtu3_readl(mbase, U3D_EPIER);
+	mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */
+
+	/* only handle ep0's */
+	if (!(int_status & (EP0ISR | SETUPENDISR)))
+		return IRQ_NONE;
+
+	/* abort current SETUP, and process new one */
+	if (int_status & SETUPENDISR)
+		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+	csr = mtu3_readl(mbase, U3D_EP0CSR);
+
+	dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr);
+
+	/* we sent a stall.. need to clear it now.. */
+	if (csr & EP0_SENTSTALL) {
+		ep0_stall_set(mtu->ep0, false, 0);
+		csr = mtu3_readl(mbase, U3D_EP0CSR);
+		ret = IRQ_HANDLED;
+	}
+	dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+
+	switch (mtu->ep0_state) {
+	case MU3D_EP0_STATE_TX:
+		/* irq on clearing txpktrdy */
+		if ((csr & EP0_FIFOFULL) == 0) {
+			ep0_tx_state(mtu);
+			ret = IRQ_HANDLED;
+		}
+		break;
+	case MU3D_EP0_STATE_RX:
+		/* irq on set rxpktrdy */
+		if (csr & EP0_RXPKTRDY) {
+			ep0_rx_state(mtu);
+			ret = IRQ_HANDLED;
+		}
+		break;
+	case MU3D_EP0_STATE_TX_END:
+		mtu3_writel(mbase, U3D_EP0CSR,
+			    (csr & EP0_W1C_BITS) | EP0_DATAEND);
+
+		mreq = next_ep0_request(mtu);
+		if (mreq)
+			ep0_req_giveback(mtu, &mreq->request);
+
+		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+		ret = IRQ_HANDLED;
+		dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+		break;
+	case MU3D_EP0_STATE_SETUP:
+		if (!(csr & EP0_SETUPPKTRDY))
+			break;
+
+		len = mtu3_readl(mbase, U3D_RXCOUNT0);
+		if (len != 8) {
+			dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len);
+			break;
+		}
+
+		ep0_handle_setup(mtu);
+		ret = IRQ_HANDLED;
+		break;
+	default:
+		/* can't happen */
+		ep0_stall_set(mtu->ep0, true, 0);
+		WARN_ON(1);
+		break;
+	}
+
+	return ret;
+}
+
+static int mtu3_ep0_enable(struct usb_ep *ep,
+			   const struct usb_endpoint_descriptor *desc)
+{
+	/* always enabled */
+	return -EINVAL;
+}
+
+static int mtu3_ep0_disable(struct usb_ep *ep)
+{
+	/* always enabled */
+	return -EINVAL;
+}
+
+static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	struct mtu3 *mtu = mep->mtu;
+
+	mreq->mtu = mtu;
+	mreq->request.actual = 0;
+	mreq->request.status = -EINPROGRESS;
+
+	dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__,
+		mep->name, decode_ep0_state(mtu), mreq->request.length);
+
+	switch (mtu->ep0_state) {
+	case MU3D_EP0_STATE_SETUP:
+	case MU3D_EP0_STATE_RX:	/* control-OUT data */
+	case MU3D_EP0_STATE_TX:	/* control-IN data */
+		break;
+	default:
+		dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__,
+			decode_ep0_state(mtu));
+		return -EINVAL;
+	}
+
+	if (mtu->delayed_status) {
+		mtu->delayed_status = false;
+		ep0_do_status_stage(mtu);
+		/* needn't giveback the request for handling delay STATUS */
+		return 0;
+	}
+
+	if (!list_empty(&mep->req_list))
+		return -EBUSY;
+
+	list_add_tail(&mreq->list, &mep->req_list);
+
+	/* sequence #1, IN ... start writing the data */
+	if (mtu->ep0_state == MU3D_EP0_STATE_TX)
+		ep0_tx_state(mtu);
+
+	return 0;
+}
+
+static int mtu3_ep0_queue(struct usb_ep *ep,
+			  struct usb_request *req, gfp_t gfp)
+{
+	struct mtu3_ep *mep;
+	struct mtu3_request *mreq;
+	struct mtu3 *mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!ep || !req)
+		return -EINVAL;
+
+	mep = to_mtu3_ep(ep);
+	mtu = mep->mtu;
+	mreq = to_mtu3_request(req);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	ret = ep0_queue(mep, mreq);
+	spin_unlock_irqrestore(&mtu->lock, flags);
+	return ret;
+}
+
+static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	/* we just won't support this */
+	return -EINVAL;
+}
+
+static int mtu3_ep0_halt(struct usb_ep *ep, int value)
+{
+	struct mtu3_ep *mep;
+	struct mtu3 *mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!ep || !value)
+		return -EINVAL;
+
+	mep = to_mtu3_ep(ep);
+	mtu = mep->mtu;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	if (!list_empty(&mep->req_list)) {
+		ret = -EBUSY;
+		goto cleanup;
+	}
+
+	switch (mtu->ep0_state) {
+	/*
+	 * stalls are usually issued after parsing SETUP packet, either
+	 * directly in irq context from setup() or else later.
+	 */
+	case MU3D_EP0_STATE_TX:
+	case MU3D_EP0_STATE_TX_END:
+	case MU3D_EP0_STATE_RX:
+	case MU3D_EP0_STATE_SETUP:
+		ep0_stall_set(mtu->ep0, true, 0);
+		break;
+	default:
+		dev_dbg(mtu->dev, "ep0 can't halt in state %s\n",
+			decode_ep0_state(mtu));
+		ret = -EINVAL;
+	}
+
+cleanup:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+	return ret;
+}
+
+const struct usb_ep_ops mtu3_ep0_ops = {
+	.enable = mtu3_ep0_enable,
+	.disable = mtu3_ep0_disable,
+	.alloc_request = mtu3_alloc_request,
+	.free_request = mtu3_free_request,
+	.queue = mtu3_ep0_queue,
+	.dequeue = mtu3_ep0_dequeue,
+	.set_halt = mtu3_ep0_halt,
+};
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_host.c b/roms/u-boot/drivers/usb/mtu3/mtu3_host.c
new file mode 100644
index 000000000..8001fc2d9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_host.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_dr.c - dual role switch and host glue layer
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <dm/lists.h>
+#include <linux/iopoll.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+static void host_ports_num_get(struct mtu3_host *u3h)
+{
+	u32 xhci_cap;
+
+	xhci_cap = mtu3_readl(u3h->ippc_base, U3D_SSUSB_IP_XHCI_CAP);
+	u3h->u2_ports = SSUSB_IP_XHCI_U2_PORT_NUM(xhci_cap);
+	u3h->u3_ports = SSUSB_IP_XHCI_U3_PORT_NUM(xhci_cap);
+
+	dev_dbg(u3h->dev, "host - u2_ports:%d, u3_ports:%d\n",
+		u3h->u2_ports, u3h->u3_ports);
+}
+
+/* only configure ports will be used later */
+static int ssusb_host_enable(struct mtu3_host *u3h)
+{
+	void __iomem *ibase = u3h->ippc_base;
+	int num_u3p = u3h->u3_ports;
+	int num_u2p = u3h->u2_ports;
+	int u3_ports_disabed;
+	u32 check_clk;
+	u32 value;
+	int i;
+
+	/* power on host ip */
+	mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+
+	/* power on and enable u3 ports except skipped ones */
+	u3_ports_disabed = 0;
+	for (i = 0; i < num_u3p; i++) {
+		if ((0x1 << i) & u3h->u3p_dis_msk) {
+			u3_ports_disabed++;
+			continue;
+		}
+
+		value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+		value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
+		value |= SSUSB_U3_PORT_HOST_SEL;
+		mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+	}
+
+	/* power on and enable all u2 ports */
+	for (i = 0; i < num_u2p; i++) {
+		value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+		value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
+		value |= SSUSB_U2_PORT_HOST_SEL;
+		mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+	}
+
+	check_clk = SSUSB_XHCI_RST_B_STS;
+	if (num_u3p > u3_ports_disabed)
+		check_clk = SSUSB_U3_MAC_RST_B_STS;
+
+	return ssusb_check_clocks(u3h->ssusb, check_clk);
+}
+
+static void ssusb_host_disable(struct mtu3_host *u3h)
+{
+	void __iomem *ibase = u3h->ippc_base;
+	int num_u3p = u3h->u3_ports;
+	int num_u2p = u3h->u2_ports;
+	u32 value;
+	int i;
+
+	/* power down and disable u3 ports except skipped ones */
+	for (i = 0; i < num_u3p; i++) {
+		if ((0x1 << i) & u3h->u3p_dis_msk)
+			continue;
+
+		value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+		value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
+		mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+	}
+
+	/* power down and disable all u2 ports */
+	for (i = 0; i < num_u2p; i++) {
+		value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+		value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
+		mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+	}
+
+	/* power down host ip */
+	mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+}
+
+/*
+ * If host supports multiple ports, the VBUSes(5V) of ports except port0
+ * which supports OTG are better to be enabled by default in DTS.
+ * Because the host driver will keep link with devices attached when system
+ * enters suspend mode, so no need to control VBUSes after initialization.
+ */
+int ssusb_host_init(struct ssusb_mtk *ssusb)
+{
+	struct mtu3_host *u3h = ssusb->u3h;
+	struct udevice *dev = u3h->dev;
+	int ret;
+
+	u3h->ssusb = ssusb;
+	u3h->hcd = ssusb->mac_base;
+	u3h->ippc_base = ssusb->ippc_base;
+
+	/* optional property, ignore the error */
+	dev_read_u32(dev, "mediatek,u3p-dis-msk", &u3h->u3p_dis_msk);
+
+	host_ports_num_get(u3h);
+	ret = ssusb_host_enable(u3h);
+	if (ret)
+		return ret;
+
+	ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+
+	ret = regulator_set_enable(ssusb->vbus_supply, true);
+	if (ret < 0 && ret != -ENOSYS) {
+		dev_err(dev, "failed to enable vbus %d!\n", ret);
+		return ret;
+	}
+
+	dev_info(dev, "%s done...\n", __func__);
+
+	return 0;
+}
+
+void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{
+	regulator_set_enable(ssusb->vbus_supply, false);
+	ssusb_host_disable(ssusb->u3h);
+}
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_hw_regs.h b/roms/u-boot/drivers/usb/mtu3/mtu3_hw_regs.h
new file mode 100644
index 000000000..9c2a7e1f4
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -0,0 +1,515 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef _SSUSB_HW_REGS_H_
+#define _SSUSB_HW_REGS_H_
+
+/* segment offset of MAC register */
+#define SSUSB_XCHI_BASE		0x0000
+#define SSUSB_DEV_BASE		0x1000
+#define SSUSB_EPCTL_CSR_BASE	0x1800
+#define SSUSB_USB3_MAC_CSR_BASE	0x2400
+#define SSUSB_USB3_SYS_CSR_BASE	0x2400
+#define SSUSB_USB2_CSR_BASE	0x3400
+
+/* IPPC register in Infra */
+#define SSUSB_SIFSLV_IPPC_BASE	0x0000
+
+/* --------------- SSUSB_DEV REGISTER DEFINITION --------------- */
+
+#define U3D_LV1ISR		(SSUSB_DEV_BASE + 0x0000)
+#define U3D_LV1IER		(SSUSB_DEV_BASE + 0x0004)
+#define U3D_LV1IESR		(SSUSB_DEV_BASE + 0x0008)
+#define U3D_LV1IECR		(SSUSB_DEV_BASE + 0x000C)
+
+#define U3D_EPISR		(SSUSB_DEV_BASE + 0x0080)
+#define U3D_EPIER		(SSUSB_DEV_BASE + 0x0084)
+#define U3D_EPIESR		(SSUSB_DEV_BASE + 0x0088)
+#define U3D_EPIECR		(SSUSB_DEV_BASE + 0x008C)
+
+#define U3D_EP0CSR		(SSUSB_DEV_BASE + 0x0100)
+#define U3D_RXCOUNT0		(SSUSB_DEV_BASE + 0x0108)
+#define U3D_RESERVED		(SSUSB_DEV_BASE + 0x010C)
+#define U3D_TX1CSR0		(SSUSB_DEV_BASE + 0x0110)
+#define U3D_TX1CSR1		(SSUSB_DEV_BASE + 0x0114)
+#define U3D_TX1CSR2		(SSUSB_DEV_BASE + 0x0118)
+
+#define U3D_RX1CSR0		(SSUSB_DEV_BASE + 0x0210)
+#define U3D_RX1CSR1		(SSUSB_DEV_BASE + 0x0214)
+#define U3D_RX1CSR2		(SSUSB_DEV_BASE + 0x0218)
+
+#define U3D_FIFO0		(SSUSB_DEV_BASE + 0x0300)
+
+#define U3D_QCR0		(SSUSB_DEV_BASE + 0x0400)
+#define U3D_QCR1		(SSUSB_DEV_BASE + 0x0404)
+#define U3D_QCR2		(SSUSB_DEV_BASE + 0x0408)
+#define U3D_QCR3		(SSUSB_DEV_BASE + 0x040C)
+#define U3D_QFCR		(SSUSB_DEV_BASE + 0x0428)
+
+#define U3D_TXQCSR1		(SSUSB_DEV_BASE + 0x0510)
+#define U3D_TXQSAR1		(SSUSB_DEV_BASE + 0x0514)
+#define U3D_TXQCPR1		(SSUSB_DEV_BASE + 0x0518)
+
+#define U3D_RXQCSR1		(SSUSB_DEV_BASE + 0x0610)
+#define U3D_RXQSAR1		(SSUSB_DEV_BASE + 0x0614)
+#define U3D_RXQCPR1		(SSUSB_DEV_BASE + 0x0618)
+#define U3D_RXQLDPR1		(SSUSB_DEV_BASE + 0x061C)
+
+#define U3D_QISAR0		(SSUSB_DEV_BASE + 0x0700)
+#define U3D_QIER0		(SSUSB_DEV_BASE + 0x0704)
+#define U3D_QIESR0		(SSUSB_DEV_BASE + 0x0708)
+#define U3D_QIECR0		(SSUSB_DEV_BASE + 0x070C)
+#define U3D_QISAR1		(SSUSB_DEV_BASE + 0x0710)
+#define U3D_QIER1		(SSUSB_DEV_BASE + 0x0714)
+#define U3D_QIESR1		(SSUSB_DEV_BASE + 0x0718)
+#define U3D_QIECR1		(SSUSB_DEV_BASE + 0x071C)
+
+#define U3D_TQERRIR0		(SSUSB_DEV_BASE + 0x0780)
+#define U3D_TQERRIER0		(SSUSB_DEV_BASE + 0x0784)
+#define U3D_TQERRIESR0		(SSUSB_DEV_BASE + 0x0788)
+#define U3D_TQERRIECR0		(SSUSB_DEV_BASE + 0x078C)
+#define U3D_RQERRIR0		(SSUSB_DEV_BASE + 0x07C0)
+#define U3D_RQERRIER0		(SSUSB_DEV_BASE + 0x07C4)
+#define U3D_RQERRIESR0		(SSUSB_DEV_BASE + 0x07C8)
+#define U3D_RQERRIECR0		(SSUSB_DEV_BASE + 0x07CC)
+#define U3D_RQERRIR1		(SSUSB_DEV_BASE + 0x07D0)
+#define U3D_RQERRIER1		(SSUSB_DEV_BASE + 0x07D4)
+#define U3D_RQERRIESR1		(SSUSB_DEV_BASE + 0x07D8)
+#define U3D_RQERRIECR1		(SSUSB_DEV_BASE + 0x07DC)
+
+#define U3D_CAP_EP0FFSZ		(SSUSB_DEV_BASE + 0x0C04)
+#define U3D_CAP_EPNTXFFSZ	(SSUSB_DEV_BASE + 0x0C08)
+#define U3D_CAP_EPNRXFFSZ	(SSUSB_DEV_BASE + 0x0C0C)
+#define U3D_CAP_EPINFO		(SSUSB_DEV_BASE + 0x0C10)
+#define U3D_MISC_CTRL		(SSUSB_DEV_BASE + 0x0C84)
+
+/*---------------- SSUSB_DEV FIELD DEFINITION ---------------*/
+
+/* U3D_LV1ISR */
+#define EP_CTRL_INTR		BIT(5)
+#define MAC2_INTR		BIT(4)
+#define DMA_INTR		BIT(3)
+#define MAC3_INTR		BIT(2)
+#define QMU_INTR		BIT(1)
+#define BMU_INTR		BIT(0)
+
+/* U3D_LV1IECR */
+#define LV1IECR_MSK		GENMASK(31, 0)
+
+/* U3D_EPISR */
+#define EPRISR(x)		(BIT(16) << (x))
+#define SETUPENDISR		BIT(16)
+#define EPTISR(x)		(BIT(0) << (x))
+#define EP0ISR			BIT(0)
+
+/* U3D_EP0CSR */
+#define EP0_SENDSTALL		BIT(25)
+#define EP0_FIFOFULL		BIT(23)
+#define EP0_SENTSTALL		BIT(22)
+#define EP0_DPHTX		BIT(20)
+#define EP0_DATAEND		BIT(19)
+#define EP0_TXPKTRDY		BIT(18)
+#define EP0_SETUPPKTRDY		BIT(17)
+#define EP0_RXPKTRDY		BIT(16)
+#define EP0_MAXPKTSZ_MSK	GENMASK(9, 0)
+#define EP0_MAXPKTSZ(x)		((x) & EP0_MAXPKTSZ_MSK)
+#define EP0_W1C_BITS	(~(EP0_RXPKTRDY | EP0_SETUPPKTRDY | EP0_SENTSTALL))
+
+/* U3D_TX1CSR0 */
+#define TX_DMAREQEN		BIT(29)
+#define TX_FIFOFULL		BIT(25)
+#define TX_FIFOEMPTY		BIT(24)
+#define TX_SENTSTALL		BIT(22)
+#define TX_SENDSTALL		BIT(21)
+#define TX_TXPKTRDY		BIT(16)
+#define TX_TXMAXPKTSZ_MSK	GENMASK(10, 0)
+#define TX_TXMAXPKTSZ(x)	((x) & TX_TXMAXPKTSZ_MSK)
+#define TX_W1C_BITS		(~(TX_SENTSTALL))
+
+/* U3D_TX1CSR1 */
+#define TX_MAX_PKT_G2(x)	(((x) & 0xff) << 24)
+#define TX_MULT_G2(x)		(((x) & 0x7) << 21)
+#define TX_MULT_OG(x)		(((x) & 0x3) << 22)
+#define TX_MAX_PKT_OG(x)	(((x) & 0x3f) << 16)
+#define TX_SLOT(x)		(((x) & 0x3f) << 8)
+#define TX_TYPE(x)		(((x) & 0x3) << 4)
+#define TX_SS_BURST(x)		(((x) & 0xf) << 0)
+#define TX_MULT(g2c, x)		\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? TX_MULT_G2(x_) : TX_MULT_OG(x_);	\
+})
+#define TX_MAX_PKT(g2c, x)	\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? TX_MAX_PKT_G2(x_) : TX_MAX_PKT_OG(x_);	\
+})
+
+/* for TX_TYPE & RX_TYPE */
+#define TYPE_BULK		(0x0)
+#define TYPE_INT		(0x1)
+#define TYPE_ISO		(0x2)
+#define TYPE_MASK		(0x3)
+
+/* U3D_TX1CSR2 */
+#define TX_BINTERVAL(x)		(((x) & 0xff) << 24)
+#define TX_FIFOSEGSIZE(x)	(((x) & 0xf) << 16)
+#define TX_FIFOADDR(x)		(((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR0 */
+#define RX_DMAREQEN		BIT(29)
+#define RX_SENTSTALL		BIT(22)
+#define RX_SENDSTALL		BIT(21)
+#define RX_RXPKTRDY		BIT(16)
+#define RX_RXMAXPKTSZ_MSK	GENMASK(10, 0)
+#define RX_RXMAXPKTSZ(x)	((x) & RX_RXMAXPKTSZ_MSK)
+#define RX_W1C_BITS		(~(RX_SENTSTALL | RX_RXPKTRDY))
+
+/* U3D_RX1CSR1 */
+#define RX_MAX_PKT_G2(x)	(((x) & 0xff) << 24)
+#define RX_MULT_G2(x)		(((x) & 0x7) << 21)
+#define RX_MULT_OG(x)		(((x) & 0x3) << 22)
+#define RX_MAX_PKT_OG(x)	(((x) & 0x3f) << 16)
+#define RX_SLOT(x)		(((x) & 0x3f) << 8)
+#define RX_TYPE(x)		(((x) & 0x3) << 4)
+#define RX_SS_BURST(x)		(((x) & 0xf) << 0)
+#define RX_MULT(g2c, x)		\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? RX_MULT_G2(x_) : RX_MULT_OG(x_);	\
+})
+#define RX_MAX_PKT(g2c, x)	\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? RX_MAX_PKT_G2(x_) : RX_MAX_PKT_OG(x_);	\
+})
+
+/* U3D_RX1CSR2 */
+#define RX_BINTERVAL(x)		(((x) & 0xff) << 24)
+#define RX_FIFOSEGSIZE(x)	(((x) & 0xf) << 16)
+#define RX_FIFOADDR(x)		(((x) & 0x1fff) << 0)
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)		(BIT(16) << (x))
+#define QMU_TX_CS_EN(x)		(BIT(0) << (x))
+#define QMU_CS16B_EN		BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)		(BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)		(BIT(16) << (x))
+#define QMU_RX_ZLP(x)		(BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE		BIT(15)
+#define QMU_Q_STOP		BIT(2)
+#define QMU_Q_RESUME		BIT(1)
+#define QMU_Q_START		BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)	(BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)	(BIT(0) << (x))
+
+/* U3D_QISAR1, U3D_QIER1, U3D_QIESR1, U3D_QIECR1 */
+#define RXQ_ZLPERR_INT		BIT(20)
+#define RXQ_LENERR_INT		BIT(18)
+#define RXQ_CSERR_INT		BIT(17)
+#define RXQ_EMPTY_INT		BIT(16)
+#define TXQ_LENERR_INT		BIT(2)
+#define TXQ_CSERR_INT		BIT(1)
+#define TXQ_EMPTY_INT		BIT(0)
+
+/* U3D_TQERRIR0, U3D_TQERRIER0, U3D_TQERRIESR0, U3D_TQERRIECR0 */
+#define QMU_TX_LEN_ERR(x)	(BIT(16) << (x))
+#define QMU_TX_CS_ERR(x)	(BIT(0) << (x))
+
+/* U3D_RQERRIR0, U3D_RQERRIER0, U3D_RQERRIESR0, U3D_RQERRIECR0 */
+#define QMU_RX_LEN_ERR(x)	(BIT(16) << (x))
+#define QMU_RX_CS_ERR(x)	(BIT(0) << (x))
+
+/* U3D_RQERRIR1, U3D_RQERRIER1, U3D_RQERRIESR1, U3D_RQERRIECR1 */
+#define QMU_RX_ZLP_ERR(n)	(BIT(16) << (n))
+
+/* U3D_CAP_EPINFO */
+#define CAP_RX_EP_NUM(x)	(((x) >> 8) & 0x1f)
+#define CAP_TX_EP_NUM(x)	((x) & 0x1f)
+
+/* U3D_MISC_CTRL */
+#define VBUS_ON			BIT(1)
+#define VBUS_FRC_EN		BIT(0)
+
+/*---------------- SSUSB_EPCTL_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_DEVICE_CONF			(SSUSB_EPCTL_CSR_BASE + 0x0000)
+#define U3D_EP_RST			(SSUSB_EPCTL_CSR_BASE + 0x0004)
+
+#define U3D_DEV_LINK_INTR_ENABLE	(SSUSB_EPCTL_CSR_BASE + 0x0050)
+#define U3D_DEV_LINK_INTR		(SSUSB_EPCTL_CSR_BASE + 0x0054)
+
+/*---------------- SSUSB_EPCTL_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_DEVICE_CONF */
+#define DEV_ADDR_MSK		GENMASK(30, 24)
+#define DEV_ADDR(x)		((0x7f & (x)) << 24)
+#define HW_USB2_3_SEL		BIT(18)
+#define SW_USB2_3_SEL_EN	BIT(17)
+#define SW_USB2_3_SEL		BIT(16)
+#define SSUSB_DEV_SPEED(x)	((x) & 0x7)
+
+/* U3D_EP_RST */
+#define EP1_IN_RST		BIT(17)
+#define EP1_OUT_RST		BIT(1)
+#define EP_RST(is_in, epnum)	(((is_in) ? BIT(16) : BIT(0)) << (epnum))
+#define EP0_RST			BIT(0)
+
+/* U3D_DEV_LINK_INTR_ENABLE */
+/* U3D_DEV_LINK_INTR */
+#define SSUSB_DEV_SPEED_CHG_INTR	BIT(0)
+
+/*---------------- SSUSB_USB3_MAC_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_LTSSM_CTRL		(SSUSB_USB3_MAC_CSR_BASE + 0x0010)
+#define U3D_USB3_CONFIG		(SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+
+#define U3D_LINK_STATE_MACHINE	(SSUSB_USB3_MAC_CSR_BASE + 0x0134)
+#define U3D_LTSSM_INTR_ENABLE	(SSUSB_USB3_MAC_CSR_BASE + 0x013C)
+#define U3D_LTSSM_INTR		(SSUSB_USB3_MAC_CSR_BASE + 0x0140)
+
+#define U3D_U3U2_SWITCH_CTRL	(SSUSB_USB3_MAC_CSR_BASE + 0x0170)
+
+/*---------------- SSUSB_USB3_MAC_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_LTSSM_CTRL */
+#define FORCE_POLLING_FAIL	BIT(4)
+#define FORCE_RXDETECT_FAIL	BIT(3)
+#define SOFT_U3_EXIT_EN		BIT(2)
+#define COMPLIANCE_EN		BIT(1)
+#define U1_GO_U2_EN		BIT(0)
+
+/* U3D_USB3_CONFIG */
+#define USB3_EN			BIT(0)
+
+/* U3D_LINK_STATE_MACHINE */
+#define LTSSM_STATE(x)	((x) & 0x1f)
+
+/* U3D_LTSSM_INTR_ENABLE */
+/* U3D_LTSSM_INTR */
+#define U3_RESUME_INTR		BIT(18)
+#define U3_LFPS_TMOUT_INTR	BIT(17)
+#define VBUS_FALL_INTR		BIT(16)
+#define VBUS_RISE_INTR		BIT(15)
+#define RXDET_SUCCESS_INTR	BIT(14)
+#define EXIT_U3_INTR		BIT(13)
+#define EXIT_U2_INTR		BIT(12)
+#define EXIT_U1_INTR		BIT(11)
+#define ENTER_U3_INTR		BIT(10)
+#define ENTER_U2_INTR		BIT(9)
+#define ENTER_U1_INTR		BIT(8)
+#define ENTER_U0_INTR		BIT(7)
+#define RECOVERY_INTR		BIT(6)
+#define WARM_RST_INTR		BIT(5)
+#define HOT_RST_INTR		BIT(4)
+#define LOOPBACK_INTR		BIT(3)
+#define COMPLIANCE_INTR		BIT(2)
+#define SS_DISABLE_INTR		BIT(1)
+#define SS_INACTIVE_INTR	BIT(0)
+
+/* U3D_U3U2_SWITCH_CTRL */
+#define SOFTCON_CLR_AUTO_EN	BIT(0)
+
+/*---------------- SSUSB_USB3_SYS_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_LINK_UX_INACT_TIMER	(SSUSB_USB3_SYS_CSR_BASE + 0x020C)
+#define U3D_LINK_POWER_CONTROL	(SSUSB_USB3_SYS_CSR_BASE + 0x0210)
+#define U3D_LINK_ERR_COUNT	(SSUSB_USB3_SYS_CSR_BASE + 0x0214)
+
+/*---------------- SSUSB_USB3_SYS_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_LINK_UX_INACT_TIMER */
+#define DEV_U2_INACT_TIMEOUT_MSK	GENMASK(23, 16)
+#define DEV_U2_INACT_TIMEOUT_VALUE(x)	(((x) & 0xff) << 16)
+#define U2_INACT_TIMEOUT_MSK		GENMASK(15, 8)
+#define U1_INACT_TIMEOUT_MSK		GENMASK(7, 0)
+#define U1_INACT_TIMEOUT_VALUE(x)	((x) & 0xff)
+
+/* U3D_LINK_POWER_CONTROL */
+#define SW_U2_ACCEPT_ENABLE	BIT(9)
+#define SW_U1_ACCEPT_ENABLE	BIT(8)
+#define UX_EXIT			BIT(5)
+#define LGO_U3			BIT(4)
+#define LGO_U2			BIT(3)
+#define LGO_U1			BIT(2)
+#define SW_U2_REQUEST_ENABLE	BIT(1)
+#define SW_U1_REQUEST_ENABLE	BIT(0)
+
+/* U3D_LINK_ERR_COUNT */
+#define CLR_LINK_ERR_CNT	BIT(16)
+#define LINK_ERROR_COUNT	GENMASK(15, 0)
+
+/*---------------- SSUSB_USB2_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_POWER_MANAGEMENT		(SSUSB_USB2_CSR_BASE + 0x0004)
+#define U3D_DEVICE_CONTROL		(SSUSB_USB2_CSR_BASE + 0x000C)
+#define U3D_USB2_TEST_MODE		(SSUSB_USB2_CSR_BASE + 0x0014)
+#define U3D_COMMON_USB_INTR_ENABLE	(SSUSB_USB2_CSR_BASE + 0x0018)
+#define U3D_COMMON_USB_INTR		(SSUSB_USB2_CSR_BASE + 0x001C)
+#define U3D_LINK_RESET_INFO		(SSUSB_USB2_CSR_BASE + 0x0024)
+#define U3D_USB20_FRAME_NUM		(SSUSB_USB2_CSR_BASE + 0x003C)
+#define U3D_USB20_LPM_PARAMETER		(SSUSB_USB2_CSR_BASE + 0x0044)
+#define U3D_USB20_MISC_CONTROL		(SSUSB_USB2_CSR_BASE + 0x004C)
+#define U3D_USB20_OPSTATE		(SSUSB_USB2_CSR_BASE + 0x0060)
+
+/*---------------- SSUSB_USB2_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_POWER_MANAGEMENT */
+#define LPM_BESL_STALL		BIT(14)
+#define LPM_BESLD_STALL		BIT(13)
+#define LPM_RWP			BIT(11)
+#define LPM_HRWE		BIT(10)
+#define LPM_MODE(x)		(((x) & 0x3) << 8)
+#define ISO_UPDATE		BIT(7)
+#define SOFT_CONN		BIT(6)
+#define HS_ENABLE		BIT(5)
+#define RESUME			BIT(2)
+#define SUSPENDM_ENABLE		BIT(0)
+
+/* U3D_DEVICE_CONTROL */
+#define DC_HOSTREQ		BIT(1)
+#define DC_SESSION		BIT(0)
+
+/* U3D_USB2_TEST_MODE */
+#define U2U3_AUTO_SWITCH	BIT(10)
+#define LPM_FORCE_STALL		BIT(8)
+#define FIFO_ACCESS		BIT(6)
+#define FORCE_FS		BIT(5)
+#define FORCE_HS		BIT(4)
+#define TEST_PACKET_MODE	BIT(3)
+#define TEST_K_MODE		BIT(2)
+#define TEST_J_MODE		BIT(1)
+#define TEST_SE0_NAK_MODE	BIT(0)
+
+/* U3D_COMMON_USB_INTR_ENABLE */
+/* U3D_COMMON_USB_INTR */
+#define LPM_RESUME_INTR		BIT(9)
+#define LPM_INTR		BIT(8)
+#define DISCONN_INTR		BIT(5)
+#define CONN_INTR		BIT(4)
+#define SOF_INTR		BIT(3)
+#define RESET_INTR		BIT(2)
+#define RESUME_INTR		BIT(1)
+#define SUSPEND_INTR		BIT(0)
+
+/* U3D_LINK_RESET_INFO */
+#define WTCHRP_MSK		GENMASK(19, 16)
+
+/* U3D_USB20_LPM_PARAMETER */
+#define LPM_BESLCK_U3(x)	(((x) & 0xf) << 12)
+#define LPM_BESLCK(x)		(((x) & 0xf) << 8)
+#define LPM_BESLDCK(x)		(((x) & 0xf) << 4)
+#define LPM_BESL		GENMASK(3, 0)
+
+/* U3D_USB20_MISC_CONTROL */
+#define LPM_U3_ACK_EN		BIT(0)
+
+/*---------------- SSUSB_SIFSLV_IPPC REGISTER DEFINITION ----------------*/
+
+#define U3D_SSUSB_IP_PW_CTRL0	(SSUSB_SIFSLV_IPPC_BASE + 0x0000)
+#define U3D_SSUSB_IP_PW_CTRL1	(SSUSB_SIFSLV_IPPC_BASE + 0x0004)
+#define U3D_SSUSB_IP_PW_CTRL2	(SSUSB_SIFSLV_IPPC_BASE + 0x0008)
+#define U3D_SSUSB_IP_PW_CTRL3	(SSUSB_SIFSLV_IPPC_BASE + 0x000C)
+#define U3D_SSUSB_IP_PW_STS1	(SSUSB_SIFSLV_IPPC_BASE + 0x0010)
+#define U3D_SSUSB_IP_PW_STS2	(SSUSB_SIFSLV_IPPC_BASE + 0x0014)
+#define U3D_SSUSB_OTG_STS	(SSUSB_SIFSLV_IPPC_BASE + 0x0018)
+#define U3D_SSUSB_OTG_STS_CLR	(SSUSB_SIFSLV_IPPC_BASE + 0x001C)
+#define U3D_SSUSB_IP_XHCI_CAP	(SSUSB_SIFSLV_IPPC_BASE + 0x0024)
+#define U3D_SSUSB_IP_DEV_CAP	(SSUSB_SIFSLV_IPPC_BASE + 0x0028)
+#define U3D_SSUSB_OTG_INT_EN	(SSUSB_SIFSLV_IPPC_BASE + 0x002C)
+#define U3D_SSUSB_U3_CTRL_0P	(SSUSB_SIFSLV_IPPC_BASE + 0x0030)
+#define U3D_SSUSB_U2_CTRL_0P	(SSUSB_SIFSLV_IPPC_BASE + 0x0050)
+#define U3D_SSUSB_REF_CK_CTRL	(SSUSB_SIFSLV_IPPC_BASE + 0x008C)
+#define U3D_SSUSB_DEV_RST_CTRL	(SSUSB_SIFSLV_IPPC_BASE + 0x0098)
+#define U3D_SSUSB_HW_ID		(SSUSB_SIFSLV_IPPC_BASE + 0x00A0)
+#define U3D_SSUSB_HW_SUB_ID	(SSUSB_SIFSLV_IPPC_BASE + 0x00A4)
+#define U3D_SSUSB_IP_TRUNK_VERS	(U3D_SSUSB_HW_SUB_ID)
+#define U3D_SSUSB_PRB_CTRL0	(SSUSB_SIFSLV_IPPC_BASE + 0x00B0)
+#define U3D_SSUSB_PRB_CTRL1	(SSUSB_SIFSLV_IPPC_BASE + 0x00B4)
+#define U3D_SSUSB_PRB_CTRL2	(SSUSB_SIFSLV_IPPC_BASE + 0x00B8)
+#define U3D_SSUSB_PRB_CTRL3	(SSUSB_SIFSLV_IPPC_BASE + 0x00BC)
+#define U3D_SSUSB_PRB_CTRL4	(SSUSB_SIFSLV_IPPC_BASE + 0x00C0)
+#define U3D_SSUSB_PRB_CTRL5	(SSUSB_SIFSLV_IPPC_BASE + 0x00C4)
+#define U3D_SSUSB_IP_SPARE0	(SSUSB_SIFSLV_IPPC_BASE + 0x00C8)
+
+/*---------------- SSUSB_SIFSLV_IPPC FIELD DEFINITION ----------------*/
+
+/* U3D_SSUSB_IP_PW_CTRL0 */
+#define SSUSB_IP_SW_RST			BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL1 */
+#define SSUSB_IP_HOST_PDN		BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL2 */
+#define SSUSB_IP_DEV_PDN		BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL3 */
+#define SSUSB_IP_PCIE_PDN		BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS1 */
+#define SSUSB_IP_SLEEP_STS		BIT(30)
+#define SSUSB_U3_MAC_RST_B_STS		BIT(16)
+#define SSUSB_XHCI_RST_B_STS		BIT(11)
+#define SSUSB_SYS125_RST_B_STS		BIT(10)
+#define SSUSB_REF_RST_B_STS		BIT(8)
+#define SSUSB_SYSPLL_STABLE		BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS2 */
+#define SSUSB_U2_MAC_SYS_RST_B_STS	BIT(0)
+
+/* U3D_SSUSB_OTG_STS */
+#define SSUSB_VBUS_VALID		BIT(9)
+
+/* U3D_SSUSB_OTG_STS_CLR */
+#define SSUSB_VBUS_INTR_CLR		BIT(6)
+
+/* U3D_SSUSB_IP_XHCI_CAP */
+#define SSUSB_IP_XHCI_U2_PORT_NUM(x)	(((x) >> 8) & 0xff)
+#define SSUSB_IP_XHCI_U3_PORT_NUM(x)	((x) & 0xff)
+
+/* U3D_SSUSB_IP_DEV_CAP */
+#define SSUSB_IP_DEV_U3_PORT_NUM(x)	((x) & 0xff)
+
+/* U3D_SSUSB_OTG_INT_EN */
+#define SSUSB_VBUS_CHG_INT_A_EN		BIT(7)
+#define SSUSB_VBUS_CHG_INT_B_EN		BIT(6)
+
+/* U3D_SSUSB_U3_CTRL_0P */
+#define SSUSB_U3_PORT_SSP_SPEED	BIT(9)
+#define SSUSB_U3_PORT_DUAL_MODE	BIT(7)
+#define SSUSB_U3_PORT_HOST_SEL		BIT(2)
+#define SSUSB_U3_PORT_PDN		BIT(1)
+#define SSUSB_U3_PORT_DIS		BIT(0)
+
+/* U3D_SSUSB_U2_CTRL_0P */
+#define SSUSB_U2_PORT_RG_IDDIG		BIT(12)
+#define SSUSB_U2_PORT_FORCE_IDDIG	BIT(11)
+#define SSUSB_U2_PORT_VBUSVALID	BIT(9)
+#define SSUSB_U2_PORT_OTG_SEL		BIT(7)
+#define SSUSB_U2_PORT_HOST		BIT(2)
+#define SSUSB_U2_PORT_PDN		BIT(1)
+#define SSUSB_U2_PORT_DIS		BIT(0)
+#define SSUSB_U2_PORT_HOST_SEL	(SSUSB_U2_PORT_VBUSVALID | SSUSB_U2_PORT_HOST)
+
+/* U3D_SSUSB_DEV_RST_CTRL */
+#define SSUSB_DEV_SW_RST		BIT(0)
+
+/* U3D_SSUSB_IP_TRUNK_VERS */
+#define IP_TRUNK_VERS(x)		(((x) >> 16) & 0xffff)
+
+#endif	/* _SSUSB_HW_REGS_H_ */
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_plat.c b/roms/u-boot/drivers/usb/mtu3/mtu3_plat.c
new file mode 100644
index 000000000..b097471f3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_plat.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm/lists.h>
+#include <linux/iopoll.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+			  enum mtu3_dr_force_mode mode)
+{
+	u32 value;
+
+	value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
+	switch (mode) {
+	case MTU3_DR_FORCE_DEVICE:
+		value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
+		break;
+	case MTU3_DR_FORCE_HOST:
+		value |= SSUSB_U2_PORT_FORCE_IDDIG;
+		value &= ~SSUSB_U2_PORT_RG_IDDIG;
+		break;
+	case MTU3_DR_FORCE_NONE:
+		value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
+		break;
+	default:
+		return;
+	}
+	mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
+}
+
+/* u2-port0 should be powered on and enabled; */
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks)
+{
+	void __iomem *ibase = ssusb->ippc_base;
+	u32 value, check_val;
+	int ret;
+
+	check_val = ex_clks | SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
+			SSUSB_REF_RST_B_STS;
+
+	ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value,
+				 ((value & check_val) == check_val), 10000);
+	if (ret) {
+		dev_err(ssusb->dev, "clks of sts1 are not stable!\n");
+		return ret;
+	}
+
+	ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS2, value,
+				 (value & SSUSB_U2_MAC_SYS_RST_B_STS), 10000);
+	if (ret) {
+		dev_err(ssusb->dev, "mac2 clock is not stable\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int ssusb_phy_setup(struct ssusb_mtk *ssusb)
+{
+	struct udevice *dev = ssusb->dev;
+	struct phy_bulk *phys = &ssusb->phys;
+	int ret;
+
+	ret = generic_phy_get_bulk(dev, phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_init_bulk(phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on_bulk(phys);
+	if (ret)
+		generic_phy_exit_bulk(phys);
+
+	return ret;
+}
+
+void ssusb_phy_shutdown(struct ssusb_mtk *ssusb)
+{
+	generic_phy_power_off_bulk(&ssusb->phys);
+	generic_phy_exit_bulk(&ssusb->phys);
+}
+
+static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
+{
+	int ret = 0;
+
+	ret = regulator_set_enable(ssusb->vusb33_supply, true);
+	if (ret < 0 && ret != -ENOSYS) {
+		dev_err(ssusb->dev, "failed to enable vusb33\n");
+		goto vusb33_err;
+	}
+
+	ret = clk_enable_bulk(&ssusb->clks);
+	if (ret)
+		goto clks_err;
+
+	ret = ssusb_phy_setup(ssusb);
+	if (ret) {
+		dev_err(ssusb->dev, "failed to setup phy\n");
+		goto phy_err;
+	}
+
+	return 0;
+
+phy_err:
+	clk_disable_bulk(&ssusb->clks);
+clks_err:
+	regulator_set_enable(ssusb->vusb33_supply, false);
+vusb33_err:
+	return ret;
+}
+
+static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
+{
+	clk_disable_bulk(&ssusb->clks);
+	regulator_set_enable(ssusb->vusb33_supply, false);
+	ssusb_phy_shutdown(ssusb);
+}
+
+static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
+{
+	/* reset whole ip (xhci & u3d) */
+	mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+	udelay(1);
+	mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+}
+
+static int get_ssusb_rscs(struct udevice *dev, struct ssusb_mtk *ssusb)
+{
+	struct udevice *child;
+	int ret;
+
+	ret = device_get_supply_regulator(dev, "vusb33-supply",
+					  &ssusb->vusb33_supply);
+	if (ret)	/* optional, ignore error */
+		dev_warn(dev, "can't get optional vusb33 %d\n", ret);
+
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &ssusb->vbus_supply);
+	if (ret)	/* optional, ignore error */
+		dev_warn(dev, "can't get optional vbus regulator %d!\n", ret);
+
+	ret = clk_get_bulk(dev, &ssusb->clks);
+	if (ret) {
+		dev_err(dev, "failed to get clocks %d!\n", ret);
+		return ret;
+	}
+
+	ssusb->ippc_base = devfdt_remap_addr_name(dev, "ippc");
+	if (!ssusb->ippc_base) {
+		dev_err(dev, "error mapping memory for ippc\n");
+		return -ENODEV;
+	}
+
+	ret = device_find_first_child(dev, &child);
+	if (ret || !child) {
+		dev_err(dev, "failed to get child %d!\n", ret);
+		return ret;
+	}
+
+	ssusb->mac_base = devfdt_remap_addr_name(child, "mac");
+	if (!ssusb->mac_base) {
+		dev_err(dev, "error mapping memory for mac\n");
+		return -ENODEV;
+	}
+
+	ssusb->dr_mode = usb_get_dr_mode(dev_ofnode(child));
+
+	if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN ||
+		ssusb->dr_mode == USB_DR_MODE_OTG)
+		ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+	if (IS_ENABLED(CONFIG_USB_MTU3_GADGET))
+		ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+	else if (IS_ENABLED(CONFIG_USB_MTU3_HOST))
+		ssusb->dr_mode = USB_DR_MODE_HOST;
+
+	dev_info(dev, "dr_mode: %d, ippc: 0x%p, mac: 0x%p\n",
+		 ssusb->dr_mode, ssusb->ippc_base, ssusb->mac_base);
+
+	return 0;
+}
+
+static int mtu3_probe(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_get_priv(dev);
+	int ret = -ENOMEM;
+
+	ssusb->dev = dev;
+
+	ret = get_ssusb_rscs(dev, ssusb);
+	if (ret)
+		return ret;
+
+	ret = ssusb_rscs_init(ssusb);
+	if (ret)
+		return ret;
+
+	ssusb_ip_sw_reset(ssusb);
+
+	return 0;
+}
+
+static int mtu3_remove(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
+
+	ssusb_rscs_exit(ssusb);
+	return 0;
+}
+
+static const struct udevice_id ssusb_of_match[] = {
+	{.compatible = "mediatek,ssusb",},
+	{},
+};
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct mtu3 *mtu = dev_get_priv(dev);
+
+	mtu3_irq(0, mtu);
+
+	return 0;
+}
+
+static int mtu3_gadget_probe(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
+	struct mtu3 *mtu = dev_get_priv(dev);
+
+	mtu->dev = dev;
+	ssusb->u3d = mtu;
+	return ssusb_gadget_init(ssusb);
+}
+
+static int mtu3_gadget_remove(struct udevice *dev)
+{
+	struct mtu3 *mtu = dev_get_priv(dev);
+
+	ssusb_gadget_exit(mtu->ssusb);
+	return 0;
+}
+
+U_BOOT_DRIVER(mtu3_peripheral) = {
+	.name = "mtu3-peripheral",
+	.id = UCLASS_USB_GADGET_GENERIC,
+	.of_match = ssusb_of_match,
+	.probe = mtu3_gadget_probe,
+	.remove = mtu3_gadget_remove,
+	.priv_auto	= sizeof(struct mtu3),
+};
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	(!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+static int mtu3_host_probe(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
+	struct mtu3_host *u3h = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int rc;
+
+	u3h->dev = dev;
+	ssusb->u3h = u3h;
+	rc = ssusb_host_init(ssusb);
+	if (rc)
+		return rc;
+
+	u3h->ctrl.quirks = XHCI_MTK_HOST;
+	hcor = (struct xhci_hcor *)((uintptr_t)u3h->hcd +
+			HC_LENGTH(xhci_readl(&u3h->hcd->cr_capbase)));
+
+	return xhci_register(dev, u3h->hcd, hcor);
+}
+
+static int mtu3_host_remove(struct udevice *dev)
+{
+	struct mtu3_host *u3h = dev_get_priv(dev);
+
+	xhci_deregister(dev);
+	ssusb_host_exit(u3h->ssusb);
+	return 0;
+}
+
+U_BOOT_DRIVER(mtu3_host) = {
+	.name = "mtu3-host",
+	.id = UCLASS_USB,
+	.of_match = ssusb_of_match,
+	.probe = mtu3_host_probe,
+	.remove = mtu3_host_remove,
+	.priv_auto	= sizeof(struct mtu3_host),
+	.ops = &xhci_usb_ops,
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
+
+static int mtu3_glue_bind(struct udevice *parent)
+{
+	struct udevice *dev;
+	enum usb_dr_mode dr_mode;
+	const char *driver;
+	const char *name;
+	ofnode node;
+	int ret;
+
+	node = ofnode_by_compatible(dev_ofnode(parent), "mediatek,ssusb");
+	if (!ofnode_valid(node))
+		return -ENODEV;
+
+	name = ofnode_get_name(node);
+	dr_mode = usb_get_dr_mode(node);
+
+	switch (dr_mode) {
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
+		dev_dbg(parent, "%s: dr_mode: peripheral\n", __func__);
+		driver = "mtu3-peripheral";
+		break;
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	(!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+	case USB_DR_MODE_HOST:
+		dev_dbg(parent, "%s: dr_mode: host\n", __func__);
+		driver = "mtu3-host";
+		break;
+#endif
+	default:
+		dev_err(parent, "%s: unsupported dr_mode %d\n",
+			__func__, dr_mode);
+		return -ENODEV;
+	};
+
+	dev_dbg(parent, "%s: node name: %s, driver %s, dr_mode %d\n",
+		__func__, name, driver, dr_mode);
+
+	ret = device_bind_driver_to_node(parent, driver, name, node, &dev);
+	if (ret)
+		dev_err(parent, "%s: not able to bind usb device mode\n",
+			__func__);
+
+	return ret;
+}
+
+static const struct udevice_id mtu3_of_match[] = {
+	{.compatible = "mediatek,mtu3",},
+	{},
+};
+
+U_BOOT_DRIVER(mtu3) = {
+	.name = "mtu3",
+	.id = UCLASS_NOP,
+	.of_match = mtu3_of_match,
+	.bind = mtu3_glue_bind,
+	.probe = mtu3_probe,
+	.remove = mtu3_remove,
+	.priv_auto	= sizeof(struct ssusb_mtk),
+};
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_qmu.c b/roms/u-boot/drivers/usb/mtu3/mtu3_qmu.c
new file mode 100644
index 000000000..95eaf6d23
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_qmu.c
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_qmu.c - Queue Management Unit driver for device controller
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+/*
+ * Queue Management Unit (QMU) is designed to unload SW effort
+ * to serve DMA interrupts.
+ * By preparing General Purpose Descriptor (GPD) and Buffer Descriptor (BD),
+ * SW links data buffers and triggers QMU to send / receive data to
+ * host / from device at a time.
+ * And now only GPD is supported.
+ *
+ * For more detailed information, please refer to QMU Programming Guide
+ */
+
+#include <asm/cache.h>
+#include <cpu_func.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+
+#include "mtu3.h"
+
+#define QMU_CHECKSUM_LEN	16
+
+#define GPD_FLAGS_HWO	BIT(0)
+#define GPD_FLAGS_BDP	BIT(1)
+#define GPD_FLAGS_BPS	BIT(2)
+#define GPD_FLAGS_IOC	BIT(7)
+
+#define GPD_EXT_FLAG_ZLP	BIT(5)
+
+#define DCACHELINE_SIZE		CONFIG_SYS_CACHELINE_SIZE
+
+void mtu3_flush_cache(uintptr_t addr, u32 len)
+{
+	WARN_ON(!(void *)addr || len == 0);
+
+	flush_dcache_range(addr & ~(DCACHELINE_SIZE - 1),
+			   ALIGN(addr + len, DCACHELINE_SIZE));
+}
+
+void mtu3_inval_cache(uintptr_t addr, u32 len)
+{
+	WARN_ON(!(void *)addr || len == 0);
+
+	invalidate_dcache_range(addr & ~(DCACHELINE_SIZE - 1),
+				ALIGN(addr + len, DCACHELINE_SIZE));
+}
+
+static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
+				       dma_addr_t dma_addr)
+{
+	dma_addr_t dma_base = ring->dma;
+	struct qmu_gpd *gpd_head = ring->start;
+	u32 offset = (dma_addr - dma_base) / sizeof(*gpd_head);
+
+	if (offset >= MAX_GPD_NUM)
+		return NULL;
+
+	return gpd_head + offset;
+}
+
+static dma_addr_t gpd_virt_to_dma(struct mtu3_gpd_ring *ring,
+				  struct qmu_gpd *gpd)
+{
+	dma_addr_t dma_base = ring->dma;
+	struct qmu_gpd *gpd_head = ring->start;
+	u32 offset;
+
+	offset = gpd - gpd_head;
+	if (offset >= MAX_GPD_NUM)
+		return 0;
+
+	return dma_base + (offset * sizeof(*gpd));
+}
+
+static void gpd_ring_init(struct mtu3_gpd_ring *ring, struct qmu_gpd *gpd)
+{
+	ring->start = gpd;
+	ring->enqueue = gpd;
+	ring->dequeue = gpd;
+	ring->end = gpd + MAX_GPD_NUM - 1;
+}
+
+static void reset_gpd_list(struct mtu3_ep *mep)
+{
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	struct qmu_gpd *gpd = ring->start;
+
+	if (gpd) {
+		gpd->flag &= ~GPD_FLAGS_HWO;
+		gpd_ring_init(ring, gpd);
+		mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+	}
+}
+
+int mtu3_gpd_ring_alloc(struct mtu3_ep *mep)
+{
+	struct qmu_gpd *gpd;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+	/* software own all gpds as default */
+	gpd = memalign(DCACHELINE_SIZE, QMU_GPD_RING_SIZE);
+	if (!gpd)
+		return -ENOMEM;
+
+	memset(gpd, 0, QMU_GPD_RING_SIZE);
+	ring->dma = (dma_addr_t)gpd;
+	gpd_ring_init(ring, gpd);
+
+	return 0;
+}
+
+void mtu3_gpd_ring_free(struct mtu3_ep *mep)
+{
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+	kfree(ring->start);
+	memset(ring, 0, sizeof(*ring));
+}
+
+void mtu3_qmu_resume(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	int epnum = mep->epnum;
+	u32 offset;
+
+	offset = mep->is_in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+	mtu3_writel(mbase, offset, QMU_Q_RESUME);
+	if (!(mtu3_readl(mbase, offset) & QMU_Q_ACTIVE))
+		mtu3_writel(mbase, offset, QMU_Q_RESUME);
+}
+
+static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
+{
+	if (ring->enqueue < ring->end)
+		ring->enqueue++;
+	else
+		ring->enqueue = ring->start;
+
+	return ring->enqueue;
+}
+
+static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
+{
+	if (ring->dequeue < ring->end)
+		ring->dequeue++;
+	else
+		ring->dequeue = ring->start;
+
+	return ring->dequeue;
+}
+
+/* check if a ring is emtpy */
+static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+{
+	struct qmu_gpd *enq = ring->enqueue;
+	struct qmu_gpd *next;
+
+	if (ring->enqueue < ring->end)
+		next = enq + 1;
+	else
+		next = ring->start;
+
+	/* one gpd is reserved to simplify gpd preparation */
+	return next == ring->dequeue;
+}
+
+int mtu3_prepare_transfer(struct mtu3_ep *mep)
+{
+	return gpd_ring_empty(&mep->gpd_ring);
+}
+
+static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	struct qmu_gpd *enq;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	struct qmu_gpd *gpd = ring->enqueue;
+	struct usb_request *req = &mreq->request;
+
+	/* set all fields to zero as default value */
+	memset(gpd, 0, sizeof(*gpd));
+
+	gpd->buffer = cpu_to_le32((u32)req->dma);
+	gpd->buf_len = cpu_to_le16(req->length);
+
+	/* get the next GPD */
+	enq = advance_enq_gpd(ring);
+	dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p\n",
+		mep->epnum, gpd, enq);
+
+	enq->flag &= ~GPD_FLAGS_HWO;
+	gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
+	mtu3_flush_cache((uintptr_t)enq, sizeof(*gpd));
+
+	if (req->zero)
+		gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
+
+	gpd->flag |= GPD_FLAGS_IOC | GPD_FLAGS_HWO;
+
+	mreq->gpd = gpd;
+
+	if (req->length)
+		mtu3_flush_cache((uintptr_t)req->buf, req->length);
+
+	mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	return 0;
+}
+
+static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	struct qmu_gpd *enq;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	struct qmu_gpd *gpd = ring->enqueue;
+	struct usb_request *req = &mreq->request;
+
+	/* set all fields to zero as default value */
+	memset(gpd, 0, sizeof(*gpd));
+
+	gpd->buffer = cpu_to_le32((u32)req->dma);
+	gpd->data_buf_len = cpu_to_le16(req->length);
+
+	/* get the next GPD */
+	enq = advance_enq_gpd(ring);
+	dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p\n",
+		mep->epnum, gpd, enq);
+
+	enq->flag &= ~GPD_FLAGS_HWO;
+	gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
+	mtu3_flush_cache((uintptr_t)enq, sizeof(*gpd));
+
+	gpd->flag |= GPD_FLAGS_IOC | GPD_FLAGS_HWO;
+
+	mreq->gpd = gpd;
+
+	mtu3_inval_cache((uintptr_t)req->buf, req->length);
+	mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	return 0;
+}
+
+void mtu3_insert_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	if (mep->is_in)
+		mtu3_prepare_tx_gpd(mep, mreq);
+	else
+		mtu3_prepare_rx_gpd(mep, mreq);
+}
+
+int mtu3_qmu_start(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	u8 epnum = mep->epnum;
+
+	if (mep->is_in) {
+		/* set QMU start address */
+		mtu3_writel(mbase, USB_QMU_TQSAR(epnum), ring->dma);
+		mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN);
+		/* send zero length packet according to ZLP flag in GPD */
+		mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum));
+		mtu3_writel(mbase, U3D_TQERRIESR0,
+			    QMU_TX_LEN_ERR(epnum) | QMU_TX_CS_ERR(epnum));
+
+		if (mtu3_readl(mbase, USB_QMU_TQCSR(epnum)) & QMU_Q_ACTIVE) {
+			dev_warn(mtu->dev, "Tx %d Active Now!\n", epnum);
+			return 0;
+		}
+		mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START);
+
+	} else {
+		mtu3_writel(mbase, USB_QMU_RQSAR(epnum), ring->dma);
+		mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN);
+		/* don't expect ZLP */
+		mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum));
+		/* move to next GPD when receive ZLP */
+		mtu3_setbits(mbase, U3D_QCR3, QMU_RX_COZ(epnum));
+		mtu3_writel(mbase, U3D_RQERRIESR0,
+			    QMU_RX_LEN_ERR(epnum) | QMU_RX_CS_ERR(epnum));
+		mtu3_writel(mbase, U3D_RQERRIESR1, QMU_RX_ZLP_ERR(epnum));
+
+		if (mtu3_readl(mbase, USB_QMU_RQCSR(epnum)) & QMU_Q_ACTIVE) {
+			dev_warn(mtu->dev, "Rx %d Active Now!\n", epnum);
+			return 0;
+		}
+		mtu3_writel(mbase, USB_QMU_RQCSR(epnum), QMU_Q_START);
+	}
+
+	return 0;
+}
+
+/* may called in atomic context */
+void mtu3_qmu_stop(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	int epnum = mep->epnum;
+	u32 value = 0;
+	u32 qcsr;
+	int ret;
+
+	qcsr = mep->is_in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+	if (!(mtu3_readl(mbase, qcsr) & QMU_Q_ACTIVE)) {
+		dev_dbg(mtu->dev, "%s's qmu is inactive now!\n", mep->name);
+		return;
+	}
+	mtu3_writel(mbase, qcsr, QMU_Q_STOP);
+
+	ret = readl_poll_timeout(mbase + qcsr, value,
+				 !(value & QMU_Q_ACTIVE), 1000);
+	if (ret) {
+		dev_err(mtu->dev, "stop %s's qmu failed\n", mep->name);
+		return;
+	}
+
+	dev_dbg(mtu->dev, "%s's qmu stop now!\n", mep->name);
+}
+
+void mtu3_qmu_flush(struct mtu3_ep *mep)
+{
+	dev_dbg(mep->mtu->dev, "%s flush QMU %s\n", __func__,
+		((mep->is_in) ? "TX" : "RX"));
+
+	/*Stop QMU */
+	mtu3_qmu_stop(mep);
+	reset_gpd_list(mep);
+}
+
+/*
+ * NOTE: request list maybe is already empty as following case:
+ * queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)-->
+ * queue_tx --> process_tasklet(meanwhile, the second one is transferred,
+ * tasklet process both of them)-->qmu_interrupt for second one.
+ * To avoid upper case, put qmu_done_tx in ISR directly to process it.
+ */
+static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
+{
+	struct mtu3_ep *mep = mtu->in_eps + epnum;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	void __iomem *mbase = mtu->mac_base;
+	struct qmu_gpd *gpd = ring->dequeue;
+	struct qmu_gpd *gpd_current = NULL;
+	struct usb_request *req = NULL;
+	struct mtu3_request *mreq;
+	dma_addr_t cur_gpd_dma;
+
+	/*transfer phy address got from QMU register to virtual address */
+	cur_gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
+	gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+	mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
+		__func__, epnum, gpd, gpd_current, ring->enqueue);
+
+	while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+		mreq = next_request(mep);
+
+		if (!mreq || mreq->gpd != gpd) {
+			dev_err(mtu->dev, "no correct TX req is found\n");
+			break;
+		}
+
+		req = &mreq->request;
+		req->actual = le16_to_cpu(gpd->buf_len);
+		mtu3_req_complete(mep, req, 0);
+
+		gpd = advance_deq_gpd(ring);
+		mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+	}
+
+	dev_dbg(mtu->dev, "%s EP%d, deq=%p, enq=%p, complete\n",
+		__func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
+{
+	struct mtu3_ep *mep = mtu->out_eps + epnum;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	void __iomem *mbase = mtu->mac_base;
+	struct qmu_gpd *gpd = ring->dequeue;
+	struct qmu_gpd *gpd_current = NULL;
+	struct usb_request *req = NULL;
+	struct mtu3_request *mreq;
+	dma_addr_t cur_gpd_dma;
+
+	cur_gpd_dma = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
+	gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+	mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
+		__func__, epnum, gpd, gpd_current, ring->enqueue);
+
+	while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+		mreq = next_request(mep);
+
+		if (!mreq || mreq->gpd != gpd) {
+			dev_err(mtu->dev, "no correct RX req is found\n");
+			break;
+		}
+		req = &mreq->request;
+
+		req->actual = le16_to_cpu(gpd->buf_len);
+		mtu3_req_complete(mep, req, 0);
+
+		gpd = advance_deq_gpd(ring);
+		mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+	}
+
+	dev_dbg(mtu->dev, "%s EP%d, deq=%p, enq=%p, complete\n",
+		__func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_isr(struct mtu3 *mtu, u32 done_status)
+{
+	int i;
+
+	for (i = 1; i < mtu->num_eps; i++) {
+		if (done_status & QMU_RX_DONE_INT(i))
+			qmu_done_rx(mtu, i);
+		if (done_status & QMU_TX_DONE_INT(i))
+			qmu_done_tx(mtu, i);
+	}
+}
+
+static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 errval;
+	int i;
+
+	if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
+		errval = mtu3_readl(mbase, U3D_RQERRIR0);
+		for (i = 1; i < mtu->num_eps; i++) {
+			if (errval & QMU_RX_CS_ERR(i))
+				dev_err(mtu->dev, "Rx %d CS error!\n", i);
+
+			if (errval & QMU_RX_LEN_ERR(i))
+				dev_err(mtu->dev, "RX %d Length error\n", i);
+		}
+		mtu3_writel(mbase, U3D_RQERRIR0, errval);
+	}
+
+	if (qmu_status & RXQ_ZLPERR_INT) {
+		errval = mtu3_readl(mbase, U3D_RQERRIR1);
+		for (i = 1; i < mtu->num_eps; i++) {
+			if (errval & QMU_RX_ZLP_ERR(i))
+				dev_dbg(mtu->dev, "RX EP%d Recv ZLP\n", i);
+		}
+		mtu3_writel(mbase, U3D_RQERRIR1, errval);
+	}
+
+	if ((qmu_status & TXQ_CSERR_INT) || (qmu_status & TXQ_LENERR_INT)) {
+		errval = mtu3_readl(mbase, U3D_TQERRIR0);
+		for (i = 1; i < mtu->num_eps; i++) {
+			if (errval & QMU_TX_CS_ERR(i))
+				dev_err(mtu->dev, "Tx %d checksum error!\n", i);
+
+			if (errval & QMU_TX_LEN_ERR(i))
+				dev_err(mtu->dev, "Tx %d zlp error!\n", i);
+		}
+		mtu3_writel(mbase, U3D_TQERRIR0, errval);
+	}
+}
+
+irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 qmu_status;
+	u32 qmu_done_status;
+
+	/* U3D_QISAR1 is read update */
+	qmu_status = mtu3_readl(mbase, U3D_QISAR1);
+	qmu_status &= mtu3_readl(mbase, U3D_QIER1);
+
+	qmu_done_status = mtu3_readl(mbase, U3D_QISAR0);
+	qmu_done_status &= mtu3_readl(mbase, U3D_QIER0);
+	mtu3_writel(mbase, U3D_QISAR0, qmu_done_status); /* W1C */
+	dev_dbg(mtu->dev, "=== QMUdone[tx=%x, rx=%x] QMUexp[%x] ===\n",
+		(qmu_done_status & 0xFFFF), qmu_done_status >> 16,
+		qmu_status);
+
+	if (qmu_done_status)
+		qmu_done_isr(mtu, qmu_done_status);
+
+	if (qmu_status)
+		qmu_exception_isr(mtu, qmu_status);
+
+	return IRQ_HANDLED;
+}
+
+void mtu3_qmu_init(struct mtu3 *mtu)
+{
+	compiletime_assert(QMU_GPD_SIZE == 16, "QMU_GPD size SHOULD be 16B");
+}
+
+void mtu3_qmu_exit(struct mtu3 *mtu)
+{
+}
diff --git a/roms/u-boot/drivers/usb/mtu3/mtu3_qmu.h b/roms/u-boot/drivers/usb/mtu3/mtu3_qmu.h
new file mode 100644
index 000000000..ba8a3aa30
--- /dev/null
+++ b/roms/u-boot/drivers/usb/mtu3/mtu3_qmu.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_qmu.h - Queue Management Unit driver header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTK_QMU_H__
+#define __MTK_QMU_H__
+
+#define MAX_GPD_NUM		16
+#define QMU_GPD_SIZE		(sizeof(struct qmu_gpd))
+#define QMU_GPD_RING_SIZE	(MAX_GPD_NUM * QMU_GPD_SIZE)
+
+#define GPD_BUF_SIZE		65532
+
+void mtu3_flush_cache(uintptr_t addr, u32 len);
+void mtu3_inval_cache(uintptr_t addr, u32 len);
+
+void mtu3_qmu_stop(struct mtu3_ep *mep);
+int mtu3_qmu_start(struct mtu3_ep *mep);
+void mtu3_qmu_resume(struct mtu3_ep *mep);
+void mtu3_qmu_flush(struct mtu3_ep *mep);
+
+void mtu3_insert_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq);
+int mtu3_prepare_transfer(struct mtu3_ep *mep);
+
+int mtu3_gpd_ring_alloc(struct mtu3_ep *mep);
+void mtu3_gpd_ring_free(struct mtu3_ep *mep);
+
+irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu);
+void mtu3_qmu_init(struct mtu3 *mtu);
+void mtu3_qmu_exit(struct mtu3 *mtu);
+
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/Kconfig b/roms/u-boot/drivers/usb/musb-new/Kconfig
new file mode 100644
index 000000000..fd6f4109b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/Kconfig
@@ -0,0 +1,101 @@
+#
+# MUSB Controller Driver
+#
+comment "MUSB Controller Driver"
+
+config USB_MUSB_HOST
+	bool "MUSB host mode support"
+	select SPL_SPRINTF if SPL
+	select TPL_SPRINTF if TPL
+	help
+	  Enables the MUSB USB dual-role controller in host mode.
+
+config USB_MUSB_GADGET
+	bool "MUSB gadget mode support"
+	select USB_GADGET_DUALSPEED
+	select SPL_SPRINTF if SPL
+	select TPL_SPRINTF if TPL
+	help
+	  Enables the MUSB USB dual-role controller in gadget mode.
+
+config USB_MUSB_DA8XX
+	bool "Enable DA8xx MUSB Controller"
+	depends on DM_USB
+	help
+	  Say y here to enable support for the dual role high
+	  speed USB controller based on the Mentor Graphics
+	  silicon IP.
+
+config USB_MUSB_TI
+	bool "Enable TI OTG USB controller"
+	depends on DM_USB
+	select USB_MUSB_DSPS
+	default n
+	help
+	  Say y here to enable support for the dual role high
+	  speed USB controller based on the Mentor Graphics
+	  silicon IP.
+
+config USB_MUSB_OMAP2PLUS
+	tristate "OMAP2430 and onwards"
+	depends on ARCH_OMAP2PLUS
+
+config USB_MUSB_AM35X
+	bool "AM35x"
+
+config USB_MUSB_DSPS
+	bool "TI DSPS platforms"
+
+if USB_MUSB_HOST || USB_MUSB_GADGET
+config USB_MUSB_MT85XX
+	bool "Enable Mediatek MT85XX DRC USB controller"
+	depends on DM_USB && ARCH_MEDIATEK
+	default n
+	help
+	  Say y to enable Mediatek MT85XX USB DRC controller support
+	  if it is available on your Mediatek MUSB IP based platform.
+	  DMA controllers are ignored. This driver follow musb-new
+	  driver and usb gadget framework.
+
+config USB_MUSB_PIC32
+	bool "Enable Microchip PIC32 DRC USB controller"
+	depends on DM_USB && MACH_PIC32
+	help
+	  Say y to enable PIC32 USB DRC controller support
+	  if it is available on your Microchip PIC32 platform.
+
+config USB_MUSB_SUNXI
+	bool "Enable sunxi OTG / DRC USB controller"
+	depends on ARCH_SUNXI
+	default y
+	---help---
+	Say y here to enable support for the sunxi OTG / DRC USB controller
+	used on almost all sunxi boards.
+
+config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
+	bool "Disable MUSB bulk split/combine"
+	default y
+	help
+	  On TI AM335x devices, MUSB has bulk split/combine feature enabled
+	  in the ConfigData register, but the current MUSB driver does not
+	  support it yet. Select this option to disable the feature until the
+	  driver adds the support.
+
+endif
+
+config USB_MUSB_PIO_ONLY
+	bool "Disable DMA (always use PIO)"
+	default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX
+	help
+	  All data is copied between memory and FIFO by the CPU.
+	  DMA controllers are ignored.
+
+config USB_MUSB_FIXED_CONFIGDATA
+	bool "Hardcode MUSB CONFIGDATA register"
+	depends on USB_MUSB_SUNXI
+	default n if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || MACH_SUN7I || MACH_SUN8I_A23
+	default y
+	help
+	  Newer Allwinner SoCs do not implement the MUSB_CONFIGDATA register,
+	  so it always reads 0. Select this option to override this and
+	  return a hardcoded value instead.
diff --git a/roms/u-boot/drivers/usb/musb-new/Makefile b/roms/u-boot/drivers/usb/musb-new/Makefile
new file mode 100644
index 000000000..6355eb12d
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# for USB OTG silicon based on Mentor Graphics INVENTRA designs
+
+obj-$(CONFIG_USB_MUSB_GADGET) += musb_gadget.o musb_gadget_ep0.o musb_core.o
+obj-$(CONFIG_USB_MUSB_GADGET) += musb_uboot.o
+obj-$(CONFIG_USB_MUSB_HOST) += musb_host.o musb_core.o musb_uboot.o
+obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
+obj-$(CONFIG_USB_MUSB_DA8XX)	+= da8xx.o
+obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
+obj-$(CONFIG_USB_MUSB_MT85XX) += mt85xx.o
+obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
+obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
+obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
+obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
+
+ccflags-y := $(call cc-option,-Wno-unused-variable) \
+		$(call cc-option,-Wno-unused-but-set-variable) \
+		$(call cc-option,-Wno-unused-label)
diff --git a/roms/u-boot/drivers/usb/musb-new/am35x.c b/roms/u-boot/drivers/usb/musb-new/am35x.c
new file mode 100644
index 000000000..0a52e09e1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/am35x.c
@@ -0,0 +1,704 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments AM35x "glue layer"
+ *
+ * Copyright (c) 2010, by Texas Instruments
+ *
+ * Based on the DA8xx "glue layer" code.
+ * Copyright (c) 2008-2009, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ */
+
+#ifndef __UBOOT__
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/usb.h>
+#else
+#include <common.h>
+#include <asm/omap_musb.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "linux-compat.h"
+#endif
+
+#include "musb_core.h"
+
+/*
+ * AM35x specific definitions
+ */
+/* USB 2.0 OTG module registers */
+#define USB_REVISION_REG	0x00
+#define USB_CTRL_REG		0x04
+#define USB_STAT_REG		0x08
+#define USB_EMULATION_REG	0x0c
+/* 0x10 Reserved */
+#define USB_AUTOREQ_REG		0x14
+#define USB_SRP_FIX_TIME_REG	0x18
+#define USB_TEARDOWN_REG	0x1c
+#define EP_INTR_SRC_REG		0x20
+#define EP_INTR_SRC_SET_REG	0x24
+#define EP_INTR_SRC_CLEAR_REG	0x28
+#define EP_INTR_MASK_REG	0x2c
+#define EP_INTR_MASK_SET_REG	0x30
+#define EP_INTR_MASK_CLEAR_REG	0x34
+#define EP_INTR_SRC_MASKED_REG	0x38
+#define CORE_INTR_SRC_REG	0x40
+#define CORE_INTR_SRC_SET_REG	0x44
+#define CORE_INTR_SRC_CLEAR_REG	0x48
+#define CORE_INTR_MASK_REG	0x4c
+#define CORE_INTR_MASK_SET_REG	0x50
+#define CORE_INTR_MASK_CLEAR_REG 0x54
+#define CORE_INTR_SRC_MASKED_REG 0x58
+/* 0x5c Reserved */
+#define USB_END_OF_INTR_REG	0x60
+
+/* Control register bits */
+#define AM35X_SOFT_RESET_MASK	1
+
+/* USB interrupt register bits */
+#define AM35X_INTR_USB_SHIFT	16
+#define AM35X_INTR_USB_MASK	(0x1ff << AM35X_INTR_USB_SHIFT)
+#define AM35X_INTR_DRVVBUS	0x100
+#define AM35X_INTR_RX_SHIFT	16
+#define AM35X_INTR_TX_SHIFT	0
+#define AM35X_TX_EP_MASK	0xffff		/* EP0 + 15 Tx EPs */
+#define AM35X_RX_EP_MASK	0xfffe		/* 15 Rx EPs */
+#define AM35X_TX_INTR_MASK	(AM35X_TX_EP_MASK << AM35X_INTR_TX_SHIFT)
+#define AM35X_RX_INTR_MASK	(AM35X_RX_EP_MASK << AM35X_INTR_RX_SHIFT)
+
+#define USB_MENTOR_CORE_OFFSET	0x400
+
+struct am35x_glue {
+	struct device		*dev;
+	struct platform_device	*musb;
+	struct clk		*phy_clk;
+	struct clk		*clk;
+};
+#define glue_to_musb(g)		platform_get_drvdata(g->musb)
+
+/*
+ * am35x_musb_enable - enable interrupts
+ */
+#ifndef __UBOOT__
+static void am35x_musb_enable(struct musb *musb)
+#else
+static int am35x_musb_enable(struct musb *musb)
+#endif
+{
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 epmask;
+
+	/* Workaround: setup IRQs through both register sets. */
+	epmask = ((musb->epmask & AM35X_TX_EP_MASK) << AM35X_INTR_TX_SHIFT) |
+	       ((musb->epmask & AM35X_RX_EP_MASK) << AM35X_INTR_RX_SHIFT);
+
+	musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
+	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK);
+
+	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
+	if (is_otg_enabled(musb))
+		musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
+			    AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
+#ifdef __UBOOT__
+	return 0;
+#endif
+}
+
+/*
+ * am35x_musb_disable - disable HDRC and flush interrupts
+ */
+static void am35x_musb_disable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+
+	musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK);
+	musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG,
+			 AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK);
+	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+	musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
+}
+
+#ifndef __UBOOT__
+#define portstate(stmt)		stmt
+
+static void am35x_musb_set_vbus(struct musb *musb, int is_on)
+{
+	WARN_ON(is_on && is_peripheral_active(musb));
+}
+
+#define	POLL_SECONDS	2
+
+static struct timer_list otg_workaround;
+
+static void otg_timer(unsigned long _musb)
+{
+	struct musb		*musb = (void *)_musb;
+	void __iomem		*mregs = musb->mregs;
+	u8			devctl;
+	unsigned long		flags;
+
+	/*
+	 * We poll because AM35x's won't expose several OTG-critical
+	 * status change events (from the transceiver) otherwise.
+	 */
+	devctl = musb_readb(mregs, MUSB_DEVCTL);
+	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
+		otg_state_string(musb->xceiv->state));
+
+	spin_lock_irqsave(&musb->lock, flags);
+	switch (musb->xceiv->state) {
+	case OTG_STATE_A_WAIT_BCON:
+		devctl &= ~MUSB_DEVCTL_SESSION;
+		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE) {
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+			MUSB_DEV_MODE(musb);
+		} else {
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+			MUSB_HST_MODE(musb);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+		musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
+			    MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!is_peripheral_enabled(musb))
+			break;
+
+		devctl = musb_readb(mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE)
+			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+		else
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
+{
+	static unsigned long last_timer;
+
+	if (!is_otg_enabled(musb))
+		return;
+
+	if (timeout == 0)
+		timeout = jiffies + msecs_to_jiffies(3);
+
+	/* Never idle if active, or when VBUS timeout is not set as host */
+	if (musb->is_active || (musb->a_wait_bcon == 0 &&
+				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+		dev_dbg(musb->controller, "%s active, deleting timer\n",
+			otg_state_string(musb->xceiv->state));
+		del_timer(&otg_workaround);
+		last_timer = jiffies;
+		return;
+	}
+
+	if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
+		dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n");
+		return;
+	}
+	last_timer = timeout;
+
+	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
+		otg_state_string(musb->xceiv->state),
+		jiffies_to_msecs(timeout - jiffies));
+	mod_timer(&otg_workaround, timeout);
+}
+#endif
+
+static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	void __iomem *reg_base = musb->ctrl_base;
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+	struct usb_otg *otg = musb->xceiv->otg;
+#else
+	struct omap_musb_board_data *data =
+		(struct omap_musb_board_data *)musb->controller;
+#endif
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+	u32 epintr, usbintr;
+
+#ifdef __UBOOT__
+	/*
+	 * It seems that on AM35X interrupt registers can be updated
+	 * before core registers. This confuses the code.
+	 * As a workaround add a small delay here.
+	 */
+	udelay(10);
+#endif
+	spin_lock_irqsave(&musb->lock, flags);
+
+	/* Get endpoint interrupts */
+	epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG);
+
+	if (epintr) {
+		musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr);
+
+		musb->int_rx =
+			(epintr & AM35X_RX_INTR_MASK) >> AM35X_INTR_RX_SHIFT;
+		musb->int_tx =
+			(epintr & AM35X_TX_INTR_MASK) >> AM35X_INTR_TX_SHIFT;
+	}
+
+	/* Get usb core interrupts */
+	usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG);
+	if (!usbintr && !epintr)
+		goto eoi;
+
+	if (usbintr) {
+		musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr);
+
+		musb->int_usb =
+			(usbintr & AM35X_INTR_USB_MASK) >> AM35X_INTR_USB_SHIFT;
+	}
+#ifndef __UBOOT__
+	/*
+	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+	 * AM35x's missing ID change IRQ.  We need an ID change IRQ to
+	 * switch appropriately between halves of the OTG state machine.
+	 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+	 */
+	if (usbintr & (AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT)) {
+		int drvvbus = musb_readl(reg_base, USB_STAT_REG);
+		void __iomem *mregs = musb->mregs;
+		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
+		int err;
+
+		err = is_host_enabled(musb) && (musb->int_usb &
+						MUSB_INTR_VBUSERROR);
+		if (err) {
+			/*
+			 * The Mentor core doesn't debounce VBUS as needed
+			 * to cope with device connect current spikes. This
+			 * means it's not uncommon for bus-powered devices
+			 * to get VBUS errors during enumeration.
+			 *
+			 * This is a workaround, but newer RTL from Mentor
+			 * seems to allow a better one: "re"-starting sessions
+			 * without waiting for VBUS to stop registering in
+			 * devctl.
+			 */
+			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+			WARNING("VBUS error workaround (delay coming)\n");
+		} else if (is_host_enabled(musb) && drvvbus) {
+			MUSB_HST_MODE(musb);
+			otg->default_a = 1;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+			del_timer(&otg_workaround);
+		} else {
+			musb->is_active = 0;
+			MUSB_DEV_MODE(musb);
+			otg->default_a = 0;
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+		}
+
+		/* NOTE: this must complete power-on within 100 ms. */
+		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
+				drvvbus ? "on" : "off",
+				otg_state_string(musb->xceiv->state),
+				err ? " ERROR" : "",
+				devctl);
+		ret = IRQ_HANDLED;
+	}
+#endif
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb)
+		ret |= musb_interrupt(musb);
+
+eoi:
+	/* EOI needs to be written for the IRQ to be re-asserted. */
+	if (ret == IRQ_HANDLED || epintr || usbintr) {
+		/* clear level interrupt */
+		if (data->clear_irq)
+			data->clear_irq(data->dev);
+		/* write EOI */
+		musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
+	}
+
+#ifndef __UBOOT__
+	/* Poll for ID change */
+	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+#endif
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return ret;
+}
+
+#ifndef __UBOOT__
+static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
+{
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+	int     retval = 0;
+
+	if (data->set_mode)
+		data->set_mode(musb_mode);
+	else
+		retval = -EIO;
+
+	return retval;
+}
+#endif
+
+static int am35x_musb_init(struct musb *musb)
+{
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+#else
+	struct omap_musb_board_data *data =
+		(struct omap_musb_board_data *)musb->controller;
+#endif
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 rev;
+
+	musb->mregs += USB_MENTOR_CORE_OFFSET;
+
+	/* Returns zero if e.g. not clocked */
+	rev = musb_readl(reg_base, USB_REVISION_REG);
+	if (!rev)
+		return -ENODEV;
+
+#ifndef __UBOOT__
+	usb_nop_xceiv_register();
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
+		return -ENODEV;
+
+	if (is_host_enabled(musb))
+		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+#endif
+
+	/* Reset the musb */
+	if (data->reset)
+		data->reset(data->dev);
+
+	/* Reset the controller */
+	musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
+
+	/* Start the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 1);
+
+	msleep(5);
+
+	musb->isr = am35x_musb_interrupt;
+
+	/* clear level interrupt */
+	if (data->clear_irq)
+		data->clear_irq(data->dev);
+
+	return 0;
+}
+
+static int am35x_musb_exit(struct musb *musb)
+{
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+#else
+	struct omap_musb_board_data *data =
+		(struct omap_musb_board_data *)musb->controller;
+#endif
+
+#ifndef __UBOOT__
+	if (is_host_enabled(musb))
+		del_timer_sync(&otg_workaround);
+#endif
+
+	/* Shutdown the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 0);
+
+#ifndef __UBOOT__
+	usb_put_phy(musb->xceiv);
+	usb_nop_xceiv_unregister();
+#endif
+
+	return 0;
+}
+
+/* AM35x supports only 32bit read operation */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+	void __iomem *fifo = hw_ep->fifo;
+	u32		val;
+	int		i;
+
+	/* Read for 32bit-aligned destination address */
+	if (likely((0x03 & (unsigned long) dst) == 0) && len >= 4) {
+		readsl(fifo, dst, len >> 2);
+		dst += len & ~0x03;
+		len &= 0x03;
+	}
+	/*
+	 * Now read the remaining 1 to 3 byte or complete length if
+	 * unaligned address.
+	 */
+	if (len > 4) {
+		for (i = 0; i < (len >> 2); i++) {
+			*(u32 *) dst = musb_readl(fifo, 0);
+			dst += 4;
+		}
+		len &= 0x03;
+	}
+	if (len > 0) {
+		val = musb_readl(fifo, 0);
+		memcpy(dst, &val, len);
+	}
+}
+
+#ifndef __UBOOT__
+static const struct musb_platform_ops am35x_ops = {
+#else
+const struct musb_platform_ops am35x_ops = {
+#endif
+	.init		= am35x_musb_init,
+	.exit		= am35x_musb_exit,
+
+	.enable		= am35x_musb_enable,
+	.disable	= am35x_musb_disable,
+
+#ifndef __UBOOT__
+	.set_mode	= am35x_musb_set_mode,
+	.try_idle	= am35x_musb_try_idle,
+
+	.set_vbus	= am35x_musb_set_vbus,
+#endif
+};
+
+#ifndef __UBOOT__
+static u64 am35x_dmamask = DMA_BIT_MASK(32);
+
+static int __devinit am35x_probe(struct platform_device *pdev)
+{
+	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct platform_device		*musb;
+	struct am35x_glue		*glue;
+
+	struct clk			*phy_clk;
+	struct clk			*clk;
+
+	int				ret = -ENOMEM;
+
+	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	if (!glue) {
+		dev_err(&pdev->dev, "failed to allocate glue context\n");
+		goto err0;
+	}
+
+	musb = platform_device_alloc("musb-hdrc", -1);
+	if (!musb) {
+		dev_err(&pdev->dev, "failed to allocate musb device\n");
+		goto err1;
+	}
+
+	phy_clk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(phy_clk)) {
+		dev_err(&pdev->dev, "failed to get PHY clock\n");
+		ret = PTR_ERR(phy_clk);
+		goto err2;
+	}
+
+	clk = clk_get(&pdev->dev, "ick");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "failed to get clock\n");
+		ret = PTR_ERR(clk);
+		goto err3;
+	}
+
+	ret = clk_enable(phy_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable PHY clock\n");
+		goto err4;
+	}
+
+	ret = clk_enable(clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable clock\n");
+		goto err5;
+	}
+
+	musb->dev.parent		= &pdev->dev;
+	musb->dev.dma_mask		= &am35x_dmamask;
+	musb->dev.coherent_dma_mask	= am35x_dmamask;
+
+	glue->dev			= &pdev->dev;
+	glue->musb			= musb;
+	glue->phy_clk			= phy_clk;
+	glue->clk			= clk;
+
+	pdata->platform_ops		= &am35x_ops;
+
+	platform_set_drvdata(pdev, glue);
+
+	ret = platform_device_add_resources(musb, pdev->resource,
+			pdev->num_resources);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add resources\n");
+		goto err6;
+	}
+
+	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add platform_data\n");
+		goto err6;
+	}
+
+	ret = platform_device_add(musb);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register musb device\n");
+		goto err6;
+	}
+
+	return 0;
+
+err6:
+	clk_disable(clk);
+
+err5:
+	clk_disable(phy_clk);
+
+err4:
+	clk_put(clk);
+
+err3:
+	clk_put(phy_clk);
+
+err2:
+	platform_device_put(musb);
+
+err1:
+	kfree(glue);
+
+err0:
+	return ret;
+}
+
+static int __devexit am35x_remove(struct platform_device *pdev)
+{
+	struct am35x_glue	*glue = platform_get_drvdata(pdev);
+
+	platform_device_del(glue->musb);
+	platform_device_put(glue->musb);
+	clk_disable(glue->clk);
+	clk_disable(glue->phy_clk);
+	clk_put(glue->clk);
+	clk_put(glue->phy_clk);
+	kfree(glue);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int am35x_suspend(struct device *dev)
+{
+	struct am35x_glue	*glue = dev_get_drvdata(dev);
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+
+	/* Shutdown the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 0);
+
+	clk_disable(glue->phy_clk);
+	clk_disable(glue->clk);
+
+	return 0;
+}
+
+static int am35x_resume(struct device *dev)
+{
+	struct am35x_glue	*glue = dev_get_drvdata(dev);
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+	int			ret;
+
+	/* Start the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 1);
+
+	ret = clk_enable(glue->phy_clk);
+	if (ret) {
+		dev_err(dev, "failed to enable PHY clock\n");
+		return ret;
+	}
+
+	ret = clk_enable(glue->clk);
+	if (ret) {
+		dev_err(dev, "failed to enable clock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct dev_pm_ops am35x_pm_ops = {
+	.suspend	= am35x_suspend,
+	.resume		= am35x_resume,
+};
+
+#define DEV_PM_OPS	&am35x_pm_ops
+#else
+#define DEV_PM_OPS	NULL
+#endif
+
+static struct platform_driver am35x_driver = {
+	.probe		= am35x_probe,
+	.remove		= __devexit_p(am35x_remove),
+	.driver		= {
+		.name	= "musb-am35x",
+		.pm	= DEV_PM_OPS,
+	},
+};
+
+MODULE_DESCRIPTION("AM35x MUSB Glue Layer");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init am35x_init(void)
+{
+	return platform_driver_register(&am35x_driver);
+}
+module_init(am35x_init);
+
+static void __exit am35x_exit(void)
+{
+	platform_driver_unregister(&am35x_driver);
+}
+module_exit(am35x_exit);
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/da8xx.c b/roms/u-boot/drivers/usb/musb-new/da8xx.c
new file mode 100644
index 000000000..68fc0c361
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/da8xx.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments da8xx "glue layer"
+ *
+ * Copyright (c) 2019, by Texas Instruments
+ *
+ * Based on the DA8xx "glue layer" code.
+ * Copyright (c) 2008-2019, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * DT support
+ * Copyright (c) 2016 Petr Kulhavy <petr@barix.com>
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/da8xx-usb.h>
+#include <linux/delay.h>
+#include <linux/usb/otg.h>
+#include <asm/global_data.h>
+#include <asm/omap_musb.h>
+#include <generic-phy.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "musb_uboot.h"
+
+/* USB 2.0 OTG module registers */
+#define DA8XX_USB_REVISION_REG	0x00
+#define DA8XX_USB_CTRL_REG	0x04
+#define DA8XX_USB_STAT_REG	0x08
+#define DA8XX_USB_EMULATION_REG 0x0c
+#define DA8XX_USB_SRP_FIX_TIME_REG 0x18
+#define DA8XX_USB_INTR_SRC_REG	0x20
+#define DA8XX_USB_INTR_SRC_SET_REG 0x24
+#define DA8XX_USB_INTR_SRC_CLEAR_REG 0x28
+#define DA8XX_USB_INTR_MASK_REG 0x2c
+#define DA8XX_USB_INTR_MASK_SET_REG 0x30
+#define DA8XX_USB_INTR_MASK_CLEAR_REG 0x34
+#define DA8XX_USB_INTR_SRC_MASKED_REG 0x38
+#define DA8XX_USB_END_OF_INTR_REG 0x3c
+#define DA8XX_USB_GENERIC_RNDIS_EP_SIZE_REG(n) (0x50 + (((n) - 1) << 2))
+
+/* Control register bits */
+#define DA8XX_SOFT_RESET_MASK	1
+
+#define DA8XX_USB_TX_EP_MASK	0x1f		/* EP0 + 4 Tx EPs */
+#define DA8XX_USB_RX_EP_MASK	0x1e		/* 4 Rx EPs */
+
+/* USB interrupt register bits */
+#define DA8XX_INTR_USB_SHIFT	16
+#define DA8XX_INTR_USB_MASK	(0x1ff << DA8XX_INTR_USB_SHIFT) /* 8 Mentor */
+					/* interrupts and DRVVBUS interrupt */
+#define DA8XX_INTR_DRVVBUS	0x100
+#define DA8XX_INTR_RX_SHIFT	8
+#define DA8XX_INTR_RX_MASK	(DA8XX_USB_RX_EP_MASK << DA8XX_INTR_RX_SHIFT)
+#define DA8XX_INTR_TX_SHIFT	0
+#define DA8XX_INTR_TX_MASK	(DA8XX_USB_TX_EP_MASK << DA8XX_INTR_TX_SHIFT)
+
+#define DA8XX_MENTOR_CORE_OFFSET 0x400
+
+static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
+{
+	struct musb		*musb = hci;
+	void __iomem		*reg_base = musb->ctrl_base;
+	unsigned long		flags;
+	irqreturn_t		ret = IRQ_NONE;
+	u32			status;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	/*
+	 * NOTE: DA8XX shadows the Mentor IRQs.  Don't manage them through
+	 * the Mentor registers (except for setup), use the TI ones and EOI.
+	 */
+
+	/* Acknowledge and handle non-CPPI interrupts */
+	status = musb_readl(reg_base, DA8XX_USB_INTR_SRC_MASKED_REG);
+	if (!status)
+		goto eoi;
+
+	musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status);
+	dev_dbg(musb->controller, "USB IRQ %08x\n", status);
+
+	musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT;
+	musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT;
+	musb->int_usb = (status & DA8XX_INTR_USB_MASK) >> DA8XX_INTR_USB_SHIFT;
+
+	/*
+	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+	 * DA8xx's missing ID change IRQ.  We need an ID change IRQ to
+	 * switch appropriately between halves of the OTG state machine.
+	 * Managing DEVCTL.Session per Mentor docs requires that we know its
+	 * value but DEVCTL.BDevice is invalid without DEVCTL.Session set.
+	 * Also, DRVVBUS pulses for SRP (but not at 5 V)...
+	 */
+	if (status & (DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT)) {
+		int drvvbus = musb_readl(reg_base, DA8XX_USB_STAT_REG);
+		void __iomem *mregs = musb->mregs;
+		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
+		int err;
+
+		err = musb->int_usb & MUSB_INTR_VBUSERROR;
+		if (err) {
+			/*
+			 * The Mentor core doesn't debounce VBUS as needed
+			 * to cope with device connect current spikes. This
+			 * means it's not uncommon for bus-powered devices
+			 * to get VBUS errors during enumeration.
+			 *
+			 * This is a workaround, but newer RTL from Mentor
+			 * seems to allow a better one: "re"-starting sessions
+			 * without waiting for VBUS to stop registering in
+			 * devctl.
+			 */
+			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+			WARNING("VBUS error workaround (delay coming)\n");
+		} else if (drvvbus) {
+			MUSB_HST_MODE(musb);
+			musb->port1_status |= USB_PORT_STAT_POWER;
+		} else if (!(musb->int_usb & MUSB_INTR_BABBLE)) {
+			/*
+			 * When babble condition happens, drvvbus interrupt
+			 * is also generated. Ignore this drvvbus interrupt
+			 * and let babble interrupt handler recovers the
+			 * controller; otherwise, the host-mode flag is lost
+			 * due to the MUSB_DEV_MODE() call below and babble
+			 * recovery logic will not be called.
+			 */
+			musb->is_active = 0;
+			MUSB_DEV_MODE(musb);
+			musb->port1_status &= ~USB_PORT_STAT_POWER;
+		}
+		ret = IRQ_HANDLED;
+	}
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb)
+		ret |= musb_interrupt(musb);
+eoi:
+	/* EOI needs to be written for the IRQ to be re-asserted. */
+	if (ret == IRQ_HANDLED || status)
+		musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return ret;
+}
+
+static int da8xx_musb_init(struct musb *musb)
+{
+	u32  revision;
+	void __iomem *reg_base = musb->ctrl_base;
+
+	int ret;
+
+	/* reset the controller */
+	writel(0x1, &da8xx_usb_regs->control);
+	udelay(50);
+
+	/* Returns zero if e.g. not clocked */
+	revision = readl(&da8xx_usb_regs->revision);
+	if (revision == 0)
+		return -ENODEV;
+
+	/* Disable all interrupts */
+	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
+		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set);
+
+	musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
+
+	/* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */
+	debug("DA8xx OTG revision %08x, control %02x\n", revision,
+	      musb_readb(reg_base, DA8XX_USB_CTRL_REG));
+
+	musb->isr = da8xx_musb_interrupt;
+	return 0;
+}
+
+static int da8xx_musb_exit(struct musb *musb)
+{
+	/* flush any interrupts */
+	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
+		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
+	writel(0, &da8xx_usb_regs->eoi);
+
+	return 0;
+}
+
+/**
+ * da8xx_musb_enable - enable interrupts
+ */
+static int da8xx_musb_enable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 mask;
+
+	/* Workaround: setup IRQs through both register sets. */
+	mask = ((musb->epmask & DA8XX_USB_TX_EP_MASK) << DA8XX_INTR_TX_SHIFT) |
+	       ((musb->epmask & DA8XX_USB_RX_EP_MASK) << DA8XX_INTR_RX_SHIFT) |
+	       DA8XX_INTR_USB_MASK;
+	musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);
+
+	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
+	musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
+		    DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
+
+	return 0;
+}
+
+/**
+ * da8xx_musb_disable - disable HDRC and flush interrupts
+ */
+static void da8xx_musb_disable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+
+	musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG,
+		    DA8XX_INTR_USB_MASK |
+		    DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK);
+	musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
+}
+
+void da8xx_musb_reset(struct udevice *dev)
+{
+	void *reg_base = dev_read_addr_ptr(dev);
+
+	/* Reset the controller */
+	musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
+}
+
+void da8xx_musb_clear_irq(struct udevice *dev)
+{
+	/* flush any interrupts */
+	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
+		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
+	writel(0, &da8xx_usb_regs->eoi);
+}
+
+const struct musb_platform_ops da8xx_ops = {
+	.init		= da8xx_musb_init,
+	.exit		= da8xx_musb_exit,
+	.enable		= da8xx_musb_enable,
+	.disable	= da8xx_musb_disable,
+};
+
+struct da8xx_musb_plat {
+	void *base;
+	void *ctrl_mod_base;
+	struct musb_hdrc_platform_data plat;
+	struct musb_hdrc_config musb_config;
+	struct omap_musb_board_data otg_board_data;
+	struct phy phy;
+};
+
+static int da8xx_musb_of_to_plat(struct udevice *dev)
+{
+	struct da8xx_musb_plat *plat = dev_get_plat(dev);
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+
+	plat->base = (void *)dev_read_addr_ptr(dev);
+	plat->musb_config.multipoint = 1;
+	plat->musb_config.dyn_fifo = 1;
+	plat->musb_config.num_eps = 5;
+	plat->musb_config.ram_bits = 10;
+	plat->plat.power = fdtdec_get_int(fdt, node, "power", 50);
+	plat->otg_board_data.interface_type = MUSB_INTERFACE_UTMI;
+	plat->plat.mode = MUSB_HOST;
+	plat->otg_board_data.dev = dev;
+	plat->plat.config = &plat->musb_config;
+	plat->plat.platform_ops = &da8xx_ops;
+	plat->plat.board_data = &plat->otg_board_data;
+	plat->otg_board_data.clear_irq = da8xx_musb_clear_irq;
+	plat->otg_board_data.reset = da8xx_musb_reset;
+	return 0;
+}
+
+static int da8xx_musb_probe(struct udevice *dev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	struct da8xx_musb_plat *plat = dev_get_plat(dev);
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	struct omap_musb_board_data *otg_board_data;
+	int ret;
+	void *base = dev_read_addr_ptr(dev);
+
+	/* Get the phy info from the device tree */
+	ret = generic_phy_get_by_name(dev, "usb-phy", &plat->phy);
+	if (ret)
+		return ret;
+
+	/* Initialize the phy */
+	ret = generic_phy_init(&plat->phy);
+	if (ret)
+		return ret;
+
+	/* enable psc for usb2.0 */
+	lpsc_on(33);
+
+	/* Enable phy */
+	generic_phy_power_on(&plat->phy);
+
+	priv->desc_before_addr = true;
+	otg_board_data = &plat->otg_board_data;
+
+	host->host = musb_init_controller(&plat->plat,
+					  (struct device *)otg_board_data,
+					  plat->base);
+	if (!host->host) {
+		ret = -ENODEV;
+		goto shutdown; /* Shutdown what we started */
+	}
+
+	ret = musb_lowlevel_init(host);
+
+	if (ret == 0)
+		return 0;
+shutdown:
+	/* Turn off the phy if we fail */
+	generic_phy_power_off(&plat->phy);
+	lpsc_disable(33);
+	return ret;
+}
+
+static int da8xx_musb_remove(struct udevice *dev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+
+	musb_stop(host->host);
+
+	return 0;
+}
+
+static const struct udevice_id da8xx_musb_ids[] = {
+	{ .compatible = "ti,da830-musb" },
+	{ }
+};
+
+U_BOOT_DRIVER(da8xx_musb) = {
+	.name	= "da8xx-musb",
+	.id		= UCLASS_USB,
+	.of_match = da8xx_musb_ids,
+	.of_to_plat = da8xx_musb_of_to_plat,
+	.probe = da8xx_musb_probe,
+	.remove = da8xx_musb_remove,
+	.ops = &musb_usb_ops,
+	.plat_auto	= sizeof(struct da8xx_musb_plat),
+	.priv_auto	= sizeof(struct musb_host_data),
+};
diff --git a/roms/u-boot/drivers/usb/musb-new/linux-compat.h b/roms/u-boot/drivers/usb/musb-new/linux-compat.h
new file mode 100644
index 000000000..6d9f19dfe
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/linux-compat.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_COMPAT_H__
+#define __LINUX_COMPAT_H__
+
+#include <malloc.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/compat.h>
+
+#define device_init_wakeup(dev, a) do {} while (0)
+
+#define platform_data device_data
+
+#define msleep(a)	udelay(a * 1000)
+
+/*
+ * Map U-Boot config options to Linux ones
+ */
+#ifdef CONFIG_OMAP34XX
+#define CONFIG_SOC_OMAP3430
+#endif
+
+#ifdef CONFIG_OMAP44XX
+#define CONFIG_ARCH_OMAP4
+#endif
+
+#endif /* __LINUX_COMPAT_H__ */
diff --git a/roms/u-boot/drivers/usb/musb-new/mt85xx.c b/roms/u-boot/drivers/usb/musb-new/mt85xx.c
new file mode 100644
index 000000000..730045cf9
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/mt85xx.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek "glue layer"
+ *
+ * Copyright (C) 2019-2021 by Mediatek
+ * Based on the AllWinner SUNXI "glue layer" code.
+ * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/delay.h>
+#include <linux/usb/musb.h>
+#include <usb.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "musb_uboot.h"
+
+#define DBG_I(fmt, ...) \
+	pr_info(fmt, ##__VA_ARGS__)
+
+struct mtk_musb_config {
+	struct musb_hdrc_config *config;
+};
+
+struct mtk_musb_glue {
+	struct musb_host_data mdata;
+	struct clk usbpllclk;
+	struct clk usbmcuclk;
+	struct clk usbclk;
+	struct mtk_musb_config *cfg;
+	struct device dev;
+};
+
+#define to_mtk_musb_glue(d)	container_of(d, struct mtk_musb_glue, dev)
+
+/******************************************************************************
+ * phy settings
+ ******************************************************************************/
+#define USB20_PHY_BASE			0x11110800
+#define USBPHY_READ8(offset)	 \
+	readb((void *)(USB20_PHY_BASE + (offset)))
+#define USBPHY_WRITE8(offset, value)	\
+	writeb(value, (void *)(USB20_PHY_BASE + (offset)))
+#define USBPHY_SET8(offset, mask)	\
+	USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) | (mask))
+#define USBPHY_CLR8(offset, mask)	\
+	USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) & (~(mask)))
+
+static void mt_usb_phy_poweron(void)
+{
+	/*
+	 * switch to USB function.
+	 * (system register, force ip into usb mode).
+	 */
+	USBPHY_CLR8(0x6b, 0x04);
+	USBPHY_CLR8(0x6e, 0x01);
+	USBPHY_CLR8(0x21, 0x03);
+
+	/* RG_USB20_BC11_SW_EN = 1'b0 */
+	USBPHY_SET8(0x22, 0x04);
+	USBPHY_CLR8(0x1a, 0x80);
+
+	/* RG_USB20_DP_100K_EN = 1'b0 */
+	/* RG_USB20_DP_100K_EN = 1'b0 */
+	USBPHY_CLR8(0x22, 0x03);
+
+	/*OTG enable*/
+	USBPHY_SET8(0x20, 0x10);
+	/* release force suspendm */
+	USBPHY_CLR8(0x6a, 0x04);
+
+	mdelay(800);
+
+	/* force enter device mode */
+	USBPHY_CLR8(0x6c, 0x10);
+	USBPHY_SET8(0x6c, 0x2E);
+	USBPHY_SET8(0x6d, 0x3E);
+}
+
+static void mt_usb_phy_savecurrent(void)
+{
+	/*
+	 * switch to USB function.
+	 * (system register, force ip into usb mode).
+	 */
+	USBPHY_CLR8(0x6b, 0x04);
+	USBPHY_CLR8(0x6e, 0x01);
+	USBPHY_CLR8(0x21, 0x03);
+
+	/* release force suspendm */
+	USBPHY_CLR8(0x6a, 0x04);
+	USBPHY_SET8(0x68, 0x04);
+	/* RG_DPPULLDOWN./RG_DMPULLDOWN. */
+	USBPHY_SET8(0x68, 0xc0);
+	/* RG_XCVRSEL[1:0] = 2'b01 */
+	USBPHY_CLR8(0x68, 0x30);
+	USBPHY_SET8(0x68, 0x10);
+	/* RG_TERMSEL = 1'b1 */
+	USBPHY_SET8(0x68, 0x04);
+	/* RG_DATAIN[3:0] = 4'b0000 */
+	USBPHY_CLR8(0x69, 0x3c);
+
+	/*
+	 * force_dp_pulldown, force_dm_pulldown,
+	 * force_xcversel, force_termsel.
+	 */
+	USBPHY_SET8(0x6a, 0xba);
+
+	/* RG_USB20_BC11_SW_EN = 1'b0 */
+	USBPHY_CLR8(0x1a, 0x80);
+	/* RG_USB20_OTG_VBUSSCMP_EN = 1'b0 */
+	USBPHY_CLR8(0x1a, 0x10);
+
+	mdelay(800);
+
+	USBPHY_CLR8(0x6a, 0x04);
+	/* rg_usb20_pll_stable = 1 */
+	//USBPHY_SET8(0x63, 0x02);
+
+	mdelay(1);
+
+	/* force suspendm = 1 */
+	//USBPHY_SET8(0x6a, 0x04);
+}
+
+static void mt_usb_phy_recover(void)
+{
+	/* clean PUPD_BIST_EN */
+	/* PUPD_BIST_EN = 1'b0 */
+	/* PMIC will use it to detect charger type */
+	USBPHY_CLR8(0x1d, 0x10);
+
+	/* force_uart_en = 1'b0 */
+	USBPHY_CLR8(0x6b, 0x04);
+	/* RG_UART_EN = 1'b0 */
+	USBPHY_CLR8(0x6e, 0x01);
+	/* force_uart_en = 1'b0 */
+	USBPHY_CLR8(0x6a, 0x04);
+
+	USBPHY_CLR8(0x21, 0x03);
+	USBPHY_CLR8(0x68, 0xf4);
+
+	/* RG_DATAIN[3:0] = 4'b0000 */
+	USBPHY_CLR8(0x69, 0x3c);
+
+	USBPHY_CLR8(0x6a, 0xba);
+
+	/* RG_USB20_BC11_SW_EN = 1'b0 */
+	USBPHY_CLR8(0x1a, 0x80);
+	/* RG_USB20_OTG_VBUSSCMP_EN = 1'b1 */
+	USBPHY_SET8(0x1a, 0x10);
+
+	//HQA adjustment
+	USBPHY_CLR8(0x18, 0x08);
+	USBPHY_SET8(0x18, 0x06);
+	mdelay(800);
+
+	/* force enter device mode */
+	//USBPHY_CLR8(0x6c, 0x10);
+	//USBPHY_SET8(0x6c, 0x2E);
+	//USBPHY_SET8(0x6d, 0x3E);
+
+	/* enable VRT internal R architecture */
+	/* RG_USB20_INTR_EN = 1'b1 */
+	USBPHY_SET8(0x00, 0x20);
+}
+
+/******************************************************************************
+ * MUSB Glue code
+ ******************************************************************************/
+
+static irqreturn_t mtk_musb_interrupt(int irq, void *__hci)
+{
+	struct musb		*musb = __hci;
+	irqreturn_t		retval = IRQ_NONE;
+
+	/* read and flush interrupts */
+	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+//	last_int_usb = musb->int_usb;
+	if (musb->int_usb)
+		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+	if (musb->int_tx)
+		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+	if (musb->int_rx)
+		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+
+	if (musb->int_usb || musb->int_tx || musb->int_rx)
+		retval |= musb_interrupt(musb);
+
+	return retval;
+}
+
+/* musb_core does not call enable / disable in a balanced manner <sigh> */
+static bool enabled;
+
+static int mtk_musb_enable(struct musb *musb)
+{
+	struct mtk_musb_glue *glue = to_mtk_musb_glue(musb->controller);
+
+	DBG_I("%s():\n", __func__);
+
+	musb_ep_select(musb->mregs, 0);
+	musb_writeb(musb->mregs, MUSB_FADDR, 0);
+
+	if (enabled)
+		return 0;
+
+	mt_usb_phy_recover();
+
+	enabled = true;
+
+	return 0;
+}
+
+static void mtk_musb_disable(struct musb *musb)
+{
+	struct mtk_musb_glue *glue = to_mtk_musb_glue(musb->controller);
+	int ret;
+
+	DBG_I("%s():\n", __func__);
+
+	if (!enabled)
+		return;
+
+	mt_usb_phy_savecurrent();
+
+	enabled = false;
+}
+
+static int mtk_musb_init(struct musb *musb)
+{
+	struct mtk_musb_glue *glue = to_mtk_musb_glue(musb->controller);
+	int ret;
+
+	DBG_I("%s():\n", __func__);
+
+	ret = clk_enable(&glue->usbpllclk);
+	if (ret) {
+		dev_err(musb->controller, "failed to enable usbpll clock\n");
+		return ret;
+	}
+	ret = clk_enable(&glue->usbmcuclk);
+	if (ret) {
+		dev_err(musb->controller, "failed to enable usbmcu clock\n");
+		return ret;
+	}
+	ret = clk_enable(&glue->usbclk);
+	if (ret) {
+		dev_err(musb->controller, "failed to enable usb clock\n");
+		return ret;
+	}
+
+	musb->isr = mtk_musb_interrupt;
+
+	return 0;
+}
+
+static int mtk_musb_exit(struct musb *musb)
+{
+	struct mtk_musb_glue *glue = to_mtk_musb_glue(musb->controller);
+
+	clk_disable(&glue->usbclk);
+	clk_disable(&glue->usbmcuclk);
+	clk_disable(&glue->usbpllclk);
+
+	return 0;
+}
+
+static const struct musb_platform_ops mtk_musb_ops = {
+	.init		= mtk_musb_init,
+	.exit		= mtk_musb_exit,
+	.enable		= mtk_musb_enable,
+	.disable	= mtk_musb_disable,
+};
+
+/* MTK OTG supports up to 7 endpoints */
+#define MTK_MUSB_MAX_EP_NUM		8
+#define MTK_MUSB_RAM_BITS		16
+
+static struct musb_fifo_cfg mtk_musb_mode_cfg[] = {
+	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(6, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(6, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(7, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(7, FIFO_RX, 512),
+};
+
+static struct musb_hdrc_config musb_config = {
+	.fifo_cfg       = mtk_musb_mode_cfg,
+	.fifo_cfg_size  = ARRAY_SIZE(mtk_musb_mode_cfg),
+	.multipoint	= true,
+	.dyn_fifo	= true,
+	.num_eps	= MTK_MUSB_MAX_EP_NUM,
+	.ram_bits	= MTK_MUSB_RAM_BITS,
+};
+
+static int musb_usb_probe(struct udevice *dev)
+{
+	struct mtk_musb_glue *glue = dev_get_priv(dev);
+	struct musb_host_data *host = &glue->mdata;
+	struct musb_hdrc_platform_data pdata;
+	void *base = dev_read_addr_ptr(dev);
+	int ret;
+
+	DBG_I("%s():\n", __func__);
+
+#ifdef CONFIG_USB_MUSB_HOST
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+#endif
+
+	if (!base)
+		return -EINVAL;
+
+	glue->cfg = (struct mtk_musb_config *)dev_get_driver_data(dev);
+	if (!glue->cfg)
+		return -EINVAL;
+
+	ret = clk_get_by_name(dev, "usbpll", &glue->usbpllclk);
+	if (ret) {
+		dev_err(dev, "failed to get usbpll clock\n");
+		return ret;
+	}
+	ret = clk_get_by_name(dev, "usbmcu", &glue->usbmcuclk);
+	if (ret) {
+		dev_err(dev, "failed to get usbmcu clock\n");
+		return ret;
+	}
+	ret = clk_get_by_name(dev, "usb", &glue->usbclk);
+	if (ret) {
+		dev_err(dev, "failed to get usb clock\n");
+		return ret;
+	}
+
+	memset(&pdata, 0, sizeof(pdata));
+	pdata.power = (u8)400;
+	pdata.platform_ops = &mtk_musb_ops;
+	pdata.config = glue->cfg->config;
+
+#ifdef CONFIG_USB_MUSB_HOST
+	priv->desc_before_addr = true;
+
+	pdata.mode = MUSB_HOST;
+	host->host = musb_init_controller(&pdata, &glue->dev, base);
+	if (!host->host)
+		return -EIO;
+
+	ret = musb_lowlevel_init(host);
+	if (!ret)
+		printf("MTK MUSB OTG (Host)\n");
+#else
+	pdata.mode = MUSB_PERIPHERAL;
+	host->host = musb_register(&pdata, &glue->dev, base);
+	if (!host->host)
+		return -EIO;
+
+	printf("MTK MUSB OTG (Peripheral)\n");
+#endif
+
+	mt_usb_phy_poweron();
+
+	return ret;
+}
+
+static int musb_usb_remove(struct udevice *dev)
+{
+	struct mtk_musb_glue *glue = dev_get_priv(dev);
+	struct musb_host_data *host = &glue->mdata;
+
+	musb_stop(host->host);
+	free(host->host);
+	host->host = NULL;
+
+	return 0;
+}
+
+static const struct mtk_musb_config mt8518_cfg = {
+	.config = &musb_config,
+};
+
+static const struct udevice_id mtk_musb_ids[] = {
+	{ .compatible = "mediatek,mt8518-musb",
+	  .data = (ulong)&mt8518_cfg },
+	{ }
+};
+
+U_BOOT_DRIVER(mtk_musb) = {
+	.name		= "mtk_musb",
+#ifdef CONFIG_USB_MUSB_HOST
+	.id		= UCLASS_USB,
+#else
+	.id		= UCLASS_USB_GADGET_GENERIC,
+#endif
+	.of_match	= mtk_musb_ids,
+	.probe		= musb_usb_probe,
+	.remove		= musb_usb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+	.ops		= &musb_usb_ops,
+#endif
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct mtk_musb_glue),
+};
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_core.c b/roms/u-boot/drivers/usb/musb-new/musb_core.c
new file mode 100644
index 000000000..22811a5ef
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_core.c
@@ -0,0 +1,2497 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MUSB OTG driver core code
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+/*
+ * Inventra (Multipoint) Dual-Role Controller Driver for Linux.
+ *
+ * This consists of a Host Controller Driver (HCD) and a peripheral
+ * controller driver implementing the "Gadget" API; OTG support is
+ * in the works.  These are normal Linux-USB controller drivers which
+ * use IRQs and have no dedicated thread.
+ *
+ * This version of the driver has only been used with products from
+ * Texas Instruments.  Those products integrate the Inventra logic
+ * with other DMA, IRQ, and bus modules, as well as other logic that
+ * needs to be reflected in this driver.
+ *
+ *
+ * NOTE:  the original Mentor code here was pretty much a collection
+ * of mechanisms that don't seem to have been fully integrated/working
+ * for *any* Linux kernel version.  This version aims at Linux 2.6.now,
+ * Key open issues include:
+ *
+ *  - Lack of host-side transaction scheduling, for all transfer types.
+ *    The hardware doesn't do it; instead, software must.
+ *
+ *    This is not an issue for OTG devices that don't support external
+ *    hubs, but for more "normal" USB hosts it's a user issue that the
+ *    "multipoint" support doesn't scale in the expected ways.  That
+ *    includes DaVinci EVM in a common non-OTG mode.
+ *
+ *      * Control and bulk use dedicated endpoints, and there's as
+ *        yet no mechanism to either (a) reclaim the hardware when
+ *        peripherals are NAKing, which gets complicated with bulk
+ *        endpoints, or (b) use more than a single bulk endpoint in
+ *        each direction.
+ *
+ *        RESULT:  one device may be perceived as blocking another one.
+ *
+ *      * Interrupt and isochronous will dynamically allocate endpoint
+ *        hardware, but (a) there's no record keeping for bandwidth;
+ *        (b) in the common case that few endpoints are available, there
+ *        is no mechanism to reuse endpoints to talk to multiple devices.
+ *
+ *        RESULT:  At one extreme, bandwidth can be overcommitted in
+ *        some hardware configurations, no faults will be reported.
+ *        At the other extreme, the bandwidth capabilities which do
+ *        exist tend to be severely undercommitted.  You can't yet hook
+ *        up both a keyboard and a mouse to an external USB hub.
+ */
+
+/*
+ * This gets many kinds of configuration information:
+ *	- Kconfig for everything user-configurable
+ *	- platform_device for addressing, irq, and platform_data
+ *	- platform_data is mostly for board-specific informarion
+ *	  (plus recentrly, SOC or family details)
+ *
+ * Most of the conditional compilation will (someday) vanish.
+ */
+
+#ifndef __UBOOT__
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/prefetch.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#else
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <usb.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/musb.h>
+#include <asm/io.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#endif
+
+#include "musb_core.h"
+
+#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
+
+
+#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
+#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver"
+
+#define MUSB_VERSION "6.0"
+
+#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
+
+#define MUSB_DRIVER_NAME "musb-hdrc"
+const char musb_driver_name[] = MUSB_DRIVER_NAME;
+
+MODULE_DESCRIPTION(DRIVER_INFO);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);
+
+
+#ifndef __UBOOT__
+/*-------------------------------------------------------------------------*/
+
+static inline struct musb *dev_to_musb(struct device *dev)
+{
+	return dev_get_drvdata(dev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
+{
+	void __iomem *addr = phy->io_priv;
+	int	i = 0;
+	u8	r;
+	u8	power;
+	int	ret;
+
+	pm_runtime_get_sync(phy->io_dev);
+
+	/* Make sure the transceiver is not in low power mode */
+	power = musb_readb(addr, MUSB_POWER);
+	power &= ~MUSB_POWER_SUSPENDM;
+	musb_writeb(addr, MUSB_POWER, power);
+
+	/* REVISIT: musbhdrc_ulpi_an.pdf recommends setting the
+	 * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM.
+	 */
+
+	musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL,
+			MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR);
+
+	while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
+				& MUSB_ULPI_REG_CMPLT)) {
+		i++;
+		if (i == 10000) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+
+	}
+	r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
+	r &= ~MUSB_ULPI_REG_CMPLT;
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
+
+	ret = musb_readb(addr, MUSB_ULPI_REG_DATA);
+
+out:
+	pm_runtime_put(phy->io_dev);
+
+	return ret;
+}
+
+static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
+{
+	void __iomem *addr = phy->io_priv;
+	int	i = 0;
+	u8	r = 0;
+	u8	power;
+	int	ret = 0;
+
+	pm_runtime_get_sync(phy->io_dev);
+
+	/* Make sure the transceiver is not in low power mode */
+	power = musb_readb(addr, MUSB_POWER);
+	power &= ~MUSB_POWER_SUSPENDM;
+	musb_writeb(addr, MUSB_POWER, power);
+
+	musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+	musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data);
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ);
+
+	while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
+				& MUSB_ULPI_REG_CMPLT)) {
+		i++;
+		if (i == 10000) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+	}
+
+	r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
+	r &= ~MUSB_ULPI_REG_CMPLT;
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
+
+out:
+	pm_runtime_put(phy->io_dev);
+
+	return ret;
+}
+
+static struct usb_phy_io_ops musb_ulpi_access = {
+	.read = musb_ulpi_read,
+	.write = musb_ulpi_write,
+};
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if !defined(CONFIG_USB_MUSB_TUSB6010)
+
+/*
+ * Load an endpoint's FIFO
+ */
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+{
+	struct musb *musb = hw_ep->musb;
+	void __iomem *fifo = hw_ep->fifo;
+
+	prefetch((u8 *)src);
+
+	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
+			'T', hw_ep->epnum, fifo, len, src);
+
+	/* we can't assume unaligned reads work */
+	if (likely((0x01 & (unsigned long) src) == 0)) {
+		u16	index = 0;
+
+		/* best case is 32bit-aligned source address */
+		if ((0x02 & (unsigned long) src) == 0) {
+			if (len >= 4) {
+				writesl(fifo, src + index, len >> 2);
+				index += len & ~0x03;
+			}
+			if (len & 0x02) {
+				musb_writew(fifo, 0, *(u16 *)&src[index]);
+				index += 2;
+			}
+		} else {
+			if (len >= 2) {
+				writesw(fifo, src + index, len >> 1);
+				index += len & ~0x01;
+			}
+		}
+		if (len & 0x01)
+			musb_writeb(fifo, 0, src[index]);
+	} else  {
+		/* byte aligned */
+		writesb(fifo, src, len);
+	}
+}
+
+#if !defined(CONFIG_USB_MUSB_AM35X) && !defined(CONFIG_USB_MUSB_PIC32)
+/*
+ * Unload an endpoint's FIFO
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+	struct musb *musb = hw_ep->musb;
+	void __iomem *fifo = hw_ep->fifo;
+
+	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
+			'R', hw_ep->epnum, fifo, len, dst);
+
+	/* we can't assume unaligned writes work */
+	if (likely((0x01 & (unsigned long) dst) == 0)) {
+		u16	index = 0;
+
+		/* best case is 32bit-aligned destination address */
+		if ((0x02 & (unsigned long) dst) == 0) {
+			if (len >= 4) {
+				readsl(fifo, dst, len >> 2);
+				index = len & ~0x03;
+			}
+			if (len & 0x02) {
+				*(u16 *)&dst[index] = musb_readw(fifo, 0);
+				index += 2;
+			}
+		} else {
+			if (len >= 2) {
+				readsw(fifo, dst, len >> 1);
+				index = len & ~0x01;
+			}
+		}
+		if (len & 0x01)
+			dst[index] = musb_readb(fifo, 0);
+	} else  {
+		/* byte aligned */
+		readsb(fifo, dst, len);
+	}
+}
+#endif
+
+#endif	/* normal PIO */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 musb_test_packet[53] = {
+	/* implicit SYNC then DATA0 to start */
+
+	/* JKJKJKJK x9 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* JJKKJJKK x8 */
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	/* JJJJKKKK x8 */
+	0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+	/* JJJJJJJKKKKKKK x8 */
+	0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	/* JJJJJJJK x8 */
+	0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+	/* JKKKKKKK x10, JK */
+	0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+
+	/* implicit CRC16 then EOP to end */
+};
+
+void musb_load_testpacket(struct musb *musb)
+{
+	void __iomem	*regs = musb->endpoints[0].regs;
+
+	musb_ep_select(musb->mregs, 0);
+	musb_write_fifo(musb->control_ep,
+			sizeof(musb_test_packet), musb_test_packet);
+	musb_writew(regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY);
+}
+
+#ifndef __UBOOT__
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Handles OTG hnp timeouts, such as b_ase0_brst
+ */
+void musb_otg_timer_func(unsigned long data)
+{
+	struct musb	*musb = (struct musb *)data;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	switch (musb->xceiv->state) {
+	case OTG_STATE_B_WAIT_ACON:
+		dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n");
+		musb_g_disconnect(musb);
+		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+		musb->is_active = 0;
+		break;
+	case OTG_STATE_A_SUSPEND:
+	case OTG_STATE_A_WAIT_BCON:
+		dev_dbg(musb->controller, "HNP: %s timeout\n",
+			otg_state_string(musb->xceiv->state));
+		musb_platform_set_vbus(musb, 0);
+		musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+		break;
+	default:
+		dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
+			otg_state_string(musb->xceiv->state));
+	}
+	musb->ignore_disconnect = 0;
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+/*
+ * Stops the HNP transition. Caller must take care of locking.
+ */
+void musb_hnp_stop(struct musb *musb)
+{
+	struct usb_hcd	*hcd = musb_to_hcd(musb);
+	void __iomem	*mbase = musb->mregs;
+	u8	reg;
+
+	dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state));
+
+	switch (musb->xceiv->state) {
+	case OTG_STATE_A_PERIPHERAL:
+		musb_g_disconnect(musb);
+		dev_dbg(musb->controller, "HNP: back to %s\n",
+			otg_state_string(musb->xceiv->state));
+		break;
+	case OTG_STATE_B_HOST:
+		dev_dbg(musb->controller, "HNP: Disabling HR\n");
+		hcd->self.is_b_host = 0;
+		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+		MUSB_DEV_MODE(musb);
+		reg = musb_readb(mbase, MUSB_POWER);
+		reg |= MUSB_POWER_SUSPENDM;
+		musb_writeb(mbase, MUSB_POWER, reg);
+		/* REVISIT: Start SESSION_REQUEST here? */
+		break;
+	default:
+		dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
+			otg_state_string(musb->xceiv->state));
+	}
+
+	/*
+	 * When returning to A state after HNP, avoid hub_port_rebounce(),
+	 * which cause occasional OPT A "Did not receive reset after connect"
+	 * errors.
+	 */
+	musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16);
+}
+#endif
+
+/*
+ * Interrupt Service Routine to record USB "global" interrupts.
+ * Since these do not happen often and signify things of
+ * paramount importance, it seems OK to check them individually;
+ * the order of the tests is specified in the manual
+ *
+ * @param musb instance pointer
+ * @param int_usb register contents
+ * @param devctl
+ * @param power
+ */
+
+static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+				u8 devctl, u8 power)
+{
+#ifndef __UBOOT__
+	struct usb_otg *otg = musb->xceiv->otg;
+#endif
+	irqreturn_t handled = IRQ_NONE;
+
+	dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
+		int_usb);
+
+#ifndef __UBOOT__
+	/* in host mode, the peripheral may issue remote wakeup.
+	 * in peripheral mode, the host may resume the link.
+	 * spurious RESUME irqs happen too, paired with SUSPEND.
+	 */
+	if (int_usb & MUSB_INTR_RESUME) {
+		handled = IRQ_HANDLED;
+		dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state));
+
+		if (devctl & MUSB_DEVCTL_HM) {
+			void __iomem *mbase = musb->mregs;
+
+			switch (musb->xceiv->state) {
+			case OTG_STATE_A_SUSPEND:
+				/* remote wakeup?  later, GetPortStatus
+				 * will stop RESUME signaling
+				 */
+
+				if (power & MUSB_POWER_SUSPENDM) {
+					/* spurious */
+					musb->int_usb &= ~MUSB_INTR_SUSPEND;
+					dev_dbg(musb->controller, "Spurious SUSPENDM\n");
+					break;
+				}
+
+				power &= ~MUSB_POWER_SUSPENDM;
+				musb_writeb(mbase, MUSB_POWER,
+						power | MUSB_POWER_RESUME);
+
+				musb->port1_status |=
+						(USB_PORT_STAT_C_SUSPEND << 16)
+						| MUSB_PORT_STAT_RESUME;
+				musb->rh_timer = jiffies
+						+ msecs_to_jiffies(20);
+
+				musb->xceiv->state = OTG_STATE_A_HOST;
+				musb->is_active = 1;
+				usb_hcd_resume_root_hub(musb_to_hcd(musb));
+				break;
+			case OTG_STATE_B_WAIT_ACON:
+				musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+				musb->is_active = 1;
+				MUSB_DEV_MODE(musb);
+				break;
+			default:
+				WARNING("bogus %s RESUME (%s)\n",
+					"host",
+					otg_state_string(musb->xceiv->state));
+			}
+		} else {
+			switch (musb->xceiv->state) {
+			case OTG_STATE_A_SUSPEND:
+				/* possibly DISCONNECT is upcoming */
+				musb->xceiv->state = OTG_STATE_A_HOST;
+				usb_hcd_resume_root_hub(musb_to_hcd(musb));
+				break;
+			case OTG_STATE_B_WAIT_ACON:
+			case OTG_STATE_B_PERIPHERAL:
+				/* disconnect while suspended?  we may
+				 * not get a disconnect irq...
+				 */
+				if ((devctl & MUSB_DEVCTL_VBUS)
+						!= (3 << MUSB_DEVCTL_VBUS_SHIFT)
+						) {
+					musb->int_usb |= MUSB_INTR_DISCONNECT;
+					musb->int_usb &= ~MUSB_INTR_SUSPEND;
+					break;
+				}
+				musb_g_resume(musb);
+				break;
+			case OTG_STATE_B_IDLE:
+				musb->int_usb &= ~MUSB_INTR_SUSPEND;
+				break;
+			default:
+				WARNING("bogus %s RESUME (%s)\n",
+					"peripheral",
+					otg_state_string(musb->xceiv->state));
+			}
+		}
+	}
+
+	/* see manual for the order of the tests */
+	if (int_usb & MUSB_INTR_SESSREQ) {
+		void __iomem *mbase = musb->mregs;
+
+		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
+				&& (devctl & MUSB_DEVCTL_BDEVICE)) {
+			dev_dbg(musb->controller, "SessReq while on B state\n");
+			return IRQ_HANDLED;
+		}
+
+		dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
+			otg_state_string(musb->xceiv->state));
+
+		/* IRQ arrives from ID pin sense or (later, if VBUS power
+		 * is removed) SRP.  responses are time critical:
+		 *  - turn on VBUS (with silicon-specific mechanism)
+		 *  - go through A_WAIT_VRISE
+		 *  - ... to A_WAIT_BCON.
+		 * a_wait_vrise_tmout triggers VBUS_ERROR transitions
+		 */
+		musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+		musb->ep0_stage = MUSB_EP0_START;
+		musb->xceiv->state = OTG_STATE_A_IDLE;
+		MUSB_HST_MODE(musb);
+		musb_platform_set_vbus(musb, 1);
+
+		handled = IRQ_HANDLED;
+	}
+
+	if (int_usb & MUSB_INTR_VBUSERROR) {
+		int	ignore = 0;
+
+		/* During connection as an A-Device, we may see a short
+		 * current spikes causing voltage drop, because of cable
+		 * and peripheral capacitance combined with vbus draw.
+		 * (So: less common with truly self-powered devices, where
+		 * vbus doesn't act like a power supply.)
+		 *
+		 * Such spikes are short; usually less than ~500 usec, max
+		 * of ~2 msec.  That is, they're not sustained overcurrent
+		 * errors, though they're reported using VBUSERROR irqs.
+		 *
+		 * Workarounds:  (a) hardware: use self powered devices.
+		 * (b) software:  ignore non-repeated VBUS errors.
+		 *
+		 * REVISIT:  do delays from lots of DEBUG_KERNEL checks
+		 * make trouble here, keeping VBUS < 4.4V ?
+		 */
+		switch (musb->xceiv->state) {
+		case OTG_STATE_A_HOST:
+			/* recovery is dicey once we've gotten past the
+			 * initial stages of enumeration, but if VBUS
+			 * stayed ok at the other end of the link, and
+			 * another reset is due (at least for high speed,
+			 * to redo the chirp etc), it might work OK...
+			 */
+		case OTG_STATE_A_WAIT_BCON:
+		case OTG_STATE_A_WAIT_VRISE:
+			if (musb->vbuserr_retry) {
+				void __iomem *mbase = musb->mregs;
+
+				musb->vbuserr_retry--;
+				ignore = 1;
+				devctl |= MUSB_DEVCTL_SESSION;
+				musb_writeb(mbase, MUSB_DEVCTL, devctl);
+			} else {
+				musb->port1_status |=
+					  USB_PORT_STAT_OVERCURRENT
+					| (USB_PORT_STAT_C_OVERCURRENT << 16);
+			}
+			break;
+		default:
+			break;
+		}
+
+		dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+				otg_state_string(musb->xceiv->state),
+				devctl,
+				({ char *s;
+				switch (devctl & MUSB_DEVCTL_VBUS) {
+				case 0 << MUSB_DEVCTL_VBUS_SHIFT:
+					s = "<SessEnd"; break;
+				case 1 << MUSB_DEVCTL_VBUS_SHIFT:
+					s = "<AValid"; break;
+				case 2 << MUSB_DEVCTL_VBUS_SHIFT:
+					s = "<VBusValid"; break;
+				/* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */
+				default:
+					s = "VALID"; break;
+				}; s; }),
+				VBUSERR_RETRY_COUNT - musb->vbuserr_retry,
+				musb->port1_status);
+
+		/* go through A_WAIT_VFALL then start a new session */
+		if (!ignore)
+			musb_platform_set_vbus(musb, 0);
+		handled = IRQ_HANDLED;
+	}
+
+	if (int_usb & MUSB_INTR_SUSPEND) {
+		dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x power %02x\n",
+			otg_state_string(musb->xceiv->state), devctl, power);
+		handled = IRQ_HANDLED;
+
+		switch (musb->xceiv->state) {
+		case OTG_STATE_A_PERIPHERAL:
+			/* We also come here if the cable is removed, since
+			 * this silicon doesn't report ID-no-longer-grounded.
+			 *
+			 * We depend on T(a_wait_bcon) to shut us down, and
+			 * hope users don't do anything dicey during this
+			 * undesired detour through A_WAIT_BCON.
+			 */
+			musb_hnp_stop(musb);
+			usb_hcd_resume_root_hub(musb_to_hcd(musb));
+			musb_root_disconnect(musb);
+			musb_platform_try_idle(musb, jiffies
+					+ msecs_to_jiffies(musb->a_wait_bcon
+						? : OTG_TIME_A_WAIT_BCON));
+
+			break;
+		case OTG_STATE_B_IDLE:
+			if (!musb->is_active)
+				break;
+		case OTG_STATE_B_PERIPHERAL:
+			musb_g_suspend(musb);
+			musb->is_active = is_otg_enabled(musb)
+					&& otg->gadget->b_hnp_enable;
+			if (musb->is_active) {
+				musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+				dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
+				mod_timer(&musb->otg_timer, jiffies
+					+ msecs_to_jiffies(
+							OTG_TIME_B_ASE0_BRST));
+			}
+			break;
+		case OTG_STATE_A_WAIT_BCON:
+			if (musb->a_wait_bcon != 0)
+				musb_platform_try_idle(musb, jiffies
+					+ msecs_to_jiffies(musb->a_wait_bcon));
+			break;
+		case OTG_STATE_A_HOST:
+			musb->xceiv->state = OTG_STATE_A_SUSPEND;
+			musb->is_active = is_otg_enabled(musb)
+					&& otg->host->b_hnp_enable;
+			break;
+		case OTG_STATE_B_HOST:
+			/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+			dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n");
+			break;
+		default:
+			/* "should not happen" */
+			musb->is_active = 0;
+			break;
+		}
+	}
+#endif
+
+	if (int_usb & MUSB_INTR_CONNECT) {
+		struct usb_hcd *hcd = musb_to_hcd(musb);
+
+		handled = IRQ_HANDLED;
+		musb->is_active = 1;
+
+		musb->ep0_stage = MUSB_EP0_START;
+
+		/* flush endpoints when transitioning from Device Mode */
+		if (is_peripheral_active(musb)) {
+			/* REVISIT HNP; just force disconnect */
+		}
+		musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask);
+		musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe);
+		musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7);
+#ifndef __UBOOT__
+		musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
+					|USB_PORT_STAT_HIGH_SPEED
+					|USB_PORT_STAT_ENABLE
+					);
+		musb->port1_status |= USB_PORT_STAT_CONNECTION
+					|(USB_PORT_STAT_C_CONNECTION << 16);
+
+		/* high vs full speed is just a guess until after reset */
+		if (devctl & MUSB_DEVCTL_LSDEV)
+			musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+
+		/* indicate new connection to OTG machine */
+		switch (musb->xceiv->state) {
+		case OTG_STATE_B_PERIPHERAL:
+			if (int_usb & MUSB_INTR_SUSPEND) {
+				dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n");
+				int_usb &= ~MUSB_INTR_SUSPEND;
+				goto b_host;
+			} else
+				dev_dbg(musb->controller, "CONNECT as b_peripheral???\n");
+			break;
+		case OTG_STATE_B_WAIT_ACON:
+			dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");
+b_host:
+			musb->xceiv->state = OTG_STATE_B_HOST;
+			hcd->self.is_b_host = 1;
+			musb->ignore_disconnect = 0;
+			del_timer(&musb->otg_timer);
+			break;
+		default:
+			if ((devctl & MUSB_DEVCTL_VBUS)
+					== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+				musb->xceiv->state = OTG_STATE_A_HOST;
+				hcd->self.is_b_host = 0;
+			}
+			break;
+		}
+
+		/* poke the root hub */
+		MUSB_HST_MODE(musb);
+		if (hcd->status_urb)
+			usb_hcd_poll_rh_status(hcd);
+		else
+			usb_hcd_resume_root_hub(hcd);
+
+		dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
+				otg_state_string(musb->xceiv->state), devctl);
+#endif
+	}
+
+#ifndef __UBOOT__
+	if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
+		dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
+				otg_state_string(musb->xceiv->state),
+				MUSB_MODE(musb), devctl);
+		handled = IRQ_HANDLED;
+
+		switch (musb->xceiv->state) {
+		case OTG_STATE_A_HOST:
+		case OTG_STATE_A_SUSPEND:
+			usb_hcd_resume_root_hub(musb_to_hcd(musb));
+			musb_root_disconnect(musb);
+			if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+				musb_platform_try_idle(musb, jiffies
+					+ msecs_to_jiffies(musb->a_wait_bcon));
+			break;
+		case OTG_STATE_B_HOST:
+			/* REVISIT this behaves for "real disconnect"
+			 * cases; make sure the other transitions from
+			 * from B_HOST act right too.  The B_HOST code
+			 * in hnp_stop() is currently not used...
+			 */
+			musb_root_disconnect(musb);
+			musb_to_hcd(musb)->self.is_b_host = 0;
+			musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+			MUSB_DEV_MODE(musb);
+			musb_g_disconnect(musb);
+			break;
+		case OTG_STATE_A_PERIPHERAL:
+			musb_hnp_stop(musb);
+			musb_root_disconnect(musb);
+			/* FALLTHROUGH */
+		case OTG_STATE_B_WAIT_ACON:
+			/* FALLTHROUGH */
+		case OTG_STATE_B_PERIPHERAL:
+		case OTG_STATE_B_IDLE:
+			musb_g_disconnect(musb);
+			break;
+		default:
+			WARNING("unhandled DISCONNECT transition (%s)\n",
+				otg_state_string(musb->xceiv->state));
+			break;
+		}
+	}
+
+	/* mentor saves a bit: bus reset and babble share the same irq.
+	 * only host sees babble; only peripheral sees bus reset.
+	 */
+	if (int_usb & MUSB_INTR_RESET) {
+		handled = IRQ_HANDLED;
+		if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
+			/*
+			 * Looks like non-HS BABBLE can be ignored, but
+			 * HS BABBLE is an error condition. For HS the solution
+			 * is to avoid babble in the first place and fix what
+			 * caused BABBLE. When HS BABBLE happens we can only
+			 * stop the session.
+			 */
+			if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV))
+				dev_dbg(musb->controller, "BABBLE devctl: %02x\n", devctl);
+			else {
+				ERR("Stopping host session -- babble\n");
+				musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+			}
+		} else if (is_peripheral_capable()) {
+			dev_dbg(musb->controller, "BUS RESET as %s\n",
+				otg_state_string(musb->xceiv->state));
+			switch (musb->xceiv->state) {
+			case OTG_STATE_A_SUSPEND:
+				/* We need to ignore disconnect on suspend
+				 * otherwise tusb 2.0 won't reconnect after a
+				 * power cycle, which breaks otg compliance.
+				 */
+				musb->ignore_disconnect = 1;
+				musb_g_reset(musb);
+				/* FALLTHROUGH */
+			case OTG_STATE_A_WAIT_BCON:	/* OPT TD.4.7-900ms */
+				/* never use invalid T(a_wait_bcon) */
+				dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
+					otg_state_string(musb->xceiv->state),
+					TA_WAIT_BCON(musb));
+				mod_timer(&musb->otg_timer, jiffies
+					+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
+				break;
+			case OTG_STATE_A_PERIPHERAL:
+				musb->ignore_disconnect = 0;
+				del_timer(&musb->otg_timer);
+				musb_g_reset(musb);
+				break;
+			case OTG_STATE_B_WAIT_ACON:
+				dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
+					otg_state_string(musb->xceiv->state));
+				musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+				musb_g_reset(musb);
+				break;
+			case OTG_STATE_B_IDLE:
+				musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+				/* FALLTHROUGH */
+			case OTG_STATE_B_PERIPHERAL:
+				musb_g_reset(musb);
+				break;
+			default:
+				dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
+					otg_state_string(musb->xceiv->state));
+			}
+		}
+	}
+#endif
+
+#if 0
+/* REVISIT ... this would be for multiplexing periodic endpoints, or
+ * supporting transfer phasing to prevent exceeding ISO bandwidth
+ * limits of a given frame or microframe.
+ *
+ * It's not needed for peripheral side, which dedicates endpoints;
+ * though it _might_ use SOF irqs for other purposes.
+ *
+ * And it's not currently needed for host side, which also dedicates
+ * endpoints, relies on TX/RX interval registers, and isn't claimed
+ * to support ISO transfers yet.
+ */
+	if (int_usb & MUSB_INTR_SOF) {
+		void __iomem *mbase = musb->mregs;
+		struct musb_hw_ep	*ep;
+		u8 epnum;
+		u16 frame;
+
+		dev_dbg(musb->controller, "START_OF_FRAME\n");
+		handled = IRQ_HANDLED;
+
+		/* start any periodic Tx transfers waiting for current frame */
+		frame = musb_readw(mbase, MUSB_FRAME);
+		ep = musb->endpoints;
+		for (epnum = 1; (epnum < musb->nr_endpoints)
+					&& (musb->epmask >= (1 << epnum));
+				epnum++, ep++) {
+			/*
+			 * FIXME handle framecounter wraps (12 bits)
+			 * eliminate duplicated StartUrb logic
+			 */
+			if (ep->dwWaitFrame >= frame) {
+				ep->dwWaitFrame = 0;
+				pr_debug("SOF --> periodic TX%s on %d\n",
+					ep->tx_channel ? " DMA" : "",
+					epnum);
+				if (!ep->tx_channel)
+					musb_h_tx_start(musb, epnum);
+				else
+					cppi_hostdma_start(musb, epnum);
+			}
+		}		/* end of for loop */
+	}
+#endif
+
+	schedule_work(&musb->irq_work);
+
+	return handled;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+* Program the HDRC to start (enable interrupts, dma, etc.).
+*/
+#ifndef __UBOOT__
+void musb_start(struct musb *musb)
+#else
+int musb_start(struct musb *musb)
+#endif
+{
+	void __iomem	*regs = musb->mregs;
+	u8		devctl = musb_readb(regs, MUSB_DEVCTL);
+#ifdef __UBOOT__
+	int ret;
+#endif
+
+	dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
+
+	/*  Set INT enable registers, enable interrupts */
+	musb_writew(regs, MUSB_INTRTXE, musb->epmask);
+	musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe);
+	musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
+
+	musb_writeb(regs, MUSB_TESTMODE, 0);
+
+	/* put into basic highspeed mode and start session */
+	musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
+						| MUSB_POWER_HSENAB
+						/* ENSUSPEND wedges tusb */
+						/* | MUSB_POWER_ENSUSPEND */
+						);
+
+	musb->is_active = 0;
+	devctl = musb_readb(regs, MUSB_DEVCTL);
+	devctl &= ~MUSB_DEVCTL_SESSION;
+
+	if (is_otg_enabled(musb)) {
+#ifndef __UBOOT__
+		/* session started after:
+		 * (a) ID-grounded irq, host mode;
+		 * (b) vbus present/connect IRQ, peripheral mode;
+		 * (c) peripheral initiates, using SRP
+		 */
+		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+			musb->is_active = 1;
+		else
+			devctl |= MUSB_DEVCTL_SESSION;
+#endif
+
+	} else if (is_host_enabled(musb)) {
+		/* assume ID pin is hard-wired to ground */
+		devctl |= MUSB_DEVCTL_SESSION;
+
+	} else /* peripheral is enabled */ {
+		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+			musb->is_active = 1;
+	}
+
+#ifndef __UBOOT__
+	musb_platform_enable(musb);
+#else
+	ret = musb_platform_enable(musb);
+	if (ret) {
+		musb->is_active = 0;
+		return ret;
+	}
+#endif
+	musb_writeb(regs, MUSB_DEVCTL, devctl);
+
+#ifdef __UBOOT__
+	return 0;
+#endif
+}
+
+
+static void musb_generic_disable(struct musb *musb)
+{
+	void __iomem	*mbase = musb->mregs;
+	u16	temp;
+
+	/* disable interrupts */
+	musb_writeb(mbase, MUSB_INTRUSBE, 0);
+	musb_writew(mbase, MUSB_INTRTXE, 0);
+	musb_writew(mbase, MUSB_INTRRXE, 0);
+
+	/* off */
+	musb_writeb(mbase, MUSB_DEVCTL, 0);
+
+	/*  flush pending interrupts */
+	temp = musb_readb(mbase, MUSB_INTRUSB);
+	temp = musb_readw(mbase, MUSB_INTRTX);
+	temp = musb_readw(mbase, MUSB_INTRRX);
+
+}
+
+/*
+ * Make the HDRC stop (disable interrupts, etc.);
+ * reversible by musb_start
+ * called on gadget driver unregister
+ * with controller locked, irqs blocked
+ * acts as a NOP unless some role activated the hardware
+ */
+void musb_stop(struct musb *musb)
+{
+	/* stop IRQs, timers, ... */
+	musb_platform_disable(musb);
+	musb_generic_disable(musb);
+	dev_dbg(musb->controller, "HDRC disabled\n");
+
+	/* FIXME
+	 *  - mark host and/or peripheral drivers unusable/inactive
+	 *  - disable DMA (and enable it in HdrcStart)
+	 *  - make sure we can musb_start() after musb_stop(); with
+	 *    OTG mode, gadget driver module rmmod/modprobe cycles that
+	 *  - ...
+	 */
+	musb_platform_try_idle(musb, 0);
+	musb_platform_exit(musb);
+}
+
+#ifndef __UBOOT__
+static void musb_shutdown(struct platform_device *pdev)
+{
+	struct musb	*musb = dev_to_musb(&pdev->dev);
+	unsigned long	flags;
+
+	pm_runtime_get_sync(musb->controller);
+
+	musb_gadget_cleanup(musb);
+
+	spin_lock_irqsave(&musb->lock, flags);
+	musb_platform_disable(musb);
+	musb_generic_disable(musb);
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	if (!is_otg_enabled(musb) && is_host_enabled(musb))
+		usb_remove_hcd(musb_to_hcd(musb));
+	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+	musb_platform_exit(musb);
+
+	pm_runtime_put(musb->controller);
+	/* FIXME power down */
+}
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The silicon either has hard-wired endpoint configurations, or else
+ * "dynamic fifo" sizing.  The driver has support for both, though at this
+ * writing only the dynamic sizing is very well tested.   Since we switched
+ * away from compile-time hardware parameters, we can no longer rely on
+ * dead code elimination to leave only the relevant one in the object file.
+ *
+ * We don't currently use dynamic fifo setup capability to do anything
+ * more than selecting one of a bunch of predefined configurations.
+ */
+#if defined(CONFIG_USB_MUSB_TUSB6010)			\
+	|| defined(CONFIG_USB_MUSB_TUSB6010_MODULE)	\
+	|| defined(CONFIG_USB_MUSB_OMAP2PLUS)		\
+	|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)	\
+	|| defined(CONFIG_USB_MUSB_AM35X)		\
+	|| defined(CONFIG_USB_MUSB_AM35X_MODULE)	\
+	|| defined(CONFIG_USB_MUSB_DSPS)		\
+	|| defined(CONFIG_USB_MUSB_DSPS_MODULE)
+static ushort __devinitdata fifo_mode = 4;
+#elif defined(CONFIG_USB_MUSB_UX500)			\
+	|| defined(CONFIG_USB_MUSB_UX500_MODULE)
+static ushort __devinitdata fifo_mode = 5;
+#else
+static ushort __devinitdata fifo_mode = 2;
+#endif
+
+/* "modprobe ... fifo_mode=1" etc */
+module_param(fifo_mode, ushort, 0);
+MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
+
+/*
+ * tables defining fifo_mode values.  define more if you like.
+ * for host side, make sure both halves of ep1 are set up.
+ */
+
+/* mode 0 - fits in 2KB */
+static struct musb_fifo_cfg __devinitdata mode_0_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 1 - fits in 4KB */
+static struct musb_fifo_cfg __devinitdata mode_1_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 2 - fits in 4KB */
+static struct musb_fifo_cfg __devinitdata mode_2_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 3 - fits in 4KB */
+static struct musb_fifo_cfg __devinitdata mode_3_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
+{ .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },
+{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },
+};
+
+/* mode 4 - fits in 16KB */
+static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = {
+{ .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  7, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  7, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  8, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 256, },
+{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 64, },
+{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 256, },
+{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 64, },
+{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 256, },
+{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 64, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
+
+/* mode 5 - fits in 8KB */
+static struct musb_fifo_cfg __devinitdata mode_5_cfg[] = {
+{ .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  6, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num =  7, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  7, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num =  8, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
+
+/*
+ * configure a fifo; for non-shared endpoints, this may be called
+ * once for a tx fifo and once for an rx fifo.
+ *
+ * returns negative errno or offset for next fifo.
+ */
+static int __devinit
+fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,
+		const struct musb_fifo_cfg *cfg, u16 offset)
+{
+	void __iomem	*mbase = musb->mregs;
+	int	size = 0;
+	u16	maxpacket = cfg->maxpacket;
+	u16	c_off = offset >> 3;
+	u8	c_size;
+
+	/* expect hw_ep has already been zero-initialized */
+
+	size = ffs(max(maxpacket, (u16) 8)) - 1;
+	maxpacket = 1 << size;
+
+	c_size = size - 3;
+	if (cfg->mode == BUF_DOUBLE) {
+		if ((offset + (maxpacket << 1)) >
+				(1 << (musb->config->ram_bits + 2)))
+			return -EMSGSIZE;
+		c_size |= MUSB_FIFOSZ_DPB;
+	} else {
+		if ((offset + maxpacket) > (1 << (musb->config->ram_bits + 2)))
+			return -EMSGSIZE;
+	}
+
+	/* configure the FIFO */
+	musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum);
+
+	/* EP0 reserved endpoint for control, bidirectional;
+	 * EP1 reserved for bulk, two unidirection halves.
+	 */
+	if (hw_ep->epnum == 1)
+		musb->bulk_ep = hw_ep;
+	/* REVISIT error check:  be sure ep0 can both rx and tx ... */
+	switch (cfg->style) {
+	case FIFO_TX:
+		musb_write_txfifosz(mbase, c_size);
+		musb_write_txfifoadd(mbase, c_off);
+		hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
+		hw_ep->max_packet_sz_tx = maxpacket;
+		break;
+	case FIFO_RX:
+		musb_write_rxfifosz(mbase, c_size);
+		musb_write_rxfifoadd(mbase, c_off);
+		hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
+		hw_ep->max_packet_sz_rx = maxpacket;
+		break;
+	case FIFO_RXTX:
+		musb_write_txfifosz(mbase, c_size);
+		musb_write_txfifoadd(mbase, c_off);
+		hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
+		hw_ep->max_packet_sz_rx = maxpacket;
+
+		musb_write_rxfifosz(mbase, c_size);
+		musb_write_rxfifoadd(mbase, c_off);
+		hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
+		hw_ep->max_packet_sz_tx = maxpacket;
+
+		hw_ep->is_shared_fifo = true;
+		break;
+	}
+
+	/* NOTE rx and tx endpoint irqs aren't managed separately,
+	 * which happens to be ok
+	 */
+	musb->epmask |= (1 << hw_ep->epnum);
+
+	return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
+}
+
+static struct musb_fifo_cfg __devinitdata ep0_cfg = {
+	.style = FIFO_RXTX, .maxpacket = 64,
+};
+
+static int __devinit ep_config_from_table(struct musb *musb)
+{
+	const struct musb_fifo_cfg	*cfg;
+	unsigned		i, n;
+	int			offset;
+	struct musb_hw_ep	*hw_ep = musb->endpoints;
+
+	if (musb->config->fifo_cfg) {
+		cfg = musb->config->fifo_cfg;
+		n = musb->config->fifo_cfg_size;
+		goto done;
+	}
+
+	switch (fifo_mode) {
+	default:
+		fifo_mode = 0;
+		/* FALLTHROUGH */
+	case 0:
+		cfg = mode_0_cfg;
+		n = ARRAY_SIZE(mode_0_cfg);
+		break;
+	case 1:
+		cfg = mode_1_cfg;
+		n = ARRAY_SIZE(mode_1_cfg);
+		break;
+	case 2:
+		cfg = mode_2_cfg;
+		n = ARRAY_SIZE(mode_2_cfg);
+		break;
+	case 3:
+		cfg = mode_3_cfg;
+		n = ARRAY_SIZE(mode_3_cfg);
+		break;
+	case 4:
+		cfg = mode_4_cfg;
+		n = ARRAY_SIZE(mode_4_cfg);
+		break;
+	case 5:
+		cfg = mode_5_cfg;
+		n = ARRAY_SIZE(mode_5_cfg);
+		break;
+	}
+
+	pr_debug("%s: setup fifo_mode %d\n", musb_driver_name, fifo_mode);
+
+done:
+	offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
+	/* assert(offset > 0) */
+
+	/* NOTE:  for RTL versions >= 1.400 EPINFO and RAMINFO would
+	 * be better than static musb->config->num_eps and DYN_FIFO_SIZE...
+	 */
+
+	for (i = 0; i < n; i++) {
+		u8	epn = cfg->hw_ep_num;
+
+		if (epn >= musb->config->num_eps) {
+			pr_debug("%s: invalid ep %d\n",
+					musb_driver_name, epn);
+			return -EINVAL;
+		}
+		offset = fifo_setup(musb, hw_ep + epn, cfg++, offset);
+		if (offset < 0) {
+			pr_debug("%s: mem overrun, ep %d\n",
+					musb_driver_name, epn);
+			return -EINVAL;
+		}
+		epn++;
+		musb->nr_endpoints = max(epn, musb->nr_endpoints);
+	}
+
+	pr_debug("%s: %d/%d max ep, %d/%d memory\n", musb_driver_name, n + 1,
+		 musb->config->num_eps * 2 - 1, offset,
+		 (1 << (musb->config->ram_bits + 2)));
+
+	if (!musb->bulk_ep) {
+		pr_debug("%s: missing bulk\n", musb_driver_name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/*
+ * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
+ * @param musb the controller
+ */
+static int __devinit ep_config_from_hw(struct musb *musb)
+{
+	u8 epnum = 0;
+	struct musb_hw_ep *hw_ep;
+	void *mbase = musb->mregs;
+	int ret = 0;
+
+	dev_dbg(musb->controller, "<== static silicon ep config\n");
+
+	/* FIXME pick up ep0 maxpacket size */
+
+	for (epnum = 1; epnum < musb->config->num_eps; epnum++) {
+		musb_ep_select(mbase, epnum);
+		hw_ep = musb->endpoints + epnum;
+
+		ret = musb_read_fifosize(musb, hw_ep, epnum);
+		if (ret < 0)
+			break;
+
+		/* FIXME set up hw_ep->{rx,tx}_double_buffered */
+
+		/* pick an RX/TX endpoint for bulk */
+		if (hw_ep->max_packet_sz_tx < 512
+				|| hw_ep->max_packet_sz_rx < 512)
+			continue;
+
+		/* REVISIT:  this algorithm is lazy, we should at least
+		 * try to pick a double buffered endpoint.
+		 */
+		if (musb->bulk_ep)
+			continue;
+		musb->bulk_ep = hw_ep;
+	}
+
+	if (!musb->bulk_ep) {
+		pr_debug("%s: missing bulk\n", musb_driver_name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
+
+/* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
+ * configure endpoints, or take their config from silicon
+ */
+static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
+{
+	u8 reg;
+	char *type;
+	char aInfo[90], aRevision[32], aDate[12];
+	void __iomem	*mbase = musb->mregs;
+	int		status = 0;
+	int		i;
+
+	/* log core options (read using indexed model) */
+	reg = musb_read_configdata(mbase);
+
+	strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
+	if (reg & MUSB_CONFIGDATA_DYNFIFO) {
+		strcat(aInfo, ", dyn FIFOs");
+		musb->dyn_fifo = true;
+	}
+#ifndef CONFIG_USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
+	if (reg & MUSB_CONFIGDATA_MPRXE) {
+		strcat(aInfo, ", bulk combine");
+		musb->bulk_combine = true;
+	}
+	if (reg & MUSB_CONFIGDATA_MPTXE) {
+		strcat(aInfo, ", bulk split");
+		musb->bulk_split = true;
+	}
+#else
+	musb->bulk_combine = false;
+	musb->bulk_split = false;
+#endif
+	if (reg & MUSB_CONFIGDATA_HBRXE) {
+		strcat(aInfo, ", HB-ISO Rx");
+		musb->hb_iso_rx = true;
+	}
+	if (reg & MUSB_CONFIGDATA_HBTXE) {
+		strcat(aInfo, ", HB-ISO Tx");
+		musb->hb_iso_tx = true;
+	}
+	if (reg & MUSB_CONFIGDATA_SOFTCONE)
+		strcat(aInfo, ", SoftConn");
+
+	pr_debug("%s:ConfigData=0x%02x (%s)\n", musb_driver_name, reg, aInfo);
+
+	aDate[0] = 0;
+	if (MUSB_CONTROLLER_MHDRC == musb_type) {
+		musb->is_multipoint = 1;
+		type = "M";
+	} else {
+		musb->is_multipoint = 0;
+		type = "";
+#ifndef	CONFIG_USB_OTG_BLACKLIST_HUB
+		printk(KERN_ERR
+			"%s: kernel must blacklist external hubs\n",
+			musb_driver_name);
+#endif
+	}
+
+	/* log release info */
+	musb->hwvers = musb_read_hwvers(mbase);
+	snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers),
+		MUSB_HWVERS_MINOR(musb->hwvers),
+		(musb->hwvers & MUSB_HWVERS_RC) ? "RC" : "");
+	pr_debug("%s: %sHDRC RTL version %s %s\n", musb_driver_name, type,
+		 aRevision, aDate);
+
+	/* configure ep0 */
+	musb_configure_ep0(musb);
+
+	/* discover endpoint configuration */
+	musb->nr_endpoints = 1;
+	musb->epmask = 1;
+
+	if (musb->dyn_fifo)
+		status = ep_config_from_table(musb);
+	else
+		status = ep_config_from_hw(musb);
+
+	if (status < 0)
+		return status;
+
+	/* finish init, and print endpoint config */
+	for (i = 0; i < musb->nr_endpoints; i++) {
+		struct musb_hw_ep	*hw_ep = musb->endpoints + i;
+
+		hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
+		hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
+		hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
+		hw_ep->fifo_sync_va =
+			musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i);
+
+		if (i == 0)
+			hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF;
+		else
+			hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2);
+#endif
+
+		hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
+		hw_ep->target_regs = musb_read_target_reg_base(i, mbase);
+		hw_ep->rx_reinit = 1;
+		hw_ep->tx_reinit = 1;
+
+		if (hw_ep->max_packet_sz_tx) {
+			dev_dbg(musb->controller,
+				"%s: hw_ep %d%s, %smax %d\n",
+				musb_driver_name, i,
+				hw_ep->is_shared_fifo ? "shared" : "tx",
+				hw_ep->tx_double_buffered
+					? "doublebuffer, " : "",
+				hw_ep->max_packet_sz_tx);
+		}
+		if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) {
+			dev_dbg(musb->controller,
+				"%s: hw_ep %d%s, %smax %d\n",
+				musb_driver_name, i,
+				"rx",
+				hw_ep->rx_double_buffered
+					? "doublebuffer, " : "",
+				hw_ep->max_packet_sz_rx);
+		}
+		if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx))
+			dev_dbg(musb->controller, "hw_ep %d not configured\n", i);
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
+	defined(CONFIG_ARCH_OMAP4)
+
+static irqreturn_t generic_interrupt(int irq, void *__hci)
+{
+	unsigned long	flags;
+	irqreturn_t	retval = IRQ_NONE;
+	struct musb	*musb = __hci;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+
+	if (musb->int_usb || musb->int_tx || musb->int_rx)
+		retval = musb_interrupt(musb);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return retval;
+}
+
+#else
+#define generic_interrupt	NULL
+#endif
+
+/*
+ * handle all the irqs defined by the HDRC core. for now we expect:  other
+ * irq sources (phy, dma, etc) will be handled first, musb->int_* values
+ * will be assigned, and the irq will already have been acked.
+ *
+ * called in irq context with spinlock held, irqs blocked
+ */
+irqreturn_t musb_interrupt(struct musb *musb)
+{
+	irqreturn_t	retval = IRQ_NONE;
+	u8		devctl, power;
+	int		ep_num;
+	u32		reg;
+
+	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+	power = musb_readb(musb->mregs, MUSB_POWER);
+
+	dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n",
+		(devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral",
+		musb->int_usb, musb->int_tx, musb->int_rx);
+
+	/* the core can interrupt us for multiple reasons; docs have
+	 * a generic interrupt flowchart to follow
+	 */
+	if (musb->int_usb)
+		retval |= musb_stage0_irq(musb, musb->int_usb,
+				devctl, power);
+
+	/* "stage 1" is handling endpoint irqs */
+
+	/* handle endpoint 0 first */
+	if (musb->int_tx & 1) {
+		if (devctl & MUSB_DEVCTL_HM) {
+			if (is_host_capable())
+				retval |= musb_h_ep0_irq(musb);
+		} else {
+			if (is_peripheral_capable())
+				retval |= musb_g_ep0_irq(musb);
+		}
+	}
+
+	/* RX on endpoints 1-15 */
+	reg = musb->int_rx >> 1;
+	ep_num = 1;
+	while (reg) {
+		if (reg & 1) {
+			/* musb_ep_select(musb->mregs, ep_num); */
+			/* REVISIT just retval = ep->rx_irq(...) */
+			retval = IRQ_HANDLED;
+			if (devctl & MUSB_DEVCTL_HM) {
+				if (is_host_capable())
+					musb_host_rx(musb, ep_num);
+			} else {
+				if (is_peripheral_capable())
+					musb_g_rx(musb, ep_num);
+			}
+		}
+
+		reg >>= 1;
+		ep_num++;
+	}
+
+	/* TX on endpoints 1-15 */
+	reg = musb->int_tx >> 1;
+	ep_num = 1;
+	while (reg) {
+		if (reg & 1) {
+			/* musb_ep_select(musb->mregs, ep_num); */
+			/* REVISIT just retval |= ep->tx_irq(...) */
+			retval = IRQ_HANDLED;
+			if (devctl & MUSB_DEVCTL_HM) {
+				if (is_host_capable())
+					musb_host_tx(musb, ep_num);
+			} else {
+				if (is_peripheral_capable())
+					musb_g_tx(musb, ep_num);
+			}
+		}
+		reg >>= 1;
+		ep_num++;
+	}
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(musb_interrupt);
+
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+static bool __devinitdata use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+
+void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
+{
+	u8	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+	/* called with controller lock already held */
+
+	if (!epnum) {
+#ifndef CONFIG_USB_TUSB_OMAP_DMA
+		if (!is_cppi_enabled()) {
+			/* endpoint 0 */
+			if (devctl & MUSB_DEVCTL_HM)
+				musb_h_ep0_irq(musb);
+			else
+				musb_g_ep0_irq(musb);
+		}
+#endif
+	} else {
+		/* endpoints 1..15 */
+		if (transmit) {
+			if (devctl & MUSB_DEVCTL_HM) {
+				if (is_host_capable())
+					musb_host_tx(musb, epnum);
+			} else {
+				if (is_peripheral_capable())
+					musb_g_tx(musb, epnum);
+			}
+		} else {
+			/* receive */
+			if (devctl & MUSB_DEVCTL_HM) {
+				if (is_host_capable())
+					musb_host_rx(musb, epnum);
+			} else {
+				if (is_peripheral_capable())
+					musb_g_rx(musb, epnum);
+			}
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(musb_dma_completion);
+
+#else
+#define use_dma			0
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t
+musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct musb *musb = dev_to_musb(dev);
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state));
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return ret;
+}
+
+static ssize_t
+musb_mode_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+	struct musb	*musb = dev_to_musb(dev);
+	unsigned long	flags;
+	int		status;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	if (sysfs_streq(buf, "host"))
+		status = musb_platform_set_mode(musb, MUSB_HOST);
+	else if (sysfs_streq(buf, "peripheral"))
+		status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);
+	else if (sysfs_streq(buf, "otg"))
+		status = musb_platform_set_mode(musb, MUSB_OTG);
+	else
+		status = -EINVAL;
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return (status == 0) ? n : status;
+}
+static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
+
+static ssize_t
+musb_vbus_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+	struct musb	*musb = dev_to_musb(dev);
+	unsigned long	flags;
+	unsigned long	val;
+
+	if (sscanf(buf, "%lu", &val) < 1) {
+		dev_err(dev, "Invalid VBUS timeout ms value\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&musb->lock, flags);
+	/* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
+	musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
+	if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
+		musb->is_active = 0;
+	musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return n;
+}
+
+static ssize_t
+musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct musb	*musb = dev_to_musb(dev);
+	unsigned long	flags;
+	unsigned long	val;
+	int		vbus;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	val = musb->a_wait_bcon;
+	/* FIXME get_vbus_status() is normally #defined as false...
+	 * and is effectively TUSB-specific.
+	 */
+	vbus = musb_platform_get_vbus_status(musb);
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return sprintf(buf, "Vbus %s, timeout %lu msec\n",
+			vbus ? "on" : "off", val);
+}
+static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
+
+/* Gadget drivers can't know that a host is connected so they might want
+ * to start SRP, but users can.  This allows userspace to trigger SRP.
+ */
+static ssize_t
+musb_srp_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+	struct musb	*musb = dev_to_musb(dev);
+	unsigned short	srp;
+
+	if (sscanf(buf, "%hu", &srp) != 1
+			|| (srp != 1)) {
+		dev_err(dev, "SRP: Value must be 1\n");
+		return -EINVAL;
+	}
+
+	if (srp == 1)
+		musb_g_wakeup(musb);
+
+	return n;
+}
+static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store);
+
+static struct attribute *musb_attributes[] = {
+	&dev_attr_mode.attr,
+	&dev_attr_vbus.attr,
+	&dev_attr_srp.attr,
+	NULL
+};
+
+static const struct attribute_group musb_attr_group = {
+	.attrs = musb_attributes,
+};
+
+#endif	/* sysfs */
+
+#ifndef __UBOOT__
+/* Only used to provide driver mode change events */
+static void musb_irq_work(struct work_struct *data)
+{
+	struct musb *musb = container_of(data, struct musb, irq_work);
+	static int old_state;
+
+	if (musb->xceiv->state != old_state) {
+		old_state = musb->xceiv->state;
+		sysfs_notify(&musb->controller->kobj, NULL, "mode");
+	}
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ * Init support
+ */
+
+static struct musb *__devinit
+allocate_instance(struct device *dev,
+		struct musb_hdrc_config *config, void __iomem *mbase)
+{
+	struct musb		*musb;
+	struct musb_hw_ep	*ep;
+	int			epnum;
+#ifndef __UBOOT__
+	struct usb_hcd	*hcd;
+
+	hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev));
+	if (!hcd)
+		return NULL;
+	/* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
+
+	musb = hcd_to_musb(hcd);
+#else
+	musb = calloc(1, sizeof(*musb));
+	if (!musb)
+		return NULL;
+#endif
+	INIT_LIST_HEAD(&musb->control);
+	INIT_LIST_HEAD(&musb->in_bulk);
+	INIT_LIST_HEAD(&musb->out_bulk);
+
+#ifndef __UBOOT__
+	hcd->uses_new_polling = 1;
+	hcd->has_tt = 1;
+#endif
+
+	musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+	musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
+	dev_set_drvdata(dev, musb);
+	musb->mregs = mbase;
+	musb->ctrl_base = mbase;
+	musb->nIrq = -ENODEV;
+	musb->config = config;
+#ifdef __UBOOT__
+	assert_noisy(musb->config->num_eps <= MUSB_C_NUM_EPS);
+#else
+	BUG_ON(musb->config->num_eps > MUSB_C_NUM_EPS);
+#endif
+	for (epnum = 0, ep = musb->endpoints;
+			epnum < musb->config->num_eps;
+			epnum++, ep++) {
+		ep->musb = musb;
+		ep->epnum = epnum;
+	}
+
+	musb->controller = dev;
+
+	return musb;
+}
+
+static void musb_free(struct musb *musb)
+{
+	/* this has multiple entry modes. it handles fault cleanup after
+	 * probe(), where things may be partially set up, as well as rmmod
+	 * cleanup after everything's been de-activated.
+	 */
+
+#ifdef CONFIG_SYSFS
+	sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);
+#endif
+
+	if (musb->nIrq >= 0) {
+		if (musb->irq_wake)
+			disable_irq_wake(musb->nIrq);
+		free_irq(musb->nIrq, musb);
+	}
+	if (is_dma_capable() && musb->dma_controller) {
+		struct dma_controller	*c = musb->dma_controller;
+
+		(void) c->stop(c);
+		dma_controller_destroy(c);
+	}
+
+	kfree(musb);
+}
+
+/*
+ * Perform generic per-controller initialization.
+ *
+ * @pDevice: the controller (already clocked, etc)
+ * @nIrq: irq
+ * @mregs: virtual address of controller registers,
+ *	not yet corrected for platform-specific offsets
+ */
+#ifndef __UBOOT__
+static int __devinit
+musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
+#else
+struct musb *
+musb_init_controller(struct musb_hdrc_platform_data *plat, struct device *dev,
+			     void *ctrl)
+#endif
+{
+	int			status;
+	struct musb		*musb;
+#ifndef __UBOOT__
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+#else
+	int nIrq = 0;
+#endif
+
+	/* The driver might handle more features than the board; OK.
+	 * Fail when the board needs a feature that's not enabled.
+	 */
+	if (!plat) {
+		dev_dbg(dev, "no platform_data?\n");
+		status = -ENODEV;
+		goto fail0;
+	}
+
+	/* allocate */
+	musb = allocate_instance(dev, plat->config, ctrl);
+	if (!musb) {
+		status = -ENOMEM;
+		goto fail0;
+	}
+
+	pm_runtime_use_autosuspend(musb->controller);
+	pm_runtime_set_autosuspend_delay(musb->controller, 200);
+	pm_runtime_enable(musb->controller);
+
+	spin_lock_init(&musb->lock);
+	musb->board_mode = plat->mode;
+	musb->board_set_power = plat->set_power;
+	musb->min_power = plat->min_power;
+	musb->ops = plat->platform_ops;
+
+	/* The musb_platform_init() call:
+	 *   - adjusts musb->mregs and musb->isr if needed,
+	 *   - may initialize an integrated tranceiver
+	 *   - initializes musb->xceiv, usually by otg_get_phy()
+	 *   - stops powering VBUS
+	 *
+	 * There are various transceiver configurations.  Blackfin,
+	 * DaVinci, TUSB60x0, and others integrate them.  OMAP3 uses
+	 * external/discrete ones in various flavors (twl4030 family,
+	 * isp1504, non-OTG, etc) mostly hooking up through ULPI.
+	 */
+	musb->isr = generic_interrupt;
+	status = musb_platform_init(musb);
+	if (status < 0)
+		goto fail1;
+
+	if (!musb->isr) {
+		status = -ENODEV;
+		goto fail2;
+	}
+
+#ifndef __UBOOT__
+	if (!musb->xceiv->io_ops) {
+		musb->xceiv->io_dev = musb->controller;
+		musb->xceiv->io_priv = musb->mregs;
+		musb->xceiv->io_ops = &musb_ulpi_access;
+	}
+#endif
+
+	pm_runtime_get_sync(musb->controller);
+
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+	if (use_dma && dev->dma_mask) {
+		struct dma_controller	*c;
+
+		c = dma_controller_create(musb, musb->mregs);
+		musb->dma_controller = c;
+		if (c)
+			(void) c->start(c);
+	}
+#endif
+#ifndef __UBOOT__
+	/* ideally this would be abstracted in platform setup */
+	if (!is_dma_capable() || !musb->dma_controller)
+		dev->dma_mask = NULL;
+#endif
+
+	/* be sure interrupts are disabled before connecting ISR */
+	musb_platform_disable(musb);
+	musb_generic_disable(musb);
+
+	/* setup musb parts of the core (especially endpoints) */
+	status = musb_core_init(plat->config->multipoint
+			? MUSB_CONTROLLER_MHDRC
+			: MUSB_CONTROLLER_HDRC, musb);
+	if (status < 0)
+		goto fail3;
+
+	setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
+
+	/* Init IRQ workqueue before request_irq */
+	INIT_WORK(&musb->irq_work, musb_irq_work);
+
+	/* attach to the IRQ */
+	if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) {
+		dev_err(dev, "request_irq %d failed!\n", nIrq);
+		status = -ENODEV;
+		goto fail3;
+	}
+	musb->nIrq = nIrq;
+/* FIXME this handles wakeup irqs wrong */
+	if (enable_irq_wake(nIrq) == 0) {
+		musb->irq_wake = 1;
+		device_init_wakeup(dev, 1);
+	} else {
+		musb->irq_wake = 0;
+	}
+
+#ifndef __UBOOT__
+	/* host side needs more setup */
+	if (is_host_enabled(musb)) {
+		struct usb_hcd	*hcd = musb_to_hcd(musb);
+
+		otg_set_host(musb->xceiv->otg, &hcd->self);
+
+		if (is_otg_enabled(musb))
+			hcd->self.otg_port = 1;
+		musb->xceiv->otg->host = &hcd->self;
+		hcd->power_budget = 2 * (plat->power ? : 250);
+
+		/* program PHY to use external vBus if required */
+		if (plat->extvbus) {
+			u8 busctl = musb_read_ulpi_buscontrol(musb->mregs);
+			busctl |= MUSB_ULPI_USE_EXTVBUS;
+			musb_write_ulpi_buscontrol(musb->mregs, busctl);
+		}
+	}
+#endif
+
+	/* For the host-only role, we can activate right away.
+	 * (We expect the ID pin to be forcibly grounded!!)
+	 * Otherwise, wait till the gadget driver hooks up.
+	 */
+	if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+		struct usb_hcd	*hcd = musb_to_hcd(musb);
+
+		MUSB_HST_MODE(musb);
+#ifndef __UBOOT__
+		musb->xceiv->otg->default_a = 1;
+		musb->xceiv->state = OTG_STATE_A_IDLE;
+
+		status = usb_add_hcd(musb_to_hcd(musb), 0, 0);
+
+		hcd->self.uses_pio_for_control = 1;
+		dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n",
+			"HOST", status,
+			musb_readb(musb->mregs, MUSB_DEVCTL),
+			(musb_readb(musb->mregs, MUSB_DEVCTL)
+					& MUSB_DEVCTL_BDEVICE
+				? 'B' : 'A'));
+#endif
+
+	} else /* peripheral is enabled */ {
+		MUSB_DEV_MODE(musb);
+#ifndef __UBOOT__
+		musb->xceiv->otg->default_a = 0;
+		musb->xceiv->state = OTG_STATE_B_IDLE;
+#endif
+
+		if (is_peripheral_capable())
+			status = musb_gadget_setup(musb);
+
+#ifndef __UBOOT__
+		dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n",
+			is_otg_enabled(musb) ? "OTG" : "PERIPHERAL",
+			status,
+			musb_readb(musb->mregs, MUSB_DEVCTL));
+#endif
+
+	}
+	if (status < 0)
+		goto fail3;
+
+	status = musb_init_debugfs(musb);
+	if (status < 0)
+		goto fail4;
+
+#ifdef CONFIG_SYSFS
+	status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
+	if (status)
+		goto fail5;
+#endif
+
+	pm_runtime_put(musb->controller);
+
+	pr_debug("USB %s mode controller at %p using %s, IRQ %d\n",
+			({char *s;
+			 switch (musb->board_mode) {
+			 case MUSB_HOST:		s = "Host"; break;
+			 case MUSB_PERIPHERAL:	s = "Peripheral"; break;
+			 default:		s = "OTG"; break;
+			 }; s; }),
+			ctrl,
+			(is_dma_capable() && musb->dma_controller)
+			? "DMA" : "PIO",
+			musb->nIrq);
+
+#ifndef __UBOOT__
+	return 0;
+#else
+	return status == 0 ? musb : NULL;
+#endif
+
+fail5:
+	musb_exit_debugfs(musb);
+
+fail4:
+#ifndef __UBOOT__
+	if (!is_otg_enabled(musb) && is_host_enabled(musb))
+		usb_remove_hcd(musb_to_hcd(musb));
+	else
+#endif
+		musb_gadget_cleanup(musb);
+
+fail3:
+	pm_runtime_put_sync(musb->controller);
+
+fail2:
+	if (musb->irq_wake)
+		device_init_wakeup(dev, 0);
+	musb_platform_exit(musb);
+
+fail1:
+	dev_err(musb->controller,
+		"musb_init_controller failed with status %d\n", status);
+
+	musb_free(musb);
+
+fail0:
+
+#ifndef __UBOOT__
+	return status;
+#else
+	return status == 0 ? musb : NULL;
+#endif
+
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
+ * bridge to a platform device; this driver then suffices.
+ */
+
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+static u64	*orig_dma_mask;
+#endif
+
+#ifndef __UBOOT__
+static int __devinit musb_probe(struct platform_device *pdev)
+{
+	struct device	*dev = &pdev->dev;
+	int		irq = platform_get_irq_byname(pdev, "mc");
+	int		status;
+	struct resource	*iomem;
+	void __iomem	*base;
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem || irq <= 0)
+		return -ENODEV;
+
+	base = ioremap(iomem->start, resource_size(iomem));
+	if (!base) {
+		dev_err(dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+	/* clobbered by use_dma=n */
+	orig_dma_mask = dev->dma_mask;
+#endif
+	status = musb_init_controller(dev, irq, base);
+	if (status < 0)
+		iounmap(base);
+
+	return status;
+}
+
+static int __devexit musb_remove(struct platform_device *pdev)
+{
+	struct musb	*musb = dev_to_musb(&pdev->dev);
+	void __iomem	*ctrl_base = musb->ctrl_base;
+
+	/* this gets called on rmmod.
+	 *  - Host mode: host may still be active
+	 *  - Peripheral mode: peripheral is deactivated (or never-activated)
+	 *  - OTG mode: both roles are deactivated (or never-activated)
+	 */
+	musb_exit_debugfs(musb);
+	musb_shutdown(pdev);
+
+	musb_free(musb);
+	iounmap(ctrl_base);
+	device_init_wakeup(&pdev->dev, 0);
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+	pdev->dev.dma_mask = orig_dma_mask;
+#endif
+	return 0;
+}
+
+#ifdef	CONFIG_PM
+
+static void musb_save_context(struct musb *musb)
+{
+	int i;
+	void __iomem *musb_base = musb->mregs;
+	void __iomem *epio;
+
+	if (is_host_enabled(musb)) {
+		musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
+		musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+		musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
+	}
+	musb->context.power = musb_readb(musb_base, MUSB_POWER);
+	musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
+	musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
+	musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
+	musb->context.index = musb_readb(musb_base, MUSB_INDEX);
+	musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
+
+	for (i = 0; i < musb->config->num_eps; ++i) {
+		struct musb_hw_ep	*hw_ep;
+
+		hw_ep = &musb->endpoints[i];
+		if (!hw_ep)
+			continue;
+
+		epio = hw_ep->regs;
+		if (!epio)
+			continue;
+
+		musb_writeb(musb_base, MUSB_INDEX, i);
+		musb->context.index_regs[i].txmaxp =
+			musb_readw(epio, MUSB_TXMAXP);
+		musb->context.index_regs[i].txcsr =
+			musb_readw(epio, MUSB_TXCSR);
+		musb->context.index_regs[i].rxmaxp =
+			musb_readw(epio, MUSB_RXMAXP);
+		musb->context.index_regs[i].rxcsr =
+			musb_readw(epio, MUSB_RXCSR);
+
+		if (musb->dyn_fifo) {
+			musb->context.index_regs[i].txfifoadd =
+					musb_read_txfifoadd(musb_base);
+			musb->context.index_regs[i].rxfifoadd =
+					musb_read_rxfifoadd(musb_base);
+			musb->context.index_regs[i].txfifosz =
+					musb_read_txfifosz(musb_base);
+			musb->context.index_regs[i].rxfifosz =
+					musb_read_rxfifosz(musb_base);
+		}
+		if (is_host_enabled(musb)) {
+			musb->context.index_regs[i].txtype =
+				musb_readb(epio, MUSB_TXTYPE);
+			musb->context.index_regs[i].txinterval =
+				musb_readb(epio, MUSB_TXINTERVAL);
+			musb->context.index_regs[i].rxtype =
+				musb_readb(epio, MUSB_RXTYPE);
+			musb->context.index_regs[i].rxinterval =
+				musb_readb(epio, MUSB_RXINTERVAL);
+
+			musb->context.index_regs[i].txfunaddr =
+				musb_read_txfunaddr(musb_base, i);
+			musb->context.index_regs[i].txhubaddr =
+				musb_read_txhubaddr(musb_base, i);
+			musb->context.index_regs[i].txhubport =
+				musb_read_txhubport(musb_base, i);
+
+			musb->context.index_regs[i].rxfunaddr =
+				musb_read_rxfunaddr(musb_base, i);
+			musb->context.index_regs[i].rxhubaddr =
+				musb_read_rxhubaddr(musb_base, i);
+			musb->context.index_regs[i].rxhubport =
+				musb_read_rxhubport(musb_base, i);
+		}
+	}
+}
+
+static void musb_restore_context(struct musb *musb)
+{
+	int i;
+	void __iomem *musb_base = musb->mregs;
+	void __iomem *ep_target_regs;
+	void __iomem *epio;
+
+	if (is_host_enabled(musb)) {
+		musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
+		musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
+		musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
+	}
+	musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+	musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
+	musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
+	musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
+	musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
+
+	for (i = 0; i < musb->config->num_eps; ++i) {
+		struct musb_hw_ep	*hw_ep;
+
+		hw_ep = &musb->endpoints[i];
+		if (!hw_ep)
+			continue;
+
+		epio = hw_ep->regs;
+		if (!epio)
+			continue;
+
+		musb_writeb(musb_base, MUSB_INDEX, i);
+		musb_writew(epio, MUSB_TXMAXP,
+			musb->context.index_regs[i].txmaxp);
+		musb_writew(epio, MUSB_TXCSR,
+			musb->context.index_regs[i].txcsr);
+		musb_writew(epio, MUSB_RXMAXP,
+			musb->context.index_regs[i].rxmaxp);
+		musb_writew(epio, MUSB_RXCSR,
+			musb->context.index_regs[i].rxcsr);
+
+		if (musb->dyn_fifo) {
+			musb_write_txfifosz(musb_base,
+				musb->context.index_regs[i].txfifosz);
+			musb_write_rxfifosz(musb_base,
+				musb->context.index_regs[i].rxfifosz);
+			musb_write_txfifoadd(musb_base,
+				musb->context.index_regs[i].txfifoadd);
+			musb_write_rxfifoadd(musb_base,
+				musb->context.index_regs[i].rxfifoadd);
+		}
+
+		if (is_host_enabled(musb)) {
+			musb_writeb(epio, MUSB_TXTYPE,
+				musb->context.index_regs[i].txtype);
+			musb_writeb(epio, MUSB_TXINTERVAL,
+				musb->context.index_regs[i].txinterval);
+			musb_writeb(epio, MUSB_RXTYPE,
+				musb->context.index_regs[i].rxtype);
+			musb_writeb(epio, MUSB_RXINTERVAL,
+
+			musb->context.index_regs[i].rxinterval);
+			musb_write_txfunaddr(musb_base, i,
+				musb->context.index_regs[i].txfunaddr);
+			musb_write_txhubaddr(musb_base, i,
+				musb->context.index_regs[i].txhubaddr);
+			musb_write_txhubport(musb_base, i,
+				musb->context.index_regs[i].txhubport);
+
+			ep_target_regs =
+				musb_read_target_reg_base(i, musb_base);
+
+			musb_write_rxfunaddr(ep_target_regs,
+				musb->context.index_regs[i].rxfunaddr);
+			musb_write_rxhubaddr(ep_target_regs,
+				musb->context.index_regs[i].rxhubaddr);
+			musb_write_rxhubport(ep_target_regs,
+				musb->context.index_regs[i].rxhubport);
+		}
+	}
+	musb_writeb(musb_base, MUSB_INDEX, musb->context.index);
+}
+
+static int musb_suspend(struct device *dev)
+{
+	struct musb	*musb = dev_to_musb(dev);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	if (is_peripheral_active(musb)) {
+		/* FIXME force disconnect unless we know USB will wake
+		 * the system up quickly enough to respond ...
+		 */
+	} else if (is_host_active(musb)) {
+		/* we know all the children are suspended; sometimes
+		 * they will even be wakeup-enabled.
+		 */
+	}
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return 0;
+}
+
+static int musb_resume_noirq(struct device *dev)
+{
+	/* for static cmos like DaVinci, register values were preserved
+	 * unless for some reason the whole soc powered down or the USB
+	 * module got reset through the PSC (vs just being disabled).
+	 */
+	return 0;
+}
+
+static int musb_runtime_suspend(struct device *dev)
+{
+	struct musb	*musb = dev_to_musb(dev);
+
+	musb_save_context(musb);
+
+	return 0;
+}
+
+static int musb_runtime_resume(struct device *dev)
+{
+	struct musb	*musb = dev_to_musb(dev);
+	static int	first = 1;
+
+	/*
+	 * When pm_runtime_get_sync called for the first time in driver
+	 * init,  some of the structure is still not initialized which is
+	 * used in restore function. But clock needs to be
+	 * enabled before any register access, so
+	 * pm_runtime_get_sync has to be called.
+	 * Also context restore without save does not make
+	 * any sense
+	 */
+	if (!first)
+		musb_restore_context(musb);
+	first = 0;
+
+	return 0;
+}
+
+static const struct dev_pm_ops musb_dev_pm_ops = {
+	.suspend	= musb_suspend,
+	.resume_noirq	= musb_resume_noirq,
+	.runtime_suspend = musb_runtime_suspend,
+	.runtime_resume = musb_runtime_resume,
+};
+
+#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops)
+#else
+#define	MUSB_DEV_PM_OPS	NULL
+#endif
+
+static struct platform_driver musb_driver = {
+	.driver = {
+		.name		= (char *)musb_driver_name,
+		.bus		= &platform_bus_type,
+		.owner		= THIS_MODULE,
+		.pm		= MUSB_DEV_PM_OPS,
+	},
+	.probe		= musb_probe,
+	.remove		= __devexit_p(musb_remove),
+	.shutdown	= musb_shutdown,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init musb_init(void)
+{
+	if (usb_disabled())
+		return 0;
+
+	pr_info("%s: version " MUSB_VERSION ", "
+		"?dma?"
+		", "
+		"otg (peripheral+host)",
+		musb_driver_name);
+	return platform_driver_register(&musb_driver);
+}
+module_init(musb_init);
+
+static void __exit musb_cleanup(void)
+{
+	platform_driver_unregister(&musb_driver);
+}
+module_exit(musb_cleanup);
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_core.h b/roms/u-boot/drivers/usb/musb-new/musb_core.h
new file mode 100644
index 000000000..821d0e06f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_core.h
@@ -0,0 +1,589 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+#ifndef __MUSB_CORE_H__
+#define __MUSB_CORE_H__
+
+#ifndef __UBOOT__
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#else
+#include <linux/errno.h>
+#endif
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/musb.h>
+
+struct musb;
+struct musb_hw_ep;
+struct musb_ep;
+
+/* Helper defines for struct musb->hwvers */
+#define MUSB_HWVERS_MAJOR(x)	((x >> 10) & 0x1f)
+#define MUSB_HWVERS_MINOR(x)	(x & 0x3ff)
+#define MUSB_HWVERS_RC		0x8000
+#define MUSB_HWVERS_1300	0x52C
+#define MUSB_HWVERS_1400	0x590
+#define MUSB_HWVERS_1800	0x720
+#define MUSB_HWVERS_1900	0x784
+#define MUSB_HWVERS_2000	0x800
+
+#include "musb_debug.h"
+#include "musb_dma.h"
+
+#include "musb_io.h"
+#include "musb_regs.h"
+
+#include "musb_gadget.h"
+#ifndef __UBOOT__
+#include <linux/usb/hcd.h>
+#endif
+#include "musb_host.h"
+
+#define	is_peripheral_enabled(musb)	((musb)->board_mode != MUSB_HOST)
+#define	is_host_enabled(musb)		((musb)->board_mode != MUSB_PERIPHERAL)
+#define	is_otg_enabled(musb)		((musb)->board_mode == MUSB_OTG)
+
+/* NOTE:  otg and peripheral-only state machines start at B_IDLE.
+ * OTG or host-only go to A_IDLE when ID is sensed.
+ */
+#define is_peripheral_active(m)		(!(m)->is_host)
+#define is_host_active(m)		((m)->is_host)
+
+#ifdef CONFIG_PROC_FS
+#include <linux/fs.h>
+#define MUSB_CONFIG_PROC_FS
+#endif
+
+/****************************** PERIPHERAL ROLE *****************************/
+
+#ifndef __UBOOT__
+#define	is_peripheral_capable()	(1)
+#else
+#ifdef CONFIG_USB_MUSB_GADGET
+#define	is_peripheral_capable()	(1)
+#else
+#define	is_peripheral_capable()	(0)
+#endif
+#endif
+
+extern irqreturn_t musb_g_ep0_irq(struct musb *);
+extern void musb_g_tx(struct musb *, u8);
+extern void musb_g_rx(struct musb *, u8);
+extern void musb_g_reset(struct musb *);
+extern void musb_g_suspend(struct musb *);
+extern void musb_g_resume(struct musb *);
+extern void musb_g_wakeup(struct musb *);
+extern void musb_g_disconnect(struct musb *);
+
+/****************************** HOST ROLE ***********************************/
+
+#ifndef __UBOOT__
+#define	is_host_capable()	(1)
+#else
+#ifdef CONFIG_USB_MUSB_HOST
+#define	is_host_capable()	(1)
+#else
+#define	is_host_capable()	(0)
+#endif
+#endif
+
+extern irqreturn_t musb_h_ep0_irq(struct musb *);
+extern void musb_host_tx(struct musb *, u8);
+extern void musb_host_rx(struct musb *, u8);
+
+/****************************** CONSTANTS ********************************/
+
+#ifndef MUSB_C_NUM_EPS
+#define MUSB_C_NUM_EPS ((u8)16)
+#endif
+
+#ifndef MUSB_MAX_END0_PACKET
+#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE)
+#endif
+
+/* host side ep0 states */
+enum musb_h_ep0_state {
+	MUSB_EP0_IDLE,
+	MUSB_EP0_START,			/* expect ack of setup */
+	MUSB_EP0_IN,			/* expect IN DATA */
+	MUSB_EP0_OUT,			/* expect ack of OUT DATA */
+	MUSB_EP0_STATUS,		/* expect ack of STATUS */
+} __attribute__ ((packed));
+
+/* peripheral side ep0 states */
+enum musb_g_ep0_state {
+	MUSB_EP0_STAGE_IDLE,		/* idle, waiting for SETUP */
+	MUSB_EP0_STAGE_SETUP,		/* received SETUP */
+	MUSB_EP0_STAGE_TX,		/* IN data */
+	MUSB_EP0_STAGE_RX,		/* OUT data */
+	MUSB_EP0_STAGE_STATUSIN,	/* (after OUT data) */
+	MUSB_EP0_STAGE_STATUSOUT,	/* (after IN data) */
+	MUSB_EP0_STAGE_ACKWAIT,		/* after zlp, before statusin */
+} __attribute__ ((packed));
+
+/*
+ * OTG protocol constants.  See USB OTG 1.3 spec,
+ * sections 5.5 "Device Timings" and 6.6.5 "Timers".
+ */
+#define OTG_TIME_A_WAIT_VRISE	100		/* msec (max) */
+#define OTG_TIME_A_WAIT_BCON	1100		/* min 1 second */
+#define OTG_TIME_A_AIDL_BDIS	200		/* min 200 msec */
+#define OTG_TIME_B_ASE0_BRST	100		/* min 3.125 ms */
+
+
+/*************************** REGISTER ACCESS ********************************/
+
+/* Endpoint registers (other than dynfifo setup) can be accessed either
+ * directly with the "flat" model, or after setting up an index register.
+ */
+
+#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \
+		|| defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_ARCH_OMAP4)
+/* REVISIT indexed access seemed to
+ * misbehave (on DaVinci) for at least peripheral IN ...
+ */
+#define	MUSB_FLAT_REG
+#endif
+
+/* TUSB mapping: "flat" plus ep0 special cases */
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+#define musb_ep_select(_mbase, _epnum) \
+	musb_writeb((_mbase), MUSB_INDEX, (_epnum))
+#define	MUSB_EP_OFFSET			MUSB_TUSB_OFFSET
+
+/* "flat" mapping: each endpoint has its own i/o address */
+#elif	defined(MUSB_FLAT_REG)
+#define musb_ep_select(_mbase, _epnum)	(((void)(_mbase)), ((void)(_epnum)))
+#define	MUSB_EP_OFFSET			MUSB_FLAT_OFFSET
+
+/* "indexed" mapping: INDEX register controls register bank select */
+#else
+#define musb_ep_select(_mbase, _epnum) \
+	musb_writeb((_mbase), MUSB_INDEX, (_epnum))
+#define	MUSB_EP_OFFSET			MUSB_INDEXED_OFFSET
+#endif
+
+/****************************** FUNCTIONS ********************************/
+
+#define MUSB_HST_MODE(_musb)\
+	{ (_musb)->is_host = true; }
+#define MUSB_DEV_MODE(_musb) \
+	{ (_musb)->is_host = false; }
+
+#define test_devctl_hst_mode(_x) \
+	(musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM)
+
+#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral")
+
+/******************************** TYPES *************************************/
+
+/**
+ * struct musb_platform_ops - Operations passed to musb_core by HW glue layer
+ * @init:	turns on clocks, sets up platform-specific registers, etc
+ * @exit:	undoes @init
+ * @set_mode:	forcefully changes operating mode
+ * @try_ilde:	tries to idle the IP
+ * @vbus_status: returns vbus status if possible
+ * @set_vbus:	forces vbus status
+ * @adjust_channel_params: pre check for standard dma channel_program func
+ * @pre_root_reset_end: called before the root usb port reset flag gets cleared
+ * @post_root_reset_end: called after the root usb port reset flag gets cleared
+ */
+struct musb_platform_ops {
+	int	(*init)(struct musb *musb);
+	int	(*exit)(struct musb *musb);
+
+#ifndef __UBOOT__
+	void	(*enable)(struct musb *musb);
+#else
+	int	(*enable)(struct musb *musb);
+#endif
+	void	(*disable)(struct musb *musb);
+
+	int	(*set_mode)(struct musb *musb, u8 mode);
+	void	(*try_idle)(struct musb *musb, unsigned long timeout);
+
+	int	(*vbus_status)(struct musb *musb);
+	void	(*set_vbus)(struct musb *musb, int on);
+
+	int	(*adjust_channel_params)(struct dma_channel *channel,
+				u16 packet_sz, u8 *mode,
+				dma_addr_t *dma_addr, u32 *len);
+	void	(*pre_root_reset_end)(struct musb *musb);
+	void	(*post_root_reset_end)(struct musb *musb);
+};
+
+/*
+ * struct musb_hw_ep - endpoint hardware (bidirectional)
+ *
+ * Ordered slightly for better cacheline locality.
+ */
+struct musb_hw_ep {
+	struct musb		*musb;
+	void __iomem		*fifo;
+	void __iomem		*regs;
+
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+	void __iomem		*conf;
+#endif
+
+	/* index in musb->endpoints[]  */
+	u8			epnum;
+
+	/* hardware configuration, possibly dynamic */
+	bool			is_shared_fifo;
+	bool			tx_double_buffered;
+	bool			rx_double_buffered;
+	u16			max_packet_sz_tx;
+	u16			max_packet_sz_rx;
+
+	struct dma_channel	*tx_channel;
+	struct dma_channel	*rx_channel;
+
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+	/* TUSB has "asynchronous" and "synchronous" dma modes */
+	dma_addr_t		fifo_async;
+	dma_addr_t		fifo_sync;
+	void __iomem		*fifo_sync_va;
+#endif
+
+	void __iomem		*target_regs;
+
+	/* currently scheduled peripheral endpoint */
+	struct musb_qh		*in_qh;
+	struct musb_qh		*out_qh;
+
+	u8			rx_reinit;
+	u8			tx_reinit;
+
+	/* peripheral side */
+	struct musb_ep		ep_in;			/* TX */
+	struct musb_ep		ep_out;			/* RX */
+};
+
+static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep)
+{
+	return next_request(&hw_ep->ep_in);
+}
+
+static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep)
+{
+	return next_request(&hw_ep->ep_out);
+}
+
+struct musb_csr_regs {
+	/* FIFO registers */
+	u16 txmaxp, txcsr, rxmaxp, rxcsr;
+	u16 rxfifoadd, txfifoadd;
+	u8 txtype, txinterval, rxtype, rxinterval;
+	u8 rxfifosz, txfifosz;
+	u8 txfunaddr, txhubaddr, txhubport;
+	u8 rxfunaddr, rxhubaddr, rxhubport;
+};
+
+struct musb_context_registers {
+
+	u8 power;
+	u16 intrtxe, intrrxe;
+	u8 intrusbe;
+	u16 frame;
+	u8 index, testmode;
+
+	u8 devctl, busctl, misc;
+	u32 otg_interfsel;
+
+	struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
+};
+
+/*
+ * struct musb - Driver instance data.
+ */
+struct musb {
+	/* device lock */
+	spinlock_t		lock;
+
+	const struct musb_platform_ops *ops;
+	struct musb_context_registers context;
+
+	irqreturn_t		(*isr)(int, void *);
+	struct work_struct	irq_work;
+	u16			hwvers;
+
+/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
+#define MUSB_PORT_STAT_RESUME	(1 << 31)
+
+	u32			port1_status;
+
+	unsigned long		rh_timer;
+
+	enum musb_h_ep0_state	ep0_stage;
+
+	/* bulk traffic normally dedicates endpoint hardware, and each
+	 * direction has its own ring of host side endpoints.
+	 * we try to progress the transfer at the head of each endpoint's
+	 * queue until it completes or NAKs too much; then we try the next
+	 * endpoint.
+	 */
+	struct musb_hw_ep	*bulk_ep;
+
+	struct list_head	control;	/* of musb_qh */
+	struct list_head	in_bulk;	/* of musb_qh */
+	struct list_head	out_bulk;	/* of musb_qh */
+
+	struct timer_list	otg_timer;
+	struct notifier_block	nb;
+
+	struct dma_controller	*dma_controller;
+
+	struct device		*controller;
+	void __iomem		*ctrl_base;
+	void __iomem		*mregs;
+
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+	dma_addr_t		async;
+	dma_addr_t		sync;
+	void __iomem		*sync_va;
+#endif
+
+	/* passed down from chip/board specific irq handlers */
+	u8			int_usb;
+	u16			int_rx;
+	u16			int_tx;
+
+	struct usb_phy		*xceiv;
+
+	int nIrq;
+	unsigned		irq_wake:1;
+
+	struct musb_hw_ep	 endpoints[MUSB_C_NUM_EPS];
+#define control_ep		endpoints
+
+#define VBUSERR_RETRY_COUNT	3
+	u16			vbuserr_retry;
+	u16 epmask;
+	u8 nr_endpoints;
+
+	u8 board_mode;		/* enum musb_mode */
+	int			(*board_set_power)(int state);
+
+	u8			min_power;	/* vbus for periph, in mA/2 */
+
+	bool			is_host;
+
+	int			a_wait_bcon;	/* VBUS timeout in msecs */
+	unsigned long		idle_timeout;	/* Next timeout in jiffies */
+
+	/* active means connected and not suspended */
+	unsigned		is_active:1;
+
+	unsigned is_multipoint:1;
+	unsigned ignore_disconnect:1;	/* during bus resets */
+
+	unsigned		hb_iso_rx:1;	/* high bandwidth iso rx? */
+	unsigned		hb_iso_tx:1;	/* high bandwidth iso tx? */
+	unsigned		dyn_fifo:1;	/* dynamic FIFO supported? */
+
+	unsigned		bulk_split:1;
+#define	can_bulk_split(musb,type) \
+	(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
+
+	unsigned		bulk_combine:1;
+#define	can_bulk_combine(musb,type) \
+	(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
+
+	/* is_suspended means USB B_PERIPHERAL suspend */
+	unsigned		is_suspended:1;
+
+	/* may_wakeup means remote wakeup is enabled */
+	unsigned		may_wakeup:1;
+
+	/* is_self_powered is reported in device status and the
+	 * config descriptor.  is_bus_powered means B_PERIPHERAL
+	 * draws some VBUS current; both can be true.
+	 */
+	unsigned		is_self_powered:1;
+	unsigned		is_bus_powered:1;
+
+	unsigned		set_address:1;
+	unsigned		test_mode:1;
+	unsigned		softconnect:1;
+
+	u8			address;
+	u8			test_mode_nr;
+	u16			ackpend;		/* ep0 */
+	enum musb_g_ep0_state	ep0_state;
+	struct usb_gadget	g;			/* the gadget */
+	struct usb_gadget_driver *gadget_driver;	/* its driver */
+
+	/*
+	 * FIXME: Remove this flag.
+	 *
+	 * This is only added to allow Blackfin to work
+	 * with current driver. For some unknown reason
+	 * Blackfin doesn't work with double buffering
+	 * and that's enabled by default.
+	 *
+	 * We added this flag to forcefully disable double
+	 * buffering until we get it working.
+	 */
+	unsigned                double_buffer_not_ok:1;
+
+	struct musb_hdrc_config	*config;
+
+#ifdef MUSB_CONFIG_PROC_FS
+	struct proc_dir_entry *proc_entry;
+#endif
+};
+
+static inline struct musb *gadget_to_musb(struct usb_gadget *g)
+{
+	return container_of(g, struct musb, g);
+}
+
+static inline int musb_read_fifosize(struct musb *musb,
+		struct musb_hw_ep *hw_ep, u8 epnum)
+{
+	void *mbase = musb->mregs;
+	u8 reg = 0;
+
+	/* read from core using indexed model */
+	reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE));
+	/* 0's returned when no more endpoints */
+	if (!reg)
+		return -ENODEV;
+
+	musb->nr_endpoints++;
+	musb->epmask |= (1 << epnum);
+
+	hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f);
+
+	/* shared TX/RX FIFO? */
+	if ((reg & 0xf0) == 0xf0) {
+		hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
+		hw_ep->is_shared_fifo = true;
+		return 0;
+	} else {
+		hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
+		hw_ep->is_shared_fifo = false;
+	}
+
+	return 0;
+}
+
+static inline void musb_configure_ep0(struct musb *musb)
+{
+	musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
+	musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
+	musb->endpoints[0].is_shared_fifo = true;
+}
+
+/***************************** Glue it together *****************************/
+
+extern const char musb_driver_name[];
+
+#ifndef __UBOOT__
+extern void musb_start(struct musb *musb);
+#else
+extern int musb_start(struct musb *musb);
+#endif
+extern void musb_stop(struct musb *musb);
+
+extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
+extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
+
+extern void musb_load_testpacket(struct musb *);
+
+extern irqreturn_t musb_interrupt(struct musb *);
+
+extern void musb_hnp_stop(struct musb *musb);
+
+static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
+{
+	if (musb->ops->set_vbus)
+		musb->ops->set_vbus(musb, is_on);
+}
+
+#ifndef __UBOOT__
+static inline void musb_platform_enable(struct musb *musb)
+{
+	if (musb->ops->enable)
+		musb->ops->enable(musb);
+}
+#else
+static inline int musb_platform_enable(struct musb *musb)
+{
+	if (!musb->ops->enable)
+		return 0;
+
+	return musb->ops->enable(musb);
+}
+#endif
+
+static inline void musb_platform_disable(struct musb *musb)
+{
+	if (musb->ops->disable)
+		musb->ops->disable(musb);
+}
+
+static inline int musb_platform_set_mode(struct musb *musb, u8 mode)
+{
+	if (!musb->ops->set_mode)
+		return 0;
+
+	return musb->ops->set_mode(musb, mode);
+}
+
+static inline void musb_platform_try_idle(struct musb *musb,
+		unsigned long timeout)
+{
+	if (musb->ops->try_idle)
+		musb->ops->try_idle(musb, timeout);
+}
+
+static inline int musb_platform_get_vbus_status(struct musb *musb)
+{
+	if (!musb->ops->vbus_status)
+		return 0;
+
+	return musb->ops->vbus_status(musb);
+}
+
+static inline int musb_platform_init(struct musb *musb)
+{
+	if (!musb->ops->init)
+		return -EINVAL;
+
+	return musb->ops->init(musb);
+}
+
+static inline int musb_platform_exit(struct musb *musb)
+{
+	if (!musb->ops->exit)
+		return -EINVAL;
+
+	return musb->ops->exit(musb);
+}
+
+#ifdef __UBOOT__
+struct musb *
+musb_init_controller(struct musb_hdrc_platform_data *plat, struct device *dev,
+			     void *ctrl);
+#endif
+#endif	/* __MUSB_CORE_H__ */
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_debug.h b/roms/u-boot/drivers/usb/musb-new/musb_debug.h
new file mode 100644
index 000000000..c468bda9f
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_debug.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver debug defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+#ifndef __MUSB_LINUX_DEBUG_H__
+#define __MUSB_LINUX_DEBUG_H__
+
+#define yprintk(facility, format, args...) \
+	do { printk(facility "%s %d: " format , \
+	__func__, __LINE__ , ## args); } while (0)
+#define WARNING(fmt, args...) yprintk(KERN_WARNING, fmt, ## args)
+#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)
+#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
+
+#ifdef CONFIG_DEBUG_FS
+int musb_init_debugfs(struct musb *musb);
+void musb_exit_debugfs(struct musb *musb);
+#else
+static inline int musb_init_debugfs(struct musb *musb)
+{
+	return 0;
+}
+static inline void musb_exit_debugfs(struct musb *musb)
+{
+}
+#endif
+
+#endif				/*  __MUSB_LINUX_DEBUG_H__ */
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_dma.h b/roms/u-boot/drivers/usb/musb-new/musb_dma.h
new file mode 100644
index 000000000..5f99356ca
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_dma.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver DMA controller abstraction
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+#ifndef __MUSB_DMA_H__
+#define __MUSB_DMA_H__
+
+struct musb_hw_ep;
+
+/*
+ * DMA Controller Abstraction
+ *
+ * DMA Controllers are abstracted to allow use of a variety of different
+ * implementations of DMA, as allowed by the Inventra USB cores.  On the
+ * host side, usbcore sets up the DMA mappings and flushes caches; on the
+ * peripheral side, the gadget controller driver does.  Responsibilities
+ * of a DMA controller driver include:
+ *
+ *  - Handling the details of moving multiple USB packets
+ *    in cooperation with the Inventra USB core, including especially
+ *    the correct RX side treatment of short packets and buffer-full
+ *    states (both of which terminate transfers).
+ *
+ *  - Knowing the correlation between dma channels and the
+ *    Inventra core's local endpoint resources and data direction.
+ *
+ *  - Maintaining a list of allocated/available channels.
+ *
+ *  - Updating channel status on interrupts,
+ *    whether shared with the Inventra core or separate.
+ */
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+#define	is_dma_capable()	(1)
+#else
+#define	is_dma_capable()	(0)
+#endif
+
+#ifdef CONFIG_USB_TI_CPPI_DMA
+#define	is_cppi_enabled()	1
+#else
+#define	is_cppi_enabled()	0
+#endif
+
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+#define tusb_dma_omap()			1
+#else
+#define tusb_dma_omap()			0
+#endif
+
+/*
+ * DMA channel status ... updated by the dma controller driver whenever that
+ * status changes, and protected by the overall controller spinlock.
+ */
+enum dma_channel_status {
+	/* unallocated */
+	MUSB_DMA_STATUS_UNKNOWN,
+	/* allocated ... but not busy, no errors */
+	MUSB_DMA_STATUS_FREE,
+	/* busy ... transactions are active */
+	MUSB_DMA_STATUS_BUSY,
+	/* transaction(s) aborted due to ... dma or memory bus error */
+	MUSB_DMA_STATUS_BUS_ABORT,
+	/* transaction(s) aborted due to ... core error or USB fault */
+	MUSB_DMA_STATUS_CORE_ABORT
+};
+
+struct dma_controller;
+
+/**
+ * struct dma_channel - A DMA channel.
+ * @private_data: channel-private data
+ * @max_len: the maximum number of bytes the channel can move in one
+ *	transaction (typically representing many USB maximum-sized packets)
+ * @actual_len: how many bytes have been transferred
+ * @status: current channel status (updated e.g. on interrupt)
+ * @desired_mode: true if mode 1 is desired; false if mode 0 is desired
+ *
+ * channels are associated with an endpoint for the duration of at least
+ * one usb transfer.
+ */
+struct dma_channel {
+	void			*private_data;
+	/* FIXME not void* private_data, but a dma_controller * */
+	size_t			max_len;
+	size_t			actual_len;
+	enum dma_channel_status	status;
+	bool			desired_mode;
+};
+
+/*
+ * dma_channel_status - return status of dma channel
+ * @c: the channel
+ *
+ * Returns the software's view of the channel status.  If that status is BUSY
+ * then it's possible that the hardware has completed (or aborted) a transfer,
+ * so the driver needs to update that status.
+ */
+static inline enum dma_channel_status
+dma_channel_status(struct dma_channel *c)
+{
+	return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN;
+}
+
+/**
+ * struct dma_controller - A DMA Controller.
+ * @start: call this to start a DMA controller;
+ *	return 0 on success, else negative errno
+ * @stop: call this to stop a DMA controller
+ *	return 0 on success, else negative errno
+ * @channel_alloc: call this to allocate a DMA channel
+ * @channel_release: call this to release a DMA channel
+ * @channel_abort: call this to abort a pending DMA transaction,
+ *	returning it to FREE (but allocated) state
+ *
+ * Controllers manage dma channels.
+ */
+struct dma_controller {
+	int			(*start)(struct dma_controller *);
+	int			(*stop)(struct dma_controller *);
+	struct dma_channel	*(*channel_alloc)(struct dma_controller *,
+					struct musb_hw_ep *, u8 is_tx);
+	void			(*channel_release)(struct dma_channel *);
+	int			(*channel_program)(struct dma_channel *channel,
+							u16 maxpacket, u8 mode,
+							dma_addr_t dma_addr,
+							u32 length);
+	int			(*channel_abort)(struct dma_channel *);
+	int			(*is_compatible)(struct dma_channel *channel,
+							u16 maxpacket,
+							void *buf, u32 length);
+};
+
+/* called after channel_program(), may indicate a fault */
+extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
+
+
+extern struct dma_controller *__init
+dma_controller_create(struct musb *, void __iomem *);
+
+extern void dma_controller_destroy(struct dma_controller *);
+
+#endif	/* __MUSB_DMA_H__ */
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_dsps.c b/roms/u-boot/drivers/usb/musb-new/musb_dsps.c
new file mode 100644
index 000000000..d55a920ae
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_dsps.c
@@ -0,0 +1,765 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments DSPS platforms "glue layer"
+ *
+ * Copyright (C) 2012, by Texas Instruments
+ *
+ * Based on the am35x "glue layer" code.
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * musb_dsps.c will be a common file for all the TI DSPS platforms
+ * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
+ * For now only ti81x is using this and in future davinci.c, am35x.c
+ * da8xx.c would be merged to this file after testing.
+ */
+
+#ifndef __UBOOT__
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#include <plat/usb.h>
+#else
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <asm/omap_musb.h>
+#include "linux-compat.h"
+#endif
+
+#include "musb_core.h"
+
+/**
+ * avoid using musb_readx()/musb_writex() as glue layer should not be
+ * dependent on musb core layer symbols.
+ */
+static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
+	{ return __raw_readb(addr + offset); }
+
+static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
+	{ return __raw_readl(addr + offset); }
+
+static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
+	{ __raw_writeb(data, addr + offset); }
+
+static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
+	{ __raw_writel(data, addr + offset); }
+
+/**
+ * DSPS musb wrapper register offset.
+ * FIXME: This should be expanded to have all the wrapper registers from TI DSPS
+ * musb ips.
+ */
+struct dsps_musb_wrapper {
+	u16	revision;
+	u16	control;
+	u16	status;
+	u16	eoi;
+	u16	epintr_set;
+	u16	epintr_clear;
+	u16	epintr_status;
+	u16	coreintr_set;
+	u16	coreintr_clear;
+	u16	coreintr_status;
+	u16	phy_utmi;
+	u16	mode;
+
+	/* bit positions for control */
+	unsigned	reset:5;
+
+	/* bit positions for interrupt */
+	unsigned	usb_shift:5;
+	u32		usb_mask;
+	u32		usb_bitmap;
+	unsigned	drvvbus:5;
+
+	unsigned	txep_shift:5;
+	u32		txep_mask;
+	u32		txep_bitmap;
+
+	unsigned	rxep_shift:5;
+	u32		rxep_mask;
+	u32		rxep_bitmap;
+
+	/* bit positions for phy_utmi */
+	unsigned	otg_disable:5;
+
+	/* bit positions for mode */
+	unsigned	iddig:5;
+	/* miscellaneous stuff */
+	u32		musb_core_offset;
+	u8		poll_seconds;
+};
+
+static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
+	.revision		= 0x00,
+	.control		= 0x14,
+	.status			= 0x18,
+	.eoi			= 0x24,
+	.epintr_set		= 0x38,
+	.epintr_clear		= 0x40,
+	.epintr_status		= 0x30,
+	.coreintr_set		= 0x3c,
+	.coreintr_clear		= 0x44,
+	.coreintr_status	= 0x34,
+	.phy_utmi		= 0xe0,
+	.mode			= 0xe8,
+	.reset			= 0,
+	.otg_disable		= 21,
+	.iddig			= 8,
+	.usb_shift		= 0,
+	.usb_mask		= 0x1ff,
+	.usb_bitmap		= (0x1ff << 0),
+	.drvvbus		= 8,
+	.txep_shift		= 0,
+	.txep_mask		= 0xffff,
+	.txep_bitmap		= (0xffff << 0),
+	.rxep_shift		= 16,
+	.rxep_mask		= 0xfffe,
+	.rxep_bitmap		= (0xfffe << 16),
+	.musb_core_offset	= 0x400,
+	.poll_seconds		= 2,
+};
+
+/**
+ * DSPS glue structure.
+ */
+struct dsps_glue {
+	struct device *dev;
+	struct platform_device *musb;	/* child musb pdev */
+	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
+	struct timer_list timer;	/* otg_workaround timer */
+};
+
+/**
+ * dsps_musb_enable - enable interrupts
+ */
+#ifndef __UBOOT__
+static void dsps_musb_enable(struct musb *musb)
+#else
+static int dsps_musb_enable(struct musb *musb)
+#endif
+{
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+#else
+	const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
+#endif
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 epmask, coremask;
+
+	/* Workaround: setup IRQs through both register sets. */
+	epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
+	       ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
+	coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
+
+	dsps_writel(reg_base, wrp->epintr_set, epmask);
+	dsps_writel(reg_base, wrp->coreintr_set, coremask);
+	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
+#ifndef __UBOOT__
+	if (is_otg_enabled(musb))
+		dsps_writel(reg_base, wrp->coreintr_set,
+			    (1 << wrp->drvvbus) << wrp->usb_shift);
+#else
+	return 0;
+#endif
+}
+
+/**
+ * dsps_musb_disable - disable HDRC and flush interrupts
+ */
+static void dsps_musb_disable(struct musb *musb)
+{
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	void __iomem *reg_base = musb->ctrl_base;
+
+	dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
+	dsps_writel(reg_base, wrp->epintr_clear,
+			 wrp->txep_bitmap | wrp->rxep_bitmap);
+	dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
+	dsps_writel(reg_base, wrp->eoi, 0);
+#endif
+}
+
+#ifndef __UBOOT__
+static void otg_timer(unsigned long _musb)
+{
+	struct musb *musb = (void *)_musb;
+	void __iomem *mregs = musb->mregs;
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	u8 devctl;
+	unsigned long flags;
+
+	/*
+	 * We poll because DSPS IP's won't expose several OTG-critical
+	 * status change events (from the transceiver) otherwise.
+	 */
+	devctl = dsps_readb(mregs, MUSB_DEVCTL);
+	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
+				otg_state_string(musb->xceiv->state));
+
+	spin_lock_irqsave(&musb->lock, flags);
+	switch (musb->xceiv->state) {
+	case OTG_STATE_A_WAIT_BCON:
+		devctl &= ~MUSB_DEVCTL_SESSION;
+		dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+		devctl = dsps_readb(musb->mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE) {
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+			MUSB_DEV_MODE(musb);
+		} else {
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+			MUSB_HST_MODE(musb);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+		dsps_writel(musb->ctrl_base, wrp->coreintr_set,
+			    MUSB_INTR_VBUSERROR << wrp->usb_shift);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!is_peripheral_enabled(musb))
+			break;
+
+		devctl = dsps_readb(mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE)
+			mod_timer(&glue->timer,
+					jiffies + wrp->poll_seconds * HZ);
+		else
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
+{
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	static unsigned long last_timer;
+
+	if (!is_otg_enabled(musb))
+		return;
+
+	if (timeout == 0)
+		timeout = jiffies + msecs_to_jiffies(3);
+
+	/* Never idle if active, or when VBUS timeout is not set as host */
+	if (musb->is_active || (musb->a_wait_bcon == 0 &&
+				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+		dev_dbg(musb->controller, "%s active, deleting timer\n",
+				otg_state_string(musb->xceiv->state));
+		del_timer(&glue->timer);
+		last_timer = jiffies;
+		return;
+	}
+
+	if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
+		dev_dbg(musb->controller,
+			"Longer idle timer already pending, ignoring...\n");
+		return;
+	}
+	last_timer = timeout;
+
+	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
+		otg_state_string(musb->xceiv->state),
+			jiffies_to_msecs(timeout - jiffies));
+	mod_timer(&glue->timer, timeout);
+}
+#endif
+
+static irqreturn_t dsps_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	void __iomem *reg_base = musb->ctrl_base;
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+#else
+	const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
+#endif
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+	u32 epintr, usbintr;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	/* Get endpoint interrupts */
+	epintr = dsps_readl(reg_base, wrp->epintr_status);
+	musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
+	musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
+
+	if (epintr)
+		dsps_writel(reg_base, wrp->epintr_status, epintr);
+
+	/* Get usb core interrupts */
+	usbintr = dsps_readl(reg_base, wrp->coreintr_status);
+	if (!usbintr && !epintr)
+		goto eoi;
+
+	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
+	if (usbintr)
+		dsps_writel(reg_base, wrp->coreintr_status, usbintr);
+
+	dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
+			usbintr, epintr);
+#ifndef __UBOOT__
+	/*
+	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+	 * DSPS IP's missing ID change IRQ.  We need an ID change IRQ to
+	 * switch appropriately between halves of the OTG state machine.
+	 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+	 */
+	if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
+		pr_info("CAUTION: musb: Babble Interrupt Occurred\n");
+
+	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
+		int drvvbus = dsps_readl(reg_base, wrp->status);
+		void __iomem *mregs = musb->mregs;
+		u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
+		int err;
+
+		err = is_host_enabled(musb) && (musb->int_usb &
+						MUSB_INTR_VBUSERROR);
+		if (err) {
+			/*
+			 * The Mentor core doesn't debounce VBUS as needed
+			 * to cope with device connect current spikes. This
+			 * means it's not uncommon for bus-powered devices
+			 * to get VBUS errors during enumeration.
+			 *
+			 * This is a workaround, but newer RTL from Mentor
+			 * seems to allow a better one: "re"-starting sessions
+			 * without waiting for VBUS to stop registering in
+			 * devctl.
+			 */
+			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+			mod_timer(&glue->timer,
+					jiffies + wrp->poll_seconds * HZ);
+			WARNING("VBUS error workaround (delay coming)\n");
+		} else if (is_host_enabled(musb) && drvvbus) {
+			musb->is_active = 1;
+			MUSB_HST_MODE(musb);
+			musb->xceiv->otg->default_a = 1;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+			del_timer(&glue->timer);
+		} else {
+			musb->is_active = 0;
+			MUSB_DEV_MODE(musb);
+			musb->xceiv->otg->default_a = 0;
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+		}
+
+		/* NOTE: this must complete power-on within 100 ms. */
+		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
+				drvvbus ? "on" : "off",
+				otg_state_string(musb->xceiv->state),
+				err ? " ERROR" : "",
+				devctl);
+		ret = IRQ_HANDLED;
+	}
+#endif
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb)
+		ret |= musb_interrupt(musb);
+
+ eoi:
+	/* EOI needs to be written for the IRQ to be re-asserted. */
+	if (ret == IRQ_HANDLED || epintr || usbintr)
+		dsps_writel(reg_base, wrp->eoi, 1);
+
+#ifndef __UBOOT__
+	/* Poll for ID change */
+	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+#endif
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return ret;
+}
+
+static int dsps_musb_init(struct musb *musb)
+{
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+	const struct dsps_musb_wrapper *wrp = glue->wrp;
+	struct omap_musb_board_data *data = plat->board_data;
+#else
+	struct omap_musb_board_data *data =
+			(struct omap_musb_board_data *)musb->controller;
+	const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
+#endif
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 rev, val;
+	int status;
+
+	/* mentor core register starts at offset of 0x400 from musb base */
+	musb->mregs += wrp->musb_core_offset;
+
+#ifndef __UBOOT__
+	/* NOP driver needs change if supporting dual instance */
+	usb_nop_xceiv_register();
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
+		return -ENODEV;
+#endif
+
+	/* Returns zero if e.g. not clocked */
+	rev = dsps_readl(reg_base, wrp->revision);
+	if (!rev) {
+		status = -ENODEV;
+		goto err0;
+	}
+
+#ifndef __UBOOT__
+	if (is_host_enabled(musb))
+		setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+#endif
+
+	/* Reset the musb */
+	dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
+
+	/* Start the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 1);
+
+	musb->isr = dsps_interrupt;
+
+	/* reset the otgdisable bit, needed for host mode to work */
+	val = dsps_readl(reg_base, wrp->phy_utmi);
+	val &= ~(1 << wrp->otg_disable);
+	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+
+	/* clear level interrupt */
+	dsps_writel(reg_base, wrp->eoi, 0);
+
+	return 0;
+err0:
+#ifndef __UBOOT__
+	usb_put_phy(musb->xceiv);
+	usb_nop_xceiv_unregister();
+#endif
+	return status;
+}
+
+static int dsps_musb_exit(struct musb *musb)
+{
+#ifndef __UBOOT__
+	struct device *dev = musb->controller;
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+	struct platform_device *pdev = to_platform_device(dev->parent);
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+#else
+	struct omap_musb_board_data *data =
+			(struct omap_musb_board_data *)musb->controller;
+#endif
+
+#ifndef __UBOOT__
+	if (is_host_enabled(musb))
+		del_timer_sync(&glue->timer);
+#endif
+
+	/* Shutdown the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 0);
+
+#ifndef __UBOOT__
+	/* NOP driver needs change if supporting dual instance */
+	usb_put_phy(musb->xceiv);
+	usb_nop_xceiv_unregister();
+#endif
+
+	return 0;
+}
+
+#ifndef __UBOOT__
+static struct musb_platform_ops dsps_ops = {
+#else
+struct musb_platform_ops musb_dsps_ops = {
+#endif
+	.init		= dsps_musb_init,
+	.exit		= dsps_musb_exit,
+
+	.enable		= dsps_musb_enable,
+	.disable	= dsps_musb_disable,
+
+#ifndef __UBOOT__
+	.try_idle	= dsps_musb_try_idle,
+#endif
+};
+
+#ifndef __UBOOT__
+static u64 musb_dmamask = DMA_BIT_MASK(32);
+#endif
+
+#ifndef __UBOOT__
+static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+{
+	struct device *dev = glue->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct musb_hdrc_platform_data  *pdata = dev->platform_data;
+	struct platform_device	*musb;
+	struct resource *res;
+	struct resource	resources[2];
+	char res_name[10];
+	int ret;
+
+	/* get memory resource */
+	sprintf(res_name, "musb%d", id);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
+	if (!res) {
+		dev_err(dev, "%s get mem resource failed\n", res_name);
+		ret = -ENODEV;
+		goto err0;
+	}
+	res->parent = NULL;
+	resources[0] = *res;
+
+	/* get irq resource */
+	sprintf(res_name, "musb%d-irq", id);
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
+	if (!res) {
+		dev_err(dev, "%s get irq resource failed\n", res_name);
+		ret = -ENODEV;
+		goto err0;
+	}
+	res->parent = NULL;
+	resources[1] = *res;
+	resources[1].name = "mc";
+
+	/* allocate the child platform device */
+	musb = platform_device_alloc("musb-hdrc", -1);
+	if (!musb) {
+		dev_err(dev, "failed to allocate musb device\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	musb->dev.parent		= dev;
+	musb->dev.dma_mask		= &musb_dmamask;
+	musb->dev.coherent_dma_mask	= musb_dmamask;
+
+	glue->musb			= musb;
+
+	pdata->platform_ops		= &dsps_ops;
+
+	ret = platform_device_add_resources(musb, resources, 2);
+	if (ret) {
+		dev_err(dev, "failed to add resources\n");
+		goto err1;
+	}
+
+	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+	if (ret) {
+		dev_err(dev, "failed to add platform_data\n");
+		goto err1;
+	}
+
+	ret = platform_device_add(musb);
+	if (ret) {
+		dev_err(dev, "failed to register musb device\n");
+		goto err1;
+	}
+
+	return 0;
+
+err1:
+	platform_device_put(musb);
+err0:
+	return ret;
+}
+
+static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
+{
+	platform_device_del(glue->musb);
+	platform_device_put(glue->musb);
+}
+
+static int __devinit dsps_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	const struct dsps_musb_wrapper *wrp =
+				(struct dsps_musb_wrapper *)id->driver_data;
+	struct dsps_glue *glue;
+	struct resource *iomem;
+	int ret;
+
+	/* allocate glue */
+	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	if (!glue) {
+		dev_err(&pdev->dev, "unable to allocate glue memory\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	/* get memory resource */
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem) {
+		dev_err(&pdev->dev, "failed to get usbss mem resource\n");
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	glue->dev = &pdev->dev;
+
+	glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
+	if (!glue->wrp) {
+		dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+	platform_set_drvdata(pdev, glue);
+
+	/* enable the usbss clocks */
+	pm_runtime_enable(&pdev->dev);
+
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+		goto err2;
+	}
+
+	/* create the child platform device for first instances of musb */
+	ret = dsps_create_musb_pdev(glue, 0);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to create child pdev\n");
+		goto err3;
+	}
+
+	return 0;
+
+err3:
+	pm_runtime_put(&pdev->dev);
+err2:
+	pm_runtime_disable(&pdev->dev);
+	kfree(glue->wrp);
+err1:
+	kfree(glue);
+err0:
+	return ret;
+}
+static int __devexit dsps_remove(struct platform_device *pdev)
+{
+	struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+	/* delete the child platform device */
+	dsps_delete_musb_pdev(glue);
+
+	/* disable usbss clocks */
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	kfree(glue->wrp);
+	kfree(glue);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dsps_suspend(struct device *dev)
+{
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+
+	/* Shutdown the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 0);
+
+	return 0;
+}
+
+static int dsps_resume(struct device *dev)
+{
+	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct omap_musb_board_data *data = plat->board_data;
+
+	/* Start the on-chip PHY and its PLL. */
+	if (data && data->set_phy_power)
+		data->set_phy_power(data->dev, 1);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
+#endif
+
+#ifndef __UBOOT__
+static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
+	{
+		.name	= "musb-ti81xx",
+		.driver_data	= (kernel_ulong_t) &ti81xx_driver_data,
+	},
+	{  },	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
+
+static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
+	{ .compatible = "musb-ti81xx", },
+	{ .compatible = "ti,ti81xx-musb", },
+	{ .compatible = "ti,am335x-musb", },
+	{  },
+};
+MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
+
+static struct platform_driver dsps_usbss_driver = {
+	.probe		= dsps_probe,
+	.remove         = __devexit_p(dsps_remove),
+	.driver         = {
+		.name   = "musb-dsps",
+		.pm	= &dsps_pm_ops,
+		.of_match_table	= musb_dsps_of_match,
+	},
+	.id_table	= musb_dsps_id_table,
+};
+
+MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
+MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init dsps_init(void)
+{
+	return platform_driver_register(&dsps_usbss_driver);
+}
+subsys_initcall(dsps_init);
+
+static void __exit dsps_exit(void)
+{
+	platform_driver_unregister(&dsps_usbss_driver);
+}
+module_exit(dsps_exit);
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_gadget.c b/roms/u-boot/drivers/usb/musb-new/musb_gadget.c
new file mode 100644
index 000000000..5b149dac6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_gadget.c
@@ -0,0 +1,2324 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MUSB OTG driver peripheral support
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.com>
+ */
+
+#ifndef __UBOOT__
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#else
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bug.h>
+#include <linux/usb/ch9.h>
+#include "linux-compat.h"
+#endif
+
+#include "musb_core.h"
+
+
+/* MUSB PERIPHERAL status 3-mar-2006:
+ *
+ * - EP0 seems solid.  It passes both USBCV and usbtest control cases.
+ *   Minor glitches:
+ *
+ *     + remote wakeup to Linux hosts work, but saw USBCV failures;
+ *       in one test run (operator error?)
+ *     + endpoint halt tests -- in both usbtest and usbcv -- seem
+ *       to break when dma is enabled ... is something wrongly
+ *       clearing SENDSTALL?
+ *
+ * - Mass storage behaved ok when last tested.  Network traffic patterns
+ *   (with lots of short transfers etc) need retesting; they turn up the
+ *   worst cases of the DMA, since short packets are typical but are not
+ *   required.
+ *
+ * - TX/IN
+ *     + both pio and dma behave in with network and g_zero tests
+ *     + no cppi throughput issues other than no-hw-queueing
+ *     + failed with FLAT_REG (DaVinci)
+ *     + seems to behave with double buffering, PIO -and- CPPI
+ *     + with gadgetfs + AIO, requests got lost?
+ *
+ * - RX/OUT
+ *     + both pio and dma behave in with network and g_zero tests
+ *     + dma is slow in typical case (short_not_ok is clear)
+ *     + double buffering ok with PIO
+ *     + double buffering *FAILS* with CPPI, wrong data bytes sometimes
+ *     + request lossage observed with gadgetfs
+ *
+ * - ISO not tested ... might work, but only weakly isochronous
+ *
+ * - Gadget driver disabling of softconnect during bind() is ignored; so
+ *   drivers can't hold off host requests until userspace is ready.
+ *   (Workaround:  they can turn it off later.)
+ *
+ * - PORTABILITY (assumes PIO works):
+ *     + DaVinci, basically works with cppi dma
+ *     + OMAP 2430, ditto with mentor dma
+ *     + TUSB 6010, platform-specific dma in the works
+ */
+
+/* ----------------------------------------------------------------------- */
+
+#define is_buffer_mapped(req) (is_dma_capable() && \
+					(req->map_state != UN_MAPPED))
+
+#ifndef CONFIG_USB_MUSB_PIO_ONLY
+/* Maps the buffer to dma  */
+
+static inline void map_dma_buffer(struct musb_request *request,
+			struct musb *musb, struct musb_ep *musb_ep)
+{
+	int compatible = true;
+	struct dma_controller *dma = musb->dma_controller;
+
+	request->map_state = UN_MAPPED;
+
+	if (!is_dma_capable() || !musb_ep->dma)
+		return;
+
+	/* Check if DMA engine can handle this request.
+	 * DMA code must reject the USB request explicitly.
+	 * Default behaviour is to map the request.
+	 */
+	if (dma->is_compatible)
+		compatible = dma->is_compatible(musb_ep->dma,
+				musb_ep->packet_sz, request->request.buf,
+				request->request.length);
+	if (!compatible)
+		return;
+
+	if (request->request.dma == DMA_ADDR_INVALID) {
+		request->request.dma = dma_map_single(
+				musb->controller,
+				request->request.buf,
+				request->request.length,
+				request->tx
+					? DMA_TO_DEVICE
+					: DMA_FROM_DEVICE);
+		request->map_state = MUSB_MAPPED;
+	} else {
+		dma_sync_single_for_device(musb->controller,
+			request->request.dma,
+			request->request.length,
+			request->tx
+				? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+		request->map_state = PRE_MAPPED;
+	}
+}
+
+/* Unmap the buffer from dma and maps it back to cpu */
+static inline void unmap_dma_buffer(struct musb_request *request,
+				struct musb *musb)
+{
+	if (!is_buffer_mapped(request))
+		return;
+
+	if (request->request.dma == DMA_ADDR_INVALID) {
+		dev_vdbg(musb->controller,
+				"not unmapping a never mapped buffer\n");
+		return;
+	}
+	if (request->map_state == MUSB_MAPPED) {
+		dma_unmap_single(musb->controller,
+			request->request.dma,
+			request->request.length,
+			request->tx
+				? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+		request->request.dma = DMA_ADDR_INVALID;
+	} else { /* PRE_MAPPED */
+		dma_sync_single_for_cpu(musb->controller,
+			request->request.dma,
+			request->request.length,
+			request->tx
+				? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+	}
+	request->map_state = UN_MAPPED;
+}
+#else
+static inline void map_dma_buffer(struct musb_request *request,
+			struct musb *musb, struct musb_ep *musb_ep)
+{
+}
+
+static inline void unmap_dma_buffer(struct musb_request *request,
+				struct musb *musb)
+{
+}
+#endif
+
+/*
+ * Immediately complete a request.
+ *
+ * @param request the request to complete
+ * @param status the status to complete the request with
+ * Context: controller locked, IRQs blocked.
+ */
+void musb_g_giveback(
+	struct musb_ep		*ep,
+	struct usb_request	*request,
+	int			status)
+__releases(ep->musb->lock)
+__acquires(ep->musb->lock)
+{
+	struct musb_request	*req;
+	struct musb		*musb;
+	int			busy = ep->busy;
+
+	req = to_musb_request(request);
+
+	list_del(&req->list);
+	if (req->request.status == -EINPROGRESS)
+		req->request.status = status;
+	musb = req->musb;
+
+	ep->busy = 1;
+	spin_unlock(&musb->lock);
+	unmap_dma_buffer(req, musb);
+	if (request->status == 0)
+		dev_dbg(musb->controller, "%s done request %p,  %d/%d\n",
+				ep->end_point.name, request,
+				req->request.actual, req->request.length);
+	else
+		dev_dbg(musb->controller, "%s request %p, %d/%d fault %d\n",
+				ep->end_point.name, request,
+				req->request.actual, req->request.length,
+				request->status);
+	req->request.complete(&req->ep->end_point, &req->request);
+	spin_lock(&musb->lock);
+	ep->busy = busy;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Abort requests queued to an endpoint using the status. Synchronous.
+ * caller locked controller and blocked irqs, and selected this ep.
+ */
+static void nuke(struct musb_ep *ep, const int status)
+{
+	struct musb		*musb = ep->musb;
+	struct musb_request	*req = NULL;
+	void __iomem *epio = ep->musb->endpoints[ep->current_epnum].regs;
+
+	ep->busy = 1;
+
+	if (is_dma_capable() && ep->dma) {
+		struct dma_controller	*c = ep->musb->dma_controller;
+		int value;
+
+		if (ep->is_in) {
+			/*
+			 * The programming guide says that we must not clear
+			 * the DMAMODE bit before DMAENAB, so we only
+			 * clear it in the second write...
+			 */
+			musb_writew(epio, MUSB_TXCSR,
+				    MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO);
+			musb_writew(epio, MUSB_TXCSR,
+					0 | MUSB_TXCSR_FLUSHFIFO);
+		} else {
+			musb_writew(epio, MUSB_RXCSR,
+					0 | MUSB_RXCSR_FLUSHFIFO);
+			musb_writew(epio, MUSB_RXCSR,
+					0 | MUSB_RXCSR_FLUSHFIFO);
+		}
+
+		value = c->channel_abort(ep->dma);
+		dev_dbg(musb->controller, "%s: abort DMA --> %d\n",
+				ep->name, value);
+		c->channel_release(ep->dma);
+		ep->dma = NULL;
+	}
+
+	while (!list_empty(&ep->req_list)) {
+		req = list_first_entry(&ep->req_list, struct musb_request, list);
+		musb_g_giveback(ep, &req->request, status);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* Data transfers - pure PIO, pure DMA, or mixed mode */
+
+/*
+ * This assumes the separate CPPI engine is responding to DMA requests
+ * from the usb core ... sequenced a bit differently from mentor dma.
+ */
+
+static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
+{
+	if (can_bulk_split(musb, ep->type))
+		return ep->hw_ep->max_packet_sz_tx;
+	else
+		return ep->packet_sz;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral tx (IN) using Mentor DMA works as follows:
+	Only mode 0 is used for transfers <= wPktSize,
+	mode 1 is used for larger transfers,
+
+	One of the following happens:
+	- Host sends IN token which causes an endpoint interrupt
+		-> TxAvail
+			-> if DMA is currently busy, exit.
+			-> if queue is non-empty, txstate().
+
+	- Request is queued by the gadget driver.
+		-> if queue was previously empty, txstate()
+
+	txstate()
+		-> start
+		  /\	-> setup DMA
+		  |     (data is transferred to the FIFO, then sent out when
+		  |	IN token(s) are recd from Host.
+		  |		-> DMA interrupt on completion
+		  |		   calls TxAvail.
+		  |		      -> stop DMA, ~DMAENAB,
+		  |		      -> set TxPktRdy for last short pkt or zlp
+		  |		      -> Complete Request
+		  |		      -> Continue next request (call txstate)
+		  |___________________________________|
+
+ * Non-Mentor DMA engines can of course work differently, such as by
+ * upleveling from irq-per-packet to irq-per-buffer.
+ */
+
+#endif
+
+/*
+ * An endpoint is transmitting data. This can be called either from
+ * the IRQ routine or from ep.queue() to kickstart a request on an
+ * endpoint.
+ *
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void txstate(struct musb *musb, struct musb_request *req)
+{
+	u8			epnum = req->epnum;
+	struct musb_ep		*musb_ep;
+	void __iomem		*epio = musb->endpoints[epnum].regs;
+	struct usb_request	*request;
+	u16			fifo_count = 0, csr;
+	int			use_dma = 0;
+
+	musb_ep = req->ep;
+
+	/* Check if EP is disabled */
+	if (!musb_ep->desc) {
+		dev_dbg(musb->controller, "ep:%s disabled - ignore request\n",
+						musb_ep->end_point.name);
+		return;
+	}
+
+	/* we shouldn't get here while DMA is active ... but we do ... */
+	if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
+		dev_dbg(musb->controller, "dma pending...\n");
+		return;
+	}
+
+	/* read TXCSR before */
+	csr = musb_readw(epio, MUSB_TXCSR);
+
+	request = &req->request;
+	fifo_count = min(max_ep_writesize(musb, musb_ep),
+			(int)(request->length - request->actual));
+
+	if (csr & MUSB_TXCSR_TXPKTRDY) {
+		dev_dbg(musb->controller, "%s old packet still ready , txcsr %03x\n",
+				musb_ep->end_point.name, csr);
+		return;
+	}
+
+	if (csr & MUSB_TXCSR_P_SENDSTALL) {
+		dev_dbg(musb->controller, "%s stalling, txcsr %03x\n",
+				musb_ep->end_point.name, csr);
+		return;
+	}
+
+	dev_dbg(musb->controller, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n",
+			epnum, musb_ep->packet_sz, fifo_count,
+			csr);
+
+#ifndef	CONFIG_USB_MUSB_PIO_ONLY
+	if (is_buffer_mapped(req)) {
+		struct dma_controller	*c = musb->dma_controller;
+		size_t request_size;
+
+		/* setup DMA, then program endpoint CSR */
+		request_size = min_t(size_t, request->length - request->actual,
+					musb_ep->dma->max_len);
+
+		use_dma = (request->dma != DMA_ADDR_INVALID);
+
+		/* MUSB_TXCSR_P_ISO is still set correctly */
+
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
+		{
+			if (request_size < musb_ep->packet_sz)
+				musb_ep->dma->desired_mode = 0;
+			else
+				musb_ep->dma->desired_mode = 1;
+
+			use_dma = use_dma && c->channel_program(
+					musb_ep->dma, musb_ep->packet_sz,
+					musb_ep->dma->desired_mode,
+					request->dma + request->actual, request_size);
+			if (use_dma) {
+				if (musb_ep->dma->desired_mode == 0) {
+					/*
+					 * We must not clear the DMAMODE bit
+					 * before the DMAENAB bit -- and the
+					 * latter doesn't always get cleared
+					 * before we get here...
+					 */
+					csr &= ~(MUSB_TXCSR_AUTOSET
+						| MUSB_TXCSR_DMAENAB);
+					musb_writew(epio, MUSB_TXCSR, csr
+						| MUSB_TXCSR_P_WZC_BITS);
+					csr &= ~MUSB_TXCSR_DMAMODE;
+					csr |= (MUSB_TXCSR_DMAENAB |
+							MUSB_TXCSR_MODE);
+					/* against programming guide */
+				} else {
+					csr |= (MUSB_TXCSR_DMAENAB
+							| MUSB_TXCSR_DMAMODE
+							| MUSB_TXCSR_MODE);
+					if (!musb_ep->hb_mult)
+						csr |= MUSB_TXCSR_AUTOSET;
+				}
+				csr &= ~MUSB_TXCSR_P_UNDERRUN;
+
+				musb_writew(epio, MUSB_TXCSR, csr);
+			}
+		}
+
+#elif defined(CONFIG_USB_TI_CPPI_DMA)
+		/* program endpoint CSR first, then setup DMA */
+		csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+		csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+		       MUSB_TXCSR_MODE;
+		musb_writew(epio, MUSB_TXCSR,
+			(MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
+				| csr);
+
+		/* ensure writebuffer is empty */
+		csr = musb_readw(epio, MUSB_TXCSR);
+
+		/* NOTE host side sets DMAENAB later than this; both are
+		 * OK since the transfer dma glue (between CPPI and Mentor
+		 * fifos) just tells CPPI it could start.  Data only moves
+		 * to the USB TX fifo when both fifos are ready.
+		 */
+
+		/* "mode" is irrelevant here; handle terminating ZLPs like
+		 * PIO does, since the hardware RNDIS mode seems unreliable
+		 * except for the last-packet-is-already-short case.
+		 */
+		use_dma = use_dma && c->channel_program(
+				musb_ep->dma, musb_ep->packet_sz,
+				0,
+				request->dma + request->actual,
+				request_size);
+		if (!use_dma) {
+			c->channel_release(musb_ep->dma);
+			musb_ep->dma = NULL;
+			csr &= ~MUSB_TXCSR_DMAENAB;
+			musb_writew(epio, MUSB_TXCSR, csr);
+			/* invariant: prequest->buf is non-null */
+		}
+#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+		use_dma = use_dma && c->channel_program(
+				musb_ep->dma, musb_ep->packet_sz,
+				request->zero,
+				request->dma + request->actual,
+				request_size);
+#endif
+	}
+#endif
+
+	if (!use_dma) {
+		/*
+		 * Unmap the dma buffer back to cpu if dma channel
+		 * programming fails
+		 */
+		unmap_dma_buffer(req, musb);
+
+		musb_write_fifo(musb_ep->hw_ep, fifo_count,
+				(u8 *) (request->buf + request->actual));
+		request->actual += fifo_count;
+		csr |= MUSB_TXCSR_TXPKTRDY;
+		csr &= ~MUSB_TXCSR_P_UNDERRUN;
+		musb_writew(epio, MUSB_TXCSR, csr);
+	}
+
+	/* host may already have the data when this message shows... */
+	dev_dbg(musb->controller, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n",
+			musb_ep->end_point.name, use_dma ? "dma" : "pio",
+			request->actual, request->length,
+			musb_readw(epio, MUSB_TXCSR),
+			fifo_count,
+			musb_readw(epio, MUSB_TXMAXP));
+}
+
+/*
+ * FIFO state update (e.g. data ready).
+ * Called from IRQ,  with controller locked.
+ */
+void musb_g_tx(struct musb *musb, u8 epnum)
+{
+	u16			csr;
+	struct musb_request	*req;
+	struct usb_request	*request;
+	u8 __iomem		*mbase = musb->mregs;
+	struct musb_ep		*musb_ep = &musb->endpoints[epnum].ep_in;
+	void __iomem		*epio = musb->endpoints[epnum].regs;
+	struct dma_channel	*dma;
+
+	musb_ep_select(mbase, epnum);
+	req = next_request(musb_ep);
+	request = &req->request;
+
+	csr = musb_readw(epio, MUSB_TXCSR);
+	dev_dbg(musb->controller, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr);
+
+	dma = is_dma_capable() ? musb_ep->dma : NULL;
+
+	/*
+	 * REVISIT: for high bandwidth, MUSB_TXCSR_P_INCOMPTX
+	 * probably rates reporting as a host error.
+	 */
+	if (csr & MUSB_TXCSR_P_SENTSTALL) {
+		csr |=	MUSB_TXCSR_P_WZC_BITS;
+		csr &= ~MUSB_TXCSR_P_SENTSTALL;
+		musb_writew(epio, MUSB_TXCSR, csr);
+		return;
+	}
+
+	if (csr & MUSB_TXCSR_P_UNDERRUN) {
+		/* We NAKed, no big deal... little reason to care. */
+		csr |=	 MUSB_TXCSR_P_WZC_BITS;
+		csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+		musb_writew(epio, MUSB_TXCSR, csr);
+		dev_vdbg(musb->controller, "underrun on ep%d, req %p\n",
+				epnum, request);
+	}
+
+	if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+		/*
+		 * SHOULD NOT HAPPEN... has with CPPI though, after
+		 * changing SENDSTALL (and other cases); harmless?
+		 */
+		dev_dbg(musb->controller, "%s dma still busy?\n", musb_ep->end_point.name);
+		return;
+	}
+
+	if (request) {
+		u8	is_dma = 0;
+
+		if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
+			is_dma = 1;
+			csr |= MUSB_TXCSR_P_WZC_BITS;
+			csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
+				 MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET);
+			musb_writew(epio, MUSB_TXCSR, csr);
+			/* Ensure writebuffer is empty. */
+			csr = musb_readw(epio, MUSB_TXCSR);
+			request->actual += musb_ep->dma->actual_len;
+			dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n",
+				epnum, csr, musb_ep->dma->actual_len, request);
+		}
+
+		/*
+		 * First, maybe a terminating short packet. Some DMA
+		 * engines might handle this by themselves.
+		 */
+		if ((request->zero && request->length
+			&& (request->length % musb_ep->packet_sz == 0)
+			&& (request->actual == request->length))
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
+			|| (is_dma && (!dma->desired_mode ||
+				(request->actual &
+					(musb_ep->packet_sz - 1))))
+#endif
+		) {
+			/*
+			 * On DMA completion, FIFO may not be
+			 * available yet...
+			 */
+			if (csr & MUSB_TXCSR_TXPKTRDY)
+				return;
+
+			dev_dbg(musb->controller, "sending zero pkt\n");
+			musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
+					| MUSB_TXCSR_TXPKTRDY);
+			request->zero = 0;
+		}
+
+		if (request->actual == request->length) {
+			musb_g_giveback(musb_ep, request, 0);
+			/*
+			 * In the giveback function the MUSB lock is
+			 * released and acquired after sometime. During
+			 * this time period the INDEX register could get
+			 * changed by the gadget_queue function especially
+			 * on SMP systems. Reselect the INDEX to be sure
+			 * we are reading/modifying the right registers
+			 */
+			musb_ep_select(mbase, epnum);
+			req = musb_ep->desc ? next_request(musb_ep) : NULL;
+			if (!req) {
+				dev_dbg(musb->controller, "%s idle now\n",
+					musb_ep->end_point.name);
+				return;
+			}
+		}
+
+		txstate(musb, req);
+	}
+}
+
+/* ------------------------------------------------------------ */
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Peripheral rx (OUT) using Mentor DMA works as follows:
+	- Only mode 0 is used.
+
+	- Request is queued by the gadget class driver.
+		-> if queue was previously empty, rxstate()
+
+	- Host sends OUT token which causes an endpoint interrupt
+	  /\      -> RxReady
+	  |	      -> if request queued, call rxstate
+	  |		/\	-> setup DMA
+	  |		|	     -> DMA interrupt on completion
+	  |		|		-> RxReady
+	  |		|		      -> stop DMA
+	  |		|		      -> ack the read
+	  |		|		      -> if data recd = max expected
+	  |		|				by the request, or host
+	  |		|				sent a short packet,
+	  |		|				complete the request,
+	  |		|				and start the next one.
+	  |		|_____________________________________|
+	  |					 else just wait for the host
+	  |					    to send the next OUT token.
+	  |__________________________________________________|
+
+ * Non-Mentor DMA engines can of course work differently.
+ */
+
+#endif
+
+/*
+ * Context: controller locked, IRQs blocked, endpoint selected
+ */
+static void rxstate(struct musb *musb, struct musb_request *req)
+{
+	const u8		epnum = req->epnum;
+	struct usb_request	*request = &req->request;
+	struct musb_ep		*musb_ep;
+	void __iomem		*epio = musb->endpoints[epnum].regs;
+	unsigned		fifo_count = 0;
+	u16			len;
+	u16			csr = musb_readw(epio, MUSB_RXCSR);
+	struct musb_hw_ep	*hw_ep = &musb->endpoints[epnum];
+	u8			use_mode_1;
+
+	if (hw_ep->is_shared_fifo)
+		musb_ep = &hw_ep->ep_in;
+	else
+		musb_ep = &hw_ep->ep_out;
+
+	len = musb_ep->packet_sz;
+
+	/* Check if EP is disabled */
+	if (!musb_ep->desc) {
+		dev_dbg(musb->controller, "ep:%s disabled - ignore request\n",
+						musb_ep->end_point.name);
+		return;
+	}
+
+	/* We shouldn't get here while DMA is active, but we do... */
+	if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
+		dev_dbg(musb->controller, "DMA pending...\n");
+		return;
+	}
+
+	if (csr & MUSB_RXCSR_P_SENDSTALL) {
+		dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n",
+		    musb_ep->end_point.name, csr);
+		return;
+	}
+
+	if (is_cppi_enabled() && is_buffer_mapped(req)) {
+		struct dma_controller	*c = musb->dma_controller;
+		struct dma_channel	*channel = musb_ep->dma;
+
+		/* NOTE:  CPPI won't actually stop advancing the DMA
+		 * queue after short packet transfers, so this is almost
+		 * always going to run as IRQ-per-packet DMA so that
+		 * faults will be handled correctly.
+		 */
+		if (c->channel_program(channel,
+				musb_ep->packet_sz,
+				!request->short_not_ok,
+				request->dma + request->actual,
+				request->length - request->actual)) {
+
+			/* make sure that if an rxpkt arrived after the irq,
+			 * the cppi engine will be ready to take it as soon
+			 * as DMA is enabled
+			 */
+			csr &= ~(MUSB_RXCSR_AUTOCLEAR
+					| MUSB_RXCSR_DMAMODE);
+			csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS;
+			musb_writew(epio, MUSB_RXCSR, csr);
+			return;
+		}
+	}
+
+	if (csr & MUSB_RXCSR_RXPKTRDY) {
+		len = musb_readw(epio, MUSB_RXCOUNT);
+
+		/*
+		 * Enable Mode 1 on RX transfers only when short_not_ok flag
+		 * is set. Currently short_not_ok flag is set only from
+		 * file_storage and f_mass_storage drivers
+		 */
+
+		if (request->short_not_ok && len == musb_ep->packet_sz)
+			use_mode_1 = 1;
+		else
+			use_mode_1 = 0;
+
+		if (request->actual < request->length) {
+#ifdef CONFIG_USB_INVENTRA_DMA
+			if (is_buffer_mapped(req)) {
+				struct dma_controller	*c;
+				struct dma_channel	*channel;
+				int			use_dma = 0;
+
+				c = musb->dma_controller;
+				channel = musb_ep->dma;
+
+	/* We use DMA Req mode 0 in rx_csr, and DMA controller operates in
+	 * mode 0 only. So we do not get endpoint interrupts due to DMA
+	 * completion. We only get interrupts from DMA controller.
+	 *
+	 * We could operate in DMA mode 1 if we knew the size of the tranfer
+	 * in advance. For mass storage class, request->length = what the host
+	 * sends, so that'd work.  But for pretty much everything else,
+	 * request->length is routinely more than what the host sends. For
+	 * most these gadgets, end of is signified either by a short packet,
+	 * or filling the last byte of the buffer.  (Sending extra data in
+	 * that last pckate should trigger an overflow fault.)  But in mode 1,
+	 * we don't get DMA completion interrupt for short packets.
+	 *
+	 * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),
+	 * to get endpoint interrupt on every DMA req, but that didn't seem
+	 * to work reliably.
+	 *
+	 * REVISIT an updated g_file_storage can set req->short_not_ok, which
+	 * then becomes usable as a runtime "use mode 1" hint...
+	 */
+
+				/* Experimental: Mode1 works with mass storage use cases */
+				if (use_mode_1) {
+					csr |= MUSB_RXCSR_AUTOCLEAR;
+					musb_writew(epio, MUSB_RXCSR, csr);
+					csr |= MUSB_RXCSR_DMAENAB;
+					musb_writew(epio, MUSB_RXCSR, csr);
+
+					/*
+					 * this special sequence (enabling and then
+					 * disabling MUSB_RXCSR_DMAMODE) is required
+					 * to get DMAReq to activate
+					 */
+					musb_writew(epio, MUSB_RXCSR,
+						csr | MUSB_RXCSR_DMAMODE);
+					musb_writew(epio, MUSB_RXCSR, csr);
+
+				} else {
+					if (!musb_ep->hb_mult &&
+						musb_ep->hw_ep->rx_double_buffered)
+						csr |= MUSB_RXCSR_AUTOCLEAR;
+					csr |= MUSB_RXCSR_DMAENAB;
+					musb_writew(epio, MUSB_RXCSR, csr);
+				}
+
+				if (request->actual < request->length) {
+					int transfer_size = 0;
+					if (use_mode_1) {
+						transfer_size = min(request->length - request->actual,
+								channel->max_len);
+						musb_ep->dma->desired_mode = 1;
+					} else {
+						transfer_size = min(request->length - request->actual,
+								(unsigned)len);
+						musb_ep->dma->desired_mode = 0;
+					}
+
+					use_dma = c->channel_program(
+							channel,
+							musb_ep->packet_sz,
+							channel->desired_mode,
+							request->dma
+							+ request->actual,
+							transfer_size);
+				}
+
+				if (use_dma)
+					return;
+			}
+#elif defined(CONFIG_USB_UX500_DMA)
+			if ((is_buffer_mapped(req)) &&
+				(request->actual < request->length)) {
+
+				struct dma_controller *c;
+				struct dma_channel *channel;
+				int transfer_size = 0;
+
+				c = musb->dma_controller;
+				channel = musb_ep->dma;
+
+				/* In case first packet is short */
+				if (len < musb_ep->packet_sz)
+					transfer_size = len;
+				else if (request->short_not_ok)
+					transfer_size =	min(request->length -
+							request->actual,
+							channel->max_len);
+				else
+					transfer_size = min(request->length -
+							request->actual,
+							(unsigned)len);
+
+				csr &= ~MUSB_RXCSR_DMAMODE;
+				csr |= (MUSB_RXCSR_DMAENAB |
+					MUSB_RXCSR_AUTOCLEAR);
+
+				musb_writew(epio, MUSB_RXCSR, csr);
+
+				if (transfer_size <= musb_ep->packet_sz) {
+					musb_ep->dma->desired_mode = 0;
+				} else {
+					musb_ep->dma->desired_mode = 1;
+					/* Mode must be set after DMAENAB */
+					csr |= MUSB_RXCSR_DMAMODE;
+					musb_writew(epio, MUSB_RXCSR, csr);
+				}
+
+				if (c->channel_program(channel,
+							musb_ep->packet_sz,
+							channel->desired_mode,
+							request->dma
+							+ request->actual,
+							transfer_size))
+
+					return;
+			}
+#endif	/* Mentor's DMA */
+
+			fifo_count = request->length - request->actual;
+			dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
+					musb_ep->end_point.name,
+					len, fifo_count,
+					musb_ep->packet_sz);
+
+			fifo_count = min_t(unsigned, len, fifo_count);
+
+#ifdef	CONFIG_USB_TUSB_OMAP_DMA
+			if (tusb_dma_omap() && is_buffer_mapped(req)) {
+				struct dma_controller *c = musb->dma_controller;
+				struct dma_channel *channel = musb_ep->dma;
+				u32 dma_addr = request->dma + request->actual;
+				int ret;
+
+				ret = c->channel_program(channel,
+						musb_ep->packet_sz,
+						channel->desired_mode,
+						dma_addr,
+						fifo_count);
+				if (ret)
+					return;
+			}
+#endif
+			/*
+			 * Unmap the dma buffer back to cpu if dma channel
+			 * programming fails. This buffer is mapped if the
+			 * channel allocation is successful
+			 */
+			 if (is_buffer_mapped(req)) {
+				unmap_dma_buffer(req, musb);
+
+				/*
+				 * Clear DMAENAB and AUTOCLEAR for the
+				 * PIO mode transfer
+				 */
+				csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+				musb_writew(epio, MUSB_RXCSR, csr);
+			}
+
+			musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
+					(request->buf + request->actual));
+			request->actual += fifo_count;
+
+			/* REVISIT if we left anything in the fifo, flush
+			 * it and report -EOVERFLOW
+			 */
+
+			/* ack the read! */
+			csr |= MUSB_RXCSR_P_WZC_BITS;
+			csr &= ~MUSB_RXCSR_RXPKTRDY;
+			musb_writew(epio, MUSB_RXCSR, csr);
+		}
+	}
+
+	/* reach the end or short packet detected */
+	if (request->actual == request->length || len < musb_ep->packet_sz)
+		musb_g_giveback(musb_ep, request, 0);
+}
+
+/*
+ * Data ready for a request; called from IRQ
+ */
+void musb_g_rx(struct musb *musb, u8 epnum)
+{
+	u16			csr;
+	struct musb_request	*req;
+	struct usb_request	*request;
+	void __iomem		*mbase = musb->mregs;
+	struct musb_ep		*musb_ep;
+	void __iomem		*epio = musb->endpoints[epnum].regs;
+	struct dma_channel	*dma;
+	struct musb_hw_ep	*hw_ep = &musb->endpoints[epnum];
+
+	if (hw_ep->is_shared_fifo)
+		musb_ep = &hw_ep->ep_in;
+	else
+		musb_ep = &hw_ep->ep_out;
+
+	musb_ep_select(mbase, epnum);
+
+	req = next_request(musb_ep);
+	if (!req)
+		return;
+
+	request = &req->request;
+
+	csr = musb_readw(epio, MUSB_RXCSR);
+	dma = is_dma_capable() ? musb_ep->dma : NULL;
+
+	dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name,
+			csr, dma ? " (dma)" : "", request);
+
+	if (csr & MUSB_RXCSR_P_SENTSTALL) {
+		csr |= MUSB_RXCSR_P_WZC_BITS;
+		csr &= ~MUSB_RXCSR_P_SENTSTALL;
+		musb_writew(epio, MUSB_RXCSR, csr);
+		return;
+	}
+
+	if (csr & MUSB_RXCSR_P_OVERRUN) {
+		/* csr |= MUSB_RXCSR_P_WZC_BITS; */
+		csr &= ~MUSB_RXCSR_P_OVERRUN;
+		musb_writew(epio, MUSB_RXCSR, csr);
+
+		dev_dbg(musb->controller, "%s iso overrun on %p\n", musb_ep->name, request);
+		if (request->status == -EINPROGRESS)
+			request->status = -EOVERFLOW;
+	}
+	if (csr & MUSB_RXCSR_INCOMPRX) {
+		/* REVISIT not necessarily an error */
+		dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name);
+	}
+
+	if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+		/* "should not happen"; likely RXPKTRDY pending for DMA */
+		dev_dbg(musb->controller, "%s busy, csr %04x\n",
+			musb_ep->end_point.name, csr);
+		return;
+	}
+
+	if (dma && (csr & MUSB_RXCSR_DMAENAB)) {
+		csr &= ~(MUSB_RXCSR_AUTOCLEAR
+				| MUSB_RXCSR_DMAENAB
+				| MUSB_RXCSR_DMAMODE);
+		musb_writew(epio, MUSB_RXCSR,
+			MUSB_RXCSR_P_WZC_BITS | csr);
+
+		request->actual += musb_ep->dma->actual_len;
+
+		dev_dbg(musb->controller, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n",
+			epnum, csr,
+			musb_readw(epio, MUSB_RXCSR),
+			musb_ep->dma->actual_len, request);
+
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \
+	defined(CONFIG_USB_UX500_DMA)
+		/* Autoclear doesn't clear RxPktRdy for short packets */
+		if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
+				|| (dma->actual_len
+					& (musb_ep->packet_sz - 1))) {
+			/* ack the read! */
+			csr &= ~MUSB_RXCSR_RXPKTRDY;
+			musb_writew(epio, MUSB_RXCSR, csr);
+		}
+
+		/* incomplete, and not short? wait for next IN packet */
+		if ((request->actual < request->length)
+				&& (musb_ep->dma->actual_len
+					== musb_ep->packet_sz)) {
+			/* In double buffer case, continue to unload fifo if
+ 			 * there is Rx packet in FIFO.
+ 			 **/
+			csr = musb_readw(epio, MUSB_RXCSR);
+			if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+				hw_ep->rx_double_buffered)
+				goto exit;
+			return;
+		}
+#endif
+		musb_g_giveback(musb_ep, request, 0);
+		/*
+		 * In the giveback function the MUSB lock is
+		 * released and acquired after sometime. During
+		 * this time period the INDEX register could get
+		 * changed by the gadget_queue function especially
+		 * on SMP systems. Reselect the INDEX to be sure
+		 * we are reading/modifying the right registers
+		 */
+		musb_ep_select(mbase, epnum);
+
+		req = next_request(musb_ep);
+		if (!req)
+			return;
+	}
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \
+	defined(CONFIG_USB_UX500_DMA)
+exit:
+#endif
+	/* Analyze request */
+	rxstate(musb, req);
+}
+
+/* ------------------------------------------------------------ */
+
+static int musb_gadget_enable(struct usb_ep *ep,
+			const struct usb_endpoint_descriptor *desc)
+{
+	unsigned long		flags;
+	struct musb_ep		*musb_ep;
+	struct musb_hw_ep	*hw_ep;
+	void __iomem		*regs;
+	struct musb		*musb;
+	void __iomem	*mbase;
+	u8		epnum;
+	u16		csr;
+	unsigned	tmp;
+	int		status = -EINVAL;
+
+	if (!ep || !desc)
+		return -EINVAL;
+
+	musb_ep = to_musb_ep(ep);
+	hw_ep = musb_ep->hw_ep;
+	regs = hw_ep->regs;
+	musb = musb_ep->musb;
+	mbase = musb->mregs;
+	epnum = musb_ep->current_epnum;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	if (musb_ep->desc) {
+		status = -EBUSY;
+		goto fail;
+	}
+	musb_ep->type = usb_endpoint_type(desc);
+
+	/* check direction and (later) maxpacket size against endpoint */
+	if (usb_endpoint_num(desc) != epnum)
+		goto fail;
+
+	/* REVISIT this rules out high bandwidth periodic transfers */
+	tmp = usb_endpoint_maxp(desc);
+	if (tmp & ~0x07ff) {
+		int ok;
+
+		if (usb_endpoint_dir_in(desc))
+			ok = musb->hb_iso_tx;
+		else
+			ok = musb->hb_iso_rx;
+
+		if (!ok) {
+			dev_dbg(musb->controller, "no support for high bandwidth ISO\n");
+			goto fail;
+		}
+		musb_ep->hb_mult = (tmp >> 11) & 3;
+	} else {
+		musb_ep->hb_mult = 0;
+	}
+
+	musb_ep->packet_sz = tmp & 0x7ff;
+	tmp = musb_ep->packet_sz * (musb_ep->hb_mult + 1);
+
+	/* enable the interrupts for the endpoint, set the endpoint
+	 * packet size (or fail), set the mode, clear the fifo
+	 */
+	musb_ep_select(mbase, epnum);
+	if (usb_endpoint_dir_in(desc)) {
+		u16 int_txe = musb_readw(mbase, MUSB_INTRTXE);
+
+		if (hw_ep->is_shared_fifo)
+			musb_ep->is_in = 1;
+		if (!musb_ep->is_in)
+			goto fail;
+
+		if (tmp > hw_ep->max_packet_sz_tx) {
+			dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n");
+			goto fail;
+		}
+
+		int_txe |= (1 << epnum);
+		musb_writew(mbase, MUSB_INTRTXE, int_txe);
+
+		/* REVISIT if can_bulk_split(), use by updating "tmp";
+		 * likewise high bandwidth periodic tx
+		 */
+		/* Set TXMAXP with the FIFO size of the endpoint
+		 * to disable double buffering mode.
+		 */
+		if (musb->double_buffer_not_ok)
+			musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+		else
+			musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz
+					| (musb_ep->hb_mult << 11));
+
+		csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
+		if (musb_readw(regs, MUSB_TXCSR)
+				& MUSB_TXCSR_FIFONOTEMPTY)
+			csr |= MUSB_TXCSR_FLUSHFIFO;
+		if (musb_ep->type == USB_ENDPOINT_XFER_ISOC)
+			csr |= MUSB_TXCSR_P_ISO;
+
+		/* set twice in case of double buffering */
+		musb_writew(regs, MUSB_TXCSR, csr);
+		/* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+		musb_writew(regs, MUSB_TXCSR, csr);
+
+	} else {
+		u16 int_rxe = musb_readw(mbase, MUSB_INTRRXE);
+
+		if (hw_ep->is_shared_fifo)
+			musb_ep->is_in = 0;
+		if (musb_ep->is_in)
+			goto fail;
+
+		if (tmp > hw_ep->max_packet_sz_rx) {
+			dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n");
+			goto fail;
+		}
+
+		int_rxe |= (1 << epnum);
+		musb_writew(mbase, MUSB_INTRRXE, int_rxe);
+
+		/* REVISIT if can_bulk_combine() use by updating "tmp"
+		 * likewise high bandwidth periodic rx
+		 */
+		/* Set RXMAXP with the FIFO size of the endpoint
+		 * to disable double buffering mode.
+		 */
+		if (musb->double_buffer_not_ok)
+			musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx);
+		else
+			musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz
+					| (musb_ep->hb_mult << 11));
+
+		/* force shared fifo to OUT-only mode */
+		if (hw_ep->is_shared_fifo) {
+			csr = musb_readw(regs, MUSB_TXCSR);
+			csr &= ~(MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY);
+			musb_writew(regs, MUSB_TXCSR, csr);
+		}
+
+		csr = MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_CLRDATATOG;
+		if (musb_ep->type == USB_ENDPOINT_XFER_ISOC)
+			csr |= MUSB_RXCSR_P_ISO;
+		else if (musb_ep->type == USB_ENDPOINT_XFER_INT)
+			csr |= MUSB_RXCSR_DISNYET;
+
+		/* set twice in case of double buffering */
+		musb_writew(regs, MUSB_RXCSR, csr);
+		musb_writew(regs, MUSB_RXCSR, csr);
+	}
+
+	/* NOTE:  all the I/O code _should_ work fine without DMA, in case
+	 * for some reason you run out of channels here.
+	 */
+	if (is_dma_capable() && musb->dma_controller) {
+		struct dma_controller	*c = musb->dma_controller;
+
+		musb_ep->dma = c->channel_alloc(c, hw_ep,
+				(desc->bEndpointAddress & USB_DIR_IN));
+	} else
+		musb_ep->dma = NULL;
+
+	musb_ep->desc = desc;
+	musb_ep->busy = 0;
+	musb_ep->wedged = 0;
+	status = 0;
+
+	pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n",
+			musb_driver_name, musb_ep->end_point.name,
+			({ char *s; switch (musb_ep->type) {
+			case USB_ENDPOINT_XFER_BULK:	s = "bulk"; break;
+			case USB_ENDPOINT_XFER_INT:	s = "int"; break;
+			default:			s = "iso"; break;
+			}; s; }),
+			musb_ep->is_in ? "IN" : "OUT",
+			musb_ep->dma ? "dma, " : "",
+			musb_ep->packet_sz);
+
+	schedule_work(&musb->irq_work);
+
+fail:
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return status;
+}
+
+/*
+ * Disable an endpoint flushing all requests queued.
+ */
+static int musb_gadget_disable(struct usb_ep *ep)
+{
+	unsigned long	flags;
+	struct musb	*musb;
+	u8		epnum;
+	struct musb_ep	*musb_ep;
+	void __iomem	*epio;
+	int		status = 0;
+
+	musb_ep = to_musb_ep(ep);
+	musb = musb_ep->musb;
+	epnum = musb_ep->current_epnum;
+	epio = musb->endpoints[epnum].regs;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	musb_ep_select(musb->mregs, epnum);
+
+	/* zero the endpoint sizes */
+	if (musb_ep->is_in) {
+		u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE);
+		int_txe &= ~(1 << epnum);
+		musb_writew(musb->mregs, MUSB_INTRTXE, int_txe);
+		musb_writew(epio, MUSB_TXMAXP, 0);
+	} else {
+		u16 int_rxe = musb_readw(musb->mregs, MUSB_INTRRXE);
+		int_rxe &= ~(1 << epnum);
+		musb_writew(musb->mregs, MUSB_INTRRXE, int_rxe);
+		musb_writew(epio, MUSB_RXMAXP, 0);
+	}
+
+	musb_ep->desc = NULL;
+#ifndef __UBOOT__
+	musb_ep->end_point.desc = NULL;
+#endif
+
+	/* abort all pending DMA and requests */
+	nuke(musb_ep, -ESHUTDOWN);
+
+	schedule_work(&musb->irq_work);
+
+	spin_unlock_irqrestore(&(musb->lock), flags);
+
+	dev_dbg(musb->controller, "%s\n", musb_ep->end_point.name);
+
+	return status;
+}
+
+/*
+ * Allocate a request for an endpoint.
+ * Reused by ep0 code.
+ */
+struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+	struct musb_ep		*musb_ep = to_musb_ep(ep);
+	struct musb		*musb = musb_ep->musb;
+	struct musb_request	*request = NULL;
+
+	request = kzalloc(sizeof *request, gfp_flags);
+	if (!request) {
+		dev_dbg(musb->controller, "not enough memory\n");
+		return NULL;
+	}
+
+	request->request.dma = DMA_ADDR_INVALID;
+	request->epnum = musb_ep->current_epnum;
+	request->ep = musb_ep;
+
+	return &request->request;
+}
+
+/*
+ * Free a request
+ * Reused by ep0 code.
+ */
+void musb_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	kfree(to_musb_request(req));
+}
+
+static LIST_HEAD(buffers);
+
+struct free_record {
+	struct list_head	list;
+	struct device		*dev;
+	unsigned		bytes;
+	dma_addr_t		dma;
+};
+
+/*
+ * Context: controller locked, IRQs blocked.
+ */
+void musb_ep_restart(struct musb *musb, struct musb_request *req)
+{
+	dev_dbg(musb->controller, "<== %s request %p len %u on hw_ep%d\n",
+		req->tx ? "TX/IN" : "RX/OUT",
+		&req->request, req->request.length, req->epnum);
+
+	musb_ep_select(musb->mregs, req->epnum);
+	if (req->tx)
+		txstate(musb, req);
+	else
+		rxstate(musb, req);
+}
+
+static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
+			gfp_t gfp_flags)
+{
+	struct musb_ep		*musb_ep;
+	struct musb_request	*request;
+	struct musb		*musb;
+	int			status = 0;
+	unsigned long		lockflags;
+
+	if (!ep || !req)
+		return -EINVAL;
+	if (!req->buf)
+		return -ENODATA;
+
+	musb_ep = to_musb_ep(ep);
+	musb = musb_ep->musb;
+
+	request = to_musb_request(req);
+	request->musb = musb;
+
+	if (request->ep != musb_ep)
+		return -EINVAL;
+
+	dev_dbg(musb->controller, "<== to %s request=%p\n", ep->name, req);
+
+	/* request is mine now... */
+	request->request.actual = 0;
+	request->request.status = -EINPROGRESS;
+	request->epnum = musb_ep->current_epnum;
+	request->tx = musb_ep->is_in;
+
+	map_dma_buffer(request, musb, musb_ep);
+
+	spin_lock_irqsave(&musb->lock, lockflags);
+
+	/* don't queue if the ep is down */
+	if (!musb_ep->desc) {
+		dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
+				req, ep->name, "disabled");
+		status = -ESHUTDOWN;
+		goto cleanup;
+	}
+
+	/* add request to the list */
+	list_add_tail(&request->list, &musb_ep->req_list);
+
+	/* it this is the head of the queue, start i/o ... */
+	if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
+		musb_ep_restart(musb, request);
+
+cleanup:
+	spin_unlock_irqrestore(&musb->lock, lockflags);
+	return status;
+}
+
+static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
+{
+	struct musb_ep		*musb_ep = to_musb_ep(ep);
+	struct musb_request	*req = to_musb_request(request);
+	struct musb_request	*r;
+	unsigned long		flags;
+	int			status = 0;
+	struct musb		*musb = musb_ep->musb;
+
+	if (!ep || !request || to_musb_request(request)->ep != musb_ep)
+		return -EINVAL;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	list_for_each_entry(r, &musb_ep->req_list, list) {
+		if (r == req)
+			break;
+	}
+	if (r != req) {
+		dev_dbg(musb->controller, "request %p not queued to %s\n", request, ep->name);
+		status = -EINVAL;
+		goto done;
+	}
+
+	/* if the hardware doesn't have the request, easy ... */
+	if (musb_ep->req_list.next != &req->list || musb_ep->busy)
+		musb_g_giveback(musb_ep, request, -ECONNRESET);
+
+	/* ... else abort the dma transfer ... */
+	else if (is_dma_capable() && musb_ep->dma) {
+		struct dma_controller	*c = musb->dma_controller;
+
+		musb_ep_select(musb->mregs, musb_ep->current_epnum);
+		if (c->channel_abort)
+			status = c->channel_abort(musb_ep->dma);
+		else
+			status = -EBUSY;
+		if (status == 0)
+			musb_g_giveback(musb_ep, request, -ECONNRESET);
+	} else {
+		/* NOTE: by sticking to easily tested hardware/driver states,
+		 * we leave counting of in-flight packets imprecise.
+		 */
+		musb_g_giveback(musb_ep, request, -ECONNRESET);
+	}
+
+done:
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return status;
+}
+
+/*
+ * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any
+ * data but will queue requests.
+ *
+ * exported to ep0 code
+ */
+static int musb_gadget_set_halt(struct usb_ep *ep, int value)
+{
+	struct musb_ep		*musb_ep = to_musb_ep(ep);
+	u8			epnum = musb_ep->current_epnum;
+	struct musb		*musb = musb_ep->musb;
+	void __iomem		*epio = musb->endpoints[epnum].regs;
+	void __iomem		*mbase;
+	unsigned long		flags;
+	u16			csr;
+	struct musb_request	*request;
+	int			status = 0;
+
+	if (!ep)
+		return -EINVAL;
+	mbase = musb->mregs;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	if ((USB_ENDPOINT_XFER_ISOC == musb_ep->type)) {
+		status = -EINVAL;
+		goto done;
+	}
+
+	musb_ep_select(mbase, epnum);
+
+	request = next_request(musb_ep);
+	if (value) {
+		if (request) {
+			dev_dbg(musb->controller, "request in progress, cannot halt %s\n",
+			    ep->name);
+			status = -EAGAIN;
+			goto done;
+		}
+		/* Cannot portably stall with non-empty FIFO */
+		if (musb_ep->is_in) {
+			csr = musb_readw(epio, MUSB_TXCSR);
+			if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+				dev_dbg(musb->controller, "FIFO busy, cannot halt %s\n", ep->name);
+				status = -EAGAIN;
+				goto done;
+			}
+		}
+	} else
+		musb_ep->wedged = 0;
+
+	/* set/clear the stall and toggle bits */
+	dev_dbg(musb->controller, "%s: %s stall\n", ep->name, value ? "set" : "clear");
+	if (musb_ep->is_in) {
+		csr = musb_readw(epio, MUSB_TXCSR);
+		csr |= MUSB_TXCSR_P_WZC_BITS
+			| MUSB_TXCSR_CLRDATATOG;
+		if (value)
+			csr |= MUSB_TXCSR_P_SENDSTALL;
+		else
+			csr &= ~(MUSB_TXCSR_P_SENDSTALL
+				| MUSB_TXCSR_P_SENTSTALL);
+		csr &= ~MUSB_TXCSR_TXPKTRDY;
+		musb_writew(epio, MUSB_TXCSR, csr);
+	} else {
+		csr = musb_readw(epio, MUSB_RXCSR);
+		csr |= MUSB_RXCSR_P_WZC_BITS
+			| MUSB_RXCSR_FLUSHFIFO
+			| MUSB_RXCSR_CLRDATATOG;
+		if (value)
+			csr |= MUSB_RXCSR_P_SENDSTALL;
+		else
+			csr &= ~(MUSB_RXCSR_P_SENDSTALL
+				| MUSB_RXCSR_P_SENTSTALL);
+		musb_writew(epio, MUSB_RXCSR, csr);
+	}
+
+	/* maybe start the first request in the queue */
+	if (!musb_ep->busy && !value && request) {
+		dev_dbg(musb->controller, "restarting the request\n");
+		musb_ep_restart(musb, request);
+	}
+
+done:
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return status;
+}
+
+#ifndef __UBOOT__
+/*
+ * Sets the halt feature with the clear requests ignored
+ */
+static int musb_gadget_set_wedge(struct usb_ep *ep)
+{
+	struct musb_ep		*musb_ep = to_musb_ep(ep);
+
+	if (!ep)
+		return -EINVAL;
+
+	musb_ep->wedged = 1;
+
+	return usb_ep_set_halt(ep);
+}
+#endif
+
+static int musb_gadget_fifo_status(struct usb_ep *ep)
+{
+	struct musb_ep		*musb_ep = to_musb_ep(ep);
+	void __iomem		*epio = musb_ep->hw_ep->regs;
+	int			retval = -EINVAL;
+
+	if (musb_ep->desc && !musb_ep->is_in) {
+		struct musb		*musb = musb_ep->musb;
+		int			epnum = musb_ep->current_epnum;
+		void __iomem		*mbase = musb->mregs;
+		unsigned long		flags;
+
+		spin_lock_irqsave(&musb->lock, flags);
+
+		musb_ep_select(mbase, epnum);
+		/* FIXME return zero unless RXPKTRDY is set */
+		retval = musb_readw(epio, MUSB_RXCOUNT);
+
+		spin_unlock_irqrestore(&musb->lock, flags);
+	}
+	return retval;
+}
+
+static void musb_gadget_fifo_flush(struct usb_ep *ep)
+{
+	struct musb_ep	*musb_ep = to_musb_ep(ep);
+	struct musb	*musb = musb_ep->musb;
+	u8		epnum = musb_ep->current_epnum;
+	void __iomem	*epio = musb->endpoints[epnum].regs;
+	void __iomem	*mbase;
+	unsigned long	flags;
+	u16		csr, int_txe;
+
+	mbase = musb->mregs;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	musb_ep_select(mbase, (u8) epnum);
+
+	/* disable interrupts */
+	int_txe = musb_readw(mbase, MUSB_INTRTXE);
+	musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
+
+	if (musb_ep->is_in) {
+		csr = musb_readw(epio, MUSB_TXCSR);
+		if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+			csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_P_WZC_BITS;
+			/*
+			 * Setting both TXPKTRDY and FLUSHFIFO makes controller
+			 * to interrupt current FIFO loading, but not flushing
+			 * the already loaded ones.
+			 */
+			csr &= ~MUSB_TXCSR_TXPKTRDY;
+			musb_writew(epio, MUSB_TXCSR, csr);
+			/* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
+			musb_writew(epio, MUSB_TXCSR, csr);
+		}
+	} else {
+		csr = musb_readw(epio, MUSB_RXCSR);
+		csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS;
+		musb_writew(epio, MUSB_RXCSR, csr);
+		musb_writew(epio, MUSB_RXCSR, csr);
+	}
+
+	/* re-enable interrupt */
+	musb_writew(mbase, MUSB_INTRTXE, int_txe);
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static const struct usb_ep_ops musb_ep_ops = {
+	.enable		= musb_gadget_enable,
+	.disable	= musb_gadget_disable,
+	.alloc_request	= musb_alloc_request,
+	.free_request	= musb_free_request,
+	.queue		= musb_gadget_queue,
+	.dequeue	= musb_gadget_dequeue,
+	.set_halt	= musb_gadget_set_halt,
+#ifndef __UBOOT__
+	.set_wedge	= musb_gadget_set_wedge,
+#endif
+	.fifo_status	= musb_gadget_fifo_status,
+	.fifo_flush	= musb_gadget_fifo_flush
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int musb_gadget_get_frame(struct usb_gadget *gadget)
+{
+	struct musb	*musb = gadget_to_musb(gadget);
+
+	return (int)musb_readw(musb->mregs, MUSB_FRAME);
+}
+
+static int musb_gadget_wakeup(struct usb_gadget *gadget)
+{
+#ifndef __UBOOT__
+	struct musb	*musb = gadget_to_musb(gadget);
+	void __iomem	*mregs = musb->mregs;
+	unsigned long	flags;
+	int		status = -EINVAL;
+	u8		power, devctl;
+	int		retries;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	switch (musb->xceiv->state) {
+	case OTG_STATE_B_PERIPHERAL:
+		/* NOTE:  OTG state machine doesn't include B_SUSPENDED;
+		 * that's part of the standard usb 1.1 state machine, and
+		 * doesn't affect OTG transitions.
+		 */
+		if (musb->may_wakeup && musb->is_suspended)
+			break;
+		goto done;
+	case OTG_STATE_B_IDLE:
+		/* Start SRP ... OTG not required. */
+		devctl = musb_readb(mregs, MUSB_DEVCTL);
+		dev_dbg(musb->controller, "Sending SRP: devctl: %02x\n", devctl);
+		devctl |= MUSB_DEVCTL_SESSION;
+		musb_writeb(mregs, MUSB_DEVCTL, devctl);
+		devctl = musb_readb(mregs, MUSB_DEVCTL);
+		retries = 100;
+		while (!(devctl & MUSB_DEVCTL_SESSION)) {
+			devctl = musb_readb(mregs, MUSB_DEVCTL);
+			if (retries-- < 1)
+				break;
+		}
+		retries = 10000;
+		while (devctl & MUSB_DEVCTL_SESSION) {
+			devctl = musb_readb(mregs, MUSB_DEVCTL);
+			if (retries-- < 1)
+				break;
+		}
+
+		spin_unlock_irqrestore(&musb->lock, flags);
+		otg_start_srp(musb->xceiv->otg);
+		spin_lock_irqsave(&musb->lock, flags);
+
+		/* Block idling for at least 1s */
+		musb_platform_try_idle(musb,
+			jiffies + msecs_to_jiffies(1 * HZ));
+
+		status = 0;
+		goto done;
+	default:
+		dev_dbg(musb->controller, "Unhandled wake: %s\n",
+			otg_state_string(musb->xceiv->state));
+		goto done;
+	}
+
+	status = 0;
+
+	power = musb_readb(mregs, MUSB_POWER);
+	power |= MUSB_POWER_RESUME;
+	musb_writeb(mregs, MUSB_POWER, power);
+	dev_dbg(musb->controller, "issue wakeup\n");
+
+	/* FIXME do this next chunk in a timer callback, no udelay */
+	mdelay(2);
+
+	power = musb_readb(mregs, MUSB_POWER);
+	power &= ~MUSB_POWER_RESUME;
+	musb_writeb(mregs, MUSB_POWER, power);
+done:
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return status;
+#else
+	return 0;
+#endif
+}
+
+static int
+musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
+{
+	struct musb	*musb = gadget_to_musb(gadget);
+
+	musb->is_self_powered = !!is_selfpowered;
+	return 0;
+}
+
+static void musb_pullup(struct musb *musb, int is_on)
+{
+	u8 power;
+
+	power = musb_readb(musb->mregs, MUSB_POWER);
+	if (is_on)
+		power |= MUSB_POWER_SOFTCONN;
+	else
+		power &= ~MUSB_POWER_SOFTCONN;
+
+	/* FIXME if on, HdrcStart; if off, HdrcStop */
+
+	dev_dbg(musb->controller, "gadget D+ pullup %s\n",
+		is_on ? "on" : "off");
+	musb_writeb(musb->mregs, MUSB_POWER, power);
+}
+
+#if 0
+static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	dev_dbg(musb->controller, "<= %s =>\n", __func__);
+
+	/*
+	 * FIXME iff driver's softconnect flag is set (as it is during probe,
+	 * though that can clear it), just musb_pullup().
+	 */
+
+	return -EINVAL;
+}
+#endif
+
+static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+#ifndef __UBOOT__
+	struct musb	*musb = gadget_to_musb(gadget);
+
+	if (!musb->xceiv->set_power)
+		return -EOPNOTSUPP;
+	return usb_phy_set_power(musb->xceiv, mA);
+#else
+	return 0;
+#endif
+}
+
+static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct musb	*musb = gadget_to_musb(gadget);
+	unsigned long	flags;
+
+	is_on = !!is_on;
+
+	pm_runtime_get_sync(musb->controller);
+
+	/* NOTE: this assumes we are sensing vbus; we'd rather
+	 * not pullup unless the B-session is active.
+	 */
+	spin_lock_irqsave(&musb->lock, flags);
+	if (is_on != musb->softconnect) {
+		musb->softconnect = is_on;
+		musb_pullup(musb, is_on);
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	pm_runtime_put(musb->controller);
+
+	return 0;
+}
+
+#ifndef __UBOOT__
+static int musb_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int musb_gadget_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+#else
+static int musb_gadget_stop(struct usb_gadget *g)
+{
+	struct musb	*musb = gadget_to_musb(g);
+
+	musb_stop(musb);
+	return 0;
+}
+#endif
+
+static const struct usb_gadget_ops musb_gadget_operations = {
+	.get_frame		= musb_gadget_get_frame,
+	.wakeup			= musb_gadget_wakeup,
+	.set_selfpowered	= musb_gadget_set_self_powered,
+	/* .vbus_session		= musb_gadget_vbus_session, */
+	.vbus_draw		= musb_gadget_vbus_draw,
+	.pullup			= musb_gadget_pullup,
+#ifndef __UBOOT__
+	.udc_start		= musb_gadget_start,
+	.udc_stop		= musb_gadget_stop,
+#else
+	.udc_start		= musb_gadget_start,
+	.udc_stop		= musb_gadget_stop,
+#endif
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* Registration */
+
+/* Only this registration code "knows" the rule (from USB standards)
+ * about there being only one external upstream port.  It assumes
+ * all peripheral ports are external...
+ */
+
+#ifndef __UBOOT__
+static void musb_gadget_release(struct device *dev)
+{
+	/* kref_put(WHAT) */
+	dev_dbg(dev, "%s\n", __func__);
+}
+#endif
+
+
+static void __devinit
+init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
+{
+	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum;
+
+	memset(ep, 0, sizeof *ep);
+
+	ep->current_epnum = epnum;
+	ep->musb = musb;
+	ep->hw_ep = hw_ep;
+	ep->is_in = is_in;
+
+	INIT_LIST_HEAD(&ep->req_list);
+
+	sprintf(ep->name, "ep%d%s", epnum,
+			(!epnum || hw_ep->is_shared_fifo) ? "" : (
+				is_in ? "in" : "out"));
+	ep->end_point.name = ep->name;
+	INIT_LIST_HEAD(&ep->end_point.ep_list);
+	if (!epnum) {
+		ep->end_point.maxpacket = 64;
+		ep->end_point.ops = &musb_g_ep0_ops;
+		musb->g.ep0 = &ep->end_point;
+	} else {
+		if (is_in)
+			ep->end_point.maxpacket = hw_ep->max_packet_sz_tx;
+		else
+			ep->end_point.maxpacket = hw_ep->max_packet_sz_rx;
+		ep->end_point.ops = &musb_ep_ops;
+		list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);
+	}
+}
+
+/*
+ * Initialize the endpoints exposed to peripheral drivers, with backlinks
+ * to the rest of the driver state.
+ */
+static inline void __devinit musb_g_init_endpoints(struct musb *musb)
+{
+	u8			epnum;
+	struct musb_hw_ep	*hw_ep;
+	unsigned		count = 0;
+
+	/* initialize endpoint list just once */
+	INIT_LIST_HEAD(&(musb->g.ep_list));
+
+	for (epnum = 0, hw_ep = musb->endpoints;
+			epnum < musb->nr_endpoints;
+			epnum++, hw_ep++) {
+		if (hw_ep->is_shared_fifo /* || !epnum */) {
+			init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 0);
+			count++;
+		} else {
+			if (hw_ep->max_packet_sz_tx) {
+				init_peripheral_ep(musb, &hw_ep->ep_in,
+							epnum, 1);
+				count++;
+			}
+			if (hw_ep->max_packet_sz_rx) {
+				init_peripheral_ep(musb, &hw_ep->ep_out,
+							epnum, 0);
+				count++;
+			}
+		}
+	}
+}
+
+/* called once during driver setup to initialize and link into
+ * the driver model; memory is zeroed.
+ */
+int __devinit musb_gadget_setup(struct musb *musb)
+{
+	int status;
+
+	/* REVISIT minor race:  if (erroneously) setting up two
+	 * musb peripherals at the same time, only the bus lock
+	 * is probably held.
+	 */
+
+	musb->g.ops = &musb_gadget_operations;
+#ifndef __UBOOT__
+	musb->g.max_speed = USB_SPEED_HIGH;
+#endif
+	musb->g.speed = USB_SPEED_UNKNOWN;
+
+#ifndef __UBOOT__
+	/* this "gadget" abstracts/virtualizes the controller */
+	dev_set_name(&musb->g.dev, "gadget");
+	musb->g.dev.parent = musb->controller;
+	musb->g.dev.dma_mask = musb->controller->dma_mask;
+	musb->g.dev.release = musb_gadget_release;
+#endif
+	musb->g.name = musb_driver_name;
+
+#ifndef __UBOOT__
+	if (is_otg_enabled(musb))
+		musb->g.is_otg = 1;
+#endif
+
+	musb_g_init_endpoints(musb);
+
+	musb->is_active = 0;
+	musb_platform_try_idle(musb, 0);
+
+#ifndef __UBOOT__
+	status = device_register(&musb->g.dev);
+	if (status != 0) {
+		put_device(&musb->g.dev);
+		return status;
+	}
+	status = usb_add_gadget_udc(musb->controller, &musb->g);
+	if (status)
+		goto err;
+#endif
+
+	return 0;
+#ifndef __UBOOT__
+err:
+	musb->g.dev.parent = NULL;
+	device_unregister(&musb->g.dev);
+	return status;
+#endif
+}
+
+void musb_gadget_cleanup(struct musb *musb)
+{
+#ifndef __UBOOT__
+	usb_del_gadget_udc(&musb->g);
+	if (musb->g.dev.parent)
+		device_unregister(&musb->g.dev);
+#endif
+}
+
+/*
+ * Register the gadget driver. Used by gadget drivers when
+ * registering themselves with the controller.
+ *
+ * -EINVAL something went wrong (not driver)
+ * -EBUSY another gadget is already using the controller
+ * -ENOMEM no memory to perform the operation
+ *
+ * @param driver the gadget driver
+ * @return <0 if error, 0 if everything is fine
+ */
+#ifndef __UBOOT__
+static int musb_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+#else
+int musb_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+#endif
+{
+	struct musb		*musb = gadget_to_musb(g);
+#ifndef __UBOOT__
+	struct usb_otg		*otg = musb->xceiv->otg;
+#endif
+	unsigned long		flags;
+	int			retval = -EINVAL;
+
+#ifndef __UBOOT__
+	if (driver->max_speed < USB_SPEED_HIGH)
+		goto err0;
+#endif
+
+	pm_runtime_get_sync(musb->controller);
+
+#ifndef __UBOOT__
+	dev_dbg(musb->controller, "registering driver %s\n", driver->function);
+#endif
+
+	musb->softconnect = 0;
+	musb->gadget_driver = driver;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	musb->is_active = 1;
+
+#ifndef __UBOOT__
+	otg_set_peripheral(otg, &musb->g);
+	musb->xceiv->state = OTG_STATE_B_IDLE;
+
+	/*
+	 * FIXME this ignores the softconnect flag.  Drivers are
+	 * allowed hold the peripheral inactive until for example
+	 * userspace hooks up printer hardware or DSP codecs, so
+	 * hosts only see fully functional devices.
+	 */
+
+	if (!is_otg_enabled(musb))
+#endif
+		musb_start(musb);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+#ifndef __UBOOT__
+	if (is_otg_enabled(musb)) {
+		struct usb_hcd	*hcd = musb_to_hcd(musb);
+
+		dev_dbg(musb->controller, "OTG startup...\n");
+
+		/* REVISIT:  funcall to other code, which also
+		 * handles power budgeting ... this way also
+		 * ensures HdrcStart is indirectly called.
+		 */
+		retval = usb_add_hcd(musb_to_hcd(musb), 0, 0);
+		if (retval < 0) {
+			dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
+			goto err2;
+		}
+
+		if ((musb->xceiv->last_event == USB_EVENT_ID)
+					&& otg->set_vbus)
+			otg_set_vbus(otg, 1);
+
+		hcd->self.uses_pio_for_control = 1;
+	}
+	if (musb->xceiv->last_event == USB_EVENT_NONE)
+		pm_runtime_put(musb->controller);
+#endif
+
+	return 0;
+
+#ifndef __UBOOT__
+err2:
+	if (!is_otg_enabled(musb))
+		musb_stop(musb);
+err0:
+	return retval;
+#endif
+}
+
+#ifndef __UBOOT__
+static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
+{
+	int			i;
+	struct musb_hw_ep	*hw_ep;
+
+	/* don't disconnect if it's not connected */
+	if (musb->g.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	else
+		musb->g.speed = USB_SPEED_UNKNOWN;
+
+	/* deactivate the hardware */
+	if (musb->softconnect) {
+		musb->softconnect = 0;
+		musb_pullup(musb, 0);
+	}
+	musb_stop(musb);
+
+	/* killing any outstanding requests will quiesce the driver;
+	 * then report disconnect
+	 */
+	if (driver) {
+		for (i = 0, hw_ep = musb->endpoints;
+				i < musb->nr_endpoints;
+				i++, hw_ep++) {
+			musb_ep_select(musb->mregs, i);
+			if (hw_ep->is_shared_fifo /* || !epnum */) {
+				nuke(&hw_ep->ep_in, -ESHUTDOWN);
+			} else {
+				if (hw_ep->max_packet_sz_tx)
+					nuke(&hw_ep->ep_in, -ESHUTDOWN);
+				if (hw_ep->max_packet_sz_rx)
+					nuke(&hw_ep->ep_out, -ESHUTDOWN);
+			}
+		}
+	}
+}
+
+/*
+ * Unregister the gadget driver. Used by gadget drivers when
+ * unregistering themselves from the controller.
+ *
+ * @param driver the gadget driver to unregister
+ */
+static int musb_gadget_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct musb	*musb = gadget_to_musb(g);
+	unsigned long	flags;
+
+	if (musb->xceiv->last_event == USB_EVENT_NONE)
+		pm_runtime_get_sync(musb->controller);
+
+	/*
+	 * REVISIT always use otg_set_peripheral() here too;
+	 * this needs to shut down the OTG engine.
+	 */
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	musb_hnp_stop(musb);
+
+	(void) musb_gadget_vbus_draw(&musb->g, 0);
+
+	musb->xceiv->state = OTG_STATE_UNDEFINED;
+	stop_activity(musb, driver);
+	otg_set_peripheral(musb->xceiv->otg, NULL);
+
+	dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
+
+	musb->is_active = 0;
+	musb_platform_try_idle(musb, 0);
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	if (is_otg_enabled(musb)) {
+		usb_remove_hcd(musb_to_hcd(musb));
+		/* FIXME we need to be able to register another
+		 * gadget driver here and have everything work;
+		 * that currently misbehaves.
+		 */
+	}
+
+	if (!is_otg_enabled(musb))
+		musb_stop(musb);
+
+	pm_runtime_put(musb->controller);
+
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+/* lifecycle operations called through plat_uds.c */
+
+void musb_g_resume(struct musb *musb)
+{
+#ifndef __UBOOT__
+	musb->is_suspended = 0;
+	switch (musb->xceiv->state) {
+	case OTG_STATE_B_IDLE:
+		break;
+	case OTG_STATE_B_WAIT_ACON:
+	case OTG_STATE_B_PERIPHERAL:
+		musb->is_active = 1;
+		if (musb->gadget_driver && musb->gadget_driver->resume) {
+			spin_unlock(&musb->lock);
+			musb->gadget_driver->resume(&musb->g);
+			spin_lock(&musb->lock);
+		}
+		break;
+	default:
+		WARNING("unhandled RESUME transition (%s)\n",
+				otg_state_string(musb->xceiv->state));
+	}
+#endif
+}
+
+/* called when SOF packets stop for 3+ msec */
+void musb_g_suspend(struct musb *musb)
+{
+#ifndef __UBOOT__
+	u8	devctl;
+
+	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+	dev_dbg(musb->controller, "devctl %02x\n", devctl);
+
+	switch (musb->xceiv->state) {
+	case OTG_STATE_B_IDLE:
+		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+			musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		musb->is_suspended = 1;
+		if (musb->gadget_driver && musb->gadget_driver->suspend) {
+			spin_unlock(&musb->lock);
+			musb->gadget_driver->suspend(&musb->g);
+			spin_lock(&musb->lock);
+		}
+		break;
+	default:
+		/* REVISIT if B_HOST, clear DEVCTL.HOSTREQ;
+		 * A_PERIPHERAL may need care too
+		 */
+		WARNING("unhandled SUSPEND transition (%s)\n",
+				otg_state_string(musb->xceiv->state));
+	}
+#endif
+}
+
+/* Called during SRP */
+void musb_g_wakeup(struct musb *musb)
+{
+	musb_gadget_wakeup(&musb->g);
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void musb_g_disconnect(struct musb *musb)
+{
+	void __iomem	*mregs = musb->mregs;
+	u8	devctl = musb_readb(mregs, MUSB_DEVCTL);
+
+	dev_dbg(musb->controller, "devctl %02x\n", devctl);
+
+	/* clear HR */
+	musb_writeb(mregs, MUSB_DEVCTL, devctl & MUSB_DEVCTL_SESSION);
+
+	/* don't draw vbus until new b-default session */
+	(void) musb_gadget_vbus_draw(&musb->g, 0);
+
+	musb->g.speed = USB_SPEED_UNKNOWN;
+	if (musb->gadget_driver && musb->gadget_driver->disconnect) {
+		spin_unlock(&musb->lock);
+		musb->gadget_driver->disconnect(&musb->g);
+		spin_lock(&musb->lock);
+	}
+
+#ifndef __UBOOT__
+	switch (musb->xceiv->state) {
+	default:
+		dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
+			otg_state_string(musb->xceiv->state));
+		musb->xceiv->state = OTG_STATE_A_IDLE;
+		MUSB_HST_MODE(musb);
+		break;
+	case OTG_STATE_A_PERIPHERAL:
+		musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+		MUSB_HST_MODE(musb);
+		break;
+	case OTG_STATE_B_WAIT_ACON:
+	case OTG_STATE_B_HOST:
+	case OTG_STATE_B_PERIPHERAL:
+	case OTG_STATE_B_IDLE:
+		musb->xceiv->state = OTG_STATE_B_IDLE;
+		break;
+	case OTG_STATE_B_SRP_INIT:
+		break;
+	}
+#endif
+
+	musb->is_active = 0;
+}
+
+void musb_g_reset(struct musb *musb)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+	void __iomem	*mbase = musb->mregs;
+	u8		devctl = musb_readb(mbase, MUSB_DEVCTL);
+	u8		power;
+
+#ifndef __UBOOT__
+	dev_dbg(musb->controller, "<== %s addr=%x driver '%s'\n",
+			(devctl & MUSB_DEVCTL_BDEVICE)
+				? "B-Device" : "A-Device",
+			musb_readb(mbase, MUSB_FADDR),
+			musb->gadget_driver
+				? musb->gadget_driver->driver.name
+				: NULL
+			);
+#endif
+
+	/* report disconnect, if we didn't already (flushing EP state) */
+	if (musb->g.speed != USB_SPEED_UNKNOWN)
+		musb_g_disconnect(musb);
+
+	/* clear HR */
+	else if (devctl & MUSB_DEVCTL_HR)
+		musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+
+
+	/* what speed did we negotiate? */
+	power = musb_readb(mbase, MUSB_POWER);
+	musb->g.speed = (power & MUSB_POWER_HSMODE)
+			? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+	/* start in USB_STATE_DEFAULT */
+	musb->is_active = 1;
+	musb->is_suspended = 0;
+	MUSB_DEV_MODE(musb);
+	musb->address = 0;
+	musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+
+	musb->may_wakeup = 0;
+	musb->g.b_hnp_enable = 0;
+	musb->g.a_alt_hnp_support = 0;
+	musb->g.a_hnp_support = 0;
+
+#ifndef __UBOOT__
+	/* Normal reset, as B-Device;
+	 * or else after HNP, as A-Device
+	 */
+	if (devctl & MUSB_DEVCTL_BDEVICE) {
+		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+		musb->g.is_a_peripheral = 0;
+	} else if (is_otg_enabled(musb)) {
+		musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+		musb->g.is_a_peripheral = 1;
+	} else
+		WARN_ON(1);
+
+	/* start with default limits on VBUS power draw */
+	(void) musb_gadget_vbus_draw(&musb->g,
+			is_otg_enabled(musb) ? 8 : 100);
+#endif
+}
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_gadget.h b/roms/u-boot/drivers/usb/musb-new/musb_gadget.h
new file mode 100644
index 000000000..7cb7a5cd6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_gadget.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver peripheral defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+#ifndef __MUSB_GADGET_H
+#define __MUSB_GADGET_H
+
+#include <linux/list.h>
+#ifdef __UBOOT__
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#endif
+
+enum buffer_map_state {
+	UN_MAPPED = 0,
+	PRE_MAPPED,
+	MUSB_MAPPED
+};
+
+struct musb_request {
+	struct usb_request	request;
+	struct list_head	list;
+	struct musb_ep		*ep;
+	struct musb		*musb;
+	u8 tx;			/* endpoint direction */
+	u8 epnum;
+	enum buffer_map_state map_state;
+};
+
+static inline struct musb_request *to_musb_request(struct usb_request *req)
+{
+	return req ? container_of(req, struct musb_request, request) : NULL;
+}
+
+extern struct usb_request *
+musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
+
+
+/*
+ * struct musb_ep - peripheral side view of endpoint rx or tx side
+ */
+struct musb_ep {
+	/* stuff towards the head is basically write-once. */
+	struct usb_ep			end_point;
+	char				name[12];
+	struct musb_hw_ep		*hw_ep;
+	struct musb			*musb;
+	u8				current_epnum;
+
+	/* ... when enabled/disabled ... */
+	u8				type;
+	u8				is_in;
+	u16				packet_sz;
+	const struct usb_endpoint_descriptor	*desc;
+	struct dma_channel		*dma;
+
+	/* later things are modified based on usage */
+	struct list_head		req_list;
+
+	u8				wedged;
+
+	/* true if lock must be dropped but req_list may not be advanced */
+	u8				busy;
+
+	u8				hb_mult;
+};
+
+static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
+{
+	return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
+}
+
+static inline struct musb_request *next_request(struct musb_ep *ep)
+{
+	struct list_head	*queue = &ep->req_list;
+
+	if (list_empty(queue))
+		return NULL;
+	return container_of(queue->next, struct musb_request, list);
+}
+
+extern void musb_g_tx(struct musb *musb, u8 epnum);
+extern void musb_g_rx(struct musb *musb, u8 epnum);
+
+extern const struct usb_ep_ops musb_g_ep0_ops;
+
+extern int musb_gadget_setup(struct musb *);
+extern void musb_gadget_cleanup(struct musb *);
+
+extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
+
+extern void musb_ep_restart(struct musb *, struct musb_request *);
+
+#ifdef __UBOOT__
+int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver);
+#endif
+#endif		/* __MUSB_GADGET_H */
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_gadget_ep0.c b/roms/u-boot/drivers/usb/musb-new/musb_gadget_ep0.c
new file mode 100644
index 000000000..cbd92fca6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -0,0 +1,1068 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MUSB OTG peripheral driver ep0 handling
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+ */
+
+#ifndef __UBOOT__
+#include <log.h>
+#include <dm/device_compat.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#else
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <asm/processor.h>
+#include "linux-compat.h"
+#endif
+
+#include "musb_core.h"
+
+/* ep0 is always musb->endpoints[0].ep_in */
+#define	next_ep0_request(musb)	next_in_request(&(musb)->endpoints[0])
+
+/*
+ * locking note:  we use only the controller lock, for simpler correctness.
+ * It's always held with IRQs blocked.
+ *
+ * It protects the ep0 request queue as well as ep0_state, not just the
+ * controller and indexed registers.  And that lock stays held unless it
+ * needs to be dropped to allow reentering this driver ... like upcalls to
+ * the gadget driver, or adjusting endpoint halt status.
+ */
+
+static char *decode_ep0stage(u8 stage)
+{
+	switch (stage) {
+	case MUSB_EP0_STAGE_IDLE:	return "idle";
+	case MUSB_EP0_STAGE_SETUP:	return "setup";
+	case MUSB_EP0_STAGE_TX:		return "in";
+	case MUSB_EP0_STAGE_RX:		return "out";
+	case MUSB_EP0_STAGE_ACKWAIT:	return "wait";
+	case MUSB_EP0_STAGE_STATUSIN:	return "in/status";
+	case MUSB_EP0_STAGE_STATUSOUT:	return "out/status";
+	default:			return "?";
+	}
+}
+
+/* handle a standard GET_STATUS request
+ * Context:  caller holds controller lock
+ */
+static int service_tx_status_request(
+	struct musb *musb,
+	const struct usb_ctrlrequest *ctrlrequest)
+{
+	void __iomem	*mbase = musb->mregs;
+	int handled = 1;
+	u8 result[2], epnum = 0;
+	const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK;
+
+	result[1] = 0;
+
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
+		result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+		if (musb->g.is_otg) {
+			result[0] |= musb->g.b_hnp_enable
+				<< USB_DEVICE_B_HNP_ENABLE;
+			result[0] |= musb->g.a_alt_hnp_support
+				<< USB_DEVICE_A_ALT_HNP_SUPPORT;
+			result[0] |= musb->g.a_hnp_support
+				<< USB_DEVICE_A_HNP_SUPPORT;
+		}
+		break;
+
+	case USB_RECIP_INTERFACE:
+		result[0] = 0;
+		break;
+
+	case USB_RECIP_ENDPOINT: {
+		int		is_in;
+		struct musb_ep	*ep;
+		u16		tmp;
+		void __iomem	*regs;
+
+		epnum = (u8) ctrlrequest->wIndex;
+		if (!epnum) {
+			result[0] = 0;
+			break;
+		}
+
+		is_in = epnum & USB_DIR_IN;
+		if (is_in) {
+			epnum &= 0x0f;
+			ep = &musb->endpoints[epnum].ep_in;
+		} else {
+			ep = &musb->endpoints[epnum].ep_out;
+		}
+		regs = musb->endpoints[epnum].regs;
+
+		if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+			handled = -EINVAL;
+			break;
+		}
+
+		musb_ep_select(mbase, epnum);
+		if (is_in)
+			tmp = musb_readw(regs, MUSB_TXCSR)
+						& MUSB_TXCSR_P_SENDSTALL;
+		else
+			tmp = musb_readw(regs, MUSB_RXCSR)
+						& MUSB_RXCSR_P_SENDSTALL;
+		musb_ep_select(mbase, 0);
+
+		result[0] = tmp ? 1 : 0;
+		} break;
+
+	default:
+		/* class, vendor, etc ... delegate */
+		handled = 0;
+		break;
+	}
+
+	/* fill up the fifo; caller updates csr0 */
+	if (handled > 0) {
+		u16	len = le16_to_cpu(ctrlrequest->wLength);
+
+		if (len > 2)
+			len = 2;
+		musb_write_fifo(&musb->endpoints[0], len, result);
+	}
+
+	return handled;
+}
+
+/*
+ * handle a control-IN request, the end0 buffer contains the current request
+ * that is supposed to be a standard control request. Assumes the fifo to
+ * be at least 2 bytes long.
+ *
+ * @return 0 if the request was NOT HANDLED,
+ * < 0 when error
+ * > 0 when the request is processed
+ *
+ * Context:  caller holds controller lock
+ */
+static int
+service_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
+{
+	int handled = 0;	/* not handled */
+
+	if ((ctrlrequest->bRequestType & USB_TYPE_MASK)
+			== USB_TYPE_STANDARD) {
+		switch (ctrlrequest->bRequest) {
+		case USB_REQ_GET_STATUS:
+			handled = service_tx_status_request(musb,
+					ctrlrequest);
+			break;
+
+		/* case USB_REQ_SYNC_FRAME: */
+
+		default:
+			break;
+		}
+	}
+	return handled;
+}
+
+/*
+ * Context:  caller holds controller lock
+ */
+static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req)
+{
+	musb_g_giveback(&musb->endpoints[0].ep_in, req, 0);
+}
+
+/*
+ * Tries to start B-device HNP negotiation if enabled via sysfs
+ */
+static inline void musb_try_b_hnp_enable(struct musb *musb)
+{
+	void __iomem	*mbase = musb->mregs;
+	u8		devctl;
+
+	dev_dbg(musb->controller, "HNP: Setting HR\n");
+	devctl = musb_readb(mbase, MUSB_DEVCTL);
+	musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR);
+}
+
+/*
+ * Handle all control requests with no DATA stage, including standard
+ * requests such as:
+ * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized
+ *	always delegated to the gadget driver
+ * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE
+ *	always handled here, except for class/vendor/... features
+ *
+ * Context:  caller holds controller lock
+ */
+static int
+service_zero_data_request(struct musb *musb,
+		struct usb_ctrlrequest *ctrlrequest)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+	int handled = -EINVAL;
+	void __iomem *mbase = musb->mregs;
+	const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK;
+
+	/* the gadget driver handles everything except what we MUST handle */
+	if ((ctrlrequest->bRequestType & USB_TYPE_MASK)
+			== USB_TYPE_STANDARD) {
+		switch (ctrlrequest->bRequest) {
+		case USB_REQ_SET_ADDRESS:
+			/* change it after the status stage */
+			musb->set_address = true;
+			musb->address = (u8) (ctrlrequest->wValue & 0x7f);
+			handled = 1;
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			switch (recip) {
+			case USB_RECIP_DEVICE:
+				if (ctrlrequest->wValue
+						!= USB_DEVICE_REMOTE_WAKEUP)
+					break;
+				musb->may_wakeup = 0;
+				handled = 1;
+				break;
+			case USB_RECIP_INTERFACE:
+				break;
+			case USB_RECIP_ENDPOINT:{
+				const u8		epnum =
+					ctrlrequest->wIndex & 0x0f;
+				struct musb_ep		*musb_ep;
+				struct musb_hw_ep	*ep;
+				struct musb_request	*request;
+				void __iomem		*regs;
+				int			is_in;
+				u16			csr;
+
+				if (epnum == 0 || epnum >= MUSB_C_NUM_EPS ||
+				    ctrlrequest->wValue != USB_ENDPOINT_HALT)
+					break;
+
+				ep = musb->endpoints + epnum;
+				regs = ep->regs;
+				is_in = ctrlrequest->wIndex & USB_DIR_IN;
+				if (is_in)
+					musb_ep = &ep->ep_in;
+				else
+					musb_ep = &ep->ep_out;
+				if (!musb_ep->desc)
+					break;
+
+				handled = 1;
+				/* Ignore request if endpoint is wedged */
+				if (musb_ep->wedged)
+					break;
+
+				musb_ep_select(mbase, epnum);
+				if (is_in) {
+					csr  = musb_readw(regs, MUSB_TXCSR);
+					csr |= MUSB_TXCSR_CLRDATATOG |
+					       MUSB_TXCSR_P_WZC_BITS;
+					csr &= ~(MUSB_TXCSR_P_SENDSTALL |
+						 MUSB_TXCSR_P_SENTSTALL |
+						 MUSB_TXCSR_TXPKTRDY);
+					musb_writew(regs, MUSB_TXCSR, csr);
+				} else {
+					csr  = musb_readw(regs, MUSB_RXCSR);
+					csr |= MUSB_RXCSR_CLRDATATOG |
+					       MUSB_RXCSR_P_WZC_BITS;
+					csr &= ~(MUSB_RXCSR_P_SENDSTALL |
+						 MUSB_RXCSR_P_SENTSTALL);
+					musb_writew(regs, MUSB_RXCSR, csr);
+				}
+
+				/* Maybe start the first request in the queue */
+				request = next_request(musb_ep);
+				if (!musb_ep->busy && request) {
+					dev_dbg(musb->controller, "restarting the request\n");
+					musb_ep_restart(musb, request);
+				}
+
+				/* select ep0 again */
+				musb_ep_select(mbase, 0);
+				} break;
+			default:
+				/* class, vendor, etc ... delegate */
+				handled = 0;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			switch (recip) {
+			case USB_RECIP_DEVICE:
+				handled = 1;
+				switch (ctrlrequest->wValue) {
+				case USB_DEVICE_REMOTE_WAKEUP:
+					musb->may_wakeup = 1;
+					break;
+				case USB_DEVICE_TEST_MODE:
+					if (musb->g.speed != USB_SPEED_HIGH)
+						goto stall;
+					if (ctrlrequest->wIndex & 0xff)
+						goto stall;
+
+					switch (ctrlrequest->wIndex >> 8) {
+					case 1:
+						pr_debug("TEST_J\n");
+						/* TEST_J */
+						musb->test_mode_nr =
+							MUSB_TEST_J;
+						break;
+					case 2:
+						/* TEST_K */
+						pr_debug("TEST_K\n");
+						musb->test_mode_nr =
+							MUSB_TEST_K;
+						break;
+					case 3:
+						/* TEST_SE0_NAK */
+						pr_debug("TEST_SE0_NAK\n");
+						musb->test_mode_nr =
+							MUSB_TEST_SE0_NAK;
+						break;
+					case 4:
+						/* TEST_PACKET */
+						pr_debug("TEST_PACKET\n");
+						musb->test_mode_nr =
+							MUSB_TEST_PACKET;
+						break;
+
+					case 0xc0:
+						/* TEST_FORCE_HS */
+						pr_debug("TEST_FORCE_HS\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FORCE_HS;
+						break;
+					case 0xc1:
+						/* TEST_FORCE_FS */
+						pr_debug("TEST_FORCE_FS\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FORCE_FS;
+						break;
+					case 0xc2:
+						/* TEST_FIFO_ACCESS */
+						pr_debug("TEST_FIFO_ACCESS\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FIFO_ACCESS;
+						break;
+					case 0xc3:
+						/* TEST_FORCE_HOST */
+						pr_debug("TEST_FORCE_HOST\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FORCE_HOST;
+						break;
+					default:
+						goto stall;
+					}
+
+					/* enter test mode after irq */
+					if (handled > 0)
+						musb->test_mode = true;
+					break;
+				case USB_DEVICE_B_HNP_ENABLE:
+					if (!musb->g.is_otg)
+						goto stall;
+					musb->g.b_hnp_enable = 1;
+					musb_try_b_hnp_enable(musb);
+					break;
+				case USB_DEVICE_A_HNP_SUPPORT:
+					if (!musb->g.is_otg)
+						goto stall;
+					musb->g.a_hnp_support = 1;
+					break;
+				case USB_DEVICE_A_ALT_HNP_SUPPORT:
+					if (!musb->g.is_otg)
+						goto stall;
+					musb->g.a_alt_hnp_support = 1;
+					break;
+				case USB_DEVICE_DEBUG_MODE:
+					handled = 0;
+					break;
+stall:
+				default:
+					handled = -EINVAL;
+					break;
+				}
+				break;
+
+			case USB_RECIP_INTERFACE:
+				break;
+
+			case USB_RECIP_ENDPOINT:{
+				const u8		epnum =
+					ctrlrequest->wIndex & 0x0f;
+				struct musb_ep		*musb_ep;
+				struct musb_hw_ep	*ep;
+				void __iomem		*regs;
+				int			is_in;
+				u16			csr;
+
+				if (epnum == 0 || epnum >= MUSB_C_NUM_EPS ||
+				    ctrlrequest->wValue	!= USB_ENDPOINT_HALT)
+					break;
+
+				ep = musb->endpoints + epnum;
+				regs = ep->regs;
+				is_in = ctrlrequest->wIndex & USB_DIR_IN;
+				if (is_in)
+					musb_ep = &ep->ep_in;
+				else
+					musb_ep = &ep->ep_out;
+				if (!musb_ep->desc)
+					break;
+
+				musb_ep_select(mbase, epnum);
+				if (is_in) {
+					csr = musb_readw(regs, MUSB_TXCSR);
+					if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+						csr |= MUSB_TXCSR_FLUSHFIFO;
+					csr |= MUSB_TXCSR_P_SENDSTALL
+						| MUSB_TXCSR_CLRDATATOG
+						| MUSB_TXCSR_P_WZC_BITS;
+					musb_writew(regs, MUSB_TXCSR, csr);
+				} else {
+					csr = musb_readw(regs, MUSB_RXCSR);
+					csr |= MUSB_RXCSR_P_SENDSTALL
+						| MUSB_RXCSR_FLUSHFIFO
+						| MUSB_RXCSR_CLRDATATOG
+						| MUSB_RXCSR_P_WZC_BITS;
+					musb_writew(regs, MUSB_RXCSR, csr);
+				}
+
+				/* select ep0 again */
+				musb_ep_select(mbase, 0);
+				handled = 1;
+				} break;
+
+			default:
+				/* class, vendor, etc ... delegate */
+				handled = 0;
+				break;
+			}
+			break;
+		default:
+			/* delegate SET_CONFIGURATION, etc */
+			handled = 0;
+		}
+	} else
+		handled = 0;
+	return handled;
+}
+
+/* we have an ep0out data packet
+ * Context:  caller holds controller lock
+ */
+static void ep0_rxstate(struct musb *musb)
+{
+	void __iomem		*regs = musb->control_ep->regs;
+	struct musb_request	*request;
+	struct usb_request	*req;
+	u16			count, csr;
+
+	request = next_ep0_request(musb);
+	req = &request->request;
+
+	/* read packet and ack; or stall because of gadget driver bug:
+	 * should have provided the rx buffer before setup() returned.
+	 */
+	if (req) {
+		void		*buf = req->buf + req->actual;
+		unsigned	len = req->length - req->actual;
+
+		/* read the buffer */
+		count = musb_readb(regs, MUSB_COUNT0);
+		if (count > len) {
+			req->status = -EOVERFLOW;
+			count = len;
+		}
+		musb_read_fifo(&musb->endpoints[0], count, buf);
+		req->actual += count;
+		csr = MUSB_CSR0_P_SVDRXPKTRDY;
+		if (count < 64 || req->actual == req->length) {
+			musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
+			csr |= MUSB_CSR0_P_DATAEND;
+		} else
+			req = NULL;
+	} else
+		csr = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL;
+
+
+	/* Completion handler may choose to stall, e.g. because the
+	 * message just received holds invalid data.
+	 */
+	if (req) {
+		musb->ackpend = csr;
+		musb_g_ep0_giveback(musb, req);
+		if (!musb->ackpend)
+			return;
+		musb->ackpend = 0;
+	}
+	musb_ep_select(musb->mregs, 0);
+	musb_writew(regs, MUSB_CSR0, csr);
+}
+
+/*
+ * transmitting to the host (IN), this code might be called from IRQ
+ * and from kernel thread.
+ *
+ * Context:  caller holds controller lock
+ */
+static void ep0_txstate(struct musb *musb)
+{
+	void __iomem		*regs = musb->control_ep->regs;
+	struct musb_request	*req = next_ep0_request(musb);
+	struct usb_request	*request;
+	u16			csr = MUSB_CSR0_TXPKTRDY;
+	u8			*fifo_src;
+	u8			fifo_count;
+
+	if (!req) {
+		/* WARN_ON(1); */
+		dev_dbg(musb->controller, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0));
+		return;
+	}
+
+	request = &req->request;
+
+	/* load the data */
+	fifo_src = (u8 *) request->buf + request->actual;
+	fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE,
+		request->length - request->actual);
+	musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src);
+	request->actual += fifo_count;
+
+	/* update the flags */
+	if (fifo_count < MUSB_MAX_END0_PACKET
+			|| (request->actual == request->length
+				&& !request->zero)) {
+		musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
+		csr |= MUSB_CSR0_P_DATAEND;
+	} else
+		request = NULL;
+
+	/* send it out, triggering a "txpktrdy cleared" irq */
+	musb_ep_select(musb->mregs, 0);
+	musb_writew(regs, MUSB_CSR0, csr);
+
+	/* report completions as soon as the fifo's loaded; there's no
+	 * win in waiting till this last packet gets acked.  (other than
+	 * very precise fault reporting, needed by USB TMC; possible with
+	 * this hardware, but not usable from portable gadget drivers.)
+	 */
+	if (request) {
+		musb->ackpend = csr;
+		musb_g_ep0_giveback(musb, request);
+		if (!musb->ackpend)
+			return;
+		musb->ackpend = 0;
+	}
+}
+
+/*
+ * Read a SETUP packet (struct usb_ctrlrequest) from the hardware.
+ * Fields are left in USB byte-order.
+ *
+ * Context:  caller holds controller lock.
+ */
+static void
+musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)
+{
+	struct musb_request	*r;
+	void __iomem		*regs = musb->control_ep->regs;
+
+	musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req);
+
+	/* NOTE:  earlier 2.6 versions changed setup packets to host
+	 * order, but now USB packets always stay in USB byte order.
+	 */
+	dev_dbg(musb->controller, "SETUP req%02x.%02x v%04x i%04x l%d\n",
+		req->bRequestType,
+		req->bRequest,
+		le16_to_cpu(req->wValue),
+		le16_to_cpu(req->wIndex),
+		le16_to_cpu(req->wLength));
+
+	/* clean up any leftover transfers */
+	r = next_ep0_request(musb);
+	if (r)
+		musb_g_ep0_giveback(musb, &r->request);
+
+	/* For zero-data requests we want to delay the STATUS stage to
+	 * avoid SETUPEND errors.  If we read data (OUT), delay accepting
+	 * packets until there's a buffer to store them in.
+	 *
+	 * If we write data, the controller acts happier if we enable
+	 * the TX FIFO right away, and give the controller a moment
+	 * to switch modes...
+	 */
+	musb->set_address = false;
+	musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY;
+	if (req->wLength == 0) {
+		if (req->bRequestType & USB_DIR_IN)
+			musb->ackpend |= MUSB_CSR0_TXPKTRDY;
+		musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT;
+	} else if (req->bRequestType & USB_DIR_IN) {
+		musb->ep0_state = MUSB_EP0_STAGE_TX;
+		musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY);
+		while ((musb_readw(regs, MUSB_CSR0)
+				& MUSB_CSR0_RXPKTRDY) != 0)
+			cpu_relax();
+		musb->ackpend = 0;
+	} else
+		musb->ep0_state = MUSB_EP0_STAGE_RX;
+}
+
+static int
+forward_to_driver(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+	int retval;
+	if (!musb->gadget_driver)
+		return -EOPNOTSUPP;
+	spin_unlock(&musb->lock);
+	retval = musb->gadget_driver->setup(&musb->g, ctrlrequest);
+	spin_lock(&musb->lock);
+	return retval;
+}
+
+/*
+ * Handle peripheral ep0 interrupt
+ *
+ * Context: irq handler; we won't re-enter the driver that way.
+ */
+irqreturn_t musb_g_ep0_irq(struct musb *musb)
+{
+	u16		csr;
+	u16		len;
+	void __iomem	*mbase = musb->mregs;
+	void __iomem	*regs = musb->endpoints[0].regs;
+	irqreturn_t	retval = IRQ_NONE;
+
+	musb_ep_select(mbase, 0);	/* select ep0 */
+	csr = musb_readw(regs, MUSB_CSR0);
+	len = musb_readb(regs, MUSB_COUNT0);
+
+	dev_dbg(musb->controller, "csr %04x, count %d, myaddr %d, ep0stage %s\n",
+			csr, len,
+			musb_readb(mbase, MUSB_FADDR),
+			decode_ep0stage(musb->ep0_state));
+
+	if (csr & MUSB_CSR0_P_DATAEND) {
+		/*
+		 * If DATAEND is set we should not call the callback,
+		 * hence the status stage is not complete.
+		 */
+		return IRQ_HANDLED;
+	}
+
+	/* I sent a stall.. need to acknowledge it now.. */
+	if (csr & MUSB_CSR0_P_SENTSTALL) {
+		musb_writew(regs, MUSB_CSR0,
+				csr & ~MUSB_CSR0_P_SENTSTALL);
+		retval = IRQ_HANDLED;
+		musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+		csr = musb_readw(regs, MUSB_CSR0);
+	}
+
+	/* request ended "early" */
+	if (csr & MUSB_CSR0_P_SETUPEND) {
+		musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
+		retval = IRQ_HANDLED;
+		/* Transition into the early status phase */
+		switch (musb->ep0_state) {
+		case MUSB_EP0_STAGE_TX:
+			musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
+			break;
+		case MUSB_EP0_STAGE_RX:
+			musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
+			break;
+		default:
+			ERR("SetupEnd came in a wrong ep0stage %s\n",
+			    decode_ep0stage(musb->ep0_state));
+		}
+		csr = musb_readw(regs, MUSB_CSR0);
+		/* NOTE:  request may need completion */
+	}
+
+	/* docs from Mentor only describe tx, rx, and idle/setup states.
+	 * we need to handle nuances around status stages, and also the
+	 * case where status and setup stages come back-to-back ...
+	 */
+	switch (musb->ep0_state) {
+
+	case MUSB_EP0_STAGE_TX:
+		/* irq on clearing txpktrdy */
+		if ((csr & MUSB_CSR0_TXPKTRDY) == 0) {
+			ep0_txstate(musb);
+			retval = IRQ_HANDLED;
+		}
+		break;
+
+	case MUSB_EP0_STAGE_RX:
+		/* irq on set rxpktrdy */
+		if (csr & MUSB_CSR0_RXPKTRDY) {
+			ep0_rxstate(musb);
+			retval = IRQ_HANDLED;
+		}
+		break;
+
+	case MUSB_EP0_STAGE_STATUSIN:
+		/* end of sequence #2 (OUT/RX state) or #3 (no data) */
+
+		/* update address (if needed) only @ the end of the
+		 * status phase per usb spec, which also guarantees
+		 * we get 10 msec to receive this irq... until this
+		 * is done we won't see the next packet.
+		 */
+		if (musb->set_address) {
+			musb->set_address = false;
+			musb_writeb(mbase, MUSB_FADDR, musb->address);
+		}
+
+		/* enter test mode if needed (exit by reset) */
+		else if (musb->test_mode) {
+			dev_dbg(musb->controller, "entering TESTMODE\n");
+
+			if (MUSB_TEST_PACKET == musb->test_mode_nr)
+				musb_load_testpacket(musb);
+
+			musb_writeb(mbase, MUSB_TESTMODE,
+					musb->test_mode_nr);
+		}
+		/* FALLTHROUGH */
+
+	case MUSB_EP0_STAGE_STATUSOUT:
+		/* end of sequence #1: write to host (TX state) */
+		{
+			struct musb_request	*req;
+
+			req = next_ep0_request(musb);
+			if (req)
+				musb_g_ep0_giveback(musb, &req->request);
+		}
+
+		/*
+		 * In case when several interrupts can get coalesced,
+		 * check to see if we've already received a SETUP packet...
+		 */
+		if (csr & MUSB_CSR0_RXPKTRDY)
+			goto setup;
+
+		retval = IRQ_HANDLED;
+		musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+		break;
+
+	case MUSB_EP0_STAGE_IDLE:
+		/*
+		 * This state is typically (but not always) indiscernible
+		 * from the status states since the corresponding interrupts
+		 * tend to happen within too little period of time (with only
+		 * a zero-length packet in between) and so get coalesced...
+		 */
+		retval = IRQ_HANDLED;
+		musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+		/* FALLTHROUGH */
+
+	case MUSB_EP0_STAGE_SETUP:
+setup:
+		if (csr & MUSB_CSR0_RXPKTRDY) {
+			struct usb_ctrlrequest	setup;
+			int			handled = 0;
+
+			if (len != 8) {
+				ERR("SETUP packet len %d != 8 ?\n", len);
+				break;
+			}
+			musb_read_setup(musb, &setup);
+			retval = IRQ_HANDLED;
+
+			/* sometimes the RESET won't be reported */
+			if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) {
+				u8	power;
+
+				printk(KERN_NOTICE "%s: peripheral reset "
+						"irq lost!\n",
+						musb_driver_name);
+				power = musb_readb(mbase, MUSB_POWER);
+				musb->g.speed = (power & MUSB_POWER_HSMODE)
+					? USB_SPEED_HIGH : USB_SPEED_FULL;
+
+			}
+
+			switch (musb->ep0_state) {
+
+			/* sequence #3 (no data stage), includes requests
+			 * we can't forward (notably SET_ADDRESS and the
+			 * device/endpoint feature set/clear operations)
+			 * plus SET_CONFIGURATION and others we must
+			 */
+			case MUSB_EP0_STAGE_ACKWAIT:
+				handled = service_zero_data_request(
+						musb, &setup);
+
+				/*
+				 * We're expecting no data in any case, so
+				 * always set the DATAEND bit -- doing this
+				 * here helps avoid SetupEnd interrupt coming
+				 * in the idle stage when we're stalling...
+				 */
+				musb->ackpend |= MUSB_CSR0_P_DATAEND;
+
+				/* status stage might be immediate */
+				if (handled > 0)
+					musb->ep0_state =
+						MUSB_EP0_STAGE_STATUSIN;
+				break;
+
+			/* sequence #1 (IN to host), includes GET_STATUS
+			 * requests that we can't forward, GET_DESCRIPTOR
+			 * and others that we must
+			 */
+			case MUSB_EP0_STAGE_TX:
+				handled = service_in_request(musb, &setup);
+				if (handled > 0) {
+					musb->ackpend = MUSB_CSR0_TXPKTRDY
+						| MUSB_CSR0_P_DATAEND;
+					musb->ep0_state =
+						MUSB_EP0_STAGE_STATUSOUT;
+				}
+				break;
+
+			/* sequence #2 (OUT from host), always forward */
+			default:		/* MUSB_EP0_STAGE_RX */
+				break;
+			}
+
+			dev_dbg(musb->controller, "handled %d, csr %04x, ep0stage %s\n",
+				handled, csr,
+				decode_ep0stage(musb->ep0_state));
+
+			/* unless we need to delegate this to the gadget
+			 * driver, we know how to wrap this up:  csr0 has
+			 * not yet been written.
+			 */
+			if (handled < 0)
+				goto stall;
+			else if (handled > 0)
+				goto finish;
+
+			handled = forward_to_driver(musb, &setup);
+			if (handled < 0) {
+				musb_ep_select(mbase, 0);
+stall:
+				dev_dbg(musb->controller, "stall (%d)\n", handled);
+				musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
+				musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+finish:
+				musb_writew(regs, MUSB_CSR0,
+						musb->ackpend);
+				musb->ackpend = 0;
+			}
+		}
+		break;
+
+	case MUSB_EP0_STAGE_ACKWAIT:
+		/* This should not happen. But happens with tusb6010 with
+		 * g_file_storage and high speed. Do nothing.
+		 */
+		retval = IRQ_HANDLED;
+		break;
+
+	default:
+		/* "can't happen" */
+		assert_noisy(false);
+		musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
+		musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+		break;
+	}
+
+	return retval;
+}
+
+
+static int
+musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+	/* always enabled */
+	return -EINVAL;
+}
+
+static int musb_g_ep0_disable(struct usb_ep *e)
+{
+	/* always enabled */
+	return -EINVAL;
+}
+
+static int
+musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
+{
+	struct musb_ep		*ep;
+	struct musb_request	*req;
+	struct musb		*musb;
+	int			status;
+	unsigned long		lockflags;
+	void __iomem		*regs;
+
+	if (!e || !r)
+		return -EINVAL;
+
+	ep = to_musb_ep(e);
+	musb = ep->musb;
+	regs = musb->control_ep->regs;
+
+	req = to_musb_request(r);
+	req->musb = musb;
+	req->request.actual = 0;
+	req->request.status = -EINPROGRESS;
+	req->tx = ep->is_in;
+
+	spin_lock_irqsave(&musb->lock, lockflags);
+
+	if (!list_empty(&ep->req_list)) {
+		status = -EBUSY;
+		goto cleanup;
+	}
+
+	switch (musb->ep0_state) {
+	case MUSB_EP0_STAGE_RX:		/* control-OUT data */
+	case MUSB_EP0_STAGE_TX:		/* control-IN data */
+	case MUSB_EP0_STAGE_ACKWAIT:	/* zero-length data */
+		status = 0;
+		break;
+	default:
+		dev_dbg(musb->controller, "ep0 request queued in state %d\n",
+				musb->ep0_state);
+		status = -EINVAL;
+		goto cleanup;
+	}
+
+	/* add request to the list */
+	list_add_tail(&req->list, &ep->req_list);
+
+	dev_dbg(musb->controller, "queue to %s (%s), length=%d\n",
+			ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
+			req->request.length);
+
+	musb_ep_select(musb->mregs, 0);
+
+	/* sequence #1, IN ... start writing the data */
+	if (musb->ep0_state == MUSB_EP0_STAGE_TX)
+		ep0_txstate(musb);
+
+	/* sequence #3, no-data ... issue IN status */
+	else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) {
+		if (req->request.length)
+			status = -EINVAL;
+		else {
+			musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
+			musb_writew(regs, MUSB_CSR0,
+					musb->ackpend | MUSB_CSR0_P_DATAEND);
+			musb->ackpend = 0;
+			musb_g_ep0_giveback(ep->musb, r);
+		}
+
+	/* else for sequence #2 (OUT), caller provides a buffer
+	 * before the next packet arrives.  deferred responses
+	 * (after SETUP is acked) are racey.
+	 */
+	} else if (musb->ackpend) {
+		musb_writew(regs, MUSB_CSR0, musb->ackpend);
+		musb->ackpend = 0;
+	}
+
+cleanup:
+	spin_unlock_irqrestore(&musb->lock, lockflags);
+	return status;
+}
+
+static int musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	/* we just won't support this */
+	return -EINVAL;
+}
+
+static int musb_g_ep0_halt(struct usb_ep *e, int value)
+{
+	struct musb_ep		*ep;
+	struct musb		*musb;
+	void __iomem		*base, *regs;
+	unsigned long		flags;
+	int			status;
+	u16			csr;
+
+	if (!e || !value)
+		return -EINVAL;
+
+	ep = to_musb_ep(e);
+	musb = ep->musb;
+	base = musb->mregs;
+	regs = musb->control_ep->regs;
+	status = 0;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	if (!list_empty(&ep->req_list)) {
+		status = -EBUSY;
+		goto cleanup;
+	}
+
+	musb_ep_select(base, 0);
+	csr = musb->ackpend;
+
+	switch (musb->ep0_state) {
+
+	/* Stalls are usually issued after parsing SETUP packet, either
+	 * directly in irq context from setup() or else later.
+	 */
+	case MUSB_EP0_STAGE_TX:		/* control-IN data */
+	case MUSB_EP0_STAGE_ACKWAIT:	/* STALL for zero-length data */
+	case MUSB_EP0_STAGE_RX:		/* control-OUT data */
+		csr = musb_readw(regs, MUSB_CSR0);
+		/* FALLTHROUGH */
+
+	/* It's also OK to issue stalls during callbacks when a non-empty
+	 * DATA stage buffer has been read (or even written).
+	 */
+	case MUSB_EP0_STAGE_STATUSIN:	/* control-OUT status */
+	case MUSB_EP0_STAGE_STATUSOUT:	/* control-IN status */
+
+		csr |= MUSB_CSR0_P_SENDSTALL;
+		musb_writew(regs, MUSB_CSR0, csr);
+		musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+		musb->ackpend = 0;
+		break;
+	default:
+		dev_dbg(musb->controller, "ep0 can't halt in state %d\n", musb->ep0_state);
+		status = -EINVAL;
+	}
+
+cleanup:
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return status;
+}
+
+const struct usb_ep_ops musb_g_ep0_ops = {
+	.enable		= musb_g_ep0_enable,
+	.disable	= musb_g_ep0_disable,
+	.alloc_request	= musb_alloc_request,
+	.free_request	= musb_free_request,
+	.queue		= musb_g_ep0_queue,
+	.dequeue	= musb_g_ep0_dequeue,
+	.set_halt	= musb_g_ep0_halt,
+};
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_host.c b/roms/u-boot/drivers/usb/musb-new/musb_host.c
new file mode 100644
index 000000000..acb2d40f3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_host.c
@@ -0,0 +1,2393 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MUSB OTG driver host support
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+ */
+
+#ifndef __UBOOT__
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#else
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <usb.h>
+#include <linux/bug.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#endif
+
+#include "musb_core.h"
+#include "musb_host.h"
+
+
+/* MUSB HOST status 22-mar-2006
+ *
+ * - There's still lots of partial code duplication for fault paths, so
+ *   they aren't handled as consistently as they need to be.
+ *
+ * - PIO mostly behaved when last tested.
+ *     + including ep0, with all usbtest cases 9, 10
+ *     + usbtest 14 (ep0out) doesn't seem to run at all
+ *     + double buffered OUT/TX endpoints saw stalls(!) with certain usbtest
+ *       configurations, but otherwise double buffering passes basic tests.
+ *     + for 2.6.N, for N > ~10, needs API changes for hcd framework.
+ *
+ * - DMA (CPPI) ... partially behaves, not currently recommended
+ *     + about 1/15 the speed of typical EHCI implementations (PCI)
+ *     + RX, all too often reqpkt seems to misbehave after tx
+ *     + TX, no known issues (other than evident silicon issue)
+ *
+ * - DMA (Mentor/OMAP) ...has at least toggle update problems
+ *
+ * - [23-feb-2009] minimal traffic scheduling to avoid bulk RX packet
+ *   starvation ... nothing yet for TX, interrupt, or bulk.
+ *
+ * - Not tested with HNP, but some SRP paths seem to behave.
+ *
+ * NOTE 24-August-2006:
+ *
+ * - Bulk traffic finally uses both sides of hardware ep1, freeing up an
+ *   extra endpoint for periodic use enabling hub + keybd + mouse.  That
+ *   mostly works, except that with "usbnet" it's easy to trigger cases
+ *   with "ping" where RX loses.  (a) ping to davinci, even "ping -f",
+ *   fine; but (b) ping _from_ davinci, even "ping -c 1", ICMP RX loses
+ *   although ARP RX wins.  (That test was done with a full speed link.)
+ */
+
+
+/*
+ * NOTE on endpoint usage:
+ *
+ * CONTROL transfers all go through ep0.  BULK ones go through dedicated IN
+ * and OUT endpoints ... hardware is dedicated for those "async" queue(s).
+ * (Yes, bulk _could_ use more of the endpoints than that, and would even
+ * benefit from it.)
+ *
+ * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
+ * So far that scheduling is both dumb and optimistic:  the endpoint will be
+ * "claimed" until its software queue is no longer refilled.  No multiplexing
+ * of transfers between endpoints, or anything clever.
+ */
+
+
+static void musb_ep_program(struct musb *musb, u8 epnum,
+			struct urb *urb, int is_out,
+			u8 *buf, u32 offset, u32 len);
+
+/*
+ * Clear TX fifo. Needed to avoid BABBLE errors.
+ */
+static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
+{
+	struct musb	*musb = ep->musb;
+	void __iomem	*epio = ep->regs;
+	u16		csr;
+	u16		lastcsr = 0;
+	int		retries = 1000;
+
+	csr = musb_readw(epio, MUSB_TXCSR);
+	while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+		if (csr != lastcsr)
+			dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
+		lastcsr = csr;
+		csr |= MUSB_TXCSR_FLUSHFIFO;
+		musb_writew(epio, MUSB_TXCSR, csr);
+		csr = musb_readw(epio, MUSB_TXCSR);
+		if (WARN(retries-- < 1,
+				"Could not flush host TX%d fifo: csr: %04x\n",
+				ep->epnum, csr))
+			return;
+		mdelay(1);
+	}
+}
+
+static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep)
+{
+	void __iomem	*epio = ep->regs;
+	u16		csr;
+	int		retries = 5;
+
+	/* scrub any data left in the fifo */
+	do {
+		csr = musb_readw(epio, MUSB_TXCSR);
+		if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY)))
+			break;
+		musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO);
+		csr = musb_readw(epio, MUSB_TXCSR);
+		udelay(10);
+	} while (--retries);
+
+	WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n",
+			ep->epnum, csr);
+
+	/* and reset for the next transfer */
+	musb_writew(epio, MUSB_TXCSR, 0);
+}
+
+/*
+ * Start transmit. Caller is responsible for locking shared resources.
+ * musb must be locked.
+ */
+static inline void musb_h_tx_start(struct musb_hw_ep *ep)
+{
+	u16	txcsr;
+
+	/* NOTE: no locks here; caller should lock and select EP */
+	if (ep->epnum) {
+		txcsr = musb_readw(ep->regs, MUSB_TXCSR);
+		txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS;
+		musb_writew(ep->regs, MUSB_TXCSR, txcsr);
+	} else {
+		txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY;
+		musb_writew(ep->regs, MUSB_CSR0, txcsr);
+	}
+
+}
+
+static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep)
+{
+	u16	txcsr;
+
+	/* NOTE: no locks here; caller should lock and select EP */
+	txcsr = musb_readw(ep->regs, MUSB_TXCSR);
+	txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS;
+	if (is_cppi_enabled())
+		txcsr |= MUSB_TXCSR_DMAMODE;
+	musb_writew(ep->regs, MUSB_TXCSR, txcsr);
+}
+
+static void musb_ep_set_qh(struct musb_hw_ep *ep, int is_in, struct musb_qh *qh)
+{
+	if (is_in != 0 || ep->is_shared_fifo)
+		ep->in_qh  = qh;
+	if (is_in == 0 || ep->is_shared_fifo)
+		ep->out_qh = qh;
+}
+
+static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in)
+{
+	return is_in ? ep->in_qh : ep->out_qh;
+}
+
+/*
+ * Start the URB at the front of an endpoint's queue
+ * end must be claimed from the caller.
+ *
+ * Context: controller locked, irqs blocked
+ */
+static void
+musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+{
+	u16			frame;
+	u32			len;
+	void __iomem		*mbase =  musb->mregs;
+	struct urb		*urb = next_urb(qh);
+	void			*buf = urb->transfer_buffer;
+	u32			offset = 0;
+	struct musb_hw_ep	*hw_ep = qh->hw_ep;
+	unsigned		pipe = urb->pipe;
+	u8			address = usb_pipedevice(pipe);
+	int			epnum = hw_ep->epnum;
+
+	/* initialize software qh state */
+	qh->offset = 0;
+	qh->segsize = 0;
+
+	/* gather right source of data */
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		/* control transfers always start with SETUP */
+		is_in = 0;
+		musb->ep0_stage = MUSB_EP0_START;
+		buf = urb->setup_packet;
+		len = 8;
+		break;
+#ifndef __UBOOT__
+	case USB_ENDPOINT_XFER_ISOC:
+		qh->iso_idx = 0;
+		qh->frame = 0;
+		offset = urb->iso_frame_desc[0].offset;
+		len = urb->iso_frame_desc[0].length;
+		break;
+#endif
+	default:		/* bulk, interrupt */
+		/* actual_length may be nonzero on retry paths */
+		buf = urb->transfer_buffer + urb->actual_length;
+		len = urb->transfer_buffer_length - urb->actual_length;
+	}
+
+	dev_dbg(musb->controller, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
+			qh, urb, address, qh->epnum,
+			is_in ? "in" : "out",
+			({char *s; switch (qh->type) {
+			case USB_ENDPOINT_XFER_CONTROL:	s = ""; break;
+			case USB_ENDPOINT_XFER_BULK:	s = "-bulk"; break;
+#ifndef __UBOOT__
+			case USB_ENDPOINT_XFER_ISOC:	s = "-iso"; break;
+#endif
+			default:			s = "-intr"; break;
+			}; s; }),
+			epnum, buf + offset, len);
+
+	/* Configure endpoint */
+	musb_ep_set_qh(hw_ep, is_in, qh);
+	musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
+
+	/* transmit may have more work: start it when it is time */
+	if (is_in)
+		return;
+
+	/* determine if the time is right for a periodic transfer */
+	switch (qh->type) {
+#ifndef __UBOOT__
+	case USB_ENDPOINT_XFER_ISOC:
+#endif
+	case USB_ENDPOINT_XFER_INT:
+		dev_dbg(musb->controller, "check whether there's still time for periodic Tx\n");
+		frame = musb_readw(mbase, MUSB_FRAME);
+		/* FIXME this doesn't implement that scheduling policy ...
+		 * or handle framecounter wrapping
+		 */
+#ifndef __UBOOT__
+		if ((urb->transfer_flags & URB_ISO_ASAP)
+				|| (frame >= urb->start_frame)) {
+			/* REVISIT the SOF irq handler shouldn't duplicate
+			 * this code; and we don't init urb->start_frame...
+			 */
+			qh->frame = 0;
+			goto start;
+		} else {
+#endif
+			qh->frame = urb->start_frame;
+			/* enable SOF interrupt so we can count down */
+			dev_dbg(musb->controller, "SOF for %d\n", epnum);
+#if 1 /* ifndef	CONFIG_ARCH_DAVINCI */
+			musb_writeb(mbase, MUSB_INTRUSBE, 0xff);
+#endif
+#ifndef __UBOOT__
+		}
+#endif
+		break;
+	default:
+start:
+		dev_dbg(musb->controller, "Start TX%d %s\n", epnum,
+			hw_ep->tx_channel ? "dma" : "pio");
+
+		if (!hw_ep->tx_channel)
+			musb_h_tx_start(hw_ep);
+		else if (is_cppi_enabled() || tusb_dma_omap())
+			musb_h_tx_dma_start(hw_ep);
+	}
+}
+
+/* Context: caller owns controller lock, IRQs are blocked */
+static void musb_giveback(struct musb *musb, struct urb *urb, int status)
+__releases(musb->lock)
+__acquires(musb->lock)
+{
+	dev_dbg(musb->controller,
+			"complete %p %pF (%d), dev%d ep%d%s, %d/%d\n",
+			urb, urb->complete, status,
+			usb_pipedevice(urb->pipe),
+			usb_pipeendpoint(urb->pipe),
+			usb_pipein(urb->pipe) ? "in" : "out",
+			urb->actual_length, urb->transfer_buffer_length
+			);
+
+	usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
+	spin_unlock(&musb->lock);
+	usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status);
+	spin_lock(&musb->lock);
+}
+
+/* For bulk/interrupt endpoints only */
+static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
+				    struct urb *urb)
+{
+	void __iomem		*epio = qh->hw_ep->regs;
+	u16			csr;
+
+	/*
+	 * FIXME: the current Mentor DMA code seems to have
+	 * problems getting toggle correct.
+	 */
+
+	if (is_in)
+		csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE;
+	else
+		csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE;
+
+	usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
+}
+
+/*
+ * Advance this hardware endpoint's queue, completing the specified URB and
+ * advancing to either the next URB queued to that qh, or else invalidating
+ * that qh and advancing to the next qh scheduled after the current one.
+ *
+ * Context: caller owns controller lock, IRQs are blocked
+ */
+static void musb_advance_schedule(struct musb *musb, struct urb *urb,
+				  struct musb_hw_ep *hw_ep, int is_in)
+{
+	struct musb_qh		*qh = musb_ep_get_qh(hw_ep, is_in);
+	struct musb_hw_ep	*ep = qh->hw_ep;
+	int			ready = qh->is_ready;
+	int			status;
+
+	status = (urb->status == -EINPROGRESS) ? 0 : urb->status;
+
+	/* save toggle eagerly, for paranoia */
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		musb_save_toggle(qh, is_in, urb);
+		break;
+#ifndef __UBOOT__
+	case USB_ENDPOINT_XFER_ISOC:
+		if (status == 0 && urb->error_count)
+			status = -EXDEV;
+		break;
+#endif
+	}
+
+	qh->is_ready = 0;
+	musb_giveback(musb, urb, status);
+	qh->is_ready = ready;
+
+	/* reclaim resources (and bandwidth) ASAP; deschedule it, and
+	 * invalidate qh as soon as list_empty(&hep->urb_list)
+	 */
+	if (list_empty(&qh->hep->urb_list)) {
+		struct list_head	*head;
+		struct dma_controller	*dma = musb->dma_controller;
+
+		if (is_in) {
+			ep->rx_reinit = 1;
+			if (ep->rx_channel) {
+				dma->channel_release(ep->rx_channel);
+				ep->rx_channel = NULL;
+			}
+		} else {
+			ep->tx_reinit = 1;
+			if (ep->tx_channel) {
+				dma->channel_release(ep->tx_channel);
+				ep->tx_channel = NULL;
+			}
+		}
+
+		/* Clobber old pointers to this qh */
+		musb_ep_set_qh(ep, is_in, NULL);
+		qh->hep->hcpriv = NULL;
+
+		switch (qh->type) {
+
+		case USB_ENDPOINT_XFER_CONTROL:
+		case USB_ENDPOINT_XFER_BULK:
+			/* fifo policy for these lists, except that NAKing
+			 * should rotate a qh to the end (for fairness).
+			 */
+			if (qh->mux == 1) {
+				head = qh->ring.prev;
+				list_del(&qh->ring);
+				kfree(qh);
+				qh = first_qh(head);
+				break;
+			}
+
+		case USB_ENDPOINT_XFER_ISOC:
+		case USB_ENDPOINT_XFER_INT:
+			/* this is where periodic bandwidth should be
+			 * de-allocated if it's tracked and allocated;
+			 * and where we'd update the schedule tree...
+			 */
+			kfree(qh);
+			qh = NULL;
+			break;
+		}
+	}
+
+	if (qh != NULL && qh->is_ready) {
+		dev_dbg(musb->controller, "... next ep%d %cX urb %p\n",
+		    hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
+		musb_start_urb(musb, is_in, qh);
+	}
+}
+
+static u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr)
+{
+	/* we don't want fifo to fill itself again;
+	 * ignore dma (various models),
+	 * leave toggle alone (may not have been saved yet)
+	 */
+	csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_RXPKTRDY;
+	csr &= ~(MUSB_RXCSR_H_REQPKT
+		| MUSB_RXCSR_H_AUTOREQ
+		| MUSB_RXCSR_AUTOCLEAR);
+
+	/* write 2x to allow double buffering */
+	musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+	musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+
+	/* flush writebuffer */
+	return musb_readw(hw_ep->regs, MUSB_RXCSR);
+}
+
+/*
+ * PIO RX for a packet (or part of it).
+ */
+static bool
+musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)
+{
+	u16			rx_count;
+	u8			*buf;
+	u16			csr;
+	bool			done = false;
+	u32			length;
+	int			do_flush = 0;
+	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum;
+	void __iomem		*epio = hw_ep->regs;
+	struct musb_qh		*qh = hw_ep->in_qh;
+	int			pipe = urb->pipe;
+	void			*buffer = urb->transfer_buffer;
+
+	/* musb_ep_select(mbase, epnum); */
+	rx_count = musb_readw(epio, MUSB_RXCOUNT);
+	dev_dbg(musb->controller, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count,
+			urb->transfer_buffer, qh->offset,
+			urb->transfer_buffer_length);
+
+	/* unload FIFO */
+#ifndef __UBOOT__
+	if (usb_pipeisoc(pipe)) {
+		int					status = 0;
+		struct usb_iso_packet_descriptor	*d;
+
+		if (iso_err) {
+			status = -EILSEQ;
+			urb->error_count++;
+		}
+
+		d = urb->iso_frame_desc + qh->iso_idx;
+		buf = buffer + d->offset;
+		length = d->length;
+		if (rx_count > length) {
+			if (status == 0) {
+				status = -EOVERFLOW;
+				urb->error_count++;
+			}
+			dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length);
+			do_flush = 1;
+		} else
+			length = rx_count;
+		urb->actual_length += length;
+		d->actual_length = length;
+
+		d->status = status;
+
+		/* see if we are done */
+		done = (++qh->iso_idx >= urb->number_of_packets);
+	} else {
+#endif
+		/* non-isoch */
+		buf = buffer + qh->offset;
+		length = urb->transfer_buffer_length - qh->offset;
+		if (rx_count > length) {
+			if (urb->status == -EINPROGRESS)
+				urb->status = -EOVERFLOW;
+			dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length);
+			do_flush = 1;
+		} else
+			length = rx_count;
+		urb->actual_length += length;
+		qh->offset += length;
+
+		/* see if we are done */
+		done = (urb->actual_length == urb->transfer_buffer_length)
+			|| (rx_count < qh->maxpacket)
+			|| (urb->status != -EINPROGRESS);
+		if (done
+				&& (urb->status == -EINPROGRESS)
+				&& (urb->transfer_flags & URB_SHORT_NOT_OK)
+				&& (urb->actual_length
+					< urb->transfer_buffer_length))
+			urb->status = -EREMOTEIO;
+#ifndef __UBOOT__
+	}
+#endif
+
+	musb_read_fifo(hw_ep, length, buf);
+
+	csr = musb_readw(epio, MUSB_RXCSR);
+	csr |= MUSB_RXCSR_H_WZC_BITS;
+	if (unlikely(do_flush))
+		musb_h_flush_rxfifo(hw_ep, csr);
+	else {
+		/* REVISIT this assumes AUTOCLEAR is never set */
+		csr &= ~(MUSB_RXCSR_RXPKTRDY | MUSB_RXCSR_H_REQPKT);
+		if (!done)
+			csr |= MUSB_RXCSR_H_REQPKT;
+		musb_writew(epio, MUSB_RXCSR, csr);
+	}
+
+	return done;
+}
+
+/* we don't always need to reinit a given side of an endpoint...
+ * when we do, use tx/rx reinit routine and then construct a new CSR
+ * to address data toggle, NYET, and DMA or PIO.
+ *
+ * it's possible that driver bugs (especially for DMA) or aborting a
+ * transfer might have left the endpoint busier than it should be.
+ * the busy/not-empty tests are basically paranoia.
+ */
+static void
+musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+{
+	u16	csr;
+
+	/* NOTE:  we know the "rx" fifo reinit never triggers for ep0.
+	 * That always uses tx_reinit since ep0 repurposes TX register
+	 * offsets; the initial SETUP packet is also a kind of OUT.
+	 */
+
+	/* if programmed for Tx, put it in RX mode */
+	if (ep->is_shared_fifo) {
+		csr = musb_readw(ep->regs, MUSB_TXCSR);
+		if (csr & MUSB_TXCSR_MODE) {
+			musb_h_tx_flush_fifo(ep);
+			csr = musb_readw(ep->regs, MUSB_TXCSR);
+			musb_writew(ep->regs, MUSB_TXCSR,
+				    csr | MUSB_TXCSR_FRCDATATOG);
+		}
+
+		/*
+		 * Clear the MODE bit (and everything else) to enable Rx.
+		 * NOTE: we mustn't clear the DMAMODE bit before DMAENAB.
+		 */
+		if (csr & MUSB_TXCSR_DMAMODE)
+			musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE);
+		musb_writew(ep->regs, MUSB_TXCSR, 0);
+
+	/* scrub all previous state, clearing toggle */
+	} else {
+		csr = musb_readw(ep->regs, MUSB_RXCSR);
+		if (csr & MUSB_RXCSR_RXPKTRDY)
+			WARNING("rx%d, packet/%d ready?\n", ep->epnum,
+				musb_readw(ep->regs, MUSB_RXCOUNT));
+
+		musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
+	}
+
+	/* target addr and (for multipoint) hub addr/port */
+	if (musb->is_multipoint) {
+		musb_write_rxfunaddr(ep->target_regs, qh->addr_reg);
+		musb_write_rxhubaddr(ep->target_regs, qh->h_addr_reg);
+		musb_write_rxhubport(ep->target_regs, qh->h_port_reg);
+
+	} else
+		musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg);
+
+	/* protocol/endpoint, interval/NAKlimit, i/o size */
+	musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
+	musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
+	/* NOTE: bulk combining rewrites high bits of maxpacket */
+	/* Set RXMAXP with the FIFO size of the endpoint
+	 * to disable double buffer mode.
+	 */
+	if (musb->double_buffer_not_ok)
+		musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
+	else
+		musb_writew(ep->regs, MUSB_RXMAXP,
+				qh->maxpacket | ((qh->hb_mult - 1) << 11));
+
+	ep->rx_reinit = 0;
+}
+
+static bool musb_tx_dma_program(struct dma_controller *dma,
+		struct musb_hw_ep *hw_ep, struct musb_qh *qh,
+		struct urb *urb, u32 offset, u32 length)
+{
+	struct dma_channel	*channel = hw_ep->tx_channel;
+	void __iomem		*epio = hw_ep->regs;
+	u16			pkt_size = qh->maxpacket;
+	u16			csr;
+	u8			mode;
+
+#ifdef	CONFIG_USB_INVENTRA_DMA
+	if (length > channel->max_len)
+		length = channel->max_len;
+
+	csr = musb_readw(epio, MUSB_TXCSR);
+	if (length > pkt_size) {
+		mode = 1;
+		csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
+		/* autoset shouldn't be set in high bandwidth */
+		if (qh->hb_mult == 1)
+			csr |= MUSB_TXCSR_AUTOSET;
+	} else {
+		mode = 0;
+		csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
+		csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
+	}
+	channel->desired_mode = mode;
+	musb_writew(epio, MUSB_TXCSR, csr);
+#else
+	if (!is_cppi_enabled() && !tusb_dma_omap())
+		return false;
+
+	channel->actual_len = 0;
+
+	/*
+	 * TX uses "RNDIS" mode automatically but needs help
+	 * to identify the zero-length-final-packet case.
+	 */
+	mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
+#endif
+
+	qh->segsize = length;
+
+	/*
+	 * Ensure the data reaches to main memory before starting
+	 * DMA transfer
+	 */
+	wmb();
+
+	if (!dma->channel_program(channel, pkt_size, mode,
+			urb->transfer_dma + offset, length)) {
+		dma->channel_release(channel);
+		hw_ep->tx_channel = NULL;
+
+		csr = musb_readw(epio, MUSB_TXCSR);
+		csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB);
+		musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS);
+		return false;
+	}
+	return true;
+}
+
+/*
+ * Program an HDRC endpoint as per the given URB
+ * Context: irqs blocked, controller lock held
+ */
+static void musb_ep_program(struct musb *musb, u8 epnum,
+			struct urb *urb, int is_out,
+			u8 *buf, u32 offset, u32 len)
+{
+	struct dma_controller	*dma_controller;
+	struct dma_channel	*dma_channel;
+	u8			dma_ok;
+	void __iomem		*mbase = musb->mregs;
+	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum;
+	void __iomem		*epio = hw_ep->regs;
+	struct musb_qh		*qh = musb_ep_get_qh(hw_ep, !is_out);
+	u16			packet_sz = qh->maxpacket;
+
+	dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s "
+				"h_addr%02x h_port%02x bytes %d\n",
+			is_out ? "-->" : "<--",
+			epnum, urb, urb->dev->speed,
+			qh->addr_reg, qh->epnum, is_out ? "out" : "in",
+			qh->h_addr_reg, qh->h_port_reg,
+			len);
+
+	musb_ep_select(mbase, epnum);
+
+	/* candidate for DMA? */
+	dma_controller = musb->dma_controller;
+	if (is_dma_capable() && epnum && dma_controller) {
+		dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
+		if (!dma_channel) {
+			dma_channel = dma_controller->channel_alloc(
+					dma_controller, hw_ep, is_out);
+			if (is_out)
+				hw_ep->tx_channel = dma_channel;
+			else
+				hw_ep->rx_channel = dma_channel;
+		}
+	} else
+		dma_channel = NULL;
+
+	/* make sure we clear DMAEnab, autoSet bits from previous run */
+
+	/* OUT/transmit/EP0 or IN/receive? */
+	if (is_out) {
+		u16	csr;
+		u16	int_txe;
+		u16	load_count;
+
+		csr = musb_readw(epio, MUSB_TXCSR);
+
+		/* disable interrupt in case we flush */
+		int_txe = musb_readw(mbase, MUSB_INTRTXE);
+		musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
+
+		/* general endpoint setup */
+		if (epnum) {
+			/* flush all old state, set default */
+			musb_h_tx_flush_fifo(hw_ep);
+
+			/*
+			 * We must not clear the DMAMODE bit before or in
+			 * the same cycle with the DMAENAB bit, so we clear
+			 * the latter first...
+			 */
+			csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT
+					| MUSB_TXCSR_AUTOSET
+					| MUSB_TXCSR_DMAENAB
+					| MUSB_TXCSR_FRCDATATOG
+					| MUSB_TXCSR_H_RXSTALL
+					| MUSB_TXCSR_H_ERROR
+					| MUSB_TXCSR_TXPKTRDY
+					);
+			csr |= MUSB_TXCSR_MODE;
+
+			if (usb_gettoggle(urb->dev, qh->epnum, 1))
+				csr |= MUSB_TXCSR_H_WR_DATATOGGLE
+					| MUSB_TXCSR_H_DATATOGGLE;
+			else
+				csr |= MUSB_TXCSR_CLRDATATOG;
+
+			musb_writew(epio, MUSB_TXCSR, csr);
+			/* REVISIT may need to clear FLUSHFIFO ... */
+			csr &= ~MUSB_TXCSR_DMAMODE;
+			musb_writew(epio, MUSB_TXCSR, csr);
+			csr = musb_readw(epio, MUSB_TXCSR);
+		} else {
+			/* endpoint 0: just flush */
+			musb_h_ep0_flush_fifo(hw_ep);
+		}
+
+		/* target addr and (for multipoint) hub addr/port */
+		if (musb->is_multipoint) {
+			musb_write_txfunaddr(mbase, epnum, qh->addr_reg);
+			musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg);
+			musb_write_txhubport(mbase, epnum, qh->h_port_reg);
+/* FIXME if !epnum, do the same for RX ... */
+		} else
+			musb_writeb(mbase, MUSB_FADDR, qh->addr_reg);
+
+		/* protocol/endpoint/interval/NAKlimit */
+		if (epnum) {
+			musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
+			if (musb->double_buffer_not_ok)
+				musb_writew(epio, MUSB_TXMAXP,
+						hw_ep->max_packet_sz_tx);
+			else if (can_bulk_split(musb, qh->type))
+				musb_writew(epio, MUSB_TXMAXP, packet_sz
+					| ((hw_ep->max_packet_sz_tx /
+						packet_sz) - 1) << 11);
+			else
+				musb_writew(epio, MUSB_TXMAXP,
+						qh->maxpacket |
+						((qh->hb_mult - 1) << 11));
+			musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
+		} else {
+			musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
+			if (musb->is_multipoint)
+				musb_writeb(epio, MUSB_TYPE0,
+						qh->type_reg);
+		}
+
+		if (can_bulk_split(musb, qh->type))
+			load_count = min((u32) hw_ep->max_packet_sz_tx,
+						len);
+		else
+			load_count = min((u32) packet_sz, len);
+
+		if (dma_channel && musb_tx_dma_program(dma_controller,
+					hw_ep, qh, urb, offset, len))
+			load_count = 0;
+
+		if (load_count) {
+			/* PIO to load FIFO */
+			qh->segsize = load_count;
+			musb_write_fifo(hw_ep, load_count, buf);
+		}
+
+		/* re-enable interrupt */
+		musb_writew(mbase, MUSB_INTRTXE, int_txe);
+
+	/* IN/receive */
+	} else {
+		u16	csr;
+
+		if (hw_ep->rx_reinit) {
+			musb_rx_reinit(musb, qh, hw_ep);
+
+			/* init new state: toggle and NYET, maybe DMA later */
+			if (usb_gettoggle(urb->dev, qh->epnum, 0))
+				csr = MUSB_RXCSR_H_WR_DATATOGGLE
+					| MUSB_RXCSR_H_DATATOGGLE;
+			else
+				csr = 0;
+			if (qh->type == USB_ENDPOINT_XFER_INT)
+				csr |= MUSB_RXCSR_DISNYET;
+
+		} else {
+			csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+
+			if (csr & (MUSB_RXCSR_RXPKTRDY
+					| MUSB_RXCSR_DMAENAB
+					| MUSB_RXCSR_H_REQPKT))
+				ERR("broken !rx_reinit, ep%d csr %04x\n",
+						hw_ep->epnum, csr);
+
+			/* scrub any stale state, leaving toggle alone */
+			csr &= MUSB_RXCSR_DISNYET;
+		}
+
+		/* kick things off */
+
+		if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
+			/* Candidate for DMA */
+			dma_channel->actual_len = 0L;
+			qh->segsize = len;
+
+			/* AUTOREQ is in a DMA register */
+			musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+			csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+
+			/*
+			 * Unless caller treats short RX transfers as
+			 * errors, we dare not queue multiple transfers.
+			 */
+			dma_ok = dma_controller->channel_program(dma_channel,
+					packet_sz, !(urb->transfer_flags &
+						     URB_SHORT_NOT_OK),
+					urb->transfer_dma + offset,
+					qh->segsize);
+			if (!dma_ok) {
+				dma_controller->channel_release(dma_channel);
+				hw_ep->rx_channel = dma_channel = NULL;
+			} else
+				csr |= MUSB_RXCSR_DMAENAB;
+		}
+
+		csr |= MUSB_RXCSR_H_REQPKT;
+		dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr);
+		musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
+		csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+	}
+}
+
+
+/*
+ * Service the default endpoint (ep0) as host.
+ * Return true until it's time to start the status stage.
+ */
+static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
+{
+	bool			 more = false;
+	u8			*fifo_dest = NULL;
+	u16			fifo_count = 0;
+	struct musb_hw_ep	*hw_ep = musb->control_ep;
+	struct musb_qh		*qh = hw_ep->in_qh;
+	struct usb_ctrlrequest	*request;
+
+	switch (musb->ep0_stage) {
+	case MUSB_EP0_IN:
+		fifo_dest = urb->transfer_buffer + urb->actual_length;
+		fifo_count = min_t(size_t, len, urb->transfer_buffer_length -
+				   urb->actual_length);
+		if (fifo_count < len)
+			urb->status = -EOVERFLOW;
+
+		musb_read_fifo(hw_ep, fifo_count, fifo_dest);
+
+		urb->actual_length += fifo_count;
+		if (len < qh->maxpacket) {
+			/* always terminate on short read; it's
+			 * rarely reported as an error.
+			 */
+		} else if (urb->actual_length <
+				urb->transfer_buffer_length)
+			more = true;
+		break;
+	case MUSB_EP0_START:
+		request = (struct usb_ctrlrequest *) urb->setup_packet;
+
+		if (!request->wLength) {
+			dev_dbg(musb->controller, "start no-DATA\n");
+			break;
+		} else if (request->bRequestType & USB_DIR_IN) {
+			dev_dbg(musb->controller, "start IN-DATA\n");
+			musb->ep0_stage = MUSB_EP0_IN;
+			more = true;
+			break;
+		} else {
+			dev_dbg(musb->controller, "start OUT-DATA\n");
+			musb->ep0_stage = MUSB_EP0_OUT;
+			more = true;
+		}
+		/* FALLTHROUGH */
+	case MUSB_EP0_OUT:
+		fifo_count = min_t(size_t, qh->maxpacket,
+				   urb->transfer_buffer_length -
+				   urb->actual_length);
+		if (fifo_count) {
+			fifo_dest = (u8 *) (urb->transfer_buffer
+					+ urb->actual_length);
+			dev_dbg(musb->controller, "Sending %d byte%s to ep0 fifo %p\n",
+					fifo_count,
+					(fifo_count == 1) ? "" : "s",
+					fifo_dest);
+			musb_write_fifo(hw_ep, fifo_count, fifo_dest);
+
+			urb->actual_length += fifo_count;
+			more = true;
+		}
+		break;
+	default:
+		ERR("bogus ep0 stage %d\n", musb->ep0_stage);
+		break;
+	}
+
+	return more;
+}
+
+/*
+ * Handle default endpoint interrupt as host. Only called in IRQ time
+ * from musb_interrupt().
+ *
+ * called with controller irqlocked
+ */
+irqreturn_t musb_h_ep0_irq(struct musb *musb)
+{
+	struct urb		*urb;
+	u16			csr, len;
+	int			status = 0;
+	void __iomem		*mbase = musb->mregs;
+	struct musb_hw_ep	*hw_ep = musb->control_ep;
+	void __iomem		*epio = hw_ep->regs;
+	struct musb_qh		*qh = hw_ep->in_qh;
+	bool			complete = false;
+	irqreturn_t		retval = IRQ_NONE;
+
+	/* ep0 only has one queue, "in" */
+	urb = next_urb(qh);
+
+	musb_ep_select(mbase, 0);
+	csr = musb_readw(epio, MUSB_CSR0);
+	len = (csr & MUSB_CSR0_RXPKTRDY)
+			? musb_readb(epio, MUSB_COUNT0)
+			: 0;
+
+	dev_dbg(musb->controller, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",
+		csr, qh, len, urb, musb->ep0_stage);
+
+	/* if we just did status stage, we are done */
+	if (MUSB_EP0_STATUS == musb->ep0_stage) {
+		retval = IRQ_HANDLED;
+		complete = true;
+	}
+
+	/* prepare status */
+	if (csr & MUSB_CSR0_H_RXSTALL) {
+		dev_dbg(musb->controller, "STALLING ENDPOINT\n");
+		status = -EPIPE;
+
+	} else if (csr & MUSB_CSR0_H_ERROR) {
+		dev_dbg(musb->controller, "no response, csr0 %04x\n", csr);
+		status = -EPROTO;
+
+	} else if (csr & MUSB_CSR0_H_NAKTIMEOUT) {
+		dev_dbg(musb->controller, "control NAK timeout\n");
+
+		/* NOTE:  this code path would be a good place to PAUSE a
+		 * control transfer, if another one is queued, so that
+		 * ep0 is more likely to stay busy.  That's already done
+		 * for bulk RX transfers.
+		 *
+		 * if (qh->ring.next != &musb->control), then
+		 * we have a candidate... NAKing is *NOT* an error
+		 */
+		musb_writew(epio, MUSB_CSR0, 0);
+		retval = IRQ_HANDLED;
+	}
+
+	if (status) {
+		dev_dbg(musb->controller, "aborting\n");
+		retval = IRQ_HANDLED;
+		if (urb)
+			urb->status = status;
+		complete = true;
+
+		/* use the proper sequence to abort the transfer */
+		if (csr & MUSB_CSR0_H_REQPKT) {
+			csr &= ~MUSB_CSR0_H_REQPKT;
+			musb_writew(epio, MUSB_CSR0, csr);
+			csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+			musb_writew(epio, MUSB_CSR0, csr);
+		} else {
+			musb_h_ep0_flush_fifo(hw_ep);
+		}
+
+		musb_writeb(epio, MUSB_NAKLIMIT0, 0);
+
+		/* clear it */
+		musb_writew(epio, MUSB_CSR0, 0);
+	}
+
+	if (unlikely(!urb)) {
+		/* stop endpoint since we have no place for its data, this
+		 * SHOULD NEVER HAPPEN! */
+		ERR("no URB for end 0\n");
+
+		musb_h_ep0_flush_fifo(hw_ep);
+		goto done;
+	}
+
+	if (!complete) {
+		/* call common logic and prepare response */
+		if (musb_h_ep0_continue(musb, len, urb)) {
+			/* more packets required */
+			csr = (MUSB_EP0_IN == musb->ep0_stage)
+				?  MUSB_CSR0_H_REQPKT : MUSB_CSR0_TXPKTRDY;
+		} else {
+			/* data transfer complete; perform status phase */
+			if (usb_pipeout(urb->pipe)
+					|| !urb->transfer_buffer_length)
+				csr = MUSB_CSR0_H_STATUSPKT
+					| MUSB_CSR0_H_REQPKT;
+			else
+				csr = MUSB_CSR0_H_STATUSPKT
+					| MUSB_CSR0_TXPKTRDY;
+
+			/* flag status stage */
+			musb->ep0_stage = MUSB_EP0_STATUS;
+
+			dev_dbg(musb->controller, "ep0 STATUS, csr %04x\n", csr);
+
+		}
+		musb_writew(epio, MUSB_CSR0, csr);
+		retval = IRQ_HANDLED;
+	} else
+		musb->ep0_stage = MUSB_EP0_IDLE;
+
+	/* call completion handler if done */
+	if (complete)
+		musb_advance_schedule(musb, urb, hw_ep, 1);
+done:
+	return retval;
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side TX (OUT) using Mentor DMA works as follows:
+	submit_urb ->
+		- if queue was empty, Program Endpoint
+		- ... which starts DMA to fifo in mode 1 or 0
+
+	DMA Isr (transfer complete) -> TxAvail()
+		- Stop DMA (~DmaEnab)	(<--- Alert ... currently happens
+					only in musb_cleanup_urb)
+		- TxPktRdy has to be set in mode 0 or for
+			short packets in mode 1.
+*/
+
+#endif
+
+/* Service a Tx-Available or dma completion irq for the endpoint */
+void musb_host_tx(struct musb *musb, u8 epnum)
+{
+	int			pipe;
+	bool			done = false;
+	u16			tx_csr;
+	size_t			length = 0;
+	size_t			offset = 0;
+	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum;
+	void __iomem		*epio = hw_ep->regs;
+	struct musb_qh		*qh = hw_ep->out_qh;
+	struct urb		*urb = next_urb(qh);
+	u32			status = 0;
+	void __iomem		*mbase = musb->mregs;
+	struct dma_channel	*dma;
+	bool			transfer_pending = false;
+
+	musb_ep_select(mbase, epnum);
+	tx_csr = musb_readw(epio, MUSB_TXCSR);
+
+	/* with CPPI, DMA sometimes triggers "extra" irqs */
+	if (!urb) {
+		dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
+		return;
+	}
+
+	pipe = urb->pipe;
+	dma = is_dma_capable() ? hw_ep->tx_channel : NULL;
+	dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
+			dma ? ", dma" : "");
+
+	/* check for errors */
+	if (tx_csr & MUSB_TXCSR_H_RXSTALL) {
+		/* dma was disabled, fifo flushed */
+		dev_dbg(musb->controller, "TX end %d stall\n", epnum);
+
+		/* stall; record URB status */
+		status = -EPIPE;
+
+	} else if (tx_csr & MUSB_TXCSR_H_ERROR) {
+		/* (NON-ISO) dma was disabled, fifo flushed */
+		dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum);
+
+		status = -ETIMEDOUT;
+
+	} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
+		dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum);
+
+		/* NOTE:  this code path would be a good place to PAUSE a
+		 * transfer, if there's some other (nonperiodic) tx urb
+		 * that could use this fifo.  (dma complicates it...)
+		 * That's already done for bulk RX transfers.
+		 *
+		 * if (bulk && qh->ring.next != &musb->out_bulk), then
+		 * we have a candidate... NAKing is *NOT* an error
+		 */
+		musb_ep_select(mbase, epnum);
+		musb_writew(epio, MUSB_TXCSR,
+				MUSB_TXCSR_H_WZC_BITS
+				| MUSB_TXCSR_TXPKTRDY);
+		return;
+	}
+
+	if (status) {
+		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+			(void) musb->dma_controller->channel_abort(dma);
+		}
+
+		/* do the proper sequence to abort the transfer in the
+		 * usb core; the dma engine should already be stopped.
+		 */
+		musb_h_tx_flush_fifo(hw_ep);
+		tx_csr &= ~(MUSB_TXCSR_AUTOSET
+				| MUSB_TXCSR_DMAENAB
+				| MUSB_TXCSR_H_ERROR
+				| MUSB_TXCSR_H_RXSTALL
+				| MUSB_TXCSR_H_NAKTIMEOUT
+				);
+
+		musb_ep_select(mbase, epnum);
+		musb_writew(epio, MUSB_TXCSR, tx_csr);
+		/* REVISIT may need to clear FLUSHFIFO ... */
+		musb_writew(epio, MUSB_TXCSR, tx_csr);
+		musb_writeb(epio, MUSB_TXINTERVAL, 0);
+
+		done = true;
+	}
+
+	/* second cppi case */
+	if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+		dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
+		return;
+	}
+
+	if (is_dma_capable() && dma && !status) {
+		/*
+		 * DMA has completed.  But if we're using DMA mode 1 (multi
+		 * packet DMA), we need a terminal TXPKTRDY interrupt before
+		 * we can consider this transfer completed, lest we trash
+		 * its last packet when writing the next URB's data.  So we
+		 * switch back to mode 0 to get that interrupt; we'll come
+		 * back here once it happens.
+		 */
+		if (tx_csr & MUSB_TXCSR_DMAMODE) {
+			/*
+			 * We shouldn't clear DMAMODE with DMAENAB set; so
+			 * clear them in a safe order.  That should be OK
+			 * once TXPKTRDY has been set (and I've never seen
+			 * it being 0 at this moment -- DMA interrupt latency
+			 * is significant) but if it hasn't been then we have
+			 * no choice but to stop being polite and ignore the
+			 * programmer's guide... :-)
+			 *
+			 * Note that we must write TXCSR with TXPKTRDY cleared
+			 * in order not to re-trigger the packet send (this bit
+			 * can't be cleared by CPU), and there's another caveat:
+			 * TXPKTRDY may be set shortly and then cleared in the
+			 * double-buffered FIFO mode, so we do an extra TXCSR
+			 * read for debouncing...
+			 */
+			tx_csr &= musb_readw(epio, MUSB_TXCSR);
+			if (tx_csr & MUSB_TXCSR_TXPKTRDY) {
+				tx_csr &= ~(MUSB_TXCSR_DMAENAB |
+					    MUSB_TXCSR_TXPKTRDY);
+				musb_writew(epio, MUSB_TXCSR,
+					    tx_csr | MUSB_TXCSR_H_WZC_BITS);
+			}
+			tx_csr &= ~(MUSB_TXCSR_DMAMODE |
+				    MUSB_TXCSR_TXPKTRDY);
+			musb_writew(epio, MUSB_TXCSR,
+				    tx_csr | MUSB_TXCSR_H_WZC_BITS);
+
+			/*
+			 * There is no guarantee that we'll get an interrupt
+			 * after clearing DMAMODE as we might have done this
+			 * too late (after TXPKTRDY was cleared by controller).
+			 * Re-read TXCSR as we have spoiled its previous value.
+			 */
+			tx_csr = musb_readw(epio, MUSB_TXCSR);
+		}
+
+		/*
+		 * We may get here from a DMA completion or TXPKTRDY interrupt.
+		 * In any case, we must check the FIFO status here and bail out
+		 * only if the FIFO still has data -- that should prevent the
+		 * "missed" TXPKTRDY interrupts and deal with double-buffered
+		 * FIFO mode too...
+		 */
+		if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) {
+			dev_dbg(musb->controller, "DMA complete but packet still in FIFO, "
+			    "CSR %04x\n", tx_csr);
+			return;
+		}
+	}
+
+	if (!status || dma || usb_pipeisoc(pipe)) {
+		if (dma)
+			length = dma->actual_len;
+		else
+			length = qh->segsize;
+		qh->offset += length;
+
+		if (usb_pipeisoc(pipe)) {
+#ifndef __UBOOT__
+			struct usb_iso_packet_descriptor	*d;
+
+			d = urb->iso_frame_desc + qh->iso_idx;
+			d->actual_length = length;
+			d->status = status;
+			if (++qh->iso_idx >= urb->number_of_packets) {
+				done = true;
+			} else {
+				d++;
+				offset = d->offset;
+				length = d->length;
+			}
+#endif
+		} else if (dma && urb->transfer_buffer_length == qh->offset) {
+			done = true;
+		} else {
+			/* see if we need to send more data, or ZLP */
+			if (qh->segsize < qh->maxpacket)
+				done = true;
+			else if (qh->offset == urb->transfer_buffer_length
+					&& !(urb->transfer_flags
+						& URB_ZERO_PACKET))
+				done = true;
+			if (!done) {
+				offset = qh->offset;
+				length = urb->transfer_buffer_length - offset;
+				transfer_pending = true;
+			}
+		}
+	}
+
+	/* urb->status != -EINPROGRESS means request has been faulted,
+	 * so we must abort this transfer after cleanup
+	 */
+	if (urb->status != -EINPROGRESS) {
+		done = true;
+		if (status == 0)
+			status = urb->status;
+	}
+
+	if (done) {
+		/* set status */
+		urb->status = status;
+		urb->actual_length = qh->offset;
+		musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT);
+		return;
+	} else if ((usb_pipeisoc(pipe) || transfer_pending) && dma) {
+		if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb,
+				offset, length)) {
+			if (is_cppi_enabled() || tusb_dma_omap())
+				musb_h_tx_dma_start(hw_ep);
+			return;
+		}
+	} else	if (tx_csr & MUSB_TXCSR_DMAENAB) {
+		dev_dbg(musb->controller, "not complete, but DMA enabled?\n");
+		return;
+	}
+
+	/*
+	 * PIO: start next packet in this URB.
+	 *
+	 * REVISIT: some docs say that when hw_ep->tx_double_buffered,
+	 * (and presumably, FIFO is not half-full) we should write *two*
+	 * packets before updating TXCSR; other docs disagree...
+	 */
+	if (length > qh->maxpacket)
+		length = qh->maxpacket;
+	/* Unmap the buffer so that CPU can use it */
+	usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
+	musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+	qh->segsize = length;
+
+	musb_ep_select(mbase, epnum);
+	musb_writew(epio, MUSB_TXCSR,
+			MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
+}
+
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+
+/* Host side RX (IN) using Mentor DMA works as follows:
+	submit_urb ->
+		- if queue was empty, ProgramEndpoint
+		- first IN token is sent out (by setting ReqPkt)
+	LinuxIsr -> RxReady()
+	/\	=> first packet is received
+	|	- Set in mode 0 (DmaEnab, ~ReqPkt)
+	|		-> DMA Isr (transfer complete) -> RxReady()
+	|		    - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab)
+	|		    - if urb not complete, send next IN token (ReqPkt)
+	|			   |		else complete urb.
+	|			   |
+	---------------------------
+ *
+ * Nuances of mode 1:
+ *	For short packets, no ack (+RxPktRdy) is sent automatically
+ *	(even if AutoClear is ON)
+ *	For full packets, ack (~RxPktRdy) and next IN token (+ReqPkt) is sent
+ *	automatically => major problem, as collecting the next packet becomes
+ *	difficult. Hence mode 1 is not used.
+ *
+ * REVISIT
+ *	All we care about at this driver level is that
+ *       (a) all URBs terminate with REQPKT cleared and fifo(s) empty;
+ *       (b) termination conditions are: short RX, or buffer full;
+ *       (c) fault modes include
+ *           - iff URB_SHORT_NOT_OK, short RX status is -EREMOTEIO.
+ *             (and that endpoint's dma queue stops immediately)
+ *           - overflow (full, PLUS more bytes in the terminal packet)
+ *
+ *	So for example, usb-storage sets URB_SHORT_NOT_OK, and would
+ *	thus be a great candidate for using mode 1 ... for all but the
+ *	last packet of one URB's transfer.
+ */
+
+#endif
+
+/* Schedule next QH from musb->in_bulk and move the current qh to
+ * the end; avoids starvation for other endpoints.
+ */
+static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
+{
+	struct dma_channel	*dma;
+	struct urb		*urb;
+	void __iomem		*mbase = musb->mregs;
+	void __iomem		*epio = ep->regs;
+	struct musb_qh		*cur_qh, *next_qh;
+	u16			rx_csr;
+
+	musb_ep_select(mbase, ep->epnum);
+	dma = is_dma_capable() ? ep->rx_channel : NULL;
+
+	/* clear nak timeout bit */
+	rx_csr = musb_readw(epio, MUSB_RXCSR);
+	rx_csr |= MUSB_RXCSR_H_WZC_BITS;
+	rx_csr &= ~MUSB_RXCSR_DATAERROR;
+	musb_writew(epio, MUSB_RXCSR, rx_csr);
+
+	cur_qh = first_qh(&musb->in_bulk);
+	if (cur_qh) {
+		urb = next_urb(cur_qh);
+		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+			musb->dma_controller->channel_abort(dma);
+			urb->actual_length += dma->actual_len;
+			dma->actual_len = 0L;
+		}
+		musb_save_toggle(cur_qh, 1, urb);
+
+		/* move cur_qh to end of queue */
+		list_move_tail(&cur_qh->ring, &musb->in_bulk);
+
+		/* get the next qh from musb->in_bulk */
+		next_qh = first_qh(&musb->in_bulk);
+
+		/* set rx_reinit and schedule the next qh */
+		ep->rx_reinit = 1;
+		musb_start_urb(musb, 1, next_qh);
+	}
+}
+
+/*
+ * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
+ * and high-bandwidth IN transfer cases.
+ */
+void musb_host_rx(struct musb *musb, u8 epnum)
+{
+	struct urb		*urb;
+	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum;
+	void __iomem		*epio = hw_ep->regs;
+	struct musb_qh		*qh = hw_ep->in_qh;
+	size_t			xfer_len;
+	void __iomem		*mbase = musb->mregs;
+	int			pipe;
+	u16			rx_csr, val;
+	bool			iso_err = false;
+	bool			done = false;
+	u32			status;
+	struct dma_channel	*dma;
+
+	musb_ep_select(mbase, epnum);
+
+	urb = next_urb(qh);
+	dma = is_dma_capable() ? hw_ep->rx_channel : NULL;
+	status = 0;
+	xfer_len = 0;
+
+	rx_csr = musb_readw(epio, MUSB_RXCSR);
+	val = rx_csr;
+
+	if (unlikely(!urb)) {
+		/* REVISIT -- THIS SHOULD NEVER HAPPEN ... but, at least
+		 * usbtest #11 (unlinks) triggers it regularly, sometimes
+		 * with fifo full.  (Only with DMA??)
+		 */
+		dev_dbg(musb->controller, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val,
+			musb_readw(epio, MUSB_RXCOUNT));
+		musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
+		return;
+	}
+
+	pipe = urb->pipe;
+
+	dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n",
+		epnum, rx_csr, urb->actual_length,
+		dma ? dma->actual_len : 0);
+
+	/* check for errors, concurrent stall & unlink is not really
+	 * handled yet! */
+	if (rx_csr & MUSB_RXCSR_H_RXSTALL) {
+		dev_dbg(musb->controller, "RX end %d STALL\n", epnum);
+
+		/* stall; record URB status */
+		status = -EPIPE;
+
+	} else if (rx_csr & MUSB_RXCSR_H_ERROR) {
+		dev_dbg(musb->controller, "end %d RX proto error\n", epnum);
+
+		status = -EPROTO;
+		musb_writeb(epio, MUSB_RXINTERVAL, 0);
+
+	} else if (rx_csr & MUSB_RXCSR_DATAERROR) {
+
+		if (USB_ENDPOINT_XFER_ISOC != qh->type) {
+			dev_dbg(musb->controller, "RX end %d NAK timeout\n", epnum);
+
+			/* NOTE: NAKing is *NOT* an error, so we want to
+			 * continue.  Except ... if there's a request for
+			 * another QH, use that instead of starving it.
+			 *
+			 * Devices like Ethernet and serial adapters keep
+			 * reads posted at all times, which will starve
+			 * other devices without this logic.
+			 */
+			if (usb_pipebulk(urb->pipe)
+					&& qh->mux == 1
+					&& !list_is_singular(&musb->in_bulk)) {
+				musb_bulk_rx_nak_timeout(musb, hw_ep);
+				return;
+			}
+			musb_ep_select(mbase, epnum);
+			rx_csr |= MUSB_RXCSR_H_WZC_BITS;
+			rx_csr &= ~MUSB_RXCSR_DATAERROR;
+			musb_writew(epio, MUSB_RXCSR, rx_csr);
+
+			goto finish;
+		} else {
+			dev_dbg(musb->controller, "RX end %d ISO data error\n", epnum);
+			/* packet error reported later */
+			iso_err = true;
+		}
+	} else if (rx_csr & MUSB_RXCSR_INCOMPRX) {
+		dev_dbg(musb->controller, "end %d high bandwidth incomplete ISO packet RX\n",
+				epnum);
+		status = -EPROTO;
+	}
+
+	/* faults abort the transfer */
+	if (status) {
+		/* clean up dma and collect transfer count */
+		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+			(void) musb->dma_controller->channel_abort(dma);
+			xfer_len = dma->actual_len;
+		}
+		musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
+		musb_writeb(epio, MUSB_RXINTERVAL, 0);
+		done = true;
+		goto finish;
+	}
+
+	if (unlikely(dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY)) {
+		/* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */
+		ERR("RX%d dma busy, csr %04x\n", epnum, rx_csr);
+		goto finish;
+	}
+
+	/* thorough shutdown for now ... given more precise fault handling
+	 * and better queueing support, we might keep a DMA pipeline going
+	 * while processing this irq for earlier completions.
+	 */
+
+	/* FIXME this is _way_ too much in-line logic for Mentor DMA */
+
+#ifndef CONFIG_USB_INVENTRA_DMA
+	if (rx_csr & MUSB_RXCSR_H_REQPKT)  {
+		/* REVISIT this happened for a while on some short reads...
+		 * the cleanup still needs investigation... looks bad...
+		 * and also duplicates dma cleanup code above ... plus,
+		 * shouldn't this be the "half full" double buffer case?
+		 */
+		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+			dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+			(void) musb->dma_controller->channel_abort(dma);
+			xfer_len = dma->actual_len;
+			done = true;
+		}
+
+		dev_dbg(musb->controller, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr,
+				xfer_len, dma ? ", dma" : "");
+		rx_csr &= ~MUSB_RXCSR_H_REQPKT;
+
+		musb_ep_select(mbase, epnum);
+		musb_writew(epio, MUSB_RXCSR,
+				MUSB_RXCSR_H_WZC_BITS | rx_csr);
+	}
+#endif
+	if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
+		xfer_len = dma->actual_len;
+
+		val &= ~(MUSB_RXCSR_DMAENAB
+			| MUSB_RXCSR_H_AUTOREQ
+			| MUSB_RXCSR_AUTOCLEAR
+			| MUSB_RXCSR_RXPKTRDY);
+		musb_writew(hw_ep->regs, MUSB_RXCSR, val);
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+		if (usb_pipeisoc(pipe)) {
+			struct usb_iso_packet_descriptor *d;
+
+			d = urb->iso_frame_desc + qh->iso_idx;
+			d->actual_length = xfer_len;
+
+			/* even if there was an error, we did the dma
+			 * for iso_frame_desc->length
+			 */
+			if (d->status != -EILSEQ && d->status != -EOVERFLOW)
+				d->status = 0;
+
+			if (++qh->iso_idx >= urb->number_of_packets)
+				done = true;
+			else
+				done = false;
+
+		} else  {
+		/* done if urb buffer is full or short packet is recd */
+		done = (urb->actual_length + xfer_len >=
+				urb->transfer_buffer_length
+			|| dma->actual_len < qh->maxpacket);
+		}
+
+		/* send IN token for next packet, without AUTOREQ */
+		if (!done) {
+			val |= MUSB_RXCSR_H_REQPKT;
+			musb_writew(epio, MUSB_RXCSR,
+				MUSB_RXCSR_H_WZC_BITS | val);
+		}
+
+		dev_dbg(musb->controller, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum,
+			done ? "off" : "reset",
+			musb_readw(epio, MUSB_RXCSR),
+			musb_readw(epio, MUSB_RXCOUNT));
+#else
+		done = true;
+#endif
+	} else if (urb->status == -EINPROGRESS) {
+		/* if no errors, be sure a packet is ready for unloading */
+		if (unlikely(!(rx_csr & MUSB_RXCSR_RXPKTRDY))) {
+			status = -EPROTO;
+			ERR("Rx interrupt with no errors or packet!\n");
+
+			/* FIXME this is another "SHOULD NEVER HAPPEN" */
+
+/* SCRUB (RX) */
+			/* do the proper sequence to abort the transfer */
+			musb_ep_select(mbase, epnum);
+			val &= ~MUSB_RXCSR_H_REQPKT;
+			musb_writew(epio, MUSB_RXCSR, val);
+			goto finish;
+		}
+
+		/* we are expecting IN packets */
+#ifdef CONFIG_USB_INVENTRA_DMA
+		if (dma) {
+			struct dma_controller	*c;
+			u16			rx_count;
+			int			ret, length;
+			dma_addr_t		buf;
+
+			rx_count = musb_readw(epio, MUSB_RXCOUNT);
+
+			dev_dbg(musb->controller, "RX%d count %d, buffer 0x%x len %d/%d\n",
+					epnum, rx_count,
+					urb->transfer_dma
+						+ urb->actual_length,
+					qh->offset,
+					urb->transfer_buffer_length);
+
+			c = musb->dma_controller;
+
+			if (usb_pipeisoc(pipe)) {
+				int d_status = 0;
+				struct usb_iso_packet_descriptor *d;
+
+				d = urb->iso_frame_desc + qh->iso_idx;
+
+				if (iso_err) {
+					d_status = -EILSEQ;
+					urb->error_count++;
+				}
+				if (rx_count > d->length) {
+					if (d_status == 0) {
+						d_status = -EOVERFLOW;
+						urb->error_count++;
+					}
+					dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",\
+					    rx_count, d->length);
+
+					length = d->length;
+				} else
+					length = rx_count;
+				d->status = d_status;
+				buf = urb->transfer_dma + d->offset;
+			} else {
+				length = rx_count;
+				buf = urb->transfer_dma +
+						urb->actual_length;
+			}
+
+			dma->desired_mode = 0;
+#ifdef USE_MODE1
+			/* because of the issue below, mode 1 will
+			 * only rarely behave with correct semantics.
+			 */
+			if ((urb->transfer_flags &
+						URB_SHORT_NOT_OK)
+				&& (urb->transfer_buffer_length -
+						urb->actual_length)
+					> qh->maxpacket)
+				dma->desired_mode = 1;
+			if (rx_count < hw_ep->max_packet_sz_rx) {
+				length = rx_count;
+				dma->desired_mode = 0;
+			} else {
+				length = urb->transfer_buffer_length;
+			}
+#endif
+
+/* Disadvantage of using mode 1:
+ *	It's basically usable only for mass storage class; essentially all
+ *	other protocols also terminate transfers on short packets.
+ *
+ * Details:
+ *	An extra IN token is sent at the end of the transfer (due to AUTOREQ)
+ *	If you try to use mode 1 for (transfer_buffer_length - 512), and try
+ *	to use the extra IN token to grab the last packet using mode 0, then
+ *	the problem is that you cannot be sure when the device will send the
+ *	last packet and RxPktRdy set. Sometimes the packet is recd too soon
+ *	such that it gets lost when RxCSR is re-set at the end of the mode 1
+ *	transfer, while sometimes it is recd just a little late so that if you
+ *	try to configure for mode 0 soon after the mode 1 transfer is
+ *	completed, you will find rxcount 0. Okay, so you might think why not
+ *	wait for an interrupt when the pkt is recd. Well, you won't get any!
+ */
+
+			val = musb_readw(epio, MUSB_RXCSR);
+			val &= ~MUSB_RXCSR_H_REQPKT;
+
+			if (dma->desired_mode == 0)
+				val &= ~MUSB_RXCSR_H_AUTOREQ;
+			else
+				val |= MUSB_RXCSR_H_AUTOREQ;
+			val |= MUSB_RXCSR_DMAENAB;
+
+			/* autoclear shouldn't be set in high bandwidth */
+			if (qh->hb_mult == 1)
+				val |= MUSB_RXCSR_AUTOCLEAR;
+
+			musb_writew(epio, MUSB_RXCSR,
+				MUSB_RXCSR_H_WZC_BITS | val);
+
+			/* REVISIT if when actual_length != 0,
+			 * transfer_buffer_length needs to be
+			 * adjusted first...
+			 */
+			ret = c->channel_program(
+				dma, qh->maxpacket,
+				dma->desired_mode, buf, length);
+
+			if (!ret) {
+				c->channel_release(dma);
+				hw_ep->rx_channel = NULL;
+				dma = NULL;
+				val = musb_readw(epio, MUSB_RXCSR);
+				val &= ~(MUSB_RXCSR_DMAENAB
+					| MUSB_RXCSR_H_AUTOREQ
+					| MUSB_RXCSR_AUTOCLEAR);
+				musb_writew(epio, MUSB_RXCSR, val);
+			}
+		}
+#endif	/* Mentor DMA */
+
+		if (!dma) {
+			/* Unmap the buffer so that CPU can use it */
+			usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
+			done = musb_host_packet_rx(musb, urb,
+					epnum, iso_err);
+			dev_dbg(musb->controller, "read %spacket\n", done ? "last " : "");
+		}
+	}
+
+finish:
+	urb->actual_length += xfer_len;
+	qh->offset += xfer_len;
+	if (done) {
+		if (urb->status == -EINPROGRESS)
+			urb->status = status;
+		musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
+	}
+}
+
+/* schedule nodes correspond to peripheral endpoints, like an OHCI QH.
+ * the software schedule associates multiple such nodes with a given
+ * host side hardware endpoint + direction; scheduling may activate
+ * that hardware endpoint.
+ */
+static int musb_schedule(
+	struct musb		*musb,
+	struct musb_qh		*qh,
+	int			is_in)
+{
+	int			idle;
+	int			best_diff;
+	int			best_end, epnum;
+	struct musb_hw_ep	*hw_ep = NULL;
+	struct list_head	*head = NULL;
+	u8			toggle;
+	u8			txtype;
+	struct urb		*urb = next_urb(qh);
+
+	/* use fixed hardware for control and bulk */
+	if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+		head = &musb->control;
+		hw_ep = musb->control_ep;
+		goto success;
+	}
+
+	/* else, periodic transfers get muxed to other endpoints */
+
+	/*
+	 * We know this qh hasn't been scheduled, so all we need to do
+	 * is choose which hardware endpoint to put it on ...
+	 *
+	 * REVISIT what we really want here is a regular schedule tree
+	 * like e.g. OHCI uses.
+	 */
+	best_diff = 4096;
+	best_end = -1;
+
+	for (epnum = 1, hw_ep = musb->endpoints + 1;
+			epnum < musb->nr_endpoints;
+			epnum++, hw_ep++) {
+		int	diff;
+
+		if (musb_ep_get_qh(hw_ep, is_in) != NULL)
+			continue;
+
+		if (hw_ep == musb->bulk_ep)
+			continue;
+
+		if (is_in)
+			diff = hw_ep->max_packet_sz_rx;
+		else
+			diff = hw_ep->max_packet_sz_tx;
+		diff -= (qh->maxpacket * qh->hb_mult);
+
+		if (diff >= 0 && best_diff > diff) {
+
+			/*
+			 * Mentor controller has a bug in that if we schedule
+			 * a BULK Tx transfer on an endpoint that had earlier
+			 * handled ISOC then the BULK transfer has to start on
+			 * a zero toggle.  If the BULK transfer starts on a 1
+			 * toggle then this transfer will fail as the mentor
+			 * controller starts the Bulk transfer on a 0 toggle
+			 * irrespective of the programming of the toggle bits
+			 * in the TXCSR register.  Check for this condition
+			 * while allocating the EP for a Tx Bulk transfer.  If
+			 * so skip this EP.
+			 */
+			hw_ep = musb->endpoints + epnum;
+			toggle = usb_gettoggle(urb->dev, qh->epnum, !is_in);
+			txtype = (musb_readb(hw_ep->regs, MUSB_TXTYPE)
+					>> 4) & 0x3;
+			if (!is_in && (qh->type == USB_ENDPOINT_XFER_BULK) &&
+				toggle && (txtype == USB_ENDPOINT_XFER_ISOC))
+				continue;
+
+			best_diff = diff;
+			best_end = epnum;
+		}
+	}
+	/* use bulk reserved ep1 if no other ep is free */
+	if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
+		hw_ep = musb->bulk_ep;
+		if (is_in)
+			head = &musb->in_bulk;
+		else
+			head = &musb->out_bulk;
+
+		/* Enable bulk RX NAK timeout scheme when bulk requests are
+		 * multiplexed.  This scheme doen't work in high speed to full
+		 * speed scenario as NAK interrupts are not coming from a
+		 * full speed device connected to a high speed device.
+		 * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
+		 * 4 (8 frame or 8ms) for FS device.
+		 */
+		if (is_in && qh->dev)
+			qh->intv_reg =
+				(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
+		goto success;
+	} else if (best_end < 0) {
+		return -ENOSPC;
+	}
+
+	idle = 1;
+	qh->mux = 0;
+	hw_ep = musb->endpoints + best_end;
+	dev_dbg(musb->controller, "qh %p periodic slot %d\n", qh, best_end);
+success:
+	if (head) {
+		idle = list_empty(head);
+		list_add_tail(&qh->ring, head);
+		qh->mux = 1;
+	}
+	qh->hw_ep = hw_ep;
+	qh->hep->hcpriv = qh;
+	if (idle)
+		musb_start_urb(musb, is_in, qh);
+	return 0;
+}
+
+#ifdef __UBOOT__
+/* check if transaction translator is needed for device */
+static int tt_needed(struct musb *musb, struct usb_device *dev)
+{
+	if ((musb_readb(musb->mregs, MUSB_POWER) & MUSB_POWER_HSMODE) &&
+			(dev->speed < USB_SPEED_HIGH))
+		return 1;
+	return 0;
+}
+#endif
+
+#ifndef __UBOOT__
+static int musb_urb_enqueue(
+#else
+int musb_urb_enqueue(
+#endif
+	struct usb_hcd			*hcd,
+	struct urb			*urb,
+	gfp_t				mem_flags)
+{
+	unsigned long			flags;
+	struct musb			*musb = hcd_to_musb(hcd);
+	struct usb_host_endpoint	*hep = urb->ep;
+	struct musb_qh			*qh;
+	struct usb_endpoint_descriptor	*epd = &hep->desc;
+	int				ret;
+	unsigned			type_reg;
+	unsigned			interval;
+
+	/* host role must be active */
+	if (!is_host_active(musb) || !musb->is_active)
+		return -ENODEV;
+
+	spin_lock_irqsave(&musb->lock, flags);
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	qh = ret ? NULL : hep->hcpriv;
+	if (qh)
+		urb->hcpriv = qh;
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	/* DMA mapping was already done, if needed, and this urb is on
+	 * hep->urb_list now ... so we're done, unless hep wasn't yet
+	 * scheduled onto a live qh.
+	 *
+	 * REVISIT best to keep hep->hcpriv valid until the endpoint gets
+	 * disabled, testing for empty qh->ring and avoiding qh setup costs
+	 * except for the first urb queued after a config change.
+	 */
+	if (qh || ret)
+		return ret;
+
+	/* Allocate and initialize qh, minimizing the work done each time
+	 * hw_ep gets reprogrammed, or with irqs blocked.  Then schedule it.
+	 *
+	 * REVISIT consider a dedicated qh kmem_cache, so it's harder
+	 * for bugs in other kernel code to break this driver...
+	 */
+	qh = kzalloc(sizeof *qh, mem_flags);
+	if (!qh) {
+		spin_lock_irqsave(&musb->lock, flags);
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+		spin_unlock_irqrestore(&musb->lock, flags);
+		return -ENOMEM;
+	}
+
+	qh->hep = hep;
+	qh->dev = urb->dev;
+	INIT_LIST_HEAD(&qh->ring);
+	qh->is_ready = 1;
+
+	qh->maxpacket = usb_endpoint_maxp(epd);
+	qh->type = usb_endpoint_type(epd);
+
+	/* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
+	 * Some musb cores don't support high bandwidth ISO transfers; and
+	 * we don't (yet!) support high bandwidth interrupt transfers.
+	 */
+	qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03);
+	if (qh->hb_mult > 1) {
+		int ok = (qh->type == USB_ENDPOINT_XFER_ISOC);
+
+		if (ok)
+			ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx)
+				|| (usb_pipeout(urb->pipe) && musb->hb_iso_tx);
+		if (!ok) {
+			ret = -EMSGSIZE;
+			goto done;
+		}
+		qh->maxpacket &= 0x7ff;
+	}
+
+	qh->epnum = usb_endpoint_num(epd);
+
+	/* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
+	qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
+
+	/* precompute rxtype/txtype/type0 register */
+	type_reg = (qh->type << 4) | qh->epnum;
+	switch (urb->dev->speed) {
+	case USB_SPEED_LOW:
+		type_reg |= 0xc0;
+		break;
+	case USB_SPEED_FULL:
+		type_reg |= 0x80;
+		break;
+	default:
+		type_reg |= 0x40;
+	}
+	qh->type_reg = type_reg;
+
+	/* Precompute RXINTERVAL/TXINTERVAL register */
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		/*
+		 * Full/low speeds use the  linear encoding,
+		 * high speed uses the logarithmic encoding.
+		 */
+		if (urb->dev->speed <= USB_SPEED_FULL) {
+			interval = max_t(u8, epd->bInterval, 1);
+			break;
+		}
+		/* FALLTHROUGH */
+	case USB_ENDPOINT_XFER_ISOC:
+		/* ISO always uses logarithmic encoding */
+		interval = min_t(u8, epd->bInterval, 16);
+		break;
+	default:
+		/* REVISIT we actually want to use NAK limits, hinting to the
+		 * transfer scheduling logic to try some other qh, e.g. try
+		 * for 2 msec first:
+		 *
+		 * interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16 : 2;
+		 *
+		 * The downside of disabling this is that transfer scheduling
+		 * gets VERY unfair for nonperiodic transfers; a misbehaving
+		 * peripheral could make that hurt.  That's perfectly normal
+		 * for reads from network or serial adapters ... so we have
+		 * partial NAKlimit support for bulk RX.
+		 *
+		 * The upside of disabling it is simpler transfer scheduling.
+		 */
+		interval = 0;
+	}
+	qh->intv_reg = interval;
+
+	/* precompute addressing for external hub/tt ports */
+	if (musb->is_multipoint) {
+#ifndef __UBOOT__
+		struct usb_device	*parent = urb->dev->parent;
+#else
+		struct usb_device	*parent = usb_dev_get_parent(urb->dev);
+#endif
+
+#ifndef __UBOOT__
+		if (parent != hcd->self.root_hub) {
+#else
+		if (parent) {
+#endif
+			qh->h_addr_reg = (u8) parent->devnum;
+
+#ifndef __UBOOT__
+			/* set up tt info if needed */
+			if (urb->dev->tt) {
+				qh->h_port_reg = (u8) urb->dev->ttport;
+				if (urb->dev->tt->hub)
+					qh->h_addr_reg =
+						(u8) urb->dev->tt->hub->devnum;
+				if (urb->dev->tt->multi)
+					qh->h_addr_reg |= 0x80;
+			}
+#else
+			if (tt_needed(musb, urb->dev)) {
+				uint8_t portnr = 0;
+				uint8_t hubaddr = 0;
+				usb_find_usb2_hub_address_port(urb->dev,
+							       &hubaddr,
+							       &portnr);
+				qh->h_addr_reg = hubaddr;
+				qh->h_port_reg = portnr;
+			}
+#endif
+		}
+	}
+
+	/* invariant: hep->hcpriv is null OR the qh that's already scheduled.
+	 * until we get real dma queues (with an entry for each urb/buffer),
+	 * we only have work to do in the former case.
+	 */
+	spin_lock_irqsave(&musb->lock, flags);
+	if (hep->hcpriv) {
+		/* some concurrent activity submitted another urb to hep...
+		 * odd, rare, error prone, but legal.
+		 */
+		kfree(qh);
+		qh = NULL;
+		ret = 0;
+	} else
+		ret = musb_schedule(musb, qh,
+				epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
+
+	if (ret == 0) {
+		urb->hcpriv = qh;
+		/* FIXME set urb->start_frame for iso/intr, it's tested in
+		 * musb_start_urb(), but otherwise only konicawc cares ...
+		 */
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+done:
+	if (ret != 0) {
+		spin_lock_irqsave(&musb->lock, flags);
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+		spin_unlock_irqrestore(&musb->lock, flags);
+		kfree(qh);
+	}
+	return ret;
+}
+
+/*
+ * abort a transfer that's at the head of a hardware queue.
+ * called with controller locked, irqs blocked
+ * that hardware queue advances to the next transfer, unless prevented
+ */
+static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
+{
+	struct musb_hw_ep	*ep = qh->hw_ep;
+	struct musb		*musb = ep->musb;
+	void __iomem		*epio = ep->regs;
+	unsigned		hw_end = ep->epnum;
+	void __iomem		*regs = ep->musb->mregs;
+	int			is_in = usb_pipein(urb->pipe);
+	int			status = 0;
+	u16			csr;
+
+	musb_ep_select(regs, hw_end);
+
+	if (is_dma_capable()) {
+		struct dma_channel	*dma;
+
+		dma = is_in ? ep->rx_channel : ep->tx_channel;
+		if (dma) {
+			status = ep->musb->dma_controller->channel_abort(dma);
+			dev_dbg(musb->controller,
+				"abort %cX%d DMA for urb %p --> %d\n",
+				is_in ? 'R' : 'T', ep->epnum,
+				urb, status);
+			urb->actual_length += dma->actual_len;
+		}
+	}
+
+	/* turn off DMA requests, discard state, stop polling ... */
+	if (ep->epnum && is_in) {
+		/* giveback saves bulk toggle */
+		csr = musb_h_flush_rxfifo(ep, 0);
+
+		/* REVISIT we still get an irq; should likely clear the
+		 * endpoint's irq status here to avoid bogus irqs.
+		 * clearing that status is platform-specific...
+		 */
+	} else if (ep->epnum) {
+		musb_h_tx_flush_fifo(ep);
+		csr = musb_readw(epio, MUSB_TXCSR);
+		csr &= ~(MUSB_TXCSR_AUTOSET
+			| MUSB_TXCSR_DMAENAB
+			| MUSB_TXCSR_H_RXSTALL
+			| MUSB_TXCSR_H_NAKTIMEOUT
+			| MUSB_TXCSR_H_ERROR
+			| MUSB_TXCSR_TXPKTRDY);
+		musb_writew(epio, MUSB_TXCSR, csr);
+		/* REVISIT may need to clear FLUSHFIFO ... */
+		musb_writew(epio, MUSB_TXCSR, csr);
+		/* flush cpu writebuffer */
+		csr = musb_readw(epio, MUSB_TXCSR);
+	} else  {
+		musb_h_ep0_flush_fifo(ep);
+	}
+	if (status == 0)
+		musb_advance_schedule(ep->musb, urb, ep, is_in);
+	return status;
+}
+
+#ifndef __UBOOT__
+static int musb_urb_dequeue(
+#else
+int musb_urb_dequeue(
+#endif
+	struct usb_hcd *hcd,
+	struct urb *urb,
+	int status)
+{
+	struct musb		*musb = hcd_to_musb(hcd);
+	struct musb_qh		*qh;
+	unsigned long		flags;
+	int			is_in  = usb_pipein(urb->pipe);
+	int			ret;
+
+	dev_dbg(musb->controller, "urb=%p, dev%d ep%d%s\n", urb,
+			usb_pipedevice(urb->pipe),
+			usb_pipeendpoint(urb->pipe),
+			is_in ? "in" : "out");
+
+	spin_lock_irqsave(&musb->lock, flags);
+	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (ret)
+		goto done;
+
+	qh = urb->hcpriv;
+	if (!qh)
+		goto done;
+
+	/*
+	 * Any URB not actively programmed into endpoint hardware can be
+	 * immediately given back; that's any URB not at the head of an
+	 * endpoint queue, unless someday we get real DMA queues.  And even
+	 * if it's at the head, it might not be known to the hardware...
+	 *
+	 * Otherwise abort current transfer, pending DMA, etc.; urb->status
+	 * has already been updated.  This is a synchronous abort; it'd be
+	 * OK to hold off until after some IRQ, though.
+	 *
+	 * NOTE: qh is invalid unless !list_empty(&hep->urb_list)
+	 */
+	if (!qh->is_ready
+			|| urb->urb_list.prev != &qh->hep->urb_list
+			|| musb_ep_get_qh(qh->hw_ep, is_in) != qh) {
+		int	ready = qh->is_ready;
+
+		qh->is_ready = 0;
+		musb_giveback(musb, urb, 0);
+		qh->is_ready = ready;
+
+		/* If nothing else (usually musb_giveback) is using it
+		 * and its URB list has emptied, recycle this qh.
+		 */
+		if (ready && list_empty(&qh->hep->urb_list)) {
+			qh->hep->hcpriv = NULL;
+			list_del(&qh->ring);
+			kfree(qh);
+		}
+	} else
+		ret = musb_cleanup_urb(urb, qh);
+done:
+	spin_unlock_irqrestore(&musb->lock, flags);
+	return ret;
+}
+
+#ifndef __UBOOT__
+/* disable an endpoint */
+static void
+musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+{
+	u8			is_in = hep->desc.bEndpointAddress & USB_DIR_IN;
+	unsigned long		flags;
+	struct musb		*musb = hcd_to_musb(hcd);
+	struct musb_qh		*qh;
+	struct urb		*urb;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	qh = hep->hcpriv;
+	if (qh == NULL)
+		goto exit;
+
+	/* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
+
+	/* Kick the first URB off the hardware, if needed */
+	qh->is_ready = 0;
+	if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) {
+		urb = next_urb(qh);
+
+		/* make software (then hardware) stop ASAP */
+		if (!urb->unlinked)
+			urb->status = -ESHUTDOWN;
+
+		/* cleanup */
+		musb_cleanup_urb(urb, qh);
+
+		/* Then nuke all the others ... and advance the
+		 * queue on hw_ep (e.g. bulk ring) when we're done.
+		 */
+		while (!list_empty(&hep->urb_list)) {
+			urb = next_urb(qh);
+			urb->status = -ESHUTDOWN;
+			musb_advance_schedule(musb, urb, qh->hw_ep, is_in);
+		}
+	} else {
+		/* Just empty the queue; the hardware is busy with
+		 * other transfers, and since !qh->is_ready nothing
+		 * will activate any of these as it advances.
+		 */
+		while (!list_empty(&hep->urb_list))
+			musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
+
+		hep->hcpriv = NULL;
+		list_del(&qh->ring);
+		kfree(qh);
+	}
+exit:
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static int musb_h_get_frame_number(struct usb_hcd *hcd)
+{
+	struct musb	*musb = hcd_to_musb(hcd);
+
+	return musb_readw(musb->mregs, MUSB_FRAME);
+}
+
+static int musb_h_start(struct usb_hcd *hcd)
+{
+	struct musb	*musb = hcd_to_musb(hcd);
+
+	/* NOTE: musb_start() is called when the hub driver turns
+	 * on port power, or when (OTG) peripheral starts.
+	 */
+	hcd->state = HC_STATE_RUNNING;
+	musb->port1_status = 0;
+	return 0;
+}
+
+static void musb_h_stop(struct usb_hcd *hcd)
+{
+	musb_stop(hcd_to_musb(hcd));
+	hcd->state = HC_STATE_HALT;
+}
+
+static int musb_bus_suspend(struct usb_hcd *hcd)
+{
+	struct musb	*musb = hcd_to_musb(hcd);
+	u8		devctl;
+
+	if (!is_host_active(musb))
+		return 0;
+
+	switch (musb->xceiv->state) {
+	case OTG_STATE_A_SUSPEND:
+		return 0;
+	case OTG_STATE_A_WAIT_VRISE:
+		/* ID could be grounded even if there's no device
+		 * on the other end of the cable.  NOTE that the
+		 * A_WAIT_VRISE timers are messy with MUSB...
+		 */
+		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+			musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+		break;
+	default:
+		break;
+	}
+
+	if (musb->is_active) {
+		WARNING("trying to suspend as %s while active\n",
+				otg_state_string(musb->xceiv->state));
+		return -EBUSY;
+	} else
+		return 0;
+}
+
+static int musb_bus_resume(struct usb_hcd *hcd)
+{
+	/* resuming child port does the work */
+	return 0;
+}
+
+const struct hc_driver musb_hc_driver = {
+	.description		= "musb-hcd",
+	.product_desc		= "MUSB HDRC host driver",
+	.hcd_priv_size		= sizeof(struct musb),
+	.flags			= HCD_USB2 | HCD_MEMORY,
+
+	/* not using irq handler or reset hooks from usbcore, since
+	 * those must be shared with peripheral code for OTG configs
+	 */
+
+	.start			= musb_h_start,
+	.stop			= musb_h_stop,
+
+	.get_frame_number	= musb_h_get_frame_number,
+
+	.urb_enqueue		= musb_urb_enqueue,
+	.urb_dequeue		= musb_urb_dequeue,
+	.endpoint_disable	= musb_h_disable,
+
+	.hub_status_data	= musb_hub_status_data,
+	.hub_control		= musb_hub_control,
+	.bus_suspend		= musb_bus_suspend,
+	.bus_resume		= musb_bus_resume,
+	/* .start_port_reset	= NULL, */
+	/* .hub_irq_enable	= NULL, */
+};
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_host.h b/roms/u-boot/drivers/usb/musb-new/musb_host.h
new file mode 100644
index 000000000..afc8fa35a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_host.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver host defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+#ifndef _MUSB_HOST_H
+#define _MUSB_HOST_H
+#ifdef __UBOOT__
+#include "usb-compat.h"
+#endif
+
+static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
+{
+	return container_of((void *) musb, struct usb_hcd, hcd_priv);
+}
+
+static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
+{
+	return (struct musb *) (hcd->hcd_priv);
+}
+
+/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */
+struct musb_qh {
+	struct usb_host_endpoint *hep;		/* usbcore info */
+	struct usb_device	*dev;
+	struct musb_hw_ep	*hw_ep;		/* current binding */
+
+	struct list_head	ring;		/* of musb_qh */
+	/* struct musb_qh		*next; */	/* for periodic tree */
+	u8			mux;		/* qh multiplexed to hw_ep */
+
+	unsigned		offset;		/* in urb->transfer_buffer */
+	unsigned		segsize;	/* current xfer fragment */
+
+	u8			type_reg;	/* {rx,tx} type register */
+	u8			intv_reg;	/* {rx,tx} interval register */
+	u8			addr_reg;	/* device address register */
+	u8			h_addr_reg;	/* hub address register */
+	u8			h_port_reg;	/* hub port register */
+
+	u8			is_ready;	/* safe to modify hw_ep */
+	u8			type;		/* XFERTYPE_* */
+	u8			epnum;
+	u8			hb_mult;	/* high bandwidth pkts per uf */
+	u16			maxpacket;
+	u16			frame;		/* for periodic schedule */
+	unsigned		iso_idx;	/* in urb->iso_frame_desc[] */
+};
+
+/* map from control or bulk queue head to the first qh on that ring */
+static inline struct musb_qh *first_qh(struct list_head *q)
+{
+	if (list_empty(q))
+		return NULL;
+	return list_entry(q->next, struct musb_qh, ring);
+}
+
+
+extern void musb_root_disconnect(struct musb *musb);
+
+struct usb_hcd;
+
+extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int musb_hub_control(struct usb_hcd *hcd,
+			u16 typeReq, u16 wValue, u16 wIndex,
+			char *buf, u16 wLength);
+
+extern const struct hc_driver musb_hc_driver;
+
+static inline struct urb *next_urb(struct musb_qh *qh)
+{
+	struct list_head	*queue;
+
+	if (!qh)
+		return NULL;
+	queue = &qh->hep->urb_list;
+	if (list_empty(queue))
+		return NULL;
+	return list_entry(queue->next, struct urb, urb_list);
+}
+
+#ifdef __UBOOT__
+int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+#endif
+#endif				/* _MUSB_HOST_H */
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_io.h b/roms/u-boot/drivers/usb/musb-new/musb_io.h
new file mode 100644
index 000000000..72a536563
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_io.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver register I/O
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
+#define __MUSB_LINUX_PLATFORM_ARCH_H__
+
+#ifndef __UBOOT__
+#include <linux/io.h>
+#else
+#include <asm/io.h>
+#endif
+
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
+	&& !defined(CONFIG_PPC32) \
+	&& !defined(CONFIG_PPC64) && !defined(CONFIG_MIPS) \
+	&& !defined(CONFIG_M68K)
+static inline void readsl(const void __iomem *addr, void *buf, int len)
+	{ insl((unsigned long)addr, buf, len); }
+static inline void readsw(const void __iomem *addr, void *buf, int len)
+	{ insw((unsigned long)addr, buf, len); }
+static inline void readsb(const void __iomem *addr, void *buf, int len)
+	{ insb((unsigned long)addr, buf, len); }
+
+static inline void writesl(const void __iomem *addr, const void *buf, int len)
+	{ outsl((unsigned long)addr, buf, len); }
+static inline void writesw(const void __iomem *addr, const void *buf, int len)
+	{ outsw((unsigned long)addr, buf, len); }
+static inline void writesb(const void __iomem *addr, const void *buf, int len)
+	{ outsb((unsigned long)addr, buf, len); }
+
+#endif
+
+/* NOTE:  these offsets are all in bytes */
+
+static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
+	{ return __raw_readw(addr + offset); }
+
+static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
+	{ return __raw_readl(addr + offset); }
+
+
+static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
+	{ __raw_writew(data, addr + offset); }
+
+static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
+	{ __raw_writel(data, addr + offset); }
+
+
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
+
+/*
+ * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
+ */
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+{
+	u16 tmp;
+	u8 val;
+
+	tmp = __raw_readw(addr + (offset & ~1));
+	if (offset & 1)
+		val = (tmp >> 8);
+	else
+		val = tmp & 0xff;
+
+	return val;
+}
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+	u16 tmp;
+
+	tmp = __raw_readw(addr + (offset & ~1));
+	if (offset & 1)
+		tmp = (data << 8) | (tmp & 0xff);
+	else
+		tmp = (tmp & 0xff00) | data;
+
+	__raw_writew(tmp, addr + (offset & ~1));
+}
+
+#else
+
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+	{ return __raw_readb(addr + offset); }
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+	{ __raw_writeb(data, addr + offset); }
+
+#endif	/* CONFIG_USB_MUSB_TUSB6010 */
+
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_regs.h b/roms/u-boot/drivers/usb/musb-new/musb_regs.h
new file mode 100644
index 000000000..e9362f6de
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_regs.h
@@ -0,0 +1,526 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MUSB OTG driver register defines
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2006-2007 Nokia Corporation
+ */
+
+#ifndef __MUSB_REGS_H__
+#define __MUSB_REGS_H__
+
+#define MUSB_EP0_FIFOSIZE	64	/* This is non-configurable */
+
+/*
+ * MUSB Register bits
+ */
+
+/* POWER */
+#define MUSB_POWER_ISOUPDATE	0x80
+#define MUSB_POWER_SOFTCONN	0x40
+#define MUSB_POWER_HSENAB	0x20
+#define MUSB_POWER_HSMODE	0x10
+#define MUSB_POWER_RESET	0x08
+#define MUSB_POWER_RESUME	0x04
+#define MUSB_POWER_SUSPENDM	0x02
+#define MUSB_POWER_ENSUSPEND	0x01
+
+/* INTRUSB */
+#define MUSB_INTR_SUSPEND	0x01
+#define MUSB_INTR_RESUME	0x02
+#define MUSB_INTR_RESET		0x04
+#define MUSB_INTR_BABBLE	0x04
+#define MUSB_INTR_SOF		0x08
+#define MUSB_INTR_CONNECT	0x10
+#define MUSB_INTR_DISCONNECT	0x20
+#define MUSB_INTR_SESSREQ	0x40
+#define MUSB_INTR_VBUSERROR	0x80	/* For SESSION end */
+
+/* DEVCTL */
+#define MUSB_DEVCTL_BDEVICE	0x80
+#define MUSB_DEVCTL_FSDEV	0x40
+#define MUSB_DEVCTL_LSDEV	0x20
+#define MUSB_DEVCTL_VBUS	0x18
+#define MUSB_DEVCTL_VBUS_SHIFT	3
+#define MUSB_DEVCTL_HM		0x04
+#define MUSB_DEVCTL_HR		0x02
+#define MUSB_DEVCTL_SESSION	0x01
+
+/* MUSB ULPI VBUSCONTROL */
+#define MUSB_ULPI_USE_EXTVBUS	0x01
+#define MUSB_ULPI_USE_EXTVBUSIND 0x02
+/* ULPI_REG_CONTROL */
+#define MUSB_ULPI_REG_REQ	(1 << 0)
+#define MUSB_ULPI_REG_CMPLT	(1 << 1)
+#define MUSB_ULPI_RDN_WR	(1 << 2)
+
+/* TESTMODE */
+#define MUSB_TEST_FORCE_HOST	0x80
+#define MUSB_TEST_FIFO_ACCESS	0x40
+#define MUSB_TEST_FORCE_FS	0x20
+#define MUSB_TEST_FORCE_HS	0x10
+#define MUSB_TEST_PACKET	0x08
+#define MUSB_TEST_K		0x04
+#define MUSB_TEST_J		0x02
+#define MUSB_TEST_SE0_NAK	0x01
+
+/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MUSB_FIFOSZ_DPB	0x10
+/* Allocation size (8, 16, 32, ... 4096) */
+#define MUSB_FIFOSZ_SIZE	0x0f
+
+/* CSR0 */
+#define MUSB_CSR0_FLUSHFIFO	0x0100
+#define MUSB_CSR0_TXPKTRDY	0x0002
+#define MUSB_CSR0_RXPKTRDY	0x0001
+
+/* CSR0 in Peripheral mode */
+#define MUSB_CSR0_P_SVDSETUPEND	0x0080
+#define MUSB_CSR0_P_SVDRXPKTRDY	0x0040
+#define MUSB_CSR0_P_SENDSTALL	0x0020
+#define MUSB_CSR0_P_SETUPEND	0x0010
+#define MUSB_CSR0_P_DATAEND	0x0008
+#define MUSB_CSR0_P_SENTSTALL	0x0004
+
+/* CSR0 in Host mode */
+#define MUSB_CSR0_H_DIS_PING		0x0800
+#define MUSB_CSR0_H_WR_DATATOGGLE	0x0400	/* Set to allow setting: */
+#define MUSB_CSR0_H_DATATOGGLE		0x0200	/* Data toggle control */
+#define MUSB_CSR0_H_NAKTIMEOUT		0x0080
+#define MUSB_CSR0_H_STATUSPKT		0x0040
+#define MUSB_CSR0_H_REQPKT		0x0020
+#define MUSB_CSR0_H_ERROR		0x0010
+#define MUSB_CSR0_H_SETUPPKT		0x0008
+#define MUSB_CSR0_H_RXSTALL		0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_CSR0_P_WZC_BITS	\
+	(MUSB_CSR0_P_SENTSTALL)
+#define MUSB_CSR0_H_WZC_BITS	\
+	(MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
+	| MUSB_CSR0_RXPKTRDY)
+
+/* TxType/RxType */
+#define MUSB_TYPE_SPEED		0xc0
+#define MUSB_TYPE_SPEED_SHIFT	6
+#define MUSB_TYPE_PROTO		0x30	/* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_SHIFT	4
+#define MUSB_TYPE_REMOTE_END	0xf	/* Implicitly zero for ep0 */
+
+/* CONFIGDATA */
+#define MUSB_CONFIGDATA_MPRXE		0x80	/* Auto bulk pkt combining */
+#define MUSB_CONFIGDATA_MPTXE		0x40	/* Auto bulk pkt splitting */
+#define MUSB_CONFIGDATA_BIGENDIAN	0x20
+#define MUSB_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */
+#define MUSB_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */
+#define MUSB_CONFIGDATA_DYNFIFO		0x04	/* Dynamic FIFO sizing */
+#define MUSB_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */
+#define MUSB_CONFIGDATA_UTMIDW		0x01	/* Data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+#define MUSB_TXCSR_AUTOSET		0x8000
+#define MUSB_TXCSR_DMAENAB		0x1000
+#define MUSB_TXCSR_FRCDATATOG		0x0800
+#define MUSB_TXCSR_DMAMODE		0x0400
+#define MUSB_TXCSR_CLRDATATOG		0x0040
+#define MUSB_TXCSR_FLUSHFIFO		0x0008
+#define MUSB_TXCSR_FIFONOTEMPTY		0x0002
+#define MUSB_TXCSR_TXPKTRDY		0x0001
+
+/* TXCSR in Peripheral mode */
+#define MUSB_TXCSR_P_ISO		0x4000
+#define MUSB_TXCSR_P_INCOMPTX		0x0080
+#define MUSB_TXCSR_P_SENTSTALL		0x0020
+#define MUSB_TXCSR_P_SENDSTALL		0x0010
+#define MUSB_TXCSR_P_UNDERRUN		0x0004
+
+/* TXCSR in Host mode */
+#define MUSB_TXCSR_H_WR_DATATOGGLE	0x0200
+#define MUSB_TXCSR_H_DATATOGGLE		0x0100
+#define MUSB_TXCSR_H_NAKTIMEOUT		0x0080
+#define MUSB_TXCSR_H_RXSTALL		0x0020
+#define MUSB_TXCSR_H_ERROR		0x0004
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_TXCSR_P_WZC_BITS	\
+	(MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
+	| MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
+#define MUSB_TXCSR_H_WZC_BITS	\
+	(MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+	| MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
+
+/* RXCSR in Peripheral and Host mode */
+#define MUSB_RXCSR_AUTOCLEAR		0x8000
+#define MUSB_RXCSR_DMAENAB		0x2000
+#define MUSB_RXCSR_DISNYET		0x1000
+#define MUSB_RXCSR_PID_ERR		0x1000
+#define MUSB_RXCSR_DMAMODE		0x0800
+#define MUSB_RXCSR_INCOMPRX		0x0100
+#define MUSB_RXCSR_CLRDATATOG		0x0080
+#define MUSB_RXCSR_FLUSHFIFO		0x0010
+#define MUSB_RXCSR_DATAERROR		0x0008
+#define MUSB_RXCSR_FIFOFULL		0x0002
+#define MUSB_RXCSR_RXPKTRDY		0x0001
+
+/* RXCSR in Peripheral mode */
+#define MUSB_RXCSR_P_ISO		0x4000
+#define MUSB_RXCSR_P_SENTSTALL		0x0040
+#define MUSB_RXCSR_P_SENDSTALL		0x0020
+#define MUSB_RXCSR_P_OVERRUN		0x0004
+
+/* RXCSR in Host mode */
+#define MUSB_RXCSR_H_AUTOREQ		0x4000
+#define MUSB_RXCSR_H_WR_DATATOGGLE	0x0400
+#define MUSB_RXCSR_H_DATATOGGLE		0x0200
+#define MUSB_RXCSR_H_RXSTALL		0x0040
+#define MUSB_RXCSR_H_REQPKT		0x0020
+#define MUSB_RXCSR_H_ERROR		0x0004
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_RXCSR_P_WZC_BITS	\
+	(MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
+	| MUSB_RXCSR_RXPKTRDY)
+#define MUSB_RXCSR_H_WZC_BITS	\
+	(MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
+	| MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
+
+/* HUBADDR */
+#define MUSB_HUBADDR_MULTI_TT		0x80
+
+
+/* SUNXI has different reg addresses, but identical r/w functions */
+#ifndef CONFIG_ARCH_SUNXI 
+
+/*
+ * Common USB registers
+ */
+
+#define MUSB_FADDR		0x00	/* 8-bit */
+#define MUSB_POWER		0x01	/* 8-bit */
+
+#define MUSB_INTRTX		0x02	/* 16-bit */
+#define MUSB_INTRRX		0x04
+#define MUSB_INTRTXE		0x06
+#define MUSB_INTRRXE		0x08
+#define MUSB_INTRUSB		0x0A	/* 8 bit */
+#define MUSB_INTRUSBE		0x0B	/* 8 bit */
+#define MUSB_FRAME		0x0C
+#define MUSB_INDEX		0x0E	/* 8 bit */
+#define MUSB_TESTMODE		0x0F	/* 8 bit */
+
+/* Get offset for a given FIFO from musb->mregs */
+#if defined(CONFIG_USB_MUSB_TUSB6010) ||	\
+	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+#define MUSB_FIFO_OFFSET(epnum)	(0x200 + ((epnum) * 0x20))
+#else
+#define MUSB_FIFO_OFFSET(epnum)	(0x20 + ((epnum) * 4))
+#endif
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL		0x60	/* 8 bit */
+
+/* These are always controlled through the INDEX register */
+#define MUSB_TXFIFOSZ		0x62	/* 8-bit (see masks) */
+#define MUSB_RXFIFOSZ		0x63	/* 8-bit (see masks) */
+#define MUSB_TXFIFOADD		0x64	/* 16-bit offset shifted right 3 */
+#define MUSB_RXFIFOADD		0x66	/* 16-bit offset shifted right 3 */
+
+/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
+#define MUSB_HWVERS		0x6C	/* 8 bit */
+#define MUSB_ULPI_BUSCONTROL	0x70	/* 8 bit */
+#define MUSB_ULPI_INT_MASK	0x72	/* 8 bit */
+#define MUSB_ULPI_INT_SRC	0x73	/* 8 bit */
+#define MUSB_ULPI_REG_DATA	0x74	/* 8 bit */
+#define MUSB_ULPI_REG_ADDR	0x75	/* 8 bit */
+#define MUSB_ULPI_REG_CONTROL	0x76	/* 8 bit */
+#define MUSB_ULPI_RAW_DATA	0x77	/* 8 bit */
+
+#define MUSB_EPINFO		0x78	/* 8 bit */
+#define MUSB_RAMINFO		0x79	/* 8 bit */
+#define MUSB_LINKINFO		0x7a	/* 8 bit */
+#define MUSB_VPLEN		0x7b	/* 8 bit */
+#define MUSB_HS_EOF1		0x7c	/* 8 bit */
+#define MUSB_FS_EOF1		0x7d	/* 8 bit */
+#define MUSB_LS_EOF1		0x7e	/* 8 bit */
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP		0x00
+#define MUSB_TXCSR		0x02
+#define MUSB_CSR0		MUSB_TXCSR	/* Re-used for EP0 */
+#define MUSB_RXMAXP		0x04
+#define MUSB_RXCSR		0x06
+#define MUSB_RXCOUNT		0x08
+#define MUSB_COUNT0		MUSB_RXCOUNT	/* Re-used for EP0 */
+#define MUSB_TXTYPE		0x0A
+#define MUSB_TYPE0		MUSB_TXTYPE	/* Re-used for EP0 */
+#define MUSB_TXINTERVAL		0x0B
+#define MUSB_NAKLIMIT0		MUSB_TXINTERVAL	/* Re-used for EP0 */
+#define MUSB_RXTYPE		0x0C
+#define MUSB_RXINTERVAL		0x0D
+#define MUSB_FIFOSIZE		0x0F
+#define MUSB_CONFIGDATA		MUSB_FIFOSIZE	/* Re-used for EP0 */
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset)	\
+	(0x10 + (_offset))
+
+/* Offsets to endpoint registers in flat models */
+#define MUSB_FLAT_OFFSET(_epnum, _offset)	\
+	(0x100 + (0x10*(_epnum)) + (_offset))
+
+#if defined(CONFIG_USB_MUSB_TUSB6010) ||	\
+	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+/* TUSB6010 EP0 configuration register is special */
+#define MUSB_TUSB_OFFSET(_epnum, _offset)	\
+	(0x10 + _offset)
+#include "tusb6010.h"		/* Needed "only" for TUSB_EP0_CONF */
+#endif
+
+#define MUSB_TXCSR_MODE			0x2000
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MUSB_TXFUNCADDR		0x00
+#define MUSB_TXHUBADDR		0x02
+#define MUSB_TXHUBPORT		0x03
+
+#define MUSB_RXFUNCADDR		0x04
+#define MUSB_RXHUBADDR		0x06
+#define MUSB_RXHUBPORT		0x07
+
+#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
+	(0x80 + (8*(_epnum)) + (_offset))
+
+#else /* CONFIG_ARCH_SUNXI */
+
+/*
+ * Common USB registers
+ */
+
+#define MUSB_FADDR		0x0098
+#define MUSB_POWER		0x0040
+
+#define MUSB_INTRTX		0x0044
+#define MUSB_INTRRX		0x0046
+#define MUSB_INTRTXE		0x0048
+#define MUSB_INTRRXE		0x004A
+#define MUSB_INTRUSB		0x004C
+#define MUSB_INTRUSBE		0x0050
+#define MUSB_FRAME		0x0054
+#define MUSB_INDEX		0x0042
+#define MUSB_TESTMODE		0x007C
+
+/* Get offset for a given FIFO from musb->mregs */
+#define MUSB_FIFO_OFFSET(epnum)	(0x00 + ((epnum) * 4))
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL		0x0041
+
+/* These are always controlled through the INDEX register */
+#define MUSB_TXFIFOSZ		0x0090
+#define MUSB_RXFIFOSZ		0x0094
+#define MUSB_TXFIFOADD		0x0092
+#define MUSB_RXFIFOADD		0x0096
+
+#define MUSB_EPINFO		0x0078
+#define MUSB_RAMINFO		0x0079
+#define MUSB_LINKINFO		0x007A
+#define MUSB_VPLEN		0x007B
+#define MUSB_HS_EOF1		0x007C
+#define MUSB_FS_EOF1		0x007D
+#define MUSB_LS_EOF1		0x007E
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP		0x0080
+#define MUSB_TXCSR		0x0082
+#define MUSB_CSR0		0x0082
+#define MUSB_RXMAXP		0x0084
+#define MUSB_RXCSR		0x0086
+#define MUSB_RXCOUNT		0x0088
+#define MUSB_COUNT0		0x0088
+#define MUSB_TXTYPE		0x008C
+#define MUSB_TYPE0		0x008C
+#define MUSB_TXINTERVAL		0x008D
+#define MUSB_NAKLIMIT0		0x008D
+#define MUSB_RXTYPE		0x008E
+#define MUSB_RXINTERVAL		0x008F
+
+#define MUSB_CONFIGDATA		0x00b0 /* musb_read_configdata adds 0x10 ! */
+#define MUSB_FIFOSIZE		0x0090
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset) (_offset)
+
+#define MUSB_TXCSR_MODE		0x2000
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MUSB_TXFUNCADDR		0x0098
+#define MUSB_TXHUBADDR		0x009A
+#define MUSB_TXHUBPORT		0x009B
+
+#define MUSB_RXFUNCADDR		0x009C
+#define MUSB_RXHUBADDR		0x009E
+#define MUSB_RXHUBPORT		0x009F
+
+/* Endpoint is selected with MUSB_INDEX. */
+#define MUSB_BUSCTL_OFFSET(_epnum, _offset) (_offset)
+
+#endif /* CONFIG_ARCH_SUNXI */
+
+static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
+{
+	musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
+}
+
+static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
+{
+	musb_writew(mbase, MUSB_TXFIFOADD, c_off);
+}
+
+static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
+{
+	musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
+}
+
+static inline void  musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
+{
+	musb_writew(mbase, MUSB_RXFIFOADD, c_off);
+}
+
+static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
+{
+#ifndef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
+	musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val);
+#endif
+}
+
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+	return musb_readb(mbase, MUSB_TXFIFOSZ);
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+	return musb_readw(mbase, MUSB_TXFIFOADD);
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+	return musb_readb(mbase, MUSB_RXFIFOSZ);
+}
+
+static inline u16  musb_read_rxfifoadd(void __iomem *mbase)
+{
+	return musb_readw(mbase, MUSB_RXFIFOADD);
+}
+
+static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
+{
+#ifdef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
+	return 0;
+#else
+	return musb_readb(mbase, MUSB_ULPI_BUSCONTROL);
+#endif
+}
+
+static inline u8 musb_read_configdata(void __iomem *mbase)
+{
+#ifdef CONFIG_USB_MUSB_FIXED_CONFIGDATA
+	/* <Sigh> allwinner saves a reg, and we need to hardcode this */
+	return 0xde;
+#else
+	musb_writeb(mbase, MUSB_INDEX, 0);
+	return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
+#endif
+}
+
+static inline u16 musb_read_hwvers(void __iomem *mbase)
+{
+#ifdef CONFIG_ARCH_SUNXI
+	return 0; /* Unknown version */
+#else
+	return musb_readw(mbase, MUSB_HWVERS);
+#endif
+}
+
+static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
+{
+	return (MUSB_BUSCTL_OFFSET(i, 0) + mbase);
+}
+
+static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
+		u8 qh_addr_reg)
+{
+	musb_writeb(ep_target_regs, MUSB_RXFUNCADDR, qh_addr_reg);
+}
+
+static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
+		u8 qh_h_addr_reg)
+{
+	musb_writeb(ep_target_regs, MUSB_RXHUBADDR, qh_h_addr_reg);
+}
+
+static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
+		u8 qh_h_port_reg)
+{
+	musb_writeb(ep_target_regs, MUSB_RXHUBPORT, qh_h_port_reg);
+}
+
+static inline void  musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
+		u8 qh_addr_reg)
+{
+	musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
+			qh_addr_reg);
+}
+
+static inline void  musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
+		u8 qh_addr_reg)
+{
+	musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
+			qh_addr_reg);
+}
+
+static inline void  musb_write_txhubport(void __iomem *mbase, u8 epnum,
+		u8 qh_h_port_reg)
+{
+	musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
+			qh_h_port_reg);
+}
+
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+	return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+	return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+	return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
+}
+
+static inline u8  musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+	return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
+}
+
+static inline u8  musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+	return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
+}
+
+static inline u8  musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+	return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
+}
+
+#endif	/* __MUSB_REGS_H__ */
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_uboot.c b/roms/u-boot/drivers/usb/musb-new/musb_uboot.c
new file mode 100644
index 000000000..8ac2f0a78
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_uboot.c
@@ -0,0 +1,491 @@
+#include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#include "musb_core.h"
+#include "musb_host.h"
+#include "musb_gadget.h"
+#include "musb_uboot.h"
+
+#ifdef CONFIG_USB_MUSB_HOST
+struct int_queue {
+	struct usb_host_endpoint hep;
+	struct urb urb;
+};
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+struct musb_host_data musb_host;
+#endif
+
+static void musb_host_complete_urb(struct urb *urb)
+{
+	urb->dev->status &= ~USB_ST_NOT_PROC;
+	urb->dev->act_len = urb->actual_length;
+}
+
+static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
+			  struct usb_device *dev, int endpoint_type,
+			  unsigned long pipe, void *buffer, int len,
+			  struct devrequest *setup, int interval)
+{
+	int epnum = usb_pipeendpoint(pipe);
+	int is_in = usb_pipein(pipe);
+
+	memset(urb, 0, sizeof(struct urb));
+	memset(hep, 0, sizeof(struct usb_host_endpoint));
+	INIT_LIST_HEAD(&hep->urb_list);
+	INIT_LIST_HEAD(&urb->urb_list);
+	urb->ep = hep;
+	urb->complete = musb_host_complete_urb;
+	urb->status = -EINPROGRESS;
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->transfer_buffer = buffer;
+	urb->transfer_dma = (unsigned long)buffer;
+	urb->transfer_buffer_length = len;
+	urb->setup_packet = (unsigned char *)setup;
+
+	urb->ep->desc.wMaxPacketSize =
+		__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
+				dev->epmaxpacketout[epnum]);
+	urb->ep->desc.bmAttributes = endpoint_type;
+	urb->ep->desc.bEndpointAddress =
+		(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
+	urb->ep->desc.bInterval = interval;
+}
+
+static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct musb *host = hcd->hcd_priv;
+	int ret;
+	unsigned long timeout;
+
+	ret = musb_urb_enqueue(hcd, urb, 0);
+	if (ret < 0) {
+		printf("Failed to enqueue URB to controller\n");
+		return ret;
+	}
+
+	timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe);
+	do {
+		if (ctrlc())
+			return -EIO;
+		host->isr(0, host);
+	} while (urb->status == -EINPROGRESS &&
+		 get_timer(0) < timeout);
+
+	if (urb->status == -EINPROGRESS)
+		musb_urb_dequeue(hcd, urb, -ETIME);
+
+	return urb->status;
+}
+
+static int _musb_submit_control_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe,
+	void *buffer, int len, struct devrequest *setup)
+{
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_CONTROL,
+		      pipe, buffer, len, setup, 0);
+
+	/* Fix speed for non hub-attached devices */
+	if (!usb_dev_get_parent(dev))
+		dev->speed = host->host_speed;
+
+	return submit_urb(&host->hcd, &host->urb);
+}
+
+static int _musb_submit_bulk_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe, void *buffer, int len)
+{
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_BULK,
+		      pipe, buffer, len, NULL, 0);
+	return submit_urb(&host->hcd, &host->urb);
+}
+
+static int _musb_submit_int_msg(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe,
+	void *buffer, int len, int interval, bool nonblock)
+{
+	construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_INT, pipe,
+		      buffer, len, NULL, interval);
+	return submit_urb(&host->hcd, &host->urb);
+}
+
+static struct int_queue *_musb_create_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, unsigned long pipe, int queuesize,
+	int elementsize, void *buffer, int interval)
+{
+	struct int_queue *queue;
+	int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
+
+	if (queuesize != 1) {
+		printf("ERROR musb int-queues only support queuesize 1\n");
+		return NULL;
+	}
+
+	if (dev->int_pending & (1 << index)) {
+		printf("ERROR int-urb is already pending on pipe %lx\n", pipe);
+		return NULL;
+	}
+
+	queue = malloc(sizeof(*queue));
+	if (!queue)
+		return NULL;
+
+	construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
+		      pipe, buffer, elementsize, NULL, interval);
+
+	ret = musb_urb_enqueue(&host->hcd, &queue->urb, 0);
+	if (ret < 0) {
+		printf("Failed to enqueue URB to controller\n");
+		free(queue);
+		return NULL;
+	}
+
+	dev->int_pending |= 1 << index;
+	return queue;
+}
+
+static int _musb_destroy_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, struct int_queue *queue)
+{
+	int index = usb_pipein(queue->urb.pipe) * 16 + 
+		    usb_pipeendpoint(queue->urb.pipe);
+
+	if (queue->urb.status == -EINPROGRESS)
+		musb_urb_dequeue(&host->hcd, &queue->urb, -ETIME);
+
+	dev->int_pending &= ~(1 << index);
+	free(queue);
+	return 0;
+}
+
+static void *_musb_poll_int_queue(struct musb_host_data *host,
+	struct usb_device *dev, struct int_queue *queue)
+{
+	if (queue->urb.status != -EINPROGRESS)
+		return NULL; /* URB has already completed in a prev. poll */
+
+	host->host->isr(0, host->host);
+
+	if (queue->urb.status != -EINPROGRESS)
+		return queue->urb.transfer_buffer; /* Done */
+
+	return NULL; /* URB still pending */
+}
+
+static int _musb_reset_root_port(struct musb_host_data *host,
+	struct usb_device *dev)
+{
+	void *mbase = host->host->mregs;
+	u8 power;
+
+	power = musb_readb(mbase, MUSB_POWER);
+	power &= 0xf0;
+	musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
+	mdelay(50);
+
+	if (host->host->ops->pre_root_reset_end)
+		host->host->ops->pre_root_reset_end(host->host);
+
+	power = musb_readb(mbase, MUSB_POWER);
+	musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
+
+	if (host->host->ops->post_root_reset_end)
+		host->host->ops->post_root_reset_end(host->host);
+
+	host->host->isr(0, host->host);
+	host->host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+			USB_SPEED_HIGH :
+			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
+			USB_SPEED_FULL : USB_SPEED_LOW;
+	mdelay((host->host_speed == USB_SPEED_LOW) ? 200 : 50);
+
+	return 0;
+}
+
+int musb_lowlevel_init(struct musb_host_data *host)
+{
+	void *mbase;
+	/* USB spec says it may take up to 1 second for a device to connect */
+	unsigned long timeout = get_timer(0) + 1000;
+	int ret;
+
+	if (!host->host) {
+		printf("MUSB host is not registered\n");
+		return -ENODEV;
+	}
+
+	ret = musb_start(host->host);
+	if (ret)
+		return ret;
+
+	mbase = host->host->mregs;
+	do {
+		if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
+			break;
+	} while (get_timer(0) < timeout);
+	if (get_timer(0) >= timeout) {
+		musb_stop(host->host);
+		return -ENODEV;
+	}
+
+	_musb_reset_root_port(host, NULL);
+	host->host->is_active = 1;
+	host->hcd.hcd_priv = host->host;
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
+int usb_lowlevel_stop(int index)
+{
+	if (!musb_host.host) {
+		printf("MUSB host is not registered\n");
+		return -ENODEV;
+	}
+
+	musb_stop(musb_host.host);
+	return 0;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length)
+{
+	return _musb_submit_bulk_msg(&musb_host, dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+		       void *buffer, int length, struct devrequest *setup)
+{
+	return _musb_submit_control_msg(&musb_host, dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+		   void *buffer, int length, int interval, bool nonblock)
+{
+	return _musb_submit_int_msg(&musb_host, dev, pipe, buffer, length,
+				    interval, nonblock);
+}
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+		unsigned long pipe, int queuesize, int elementsize,
+		void *buffer, int interval)
+{
+	return _musb_create_int_queue(&musb_host, dev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _musb_poll_int_queue(&musb_host, dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+	return _musb_destroy_int_queue(&musb_host, dev, queue);
+}
+
+int usb_reset_root_port(struct usb_device *dev)
+{
+	return _musb_reset_root_port(&musb_host, dev);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	return musb_lowlevel_init(&musb_host);
+}
+#endif /* !CONFIG_IS_ENABLED(DM_USB) */
+
+#if CONFIG_IS_ENABLED(DM_USB)
+static int musb_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_control_msg(host, udev, pipe, buffer, length, setup);
+}
+
+static int musb_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_bulk_msg(host, udev, pipe, buffer, length);
+}
+
+static int musb_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval, bool nonblock)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_submit_int_msg(host, udev, pipe, buffer, length, interval,
+				    nonblock);
+}
+
+static struct int_queue *musb_create_int_queue(struct udevice *dev,
+		struct usb_device *udev, unsigned long pipe, int queuesize,
+		int elementsize, void *buffer, int interval)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_create_int_queue(host, udev, pipe, queuesize, elementsize,
+				      buffer, interval);
+}
+
+static void *musb_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+				 struct int_queue *queue)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_poll_int_queue(host, udev, queue);
+}
+
+static int musb_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+				  struct int_queue *queue)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_destroy_int_queue(host, udev, queue);
+}
+
+static int musb_reset_root_port(struct udevice *dev, struct usb_device *udev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	return _musb_reset_root_port(host, udev);
+}
+
+struct dm_usb_ops musb_usb_ops = {
+	.control = musb_submit_control_msg,
+	.bulk = musb_submit_bulk_msg,
+	.interrupt = musb_submit_int_msg,
+	.create_int_queue = musb_create_int_queue,
+	.poll_int_queue = musb_poll_int_queue,
+	.destroy_int_queue = musb_destroy_int_queue,
+	.reset_root_port = musb_reset_root_port,
+};
+#endif /* CONFIG_IS_ENABLED(DM_USB) */
+#endif /* CONFIG_USB_MUSB_HOST */
+
+#if defined(CONFIG_USB_MUSB_GADGET) && !CONFIG_IS_ENABLED(DM_USB_GADGET)
+static struct musb *gadget;
+
+int usb_gadget_handle_interrupts(int index)
+{
+	WATCHDOG_RESET();
+	if (!gadget || !gadget->isr)
+		return -EINVAL;
+
+	return gadget->isr(0, gadget);
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int ret;
+
+	if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind ||
+	    !driver->setup) {
+		printf("bad parameter.\n");
+		return -EINVAL;
+	}
+
+	if (!gadget) {
+		printf("Controller uninitialized\n");
+		return -ENXIO;
+	}
+
+	ret = musb_gadget_start(&gadget->g, driver);
+	if (ret < 0) {
+		printf("gadget_start failed with %d\n", ret);
+		return ret;
+	}
+
+	ret = driver->bind(&gadget->g);
+	if (ret < 0) {
+		printf("bind failed with %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	if (driver->disconnect)
+		driver->disconnect(&gadget->g);
+	if (driver->unbind)
+		driver->unbind(&gadget->g);
+	return 0;
+}
+#endif /* CONFIG_USB_MUSB_GADGET */
+
+struct musb *musb_register(struct musb_hdrc_platform_data *plat, void *bdata,
+			   void *ctl_regs)
+{
+	struct musb **musbp;
+
+	switch (plat->mode) {
+#if defined(CONFIG_USB_MUSB_HOST) && !CONFIG_IS_ENABLED(DM_USB)
+	case MUSB_HOST:
+		musbp = &musb_host.host;
+		break;
+#endif
+#if defined(CONFIG_USB_MUSB_GADGET) && !CONFIG_IS_ENABLED(DM_USB_GADGET)
+	case MUSB_PERIPHERAL:
+		musbp = &gadget;
+		break;
+#endif
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	*musbp = musb_init_controller(plat, (struct device *)bdata, ctl_regs);
+	if (IS_ERR(*musbp)) {
+		printf("Failed to init the controller\n");
+		return ERR_CAST(*musbp);
+	}
+
+	return *musbp;
+}
+
+#if CONFIG_IS_ENABLED(DM_USB)
+struct usb_device *usb_dev_get_parent(struct usb_device *udev)
+{
+	struct udevice *parent = udev->dev->parent;
+
+	/*
+	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
+	 * to the parent udevice, not the actual udevice belonging to the
+	 * udev as the device is not instantiated yet.
+	 *
+	 * If dev is an usb-bus, then we are called from usb_scan_device() for
+	 * an usb-device plugged directly into the root port, return NULL.
+	 */
+	if (device_get_uclass_id(udev->dev) == UCLASS_USB)
+		return NULL;
+
+	/*
+	 * If these 2 are not the same we are being called from
+	 * usb_scan_device() and udev itself is the parent.
+	 */
+	if (dev_get_parent_priv(udev->dev) != udev)
+		return udev;
+
+	/* We are being called normally, use the parent pointer */
+	if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
+		return dev_get_parent_priv(parent);
+
+	return NULL;
+}
+#else
+struct usb_device *usb_dev_get_parent(struct usb_device *udev)
+{
+	return udev->parent;
+}
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/musb_uboot.h b/roms/u-boot/drivers/usb/musb-new/musb_uboot.h
new file mode 100644
index 000000000..18282efcc
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/musb_uboot.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * MUSB OTG driver u-boot specific functions
+ *
+ * Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
+ */
+#ifndef __MUSB_UBOOT_H__
+#define __MUSB_UBOOT_H__
+
+#include <usb.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#include "musb_core.h"
+
+struct musb_host_data {
+	struct musb *host;
+	struct usb_hcd hcd;
+	enum usb_device_speed host_speed;
+	struct usb_host_endpoint hep;
+	struct urb urb;
+};
+
+extern struct dm_usb_ops musb_usb_ops;
+
+int musb_lowlevel_init(struct musb_host_data *host);
+
+#endif
diff --git a/roms/u-boot/drivers/usb/musb-new/omap2430.c b/roms/u-boot/drivers/usb/musb-new/omap2430.c
new file mode 100644
index 000000000..7d15b94a6
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/omap2430.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2005-2007 by Texas Instruments
+ * Some code has been taken from tusb6010.c
+ * Copyrights for that are attributable to:
+ * Copyright (C) 2006 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ */
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <serial.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <linux/err.h>
+#include <linux/usb/otg.h>
+#include <asm/global_data.h>
+#include <asm/omap_common.h>
+#include <asm/omap_musb.h>
+#include <twl4030.h>
+#include <twl6030.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "omap2430.h"
+#include "musb_uboot.h"
+
+static inline void omap2430_low_level_exit(struct musb *musb)
+{
+	u32 l;
+
+	/* in any role */
+	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
+	l |= ENABLEFORCE;	/* enable MSTANDBY */
+	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+}
+
+static inline void omap2430_low_level_init(struct musb *musb)
+{
+	u32 l;
+
+	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
+	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
+	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
+}
+
+
+static int omap2430_musb_init(struct musb *musb)
+{
+	u32 l;
+	int status = 0;
+	unsigned long int start;
+
+	struct omap_musb_board_data *data =
+		(struct omap_musb_board_data *)musb->controller;
+
+	/* Reset the controller */
+	musb_writel(musb->mregs, OTG_SYSCONFIG, SOFTRST);
+
+	start = get_timer(0);
+
+	while (1) {
+		l = musb_readl(musb->mregs, OTG_SYSCONFIG);
+		if ((l & SOFTRST) == 0)
+			break;
+
+		if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
+			dev_err(musb->controller, "MUSB reset is taking too long\n");
+			return -ENODEV;
+		}
+	}
+
+	l = musb_readl(musb->mregs, OTG_INTERFSEL);
+
+	if (data->interface_type == MUSB_INTERFACE_UTMI) {
+		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
+		l &= ~ULPI_12PIN;       /* Disable ULPI */
+		l |= UTMI_8BIT;         /* Enable UTMI  */
+	} else {
+		l |= ULPI_12PIN;
+	}
+
+	musb_writel(musb->mregs, OTG_INTERFSEL, l);
+
+	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
+			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
+			musb_readl(musb->mregs, OTG_REVISION),
+			musb_readl(musb->mregs, OTG_SYSCONFIG),
+			musb_readl(musb->mregs, OTG_SYSSTATUS),
+			musb_readl(musb->mregs, OTG_INTERFSEL),
+			musb_readl(musb->mregs, OTG_SIMENABLE));
+	return 0;
+
+err1:
+	return status;
+}
+
+static int omap2430_musb_enable(struct musb *musb)
+{
+#ifdef CONFIG_TWL4030_USB
+	if (twl4030_usb_ulpi_init()) {
+		serial_printf("ERROR: %s Could not initialize PHY\n",
+				__PRETTY_FUNCTION__);
+	}
+#endif
+
+#ifdef CONFIG_TWL6030_POWER
+	twl6030_usb_device_settings();
+#endif
+
+#ifdef CONFIG_OMAP44XX
+	u32 *usbotghs_control = (u32 *)((*ctrl)->control_usbotghs_ctrl);
+	*usbotghs_control = USBOTGHS_CONTROL_AVALID |
+		USBOTGHS_CONTROL_VBUSVALID | USBOTGHS_CONTROL_IDDIG;
+#endif
+
+	return 0;
+}
+
+static void omap2430_musb_disable(struct musb *musb)
+{
+
+}
+
+static int omap2430_musb_exit(struct musb *musb)
+{
+	del_timer_sync(&musb_idle_timer);
+
+	omap2430_low_level_exit(musb);
+
+	return 0;
+}
+
+const struct musb_platform_ops omap2430_ops = {
+	.init		= omap2430_musb_init,
+	.exit		= omap2430_musb_exit,
+	.enable		= omap2430_musb_enable,
+	.disable	= omap2430_musb_disable,
+};
+
+#if CONFIG_IS_ENABLED(DM_USB)
+
+struct omap2430_musb_plat {
+	void *base;
+	void *ctrl_mod_base;
+	struct musb_hdrc_platform_data plat;
+	struct musb_hdrc_config musb_config;
+	struct omap_musb_board_data otg_board_data;
+};
+
+static int omap2430_musb_of_to_plat(struct udevice *dev)
+{
+	struct omap2430_musb_plat *plat = dev_get_plat(dev);
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+
+	plat->base = (void *)dev_read_addr_ptr(dev);
+
+	plat->musb_config.multipoint = fdtdec_get_int(fdt, node, "multipoint",
+						      -1);
+	if (plat->musb_config.multipoint < 0) {
+		pr_err("MUSB multipoint DT entry missing\n");
+		return -ENOENT;
+	}
+
+	plat->musb_config.dyn_fifo = 1;
+	plat->musb_config.num_eps = fdtdec_get_int(fdt, node, "num-eps", -1);
+	if (plat->musb_config.num_eps < 0) {
+		pr_err("MUSB num-eps DT entry missing\n");
+		return -ENOENT;
+	}
+
+	plat->musb_config.ram_bits = fdtdec_get_int(fdt, node, "ram-bits", -1);
+	if (plat->musb_config.ram_bits < 0) {
+		pr_err("MUSB ram-bits DT entry missing\n");
+		return -ENOENT;
+	}
+
+	plat->plat.power = fdtdec_get_int(fdt, node, "power", -1);
+	if (plat->plat.power < 0) {
+		pr_err("MUSB power DT entry missing\n");
+		return -ENOENT;
+	}
+
+	plat->otg_board_data.interface_type = fdtdec_get_int(fdt, node,
+							     "interface-type",
+							     -1);
+	if (plat->otg_board_data.interface_type < 0) {
+		pr_err("MUSB interface-type DT entry missing\n");
+		return -ENOENT;
+	}
+
+#if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */
+	plat->plat.mode = fdtdec_get_int(fdt, node, "mode", -1);
+	if (plat->plat.mode < 0) {
+		pr_err("MUSB mode DT entry missing\n");
+		return -ENOENT;
+	}
+#else /* MUSB_OTG, it doesn't work */
+#ifdef CONFIG_USB_MUSB_HOST /* Host seems to be the only option that works */
+	plat->plat.mode = MUSB_HOST;
+#else /* For that matter, MUSB_PERIPHERAL doesn't either */
+	plat->plat.mode = MUSB_PERIPHERAL;
+#endif
+#endif
+	plat->otg_board_data.dev = dev;
+	plat->plat.config = &plat->musb_config;
+	plat->plat.platform_ops = &omap2430_ops;
+	plat->plat.board_data = &plat->otg_board_data;
+	return 0;
+}
+
+static int omap2430_musb_probe(struct udevice *dev)
+{
+#ifdef CONFIG_USB_MUSB_HOST
+	struct musb_host_data *host = dev_get_priv(dev);
+#else
+	struct musb *musbp;
+#endif
+	struct omap2430_musb_plat *plat = dev_get_plat(dev);
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	struct omap_musb_board_data *otg_board_data;
+	int ret = 0;
+	void *base = dev_read_addr_ptr(dev);
+
+	priv->desc_before_addr = true;
+
+	otg_board_data = &plat->otg_board_data;
+
+#ifdef CONFIG_USB_MUSB_HOST
+	host->host = musb_init_controller(&plat->plat,
+					  (struct device *)otg_board_data,
+					  plat->base);
+	if (!host->host) {
+		return -EIO;
+	}
+
+	ret = musb_lowlevel_init(host);
+#else
+	musbp = musb_register(&plat->plat, (struct device *)otg_board_data,
+			      plat->base);
+	if (IS_ERR_OR_NULL(musbp))
+		return -EINVAL;
+#endif
+	return ret;
+}
+
+static int omap2430_musb_remove(struct udevice *dev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+
+	musb_stop(host->host);
+
+	return 0;
+}
+
+static const struct udevice_id omap2430_musb_ids[] = {
+	{ .compatible = "ti,omap3-musb" },
+	{ .compatible = "ti,omap4-musb" },
+	{ }
+};
+
+U_BOOT_DRIVER(omap2430_musb) = {
+	.name	= "omap2430-musb",
+#ifdef CONFIG_USB_MUSB_HOST
+	.id		= UCLASS_USB,
+#else
+	.id		= UCLASS_USB_GADGET_GENERIC,
+#endif
+	.of_match = omap2430_musb_ids,
+	.of_to_plat = omap2430_musb_of_to_plat,
+	.probe = omap2430_musb_probe,
+	.remove = omap2430_musb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+	.ops = &musb_usb_ops,
+#endif
+	.plat_auto	= sizeof(struct omap2430_musb_plat),
+	.priv_auto	= sizeof(struct musb_host_data),
+};
+
+#endif /* CONFIG_IS_ENABLED(DM_USB) */
diff --git a/roms/u-boot/drivers/usb/musb-new/omap2430.h b/roms/u-boot/drivers/usb/musb-new/omap2430.h
new file mode 100644
index 000000000..71c1f0a68
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/omap2430.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2005-2006 by Texas Instruments
+ */
+
+#ifndef __MUSB_OMAP243X_H__
+#define __MUSB_OMAP243X_H__
+
+#ifndef __UBOOT__
+#include <plat/usb.h>
+#else
+#undef RESETDONE
+#endif
+
+/*
+ * OMAP2430-specific definitions
+ */
+
+#define OTG_REVISION		0x400
+
+#define OTG_SYSCONFIG		0x404
+#	define	MIDLEMODE	12	/* bit position */
+#	define	FORCESTDBY		(0 << MIDLEMODE)
+#	define	NOSTDBY			(1 << MIDLEMODE)
+#	define	SMARTSTDBY		(2 << MIDLEMODE)
+
+#	define	SIDLEMODE		3	/* bit position */
+#	define	FORCEIDLE		(0 << SIDLEMODE)
+#	define	NOIDLE			(1 << SIDLEMODE)
+#	define	SMARTIDLE		(2 << SIDLEMODE)
+
+#	define	ENABLEWAKEUP		(1 << 2)
+#	define	SOFTRST			(1 << 1)
+#	define	AUTOIDLE		(1 << 0)
+
+#define OTG_SYSSTATUS		0x408
+#	define	RESETDONE		(1 << 0)
+
+#define OTG_INTERFSEL		0x40c
+#	define	EXTCP			(1 << 2)
+#	define	PHYSEL			0	/* bit position */
+#	define	UTMI_8BIT		(0 << PHYSEL)
+#	define	ULPI_12PIN		(1 << PHYSEL)
+#	define	ULPI_8PIN		(2 << PHYSEL)
+
+#define OTG_SIMENABLE		0x410
+#	define	TM1			(1 << 0)
+
+#define OTG_FORCESTDBY		0x414
+#	define	ENABLEFORCE		(1 << 0)
+
+/*
+ * OMAP4-specific definitions
+ */
+
+#define USBOTGHS_CONTROL_AVALID		(1 << 0)
+#define USBOTGHS_CONTROL_VBUSVALID	(1 << 2)
+#define USBOTGHS_CONTROL_IDDIG		(1 << 4)
+
+#endif	/* __MUSB_OMAP243X_H__ */
diff --git a/roms/u-boot/drivers/usb/musb-new/pic32.c b/roms/u-boot/drivers/usb/musb-new/pic32.c
new file mode 100644
index 000000000..4ed5e6e90
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/pic32.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Microchip PIC32 MUSB "glue layer"
+ *
+ * Copyright (C) 2015, Microchip Technology Inc.
+ *  Cristian Birsan <cristian.birsan@microchip.com>
+ *  Purna Chandra Mandal <purna.mandal@microchip.com>
+ *
+ * Based on the dsps "glue layer" code.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/usb/musb.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "musb_uboot.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PIC32_TX_EP_MASK	0x0f		/* EP0 + 7 Tx EPs */
+#define PIC32_RX_EP_MASK	0x0e		/* 7 Rx EPs */
+
+#define MUSB_SOFTRST		0x7f
+#define  MUSB_SOFTRST_NRST	BIT(0)
+#define  MUSB_SOFTRST_NRSTX	BIT(1)
+
+#define USBCRCON		0
+#define  USBCRCON_USBWKUPEN	BIT(0)  /* Enable Wakeup Interrupt */
+#define  USBCRCON_USBRIE	BIT(1)  /* Enable Remote resume Interrupt */
+#define  USBCRCON_USBIE		BIT(2)  /* Enable USB General interrupt */
+#define  USBCRCON_SENDMONEN	BIT(3)  /* Enable Session End VBUS monitoring */
+#define  USBCRCON_BSVALMONEN	BIT(4)  /* Enable B-Device VBUS monitoring */
+#define  USBCRCON_ASVALMONEN	BIT(5)  /* Enable A-Device VBUS monitoring */
+#define  USBCRCON_VBUSMONEN	BIT(6)  /* Enable VBUS monitoring */
+#define  USBCRCON_PHYIDEN	BIT(7)  /* PHY ID monitoring enable */
+#define  USBCRCON_USBIDVAL	BIT(8)  /* USB ID value */
+#define  USBCRCON_USBIDOVEN	BIT(9)  /* USB ID override enable */
+#define  USBCRCON_USBWK		BIT(24) /* USB Wakeup Status */
+#define  USBCRCON_USBRF		BIT(25) /* USB Resume Status */
+#define  USBCRCON_USBIF		BIT(26) /* USB General Interrupt Status */
+
+/* PIC32 controller data */
+struct pic32_musb_data {
+	struct musb_host_data mdata;
+	struct device dev;
+	void __iomem *musb_glue;
+};
+
+#define to_pic32_musb_data(d)	\
+	container_of(d, struct pic32_musb_data, dev)
+
+static void pic32_musb_disable(struct musb *musb)
+{
+	/* no way to shut the controller */
+}
+
+static int pic32_musb_enable(struct musb *musb)
+{
+	/* soft reset by NRSTx */
+	musb_writeb(musb->mregs, MUSB_SOFTRST, MUSB_SOFTRST_NRSTX);
+	/* set mode */
+	musb_platform_set_mode(musb, musb->board_mode);
+
+	return 0;
+}
+
+static irqreturn_t pic32_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	irqreturn_t ret = IRQ_NONE;
+	u32 epintr, usbintr;
+
+	/* ack usb core interrupts */
+	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+	if (musb->int_usb)
+		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+
+	/* ack endpoint interrupts */
+	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX) & PIC32_RX_EP_MASK;
+	if (musb->int_rx)
+		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+
+	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX) & PIC32_TX_EP_MASK;
+	if (musb->int_tx)
+		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+
+	/* drop spurious RX and TX if device is disconnected */
+	if (musb->int_usb & MUSB_INTR_DISCONNECT) {
+		musb->int_tx = 0;
+		musb->int_rx = 0;
+	}
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb)
+		ret = musb_interrupt(musb);
+
+	return ret;
+}
+
+static int pic32_musb_set_mode(struct musb *musb, u8 mode)
+{
+	struct device *dev = musb->controller;
+	struct pic32_musb_data *pdata = to_pic32_musb_data(dev);
+
+	switch (mode) {
+	case MUSB_HOST:
+		clrsetbits_le32(pdata->musb_glue + USBCRCON,
+				USBCRCON_USBIDVAL, USBCRCON_USBIDOVEN);
+		break;
+	case MUSB_PERIPHERAL:
+		setbits_le32(pdata->musb_glue + USBCRCON,
+			     USBCRCON_USBIDVAL | USBCRCON_USBIDOVEN);
+		break;
+	case MUSB_OTG:
+		dev_err(dev, "support for OTG is unimplemented\n");
+		break;
+	default:
+		dev_err(dev, "unsupported mode %d\n", mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int pic32_musb_init(struct musb *musb)
+{
+	struct pic32_musb_data *pdata = to_pic32_musb_data(musb->controller);
+	u32 ctrl, hwvers;
+	u8 power;
+
+	/* Returns zero if not clocked */
+	hwvers = musb_read_hwvers(musb->mregs);
+	if (!hwvers)
+		return -ENODEV;
+
+	/* Reset the musb */
+	power = musb_readb(musb->mregs, MUSB_POWER);
+	power = power | MUSB_POWER_RESET;
+	musb_writeb(musb->mregs, MUSB_POWER, power);
+	mdelay(100);
+
+	/* Start the on-chip PHY and its PLL. */
+	power = power & ~MUSB_POWER_RESET;
+	musb_writeb(musb->mregs, MUSB_POWER, power);
+
+	musb->isr = pic32_interrupt;
+
+	ctrl =  USBCRCON_USBIF | USBCRCON_USBRF |
+		USBCRCON_USBWK | USBCRCON_USBIDOVEN |
+		USBCRCON_PHYIDEN | USBCRCON_USBIE |
+		USBCRCON_USBRIE | USBCRCON_USBWKUPEN |
+		USBCRCON_VBUSMONEN;
+	writel(ctrl, pdata->musb_glue + USBCRCON);
+
+	return 0;
+}
+
+/* PIC32 supports only 32bit read operation */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+	void __iomem *fifo = hw_ep->fifo;
+	u32 val, rem = len % 4;
+
+	/* USB stack ensures dst is always 32bit aligned. */
+	readsl(fifo, dst, len / 4);
+	if (rem) {
+		dst += len & ~0x03;
+		val = musb_readl(fifo, 0);
+		memcpy(dst, &val, rem);
+	}
+}
+
+const struct musb_platform_ops pic32_musb_ops = {
+	.init		= pic32_musb_init,
+	.set_mode	= pic32_musb_set_mode,
+	.disable	= pic32_musb_disable,
+	.enable		= pic32_musb_enable,
+};
+
+/* PIC32 default FIFO config - fits in 8KB */
+static struct musb_fifo_cfg pic32_musb_fifo_config[] = {
+	{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+	{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+	{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
+	{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
+	{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
+	{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, },
+	{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, },
+	{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, },
+};
+
+static struct musb_hdrc_config pic32_musb_config = {
+	.fifo_cfg	= pic32_musb_fifo_config,
+	.fifo_cfg_size	= ARRAY_SIZE(pic32_musb_fifo_config),
+	.multipoint     = 1,
+	.dyn_fifo       = 1,
+	.num_eps        = 8,
+	.ram_bits       = 11,
+};
+
+/* PIC32 has one MUSB controller which can be host or gadget */
+static struct musb_hdrc_platform_data pic32_musb_plat = {
+	.mode           = MUSB_HOST,
+	.config         = &pic32_musb_config,
+	.power          = 250,		/* 500mA */
+	.platform_ops	= &pic32_musb_ops,
+};
+
+static int musb_usb_probe(struct udevice *dev)
+{
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	struct pic32_musb_data *pdata = dev_get_priv(dev);
+	struct musb_host_data *mdata = &pdata->mdata;
+	struct fdt_resource mc, glue;
+	void *fdt = (void *)gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	void __iomem *mregs;
+	int ret;
+
+	priv->desc_before_addr = true;
+
+	ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+				     "mc", &mc);
+	if (ret < 0) {
+		printf("pic32-musb: resource \"mc\" not found\n");
+		return ret;
+	}
+
+	ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
+				     "control", &glue);
+	if (ret < 0) {
+		printf("pic32-musb: resource \"control\" not found\n");
+		return ret;
+	}
+
+	mregs = ioremap(mc.start, fdt_resource_size(&mc));
+	pdata->musb_glue = ioremap(glue.start, fdt_resource_size(&glue));
+
+	/* init controller */
+#ifdef CONFIG_USB_MUSB_HOST
+	mdata->host = musb_init_controller(&pic32_musb_plat,
+					   &pdata->dev, mregs);
+	if (!mdata->host)
+		return -EIO;
+
+	ret = musb_lowlevel_init(mdata);
+#else
+	pic32_musb_plat.mode = MUSB_PERIPHERAL;
+	mdata->host = musb_register(&pic32_musb_plat, &pdata->dev, mregs);
+	if (!mdata->host)
+		return -EIO;
+#endif
+	if ((ret == 0) && mdata->host)
+		printf("PIC32 MUSB OTG\n");
+
+	return ret;
+}
+
+static int musb_usb_remove(struct udevice *dev)
+{
+	struct pic32_musb_data *pdata = dev_get_priv(dev);
+
+	musb_stop(pdata->mdata.host);
+
+	return 0;
+}
+
+static const struct udevice_id pic32_musb_ids[] = {
+	{ .compatible = "microchip,pic32mzda-usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_musb) = {
+	.name		= "pic32-musb",
+	.id		= UCLASS_USB,
+	.of_match	= pic32_musb_ids,
+	.probe		= musb_usb_probe,
+	.remove		= musb_usb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+	.ops		= &musb_usb_ops,
+#endif
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct pic32_musb_data),
+};
diff --git a/roms/u-boot/drivers/usb/musb-new/sunxi.c b/roms/u-boot/drivers/usb/musb-new/sunxi.c
new file mode 100644
index 000000000..fea4105f3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/sunxi.c
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner SUNXI "glue layer"
+ *
+ * Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
+ *  Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
+ *  javen <javen@allwinnertech.com>
+ *
+ * Based on the DA8xx "glue layer" code.
+ *  Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+ *  Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <phy-sun4i-usb.h>
+#include <reset.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/usb/musb.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "musb_uboot.h"
+
+/******************************************************************************
+ ******************************************************************************
+ * From the Allwinner driver
+ ******************************************************************************
+ ******************************************************************************/
+
+/******************************************************************************
+ * From include/sunxi_usb_bsp.h
+ ******************************************************************************/
+
+/* reg offsets */
+#define  USBC_REG_o_ISCR	0x0400
+#define  USBC_REG_o_PHYCTL	0x0404
+#define  USBC_REG_o_PHYBIST	0x0408
+#define  USBC_REG_o_PHYTUNE	0x040c
+
+#define  USBC_REG_o_VEND0	0x0043
+
+/* Interface Status and Control */
+#define  USBC_BP_ISCR_VBUS_VALID_FROM_DATA	30
+#define  USBC_BP_ISCR_VBUS_VALID_FROM_VBUS	29
+#define  USBC_BP_ISCR_EXT_ID_STATUS		28
+#define  USBC_BP_ISCR_EXT_DM_STATUS		27
+#define  USBC_BP_ISCR_EXT_DP_STATUS		26
+#define  USBC_BP_ISCR_MERGED_VBUS_STATUS	25
+#define  USBC_BP_ISCR_MERGED_ID_STATUS		24
+
+#define  USBC_BP_ISCR_ID_PULLUP_EN		17
+#define  USBC_BP_ISCR_DPDM_PULLUP_EN		16
+#define  USBC_BP_ISCR_FORCE_ID			14
+#define  USBC_BP_ISCR_FORCE_VBUS_VALID		12
+#define  USBC_BP_ISCR_VBUS_VALID_SRC		10
+
+#define  USBC_BP_ISCR_HOSC_EN			7
+#define  USBC_BP_ISCR_VBUS_CHANGE_DETECT	6
+#define  USBC_BP_ISCR_ID_CHANGE_DETECT		5
+#define  USBC_BP_ISCR_DPDM_CHANGE_DETECT	4
+#define  USBC_BP_ISCR_IRQ_ENABLE		3
+#define  USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN	2
+#define  USBC_BP_ISCR_ID_CHANGE_DETECT_EN	1
+#define  USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN	0
+
+/******************************************************************************
+ * From usbc/usbc.c
+ ******************************************************************************/
+
+#define OFF_SUN6I_AHB_RESET0	0x2c0
+
+struct sunxi_musb_config {
+	struct musb_hdrc_config *config;
+};
+
+struct sunxi_glue {
+	struct musb_host_data mdata;
+	struct clk clk;
+	struct reset_ctl rst;
+	struct sunxi_musb_config *cfg;
+	struct device dev;
+	struct phy phy;
+};
+#define to_sunxi_glue(d)	container_of(d, struct sunxi_glue, dev)
+
+static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
+{
+	u32 temp = reg_val;
+
+	temp &= ~BIT(USBC_BP_ISCR_VBUS_CHANGE_DETECT);
+	temp &= ~BIT(USBC_BP_ISCR_ID_CHANGE_DETECT);
+	temp &= ~BIT(USBC_BP_ISCR_DPDM_CHANGE_DETECT);
+
+	return temp;
+}
+
+static void USBC_EnableIdPullUp(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val |= BIT(USBC_BP_ISCR_ID_PULLUP_EN);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_EnableDpDmPullUp(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val |= BIT(USBC_BP_ISCR_DPDM_PULLUP_EN);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceIdToLow(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
+	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceIdToHigh(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
+	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceVbusValidToLow(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ForceVbusValidToHigh(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
+static void USBC_ConfigFIFO_Base(void)
+{
+	u32 reg_value;
+
+	/* config usb fifo, 8kb mode */
+	reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
+	reg_value &= ~(0x03 << 0);
+	reg_value |= BIT(0);
+	writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+}
+
+/******************************************************************************
+ * Needed for the DFU polling magic
+ ******************************************************************************/
+
+static u8 last_int_usb;
+
+bool dfu_usb_get_reset(void)
+{
+	return !!(last_int_usb & MUSB_INTR_RESET);
+}
+
+/******************************************************************************
+ * MUSB Glue code
+ ******************************************************************************/
+
+static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
+{
+	struct musb		*musb = __hci;
+	irqreturn_t		retval = IRQ_NONE;
+
+	/* read and flush interrupts */
+	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+	last_int_usb = musb->int_usb;
+	if (musb->int_usb)
+		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+	if (musb->int_tx)
+		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+	if (musb->int_rx)
+		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+
+	if (musb->int_usb || musb->int_tx || musb->int_rx)
+		retval |= musb_interrupt(musb);
+
+	return retval;
+}
+
+/* musb_core does not call enable / disable in a balanced manner <sigh> */
+static bool enabled = false;
+
+static int sunxi_musb_enable(struct musb *musb)
+{
+	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+	int ret;
+
+	pr_debug("%s():\n", __func__);
+
+	musb_ep_select(musb->mregs, 0);
+	musb_writeb(musb->mregs, MUSB_FADDR, 0);
+
+	if (enabled)
+		return 0;
+
+	/* select PIO mode */
+	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
+
+	if (is_host_enabled(musb)) {
+		ret = sun4i_usb_phy_vbus_detect(&glue->phy);
+		if (ret == 1) {
+			printf("A charger is plugged into the OTG: ");
+			return -ENODEV;
+		}
+
+		ret = sun4i_usb_phy_id_detect(&glue->phy);
+		if (ret == 1) {
+			printf("No host cable detected: ");
+			return -ENODEV;
+		}
+
+		ret = generic_phy_power_on(&glue->phy);
+		if (ret) {
+			pr_debug("failed to power on USB PHY\n");
+			return ret;
+		}
+	}
+
+	USBC_ForceVbusValidToHigh(musb->mregs);
+
+	enabled = true;
+	return 0;
+}
+
+static void sunxi_musb_disable(struct musb *musb)
+{
+	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+	int ret;
+
+	pr_debug("%s():\n", __func__);
+
+	if (!enabled)
+		return;
+
+	if (is_host_enabled(musb)) {
+		ret = generic_phy_power_off(&glue->phy);
+		if (ret) {
+			pr_debug("failed to power off USB PHY\n");
+			return;
+		}
+	}
+
+	USBC_ForceVbusValidToLow(musb->mregs);
+	mdelay(200); /* Wait for the current session to timeout */
+
+	enabled = false;
+}
+
+static int sunxi_musb_init(struct musb *musb)
+{
+	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+	int ret;
+
+	pr_debug("%s():\n", __func__);
+
+	ret = clk_enable(&glue->clk);
+	if (ret) {
+		dev_err(musb->controller, "failed to enable clock\n");
+		return ret;
+	}
+
+	if (reset_valid(&glue->rst)) {
+		ret = reset_deassert(&glue->rst);
+		if (ret) {
+			dev_err(musb->controller, "failed to deassert reset\n");
+			goto err_clk;
+		}
+	}
+
+	ret = generic_phy_init(&glue->phy);
+	if (ret) {
+		dev_dbg(musb->controller, "failed to init USB PHY\n");
+		goto err_rst;
+	}
+
+	musb->isr = sunxi_musb_interrupt;
+
+	USBC_ConfigFIFO_Base();
+	USBC_EnableDpDmPullUp(musb->mregs);
+	USBC_EnableIdPullUp(musb->mregs);
+
+	if (is_host_enabled(musb)) {
+		/* Host mode */
+		USBC_ForceIdToLow(musb->mregs);
+	} else {
+		/* Peripheral mode */
+		USBC_ForceIdToHigh(musb->mregs);
+	}
+	USBC_ForceVbusValidToHigh(musb->mregs);
+
+	return 0;
+
+err_rst:
+	if (reset_valid(&glue->rst))
+		reset_assert(&glue->rst);
+err_clk:
+	clk_disable(&glue->clk);
+	return ret;
+}
+
+static int sunxi_musb_exit(struct musb *musb)
+{
+	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+	int ret = 0;
+
+	if (generic_phy_valid(&glue->phy)) {
+		ret = generic_phy_exit(&glue->phy);
+		if (ret) {
+			dev_dbg(musb->controller,
+				"failed to power off usb phy\n");
+			return ret;
+		}
+	}
+
+	if (reset_valid(&glue->rst))
+		reset_assert(&glue->rst);
+	clk_disable(&glue->clk);
+
+	return 0;
+}
+
+static void sunxi_musb_pre_root_reset_end(struct musb *musb)
+{
+	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+
+	sun4i_usb_phy_set_squelch_detect(&glue->phy, false);
+}
+
+static void sunxi_musb_post_root_reset_end(struct musb *musb)
+{
+	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+
+	sun4i_usb_phy_set_squelch_detect(&glue->phy, true);
+}
+
+static const struct musb_platform_ops sunxi_musb_ops = {
+	.init		= sunxi_musb_init,
+	.exit		= sunxi_musb_exit,
+	.enable		= sunxi_musb_enable,
+	.disable	= sunxi_musb_disable,
+	.pre_root_reset_end = sunxi_musb_pre_root_reset_end,
+	.post_root_reset_end = sunxi_musb_post_root_reset_end,
+};
+
+/* Allwinner OTG supports up to 5 endpoints */
+#define SUNXI_MUSB_MAX_EP_NUM		6
+#define SUNXI_MUSB_RAM_BITS		11
+
+static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
+	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
+};
+
+/* H3/V3s OTG supports only 4 endpoints */
+#define SUNXI_MUSB_MAX_EP_NUM_H3	5
+
+static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = {
+	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
+	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
+	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
+};
+
+static struct musb_hdrc_config musb_config = {
+	.fifo_cfg       = sunxi_musb_mode_cfg,
+	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg),
+	.multipoint	= true,
+	.dyn_fifo	= true,
+	.num_eps	= SUNXI_MUSB_MAX_EP_NUM,
+	.ram_bits	= SUNXI_MUSB_RAM_BITS,
+};
+
+static struct musb_hdrc_config musb_config_h3 = {
+	.fifo_cfg       = sunxi_musb_mode_cfg_h3,
+	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg_h3),
+	.multipoint	= true,
+	.dyn_fifo	= true,
+	.soft_con       = true,
+	.num_eps	= SUNXI_MUSB_MAX_EP_NUM_H3,
+	.ram_bits	= SUNXI_MUSB_RAM_BITS,
+};
+
+static int musb_usb_probe(struct udevice *dev)
+{
+	struct sunxi_glue *glue = dev_get_priv(dev);
+	struct musb_host_data *host = &glue->mdata;
+	struct musb_hdrc_platform_data pdata;
+	void *base = dev_read_addr_ptr(dev);
+	int ret;
+
+#ifdef CONFIG_USB_MUSB_HOST
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+#endif
+
+	if (!base)
+		return -EINVAL;
+
+	glue->cfg = (struct sunxi_musb_config *)dev_get_driver_data(dev);
+	if (!glue->cfg)
+		return -EINVAL;
+
+	ret = clk_get_by_index(dev, 0, &glue->clk);
+	if (ret) {
+		dev_err(dev, "failed to get clock\n");
+		return ret;
+	}
+
+	ret = reset_get_by_index(dev, 0, &glue->rst);
+	if (ret && ret != -ENOENT) {
+		dev_err(dev, "failed to get reset\n");
+		return ret;
+	}
+
+	ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
+	if (ret) {
+		pr_err("failed to get usb PHY\n");
+		return ret;
+	}
+
+	memset(&pdata, 0, sizeof(pdata));
+	pdata.power = 250;
+	pdata.platform_ops = &sunxi_musb_ops;
+	pdata.config = glue->cfg->config;
+
+#ifdef CONFIG_USB_MUSB_HOST
+	priv->desc_before_addr = true;
+
+	pdata.mode = MUSB_HOST;
+	host->host = musb_init_controller(&pdata, &glue->dev, base);
+	if (!host->host)
+		return -EIO;
+
+	ret = musb_lowlevel_init(host);
+	if (!ret)
+		printf("Allwinner mUSB OTG (Host)\n");
+#else
+	pdata.mode = MUSB_PERIPHERAL;
+	host->host = musb_register(&pdata, &glue->dev, base);
+	if (!host->host)
+		return -EIO;
+
+	printf("Allwinner mUSB OTG (Peripheral)\n");
+#endif
+
+	return ret;
+}
+
+static int musb_usb_remove(struct udevice *dev)
+{
+	struct sunxi_glue *glue = dev_get_priv(dev);
+	struct musb_host_data *host = &glue->mdata;
+
+	musb_stop(host->host);
+	free(host->host);
+	host->host = NULL;
+
+	return 0;
+}
+
+static const struct sunxi_musb_config sun4i_a10_cfg = {
+	.config = &musb_config,
+};
+
+static const struct sunxi_musb_config sun6i_a31_cfg = {
+	.config = &musb_config,
+};
+
+static const struct sunxi_musb_config sun8i_h3_cfg = {
+	.config = &musb_config_h3,
+};
+
+static const struct udevice_id sunxi_musb_ids[] = {
+	{ .compatible = "allwinner,sun4i-a10-musb",
+			.data = (ulong)&sun4i_a10_cfg },
+	{ .compatible = "allwinner,sun6i-a31-musb",
+			.data = (ulong)&sun6i_a31_cfg },
+	{ .compatible = "allwinner,sun8i-a33-musb",
+			.data = (ulong)&sun6i_a31_cfg },
+	{ .compatible = "allwinner,sun8i-h3-musb",
+			.data = (ulong)&sun8i_h3_cfg },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_musb) = {
+	.name		= "sunxi-musb",
+#ifdef CONFIG_USB_MUSB_HOST
+	.id		= UCLASS_USB,
+#else
+	.id		= UCLASS_USB_GADGET_GENERIC,
+#endif
+	.of_match	= sunxi_musb_ids,
+	.probe		= musb_usb_probe,
+	.remove		= musb_usb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+	.ops		= &musb_usb_ops,
+#endif
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct sunxi_glue),
+};
diff --git a/roms/u-boot/drivers/usb/musb-new/ti-musb.c b/roms/u-boot/drivers/usb/musb-new/ti-musb.c
new file mode 100644
index 000000000..91042935b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/ti-musb.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MISC driver for TI MUSB Glue.
+ *
+ * (C) Copyright 2016
+ *     Texas Instruments Incorporated, <www.ti.com>
+ */
+#include <common.h>
+#include <command.h>
+#include <console.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <linux/usb/otg.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+#include <asm/io.h>
+#include <asm/omap_musb.h>
+#include "musb_uboot.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(DM_USB)
+/* USB 2.0 PHY Control */
+#define CM_PHY_PWRDN			(1 << 0)
+#define CM_PHY_OTG_PWRDN		(1 << 1)
+#define OTGVDET_EN			(1 << 19)
+#define OTGSESSENDEN			(1 << 20)
+
+#define AM335X_USB0_CTRL	0x0
+#define AM335X_USB1_CTRL	0x8
+
+static void ti_musb_set_phy_power(struct udevice *dev, u8 on)
+{
+	struct ti_musb_plat *plat = dev_get_plat(dev);
+
+	if (!plat->ctrl_mod_base)
+		return;
+
+	if (on) {
+		clrsetbits_le32(plat->ctrl_mod_base,
+				CM_PHY_PWRDN | CM_PHY_OTG_PWRDN,
+				OTGVDET_EN | OTGSESSENDEN);
+	} else {
+		clrsetbits_le32(plat->ctrl_mod_base, 0,
+				CM_PHY_PWRDN | CM_PHY_OTG_PWRDN);
+	}
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+
+static int ti_musb_get_usb_index(int node)
+{
+	const void *fdt = gd->fdt_blob;
+	int i = 0;
+	char path[64];
+	const char *alias_path;
+	char alias[16];
+
+	fdt_get_path(fdt, node, path, sizeof(path));
+
+	do {
+		snprintf(alias, sizeof(alias), "usb%d", i);
+		alias_path = fdt_get_alias(fdt, alias);
+		if (alias_path == NULL) {
+			debug("USB index not found\n");
+			return -ENOENT;
+		}
+
+		if (!strcmp(path, alias_path))
+			return i;
+
+		i++;
+	} while (alias_path);
+
+	return -ENOENT;
+}
+
+static int ti_musb_of_to_plat(struct udevice *dev)
+{
+	struct ti_musb_plat *plat = dev_get_plat(dev);
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	int phys;
+	int ctrl_mod;
+	int usb_index;
+	struct musb_hdrc_config *musb_config;
+
+	plat->base = (void *)devfdt_get_addr_index(dev, 1);
+
+	phys = fdtdec_lookup_phandle(fdt, node, "phys");
+	ctrl_mod = fdtdec_lookup_phandle(fdt, phys, "ti,ctrl_mod");
+	plat->ctrl_mod_base = (void *)fdtdec_get_addr(fdt, ctrl_mod, "reg");
+	usb_index = ti_musb_get_usb_index(node);
+	switch (usb_index) {
+	case 1:
+		plat->ctrl_mod_base += AM335X_USB1_CTRL;
+		break;
+	case 0:
+		plat->ctrl_mod_base += AM335X_USB0_CTRL;
+		break;
+	default:
+		break;
+	}
+
+	musb_config = malloc(sizeof(struct musb_hdrc_config));
+	memset(musb_config, 0, sizeof(struct musb_hdrc_config));
+
+	musb_config->multipoint = fdtdec_get_int(fdt, node,
+						 "mentor,multipoint", -1);
+	if (musb_config->multipoint < 0) {
+		pr_err("MUSB multipoint DT entry missing\n");
+		return -ENOENT;
+	}
+
+	musb_config->dyn_fifo = 1;
+
+	musb_config->num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps",
+					      -1);
+	if (musb_config->num_eps < 0) {
+		pr_err("MUSB num-eps DT entry missing\n");
+		return -ENOENT;
+	}
+
+	musb_config->ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits",
+					       -1);
+	if (musb_config->ram_bits < 0) {
+		pr_err("MUSB ram-bits DT entry missing\n");
+		return -ENOENT;
+	}
+
+	plat->plat.config = musb_config;
+
+	plat->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1);
+	if (plat->plat.power < 0) {
+		pr_err("MUSB mentor,power DT entry missing\n");
+		return -ENOENT;
+	}
+
+	plat->plat.platform_ops = &musb_dsps_ops;
+
+	return 0;
+}
+#endif
+
+static int ti_musb_host_probe(struct udevice *dev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+	struct ti_musb_plat *plat = dev_get_plat(dev);
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	int ret;
+
+	priv->desc_before_addr = true;
+
+	host->host = musb_init_controller(&plat->plat,
+					  NULL,
+					  plat->base);
+	if (!host->host)
+		return -EIO;
+
+	ti_musb_set_phy_power(dev, 1);
+	ret = musb_lowlevel_init(host);
+
+	return ret;
+}
+
+static int ti_musb_host_remove(struct udevice *dev)
+{
+	struct musb_host_data *host = dev_get_priv(dev);
+
+	musb_stop(host->host);
+	ti_musb_set_phy_power(dev, 0);
+
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int ti_musb_host_of_to_plat(struct udevice *dev)
+{
+	struct ti_musb_plat *plat = dev_get_plat(dev);
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	int ret;
+
+	ret = ti_musb_of_to_plat(dev);
+	if (ret) {
+		pr_err("plat dt parse error\n");
+		return ret;
+	}
+
+	plat->plat.mode = MUSB_HOST;
+
+	return 0;
+}
+#endif
+
+U_BOOT_DRIVER(ti_musb_host) = {
+	.name	= "ti-musb-host",
+	.id	= UCLASS_USB,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_to_plat = ti_musb_host_of_to_plat,
+#endif
+	.probe = ti_musb_host_probe,
+	.remove = ti_musb_host_remove,
+	.ops	= &musb_usb_ops,
+	.plat_auto	= sizeof(struct ti_musb_plat),
+	.priv_auto	= sizeof(struct musb_host_data),
+};
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+struct ti_musb_peripheral {
+	struct musb *periph;
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int ti_musb_peripheral_of_to_plat(struct udevice *dev)
+{
+	struct ti_musb_plat *plat = dev_get_plat(dev);
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	int ret;
+
+	ret = ti_musb_of_to_plat(dev);
+	if (ret) {
+		pr_err("plat dt parse error\n");
+		return ret;
+	}
+	plat->plat.mode = MUSB_PERIPHERAL;
+
+	return 0;
+}
+#endif
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct ti_musb_peripheral *priv = dev_get_priv(dev);
+
+	priv->periph->isr(0, priv->periph);
+
+	return 0;
+}
+
+static int ti_musb_peripheral_probe(struct udevice *dev)
+{
+	struct ti_musb_peripheral *priv = dev_get_priv(dev);
+	struct ti_musb_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	priv->periph = musb_init_controller(&plat->plat,
+					    NULL,
+					    plat->base);
+	if (!priv->periph)
+		return -EIO;
+
+	ti_musb_set_phy_power(dev, 1);
+	musb_gadget_setup(priv->periph);
+	return usb_add_gadget_udc((struct device *)dev, &priv->periph->g);
+}
+
+static int ti_musb_peripheral_remove(struct udevice *dev)
+{
+	struct ti_musb_peripheral *priv = dev_get_priv(dev);
+
+	usb_del_gadget_udc(&priv->periph->g);
+	ti_musb_set_phy_power(dev, 0);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ti_musb_peripheral) = {
+	.name	= "ti-musb-peripheral",
+	.id	= UCLASS_USB_GADGET_GENERIC,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_to_plat = ti_musb_peripheral_of_to_plat,
+#endif
+	.probe = ti_musb_peripheral_probe,
+	.remove = ti_musb_peripheral_remove,
+	.ops	= &musb_usb_ops,
+	.plat_auto	= sizeof(struct ti_musb_plat),
+	.priv_auto	= sizeof(struct ti_musb_peripheral),
+	.flags = DM_FLAG_PRE_RELOC,
+};
+#endif
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int ti_musb_wrapper_bind(struct udevice *parent)
+{
+	ofnode node;
+	int ret;
+
+	ofnode_for_each_subnode(node, dev_ofnode(parent)) {
+		struct udevice *dev;
+		const char *name = ofnode_get_name(node);
+		enum usb_dr_mode dr_mode;
+		struct driver *drv;
+
+		if (strncmp(name, "usb@", 4))
+			continue;
+
+		dr_mode = usb_get_dr_mode(node);
+		switch (dr_mode) {
+		case USB_DR_MODE_PERIPHERAL:
+			/* Bind MUSB device */
+			ret = device_bind_driver_to_node(parent,
+							 "ti-musb-peripheral",
+							 name,
+							 node,
+							 &dev);
+			if (ret)
+				pr_err("musb - not able to bind usb peripheral node\n");
+			break;
+		case USB_DR_MODE_HOST:
+			/* Bind MUSB host */
+			ret = device_bind_driver_to_node(parent,
+							 "ti-musb-host",
+							 name,
+							 node,
+							 &dev);
+			if (ret)
+				pr_err("musb - not able to bind usb host node\n");
+			break;
+		default:
+			break;
+		};
+	}
+	return 0;
+}
+
+static const struct udevice_id ti_musb_ids[] = {
+	{ .compatible = "ti,am33xx-usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(ti_musb_wrapper) = {
+	.name	= "ti-musb-wrapper",
+	.id	= UCLASS_MISC,
+	.of_match = ti_musb_ids,
+	.bind = ti_musb_wrapper_bind,
+};
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
+
+#endif /* CONFIG_IS_ENABLED(DM_USB) */
diff --git a/roms/u-boot/drivers/usb/musb-new/usb-compat.h b/roms/u-boot/drivers/usb/musb-new/usb-compat.h
new file mode 100644
index 000000000..1c66c4fe3
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb-new/usb-compat.h
@@ -0,0 +1,79 @@
+#ifndef __USB_COMPAT_H__
+#define __USB_COMPAT_H__
+
+#include "usb.h"
+
+struct udevice;
+
+struct usb_hcd {
+	void *hcd_priv;
+};
+
+struct usb_host_endpoint {
+	struct usb_endpoint_descriptor		desc;
+	struct list_head urb_list;
+	void *hcpriv;
+};
+
+/*
+ * urb->transfer_flags:
+ *
+ * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
+ */
+#define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */
+#define URB_ZERO_PACKET		0x0040	/* Finish bulk OUT with short packet */
+
+struct urb;
+
+typedef void (*usb_complete_t)(struct urb *);
+
+struct urb {
+	void *hcpriv;			/* private data for host controller */
+	struct list_head urb_list;	/* list head for use by the urb's
+					 * current owner */
+	struct usb_device *dev;		/* (in) pointer to associated device */
+	struct usb_host_endpoint *ep;	/* (internal) pointer to endpoint */
+	unsigned int pipe;		/* (in) pipe information */
+	int status;			/* (return) non-ISO status */
+	unsigned int transfer_flags;	/* (in) URB_SHORT_NOT_OK | ...*/
+	void *transfer_buffer;		/* (in) associated data buffer */
+	dma_addr_t transfer_dma;	/* (in) dma addr for transfer_buffer */
+	u32 transfer_buffer_length;	/* (in) data buffer length */
+	u32 actual_length;		/* (return) actual transfer length */
+	unsigned char *setup_packet;	/* (in) setup packet (control only) */
+	int start_frame;		/* (modify) start frame (ISO) */
+	usb_complete_t complete;	/* (in) completion routine */
+};
+
+#define usb_hcd_link_urb_to_ep(hcd, urb)	({		\
+	int ret = 0;						\
+	list_add_tail(&urb->urb_list, &urb->ep->urb_list);	\
+	ret; })
+#define usb_hcd_unlink_urb_from_ep(hcd, urb)	list_del_init(&urb->urb_list)
+#define usb_hcd_check_unlink_urb(hdc, urb, status)	0
+
+static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
+					struct urb *urb,
+					int status)
+{
+	urb->status = status;
+	if (urb->complete)
+		urb->complete(urb);
+}
+
+static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd,
+					struct urb *urb)
+{
+	/* TODO: add cache invalidation here */
+	return 0;
+}
+
+/**
+ * usb_dev_get_parent() - Get the parent of a USB device
+ *
+ * @udev: USB struct containing information about the device
+ * @return associated device for which udev == dev_get_parent_priv(dev)
+ */
+struct usb_device *usb_dev_get_parent(struct usb_device *udev);
+
+#endif /* __USB_COMPAT_H__ */
diff --git a/roms/u-boot/drivers/usb/musb/Kconfig b/roms/u-boot/drivers/usb/musb/Kconfig
new file mode 100644
index 000000000..2508b6ed0
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/Kconfig
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2017
+# Adam Ford, Logic PD, aford173@gmail.com
+
+comment "Legacy MUSB Support"
+
+config USB_MUSB_HCD
+	bool "Legacy MUSB Host Controller"
+
+config USB_MUSB_UDC
+	bool "Legacy USB Device Controller"
+
+config USB_OMAP3
+	bool "Legacy MUSB OMAP3 / OMAP4"
+	depends on ARCH_OMAP2PLUS
+
+config USB_AM35X
+	bool"Legacy MUSB AM35x"
+	depends on ARCH_OMAP2PLUS && !USB_OMAP3
diff --git a/roms/u-boot/drivers/usb/musb/Makefile b/roms/u-boot/drivers/usb/musb/Makefile
new file mode 100644
index 000000000..744f2cfaa
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+obj-$(CONFIG_USB_MUSB_HCD) += musb_hcd.o musb_core.o
+obj-$(CONFIG_USB_MUSB_UDC) += musb_udc.o musb_core.o
+obj-$(CONFIG_USB_OMAP3) += omap3.o
+obj-$(CONFIG_USB_AM35X) += am35x.o
diff --git a/roms/u-boot/drivers/usb/musb/am35x.c b/roms/u-boot/drivers/usb/musb/am35x.c
new file mode 100644
index 000000000..f945f1f5e
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/am35x.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * am35x.c - TI's AM35x platform specific usb wrapper functions.
+ *
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *
+ * Based on drivers/usb/musb/da8xx.c
+ *
+ * Copyright (c) 2010 Texas Instruments Incorporated
+ */
+
+#include <common.h>
+#include <linux/delay.h>
+
+#include "am35x.h"
+
+/* MUSB platform configuration */
+struct musb_config musb_cfg = {
+	.regs		= (struct musb_regs *)AM35X_USB_OTG_CORE_BASE,
+	.timeout	= AM35X_USB_OTG_TIMEOUT,
+	.musb_speed	= 0,
+};
+
+/*
+ * Enable the USB phy
+ */
+static u8 phy_on(void)
+{
+	u32 devconf2;
+	u32 timeout;
+
+	devconf2 = readl(&am35x_scm_general_regs->devconf2);
+
+	devconf2 &= ~(DEVCONF2_RESET | DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN |
+		      DEVCONF2_OTGMODE | DEVCONF2_REFFREQ |
+		      DEVCONF2_PHY_GPIOMODE);
+	devconf2 |= DEVCONF2_SESENDEN | DEVCONF2_VBDTCTEN | DEVCONF2_PHY_PLLON |
+		    DEVCONF2_REFFREQ_13MHZ | DEVCONF2_DATPOL;
+
+	writel(devconf2, &am35x_scm_general_regs->devconf2);
+
+	/* wait until the USB phy is turned on */
+	timeout = musb_cfg.timeout;
+	while (timeout--)
+		if (readl(&am35x_scm_general_regs->devconf2) & DEVCONF2_PHYCKGD)
+			return 1;
+
+	/* USB phy was not turned on */
+	return 0;
+}
+
+/*
+ * Disable the USB phy
+ */
+static void phy_off(void)
+{
+	u32 devconf2;
+
+	/*
+	 * Power down the on-chip PHY.
+	 */
+	devconf2 = readl(&am35x_scm_general_regs->devconf2);
+
+	devconf2 &= ~DEVCONF2_PHY_PLLON;
+	devconf2 |= DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN;
+	writel(devconf2, &am35x_scm_general_regs->devconf2);
+}
+
+/*
+ * This function performs platform specific initialization for usb0.
+ */
+int musb_platform_init(void)
+{
+	u32 revision;
+	u32 sw_reset;
+
+	/* global usb reset */
+	sw_reset = readl(&am35x_scm_general_regs->ip_sw_reset);
+	sw_reset |= (1 << 0);
+	writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset);
+	sw_reset &= ~(1 << 0);
+	writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset);
+
+	/* reset the controller */
+	writel(0x1, &am35x_usb_regs->control);
+	udelay(5000);
+
+	/* start the on-chip usb phy and its pll */
+	if (phy_on() == 0)
+		return -1;
+
+	/* Returns zero if e.g. not clocked */
+	revision = readl(&am35x_usb_regs->revision);
+	if (revision == 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * This function performs platform specific deinitialization for usb0.
+ */
+void musb_platform_deinit(void)
+{
+	/* Turn off the phy */
+	phy_off();
+}
+
+/*
+ * This function reads data from endpoint fifo for AM35x
+ * which supports only 32bit read operation.
+ *
+ * ep           - endpoint number
+ * length       - number of bytes to read from FIFO
+ * fifo_data    - pointer to data buffer into which data is read
+ */
+__attribute__((weak))
+void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+	u8  *data = (u8 *)fifo_data;
+	u32 val;
+	int i;
+
+	/* select the endpoint index */
+	writeb(ep, &musbr->index);
+
+	if (length > 4) {
+		for (i = 0; i < (length >> 2); i++) {
+			val = readl(&musbr->fifox[ep]);
+			memcpy(data, &val, 4);
+			data += 4;
+		}
+		length %= 4;
+	}
+	if (length > 0) {
+		val = readl(&musbr->fifox[ep]);
+		memcpy(data, &val, length);
+	}
+}
diff --git a/roms/u-boot/drivers/usb/musb/am35x.h b/roms/u-boot/drivers/usb/musb/am35x.h
new file mode 100644
index 000000000..82ad94329
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/am35x.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * am35x.h - TI's AM35x platform specific usb wrapper definitions.
+ *
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *
+ * Based on drivers/usb/musb/da8xx.h
+ *
+ * Copyright (c) 2010 Texas Instruments Incorporated
+ */
+
+#ifndef __AM35X_USB_H__
+#define __AM35X_USB_H__
+
+#include <asm/arch/am35x_def.h>
+#include "musb_core.h"
+
+/* Base address of musb wrapper */
+#define AM35X_USB_OTG_BASE	0x5C040000
+
+/* Base address of musb core */
+#define AM35X_USB_OTG_CORE_BASE	(AM35X_USB_OTG_BASE + 0x400)
+
+/* Timeout for AM35x usb module */
+#define AM35X_USB_OTG_TIMEOUT	0x3FFFFFF
+
+/*
+ * AM35x platform USB wrapper register overlay.
+ */
+struct am35x_usb_regs {
+	u32	revision;
+	u32	control;
+	u32	status;
+	u32	emulation;
+	u32	reserved0[1];
+	u32	autoreq;
+	u32	srpfixtime;
+	u32	ep_intsrc;
+	u32	ep_intsrcset;
+	u32	ep_intsrcclr;
+	u32	ep_intmsk;
+	u32	ep_intmskset;
+	u32	ep_intmskclr;
+	u32	ep_intsrcmsked;
+	u32	reserved1[1];
+	u32	core_intsrc;
+	u32	core_intsrcset;
+	u32	core_intsrcclr;
+	u32	core_intmsk;
+	u32	core_intmskset;
+	u32	core_intmskclr;
+	u32	core_intsrcmsked;
+	u32	reserved2[1];
+	u32	eoi;
+	u32	mop_sop_en;
+	u32	reserved3[2];
+	u32	txmode;
+	u32	rxmode;
+	u32	epcount_mode;
+};
+
+#define am35x_usb_regs ((struct am35x_usb_regs *)AM35X_USB_OTG_BASE)
+
+/* USB 2.0 PHY Control */
+#define DEVCONF2_PHY_GPIOMODE	(1 << 23)
+#define DEVCONF2_OTGMODE	(3 << 14)
+#define DEVCONF2_SESENDEN	(1 << 13)       /* Vsess_end comparator */
+#define DEVCONF2_VBDTCTEN	(1 << 12)       /* Vbus comparator */
+#define DEVCONF2_REFFREQ_24MHZ	(2 << 8)
+#define DEVCONF2_REFFREQ_26MHZ	(7 << 8)
+#define DEVCONF2_REFFREQ_13MHZ	(6 << 8)
+#define DEVCONF2_REFFREQ	(0xf << 8)
+#define DEVCONF2_PHYCKGD	(1 << 7)
+#define DEVCONF2_VBUSSENSE	(1 << 6)
+#define DEVCONF2_PHY_PLLON	(1 << 5)        /* override PLL suspend */
+#define DEVCONF2_RESET		(1 << 4)
+#define DEVCONF2_PHYPWRDN	(1 << 3)
+#define DEVCONF2_OTGPWRDN	(1 << 2)
+#define DEVCONF2_DATPOL		(1 << 1)
+
+#endif	/* __AM35X_USB_H__ */
diff --git a/roms/u-boot/drivers/usb/musb/musb_core.c b/roms/u-boot/drivers/usb/musb/musb_core.c
new file mode 100644
index 000000000..9651f074a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/musb_core.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Mentor USB OTG Core functionality common for both Host and Device
+ * functionality.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+
+#include "musb_core.h"
+struct musb_regs *musbr;
+
+/*
+ * program the mentor core to start (enable interrupts, dma, etc.)
+ */
+void musb_start(void)
+{
+#if defined(CONFIG_USB_MUSB_HCD)
+	u8 devctl;
+	u8 busctl;
+#endif
+
+	/* disable all interrupts */
+	writew(0, &musbr->intrtxe);
+	writew(0, &musbr->intrrxe);
+	writeb(0, &musbr->intrusbe);
+	writeb(0, &musbr->testmode);
+
+	/* put into basic highspeed mode and start session */
+	writeb(MUSB_POWER_HSENAB, &musbr->power);
+#if defined(CONFIG_USB_MUSB_HCD)
+	/* Program PHY to use EXT VBUS if required */
+	if (musb_cfg.extvbus == 1) {
+		busctl = musb_read_ulpi_buscontrol(musbr);
+		musb_write_ulpi_buscontrol(musbr, busctl | ULPI_USE_EXTVBUS);
+	}
+
+	devctl = readb(&musbr->devctl);
+	writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
+#endif
+}
+
+#ifdef MUSB_NO_DYNAMIC_FIFO
+# define config_fifo(dir, idx, addr)
+#else
+# define config_fifo(dir, idx, addr) \
+	do { \
+		writeb(idx, &musbr->dir##fifosz); \
+		writew(addr, &musbr->dir##fifoadd); \
+	} while (0)
+#endif
+
+/*
+ * This function configures the endpoint configuration. The musb hcd or musb
+ * device implementation can use this function to configure the endpoints
+ * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
+ * should not be more than the available FIFO size.
+ *
+ * epinfo	- Pointer to EP configuration table
+ * cnt		- Number of entries in the EP conf table.
+ */
+void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt)
+{
+	u16 csr;
+	u16 fifoaddr = 64 >> 3; /* First 64 bytes of FIFO reserved for EP0 */
+	u32 fifosize;
+	u8  idx;
+
+	while (cnt--) {
+		/* prepare fifosize to write to register */
+		fifosize = epinfo->epsize >> 3;
+		idx = fifosize ? ((ffs(fifosize) - 1) & 0xF) : 0;
+
+		writeb(epinfo->epnum, &musbr->index);
+		if (epinfo->epdir) {
+			/* Configure fifo size and fifo base address */
+			config_fifo(tx, idx, fifoaddr);
+
+			csr = readw(&musbr->txcsr);
+			/* clear the data toggle bit */
+			writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
+			/* Flush fifo if required */
+			if (csr & MUSB_TXCSR_TXPKTRDY)
+				writew(csr | MUSB_TXCSR_FLUSHFIFO,
+					&musbr->txcsr);
+		} else {
+			/* Configure fifo size and fifo base address */
+			config_fifo(rx, idx, fifoaddr);
+
+			csr = readw(&musbr->rxcsr);
+			/* clear the data toggle bit */
+			writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
+			/* Flush fifo if required */
+			if (csr & MUSB_RXCSR_RXPKTRDY)
+				writew(csr | MUSB_RXCSR_FLUSHFIFO,
+					&musbr->rxcsr);
+		}
+		fifoaddr += 1 << idx;
+		epinfo++;
+	}
+}
+
+/*
+ * This function writes data to endpoint fifo
+ *
+ * ep		- endpoint number
+ * length	- number of bytes to write to FIFO
+ * fifo_data	- Pointer to data buffer that contains the data to write
+ */
+__attribute__((weak))
+void write_fifo(u8 ep, u32 length, void *fifo_data)
+{
+	u8  *data = (u8 *)fifo_data;
+
+	/* select the endpoint index */
+	writeb(ep, &musbr->index);
+
+	/* write the data to the fifo */
+	while (length--)
+		writeb(*data++, &musbr->fifox[ep]);
+}
+
+/*
+ * AM35x supports only 32bit read operations so
+ * use seperate read_fifo() function for it.
+ */
+#ifndef CONFIG_USB_AM35X
+/*
+ * This function reads data from endpoint fifo
+ *
+ * ep           - endpoint number
+ * length       - number of bytes to read from FIFO
+ * fifo_data    - pointer to data buffer into which data is read
+ */
+__attribute__((weak))
+void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+	u8  *data = (u8 *)fifo_data;
+
+	/* select the endpoint index */
+	writeb(ep, &musbr->index);
+
+	/* read the data to the fifo */
+	while (length--)
+		*data++ = readb(&musbr->fifox[ep]);
+}
+#endif /* CONFIG_USB_AM35X */
diff --git a/roms/u-boot/drivers/usb/musb/musb_core.h b/roms/u-boot/drivers/usb/musb/musb_core.h
new file mode 100644
index 000000000..e5d8ac702
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/musb_core.h
@@ -0,0 +1,343 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************
+ * Copyright 2008 Mentor Graphics Corporation
+ * Copyright (C) 2008 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+#include <usb_defs.h>
+#include <asm/io.h>
+
+#define MUSB_EP0_FIFOSIZE	64	/* This is non-configurable */
+
+/* EP0 */
+struct musb_ep0_regs {
+	u16	reserved4;
+	u16	csr0;
+	u16	reserved5;
+	u16	reserved6;
+	u16	count0;
+	u8	host_type0;
+	u8	host_naklimit0;
+	u8	reserved7;
+	u8	reserved8;
+	u8	reserved9;
+	u8	configdata;
+};
+
+/* EP 1-15 */
+struct musb_epN_regs {
+	u16	txmaxp;
+	u16	txcsr;
+	u16	rxmaxp;
+	u16	rxcsr;
+	u16	rxcount;
+	u8	txtype;
+	u8	txinterval;
+	u8	rxtype;
+	u8	rxinterval;
+	u8	reserved0;
+	u8	fifosize;
+};
+
+/* Mentor USB core register overlay structure */
+#ifndef musb_regs
+struct musb_regs {
+	/* common registers */
+	u8	faddr;
+	u8	power;
+	u16	intrtx;
+	u16	intrrx;
+	u16	intrtxe;
+	u16	intrrxe;
+	u8	intrusb;
+	u8	intrusbe;
+	u16	frame;
+	u8	index;
+	u8	testmode;
+	/* indexed registers */
+	u16	txmaxp;
+	u16	txcsr;
+	u16	rxmaxp;
+	u16	rxcsr;
+	u16	rxcount;
+	u8	txtype;
+	u8	txinterval;
+	u8	rxtype;
+	u8	rxinterval;
+	u8	reserved0;
+	u8	fifosize;
+	/* fifo */
+	u32	fifox[16];
+	/* OTG, dynamic FIFO, version & vendor registers */
+	u8	devctl;
+	u8	reserved1;
+	u8	txfifosz;
+	u8	rxfifosz;
+	u16	txfifoadd;
+	u16	rxfifoadd;
+	u32	vcontrol;
+	u16	hwvers;
+	u16	reserved2a[1];
+	u8	ulpi_busctl;
+	u8	reserved2b[1];
+	u16	reserved2[3];
+	u8	epinfo;
+	u8	raminfo;
+	u8	linkinfo;
+	u8	vplen;
+	u8	hseof1;
+	u8	fseof1;
+	u8	lseof1;
+	u8	reserved3;
+	/* target address registers */
+	struct musb_tar_regs {
+		u8	txfuncaddr;
+		u8	reserved0;
+		u8	txhubaddr;
+		u8	txhubport;
+		u8	rxfuncaddr;
+		u8	reserved1;
+		u8	rxhubaddr;
+		u8	rxhubport;
+	} tar[16];
+	/*
+	 * endpoint registers
+	 * ep0 elements are valid when array index is 0
+	 * otherwise epN is valid
+	 */
+	union musb_ep_regs {
+		struct musb_ep0_regs ep0;
+		struct musb_epN_regs epN;
+	} ep[16];
+
+} __attribute__((packed));
+#endif
+
+/*
+ * MUSB Register bits
+ */
+
+/* POWER */
+#define MUSB_POWER_ISOUPDATE	0x80
+#define MUSB_POWER_SOFTCONN	0x40
+#define MUSB_POWER_HSENAB	0x20
+#define MUSB_POWER_HSMODE	0x10
+#define MUSB_POWER_RESET	0x08
+#define MUSB_POWER_RESUME	0x04
+#define MUSB_POWER_SUSPENDM	0x02
+#define MUSB_POWER_ENSUSPEND	0x01
+#define MUSB_POWER_HSMODE_SHIFT	4
+
+/* INTRUSB */
+#define MUSB_INTR_SUSPEND	0x01
+#define MUSB_INTR_RESUME	0x02
+#define MUSB_INTR_RESET		0x04
+#define MUSB_INTR_BABBLE	0x04
+#define MUSB_INTR_SOF		0x08
+#define MUSB_INTR_CONNECT	0x10
+#define MUSB_INTR_DISCONNECT	0x20
+#define MUSB_INTR_SESSREQ	0x40
+#define MUSB_INTR_VBUSERROR	0x80	/* For SESSION end */
+
+/* DEVCTL */
+#define MUSB_DEVCTL_BDEVICE	0x80
+#define MUSB_DEVCTL_FSDEV	0x40
+#define MUSB_DEVCTL_LSDEV	0x20
+#define MUSB_DEVCTL_VBUS	0x18
+#define MUSB_DEVCTL_VBUS_SHIFT	3
+#define MUSB_DEVCTL_HM		0x04
+#define MUSB_DEVCTL_HR		0x02
+#define MUSB_DEVCTL_SESSION	0x01
+
+/* ULPI VBUSCONTROL */
+#define ULPI_USE_EXTVBUS	0x01
+#define ULPI_USE_EXTVBUSIND	0x02
+
+/* TESTMODE */
+#define MUSB_TEST_FORCE_HOST	0x80
+#define MUSB_TEST_FIFO_ACCESS	0x40
+#define MUSB_TEST_FORCE_FS	0x20
+#define MUSB_TEST_FORCE_HS	0x10
+#define MUSB_TEST_PACKET	0x08
+#define MUSB_TEST_K		0x04
+#define MUSB_TEST_J		0x02
+#define MUSB_TEST_SE0_NAK	0x01
+
+/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MUSB_FIFOSZ_DPB		0x10
+/* Allocation size (8, 16, 32, ... 4096) */
+#define MUSB_FIFOSZ_SIZE	0x0f
+
+/* CSR0 */
+#define MUSB_CSR0_FLUSHFIFO	0x0100
+#define MUSB_CSR0_TXPKTRDY	0x0002
+#define MUSB_CSR0_RXPKTRDY	0x0001
+
+/* CSR0 in Peripheral mode */
+#define MUSB_CSR0_P_SVDSETUPEND	0x0080
+#define MUSB_CSR0_P_SVDRXPKTRDY	0x0040
+#define MUSB_CSR0_P_SENDSTALL	0x0020
+#define MUSB_CSR0_P_SETUPEND	0x0010
+#define MUSB_CSR0_P_DATAEND	0x0008
+#define MUSB_CSR0_P_SENTSTALL	0x0004
+
+/* CSR0 in Host mode */
+#define MUSB_CSR0_H_DIS_PING		0x0800
+#define MUSB_CSR0_H_WR_DATATOGGLE	0x0400	/* Set to allow setting: */
+#define MUSB_CSR0_H_DATATOGGLE		0x0200	/* Data toggle control */
+#define MUSB_CSR0_H_NAKTIMEOUT		0x0080
+#define MUSB_CSR0_H_STATUSPKT		0x0040
+#define MUSB_CSR0_H_REQPKT		0x0020
+#define MUSB_CSR0_H_ERROR		0x0010
+#define MUSB_CSR0_H_SETUPPKT		0x0008
+#define MUSB_CSR0_H_RXSTALL		0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_CSR0_P_WZC_BITS	\
+	(MUSB_CSR0_P_SENTSTALL)
+#define MUSB_CSR0_H_WZC_BITS	\
+	(MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
+	| MUSB_CSR0_RXPKTRDY)
+
+/* TxType/RxType */
+#define MUSB_TYPE_SPEED		0xc0
+#define MUSB_TYPE_SPEED_SHIFT	6
+#define MUSB_TYPE_SPEED_HIGH 	1
+#define MUSB_TYPE_SPEED_FULL 	2
+#define MUSB_TYPE_SPEED_LOW	3
+#define MUSB_TYPE_PROTO		0x30	/* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_SHIFT	4
+#define MUSB_TYPE_REMOTE_END	0xf	/* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_BULK 	2
+#define MUSB_TYPE_PROTO_INTR 	3
+
+/* CONFIGDATA */
+#define MUSB_CONFIGDATA_MPRXE		0x80	/* Auto bulk pkt combining */
+#define MUSB_CONFIGDATA_MPTXE		0x40	/* Auto bulk pkt splitting */
+#define MUSB_CONFIGDATA_BIGENDIAN	0x20
+#define MUSB_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */
+#define MUSB_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */
+#define MUSB_CONFIGDATA_DYNFIFO		0x04	/* Dynamic FIFO sizing */
+#define MUSB_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */
+#define MUSB_CONFIGDATA_UTMIDW		0x01	/* Data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+#define MUSB_TXCSR_AUTOSET		0x8000
+#define MUSB_TXCSR_MODE			0x2000
+#define MUSB_TXCSR_DMAENAB		0x1000
+#define MUSB_TXCSR_FRCDATATOG		0x0800
+#define MUSB_TXCSR_DMAMODE		0x0400
+#define MUSB_TXCSR_CLRDATATOG		0x0040
+#define MUSB_TXCSR_FLUSHFIFO		0x0008
+#define MUSB_TXCSR_FIFONOTEMPTY		0x0002
+#define MUSB_TXCSR_TXPKTRDY		0x0001
+
+/* TXCSR in Peripheral mode */
+#define MUSB_TXCSR_P_ISO		0x4000
+#define MUSB_TXCSR_P_INCOMPTX		0x0080
+#define MUSB_TXCSR_P_SENTSTALL		0x0020
+#define MUSB_TXCSR_P_SENDSTALL		0x0010
+#define MUSB_TXCSR_P_UNDERRUN		0x0004
+
+/* TXCSR in Host mode */
+#define MUSB_TXCSR_H_WR_DATATOGGLE	0x0200
+#define MUSB_TXCSR_H_DATATOGGLE		0x0100
+#define MUSB_TXCSR_H_NAKTIMEOUT		0x0080
+#define MUSB_TXCSR_H_RXSTALL		0x0020
+#define MUSB_TXCSR_H_ERROR		0x0004
+#define MUSB_TXCSR_H_DATATOGGLE_SHIFT	8
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_TXCSR_P_WZC_BITS	\
+	(MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
+	| MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
+#define MUSB_TXCSR_H_WZC_BITS	\
+	(MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+	| MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
+
+/* RXCSR in Peripheral and Host mode */
+#define MUSB_RXCSR_AUTOCLEAR		0x8000
+#define MUSB_RXCSR_DMAENAB		0x2000
+#define MUSB_RXCSR_DISNYET		0x1000
+#define MUSB_RXCSR_PID_ERR		0x1000
+#define MUSB_RXCSR_DMAMODE		0x0800
+#define MUSB_RXCSR_INCOMPRX		0x0100
+#define MUSB_RXCSR_CLRDATATOG		0x0080
+#define MUSB_RXCSR_FLUSHFIFO		0x0010
+#define MUSB_RXCSR_DATAERROR		0x0008
+#define MUSB_RXCSR_FIFOFULL		0x0002
+#define MUSB_RXCSR_RXPKTRDY		0x0001
+
+/* RXCSR in Peripheral mode */
+#define MUSB_RXCSR_P_ISO		0x4000
+#define MUSB_RXCSR_P_SENTSTALL		0x0040
+#define MUSB_RXCSR_P_SENDSTALL		0x0020
+#define MUSB_RXCSR_P_OVERRUN		0x0004
+
+/* RXCSR in Host mode */
+#define MUSB_RXCSR_H_AUTOREQ		0x4000
+#define MUSB_RXCSR_H_WR_DATATOGGLE	0x0400
+#define MUSB_RXCSR_H_DATATOGGLE		0x0200
+#define MUSB_RXCSR_H_RXSTALL		0x0040
+#define MUSB_RXCSR_H_REQPKT		0x0020
+#define MUSB_RXCSR_H_ERROR		0x0004
+#define MUSB_S_RXCSR_H_DATATOGGLE	9
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_RXCSR_P_WZC_BITS	\
+	(MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
+	| MUSB_RXCSR_RXPKTRDY)
+#define MUSB_RXCSR_H_WZC_BITS	\
+	(MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
+	| MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
+
+/* HUBADDR */
+#define MUSB_HUBADDR_MULTI_TT		0x80
+
+/* Endpoint configuration information. Note: The value of endpoint fifo size
+ * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other
+ * values are not supported
+ */
+struct musb_epinfo {
+	u8	epnum;	/* endpoint number 	*/
+	u8	epdir;	/* endpoint direction	*/
+	u16	epsize;	/* endpoint FIFO size	*/
+};
+
+/*
+ * Platform specific MUSB configuration. Any platform using the musb
+ * functionality should create one instance of this structure in the
+ * platform specific file.
+ */
+struct musb_config {
+	struct	musb_regs	*regs;
+	u32			timeout;
+	u8			musb_speed;
+	u8			extvbus;
+};
+
+/* externally defined data */
+extern struct musb_config	musb_cfg;
+extern struct musb_regs		*musbr;
+
+/* exported functions */
+extern void musb_start(void);
+extern void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt);
+extern void write_fifo(u8 ep, u32 length, void *fifo_data);
+extern void read_fifo(u8 ep, u32 length, void *fifo_data);
+
+static inline u8 musb_read_ulpi_buscontrol(struct musb_regs *musbr)
+{
+	return readb(&musbr->ulpi_busctl);
+}
+static inline void musb_write_ulpi_buscontrol(struct musb_regs *musbr, u8 val)
+{
+	writeb(val, &musbr->ulpi_busctl);
+}
+
+#endif	/* __MUSB_HDRC_DEFS_H__ */
diff --git a/roms/u-boot/drivers/usb/musb/musb_debug.h b/roms/u-boot/drivers/usb/musb/musb_debug.h
new file mode 100644
index 000000000..2c5e192ab
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/musb_debug.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ */
+
+/* Define MUSB_DEBUG before including this file to get debug macros */
+#ifdef MUSB_DEBUG
+
+#define MUSB_FLAGS_PRINT(v, x, y)		\
+  if (((v) & MUSB_##x##_##y))			\
+		serial_printf("\t\t"#y"\n")
+
+static inline void musb_print_pwr(u8 b)
+{
+	serial_printf("\tpower   0x%2.2x\n", b);
+	MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE);
+	MUSB_FLAGS_PRINT(b, POWER, SOFTCONN);
+	MUSB_FLAGS_PRINT(b, POWER, HSENAB);
+	MUSB_FLAGS_PRINT(b, POWER, HSMODE);
+	MUSB_FLAGS_PRINT(b, POWER, RESET);
+	MUSB_FLAGS_PRINT(b, POWER, RESUME);
+	MUSB_FLAGS_PRINT(b, POWER, SUSPENDM);
+	MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND);
+}
+
+static inline void musb_print_csr0(u16 w)
+{
+	serial_printf("\tcsr0    0x%4.4x\n", w);
+	MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO);
+	MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND);
+	MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY);
+	MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL);
+	MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND);
+	MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND);
+	MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL);
+	MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY);
+	MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY);
+}
+
+static inline void musb_print_intrusb(u8 b)
+{
+	serial_printf("\tintrusb 0x%2.2x\n", b);
+	MUSB_FLAGS_PRINT(b, INTR, VBUSERROR);
+	MUSB_FLAGS_PRINT(b, INTR, SESSREQ);
+	MUSB_FLAGS_PRINT(b, INTR, DISCONNECT);
+	MUSB_FLAGS_PRINT(b, INTR, CONNECT);
+	MUSB_FLAGS_PRINT(b, INTR, SOF);
+	MUSB_FLAGS_PRINT(b, INTR, RESUME);
+	MUSB_FLAGS_PRINT(b, INTR, SUSPEND);
+
+	if (b & MUSB_INTR_BABBLE)
+		serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
+
+}
+
+static inline void musb_print_intrtx(u16 w)
+{
+	serial_printf("\tintrtx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_intrrx(u16 w)
+{
+	serial_printf("\tintrx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_devctl(u8 b)
+{
+	serial_printf("\tdevctl  0x%2.2x\n", b);
+	if (b & MUSB_DEVCTL_BDEVICE)
+		serial_printf("\t\tB device\n");
+	else
+		serial_printf("\t\tA device\n");
+	if (b & MUSB_DEVCTL_FSDEV)
+		serial_printf("\t\tFast Device -(host mode)\n");
+	if (b & MUSB_DEVCTL_LSDEV)
+		serial_printf("\t\tSlow Device -(host mode)\n");
+	if (b & MUSB_DEVCTL_HM)
+		serial_printf("\t\tHost mode\n");
+	else
+		serial_printf("\t\tPeripherial mode\n");
+	if (b & MUSB_DEVCTL_HR)
+		serial_printf("\t\tHost request started(B device)\n");
+	else
+		serial_printf("\t\tHost request finished(B device)\n");
+	if (b & MUSB_DEVCTL_BDEVICE) {
+		if (b & MUSB_DEVCTL_SESSION)
+			serial_printf("\t\tStart of session(B device)\n");
+		else
+			serial_printf("\t\tEnd of session(B device)\n");
+	} else {
+		if (b & MUSB_DEVCTL_SESSION)
+			serial_printf("\t\tStart of session(A device)\n");
+		else
+			serial_printf("\t\tEnd of session(A device)\n");
+	}
+}
+
+static inline void musb_print_config(u8 b)
+{
+	serial_printf("\tconfig 0x%2.2x\n", b);
+	if (b & MUSB_CONFIGDATA_MPRXE)
+		serial_printf("\t\tAuto combine rx bulk packets\n");
+	if (b & MUSB_CONFIGDATA_MPTXE)
+		serial_printf("\t\tAuto split tx bulk packets\n");
+	if (b & MUSB_CONFIGDATA_BIGENDIAN)
+		serial_printf("\t\tBig Endian ordering\n");
+	else
+		serial_printf("\t\tLittle Endian ordering\n");
+	if (b & MUSB_CONFIGDATA_HBRXE)
+		serial_printf("\t\tHigh speed rx iso endpoint\n");
+	if (b & MUSB_CONFIGDATA_HBTXE)
+		serial_printf("\t\tHigh speed tx iso endpoint\n");
+	if (b & MUSB_CONFIGDATA_DYNFIFO)
+		serial_printf("\t\tDynamic fifo sizing\n");
+	if (b & MUSB_CONFIGDATA_SOFTCONE)
+		serial_printf("\t\tSoft Connect\n");
+	if (b & MUSB_CONFIGDATA_UTMIDW)
+		serial_printf("\t\t16 bit data width\n");
+	else
+		serial_printf("\t\t8 bit data width\n");
+}
+
+static inline void musb_print_rxmaxp(u16 w)
+{
+	serial_printf("\trxmaxp  0x%4.4x\n", w);
+}
+
+static inline void musb_print_rxcsr(u16 w)
+{
+	serial_printf("\trxcsr   0x%4.4x\n", w);
+	MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR);
+	MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB);
+	MUSB_FLAGS_PRINT(w, RXCSR, DISNYET);
+	MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR);
+	MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE);
+	MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG);
+	MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO);
+	MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR);
+	MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL);
+	MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY);
+	MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL);
+	MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL);
+	MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN);
+
+	if (w & MUSB_RXCSR_P_ISO)
+		serial_printf("\t\tiso mode\n");
+	else
+		serial_printf("\t\tbulk mode\n");
+
+}
+
+static inline void musb_print_txmaxp(u16 w)
+{
+	serial_printf("\ttxmaxp  0x%4.4x\n", w);
+}
+
+static inline void musb_print_txcsr(u16 w)
+{
+	serial_printf("\ttxcsr   0x%4.4x\n", w);
+	MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY);
+	MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY);
+	MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO);
+	MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG);
+	MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN);
+	MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL);
+	MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL);
+
+	if (w & MUSB_TXCSR_MODE)
+		serial_printf("\t\tTX mode\n");
+	else
+		serial_printf("\t\tRX mode\n");
+}
+
+#else
+
+/* stubs */
+
+#define musb_print_pwr(b)
+#define musb_print_csr0(w)
+#define musb_print_intrusb(b)
+#define musb_print_intrtx(w)
+#define musb_print_intrrx(w)
+#define musb_print_devctl(b)
+#define musb_print_config(b)
+#define musb_print_rxmaxp(w)
+#define musb_print_rxcsr(w)
+#define musb_print_txmaxp(w)
+#define musb_print_txcsr(w)
+
+#endif /* MUSB_DEBUG */
diff --git a/roms/u-boot/drivers/usb/musb/musb_hcd.c b/roms/u-boot/drivers/usb/musb/musb_hcd.c
new file mode 100644
index 000000000..afbc64888
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/musb_hcd.c
@@ -0,0 +1,1162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include <log.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include "musb_hcd.h"
+
+/* MSC control transfers */
+#define USB_MSC_BBB_RESET 	0xFF
+#define USB_MSC_BBB_GET_MAX_LUN	0xFE
+
+/* Endpoint configuration information */
+static const struct musb_epinfo epinfo[3] = {
+	{MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
+	{MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In  - 512 Bytes */
+	{MUSB_INTR_EP, 0, 64}   /* EP2 - Interrupt IN - 64 Bytes */
+};
+
+/* --- Virtual Root Hub ---------------------------------------------------- */
+#ifdef MUSB_NO_MULTIPOINT
+static int rh_devnum;
+static u32 port_status;
+
+#include <usbroothubdes.h>
+
+#endif
+
+/*
+ * This function writes the data toggle value.
+ */
+static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
+{
+	u16 toggle = usb_gettoggle(dev, ep, dir_out);
+	u16 csr;
+
+	if (dir_out) {
+		csr = readw(&musbr->txcsr);
+		if (!toggle) {
+			if (csr & MUSB_TXCSR_MODE)
+				csr = MUSB_TXCSR_CLRDATATOG;
+			else
+				csr = 0;
+			writew(csr, &musbr->txcsr);
+		} else {
+			csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
+			writew(csr, &musbr->txcsr);
+			csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
+			writew(csr, &musbr->txcsr);
+		}
+	} else {
+		if (!toggle) {
+			csr = readw(&musbr->txcsr);
+			if (csr & MUSB_TXCSR_MODE)
+				csr = MUSB_RXCSR_CLRDATATOG;
+			else
+				csr = 0;
+			writew(csr, &musbr->rxcsr);
+		} else {
+			csr = readw(&musbr->rxcsr);
+			csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
+			writew(csr, &musbr->rxcsr);
+			csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
+			writew(csr, &musbr->rxcsr);
+		}
+	}
+}
+
+/*
+ * This function checks if RxStall has occurred on the endpoint. If a RxStall
+ * has occurred, the RxStall is cleared and 1 is returned. If RxStall has
+ * not occurred, 0 is returned.
+ */
+static u8 check_stall(u8 ep, u8 dir_out)
+{
+	u16 csr;
+
+	/* For endpoint 0 */
+	if (!ep) {
+		csr = readw(&musbr->txcsr);
+		if (csr & MUSB_CSR0_H_RXSTALL) {
+			csr &= ~MUSB_CSR0_H_RXSTALL;
+			writew(csr, &musbr->txcsr);
+			return 1;
+		}
+	} else { /* For non-ep0 */
+		if (dir_out) { /* is it tx ep */
+			csr = readw(&musbr->txcsr);
+			if (csr & MUSB_TXCSR_H_RXSTALL) {
+				csr &= ~MUSB_TXCSR_H_RXSTALL;
+				writew(csr, &musbr->txcsr);
+				return 1;
+			}
+		} else { /* is it rx ep */
+			csr = readw(&musbr->rxcsr);
+			if (csr & MUSB_RXCSR_H_RXSTALL) {
+				csr &= ~MUSB_RXCSR_H_RXSTALL;
+				writew(csr, &musbr->rxcsr);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
+ * error and -2 for stall.
+ */
+static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
+{
+	u16 csr;
+	int result = 1;
+	int timeout = CONFIG_USB_MUSB_TIMEOUT;
+
+	while (result > 0) {
+		csr = readw(&musbr->txcsr);
+		if (csr & MUSB_CSR0_H_ERROR) {
+			csr &= ~MUSB_CSR0_H_ERROR;
+			writew(csr, &musbr->txcsr);
+			dev->status = USB_ST_CRC_ERR;
+			result = -1;
+			break;
+		}
+
+		switch (bit_mask) {
+		case MUSB_CSR0_TXPKTRDY:
+			if (!(csr & MUSB_CSR0_TXPKTRDY)) {
+				if (check_stall(MUSB_CONTROL_EP, 0)) {
+					dev->status = USB_ST_STALLED;
+					result = -2;
+				} else
+					result = 0;
+			}
+			break;
+
+		case MUSB_CSR0_RXPKTRDY:
+			if (check_stall(MUSB_CONTROL_EP, 0)) {
+				dev->status = USB_ST_STALLED;
+				result = -2;
+			} else
+				if (csr & MUSB_CSR0_RXPKTRDY)
+					result = 0;
+			break;
+
+		case MUSB_CSR0_H_REQPKT:
+			if (!(csr & MUSB_CSR0_H_REQPKT)) {
+				if (check_stall(MUSB_CONTROL_EP, 0)) {
+					dev->status = USB_ST_STALLED;
+					result = -2;
+				} else
+					result = 0;
+			}
+			break;
+		}
+
+		/* Check the timeout */
+		if (--timeout)
+			udelay(1);
+		else {
+			dev->status = USB_ST_CRC_ERR;
+			result = -1;
+			break;
+		}
+	}
+
+	return result;
+}
+
+/*
+ * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static int wait_until_txep_ready(struct usb_device *dev, u8 ep)
+{
+	u16 csr;
+	int timeout = CONFIG_USB_MUSB_TIMEOUT;
+
+	do {
+		if (check_stall(ep, 1)) {
+			dev->status = USB_ST_STALLED;
+			return 0;
+		}
+
+		csr = readw(&musbr->txcsr);
+		if (csr & MUSB_TXCSR_H_ERROR) {
+			dev->status = USB_ST_CRC_ERR;
+			return 0;
+		}
+
+		/* Check the timeout */
+		if (--timeout)
+			udelay(1);
+		else {
+			dev->status = USB_ST_CRC_ERR;
+			return -1;
+		}
+
+	} while (csr & MUSB_TXCSR_TXPKTRDY);
+	return 1;
+}
+
+/*
+ * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static int wait_until_rxep_ready(struct usb_device *dev, u8 ep)
+{
+	u16 csr;
+	int timeout = CONFIG_USB_MUSB_TIMEOUT;
+
+	do {
+		if (check_stall(ep, 0)) {
+			dev->status = USB_ST_STALLED;
+			return 0;
+		}
+
+		csr = readw(&musbr->rxcsr);
+		if (csr & MUSB_RXCSR_H_ERROR) {
+			dev->status = USB_ST_CRC_ERR;
+			return 0;
+		}
+
+		/* Check the timeout */
+		if (--timeout)
+			udelay(1);
+		else {
+			dev->status = USB_ST_CRC_ERR;
+			return -1;
+		}
+
+	} while (!(csr & MUSB_RXCSR_RXPKTRDY));
+	return 1;
+}
+
+/*
+ * This function performs the setup phase of the control transfer
+ */
+static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
+{
+	int result;
+	u16 csr;
+
+	/* write the control request to ep0 fifo */
+	write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
+
+	/* enable transfer of setup packet */
+	csr = readw(&musbr->txcsr);
+	csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
+	writew(csr, &musbr->txcsr);
+
+	/* wait until the setup packet is transmitted */
+	result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+	dev->act_len = 0;
+	return result;
+}
+
+/*
+ * This function handles the control transfer in data phase
+ */
+static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+	u16 csr;
+	u32 rxlen = 0;
+	u32 nextlen = 0;
+	u8  maxpktsize = (1 << dev->maxpacketsize) * 8;
+	u8  *rxbuff = (u8 *)buffer;
+	u8  rxedlength;
+	int result;
+
+	while (rxlen < len) {
+		/* Determine the next read length */
+		nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
+
+		/* Set the ReqPkt bit */
+		csr = readw(&musbr->txcsr);
+		writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
+		result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
+		if (result < 0)
+			return result;
+
+		/* Actual number of bytes received by usb */
+		rxedlength = readb(&musbr->rxcount);
+
+		/* Read the data from the RxFIFO */
+		read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
+
+		/* Clear the RxPktRdy Bit */
+		csr = readw(&musbr->txcsr);
+		csr &= ~MUSB_CSR0_RXPKTRDY;
+		writew(csr, &musbr->txcsr);
+
+		/* short packet? */
+		if (rxedlength != nextlen) {
+			dev->act_len += rxedlength;
+			break;
+		}
+		rxlen += nextlen;
+		dev->act_len = rxlen;
+	}
+	return 0;
+}
+
+/*
+ * This function handles the control transfer out data phase
+ */
+static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+	u16 csr;
+	u32 txlen = 0;
+	u32 nextlen = 0;
+	u8  maxpktsize = (1 << dev->maxpacketsize) * 8;
+	u8  *txbuff = (u8 *)buffer;
+	int result = 0;
+
+	while (txlen < len) {
+		/* Determine the next write length */
+		nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
+
+		/* Load the data to send in FIFO */
+		write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
+
+		/* Set TXPKTRDY bit */
+		csr = readw(&musbr->txcsr);
+			
+		csr |= MUSB_CSR0_TXPKTRDY;
+		csr |= MUSB_CSR0_H_DIS_PING;
+		writew(csr, &musbr->txcsr);
+		result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+		if (result < 0)
+			break;
+
+		txlen += nextlen;
+		dev->act_len = txlen;
+	}
+	return result;
+}
+
+/*
+ * This function handles the control transfer out status phase
+ */
+static int ctrlreq_out_status_phase(struct usb_device *dev)
+{
+	u16 csr;
+	int result;
+
+	/* Set the StatusPkt bit */
+	csr = readw(&musbr->txcsr);
+	csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT);
+	csr |= MUSB_CSR0_H_DIS_PING;
+	writew(csr, &musbr->txcsr);
+
+	/* Wait until TXPKTRDY bit is cleared */
+	result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+	return result;
+}
+
+/*
+ * This function handles the control transfer in status phase
+ */
+static int ctrlreq_in_status_phase(struct usb_device *dev)
+{
+	u16 csr;
+	int result;
+
+	/* Set the StatusPkt bit and ReqPkt bit */
+	csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
+	csr |= MUSB_CSR0_H_DIS_PING;
+	writew(csr, &musbr->txcsr);
+	result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
+
+	/* clear StatusPkt bit and RxPktRdy bit */
+	csr = readw(&musbr->txcsr);
+	csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
+	writew(csr, &musbr->txcsr);
+	return result;
+}
+
+/*
+ * determines the speed of the device (High/Full/Slow)
+ */
+static u8 get_dev_speed(struct usb_device *dev)
+{
+	return (dev->speed == USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
+		((dev->speed == USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
+						MUSB_TYPE_SPEED_FULL);
+}
+
+/*
+ * configure the hub address and the port address.
+ */
+static void config_hub_port(struct usb_device *dev, u8 ep)
+{
+	u8 chid;
+	u8 hub;
+
+	/* Find out the nearest parent which is high speed */
+	while (dev->parent->parent != NULL)
+		if (get_dev_speed(dev->parent) !=  MUSB_TYPE_SPEED_HIGH)
+			dev = dev->parent;
+		else
+			break;
+
+	/* determine the port address at that hub */
+	hub = dev->parent->devnum;
+	for (chid = 0; chid < USB_MAXCHILDREN; chid++)
+		if (dev->parent->children[chid] == dev)
+			break;
+
+#ifndef MUSB_NO_MULTIPOINT
+	/* configure the hub address and the port address */
+	writeb(hub, &musbr->tar[ep].txhubaddr);
+	writeb((chid + 1), &musbr->tar[ep].txhubport);
+	writeb(hub, &musbr->tar[ep].rxhubaddr);
+	writeb((chid + 1), &musbr->tar[ep].rxhubport);
+#endif
+}
+
+#ifdef MUSB_NO_MULTIPOINT
+
+static void musb_port_reset(int do_reset)
+{
+	u8 power = readb(&musbr->power);
+
+	if (do_reset) {
+		power &= 0xf0;
+		writeb(power | MUSB_POWER_RESET, &musbr->power);
+		port_status |= USB_PORT_STAT_RESET;
+		port_status &= ~USB_PORT_STAT_ENABLE;
+		udelay(30000);
+	} else {
+		writeb(power & ~MUSB_POWER_RESET, &musbr->power);
+
+		power = readb(&musbr->power);
+		if (power & MUSB_POWER_HSMODE)
+			port_status |= USB_PORT_STAT_HIGH_SPEED;
+
+		port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16));
+		port_status |= USB_PORT_STAT_ENABLE
+			| (USB_PORT_STAT_C_RESET << 16)
+			| (USB_PORT_STAT_C_ENABLE << 16);
+	}
+}
+
+/*
+ * root hub control
+ */
+static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+			      void *buffer, int transfer_len,
+			      struct devrequest *cmd)
+{
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	u32 datab[4];
+	const u8 *data_buf = (u8 *) datab;
+	u16 bmRType_bReq;
+	u16 wValue;
+	u16 wIndex;
+	u16 wLength;
+	u16 int_usb;
+
+	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+		debug("Root-Hub submit IRQ: NOT implemented\n");
+		return 0;
+	}
+
+	bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+	wValue = swap_16(cmd->value);
+	wIndex = swap_16(cmd->index);
+	wLength = swap_16(cmd->length);
+
+	debug("--- HUB ----------------------------------------\n");
+	debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n",
+	    bmRType_bReq, wValue, wIndex, wLength);
+	debug("------------------------------------------------\n");
+
+	switch (bmRType_bReq) {
+	case RH_GET_STATUS:
+		debug("RH_GET_STATUS\n");
+
+		*(__u16 *) data_buf = swap_16(1);
+		len = 2;
+		break;
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		debug("RH_GET_STATUS | RH_INTERFACE\n");
+
+		*(__u16 *) data_buf = swap_16(0);
+		len = 2;
+		break;
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		debug("RH_GET_STATUS | RH_ENDPOINT\n");
+
+		*(__u16 *) data_buf = swap_16(0);
+		len = 2;
+		break;
+
+	case RH_GET_STATUS | RH_CLASS:
+		debug("RH_GET_STATUS | RH_CLASS\n");
+
+		*(__u32 *) data_buf = swap_32(0);
+		len = 4;
+		break;
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n");
+
+		int_usb = readw(&musbr->intrusb);
+		if (int_usb & MUSB_INTR_CONNECT) {
+			port_status |= USB_PORT_STAT_CONNECTION
+				| (USB_PORT_STAT_C_CONNECTION << 16);
+			port_status |= USB_PORT_STAT_HIGH_SPEED
+				| USB_PORT_STAT_ENABLE;
+		}
+
+		if (port_status & USB_PORT_STAT_RESET)
+			musb_port_reset(0);
+
+		*(__u32 *) data_buf = swap_32(port_status);
+		len = 4;
+		break;
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n");
+
+		switch (wValue) {
+		case RH_ENDPOINT_STALL:
+			debug("C_HUB_ENDPOINT_STALL\n");
+			len = 0;
+			break;
+		}
+		port_status &= ~(1 << wValue);
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		debug("RH_CLEAR_FEATURE | RH_CLASS\n");
+
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			debug("C_HUB_LOCAL_POWER\n");
+			len = 0;
+			break;
+
+		case RH_C_HUB_OVER_CURRENT:
+			debug("C_HUB_OVER_CURRENT\n");
+			len = 0;
+			break;
+		}
+		port_status &= ~(1 << wValue);
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n");
+
+		switch (wValue) {
+		case RH_PORT_ENABLE:
+			len = 0;
+			break;
+
+		case RH_PORT_SUSPEND:
+			len = 0;
+			break;
+
+		case RH_PORT_POWER:
+			len = 0;
+			break;
+
+		case RH_C_PORT_CONNECTION:
+			len = 0;
+			break;
+
+		case RH_C_PORT_ENABLE:
+			len = 0;
+			break;
+
+		case RH_C_PORT_SUSPEND:
+			len = 0;
+			break;
+
+		case RH_C_PORT_OVER_CURRENT:
+			len = 0;
+			break;
+
+		case RH_C_PORT_RESET:
+			len = 0;
+			break;
+
+		default:
+			debug("invalid wValue\n");
+			stat = USB_ST_STALLED;
+		}
+
+		port_status &= ~(1 << wValue);
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n");
+
+		switch (wValue) {
+		case RH_PORT_SUSPEND:
+			len = 0;
+			break;
+
+		case RH_PORT_RESET:
+			musb_port_reset(1);
+			len = 0;
+			break;
+
+		case RH_PORT_POWER:
+			len = 0;
+			break;
+
+		case RH_PORT_ENABLE:
+			len = 0;
+			break;
+
+		default:
+			debug("invalid wValue\n");
+			stat = USB_ST_STALLED;
+		}
+
+		port_status |= 1 << wValue;
+		break;
+
+	case RH_SET_ADDRESS:
+		debug("RH_SET_ADDRESS\n");
+
+		rh_devnum = wValue;
+		len = 0;
+		break;
+
+	case RH_GET_DESCRIPTOR:
+		debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength);
+
+		switch (wValue) {
+		case (USB_DT_DEVICE << 8):	/* device descriptor */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_dev_des),
+						wLength));
+			data_buf = root_hub_dev_des;
+			break;
+
+		case (USB_DT_CONFIG << 8):	/* configuration descriptor */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_config_des),
+						wLength));
+			data_buf = root_hub_config_des;
+			break;
+
+		case ((USB_DT_STRING << 8) | 0x00):	/* string 0 descriptors */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_str_index0),
+						wLength));
+			data_buf = root_hub_str_index0;
+			break;
+
+		case ((USB_DT_STRING << 8) | 0x01):	/* string 1 descriptors */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_str_index1),
+						wLength));
+			data_buf = root_hub_str_index1;
+			break;
+
+		default:
+			debug("invalid wValue\n");
+			stat = USB_ST_STALLED;
+		}
+
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS: {
+		u8 *_data_buf = (u8 *) datab;
+		debug("RH_GET_DESCRIPTOR | RH_CLASS\n");
+
+		_data_buf[0] = 0x09;	/* min length; */
+		_data_buf[1] = 0x29;
+		_data_buf[2] = 0x1;	/* 1 port */
+		_data_buf[3] = 0x01;	/* per-port power switching */
+		_data_buf[3] |= 0x10;	/* no overcurrent reporting */
+
+		/* Corresponds to data_buf[4-7] */
+		_data_buf[4] = 0;
+		_data_buf[5] = 5;
+		_data_buf[6] = 0;
+		_data_buf[7] = 0x02;
+		_data_buf[8] = 0xff;
+
+		len = min_t(unsigned int, leni,
+			    min_t(unsigned int, data_buf[0], wLength));
+		break;
+	}
+
+	case RH_GET_CONFIGURATION:
+		debug("RH_GET_CONFIGURATION\n");
+
+		*(__u8 *) data_buf = 0x01;
+		len = 1;
+		break;
+
+	case RH_SET_CONFIGURATION:
+		debug("RH_SET_CONFIGURATION\n");
+
+		len = 0;
+		break;
+
+	default:
+		debug("*** *** *** unsupported root hub command *** *** ***\n");
+		stat = USB_ST_STALLED;
+	}
+
+	len = min_t(int, len, leni);
+	if (buffer != data_buf)
+		memcpy(buffer, data_buf, len);
+
+	dev->act_len = len;
+	dev->status = stat;
+	debug("dev act_len %d, status %lu\n", dev->act_len, dev->status);
+
+	return stat;
+}
+
+static void musb_rh_init(void)
+{
+	rh_devnum = 0;
+	port_status = 0;
+}
+
+#else
+
+static void musb_rh_init(void) {}
+
+#endif
+
+/*
+ * do a control transfer
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+			int len, struct devrequest *setup)
+{
+	int devnum = usb_pipedevice(pipe);
+	u8  devspeed;
+
+#ifdef MUSB_NO_MULTIPOINT
+	/* Control message is for the HUB? */
+	if (devnum == rh_devnum) {
+		int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup);
+		if (stat)
+			return stat;
+	}
+#endif
+
+	/* select control endpoint */
+	writeb(MUSB_CONTROL_EP, &musbr->index);
+	readw(&musbr->txcsr);
+
+#ifndef MUSB_NO_MULTIPOINT
+	/* target addr and (for multipoint) hub addr/port */
+	writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
+	writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
+#endif
+
+	/* configure the hub address and the port number as required */
+	devspeed = get_dev_speed(dev);
+	if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+		(devspeed != MUSB_TYPE_SPEED_HIGH)) {
+		config_hub_port(dev, MUSB_CONTROL_EP);
+		writeb(devspeed << 6, &musbr->txtype);
+	} else {
+		writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
+#ifndef MUSB_NO_MULTIPOINT
+		writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
+		writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
+		writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
+		writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
+#endif
+	}
+
+	/* Control transfer setup phase */
+	if (ctrlreq_setup_phase(dev, setup) < 0)
+		return 0;
+
+	switch (setup->request) {
+	case USB_REQ_GET_DESCRIPTOR:
+	case USB_REQ_GET_CONFIGURATION:
+	case USB_REQ_GET_INTERFACE:
+	case USB_REQ_GET_STATUS:
+	case USB_MSC_BBB_GET_MAX_LUN:
+		/* control transfer in-data-phase */
+		if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
+			return 0;
+		/* control transfer out-status-phase */
+		if (ctrlreq_out_status_phase(dev) < 0)
+			return 0;
+		break;
+
+	case USB_REQ_SET_ADDRESS:
+	case USB_REQ_SET_CONFIGURATION:
+	case USB_REQ_SET_FEATURE:
+	case USB_REQ_SET_INTERFACE:
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_MSC_BBB_RESET:
+		/* control transfer in status phase */
+		if (ctrlreq_in_status_phase(dev) < 0)
+			return 0;
+		break;
+
+	case USB_REQ_SET_DESCRIPTOR:
+		/* control transfer out data phase */
+		if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
+			return 0;
+		/* control transfer in status phase */
+		if (ctrlreq_in_status_phase(dev) < 0)
+			return 0;
+		break;
+
+	default:
+		/* unhandled control transfer */
+		return -1;
+	}
+
+	dev->status = 0;
+	dev->act_len = len;
+
+#ifdef MUSB_NO_MULTIPOINT
+	/* Set device address to USB_FADDR register */
+	if (setup->request == USB_REQ_SET_ADDRESS)
+		writeb(dev->devnum, &musbr->faddr);
+#endif
+
+	return len;
+}
+
+/*
+ * do a bulk transfer
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+					void *buffer, int len)
+{
+	int dir_out = usb_pipeout(pipe);
+	int ep = usb_pipeendpoint(pipe);
+#ifndef MUSB_NO_MULTIPOINT
+	int devnum = usb_pipedevice(pipe);
+#endif
+	u8  type;
+	u16 csr;
+	u32 txlen = 0;
+	u32 nextlen = 0;
+	u8  devspeed;
+
+	/* select bulk endpoint */
+	writeb(MUSB_BULK_EP, &musbr->index);
+
+#ifndef MUSB_NO_MULTIPOINT
+	/* write the address of the device */
+	if (dir_out)
+		writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
+	else
+		writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
+#endif
+
+	/* configure the hub address and the port number as required */
+	devspeed = get_dev_speed(dev);
+	if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+		(devspeed != MUSB_TYPE_SPEED_HIGH)) {
+		/*
+		 * MUSB is in high speed and the destination device is full
+		 * speed device. So configure the hub address and port
+		 * address registers.
+		 */
+		config_hub_port(dev, MUSB_BULK_EP);
+	} else {
+#ifndef MUSB_NO_MULTIPOINT
+		if (dir_out) {
+			writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
+			writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
+		} else {
+			writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
+			writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
+		}
+#endif
+		devspeed = musb_cfg.musb_speed;
+	}
+
+	/* Write the saved toggle bit value */
+	write_toggle(dev, ep, dir_out);
+
+	if (dir_out) { /* bulk-out transfer */
+		/* Program the TxType register */
+		type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+			   (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+			   (ep & MUSB_TYPE_REMOTE_END);
+		writeb(type, &musbr->txtype);
+
+		/* Write maximum packet size to the TxMaxp register */
+		writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
+		while (txlen < len) {
+			nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
+					(len-txlen) : dev->epmaxpacketout[ep];
+
+			/* Write the data to the FIFO */
+			write_fifo(MUSB_BULK_EP, nextlen,
+					(void *)(((u8 *)buffer) + txlen));
+
+			/* Set the TxPktRdy bit */
+			csr = readw(&musbr->txcsr);
+			writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
+
+			/* Wait until the TxPktRdy bit is cleared */
+			if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) {
+				readw(&musbr->txcsr);
+				usb_settoggle(dev, ep, dir_out,
+				(csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+				dev->act_len = txlen;
+				return 0;
+			}
+			txlen += nextlen;
+		}
+
+		/* Keep a copy of the data toggle bit */
+		csr = readw(&musbr->txcsr);
+		usb_settoggle(dev, ep, dir_out,
+				(csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+	} else { /* bulk-in transfer */
+		/* Write the saved toggle bit value */
+		write_toggle(dev, ep, dir_out);
+
+		/* Program the RxType register */
+		type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+			   (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+			   (ep & MUSB_TYPE_REMOTE_END);
+		writeb(type, &musbr->rxtype);
+
+		/* Write the maximum packet size to the RxMaxp register */
+		writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+		while (txlen < len) {
+			nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+					(len-txlen) : dev->epmaxpacketin[ep];
+
+			/* Set the ReqPkt bit */
+			csr = readw(&musbr->rxcsr);
+			writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+			/* Wait until the RxPktRdy bit is set */
+			if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) {
+				csr = readw(&musbr->rxcsr);
+				usb_settoggle(dev, ep, dir_out,
+				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+				csr &= ~MUSB_RXCSR_RXPKTRDY;
+				writew(csr, &musbr->rxcsr);
+				dev->act_len = txlen;
+				return 0;
+			}
+
+			/* Read the data from the FIFO */
+			read_fifo(MUSB_BULK_EP, nextlen,
+					(void *)(((u8 *)buffer) + txlen));
+
+			/* Clear the RxPktRdy bit */
+			csr =  readw(&musbr->rxcsr);
+			csr &= ~MUSB_RXCSR_RXPKTRDY;
+			writew(csr, &musbr->rxcsr);
+			txlen += nextlen;
+		}
+
+		/* Keep a copy of the data toggle bit */
+		csr = readw(&musbr->rxcsr);
+		usb_settoggle(dev, ep, dir_out,
+				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+	}
+
+	/* bulk transfer is complete */
+	dev->status = 0;
+	dev->act_len = len;
+	return 0;
+}
+
+/*
+ * This function initializes the usb controller module.
+ */
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	u8  power;
+	u32 timeout;
+
+	musb_rh_init();
+
+	if (musb_platform_init() == -1)
+		return -1;
+
+	/* Configure all the endpoint FIFO's and start usb controller */
+	musbr = musb_cfg.regs;
+	musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
+	musb_start();
+
+	/*
+	 * Wait until musb is enabled in host mode with a timeout. There
+	 * should be a usb device connected.
+	 */
+	timeout = musb_cfg.timeout;
+	while (--timeout)
+		if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
+			break;
+
+	/* if musb core is not in host mode, then return */
+	if (!timeout)
+		return -1;
+
+	/* start usb bus reset */
+	power = readb(&musbr->power);
+	writeb(power | MUSB_POWER_RESET, &musbr->power);
+
+	/* After initiating a usb reset, wait for about 20ms to 30ms */
+	udelay(30000);
+
+	/* stop usb bus reset */
+	power = readb(&musbr->power);
+	power &= ~MUSB_POWER_RESET;
+	writeb(power, &musbr->power);
+
+	/* Determine if the connected device is a high/full/low speed device */
+	musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
+			MUSB_TYPE_SPEED_HIGH :
+			((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
+			MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
+	return 0;
+}
+
+/*
+ * This function stops the operation of the davinci usb module.
+ */
+int usb_lowlevel_stop(int index)
+{
+	/* Reset the USB module */
+	musb_platform_deinit();
+	writeb(0, &musbr->devctl);
+	return 0;
+}
+
+/*
+ * This function supports usb interrupt transfers. Currently, usb interrupt
+ * transfers are not supported.
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int len, int interval, bool nonblock)
+{
+	int dir_out = usb_pipeout(pipe);
+	int ep = usb_pipeendpoint(pipe);
+#ifndef MUSB_NO_MULTIPOINT
+	int devnum = usb_pipedevice(pipe);
+#endif
+	u8  type;
+	u16 csr;
+	u32 txlen = 0;
+	u32 nextlen = 0;
+	u8  devspeed;
+
+	/* select interrupt endpoint */
+	writeb(MUSB_INTR_EP, &musbr->index);
+
+#ifndef MUSB_NO_MULTIPOINT
+	/* write the address of the device */
+	if (dir_out)
+		writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
+	else
+		writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
+#endif
+
+	/* configure the hub address and the port number as required */
+	devspeed = get_dev_speed(dev);
+	if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+		(devspeed != MUSB_TYPE_SPEED_HIGH)) {
+		/*
+		 * MUSB is in high speed and the destination device is full
+		 * speed device. So configure the hub address and port
+		 * address registers.
+		 */
+		config_hub_port(dev, MUSB_INTR_EP);
+	} else {
+#ifndef MUSB_NO_MULTIPOINT
+		if (dir_out) {
+			writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
+			writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
+		} else {
+			writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
+			writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
+		}
+#endif
+		devspeed = musb_cfg.musb_speed;
+	}
+
+	/* Write the saved toggle bit value */
+	write_toggle(dev, ep, dir_out);
+
+	if (!dir_out) { /* intrrupt-in transfer */
+		/* Write the saved toggle bit value */
+		write_toggle(dev, ep, dir_out);
+		writeb(interval, &musbr->rxinterval);
+
+		/* Program the RxType register */
+		type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+			   (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
+			   (ep & MUSB_TYPE_REMOTE_END);
+		writeb(type, &musbr->rxtype);
+
+		/* Write the maximum packet size to the RxMaxp register */
+		writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+
+		while (txlen < len) {
+			nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+					(len-txlen) : dev->epmaxpacketin[ep];
+
+			/* Set the ReqPkt bit */
+			csr = readw(&musbr->rxcsr);
+			writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+			/* Wait until the RxPktRdy bit is set */
+			if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) {
+				csr = readw(&musbr->rxcsr);
+				usb_settoggle(dev, ep, dir_out,
+				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+				csr &= ~MUSB_RXCSR_RXPKTRDY;
+				writew(csr, &musbr->rxcsr);
+				dev->act_len = txlen;
+				return 0;
+			}
+
+			/* Read the data from the FIFO */
+			read_fifo(MUSB_INTR_EP, nextlen,
+					(void *)(((u8 *)buffer) + txlen));
+
+			/* Clear the RxPktRdy bit */
+			csr =  readw(&musbr->rxcsr);
+			csr &= ~MUSB_RXCSR_RXPKTRDY;
+			writew(csr, &musbr->rxcsr);
+			txlen += nextlen;
+		}
+
+		/* Keep a copy of the data toggle bit */
+		csr = readw(&musbr->rxcsr);
+		usb_settoggle(dev, ep, dir_out,
+				(csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+	}
+
+	/* interrupt transfer is complete */
+	dev->irq_status = 0;
+	dev->irq_act_len = len;
+	dev->irq_handle(dev);
+	dev->status = 0;
+	dev->act_len = len;
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/musb/musb_hcd.h b/roms/u-boot/drivers/usb/musb/musb_hcd.h
new file mode 100644
index 000000000..7eb65e6b1
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/musb_hcd.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#ifndef __MUSB_HCD_H__
+#define __MUSB_HCD_H__
+
+#include "musb_core.h"
+#ifdef CONFIG_USB_KEYBOARD
+#include <stdio_dev.h>
+extern unsigned char new[];
+#endif
+
+#ifndef CONFIG_USB_MUSB_TIMEOUT
+# define CONFIG_USB_MUSB_TIMEOUT 100000
+#endif
+
+/* This defines the endpoint number used for control transfers */
+#define MUSB_CONTROL_EP 0
+
+/* This defines the endpoint number used for bulk transfer */
+#ifndef MUSB_BULK_EP
+# define MUSB_BULK_EP 1
+#endif
+
+/* This defines the endpoint number used for interrupt transfer */
+#define MUSB_INTR_EP 2
+
+/* Determine the operating speed of MUSB core */
+#define musb_ishighspeed() \
+	((readb(&musbr->power) & MUSB_POWER_HSMODE) \
+		>> MUSB_POWER_HSMODE_SHIFT)
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE		   0x01
+#define RH_ENDPOINT		   0x02
+#define RH_OTHER		   0x03
+
+#define RH_CLASS		   0x20
+#define RH_VENDOR		   0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	   0x00
+#define RH_PORT_ENABLE		   0x01
+#define RH_PORT_SUSPEND		   0x02
+#define RH_PORT_OVER_CURRENT	   0x03
+#define RH_PORT_RESET		   0x04
+#define RH_PORT_POWER		   0x08
+#define RH_PORT_LOW_SPEED	   0x09
+
+#define RH_C_PORT_CONNECTION	   0x10
+#define RH_C_PORT_ENABLE	   0x11
+#define RH_C_PORT_SUSPEND	   0x12
+#define RH_C_PORT_OVER_CURRENT	   0x13
+#define RH_C_PORT_RESET		   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	   0x00
+#define RH_C_HUB_OVER_CURRENT	   0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	   0x00
+#define RH_ENDPOINT_STALL	   0x01
+
+#define RH_ACK			   0x01
+#define RH_REQ_ERR		   -1
+#define RH_NACK			   0x00
+
+/* extern functions */
+extern int musb_platform_init(void);
+extern void musb_platform_deinit(void);
+
+#endif	/* __MUSB_HCD_H__ */
diff --git a/roms/u-boot/drivers/usb/musb/musb_udc.c b/roms/u-boot/drivers/usb/musb/musb_udc.c
new file mode 100644
index 000000000..b9510e304
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/musb_udc.c
@@ -0,0 +1,954 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is a rewrite of the usb device part of
+ * repository git.omapzoom.org/repo/u-boot.git, branch master,
+ * file cpu/omap3/fastboot.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * -------------------------------------------------------------------------
+ *
+ * The details of connecting the device to the uboot usb device subsystem
+ * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
+ * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 Texas Instruments Incorporated.
+ *
+ * Based on
+ * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
+ * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
+ *
+ * Author: Diego Dompe (diego.dompe@ridgerun.com)
+ *         Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#include <common.h>
+#include <hang.h>
+#include <serial.h>
+#include <usbdevice.h>
+#include <linux/delay.h>
+#include <usb/udc.h>
+#include "../gadget/ep0.h"
+#include "musb_core.h"
+#if defined(CONFIG_USB_OMAP3)
+#include "omap3.h"
+#elif defined(CONFIG_USB_AM35X)
+#include "am35x.h"
+#endif
+
+/* Define MUSB_DEBUG for debugging */
+/* #define MUSB_DEBUG */
+#include "musb_debug.h"
+
+#define MAX_ENDPOINT 15
+
+#define GET_ENDPOINT(dev,ep)						\
+(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
+
+#define SET_EP0_STATE(s)						\
+do {									\
+	if ((0 <= (s)) && (SET_ADDRESS >= (s))) {			\
+		if ((s) != ep0_state) {					\
+			if ((debug_setup) && (debug_level > 1))		\
+				serial_printf("INFO : Changing state "  \
+					      "from %s to %s in %s at " \
+					      "line %d\n",		\
+					      ep0_state_strings[ep0_state],\
+					      ep0_state_strings[s],	\
+					      __PRETTY_FUNCTION__,	\
+					      __LINE__);		\
+			ep0_state = s;					\
+		}							\
+	} else {							\
+		if (debug_level > 0)					\
+			serial_printf("Error at %s %d with setting "	\
+				      "state %d is invalid\n",		\
+				      __PRETTY_FUNCTION__, __LINE__, s); \
+	}								\
+} while (0)
+
+/* static implies these initialized to 0 or NULL */
+static int debug_setup;
+static int debug_level;
+static struct musb_epinfo epinfo[MAX_ENDPOINT * 2 + 2];
+static enum ep0_state_enum {
+	IDLE = 0,
+	TX,
+	RX,
+	SET_ADDRESS
+} ep0_state = IDLE;
+static char *ep0_state_strings[4] = {
+	"IDLE",
+	"TX",
+	"RX",
+	"SET_ADDRESS",
+};
+
+static struct urb *ep0_urb;
+struct usb_endpoint_instance *ep0_endpoint;
+static struct usb_device_instance *udc_device;
+static int enabled;
+
+static u16 pending_intrrx;
+
+#ifdef MUSB_DEBUG
+static void musb_db_regs(void)
+{
+	u8 b;
+	u16 w;
+
+	b = readb(&musbr->faddr);
+	serial_printf("\tfaddr   0x%2.2x\n", b);
+
+	b = readb(&musbr->power);
+	musb_print_pwr(b);
+
+	w = readw(&musbr->ep[0].ep0.csr0);
+	musb_print_csr0(w);
+
+	b = readb(&musbr->devctl);
+	musb_print_devctl(b);
+
+	b = readb(&musbr->ep[0].ep0.configdata);
+	musb_print_config(b);
+
+	w = readw(&musbr->frame);
+	serial_printf("\tframe   0x%4.4x\n", w);
+
+	b = readb(&musbr->index);
+	serial_printf("\tindex   0x%2.2x\n", b);
+
+	w = readw(&musbr->ep[1].epN.rxmaxp);
+	musb_print_rxmaxp(w);
+
+	w = readw(&musbr->ep[1].epN.rxcsr);
+	musb_print_rxcsr(w);
+
+	w = readw(&musbr->ep[1].epN.txmaxp);
+	musb_print_txmaxp(w);
+
+	w = readw(&musbr->ep[1].epN.txcsr);
+	musb_print_txcsr(w);
+}
+#else
+#define musb_db_regs()
+#endif /* DEBUG_MUSB */
+
+static void musb_peri_softconnect(void)
+{
+	u8 power, devctl;
+
+	/* Power off MUSB */
+	power = readb(&musbr->power);
+	power &= ~MUSB_POWER_SOFTCONN;
+	writeb(power, &musbr->power);
+
+	/* Read intr to clear */
+	readb(&musbr->intrusb);
+	readw(&musbr->intrrx);
+	readw(&musbr->intrtx);
+
+	udelay(1000 * 1000); /* 1 sec */
+
+	/* Power on MUSB */
+	power = readb(&musbr->power);
+	power |= MUSB_POWER_SOFTCONN;
+	/*
+	 * The usb device interface is usb 1.1
+	 * Disable 2.0 high speed by clearring the hsenable bit.
+	 */
+	power &= ~MUSB_POWER_HSENAB;
+	writeb(power, &musbr->power);
+
+	/* Check if device is in b-peripheral mode */
+	devctl = readb(&musbr->devctl);
+	if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
+	    (devctl & MUSB_DEVCTL_HM)) {
+		serial_printf("ERROR : Unsupport USB mode\n");
+		serial_printf("Check that mini-B USB cable is attached "
+			      "to the device\n");
+	}
+
+	if (debug_setup && (debug_level > 1))
+		musb_db_regs();
+}
+
+static void musb_peri_reset(void)
+{
+	if ((debug_setup) && (debug_level > 1))
+		serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
+
+	if (ep0_endpoint)
+		ep0_endpoint->endpoint_address = 0xff;
+
+	/* Sync sw and hw addresses */
+	writeb(udc_device->address, &musbr->faddr);
+
+	SET_EP0_STATE(IDLE);
+}
+
+static void musb_peri_resume(void)
+{
+	/* noop */
+}
+
+static void musb_peri_ep0_stall(void)
+{
+	u16 csr0;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+	csr0 |= MUSB_CSR0_P_SENDSTALL;
+	writew(csr0, &musbr->ep[0].ep0.csr0);
+	if ((debug_setup) && (debug_level > 1))
+		serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
+}
+
+static void musb_peri_ep0_ack_req(void)
+{
+	u16 csr0;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+	csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
+	writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready(void)
+{
+	u16 csr0;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+	csr0 |= MUSB_CSR0_TXPKTRDY;
+	writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready_and_last(void)
+{
+	u16 csr0;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+	csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
+	writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_last(void)
+{
+	u16 csr0;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+	csr0 |= MUSB_CSR0_P_DATAEND;
+	writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_set_address(void)
+{
+	u8 faddr;
+	writeb(udc_device->address, &musbr->faddr);
+
+	/* Verify */
+	faddr = readb(&musbr->faddr);
+	if (udc_device->address == faddr) {
+		SET_EP0_STATE(IDLE);
+		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+		if ((debug_setup) && (debug_level > 1))
+			serial_printf("INFO : %s Address set to %d\n",
+				      __PRETTY_FUNCTION__, udc_device->address);
+	} else {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s Address missmatch "
+				      "sw %d vs hw %d\n",
+				      __PRETTY_FUNCTION__,
+				      udc_device->address, faddr);
+	}
+}
+
+static void musb_peri_rx_ack(unsigned int ep)
+{
+	u16 peri_rxcsr;
+
+	peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+	peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
+	writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
+}
+
+static void musb_peri_tx_ready(unsigned int ep)
+{
+	u16 peri_txcsr;
+
+	peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+	peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
+	writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+}
+
+static void musb_peri_ep0_zero_data_request(int err)
+{
+	musb_peri_ep0_ack_req();
+
+	if (err) {
+		musb_peri_ep0_stall();
+		SET_EP0_STATE(IDLE);
+	} else {
+
+		musb_peri_ep0_last();
+
+		/* USBD state */
+		switch (ep0_urb->device_request.bRequest) {
+		case USB_REQ_SET_ADDRESS:
+			if ((debug_setup) && (debug_level > 1))
+				serial_printf("INFO : %s received set "
+					      "address\n", __PRETTY_FUNCTION__);
+			break;
+
+		case USB_REQ_SET_CONFIGURATION:
+			if ((debug_setup) && (debug_level > 1))
+				serial_printf("INFO : %s Configured\n",
+					      __PRETTY_FUNCTION__);
+			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+			break;
+		}
+
+		/* EP0 state */
+		if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
+			SET_EP0_STATE(SET_ADDRESS);
+		} else {
+			SET_EP0_STATE(IDLE);
+		}
+	}
+}
+
+static void musb_peri_ep0_rx_data_request(void)
+{
+	/*
+	 * This is the completion of the data OUT / RX
+	 *
+	 * Host is sending data to ep0 that is not
+	 * part of setup.  This comes from the cdc_recv_setup
+	 * op that is device specific.
+	 *
+	 */
+	musb_peri_ep0_ack_req();
+
+	ep0_endpoint->rcv_urb = ep0_urb;
+	ep0_urb->actual_length = 0;
+	SET_EP0_STATE(RX);
+}
+
+static void musb_peri_ep0_tx_data_request(int err)
+{
+	if (err) {
+		musb_peri_ep0_stall();
+		SET_EP0_STATE(IDLE);
+	} else {
+		musb_peri_ep0_ack_req();
+
+		ep0_endpoint->tx_urb = ep0_urb;
+		ep0_endpoint->sent = 0;
+		SET_EP0_STATE(TX);
+	}
+}
+
+static void musb_peri_ep0_idle(void)
+{
+	u16 count0;
+	int err;
+	u16 csr0;
+
+	/*
+	 * Verify addresses
+	 * A lot of confusion can be caused if the address
+	 * in software, udc layer, does not agree with the
+	 * hardware.  Since the setting of the hardware address
+	 * must be set after the set address request, the
+	 * usb state machine is out of sync for a few frame.
+	 * It is a good idea to run this check when changes
+	 * are made to the state machine.
+	 */
+	if ((debug_level > 0) &&
+	    (ep0_state != SET_ADDRESS)) {
+		u8 faddr;
+
+		faddr = readb(&musbr->faddr);
+		if (udc_device->address != faddr) {
+			serial_printf("ERROR : %s addresses do not"
+				      "match sw %d vs hw %d\n",
+				      __PRETTY_FUNCTION__,
+				      udc_device->address, faddr);
+			udelay(1000 * 1000);
+			hang();
+		}
+	}
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+	if (!(MUSB_CSR0_RXPKTRDY & csr0))
+		goto end;
+
+	count0 = readw(&musbr->ep[0].ep0.count0);
+	if (count0 == 0)
+		goto end;
+
+	if (count0 != 8) {
+		if ((debug_setup) && (debug_level > 1))
+			serial_printf("WARN : %s SETUP incorrect size %d\n",
+				      __PRETTY_FUNCTION__, count0);
+		musb_peri_ep0_stall();
+		goto end;
+	}
+
+	read_fifo(0, count0, &ep0_urb->device_request);
+
+	if (debug_level > 2)
+		print_usb_device_request(&ep0_urb->device_request);
+
+	if (ep0_urb->device_request.wLength == 0) {
+		err = ep0_recv_setup(ep0_urb);
+
+		/* Zero data request */
+		musb_peri_ep0_zero_data_request(err);
+	} else {
+		/* Is data coming or going ? */
+		u8 reqType = ep0_urb->device_request.bmRequestType;
+
+		if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
+			err = ep0_recv_setup(ep0_urb);
+			/* Device to host */
+			musb_peri_ep0_tx_data_request(err);
+		} else {
+			/*
+			 * Host to device
+			 *
+			 * The RX routine will call ep0_recv_setup
+			 * when the data packet has arrived.
+			 */
+			musb_peri_ep0_rx_data_request();
+		}
+	}
+
+end:
+	return;
+}
+
+static void musb_peri_ep0_rx(void)
+{
+	/*
+	 * This is the completion of the data OUT / RX
+	 *
+	 * Host is sending data to ep0 that is not
+	 * part of setup.  This comes from the cdc_recv_setup
+	 * op that is device specific.
+	 *
+	 * Pass the data back to driver ep0_recv_setup which
+	 * should give the cdc_recv_setup the chance to handle
+	 * the rx
+	 */
+	u16 csr0;
+	u16 count0;
+
+	if (debug_level > 3) {
+		if (0 != ep0_urb->actual_length) {
+			serial_printf("%s finished ? %d of %d\n",
+				      __PRETTY_FUNCTION__,
+				      ep0_urb->actual_length,
+				      ep0_urb->device_request.wLength);
+		}
+	}
+
+	if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
+		musb_peri_ep0_last();
+		SET_EP0_STATE(IDLE);
+		ep0_recv_setup(ep0_urb);
+		return;
+	}
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+	if (!(MUSB_CSR0_RXPKTRDY & csr0))
+		return;
+
+	count0 = readw(&musbr->ep[0].ep0.count0);
+
+	if (count0) {
+		struct usb_endpoint_instance *endpoint;
+		u32 length;
+		u8 *data;
+
+		endpoint = ep0_endpoint;
+		if (endpoint && endpoint->rcv_urb) {
+			struct urb *urb = endpoint->rcv_urb;
+			unsigned int remaining_space = urb->buffer_length -
+				urb->actual_length;
+
+			if (remaining_space) {
+				int urb_bad = 0; /* urb is good */
+
+				if (count0 > remaining_space)
+					length = remaining_space;
+				else
+					length = count0;
+
+				data = (u8 *) urb->buffer_data;
+				data += urb->actual_length;
+
+				/* The common musb fifo reader */
+				read_fifo(0, length, data);
+
+				musb_peri_ep0_ack_req();
+
+				/*
+				 * urb's actual_length is updated in
+				 * usbd_rcv_complete
+				 */
+				usbd_rcv_complete(endpoint, length, urb_bad);
+
+			} else {
+				if (debug_level > 0)
+					serial_printf("ERROR : %s no space in "
+						      "rcv buffer\n",
+						      __PRETTY_FUNCTION__);
+			}
+		} else {
+			if (debug_level > 0)
+				serial_printf("ERROR : %s problem with "
+					      "endpoint\n",
+					      __PRETTY_FUNCTION__);
+		}
+	} else {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s with nothing to do\n",
+				      __PRETTY_FUNCTION__);
+	}
+}
+
+static void musb_peri_ep0_tx(void)
+{
+	u16 csr0;
+	int transfer_size = 0;
+	unsigned int p, pm;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+	/* Check for pending tx */
+	if (csr0 & MUSB_CSR0_TXPKTRDY)
+		goto end;
+
+	/* Check if this is the last packet sent */
+	if (ep0_endpoint->sent >= ep0_urb->actual_length) {
+		SET_EP0_STATE(IDLE);
+		goto end;
+	}
+
+	transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
+	/* Is the transfer size negative ? */
+	if (transfer_size <= 0) {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s problem with the"
+				      " transfer size %d\n",
+				      __PRETTY_FUNCTION__,
+				      transfer_size);
+		SET_EP0_STATE(IDLE);
+		goto end;
+	}
+
+	/* Truncate large transfers to the fifo size */
+	if (transfer_size > ep0_endpoint->tx_packetSize)
+		transfer_size = ep0_endpoint->tx_packetSize;
+
+	write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
+	ep0_endpoint->sent += transfer_size;
+
+	/* Done or more to send ? */
+	if (ep0_endpoint->sent >= ep0_urb->actual_length)
+		musb_ep0_tx_ready_and_last();
+	else
+		musb_ep0_tx_ready();
+
+	/* Wait a bit */
+	pm = 10;
+	for (p = 0; p < pm; p++) {
+		csr0 = readw(&musbr->ep[0].ep0.csr0);
+		if (!(csr0 & MUSB_CSR0_TXPKTRDY))
+			break;
+
+		/* Double the delay. */
+		udelay(1 << pm);
+	}
+
+	if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
+		SET_EP0_STATE(IDLE);
+
+end:
+	return;
+}
+
+static void musb_peri_ep0(void)
+{
+	u16 csr0;
+
+	if (SET_ADDRESS == ep0_state)
+		return;
+
+	csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+	/* Error conditions */
+	if (MUSB_CSR0_P_SENTSTALL & csr0) {
+		csr0 &= ~MUSB_CSR0_P_SENTSTALL;
+		writew(csr0, &musbr->ep[0].ep0.csr0);
+		SET_EP0_STATE(IDLE);
+	}
+	if (MUSB_CSR0_P_SETUPEND & csr0) {
+		csr0 |= MUSB_CSR0_P_SVDSETUPEND;
+		writew(csr0, &musbr->ep[0].ep0.csr0);
+		SET_EP0_STATE(IDLE);
+		if ((debug_setup) && (debug_level > 1))
+			serial_printf("WARN: %s SETUPEND\n",
+				      __PRETTY_FUNCTION__);
+	}
+
+	/* Normal states */
+	if (IDLE == ep0_state)
+		musb_peri_ep0_idle();
+
+	if (TX == ep0_state)
+		musb_peri_ep0_tx();
+
+	if (RX == ep0_state)
+		musb_peri_ep0_rx();
+}
+
+static void musb_peri_rx_ep(unsigned int ep)
+{
+	u16 peri_rxcount;
+	u16 peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+
+	if (!(peri_rxcsr & MUSB_RXCSR_RXPKTRDY)) {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s %d without MUSB_RXCSR_RXPKTRDY set\n",
+				      __PRETTY_FUNCTION__, ep);
+		return;
+	}
+
+	peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
+	if (peri_rxcount) {
+		struct usb_endpoint_instance *endpoint;
+		u32 length;
+		u8 *data;
+
+		endpoint = GET_ENDPOINT(udc_device, ep);
+		if (endpoint && endpoint->rcv_urb) {
+			struct urb *urb = endpoint->rcv_urb;
+			unsigned int remaining_space = urb->buffer_length -
+				urb->actual_length;
+
+			if (remaining_space) {
+				int urb_bad = 0; /* urb is good */
+
+				if (peri_rxcount > remaining_space)
+					length = remaining_space;
+				else
+					length = peri_rxcount;
+
+				data = (u8 *) urb->buffer_data;
+				data += urb->actual_length;
+
+				/* The common musb fifo reader */
+				read_fifo(ep, length, data);
+
+				if (length == peri_rxcount)
+					musb_peri_rx_ack(ep);
+				else
+					pending_intrrx |= (1 << ep);
+
+				/*
+				 * urb's actual_length is updated in
+				 * usbd_rcv_complete
+				 */
+				usbd_rcv_complete(endpoint, length, urb_bad);
+
+			} else {
+				if (debug_level > 0)
+					serial_printf("ERROR : %s %d no space "
+						      "in rcv buffer\n",
+						      __PRETTY_FUNCTION__, ep);
+
+				pending_intrrx |= (1 << ep);
+			}
+		} else {
+			if (debug_level > 0)
+				serial_printf("ERROR : %s %d problem with "
+					      "endpoint\n",
+					      __PRETTY_FUNCTION__, ep);
+
+			pending_intrrx |= (1 << ep);
+		}
+
+	} else {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s %d with nothing to do\n",
+				      __PRETTY_FUNCTION__, ep);
+
+		musb_peri_rx_ack(ep);
+	}
+}
+
+static void musb_peri_rx(u16 intr)
+{
+	unsigned int ep;
+
+	/* First bit is reserved and does not indicate interrupt for EP0 */
+
+	for (ep = 1; ep < 16; ep++) {
+		if ((1 << ep) & intr)
+			musb_peri_rx_ep(ep);
+	}
+}
+
+static void musb_peri_tx(u16 intr)
+{
+	unsigned int ep;
+
+	/* Check for EP0: first bit indicates interrupt for both RX and TX */
+	if (0x01 & intr)
+		musb_peri_ep0();
+
+	for (ep = 1; ep < 16; ep++) {
+		if ((1 << ep) & intr)
+			udc_endpoint_write(GET_ENDPOINT(udc_device, ep));
+	}
+}
+
+void udc_irq(void)
+{
+	/* This is a high freq called function */
+	if (enabled) {
+		u8 intrusb;
+
+		intrusb = readb(&musbr->intrusb);
+
+		/*
+		 * See drivers/usb/gadget/mpc8xx_udc.c for
+		 * state diagram going from detached through
+		 * configuration.
+		 */
+		if (MUSB_INTR_RESUME & intrusb) {
+			usbd_device_event_irq(udc_device,
+					      DEVICE_BUS_ACTIVITY, 0);
+			musb_peri_resume();
+		}
+
+		if (MUSB_INTR_RESET & intrusb) {
+			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+			musb_peri_reset();
+		}
+
+		if (MUSB_INTR_DISCONNECT & intrusb) {
+			/* cable unplugged from hub/host */
+			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+			musb_peri_reset();
+			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+		}
+
+		if (MUSB_INTR_SOF & intrusb) {
+			usbd_device_event_irq(udc_device,
+					      DEVICE_BUS_ACTIVITY, 0);
+			musb_peri_resume();
+		}
+
+		if (MUSB_INTR_SUSPEND & intrusb) {
+			usbd_device_event_irq(udc_device,
+					      DEVICE_BUS_INACTIVE, 0);
+		}
+
+		if (ep0_state != SET_ADDRESS) {
+			u16 intrrx, intrtx;
+
+			intrrx = readw(&musbr->intrrx);
+			intrtx = readw(&musbr->intrtx);
+
+			intrrx |= pending_intrrx;
+			pending_intrrx = 0;
+
+			if (intrrx)
+				musb_peri_rx(intrrx);
+
+			if (intrtx)
+				musb_peri_tx(intrtx);
+		} else {
+			if (readw(&musbr->intrtx) & 0x1) {
+				u8 faddr;
+				faddr = readb(&musbr->faddr);
+				/*
+				 * Setting of the address can fail.
+				 * Normally it succeeds the second time.
+				 */
+				if (udc_device->address != faddr)
+					musb_peri_ep0_set_address();
+			}
+		}
+	}
+}
+
+void udc_set_nak(int ep_num)
+{
+	/* noop */
+}
+
+void udc_unset_nak(int ep_num)
+{
+	/* noop */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+	int ret = 0;
+
+	/* Transmit only if the hardware is available */
+	if (endpoint->tx_urb && endpoint->state == 0) {
+		unsigned int ep = endpoint->endpoint_address &
+			USB_ENDPOINT_NUMBER_MASK;
+
+		u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+
+		/* Error conditions */
+		if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
+			peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
+			writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+		}
+
+		if (debug_level > 1)
+			musb_print_txcsr(peri_txcsr);
+
+		/* Check if a packet is waiting to be sent */
+		if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
+			u32 length;
+			u8 *data;
+			struct urb *urb = endpoint->tx_urb;
+			unsigned int remaining_packet = urb->actual_length -
+				endpoint->sent;
+
+			if (endpoint->tx_packetSize < remaining_packet)
+				length = endpoint->tx_packetSize;
+			else
+				length = remaining_packet;
+
+			data = (u8 *) urb->buffer;
+			data += endpoint->sent;
+
+			/* common musb fifo function */
+			write_fifo(ep, length, data);
+
+			musb_peri_tx_ready(ep);
+
+			endpoint->last = length;
+			/* usbd_tx_complete will take care of updating 'sent' */
+			usbd_tx_complete(endpoint);
+		}
+	} else {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s Problem with urb %p "
+				      "or ep state %d\n",
+				      __PRETTY_FUNCTION__,
+				      endpoint->tx_urb, endpoint->state);
+	}
+
+	return ret;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+		  struct usb_endpoint_instance *endpoint)
+{
+	if (0 == id) {
+		/* EP0 */
+		ep0_endpoint = endpoint;
+		ep0_endpoint->endpoint_address = 0xff;
+		ep0_urb = usbd_alloc_urb(device, endpoint);
+	} else if (MAX_ENDPOINT >= id) {
+		epinfo[(id * 2) + 0].epsize = endpoint->rcv_packetSize;
+		epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
+		musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
+	} else {
+		if (debug_level > 0)
+			serial_printf("ERROR : %s endpoint request %d "
+				      "exceeds maximum %d\n",
+				      __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
+	}
+}
+
+void udc_connect(void)
+{
+	/* noop */
+}
+
+void udc_disconnect(void)
+{
+	/* noop */
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+	/* Save the device structure pointer */
+	udc_device = device;
+
+	enabled = 1;
+}
+
+void udc_disable(void)
+{
+	enabled = 0;
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+	usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+	/*
+	 * The DEVICE_CREATE event puts the USB device in the state
+	 * STATE_ATTACHED.
+	 */
+	usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+	/* Resets the address to 0 */
+	usbd_device_event_irq(device, DEVICE_RESET, 0);
+
+	udc_enable(device);
+}
+
+int udc_init(void)
+{
+	int ret;
+	int ep_loop;
+
+	ret = musb_platform_init();
+	if (ret < 0)
+		goto end;
+
+	/* Configure all the endpoint FIFO's and start usb controller */
+	musbr = musb_cfg.regs;
+
+	/* Initialize the endpoints */
+	for (ep_loop = 0; ep_loop <= MAX_ENDPOINT * 2; ep_loop++) {
+		epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
+		epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
+		epinfo[ep_loop].epsize = 0;
+	}
+
+	musb_peri_softconnect();
+
+	ret = 0;
+end:
+
+	return ret;
+}
diff --git a/roms/u-boot/drivers/usb/musb/omap3.c b/roms/u-boot/drivers/usb/musb/omap3.c
new file mode 100644
index 000000000..080bd7852
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/omap3.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2009 Texas Instruments
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#include <serial.h>
+#include <asm/omap_common.h>
+#include <twl4030.h>
+#include <twl6030.h>
+#include "omap3.h"
+
+static int platform_needs_initialization = 1;
+
+struct musb_config musb_cfg = {
+	.regs		= (struct musb_regs *)MENTOR_USB0_BASE,
+	.timeout	= OMAP3_USB_TIMEOUT,
+	.musb_speed	= 0,
+};
+
+/*
+ * OMAP3 USB OTG registers.
+ */
+struct omap3_otg_regs {
+	u32	revision;
+	u32	sysconfig;
+	u32	sysstatus;
+	u32	interfsel;
+	u32	simenable;
+	u32	forcestdby;
+};
+
+static struct omap3_otg_regs *otg;
+
+#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE		0x2000
+#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE		0x1000
+#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE		0x0010
+#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE		0x0008
+#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP		0x0004
+#define OMAP3_OTG_SYSCONFIG_SOFTRESET			0x0002
+#define OMAP3_OTG_SYSCONFIG_AUTOIDLE			0x0001
+
+#define OMAP3_OTG_SYSSTATUS_RESETDONE			0x0001
+
+/* OMAP4430 has an internal PHY, use it */
+#ifdef CONFIG_OMAP44XX
+#define OMAP3_OTG_INTERFSEL_OMAP			0x0000
+#else
+#define OMAP3_OTG_INTERFSEL_OMAP			0x0001
+#endif
+
+#define OMAP3_OTG_FORCESTDBY_STANDBY			0x0001
+
+
+#ifdef DEBUG_MUSB_OMAP3
+static void musb_db_otg_regs(void)
+{
+	u32 l;
+	l = readl(&otg->revision);
+	serial_printf("OTG_REVISION 0x%x\n", l);
+	l = readl(&otg->sysconfig);
+	serial_printf("OTG_SYSCONFIG 0x%x\n", l);
+	l = readl(&otg->sysstatus);
+	serial_printf("OTG_SYSSTATUS 0x%x\n", l);
+	l = readl(&otg->interfsel);
+	serial_printf("OTG_INTERFSEL 0x%x\n", l);
+	l = readl(&otg->forcestdby);
+	serial_printf("OTG_FORCESTDBY 0x%x\n", l);
+}
+#endif
+
+int musb_platform_init(void)
+{
+	int ret = -1;
+
+	if (platform_needs_initialization) {
+		u32 stdby;
+
+		/*
+		 * OMAP3EVM uses ISP1504 phy and so
+		 * twl4030 related init is not required.
+		 */
+#ifdef CONFIG_TWL4030_USB
+		if (twl4030_usb_ulpi_init()) {
+			serial_printf("ERROR: %s Could not initialize PHY\n",
+				__PRETTY_FUNCTION__);
+			goto end;
+		}
+#endif
+
+#ifdef CONFIG_TWL6030_POWER
+		twl6030_usb_device_settings();
+#endif
+
+		otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
+
+		/* Set OTG to always be on */
+		writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
+		       OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
+
+		/* Set the interface */
+		writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
+
+		/* Clear force standby */
+		stdby = readl(&otg->forcestdby);
+		stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
+		writel(stdby, &otg->forcestdby);
+
+#ifdef CONFIG_TARGET_OMAP3_EVM
+		musb_cfg.extvbus = omap3_evm_need_extvbus();
+#endif
+
+#ifdef CONFIG_OMAP44XX
+		u32 *usbotghs_control =
+			(u32 *)((*ctrl)->control_usbotghs_ctrl);
+		*usbotghs_control = 0x15;
+#endif
+		platform_needs_initialization = 0;
+	}
+
+	ret = platform_needs_initialization;
+
+#ifdef CONFIG_TWL4030_USB
+end:
+#endif
+	return ret;
+
+}
+
+void musb_platform_deinit(void)
+{
+	/* noop */
+}
diff --git a/roms/u-boot/drivers/usb/musb/omap3.h b/roms/u-boot/drivers/usb/musb/omap3.h
new file mode 100644
index 000000000..78fdb2959
--- /dev/null
+++ b/roms/u-boot/drivers/usb/musb/omap3.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is based on the file drivers/usb/musb/davinci.h
+ *
+ * This is the unique part of its copyright:
+ *
+ * --------------------------------------------------------------------
+ *
+ * Copyright (c) 2008 Texas Instruments
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ *
+ * --------------------------------------------------------------------
+ */
+#ifndef _MUSB_OMAP3_H_
+#define _MUSB_OMAP3_H_
+
+#include <asm/arch/cpu.h>
+#include "musb_core.h"
+
+/* Base address of MUSB registers */
+#define MENTOR_USB0_BASE MUSB_BASE
+
+/* Base address of OTG registers */
+#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
+
+/* Timeout for USB module */
+#define OMAP3_USB_TIMEOUT 0x3FFFFFF
+
+int musb_platform_init(void);
+
+#ifdef CONFIG_TARGET_OMAP3_EVM
+extern u8 omap3_evm_need_extvbus(void);
+#endif
+
+#endif /* _MUSB_OMAP3_H */
diff --git a/roms/u-boot/drivers/usb/phy/Kconfig b/roms/u-boot/drivers/usb/phy/Kconfig
new file mode 100644
index 000000000..8741553d0
--- /dev/null
+++ b/roms/u-boot/drivers/usb/phy/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2017
+# Adam Ford, Logic PD, aford173@gmail.com
+
+comment "USB Phy"
+
+config TWL4030_USB
+	bool "TWL4030 PHY"
+
+config OMAP_USB_PHY
+	bool "OMAP PHY"
+
+config ROCKCHIP_USB2_PHY
+	bool "Rockchip USB2 PHY"
diff --git a/roms/u-boot/drivers/usb/phy/Makefile b/roms/u-boot/drivers/usb/phy/Makefile
new file mode 100644
index 000000000..20f7edf48
--- /dev/null
+++ b/roms/u-boot/drivers/usb/phy/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2009 Wind River Systems, Inc.
+# Tom Rix <Tom.Rix@windriver.com>
+
+obj-$(CONFIG_TWL4030_USB) += twl4030.o
+obj-$(CONFIG_OMAP_USB_PHY) += omap_usb_phy.o
+obj-$(CONFIG_ROCKCHIP_USB2_PHY) += rockchip_usb2_phy.o
diff --git a/roms/u-boot/drivers/usb/phy/omap_usb_phy.c b/roms/u-boot/drivers/usb/phy/omap_usb_phy.c
new file mode 100644
index 000000000..be733f39b
--- /dev/null
+++ b/roms/u-boot/drivers/usb/phy/omap_usb_phy.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP USB PHY Support
+ *
+ * (C) Copyright 2013
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/omap_common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/sys_proto.h>
+
+#include <linux/compat.h>
+#include <linux/usb/dwc3.h>
+#include <linux/usb/xhci-omap.h>
+
+#include <usb/xhci.h>
+
+#ifdef CONFIG_OMAP_USB3PHY1_HOST
+struct usb3_dpll_params {
+	u16	m;
+	u8	n;
+	u8	freq:3;
+	u8	sd;
+	u32	mf;
+};
+
+struct usb3_dpll_map {
+	unsigned long rate;
+	struct usb3_dpll_params params;
+	struct usb3_dpll_map *dpll_map;
+};
+
+static struct usb3_dpll_map dpll_map_usb[] = {
+	{12000000, {1250, 5, 4, 20, 0} },	/* 12 MHz */
+	{16800000, {3125, 20, 4, 20, 0} },	/* 16.8 MHz */
+	{19200000, {1172, 8, 4, 20, 65537} },	/* 19.2 MHz */
+	{20000000, {1000, 7, 4, 10, 0} },	/* 20 MHz */
+	{26000000, {1250, 12, 4, 20, 0} },	/* 26 MHz */
+	{38400000, {3125, 47, 4, 20, 92843} },	/* 38.4 MHz */
+	{ },					/* Terminator */
+};
+
+static struct usb3_dpll_params *omap_usb3_get_dpll_params(void)
+{
+	unsigned long rate;
+	struct usb3_dpll_map *dpll_map = dpll_map_usb;
+
+	rate = get_sys_clk_freq();
+
+	for (; dpll_map->rate; dpll_map++) {
+		if (rate == dpll_map->rate)
+			return &dpll_map->params;
+	}
+
+	dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+
+	return NULL;
+}
+
+static void omap_usb_dpll_relock(struct omap_usb3_phy *phy_regs)
+{
+	u32 val;
+
+	writel(SET_PLL_GO, &phy_regs->pll_go);
+	do {
+		val = readl(&phy_regs->pll_status);
+			if (val & PLL_LOCK)
+				break;
+	} while (1);
+}
+
+static void omap_usb_dpll_lock(struct omap_usb3_phy *phy_regs)
+{
+	struct usb3_dpll_params	*dpll_params;
+	u32 val;
+
+	dpll_params = omap_usb3_get_dpll_params();
+	if (!dpll_params)
+		return;
+
+	val = readl(&phy_regs->pll_config_1);
+	val &= ~PLL_REGN_MASK;
+	val |= dpll_params->n << PLL_REGN_SHIFT;
+	writel(val, &phy_regs->pll_config_1);
+
+	val = readl(&phy_regs->pll_config_2);
+	val &= ~PLL_SELFREQDCO_MASK;
+	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
+	writel(val, &phy_regs->pll_config_2);
+
+	val = readl(&phy_regs->pll_config_1);
+	val &= ~PLL_REGM_MASK;
+	val |= dpll_params->m << PLL_REGM_SHIFT;
+	writel(val, &phy_regs->pll_config_1);
+
+	val = readl(&phy_regs->pll_config_4);
+	val &= ~PLL_REGM_F_MASK;
+	val |= dpll_params->mf << PLL_REGM_F_SHIFT;
+	writel(val, &phy_regs->pll_config_4);
+
+	val = readl(&phy_regs->pll_config_3);
+	val &= ~PLL_SD_MASK;
+	val |= dpll_params->sd << PLL_SD_SHIFT;
+	writel(val, &phy_regs->pll_config_3);
+
+	omap_usb_dpll_relock(phy_regs);
+}
+
+static void usb3_phy_partial_powerup(struct omap_usb3_phy *phy_regs)
+{
+	u32 rate = get_sys_clk_freq()/1000000;
+	u32 val;
+
+	val = readl((*ctrl)->control_phy_power_usb);
+	val &= ~(USB3_PWRCTL_CLK_CMD_MASK | USB3_PWRCTL_CLK_FREQ_MASK);
+	val |= (USB3_PHY_PARTIAL_RX_POWERON | USB3_PHY_TX_RX_POWERON);
+	val |= rate << USB3_PWRCTL_CLK_FREQ_SHIFT;
+
+	writel(val, (*ctrl)->control_phy_power_usb);
+}
+
+void usb_phy_power(int on)
+{
+	u32 val;
+
+	val = readl((*ctrl)->control_phy_power_usb);
+	if (on) {
+		val &= ~USB3_PWRCTL_CLK_CMD_MASK;
+		val |= USB3_PHY_TX_RX_POWERON;
+	} else {
+		val &= (~USB3_PWRCTL_CLK_CMD_MASK & ~USB3_PHY_TX_RX_POWERON);
+	}
+
+	writel(val, (*ctrl)->control_phy_power_usb);
+}
+
+void omap_usb3_phy_init(struct omap_usb3_phy *phy_regs)
+{
+	omap_usb_dpll_lock(phy_regs);
+	usb3_phy_partial_powerup(phy_regs);
+	/*
+	 * Give enough time for the PHY to partially power-up before
+	 * powering it up completely. delay value suggested by the HW
+	 * team.
+	 */
+	mdelay(100);
+}
+
+static void omap_enable_usb3_phy(struct omap_xhci *omap)
+{
+	u32	val;
+
+	val = (USBOTGSS_DMADISABLE |
+			USBOTGSS_STANDBYMODE_SMRT_WKUP |
+			USBOTGSS_IDLEMODE_NOIDLE);
+	writel(val, &omap->otg_wrapper->sysconfig);
+
+	/* Clear the utmi OTG status */
+	val = readl(&omap->otg_wrapper->utmi_otg_status);
+	writel(val, &omap->otg_wrapper->utmi_otg_status);
+
+	/* Enable interrupts */
+	writel(USBOTGSS_COREIRQ_EN, &omap->otg_wrapper->irqenable_set_0);
+	val = (USBOTGSS_IRQ_SET_1_IDPULLUP_FALL_EN |
+			USBOTGSS_IRQ_SET_1_DISCHRGVBUS_FALL_EN |
+			USBOTGSS_IRQ_SET_1_CHRGVBUS_FALL_EN	|
+			USBOTGSS_IRQ_SET_1_DRVVBUS_FALL_EN	|
+			USBOTGSS_IRQ_SET_1_IDPULLUP_RISE_EN	|
+			USBOTGSS_IRQ_SET_1_DISCHRGVBUS_RISE_EN	|
+			USBOTGSS_IRQ_SET_1_CHRGVBUS_RISE_EN |
+			USBOTGSS_IRQ_SET_1_DRVVBUS_RISE_EN |
+			USBOTGSS_IRQ_SET_1_OEVT_EN);
+	writel(val, &omap->otg_wrapper->irqenable_set_1);
+
+	/* Clear the IRQ status */
+	val = readl(&omap->otg_wrapper->irqstatus_1);
+	writel(val, &omap->otg_wrapper->irqstatus_1);
+	val = readl(&omap->otg_wrapper->irqstatus_0);
+	writel(val, &omap->otg_wrapper->irqstatus_0);
+};
+#endif /* CONFIG_OMAP_USB3PHY1_HOST */
+
+#ifdef CONFIG_OMAP_USB2PHY2_HOST
+static void omap_enable_usb2_phy2(struct omap_xhci *omap)
+{
+	u32 reg, val;
+
+	val = (~USB2PHY_AUTORESUME_EN & USB2PHY_DISCHGDET);
+	writel(val, (*ctrl)->control_srcomp_north_side);
+
+	setbits_le32((*prcm)->cm_coreaon_usb_phy2_core_clkctrl,
+			USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K);
+
+	setbits_le32((*prcm)->cm_l3init_hsusbhost_clkctrl,
+					(USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K |
+					 OTG_SS_CLKCTRL_MODULEMODE_HW));
+
+	/* This is an undocumented Reserved register */
+	reg = 0x4a0086c0;
+	val = readl(reg);
+	val |= 0x100;
+	setbits_le32(reg, val);
+}
+
+void usb_phy_power(int on)
+{
+	return;
+}
+#endif /* CONFIG_OMAP_USB2PHY2_HOST */
+
+#ifdef CONFIG_AM437X_USB2PHY2_HOST
+static void am437x_enable_usb2_phy2(struct omap_xhci *omap)
+{
+	const u32 usb_otg_ss_clk_val = (USBOTGSSX_CLKCTRL_MODULE_EN |
+				USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960);
+
+	writel(usb_otg_ss_clk_val, PRM_PER_USB_OTG_SS0_CLKCTRL);
+	writel(usb_otg_ss_clk_val, PRM_PER_USB_OTG_SS1_CLKCTRL);
+
+	writel(USBPHYOCPSCP_MODULE_EN, PRM_PER_USBPHYOCP2SCP0_CLKCTRL);
+	writel(USBPHYOCPSCP_MODULE_EN, PRM_PER_USBPHYOCP2SCP1_CLKCTRL);
+}
+
+void usb_phy_power(int on)
+{
+	u32 val;
+
+	/* USB1_CTRL */
+	val = readl(USB1_CTRL);
+	if (on) {
+		/*
+		 * these bits are re-used on AM437x to power up/down the USB
+		 * CM and OTG PHYs, if we don't toggle them, USB will not be
+		 * functional on newer silicon revisions
+		 */
+		val &= ~(USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN);
+	} else {
+		val |= USB1_CTRL_CM_PWRDN | USB1_CTRL_OTG_PWRDN;
+	}
+
+	writel(val, USB1_CTRL);
+}
+#endif /* CONFIG_AM437X_USB2PHY2_HOST */
+
+void omap_enable_phy(struct omap_xhci *omap)
+{
+#ifdef CONFIG_OMAP_USB2PHY2_HOST
+	omap_enable_usb2_phy2(omap);
+#endif
+
+#ifdef CONFIG_AM437X_USB2PHY2_HOST
+	am437x_enable_usb2_phy2(omap);
+#endif
+
+#ifdef CONFIG_OMAP_USB3PHY1_HOST
+	omap_enable_usb3_phy(omap);
+	omap_usb3_phy_init(omap->usb3_phy);
+#endif
+}
diff --git a/roms/u-boot/drivers/usb/phy/rockchip_usb2_phy.c b/roms/u-boot/drivers/usb/phy/rockchip_usb2_phy.c
new file mode 100644
index 000000000..93caa821a
--- /dev/null
+++ b/roms/u-boot/drivers/usb/phy/rockchip_usb2_phy.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <hang.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#include "../gadget/dwc2_udc_otg_priv.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BIT_WRITEABLE_SHIFT	16
+
+struct usb2phy_reg {
+	unsigned int offset;
+	unsigned int bitend;
+	unsigned int bitstart;
+	unsigned int disable;
+	unsigned int enable;
+};
+
+/**
+ * struct rockchip_usb2_phy_cfg: usb-phy port configuration
+ * @port_reset: usb otg per-port reset register
+ * @soft_con: software control usb otg register
+ * @suspend: phy suspend register
+ */
+struct rockchip_usb2_phy_cfg {
+	struct usb2phy_reg port_reset;
+	struct usb2phy_reg soft_con;
+	struct usb2phy_reg suspend;
+};
+
+struct rockchip_usb2_phy_dt_id {
+	char		compatible[128];
+	const void	*data;
+};
+
+static const struct rockchip_usb2_phy_cfg rk3288_pdata = {
+	.port_reset     = {0x00, 12, 12, 0, 1},
+	.soft_con       = {0x08, 2, 2, 0, 1},
+	.suspend	= {0x0c, 5, 0, 0x01, 0x2A},
+};
+
+static struct rockchip_usb2_phy_dt_id rockchip_usb2_phy_dt_ids[] = {
+	{ .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
+	{}
+};
+
+static void property_enable(struct dwc2_plat_otg_data *pdata,
+				  const struct usb2phy_reg *reg, bool en)
+{
+	unsigned int val, mask, tmp;
+
+	tmp = en ? reg->enable : reg->disable;
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+	writel(val, pdata->regs_phy + reg->offset);
+}
+
+
+void otg_phy_init(struct dwc2_udc *dev)
+{
+	struct dwc2_plat_otg_data *pdata = dev->pdata;
+	struct rockchip_usb2_phy_cfg *phy_cfg = NULL;
+	struct rockchip_usb2_phy_dt_id *of_id;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rockchip_usb2_phy_dt_ids); i++) {
+		of_id = &rockchip_usb2_phy_dt_ids[i];
+		if (ofnode_device_is_compatible(pdata->phy_of_node,
+						of_id->compatible)){
+			phy_cfg = (struct rockchip_usb2_phy_cfg *)of_id->data;
+			break;
+		}
+	}
+	if (!phy_cfg) {
+		debug("Can't find device platform data\n");
+
+		hang();
+		return;
+	}
+	pdata->priv = phy_cfg;
+	/* disable software control */
+	property_enable(pdata, &phy_cfg->soft_con, false);
+
+	/* reset otg port */
+	property_enable(pdata, &phy_cfg->port_reset, true);
+	mdelay(1);
+	property_enable(pdata, &phy_cfg->port_reset, false);
+	udelay(1);
+}
+
+void otg_phy_off(struct dwc2_udc *dev)
+{
+	struct dwc2_plat_otg_data *pdata = dev->pdata;
+	struct rockchip_usb2_phy_cfg *phy_cfg = pdata->priv;
+
+	/* enable software control */
+	property_enable(pdata, &phy_cfg->soft_con, true);
+	/* enter suspend */
+	property_enable(pdata, &phy_cfg->suspend, true);
+}
diff --git a/roms/u-boot/drivers/usb/phy/twl4030.c b/roms/u-boot/drivers/usb/phy/twl4030.c
new file mode 100644
index 000000000..676868bea
--- /dev/null
+++ b/roms/u-boot/drivers/usb/phy/twl4030.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/gadget/twl4030_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ *  * (C) Copyright 2009 Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * Based on: twl4030_usb.c in linux 2.6 (drivers/i2c/chips/twl4030_usb.c)
+ * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * Author: Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * ------------------------------------------------------------------------
+ */
+
+#include <twl4030.h>
+#include <linux/delay.h>
+
+/* Defines for bits in registers */
+#define OPMODE_MASK		(3 << 3)
+#define XCVRSELECT_MASK		(3 << 0)
+#define CARKITMODE		(1 << 2)
+#define OTG_ENAB		(1 << 5)
+#define PHYPWD			(1 << 0)
+#define CLOCKGATING_EN		(1 << 2)
+#define CLK32K_EN		(1 << 1)
+#define REQ_PHY_DPLL_CLK	(1 << 0)
+#define PHY_DPLL_CLK		(1 << 0)
+
+static int twl4030_usb_write(u8 address, u8 data)
+{
+	int ret;
+
+	ret = twl4030_i2c_write_u8(TWL4030_CHIP_USB, address, data);
+	if (ret != 0)
+		printf("TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+
+	return ret;
+}
+
+static int twl4030_usb_read(u8 address)
+{
+	u8 data;
+	int ret;
+
+	ret = twl4030_i2c_read_u8(TWL4030_CHIP_USB, address, &data);
+	if (ret == 0)
+		ret = data;
+	else
+		printf("TWL4030:USB:Read[0x%x] Error %d\n", address, ret);
+
+	return ret;
+}
+
+static void twl4030_usb_ldo_init(void)
+{
+	/* Enable writing to power configuration registers */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+			     TWL4030_PM_MASTER_PROTECT_KEY, 0xC0);
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+			     TWL4030_PM_MASTER_PROTECT_KEY, 0x0C);
+
+	/* put VUSB3V1 LDO in active state */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB_DEDICATED2, 0x00);
+
+	/* input to VUSB3V1 LDO is from VBAT, not VBUS */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB_DEDICATED1, 0x14);
+
+	/* turn on 3.1V regulator */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB3V1_DEV_GRP, 0x20);
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB3V1_TYPE, 0x00);
+
+	/* turn on 1.5V regulator */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB1V5_DEV_GRP, 0x20);
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB1V5_TYPE, 0x00);
+
+	/* turn on 1.8V regulator */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB1V8_DEV_GRP, 0x20);
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER,
+			     TWL4030_PM_RECEIVER_VUSB1V8_TYPE, 0x00);
+
+	/* disable access to power configuration registers */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+			     TWL4030_PM_MASTER_PROTECT_KEY, 0x00);
+}
+
+static void twl4030_phy_power(void)
+{
+	u8 pwr, clk;
+
+	/* Power the PHY */
+	pwr = twl4030_usb_read(TWL4030_USB_PHY_PWR_CTRL);
+	pwr &= ~PHYPWD;
+	twl4030_usb_write(TWL4030_USB_PHY_PWR_CTRL, pwr);
+	/* Enable clocks */
+	clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+	clk |= CLOCKGATING_EN | CLK32K_EN;
+	twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+}
+
+/*
+ * Initiaze the ULPI interface
+ * ULPI : Universal Transceiver Macrocell Low Pin Interface
+ * An interface between the USB link controller like musb and the
+ * the PHY or transceiver that drives the actual bus.
+ */
+int twl4030_usb_ulpi_init(void)
+{
+	long timeout = 1000 * 1000; /* 1 sec */;
+	u8 clk, sts, pwr;
+
+	/* twl4030 ldo init */
+	twl4030_usb_ldo_init();
+
+	/* Enable the twl4030 phy */
+	twl4030_phy_power();
+
+	/* Enable DPLL to access PHY registers over I2C */
+	clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+	clk |= REQ_PHY_DPLL_CLK;
+	twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+
+	/* Check if the PHY DPLL is locked */
+	sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+	while (!(sts & PHY_DPLL_CLK) && 0 < timeout) {
+		udelay(10);
+		sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+		timeout -= 10;
+	}
+
+	/* Final check */
+	sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+	if (!(sts & PHY_DPLL_CLK)) {
+		printf("Error:TWL4030:USB Timeout setting PHY DPLL clock\n");
+		return -1;
+	}
+
+	/*
+	 * There are two circuit blocks attached to the PHY,
+	 * Carkit and USB OTG.  Disable Carkit and enable USB OTG
+	 */
+	twl4030_usb_write(TWL4030_USB_IFC_CTRL_CLR, CARKITMODE);
+	pwr = twl4030_usb_read(TWL4030_USB_POWER_CTRL);
+	pwr |= OTG_ENAB;
+	twl4030_usb_write(TWL4030_USB_POWER_CTRL_SET, pwr);
+
+	/* Clear the opmode bits to ensure normal encode */
+	twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, OPMODE_MASK);
+
+	/* Clear the xcvrselect bits to enable the high speed transeiver */
+	twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, XCVRSELECT_MASK);
+
+	/* Let ULPI control the DPLL clock */
+	clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+	clk &= ~REQ_PHY_DPLL_CLK;
+	twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+
+	return 0;
+}
diff --git a/roms/u-boot/drivers/usb/ulpi/Kconfig b/roms/u-boot/drivers/usb/ulpi/Kconfig
new file mode 100644
index 000000000..001564d40
--- /dev/null
+++ b/roms/u-boot/drivers/usb/ulpi/Kconfig
@@ -0,0 +1,32 @@
+comment "ULPI drivers"
+
+choice
+	prompt "ULPI Viewport type"
+	optional
+	help
+	  Select ULPI viewport (SoC-side interface to ULPI) implementation
+	  appropriate for the device if you want to communicate with
+	  UTMI (USB PHY) via ULPI interface.
+
+config USB_ULPI_VIEWPORT
+	bool "Generic ULPI Viewport"
+	help
+	  Support generic ULPI Viewport implementation that is used on
+	  some Tegra and Snapdragon devices.
+
+config USB_ULPI_VIEWPORT_OMAP
+	bool "OMAP ULPI Viewport"
+	help
+	  Support ULPI Viewport implementation that is used on OMAP devices.
+
+endchoice
+
+config USB_ULPI
+	bool "ULPI support"
+	depends on (USB_ULPI_VIEWPORT || USB_ULPI_VIEWPORT_OMAP)
+	help
+	  Select to commnicate with USB PHY via ULPI interface.
+	  ULPI is wrapper on UTMI+ core that is used as
+	  PHY Transreceiver for USB controllers.
+
+	  This driver uses ULPI viewports that are specific for each SoC.
diff --git a/roms/u-boot/drivers/usb/ulpi/Makefile b/roms/u-boot/drivers/usb/ulpi/Makefile
new file mode 100644
index 000000000..f05b77435
--- /dev/null
+++ b/roms/u-boot/drivers/usb/ulpi/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+
+obj-$(CONFIG_USB_ULPI)		+= ulpi.o
+obj-$(CONFIG_USB_ULPI_VIEWPORT)	+= ulpi-viewport.o
+obj-$(CONFIG_USB_ULPI_VIEWPORT_OMAP)	+= omap-ulpi-viewport.o
diff --git a/roms/u-boot/drivers/usb/ulpi/omap-ulpi-viewport.c b/roms/u-boot/drivers/usb/ulpi/omap-ulpi-viewport.c
new file mode 100644
index 000000000..8b930e3fa
--- /dev/null
+++ b/roms/u-boot/drivers/usb/ulpi/omap-ulpi-viewport.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OMAP ulpi viewport support
+ * Based on drivers/usb/ulpi/ulpi-viewport.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Govindraj R <govindraj.raja@ti.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <usb/ulpi.h>
+
+#define OMAP_ULPI_WR_OPSEL	(2 << 22)
+#define OMAP_ULPI_RD_OPSEL	(3 << 22)
+#define OMAP_ULPI_START		(1 << 31)
+
+/*
+ * Wait for having ulpi in done state
+ */
+static int ulpi_wait(struct ulpi_viewport *ulpi_vp, u32 mask)
+{
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	while (--timeout) {
+		if (!(readl(ulpi_vp->viewport_addr) & mask))
+			return 0;
+
+		udelay(1);
+	}
+
+	return ULPI_ERROR;
+}
+
+/*
+ * Issue a ULPI read/write request
+ */
+static int ulpi_request(struct ulpi_viewport *ulpi_vp, u32 value)
+{
+	int err;
+
+	writel(value, ulpi_vp->viewport_addr);
+
+	err = ulpi_wait(ulpi_vp, OMAP_ULPI_START);
+	if (err)
+		debug("ULPI request timed out\n");
+
+	return err;
+}
+
+int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value)
+{
+	u32 val = OMAP_ULPI_START | (((ulpi_vp->port_num + 1) & 0xf) << 24) |
+			OMAP_ULPI_WR_OPSEL | ((u32)reg << 16) | (value & 0xff);
+
+	return ulpi_request(ulpi_vp, val);
+}
+
+u32 ulpi_read(struct ulpi_viewport *ulpi_vp, u8 *reg)
+{
+	int err;
+	u32 val = OMAP_ULPI_START | (((ulpi_vp->port_num + 1) & 0xf) << 24) |
+			 OMAP_ULPI_RD_OPSEL | ((u32)reg << 16);
+
+	err = ulpi_request(ulpi_vp, val);
+	if (err)
+		return err;
+
+	return readl(ulpi_vp->viewport_addr) & 0xff;
+}
diff --git a/roms/u-boot/drivers/usb/ulpi/ulpi-viewport.c b/roms/u-boot/drivers/usb/ulpi/ulpi-viewport.c
new file mode 100644
index 000000000..3bb152be8
--- /dev/null
+++ b/roms/u-boot/drivers/usb/ulpi/ulpi-viewport.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Based on:
+ * linux/drivers/usb/otg/ulpi_viewport.c
+ *
+ * Original Copyright follow:
+ * Copyright (C) 2011 Google, Inc.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <usb/ulpi.h>
+
+/* ULPI viewport control bits */
+#define ULPI_SS		(1 << 27)
+#define ULPI_RWCTRL	(1 << 29)
+#define ULPI_RWRUN	(1 << 30)
+#define ULPI_WU		(1 << 31)
+
+/*
+ * Wait for the ULPI request to complete
+ *
+ * @ulpi_viewport	- the address of the viewport
+ * @mask		- expected value to wait for
+ *
+ * returns 0 on mask match, ULPI_ERROR on time out.
+ */
+static int ulpi_wait(struct ulpi_viewport *ulpi_vp, u32 mask)
+{
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	/* Wait for the bits in mask to become zero. */
+	while (--timeout) {
+		if ((readl(ulpi_vp->viewport_addr) & mask) == 0)
+			return 0;
+
+		udelay(1);
+	}
+
+	return ULPI_ERROR;
+}
+
+/*
+ * Wake the ULPI PHY up for communication
+ *
+ * returns 0 on success.
+ */
+static int ulpi_wakeup(struct ulpi_viewport *ulpi_vp)
+{
+	int err;
+
+	if (readl(ulpi_vp->viewport_addr) & ULPI_SS)
+		return 0; /* already awake */
+
+	writel(ULPI_WU, ulpi_vp->viewport_addr);
+
+	err = ulpi_wait(ulpi_vp, ULPI_WU);
+	if (err)
+		printf("ULPI wakeup timed out\n");
+
+	return err;
+}
+
+/*
+ * Issue a ULPI read/write request
+ *
+ * @value - the ULPI request
+ */
+static int ulpi_request(struct ulpi_viewport *ulpi_vp, u32 value)
+{
+	int err;
+
+	err = ulpi_wakeup(ulpi_vp);
+	if (err)
+		return err;
+
+	writel(value, ulpi_vp->viewport_addr);
+
+	err = ulpi_wait(ulpi_vp, ULPI_RWRUN);
+	if (err)
+		printf("ULPI request timed out\n");
+
+	return err;
+}
+
+int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value)
+{
+	u32 addr = (uintptr_t)reg & 0xFF;
+	u32 val = ULPI_RWRUN | ULPI_RWCTRL | addr << 16 | (value & 0xff);
+
+	val |= (ulpi_vp->port_num & 0x7) << 24;
+	return ulpi_request(ulpi_vp, val);
+}
+
+u32 ulpi_read(struct ulpi_viewport *ulpi_vp, u8 *reg)
+{
+	int err;
+	u32 val = ULPI_RWRUN | ((uintptr_t)reg & 0xFF) << 16;
+
+	val |= (ulpi_vp->port_num & 0x7) << 24;
+	err = ulpi_request(ulpi_vp, val);
+	if (err)
+		return err;
+
+	return (readl(ulpi_vp->viewport_addr) >> 8) & 0xff;
+}
diff --git a/roms/u-boot/drivers/usb/ulpi/ulpi.c b/roms/u-boot/drivers/usb/ulpi/ulpi.c
new file mode 100644
index 000000000..dd0da0e84
--- /dev/null
+++ b/roms/u-boot/drivers/usb/ulpi/ulpi.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Based on:
+ * linux/drivers/usb/otg/ulpi.c
+ * Generic ULPI USB transceiver support
+ *
+ * Original Copyright follow:
+ * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on sources from
+ *
+ *   Sascha Hauer <s.hauer@pengutronix.de>
+ *   Freescale Semiconductors
+ */
+
+#include <common.h>
+#include <exports.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <usb/ulpi.h>
+
+#define ULPI_ID_REGS_COUNT	4
+#define ULPI_TEST_VALUE		0x55	/* 0x55 == 0b01010101 */
+
+static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
+{
+	u32 val, tval = ULPI_TEST_VALUE;
+	int err, i;
+
+	/* Use the 'special' test value to check all bits */
+	for (i = 0; i < 2; i++, tval <<= 1) {
+		err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
+		if (err)
+			return err;
+
+		val = ulpi_read(ulpi_vp, &ulpi->scratch);
+		if (val != tval) {
+			printf("ULPI integrity check failed\n");
+			return val;
+		}
+	}
+
+	return 0;
+}
+
+int ulpi_init(struct ulpi_viewport *ulpi_vp)
+{
+	u32 val, id = 0;
+	u8 *reg = &ulpi->product_id_high;
+	int i;
+
+	/* Assemble ID from four ULPI ID registers (8 bits each). */
+	for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
+		val = ulpi_read(ulpi_vp, reg - i);
+		if (val == ULPI_ERROR)
+			return val;
+
+		id = (id << 8) | val;
+	}
+
+	/* Split ID into vendor and product ID. */
+	debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
+
+	return ulpi_integrity_check(ulpi_vp);
+}
+
+int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
+{
+	u32 tspeed = ULPI_FC_FULL_SPEED;
+	u32 val;
+
+	switch (speed) {
+	case ULPI_FC_HIGH_SPEED:
+	case ULPI_FC_FULL_SPEED:
+	case ULPI_FC_LOW_SPEED:
+	case ULPI_FC_FS4LS:
+		tspeed = speed;
+		break;
+	default:
+		printf("ULPI: %s: wrong transceiver speed specified: %u, "
+			"falling back to full speed\n", __func__, speed);
+	}
+
+	val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	/* clear the previous speed setting */
+	val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
+
+	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
+}
+
+int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
+{
+	u32 flags = ULPI_OTG_DRVVBUS;
+	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+
+	if (ext_power)
+		flags |= ULPI_OTG_DRVVBUS_EXT;
+
+	return ulpi_write(ulpi_vp, reg, flags);
+}
+
+int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
+			int passthu, int complement)
+{
+	u32 flags, val;
+	u8 *reg;
+
+	reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+	val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
+	if (val)
+		return val;
+
+	flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
+	flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
+
+	val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
+	val |= flags;
+	val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
+	if (val)
+		return val;
+
+	return 0;
+}
+
+int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
+{
+	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
+	u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+
+	return ulpi_write(ulpi_vp, reg, val);
+}
+
+int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
+{
+	u32 topmode = ULPI_FC_OPMODE_NORMAL;
+	u32 val;
+
+	switch (opmode) {
+	case ULPI_FC_OPMODE_NORMAL:
+	case ULPI_FC_OPMODE_NONDRIVING:
+	case ULPI_FC_OPMODE_DISABLE_NRZI:
+	case ULPI_FC_OPMODE_NOSYNC_NOEOP:
+		topmode = opmode;
+		break;
+	default:
+		printf("ULPI: %s: wrong OpMode specified: %u, "
+			"falling back to OpMode Normal\n", __func__, opmode);
+	}
+
+	val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	/* clear the previous opmode setting */
+	val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
+
+	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
+}
+
+int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
+{
+	switch (smode) {
+	case ULPI_IFACE_6_PIN_SERIAL_MODE:
+	case ULPI_IFACE_3_PIN_SERIAL_MODE:
+		break;
+	default:
+		printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
+			__func__, smode);
+		return ULPI_ERROR;
+	}
+
+	return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
+}
+
+int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
+{
+	int err;
+
+	err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
+			ULPI_FC_SUSPENDM);
+	if (err)
+		printf("ULPI: %s: failed writing the suspend bit\n", __func__);
+
+	return err;
+}
+
+/*
+ * Wait for ULPI PHY reset to complete.
+ * Actual wait for reset must be done in a view port specific way,
+ * because it involves checking the DIR line.
+ */
+static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
+{
+	u32 val;
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	/* Wait for the RESET bit to become zero */
+	while (--timeout) {
+		/*
+		 * This function is generic and suppose to work
+		 * with any viewport, so we cheat here and don't check
+		 * for the error of ulpi_read(), if there is one, then
+		 * there will be a timeout.
+		 */
+		val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
+		if (!(val & ULPI_FC_RESET))
+			return 0;
+
+		udelay(1);
+	}
+
+	printf("ULPI: %s: reset timed out\n", __func__);
+
+	return ULPI_ERROR;
+}
+int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
+	__attribute__((weak, alias("__ulpi_reset_wait")));
+
+int ulpi_reset(struct ulpi_viewport *ulpi_vp)
+{
+	int err;
+
+	err = ulpi_write(ulpi_vp,
+			&ulpi->function_ctrl_set, ULPI_FC_RESET);
+	if (err) {
+		printf("ULPI: %s: failed writing reset bit\n", __func__);
+		return err;
+	}
+
+	return ulpi_reset_wait(ulpi_vp);
+}
-- 
cgit