ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/drivers/usb/dwc3/Kconfig b/marvell/linux/drivers/usb/dwc3/Kconfig
new file mode 100644
index 0000000..52b8dd3
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/Kconfig
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config USB_DWC3
+	tristate "DesignWare USB3 DRD Core Support"
+	depends on (USB || USB_GADGET) && HAS_DMA
+	select USB_XHCI_PLATFORM if USB_XHCI_HCD
+	help
+	  Say Y or M here if your system has a Dual Role SuperSpeed
+	  USB controller based on the DesignWare USB3 IP Core.
+
+	  If you choose to build this driver is a dynamically linked
+	  module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_ULPI
+	bool "Register ULPI PHY Interface"
+	depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_DWC3
+	help
+	  Select this if you have ULPI type PHY attached to your DWC3
+	  controller.
+
+choice
+	bool "DWC3 Mode Selection"
+	default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
+	default USB_DWC3_HOST if (USB && !USB_GADGET)
+	default USB_DWC3_GADGET if (!USB && USB_GADGET)
+
+config USB_DWC3_HOST
+	bool "Host only mode"
+	depends on USB=y || USB=USB_DWC3
+	help
+	  Select this when you want to use DWC3 in host mode only,
+	  thereby the gadget feature will be regressed.
+
+config USB_DWC3_GADGET
+	bool "Gadget only mode"
+	depends on USB_GADGET=y || USB_GADGET=USB_DWC3
+	help
+	  Select this when you want to use DWC3 in gadget mode only,
+	  thereby the host feature will be regressed.
+
+config USB_DWC3_DUAL_ROLE
+	bool "Dual Role mode"
+	depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
+	help
+	  This is the default mode of working of DWC3 controller where
+	  both host and gadget features are enabled.
+
+endchoice
+
+config DWC3_HWSULOG
+	bool "DWC3 hardware sulog feature"
+	depends on USB_DWC3
+	help
+	  Select this when you want to use DWC3 to transfer hwsulog for
+	  ASR modem.
+
+comment "Platform Glue Driver Support"
+
+config USB_DWC3_OMAP
+	tristate "Texas Instruments OMAP5 and similar Platforms"
+	depends on ARCH_OMAP2PLUS || COMPILE_TEST
+	depends on EXTCON || !EXTCON
+	depends on OF
+	default USB_DWC3
+	help
+	  Some platforms from Texas Instruments like OMAP5, DRA7xxx and
+	  AM437x use this IP for USB2/3 functionality.
+
+	  Say 'Y' or 'M' here if you have one such device
+
+config USB_DWC3_EXYNOS
+	tristate "Samsung Exynos Platform"
+	depends on (ARCH_EXYNOS || COMPILE_TEST) && OF
+	default USB_DWC3
+	help
+	  Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
+	  say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_PCI
+	tristate "PCIe-based Platforms"
+	depends on USB_PCI && ACPI
+	default USB_DWC3
+	help
+	  If you're using the DesignWare Core IP with a PCIe (but not HAPS
+	  platform), please say 'Y' or 'M' here.
+
+config USB_DWC3_HAPS
+	tristate "Synopsys PCIe-based HAPS Platforms"
+	depends on USB_PCI
+	default USB_DWC3
+	help
+	  If you're using the DesignWare Core IP with a Synopsys PCIe HAPS
+	  platform, please say 'Y' or 'M' here.
+
+config USB_DWC3_KEYSTONE
+	tristate "Texas Instruments Keystone2/AM654 Platforms"
+	depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
+	default USB_DWC3
+	help
+	  Support of USB2/3 functionality in TI Keystone2 and AM654 platforms.
+	  Say 'Y' or 'M' here if you have one such device
+
+config USB_DWC3_MESON_G12A
+       tristate "Amlogic Meson G12A Platforms"
+       depends on OF && COMMON_CLK
+       depends on ARCH_MESON || COMPILE_TEST
+       default USB_DWC3
+       select USB_ROLE_SWITCH
+	select REGMAP_MMIO
+       help
+         Support USB2/3 functionality in Amlogic G12A platforms.
+	 Say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_OF_SIMPLE
+       tristate "Generic OF Simple Glue Layer"
+       depends on OF && COMMON_CLK
+       default USB_DWC3
+       help
+         Support USB2/3 functionality in simple SoC integrations.
+	 Currently supports Xilinx and Qualcomm DWC USB3 IP.
+	 Say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_ST
+	tristate "STMicroelectronics Platforms"
+	depends on (ARCH_STI || COMPILE_TEST) && OF
+	default USB_DWC3
+	help
+	  STMicroelectronics SoCs with one DesignWare Core USB3 IP
+	  inside (i.e. STiH407).
+	  Say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_QCOM
+	tristate "Qualcomm Platform"
+	depends on ARCH_QCOM || COMPILE_TEST
+	depends on EXTCON || !EXTCON
+	depends on (OF || ACPI)
+	default USB_DWC3
+	help
+	  Some Qualcomm SoCs use DesignWare Core IP for USB2/3
+	  functionality.
+	  This driver also handles Qscratch wrapper which is needed
+	  for peripheral mode support.
+	  Say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_ASR
+	tristate "ASR DWC3 Device Platforms"
+	depends on OF && USB_DWC3_GADGET
+	default USB_DWC3
+	help
+	  Support of USB2/3 functionality in ASR platforms.
+	  Say 'Y' or 'M' here if you have one such device
+
+config USB_DWC3_ASR_OTG
+        tristate "ASR DWC3 OTG Platforms"
+        depends on OF && USB_DWC3_DUAL_ROLE
+        help
+          Support of USB2/3 OTG functionality in ASR platforms.
+          Say 'Y' or 'M' here if you have one such device
+endif
diff --git a/marvell/linux/drivers/usb/dwc3/Makefile b/marvell/linux/drivers/usb/dwc3/Makefile
new file mode 100644
index 0000000..4a82ea8
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/Makefile
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0
+# define_trace.h needs to know how to find our header
+CFLAGS_trace.o				:= -I$(src)
+
+obj-$(CONFIG_USB_DWC3)			+= dwc3.o
+
+dwc3-y					:= core.o
+
+ifneq ($(CONFIG_TRACING),)
+	dwc3-y				+= trace.o
+endif
+
+ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
+	dwc3-y				+= host.o
+endif
+
+ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
+	dwc3-y				+= gadget.o ep0.o
+endif
+
+#ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
+#	dwc3-y				+= drd.o
+#endif
+
+ifneq ($(CONFIG_USB_DWC3_ULPI),)
+	dwc3-y				+= ulpi.o
+endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+	dwc3-y				+= debugfs.o
+endif
+
+##
+# Platform-specific glue layers go here
+#
+# NOTICE: Make sure your glue layer doesn't depend on anything
+# which is arch-specific and that it compiles on all situations.
+#
+# We want to keep this requirement in order to be able to compile
+# the entire driver (with all its glue layers) on several architectures
+# and make sure it compiles fine. This will also help with allmodconfig
+# and allyesconfig builds.
+##
+
+obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_EXYNOS)		+= dwc3-exynos.o
+obj-$(CONFIG_USB_DWC3_PCI)		+= dwc3-pci.o
+obj-$(CONFIG_USB_DWC3_HAPS)		+= dwc3-haps.o
+obj-$(CONFIG_USB_DWC3_KEYSTONE)		+= dwc3-keystone.o
+obj-$(CONFIG_USB_DWC3_MESON_G12A)	+= dwc3-meson-g12a.o
+obj-$(CONFIG_USB_DWC3_OF_SIMPLE)	+= dwc3-of-simple.o
+obj-$(CONFIG_USB_DWC3_ST)		+= dwc3-st.o
+obj-$(CONFIG_USB_DWC3_QCOM)		+= dwc3-qcom.o
+obj-$(CONFIG_USB_DWC3_ASR)		+= dwc3-asr.o
+obj-$(CONFIG_USB_DWC3_ASR_OTG)		+= dwc3-asr-otg.o
diff --git a/marvell/linux/drivers/usb/dwc3/core.c b/marvell/linux/drivers/usb/dwc3/core.c
new file mode 100644
index 0000000..23918bf
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/core.c
@@ -0,0 +1,2344 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/acpi.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/reset.h>
+#include <linux/pm_qos.h>
+#include <linux/cputype.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include <soc/asr/regs-addr.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "debug.h"
+
+#define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
+
+static struct dwc3 *g_dwc;
+
+#define DWC3_NR_SAVE_REGS	(32)
+#define DWC3_REG_LINE_STATUS	(0x1004c)
+
+struct dwc3_save_regs {
+	u32 reg;
+	u32 val;
+};
+
+static bool burst1_is_set;
+static struct dwc3_save_regs dwc3_global_regs_array[DWC3_NR_SAVE_REGS];
+static int reg_index;
+
+static void dwc3_save_controller_regs(u32 reg, u32 val)
+{
+	dwc3_global_regs_array[reg_index].reg = reg;
+	dwc3_global_regs_array[reg_index].val = val;
+	reg_index++;
+	if (reg_index >= DWC3_NR_SAVE_REGS) {
+		pr_info("dwc3 reg array out of range\n");
+		BUG();
+	}
+}
+
+#ifdef CONFIG_USB_DWC3_ASR_OTG
+static void dwc3_restore_global_regs(struct dwc3 *dwc)
+{
+	int i;
+	u32 val, mode;
+
+	dev_info(dwc->dev, "dwc3: reconfig %d global regs\n", reg_index);
+	for (i = 0; i < reg_index; i++) {
+		if (DWC3_GCTL == dwc3_global_regs_array[i].reg) {
+			if (dwc->otg_state == OTG_STATE_A_HOST)
+				mode = DWC3_GCTL_PRTCAP_HOST;
+			else
+				mode = DWC3_GCTL_PRTCAP_DEVICE;
+			pr_info("dwc3 usb mode: %d\n", mode);
+			val = dwc3_global_regs_array[i].val;
+			val &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+			val |= DWC3_GCTL_PRTCAPDIR(mode);
+			dwc3_writel(dwc->regs, DWC3_GCTL, val);	
+		} else {
+			dwc3_writel(dwc->regs, dwc3_global_regs_array[i].reg,
+					dwc3_global_regs_array[i].val);
+		}
+	}
+}
+#else
+static void dwc3_restore_global_regs(struct dwc3 *dwc)
+{
+	int i;
+
+	dev_info(dwc->dev, "dwc3: reconfig %d global regs\n", reg_index);
+	for (i = 0; i < reg_index; i++) {
+		dwc3_writel(dwc->regs, dwc3_global_regs_array[i].reg,
+					dwc3_global_regs_array[i].val);
+	}
+}
+#endif
+
+void dwc3_force_usb2_mode(void)
+{
+	u32 reg;
+
+	if (g_dwc) {
+		dev_warn(g_dwc->dev, "warning: dwc3 force usb2 mode\n");
+		reg = dwc3_readl(g_dwc->regs, DWC3_GUCTL1);
+		/* force_20_clk_for_30_clk */
+		reg |= (1 << 26);
+		dwc3_writel(g_dwc->regs, DWC3_GUCTL1, reg);
+	}
+}
+
+void dwc3_set_burst1(bool set)
+{
+	u32 reg;
+
+	if ((!(cpu_is_asr1903() || cpu_is_asr1901())) || burst1_is_set)
+		return;
+
+	reg = dwc3_readl(g_dwc->regs, DWC3_GSBUSCFG0);
+	reg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
+	dwc3_writel(g_dwc->regs, DWC3_GSBUSCFG0, reg);
+	burst1_is_set = true;
+	pr_info("set burst reg: 0x%x\n", reg);
+}
+
+#ifdef CONFIG_CPU_ASR1901
+u32 dwc3_get_line_status(void)
+{
+	u32 regval;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+
+	regval = readl(apmu_base + 0x118);
+
+	return ((regval & 0x3) << 8);
+}
+#elif defined(CONFIG_CPU_ASR1903)
+u32 dwc3_get_line_status(void)
+{
+	u32 regval;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+
+	regval = readl(apmu_base + 0x7c);
+
+	return (((regval >> 26) & 0x3) << 8);
+}
+#else
+u32 dwc3_get_line_status(void)
+{
+	u32 reg;
+
+	if (!g_dwc) {
+		return 0;
+		dev_warn(g_dwc->dev, "warning: g_dwc is NULL\n");
+	}
+
+	reg = dwc3_readl(g_dwc->regs, DWC3_REG_LINE_STATUS);
+
+	return reg;
+}
+#endif
+u32 dwc3_usb_is_running(void)
+{
+	u32 reg;
+
+	if (!g_dwc) {
+		dev_warn(g_dwc->dev, "warning: g_dwc is NULL\n");
+		return 0;
+	}
+
+	reg = dwc3_readl(g_dwc->regs, DWC3_DCTL);
+
+	return (reg & DWC3_DCTL_RUN_STOP);
+}
+
+u32 dwc3_is_superspeed_plus(void)
+{
+	if (!g_dwc) {
+		dev_warn(g_dwc->dev, "warning: g_dwc is NULL\n");
+		return 0;
+	}
+
+	if (g_dwc->gadget.speed == USB_SPEED_SUPER || g_dwc->gadget.speed == USB_SPEED_SUPER_PLUS)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * dwc3_get_dr_mode - Validates and sets dr_mode
+ * @dwc: pointer to our context structure
+ */
+static int dwc3_get_dr_mode(struct dwc3 *dwc)
+{
+	enum usb_dr_mode mode;
+	struct device *dev = dwc->dev;
+	unsigned int hw_mode;
+
+	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+		dwc->dr_mode = USB_DR_MODE_OTG;
+
+	mode = dwc->dr_mode;
+	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+
+	switch (hw_mode) {
+	case DWC3_GHWPARAMS0_MODE_GADGET:
+		if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
+			dev_err(dev,
+				"Controller does not support host mode.\n");
+			return -EINVAL;
+		}
+		mode = USB_DR_MODE_PERIPHERAL;
+		break;
+	case DWC3_GHWPARAMS0_MODE_HOST:
+		if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+			dev_err(dev,
+				"Controller does not support device mode.\n");
+			return -EINVAL;
+		}
+		mode = USB_DR_MODE_HOST;
+		break;
+	default:
+		if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+			mode = USB_DR_MODE_HOST;
+		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+			mode = USB_DR_MODE_PERIPHERAL;
+
+		/*
+		 * DWC_usb31 and DWC_usb3 v3.30a and higher do not support OTG
+		 * mode. If the controller supports DRD but the dr_mode is not
+		 * specified or set to OTG, then set the mode to peripheral.
+		 */
+		if (mode == USB_DR_MODE_OTG &&
+		    dwc->revision >= DWC3_REVISION_330A) {
+			printk("dwc3 dr_mode: %d, hw_mode: %d\n", dwc->dr_mode, hw_mode);
+#ifndef CONFIG_USB_DWC3_ASR_OTG
+			mode = USB_DR_MODE_PERIPHERAL;
+#endif
+		}
+	}
+
+	if (mode != dwc->dr_mode) {
+		dev_warn(dev,
+			 "Configuration mismatch. dr_mode forced to %s\n",
+			 mode == USB_DR_MODE_HOST ? "host" : "gadget");
+
+		dwc->dr_mode = mode;
+	}
+	printk("dwc3 dr_mode: %d\n", dwc->dr_mode);
+
+	return 0;
+}
+
+#ifdef CONFIG_USB_DWC3_ASR_OTG
+void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
+{
+	u32 reg;
+
+	if (dwc->otg_state == OTG_STATE_A_HOST)
+		mode = DWC3_GCTL_PRTCAP_HOST;
+	else
+		mode = DWC3_GCTL_PRTCAP_DEVICE;
+
+	pr_info("dwc3 set mode: %d\n", mode);
+	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_save_controller_regs(DWC3_GCTL, reg);
+	dwc->current_dr_role = mode;
+}
+#else
+void dwc3_set_prtcap(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_save_controller_regs(DWC3_GCTL, reg);
+	dwc->current_dr_role = mode;
+}
+#endif
+static void __maybe_unused __dwc3_set_mode(struct work_struct *work)
+{
+	struct dwc3 *dwc = work_to_dwc(work);
+	unsigned long flags;
+	int ret;
+	u32 reg;
+
+	if (dwc->dr_mode != USB_DR_MODE_OTG)
+		return;
+
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
+		dwc3_otg_update(dwc, 0);
+
+	if (!dwc->desired_dr_role)
+		return;
+
+	if (dwc->desired_dr_role == dwc->current_dr_role)
+		return;
+
+	if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
+		return;
+
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		dwc3_gadget_exit(dwc);
+		dwc3_event_buffers_cleanup(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		dwc3_otg_exit(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_otg_update(dwc, 1);
+		break;
+	default:
+		break;
+	}
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	dwc3_set_prtcap(dwc, dwc->desired_dr_role);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (dwc->desired_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to initialize host\n");
+		} else {
+			if (dwc->usb2_phy)
+				otg_set_vbus(dwc->usb2_phy->otg, true);
+			phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+			phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
+			if (dwc->dis_split_quirk) {
+				reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
+				reg |= DWC3_GUCTL3_SPLITDISABLE;
+				dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
+				dwc3_save_controller_regs(DWC3_GUCTL3, reg);
+			}
+		}
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		dwc3_event_buffers_setup(dwc);
+
+		if (dwc->usb2_phy)
+			otg_set_vbus(dwc->usb2_phy->otg, false);
+		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
+		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
+
+		ret = dwc3_gadget_init(dwc);
+		if (ret)
+			dev_err(dwc->dev, "failed to initialize peripheral\n");
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		dwc3_otg_init(dwc);
+		dwc3_otg_update(dwc, 0);
+		break;
+	default:
+		break;
+	}
+}
+
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc->desired_dr_role = mode;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	queue_work(system_freezable_wq, &dwc->drd_work);
+}
+
+u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+
+	dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
+			DWC3_GDBGFIFOSPACE_NUM(dep->number) |
+			DWC3_GDBGFIFOSPACE_TYPE(type));
+	dwc3_save_controller_regs(DWC3_GDBGFIFOSPACE,
+			DWC3_GDBGFIFOSPACE_NUM(dep->number) |
+			DWC3_GDBGFIFOSPACE_TYPE(type));
+	reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
+
+	return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
+}
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+int dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+	u32		reg;
+	int		retries = 1000;
+	int		ret;
+
+	/* ASR private: clear suspend phy before phy init */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	usb_phy_init(dwc->usb2_phy);
+	usb_phy_init(dwc->usb3_phy);
+	ret = phy_init(dwc->usb2_generic_phy);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_init(dwc->usb3_generic_phy);
+	if (ret < 0) {
+		phy_exit(dwc->usb2_generic_phy);
+		return ret;
+	}
+
+	/*
+	 * We're resetting only the device side because, if we're in host mode,
+	 * XHCI driver will reset the host block. If dwc3 was configured for
+	 * host-only mode, then we can return early.
+	 */
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
+		return 0;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg |= DWC3_DCTL_CSFTRST;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	/*
+	 * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit
+	 * is cleared only after all the clocks are synchronized. This can
+	 * take a little more than 50ms. Set the polling rate at 20ms
+	 * for 10 times instead.
+	 */
+	if (dwc3_is_usb31(dwc) && dwc->revision >= DWC3_USB31_REVISION_190A)
+		retries = 10;
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		if (!(reg & DWC3_DCTL_CSFTRST))
+			goto done;
+
+		if (dwc3_is_usb31(dwc) &&
+		    dwc->revision >= DWC3_USB31_REVISION_190A)
+			msleep(20);
+		else
+			udelay(1);
+	} while (--retries);
+
+	phy_exit(dwc->usb3_generic_phy);
+	phy_exit(dwc->usb2_generic_phy);
+
+	return -ETIMEDOUT;
+
+done:
+	/*
+	 * For DWC_usb31 controller 1.80a and prior, once DCTL.CSFRST bit
+	 * is cleared, we must wait at least 50ms before accessing the PHY
+	 * domain (synchronization delay).
+	 */
+	if (dwc3_is_usb31(dwc) && dwc->revision <= DWC3_USB31_REVISION_180A)
+		msleep(50);
+
+	return 0;
+}
+
+/*
+ * dwc3_frame_length_adjustment - Adjusts frame length if required
+ * @dwc3: Pointer to our controller context structure
+ */
+static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
+{
+	u32 reg;
+	u32 dft;
+
+	if (dwc->revision < DWC3_REVISION_250A)
+		return;
+
+	if (dwc->fladj == 0)
+		return;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
+	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
+	if (dft != dwc->fladj) {
+		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
+		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
+		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
+		dwc3_save_controller_regs(DWC3_GFLADJ, reg);
+	}
+}
+
+/**
+ * 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(dwc->sysdev, evt->length, evt->buf, evt->dma);
+}
+
+/**
+ * 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(dwc->dev, sizeof(*evt), GFP_KERNEL);
+	if (!evt)
+		return ERR_PTR(-ENOMEM);
+
+	evt->dwc	= dwc;
+	evt->length	= length;
+	evt->cache	= devm_kzalloc(dwc->dev, length, GFP_KERNEL);
+	if (!evt->cache)
+		return ERR_PTR(-ENOMEM);
+
+	evt->buf	= dma_alloc_coherent(dwc->sysdev, length,
+			&evt->dma, GFP_KERNEL);
+	if (!evt->buf)
+		return ERR_PTR(-ENOMEM);
+
+	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;
+
+	evt = dwc->ev_buf;
+	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)
+{
+	struct dwc3_event_buffer *evt;
+	unsigned int hw_mode;
+
+	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+	if (hw_mode == DWC3_GHWPARAMS0_MODE_HOST) {
+		dwc->ev_buf = NULL;
+		return 0;
+	}
+
+	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_buf = 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.
+ */
+int dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	u32				reg;
+
+	if (!dwc->ev_buf)
+		return 0;
+
+	evt = dwc->ev_buf;
+	evt->lpos = 0;
+	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
+			lower_32_bits(evt->dma));
+	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
+			upper_32_bits(evt->dma));
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
+			DWC3_GEVNTSIZ_SIZE(evt->length));
+
+	/* Clear any stale event */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
+
+	dwc3_save_controller_regs(DWC3_GEVNTADRLO(0), lower_32_bits(evt->dma));
+	dwc3_save_controller_regs(DWC3_GEVNTADRHI(0), upper_32_bits(evt->dma));
+	dwc3_save_controller_regs(DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_SIZE(evt->length));
+	dwc3_save_controller_regs(DWC3_GEVNTCOUNT(0), 0);
+
+	return 0;
+}
+
+void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	u32				reg;
+
+	if (!dwc->ev_buf)
+		return;
+	/*
+	 * Exynos platforms may not be able to access event buffer if the
+	 * controller failed to halt on dwc3_core_exit().
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+		return;
+
+	evt = dwc->ev_buf;
+
+	evt->lpos = 0;
+
+	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
+	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
+			| DWC3_GEVNTSIZ_SIZE(0));
+
+	/* Clear any stale event */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
+}
+
+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;
+
+	 /* should never fall here */
+	if (!WARN_ON(dwc->scratchbuf))
+		return 0;
+
+	scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf,
+			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+			DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dwc->sysdev, scratch_addr)) {
+		dev_err(dwc->sysdev, "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(dwc->sysdev, dwc->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;
+
+	 /* should never fall here */
+	if (!WARN_ON(dwc->scratchbuf))
+		return;
+
+	dma_unmap_single(dwc->sysdev, 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_eps = DWC3_NUM_EPS(parms);
+}
+
+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 int dwc3_core_ulpi_init(struct dwc3 *dwc)
+{
+	int intf;
+	int ret = 0;
+
+	intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
+
+	if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
+	    (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
+	     dwc->hsphy_interface &&
+	     !strncmp(dwc->hsphy_interface, "ulpi", 4)))
+		ret = dwc3_ulpi_init(dwc);
+
+	return ret;
+}
+
+/**
+ * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success. The USB PHY interfaces are configured but not
+ * initialized. The PHY interfaces and the PHYs get initialized together with
+ * the core in dwc3_core_init.
+ */
+static int dwc3_phy_setup(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+	/*
+	 * Make sure UX_EXIT_PX is cleared as that causes issues with some
+	 * PHYs. Also, this bit is not supposed to be used in normal operation.
+	 */
+	reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
+
+	/*
+	 * 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->dis_rxdet_inp3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
+
+	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_save_controller_regs(DWC3_GUSB3PIPECTL(0), reg);
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+	/* Select the HS PHY interface */
+	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
+	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
+		if (dwc->hsphy_interface &&
+				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
+			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
+			break;
+		} else if (dwc->hsphy_interface &&
+				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
+			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
+			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+			dwc3_save_controller_regs(DWC3_GUSB2PHYCFG(0), reg);
+		} else {
+			/* Relying on default value. */
+			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
+				break;
+		}
+		/* FALLTHROUGH */
+	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
+		/* FALLTHROUGH */
+	default:
+		break;
+	}
+
+	switch (dwc->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;
+	}
+
+#if 0 /* ASR private */
+	/*
+	 * 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;
+#endif
+
+	if (dwc->dis_u2_susphy_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+	if (dwc->dis_enblslpm_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+	else
+		reg |= DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+	if (dwc->dis_u2_freeclk_exists_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
+	reg |= DWC3_GUSB2PHYCFG_TOUCAL; /* ASR private setting */
+
+#ifdef CONFIG_CPU_ASR1903
+	if (((mmp_chip_id >> 24) & 0x7) == 0x1) {
+		pr_info("platform is fpga\n");
+		reg = 0x4000240f;
+	}
+#endif
+
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	dwc3_save_controller_regs(DWC3_GUSB2PHYCFG(0), reg);
+
+	return 0;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+	dwc3_event_buffers_cleanup(dwc);
+
+	usb_phy_set_suspend(dwc->usb2_phy, 1);
+	usb_phy_set_suspend(dwc->usb3_phy, 1);
+	phy_power_off(dwc->usb2_generic_phy);
+	phy_power_off(dwc->usb3_generic_phy);
+
+	usb_phy_shutdown(dwc->usb2_phy);
+	usb_phy_shutdown(dwc->usb3_phy);
+	phy_exit(dwc->usb2_generic_phy);
+	phy_exit(dwc->usb3_generic_phy);
+
+	clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
+	reset_control_assert(dwc->reset);
+}
+
+static bool dwc3_core_is_valid(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+
+	/* This should read as U3 followed by revision number */
+	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
+		/* Detected DWC_usb3 IP */
+		dwc->revision = reg;
+	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
+		/* Detected DWC_usb31 IP */
+		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
+		dwc->revision |= DWC3_REVISION_IS_DWC31;
+		dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
+	} else {
+		return false;
+	}
+
+	return true;
+}
+
+static void dwc3_core_setup_global_control(struct dwc3 *dwc)
+{
+	u32 hwparams4 = dwc->hwparams.hwparams4;
+	u32 reg;
+
+	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:
+		/* nothing */
+		break;
+	}
+
+	/* check if current dwc3 is on simulation board */
+	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
+		dev_info(dwc->dev, "Running with FPGA optimizations\n");
+		dwc->is_fpga = true;
+	}
+
+	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
+			"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_writel(dwc->regs, DWC3_GCTL, reg);
+	dwc3_save_controller_regs(DWC3_GCTL, reg);
+}
+
+static int dwc3_core_get_phy(struct dwc3 *dwc);
+static int dwc3_core_ulpi_init(struct dwc3 *dwc);
+
+/* set global incr burst type configuration registers */
+static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
+{
+	struct device *dev = dwc->dev;
+	/* incrx_mode : for INCR burst type. */
+	bool incrx_mode;
+	/* incrx_size : for size of INCRX burst. */
+	u32 incrx_size;
+	u32 *vals;
+	u32 cfg;
+	int ntype;
+	int ret;
+	int i;
+
+	cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
+
+	/*
+	 * Handle property "snps,incr-burst-type-adjustment".
+	 * Get the number of value from this property:
+	 * result <= 0, means this property is not supported.
+	 * result = 1, means INCRx burst mode supported.
+	 * result > 1, means undefined length burst mode supported.
+	 */
+	ntype = device_property_count_u32(dev, "snps,incr-burst-type-adjustment");
+	if (ntype <= 0)
+		return;
+
+	vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
+	if (!vals) {
+		dev_err(dev, "Error to get memory\n");
+		return;
+	}
+
+	/* Get INCR burst type, and parse it */
+	ret = device_property_read_u32_array(dev,
+			"snps,incr-burst-type-adjustment", vals, ntype);
+	if (ret) {
+		kfree(vals);
+		dev_err(dev, "Error to get property\n");
+		return;
+	}
+
+	incrx_size = *vals;
+
+	if (ntype > 1) {
+		/* INCRX (undefined length) burst mode */
+		incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE;
+		for (i = 1; i < ntype; i++) {
+			if (vals[i] > incrx_size)
+				incrx_size = vals[i];
+		}
+	} else {
+		/* INCRX burst mode */
+		incrx_mode = INCRX_BURST_MODE;
+	}
+
+	kfree(vals);
+
+	/* Enable Undefined Length INCR Burst and Enable INCRx Burst */
+	cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
+	if (incrx_mode)
+		cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
+	switch (incrx_size) {
+	case 256:
+		cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
+		break;
+	case 128:
+		cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
+		break;
+	case 64:
+		cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
+		break;
+	case 32:
+		cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
+		break;
+	case 16:
+		cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
+		break;
+	case 8:
+		cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
+		break;
+	case 4:
+		cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
+		break;
+	case 1:
+		break;
+	default:
+		dev_err(dev, "Invalid property\n");
+		break;
+	}
+
+	dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
+	dwc3_save_controller_regs(DWC3_GSBUSCFG0, cfg);
+}
+
+/**
+ * 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)
+{
+	u32			reg;
+	int			ret;
+
+	/*
+	 * Write Linux Version Code to our GUID register so it's easy to figure
+	 * out which kernel version a bug was found.
+	 */
+	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
+
+	/* 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;
+	}
+
+	ret = dwc3_phy_setup(dwc);
+	if (ret)
+		goto err0;
+
+	if (!dwc->ulpi_ready) {
+		ret = dwc3_core_ulpi_init(dwc);
+		if (ret) {
+			if (ret == -ETIMEDOUT) {
+				dwc3_core_soft_reset(dwc);
+				ret = -EPROBE_DEFER;
+			}
+			goto err0;
+		}
+		dwc->ulpi_ready = true;
+	}
+
+	if (!dwc->phys_ready) {
+		ret = dwc3_core_get_phy(dwc);
+		if (ret)
+			goto err0a;
+		dwc->phys_ready = true;
+	}
+
+	ret = dwc3_core_soft_reset(dwc);
+	if (ret)
+		goto err0a;
+
+	dwc3_core_setup_global_control(dwc);
+	dwc3_core_num_eps(dwc);
+
+	ret = dwc3_setup_scratch_buffers(dwc);
+	if (ret)
+		goto err1;
+
+	/* Adjust Frame Length */
+	dwc3_frame_length_adjustment(dwc);
+
+	dwc3_set_incr_burst_type(dwc);
+
+	usb_phy_set_suspend(dwc->usb2_phy, 0);
+	usb_phy_set_suspend(dwc->usb3_phy, 0);
+	ret = phy_power_on(dwc->usb2_generic_phy);
+	if (ret < 0)
+		goto err2;
+
+	ret = phy_power_on(dwc->usb3_generic_phy);
+	if (ret < 0)
+		goto err3;
+
+	ret = dwc3_event_buffers_setup(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to setup event buffers\n");
+		goto err4;
+	}
+
+	/*
+	 * ENDXFER polling is available on version 3.10a and later of
+	 * the DWC_usb3 controller. It is NOT available in the
+	 * DWC_usb31 controller.
+	 */
+	if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
+		reg |= DWC3_GUCTL2_RST_ACTBITLATER;
+		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
+		dwc3_save_controller_regs(DWC3_GUCTL2, reg);
+	}
+
+	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 0 /* ASR private */
+		if (dwc->dis_tx_ipgap_linecheck_quirk)
+			reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
+#endif
+		if (dwc->parkmode_disable_ss_quirk)
+			reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
+
+		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+		dwc3_save_controller_regs(DWC3_GUCTL1, reg);
+	}
+
+	/*
+	 * Must config both number of packets and max burst settings to enable
+	 * RX and/or TX threshold.
+	 */
+	if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) {
+		u8 rx_thr_num = dwc->rx_thr_num_pkt_prd;
+		u8 rx_maxburst = dwc->rx_max_burst_prd;
+		u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
+		u8 tx_maxburst = dwc->tx_max_burst_prd;
+
+		if (rx_thr_num && rx_maxburst) {
+			reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
+			reg |= DWC31_RXTHRNUMPKTSEL_PRD;
+
+			reg &= ~DWC31_RXTHRNUMPKT_PRD(~0);
+			reg |= DWC31_RXTHRNUMPKT_PRD(rx_thr_num);
+
+			reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0);
+			reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst);
+
+			dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
+			dwc3_save_controller_regs(DWC3_GRXTHRCFG, reg);
+		}
+
+		if (tx_thr_num && tx_maxburst) {
+			reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
+			reg |= DWC31_TXTHRNUMPKTSEL_PRD;
+
+			reg &= ~DWC31_TXTHRNUMPKT_PRD(~0);
+			reg |= DWC31_TXTHRNUMPKT_PRD(tx_thr_num);
+
+			reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0);
+			reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst);
+
+			dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
+			dwc3_save_controller_regs(DWC3_GTXTHRCFG, reg);
+		}
+	}
+
+	return 0;
+
+err4:
+	phy_power_off(dwc->usb3_generic_phy);
+
+err3:
+	phy_power_off(dwc->usb2_generic_phy);
+
+err2:
+	usb_phy_set_suspend(dwc->usb2_phy, 1);
+	usb_phy_set_suspend(dwc->usb3_phy, 1);
+
+err1:
+	usb_phy_shutdown(dwc->usb2_phy);
+	usb_phy_shutdown(dwc->usb3_phy);
+	phy_exit(dwc->usb2_generic_phy);
+	phy_exit(dwc->usb3_generic_phy);
+
+err0a:
+	dwc3_ulpi_exit(dwc);
+
+err0:
+	return ret;
+}
+
+static int dwc3_core_get_phy(struct dwc3 *dwc)
+{
+	struct device		*dev = dwc->dev;
+	struct device_node	*node = dev->of_node;
+	int ret;
+
+	if (node) {
+		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
+		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+	} else {
+		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+	}
+
+	if (IS_ERR(dwc->usb2_phy)) {
+		ret = PTR_ERR(dwc->usb2_phy);
+		if (ret == -ENXIO || ret == -ENODEV) {
+			dwc->usb2_phy = NULL;
+		} else if (ret == -EPROBE_DEFER) {
+			dev_err(dev, "dwc3_core_get_phy: EPROBE_DEFER\n");
+			return ret;
+		} else {
+			dev_err(dev, "no usb2 phy configured\n");
+			return ret;
+		}
+	}
+
+	if (IS_ERR(dwc->usb3_phy)) {
+		ret = PTR_ERR(dwc->usb3_phy);
+		if (ret == -ENXIO || ret == -ENODEV) {
+			dwc->usb3_phy = NULL;
+		} else if (ret == -EPROBE_DEFER) {
+			return ret;
+		} else {
+			dev_err(dev, "no usb3 phy configured\n");
+			return ret;
+		}
+	}
+
+	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
+	if (IS_ERR(dwc->usb2_generic_phy)) {
+		ret = PTR_ERR(dwc->usb2_generic_phy);
+		if (ret == -ENOSYS || ret == -ENODEV) {
+			dwc->usb2_generic_phy = NULL;
+		} else if (ret == -EPROBE_DEFER) {
+			return ret;
+		} else {
+			dev_err(dev, "no usb2 phy configured\n");
+			return ret;
+		}
+	}
+
+	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
+	if (IS_ERR(dwc->usb3_generic_phy)) {
+		ret = PTR_ERR(dwc->usb3_generic_phy);
+		if (ret == -ENOSYS || ret == -ENODEV) {
+			dwc->usb3_generic_phy = NULL;
+		} else if (ret == -EPROBE_DEFER) {
+			return ret;
+		} else {
+			dev_err(dev, "no usb3 phy configured\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int dwc3_core_init_mode(struct dwc3 *dwc)
+{
+	struct device *dev = dwc->dev;
+	int ret;
+
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+
+		if (dwc->usb2_phy)
+			otg_set_vbus(dwc->usb2_phy->otg, false);
+		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
+		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
+
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to initialize gadget\n");
+			return ret;
+		}
+		break;
+	case USB_DR_MODE_HOST:
+		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+
+		if (dwc->usb2_phy)
+			otg_set_vbus(dwc->usb2_phy->otg, true);
+		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
+		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
+
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to initialize host\n");
+			return ret;
+		}
+		break;
+	case USB_DR_MODE_OTG:
+#ifdef CONFIG_USB_DWC3_ASR_OTG
+		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to initialize host\n");
+			return ret;
+		}
+
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to initialize gadget\n");
+			return ret;
+		}
+		break;
+#else
+		INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
+		ret = dwc3_drd_init(dwc);
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to initialize dual-role\n");
+			return ret;
+		}
+		break;
+#endif
+	default:
+		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+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:
+#ifndef CONFIG_USB_DWC3_ASR_OTG
+		dwc3_drd_exit(dwc);
+#endif
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	/* de-assert DRVVBUS for HOST and OTG mode */
+	dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+}
+
+#define DWC3_ALIGN_MASK		(16 - 1)
+
+
+/**
+ * dwc3_soft_reset - Issue soft reset
+ * @dwc: Pointer to our controller context structure
+ */
+static int dwc3_soft_reset(struct dwc3 *dwc)
+{
+	unsigned long timeout = 1000;
+	u32 reg;
+
+	/*
+	 * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit
+	 * is cleared only after all the clocks are synchronized. This can
+	 * take a little more than 50ms. Set the polling rate at 20ms
+	 * for 10 times instead.
+	 */
+	if (dwc3_is_usb31(dwc) && dwc->revision >= DWC3_USB31_REVISION_190A)
+		timeout = 20;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg |= DWC3_DCTL_CSFTRST;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		if (!(reg & DWC3_DCTL_CSFTRST))
+			goto done;
+
+		if (dwc3_is_usb31(dwc) &&
+			dwc->revision >= DWC3_USB31_REVISION_190A)
+			msleep(10);
+		else
+			udelay(1);
+	} while (--timeout);
+
+	if (timeout == 0) {
+		dev_err(dwc->dev, "dwc3_soft_reset failed\n");
+		return -EIO;
+	}
+
+done:
+	/* reset this flag */
+	burst1_is_set = false;
+	return 0;
+}
+
+#ifdef CONFIG_CPU_ASR18XX
+#define KAGU_APMU_USB_CLK_CTL	(0x170) /* kagu */
+#define LAPW_APMU_USB_CLK_CTL	(0x05C) /* lapw */
+#else
+#define KSTR_APMU_USB_CLK_CTL	(0x3b8) /* 190x */
+#endif
+
+int dwc3_controller_reset(struct dwc3 *dwc)
+{
+	int ret;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+#ifndef CONFIG_CPU_ASR18XX
+	u32 val = 0;
+#endif
+
+	/* Add global reset and phy reinit to guarantee safe reset per ASIC */
+#ifdef CONFIG_CPU_ASR18XX
+	if (cpu_is_asr1903()) {
+		writel(0x0, apmu_base + LAPW_APMU_USB_CLK_CTL);
+		udelay(200);
+		writel(0xF, apmu_base + LAPW_APMU_USB_CLK_CTL);
+	} else {
+		writel(0x0, apmu_base + KAGU_APMU_USB_CLK_CTL);
+		udelay(200);
+		writel(0x1E000, apmu_base + KAGU_APMU_USB_CLK_CTL);		
+	}
+#else
+	val = readl(apmu_base + KSTR_APMU_USB_CLK_CTL);
+	val &= ~0x1E000;
+	writel(val, apmu_base + KSTR_APMU_USB_CLK_CTL);
+	udelay(200);
+	val |= 0x1E000;
+	writel(val, apmu_base + KSTR_APMU_USB_CLK_CTL);
+#endif
+	dwc->usb_do_restart = 0;
+	usb_phy_shutdown(dwc->usb2_phy);
+	usb_phy_shutdown(dwc->usb3_phy);
+	usb_phy_init(dwc->usb2_phy);
+	usb_phy_init(dwc->usb3_phy);
+	usb_phy_set_suspend(dwc->usb2_phy, 0);
+	usb_phy_set_suspend(dwc->usb3_phy, 0);
+	dwc->gadget.speed = USB_SPEED_UNKNOWN;
+
+	ret = dwc3_soft_reset(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "dwc3_soft_reset failure\n");
+		goto out;
+	}
+	dwc3_restore_global_regs(dwc);
+out:
+	return ret;
+}
+
+static void dwc3_get_properties(struct dwc3 *dwc)
+{
+	struct device		*dev = dwc->dev;
+	u8			lpm_nyet_threshold;
+	u8			tx_de_emphasis;
+	u8			hird_threshold;
+	u8			rx_thr_num_pkt_prd = 0;
+	u8			rx_max_burst_prd = 0;
+	u8			tx_thr_num_pkt_prd = 0;
+	u8			tx_max_burst_prd = 0;
+
+	/* default to highest possible threshold */
+	lpm_nyet_threshold = 0xf;
+
+	/* 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 = usb_get_maximum_speed(dev);
+
+	/* force to high speed */
+	if (cpu_is_asr1828_a0())
+		dwc->maximum_speed = USB_SPEED_HIGH;
+
+	dwc->dr_mode = usb_get_dr_mode(dev);
+
+	dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
+
+	dwc->sysdev_is_parent = device_property_read_bool(dev,
+				"linux,sysdev_is_parent");
+	if (dwc->sysdev_is_parent)
+		dwc->sysdev = dwc->dev->parent;
+	else
+		dwc->sysdev = dwc->dev;
+
+	dwc->has_lpm_erratum = device_property_read_bool(dev,
+				"snps,has-lpm-erratum");
+	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
+				&lpm_nyet_threshold);
+	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
+				"snps,is-utmi-l1-suspend");
+	device_property_read_u8(dev, "snps,hird-threshold",
+				&hird_threshold);
+	dwc->dis_start_transfer_quirk = device_property_read_bool(dev,
+				"snps,dis-start-transfer-quirk");
+	dwc->usb3_lpm_capable = device_property_read_bool(dev,
+				"snps,usb3_lpm_capable");
+	dwc->usb2_lpm_disable = device_property_read_bool(dev,
+				"snps,usb2-lpm-disable");
+	device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd",
+				&rx_thr_num_pkt_prd);
+	device_property_read_u8(dev, "snps,rx-max-burst-prd",
+				&rx_max_burst_prd);
+	device_property_read_u8(dev, "snps,tx-thr-num-pkt-prd",
+				&tx_thr_num_pkt_prd);
+	device_property_read_u8(dev, "snps,tx-max-burst-prd",
+				&tx_max_burst_prd);
+
+	dwc->disable_scramble_quirk = device_property_read_bool(dev,
+				"snps,disable_scramble_quirk");
+	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
+				"snps,u2exit_lfps_quirk");
+	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
+				"snps,u2ss_inp3_quirk");
+	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
+				"snps,req_p1p2p3_quirk");
+	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
+				"snps,del_p1p2p3_quirk");
+	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
+				"snps,del_phy_power_chg_quirk");
+	dwc->lfps_filter_quirk = device_property_read_bool(dev,
+				"snps,lfps_filter_quirk");
+	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
+				"snps,rx_detect_poll_quirk");
+	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
+				"snps,dis_u3_susphy_quirk");
+	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
+				"snps,dis_u2_susphy_quirk");
+	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
+				"snps,dis_enblslpm_quirk");
+	dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
+				"snps,dis-u1-entry-quirk");
+	dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
+				"snps,dis-u2-entry-quirk");
+	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
+				"snps,dis_rxdet_inp3_quirk");
+	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+				"snps,dis-u2-freeclk-exists-quirk");
+	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+				"snps,dis-del-phy-power-chg-quirk");
+	dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
+				"snps,dis-tx-ipgap-linecheck-quirk");
+	dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
+				"snps,parkmode-disable-ss-quirk");
+
+	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
+				"snps,tx_de_emphasis_quirk");
+
+	dwc->allow_suspend = device_property_read_bool(dev,
+				"allow-suspend");
+	dwc->no_acchg_det = device_property_read_bool(dev,
+				"no-acchg-det");
+
+	device_property_read_u8(dev, "snps,tx_de_emphasis",
+				&tx_de_emphasis);
+	device_property_read_string(dev, "snps,hsphy_interface",
+				    &dwc->hsphy_interface);
+	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
+				 &dwc->fladj);
+
+	dwc->dis_metastability_quirk = device_property_read_bool(dev,
+				"snps,dis_metastability_quirk");
+
+	dwc->dis_split_quirk = device_property_read_bool(dev,
+				"snps,dis-split-quirk");
+
+	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+	dwc->tx_de_emphasis = tx_de_emphasis;
+
+	dwc->hird_threshold = hird_threshold;
+
+	dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd;
+	dwc->rx_max_burst_prd = rx_max_burst_prd;
+
+	dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
+	dwc->tx_max_burst_prd = tx_max_burst_prd;
+
+	dwc->imod_interval = 0;
+}
+
+/* check whether the core supports IMOD */
+bool dwc3_has_imod(struct dwc3 *dwc)
+{
+	return ((dwc3_is_usb3(dwc) &&
+		 dwc->revision >= DWC3_REVISION_300A) ||
+		(dwc3_is_usb31(dwc) &&
+		 dwc->revision >= DWC3_USB31_REVISION_120A));
+}
+
+static void dwc3_check_params(struct dwc3 *dwc)
+{
+	struct device *dev = dwc->dev;
+
+	/* Check for proper value of imod_interval */
+	if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
+		dev_warn(dwc->dev, "Interrupt moderation not supported\n");
+		dwc->imod_interval = 0;
+	}
+
+	/*
+	 * Workaround for STAR 9000961433 which affects only version
+	 * 3.00a of the DWC_usb3 core. This prevents the controller
+	 * interrupt from being masked while handling events. IMOD
+	 * allows us to work around this issue. Enable it for the
+	 * affected version.
+	 */
+	if (!dwc->imod_interval &&
+	    (dwc->revision == DWC3_REVISION_300A))
+		dwc->imod_interval = 1;
+
+	/* Check the maximum_speed parameter */
+	switch (dwc->maximum_speed) {
+	case USB_SPEED_LOW:
+	case USB_SPEED_FULL:
+	case USB_SPEED_HIGH:
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		break;
+	default:
+		dev_err(dev, "invalid maximum_speed parameter %d\n",
+			dwc->maximum_speed);
+		/* fall through */
+	case USB_SPEED_UNKNOWN:
+		/* default to superspeed */
+		dwc->maximum_speed = USB_SPEED_SUPER;
+
+		/*
+		 * default to superspeed plus if we are capable.
+		 */
+		if (dwc3_is_usb31(dwc) &&
+		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
+		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
+			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
+
+		break;
+	}
+}
+
+static int dwc3_probe(struct platform_device *pdev)
+{
+	struct device		*dev = &pdev->dev;
+	struct resource		*res, dwc_res;
+	struct dwc3		*dwc;
+
+	int			ret;
+
+	void __iomem		*regs;
+	const __be32 *prop;
+	unsigned int proplen;
+	struct device_node *np = dev->of_node;
+
+	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
+	if (!dwc)
+		return -ENOMEM;
+
+	dwc->dev = dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing memory resource\n");
+		return -ENODEV;
+	}
+
+	dwc->xhci_resources[0].start = res->start;
+	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+					DWC3_XHCI_REGS_END;
+	dwc->xhci_resources[0].flags = res->flags;
+	dwc->xhci_resources[0].name = res->name;
+
+	/*
+	 * Request memory region but exclude xHCI regs,
+	 * since it will be requested by the xhci-plat driver.
+	 */
+	dwc_res = *res;
+	dwc_res.start += DWC3_GLOBALS_REGS_START;
+
+	regs = devm_ioremap_resource(dev, &dwc_res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dwc->regs	= regs;
+	dwc->regs_size	= resource_size(&dwc_res);
+
+	dwc3_get_properties(dwc);
+
+	dwc->reset = devm_reset_control_array_get(dev, true, true);
+	if (IS_ERR(dwc->reset)) {
+		dev_err(dwc->dev, "devm_reset_control_array_get failed\n");
+		return PTR_ERR(dwc->reset);
+	}
+	if (dev->of_node) {
+		ret = devm_clk_bulk_get_all(dev, &dwc->clks);
+		if (ret == -EPROBE_DEFER) {
+			dev_err(dwc->dev, "devm_clk_bulk_get_all failed\n");
+			return ret;
+		}
+		/*
+		 * Clocks are optional, but new DT platforms should support all
+		 * clocks as required by the DT-binding.
+		 */
+		if (ret < 0)
+			dwc->num_clks = 0;
+		else
+			dwc->num_clks = ret;
+
+	}
+
+	ret = reset_control_deassert(dwc->reset);
+	if (ret) {
+		dev_err(dwc->dev, "reset_control_deassert failed\n");
+		return ret;
+	}
+
+	ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks);
+	if (ret) {
+		dev_err(dwc->dev, "clk_bulk_prepare_enable failed\n");
+		goto assert_reset;
+	}
+
+	if (!dwc3_core_is_valid(dwc)) {
+		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+		ret = -ENODEV;
+		goto disable_clks;
+	}
+
+	platform_set_drvdata(pdev, dwc);
+	dwc3_cache_hwparams(dwc);
+
+	spin_lock_init(&dwc->lock);
+
+#if 0 /* ASR private */
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
+	pm_runtime_enable(dev);
+
+	pm_runtime_forbid(dev);
+#endif
+
+	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+	if (ret) {
+		dev_err(dwc->dev, "failed to allocate event buffers\n");
+		ret = -ENOMEM;
+		goto err2;
+	}
+	
+	ret = dwc3_get_dr_mode(dwc);
+	if (ret)
+		goto err3;
+
+	ret = dwc3_alloc_scratch_buffers(dwc);
+	if (ret)
+		goto err3;
+
+	ret = dwc3_core_init(dwc);
+	if (ret) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to initialize core: %d\n", ret);
+		goto err4;
+	}
+
+	dwc3_check_params(dwc);
+	dwc3_debugfs_init(dwc);
+
+	ret = dwc3_core_init_mode(dwc);
+	if (ret) {
+		dev_err(dev, "dwc3_core_init_mode failed\n");
+		goto err5;
+	}
+
+#if 0 /* ASR private */
+	pm_runtime_put(dev);
+#endif
+
+	prop = of_get_property(np, "lpm-qos", &proplen);
+	if (!prop) {
+		dev_err(dwc->dev, "lpm-qos not defined\n");
+		goto err2;
+	} else
+		dwc->lpm_qos = be32_to_cpup(prop);
+	dwc->qos_idle.name = pdev->name;
+	pm_qos_add_request(&dwc->qos_idle, PM_QOS_CPUIDLE_BLOCK,
+			PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);
+
+	g_dwc = dwc;
+	dev_info(dev, "dwc3 probe successful\n");
+
+	dma_set_max_seg_size(dev, UINT_MAX);
+
+	return 0;
+
+err5:
+	dwc3_debugfs_exit(dwc);
+	dwc3_event_buffers_cleanup(dwc);
+
+	usb_phy_set_suspend(dwc->usb2_phy, 1);
+	usb_phy_set_suspend(dwc->usb3_phy, 1);
+	phy_power_off(dwc->usb2_generic_phy);
+	phy_power_off(dwc->usb3_generic_phy);
+
+	usb_phy_shutdown(dwc->usb2_phy);
+	usb_phy_shutdown(dwc->usb3_phy);
+	phy_exit(dwc->usb2_generic_phy);
+	phy_exit(dwc->usb3_generic_phy);
+
+	dwc3_ulpi_exit(dwc);
+
+err4:
+	dwc3_free_scratch_buffers(dwc);
+
+err3:
+	dwc3_free_event_buffers(dwc);
+
+err2:
+#if 0 /* ASR private */
+	pm_runtime_allow(dev);
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_put_noidle(dev);
+#endif
+disable_clks:
+	clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
+assert_reset:
+	reset_control_assert(dwc->reset);
+
+	return ret;
+}
+
+static int dwc3_remove(struct platform_device *pdev)
+{
+	struct dwc3	*dwc = platform_get_drvdata(pdev);
+
+#if 0 /* ASR private */
+	pm_runtime_get_sync(&pdev->dev);
+#endif
+	dwc3_core_exit_mode(dwc);
+	dwc3_debugfs_exit(dwc);
+
+	dwc3_core_exit(dwc);
+	dwc3_ulpi_exit(dwc);
+
+#if 0 /* ASR private */
+	pm_runtime_allow(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_put_noidle(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+#endif
+
+	dwc3_free_event_buffers(dwc);
+	dwc3_free_scratch_buffers(dwc);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+#if 0 /* ASR private */
+static int dwc3_core_init_for_resume(struct dwc3 *dwc)
+{
+	int ret;
+
+	ret = reset_control_deassert(dwc->reset);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks);
+	if (ret)
+		goto assert_reset;
+
+	ret = dwc3_core_init(dwc);
+	if (ret)
+		goto disable_clks;
+
+	return 0;
+
+disable_clks:
+	clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
+assert_reset:
+	reset_control_assert(dwc->reset);
+
+	return ret;
+}
+
+static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
+{
+	unsigned long	flags;
+	u32 reg;
+
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_gadget_suspend(dwc);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		synchronize_irq(dwc->irq_gadget);
+		dwc3_core_exit(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_HOST:
+		if (!PMSG_IS_AUTO(msg)) {
+			dwc3_core_exit(dwc);
+			break;
+		}
+
+		/* Let controller to suspend HSPHY before PHY driver suspends */
+		if (dwc->dis_u2_susphy_quirk ||
+		    dwc->dis_enblslpm_quirk) {
+			reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+			reg |=  DWC3_GUSB2PHYCFG_ENBLSLPM |
+				DWC3_GUSB2PHYCFG_SUSPHY;
+			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+			/* Give some time for USB2 PHY to suspend */
+			usleep_range(5000, 6000);
+		}
+#if 0 /* ASR private */
+		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
+		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
+#endif
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		/* do nothing during runtime_suspend */
+		if (PMSG_IS_AUTO(msg))
+			break;
+
+		if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
+			spin_lock_irqsave(&dwc->lock, flags);
+			dwc3_gadget_suspend(dwc);
+			spin_unlock_irqrestore(&dwc->lock, flags);
+			synchronize_irq(dwc->irq_gadget);
+		}
+
+		dwc3_otg_exit(dwc);
+		dwc3_core_exit(dwc);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	return 0;
+}
+
+static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
+{
+	unsigned long	flags;
+	int		ret;
+	u32		reg;
+
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		ret = dwc3_core_init_for_resume(dwc);
+		if (ret)
+			return ret;
+
+		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_gadget_resume(dwc);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		break;
+	case DWC3_GCTL_PRTCAP_HOST:
+		if (!PMSG_IS_AUTO(msg)) {
+			ret = dwc3_core_init_for_resume(dwc);
+			if (ret)
+				return ret;
+			dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+			break;
+		}
+		/* Restore GUSB2PHYCFG bits that were modified in suspend */
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+		if (dwc->dis_u2_susphy_quirk)
+			reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+		if (dwc->dis_enblslpm_quirk)
+			reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+#if 0 /* ASR private */
+		phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
+		phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
+#endif
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		/* nothing to do on runtime_resume */
+		if (PMSG_IS_AUTO(msg))
+			break;
+
+		ret = dwc3_core_init_for_resume(dwc);
+		if (ret)
+			return ret;
+
+		dwc3_set_prtcap(dwc, dwc->current_dr_role);
+
+		dwc3_otg_init(dwc);
+		if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
+			dwc3_otg_host_init(dwc);
+		} else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
+			spin_lock_irqsave(&dwc->lock, flags);
+			dwc3_gadget_resume(dwc);
+			spin_unlock_irqrestore(&dwc->lock, flags);
+		}
+
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	return 0;
+}
+static int dwc3_runtime_checks(struct dwc3 *dwc)
+{
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		if (dwc->connected)
+			return -EBUSY;
+		break;
+	case DWC3_GCTL_PRTCAP_HOST:
+	default:
+		/* do nothing */
+		break;
+	}
+
+	return 0;
+}
+
+static int dwc3_runtime_suspend(struct device *dev)
+{
+	struct dwc3     *dwc = dev_get_drvdata(dev);
+	int		ret;
+
+	if (dwc3_runtime_checks(dwc))
+		return -EBUSY;
+
+	ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
+	if (ret)
+		return ret;
+
+	device_init_wakeup(dev, true);
+
+	return 0;
+}
+
+static int dwc3_runtime_resume(struct device *dev)
+{
+	struct dwc3     *dwc = dev_get_drvdata(dev);
+	int		ret;
+
+	device_init_wakeup(dev, false);
+
+	ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
+	if (ret)
+		return ret;
+
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		if (dwc->pending_events) {
+			pm_runtime_put(dwc->dev);
+			dwc->pending_events = false;
+			enable_irq(dwc->irq_gadget);
+		}
+		break;
+	case DWC3_GCTL_PRTCAP_HOST:
+	default:
+		/* do nothing */
+		break;
+	}
+#if 0 /* ASR private */
+	pm_runtime_mark_last_busy(dev);
+#endif
+
+	return 0;
+}
+
+static int dwc3_runtime_idle(struct device *dev)
+{
+	struct dwc3     *dwc = dev_get_drvdata(dev);
+
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		if (dwc3_runtime_checks(dwc))
+			return -EBUSY;
+		break;
+	case DWC3_GCTL_PRTCAP_HOST:
+	default:
+		/* do nothing */
+		break;
+	}
+#if 0 /* ASR private */
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_autosuspend(dev);
+#endif
+	return 0;
+}
+#endif
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+#if 0 /* ASR private */
+static int dwc3_suspend(struct device *dev)
+{
+	struct dwc3	*dwc = dev_get_drvdata(dev);
+	int		ret;
+
+	ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
+	if (ret)
+		return ret;
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int dwc3_resume(struct device *dev)
+{
+	struct dwc3	*dwc = dev_get_drvdata(dev);
+	int		ret;
+
+	pinctrl_pm_select_default_state(dev);
+
+	ret = dwc3_resume_common(dwc, PMSG_RESUME);
+	if (ret)
+		return ret;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void dwc3_complete(struct device *dev)
+{
+	struct dwc3	*dwc = dev_get_drvdata(dev);
+	u32		reg;
+
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
+			dwc->dis_split_quirk) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
+		reg |= DWC3_GUCTL3_SPLITDISABLE;
+		dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
+	}
+}
+#else
+static int dwc3_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int dwc3_resume(struct device *dev)
+{
+	return 0;
+}
+#if 0 /* ASR private */
+static void dwc3_complete(struct device *dev)
+{
+}
+#endif
+#endif
+#else
+#define dwc3_complete NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dwc3_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+#ifdef CONFIG_PM_RUNTIME
+#if 0 /* ASR private */ for performance consideration
+
+	/*
+	 * Runtime suspend halts the controller on disconnection. It relies on
+	 * platforms with custom connection notification to start the controller
+	 * again.
+	 */
+	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
+			dwc3_runtime_idle)
+#endif
+#endif
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_dwc3_match[] = {
+	{
+		.compatible = "snps,dwc3"
+	},
+	{
+		.compatible = "synopsys,dwc3"
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_match);
+#endif
+
+#ifdef CONFIG_ACPI
+
+#define ACPI_ID_INTEL_BSW	"808622B7"
+
+static const struct acpi_device_id dwc3_acpi_match[] = {
+	{ ACPI_ID_INTEL_BSW, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
+#endif
+
+static struct platform_driver dwc3_driver = {
+	.probe		= dwc3_probe,
+	.remove		= dwc3_remove,
+	.driver		= {
+		.name	= "dwc3",
+		.of_match_table	= of_match_ptr(of_dwc3_match),
+		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
+		.pm	= &dwc3_dev_pm_ops,
+	},
+};
+
+module_platform_driver(dwc3_driver);
+
+MODULE_ALIAS("platform:dwc3");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
diff --git a/marvell/linux/drivers/usb/dwc3/core.h b/marvell/linux/drivers/usb/dwc3/core.h
new file mode 100644
index 0000000..94cd507
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/core.h
@@ -0,0 +1,1596 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_kabi.h>
+#include <linux/pm_qos.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/role.h>
+#include <linux/ulpi/interface.h>
+
+#include <linux/phy/phy.h>
+
+#define DWC3_MSG_MAX	500
+
+/* Global constants */
+#define DWC3_PULL_UP_TIMEOUT	500	/* ms */
+#define DWC3_BOUNCE_SIZE	1024	/* size of a superspeed bulk */
+#define DWC3_EP0_SETUP_SIZE	512
+
+#ifdef CONFIG_CPU_ASR1903
+#define DWC3_ENDPOINTS_NUM	22
+#else
+#define DWC3_ENDPOINTS_NUM	32
+#endif
+
+#define DWC3_XHCI_RESOURCES_NUM	2
+#define DWC3_ISOC_MAX_RETRIES	10	/* old value 5 */
+
+#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */
+
+#if defined(CONFIG_ASR_TOE) || defined(CONFIG_CPU_ASR1901)
+#define DWC3_EVENT_BUFFERS_SIZE	(8192 * 4)
+#else
+#define DWC3_EVENT_BUFFERS_SIZE	4096
+#endif
+
+#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
+
+/* Controller's role while using the OTG block */
+#define DWC3_OTG_ROLE_IDLE	0
+#define DWC3_OTG_ROLE_HOST	1
+#define DWC3_OTG_ROLE_DEVICE	2
+
+#define DWC3_GEVNTCOUNT_MASK	0xfffc
+#define DWC3_GEVNTCOUNT_EHB	BIT(31)
+#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
+
+#ifdef CONFIG_CPU_ASR1901
+#define DWC3_GDBGLTSSM		0xd050
+#else
+#define DWC3_GDBGLTSSM		0xc164
+#endif
+
+#define DWC3_GDBGBMU		0xc16c
+#define DWC3_GDBGLSPMUX		0xc170
+#define DWC3_GDBGLSP		0xc174
+#define DWC3_GDBGEPINFO0	0xc178
+#define DWC3_GDBGEPINFO1	0xc17c
+#define DWC3_GPRTBIMAP_HS0	0xc180
+#define DWC3_GPRTBIMAP_HS1	0xc184
+#define DWC3_GPRTBIMAP_FS0	0xc188
+#define DWC3_GPRTBIMAP_FS1	0xc18c
+#define DWC3_GUCTL2		0xc19c
+
+#define DWC3_VER_NUMBER		0xc1a0
+#define DWC3_VER_TYPE		0xc1a4
+
+#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
+#define DWC3_GUCTL3		0xc60c
+#define DWC3_GFLADJ		0xc630
+
+/* 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_DEP_BASE(n)	(0xc800 + ((n) * 0x10))
+#define DWC3_DEPCMDPAR2		0x00
+#define DWC3_DEPCMDPAR1		0x04
+#define DWC3_DEPCMDPAR0		0x08
+#define DWC3_DEPCMD		0x0c
+
+#define DWC3_DEV_IMOD(n)	(0xca00 + ((n) * 0x4))
+
+/* 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 SoC Bus Configuration INCRx Register 0 */
+#define DWC3_GSBUSCFG0_INCR256BRSTENA	(1 << 7) /* INCR256 burst */
+#define DWC3_GSBUSCFG0_INCR128BRSTENA	(1 << 6) /* INCR128 burst */
+#define DWC3_GSBUSCFG0_INCR64BRSTENA	(1 << 5) /* INCR64 burst */
+#define DWC3_GSBUSCFG0_INCR32BRSTENA	(1 << 4) /* INCR32 burst */
+#define DWC3_GSBUSCFG0_INCR16BRSTENA	(1 << 3) /* INCR16 burst */
+#define DWC3_GSBUSCFG0_INCR8BRSTENA	(1 << 2) /* INCR8 burst */
+#define DWC3_GSBUSCFG0_INCR4BRSTENA	(1 << 1) /* INCR4 burst */
+#define DWC3_GSBUSCFG0_INCRBRSTENA	(1 << 0) /* undefined length enable */
+#define DWC3_GSBUSCFG0_INCRBRST_MASK	0xff
+
+/* Global Debug LSP MUX Select */
+#define DWC3_GDBGLSPMUX_ENDBC		BIT(15)	/* Host only */
+#define DWC3_GDBGLSPMUX_HOSTSELECT(n)	((n) & 0x3fff)
+#define DWC3_GDBGLSPMUX_DEVSELECT(n)	(((n) & 0xf) << 4)
+#define DWC3_GDBGLSPMUX_EPSELECT(n)	((n) & 0xf)
+
+/* Global Debug Queue/FIFO Space Available Register */
+#define DWC3_GDBGFIFOSPACE_NUM(n)	((n) & 0x1f)
+#define DWC3_GDBGFIFOSPACE_TYPE(n)	(((n) << 5) & 0x1e0)
+#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
+
+#define DWC3_TXFIFO		0
+#define DWC3_RXFIFO		1
+#define DWC3_TXREQQ		2
+#define DWC3_RXREQQ		3
+#define DWC3_RXINFOQ		4
+#define DWC3_PSTATQ		5
+#define DWC3_DESCFETCHQ		6
+#define DWC3_EVENTQ		7
+#define DWC3_AUXEVENTQ		8
+
+/* Global RX Threshold Configuration Register */
+#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
+#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
+#define DWC3_GRXTHRCFG_PKTCNTSEL BIT(29)
+
+/* Global RX Threshold Configuration Register for DWC_usb31 only */
+#define DWC31_GRXTHRCFG_MAXRXBURSTSIZE(n)	(((n) & 0x1f) << 16)
+#define DWC31_GRXTHRCFG_RXPKTCNT(n)		(((n) & 0x1f) << 21)
+#define DWC31_GRXTHRCFG_PKTCNTSEL		BIT(26)
+#define DWC31_RXTHRNUMPKTSEL_HS_PRD		BIT(15)
+#define DWC31_RXTHRNUMPKT_HS_PRD(n)		(((n) & 0x3) << 13)
+#define DWC31_RXTHRNUMPKTSEL_PRD		BIT(10)
+#define DWC31_RXTHRNUMPKT_PRD(n)		(((n) & 0x1f) << 5)
+#define DWC31_MAXRXBURSTSIZE_PRD(n)		((n) & 0x1f)
+
+/* Global TX Threshold Configuration Register for DWC_usb31 only */
+#define DWC31_GTXTHRCFG_MAXTXBURSTSIZE(n)	(((n) & 0x1f) << 16)
+#define DWC31_GTXTHRCFG_TXPKTCNT(n)		(((n) & 0x1f) << 21)
+#define DWC31_GTXTHRCFG_PKTCNTSEL		BIT(26)
+#define DWC31_TXTHRNUMPKTSEL_HS_PRD		BIT(15)
+#define DWC31_TXTHRNUMPKT_HS_PRD(n)		(((n) & 0x3) << 13)
+#define DWC31_TXTHRNUMPKTSEL_PRD		BIT(10)
+#define DWC31_TXTHRNUMPKT_PRD(n)		(((n) & 0x1f) << 5)
+#define DWC31_MAXTXBURSTSIZE_PRD(n)		((n) & 0x1f)
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
+#define DWC3_GCTL_U2RSTECN	BIT(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		BIT(11)
+#define DWC3_GCTL_SOFITPSYNC		BIT(10)
+#define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)
+#define DWC3_GCTL_DISSCRAMBLE		BIT(3)
+#define DWC3_GCTL_U2EXIT_LFPS		BIT(2)
+#define DWC3_GCTL_GBLHIBERNATIONEN	BIT(1)
+#define DWC3_GCTL_DSBLCLKGTNG		BIT(0)
+
+/* Global User Control 1 Register */
+#define DWC3_GUCTL1_PARKMODE_DISABLE_SS	BIT(17)
+#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS	BIT(28)
+#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW	BIT(24)
+
+/* Global Status Register */
+#define DWC3_GSTS_OTG_IP	BIT(10)
+#define DWC3_GSTS_BC_IP		BIT(9)
+#define DWC3_GSTS_ADP_IP	BIT(8)
+#define DWC3_GSTS_HOST_IP	BIT(7)
+#define DWC3_GSTS_DEVICE_IP	BIT(6)
+#define DWC3_GSTS_CSR_TIMEOUT	BIT(5)
+#define DWC3_GSTS_BUS_ERR_ADDR_VLD	BIT(4)
+#define DWC3_GSTS_CURMOD(n)	((n) & 0x3)
+#define DWC3_GSTS_CURMOD_DEVICE	0
+#define DWC3_GSTS_CURMOD_HOST	1
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST	BIT(31)
+#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS	BIT(30)
+#define DWC3_GUSB2PHYCFG_SUSPHY		BIT(6)
+#define DWC3_GUSB2PHYCFG_ULPI_UTMI	BIT(4)
+#define DWC3_GUSB2PHYCFG_ENBLSLPM	BIT(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		13
+#define USBTRDTIM_UTMI_16_BIT		5
+#define UTMI_PHYIF_16_BIT		1
+#define UTMI_PHYIF_8_BIT		0
+
+#define DWC3_GUSB2PHYCFG_TOUCAL		0x7
+
+/* Global USB2 PHY Vendor Control Register */
+#define DWC3_GUSB2PHYACC_NEWREGREQ	BIT(25)
+#define DWC3_GUSB2PHYACC_DONE		BIT(24)
+#define DWC3_GUSB2PHYACC_BUSY		BIT(23)
+#define DWC3_GUSB2PHYACC_WRITE		BIT(22)
+#define DWC3_GUSB2PHYACC_ADDR(n)	(n << 16)
+#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n)	(n << 8)
+#define DWC3_GUSB2PHYACC_DATA(n)	(n & 0xff)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST	BIT(31)
+#define DWC3_GUSB3PIPECTL_U2SSINP3OK	BIT(29)
+#define DWC3_GUSB3PIPECTL_DISRXDETINP3	BIT(28)
+#define DWC3_GUSB3PIPECTL_UX_EXIT_PX	BIT(27)
+#define DWC3_GUSB3PIPECTL_REQP1P2P3	BIT(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	BIT(18)
+#define DWC3_GUSB3PIPECTL_SUSPHY	BIT(17)
+#define DWC3_GUSB3PIPECTL_LFPSFILT	BIT(9)
+#define DWC3_GUSB3PIPECTL_RX_DETOPOLL	BIT(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 DWC31_GTXFIFOSIZ_TXFRAMNUM	BIT(15)		/* DWC_usb31 only */
+#define DWC31_GTXFIFOSIZ_TXFDEF(n)	((n) & 0x7fff)	/* DWC_usb31 only */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
+
+/* Global RX Fifo Size Register */
+#define DWC31_GRXFIFOSIZ_RXFDEP(n)	((n) & 0x7fff)	/* DWC_usb31 only */
+#define DWC3_GRXFIFOSIZ_RXFDEP(n)	((n) & 0xffff)
+
+/* Global Event Size Registers */
+#define DWC3_GEVNTSIZ_INTMASK		BIT(31)
+#define DWC3_GEVNTSIZ_SIZE(n)		((n) & 0xffff)
+
+/* Global HWPARAMS0 Register */
+#define DWC3_GHWPARAMS0_MODE(n)		((n) & 0x3)
+#define DWC3_GHWPARAMS0_MODE_GADGET	0
+#define DWC3_GHWPARAMS0_MODE_HOST	1
+#define DWC3_GHWPARAMS0_MODE_DRD	2
+#define DWC3_GHWPARAMS0_MBUS_TYPE(n)	(((n) >> 3) & 0x7)
+#define DWC3_GHWPARAMS0_SBUS_TYPE(n)	(((n) >> 6) & 0x3)
+#define DWC3_GHWPARAMS0_MDWIDTH(n)	(((n) >> 8) & 0xff)
+#define DWC3_GHWPARAMS0_SDWIDTH(n)	(((n) >> 16) & 0xff)
+#define DWC3_GHWPARAMS0_AWIDTH(n)	(((n) >> 24) & 0xff)
+
+/* 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)
+#define DWC3_GHWPARAMS1_ENDBC		BIT(31)
+
+/* Global HWPARAMS3 Register */
+#define DWC3_GHWPARAMS3_SSPHY_IFC(n)		((n) & 3)
+#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN1		1
+#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN2		2 /* DWC_usb31 only */
+#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_BCSUPPORT		BIT(14)
+#define DWC3_GHWPARAMS6_OTG3SUPPORT		BIT(13)
+#define DWC3_GHWPARAMS6_ADPSUPPORT		BIT(12)
+#define DWC3_GHWPARAMS6_HNPSUPPORT		BIT(11)
+#define DWC3_GHWPARAMS6_SRPSUPPORT		BIT(10)
+#define DWC3_GHWPARAMS6_EN_FPGA			BIT(7)
+
+/* Global HWPARAMS7 Register */
+#define DWC3_GHWPARAMS7_RAM1_DEPTH(n)	((n) & 0xffff)
+#define DWC3_GHWPARAMS7_RAM2_DEPTH(n)	(((n) >> 16) & 0xffff)
+
+/* Global Frame Length Adjustment Register */
+#define DWC3_GFLADJ_30MHZ_SDBND_SEL		BIT(7)
+#define DWC3_GFLADJ_30MHZ_MASK			0x3f
+
+/* Global User Control Register 2 */
+#define DWC3_GUCTL2_RST_ACTBITLATER		BIT(14)
+
+/* Global User Control Register 3 */
+#define DWC3_GUCTL3_SPLITDISABLE		BIT(14)
+
+/* 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_PLUS (5 << 0)  /* DWC_usb31 only */
+#define DWC3_DCFG_SUPERSPEED	(4 << 0)
+#define DWC3_DCFG_HIGHSPEED	(0 << 0)
+#define DWC3_DCFG_FULLSPEED	BIT(0)
+#define DWC3_DCFG_LOWSPEED	(2 << 0)
+
+#define DWC3_DCFG_NUMP_SHIFT	17
+#define DWC3_DCFG_NUMP(n)	(((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
+#define DWC3_DCFG_NUMP_MASK	(0x1f << DWC3_DCFG_NUMP_SHIFT)
+#define DWC3_DCFG_LPM_CAP	BIT(22)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP	BIT(31)
+#define DWC3_DCTL_CSFTRST	BIT(30)
+#define DWC3_DCTL_LSFTRST	BIT(29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n)	((n) << 24)
+
+#define DWC3_DCTL_APPL1RES	BIT(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_NYET_THRES(n)		(((n) & 0xf) << 20)
+
+#define DWC3_DCTL_KEEP_CONNECT		BIT(19)
+#define DWC3_DCTL_L1_HIBER_EN		BIT(18)
+#define DWC3_DCTL_CRS			BIT(17)
+#define DWC3_DCTL_CSS			BIT(16)
+
+#define DWC3_DCTL_INITU2ENA		BIT(12)
+#define DWC3_DCTL_ACCEPTU2ENA		BIT(11)
+#define DWC3_DCTL_INITU1ENA		BIT(10)
+#define DWC3_DCTL_ACCEPTU1ENA		BIT(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	BIT(12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN	BIT(11)
+#define DWC3_DEVTEN_CMDCMPLTEN		BIT(10)
+#define DWC3_DEVTEN_ERRTICERREN		BIT(9)
+#define DWC3_DEVTEN_SOFEN		BIT(7)
+#define DWC3_DEVTEN_EOPFEN		BIT(6)
+#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	BIT(5)
+#define DWC3_DEVTEN_WKUPEVTEN		BIT(4)
+#define DWC3_DEVTEN_ULSTCNGEN		BIT(3)
+#define DWC3_DEVTEN_CONNECTDONEEN	BIT(2)
+#define DWC3_DEVTEN_USBRSTEN		BIT(1)
+#define DWC3_DEVTEN_DISCONNEVTEN	BIT(0)
+
+/* Device Status Register */
+#define DWC3_DSTS_DCNRD			BIT(29)
+
+/* This applies for core versions 1.87a and earlier */
+#define DWC3_DSTS_PWRUPREQ		BIT(24)
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DSTS_RSS			BIT(25)
+#define DWC3_DSTS_SSS			BIT(24)
+
+#define DWC3_DSTS_COREIDLE		BIT(23)
+#define DWC3_DSTS_DEVCTRLHLT		BIT(22)
+
+#define DWC3_DSTS_USBLNKST_MASK		(0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n)		(((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY		BIT(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_PLUS	(5 << 0) /* DWC_usb31 only */
+#define DWC3_DSTS_SUPERSPEED		(4 << 0)
+#define DWC3_DSTS_HIGHSPEED		(0 << 0)
+#define DWC3_DSTS_FULLSPEED		BIT(0)
+#define DWC3_DSTS_LOWSPEED		(2 << 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) >> 12) & 0x0F)
+#define DWC3_DGCMD_CMDACT		BIT(10)
+#define DWC3_DGCMD_CMDIOC		BIT(8)
+
+/* Device Generic Command Parameter Register */
+#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT	BIT(0)
+#define DWC3_DGCMDPAR_FIFO_NUM(n)		((n) << 0)
+#define DWC3_DGCMDPAR_RX_FIFO			(0 << 5)
+#define DWC3_DGCMDPAR_TX_FIFO			BIT(5)
+#define DWC3_DGCMDPAR_LOOPBACK_DIS		(0 << 0)
+#define DWC3_DGCMDPAR_LOOPBACK_ENA		BIT(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) >> 12) & 0x0F)
+#define DWC3_DEPCMD_HIPRI_FORCERM	BIT(11)
+#define DWC3_DEPCMD_CLEARPENDIN		BIT(11)
+#define DWC3_DEPCMD_CMDACT		BIT(10)
+#define DWC3_DEPCMD_CMDIOC		BIT(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)
+
+#define DWC3_DEPCMD_CMD(x)		((x) & 0xf)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n)		BIT(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
+
+#define DWC3_DEV_IMOD_COUNT_SHIFT	16
+#define DWC3_DEV_IMOD_COUNT_MASK	(0xffff << 16)
+#define DWC3_DEV_IMOD_INTERVAL_SHIFT	0
+#define DWC3_DEV_IMOD_INTERVAL_MASK	(0xffff << 0)
+
+/* OTG Configuration Register */
+#define DWC3_OCFG_DISPWRCUTTOFF		BIT(5)
+#define DWC3_OCFG_HIBDISMASK		BIT(4)
+#define DWC3_OCFG_SFTRSTMASK		BIT(3)
+#define DWC3_OCFG_OTGVERSION		BIT(2)
+#define DWC3_OCFG_HNPCAP		BIT(1)
+#define DWC3_OCFG_SRPCAP		BIT(0)
+
+/* OTG CTL Register */
+#define DWC3_OCTL_OTG3GOERR		BIT(7)
+#define DWC3_OCTL_PERIMODE		BIT(6)
+#define DWC3_OCTL_PRTPWRCTL		BIT(5)
+#define DWC3_OCTL_HNPREQ		BIT(4)
+#define DWC3_OCTL_SESREQ		BIT(3)
+#define DWC3_OCTL_TERMSELIDPULSE	BIT(2)
+#define DWC3_OCTL_DEVSETHNPEN		BIT(1)
+#define DWC3_OCTL_HSTSETHNPEN		BIT(0)
+
+/* OTG Event Register */
+#define DWC3_OEVT_DEVICEMODE		BIT(31)
+#define DWC3_OEVT_XHCIRUNSTPSET		BIT(27)
+#define DWC3_OEVT_DEVRUNSTPSET		BIT(26)
+#define DWC3_OEVT_HIBENTRY		BIT(25)
+#define DWC3_OEVT_CONIDSTSCHNG		BIT(24)
+#define DWC3_OEVT_HRRCONFNOTIF		BIT(23)
+#define DWC3_OEVT_HRRINITNOTIF		BIT(22)
+#define DWC3_OEVT_ADEVIDLE		BIT(21)
+#define DWC3_OEVT_ADEVBHOSTEND		BIT(20)
+#define DWC3_OEVT_ADEVHOST		BIT(19)
+#define DWC3_OEVT_ADEVHNPCHNG		BIT(18)
+#define DWC3_OEVT_ADEVSRPDET		BIT(17)
+#define DWC3_OEVT_ADEVSESSENDDET	BIT(16)
+#define DWC3_OEVT_BDEVBHOSTEND		BIT(11)
+#define DWC3_OEVT_BDEVHNPCHNG		BIT(10)
+#define DWC3_OEVT_BDEVSESSVLDDET	BIT(9)
+#define DWC3_OEVT_BDEVVBUSCHNG		BIT(8)
+#define DWC3_OEVT_BSESSVLD		BIT(3)
+#define DWC3_OEVT_HSTNEGSTS		BIT(2)
+#define DWC3_OEVT_SESREQSTS		BIT(1)
+#define DWC3_OEVT_ERROR			BIT(0)
+
+/* OTG Event Enable Register */
+#define DWC3_OEVTEN_XHCIRUNSTPSETEN	BIT(27)
+#define DWC3_OEVTEN_DEVRUNSTPSETEN	BIT(26)
+#define DWC3_OEVTEN_HIBENTRYEN		BIT(25)
+#define DWC3_OEVTEN_CONIDSTSCHNGEN	BIT(24)
+#define DWC3_OEVTEN_HRRCONFNOTIFEN	BIT(23)
+#define DWC3_OEVTEN_HRRINITNOTIFEN	BIT(22)
+#define DWC3_OEVTEN_ADEVIDLEEN		BIT(21)
+#define DWC3_OEVTEN_ADEVBHOSTENDEN	BIT(20)
+#define DWC3_OEVTEN_ADEVHOSTEN		BIT(19)
+#define DWC3_OEVTEN_ADEVHNPCHNGEN	BIT(18)
+#define DWC3_OEVTEN_ADEVSRPDETEN	BIT(17)
+#define DWC3_OEVTEN_ADEVSESSENDDETEN	BIT(16)
+#define DWC3_OEVTEN_BDEVBHOSTENDEN	BIT(11)
+#define DWC3_OEVTEN_BDEVHNPCHNGEN	BIT(10)
+#define DWC3_OEVTEN_BDEVSESSVLDDETEN	BIT(9)
+#define DWC3_OEVTEN_BDEVVBUSCHNGEN	BIT(8)
+
+/* OTG Status Register */
+#define DWC3_OSTS_DEVRUNSTP		BIT(13)
+#define DWC3_OSTS_XHCIRUNSTP		BIT(12)
+#define DWC3_OSTS_PERIPHERALSTATE	BIT(4)
+#define DWC3_OSTS_XHCIPRTPOWER		BIT(3)
+#define DWC3_OSTS_BSESVLD		BIT(2)
+#define DWC3_OSTS_VBUSVLD		BIT(1)
+#define DWC3_OSTS_CONIDSTS		BIT(0)
+
+/* Structures */
+
+struct dwc3_trb;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @buf: _THE_ buffer
+ * @cache: The buffer cache used in the threaded interrupt
+ * @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;
+	void			*cache;
+	unsigned		length;
+	unsigned int		lpos;
+	unsigned int		count;
+	unsigned int		flags;
+
+#define DWC3_EVENT_PENDING	BIT(0)
+
+	dma_addr_t		dma;
+
+	struct dwc3		*dwc;
+
+	ANDROID_KABI_RESERVE(1);
+};
+
+#define DWC3_EP_FLAG_STALLED	BIT(0)
+#define DWC3_EP_FLAG_WEDGED	BIT(1)
+
+#define DWC3_EP_DIRECTION_TX	true
+#define DWC3_EP_DIRECTION_RX	false
+
+#define DWC3_TRB_NUM		256
+
+#define ASR1901_DWC3_EP2_TRB_NUM	2048
+#define ASR1901_DWC3_EP3_TRB_NUM	1024
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @cancelled_list: list of cancelled requests for this endpoint
+ * @pending_list: list of pending requests for this endpoint
+ * @started_list: list of started requests on this endpoint
+ * @regs: pointer to first endpoint register
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @trb_enqueue: enqueue 'pointer' into TRB array
+ * @trb_dequeue: dequeue 'pointer' into TRB array
+ * @dwc: pointer to DWC controller
+ * @saved_state: ep state saved during hibernation
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @resource_index: Resource transfer index
+ * @frame_number: set to the frame number we want this transfer to start (ISOC)
+ * @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
+ * @combo_num: the test combination BIT[15:14] of the frame number to test
+ *		isochronous START TRANSFER command failure workaround
+ * @start_cmd_status: the status of testing START TRANSFER command with
+ *		combo_num = 'b00
+ */
+struct dwc3_ep {
+	struct usb_ep		endpoint;
+	struct list_head	cancelled_list;
+	struct list_head	pending_list;
+	struct list_head	started_list;
+
+	void __iomem		*regs;
+
+	struct dwc3_trb		*trb_pool;
+	dma_addr_t		trb_pool_dma;
+	u32			trb_num;
+	struct dwc3		*dwc;
+
+	u32			saved_state;
+	unsigned		flags;
+#define DWC3_EP_ENABLED		BIT(0)
+#define DWC3_EP_STALL		BIT(1)
+#define DWC3_EP_WEDGE		BIT(2)
+#define DWC3_EP_TRANSFER_STARTED BIT(3)
+#define DWC3_EP_END_TRANSFER_PENDING BIT(4)
+#define DWC3_EP_PENDING_REQUEST	BIT(5)
+#define DWC3_EP_DELAY_START	BIT(6)
+#define DWC3_EP_PENDING_CLEAR_STALL	BIT(11)
+
+#define DWC3_EP_STALL_IN_PROGRESS	BIT(20)
+
+	/* This last one is specific to EP0 */
+#define DWC3_EP0_DIR_IN		BIT(31)
+
+	/*
+	 * IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
+	 * use a u8 type here. If anybody decides to increase number of TRBs to
+	 * anything larger than 256 - I can't see why people would want to do
+	 * this though - then this type needs to be changed.
+	 *
+	 * By using u8 types we ensure that our % operator when incrementing
+	 * enqueue and dequeue get optimized away by the compiler.
+	 */
+	u16			trb_enqueue;
+	u16			trb_dequeue;
+
+	u8			number;
+	u8			type;
+	u8			resource_index;
+	u32			frame_number;
+	u32			interval;
+
+	char			name[20];
+
+	unsigned		direction:1;
+	unsigned		stream_capable:1;
+
+	/* For isochronous START TRANSFER workaround only */
+	u8			combo_num;
+	int			start_cmd_status;
+	unsigned		num_reqs;
+	unsigned		num_cmds;
+
+	ANDROID_KABI_RESERVE(1);
+	ANDROID_KABI_RESERVE(2);
+};
+
+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		BIT(0)
+#define DWC3_TRB_CTRL_LST		BIT(1)
+#define DWC3_TRB_CTRL_CHN		BIT(2)
+#define DWC3_TRB_CTRL_CSP		BIT(3)
+#define DWC3_TRB_CTRL_TRBCTL(n)		(((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI		BIT(10)
+#define DWC3_TRB_CTRL_IOC		BIT(11)
+#define DWC3_TRB_CTRL_SID_SOFN(n)	(((n) & 0xffff) << 14)
+#define DWC3_TRB_CTRL_GET_SID_SOFN(n)	(((n) & (0xffff << 14)) >> 14)
+
+#define DWC3_TRBCTL_TYPE(n)		((n) & (0x3f << 4))
+#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
+ * @ctrl: DWC-F
+ */
+struct dwc3_trb {
+	u32		bpl;
+	u32		bph;
+	u32		size;
+	u32		ctrl;
+} __packed;
+
+/**
+ * struct 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;
+
+	ANDROID_KABI_RESERVE(1);
+	ANDROID_KABI_RESERVE(2);
+};
+
+/* 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 - representation of a transfer request
+ * @request: struct usb_request to be transferred
+ * @list: a list_head used for request queueing
+ * @dep: struct dwc3_ep owning this request
+ * @sg: pointer to first incomplete sg
+ * @start_sg: pointer to the sg which should be queued next
+ * @num_pending_sgs: counter to pending sgs
+ * @num_queued_sgs: counter to the number of sgs which already got queued
+ * @remaining: amount of data remaining
+ * @status: internal dwc3 request status tracking
+ * @epnum: endpoint number to which this request refers
+ * @trb: pointer to struct dwc3_trb
+ * @trb_dma: DMA address of @trb
+ * @num_trbs: number of TRBs used by this request
+ * @needs_extra_trb: true when request needs one extra TRB (either due to ZLP
+ *	or unaligned OUT)
+ * @direction: IN or OUT direction flag
+ * @mapped: true when request has been dma-mapped
+ */
+struct dwc3_request {
+	struct usb_request	request;
+	struct list_head	list;
+	struct dwc3_ep		*dep;
+	struct scatterlist	*sg;
+	struct scatterlist	*start_sg;
+
+	unsigned		num_pending_sgs;
+	unsigned int		num_queued_sgs;
+	unsigned		remaining;
+
+	unsigned int		status;
+#define DWC3_REQUEST_STATUS_QUEUED	0
+#define DWC3_REQUEST_STATUS_STARTED	1
+#define DWC3_REQUEST_STATUS_CANCELLED	2
+#define DWC3_REQUEST_STATUS_COMPLETED	3
+#define DWC3_REQUEST_STATUS_UNKNOWN	-1
+
+	u8			epnum;
+	struct dwc3_trb		*trb;
+	dma_addr_t		trb_dma;
+
+	unsigned		num_trbs;
+
+	unsigned		needs_extra_trb:1;
+	unsigned		direction:1;
+	unsigned		mapped:1;
+
+	//ANDROID_KABI_RESERVE(1);
+	//ANDROID_KABI_RESERVE(2);
+};
+
+/*
+ * 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
+ * @drd_work: workqueue used for role swapping
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @bounce: address of bounce buffer
+ * @scratchbuf: address of scratch buffer
+ * @setup_buf: used while precessing STD USB requests
+ * @ep0_trb_addr: dma address of @ep0_trb
+ * @bounce_addr: dma address of @bounce
+ * @ep0_usb_req: dummy req used while handling STD USB requests
+ * @scratch_addr: dma address of scratchbuf
+ * @ep0_in_setup: one control transfer is completed and enter setup phase
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @sysdev: pointer to the DMA-capable device
+ * @xhci: pointer to our xHCI child
+ * @xhci_resources: struct resources for our @xhci child
+ * @ev_buf: struct dwc3_event_buffer pointer
+ * @eps: endpoint array
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @clks: array of clocks
+ * @num_clks: number of clocks
+ * @reset: reset control
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @fladj: frame length adjustment
+ * @irq_gadget: peripheral controller's IRQ number
+ * @otg_irq: IRQ number for OTG IRQs
+ * @current_otg_role: current role of operation while using the OTG block
+ * @desired_otg_role: desired role of operation while using the OTG block
+ * @otg_restart_host: flag that OTG controller needs to restart host
+ * @nr_scratch: number of scratch buffers
+ * @u1u2: only used on revisions <1.83a for workaround
+ * @maximum_speed: maximum speed requested (mainly for testing purposes)
+ * @revision: revision register contents
+ * @version_type: VERSIONTYPE register contents, a sub release of a revision
+ * @dr_mode: requested mode of operation
+ * @current_dr_role: current role of operation when in dual-role mode
+ * @desired_dr_role: desired role of operation when in dual-role mode
+ * @edev: extcon handle
+ * @edev_nb: extcon notifier
+ * @hsphy_mode: UTMI phy mode, one of following:
+ *		- USBPHY_INTERFACE_MODE_UTMI
+ *		- USBPHY_INTERFACE_MODE_UTMIW
+ * @role_sw: usb_role_switch handle
+ * @role_switch_default_mode: default operation mode of controller while
+ *			usb role is USB_ROLE_NONE.
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
+ * @usb2_generic_phy: pointer to USB2 PHY
+ * @usb3_generic_phy: pointer to USB3 PHY
+ * @phys_ready: flag to indicate that PHYs are ready
+ * @ulpi: pointer to ulpi interface
+ * @ulpi_ready: flag to indicate that ULPI is initialized
+ * @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_eps: number of 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)
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ * @regset: debugfs pointer to regdump file
+ * @dbg_lsp_select: current debug lsp mux register selection
+ * @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
+ * @rx_thr_num_pkt_prd: periodic ESS receive packet count
+ * @rx_max_burst_prd: max periodic ESS receive burst size
+ * @tx_thr_num_pkt_prd: periodic ESS transmit packet count
+ * @tx_max_burst_prd: max periodic ESS transmit burst size
+ * @hsphy_interface: "utmi" or "ulpi"
+ * @connected: true when we're connected to a host, false otherwise
+ * @softconnect: true when gadget connect is called, false when disconnect runs
+ * @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
+ * @sysdev_is_parent: true when dwc3 device has a parent driver
+ * @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_fpga: true when we are using the FPGA board
+ * @pending_events: true when we have pending IRQs to be handled
+ * @pullups_connected: true when Run/Stop bit is set
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @three_stage_setup: set if we perform a three phase setup
+ * @dis_start_transfer_quirk: set if start_transfer failure SW workaround is
+ *			not needed for DWC_usb31 version 1.70a-ea06 and below
+ * @usb3_lpm_capable: set if hadrware supports Link Power Management
+ * @usb2_lpm_disable: set to disable usb2 lpm
+ * @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
+ * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
+ *                      disabling the suspend signal to the PHY.
+ * @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled.
+ * @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled.
+ * @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
+ * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
+ *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
+ *			provide a free-running PHY clock.
+ * @dis_del_phy_power_chg_quirk: set if we disable delay phy power
+ *			change quirk.
+ * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
+ *			check during HS transmit.
+ * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
+ *			instances in park mode.
+ * @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
+ * @dis_metastability_quirk: set to disable metastability quirk.
+ * @dis_split_quirk: set to disable split boundary.
+ * @imod_interval: set the interrupt moderation interval in 250ns
+ *                 increments or 0 to disable.
+ */
+struct dwc3 {
+	struct work_struct	drd_work;
+	struct usb_ctrlrequest	*ctrl_req;
+	struct dwc3_trb		*ep0_trb;
+	void			*bounce;
+	void			*scratchbuf;
+	u8			*setup_buf;
+	dma_addr_t		ctrl_req_addr;	
+	dma_addr_t		ep0_trb_addr;
+	dma_addr_t		bounce_addr;
+	dma_addr_t		scratch_addr;
+	struct dwc3_request	ep0_usb_req;
+	struct completion	ep0_in_setup;
+
+	/* device lock */
+	spinlock_t		lock;
+
+	struct device		*dev;
+	struct device		*sysdev;
+
+	struct platform_device	*xhci;
+	struct resource		xhci_resources[DWC3_XHCI_RESOURCES_NUM];
+
+	struct dwc3_event_buffer *ev_buf;
+	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
+
+	struct usb_gadget	gadget;
+	struct usb_gadget_driver *gadget_driver;
+
+	struct clk_bulk_data	*clks;
+	int			num_clks;
+
+	struct reset_control	*reset;
+
+	struct usb_phy		*usb2_phy;
+	struct usb_phy		*usb3_phy;
+
+	struct phy		*usb2_generic_phy;
+	struct phy		*usb3_generic_phy;
+
+	bool			phys_ready;
+
+	struct ulpi		*ulpi;
+	bool			ulpi_ready;
+
+	void __iomem		*regs;
+	size_t			regs_size;
+	void __iomem		*hwsulog_regs;
+
+	enum usb_dr_mode	dr_mode;
+	u32			current_dr_role;
+	u32			desired_dr_role;
+	struct extcon_dev	*edev;
+	struct notifier_block	edev_nb;
+	enum usb_phy_interface	hsphy_mode;
+	struct usb_role_switch	*role_sw;
+	enum usb_dr_mode	role_switch_default_mode;
+
+	u32			fladj;
+	u32			irq_gadget;
+	u32			otg_irq;
+	u32			current_otg_role;
+	u32			desired_otg_role;
+	bool			otg_restart_host;
+	u32			nr_scratch;
+	u32			u1u2;
+	u32			maximum_speed;
+
+	/*
+	 * All 3.1 IP version constants are greater than the 3.0 IP
+	 * version constants. This works for most version checks in
+	 * dwc3. However, in the future, this may not apply as
+	 * features may be developed on newer versions of the 3.0 IP
+	 * that are not in the 3.1 IP.
+	 */
+	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
+#define DWC3_REVISION_300A	0x5533300a
+#define DWC3_REVISION_310A	0x5533310a
+#define DWC3_REVISION_330A	0x5533330a
+
+/*
+ * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
+ * just so dwc31 revisions are always larger than dwc3.
+ */
+#define DWC3_REVISION_IS_DWC31		0x80000000
+#define DWC3_USB31_REVISION_110A	(0x3131302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_120A	(0x3132302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_160A	(0x3136302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_170A	(0x3137302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_180A	(0x3138302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_190A	(0x3139302a | DWC3_REVISION_IS_DWC31)
+
+	u32			version_type;
+
+#define DWC31_VERSIONTYPE_EA01		0x65613031
+#define DWC31_VERSIONTYPE_EA02		0x65613032
+#define DWC31_VERSIONTYPE_EA03		0x65613033
+#define DWC31_VERSIONTYPE_EA04		0x65613034
+#define DWC31_VERSIONTYPE_EA05		0x65613035
+#define DWC31_VERSIONTYPE_EA06		0x65613036
+
+	enum dwc3_ep0_next	ep0_next_event;
+	enum dwc3_ep0_state	ep0state;
+	enum dwc3_link_state	link_state;
+
+	u16			u2sel;
+	u16			u2pel;
+	u8			u1sel;
+	u8			u1pel;
+
+	u8			speed;
+
+	u8			num_eps;
+
+	struct dwc3_hwparams	hwparams;
+	struct dentry		*root;
+	struct debugfs_regset32	*regset;
+
+	u32			dbg_lsp_select;
+
+	u8			test_mode;
+	u8			test_mode_nr;
+	u8			lpm_nyet_threshold;
+	u8			hird_threshold;
+	u8			rx_thr_num_pkt_prd;
+	u8			rx_max_burst_prd;
+	u8			tx_thr_num_pkt_prd;
+	u8			tx_max_burst_prd;
+
+	const char		*hsphy_interface;
+
+	unsigned		connected:1;
+	/* unsigned		softconnect:1; */
+	unsigned		delayed_status:1;
+	unsigned		ep0_bounced:1;
+	unsigned		ep0_expect_in:1;
+	unsigned		has_hibernation:1;
+	unsigned		sysdev_is_parent:1;
+	unsigned		has_lpm_erratum:1;
+	unsigned		is_utmi_l1_suspend:1;
+	unsigned		is_fpga:1;
+	unsigned		pending_events:1;
+	unsigned		pullups_connected:1;
+	unsigned		setup_packet_pending:1;
+	unsigned		three_stage_setup:1;
+	unsigned		dis_start_transfer_quirk:1;
+	unsigned		usb3_lpm_capable:1;
+	unsigned		usb2_lpm_disable: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_enblslpm_quirk:1;
+	unsigned		dis_u1_entry_quirk:1;
+	unsigned		dis_u2_entry_quirk:1;
+	unsigned		dis_rxdet_inp3_quirk:1;
+	unsigned		dis_u2_freeclk_exists_quirk:1;
+	unsigned		dis_del_phy_power_chg_quirk:1;
+	unsigned		dis_tx_ipgap_linecheck_quirk:1;
+	unsigned		parkmode_disable_ss_quirk:1;
+
+	unsigned		tx_de_emphasis_quirk:1;
+	unsigned		tx_de_emphasis:2;
+
+	unsigned		dis_metastability_quirk:1;
+
+	unsigned		dis_split_quirk:1;
+
+	unsigned		allow_suspend:1;
+	unsigned		no_acchg_det:1;
+
+	u16			imod_interval;
+
+	struct work_struct	vbus_work;
+	struct workqueue_struct *qwork;
+	struct notifier_block notifier;
+	unsigned int		softconnect;
+	unsigned int		vbus_active;
+	unsigned int            active;
+	struct pm_qos_request   qos_idle;
+	s32                     lpm_qos;
+
+	unsigned int		prev_charger_type;
+	unsigned int		charger_type;
+	struct delayed_work     delayed_charger_work;
+	bool bus_reset_received;
+	bool suspend_received;
+
+	struct delayed_work usb_restart_work;
+	u32 usb_do_restart;
+
+	int			otg_state;
+	unsigned long		phys_mem_end;
+
+	ANDROID_KABI_RESERVE(1);
+	ANDROID_KABI_RESERVE(2);
+	ANDROID_KABI_RESERVE(3);
+	ANDROID_KABI_RESERVE(4);
+};
+
+#define INCRX_BURST_MODE 0
+#define INCRX_UNDEF_LENGTH_BURST_MODE 1
+
+#define work_to_dwc(w)		(container_of((w), struct dwc3, drd_work))
+
+/* -------------------------------------------------------------------------- */
+
+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
+
+/**
+ * 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	BIT(3)
+
+/* Within XferComplete or XferInProgress */
+#define DEPEVT_STATUS_BUSERR	BIT(0)
+#define DEPEVT_STATUS_SHORT	BIT(1)
+#define DEPEVT_STATUS_IOC	BIT(2)
+#define DEPEVT_STATUS_LST	BIT(3) /* XferComplete */
+#define DEPEVT_STATUS_MISSED_ISOC BIT(3) /* XferInProgress */
+
+/* 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
+#define DEPEVT_STATUS_CONTROL_PHASE(n)	((n) & 3)
+
+/* In response to Start Transfer */
+#define DEPEVT_TRANSFER_NO_RESOURCE	1
+#define DEPEVT_TRANSFER_BUS_EXPIRY	2
+
+	u32	parameters:16;
+
+/* For Command Complete Events */
+#define DEPEVT_PARAMETER_CMD(n)	(((n) & (0xf << 8)) >> 8)
+} __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 */
+void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
+void dwc3_report_sdp_charger(struct dwc3 *dwc);
+u32 dwc3_get_line_status(void);
+int hwsulog_error_handler(void);
+
+/* check whether we are on the DWC_usb3 core */
+static inline bool dwc3_is_usb3(struct dwc3 *dwc)
+{
+	return !(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
+/* check whether we are on the DWC_usb31 core */
+static inline bool dwc3_is_usb31(struct dwc3 *dwc)
+{
+	return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
+bool dwc3_has_imod(struct dwc3 *dwc);
+
+int dwc3_event_buffers_setup(struct dwc3 *dwc);
+void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
+
+int dwc3_core_soft_reset(struct dwc3 *dwc);
+
+#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_host_init(struct dwc3 *dwc);
+void dwc3_host_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_host_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_host_exit(struct dwc3 *dwc)
+{ }
+#endif
+
+#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+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_ep *dep, 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_ep *dep, 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
+
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_drd_init(struct dwc3 *dwc);
+void dwc3_drd_exit(struct dwc3 *dwc);
+void dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus);
+void dwc3_otg_host_init(struct dwc3 *dwc);
+#else
+static inline int dwc3_drd_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_drd_exit(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_init(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_exit(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
+{ }
+static inline void dwc3_otg_host_init(struct dwc3 *dwc)
+{ }
+#endif
+
+/* power management interface */
+#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+	return 0;
+}
+
+static inline int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+	return 0;
+}
+
+#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
+int dwc3_controller_reset(struct dwc3 *dwc);
+
+#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
+int dwc3_ulpi_init(struct dwc3 *dwc);
+void dwc3_ulpi_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_ulpi_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
+{ }
+#endif
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/marvell/linux/drivers/usb/dwc3/debug.h b/marvell/linux/drivers/usb/dwc3/debug.h
new file mode 100644
index 0000000..e105ddf
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/debug.h
@@ -0,0 +1,423 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#ifndef __DWC3_DEBUG_H
+#define __DWC3_DEBUG_H
+
+#include "core.h"
+
+/**
+ * dwc3_gadget_ep_cmd_string - returns endpoint command string
+ * @cmd: command code
+ */
+static inline const char *
+dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DEPCMD_DEPSTARTCFG:
+		return "Start New Configuration";
+	case DWC3_DEPCMD_ENDTRANSFER:
+		return "End Transfer";
+	case DWC3_DEPCMD_UPDATETRANSFER:
+		return "Update Transfer";
+	case DWC3_DEPCMD_STARTTRANSFER:
+		return "Start Transfer";
+	case DWC3_DEPCMD_CLEARSTALL:
+		return "Clear Stall";
+	case DWC3_DEPCMD_SETSTALL:
+		return "Set Stall";
+	case DWC3_DEPCMD_GETEPSTATE:
+		return "Get Endpoint State";
+	case DWC3_DEPCMD_SETTRANSFRESOURCE:
+		return "Set Endpoint Transfer Resource";
+	case DWC3_DEPCMD_SETEPCONFIG:
+		return "Set Endpoint Configuration";
+	default:
+		return "UNKNOWN command";
+	}
+}
+
+/**
+ * dwc3_gadget_generic_cmd_string - returns generic command string
+ * @cmd: command code
+ */
+static inline const char *
+dwc3_gadget_generic_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DGCMD_SET_LMP:
+		return "Set LMP";
+	case DWC3_DGCMD_SET_PERIODIC_PAR:
+		return "Set Periodic Parameters";
+	case DWC3_DGCMD_XMIT_FUNCTION:
+		return "Transmit Function Wake Device Notification";
+	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
+		return "Set Scratchpad Buffer Array Address Lo";
+	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
+		return "Set Scratchpad Buffer Array Address Hi";
+	case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
+		return "Selected FIFO Flush";
+	case DWC3_DGCMD_ALL_FIFO_FLUSH:
+		return "All FIFO Flush";
+	case DWC3_DGCMD_SET_ENDPOINT_NRDY:
+		return "Set Endpoint NRDY";
+	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
+		return "Run SoC Bus Loopback Test";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+/**
+ * dwc3_gadget_link_string - returns link name
+ * @link_state: link state code
+ */
+static inline const char *
+dwc3_gadget_link_string(enum dwc3_link_state link_state)
+{
+	switch (link_state) {
+	case DWC3_LINK_STATE_U0:
+		return "U0";
+	case DWC3_LINK_STATE_U1:
+		return "U1";
+	case DWC3_LINK_STATE_U2:
+		return "U2";
+	case DWC3_LINK_STATE_U3:
+		return "U3";
+	case DWC3_LINK_STATE_SS_DIS:
+		return "SS.Disabled";
+	case DWC3_LINK_STATE_RX_DET:
+		return "RX.Detect";
+	case DWC3_LINK_STATE_SS_INACT:
+		return "SS.Inactive";
+	case DWC3_LINK_STATE_POLL:
+		return "Polling";
+	case DWC3_LINK_STATE_RECOV:
+		return "Recovery";
+	case DWC3_LINK_STATE_HRESET:
+		return "Hot Reset";
+	case DWC3_LINK_STATE_CMPLY:
+		return "Compliance";
+	case DWC3_LINK_STATE_LPBK:
+		return "Loopback";
+	case DWC3_LINK_STATE_RESET:
+		return "Reset";
+	case DWC3_LINK_STATE_RESUME:
+		return "Resume";
+	default:
+		return "UNKNOWN link state\n";
+	}
+}
+
+/**
+ * dwc3_gadget_hs_link_string - returns highspeed and below link name
+ * @link_state: link state code
+ */
+static inline const char *
+dwc3_gadget_hs_link_string(enum dwc3_link_state link_state)
+{
+	switch (link_state) {
+	case DWC3_LINK_STATE_U0:
+		return "On";
+	case DWC3_LINK_STATE_U2:
+		return "Sleep";
+	case DWC3_LINK_STATE_U3:
+		return "Suspend";
+	case DWC3_LINK_STATE_SS_DIS:
+		return "Disconnected";
+	case DWC3_LINK_STATE_RX_DET:
+		return "Early Suspend";
+	case DWC3_LINK_STATE_RECOV:
+		return "Recovery";
+	case DWC3_LINK_STATE_RESET:
+		return "Reset";
+	case DWC3_LINK_STATE_RESUME:
+		return "Resume";
+	default:
+		return "UNKNOWN link state\n";
+	}
+}
+
+/**
+ * dwc3_trb_type_string - returns TRB type as a string
+ * @type: the type of the TRB
+ */
+static inline const char *dwc3_trb_type_string(unsigned int type)
+{
+	switch (type) {
+	case DWC3_TRBCTL_NORMAL:
+		return "normal";
+	case DWC3_TRBCTL_CONTROL_SETUP:
+		return "setup";
+	case DWC3_TRBCTL_CONTROL_STATUS2:
+		return "status2";
+	case DWC3_TRBCTL_CONTROL_STATUS3:
+		return "status3";
+	case DWC3_TRBCTL_CONTROL_DATA:
+		return "data";
+	case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
+		return "isoc-first";
+	case DWC3_TRBCTL_ISOCHRONOUS:
+		return "isoc";
+	case DWC3_TRBCTL_LINK_TRB:
+		return "link";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline 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";
+	}
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(char *str, size_t size,
+		const struct dwc3_event_devt *event)
+{
+	enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK;
+
+	switch (event->type) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		snprintf(str, size, "Disconnect: [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_RESET:
+		snprintf(str, size, "Reset [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		snprintf(str, size, "Connection Done [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		snprintf(str, size, "Link Change [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		snprintf(str, size, "WakeUp [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_EOPF:
+		snprintf(str, size, "End-Of-Frame [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_SOF:
+		snprintf(str, size, "Start-Of-Frame [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		snprintf(str, size, "Erratic Error [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		snprintf(str, size, "Command Complete [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		snprintf(str, size, "Overflow [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	default:
+		snprintf(str, size, "UNKNOWN");
+	}
+
+	return str;
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(char *str, size_t size,
+		const struct dwc3_event_depevt *event, u32 ep0state)
+{
+	u8 epnum = event->endpoint_number;
+	size_t len;
+	int status;
+
+	len = scnprintf(str, size, "ep%d%s: ", epnum >> 1,
+			(epnum & 1) ? "in" : "out");
+
+	status = event->status;
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		len += scnprintf(str + len, size - len,
+				"Transfer Complete (%c%c%c)",
+				status & DEPEVT_STATUS_SHORT ? 'S' : 's',
+				status & DEPEVT_STATUS_IOC ? 'I' : 'i',
+				status & DEPEVT_STATUS_LST ? 'L' : 'l');
+
+		if (epnum <= 1)
+			scnprintf(str + len, size - len, " [%s]",
+					dwc3_ep0_state_string(ep0state));
+		break;
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		scnprintf(str + len, size - len,
+				"Transfer In Progress [%d] (%c%c%c)",
+				event->parameters,
+				status & DEPEVT_STATUS_SHORT ? 'S' : 's',
+				status & DEPEVT_STATUS_IOC ? 'I' : 'i',
+				status & DEPEVT_STATUS_LST ? 'M' : 'm');
+		break;
+	case DWC3_DEPEVT_XFERNOTREADY:
+		len += scnprintf(str + len, size - len,
+				"Transfer Not Ready [%d]%s",
+				event->parameters,
+				status & DEPEVT_STATUS_TRANSFER_ACTIVE ?
+				" (Active)" : " (Not Active)");
+
+		/* Control Endpoints */
+		if (epnum <= 1) {
+			int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status);
+
+			switch (phase) {
+			case DEPEVT_STATUS_CONTROL_DATA:
+				scnprintf(str + len, size - len,
+						" [Data Phase]");
+				break;
+			case DEPEVT_STATUS_CONTROL_STATUS:
+				scnprintf(str + len, size - len,
+						" [Status Phase]");
+			}
+		}
+		break;
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		scnprintf(str + len, size - len, "FIFO");
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
+		status = event->status;
+
+		switch (status) {
+		case DEPEVT_STREAMEVT_FOUND:
+			scnprintf(str + len, size - len, " Stream %d Found",
+					event->parameters);
+			break;
+		case DEPEVT_STREAMEVT_NOTFOUND:
+		default:
+			scnprintf(str + len, size - len, " Stream Not Found");
+			break;
+		}
+
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		scnprintf(str + len, size - len, "Endpoint Command Complete");
+		break;
+	default:
+		scnprintf(str + len, size - len, "UNKNOWN");
+	}
+
+	return str;
+}
+
+/**
+ * dwc3_gadget_event_type_string - return event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_type_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		return "Disconnect";
+	case DWC3_DEVICE_EVENT_RESET:
+		return "Reset";
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		return "Connect Done";
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		return "Link Status Change";
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		return "Wake-Up";
+	case DWC3_DEVICE_EVENT_HIBER_REQ:
+		return "Hibernation";
+	case DWC3_DEVICE_EVENT_EOPF:
+		return "End of Periodic Frame";
+	case DWC3_DEVICE_EVENT_SOF:
+		return "Start of Frame";
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		return "Erratic Error";
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		return "Command Complete";
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		return "Overflow";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *dwc3_decode_event(char *str, size_t size, u32 event,
+		u32 ep0state)
+{
+	const union dwc3_event evt = (union dwc3_event) event;
+
+	if (evt.type.is_devspec)
+		return dwc3_gadget_event_string(str, size, &evt.devt);
+	else
+		return dwc3_ep_event_string(str, size, &evt.depevt, ep0state);
+}
+
+static inline const char *dwc3_ep_cmd_status_string(int status)
+{
+	switch (status) {
+	case -ETIMEDOUT:
+		return "Timed Out";
+	case 0:
+		return "Successful";
+	case DEPEVT_TRANSFER_NO_RESOURCE:
+		return "No Resource";
+	case DEPEVT_TRANSFER_BUS_EXPIRY:
+		return "Bus Expiry";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
+{
+	switch (status) {
+	case -ETIMEDOUT:
+		return "Timed Out";
+	case 0:
+		return "Successful";
+	case 1:
+		return "Error";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+extern void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep);
+extern void dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
+{  }
+static inline void dwc3_debugfs_init(struct dwc3 *d)
+{  }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{  }
+#endif
+#endif /* __DWC3_DEBUG_H */
diff --git a/marvell/linux/drivers/usb/dwc3/debugfs.c b/marvell/linux/drivers/usb/dwc3/debugfs.c
new file mode 100644
index 0000000..7fa4d4d
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/debugfs.c
@@ -0,0 +1,1069 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include <linux/usb/ch9.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+#include "debug.h"
+
+#define DWC3_LSP_MUX_UNSELECTED 0xfffff
+
+#define dump_register(nm)				\
+{							\
+	.name	= __stringify(nm),			\
+	.offset	= DWC3_ ##nm,				\
+}
+
+#define dump_ep_register_set(n)			\
+	{					\
+		.name = "DEPCMDPAR2("__stringify(n)")",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMDPAR2,	\
+	},					\
+	{					\
+		.name = "DEPCMDPAR1("__stringify(n)")",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMDPAR1,	\
+	},					\
+	{					\
+		.name = "DEPCMDPAR0("__stringify(n)")",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMDPAR0,	\
+	},					\
+	{					\
+		.name = "DEPCMD("__stringify(n)")",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMD,		\
+	}
+
+
+static const struct debugfs_reg32 dwc3_regs[] = {
+	dump_register(GSBUSCFG0),
+	dump_register(GSBUSCFG1),
+	dump_register(GTXTHRCFG),
+	dump_register(GRXTHRCFG),
+	dump_register(GCTL),
+	dump_register(GEVTEN),
+	dump_register(GSTS),
+	dump_register(GUCTL1),
+	dump_register(GSNPSID),
+	dump_register(GGPIO),
+	dump_register(GUID),
+	dump_register(GUCTL),
+	dump_register(GBUSERRADDR0),
+	dump_register(GBUSERRADDR1),
+	dump_register(GPRTBIMAP0),
+	dump_register(GPRTBIMAP1),
+	dump_register(GHWPARAMS0),
+	dump_register(GHWPARAMS1),
+	dump_register(GHWPARAMS2),
+	dump_register(GHWPARAMS3),
+	dump_register(GHWPARAMS4),
+	dump_register(GHWPARAMS5),
+	dump_register(GHWPARAMS6),
+	dump_register(GHWPARAMS7),
+	dump_register(GDBGFIFOSPACE),
+	dump_register(GDBGLTSSM),
+	dump_register(GDBGBMU),
+	dump_register(GPRTBIMAP_HS0),
+	dump_register(GPRTBIMAP_HS1),
+	dump_register(GPRTBIMAP_FS0),
+	dump_register(GPRTBIMAP_FS1),
+
+	dump_register(GUSB2PHYCFG(0)),
+	dump_register(GUSB2PHYCFG(1)),
+	dump_register(GUSB2PHYCFG(2)),
+	dump_register(GUSB2PHYCFG(3)),
+	dump_register(GUSB2PHYCFG(4)),
+	dump_register(GUSB2PHYCFG(5)),
+	dump_register(GUSB2PHYCFG(6)),
+	dump_register(GUSB2PHYCFG(7)),
+	dump_register(GUSB2PHYCFG(8)),
+	dump_register(GUSB2PHYCFG(9)),
+	dump_register(GUSB2PHYCFG(10)),
+	dump_register(GUSB2PHYCFG(11)),
+	dump_register(GUSB2PHYCFG(12)),
+	dump_register(GUSB2PHYCFG(13)),
+	dump_register(GUSB2PHYCFG(14)),
+	dump_register(GUSB2PHYCFG(15)),
+
+	dump_register(GUSB2I2CCTL(0)),
+	dump_register(GUSB2I2CCTL(1)),
+	dump_register(GUSB2I2CCTL(2)),
+	dump_register(GUSB2I2CCTL(3)),
+	dump_register(GUSB2I2CCTL(4)),
+	dump_register(GUSB2I2CCTL(5)),
+	dump_register(GUSB2I2CCTL(6)),
+	dump_register(GUSB2I2CCTL(7)),
+	dump_register(GUSB2I2CCTL(8)),
+	dump_register(GUSB2I2CCTL(9)),
+	dump_register(GUSB2I2CCTL(10)),
+	dump_register(GUSB2I2CCTL(11)),
+	dump_register(GUSB2I2CCTL(12)),
+	dump_register(GUSB2I2CCTL(13)),
+	dump_register(GUSB2I2CCTL(14)),
+	dump_register(GUSB2I2CCTL(15)),
+
+	dump_register(GUSB2PHYACC(0)),
+	dump_register(GUSB2PHYACC(1)),
+	dump_register(GUSB2PHYACC(2)),
+	dump_register(GUSB2PHYACC(3)),
+	dump_register(GUSB2PHYACC(4)),
+	dump_register(GUSB2PHYACC(5)),
+	dump_register(GUSB2PHYACC(6)),
+	dump_register(GUSB2PHYACC(7)),
+	dump_register(GUSB2PHYACC(8)),
+	dump_register(GUSB2PHYACC(9)),
+	dump_register(GUSB2PHYACC(10)),
+	dump_register(GUSB2PHYACC(11)),
+	dump_register(GUSB2PHYACC(12)),
+	dump_register(GUSB2PHYACC(13)),
+	dump_register(GUSB2PHYACC(14)),
+	dump_register(GUSB2PHYACC(15)),
+
+	dump_register(GUSB3PIPECTL(0)),
+	dump_register(GUSB3PIPECTL(1)),
+	dump_register(GUSB3PIPECTL(2)),
+	dump_register(GUSB3PIPECTL(3)),
+	dump_register(GUSB3PIPECTL(4)),
+	dump_register(GUSB3PIPECTL(5)),
+	dump_register(GUSB3PIPECTL(6)),
+	dump_register(GUSB3PIPECTL(7)),
+	dump_register(GUSB3PIPECTL(8)),
+	dump_register(GUSB3PIPECTL(9)),
+	dump_register(GUSB3PIPECTL(10)),
+	dump_register(GUSB3PIPECTL(11)),
+	dump_register(GUSB3PIPECTL(12)),
+	dump_register(GUSB3PIPECTL(13)),
+	dump_register(GUSB3PIPECTL(14)),
+	dump_register(GUSB3PIPECTL(15)),
+
+	dump_register(GTXFIFOSIZ(0)),
+	dump_register(GTXFIFOSIZ(1)),
+	dump_register(GTXFIFOSIZ(2)),
+	dump_register(GTXFIFOSIZ(3)),
+	dump_register(GTXFIFOSIZ(4)),
+	dump_register(GTXFIFOSIZ(5)),
+	dump_register(GTXFIFOSIZ(6)),
+	dump_register(GTXFIFOSIZ(7)),
+	dump_register(GTXFIFOSIZ(8)),
+	dump_register(GTXFIFOSIZ(9)),
+	dump_register(GTXFIFOSIZ(10)),
+	dump_register(GTXFIFOSIZ(11)),
+	dump_register(GTXFIFOSIZ(12)),
+	dump_register(GTXFIFOSIZ(13)),
+	dump_register(GTXFIFOSIZ(14)),
+	dump_register(GTXFIFOSIZ(15)),
+	dump_register(GTXFIFOSIZ(16)),
+	dump_register(GTXFIFOSIZ(17)),
+	dump_register(GTXFIFOSIZ(18)),
+	dump_register(GTXFIFOSIZ(19)),
+	dump_register(GTXFIFOSIZ(20)),
+	dump_register(GTXFIFOSIZ(21)),
+	dump_register(GTXFIFOSIZ(22)),
+	dump_register(GTXFIFOSIZ(23)),
+	dump_register(GTXFIFOSIZ(24)),
+	dump_register(GTXFIFOSIZ(25)),
+	dump_register(GTXFIFOSIZ(26)),
+	dump_register(GTXFIFOSIZ(27)),
+	dump_register(GTXFIFOSIZ(28)),
+	dump_register(GTXFIFOSIZ(29)),
+	dump_register(GTXFIFOSIZ(30)),
+	dump_register(GTXFIFOSIZ(31)),
+
+	dump_register(GRXFIFOSIZ(0)),
+	dump_register(GRXFIFOSIZ(1)),
+	dump_register(GRXFIFOSIZ(2)),
+	dump_register(GRXFIFOSIZ(3)),
+	dump_register(GRXFIFOSIZ(4)),
+	dump_register(GRXFIFOSIZ(5)),
+	dump_register(GRXFIFOSIZ(6)),
+	dump_register(GRXFIFOSIZ(7)),
+	dump_register(GRXFIFOSIZ(8)),
+	dump_register(GRXFIFOSIZ(9)),
+	dump_register(GRXFIFOSIZ(10)),
+	dump_register(GRXFIFOSIZ(11)),
+	dump_register(GRXFIFOSIZ(12)),
+	dump_register(GRXFIFOSIZ(13)),
+	dump_register(GRXFIFOSIZ(14)),
+	dump_register(GRXFIFOSIZ(15)),
+	dump_register(GRXFIFOSIZ(16)),
+	dump_register(GRXFIFOSIZ(17)),
+	dump_register(GRXFIFOSIZ(18)),
+	dump_register(GRXFIFOSIZ(19)),
+	dump_register(GRXFIFOSIZ(20)),
+	dump_register(GRXFIFOSIZ(21)),
+	dump_register(GRXFIFOSIZ(22)),
+	dump_register(GRXFIFOSIZ(23)),
+	dump_register(GRXFIFOSIZ(24)),
+	dump_register(GRXFIFOSIZ(25)),
+	dump_register(GRXFIFOSIZ(26)),
+	dump_register(GRXFIFOSIZ(27)),
+	dump_register(GRXFIFOSIZ(28)),
+	dump_register(GRXFIFOSIZ(29)),
+	dump_register(GRXFIFOSIZ(30)),
+	dump_register(GRXFIFOSIZ(31)),
+
+	dump_register(GEVNTADRLO(0)),
+	dump_register(GEVNTADRHI(0)),
+	dump_register(GEVNTSIZ(0)),
+	dump_register(GEVNTCOUNT(0)),
+
+	dump_register(GHWPARAMS8),
+	dump_register(DCFG),
+	dump_register(DCTL),
+	dump_register(DEVTEN),
+	dump_register(DSTS),
+	dump_register(DGCMDPAR),
+	dump_register(DGCMD),
+	dump_register(DALEPENA),
+
+	dump_ep_register_set(0),
+	dump_ep_register_set(1),
+	dump_ep_register_set(2),
+	dump_ep_register_set(3),
+	dump_ep_register_set(4),
+	dump_ep_register_set(5),
+	dump_ep_register_set(6),
+	dump_ep_register_set(7),
+	dump_ep_register_set(8),
+	dump_ep_register_set(9),
+	dump_ep_register_set(10),
+	dump_ep_register_set(11),
+	dump_ep_register_set(12),
+	dump_ep_register_set(13),
+	dump_ep_register_set(14),
+	dump_ep_register_set(15),
+	dump_ep_register_set(16),
+	dump_ep_register_set(17),
+	dump_ep_register_set(18),
+	dump_ep_register_set(19),
+	dump_ep_register_set(20),
+	dump_ep_register_set(21),
+	dump_ep_register_set(22),
+	dump_ep_register_set(23),
+	dump_ep_register_set(24),
+	dump_ep_register_set(25),
+	dump_ep_register_set(26),
+	dump_ep_register_set(27),
+	dump_ep_register_set(28),
+	dump_ep_register_set(29),
+	dump_ep_register_set(30),
+	dump_ep_register_set(31),
+
+	dump_register(OCFG),
+	dump_register(OCTL),
+	dump_register(OEVT),
+	dump_register(OEVTEN),
+	dump_register(OSTS),
+};
+
+static void dwc3_host_lsp(struct seq_file *s)
+{
+	struct dwc3		*dwc = s->private;
+	bool			dbc_enabled;
+	u32			sel;
+	u32			reg;
+	u32			val;
+
+	dbc_enabled = !!(dwc->hwparams.hwparams1 & DWC3_GHWPARAMS1_ENDBC);
+
+	sel = dwc->dbg_lsp_select;
+	if (sel == DWC3_LSP_MUX_UNSELECTED) {
+		seq_puts(s, "Write LSP selection to print for host\n");
+		return;
+	}
+
+	reg = DWC3_GDBGLSPMUX_HOSTSELECT(sel);
+
+	dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
+	val = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
+	seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", sel, val);
+
+	if (dbc_enabled && sel < 256) {
+		reg |= DWC3_GDBGLSPMUX_ENDBC;
+		dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
+		val = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
+		seq_printf(s, "GDBGLSP_DBC[%d] = 0x%08x\n", sel, val);
+	}
+}
+
+static void dwc3_gadget_lsp(struct seq_file *s)
+{
+	struct dwc3		*dwc = s->private;
+	int			i;
+	u32			reg;
+
+	for (i = 0; i < 16; i++) {
+		reg = DWC3_GDBGLSPMUX_DEVSELECT(i);
+		dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
+		reg = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
+		seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", i, reg);
+	}
+}
+
+static int dwc3_lsp_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned int		current_mode;
+	unsigned long		flags;
+	u32			reg;
+#if 0
+	int			ret;
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_GSTS);
+	current_mode = DWC3_GSTS_CURMOD(reg);
+
+	switch (current_mode) {
+	case DWC3_GSTS_CURMOD_HOST:
+		dwc3_host_lsp(s);
+		break;
+	case DWC3_GSTS_CURMOD_DEVICE:
+		dwc3_gadget_lsp(s);
+		break;
+	default:
+		seq_puts(s, "Mode is unknown, no LSP register printed\n");
+		break;
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+
+	return 0;
+}
+
+static int dwc3_lsp_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_lsp_show, inode->i_private);
+}
+
+static ssize_t dwc3_lsp_write(struct file *file, const char __user *ubuf,
+			      size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	char			buf[32] = { 0 };
+	u32			sel;
+	int			ret;
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	ret = kstrtouint(buf, 0, &sel);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc->dbg_lsp_select = sel;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return count;
+}
+
+static const struct file_operations dwc3_lsp_fops = {
+	.open			= dwc3_lsp_open,
+	.write			= dwc3_lsp_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_mode_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			reg;
+#if 0
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (DWC3_GCTL_PRTCAP(reg)) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		seq_printf(s, "host\n");
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		seq_printf(s, "device\n");
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		seq_printf(s, "otg\n");
+		break;
+	default:
+		seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
+	}
+
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+	return 0;
+}
+
+static int dwc3_mode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_mode_show, inode->i_private);
+}
+
+static ssize_t dwc3_mode_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	u32			mode = 0;
+	char			buf[32];
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "host", 4))
+		mode = DWC3_GCTL_PRTCAP_HOST;
+
+	if (!strncmp(buf, "device", 6))
+		mode = DWC3_GCTL_PRTCAP_DEVICE;
+
+	if (!strncmp(buf, "otg", 3))
+		mode = DWC3_GCTL_PRTCAP_OTG;
+
+	dwc3_set_mode(dwc, mode);
+
+	return count;
+}
+
+static const struct file_operations dwc3_mode_fops = {
+	.open			= dwc3_mode_open,
+	.write			= dwc3_mode_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_testmode_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			reg;
+#if 0
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= DWC3_DCTL_TSTCTRL_MASK;
+	reg >>= 1;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (reg) {
+	case 0:
+		seq_printf(s, "no test\n");
+		break;
+	case TEST_J:
+		seq_printf(s, "test_j\n");
+		break;
+	case TEST_K:
+		seq_printf(s, "test_k\n");
+		break;
+	case TEST_SE0_NAK:
+		seq_printf(s, "test_se0_nak\n");
+		break;
+	case TEST_PACKET:
+		seq_printf(s, "test_packet\n");
+		break;
+	case TEST_FORCE_EN:
+		seq_printf(s, "test_force_enable\n");
+		break;
+	default:
+		seq_printf(s, "UNKNOWN %d\n", reg);
+	}
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+	return 0;
+}
+
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_testmode_show, inode->i_private);
+}
+
+static ssize_t dwc3_testmode_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			testmode = 0;
+	char			buf[32];
+	//int			ret;
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "test_j", 6))
+		testmode = TEST_J;
+	else if (!strncmp(buf, "test_k", 6))
+		testmode = TEST_K;
+	else if (!strncmp(buf, "test_se0_nak", 12))
+		testmode = TEST_SE0_NAK;
+	else if (!strncmp(buf, "test_packet", 11))
+		testmode = TEST_PACKET;
+	else if (!strncmp(buf, "test_force_enable", 17))
+		testmode = TEST_FORCE_EN;
+	else
+		testmode = 0;
+
+#if 0
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_gadget_set_test_mode(dwc, testmode);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+	return count;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+	.open			= dwc3_testmode_open,
+	.write			= dwc3_testmode_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_link_state_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	enum dwc3_link_state	state;
+	u32			reg;
+	u8			speed;
+#if 0
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_GSTS);
+	if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
+		seq_puts(s, "Not available\n");
+		spin_unlock_irqrestore(&dwc->lock, flags);
+#if 0
+		pm_runtime_put_sync(dwc->dev);
+#endif
+		return 0;
+	}
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	state = DWC3_DSTS_USBLNKST(reg);
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+
+	seq_printf(s, "%s\n", (speed >= DWC3_DSTS_SUPERSPEED) ?
+		   dwc3_gadget_link_string(state) :
+		   dwc3_gadget_hs_link_string(state));
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+	return 0;
+}
+
+static int dwc3_link_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_link_state_show, inode->i_private);
+}
+
+static ssize_t dwc3_link_state_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	enum dwc3_link_state	state = 0;
+	char			buf[32];
+	u32			reg;
+	u8			speed;
+	//int			ret;
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "SS.Disabled", 11))
+		state = DWC3_LINK_STATE_SS_DIS;
+	else if (!strncmp(buf, "Rx.Detect", 9))
+		state = DWC3_LINK_STATE_RX_DET;
+	else if (!strncmp(buf, "SS.Inactive", 11))
+		state = DWC3_LINK_STATE_SS_INACT;
+	else if (!strncmp(buf, "Recovery", 8))
+		state = DWC3_LINK_STATE_RECOV;
+	else if (!strncmp(buf, "Compliance", 10))
+		state = DWC3_LINK_STATE_CMPLY;
+	else if (!strncmp(buf, "Loopback", 8))
+		state = DWC3_LINK_STATE_LPBK;
+	else
+		return -EINVAL;
+
+#if 0
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_GSTS);
+	if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+		pm_runtime_put_sync(dwc->dev);
+#endif
+		return -EINVAL;
+	}
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+
+	if (speed < DWC3_DSTS_SUPERSPEED &&
+	    state != DWC3_LINK_STATE_RECOV) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+		pm_runtime_put_sync(dwc->dev);
+#endif
+		return -EINVAL;
+	}
+
+	dwc3_gadget_set_link_state(dwc, state);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+	return count;
+}
+
+static const struct file_operations dwc3_link_state_fops = {
+	.open			= dwc3_link_state_open,
+	.write			= dwc3_link_state_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+struct dwc3_ep_file_map {
+	const char name[25];
+	const struct file_operations *const fops;
+};
+#if 0
+static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_TXFIFO);
+
+	/* Convert to bytes */
+	val *= DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+	val >>= 3;
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_RXFIFO);
+
+	/* Convert to bytes */
+	val *= DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+	val >>= 3;
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_event_queue_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u32			val;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
+	seq_printf(s, "%u\n", val);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+
+static int dwc3_transfer_type_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!(dep->flags & DWC3_EP_ENABLED) ||
+			!dep->endpoint.desc) {
+		seq_printf(s, "--\n");
+		goto out;
+	}
+
+	switch (usb_endpoint_type(dep->endpoint.desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		seq_printf(s, "control\n");
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		seq_printf(s, "isochronous\n");
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		seq_printf(s, "bulk\n");
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		seq_printf(s, "interrupt\n");
+		break;
+	default:
+		seq_printf(s, "--\n");
+	}
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+#endif
+
+static int dwc3_trb_ring_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	int			i;
+#if 0
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+#endif
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (dep->number <= 1) {
+		seq_printf(s, "--\n");
+		goto out;
+	}
+
+	seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n");
+
+	for (i = 0; i < dep->trb_num; i++) {
+		struct dwc3_trb *trb = &dep->trb_pool[i];
+		unsigned int type = DWC3_TRBCTL_TYPE(trb->ctrl);
+
+		seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d       %c%c\n",
+				trb->bph, trb->bpl, trb->size,
+				dwc3_trb_type_string(type),
+				!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
+				!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
+				!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
+				!!(trb->ctrl & DWC3_TRB_CTRL_CHN),
+				!!(trb->ctrl & DWC3_TRB_CTRL_LST),
+				!!(trb->ctrl & DWC3_TRB_CTRL_HWO),
+				dep->trb_enqueue == i ? 'E' : ' ',
+				dep->trb_dequeue == i ? 'D' : ' ');
+	}
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if 0
+	pm_runtime_put_sync(dwc->dev);
+#endif
+	return 0;
+}
+
+#if 0
+static int dwc3_ep_info_register_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_ep		*dep = s->private;
+	struct dwc3		*dwc = dep->dwc;
+	unsigned long		flags;
+	u64			ep_info;
+	u32			lower_32_bits;
+	u32			upper_32_bits;
+	u32			reg;
+	int			ret;
+
+	ret = pm_runtime_resume_and_get(dwc->dev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number);
+	dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
+
+	lower_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO0);
+	upper_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO1);
+
+	ep_info = ((u64)upper_32_bits << 32) | lower_32_bits;
+	seq_printf(s, "0x%016llx\n", ep_info);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	pm_runtime_put_sync(dwc->dev);
+
+	return 0;
+}
+#endif
+
+#if 0
+DEFINE_SHOW_ATTRIBUTE(dwc3_tx_fifo_size);
+DEFINE_SHOW_ATTRIBUTE(dwc3_rx_fifo_size);
+DEFINE_SHOW_ATTRIBUTE(dwc3_tx_request_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_rx_request_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_rx_info_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_descriptor_fetch_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_event_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_transfer_type);
+#endif
+DEFINE_SHOW_ATTRIBUTE(dwc3_trb_ring);
+//DEFINE_SHOW_ATTRIBUTE(dwc3_ep_info_register);
+
+static const struct dwc3_ep_file_map dwc3_ep_file_map[] = {
+#if 0
+	{ "tx_fifo_size", &dwc3_tx_fifo_size_fops, },
+	{ "rx_fifo_size", &dwc3_rx_fifo_size_fops, },
+	{ "tx_request_queue", &dwc3_tx_request_queue_fops, },
+	{ "rx_request_queue", &dwc3_rx_request_queue_fops, },
+	{ "rx_info_queue", &dwc3_rx_info_queue_fops, },
+	{ "descriptor_fetch_queue", &dwc3_descriptor_fetch_queue_fops, },
+	{ "event_queue", &dwc3_event_queue_fops, },
+	{ "transfer_type", &dwc3_transfer_type_fops, },
+#endif
+	{ "trb_ring", &dwc3_trb_ring_fops, },
+//	{ "GDBGEPINFO", &dwc3_ep_info_register_fops, },
+};
+
+static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
+		struct dentry *parent)
+{
+	int			i;
+
+	for (i = 0; i < ARRAY_SIZE(dwc3_ep_file_map); i++) {
+		const struct file_operations *fops = dwc3_ep_file_map[i].fops;
+		const char *name = dwc3_ep_file_map[i].name;
+
+		debugfs_create_file(name, S_IRUGO, parent, dep, fops);
+	}
+}
+
+void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
+{
+	struct dentry		*dir;
+
+	dir = debugfs_create_dir(dep->name, dep->dwc->root);
+	dwc3_debugfs_create_endpoint_files(dep, dir);
+}
+
+void dwc3_debugfs_init(struct dwc3 *dwc)
+{
+	struct dentry		*root;
+
+	dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
+	if (!dwc->regset)
+		return;
+
+	dwc->dbg_lsp_select = DWC3_LSP_MUX_UNSELECTED;
+
+	dwc->regset->regs = dwc3_regs;
+	dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
+	dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
+	dwc->regset->dev = dwc->dev;
+
+	root = debugfs_create_dir(dev_name(dwc->dev), NULL);
+	dwc->root = root;
+
+	debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
+
+	debugfs_create_file("lsp_dump", S_IRUGO | S_IWUSR, root, dwc,
+			    &dwc3_lsp_fops);
+
+	if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
+		debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, dwc,
+				    &dwc3_mode_fops);
+	}
+
+	if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
+			IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+		debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, dwc,
+				    &dwc3_testmode_fops);
+		debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, dwc,
+				    &dwc3_link_state_fops);
+	}
+}
+
+void dwc3_debugfs_exit(struct dwc3 *dwc)
+{
+	debugfs_remove_recursive(dwc->root);
+	kfree(dwc->regset);
+}
diff --git a/marvell/linux/drivers/usb/dwc3/drd.c b/marvell/linux/drivers/usb/dwc3/drd.c
new file mode 100644
index 0000000..db68d48
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/drd.c
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * drd.c - DesignWare USB3 DRD Controller Dual-role support
+ *
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Roger Quadros <rogerq@ti.com>
+ */
+
+#include <linux/extcon.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include "debug.h"
+#include "core.h"
+#include "gadget.h"
+
+static void dwc3_otg_disable_events(struct dwc3 *dwc, u32 disable_mask)
+{
+	u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+
+	reg &= ~(disable_mask);
+	dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
+}
+
+static void dwc3_otg_enable_events(struct dwc3 *dwc, u32 enable_mask)
+{
+	u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+
+	reg |= (enable_mask);
+	dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
+}
+
+static void dwc3_otg_clear_events(struct dwc3 *dwc)
+{
+	u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT);
+
+	dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
+}
+
+#define DWC3_OTG_ALL_EVENTS	(DWC3_OEVTEN_XHCIRUNSTPSETEN | \
+		DWC3_OEVTEN_DEVRUNSTPSETEN | DWC3_OEVTEN_HIBENTRYEN | \
+		DWC3_OEVTEN_CONIDSTSCHNGEN | DWC3_OEVTEN_HRRCONFNOTIFEN | \
+		DWC3_OEVTEN_HRRINITNOTIFEN | DWC3_OEVTEN_ADEVIDLEEN | \
+		DWC3_OEVTEN_ADEVBHOSTENDEN | DWC3_OEVTEN_ADEVHOSTEN | \
+		DWC3_OEVTEN_ADEVHNPCHNGEN | DWC3_OEVTEN_ADEVSRPDETEN | \
+		DWC3_OEVTEN_ADEVSESSENDDETEN | DWC3_OEVTEN_BDEVBHOSTENDEN | \
+		DWC3_OEVTEN_BDEVHNPCHNGEN | DWC3_OEVTEN_BDEVSESSVLDDETEN | \
+		DWC3_OEVTEN_BDEVVBUSCHNGEN)
+
+static irqreturn_t dwc3_otg_thread_irq(int irq, void *_dwc)
+{
+	struct dwc3 *dwc = _dwc;
+
+	spin_lock(&dwc->lock);
+	if (dwc->otg_restart_host) {
+		dwc3_otg_host_init(dwc);
+		dwc->otg_restart_host = 0;
+	}
+
+	spin_unlock(&dwc->lock);
+
+	dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_otg_irq(int irq, void *_dwc)
+{
+	u32 reg;
+	struct dwc3 *dwc = _dwc;
+	irqreturn_t ret = IRQ_NONE;
+
+	reg = dwc3_readl(dwc->regs, DWC3_OEVT);
+	if (reg) {
+		/* ignore non OTG events, we can't disable them in OEVTEN */
+		if (!(reg & DWC3_OTG_ALL_EVENTS)) {
+			dwc3_writel(dwc->regs, DWC3_OEVT, reg);
+			return IRQ_NONE;
+		}
+
+		if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST &&
+		    !(reg & DWC3_OEVT_DEVICEMODE))
+			dwc->otg_restart_host = 1;
+		dwc3_writel(dwc->regs, DWC3_OEVT, reg);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	return ret;
+}
+
+static void dwc3_otgregs_init(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	/*
+	 * Prevent host/device reset from resetting OTG core.
+	 * If we don't do this then xhci_reset (USBCMD.HCRST) will reset
+	 * the signal outputs sent to the PHY, the OTG FSM logic of the
+	 * core and also the resets to the VBUS filters inside the core.
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+	reg |= DWC3_OCFG_SFTRSTMASK;
+	dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+
+	/* Disable hibernation for simplicity */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_GBLHIBERNATIONEN;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	/*
+	 * Initialize OTG registers as per
+	 * Figure 11-4 OTG Driver Overall Programming Flow
+	 */
+	/* OCFG.SRPCap = 0, OCFG.HNPCap = 0 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+	reg &= ~(DWC3_OCFG_SRPCAP | DWC3_OCFG_HNPCAP);
+	dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+	/* OEVT = FFFF */
+	dwc3_otg_clear_events(dwc);
+	/* OEVTEN = 0 */
+	dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
+	/* OEVTEN.ConIDStsChngEn = 1. Instead we enable all events */
+	dwc3_otg_enable_events(dwc, DWC3_OTG_ALL_EVENTS);
+	/*
+	 * OCTL.PeriMode = 1, OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0,
+	 * OCTL.HNPReq = 0
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+	reg |= DWC3_OCTL_PERIMODE;
+	reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN |
+		 DWC3_OCTL_HNPREQ);
+	dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+static int dwc3_otg_get_irq(struct dwc3 *dwc)
+{
+	struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
+	int irq;
+
+	irq = platform_get_irq_byname_optional(dwc3_pdev, "otg");
+	if (irq > 0)
+		goto out;
+
+	if (irq == -EPROBE_DEFER)
+		goto out;
+
+	irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
+	if (irq > 0)
+		goto out;
+
+	if (irq == -EPROBE_DEFER)
+		goto out;
+
+	irq = platform_get_irq(dwc3_pdev, 0);
+	if (irq > 0)
+		goto out;
+
+	if (!irq)
+		irq = -EINVAL;
+
+out:
+	return irq;
+}
+
+void dwc3_otg_init(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	/*
+	 * As per Figure 11-4 OTG Driver Overall Programming Flow,
+	 * block "Initialize GCTL for OTG operation".
+	 */
+	/* GCTL.PrtCapDir=2'b11 */
+	dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
+	/* GUSB2PHYCFG0.SusPHY=0 */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	/* Initialize OTG registers */
+	dwc3_otgregs_init(dwc);
+}
+
+void dwc3_otg_exit(struct dwc3 *dwc)
+{
+	/* disable all OTG IRQs */
+	dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
+	/* clear all events */
+	dwc3_otg_clear_events(dwc);
+}
+
+/* should be called before Host controller driver is started */
+void dwc3_otg_host_init(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	/* As per Figure 11-10 A-Device Flow Diagram */
+	/* OCFG.HNPCap = 0, OCFG.SRPCap = 0. Already 0 */
+
+	/*
+	 * OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0,
+	 * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+	reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE |
+			DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
+	dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+
+	/*
+	 * OCFG.DisPrtPwrCutoff = 0/1
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+	reg &= ~DWC3_OCFG_DISPWRCUTTOFF;
+	dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+
+	/*
+	 * OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP
+	 * We don't want SRP/HNP for simple dual-role so leave
+	 * these disabled.
+	 */
+
+	/*
+	 * OEVTEN.OTGADevHostEvntEn = 1
+	 * OEVTEN.OTGADevSessEndDetEvntEn = 1
+	 * We don't want HNP/role-swap so leave these disabled.
+	 */
+
+	/* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */
+	if (!dwc->dis_u2_susphy_quirk) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	}
+
+	/* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+	reg |= DWC3_OCTL_PRTPWRCTL;
+	dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+/* should be called after Host controller driver is stopped */
+static void dwc3_otg_host_exit(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	/*
+	 * Exit from A-device flow as per
+	 * Figure 11-4 OTG Driver Overall Programming Flow
+	 */
+
+	/*
+	 * OEVTEN.OTGADevBHostEndEvntEn=0, OEVTEN.OTGADevHNPChngEvntEn=0
+	 * OEVTEN.OTGADevSessEndDetEvntEn=0,
+	 * OEVTEN.OTGADevHostEvntEn = 0
+	 * But we don't disable any OTG events
+	 */
+
+	/* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+	reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL);
+	dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+/* should be called before the gadget controller driver is started */
+static void dwc3_otg_device_init(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	/* As per Figure 11-20 B-Device Flow Diagram */
+
+	/*
+	 * OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1
+	 * but we keep them 0 for simple dual-role operation.
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+	/* OCFG.OTGSftRstMsk = 0/1 */
+	reg |= DWC3_OCFG_SFTRSTMASK;
+	dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+	/*
+	 * OCTL.PeriMode = 1
+	 * OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0
+	 * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+	reg |= DWC3_OCTL_PERIMODE;
+	reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ |
+			DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
+	dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+	/* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */
+	dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN);
+	/* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */
+	if (!dwc->dis_u2_susphy_quirk) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	}
+	/* GCTL.GblHibernationEn = 0. Already 0. */
+}
+
+/* should be called after the gadget controller driver is stopped */
+static void dwc3_otg_device_exit(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	/*
+	 * Exit from B-device flow as per
+	 * Figure 11-4 OTG Driver Overall Programming Flow
+	 */
+
+	/*
+	 * OEVTEN.OTGBDevHNPChngEvntEn = 0
+	 * OEVTEN.OTGBDevVBusChngEvntEn = 0
+	 * OEVTEN.OTGBDevBHostEndEvntEn = 0
+	 */
+	dwc3_otg_disable_events(dwc, DWC3_OEVTEN_BDEVHNPCHNGEN |
+				DWC3_OEVTEN_BDEVVBUSCHNGEN |
+				DWC3_OEVTEN_BDEVBHOSTENDEN);
+
+	/* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */
+	reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+	reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ);
+	reg |= DWC3_OCTL_PERIMODE;
+	dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
+{
+	int ret;
+	u32 reg;
+	int id;
+	unsigned long flags;
+
+	if (dwc->dr_mode != USB_DR_MODE_OTG)
+		return;
+
+	/* don't do anything if debug user changed role to not OTG */
+	if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG)
+		return;
+
+	if (!ignore_idstatus) {
+		reg = dwc3_readl(dwc->regs, DWC3_OSTS);
+		id = !!(reg & DWC3_OSTS_CONIDSTS);
+
+		dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE :
+					DWC3_OTG_ROLE_HOST;
+	}
+
+	if (dwc->desired_otg_role == dwc->current_otg_role)
+		return;
+
+	switch (dwc->current_otg_role) {
+	case DWC3_OTG_ROLE_HOST:
+		dwc3_host_exit(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_otg_host_exit(dwc);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		break;
+	case DWC3_OTG_ROLE_DEVICE:
+		dwc3_gadget_exit(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_event_buffers_cleanup(dwc);
+		dwc3_otg_device_exit(dwc);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		break;
+	default:
+		break;
+	}
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	dwc->current_otg_role = dwc->desired_otg_role;
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (dwc->desired_otg_role) {
+	case DWC3_OTG_ROLE_HOST:
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_otgregs_init(dwc);
+		dwc3_otg_host_init(dwc);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to initialize host\n");
+		} else {
+			if (dwc->usb2_phy)
+				otg_set_vbus(dwc->usb2_phy->otg, true);
+			if (dwc->usb2_generic_phy)
+				phy_set_mode(dwc->usb2_generic_phy,
+					     PHY_MODE_USB_HOST);
+		}
+		break;
+	case DWC3_OTG_ROLE_DEVICE:
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_otgregs_init(dwc);
+		dwc3_otg_device_init(dwc);
+		dwc3_event_buffers_setup(dwc);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+
+		if (dwc->usb2_phy)
+			otg_set_vbus(dwc->usb2_phy->otg, false);
+		if (dwc->usb2_generic_phy)
+			phy_set_mode(dwc->usb2_generic_phy,
+				     PHY_MODE_USB_DEVICE);
+		ret = dwc3_gadget_init(dwc);
+		if (ret)
+			dev_err(dwc->dev, "failed to initialize peripheral\n");
+		break;
+	default:
+		break;
+	}
+}
+
+static void dwc3_drd_update(struct dwc3 *dwc)
+{
+	int id;
+
+	if (dwc->edev) {
+		id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+		if (id < 0)
+			id = 0;
+		dwc3_set_mode(dwc, id ?
+			      DWC3_GCTL_PRTCAP_HOST :
+			      DWC3_GCTL_PRTCAP_DEVICE);
+	}
+}
+
+static int dwc3_drd_notifier(struct notifier_block *nb,
+			     unsigned long event, void *ptr)
+{
+	struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
+
+	dwc3_set_mode(dwc, event ?
+		      DWC3_GCTL_PRTCAP_HOST :
+		      DWC3_GCTL_PRTCAP_DEVICE);
+
+	return NOTIFY_DONE;
+}
+
+static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
+{
+	struct device *dev = dwc->dev;
+	struct device_node *np_phy, *np_conn;
+	struct extcon_dev *edev;
+	const char *name;
+
+	if (device_property_read_bool(dev, "extcon"))
+		return extcon_get_edev_by_phandle(dev, 0);
+
+	/*
+	 * Device tree platforms should get extcon via phandle.
+	 * On ACPI platforms, we get the name from a device property.
+	 * This device property is for kernel internal use only and
+	 * is expected to be set by the glue code.
+	 */
+	if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
+		edev = extcon_get_extcon_dev(name);
+		if (!edev)
+			return ERR_PTR(-EPROBE_DEFER);
+
+		return edev;
+	}
+
+	np_phy = of_parse_phandle(dev->of_node, "phys", 0);
+	np_conn = of_graph_get_remote_node(np_phy, -1, -1);
+
+	if (np_conn)
+		edev = extcon_find_edev_by_node(np_conn);
+	else
+		edev = NULL;
+
+	of_node_put(np_conn);
+	of_node_put(np_phy);
+
+	return edev;
+}
+
+#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
+#define ROLE_SWITCH 1
+static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	u32 mode;
+
+	switch (role) {
+	case USB_ROLE_HOST:
+		mode = DWC3_GCTL_PRTCAP_HOST;
+		break;
+	case USB_ROLE_DEVICE:
+		mode = DWC3_GCTL_PRTCAP_DEVICE;
+		break;
+	default:
+		if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
+			mode = DWC3_GCTL_PRTCAP_HOST;
+		else
+			mode = DWC3_GCTL_PRTCAP_DEVICE;
+		break;
+	}
+
+	dwc3_set_mode(dwc, mode);
+	return 0;
+}
+
+static enum usb_role dwc3_usb_role_switch_get(struct device *dev)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	unsigned long flags;
+	enum usb_role role;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		role = USB_ROLE_HOST;
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		role = USB_ROLE_DEVICE;
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		role = dwc->current_otg_role;
+		break;
+	default:
+		if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
+			role = USB_ROLE_HOST;
+		else
+			role = USB_ROLE_DEVICE;
+		break;
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	return role;
+}
+
+static int dwc3_setup_role_switch(struct dwc3 *dwc)
+{
+	struct usb_role_switch_desc dwc3_role_switch = {NULL};
+	const char *str;
+	u32 mode;
+	int ret;
+
+	ret = device_property_read_string(dwc->dev, "role-switch-default-mode",
+					  &str);
+	if (ret >= 0  && !strncmp(str, "host", strlen("host"))) {
+		dwc->role_switch_default_mode = USB_DR_MODE_HOST;
+		mode = DWC3_GCTL_PRTCAP_HOST;
+	} else {
+		dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL;
+		mode = DWC3_GCTL_PRTCAP_DEVICE;
+	}
+
+	dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
+	dwc3_role_switch.set = dwc3_usb_role_switch_set;
+	dwc3_role_switch.get = dwc3_usb_role_switch_get;
+	dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch);
+	if (IS_ERR(dwc->role_sw))
+		return PTR_ERR(dwc->role_sw);
+
+	dwc3_set_mode(dwc, mode);
+	return 0;
+}
+#else
+#define ROLE_SWITCH 0
+#define dwc3_setup_role_switch(x) 0
+#endif
+
+int dwc3_drd_init(struct dwc3 *dwc)
+{
+	int ret, irq;
+
+	dwc->edev = dwc3_get_extcon(dwc);
+	if (IS_ERR(dwc->edev))
+		return PTR_ERR(dwc->edev);
+
+	if (ROLE_SWITCH &&
+	    device_property_read_bool(dwc->dev, "usb-role-switch")) {
+		ret = dwc3_setup_role_switch(dwc);
+		if (ret < 0)
+			return ret;
+	} else if (dwc->edev) {
+		dwc->edev_nb.notifier_call = dwc3_drd_notifier;
+		ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+					       &dwc->edev_nb);
+		if (ret < 0) {
+			dev_err(dwc->dev, "couldn't register cable notifier\n");
+			return ret;
+		}
+
+		dwc3_drd_update(dwc);
+	} else {
+		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
+		dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG;
+
+		/* use OTG block to get ID event */
+		irq = dwc3_otg_get_irq(dwc);
+		if (irq < 0)
+			return irq;
+
+		dwc->otg_irq = irq;
+
+		/* disable all OTG IRQs */
+		dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
+		/* clear all events */
+		dwc3_otg_clear_events(dwc);
+
+		ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq,
+					   dwc3_otg_thread_irq,
+					   IRQF_SHARED, "dwc3-otg", dwc);
+		if (ret) {
+			dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				dwc->otg_irq, ret);
+			ret = -ENODEV;
+			return ret;
+		}
+
+		dwc3_otg_init(dwc);
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+	}
+
+	return 0;
+}
+
+void dwc3_drd_exit(struct dwc3 *dwc)
+{
+	unsigned long flags;
+
+	if (dwc->role_sw)
+		usb_role_switch_unregister(dwc->role_sw);
+
+	if (dwc->edev)
+		extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+					   &dwc->edev_nb);
+
+	cancel_work_sync(&dwc->drd_work);
+
+	/* debug user might have changed role, clean based on current role */
+	switch (dwc->current_dr_role) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		dwc3_gadget_exit(dwc);
+		dwc3_event_buffers_cleanup(dwc);
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		dwc3_otg_exit(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_otg_update(dwc, 1);
+		break;
+	default:
+		break;
+	}
+
+	if (!dwc->edev)
+		free_irq(dwc->otg_irq, dwc);
+}
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-asr-otg.c b/marvell/linux/drivers/usb/dwc3/dwc3-asr-otg.c
new file mode 100644
index 0000000..c1ce798
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-asr-otg.c
@@ -0,0 +1,746 @@
+/*
+ * Base driver for ASR USB
+ *
+ * Copyright 2024 ASR Microelectronics Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/platform_data/mv_usb.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <soc/asr/regs-addr.h>
+#include <linux/delay.h>
+#include <linux/cputype.h>
+#include <linux/usb/phy.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/pm_qos.h>
+#include <linux/gpio.h>
+#include <linux/edge_wakeup_mmp.h>
+#include <linux/mutex.h>
+
+#include "core.h"
+
+#define ENNUM		-1
+#define USB_HANDLE_TIME_MSEC (5000)
+#define VBUS_RISE_FALL_MS		(10)
+
+#ifdef CONFIG_CPU_ASR1901
+#define APMU_USB_WAKE_CLR		(0x07c)
+#define USB_WAKE_INT_EN			(0x1 << 15)
+#define USB_WAKE_PMU_EN			(0x1 << 14)
+
+#define USB_VBUS_WAKE_EN		(0x1 << 10)
+#define USB_ID_WAKE_EN			(0x1 << 12)
+#define USB_LINEST_WAKE_EN		((0x1 << 8) | (0x1 << 9))
+#define USB_RXELEC_WAKE_EN		(0x1 << 11)
+
+#define USB_VBUS_WAKE_CLR		(0x1 << 18)
+#define USB_ID_WAKE_CLR			(0x1 << 20)
+#define USB_LINEST_WAKE_CLR		((0x1 << 16) | (0x1 << 17))
+#define USB_RXELEC_WAKE_CLR		(0x1 << 19)
+#elif defined(CONFIG_CPU_ASR1903)
+#define APMU_USB_WAKE_CLR		(0x07c)
+
+#define USB_WAKE_INT_EN			(0x1 << 29)
+#define USB_WAKE_PMU_EN			(0x1 << 29)
+
+#define USB_VBUS_WAKE_EN		(0x1 << 11)
+#define USB_ID_WAKE_EN			(0x1 << 22)
+#define USB_LINEST_WAKE_EN		((0x1 << 9) | (0x1 << 10))
+#define USB_RXELEC_WAKE_EN		((0x1 << 9) | (0x1 << 10))
+
+#define USB_VBUS_WAKE_CLR		(0x1 << 4)
+#define USB_ID_WAKE_CLR			(0x1 << 23)
+#define USB_LINEST_WAKE_CLR		(0x1 << 7)
+#define USB_RXELEC_WAKE_CLR		(0x1 << 7)
+#else
+#define APMU_USB_WAKE_CLR		(0x07c)
+
+#define USB_WAKE_INT_EN			(0x1 << 16)
+#define USB_WAKE_PMU_EN			(0x1 << 16)
+
+#define USB_VBUS_WAKE_EN		(0x1 << 11)
+#define USB_ID_WAKE_EN			(0x1 << 12)
+#define USB_LINEST_WAKE_EN		((0x1 << 9) | (0x1 << 10))
+#define USB_RXELEC_WAKE_EN		(0x1 << 28)
+
+#define USB_VBUS_WAKE_CLR		(0x1 << 4)
+#define USB_ID_WAKE_CLR			(0x1 << 23)
+#define USB_LINEST_WAKE_CLR		(0x1 << 7)
+#define USB_RXELEC_WAKE_CLR		(0x1 << 29)
+#endif
+
+struct dwc3_asr {
+	struct device		*dev;
+	struct clk		*usb_clk;
+	int			vbus_irq;
+
+#ifdef CONFIG_DWC3_HWSULOG
+	int			sulog_irq;
+#endif
+
+	int			usbid_irq;
+	spinlock_t		lock;
+	u32			usbid_gpio;
+	u32			edge_det_gpio;
+	u32			cur_usbid_val;
+	u32			cur_vbus_val;
+	int			gpio_num;
+	int			otg_state;
+
+	struct usb_gadget *gadget;
+	struct usb_hcd	*hcd;
+	struct usb_hcd	*shared_hcd;
+	struct dwc3 *dwc;
+
+	struct usb_phy		*usb2_phy;
+	struct usb_phy		*usb3_phy;
+	struct delayed_work	otg_work;
+
+	struct pm_qos_request	qos_idle;
+	s32 					lpm_qos;
+	struct mutex mtx_lock;
+};
+
+extern void dwc3_release_pm_qos(void);
+extern void dwc3_release_pm_qos_timeout(u32 sec);
+extern void dwc3_acquire_pm_qos(void);
+extern void dwc3_acquire_wakeup_event(void);
+
+extern struct dwc3 *dwc3_get_controller(void);
+#ifdef CONFIG_DWC3_HWSULOG
+extern void dwc3_hwsulog_clear_int(void);
+#endif
+static u32 force_host = 0;
+static u32 force_dev = 0;
+static bool usb_host_vbus_on;
+static struct dwc3_asr *g_adwc;
+
+module_param(force_dev, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(force_dev, "dwc3 otg force device mode");
+
+module_param(force_host, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(force_host, "dwc3 otg force host mode");
+bool is_otg_host_vbus_on(void)
+{
+	return usb_host_vbus_on;
+}
+
+int usb_otg_set_vbus(struct dwc3_asr *adwc, bool on)
+{
+	int ret = 0;
+
+	usb_host_vbus_on = on;
+	if (adwc->gpio_num >= 0)
+		ret = gpio_direction_output(adwc->gpio_num , on);
+	return ret;
+}
+
+int usb_otg_set_host(struct usb_hcd *hcd, struct usb_hcd *shared_hcd)
+{
+	g_adwc->hcd = hcd;
+	g_adwc->shared_hcd = shared_hcd;
+	g_adwc->hcd->usb_phy = g_adwc->shared_hcd->usb_phy = g_adwc->usb2_phy;
+
+	return 0;
+}
+
+int usb_otg_set_peripheral(struct usb_gadget *gadget)
+{
+	g_adwc->gadget = gadget;
+
+	return 0;
+}
+
+int usb_otg_set_phy(struct usb_phy *usb2phy, struct usb_phy *usb3phy)
+{
+	g_adwc->usb2_phy = usb2phy;
+	g_adwc->usb3_phy = usb3phy;
+
+	return 0;
+}
+
+int usb_otg_set_controller(struct dwc3 *dwc)
+{
+	dwc->otg_state = g_adwc->otg_state;
+	g_adwc->dwc = dwc;
+
+	return 0;
+}
+
+static void dwc3_otg_start_host(struct dwc3_asr *adwc, int on)
+{
+	struct usb_hcd *hcd = g_adwc->hcd;
+	struct usb_hcd *shared_hcd = g_adwc->shared_hcd;
+
+	if (!hcd || !shared_hcd) {
+		dev_err(g_adwc->dev, "adwc->hcd is not set!\n");
+		return;
+	}
+
+	dev_info(g_adwc->dev, "%s host\n", on ? "start" : "stop");
+	adwc->dwc->otg_state = adwc->otg_state;
+
+	if (on) {
+		/* set constraint before turn on vbus */
+		pm_stay_awake(adwc->dev);
+		pm_qos_update_request(&adwc->qos_idle, adwc->lpm_qos);
+		dwc3_controller_reset(adwc->dwc);
+		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+		usb_add_hcd(shared_hcd, shared_hcd->irq, IRQF_SHARED);
+	} else {
+		usb_remove_hcd(shared_hcd);
+		usb_remove_hcd(hcd);
+		dwc3_controller_reset(adwc->dwc);
+		usb_phy_set_suspend(adwc->dwc->usb2_phy, 1);
+		usb_phy_set_suspend(adwc->dwc->usb3_phy, 1);
+		pm_qos_update_request(&adwc->qos_idle, PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);
+		pm_relax(adwc->dev);
+	}
+}
+
+static void dwc3_otg_start_peripherals(struct dwc3_asr *adwc, int on)
+{
+	struct usb_gadget *gadget = g_adwc->gadget;
+
+	if (!gadget) {
+		dev_err(g_adwc->dev, "adwc->gadget is not set!\n");
+		return;
+	}
+
+	dev_info(g_adwc->dev, "gadget %s\n", on ? "on" : "off");
+	adwc->dwc->otg_state = adwc->otg_state;
+	pm_wakeup_event(adwc->dev, USB_HANDLE_TIME_MSEC);
+	pm_qos_update_request_timeout(&adwc->qos_idle, adwc->lpm_qos, USB_HANDLE_TIME_MSEC * 1000);
+	if (on) {
+		/* dwc3_controller_reset(adwc->dwc); */
+		usb_gadget_vbus_connect(adwc->gadget);
+	} else {
+		usb_gadget_vbus_disconnect(adwc->gadget);
+		/* usb_phy_set_suspend(adwc->uphy, 1); */
+	}
+}
+
+static void usb_otg_work_fn(struct work_struct *work)
+{
+	int vbus, ret;
+	struct dwc3_asr *adwc = g_adwc;
+	int 		old_otg_state;
+
+	/* check ID and VBUS and update cable state */
+	if (adwc->usbid_gpio >= 0)
+		adwc->cur_usbid_val = gpio_get_value(adwc->usbid_gpio);
+	else
+		adwc->cur_usbid_val = 1;
+
+	mutex_lock(&adwc->mtx_lock);
+	ret = pxa_usb_extern_call(PXA_USB_DEV_OTG, vbus, get_vbus, &vbus);
+	if (ret) {
+		vbus = usb_phy_get_vbus(adwc->usb2_phy);
+	}
+	adwc->cur_vbus_val = vbus;
+
+	if (force_host)
+		adwc->cur_usbid_val = 0;
+	else if (force_dev)
+		adwc->cur_usbid_val = 1;
+
+	old_otg_state = adwc->otg_state;
+	pr_info("=>old_otg_state: %d, usbid: %d vbus: %d\n",
+			adwc->otg_state, adwc->cur_usbid_val, adwc->cur_vbus_val);
+
+	/* at first we clean states which are no longer active */
+	if (adwc->otg_state == OTG_STATE_B_IDLE) {
+		if (!adwc->cur_usbid_val) {
+			printk("disable vbus irq\n");
+			disable_irq(adwc->vbus_irq);
+			adwc->otg_state = OTG_STATE_A_HOST;
+			usb_phy_set_suspend(adwc->dwc->usb2_phy, 0);
+			usb_phy_set_suspend(adwc->dwc->usb3_phy, 0);
+			dwc3_otg_start_host(adwc, 1);
+			msleep(VBUS_RISE_FALL_MS);
+			usb_otg_set_vbus(adwc, true);
+		} else {
+			if (vbus)
+				adwc->otg_state = OTG_STATE_B_PERIPHERAL;
+			else
+				adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_peripherals(adwc, vbus);
+		}
+	} else if (adwc->otg_state == OTG_STATE_B_PERIPHERAL) {
+		if (!adwc->cur_vbus_val) {
+			adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_peripherals(adwc, 0);
+		}
+	} else if (adwc->otg_state == OTG_STATE_A_HOST) {
+		if (adwc->cur_usbid_val) {
+			adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_host(adwc, 0);
+			msleep(1);
+			usb_otg_set_vbus(adwc, false);
+			msleep(VBUS_RISE_FALL_MS);
+			/* usb_phy_set_suspend(adwc->dwc->usb2_phy, 1);
+			usb_phy_set_suspend(adwc->dwc->usb3_phy, 1); */
+			printk("enable vbus irq\n");
+			enable_irq(adwc->vbus_irq);
+		}
+	}
+	mutex_unlock(&adwc->mtx_lock);
+	pr_info("cur_otg_state: [%d->%d], usbid: %d vbus: %d\n",
+			old_otg_state, adwc->otg_state,
+			adwc->cur_usbid_val, adwc->cur_vbus_val);
+}
+
+static irqreturn_t vbus_irq(int irq, void *dev)
+{
+	struct dwc3_asr *adwc = (struct dwc3_asr *)dev;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+
+	dev_info(adwc->dev, "asr-usb vbus int enter..\n");
+#ifdef CONFIG_DWC3_HWSULOG
+	dwc3_hwsulog_clear_int();
+#endif
+
+	/* wait 50ms for vbus to be stable */
+	msleep(50);
+	if (cpu_is_asr1901() || cpu_is_asr1906())
+		writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+			| USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR
+			| USB_ID_WAKE_CLR | USB_RXELEC_WAKE_CLR,
+			apmu_base + APMU_USB_WAKE_CLR);
+	else
+		writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+			| (USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR | USB_RXELEC_WAKE_CLR
+			| USB_ID_WAKE_CLR | USB_WAKE_INT_EN),
+			apmu_base + APMU_USB_WAKE_CLR);
+
+	pm_wakeup_event(adwc->dev, USB_HANDLE_TIME_MSEC);
+	//pxa_usb_notify(PXA_USB_DEV_OTG, EVENT_VBUS, 0);
+	if (work_pending(&g_adwc->otg_work.work)) {
+		dev_info(adwc->dev, "cancel otg work...");
+		cancel_delayed_work_sync(&g_adwc->otg_work);
+		dev_info(adwc->dev, "done\n");
+		pm_wakeup_event(adwc->dev, USB_HANDLE_TIME_MSEC);
+	}
+	schedule_delayed_work(&g_adwc->otg_work, 0);
+	dev_info(adwc->dev, "asr-usb vbus interrupt is served..\n");
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t usbid_irq(int irq, void *dev_id)
+{
+	struct dwc3_asr *adwc = (struct dwc3_asr *)g_adwc;
+	dev_info(adwc->dev, "dwc3 usbid_irq is served..\n");
+	vbus_irq(irq, dev_id);
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_DWC3_HWSULOG
+static irqreturn_t sulog_irq_handler(int irq, void *dev)
+{
+	hwsulog_error_handler();
+
+	return IRQ_HANDLED;
+}
+#endif
+
+static void usbid_wakeup_handler(int gpio, void *data)
+{
+}
+
+static int usbid_irq_init(struct platform_device *pdev, struct dwc3_asr *adwc)
+{
+	int ret = -1;
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+			"usbid_gpio", &adwc->usbid_gpio);
+	pr_info("dwc3:usbid_gpio: %d\n", adwc->usbid_gpio);
+
+	if (ret) {
+		adwc->usbid_gpio = -1;
+		pr_err("%s no usbid-gpio defined\n", __func__);
+		return ret;
+	}
+
+	of_property_read_u32(pdev->dev.of_node,
+			"edge_detect_gpio", &adwc->edge_det_gpio); 
+	if (adwc->edge_det_gpio > 0) {
+			ret = request_mfp_edge_wakeup(adwc->edge_det_gpio,
+						      usbid_wakeup_handler,
+						      NULL, &pdev->dev);
+			if (ret) {
+				dev_err(adwc->dev, "failed to request edge wakeup.\n");
+				goto out;	
+			}
+	}
+
+	adwc->cur_usbid_val = gpio_get_value(adwc->usbid_gpio);
+	ret = gpio_request(adwc->usbid_gpio, "dwc3-usbid");
+	gpio_direction_input(adwc->usbid_gpio);
+
+	adwc->usbid_irq = gpio_to_irq(adwc->usbid_gpio);
+	ret =
+	    request_threaded_irq(adwc->usbid_irq, NULL, usbid_irq,
+			IRQF_SHARED | IRQF_TRIGGER_RISING |
+			IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "dwc3-usbid",
+			adwc);
+	if (ret < 0) {
+		dev_err(adwc->dev, "%s: request irq failed!\n",
+				 __func__);
+	}
+
+out:
+	return ret;
+}
+
+static ssize_t otg_mode_store(struct device *pdev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct dwc3_asr *adwc = dev_get_drvdata(pdev);
+
+	mutex_lock(&adwc->mtx_lock);
+	if (!strncmp(buf, "host", 4)) {
+		if(adwc->otg_state == OTG_STATE_A_HOST) {
+			pr_err("already in host mode\n");
+			goto out;
+		}
+		disable_irq(adwc->vbus_irq);
+		pr_info("disable vbus irq\n");
+
+		if (adwc->otg_state == OTG_STATE_B_PERIPHERAL) {
+			adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_peripherals(adwc, 0);
+		}
+
+		if (adwc->otg_state == OTG_STATE_B_IDLE) {
+			force_host = 1;
+			force_dev  = 0;
+			usb_otg_set_vbus(adwc, true);
+			msleep(VBUS_RISE_FALL_MS);
+			adwc->otg_state = OTG_STATE_A_HOST;
+			dwc3_otg_start_host(adwc, 1);
+			dev_info(pdev, "userspace set host: otg_mode: %d\n", adwc->otg_state);
+		}
+	} else if (!strncmp(buf, "device", 6)) {
+		if(adwc->otg_state == OTG_STATE_B_PERIPHERAL) {
+			pr_err("already in device mode\n");
+			goto out;
+		}
+
+		if (adwc->otg_state == OTG_STATE_A_HOST) {
+			adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_host(adwc, 0);
+			msleep(1);
+			usb_otg_set_vbus(adwc, false);
+			msleep(VBUS_RISE_FALL_MS);
+		}
+
+		if (adwc->otg_state == OTG_STATE_B_IDLE) {
+			force_host = 0;
+			force_dev  = 1;
+			adwc->otg_state = OTG_STATE_B_PERIPHERAL;
+			dwc3_otg_start_peripherals(adwc, 1);
+			dev_info(pdev, "userspace set device: otg_mode: %d\n", adwc->otg_state);
+		}
+
+		enable_irq(adwc->vbus_irq);
+		pr_err("enable vbus irq\n");
+	} else {
+		force_host = 0;
+		force_dev  = 0;
+		if (adwc->otg_state == OTG_STATE_B_PERIPHERAL) {
+			adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_peripherals(adwc, 0);
+		} else if (adwc->otg_state == OTG_STATE_A_HOST) {
+			adwc->otg_state = OTG_STATE_B_IDLE;
+			dwc3_otg_start_host(adwc, 0);
+			msleep(1);
+			usb_otg_set_vbus(adwc, false);
+			msleep(VBUS_RISE_FALL_MS);
+			printk("enable vbus irq\n");
+			enable_irq(adwc->vbus_irq);
+		} else {
+			 dev_info(pdev, "already in idle none host/device mode: %d\n", adwc->otg_state);
+		}
+	}
+
+out:
+	mutex_unlock(&adwc->mtx_lock);
+
+	return count;
+}
+
+static ssize_t otg_mode_show(struct device *pdev, struct device_attribute *attr, char *buf)
+{
+	struct dwc3_asr *adwc = dev_get_drvdata(pdev);
+	char *host_dev_str;
+
+	if (adwc->otg_state == OTG_STATE_A_HOST)
+		host_dev_str = "host";
+	else if (adwc->otg_state == OTG_STATE_B_PERIPHERAL)
+		host_dev_str = "device";
+	else
+		host_dev_str = "idle";
+
+	return sprintf(buf, "otg_state:%d, otg mode: %s\n", adwc->otg_state, host_dev_str);
+}
+
+static DEVICE_ATTR(otg_mode, S_IWUSR |S_IRUGO, otg_mode_show, otg_mode_store);
+
+static int dwc3_asr_otg_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct dwc3_asr *adwc;
+	int ret;
+	void __iomem *apmu_base;
+	const __be32 *prop;
+	unsigned int proplen;
+	u32 data;
+
+	adwc = devm_kzalloc(&pdev->dev, sizeof(*adwc), GFP_KERNEL);
+	if (!adwc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, adwc);
+
+	adwc->dev = &pdev->dev;
+	adwc->usb_clk = devm_clk_get(adwc->dev, NULL);
+	if (IS_ERR(adwc->usb_clk)) {
+		dev_err(adwc->dev, "failed to get core clock\n");
+		return PTR_ERR(adwc->usb_clk);
+	}
+
+	ret = clk_prepare_enable(adwc->usb_clk);
+	if (ret) {
+		dev_err(adwc->dev, "failed to enable core clock\n");
+		goto err_core;
+	}
+
+	adwc->vbus_irq = platform_get_irq(pdev, 0);
+	if (adwc->vbus_irq < 0) {
+		dev_err(&pdev->dev, "failed to get vbus irq\n");
+		ret = -ENXIO;
+		goto err_iface;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, adwc->vbus_irq,
+					NULL, vbus_irq,
+					IRQF_ONESHOT | IRQF_NO_SUSPEND,
+					"asr-usb-vbus", adwc);
+	if (ret) {
+		dev_info(&pdev->dev,
+			"Can not request irq for VBUS\n");
+		goto err_iface;
+	}
+
+#ifdef CONFIG_DWC3_HWSULOG
+	adwc->sulog_irq = platform_get_irq(pdev, 1);
+	if (adwc->sulog_irq < 0) {
+		dev_info(&pdev->dev, "no sulog irq\n");
+	} else {
+		ret = devm_request_threaded_irq(&pdev->dev, adwc->sulog_irq,
+						NULL, sulog_irq_handler,
+						IRQF_ONESHOT | IRQF_SHARED,
+						"dwc3-sulog-irq", adwc);
+		if (ret) {
+			dev_info(&pdev->dev,
+				"Can not request irq for dwc3 sulog %d\n", ret);
+			goto err_iface;
+		}
+	}
+#endif
+
+	usbid_irq_init(pdev, adwc);
+	INIT_DELAYED_WORK(&adwc->otg_work, usb_otg_work_fn);
+
+	if (of_property_read_bool(node , "otg,use-gpio-vbus")) {
+		if (of_property_read_u32(node , "gpio-num", &adwc->gpio_num)) {
+			adwc->gpio_num = ENNUM;
+			dev_info(&pdev->dev, "failed to find GPIO number in dts\n");
+		} else {
+			if (gpio_request(adwc->gpio_num, "OTGVBUS")) {
+				dev_err(&pdev->dev , "OTG Request GPIO failed, gpio: %d\n" ,
+					adwc->gpio_num);
+				adwc->gpio_num = ENNUM;
+			} else
+				gpio_direction_output(adwc->gpio_num , 0);
+		}
+	} else
+		adwc->gpio_num = ENNUM;
+
+	if (!of_property_read_u32(node, "otg-force-host-mode", &data)) {
+		dev_info(&pdev->dev, "otg force host mode\n");
+		force_host = 1;
+		force_dev = 0;
+	} else if (!of_property_read_u32(node, "otg-force-dev-mode", &data)) {
+		dev_info(&pdev->dev, "otg force dev mode\n");
+		force_dev = 1;
+		force_host = 0;
+	}
+
+	prop = of_get_property(node, "lpm-qos", &proplen);
+	if (!prop) {
+		pr_err("lpm-qos for dwc otg is not defined\n");
+		goto err_iface;
+	} else
+		adwc->lpm_qos = be32_to_cpup(prop);
+
+	adwc->qos_idle.name = "dwc3-otg";
+	pm_qos_add_request(&adwc->qos_idle, PM_QOS_CPUIDLE_BLOCK,
+			PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);
+
+	platform_set_drvdata(pdev, adwc);
+	device_init_wakeup(&pdev->dev, 1);
+	g_adwc = adwc;
+	ret = of_platform_populate(node, NULL, NULL, adwc->dev);
+	if (ret) {
+		dev_err(adwc->dev, "failed to register core - %d\n", ret);
+		goto err_iface;
+	}
+
+	schedule_delayed_work(&g_adwc->otg_work, HZ);
+	adwc->otg_state = OTG_STATE_B_IDLE;
+	mutex_init(&adwc->mtx_lock);
+	ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_otg_mode.attr);
+	if(ret){
+		dev_err(&pdev->dev, "create host_dev mode failed");
+		goto err_iface;
+	}
+
+	apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+	writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+		| (USB_WAKE_INT_EN | USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR | USB_ID_WAKE_CLR),
+		apmu_base + APMU_USB_WAKE_CLR);
+	writel(readl(apmu_base + APMU_USB_WAKE_CLR) | USB_WAKE_INT_EN | USB_VBUS_WAKE_EN,
+		apmu_base + APMU_USB_WAKE_CLR);
+	dev_info(&pdev->dev, "%s done\n", __func__);
+
+	return 0;
+
+err_iface:
+	clk_disable_unprepare(adwc->usb_clk);
+err_core:
+	return ret;
+}
+
+static int dwc3_asr_otg_remove(struct platform_device *pdev)
+{
+	struct dwc3_asr *adwc = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(adwc->usb_clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_asr_suspend_noirq(struct device *dev)
+{
+	struct dwc3_asr *adwc = dev_get_drvdata(dev);
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+	struct dwc3 *dwc = dwc3_get_controller();
+
+	writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+		| (USB_WAKE_INT_EN | USB_WAKE_PMU_EN
+		| USB_LINEST_WAKE_EN | USB_ID_WAKE_EN | USB_RXELEC_WAKE_EN
+		| USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR
+		| USB_ID_WAKE_CLR | USB_RXELEC_WAKE_CLR),
+		apmu_base + APMU_USB_WAKE_CLR);
+
+	if (dwc->allow_suspend) {
+		if (dwc->link_state == DWC3_LINK_STATE_U3)
+			usb_phy_set_suspend2(dwc->usb2_phy, 1);
+		else
+			pr_info("dwc3 linkst: %d\n", dwc->link_state);
+	}
+
+	enable_irq_wake(adwc->vbus_irq);
+
+	dwc3_release_pm_qos();
+	return 0;
+}
+
+static int dwc3_asr_resume_noirq(struct device *dev)
+{
+	volatile u32 value;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+	struct dwc3_asr *adwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = dwc3_get_controller();
+
+	if (dwc->allow_suspend) {
+		if (dwc->vbus_active) {
+			dwc3_acquire_pm_qos();
+			usb_phy_set_suspend2(dwc->usb2_phy, 0);
+		} else {
+			pr_info("dwc3 vbus off, linkst: %d\n", dwc->link_state);
+		}
+	}
+
+	/* clear linestat wakeup and disable linestat/pmu wake en */
+	value = readl(apmu_base + APMU_USB_WAKE_CLR);
+	value |= (USB_WAKE_INT_EN | USB_LINEST_WAKE_CLR | USB_RXELEC_WAKE_CLR);
+	writel(value, apmu_base + APMU_USB_WAKE_CLR);
+	udelay(50);
+
+	value = readl(apmu_base + APMU_USB_WAKE_CLR);
+	value &= ~(USB_WAKE_PMU_EN | USB_LINEST_WAKE_EN | USB_RXELEC_WAKE_EN);
+	value |= (USB_VBUS_WAKE_EN | USB_ID_WAKE_EN | USB_WAKE_INT_EN);	
+	writel(value, apmu_base + APMU_USB_WAKE_CLR);
+
+	disable_irq_wake(adwc->vbus_irq);
+	return 0;
+}
+
+static const struct dev_pm_ops dwc3_asr_pm_ops = {
+	.suspend_noirq = dwc3_asr_suspend_noirq,
+	.resume_noirq = dwc3_asr_resume_noirq,
+};
+#endif
+
+static const struct of_device_id of_dwc3_match[] = {
+	{ .compatible = "asr,dwc3" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_match);
+
+static struct platform_driver dwc3_asr_driver = {
+	.probe		= dwc3_asr_otg_probe,
+	.remove		= dwc3_asr_otg_remove,
+	.driver		= {
+		.name	= "asr-dwc3",
+		.of_match_table	= of_dwc3_match,
+#ifdef CONFIG_PM_SLEEP
+		.pm = &dwc3_asr_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(dwc3_asr_driver);
+
+MODULE_ALIAS("platform:asr-dwc3");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASR USB Glue Layer");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-asr.c b/marvell/linux/drivers/usb/dwc3/dwc3-asr.c
new file mode 100644
index 0000000..39d4ac6
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-asr.c
@@ -0,0 +1,324 @@
+/*
+ * Base driver for ASR USB
+ *
+ * Copyright 2021 ASR Microelectronics (Shanghai) Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/platform_data/mv_usb.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <soc/asr/regs-addr.h>
+#include <linux/delay.h>
+#include <linux/cputype.h>
+#include <linux/usb/phy.h>
+
+#include "core.h"
+
+#define USB_HANDLE_TIME_MSEC (5000)
+#ifdef CONFIG_CPU_ASR1901
+#define APMU_USB_WAKE_CLR		(0x07c)
+#define USB_WAKE_INT_EN			(0x1 << 15)
+#define USB_WAKE_PMU_EN			(0x1 << 14)
+
+#define USB_VBUS_WAKE_EN		(0x1 << 10)
+#define USB_ID_WAKE_EN			(0x1 << 12)
+#define USB_LINEST_WAKE_EN		((0x1 << 8) | (0x1 << 9))
+#define USB_RXELEC_WAKE_EN		(0x1 << 11)
+
+#define USB_VBUS_WAKE_CLR		(0x1 << 18)
+#define USB_ID_WAKE_CLR			(0x1 << 20)
+#define USB_LINEST_WAKE_CLR		((0x1 << 16) | (0x1 << 17))
+#define USB_RXELEC_WAKE_CLR		(0x1 << 19)
+#elif defined(CONFIG_CPU_ASR1903)
+#define APMU_USB_WAKE_CLR		(0x07c)
+
+#define USB_WAKE_INT_EN			(0x1 << 29)
+#define USB_WAKE_PMU_EN			(0x1 << 29)
+
+#define USB_VBUS_WAKE_EN		(0x1 << 11)
+#define USB_ID_WAKE_EN			(0x1 << 22)
+#define USB_LINEST_WAKE_EN		((0x1 << 9) | (0x1 << 10))
+#define USB_RXELEC_WAKE_EN		((0x1 << 9) | (0x1 << 10))
+
+#define USB_VBUS_WAKE_CLR		(0x1 << 4)
+#define USB_ID_WAKE_CLR			(0x1 << 23)
+#define USB_LINEST_WAKE_CLR		(0x1 << 7)
+#define USB_RXELEC_WAKE_CLR		(0x1 << 7)
+#else
+#define APMU_USB_WAKE_CLR		(0x07c)
+
+#define USB_WAKE_INT_EN			(0x1 << 16)
+#define USB_WAKE_PMU_EN			(0x1 << 16)
+
+#define USB_VBUS_WAKE_EN		(0x1 << 11)
+#define USB_ID_WAKE_EN			(0x1 << 12)
+#define USB_LINEST_WAKE_EN		((0x1 << 9) | (0x1 << 10))
+#define USB_RXELEC_WAKE_EN		(0x1 << 28)
+
+#define USB_VBUS_WAKE_CLR		(0x1 << 4)
+#define USB_ID_WAKE_CLR			(0x1 << 23)
+#define USB_LINEST_WAKE_CLR		(0x1 << 7)
+#define USB_RXELEC_WAKE_CLR		(0x1 << 29)
+#endif
+
+struct dwc3_asr {
+	struct device		*dev;
+	struct clk		*usb_clk;
+	int			vbus_irq;
+#ifdef CONFIG_DWC3_HWSULOG
+	int			sulog_irq;
+#endif
+	spinlock_t		lock;
+};
+extern void dwc3_release_pm_qos(void);
+extern void dwc3_release_pm_qos_timeout(u32 sec);
+extern void dwc3_acquire_pm_qos(void);
+extern void dwc3_acquire_wakeup_event(void);
+
+extern struct dwc3 *dwc3_get_controller(void);
+#ifdef CONFIG_DWC3_HWSULOG
+extern void dwc3_hwsulog_clear_int(void);
+#endif
+
+static irqreturn_t vbus_irq(int irq, void *dev)
+{
+	struct dwc3_asr *adwc = (struct dwc3_asr *)dev;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+
+#ifdef CONFIG_DWC3_HWSULOG
+	dwc3_hwsulog_clear_int();
+#endif
+
+	/* wait 50ms for vbus to be stable */
+	msleep(50);
+	if (cpu_is_asr1901() || cpu_is_asr1906())
+		writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+			| USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR
+			| USB_ID_WAKE_CLR | USB_RXELEC_WAKE_CLR,
+			apmu_base + APMU_USB_WAKE_CLR);
+	else
+		writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+			| (USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR | USB_RXELEC_WAKE_CLR
+			| USB_ID_WAKE_CLR | USB_WAKE_INT_EN),
+			apmu_base + APMU_USB_WAKE_CLR);
+
+	pm_wakeup_event(adwc->dev, USB_HANDLE_TIME_MSEC);
+	pxa_usb_notify(PXA_USB_DEV_OTG, EVENT_VBUS, 0);
+	dev_info(adwc->dev, "asr-usb vbus interrupt is served..\n");
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_DWC3_HWSULOG
+static irqreturn_t sulog_irq_handler(int irq, void *dev)
+{
+	hwsulog_error_handler();
+
+	return IRQ_HANDLED;
+}
+#endif
+
+static int dwc3_asr_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct dwc3_asr *adwc;
+	int ret;
+	void __iomem *apmu_base;
+
+	adwc = devm_kzalloc(&pdev->dev, sizeof(*adwc), GFP_KERNEL);
+	if (!adwc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, adwc);
+
+	adwc->dev = &pdev->dev;
+
+	adwc->usb_clk = devm_clk_get(adwc->dev, NULL);
+	if (IS_ERR(adwc->usb_clk)) {
+		dev_err(adwc->dev, "failed to get core clock\n");
+		return PTR_ERR(adwc->usb_clk);
+	}
+
+	ret = clk_prepare_enable(adwc->usb_clk);
+	if (ret) {
+		dev_err(adwc->dev, "failed to enable core clock\n");
+		goto err_core;
+	}
+
+	ret = of_platform_populate(node, NULL, NULL, adwc->dev);
+	if (ret) {
+		dev_err(adwc->dev, "failed to register core - %d\n", ret);
+		goto err_iface;
+	}
+
+	adwc->vbus_irq = platform_get_irq(pdev, 0);
+	if (adwc->vbus_irq < 0) {
+		dev_err(&pdev->dev, "failed to get vbus irq\n");
+		ret = -ENXIO;
+		goto err_iface;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, adwc->vbus_irq,
+					NULL, vbus_irq,
+					IRQF_ONESHOT | IRQF_NO_SUSPEND,
+					"asr-usb-vbus", adwc);
+	if (ret) {
+		dev_info(&pdev->dev,
+			"Can not request irq for VBUS\n");
+		goto err_iface;
+	}
+
+#ifdef CONFIG_DWC3_HWSULOG
+	adwc->sulog_irq = platform_get_irq(pdev, 1);
+	if (adwc->sulog_irq < 0) {
+		dev_info(&pdev->dev, "no sulog irq\n");
+	} else {
+		ret = devm_request_threaded_irq(&pdev->dev, adwc->sulog_irq,
+						NULL, sulog_irq_handler,
+						IRQF_ONESHOT | IRQF_SHARED,
+						"dwc3-sulog-irq", adwc);
+		if (ret) {
+			dev_info(&pdev->dev,
+				"Can not request irq for dwc3 sulog %d\n", ret);
+			goto err_iface;
+		}
+	}
+#endif
+
+	apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+	writel(readl(apmu_base + APMU_USB_WAKE_CLR) | USB_WAKE_INT_EN | USB_VBUS_WAKE_EN,
+		apmu_base + APMU_USB_WAKE_CLR);
+	writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+		| (USB_WAKE_INT_EN | USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR | USB_ID_WAKE_CLR),
+		apmu_base + APMU_USB_WAKE_CLR);
+
+	platform_set_drvdata(pdev, adwc);
+	device_init_wakeup(&pdev->dev, 1);
+
+	dev_info(&pdev->dev, "%s done\n", __func__);
+
+	return 0;
+
+err_iface:
+	clk_disable_unprepare(adwc->usb_clk);
+err_core:
+	return ret;
+}
+
+static int dwc3_asr_remove(struct platform_device *pdev)
+{
+	struct dwc3_asr *adwc = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(adwc->usb_clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_asr_suspend_noirq(struct device *dev)
+{
+	struct dwc3_asr *adwc = dev_get_drvdata(dev);
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+	struct dwc3 *dwc = dwc3_get_controller();
+
+	writel(readl(apmu_base + APMU_USB_WAKE_CLR)
+		| (USB_WAKE_INT_EN | USB_WAKE_PMU_EN
+		| USB_LINEST_WAKE_EN | USB_ID_WAKE_EN | USB_RXELEC_WAKE_EN
+		| USB_VBUS_WAKE_CLR | USB_LINEST_WAKE_CLR
+		| USB_ID_WAKE_CLR | USB_RXELEC_WAKE_CLR),
+		apmu_base + APMU_USB_WAKE_CLR);
+
+	if (dwc->allow_suspend) {
+		if (dwc->link_state == DWC3_LINK_STATE_U3)
+			usb_phy_set_suspend2(dwc->usb2_phy, 1);
+		else
+			pr_info("dwc3 linkst: %d\n", dwc->link_state);
+	}
+
+	enable_irq_wake(adwc->vbus_irq);
+
+	dwc3_release_pm_qos();
+	return 0;
+}
+
+static int dwc3_asr_resume_noirq(struct device *dev)
+{
+	volatile u32 value;
+	void __iomem *apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
+	struct dwc3_asr *adwc = dev_get_drvdata(dev);
+	struct dwc3 *dwc = dwc3_get_controller();
+
+	if (dwc->allow_suspend) {
+		if (dwc->vbus_active) {
+			dwc3_acquire_pm_qos();
+			usb_phy_set_suspend2(dwc->usb2_phy, 0);
+		} else {
+			pr_info("dwc3 vbus off, linkst: %d\n", dwc->link_state);
+		}
+	}
+
+	/* clear linestat wakeup and disable linestat/pmu wake en */
+	value = readl(apmu_base + APMU_USB_WAKE_CLR);
+	value |= (USB_WAKE_INT_EN | USB_LINEST_WAKE_CLR | USB_RXELEC_WAKE_CLR);
+	writel(value, apmu_base + APMU_USB_WAKE_CLR);
+	udelay(50);
+
+	value = readl(apmu_base + APMU_USB_WAKE_CLR);
+	value &= ~(USB_WAKE_PMU_EN | USB_LINEST_WAKE_EN | USB_RXELEC_WAKE_EN);
+	value |= (USB_VBUS_WAKE_EN | USB_ID_WAKE_EN | USB_WAKE_INT_EN);	
+	writel(value, apmu_base + APMU_USB_WAKE_CLR);
+
+	disable_irq_wake(adwc->vbus_irq);
+	return 0;
+}
+
+static const struct dev_pm_ops dwc3_asr_pm_ops = {
+	.suspend_noirq = dwc3_asr_suspend_noirq,
+	.resume_noirq = dwc3_asr_resume_noirq,
+};
+#endif
+
+static const struct of_device_id of_dwc3_match[] = {
+	{ .compatible = "asr,dwc3" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_match);
+
+static struct platform_driver dwc3_asr_driver = {
+	.probe		= dwc3_asr_probe,
+	.remove		= dwc3_asr_remove,
+	.driver		= {
+		.name	= "asr-dwc3",
+		.of_match_table	= of_dwc3_match,
+#ifdef CONFIG_PM_SLEEP
+		.pm = &dwc3_asr_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(dwc3_asr_driver);
+
+MODULE_ALIAS("platform:asr-dwc3");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASR USB Glue Layer");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-exynos.c b/marvell/linux/drivers/usb/dwc3/dwc3-exynos.c
new file mode 100644
index 0000000..c594e3e
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-exynos.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
+
+#define DWC3_EXYNOS_MAX_CLOCKS	4
+
+struct dwc3_exynos_driverdata {
+	const char		*clk_names[DWC3_EXYNOS_MAX_CLOCKS];
+	int			num_clks;
+	int			suspend_clk_idx;
+};
+
+struct dwc3_exynos {
+	struct device		*dev;
+
+	const char		**clk_names;
+	struct clk		*clks[DWC3_EXYNOS_MAX_CLOCKS];
+	int			num_clks;
+	int			suspend_clk_idx;
+
+	struct regulator	*vdd33;
+	struct regulator	*vdd10;
+};
+
+static int dwc3_exynos_probe(struct platform_device *pdev)
+{
+	struct dwc3_exynos	*exynos;
+	struct device		*dev = &pdev->dev;
+	struct device_node	*node = dev->of_node;
+	const struct dwc3_exynos_driverdata *driver_data;
+	int			i, ret;
+
+	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
+	if (!exynos)
+		return -ENOMEM;
+
+	driver_data = of_device_get_match_data(dev);
+	exynos->dev = dev;
+	exynos->num_clks = driver_data->num_clks;
+	exynos->clk_names = (const char **)driver_data->clk_names;
+	exynos->suspend_clk_idx = driver_data->suspend_clk_idx;
+
+	platform_set_drvdata(pdev, exynos);
+
+	for (i = 0; i < exynos->num_clks; i++) {
+		exynos->clks[i] = devm_clk_get(dev, exynos->clk_names[i]);
+		if (IS_ERR(exynos->clks[i])) {
+			dev_err(dev, "failed to get clock: %s\n",
+				exynos->clk_names[i]);
+			return PTR_ERR(exynos->clks[i]);
+		}
+	}
+
+	for (i = 0; i < exynos->num_clks; i++) {
+		ret = clk_prepare_enable(exynos->clks[i]);
+		if (ret) {
+			while (i-- > 0)
+				clk_disable_unprepare(exynos->clks[i]);
+			return ret;
+		}
+	}
+
+	if (exynos->suspend_clk_idx >= 0)
+		clk_prepare_enable(exynos->clks[exynos->suspend_clk_idx]);
+
+	exynos->vdd33 = devm_regulator_get(dev, "vdd33");
+	if (IS_ERR(exynos->vdd33)) {
+		ret = PTR_ERR(exynos->vdd33);
+		goto vdd33_err;
+	}
+	ret = regulator_enable(exynos->vdd33);
+	if (ret) {
+		dev_err(dev, "Failed to enable VDD33 supply\n");
+		goto vdd33_err;
+	}
+
+	exynos->vdd10 = devm_regulator_get(dev, "vdd10");
+	if (IS_ERR(exynos->vdd10)) {
+		ret = PTR_ERR(exynos->vdd10);
+		goto vdd10_err;
+	}
+	ret = regulator_enable(exynos->vdd10);
+	if (ret) {
+		dev_err(dev, "Failed to enable VDD10 supply\n");
+		goto vdd10_err;
+	}
+
+	if (node) {
+		ret = of_platform_populate(node, NULL, NULL, dev);
+		if (ret) {
+			dev_err(dev, "failed to add dwc3 core\n");
+			goto populate_err;
+		}
+	} else {
+		dev_err(dev, "no device node, failed to add dwc3 core\n");
+		ret = -ENODEV;
+		goto populate_err;
+	}
+
+	return 0;
+
+populate_err:
+	regulator_disable(exynos->vdd10);
+vdd10_err:
+	regulator_disable(exynos->vdd33);
+vdd33_err:
+	for (i = exynos->num_clks - 1; i >= 0; i--)
+		clk_disable_unprepare(exynos->clks[i]);
+
+	if (exynos->suspend_clk_idx >= 0)
+		clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]);
+
+	return ret;
+}
+
+static int dwc3_exynos_remove(struct platform_device *pdev)
+{
+	struct dwc3_exynos	*exynos = platform_get_drvdata(pdev);
+	int i;
+
+	of_platform_depopulate(&pdev->dev);
+
+	for (i = exynos->num_clks - 1; i >= 0; i--)
+		clk_disable_unprepare(exynos->clks[i]);
+
+	if (exynos->suspend_clk_idx >= 0)
+		clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]);
+
+	regulator_disable(exynos->vdd33);
+	regulator_disable(exynos->vdd10);
+
+	return 0;
+}
+
+static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
+	.clk_names = { "usbdrd30" },
+	.num_clks = 1,
+	.suspend_clk_idx = -1,
+};
+
+static const struct dwc3_exynos_driverdata exynos5433_drvdata = {
+	.clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
+	.num_clks = 4,
+	.suspend_clk_idx = 1,
+};
+
+static const struct dwc3_exynos_driverdata exynos7_drvdata = {
+	.clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" },
+	.num_clks = 3,
+	.suspend_clk_idx = 1,
+};
+
+static const struct of_device_id exynos_dwc3_match[] = {
+	{
+		.compatible = "samsung,exynos5250-dwusb3",
+		.data = &exynos5250_drvdata,
+	}, {
+		.compatible = "samsung,exynos5433-dwusb3",
+		.data = &exynos5433_drvdata,
+	}, {
+		.compatible = "samsung,exynos7-dwusb3",
+		.data = &exynos7_drvdata,
+	}, {
+	}
+};
+MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_exynos_suspend(struct device *dev)
+{
+	struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+	int i;
+
+	for (i = exynos->num_clks - 1; i >= 0; i--)
+		clk_disable_unprepare(exynos->clks[i]);
+
+	regulator_disable(exynos->vdd33);
+	regulator_disable(exynos->vdd10);
+
+	return 0;
+}
+
+static int dwc3_exynos_resume(struct device *dev)
+{
+	struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+	int i, ret;
+
+	ret = regulator_enable(exynos->vdd33);
+	if (ret) {
+		dev_err(dev, "Failed to enable VDD33 supply\n");
+		return ret;
+	}
+	ret = regulator_enable(exynos->vdd10);
+	if (ret) {
+		dev_err(dev, "Failed to enable VDD10 supply\n");
+		return ret;
+	}
+
+	for (i = 0; i < exynos->num_clks; i++) {
+		ret = clk_prepare_enable(exynos->clks[i]);
+		if (ret) {
+			while (i-- > 0)
+				clk_disable_unprepare(exynos->clks[i]);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
+};
+
+#define DEV_PM_OPS	(&dwc3_exynos_dev_pm_ops)
+#else
+#define DEV_PM_OPS	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver dwc3_exynos_driver = {
+	.probe		= dwc3_exynos_probe,
+	.remove		= dwc3_exynos_remove,
+	.driver		= {
+		.name	= "exynos-dwc3",
+		.of_match_table = exynos_dwc3_match,
+		.pm	= DEV_PM_OPS,
+	},
+};
+
+module_platform_driver(dwc3_exynos_driver);
+
+MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-haps.c b/marvell/linux/drivers/usb/dwc3/dwc3-haps.c
new file mode 100644
index 0000000..3cecbf1
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-haps.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-haps.c - Synopsys HAPS PCI Specific glue layer
+ *
+ * Copyright (C) 2018 Synopsys, Inc.
+ *
+ * Authors: Thinh Nguyen <thinhn@synopsys.com>,
+ *          John Youn <johnyoun@synopsys.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+/**
+ * struct dwc3_haps - Driver private structure
+ * @dwc3: child dwc3 platform_device
+ * @pci: our link to PCI bus
+ */
+struct dwc3_haps {
+	struct platform_device *dwc3;
+	struct pci_dev *pci;
+};
+
+static const struct property_entry initial_properties[] = {
+	PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
+	PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+	PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{ },
+};
+
+static int dwc3_haps_probe(struct pci_dev *pci,
+			   const struct pci_device_id *id)
+{
+	struct dwc3_haps	*dwc;
+	struct device		*dev = &pci->dev;
+	struct resource		res[2];
+	int			ret;
+
+	ret = pcim_enable_device(pci);
+	if (ret) {
+		dev_err(dev, "failed to enable pci device\n");
+		return -ENODEV;
+	}
+
+	pci_set_master(pci);
+
+	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
+	if (!dwc)
+		return -ENOMEM;
+
+	dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
+	if (!dwc->dwc3)
+		return -ENOMEM;
+
+	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+	res[0].start	= pci_resource_start(pci, 0);
+	res[0].end	= pci_resource_end(pci, 0);
+	res[0].name	= "dwc_usb3";
+	res[0].flags	= IORESOURCE_MEM;
+
+	res[1].start	= pci->irq;
+	res[1].name	= "dwc_usb3";
+	res[1].flags	= IORESOURCE_IRQ;
+
+	ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
+	if (ret) {
+		dev_err(dev, "couldn't add resources to dwc3 device\n");
+		goto err;
+	}
+
+	dwc->pci = pci;
+	dwc->dwc3->dev.parent = dev;
+
+	ret = platform_device_add_properties(dwc->dwc3, initial_properties);
+	if (ret)
+		goto err;
+
+	ret = platform_device_add(dwc->dwc3);
+	if (ret) {
+		dev_err(dev, "failed to register dwc3 device\n");
+		goto err;
+	}
+
+	pci_set_drvdata(pci, dwc);
+
+	return 0;
+err:
+	platform_device_put(dwc->dwc3);
+	return ret;
+}
+
+static void dwc3_haps_remove(struct pci_dev *pci)
+{
+	struct dwc3_haps *dwc = pci_get_drvdata(pci);
+
+	platform_device_unregister(dwc->dwc3);
+}
+
+static const struct pci_device_id dwc3_haps_id_table[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+			   PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+		/*
+		 * i.MX6QP and i.MX7D platform use a PCIe controller with the
+		 * same VID and PID as this USB controller. The system may
+		 * incorrectly match this driver to that PCIe controller. To
+		 * workaround this, specifically use class type USB to prevent
+		 * incorrect driver matching.
+		 */
+		.class = (PCI_CLASS_SERIAL_USB << 8),
+		.class_mask = 0xffff00,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+			   PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+			   PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
+	},
+	{  }	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_haps_id_table);
+
+static struct pci_driver dwc3_haps_driver = {
+	.name		= "dwc3-haps",
+	.id_table	= dwc3_haps_id_table,
+	.probe		= dwc3_haps_probe,
+	.remove		= dwc3_haps_remove,
+};
+
+MODULE_AUTHOR("Thinh Nguyen <thinhn@synopsys.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys HAPS PCI Glue Layer");
+
+module_pci_driver(dwc3_haps_driver);
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-keystone.c b/marvell/linux/drivers/usb/dwc3/dwc3-keystone.c
new file mode 100644
index 0000000..1e14a6f
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-keystone.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-keystone.c - Keystone Specific Glue layer
+ *
+ * Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: WingMan Kwok <w-kwok2@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+/* USBSS register offsets */
+#define USBSS_REVISION		0x0000
+#define USBSS_SYSCONFIG		0x0010
+#define USBSS_IRQ_EOI		0x0018
+#define USBSS_IRQSTATUS_RAW_0	0x0020
+#define USBSS_IRQSTATUS_0	0x0024
+#define USBSS_IRQENABLE_SET_0	0x0028
+#define USBSS_IRQENABLE_CLR_0	0x002c
+
+/* IRQ register bits */
+#define USBSS_IRQ_EOI_LINE(n)	BIT(n)
+#define USBSS_IRQ_EVENT_ST	BIT(0)
+#define USBSS_IRQ_COREIRQ_EN	BIT(0)
+#define USBSS_IRQ_COREIRQ_CLR	BIT(0)
+
+struct dwc3_keystone {
+	struct device			*dev;
+	void __iomem			*usbss;
+};
+
+static inline u32 kdwc3_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void kdwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+static void kdwc3_enable_irqs(struct dwc3_keystone *kdwc)
+{
+	u32 val;
+
+	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0);
+	val |= USBSS_IRQ_COREIRQ_EN;
+	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val);
+}
+
+static void kdwc3_disable_irqs(struct dwc3_keystone *kdwc)
+{
+	u32 val;
+
+	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0);
+	val &= ~USBSS_IRQ_COREIRQ_EN;
+	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val);
+}
+
+static irqreturn_t dwc3_keystone_interrupt(int irq, void *_kdwc)
+{
+	struct dwc3_keystone	*kdwc = _kdwc;
+
+	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_CLR_0, USBSS_IRQ_COREIRQ_CLR);
+	kdwc3_writel(kdwc->usbss, USBSS_IRQSTATUS_0, USBSS_IRQ_EVENT_ST);
+	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, USBSS_IRQ_COREIRQ_EN);
+	kdwc3_writel(kdwc->usbss, USBSS_IRQ_EOI, USBSS_IRQ_EOI_LINE(0));
+
+	return IRQ_HANDLED;
+}
+
+static int kdwc3_probe(struct platform_device *pdev)
+{
+	struct device		*dev = &pdev->dev;
+	struct device_node	*node = pdev->dev.of_node;
+	struct dwc3_keystone	*kdwc;
+	int			error, irq;
+
+	kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL);
+	if (!kdwc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, kdwc);
+
+	kdwc->dev = dev;
+
+	kdwc->usbss = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(kdwc->usbss))
+		return PTR_ERR(kdwc->usbss);
+
+	pm_runtime_enable(kdwc->dev);
+
+	error = pm_runtime_get_sync(kdwc->dev);
+	if (error < 0) {
+		dev_err(kdwc->dev, "pm_runtime_get_sync failed, error %d\n",
+			error);
+		goto err_irq;
+	}
+
+	/* IRQ processing not required currently for AM65 */
+	if (of_device_is_compatible(node, "ti,am654-dwc3"))
+		goto skip_irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		error = irq;
+		goto err_irq;
+	}
+
+	error = devm_request_irq(dev, irq, dwc3_keystone_interrupt, IRQF_SHARED,
+			dev_name(dev), kdwc);
+	if (error) {
+		dev_err(dev, "failed to request IRQ #%d --> %d\n",
+				irq, error);
+		goto err_irq;
+	}
+
+	kdwc3_enable_irqs(kdwc);
+
+skip_irq:
+	error = of_platform_populate(node, NULL, NULL, dev);
+	if (error) {
+		dev_err(&pdev->dev, "failed to create dwc3 core\n");
+		goto err_core;
+	}
+
+	return 0;
+
+err_core:
+	kdwc3_disable_irqs(kdwc);
+err_irq:
+	pm_runtime_put_sync(kdwc->dev);
+	pm_runtime_disable(kdwc->dev);
+
+	return error;
+}
+
+static int kdwc3_remove_core(struct device *dev, void *c)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	platform_device_unregister(pdev);
+
+	return 0;
+}
+
+static int kdwc3_remove(struct platform_device *pdev)
+{
+	struct dwc3_keystone *kdwc = platform_get_drvdata(pdev);
+	struct device_node *node = pdev->dev.of_node;
+
+	if (!of_device_is_compatible(node, "ti,am654-dwc3"))
+		kdwc3_disable_irqs(kdwc);
+
+	device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core);
+	pm_runtime_put_sync(kdwc->dev);
+	pm_runtime_disable(kdwc->dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id kdwc3_of_match[] = {
+	{ .compatible = "ti,keystone-dwc3", },
+	{ .compatible = "ti,am654-dwc3" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, kdwc3_of_match);
+
+static struct platform_driver kdwc3_driver = {
+	.probe		= kdwc3_probe,
+	.remove		= kdwc3_remove,
+	.driver		= {
+		.name	= "keystone-dwc3",
+		.of_match_table	= kdwc3_of_match,
+	},
+};
+
+module_platform_driver(kdwc3_driver);
+
+MODULE_ALIAS("platform:keystone-dwc3");
+MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 KEYSTONE Glue Layer");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-meson-g12a.c b/marvell/linux/drivers/usb/dwc3/dwc3-meson-g12a.c
new file mode 100644
index 0000000..8a3ec1a
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -0,0 +1,640 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB Glue for Amlogic G12A SoCs
+ *
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+/*
+ * The USB is organized with a glue around the DWC3 Controller IP as :
+ * - Control registers for each USB2 Ports
+ * - Control registers for the USB PHY layer
+ * - SuperSpeed PHY can be enabled only if port is used
+ * - Dynamic OTG switching with ID change interrupt
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/reset.h>
+#include <linux/phy/phy.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/role.h>
+#include <linux/regulator/consumer.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 device		*dev;
+	struct regmap		*regmap;
+	struct clk		*clk;
+	struct reset_control	*reset;
+	struct phy		*phys[PHY_COUNT];
+	enum usb_dr_mode	otg_mode;
+	enum phy_mode		otg_phy_mode;
+	unsigned int		usb2_ports;
+	unsigned int		usb3_ports;
+	struct regulator	*vbus;
+	struct usb_role_switch_desc switch_desc;
+	struct usb_role_switch	*role_switch;
+};
+
+static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
+					  int i, enum phy_mode mode)
+{
+	if (mode == PHY_MODE_USB_HOST)
+		regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+				U2P_R0_HOST_DEVICE,
+				U2P_R0_HOST_DEVICE);
+	else
+		regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
+				U2P_R0_HOST_DEVICE, 0);
+}
+
+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 = PHY_MODE_USB_DEVICE;
+	else
+		priv->otg_phy_mode = PHY_MODE_USB_HOST;
+
+	for (i = 0 ; i < USB3_HOST_PHY ; ++i) {
+		if (!priv->phys[i])
+			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,
+						      PHY_MODE_USB_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_otg_apply_mode(struct dwc3_meson_g12a *priv)
+{
+	if (priv->otg_phy_mode == PHY_MODE_USB_DEVICE) {
+		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_otg_apply_mode(priv);
+
+	return 0;
+}
+
+static const struct regmap_config phy_meson_g12a_usb3_regmap_conf = {
+	.reg_bits = 8,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = USB_R5,
+};
+
+static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
+{
+	int i;
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		priv->phys[i] = devm_phy_optional_get(priv->dev, phy_names[i]);
+		if (!priv->phys[i])
+			continue;
+
+		if (IS_ERR(priv->phys[i]))
+			return PTR_ERR(priv->phys[i]);
+
+		if (i == USB3_HOST_PHY)
+			priv->usb3_ports++;
+		else
+			priv->usb2_ports++;
+	}
+
+	dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports);
+	dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports);
+
+	return 0;
+}
+
+static enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv)
+{
+	u32 reg;
+
+	regmap_read(priv->regmap, USB_R5, &reg);
+
+	if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG))
+		return PHY_MODE_USB_DEVICE;
+
+	return PHY_MODE_USB_HOST;
+}
+
+static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
+					enum phy_mode mode)
+{
+	int ret;
+
+	if (!priv->phys[USB2_OTG_PHY])
+		return -EINVAL;
+
+	if (mode == PHY_MODE_USB_HOST)
+		dev_info(priv->dev, "switching to Host Mode\n");
+	else
+		dev_info(priv->dev, "switching to Device Mode\n");
+
+	if (priv->vbus) {
+		if (mode == PHY_MODE_USB_DEVICE)
+			ret = regulator_disable(priv->vbus);
+		else
+			ret = regulator_enable(priv->vbus);
+		if (ret)
+			return ret;
+	}
+
+	priv->otg_phy_mode = mode;
+
+	dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode);
+
+	dwc3_meson_g12a_usb_otg_apply_mode(priv);
+
+	return 0;
+}
+
+static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role)
+{
+	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
+	enum phy_mode mode;
+
+	if (role == USB_ROLE_NONE)
+		return 0;
+
+	mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST
+				       : PHY_MODE_USB_DEVICE;
+
+	if (mode == priv->otg_phy_mode)
+		return 0;
+
+	return dwc3_meson_g12a_otg_mode_set(priv, mode);
+}
+
+static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
+{
+	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
+
+	return priv->otg_phy_mode == PHY_MODE_USB_HOST ?
+		USB_ROLE_HOST : USB_ROLE_DEVICE;
+}
+
+static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
+{
+	struct dwc3_meson_g12a *priv = data;
+	enum phy_mode otg_id;
+
+	otg_id = dwc3_meson_g12a_get_id(priv);
+	if (otg_id != priv->otg_phy_mode) {
+		if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
+			dev_warn(priv->dev, "Failed to switch OTG mode\n");
+	}
+
+	regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+
+	return IRQ_HANDLED;
+}
+
+static struct device *dwc3_meson_g12_find_child(struct device *dev,
+						const char *compatible)
+{
+	struct platform_device *pdev;
+	struct device_node *np;
+
+	np = of_get_compatible_child(dev->of_node, compatible);
+	if (!np)
+		return NULL;
+
+	pdev = of_find_device_by_node(np);
+	of_node_put(np);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+
+static int dwc3_meson_g12a_probe(struct platform_device *pdev)
+{
+	struct dwc3_meson_g12a	*priv;
+	struct device		*dev = &pdev->dev;
+	struct device_node	*np = dev->of_node;
+	void __iomem *base;
+	enum phy_mode otg_id;
+	int ret, i, irq;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	priv->regmap = devm_regmap_init_mmio(dev, base,
+					     &phy_meson_g12a_usb3_regmap_conf);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	priv->vbus = devm_regulator_get_optional(dev, "vbus");
+	if (IS_ERR(priv->vbus)) {
+		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
+			return PTR_ERR(priv->vbus);
+		priv->vbus = NULL;
+	}
+
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret)
+		return ret;
+
+	devm_add_action_or_reset(dev,
+				 (void(*)(void *))clk_disable_unprepare,
+				 priv->clk);
+
+	platform_set_drvdata(pdev, priv);
+	priv->dev = dev;
+
+	priv->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(priv->reset)) {
+		ret = PTR_ERR(priv->reset);
+		dev_err(dev, "failed to get device reset, err=%d\n", ret);
+		return ret;
+	}
+
+	ret = reset_control_reset(priv->reset);
+	if (ret)
+		return ret;
+
+	ret = dwc3_meson_g12a_get_phys(priv);
+	if (ret)
+		return ret;
+
+	if (priv->vbus) {
+		ret = regulator_enable(priv->vbus);
+		if (ret)
+			return ret;
+	}
+
+	/* Get dr_mode */
+	priv->otg_mode = usb_get_dr_mode(dev);
+
+	if (priv->otg_mode == USB_DR_MODE_OTG) {
+		/* Ack irq before registering */
+		regmap_update_bits(priv->regmap, USB_R5,
+				   USB_R5_ID_DIG_IRQ, 0);
+
+		irq = platform_get_irq(pdev, 0);
+		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+						dwc3_meson_g12a_irq_thread,
+						IRQF_ONESHOT, pdev->name, priv);
+		if (ret)
+			return ret;
+	}
+
+	dwc3_meson_g12a_usb_init(priv);
+
+	/* Init PHYs */
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		ret = phy_init(priv->phys[i]);
+		if (ret)
+			return ret;
+	}
+
+	/* Set PHY Power */
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		ret = phy_power_on(priv->phys[i]);
+		if (ret)
+			goto err_phys_exit;
+	}
+
+	ret = of_platform_populate(np, NULL, NULL, dev);
+	if (ret) {
+		clk_disable_unprepare(priv->clk);
+		goto err_phys_power;
+	}
+
+	/* Setup OTG mode corresponding to the ID pin */
+	if (priv->otg_mode == USB_DR_MODE_OTG) {
+		otg_id = dwc3_meson_g12a_get_id(priv);
+		if (otg_id != priv->otg_phy_mode) {
+			if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
+				dev_warn(dev, "Failed to switch OTG mode\n");
+		}
+	}
+
+	/* Setup role switcher */
+	priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
+								"snps,dwc3");
+	priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
+	priv->switch_desc.allow_userspace_control = true;
+	priv->switch_desc.set = dwc3_meson_g12a_role_set;
+	priv->switch_desc.get = dwc3_meson_g12a_role_get;
+
+	priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
+	if (IS_ERR(priv->role_switch))
+		dev_warn(dev, "Unable to register Role Switch\n");
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	return 0;
+
+err_phys_power:
+	for (i = 0 ; i < PHY_COUNT ; ++i)
+		phy_power_off(priv->phys[i]);
+
+err_phys_exit:
+	for (i = 0 ; i < PHY_COUNT ; ++i)
+		phy_exit(priv->phys[i]);
+
+	return ret;
+}
+
+static int dwc3_meson_g12a_remove(struct platform_device *pdev)
+{
+	struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	int i;
+
+	usb_role_switch_unregister(priv->role_switch);
+
+	of_platform_depopulate(dev);
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		phy_power_off(priv->phys[i]);
+		phy_exit(priv->phys[i]);
+	}
+
+	pm_runtime_disable(dev);
+	pm_runtime_put_noidle(dev);
+	pm_runtime_set_suspended(dev);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev)
+{
+	struct dwc3_meson_g12a	*priv = dev_get_drvdata(dev);
+
+	clk_disable(priv->clk);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev)
+{
+	struct dwc3_meson_g12a	*priv = dev_get_drvdata(dev);
+
+	return clk_enable(priv->clk);
+}
+
+static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
+{
+	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
+	int i, ret;
+
+	if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
+		ret = regulator_disable(priv->vbus);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		phy_power_off(priv->phys[i]);
+		phy_exit(priv->phys[i]);
+	}
+
+	reset_control_assert(priv->reset);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
+{
+	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
+	int i, ret;
+
+	reset_control_deassert(priv->reset);
+
+	dwc3_meson_g12a_usb_init(priv);
+
+	/* Init PHYs */
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		ret = phy_init(priv->phys[i]);
+		if (ret)
+			return ret;
+	}
+
+	/* Set PHY Power */
+	for (i = 0 ; i < PHY_COUNT ; ++i) {
+		ret = phy_power_on(priv->phys[i]);
+		if (ret)
+			return ret;
+	}
+
+       if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
+               ret = regulator_enable(priv->vbus);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume)
+	SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend,
+			   dwc3_meson_g12a_runtime_resume, NULL)
+};
+
+static const struct of_device_id dwc3_meson_g12a_match[] = {
+	{ .compatible = "amlogic,meson-g12a-usb-ctrl" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
+
+static struct platform_driver dwc3_meson_g12a_driver = {
+	.probe		= dwc3_meson_g12a_probe,
+	.remove		= dwc3_meson_g12a_remove,
+	.driver		= {
+		.name	= "dwc3-meson-g12a",
+		.of_match_table = dwc3_meson_g12a_match,
+		.pm	= &dwc3_meson_g12a_dev_pm_ops,
+	},
+};
+
+module_platform_driver(dwc3_meson_g12a_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-of-simple.c b/marvell/linux/drivers/usb/dwc3/dwc3-of-simple.c
new file mode 100644
index 0000000..d055e00
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-of-simple.c
@@ -0,0 +1,204 @@
+// 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>
+ *
+ * This is a combination of the old dwc3-qcom.c by Ivan T. Ivanov
+ * <iivanov@mm-sol.com> and the original patch adding support for Xilinx' SoC
+ * by Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+struct dwc3_of_simple {
+	struct device		*dev;
+	struct clk_bulk_data	*clks;
+	int			num_clocks;
+	struct reset_control	*resets;
+	bool			pulse_resets;
+	bool			need_reset;
+};
+
+static int dwc3_of_simple_probe(struct platform_device *pdev)
+{
+	struct dwc3_of_simple	*simple;
+	struct device		*dev = &pdev->dev;
+	struct device_node	*np = dev->of_node;
+
+	int			ret;
+	bool			shared_resets = false;
+
+	simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
+	if (!simple)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, simple);
+	simple->dev = dev;
+
+	/*
+	 * Some controllers need to toggle the usb3-otg reset before trying to
+	 * initialize the PHY, otherwise the PHY times out.
+	 */
+	if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
+		simple->need_reset = true;
+
+	if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
+	    of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
+		shared_resets = true;
+		simple->pulse_resets = true;
+	}
+
+	simple->resets = of_reset_control_array_get(np, shared_resets, true,
+						    true);
+	if (IS_ERR(simple->resets)) {
+		ret = PTR_ERR(simple->resets);
+		dev_err(dev, "failed to get device resets, err=%d\n", ret);
+		return ret;
+	}
+
+	if (simple->pulse_resets) {
+		ret = reset_control_reset(simple->resets);
+		if (ret)
+			goto err_resetc_put;
+	} else {
+		ret = reset_control_deassert(simple->resets);
+		if (ret)
+			goto err_resetc_put;
+	}
+
+	ret = clk_bulk_get_all(simple->dev, &simple->clks);
+	if (ret < 0)
+		goto err_resetc_assert;
+
+	simple->num_clocks = ret;
+	ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks);
+	if (ret)
+		goto err_resetc_assert;
+
+	ret = of_platform_populate(np, NULL, NULL, dev);
+	if (ret)
+		goto err_clk_put;
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	return 0;
+
+err_clk_put:
+	clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
+	clk_bulk_put_all(simple->num_clocks, simple->clks);
+
+err_resetc_assert:
+	if (!simple->pulse_resets)
+		reset_control_assert(simple->resets);
+
+err_resetc_put:
+	reset_control_put(simple->resets);
+	return ret;
+}
+
+static int dwc3_of_simple_remove(struct platform_device *pdev)
+{
+	struct dwc3_of_simple	*simple = platform_get_drvdata(pdev);
+	struct device		*dev = &pdev->dev;
+
+	of_platform_depopulate(dev);
+
+	clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
+	clk_bulk_put_all(simple->num_clocks, simple->clks);
+	simple->num_clocks = 0;
+
+	if (!simple->pulse_resets)
+		reset_control_assert(simple->resets);
+
+	reset_control_put(simple->resets);
+
+	pm_runtime_disable(dev);
+	pm_runtime_put_noidle(dev);
+	pm_runtime_set_suspended(dev);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev)
+{
+	struct dwc3_of_simple	*simple = dev_get_drvdata(dev);
+
+	clk_bulk_disable(simple->num_clocks, simple->clks);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev)
+{
+	struct dwc3_of_simple	*simple = dev_get_drvdata(dev);
+
+	return clk_bulk_enable(simple->num_clocks, simple->clks);
+}
+
+static int __maybe_unused dwc3_of_simple_suspend(struct device *dev)
+{
+	struct dwc3_of_simple *simple = dev_get_drvdata(dev);
+
+	if (simple->need_reset)
+		reset_control_assert(simple->resets);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_of_simple_resume(struct device *dev)
+{
+	struct dwc3_of_simple *simple = dev_get_drvdata(dev);
+
+	if (simple->need_reset)
+		reset_control_deassert(simple->resets);
+
+	return 0;
+}
+
+static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume)
+	SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
+			dwc3_of_simple_runtime_resume, NULL)
+};
+
+static const struct of_device_id of_dwc3_simple_match[] = {
+	{ .compatible = "rockchip,rk3399-dwc3" },
+	{ .compatible = "xlnx,zynqmp-dwc3" },
+	{ .compatible = "cavium,octeon-7130-usb-uctl" },
+	{ .compatible = "sprd,sc9860-dwc3" },
+	{ .compatible = "amlogic,meson-axg-dwc3" },
+	{ .compatible = "amlogic,meson-gxl-dwc3" },
+	{ .compatible = "allwinner,sun50i-h6-dwc3" },
+	{ .compatible = "hisilicon,hi3670-dwc3" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
+
+static struct platform_driver dwc3_of_simple_driver = {
+	.probe		= dwc3_of_simple_probe,
+	.remove		= dwc3_of_simple_remove,
+	.driver		= {
+		.name	= "dwc3-of-simple",
+		.of_match_table = of_dwc3_simple_match,
+		.pm	= &dwc3_of_simple_dev_pm_ops,
+	},
+};
+
+module_platform_driver(dwc3_of_simple_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-omap.c b/marvell/linux/drivers/usb/dwc3/dwc3-omap.c
new file mode 100644
index 0000000..5465b35
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-omap.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/extcon.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/usb/otg.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_STATUS		0x0080
+#define USBOTGSS_UTMI_OTG_CTRL			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		BIT(16)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER		BIT(0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST		BIT(0)
+
+/* IRQMISC BITS */
+#define USBOTGSS_IRQMISC_DMADISABLECLR		BIT(17)
+#define USBOTGSS_IRQMISC_OEVT			BIT(16)
+#define USBOTGSS_IRQMISC_DRVVBUS_RISE		BIT(13)
+#define USBOTGSS_IRQMISC_CHRGVBUS_RISE		BIT(12)
+#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE	BIT(11)
+#define USBOTGSS_IRQMISC_IDPULLUP_RISE		BIT(8)
+#define USBOTGSS_IRQMISC_DRVVBUS_FALL		BIT(5)
+#define USBOTGSS_IRQMISC_CHRGVBUS_FALL		BIT(4)
+#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL		BIT(3)
+#define USBOTGSS_IRQMISC_IDPULLUP_FALL		BIT(0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS	BIT(5)
+#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS	BIT(4)
+#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS	BIT(3)
+#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP	BIT(0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE		BIT(31)
+#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT	BIT(9)
+#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE BIT(8)
+#define USBOTGSS_UTMI_OTG_CTRL_IDDIG		BIT(4)
+#define USBOTGSS_UTMI_OTG_CTRL_SESSEND		BIT(3)
+#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID	BIT(2)
+#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID	BIT(1)
+
+enum dwc3_omap_utmi_mode {
+	DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
+	DWC3_OMAP_UTMI_MODE_HW,
+	DWC3_OMAP_UTMI_MODE_SW,
+};
+
+struct dwc3_omap {
+	struct device		*dev;
+
+	int			irq;
+	void __iomem		*base;
+
+	u32			utmi_otg_ctrl;
+	u32			utmi_otg_offset;
+	u32			irqmisc_offset;
+	u32			irq_eoi_offset;
+	u32			debug_offset;
+	u32			irq0_offset;
+
+	struct extcon_dev	*edev;
+	struct notifier_block	vbus_nb;
+	struct notifier_block	id_nb;
+
+	struct regulator	*vbus_reg;
+};
+
+enum omap_dwc3_vbus_id_status {
+	OMAP_DWC3_ID_FLOAT,
+	OMAP_DWC3_ID_GROUND,
+	OMAP_DWC3_VBUS_OFF,
+	OMAP_DWC3_VBUS_VALID,
+};
+
+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_ctrl(struct dwc3_omap *omap)
+{
+	return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_CTRL +
+							omap->utmi_otg_offset);
+}
+
+static void dwc3_omap_write_utmi_ctrl(struct dwc3_omap *omap, u32 value)
+{
+	dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_CTRL +
+					omap->utmi_otg_offset, value);
+
+}
+
+static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap)
+{
+	return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_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_RAW_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)
+{
+	int	ret;
+	u32	val;
+
+	switch (status) {
+	case OMAP_DWC3_ID_GROUND:
+		if (omap->vbus_reg) {
+			ret = regulator_enable(omap->vbus_reg);
+			if (ret) {
+				dev_err(omap->dev, "regulator enable failed\n");
+				return;
+			}
+		}
+
+		val = dwc3_omap_read_utmi_ctrl(omap);
+		val &= ~USBOTGSS_UTMI_OTG_CTRL_IDDIG;
+		dwc3_omap_write_utmi_ctrl(omap, val);
+		break;
+
+	case OMAP_DWC3_VBUS_VALID:
+		val = dwc3_omap_read_utmi_ctrl(omap);
+		val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND;
+		val |= USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
+				| USBOTGSS_UTMI_OTG_CTRL_SESSVALID;
+		dwc3_omap_write_utmi_ctrl(omap, val);
+		break;
+
+	case OMAP_DWC3_ID_FLOAT:
+		if (omap->vbus_reg && regulator_is_enabled(omap->vbus_reg))
+			regulator_disable(omap->vbus_reg);
+		val = dwc3_omap_read_utmi_ctrl(omap);
+		val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG;
+		dwc3_omap_write_utmi_ctrl(omap, val);
+		break;
+
+	case OMAP_DWC3_VBUS_OFF:
+		val = dwc3_omap_read_utmi_ctrl(omap);
+		val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID
+				| USBOTGSS_UTMI_OTG_CTRL_VBUSVALID);
+		val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND;
+		dwc3_omap_write_utmi_ctrl(omap, val);
+		break;
+
+	default:
+		dev_WARN(omap->dev, "invalid state\n");
+	}
+}
+
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap);
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap);
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+	struct dwc3_omap	*omap = _omap;
+
+	if (dwc3_omap_read_irqmisc_status(omap) ||
+	    dwc3_omap_read_irq0_status(omap)) {
+		/* mask irqs */
+		dwc3_omap_disable_irqs(omap);
+		return IRQ_WAKE_THREAD;
+	}
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t dwc3_omap_interrupt_thread(int irq, void *_omap)
+{
+	struct dwc3_omap	*omap = _omap;
+	u32			reg;
+
+	/* clear irq status flags */
+	reg = dwc3_omap_read_irqmisc_status(omap);
+	dwc3_omap_write_irqmisc_status(omap, reg);
+
+	reg = dwc3_omap_read_irq0_status(omap);
+	dwc3_omap_write_irq0_status(omap, reg);
+
+	/* unmask irqs */
+	dwc3_omap_enable_irqs(omap);
+
+	return IRQ_HANDLED;
+}
+
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
+{
+	u32			reg;
+
+	/* enable all IRQs */
+	reg = USBOTGSS_IRQO_COREIRQ_ST;
+	dwc3_omap_write_irq0_set(omap, reg);
+
+	reg = (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);
+
+	dwc3_omap_write_irqmisc_set(omap, reg);
+}
+
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
+{
+	u32			reg;
+
+	/* disable all IRQs */
+	reg = USBOTGSS_IRQO_COREIRQ_ST;
+	dwc3_omap_write_irq0_clr(omap, reg);
+
+	reg = (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);
+
+	dwc3_omap_write_irqmisc_clr(omap, reg);
+}
+
+static int dwc3_omap_id_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb);
+
+	if (event)
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+
+	return NOTIFY_DONE;
+}
+
+static int dwc3_omap_vbus_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb);
+
+	if (event)
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+	return NOTIFY_DONE;
+}
+
+static void dwc3_omap_map_offset(struct dwc3_omap *omap)
+{
+	struct device_node	*node = omap->dev->of_node;
+
+	/*
+	 * 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.
+	 */
+	if (of_device_is_compatible(node, "ti,am437x-dwc3")) {
+		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;
+	}
+}
+
+static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
+{
+	u32			reg;
+	struct device_node	*node = omap->dev->of_node;
+	u32			utmi_mode = 0;
+
+	reg = dwc3_omap_read_utmi_ctrl(omap);
+
+	of_property_read_u32(node, "utmi-mode", &utmi_mode);
+
+	switch (utmi_mode) {
+	case DWC3_OMAP_UTMI_MODE_SW:
+		reg |= USBOTGSS_UTMI_OTG_CTRL_SW_MODE;
+		break;
+	case DWC3_OMAP_UTMI_MODE_HW:
+		reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE;
+		break;
+	default:
+		dev_WARN(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
+	}
+
+	dwc3_omap_write_utmi_ctrl(omap, reg);
+}
+
+static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
+{
+	int			ret;
+	struct device_node	*node = omap->dev->of_node;
+	struct extcon_dev	*edev;
+
+	if (of_property_read_bool(node, "extcon")) {
+		edev = extcon_get_edev_by_phandle(omap->dev, 0);
+		if (IS_ERR(edev)) {
+			dev_vdbg(omap->dev, "couldn't get extcon device\n");
+			return -EPROBE_DEFER;
+		}
+
+		omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
+		ret = devm_extcon_register_notifier(omap->dev, edev,
+						EXTCON_USB, &omap->vbus_nb);
+		if (ret < 0)
+			dev_vdbg(omap->dev, "failed to register notifier for USB\n");
+
+		omap->id_nb.notifier_call = dwc3_omap_id_notifier;
+		ret = devm_extcon_register_notifier(omap->dev, edev,
+						EXTCON_USB_HOST, &omap->id_nb);
+		if (ret < 0)
+			dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n");
+
+		if (extcon_get_state(edev, EXTCON_USB) == true)
+			dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+		else
+			dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+		if (extcon_get_state(edev, EXTCON_USB_HOST) == true)
+			dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+		else
+			dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+
+		omap->edev = edev;
+	}
+
+	return 0;
+}
+
+static int dwc3_omap_probe(struct platform_device *pdev)
+{
+	struct device_node	*node = pdev->dev.of_node;
+
+	struct dwc3_omap	*omap;
+	struct device		*dev = &pdev->dev;
+	struct regulator	*vbus_reg = NULL;
+
+	int			ret;
+	int			irq;
+
+	u32			reg;
+
+	void __iomem		*base;
+
+	if (!node) {
+		dev_err(dev, "device node not found\n");
+		return -EINVAL;
+	}
+
+	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
+	if (!omap)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, omap);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	if (of_property_read_bool(node, "vbus-supply")) {
+		vbus_reg = devm_regulator_get(dev, "vbus");
+		if (IS_ERR(vbus_reg)) {
+			dev_err(dev, "vbus init failed\n");
+			return PTR_ERR(vbus_reg);
+		}
+	}
+
+	omap->dev	= dev;
+	omap->irq	= irq;
+	omap->base	= base;
+	omap->vbus_reg	= vbus_reg;
+
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "get_sync failed with err %d\n", ret);
+		goto err1;
+	}
+
+	dwc3_omap_map_offset(omap);
+	dwc3_omap_set_utmi_mode(omap);
+
+	/* check the DMA Status */
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
+
+	ret = dwc3_omap_extcon_register(omap);
+	if (ret < 0)
+		goto err1;
+
+	ret = of_platform_populate(node, NULL, NULL, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to create dwc3 core\n");
+		goto err1;
+	}
+
+	ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
+					dwc3_omap_interrupt_thread, IRQF_SHARED,
+					"dwc3-omap", omap);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ #%d --> %d\n",
+			omap->irq, ret);
+		goto err2;
+	}
+	dwc3_omap_enable_irqs(omap);
+	return 0;
+
+err2:
+	of_platform_depopulate(dev);
+err1:
+	pm_runtime_put_sync(dev);
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static int dwc3_omap_remove(struct platform_device *pdev)
+{
+	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
+
+	dwc3_omap_disable_irqs(omap);
+	disable_irq(omap->irq);
+	of_platform_depopulate(omap->dev);
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id of_dwc3_match[] = {
+	{
+		.compatible =	"ti,dwc3"
+	},
+	{
+		.compatible =	"ti,am437x-dwc3"
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_match);
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_omap_suspend(struct device *dev)
+{
+	struct dwc3_omap	*omap = dev_get_drvdata(dev);
+
+	omap->utmi_otg_ctrl = dwc3_omap_read_utmi_ctrl(omap);
+	dwc3_omap_disable_irqs(omap);
+
+	return 0;
+}
+
+static int dwc3_omap_resume(struct device *dev)
+{
+	struct dwc3_omap	*omap = dev_get_drvdata(dev);
+
+	dwc3_omap_write_utmi_ctrl(omap, omap->utmi_otg_ctrl);
+	dwc3_omap_enable_irqs(omap);
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void dwc3_omap_complete(struct device *dev)
+{
+	struct dwc3_omap	*omap = dev_get_drvdata(dev);
+
+	if (extcon_get_state(omap->edev, EXTCON_USB))
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+	if (extcon_get_state(omap->edev, EXTCON_USB_HOST))
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+}
+
+static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
+
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
+	.complete = dwc3_omap_complete,
+};
+
+#define DEV_PM_OPS	(&dwc3_omap_dev_pm_ops)
+#else
+#define DEV_PM_OPS	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver dwc3_omap_driver = {
+	.probe		= dwc3_omap_probe,
+	.remove		= dwc3_omap_remove,
+	.driver		= {
+		.name	= "omap-dwc3",
+		.of_match_table	= of_dwc3_match,
+		.pm	= DEV_PM_OPS,
+	},
+};
+
+module_platform_driver(dwc3_omap_driver);
+
+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/marvell/linux/drivers/usb/dwc3/dwc3-pci.c b/marvell/linux/drivers/usb/dwc3/dwc3-pci.c
new file mode 100644
index 0000000..8d4f1b1
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-pci.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-pci.c - PCI Specific glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+
+#define PCI_DEVICE_ID_INTEL_BYT			0x0f37
+#define PCI_DEVICE_ID_INTEL_MRFLD		0x119e
+#define PCI_DEVICE_ID_INTEL_BSW			0x22b7
+#define PCI_DEVICE_ID_INTEL_SPTLP		0x9d30
+#define PCI_DEVICE_ID_INTEL_SPTH		0xa130
+#define PCI_DEVICE_ID_INTEL_BXT			0x0aaa
+#define PCI_DEVICE_ID_INTEL_BXT_M		0x1aaa
+#define PCI_DEVICE_ID_INTEL_APL			0x5aaa
+#define PCI_DEVICE_ID_INTEL_KBP			0xa2b0
+#define PCI_DEVICE_ID_INTEL_CMLLP		0x02ee
+#define PCI_DEVICE_ID_INTEL_CMLH		0x06ee
+#define PCI_DEVICE_ID_INTEL_GLK			0x31aa
+#define PCI_DEVICE_ID_INTEL_CNPLP		0x9dee
+#define PCI_DEVICE_ID_INTEL_CNPH		0xa36e
+#define PCI_DEVICE_ID_INTEL_CNPV		0xa3b0
+#define PCI_DEVICE_ID_INTEL_ICLLP		0x34ee
+#define PCI_DEVICE_ID_INTEL_EHLLP		0x4b7e
+#define PCI_DEVICE_ID_INTEL_TGPLP		0xa0ee
+#define PCI_DEVICE_ID_INTEL_TGPH		0x43ee
+#define PCI_DEVICE_ID_INTEL_JSP			0x4dee
+#define PCI_DEVICE_ID_INTEL_ADLS		0x7ae1
+
+#define PCI_INTEL_BXT_DSM_GUID		"732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
+#define PCI_INTEL_BXT_FUNC_PMU_PWR	4
+#define PCI_INTEL_BXT_STATE_D0		0
+#define PCI_INTEL_BXT_STATE_D3		3
+
+#define GP_RWBAR			1
+#define GP_RWREG1			0xa0
+#define GP_RWREG1_ULPI_REFCLK_DISABLE	(1 << 17)
+
+/**
+ * struct dwc3_pci - Driver private structure
+ * @dwc3: child dwc3 platform_device
+ * @pci: our link to PCI bus
+ * @guid: _DSM GUID
+ * @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
+ * @wakeup_work: work for asynchronous resume
+ */
+struct dwc3_pci {
+	struct platform_device *dwc3;
+	struct pci_dev *pci;
+
+	guid_t guid;
+
+	unsigned int has_dsm_for_pm:1;
+	struct work_struct wakeup_work;
+};
+
+static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
+static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
+	{ "reset-gpios", &reset_gpios, 1 },
+	{ "cs-gpios", &cs_gpios, 1 },
+	{ },
+};
+
+static struct gpiod_lookup_table platform_bytcr_gpios = {
+	.dev_id		= "0000:00:16.0",
+	.table		= {
+		GPIO_LOOKUP("INT33FC:00", 54, "cs", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("INT33FC:02", 14, "reset", GPIO_ACTIVE_HIGH),
+		{}
+	},
+};
+
+static int dwc3_byt_enable_ulpi_refclock(struct pci_dev *pci)
+{
+	void __iomem	*reg;
+	u32		value;
+
+	reg = pcim_iomap(pci, GP_RWBAR, 0);
+	if (!reg)
+		return -ENOMEM;
+
+	value = readl(reg + GP_RWREG1);
+	if (!(value & GP_RWREG1_ULPI_REFCLK_DISABLE))
+		goto unmap; /* ULPI refclk already enabled */
+
+	value &= ~GP_RWREG1_ULPI_REFCLK_DISABLE;
+	writel(value, reg + GP_RWREG1);
+	/* This comes from the Intel Android x86 tree w/o any explanation */
+	msleep(100);
+unmap:
+	pcim_iounmap(pci, reg);
+	return 0;
+}
+
+static const struct property_entry dwc3_pci_intel_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
+static const struct property_entry dwc3_pci_mrfld_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
+	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
+static const struct property_entry dwc3_pci_amd_properties[] = {
+	PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+	PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
+	PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
+	PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
+	/* FIXME these quirks should be removed when AMD NL tapes out */
+	PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+	PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
+static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+{
+	struct pci_dev			*pdev = dwc->pci;
+
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+		if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
+		    pdev->device == PCI_DEVICE_ID_INTEL_BXT_M ||
+		    pdev->device == PCI_DEVICE_ID_INTEL_EHLLP) {
+			guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
+			dwc->has_dsm_for_pm = true;
+		}
+
+		if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
+			struct gpio_desc *gpio;
+			int ret;
+
+			/* On BYT the FW does not always enable the refclock */
+			ret = dwc3_byt_enable_ulpi_refclock(pdev);
+			if (ret)
+				return ret;
+
+			ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
+					acpi_dwc3_byt_gpios);
+			if (ret)
+				dev_dbg(&pdev->dev, "failed to add mapping table\n");
+
+			/*
+			 * A lot of BYT devices lack ACPI resource entries for
+			 * the GPIOs. If the ACPI entry for the GPIO controller
+			 * is present add a fallback mapping to the reference
+			 * design GPIOs which all boards seem to use.
+			 */
+			if (acpi_dev_present("INT33FC", NULL, -1))
+				gpiod_add_lookup_table(&platform_bytcr_gpios);
+
+			/*
+			 * These GPIOs will turn on the USB2 PHY. Note that we have to
+			 * put the gpio descriptors again here because the phy driver
+			 * might want to grab them, too.
+			 */
+			gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
+			if (IS_ERR(gpio))
+				return PTR_ERR(gpio);
+
+			gpiod_set_value_cansleep(gpio, 1);
+			gpiod_put(gpio);
+
+			gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+			if (IS_ERR(gpio))
+				return PTR_ERR(gpio);
+
+			if (gpio) {
+				gpiod_set_value_cansleep(gpio, 1);
+				gpiod_put(gpio);
+				usleep_range(10000, 11000);
+			}
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static void dwc3_pci_resume_work(struct work_struct *work)
+{
+	struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
+	struct platform_device *dwc3 = dwc->dwc3;
+	int ret;
+
+	ret = pm_runtime_get_sync(&dwc3->dev);
+	if (ret < 0) {
+		pm_runtime_put_sync_autosuspend(&dwc3->dev);
+		return;
+	}
+
+	pm_runtime_mark_last_busy(&dwc3->dev);
+	pm_runtime_put_sync_autosuspend(&dwc3->dev);
+}
+#endif
+
+static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+	struct property_entry *p = (struct property_entry *)id->driver_data;
+	struct dwc3_pci		*dwc;
+	struct resource		res[2];
+	int			ret;
+	struct device		*dev = &pci->dev;
+
+	ret = pcim_enable_device(pci);
+	if (ret) {
+		dev_err(dev, "failed to enable pci device\n");
+		return -ENODEV;
+	}
+
+	pci_set_master(pci);
+
+	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
+	if (!dwc)
+		return -ENOMEM;
+
+	dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
+	if (!dwc->dwc3)
+		return -ENOMEM;
+
+	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+	res[0].start	= pci_resource_start(pci, 0);
+	res[0].end	= pci_resource_end(pci, 0);
+	res[0].name	= "dwc_usb3";
+	res[0].flags	= IORESOURCE_MEM;
+
+	res[1].start	= pci->irq;
+	res[1].name	= "dwc_usb3";
+	res[1].flags	= IORESOURCE_IRQ;
+
+	ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
+	if (ret) {
+		dev_err(dev, "couldn't add resources to dwc3 device\n");
+		goto err;
+	}
+
+	dwc->pci = pci;
+	dwc->dwc3->dev.parent = dev;
+	ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
+
+	ret = platform_device_add_properties(dwc->dwc3, p);
+	if (ret < 0)
+		goto err;
+
+	ret = dwc3_pci_quirks(dwc);
+	if (ret)
+		goto err;
+
+	ret = platform_device_add(dwc->dwc3);
+	if (ret) {
+		dev_err(dev, "failed to register dwc3 device\n");
+		goto err;
+	}
+
+	device_init_wakeup(dev, true);
+	pci_set_drvdata(pci, dwc);
+	pm_runtime_put(dev);
+#ifdef CONFIG_PM
+	INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
+#endif
+
+	return 0;
+err:
+	platform_device_put(dwc->dwc3);
+	return ret;
+}
+
+static void dwc3_pci_remove(struct pci_dev *pci)
+{
+	struct dwc3_pci		*dwc = pci_get_drvdata(pci);
+	struct pci_dev		*pdev = dwc->pci;
+
+	if (pdev->device == PCI_DEVICE_ID_INTEL_BYT)
+		gpiod_remove_lookup_table(&platform_bytcr_gpios);
+#ifdef CONFIG_PM
+	cancel_work_sync(&dwc->wakeup_work);
+#endif
+	device_init_wakeup(&pci->dev, false);
+	pm_runtime_get(&pci->dev);
+	platform_device_unregister(dwc->dwc3);
+}
+
+static const struct pci_device_id dwc3_pci_id_table[] = {
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
+	  (kernel_ulong_t) &dwc3_pci_mrfld_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
+	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
+	  (kernel_ulong_t) &dwc3_pci_amd_properties, },
+	{  }	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+
+#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
+static int dwc3_pci_dsm(struct dwc3_pci *dwc, int param)
+{
+	union acpi_object *obj;
+	union acpi_object tmp;
+	union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
+
+	if (!dwc->has_dsm_for_pm)
+		return 0;
+
+	tmp.type = ACPI_TYPE_INTEGER;
+	tmp.integer.value = param;
+
+	obj = acpi_evaluate_dsm(ACPI_HANDLE(&dwc->pci->dev), &dwc->guid,
+			1, PCI_INTEL_BXT_FUNC_PMU_PWR, &argv4);
+	if (!obj) {
+		dev_err(&dwc->pci->dev, "failed to evaluate _DSM\n");
+		return -EIO;
+	}
+
+	ACPI_FREE(obj);
+
+	return 0;
+}
+#endif /* CONFIG_PM || CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int dwc3_pci_runtime_suspend(struct device *dev)
+{
+	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
+
+	if (device_can_wakeup(dev))
+		return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
+
+	return -EBUSY;
+}
+
+static int dwc3_pci_runtime_resume(struct device *dev)
+{
+	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
+	int			ret;
+
+	ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
+	if (ret)
+		return ret;
+
+	queue_work(pm_wq, &dwc->wakeup_work);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_pci_suspend(struct device *dev)
+{
+	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
+
+	return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
+}
+
+static int dwc3_pci_resume(struct device *dev)
+{
+	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
+
+	return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
+	SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume,
+		NULL)
+};
+
+static struct pci_driver dwc3_pci_driver = {
+	.name		= "dwc3-pci",
+	.id_table	= dwc3_pci_id_table,
+	.probe		= dwc3_pci_probe,
+	.remove		= dwc3_pci_remove,
+	.driver		= {
+		.pm	= &dwc3_pci_dev_pm_ops,
+	}
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
+
+module_pci_driver(dwc3_pci_driver);
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-qcom.c b/marvell/linux/drivers/usb/dwc3/dwc3-qcom.c
new file mode 100644
index 0000000..742be1e
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-qcom.c
@@ -0,0 +1,809 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Inspired by dwc3-of-simple.c
+ */
+
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/extcon.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/usb/of.h>
+#include <linux/reset.h>
+#include <linux/iopoll.h>
+
+#include "core.h"
+
+/* USB QSCRATCH Hardware registers */
+#define QSCRATCH_HS_PHY_CTRL			0x10
+#define UTMI_OTG_VBUS_VALID			BIT(20)
+#define SW_SESSVLD_SEL				BIT(28)
+
+#define QSCRATCH_SS_PHY_CTRL			0x30
+#define LANE0_PWR_PRESENT			BIT(24)
+
+#define QSCRATCH_GENERAL_CFG			0x08
+#define PIPE_UTMI_CLK_SEL			BIT(0)
+#define PIPE3_PHYSTATUS_SW			BIT(3)
+#define PIPE_UTMI_CLK_DIS			BIT(8)
+
+#define PWR_EVNT_IRQ_STAT_REG			0x58
+#define PWR_EVNT_LPM_IN_L2_MASK			BIT(4)
+#define PWR_EVNT_LPM_OUT_L2_MASK		BIT(5)
+
+#define SDM845_QSCRATCH_BASE_OFFSET		0xf8800
+#define SDM845_QSCRATCH_SIZE			0x400
+#define SDM845_DWC3_CORE_SIZE			0xcd00
+
+struct dwc3_acpi_pdata {
+	u32			qscratch_base_offset;
+	u32			qscratch_base_size;
+	u32			dwc3_core_base_size;
+	int			hs_phy_irq_index;
+	int			dp_hs_phy_irq_index;
+	int			dm_hs_phy_irq_index;
+	int			ss_phy_irq_index;
+};
+
+struct dwc3_qcom {
+	struct device		*dev;
+	void __iomem		*qscratch_base;
+	struct platform_device	*dwc3;
+	struct clk		**clks;
+	int			num_clocks;
+	struct reset_control	*resets;
+
+	int			hs_phy_irq;
+	int			dp_hs_phy_irq;
+	int			dm_hs_phy_irq;
+	int			ss_phy_irq;
+
+	struct extcon_dev	*edev;
+	struct extcon_dev	*host_edev;
+	struct notifier_block	vbus_nb;
+	struct notifier_block	host_nb;
+
+	const struct dwc3_acpi_pdata *acpi_pdata;
+
+	enum usb_dr_mode	mode;
+	bool			is_suspended;
+	bool			pm_suspended;
+};
+
+static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
+{
+	u32 reg;
+
+	reg = readl(base + offset);
+	reg |= val;
+	writel(reg, base + offset);
+
+	/* ensure that above write is through */
+	readl(base + offset);
+}
+
+static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
+{
+	u32 reg;
+
+	reg = readl(base + offset);
+	reg &= ~val;
+	writel(reg, base + offset);
+
+	/* ensure that above write is through */
+	readl(base + offset);
+}
+
+static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
+{
+	if (enable) {
+		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
+				  LANE0_PWR_PRESENT);
+		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
+				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
+	} else {
+		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
+				  LANE0_PWR_PRESENT);
+		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
+				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
+	}
+}
+
+static int dwc3_qcom_vbus_notifier(struct notifier_block *nb,
+				   unsigned long event, void *ptr)
+{
+	struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb);
+
+	/* enable vbus override for device mode */
+	dwc3_qcom_vbus_override_enable(qcom, event);
+	qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST;
+
+	return NOTIFY_DONE;
+}
+
+static int dwc3_qcom_host_notifier(struct notifier_block *nb,
+				   unsigned long event, void *ptr)
+{
+	struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb);
+
+	/* disable vbus override in host mode */
+	dwc3_qcom_vbus_override_enable(qcom, !event);
+	qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL;
+
+	return NOTIFY_DONE;
+}
+
+static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
+{
+	struct device		*dev = qcom->dev;
+	struct extcon_dev	*host_edev;
+	int			ret;
+
+	if (!of_property_read_bool(dev->of_node, "extcon"))
+		return 0;
+
+	qcom->edev = extcon_get_edev_by_phandle(dev, 0);
+	if (IS_ERR(qcom->edev))
+		return PTR_ERR(qcom->edev);
+
+	qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier;
+
+	qcom->host_edev = extcon_get_edev_by_phandle(dev, 1);
+	if (IS_ERR(qcom->host_edev))
+		qcom->host_edev = NULL;
+
+	ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB,
+					    &qcom->vbus_nb);
+	if (ret < 0) {
+		dev_err(dev, "VBUS notifier register failed\n");
+		return ret;
+	}
+
+	if (qcom->host_edev)
+		host_edev = qcom->host_edev;
+	else
+		host_edev = qcom->edev;
+
+	qcom->host_nb.notifier_call = dwc3_qcom_host_notifier;
+	ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST,
+					    &qcom->host_nb);
+	if (ret < 0) {
+		dev_err(dev, "Host notifier register failed\n");
+		return ret;
+	}
+
+	/* Update initial VBUS override based on extcon state */
+	if (extcon_get_state(qcom->edev, EXTCON_USB) ||
+	    !extcon_get_state(host_edev, EXTCON_USB_HOST))
+		dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev);
+	else
+		dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev);
+
+	return 0;
+}
+
+/* Only usable in contexts where the role can not change. */
+static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
+{
+	struct dwc3 *dwc;
+
+	/*
+	 * FIXME: Fix this layering violation.
+	 */
+	dwc = platform_get_drvdata(qcom->dwc3);
+
+	/* Core driver may not have probed yet. */
+	if (!dwc)
+		return false;
+
+	return dwc->xhci;
+}
+
+static void dwc3_qcom_enable_wakeup_irq(int irq)
+{
+	if (!irq)
+		return;
+
+	enable_irq(irq);
+	enable_irq_wake(irq);
+}
+
+static void dwc3_qcom_disable_wakeup_irq(int irq)
+{
+	if (!irq)
+		return;
+
+	disable_irq_wake(irq);
+	disable_irq_nosync(irq);
+}
+
+static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
+{
+	dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq);
+
+	dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
+
+	dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
+
+	dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq);
+}
+
+static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
+{
+	dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq);
+
+	dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq);
+
+	dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq);
+
+	dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq);
+}
+
+static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
+{
+	u32 val;
+	int i;
+
+	if (qcom->is_suspended)
+		return 0;
+
+	val = readl(qcom->qscratch_base + PWR_EVNT_IRQ_STAT_REG);
+	if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
+		dev_err(qcom->dev, "HS-PHY not in L2\n");
+
+	for (i = qcom->num_clocks - 1; i >= 0; i--)
+		clk_disable_unprepare(qcom->clks[i]);
+
+	if (device_may_wakeup(qcom->dev))
+		dwc3_qcom_enable_interrupts(qcom);
+
+	qcom->is_suspended = true;
+
+	return 0;
+}
+
+static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
+{
+	int ret;
+	int i;
+
+	if (!qcom->is_suspended)
+		return 0;
+
+	if (device_may_wakeup(qcom->dev))
+		dwc3_qcom_disable_interrupts(qcom);
+
+	for (i = 0; i < qcom->num_clocks; i++) {
+		ret = clk_prepare_enable(qcom->clks[i]);
+		if (ret < 0) {
+			while (--i >= 0)
+				clk_disable_unprepare(qcom->clks[i]);
+			return ret;
+		}
+	}
+
+	/* Clear existing events from PHY related to L2 in/out */
+	dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
+			  PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
+
+	qcom->is_suspended = false;
+
+	return 0;
+}
+
+static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
+{
+	struct dwc3_qcom *qcom = data;
+	struct dwc3	*dwc = platform_get_drvdata(qcom->dwc3);
+
+	/* If pm_suspended then let pm_resume take care of resuming h/w */
+	if (qcom->pm_suspended)
+		return IRQ_HANDLED;
+
+	/*
+	 * This is safe as role switching is done from a freezable workqueue
+	 * and the wakeup interrupts are disabled as part of resume.
+	 */
+	if (dwc3_qcom_is_host(qcom))
+		pm_runtime_resume(&dwc->xhci->dev);
+
+	return IRQ_HANDLED;
+}
+
+static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
+{
+	/* Configure dwc3 to use UTMI clock as PIPE clock not present */
+	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
+			  PIPE_UTMI_CLK_DIS);
+
+	usleep_range(100, 1000);
+
+	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
+			  PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW);
+
+	usleep_range(100, 1000);
+
+	dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
+			  PIPE_UTMI_CLK_DIS);
+}
+
+static int dwc3_qcom_get_irq(struct platform_device *pdev,
+			     const char *name, int num)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (np)
+		ret = platform_get_irq_byname(pdev, name);
+	else
+		ret = platform_get_irq(pdev, num);
+
+	return ret;
+}
+
+static int dwc3_qcom_setup_irq(struct platform_device *pdev)
+{
+	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+	const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
+	int irq, ret;
+	irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
+				pdata ? pdata->hs_phy_irq_index : -1);
+	if (irq > 0) {
+		/* Keep wakeup interrupts disabled until suspend */
+		irq_set_status_flags(irq, IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
+					qcom_dwc3_resume_irq,
+					IRQF_ONESHOT,
+					"qcom_dwc3 HS", qcom);
+		if (ret) {
+			dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret);
+			return ret;
+		}
+		qcom->hs_phy_irq = irq;
+	}
+
+	irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
+				pdata ? pdata->dp_hs_phy_irq_index : -1);
+	if (irq > 0) {
+		irq_set_status_flags(irq, IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
+					qcom_dwc3_resume_irq,
+					IRQF_ONESHOT,
+					"qcom_dwc3 DP_HS", qcom);
+		if (ret) {
+			dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret);
+			return ret;
+		}
+		qcom->dp_hs_phy_irq = irq;
+	}
+
+	irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
+				pdata ? pdata->dm_hs_phy_irq_index : -1);
+	if (irq > 0) {
+		irq_set_status_flags(irq, IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
+					qcom_dwc3_resume_irq,
+					IRQF_ONESHOT,
+					"qcom_dwc3 DM_HS", qcom);
+		if (ret) {
+			dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret);
+			return ret;
+		}
+		qcom->dm_hs_phy_irq = irq;
+	}
+
+	irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
+				pdata ? pdata->ss_phy_irq_index : -1);
+	if (irq > 0) {
+		irq_set_status_flags(irq, IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
+					qcom_dwc3_resume_irq,
+					IRQF_ONESHOT,
+					"qcom_dwc3 SS", qcom);
+		if (ret) {
+			dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret);
+			return ret;
+		}
+		qcom->ss_phy_irq = irq;
+	}
+
+	return 0;
+}
+
+static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
+{
+	struct device		*dev = qcom->dev;
+	struct device_node	*np = dev->of_node;
+	int			i;
+
+	if (!np || !count)
+		return 0;
+
+	if (count < 0)
+		return count;
+
+	qcom->num_clocks = count;
+
+	qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
+				  sizeof(struct clk *), GFP_KERNEL);
+	if (!qcom->clks)
+		return -ENOMEM;
+
+	for (i = 0; i < qcom->num_clocks; i++) {
+		struct clk	*clk;
+		int		ret;
+
+		clk = of_clk_get(np, i);
+		if (IS_ERR(clk)) {
+			while (--i >= 0)
+				clk_put(qcom->clks[i]);
+			return PTR_ERR(clk);
+		}
+
+		ret = clk_prepare_enable(clk);
+		if (ret < 0) {
+			while (--i >= 0) {
+				clk_disable_unprepare(qcom->clks[i]);
+				clk_put(qcom->clks[i]);
+			}
+			clk_put(clk);
+
+			return ret;
+		}
+
+		qcom->clks[i] = clk;
+	}
+
+	return 0;
+}
+
+static const struct property_entry dwc3_qcom_acpi_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "host"),
+	{}
+};
+
+static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
+{
+	struct dwc3_qcom 	*qcom = platform_get_drvdata(pdev);
+	struct device		*dev = &pdev->dev;
+	struct resource		*res, *child_res = NULL;
+	int			irq;
+	int			ret;
+
+	qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
+	if (!qcom->dwc3)
+		return -ENOMEM;
+
+	qcom->dwc3->dev.parent = dev;
+	qcom->dwc3->dev.type = dev->type;
+	qcom->dwc3->dev.dma_mask = dev->dma_mask;
+	qcom->dwc3->dev.dma_parms = dev->dma_parms;
+	qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
+
+	child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
+	if (!child_res)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get memory resource\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	child_res[0].flags = res->flags;
+	child_res[0].start = res->start;
+	child_res[0].end = child_res[0].start +
+		qcom->acpi_pdata->dwc3_core_base_size;
+
+	irq = platform_get_irq(pdev, 0);
+	child_res[1].flags = IORESOURCE_IRQ;
+	child_res[1].start = child_res[1].end = irq;
+
+	ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add resources\n");
+		goto out;
+	}
+
+	ret = platform_device_add_properties(qcom->dwc3,
+					     dwc3_qcom_acpi_properties);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add properties\n");
+		goto out;
+	}
+
+	ret = platform_device_add(qcom->dwc3);
+	if (ret)
+		dev_err(&pdev->dev, "failed to add device\n");
+
+out:
+	kfree(child_res);
+	return ret;
+}
+
+static int dwc3_qcom_of_register_core(struct platform_device *pdev)
+{
+	struct dwc3_qcom 	*qcom = platform_get_drvdata(pdev);
+	struct device_node	*np = pdev->dev.of_node, *dwc3_np;
+	struct device		*dev = &pdev->dev;
+	int			ret;
+
+	dwc3_np = of_get_child_by_name(np, "dwc3");
+	if (!dwc3_np) {
+		dev_err(dev, "failed to find dwc3 core child\n");
+		return -ENODEV;
+	}
+
+	ret = of_platform_populate(np, NULL, NULL, dev);
+	if (ret) {
+		dev_err(dev, "failed to register dwc3 core - %d\n", ret);
+		goto node_put;
+	}
+
+	qcom->dwc3 = of_find_device_by_node(dwc3_np);
+	if (!qcom->dwc3) {
+		ret = -ENODEV;
+		dev_err(dev, "failed to get dwc3 platform device\n");
+		of_platform_depopulate(dev);
+	}
+
+node_put:
+	of_node_put(dwc3_np);
+
+	return ret;
+}
+
+static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
+	.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
+	.qscratch_base_size = SDM845_QSCRATCH_SIZE,
+	.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
+	.hs_phy_irq_index = 1,
+	.dp_hs_phy_irq_index = 4,
+	.dm_hs_phy_irq_index = 3,
+	.ss_phy_irq_index = 2
+};
+
+static int dwc3_qcom_probe(struct platform_device *pdev)
+{
+	struct device_node	*np = pdev->dev.of_node;
+	struct device		*dev = &pdev->dev;
+	struct dwc3_qcom	*qcom;
+	struct resource		*res, *parent_res = NULL;
+	struct resource		local_res;
+	int			ret, i;
+	bool			ignore_pipe_clk;
+
+	qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
+	if (!qcom)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, qcom);
+	qcom->dev = &pdev->dev;
+
+	if (has_acpi_companion(dev)) {
+		qcom->acpi_pdata = acpi_device_get_match_data(dev);
+		if (!qcom->acpi_pdata) {
+			dev_err(&pdev->dev, "no supporting ACPI device data\n");
+			return -EINVAL;
+		}
+	}
+
+	qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
+	if (IS_ERR(qcom->resets)) {
+		ret = PTR_ERR(qcom->resets);
+		dev_err(&pdev->dev, "failed to get resets, err=%d\n", ret);
+		return ret;
+	}
+
+	ret = reset_control_assert(qcom->resets);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
+		return ret;
+	}
+
+	usleep_range(10, 1000);
+
+	ret = reset_control_deassert(qcom->resets);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
+		goto reset_assert;
+	}
+
+	ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
+	if (ret) {
+		dev_err(dev, "failed to get clocks\n");
+		goto reset_assert;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (np) {
+		parent_res = res;
+	} else {
+		memcpy(&local_res, res, sizeof(struct resource));
+		parent_res = &local_res;
+
+		parent_res->start = res->start +
+			qcom->acpi_pdata->qscratch_base_offset;
+		parent_res->end = parent_res->start +
+			qcom->acpi_pdata->qscratch_base_size;
+	}
+
+	qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
+	if (IS_ERR(qcom->qscratch_base)) {
+		dev_err(dev, "failed to map qscratch, err=%d\n", ret);
+		ret = PTR_ERR(qcom->qscratch_base);
+		goto clk_disable;
+	}
+
+	ret = dwc3_qcom_setup_irq(pdev);
+	if (ret) {
+		dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
+		goto clk_disable;
+	}
+
+	/*
+	 * Disable pipe_clk requirement if specified. Used when dwc3
+	 * operates without SSPHY and only HS/FS/LS modes are supported.
+	 */
+	ignore_pipe_clk = device_property_read_bool(dev,
+				"qcom,select-utmi-as-pipe-clk");
+	if (ignore_pipe_clk)
+		dwc3_qcom_select_utmi_clk(qcom);
+
+	if (np)
+		ret = dwc3_qcom_of_register_core(pdev);
+	else
+		ret = dwc3_qcom_acpi_register_core(pdev);
+
+	if (ret) {
+		dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
+		goto clk_disable;
+	}
+
+	qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
+
+	/* enable vbus override for device mode */
+	if (qcom->mode != USB_DR_MODE_HOST)
+		dwc3_qcom_vbus_override_enable(qcom, true);
+
+	/* register extcon to override sw_vbus on Vbus change later */
+	ret = dwc3_qcom_register_extcon(qcom);
+	if (ret)
+		goto depopulate;
+
+	device_init_wakeup(&pdev->dev, 1);
+	qcom->is_suspended = false;
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_forbid(dev);
+
+	return 0;
+
+depopulate:
+	if (np)
+		of_platform_depopulate(&pdev->dev);
+	else
+		platform_device_del(qcom->dwc3);
+	platform_device_put(qcom->dwc3);
+clk_disable:
+	for (i = qcom->num_clocks - 1; i >= 0; i--) {
+		clk_disable_unprepare(qcom->clks[i]);
+		clk_put(qcom->clks[i]);
+	}
+reset_assert:
+	reset_control_assert(qcom->resets);
+
+	return ret;
+}
+
+static int dwc3_qcom_remove(struct platform_device *pdev)
+{
+	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int i;
+
+	if (np)
+		of_platform_depopulate(&pdev->dev);
+	else
+		platform_device_del(qcom->dwc3);
+	platform_device_put(qcom->dwc3);
+
+	for (i = qcom->num_clocks - 1; i >= 0; i--) {
+		clk_disable_unprepare(qcom->clks[i]);
+		clk_put(qcom->clks[i]);
+	}
+	qcom->num_clocks = 0;
+
+	reset_control_assert(qcom->resets);
+
+	pm_runtime_allow(dev);
+	pm_runtime_disable(dev);
+
+	return 0;
+}
+
+static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
+{
+	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = dwc3_qcom_suspend(qcom);
+	if (!ret)
+		qcom->pm_suspended = true;
+
+	return ret;
+}
+
+static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
+{
+	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dwc3_qcom_resume(qcom);
+	if (!ret)
+		qcom->pm_suspended = false;
+
+	return ret;
+}
+
+static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
+{
+	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+
+	return dwc3_qcom_suspend(qcom);
+}
+
+static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
+{
+	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+
+	return dwc3_qcom_resume(qcom);
+}
+
+static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
+	SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id dwc3_qcom_of_match[] = {
+	{ .compatible = "qcom,dwc3" },
+	{ .compatible = "qcom,msm8996-dwc3" },
+	{ .compatible = "qcom,msm8998-dwc3" },
+	{ .compatible = "qcom,sdm845-dwc3" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
+
+static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
+	{ "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
+
+static struct platform_driver dwc3_qcom_driver = {
+	.probe		= dwc3_qcom_probe,
+	.remove		= dwc3_qcom_remove,
+	.driver		= {
+		.name	= "dwc3-qcom",
+		.pm	= &dwc3_qcom_dev_pm_ops,
+		.of_match_table	= dwc3_qcom_of_match,
+		.acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
+	},
+};
+
+module_platform_driver(dwc3_qcom_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare DWC3 QCOM Glue Driver");
diff --git a/marvell/linux/drivers/usb/dwc3/dwc3-st.c b/marvell/linux/drivers/usb/dwc3/dwc3-st.c
new file mode 100644
index 0000000..c48fd6b
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/dwc3-st.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * dwc3-st.c Support for dwc3 platform devices on ST Microelectronics platforms
+ *
+ * This is a small driver for the dwc3 to provide the glue logic
+ * to configure the controller. Tested on STi platforms.
+ *
+ * Copyright (C) 2014 Stmicroelectronics
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ * Contributors: Aymen Bouattay <aymen.bouattay@st.com>
+ *               Peter Griffin <peter.griffin@linaro.org>
+ *
+ * Inspired by dwc3-omap.c and dwc3-exynos.c.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/usb/of.h>
+
+#include "core.h"
+#include "io.h"
+
+/* glue registers */
+#define CLKRST_CTRL		0x00
+#define AUX_CLK_EN		BIT(0)
+#define SW_PIPEW_RESET_N	BIT(4)
+#define EXT_CFG_RESET_N		BIT(8)
+/*
+ * 1'b0 : The host controller complies with the xHCI revision 0.96
+ * 1'b1 : The host controller complies with the xHCI revision 1.0
+ */
+#define XHCI_REVISION		BIT(12)
+
+#define USB2_VBUS_MNGMNT_SEL1	0x2C
+/*
+ * For all fields in USB2_VBUS_MNGMNT_SEL1
+ * 2’b00 : Override value from Reg 0x30 is selected
+ * 2’b01 : utmiotg_<signal_name> from usb3_top is selected
+ * 2’b10 : pipew_<signal_name> from PIPEW instance is selected
+ * 2’b11 : value is 1'b0
+ */
+#define USB2_VBUS_REG30		0x0
+#define USB2_VBUS_UTMIOTG	0x1
+#define USB2_VBUS_PIPEW		0x2
+#define USB2_VBUS_ZERO		0x3
+
+#define SEL_OVERRIDE_VBUSVALID(n)	(n << 0)
+#define SEL_OVERRIDE_POWERPRESENT(n)	(n << 4)
+#define SEL_OVERRIDE_BVALID(n)		(n << 8)
+
+/* Static DRD configuration */
+#define USB3_CONTROL_MASK		0xf77
+
+#define USB3_DEVICE_NOT_HOST		BIT(0)
+#define USB3_FORCE_VBUSVALID		BIT(1)
+#define USB3_DELAY_VBUSVALID		BIT(2)
+#define USB3_SEL_FORCE_OPMODE		BIT(4)
+#define USB3_FORCE_OPMODE(n)		(n << 5)
+#define USB3_SEL_FORCE_DPPULLDOWN2	BIT(8)
+#define USB3_FORCE_DPPULLDOWN2		BIT(9)
+#define USB3_SEL_FORCE_DMPULLDOWN2	BIT(10)
+#define USB3_FORCE_DMPULLDOWN2		BIT(11)
+
+/**
+ * struct st_dwc3 - dwc3-st driver private structure
+ * @dev:		device pointer
+ * @glue_base:		ioaddr for the glue registers
+ * @regmap:		regmap pointer for getting syscfg
+ * @syscfg_reg_off:	usb syscfg control offset
+ * @dr_mode:		drd static host/device config
+ * @rstc_pwrdn:		rest controller for powerdown signal
+ * @rstc_rst:		reset controller for softreset signal
+ */
+
+struct st_dwc3 {
+	struct device *dev;
+	void __iomem *glue_base;
+	struct regmap *regmap;
+	int syscfg_reg_off;
+	enum usb_dr_mode dr_mode;
+	struct reset_control *rstc_pwrdn;
+	struct reset_control *rstc_rst;
+};
+
+static inline u32 st_dwc3_readl(void __iomem *base, u32 offset)
+{
+	return readl_relaxed(base + offset);
+}
+
+static inline void st_dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel_relaxed(value, base + offset);
+}
+
+/**
+ * st_dwc3_drd_init: program the port
+ * @dwc3_data: driver private structure
+ * Description: this function is to program the port as either host or device
+ * according to the static configuration passed from devicetree.
+ * OTG and dual role are not yet supported!
+ */
+static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
+{
+	u32 val;
+	int err;
+
+	err = regmap_read(dwc3_data->regmap, dwc3_data->syscfg_reg_off, &val);
+	if (err)
+		return err;
+
+	val &= USB3_CONTROL_MASK;
+
+	switch (dwc3_data->dr_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);
+
+		/*
+		 * USB3_PORT2_FORCE_VBUSVALID When '1' and when
+		 * USB3_PORT2_DEVICE_NOT_HOST = 1, forces VBUSVLDEXT2 input
+		 * of the pico PHY to 1.
+		 */
+
+		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);
+
+		/*
+		 * USB3_DELAY_VBUSVALID is ANDed with USB_C_VBUSVALID. Thus,
+		 * when set to ‘0‘, it can delay the arrival of VBUSVALID
+		 * information to VBUSVLDEXT2 input of the pico PHY.
+		 * We don't want to do that so we set the bit to '1'.
+		 */
+
+		val |= USB3_DELAY_VBUSVALID;
+		break;
+
+	default:
+		dev_err(dwc3_data->dev, "Unsupported mode of operation %d\n",
+			dwc3_data->dr_mode);
+		return -EINVAL;
+	}
+
+	return regmap_write(dwc3_data->regmap, dwc3_data->syscfg_reg_off, val);
+}
+
+/**
+ * st_dwc3_init: init the controller via glue logic
+ * @dwc3_data: driver private structure
+ */
+static void st_dwc3_init(struct st_dwc3 *dwc3_data)
+{
+	u32 reg = st_dwc3_readl(dwc3_data->glue_base, CLKRST_CTRL);
+
+	reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION;
+	reg &= ~SW_PIPEW_RESET_N;
+	st_dwc3_writel(dwc3_data->glue_base, CLKRST_CTRL, reg);
+
+	/* configure mux for vbus, powerpresent and bvalid signals */
+	reg = st_dwc3_readl(dwc3_data->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);
+
+	st_dwc3_writel(dwc3_data->glue_base, USB2_VBUS_MNGMNT_SEL1, reg);
+
+	reg = st_dwc3_readl(dwc3_data->glue_base, CLKRST_CTRL);
+	reg |= SW_PIPEW_RESET_N;
+	st_dwc3_writel(dwc3_data->glue_base, CLKRST_CTRL, reg);
+}
+
+static int st_dwc3_probe(struct platform_device *pdev)
+{
+	struct st_dwc3 *dwc3_data;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node, *child;
+	struct platform_device *child_pdev;
+	struct regmap *regmap;
+	int ret;
+
+	dwc3_data = devm_kzalloc(dev, sizeof(*dwc3_data), GFP_KERNEL);
+	if (!dwc3_data)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg-glue");
+	dwc3_data->glue_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dwc3_data->glue_base))
+		return PTR_ERR(dwc3_data->glue_base);
+
+	regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg");
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	dwc3_data->dev = dev;
+	dwc3_data->regmap = regmap;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg-reg");
+	if (!res)
+		return -ENXIO;
+
+	dwc3_data->syscfg_reg_off = res->start;
+
+	dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n",
+		 dwc3_data->glue_base, dwc3_data->syscfg_reg_off);
+
+	dwc3_data->rstc_pwrdn =
+		devm_reset_control_get_exclusive(dev, "powerdown");
+	if (IS_ERR(dwc3_data->rstc_pwrdn)) {
+		dev_err(&pdev->dev, "could not get power controller\n");
+		return PTR_ERR(dwc3_data->rstc_pwrdn);
+	}
+
+	/* Manage PowerDown */
+	reset_control_deassert(dwc3_data->rstc_pwrdn);
+
+	dwc3_data->rstc_rst =
+		devm_reset_control_get_shared(dev, "softreset");
+	if (IS_ERR(dwc3_data->rstc_rst)) {
+		dev_err(&pdev->dev, "could not get reset controller\n");
+		ret = PTR_ERR(dwc3_data->rstc_rst);
+		goto undo_powerdown;
+	}
+
+	/* Manage SoftReset */
+	reset_control_deassert(dwc3_data->rstc_rst);
+
+	child = of_get_child_by_name(node, "dwc3");
+	if (!child) {
+		dev_err(&pdev->dev, "failed to find dwc3 core node\n");
+		ret = -ENODEV;
+		goto err_node_put;
+	}
+
+	/* Allocate and initialize the core */
+	ret = of_platform_populate(node, NULL, NULL, dev);
+	if (ret) {
+		dev_err(dev, "failed to add dwc3 core\n");
+		goto err_node_put;
+	}
+
+	child_pdev = of_find_device_by_node(child);
+	if (!child_pdev) {
+		dev_err(dev, "failed to find dwc3 core device\n");
+		ret = -ENODEV;
+		goto depopulate;
+	}
+
+	dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev);
+	of_node_put(child);
+	of_dev_put(child_pdev);
+
+	/*
+	 * Configure the USB port as device or host according to the static
+	 * configuration passed from DT.
+	 * DRD is the only mode currently supported so this will be enhanced
+	 * as soon as OTG is available.
+	 */
+	ret = st_dwc3_drd_init(dwc3_data);
+	if (ret) {
+		dev_err(dev, "drd initialisation failed\n");
+		of_platform_depopulate(dev);
+		goto undo_softreset;
+	}
+
+	/* ST glue logic init */
+	st_dwc3_init(dwc3_data);
+
+	platform_set_drvdata(pdev, dwc3_data);
+	return 0;
+
+depopulate:
+	of_platform_depopulate(dev);
+err_node_put:
+	of_node_put(child);
+undo_softreset:
+	reset_control_assert(dwc3_data->rstc_rst);
+undo_powerdown:
+	reset_control_assert(dwc3_data->rstc_pwrdn);
+	return ret;
+}
+
+static int st_dwc3_remove(struct platform_device *pdev)
+{
+	struct st_dwc3 *dwc3_data = platform_get_drvdata(pdev);
+
+	of_platform_depopulate(&pdev->dev);
+
+	reset_control_assert(dwc3_data->rstc_pwrdn);
+	reset_control_assert(dwc3_data->rstc_rst);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int st_dwc3_suspend(struct device *dev)
+{
+	struct st_dwc3 *dwc3_data = dev_get_drvdata(dev);
+
+	reset_control_assert(dwc3_data->rstc_pwrdn);
+	reset_control_assert(dwc3_data->rstc_rst);
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int st_dwc3_resume(struct device *dev)
+{
+	struct st_dwc3 *dwc3_data = dev_get_drvdata(dev);
+	int ret;
+
+	pinctrl_pm_select_default_state(dev);
+
+	reset_control_deassert(dwc3_data->rstc_pwrdn);
+	reset_control_deassert(dwc3_data->rstc_rst);
+
+	ret = st_dwc3_drd_init(dwc3_data);
+	if (ret) {
+		dev_err(dev, "drd initialisation failed\n");
+		return ret;
+	}
+
+	/* ST glue logic init */
+	st_dwc3_init(dwc3_data);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(st_dwc3_dev_pm_ops, st_dwc3_suspend, st_dwc3_resume);
+
+static const struct of_device_id st_dwc3_match[] = {
+	{ .compatible = "st,stih407-dwc3" },
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, st_dwc3_match);
+
+static struct platform_driver st_dwc3_driver = {
+	.probe = st_dwc3_probe,
+	.remove = st_dwc3_remove,
+	.driver = {
+		.name = "usb-st-dwc3",
+		.of_match_table = st_dwc3_match,
+		.pm = &st_dwc3_dev_pm_ops,
+	},
+};
+
+module_platform_driver(st_dwc3_driver);
+
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_DESCRIPTION("DesignWare USB3 STi Glue Layer");
+MODULE_LICENSE("GPL v2");
diff --git a/marvell/linux/drivers/usb/dwc3/ep0.c b/marvell/linux/drivers/usb/dwc3/ep0.c
new file mode 100644
index 0000000..3b9e6ac
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/ep0.c
@@ -0,0 +1,1272 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/cputype.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+
+#include "core.h"
+#include "debug.h"
+#include "gadget.h"
+#include "io.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 void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
+		dma_addr_t buf_dma, u32 len, u32 type, bool chain)
+{
+	struct dwc3_trb			*trb;
+	struct dwc3			*dwc;
+
+	dwc = dep->dwc;
+
+	if ((dep->trb_enqueue > 1) || (chain && (dep->trb_enqueue != 0))) {
+		pr_err("!!!!error: ep%d trb_enqueue: %d, len: %d, type: %d\n", dep->number, dep->trb_enqueue, len, type);
+		WARN(1, "ep0 trb error\n");
+	}
+
+	trb = &dwc->ep0_trb[dep->trb_enqueue];
+
+	if (chain) {
+		dep->trb_enqueue++;
+		dep->trb_enqueue = dep->trb_enqueue & (DWC3_TRB_NUM - 1);
+	}
+	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);
+
+	trace_dwc3_prepare_trb(dep, trb);
+}
+
+static int dwc3_ep0_start_trans(struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3			*dwc;
+	int				ret;
+
+	if (dep->flags & DWC3_EP_TRANSFER_STARTED) {
+		pr_info("!!!!!ep%d STARTED\n", dep->number);
+		return 0;
+	}
+	dwc = dep->dwc;
+
+	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(dep, DWC3_DEPCMD_STARTTRANSFER, &params);
+	if (ret < 0) {
+		dev_err(dwc->dev, "ep%d start xfer failed, ret: %d\n", dep->number, ret);
+		return ret;
+	}
+
+	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->pending_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]);
+
+		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 || !dwc->pullups_connected) {
+		dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
+				dep->name);
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	if (os_detect_is_done()) {
+		dev_err(dwc->dev,
+				"os detection is done, skip ep:%s req: %d\n", dep->name, request->length);
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+#endif
+
+	/* we share one TRB for ep0/1 */
+	if (!list_empty(&dep->pending_list)) {
+		ret = -EBUSY;
+		dev_err(dwc->dev, "ep%d still pending\n", dep->number);
+		goto out;
+	}
+
+	ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+static void dwc3_reset_ep0(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];
+	dep->flags = DWC3_EP_ENABLED;
+	dwc->delayed_status = false;
+
+	if (!list_empty(&dep->pending_list)) {
+		struct dwc3_request	*req;
+
+		req = next_request(&dep->pending_list);
+		dwc3_gadget_giveback(dep, req, -ECONNRESET);
+	}
+}
+#endif
+
+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->pending_list)) {
+		struct dwc3_request	*req;
+
+		req = next_request(&dep->pending_list);
+		if (!dwc->connected)
+			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+		else
+			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)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+	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)
+{
+	struct dwc3_ep			*dep;
+	int				ret;
+
+	complete(&dwc->ep0_in_setup);
+
+	dep = dwc->eps[0];
+	dwc3_ep0_prepare_one_trb(dep, dwc->ctrl_req_addr, 8,
+			DWC3_TRBCTL_CONTROL_SETUP, false);
+	ret = dwc3_ep0_start_trans(dep);
+	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 == NULL) {
+		dev_err(dwc->dev, "ep%d NULL\n", epnum);
+		return NULL;
+	}
+
+	if (dep->flags & DWC3_EP_ENABLED)
+		return dep;
+
+	dev_err(dwc->dev, "ep%d not enabled, flags: %x\n", epnum, dep->flags);
+	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			value;
+	u32			reg;
+	u16			usb_status = 0;
+	__le16			*response_pkt;
+
+	/* We don't support PTM_STATUS */
+	value = le16_to_cpu(ctrl->wValue);
+	if (value != 0)
+		return -EINVAL;
+
+	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->gadget.is_selfpowered;
+
+		if ((dwc->speed == DWC3_DSTS_SUPERSPEED) ||
+		    (dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
+			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) {
+			dev_err(dwc->dev, "usb err: dep is NULL\n");
+			return -EINVAL;
+		}
+		if (dep->flags & DWC3_EP_STALL)
+			usb_status = 1 << USB_ENDPOINT_HALT;
+		break;
+	default:
+		dev_err(dwc->dev, "%s recip: %x\n", __func__, recip);
+		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_u1(struct dwc3 *dwc, enum usb_device_state state,
+		int set)
+{
+	u32 reg;
+
+	if (state != USB_STATE_CONFIGURED)
+		return -EINVAL;
+	if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
+			(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
+		return -EINVAL;
+	if (set && dwc->dis_u1_entry_quirk)
+		return -EINVAL;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (cpu_is_asr1901() || cpu_is_asr1906()) {
+		reg &= ~DWC3_DCTL_INITU1ENA;
+	} else {
+		if (set)
+			reg |= DWC3_DCTL_INITU1ENA;
+		else
+			reg &= ~DWC3_DCTL_INITU1ENA;
+	}
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	return 0;
+}
+
+static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state,
+		int set)
+{
+	u32 reg;
+
+
+	if (state != USB_STATE_CONFIGURED)
+		return -EINVAL;
+	if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
+			(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
+		return -EINVAL;
+	if (set && dwc->dis_u2_entry_quirk)
+		return -EINVAL;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (cpu_is_asr1901() || cpu_is_asr1906()) {
+		reg &= ~DWC3_DCTL_INITU2ENA;
+	} else {
+		if (set)
+			reg |= DWC3_DCTL_INITU2ENA;
+		else
+			reg &= ~DWC3_DCTL_INITU2ENA;
+	}
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	return 0;
+}
+
+static int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state,
+		u32 wIndex, int set)
+{
+	if ((wIndex & 0xff) != 0)
+		return -EINVAL;
+	if (!set)
+		return -EINVAL;
+
+	switch (wIndex >> 8) {
+	case TEST_J:
+	case TEST_K:
+	case TEST_SE0_NAK:
+	case TEST_PACKET:
+	case TEST_FORCE_EN:
+		dwc->test_mode_nr = wIndex >> 8;
+		dwc->test_mode = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dwc3_ep0_handle_device(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	enum usb_device_state	state;
+	u32			wValue;
+	u32			wIndex;
+	int			ret = 0;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+	state = dwc->gadget.state;
+
+	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:
+		ret = dwc3_ep0_handle_u1(dwc, state, set);
+		break;
+	case USB_DEVICE_U2_ENABLE:
+		ret = dwc3_ep0_handle_u2(dwc, state, set);
+		break;
+	case USB_DEVICE_LTM_ENABLE:
+		ret = -EINVAL;
+		break;
+	case USB_DEVICE_TEST_MODE:
+		ret = dwc3_ep0_handle_test(dwc, state, wIndex, set);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int dwc3_ep0_handle_intf(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	u32			wValue;
+	int			ret = 0;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+
+	switch (wValue) {
+	case USB_INTRF_FUNC_SUSPEND:
+		/*
+		 * REVISIT: Ideally we would enable some low power mode here,
+		 * however it's unclear what we should be doing here.
+		 *
+		 * For now, we're not doing anything, just making sure we return
+		 * 0 so USB Command Verifier tests pass without any errors.
+		 */
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	struct dwc3_ep		*dep;
+	u32			wValue;
+	int			ret;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+
+	switch (wValue) {
+	case USB_ENDPOINT_HALT:
+		dep = dwc3_wIndex_to_dep(dwc, ctrl->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) {
+			dev_err(dwc->dev, "set ep%d halt %d\n", dep->number, ret);
+			return -EINVAL;
+		}
+
+		/* ClearFeature(Halt) may need delayed status */
+		if (!set && (dep->flags & DWC3_EP_END_TRANSFER_PENDING))
+			return USB_GADGET_DELAYED_STATUS;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	u32			recip;
+	int			ret;
+
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		ret = dwc3_ep0_handle_device(dwc, ctrl, set);
+		break;
+	case USB_RECIP_INTERFACE:
+		ret = dwc3_ep0_handle_intf(dwc, ctrl, set);
+		break;
+	case USB_RECIP_ENDPOINT:
+		ret = dwc3_ep0_handle_endpoint(dwc, ctrl, set);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+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_err(dwc->dev, "invalid device address %d\n", addr);
+		return -EINVAL;
+	}
+
+	if (state == USB_STATE_CONFIGURED) {
+		dev_err(dwc->dev, "can't SetAddress() from Configured State\n");
+		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);
+		dwc3_report_sdp_charger(dwc);
+	} 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;
+
+	cfg = le16_to_cpu(ctrl->wValue);
+
+	switch (state) {
+	case USB_STATE_DEFAULT:
+		dev_err(dwc->dev, "err: set cfg on state default\n");
+		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);
+			if (cpu_is_asr1901() || cpu_is_asr1906()) {
+				reg &= ~(DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+			} else {			
+				if (!dwc->dis_u1_entry_quirk)
+					reg |= DWC3_DCTL_ACCEPTU1ENA;
+				if (!dwc->dis_u2_entry_quirk)
+					reg |= DWC3_DCTL_ACCEPTU2ENA;
+			}
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+		}
+		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;
+		__le16	u2sel;
+		__le16	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) {
+		dev_err(dwc->dev, "usb err: set sel on state default\n");
+		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;
+
+	dwc->gadget.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:
+		ret = dwc3_ep0_handle_status(dwc, ctrl);
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+		break;
+	case USB_REQ_SET_ADDRESS:
+		ret = dwc3_ep0_set_address(dwc, ctrl);
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		ret = dwc3_ep0_set_config(dwc, ctrl);
+		break;
+	case USB_REQ_SET_SEL:
+		ret = dwc3_ep0_set_sel(dwc, ctrl);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
+		break;
+	default:
+		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) {
+		dev_err(dwc->dev, "dwc gadget_driver NULL\n");
+		goto out;
+	}
+
+	if (!dwc->vbus_active) {
+		dev_err(dwc->dev, "!!!inspect setup: vbus_active 0\n");
+		goto out;
+	}
+
+	trace_dwc3_ctrl_req(ctrl);
+
+	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 (!dwc->vbus_active) {
+		dev_err(dwc->dev, "!!!dwc setup: exit\n");
+		return;
+	}
+
+	if (ret < 0) {
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+		if (os_detect_is_done()) {
+			dev_info(dwc->dev, "os detect:  reset ep0\n");
+			dwc3_reset_ep0(dwc);
+			return;
+		}
+#endif
+		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;
+	struct usb_request	*ur;
+	struct dwc3_trb		*trb;
+	struct dwc3_ep		*ep0;
+	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;
+	trace_dwc3_complete_trb(ep0, trb);
+
+	r = next_request(&ep0->pending_list);
+	if (!r)
+		return;
+
+	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+	if (status == DWC3_TRBSTS_SETUP_PENDING) {
+		dwc->setup_packet_pending = true;
+		if (r)
+			dwc3_gadget_giveback(ep0, r, -ECONNRESET);
+		pr_info("ep0state: %d, DWC3_TRBSTS_SETUP_PENDING\n", dwc->ep0state);
+		return;
+	}
+
+	ur = &r->request;
+
+	length = trb->size & DWC3_TRB_SIZE_MASK;
+	transferred = ur->length - length;
+	ur->actual += transferred;
+
+	if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+	     ur->length && ur->zero) || dwc->ep0_bounced) {
+		trb++;
+		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+		trace_dwc3_complete_trb(ep0, trb);
+
+		if (r->direction)
+			dwc->eps[1]->trb_enqueue = 0;
+		else
+			dwc->eps[0]->trb_enqueue = 0;
+
+		dwc->ep0_bounced = false;
+	}
+
+	if ((epnum & 1) && ur->actual < ur->length)
+		dwc3_ep0_stall_and_restart(dwc);
+	else
+		dwc3_gadget_giveback(ep0, r, 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;
+
+	trace_dwc3_complete_trb(dep, trb);
+
+	if (!list_empty(&dep->pending_list)) {
+		r = next_request(&dep->pending_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_err(dwc->dev, "invalid test #%d\n",
+					dwc->test_mode_nr);
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+	}
+
+	status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+	if (status == DWC3_TRBSTS_SETUP_PENDING)
+		dwc->setup_packet_pending = true;
+
+	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_TRANSFER_STARTED;
+	dep->resource_index = 0;
+	dwc->setup_packet_pending = false;
+
+	switch (dwc->ep0state) {
+	case EP0_SETUP_PHASE:
+		dwc3_ep0_inspect_setup(dwc, event);
+		break;
+
+	case EP0_DATA_PHASE:
+		dwc3_ep0_complete_data(dwc, event);
+		break;
+
+	case EP0_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)
+{
+	unsigned int		trb_length = 0;
+	int			ret;
+
+	req->direction = !!dep->number;
+
+	if (req->request.length == 0) {
+		if (!req->direction)
+			trb_length = dep->endpoint.maxpacket;
+
+		dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, trb_length,
+				DWC3_TRBCTL_CONTROL_DATA, false);
+		ret = dwc3_ep0_start_trans(dep);
+	} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
+			&& (dep->number == 0)) {
+		u32	maxpacket;
+		u32	rem;
+
+		ret = usb_gadget_map_request_by_dev(dwc->sysdev,
+				&req->request, dep->number);
+		if (ret) {
+			dev_err(dwc->dev, "%s map req failed\n", __func__);
+			return;
+		}
+		maxpacket = dep->endpoint.maxpacket;
+		rem = req->request.length % maxpacket;
+		dwc->ep0_bounced = true;
+
+		/* prepare normal TRB */
+		dwc3_ep0_prepare_one_trb(dep, req->request.dma,
+					 req->request.length,
+					 DWC3_TRBCTL_CONTROL_DATA,
+					 true);
+
+		req->trb = &dwc->ep0_trb[(dep->trb_enqueue - 1) & (DWC3_TRB_NUM - 1)];
+
+		/* Now prepare one extra TRB to align transfer size */
+		dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
+					 maxpacket - rem,
+					 DWC3_TRBCTL_CONTROL_DATA,
+					 false);
+		ret = dwc3_ep0_start_trans(dep);
+	} else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
+		   req->request.length && req->request.zero) {
+
+		ret = usb_gadget_map_request_by_dev(dwc->sysdev,
+				&req->request, dep->number);
+		if (ret) {
+			dev_err(dwc->dev, "%s map req failed,len: %d\n", __func__, req->request.length);
+			return;
+		}
+		/* prepare normal TRB */
+		dwc3_ep0_prepare_one_trb(dep, req->request.dma,
+					 req->request.length,
+					 DWC3_TRBCTL_CONTROL_DATA,
+					 true);
+
+		req->trb = &dwc->ep0_trb[(dep->trb_enqueue - 1) & (DWC3_TRB_NUM - 1)];
+
+		if (!req->direction)
+			trb_length = dep->endpoint.maxpacket;
+
+		/* Now prepare one extra TRB to align transfer size */
+		dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
+					 trb_length, DWC3_TRBCTL_CONTROL_DATA,
+					 false);
+		ret = dwc3_ep0_start_trans(dep);
+	} else {
+		ret = usb_gadget_map_request_by_dev(dwc->sysdev,
+				&req->request, dep->number);
+		if (ret) {
+			dev_err(dwc->dev, "%s map req failed,len: %d\n", __func__, req->request.length);
+			return;
+		}
+
+		dwc3_ep0_prepare_one_trb(dep, req->request.dma,
+				req->request.length, DWC3_TRBCTL_CONTROL_DATA,
+				false);
+
+		req->trb = &dwc->ep0_trb[dep->trb_enqueue];
+
+		ret = dwc3_ep0_start_trans(dep);
+	}
+
+	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;
+
+	dwc3_ep0_prepare_one_trb(dep, dwc->ctrl_req_addr, 0, type, false);
+	return dwc3_ep0_start_trans(dep);
+}
+
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	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];
+
+	if (unlikely(event->endpoint_number == dwc->ep0_expect_in)) {
+		dev_err(dwc->dev, "error event: 0x%x\n", *((u32 *)event));
+		dep = dwc->eps[!dwc->ep0_expect_in];
+	}
+
+	__dwc3_ep0_do_control_status(dwc, dep);
+}
+
+void dwc3_ep0_send_delayed_status(struct dwc3 *dwc)
+{
+	unsigned int direction = !dwc->ep0_expect_in;
+
+	dwc->delayed_status = false;
+
+	if (dwc->ep0state != EP0_STATUS_PHASE)
+		return;
+
+	__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
+}
+
+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) {
+		dev_err(dwc->dev, "usb err: resource_index = 0\n");
+		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(dep, cmd, &params);
+	WARN_ON_ONCE(ret);
+	dep->resource_index = 0;
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	switch (event->status) {
+	case DEPEVT_STATUS_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_err(dwc->dev, "unexpected direction for Data Phase\n");
+			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;
+
+		dwc->ep0state = EP0_STATUS_PHASE;
+
+		if (dwc->delayed_status) {
+			struct dwc3_ep *dep = dwc->eps[0];
+
+			WARN_ON_ONCE(event->endpoint_number != 1);
+			/*
+			 * We should handle the delay STATUS phase here if the
+			 * request for handling delay STATUS has been queued
+			 * into the list.
+			 */
+			if (!list_empty(&dep->pending_list)) {
+				dwc->delayed_status = false;
+				usb_gadget_set_state(&dwc->gadget,
+						     USB_STATE_CONFIGURED);
+				dwc3_ep0_do_control_status(dwc, event);
+			}
+
+			return;
+		}
+
+		dwc3_ep0_do_control_status(dwc, event);
+	}
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep	*dep = dwc->eps[event->endpoint_number];
+	u8		cmd;
+
+	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:
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		cmd = DEPEVT_PARAMETER_CMD(event->parameters);
+
+		if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
+			dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
+			dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+		}
+		break;
+	}
+}
diff --git a/marvell/linux/drivers/usb/dwc3/gadget.c b/marvell/linux/drivers/usb/dwc3/gadget.c
new file mode 100644
index 0000000..a97f54b
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/gadget.c
@@ -0,0 +1,5612 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/pm_qos.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/gadget.h>
+#include <linux/platform_data/mv_usb.h>
+#include <linux/usb/mv_usb2_phy.h>
+#include <linux/power_supply.h>
+#include <linux/cputype.h>
+#include <soc/asr/addr-map.h>
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+#include <linux/usb/composite.h>
+#endif
+#include <linux/memblock.h>
+
+#include "debug.h"
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+#ifdef CONFIG_CPU_ASR1901
+#include "../gadget/function/u_ether.h"
+#endif
+
+#define DWC3_ALIGN_FRAME(d, n)	(((d)->frame_number + ((d)->interval * (n))) \
+					& ~((d)->interval - 1))
+#define ENUMERATION_DELAY               (2 * HZ)
+#define DWC3_WAKEUP_TIMEOUT_SEC         (5)
+
+
+static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
+		bool interrupt);
+static void dwc3_stop_active_transfers(struct dwc3 *dwc);
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc);
+static void __dwc3_gadget_stop(struct dwc3 *dwc);
+static int __dwc3_gadget_start(struct dwc3 *dwc);
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend);
+static void dwc3_gadget_set_speed_nolock(struct usb_gadget *g,
+				  enum usb_device_speed speed);
+#ifdef CONFIG_USB_G_ANDROID
+extern void android_dev_enable(uint8_t enabled);
+#endif
+
+static BLOCKING_NOTIFIER_HEAD(dwc3_notifier_list);
+static struct dwc3 *the_controller;
+
+static DEFINE_MUTEX(usb_con_mutex);
+
+static ATOMIC_NOTIFIER_HEAD(asr_udc_resume_list);
+
+struct dwc3 *dwc3_get_controller(void)
+{
+	return the_controller;
+}
+
+static void dwc3_restart_work(struct work_struct *work)
+{
+	u32			vbus = 0;
+	int			ret;
+
+	the_controller->usb_do_restart = 0;
+	ret = pxa_usb_extern_call(PXA_USB_DEV_OTG, vbus, get_vbus, &vbus);
+	if (ret) {
+		vbus = usb_phy_get_vbus(the_controller->usb2_phy);
+	}
+
+	if ((!the_controller->vbus_active) || (!vbus)) {
+		pr_err("%s vbus is off\n", __func__);
+		return;
+	}
+
+	msleep(500);
+	ret = pxa_usb_extern_call(PXA_USB_DEV_OTG, vbus, get_vbus, &vbus);
+	if (ret) {
+		vbus = usb_phy_get_vbus(the_controller->usb2_phy);
+	}
+
+	if ((!the_controller->vbus_active) || (!vbus)) {
+		pr_err("%s vbus is off2\n", __func__);
+		return;
+	}
+
+	pr_info("%s \n", __func__);
+	android_dev_enable(0);
+	android_dev_enable(1);	
+}
+#ifdef CONFIG_DWC3_HWSULOG
+#define SULOG_BASE_OFFSET	(0x20000)
+#define SULOG_PORT0_OFFSET	(0x0)
+#define SULOG_PORT1_OFFSET	(0x8000)
+#define SULOG_REG_CTRL		(0x0)
+#define SULOG_EP_CFG		(0x4)
+#define SULOG_DLY_TIMER		(0x74)
+#define SULOG_INT_CFG		(0x80)
+#define SULOG_INT_STS		(0x84)
+
+#ifndef CONFIG_CPU_ASR1901
+#define RIPC_VIRT_BASE		(APB_VIRT_BASE + 0x03D100 + 0x1C)
+#else
+#define RIPC_VIRT_BASE		(APB_VIRT_BASE + 0x0B0100 + 0x1C)
+#endif
+
+static int hwsulog_ep;
+static bool hwsulog_enabled = false;
+static bool hwsulog_on = false;
+extern u32 sulog_ep_num;
+
+extern void register_hwsulog_udc_func(int (*func) (int ep_num, u32 flag));
+extern void unregister_hwsulog_udc_func(void);
+
+bool dwc3_hwsulog_is_on(void)
+{
+	return hwsulog_on;
+}
+
+void dwc3_hwsulog_on(bool is_on)
+{
+	hwsulog_on = is_on;
+
+	if (cpu_is_asr1901() || cpu_is_asr1906()) {
+		if (is_on) {
+			pr_info("enable sulog\n");
+			writel(3, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_CFG));
+			writel((readl(the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_STS)),
+				(the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_STS));
+			writel((0x1 << 0) | (0x1 << 7) | (0x1 << 6)| (0x1 << 31),
+					(the_controller->hwsulog_regs + SULOG_REG_CTRL));
+		} else {
+			writel((0x1 << 7) | (0x1 << 6)| (0x1 << 31),
+					(the_controller->hwsulog_regs + SULOG_REG_CTRL));
+			pr_info("disable sulog\n");
+		}
+	}
+}
+
+int hwsulog_set_clear_stop_flag(bool set)
+{
+	u32 regval;
+
+	regval = readl(RIPC_VIRT_BASE);
+	if (set)
+		regval |= (0x1 << 0);
+	else
+		regval &= ~(0x1 << 0);
+	writel(regval, RIPC_VIRT_BASE);
+
+	return 0;
+}
+
+int asr_udc_hwsulog_callback(int ep_num, u32 flag)
+{
+	pr_info("%s flag: %d, ep: %d\n", __func__, flag, ep_num);
+	BUG_ON(!the_controller);
+	BUG_ON(!the_controller->hwsulog_regs);
+	ep_num = ep_num * 2 + 1;
+
+	if (1 == flag) {
+		/* don't configure sulog again if sulog is already working */
+		if (true == hwsulog_enabled) {
+			pr_err("hwsulog already enabled");
+		}
+
+		/* clear flag */
+		hwsulog_set_clear_stop_flag(false);
+		writel(ep_num & 0x1f, (the_controller->hwsulog_regs + SULOG_EP_CFG));
+		/* 1828: 4g only, 1903: 4g/5g */
+		if (cpu_is_asr1828()) {
+			writel((0x1 << 0) | (0x1 << 7), 
+				(the_controller->hwsulog_regs + SULOG_REG_CTRL));
+			writel(0x0, (the_controller->hwsulog_regs +
+						SULOG_PORT1_OFFSET + SULOG_REG_CTRL));
+
+			writel(0, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_CFG));
+		} else if (cpu_is_asr1903()) {
+			writel((0x1 << 0) | (0x1 << 7) | (0x1 << 6) | (0x1 << 31), 
+				(the_controller->hwsulog_regs + SULOG_REG_CTRL));
+
+			writel(3, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_CFG));
+			writel(3, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_STS));
+			writel(0x80000200, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_DLY_TIMER));
+		} else { /* asr1901 and asr1906 */
+			writel((0x1 << 7) | (0x1 << 6) | (0x1 << 31),
+				(the_controller->hwsulog_regs + SULOG_REG_CTRL));
+			writel(0, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_CFG));
+			writel(0, (the_controller->hwsulog_regs + SULOG_PORT1_OFFSET + SULOG_INT_CFG));
+		}
+
+		hwsulog_ep = ep_num;
+		hwsulog_enabled = true;
+	} else {
+		hwsulog_set_clear_stop_flag(true);
+		writel(0, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_CFG));
+		//writel(0x0, (the_controller->hwsulog_regs + SULOG_REG_CTRL));
+		hwsulog_ep = 0;
+		hwsulog_enabled = false;
+	}
+
+	return 0;
+}
+
+static void hwsulog_dump_regs(void)
+{
+	u32 i;
+
+	for (i = 0; i < 0xa0; i += 0x20) {
+		pr_info("0x%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+			i, readl(the_controller->hwsulog_regs + i + 0),
+			readl(the_controller->hwsulog_regs + i + 4),
+			readl(the_controller->hwsulog_regs + i + 8),
+			readl(the_controller->hwsulog_regs + i + 0xc),
+			readl(the_controller->hwsulog_regs + i + 0x10),
+			readl(the_controller->hwsulog_regs + i + 0x14),
+			readl(the_controller->hwsulog_regs + i + 0x18),
+			readl(the_controller->hwsulog_regs + i + 0x1c));
+	}
+	for (i = 0x100; i < 0x160; i += 0x20) {
+		pr_info("0x%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+			i, readl(the_controller->hwsulog_regs + i + 0),
+			readl(the_controller->hwsulog_regs + i + 4),
+			readl(the_controller->hwsulog_regs + i + 8),
+			readl(the_controller->hwsulog_regs + i + 0xc),
+			readl(the_controller->hwsulog_regs + i + 0x10),
+			readl(the_controller->hwsulog_regs + i + 0x14),
+			readl(the_controller->hwsulog_regs + i + 0x18),
+			readl(the_controller->hwsulog_regs + i + 0x1c));
+	}
+}
+
+static int hwsulog_restart_usb(void)
+{
+	writel(0, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_CFG));
+	writel(3, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_STS));
+
+	if (!work_pending(&the_controller->usb_restart_work.work)) {
+		hwsulog_set_clear_stop_flag(true);
+		schedule_delayed_work(&the_controller->usb_restart_work, 0);
+	}
+	hwsulog_dump_regs();
+	return 0;
+}
+
+static int hwsulog_restart_xfer(void)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	u32				cmd;
+	unsigned long flags;
+	struct dwc3_ep *dep = the_controller->eps[hwsulog_ep];
+	int ret;
+
+	memset(&params, 0, sizeof(params));
+	params.param1 = 0xc0000000;
+	cmd = DWC3_DEPCMD_STARTTRANSFER;
+
+	spin_lock_irqsave(&the_controller->lock, flags);
+	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
+
+	hwsulog_dump_regs();
+	return ret;
+}
+
+int hwsulog_error_handler(void)
+{
+	u32 regval;
+	int ret;
+
+	BUG_ON(!the_controller);
+	BUG_ON(!the_controller->hwsulog_regs);
+
+	regval = readl(the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_STS);
+	writel(regval, (the_controller->hwsulog_regs + SULOG_PORT0_OFFSET + SULOG_INT_STS));
+	pr_info_ratelimited("%s, sts: 0x%x\n", __func__, regval);
+
+	/* usb controller is dead, the only thing to do is to restart usb */
+	if (regval & (0x1 << 0)) {
+		hwsulog_restart_usb();
+		return 0;
+	}
+
+	if (regval & (0x1 << 1)) {
+		ret = hwsulog_restart_xfer();
+		if (-ETIMEDOUT == ret)
+			hwsulog_restart_usb();
+	}
+
+	return 0;
+}
+
+void dwc3_hwsulog_clear_int(void)
+{
+	hwsulog_error_handler();
+}
+#endif
+
+void dwc3_release_wakeup_event(void)
+{
+	pm_relax(the_controller->dev);	
+}
+
+void dwc3_release_wakeup_event_timeout(u32 sec)
+{
+	pm_wakeup_event(the_controller->dev, (sec * 1000));
+}
+
+void dwc3_acquire_wakeup_event(void)
+{
+	pm_stay_awake(the_controller->dev);
+}
+
+void dwc3_release_pm_qos(void)
+{
+	pm_qos_update_request(&the_controller->qos_idle,
+		PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);
+}
+
+void dwc3_release_pm_qos_timeout(u32 sec)
+{
+	pm_qos_update_request_timeout(&the_controller->qos_idle,
+		PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE, sec * (1000 * 1000));
+}
+
+void dwc3_acquire_pm_qos(void)
+{
+	pm_qos_update_request(&the_controller->qos_idle, the_controller->lpm_qos);
+}
+
+int asr_udc_register_resume_notifier(struct notifier_block *nb)
+{
+	int ret = 0;
+
+	ret = atomic_notifier_chain_register(&asr_udc_resume_list, nb);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int asr_udc_unregister_resume_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&asr_udc_resume_list, nb);
+}
+
+static void asr_udc_notify_resume_event(struct dwc3 *dwc, int event)
+{
+	atomic_notifier_call_chain(&asr_udc_resume_list, event, NULL);
+}
+
+static const char *charger_type(unsigned int type)
+{
+	switch (type) {
+	case NULL_CHARGER: return "NULL_CHARGER";
+	case DEFAULT_CHARGER: return "DEFAULT_CHARGER";
+	case DCP_CHARGER: return "DCP_CHARGER";
+	case CDP_CHARGER: return "CDP_CHARGER";
+	case SDP_CHARGER: return "SDP_CHARGER";
+	default: return "NONE_STANDARD_CHARGER";
+	}
+}
+
+int udc_get_charger_type(void)
+{
+	struct dwc3 *dwc = the_controller;
+
+	if (!dwc)
+		return POWER_SUPPLY_TYPE_UNKNOWN;
+
+	switch(dwc->charger_type) {
+	case SDP_CHARGER:
+		return POWER_SUPPLY_TYPE_USB;
+	case DCP_CHARGER:
+		return POWER_SUPPLY_TYPE_USB_DCP;
+
+	case DEFAULT_CHARGER:
+	case CDP_CHARGER:
+	case NONE_STANDARD_CHARGER:
+	default:
+		return POWER_SUPPLY_TYPE_UNKNOWN;
+	}
+}
+
+static void call_charger_notifier(struct dwc3 *dwc)
+{
+	blocking_notifier_call_chain(&dwc3_notifier_list,
+				dwc->charger_type, NULL);
+}
+
+/* For any user that care about USB udc events, for example the charger*/
+int mv_udc_register_client(struct notifier_block *nb)
+{
+	struct dwc3 *dwc = the_controller;
+	int ret = 0;
+
+	if (!dwc)
+		return -ENODEV;
+
+	ret = blocking_notifier_chain_register(&dwc3_notifier_list, nb);
+	if (ret)
+		return ret;
+
+	if (dwc->charger_type)
+		call_charger_notifier(dwc);
+
+	return 0;
+}
+EXPORT_SYMBOL(mv_udc_register_client);
+
+int mv_udc_unregister_client(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&dwc3_notifier_list, nb);
+}
+EXPORT_SYMBOL(mv_udc_unregister_client);
+
+static void do_delayed_charger_work(struct work_struct *work)
+{
+	struct dwc3 *dwc = NULL;
+
+	dwc = container_of(work, struct dwc3, delayed_charger_work.work);
+
+	/* if still see DEFAULT_CHARGER, check again */
+	if (dwc->charger_type == DEFAULT_CHARGER) {
+		dwc->charger_type = NONE_STANDARD_CHARGER;
+	}
+
+	dev_info(dwc->dev, "final charger type: %s\n",
+				charger_type(dwc->charger_type));
+
+	call_charger_notifier(dwc);
+
+
+	/* SDP or CDP need transfer data, hold wake lock
+	* also hold lock for DCP: some chargers have watchdog or do not 
+	* have irq indication so need to work in polling mode
+	* and should not suspend
+	*/
+	if ((dwc->charger_type == SDP_CHARGER) ||
+		 (dwc->charger_type == NONE_STANDARD_CHARGER) ||
+		(dwc->charger_type == CDP_CHARGER) ||
+		(dwc->charger_type == DCP_CHARGER)) {
+		pm_stay_awake(dwc->dev);
+		pm_qos_update_request(&dwc->qos_idle, dwc->lpm_qos);
+	} else {
+		dev_info(dwc->dev, "rls pm lock\n");
+		pm_qos_update_request(&dwc->qos_idle,
+			PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);
+		/*
+		* leave some delay for charger driver to do something
+		* for nz3 we need some extra time to restore os type,
+		* so change it to 4s here
+		*/
+		pm_wakeup_event(dwc->dev, 5000);
+	}
+}
+
+void dwc3_report_sdp_charger(struct dwc3 *dwc)
+{
+	if (work_pending(&dwc->delayed_charger_work.work))
+		cancel_delayed_work(&dwc->delayed_charger_work);
+	dwc->charger_type = SDP_CHARGER;
+	schedule_delayed_work(&dwc->delayed_charger_work, 0);
+}
+
+
+static void __maybe_unused dump_dwc3_regs(struct dwc3 *dwc)
+{
+	u32 i;
+
+	for (i = 0xc100; i < 0xcc00; i += 32) {
+		pr_info("0x%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", i,
+			dwc3_readl(dwc->regs, i + 0),
+			dwc3_readl(dwc->regs, i + 4),
+			dwc3_readl(dwc->regs, i + 8),
+			dwc3_readl(dwc->regs, i + 12),
+			dwc3_readl(dwc->regs, i + 16),
+			dwc3_readl(dwc->regs, i + 20),
+			dwc3_readl(dwc->regs, i + 24),
+			dwc3_readl(dwc->regs, i + 28));
+	}
+
+	usb_phy_dump_cfg(dwc->usb2_phy);
+}
+
+/**
+ * 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);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * dwc3_ep_inc_trb - increment a trb index.
+ * @index: Pointer to the TRB index to increment.
+ *
+ * The index should never point to the link TRB. After incrementing,
+ * if it is point to the link TRB, wrap around to the beginning. The
+ * link TRB is always at the last TRB entry.
+ */
+static inline void dwc3_ep_inc_trb(u16 *index, struct dwc3_ep *dep)
+{
+	(*index)++;
+	(*index) = (*index) & (dep->trb_num - 1);
+	if (*index == (dep->trb_num - 1))
+		*index = 0;
+}
+
+/**
+ * dwc3_ep_inc_enq - increment endpoint's enqueue pointer
+ * @dep: The endpoint whose enqueue pointer we're incrementing
+ */
+static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
+{
+	dwc3_ep_inc_trb(&dep->trb_enqueue, dep);
+}
+
+/**
+ * dwc3_ep_inc_deq - increment endpoint's dequeue pointer
+ * @dep: The endpoint whose enqueue pointer we're incrementing
+ */
+static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
+{
+	dwc3_ep_inc_trb(&dep->trb_dequeue, dep);
+}
+
+static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
+		struct dwc3_request *req, int status)
+{
+	struct dwc3			*dwc = dep->dwc;
+
+	list_del(&req->list);
+	req->remaining = 0;
+	req->needs_extra_trb = false;
+	req->num_trbs = 0;
+
+	if (req->request.status == -EINPROGRESS)
+		req->request.status = status;
+
+	if (req->trb)
+		usb_gadget_unmap_request_by_dev(dwc->sysdev,
+				&req->request, req->direction);
+
+	req->trb = NULL;
+	trace_dwc3_gadget_giveback(req);
+
+#if 0 /* ASR private */
+	if (dep->number > 1)
+		pm_runtime_put(dwc->dev);
+#endif
+}
+
+/**
+ * dwc3_gadget_giveback - call struct usb_request's ->complete callback
+ * @dep: The endpoint to whom the request belongs to
+ * @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 dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status)
+{
+	struct dwc3			*dwc = dep->dwc;
+
+	if (unlikely((dwc->vbus_active == 0) && (req->request.actual == 0) && (status == 0))) {
+		pr_info_ratelimited("dwc3 gbk: vbus = 0\n");
+		status = -ESHUTDOWN;
+	}
+
+	dwc3_gadget_del_and_unmap_request(dep, req, status);
+	req->status = DWC3_REQUEST_STATUS_COMPLETED;
+
+	spin_unlock(&dwc->lock);
+	usb_gadget_giveback_request(&dep->endpoint, &req->request);
+	spin_lock(&dwc->lock);
+}
+
+/**
+ * dwc3_send_gadget_generic_command - issue a generic command for the controller
+ * @dwc: pointer to the controller context
+ * @cmd: the command to be issued
+ * @param: command parameter
+ *
+ * Caller should take care of locking. Issue @cmd with a given @param to @dwc
+ * and wait for its completion.
+ */
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
+{
+	u32		timeout = 500;
+	int		status = 0;
+	int		ret = 0;
+	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)) {
+			status = DWC3_DGCMD_STATUS(reg);
+			if (status)
+				ret = -EINVAL;
+			break;
+		}
+	} while (--timeout);
+
+	if (!timeout) {
+		ret = -ETIMEDOUT;
+		status = -ETIMEDOUT;
+	}
+
+	trace_dwc3_gadget_generic_cmd(cmd, param, status);
+
+	return ret;
+}
+
+static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
+
+/**
+ * dwc3_send_gadget_ep_cmd - issue an endpoint command
+ * @dep: the endpoint to which the command is going to be issued
+ * @cmd: the command to be issued
+ * @params: parameters to the command
+ *
+ * Caller should handle locking. This function will issue @cmd with given
+ * @params to @dep and wait for its completion.
+ */
+int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
+		struct dwc3_gadget_ep_cmd_params *params)
+{
+	const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
+	struct dwc3		*dwc = dep->dwc;
+	u32			timeout = 100000;
+	u32			saved_config = 0;
+	u32			reg;
+
+	int			cmd_status = 0;
+	int			ret = -EINVAL;
+
+	/*
+	 * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or
+	 * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an
+	 * endpoint command.
+	 *
+	 * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY
+	 * settings. Restore them after the command is completed.
+	 *
+	 * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
+	 */
+	if (dwc->gadget.speed <= USB_SPEED_HIGH) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+		if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
+			saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
+			reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+		}
+
+		if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) {
+			saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM;
+			reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+		}
+
+		if (saved_config)
+			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	}
+
+	if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
+		int link_state;
+
+		link_state = dwc3_gadget_get_link_state(dwc);
+		if ((link_state == DWC3_LINK_STATE_U1 ||
+		    link_state == DWC3_LINK_STATE_U2 ||
+		    link_state == DWC3_LINK_STATE_U3) &&
+		    (dwc->gadget.state >= USB_STATE_ADDRESS)) {
+			ret = __dwc3_gadget_wakeup(dwc);
+			dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
+					ret);
+		}
+	}
+
+	if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_UPDATETRANSFER) {
+		int link_state;
+
+		link_state = dwc3_gadget_get_link_state(dwc);
+		if ((link_state == DWC3_LINK_STATE_U3) &&
+		    (dwc->gadget.state >= USB_STATE_ADDRESS)) {
+			ret = __dwc3_gadget_wakeup(dwc);
+			if (ret < 0)
+				dev_warn_ratelimited(dwc->dev, "u3 wakeup failed --> %d\n",
+					ret);
+		}
+	}
+
+	dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);
+	dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1);
+	dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2);
+
+	/*
+	 * Synopsys Databook 2.60a states in section 6.3.2.5.6 of that if we're
+	 * not relying on XferNotReady, we can make use of a special "No
+	 * Response Update Transfer" command where we should clear both CmdAct
+	 * and CmdIOC bits.
+	 *
+	 * With this, we don't need to wait for command completion and can
+	 * straight away issue further commands to the endpoint.
+	 *
+	 * NOTICE: We're making an assumption that control endpoints will never
+	 * make use of Update Transfer command. This is a safe assumption
+	 * because we can never have more than one request at a time with
+	 * Control Endpoints. If anybody changes that assumption, this chunk
+	 * needs to be updated accordingly.
+	 */
+	if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_UPDATETRANSFER &&
+			!usb_endpoint_xfer_isoc(desc))
+		cmd &= ~(DWC3_DEPCMD_CMDIOC | DWC3_DEPCMD_CMDACT);
+	else
+		cmd |= DWC3_DEPCMD_CMDACT;
+	dep->num_cmds++;
+
+	dwc3_writel(dep->regs, DWC3_DEPCMD, cmd);
+	do {
+		reg = dwc3_readl(dep->regs, DWC3_DEPCMD);
+		if (!(reg & DWC3_DEPCMD_CMDACT)) {
+			cmd_status = DWC3_DEPCMD_STATUS(reg);
+
+			switch (cmd_status) {
+			case 0:
+				ret = 0;
+				break;
+			case DEPEVT_TRANSFER_NO_RESOURCE:
+				dev_err(dwc->dev, "ep%d XFER_NO_RESOURCE cmd: 0x%x, param: 0x%x 0x%x 0x%x\n",
+					dep->number, cmd,
+					params->param0, params->param1, params->param2);
+				ret = -EINVAL;
+				break;
+			case DEPEVT_TRANSFER_BUS_EXPIRY:
+				/*
+				 * SW issues START TRANSFER command to
+				 * isochronous ep with future frame interval. If
+				 * future interval time has already passed when
+				 * core receives the command, it will respond
+				 * with an error status of 'Bus Expiry'.
+				 *
+				 * Instead of always returning -EINVAL, let's
+				 * give a hint to the gadget driver that this is
+				 * the case by returning -EAGAIN.
+				 */
+				if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+					printk_ratelimited(KERN_DEBUG "ep%d XFER_BUS_EXPIRY cmd: 0x%x, param: 0x%x 0x%x 0x%x 0x%x\n",
+						dep->number, cmd,
+						params->param0, params->param1, params->param2,
+						dwc3_readl(dwc->regs, DWC3_DSTS));
+				else
+					dev_err(dwc->dev, "ep%d XFER_BUS_EXPIRY cmd: 0x%x, param: 0x%x 0x%x 0x%x 0x%x\n",
+						dep->number, cmd,
+						params->param0, params->param1, params->param2,
+						dwc3_readl(dwc->regs, DWC3_DSTS));					
+				ret = -EAGAIN;
+				break;
+			default:
+				dev_WARN(dwc->dev, "UNKNOWN cmd status\n");
+			}
+
+			break;
+		}
+	} while (--timeout);
+
+	if ((timeout == 0) && (cmd != 0x402)) {
+		dev_err(dwc->dev, "cmd: 0x%x timeout == 0, usb restart\n", cmd);
+		ret = -ETIMEDOUT;
+		cmd_status = -ETIMEDOUT;
+		/* dump_dwc3_regs(dwc); */
+		dwc->usb_do_restart = 1;
+		usb_phy_dump_cfg(dwc->usb2_phy);
+	}
+
+	trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
+
+	if (ret == 0 && DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
+		dep->flags |= DWC3_EP_TRANSFER_STARTED;
+		dwc3_gadget_ep_get_transfer_index(dep);
+	}
+
+	if (saved_config) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+		reg |= saved_config;
+		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	}
+
+	return ret;
+}
+
+static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
+{
+	struct dwc3 *dwc = dep->dwc;
+	struct dwc3_gadget_ep_cmd_params params;
+	u32 cmd = DWC3_DEPCMD_CLEARSTALL;
+
+	/*
+	 * As of core revision 2.60a the recommended programming model
+	 * is to set the ClearPendIN bit when issuing a Clear Stall EP
+	 * command for IN endpoints. This is to prevent an issue where
+	 * some (non-compliant) hosts may not send ACK TPs for pending
+	 * IN transfers due to a mishandled error condition. Synopsys
+	 * STAR 9000614252.
+	 */
+	if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) &&
+	    (dwc->gadget.speed >= USB_SPEED_SUPER))
+		cmd |= DWC3_DEPCMD_CLEARPENDIN;
+
+	memset(&params, 0, sizeof(params));
+
+	return dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+}
+
+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)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	if (dep->trb_pool)
+		return 0;
+
+	if ((cpu_is_asr1901() || cpu_is_asr1906()) && (dep->number == 2))
+		dep->trb_num = ASR1901_DWC3_EP2_TRB_NUM;
+	else if ((cpu_is_asr1901() || cpu_is_asr1906()) && (dep->number == 3))
+		dep->trb_num = ASR1901_DWC3_EP3_TRB_NUM;
+	else
+		dep->trb_num = DWC3_TRB_NUM;
+
+	dep->trb_pool = dma_alloc_coherent(dwc->sysdev,
+			sizeof(struct dwc3_trb) * dep->trb_num,
+			&dep->trb_pool_dma, GFP_KERNEL);
+	if (!dep->trb_pool) {
+		dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+				dep->name);
+		return -ENOMEM;
+	}
+	memset(dep->trb_pool, 0x0, sizeof(struct dwc3_trb) * dep->trb_num);
+
+	return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+
+	dma_free_coherent(dwc->sysdev, sizeof(struct dwc3_trb) * dep->trb_num,
+			dep->trb_pool, dep->trb_pool_dma);
+
+	dep->trb_pool = NULL;
+	dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_set_xfer_resource(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(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
+			&params);
+}
+
+/**
+ * dwc3_gadget_start_config - configure ep resources
+ * @dep: endpoint that is being enabled
+ *
+ * Issue a %DWC3_DEPCMD_DEPSTARTCFG command to @dep. After the command's
+ * completion, it will set Transfer Resource for all available endpoints.
+ *
+ * The assignment of transfer resources cannot perfectly follow the data book
+ * due to the fact that the controller driver does not have all knowledge of the
+ * configuration in advance. It is given this information piecemeal by the
+ * composite gadget framework after every SET_CONFIGURATION and
+ * SET_INTERFACE. Trying to follow the databook programming model in this
+ * scenario can cause errors. For two reasons:
+ *
+ * 1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every
+ * %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE (8.1.5). This is
+ * incorrect in the scenario of multiple interfaces.
+ *
+ * 2) The databook does not mention doing more %DWC3_DEPCMD_DEPXFERCFG for new
+ * endpoint on alt setting (8.1.6).
+ *
+ * The following simplified method is used instead:
+ *
+ * All hardware endpoints can be assigned a transfer resource and this setting
+ * will stay persistent until either a core reset or hibernation. So whenever we
+ * do a %DWC3_DEPCMD_DEPSTARTCFG(0) we can go ahead and do
+ * %DWC3_DEPCMD_DEPXFERCFG for every hardware endpoint as well. We are
+ * guaranteed that there are as many transfer resources as endpoints.
+ *
+ * This function is called for each endpoint when it is being enabled but is
+ * triggered only when called for EP0-out, which always happens first, and which
+ * should only happen in one of the above conditions.
+ */
+static int dwc3_gadget_start_config(struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3		*dwc;
+	u32			cmd;
+	int			i;
+	int			ret;
+
+	if (dep->number)
+		return 0;
+
+	memset(&params, 0x00, sizeof(params));
+	cmd = DWC3_DEPCMD_DEPSTARTCFG;
+	dwc = dep->dwc;
+
+	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+	if (ret) {
+		dev_err(dwc->dev, "DWC3_DEPCMD_DEPSTARTCFG failed\n");
+		return ret;
+	}
+	for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+		struct dwc3_ep *dep = dwc->eps[i];
+
+		if (!dep)
+			continue;
+
+		ret = dwc3_gadget_set_xfer_resource(dep);
+		if (ret) {
+			dev_err(dwc->dev, "dwc3_gadget_set_xfer_resource failed\n");
+			return ret;
+		}
+	}
+
+	dev_info(dep->dwc->dev, "st ep cfg done\n");
+	return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
+{
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	const struct usb_endpoint_descriptor *desc;
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3 *dwc = dep->dwc;
+
+	comp_desc = dep->endpoint.comp_desc;
+	desc = dep->endpoint.desc;
+
+	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;
+		params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
+	}
+
+	params.param0 |= action;
+	if (action == DWC3_DEPCFG_ACTION_RESTORE)
+		params.param2 |= dep->saved_state;
+
+	if (usb_endpoint_xfer_control(desc))
+		params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
+
+	if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc))
+		params.param1 |= 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) {
+		u8 bInterval_m1;
+
+		/*
+		 * Valid range for DEPCFG.bInterval_m1 is from 0 to 13, and it
+		 * must be set to 0 when the controller operates in full-speed.
+		 */
+		bInterval_m1 = min_t(u8, desc->bInterval - 1, 13);
+		if (dwc->gadget.speed == USB_SPEED_FULL)
+			bInterval_m1 = 0;
+
+		if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
+		    dwc->gadget.speed == USB_SPEED_FULL)
+			dep->interval = desc->bInterval;
+		else
+			dep->interval = 1 << (desc->bInterval - 1);
+
+		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1);
+	}
+
+	return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - initializes a hw endpoint
+ * @dep: endpoint to be initialized
+ * @action: one of INIT, MODIFY or RESTORE
+ *
+ * Caller should take care of locking. Execute all necessary commands to
+ * initialize a HW endpoint so it can be used by a gadget driver.
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
+{
+	const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
+	struct dwc3		*dwc = dep->dwc;
+
+	u32			reg;
+	int			ret;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		ret = dwc3_gadget_start_config(dep);
+		if (ret) {
+			dev_err(dep->dwc->dev, "start ep%d config failed %d\n", dep->number, ret);
+			return ret;
+		}
+	}
+
+	ret = dwc3_gadget_set_ep_config(dep, action);
+	if (ret) {
+		dev_err(dep->dwc->dev, "set ep%d config failed %d\n", dep->number, ret);
+		return ret;
+	}
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		struct dwc3_trb	*trb_st_hw;
+		struct dwc3_trb	*trb_link;
+
+		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 ((dep->number == 0) || (dep->number == 1)) {
+			if (dep->trb_dequeue || dep->trb_enqueue) {
+				pr_info("reset trb index(%d %d) for ep%d\n", dep->trb_dequeue, dep->trb_enqueue, dep->number);
+				dep->trb_dequeue = 0;
+				dep->trb_enqueue = 0;
+			}
+		}
+
+		if (usb_endpoint_xfer_control(desc))
+			goto out;
+
+		/* Initialize the TRB ring */
+		dep->trb_dequeue = 0;
+		dep->trb_enqueue = 0;
+
+		memset(dep->trb_pool, 0,
+		       sizeof(struct dwc3_trb) * dep->trb_num);
+		/* Link TRB. The HWO bit is never reset */
+		trb_st_hw = &dep->trb_pool[0];
+
+		trb_link = &dep->trb_pool[dep->trb_num - 1];
+
+		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;
+	}
+
+#ifndef CONFIG_DWC3_HWSULOG
+	/*
+	 * Issue StartTransfer here with no-op TRB so we can always rely on No
+	 * Response Update Transfer command.
+	 */
+	if ((usb_endpoint_xfer_bulk(desc) && !dep->stream_capable) ||
+			usb_endpoint_xfer_int(desc)) {
+		struct dwc3_gadget_ep_cmd_params params;
+		struct dwc3_trb	*trb;
+		dma_addr_t trb_dma;
+		u32 cmd;
+
+		memset(&params, 0, sizeof(params));
+		trb = &dep->trb_pool[0];
+		trb_dma = dwc3_trb_dma_offset(dep, trb);
+
+		params.param0 = upper_32_bits(trb_dma);
+		params.param1 = lower_32_bits(trb_dma);
+
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+
+		ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+		if (ret < 0) {
+			dev_info(dep->dwc->dev, "ep%d STARTTRANSFER failed: %d\n", dep->number, ret);
+			return ret;
+		}
+	}
+#else
+	/*
+	 * Issue StartTransfer here with no-op TRB so we can always rely on No
+	 * Response Update Transfer command.
+	 */
+	if (sulog_ep_num && (dep->number == (sulog_ep_num * 2 + 1))) {
+		pr_info("skip sulog ep: %d\n", sulog_ep_num);
+	} else if (((usb_endpoint_xfer_bulk(desc) && !dep->stream_capable) ||
+			usb_endpoint_xfer_int(desc))) {
+		struct dwc3_gadget_ep_cmd_params params;
+		struct dwc3_trb *trb;
+		dma_addr_t trb_dma;
+		u32 cmd;
+
+		memset(&params, 0, sizeof(params));
+		trb = &dep->trb_pool[0];
+		trb_dma = dwc3_trb_dma_offset(dep, trb);
+
+		params.param0 = upper_32_bits(trb_dma);
+		params.param1 = lower_32_bits(trb_dma);
+
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+
+		ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+		if (ret < 0) {
+			dev_info(dep->dwc->dev, "ep%d STARTTRANSFER failed: %d\n", dep->number, ret);
+			return ret;
+		}
+	}
+#endif
+out:
+	trace_dwc3_gadget_ep_enable(dep);
+	if (dep->number <= 1)
+		dev_info(dep->dwc->dev, "ep%d enable done\n", dep->number);
+	return 0;
+}
+
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_request		*req;
+
+	dwc3_stop_active_transfer(dep, true, false);
+
+	/* - giveback all requests to gadget driver */
+	while (!list_empty(&dep->started_list)) {
+		req = next_request(&dep->started_list);
+
+		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+	}
+
+	while (!list_empty(&dep->pending_list)) {
+		req = next_request(&dep->pending_list);
+
+		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+	}
+
+	while (!list_empty(&dep->cancelled_list)) {
+		req = next_request(&dep->cancelled_list);
+
+		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+	}
+}
+
+/**
+ * __dwc3_gadget_ep_disable - disables a hw endpoint
+ * @dep: the endpoint to disable
+ *
+ * This function undoes what __dwc3_gadget_ep_enable did and also removes
+ * requests which are currently being processed by 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;
+
+	trace_dwc3_gadget_ep_disable(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);
+
+	/* Clear out the ep descriptors for non-ep0 */
+	if (dep->number > 1) {
+		dep->endpoint.comp_desc = NULL;
+		dep->endpoint.desc = NULL;
+	}
+
+	dwc3_remove_requests(dwc, dep);
+
+	dep->stream_capable = false;
+	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;
+	struct dwc3			*dwc;
+	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);
+	dwc = dep->dwc;
+
+	if (dev_WARN_ONCE(dwc->dev, dep->flags & DWC3_EP_ENABLED,
+					"%s is already enabled\n",
+					dep->name))
+		return 0;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep;
+	struct dwc3			*dwc;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+	dwc = dep->dwc;
+
+	if (dev_WARN_ONCE(dwc->dev, !(dep->flags & DWC3_EP_ENABLED),
+					"%s is already disabled\n",
+					dep->name))
+		return 0;
+
+	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->direction	= dep->direction;
+	req->epnum	= dep->number;
+	req->dep	= dep;
+	req->status	= DWC3_REQUEST_STATUS_UNKNOWN;
+
+	trace_dwc3_alloc_request(req);
+
+	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);
+
+	trace_dwc3_free_request(req);
+	kfree(req);
+}
+
+/**
+ * dwc3_ep_prev_trb - returns the previous TRB in the ring
+ * @dep: The endpoint with the TRB ring
+ * @index: The index of the current TRB in the ring
+ *
+ * Returns the TRB prior to the one pointed to by the index. If the
+ * index is 0, we will wrap backwards, skip the link TRB, and return
+ * the one just before that.
+ */
+static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u16 index)
+{
+	u16 tmp = index;
+
+
+	if (!tmp)
+		tmp = dep->trb_num - 1;
+
+	return &dep->trb_pool[tmp - 1];
+}
+
+static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
+{
+	u16			trbs_left;
+
+	/*
+	 * If the enqueue & dequeue are equal then the TRB ring is either full
+	 * or empty. It's considered full when there are DWC3_TRB_NUM-1 of TRBs
+	 * pending to be processed by the driver.
+	 */
+	if (dep->trb_enqueue == dep->trb_dequeue) {
+		struct dwc3_request *req;
+
+		/*
+		 * If there is any request remained in the started_list with
+		 * active TRBs at this point, then there is no TRB available.
+		 */
+		req = next_request(&dep->started_list);
+		if (req && req->num_trbs)
+			return 0;
+
+		return dep->trb_num - 1;
+	}
+
+	trbs_left = dep->trb_dequeue - dep->trb_enqueue;
+
+	trbs_left &= (dep->trb_num - 1);
+
+
+	if (dep->trb_dequeue < dep->trb_enqueue)
+		trbs_left--;
+
+	return trbs_left;
+}
+
+static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
+		dma_addr_t dma, unsigned length, unsigned chain, unsigned node,
+		unsigned stream_id, unsigned short_not_ok, unsigned no_interrupt)
+{
+	struct dwc3		*dwc = dep->dwc;
+	struct usb_gadget	*gadget = &dwc->gadget;
+	enum usb_device_speed	speed = gadget->speed;
+
+	/* sanity check */
+	if (unlikely(length && ((dma > dwc->phys_mem_end)
+		|| ((dma + length) > dwc->phys_mem_end)))) {
+		pr_emerg("dwc3 dma: 0x%x, len: 0x%x, dwc->phys_mem_end: 0x%lx\n",
+			dma, length, dwc->phys_mem_end);
+		BUG();
+	}
+
+	trb->size = DWC3_TRB_SIZE_LENGTH(length);
+	trb->bpl = lower_32_bits(dma);
+
+#ifndef CONFIG_CPU_ASR1901
+	trb->bph = upper_32_bits(dma);
+#endif
+
+	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;
+
+			/*
+			 * USB Specification 2.0 Section 5.9.2 states that: "If
+			 * there is only a single transaction in the microframe,
+			 * only a DATA0 data packet PID is used.  If there are
+			 * two transactions per microframe, DATA1 is used for
+			 * the first transaction data packet and DATA0 is used
+			 * for the second transaction data packet.  If there are
+			 * three transactions per microframe, DATA2 is used for
+			 * the first transaction data packet, DATA1 is used for
+			 * the second, and DATA0 is used for the third."
+			 *
+			 * IOW, we should satisfy the following cases:
+			 *
+			 * 1) length <= maxpacket
+			 *	- DATA0
+			 *
+			 * 2) maxpacket < length <= (2 * maxpacket)
+			 *	- DATA1, DATA0
+			 *
+			 * 3) (2 * maxpacket) < length <= (3 * maxpacket)
+			 *	- DATA2, DATA1, DATA0
+			 */
+			if (speed == USB_SPEED_HIGH) {
+				struct usb_ep *ep = &dep->endpoint;
+				unsigned int mult = 2;
+				unsigned int maxp = usb_endpoint_maxp(ep->desc);
+
+				if (length <= (2 * maxp))
+					mult--;
+
+				if (length <= maxp)
+					mult--;
+
+				trb->size |= DWC3_TRB_SIZE_PCM1(mult);
+			}
+		} else {
+			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
+		}
+
+		if (!no_interrupt && !chain)
+			trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+		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 :)
+		 */
+		dev_WARN(dwc->dev, "Unknown endpoint type %d\n",
+				usb_endpoint_type(dep->endpoint.desc));
+	}
+
+	/*
+	 * Enable Continue on Short Packet
+	 * when endpoint is not a stream capable
+	 */
+	if (usb_endpoint_dir_out(dep->endpoint.desc)) {
+		if (!dep->stream_capable)
+			trb->ctrl |= DWC3_TRB_CTRL_CSP;
+
+		if (short_not_ok)
+			trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+	}
+
+	if ((!no_interrupt && !chain) ||
+			(dwc3_calc_trbs_left(dep) == 1))
+		trb->ctrl |= DWC3_TRB_CTRL_IOC;
+
+	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(stream_id);
+
+	/*
+	 * As per data book 4.2.3.2TRB Control Bit Rules section
+	 *
+	 * The controller autonomously checks the HWO field of a TRB to determine if the
+	 * entire TRB is valid. Therefore, software must ensure that the rest of the TRB
+	 * is valid before setting the HWO field to '1'. In most systems, this means that
+	 * software must update the fourth DWORD of a TRB last.
+	 *
+	 * However there is a possibility of CPU re-ordering here which can cause
+	 * controller to observe the HWO bit set prematurely.
+	 * Add a write memory barrier to prevent CPU re-ordering.
+	 */
+	wmb();
+	trb->ctrl |= DWC3_TRB_CTRL_HWO;
+
+	dwc3_ep_inc_enq(dep);
+
+	trace_dwc3_prepare_trb(dep, trb);
+}
+
+/**
+ * dwc3_prepare_one_trb - setup one TRB from one request
+ * @dep: endpoint for which this request is prepared
+ * @req: dwc3_request pointer
+ * @trb_length: buffer size of the TRB
+ * @chain: should this TRB be chained to the next?
+ * @node: only for isochronous endpoints. First TRB needs different type.
+ */
+static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+		struct dwc3_request *req, unsigned int trb_length,
+		unsigned chain, unsigned node)
+{
+	struct dwc3_trb		*trb;
+	dma_addr_t		dma;
+	unsigned		stream_id = req->request.stream_id;
+	unsigned		short_not_ok = req->request.short_not_ok;
+	unsigned		no_interrupt = req->request.no_interrupt;
+
+	if (req->request.num_sgs > 0)
+		dma = sg_dma_address(req->start_sg);
+	else
+		dma = req->request.dma;
+
+	trb = &dep->trb_pool[dep->trb_enqueue];
+
+	if (!req->trb) {
+		dwc3_gadget_move_started_request(req);
+		req->trb = trb;
+		req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+	}
+
+	req->num_trbs++;
+
+	__dwc3_prepare_one_trb(dep, trb, dma, trb_length, chain, node,
+			stream_id, short_not_ok, no_interrupt);
+}
+
+static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
+		struct dwc3_request *req)
+{
+	struct scatterlist *sg = req->start_sg;
+	struct scatterlist *s;
+	int		i, used_trbs = 0;
+	unsigned int length = req->request.length;
+	unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
+	unsigned int rem = length % maxp;
+	unsigned int remaining = req->request.num_mapped_sgs
+		- req->num_queued_sgs;
+
+	/*
+	 * If we resume preparing the request, then get the remaining length of
+	 * the request and resume where we left off.
+	 */
+	for_each_sg(req->request.sg, s, req->num_queued_sgs, i)
+		length -= sg_dma_len(s);
+
+	for_each_sg(sg, s, remaining, i) {
+		unsigned int num_trbs_left = dwc3_calc_trbs_left(dep);
+		unsigned int trb_length;
+		unsigned chain = true;
+
+		trb_length = min_t(unsigned int, length, sg_dma_len(s));
+
+		length -= trb_length;
+
+		/*
+		 * IOMMU driver is coalescing the list of sgs which shares a
+		 * page boundary into one and giving it to USB driver. With
+		 * this the number of sgs mapped is not equal to the number of
+		 * sgs passed. So mark the chain bit to false if it isthe last
+		 * mapped sg.
+		 */
+		if ((i == remaining - 1) || !length)
+			chain = false;
+
+		if (!num_trbs_left)
+			break;
+
+		if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
+			struct dwc3	*dwc = dep->dwc;
+			struct dwc3_trb	*trb;
+
+			if (num_trbs_left < 2) {
+				break;
+			}
+
+			req->needs_extra_trb = true;
+
+			/* prepare normal TRB */
+			dwc3_prepare_one_trb(dep, req, trb_length, true, i);
+			used_trbs++;
+
+			/* Now prepare one extra TRB to align transfer size */
+			trb = &dep->trb_pool[dep->trb_enqueue];
+			req->num_trbs++;
+			__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr,
+					maxp - rem, false, 1,
+					req->request.stream_id,
+					req->request.short_not_ok,
+					req->request.no_interrupt);
+			used_trbs++;
+		} else if (req->request.zero && req->request.length &&
+			   !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+			   !rem && !chain) {
+			struct dwc3	*dwc = dep->dwc;
+			struct dwc3_trb	*trb;
+
+			if ((req->direction && (num_trbs_left < 2)) ||
+				((!req->direction) && (num_trbs_left < 3))) {
+				break;
+			}
+
+			req->needs_extra_trb = true;
+
+			/* Prepare normal TRB */
+			dwc3_prepare_one_trb(dep, req, trb_length, true, i);
+			used_trbs++;
+			/* Prepare one extra TRB to handle ZLP */
+			trb = &dep->trb_pool[dep->trb_enqueue];
+			req->num_trbs++;
+			__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
+					       !req->direction, 1,
+					       req->request.stream_id,
+					       req->request.short_not_ok,
+					       req->request.no_interrupt);
+			used_trbs++;
+			/* Prepare one more TRB to handle MPS alignment */
+			if (!req->direction) {
+				trb = &dep->trb_pool[dep->trb_enqueue];
+				req->num_trbs++;
+				__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
+						       false, 1, req->request.stream_id,
+						       req->request.short_not_ok,
+						       req->request.no_interrupt);
+				used_trbs++;
+			}
+		} else {
+			dwc3_prepare_one_trb(dep, req, trb_length, chain, i);
+			used_trbs++;
+		}
+
+		/*
+		 * There can be a situation where all sgs in sglist are not
+		 * queued because of insufficient trb number. To handle this
+		 * case, update start_sg to next sg to be queued, so that
+		 * we have free trbs we can continue queuing from where we
+		 * previously stopped
+		 */
+		if (chain)
+			req->start_sg = sg_next(s);
+
+		req->num_queued_sgs++;
+		req->num_pending_sgs--;
+
+		/*
+		 * The number of pending SG entries may not correspond to the
+		 * number of mapped SG entries. If all the data are queued, then
+		 * don't include unused SG entries.
+		 */
+		if (length == 0) {
+			req->num_pending_sgs = 0;
+			break;
+		}
+
+		if (!dwc3_calc_trbs_left(dep))
+			break;
+	}
+
+	return used_trbs;
+}
+
+static int dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
+		struct dwc3_request *req)
+{
+	unsigned int length = req->request.length;
+	unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
+	unsigned int rem = length % maxp;
+	int used_trbs = 0;
+
+	if ((!length || rem) && usb_endpoint_dir_out(dep->endpoint.desc)) {
+		struct dwc3	*dwc = dep->dwc;
+		struct dwc3_trb	*trb;
+
+		if (dwc3_calc_trbs_left(dep) < 2) {
+			pr_err_ratelimited("ep%d L%d: left trbs: %d\n",
+				dep->number, __LINE__, dwc3_calc_trbs_left(dep));
+			return used_trbs;
+		}
+
+		req->needs_extra_trb = true;
+
+		/* prepare normal TRB */
+		dwc3_prepare_one_trb(dep, req, length, true, 0);
+		used_trbs++;
+
+		/* Now prepare one extra TRB to align transfer size */
+		trb = &dep->trb_pool[dep->trb_enqueue];
+		req->num_trbs++;
+		__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem,
+				false, 1, req->request.stream_id,
+				req->request.short_not_ok,
+				req->request.no_interrupt);
+		used_trbs++;
+	} else if (req->request.zero && req->request.length &&
+		   !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+		   (IS_ALIGNED(req->request.length, maxp))) {
+		struct dwc3	*dwc = dep->dwc;
+		struct dwc3_trb	*trb;
+		unsigned int num_trbs_left = dwc3_calc_trbs_left(dep);
+
+		if ((req->direction && (num_trbs_left < 2)) ||
+			((!req->direction) && (num_trbs_left < 3))) {
+			pr_err_ratelimited("ep%d L%d: left trbs: %d\n",
+				dep->number, __LINE__, dwc3_calc_trbs_left(dep));
+			return used_trbs;
+		}
+
+		req->needs_extra_trb = true;
+
+		/* prepare normal TRB */
+		dwc3_prepare_one_trb(dep, req, length, true, 0);
+		used_trbs++;
+		/* Prepare one extra TRB to handle ZLP */
+		trb = &dep->trb_pool[dep->trb_enqueue];
+		req->num_trbs++;
+		__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
+				!req->direction, 1, req->request.stream_id,
+				req->request.short_not_ok,
+				req->request.no_interrupt);
+		used_trbs++;
+		/* Prepare one more TRB to handle MPS alignment for OUT */
+		if (!req->direction) {
+			trb = &dep->trb_pool[dep->trb_enqueue];
+			req->num_trbs++;
+			__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
+					       false, 1, req->request.stream_id,
+					       req->request.short_not_ok,
+					       req->request.no_interrupt);
+			used_trbs++;
+		}
+	} else {
+		dwc3_prepare_one_trb(dep, req, length, false, 0);
+		used_trbs++;
+	}
+
+	return used_trbs;
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ *
+ * 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)
+{
+	struct dwc3_request	*req, *n;
+	int			ret = 0;
+
+	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+	BUILD_BUG_ON_NOT_POWER_OF_2(ASR1901_DWC3_EP2_TRB_NUM);
+	BUILD_BUG_ON_NOT_POWER_OF_2(ASR1901_DWC3_EP3_TRB_NUM);
+
+	/*
+	 * We can get in a situation where there's a request in the started list
+	 * but there weren't enough TRBs to fully kick it in the first time
+	 * around, so it has been waiting for more TRBs to be freed up.
+	 *
+	 * In that case, we should check if we have a request with pending_sgs
+	 * in the started list and prepare TRBs for that request first,
+	 * otherwise we will prepare TRBs completely out of order and that will
+	 * break things.
+	 */
+	list_for_each_entry(req, &dep->started_list, list) {
+		if (req->num_pending_sgs > 0) {
+			ret = dwc3_prepare_one_trb_sg(dep, req);
+			if ((!ret) || req->num_pending_sgs)
+				return;
+		}
+		if (!dwc3_calc_trbs_left(dep))
+			return;
+	}
+
+	list_for_each_entry_safe(req, n, &dep->pending_list, list) {
+		struct dwc3	*dwc = dep->dwc;
+
+		ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request,
+						    dep->direction);
+		if (ret)
+			return;
+
+		req->sg			= req->request.sg;
+		req->start_sg		= req->sg;
+		req->num_queued_sgs	= 0;
+		req->num_pending_sgs	= req->request.num_mapped_sgs;
+#ifdef CONFIG_ASR_TOE
+		/* to catch toe error for u_ther_toe.c */
+		if (unlikely(dep->number == 3 && req->request.length > 0x10000)) {
+			pr_err("req size error: %d\n", req->request.length);
+			BUG();
+		}
+#endif
+		if (req->num_pending_sgs > 0) {
+			ret = dwc3_prepare_one_trb_sg(dep, req);
+			if (req->num_pending_sgs)
+				return;
+		} else {
+			ret = dwc3_prepare_one_trb_linear(dep, req);
+		}
+
+		if ((!ret) || (!dwc3_calc_trbs_left(dep)))
+			return;
+	}
+}
+
+static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep);
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_request		*req;
+	int				starting;
+	int				ret;
+	u32				cmd;
+
+	if (!dwc3_calc_trbs_left(dep))
+		return 0;
+
+	starting = !(dep->flags & DWC3_EP_TRANSFER_STARTED);
+
+	dwc3_prepare_trbs(dep);
+	req = next_request(&dep->started_list);
+	if (!req) {
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return 0;
+	}
+
+	memset(&params, 0, sizeof(params));
+
+	if (starting) {
+		params.param0 = upper_32_bits(req->trb_dma);
+		params.param1 = lower_32_bits(req->trb_dma);
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+
+		if (dep->stream_capable)
+			cmd |= DWC3_DEPCMD_PARAM(req->request.stream_id);
+
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+			cmd |= DWC3_DEPCMD_PARAM(dep->frame_number);
+	} else {
+		cmd = DWC3_DEPCMD_UPDATETRANSFER |
+			DWC3_DEPCMD_PARAM(dep->resource_index);
+	}
+
+	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+	if (ret < 0) {
+		struct dwc3_request *tmp;
+
+		if (ret == -EAGAIN)
+			return ret;
+
+		dwc3_stop_active_transfer(dep, true, true);
+
+		list_for_each_entry_safe(req, tmp, &dep->started_list, list)
+			dwc3_gadget_move_cancelled_request(req);
+
+		/* If ep isn't started, then there's no end transfer pending */
+		if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
+			dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
+{
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	return DWC3_DSTS_SOFFN(reg);
+}
+
+/**
+ * dwc3_gadget_start_isoc_quirk - workaround invalid frame number
+ * @dep: isoc endpoint
+ *
+ * This function tests for the correct combination of BIT[15:14] from the 16-bit
+ * microframe number reported by the XferNotReady event for the future frame
+ * number to start the isoc transfer.
+ *
+ * In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed
+ * isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the
+ * XferNotReady event are invalid. The driver uses this number to schedule the
+ * isochronous transfer and passes it to the START TRANSFER command. Because
+ * this number is invalid, the command may fail. If BIT[15:14] matches the
+ * internal 16-bit microframe, the START TRANSFER command will pass and the
+ * transfer will start at the scheduled time, if it is off by 1, the command
+ * will still pass, but the transfer will start 2 seconds in the future. For all
+ * other conditions, the START TRANSFER command will fail with bus-expiry.
+ *
+ * In order to workaround this issue, we can test for the correct combination of
+ * BIT[15:14] by sending START TRANSFER commands with different values of
+ * BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart
+ * (or 2 seconds). 4 seconds into the future will result in a bus-expiry status.
+ * As the result, within the 4 possible combinations for BIT[15:14], there will
+ * be 2 successful and 2 failure START COMMAND status. One of the 2 successful
+ * command status will result in a 2-second delay start. The smaller BIT[15:14]
+ * value is the correct combination.
+ *
+ * Since there are only 4 outcomes and the results are ordered, we can simply
+ * test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to
+ * deduce the smaller successful combination.
+ *
+ * Let test0 = test status for combination 'b00 and test1 = test status for 'b01
+ * of BIT[15:14]. The correct combination is as follow:
+ *
+ * if test0 fails and test1 passes, BIT[15:14] is 'b01
+ * if test0 fails and test1 fails, BIT[15:14] is 'b10
+ * if test0 passes and test1 fails, BIT[15:14] is 'b11
+ * if test0 passes and test1 passes, BIT[15:14] is 'b00
+ *
+ * Synopsys STAR 9001202023: Wrong microframe number for isochronous IN
+ * endpoints.
+ */
+static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
+{
+	int cmd_status = 0;
+	bool test0;
+	bool test1;
+
+	while (dep->combo_num < 2) {
+		struct dwc3_gadget_ep_cmd_params params;
+		u32 test_frame_number;
+		u32 cmd;
+
+		/*
+		 * Check if we can start isoc transfer on the next interval or
+		 * 4 uframes in the future with BIT[15:14] as dep->combo_num
+		 */
+		test_frame_number = dep->frame_number & 0x3fff;
+		test_frame_number |= dep->combo_num << 14;
+		test_frame_number += max_t(u32, 4, dep->interval);
+
+		params.param0 = upper_32_bits(dep->dwc->bounce_addr);
+		params.param1 = lower_32_bits(dep->dwc->bounce_addr);
+
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+		cmd |= DWC3_DEPCMD_PARAM(test_frame_number);
+		cmd_status = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+
+		/* Redo if some other failure beside bus-expiry is received */
+		if (cmd_status && cmd_status != -EAGAIN) {
+			dep->start_cmd_status = 0;
+			dep->combo_num = 0;
+			return 0;
+		}
+
+		/* Store the first test status */
+		if (dep->combo_num == 0)
+			dep->start_cmd_status = cmd_status;
+
+		dep->combo_num++;
+
+		/*
+		 * End the transfer if the START_TRANSFER command is successful
+		 * to wait for the next XferNotReady to test the command again
+		 */
+		if (cmd_status == 0) {
+			dwc3_stop_active_transfer(dep, true, true);
+			return 0;
+		}
+	}
+
+	/* test0 and test1 are both completed at this point */
+	test0 = (dep->start_cmd_status == 0);
+	test1 = (cmd_status == 0);
+
+	if (!test0 && test1)
+		dep->combo_num = 1;
+	else if (!test0 && !test1)
+		dep->combo_num = 2;
+	else if (test0 && !test1)
+		dep->combo_num = 3;
+	else if (test0 && test1)
+		dep->combo_num = 0;
+
+	dep->frame_number &= 0x3fff;
+	dep->frame_number |= dep->combo_num << 14;
+	dep->frame_number += max_t(u32, 4, dep->interval);
+
+	/* Reinitialize test variables */
+	dep->start_cmd_status = 0;
+	dep->combo_num = 0;
+
+	return __dwc3_gadget_kick_transfer(dep);
+}
+
+static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
+{
+	struct dwc3 *dwc = dep->dwc;
+	int ret;
+	int i;
+
+	if (list_empty(&dep->pending_list)) {
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return -EAGAIN;
+	}
+
+	if (!dwc->dis_start_transfer_quirk && dwc3_is_usb31(dwc) &&
+	    (dwc->revision <= DWC3_USB31_REVISION_160A ||
+	     (dwc->revision == DWC3_USB31_REVISION_170A &&
+	      dwc->version_type >= DWC31_VERSIONTYPE_EA01 &&
+	      dwc->version_type <= DWC31_VERSIONTYPE_EA06))) {
+
+		if (dwc->gadget.speed <= USB_SPEED_HIGH && dep->direction)
+			return dwc3_gadget_start_isoc_quirk(dep);
+	}
+
+	for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) {
+		dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1);
+
+		ret = __dwc3_gadget_kick_transfer(dep);
+		if (ret != -EAGAIN)
+			break;
+	}
+	if (ret == -EAGAIN)
+		dev_err(dwc->dev, "%s failed: frame: 0x%x\n", __func__, dep->frame_number);
+
+	return ret;
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
+		dev_err_ratelimited(dwc->dev, "%s: can't queue to disabled endpoint\n",
+				dep->name);
+		return -ESHUTDOWN;
+	}
+
+	if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
+				&req->request, req->dep->name))
+		return -EINVAL;
+
+	if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED,
+				"%s: request %pK already in flight\n",
+				dep->name, &req->request))
+		return -EINVAL;
+
+#if 0 /* ASR private */
+	pm_runtime_get(dwc->dev);
+#endif
+
+	if ((!list_empty(&dep->cancelled_list)) && (!(dep->flags & DWC3_EP_STALL_IN_PROGRESS))) {
+		pr_err("!!!ep%d has cancelled reqs\n", dep->number);
+		dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+	}
+
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	dep->num_reqs++;
+
+	trace_dwc3_ep_queue(req);
+
+	list_add_tail(&req->list, &dep->pending_list);
+	req->status = DWC3_REQUEST_STATUS_QUEUED;
+
+	/*
+	 * Start the transfer only after the END_TRANSFER is completed
+	 * and endpoint STALL is cleared.
+	 */
+	if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
+	    (dep->flags & DWC3_EP_WEDGE) ||
+	    (dep->flags & DWC3_EP_STALL)) {
+		dep->flags |= DWC3_EP_DELAY_START;
+		return 0;
+	}
+
+	/*
+	 * NOTICE: Isochronous endpoints should NEVER be prestarted. We must
+	 * wait for a XferNotReady event so we will know what's the current
+	 * (micro-)frame number.
+	 *
+	 * Without this trick, we are very, very likely gonna get Bus Expiry
+	 * errors which will force us issue EndTransfer command.
+	 */
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+		if (!(dep->flags & DWC3_EP_PENDING_REQUEST) &&
+				!(dep->flags & DWC3_EP_TRANSFER_STARTED))
+			return 0;
+
+		if ((dep->flags & DWC3_EP_PENDING_REQUEST)) {
+			if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) {
+				return __dwc3_gadget_start_isoc(dep);
+			}
+		}
+	}
+
+#ifdef CONFIG_CPU_ASR18XX
+	if ((dep->number == 2) && (!usb_endpoint_xfer_isoc(dep->endpoint.desc))) {
+		if ((dep->num_reqs & 0xF) == 1)
+			__dwc3_gadget_kick_transfer(dep);
+		else
+			return 0;
+	} else {
+		__dwc3_gadget_kick_transfer(dep);
+	}
+#else
+	__dwc3_gadget_kick_transfer(dep);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_ASR_TOE
+
+static int __dwc3_gadget_ep_queue_mult(struct dwc3_ep *dep, void *data)
+{
+	int i;
+	struct dwc3		*dwc = dep->dwc;
+	struct uether_rx_aggr *rx_aggr = (struct uether_rx_aggr *)data;
+	struct dwc3_request *req;
+
+	if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected
+		|| (dwc->link_state == DWC3_LINK_STATE_U3)) {
+		dev_err_ratelimited(dwc->dev,
+				"%s: queue fail, pullups_connected: %d, connected: %d, link_st: %d\n",
+				dep->name, dwc->pullups_connected, dwc->connected, dwc->link_state);
+		return -ESHUTDOWN;
+	}
+
+	if (dwc->gadget.state != USB_STATE_CONFIGURED) {
+		dev_err_ratelimited(dwc->dev,
+			"state%d ncfg\n", dwc->gadget.state);
+		return -ESHUTDOWN;
+	}
+
+#if 0 /* ASR private */
+	pm_runtime_get(dwc->dev);
+#endif
+
+	if ((!list_empty(&dep->cancelled_list)) && (!(dep->flags & DWC3_EP_STALL_IN_PROGRESS))) {
+		pr_err("!!!ep%d has cancelled reqs\n", dep->number);
+		dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+	}
+
+	BUG_ON(rx_aggr->nr_rx_req > MAX_RX_REQ_NUMBER);
+
+	for (i = 0; i < rx_aggr->nr_rx_req; i++) {
+		req = to_dwc3_request(rx_aggr->rx_req_array[i]);
+		if (unlikely(WARN(req->dep != dep, "request %pK belongs to '%s'\n",
+						&req->request, req->dep->name)))
+			return -EINVAL;
+
+		if (unlikely(WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED,
+					"%s: request %pK already in flight\n",
+					dep->name, &req->request)))
+			return -EINVAL;
+
+		req->request.actual	= 0;
+		req->request.status	= -EINPROGRESS;
+
+		trace_dwc3_ep_queue(req);
+
+		list_add_tail(&req->list, &dep->pending_list);
+		req->status = DWC3_REQUEST_STATUS_QUEUED;
+	}
+	rx_aggr->nr_rx_req = 0;
+
+	/*
+	 * Start the transfer only after the END_TRANSFER is completed
+	 * and endpoint STALL is cleared.
+	 */
+	if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
+	    (dep->flags & DWC3_EP_WEDGE) ||
+	    (dep->flags & DWC3_EP_STALL)) {
+		pr_info_ratelimited("ep2 queue mult : 0x%x\n", dep->flags);
+		dep->flags |= DWC3_EP_DELAY_START;
+		return 0;
+	}
+
+	/*
+	 * NOTICE: Isochronous endpoints should NEVER be prestarted. We must
+	 * wait for a XferNotReady event so we will know what's the current
+	 * (micro-)frame number.
+	 *
+	 * Without this trick, we are very, very likely gonna get Bus Expiry
+	 * errors which will force us issue EndTransfer command.
+	 */
+	if (unlikely(usb_endpoint_xfer_isoc(dep->endpoint.desc))) {
+		if (!(dep->flags & DWC3_EP_PENDING_REQUEST) &&
+				!(dep->flags & DWC3_EP_TRANSFER_STARTED))
+			return 0;
+
+		if ((dep->flags & DWC3_EP_PENDING_REQUEST)) {
+			if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) {
+				return __dwc3_gadget_start_isoc(dep);
+			}
+		}
+	}
+
+	__dwc3_gadget_kick_transfer(dep);
+
+	return 0;
+}
+#endif
+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);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (unlikely(!dwc->vbus_active || !dwc->softconnect)) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dev_err_ratelimited(dwc->dev, "dwc3 already disconnected\n");
+		return -ESHUTDOWN;
+	}
+
+#ifdef CONFIG_DWC3_HWSULOG
+	if (unlikely(sulog_ep_num && (dep->number == (sulog_ep_num * 2 + 1)))) {
+		dev_err(dwc->dev, "sulog error\n");
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		return -ESHUTDOWN;
+	}
+#endif
+
+	ret = __dwc3_gadget_ep_queue(dep, req);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+#ifdef CONFIG_ASR_TOE
+static int dwc3_gadget_ep_queue_mult(struct usb_ep *ep,
+        gfp_t gfp_flags, void *data)
+{
+        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 (unlikely(!dwc->vbus_active || !dwc->softconnect)) {
+                spin_unlock_irqrestore(&dwc->lock, flags);
+                dev_err_ratelimited(dwc->dev, "usb already disconnected\n");
+                return -ESHUTDOWN;
+        }
+
+        ret = __dwc3_gadget_ep_queue_mult(dep, data);
+        spin_unlock_irqrestore(&dwc->lock, flags);
+
+        return ret;
+}
+#endif
+
+static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+	int i;
+
+	/* If req->trb is not set, then the request has not started */
+	if (!req->trb)
+		return;
+
+	/*
+	 * If request was already started, this means we had to
+	 * stop the transfer. With that we also need to ignore
+	 * all TRBs used by the request, however TRBs can only
+	 * be modified after completion of END_TRANSFER
+	 * command. So what we do here is that we wait for
+	 * END_TRANSFER completion and only after that, we jump
+	 * over TRBs by clearing HWO and incrementing dequeue
+	 * pointer.
+	 */
+	for (i = 0; i < req->num_trbs; i++) {
+		struct dwc3_trb *trb;
+
+		trb = &dep->trb_pool[dep->trb_dequeue];
+		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+		dwc3_ep_inc_deq(dep);
+	}
+
+	req->num_trbs = 0;
+}
+
+static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep)
+{
+	struct dwc3_request		*req;
+	struct dwc3_request		*tmp;
+
+	list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) {
+		dwc3_gadget_ep_skip_trbs(dep, req);
+		dwc3_gadget_giveback(dep, req, -ECONNRESET);
+	}
+}
+
+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;
+
+	trace_dwc3_ep_dequeue(req);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	list_for_each_entry(r, &dep->pending_list, list) {
+		if (r == req)
+			break;
+	}
+
+	if (r != req) {
+		list_for_each_entry(r, &dep->started_list, list) {
+			if (r == req)
+				break;
+		}
+		if (r == req) {
+			/* wait until it is processed */
+			dwc3_stop_active_transfer(dep, true, true);
+
+			if (!r->trb)
+				goto out0;
+
+			dwc3_gadget_move_cancelled_request(req);
+			if (dep->flags & DWC3_EP_TRANSFER_STARTED)
+				goto out0;
+			else
+				goto out1;
+		}
+		dev_err(dwc->dev, "request %pK was not queued to %s\n",
+				request, ep->name);
+		ret = -EINVAL;
+		goto out0;
+	}
+
+out1:
+	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;
+	struct dwc3_request			*req;
+	struct dwc3_request			*tmp;
+	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));
+
+	pr_info("ep%d hlt%d\n", dep->number, value);
+
+	if (value) {
+		struct dwc3_trb *trb;
+
+		unsigned transfer_in_flight;
+		unsigned started;
+
+		if (dep->number > 1)
+			trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
+		else
+			trb = &dwc->ep0_trb[dep->trb_enqueue];
+
+		transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
+		started = !list_empty(&dep->started_list);
+
+		if (!protocol && ((dep->direction && transfer_in_flight) ||
+				(!dep->direction && started))) {
+			return -EAGAIN;
+		}
+
+		ret = dwc3_send_gadget_ep_cmd(dep, 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 {
+		/*
+		 * Don't issue CLEAR_STALL command to control endpoints. The
+		 * controller automatically clears the STALL when it receives
+		 * the SETUP token.
+		 */
+		if (dep->number <= 1) {
+			dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
+			return 0;
+		}
+
+		dep->flags |= DWC3_EP_STALL_IN_PROGRESS;
+
+		dwc3_stop_active_transfer(dep, true, true);
+
+		list_for_each_entry_safe(req, tmp, &dep->started_list, list)
+			dwc3_gadget_move_cancelled_request(req);
+
+		if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {
+			dep->flags |= DWC3_EP_PENDING_CLEAR_STALL;
+			return 0;
+		}
+
+		dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+
+		dep->flags &= ~DWC3_EP_STALL_IN_PROGRESS;
+
+		ret = dwc3_send_clear_stall_ep_cmd(dep);
+		if (ret) {
+			dev_err(dwc->dev, "failed to clear STALL on %s\n",
+					dep->name);
+			return ret;
+		}
+
+		dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
+
+		if ((dep->flags & DWC3_EP_DELAY_START) &&
+		    !usb_endpoint_xfer_isoc(dep->endpoint.desc))
+			__dwc3_gadget_kick_transfer(dep);
+
+		dep->flags &= ~DWC3_EP_DELAY_START;
+	}
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	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);
+	struct dwc3			*dwc = dep->dwc;
+	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,
+#ifdef CONFIG_ASR_TOE
+	.queue_mult 			= dwc3_gadget_ep_queue_mult,
+#endif
+	.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);
+
+	return __dwc3_gadget_get_frame(dwc);
+}
+
+static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
+{
+	int			retries;
+
+	int			ret;
+	u32			reg;
+
+	u8			link_state;
+
+	/*
+	 * 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);
+
+	link_state = DWC3_DSTS_USBLNKST(reg);
+
+	switch (link_state) {
+	case DWC3_LINK_STATE_RESET:
+	case DWC3_LINK_STATE_RX_DET:	/* in HS, means Early Suspend */
+	case DWC3_LINK_STATE_U3:	/* in HS, means SUSPEND */
+	case DWC3_LINK_STATE_U2:	/* in HS, means Sleep (L1) */
+	case DWC3_LINK_STATE_U1:
+	case DWC3_LINK_STATE_RESUME:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	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");
+		return ret;
+	}
+
+	/* 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 */
+	retries = 20000;
+
+	while (retries--) {
+		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_ratelimited(dwc->dev, "1st failed to send remote wakeup, link_st: %d cur link_st: %d\n",
+				link_state, DWC3_DSTS_USBLNKST(reg));
+		/* try again, poll until Link State changes to ON, max delay 1ms */
+		retries = 100;
+		while (retries--) {
+			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_ratelimited(dwc->dev, "2nd failed to send remote wakeup, %d, link_st: %d cur link_st: %d\n",
+				retries, link_state, DWC3_DSTS_USBLNKST(reg));
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	int			ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_wakeup(dwc);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static void dwc3_charger_type_confirm(struct dwc3 *dwc)
+{
+	unsigned long flags;
+	int ret, timeout = 95; /* 950 ms, should get charger type in 1s */
+	unsigned int vbus = 0;
+
+	pr_emerg("%s\n", __func__);
+
+	if (dwc->no_acchg_det) {
+		pr_info("don't detect ac charger type\n");
+		return;
+	}
+
+	while (timeout--) {
+		if (dwc->bus_reset_received || dwc->suspend_received) {
+			pr_err("udc_charger: reset/suspend = %d/%d\n",
+				dwc->bus_reset_received, dwc->suspend_received);
+			return;
+		}
+
+		ret = pxa_usb_extern_call(PXA_USB_DEV_OTG, vbus, get_vbus, &vbus);
+		if (ret) {
+			vbus = usb_phy_get_vbus(dwc->usb2_phy);
+			if (vbus == 0) {
+				pr_err("%s: usb plugout\n", __func__);
+				return;
+			}
+		} else if (vbus == 0) {
+			pr_err("%s: usb plugout\n", __func__);
+			return;
+		}
+		msleep(10);
+	}
+
+	dev_err(dwc->dev, "!!!dsts: 0x%x, gdbgltssm: 0x%x\n",
+			dwc3_readl(dwc->regs, DWC3_DSTS),
+			dwc3_readl(dwc->regs, DWC3_GDBGLTSSM));
+	usb_phy_dump_cfg(dwc->usb2_phy);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	__dwc3_gadget_stop(dwc);
+	dwc3_gadget_run_stop(dwc, 0, false);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	dwc3_controller_reset(dwc);
+	spin_lock_irqsave(&dwc->lock, flags);
+	__dwc3_gadget_start(dwc);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	dwc->charger_type = usb_phy_charger_detect(dwc->usb2_phy);
+	pr_err("%s: suspend usb phy\n", __func__);
+	spin_lock_irqsave(&dwc->lock, flags);
+	usb_phy_set_suspend(dwc->usb2_phy, 1);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	if (work_pending(&dwc->delayed_charger_work.work))
+			cancel_delayed_work(&dwc->delayed_charger_work);
+	schedule_delayed_work(&dwc->delayed_charger_work, 0);
+}
+
+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);
+	g->is_selfpowered = !!is_selfpowered;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 2; epnum < dwc->num_eps; epnum++) {
+		struct dwc3_ep *dep;
+
+		dep = dwc->eps[epnum];
+		if (!dep)
+			continue;
+
+		dwc3_remove_requests(dwc, dep);
+	}
+}
+
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
+{
+	u32			reg;
+	u32			timeout = 500;
+
+	dev_info(dwc->dev, "%s: is_on: %d, suspend: %d active: %d\n",
+			__func__, is_on, suspend, dwc->active);
+	if (is_on && dwc->active)
+		return 0;
+
+	if ((!is_on) && (!dwc->active))
+		return 0;
+
+#if 0 /* ASR private */
+	if (pm_runtime_suspended(dwc->dev))
+		return 0;
+#endif
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (is_on) {
+		dwc->bus_reset_received = 0;
+		dwc->suspend_received = 0;
+		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);
+		reg &= DWC3_DSTS_DEVCTRLHLT;
+	} while (--timeout && !(!is_on ^ !reg));
+
+	if (!timeout) {
+		/* return 0; */
+		dev_warn(dwc->dev, "dctl: 0x%x, dsts: 0x%x, ecount: 0x%x\n",
+			dwc3_readl(dwc->regs, DWC3_DCTL),
+			dwc3_readl(dwc->regs, DWC3_DSTS),
+			dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)));
+		if (!is_on) {
+			reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+			reg &= DWC3_GEVNTCOUNT_MASK;
+			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			reg &= ~DWC3_DCTL_RUN_STOP;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+		}
+	}
+
+	if (!is_on) {
+		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);
+
+		/* Reset device address to zero */
+		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+		reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+		reg &= ~DWC3_DCFG_LPM_CAP;
+		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+		usb_gadget_set_state(&dwc->gadget, USB_STATE_ATTACHED);
+
+		/* report disconnect; the driver is already quiesced */
+		if (dwc->gadget_driver && dwc->gadget_driver->disconnect && dwc->gadget.speed != USB_SPEED_UNKNOWN) {
+			if (irqs_disabled()) {
+				spin_unlock_irq(&dwc->lock);
+				dwc->gadget_driver->disconnect(&dwc->gadget);
+				spin_lock_irq(&dwc->lock);
+			} else {
+				spin_unlock(&dwc->lock);
+				dwc->gadget_driver->disconnect(&dwc->gadget);
+				spin_lock(&dwc->lock);
+			}
+		}
+		dwc->ev_buf->count = 0;
+		dwc->ev_buf->lpos = 0;
+		dwc->ev_buf->flags &= ~DWC3_EVENT_PENDING;
+		dwc->gadget.speed = USB_SPEED_UNKNOWN;
+	}
+	dwc->active = is_on;
+
+	dev_err(dwc->dev, "gadget %s data soft-%s",
+			dwc->gadget_driver
+			? dwc->gadget_driver->function : "no-function",
+			is_on ? "connect" : "disconnect");
+	dev_info(dwc->dev, "%s: dwc3 controller %s\n",
+			__func__, is_on ? "connect" : "disconnect");
+	return 0;
+}
+
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc);
+static void __dwc3_gadget_stop(struct dwc3 *dwc);
+static int __dwc3_gadget_start(struct dwc3 *dwc);
+
+#ifndef CONFIG_USB_DWC3_ASR_OTG
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	int			ret = 0;
+
+	is_on = !!is_on;
+
+	mutex_lock(&usb_con_mutex);
+
+	if (dwc->softconnect == is_on) {
+		dev_info(dwc->dev, "dwc3 already pulled up\n");
+		goto out;
+	}
+
+	dwc->softconnect = (is_on != 0);
+
+	if (dwc->charger_type == DCP_CHARGER) {
+		dev_info(dwc->dev, "dwc3 pullup out on DCP_CHARGER\n");
+		goto out;
+	}
+
+	dev_info(dwc->dev, "%s: softconnect %d, vbus_active %d, pre_chrgr: %d\n",
+			__func__, dwc->softconnect, dwc->vbus_active, dwc->prev_charger_type);
+
+	/*
+	 * Per databook, when we want to stop the gadget, if a control transfer
+	 * is still in process, complete it and get the core into setup phase.
+	 */
+
+	if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) {
+		dev_info(dwc->dev, "waiting dwc->ep0state %d\n", dwc->ep0state);
+		reinit_completion(&dwc->ep0_in_setup);
+
+		ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
+				msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
+		if (ret == 0)
+			dev_warn(dwc->dev, "timed out waiting for SETUP phase: %d\n", dwc->ep0state);
+	}
+
+	/*
+	 * Avoid issuing a runtime resume if the device is already in the
+	 * suspended state during gadget disconnect.  DWC3 gadget was already
+	 * halted/stopped during runtime suspend.
+	 */
+
+#if 0 /* ASR private */
+	if (!is_on) {
+		pm_runtime_barrier(dwc->dev);
+		if (pm_runtime_suspended(dwc->dev))
+			return 0;
+	}
+#endif
+
+	/*
+	 * Check the return value for successful resume, or error.  For a
+	 * successful resume, the DWC3 runtime PM resume routine will handle
+	 * the run stop sequence, so avoid duplicate operations here.
+	 */
+#if 0 /* ASR private */
+	ret = pm_runtime_get_sync(dwc->dev);
+	if (!ret || ret < 0) {
+		pm_runtime_put(dwc->dev);
+		if (ret < 0)
+			pm_runtime_set_suspended(dwc->dev);
+		return ret;
+	}
+#endif
+	/*
+	 * Synchronize and disable any further event handling while controller
+	 * is being enabled/disabled.
+	 */
+	disable_irq(dwc->irq_gadget);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->gadget_driver && (!dwc->softconnect) && dwc->vbus_active) {
+		u32 count;
+
+#ifdef CONFIG_DWC3_HWSULOG
+		hwsulog_on = false;
+#endif
+		dwc->connected = false;
+		/*
+		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+		 * Section 4.1.8 Table 4-7, it states that for a device-initiated
+		 * disconnect, the SW needs to ensure that it sends "a DEPENDXFER
+		 * command for any active transfers" before clearing the RunStop
+		 * bit.
+		 */
+		dwc3_stop_active_transfers(dwc);
+		__dwc3_gadget_stop(dwc);
+		/*
+		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+		 * Section 1.3.4, it mentions that for the DEVCTRLHLT bit, the
+		 * "software needs to acknowledge the events that are generated
+		 * (by writing to GEVNTCOUNTn) while it is waiting for this bit
+		 * to be set to '1'."
+		 */
+		count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		count &= DWC3_GEVNTCOUNT_MASK;
+		if (count > 0) {
+			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+			dwc->ev_buf->lpos = 0; /* (dwc->ev_buf->lpos + count) %
+						dwc->ev_buf->length; */
+			dev_err(dwc->dev, "skip: %d event, dwc->ev_buf->lpos: 0x%x\n",
+				count, dwc->ev_buf->lpos);
+		}
+		ret = dwc3_gadget_run_stop(dwc, 0, false);
+		if (cpu_is_asr1901() || cpu_is_asr1906())
+			spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_controller_reset(dwc);
+		if (cpu_is_asr1901() || cpu_is_asr1906())
+			spin_lock_irqsave(&dwc->lock, flags);
+
+#if 0 //upstream already done by ASR code
+		/*
+		 * In the Synopsys DWC_usb31 1.90a programming guide section
+		 * 4.1.9, it specifies that for a reconnect after a
+		 * device-initiated disconnect requires a core soft reset
+		 * (DCTL.CSftRst) before enabling the run/stop bit.
+		 */
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_core_soft_reset(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+#endif
+		__dwc3_gadget_start(dwc);
+		dwc->ev_buf->count = 0;
+		dwc->ev_buf->flags &= ~DWC3_EVENT_PENDING;
+		dwc->ev_buf->lpos = 0;
+		memset(dwc->ev_buf->buf, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+		memset(dwc->ev_buf->cache, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+	} else if (dwc->gadget_driver && dwc->softconnect && dwc->vbus_active) {
+		if (work_pending(&dwc->usb_restart_work.work))
+			cancel_delayed_work(&dwc->usb_restart_work);
+		ret = dwc3_gadget_run_stop(dwc, 1, false);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		enable_irq(dwc->irq_gadget);
+		dwc3_charger_type_confirm(dwc);
+		goto out;
+	}
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	enable_irq(dwc->irq_gadget);
+
+#if 0 /* ASR private */
+	pm_runtime_put(dwc->dev);
+#endif
+
+out:
+	mutex_unlock(&usb_con_mutex);
+	return ret;
+}
+#else
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	int			ret = 0;
+
+	is_on = !!is_on;
+
+	pr_emerg("dwc3 pullup(%d) otg state: %d - %s\n",
+		is_on, dwc->otg_state, usb_otg_state_string(dwc->otg_state));
+
+	if (dwc->otg_state != OTG_STATE_B_IDLE
+		&& dwc->otg_state != OTG_STATE_B_PERIPHERAL) {
+		dwc->softconnect = (is_on != 0);
+		pr_info("pullup exit for host mode\n");
+		return 0;
+	}
+
+	mutex_lock(&usb_con_mutex);
+
+	if (dwc->softconnect == is_on) {
+		dev_info(dwc->dev, "dwc3 already pulled up\n");
+		goto out;
+	}
+
+	dwc->softconnect = (is_on != 0);
+
+	if (dwc->charger_type == DCP_CHARGER) {
+		dev_info(dwc->dev, "dwc3 pullup out on DCP_CHARGER\n");
+		goto out;
+	}
+
+	dev_info(dwc->dev, "%s: softconnect %d, vbus_active %d, pre_chrgr: %d\n",
+			__func__, dwc->softconnect, dwc->vbus_active, dwc->prev_charger_type);
+
+	/*
+	 * Per databook, when we want to stop the gadget, if a control transfer
+	 * is still in process, complete it and get the core into setup phase.
+	 */
+
+	if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) {
+		dev_info(dwc->dev, "waiting dwc->ep0state %d\n", dwc->ep0state);
+		reinit_completion(&dwc->ep0_in_setup);
+
+		ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
+				msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
+		if (ret == 0)
+			dev_warn(dwc->dev, "timed out waiting for SETUP phase: %d\n", dwc->ep0state);
+	}
+
+	/*
+	 * Avoid issuing a runtime resume if the device is already in the
+	 * suspended state during gadget disconnect.  DWC3 gadget was already
+	 * halted/stopped during runtime suspend.
+	 */
+
+#if 0 /* ASR private */
+	if (!is_on) {
+		pm_runtime_barrier(dwc->dev);
+		if (pm_runtime_suspended(dwc->dev))
+			return 0;
+	}
+#endif
+
+	/*
+	 * Check the return value for successful resume, or error.  For a
+	 * successful resume, the DWC3 runtime PM resume routine will handle
+	 * the run stop sequence, so avoid duplicate operations here.
+	 */
+#if 0 /* ASR private */
+	ret = pm_runtime_get_sync(dwc->dev);
+	if (!ret || ret < 0) {
+		pm_runtime_put(dwc->dev);
+		if (ret < 0)
+			pm_runtime_set_suspended(dwc->dev);
+		return ret;
+	}
+#endif
+	/*
+	 * Synchronize and disable any further event handling while controller
+	 * is being enabled/disabled.
+	 */
+	disable_irq(dwc->irq_gadget);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->gadget_driver && (!dwc->softconnect) && dwc->vbus_active) {
+		u32 count;
+#ifdef CONFIG_DWC3_HWSULOG
+		hwsulog_on = false;
+#endif
+		dwc->connected = false;
+		/*
+		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+		 * Section 4.1.8 Table 4-7, it states that for a device-initiated
+		 * disconnect, the SW needs to ensure that it sends "a DEPENDXFER
+		 * command for any active transfers" before clearing the RunStop
+		 * bit.
+		 */
+		dwc3_stop_active_transfers(dwc);
+		__dwc3_gadget_stop(dwc);
+		/*
+		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+		 * Section 1.3.4, it mentions that for the DEVCTRLHLT bit, the
+		 * "software needs to acknowledge the events that are generated
+		 * (by writing to GEVNTCOUNTn) while it is waiting for this bit
+		 * to be set to '1'."
+		 */
+		count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		count &= DWC3_GEVNTCOUNT_MASK;
+		if (count > 0) {
+			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+			dwc->ev_buf->lpos = 0; /* (dwc->ev_buf->lpos + count) %
+						dwc->ev_buf->length; */
+			dev_err(dwc->dev, "skip: %d event, dwc->ev_buf->lpos: 0x%x\n",
+				count, dwc->ev_buf->lpos);
+		}
+		ret = dwc3_gadget_run_stop(dwc, 0, false);
+		if (cpu_is_asr1901() || cpu_is_asr1906())
+			spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_controller_reset(dwc);
+		if (cpu_is_asr1901() || cpu_is_asr1906())
+			spin_lock_irqsave(&dwc->lock, flags);
+		/* __dwc3_gadget_start(dwc); */
+		dwc->ev_buf->count = 0;
+		dwc->ev_buf->flags &= ~DWC3_EVENT_PENDING;
+		dwc->ev_buf->lpos = 0;
+		memset(dwc->ev_buf->buf, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+		memset(dwc->ev_buf->cache, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+	} else if (dwc->gadget_driver && dwc->softconnect && dwc->vbus_active) {
+		if (work_pending(&dwc->usb_restart_work.work))
+			cancel_delayed_work(&dwc->usb_restart_work);
+
+#if 0 //upstream already done by ASR code
+		/*
+		 * In the Synopsys DWC_usb31 1.90a programming guide section
+		 * 4.1.9, it specifies that for a reconnect after a
+		 * device-initiated disconnect requires a core soft reset
+		 * (DCTL.CSftRst) before enabling the run/stop bit.
+		 */
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_core_soft_reset(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+#endif
+		__dwc3_gadget_start(dwc);
+		ret = dwc3_gadget_run_stop(dwc, 1, false);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		enable_irq(dwc->irq_gadget);
+		dwc3_charger_type_confirm(dwc);
+		goto out;
+	}
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	enable_irq(dwc->irq_gadget);
+
+#if 0 /* ASR private */
+	pm_runtime_put(dwc->dev);
+#endif
+
+out:
+	mutex_unlock(&usb_con_mutex);
+	return ret;
+}
+#endif
+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_CONNECTDONEEN |
+			DWC3_DEVTEN_USBRSTEN |
+			DWC3_DEVTEN_DISCONNEVTEN);
+
+	if (dwc->revision < DWC3_REVISION_250A)
+		reg |= DWC3_DEVTEN_ULSTCNGEN;
+
+	/* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */
+	if (dwc->revision >= DWC3_REVISION_230A)
+		reg |= DWC3_DEVTEN_EOPFEN;
+
+	/* add link event irq for state change handler */
+	reg |= DWC3_DEVTEN_ULSTCNGEN;
+
+	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 irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+
+/**
+ * dwc3_gadget_setup_nump - calculate and initialize NUMP field of %DWC3_DCFG
+ * @dwc: pointer to our context structure
+ *
+ * The following looks like complex but it's actually very simple. In order to
+ * calculate the number of packets we can burst at once on OUT transfers, we're
+ * gonna use RxFIFO size.
+ *
+ * To calculate RxFIFO size we need two numbers:
+ * MDWIDTH = size, in bits, of the internal memory bus
+ * RAM2_DEPTH = depth, in MDWIDTH, of internal RAM2 (where RxFIFO sits)
+ *
+ * Given these two numbers, the formula is simple:
+ *
+ * RxFIFO Size = (RAM2_DEPTH * MDWIDTH / 8) - 24 - 16;
+ *
+ * 24 bytes is for 3x SETUP packets
+ * 16 bytes is a clock domain crossing tolerance
+ *
+ * Given RxFIFO Size, NUMP = RxFIFOSize / 1024;
+ */
+static void dwc3_gadget_setup_nump(struct dwc3 *dwc)
+{
+	u32 ram2_depth;
+	u32 mdwidth;
+	u32 nump;
+	u32 reg;
+
+	ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7);
+	mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0);
+
+	nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024;
+	nump = min_t(u32, nump, 16);
+
+	/* update NumP */
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~DWC3_DCFG_NUMP_MASK;
+	reg |= nump << DWC3_DCFG_NUMP_SHIFT;
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static int __dwc3_gadget_start(struct dwc3 *dwc)
+{
+	struct dwc3_ep		*dep;
+	int			ret = 0;
+	u32			reg;
+
+	/*
+	 * Use IMOD if enabled via dwc->imod_interval. Otherwise, if
+	 * the core supports IMOD, disable it.
+	 */
+	if (dwc->imod_interval) {
+		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
+	} else if (dwc3_has_imod(dwc)) {
+		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
+	}
+
+	/*
+	 * We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP
+	 * field instead of letting dwc3 itself calculate that automatically.
+	 *
+	 * This way, we maximize the chances that we'll be able to get several
+	 * bursts of data without going through any sort of endpoint throttling.
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
+	if (dwc3_is_usb31(dwc))
+		reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL;
+	else
+		reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
+
+	dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
+
+	dwc3_gadget_setup_nump(dwc);
+	dwc3_gadget_set_speed_nolock(&dwc->gadget, dwc->maximum_speed);
+
+	/* Start with SuperSpeed Default */
+	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err0;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err1;
+	}
+
+	if (dwc->ep0state != EP0_SETUP_PHASE)
+		pr_info("dwc->ep0state: %d\n", dwc->ep0state);
+	/* begin to receive SETUP packets */
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc->link_state = DWC3_LINK_STATE_SS_DIS;
+	dwc->delayed_status = false;
+	dwc->three_stage_setup = 0;
+	dwc->setup_packet_pending = 0;
+	dwc->ep0_bounced = 0;
+	dwc3_ep0_out_start(dwc);
+
+	dwc3_gadget_enable_irq(dwc);
+
+	return 0;
+
+err1:
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+	return ret;
+}
+
+#ifndef CONFIG_USB_DWC3_ASR_OTG
+static int dwc3_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	int			ret = 0;
+	int			irq;
+#ifdef CONFIG_CPU_ASR1901
+	struct irq_desc *desc;
+#endif
+
+	irq = dwc->irq_gadget;
+	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+			IRQF_SHARED, "dwc3", dwc->ev_buf);
+	if (ret) {
+		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				irq, ret);
+		goto err0;
+	}
+
+#ifdef CONFIG_CPU_ASR1901
+	desc = irq_to_desc(irq);
+	if (desc && nr_cpu_ids > 1) {
+		dev_err(dwc->dev, "set dwc3 irq thread on cpu-1 by default\n");
+		sched_setaffinity(desc->action->thread->pid, cpumask_of(1));
+	}
+#endif
+
+	if (cpu_is_asr1901() || cpu_is_asr1906())
+		usb_phy_set_suspend(dwc->usb2_phy, 0);
+	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->driver.name);
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	dwc->gadget_driver	= driver;
+
+	if (!(cpu_is_asr1901() || cpu_is_asr1906()))
+		usb_phy_set_suspend(dwc->usb2_phy, 0);
+	__dwc3_gadget_start(dwc);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	if (dwc->qwork)
+		queue_work(dwc->qwork, &dwc->vbus_work);
+
+	return 0;
+
+err1:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	free_irq(irq, dwc);
+
+err0:
+	return ret;
+}
+#else
+static int dwc3_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+	int			ret = 0;
+	int			irq;
+#ifdef CONFIG_CPU_ASR1901
+	struct irq_desc *desc;
+	struct irqaction *action;
+#endif
+
+	irq = dwc->irq_gadget;
+	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+			IRQF_SHARED, "dwc3", dwc->ev_buf);
+	if (ret) {
+		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				irq, ret);
+		goto err0;
+	}
+
+#ifdef CONFIG_CPU_ASR1901
+	desc = irq_to_desc(irq);
+	if (desc && nr_cpu_ids > 1) {
+		for (action = desc->action; action != NULL; action = action->next) {
+			if (action->handler == dwc3_interrupt) {
+				dev_err(dwc->dev, "set dwc3 irq thread on cpu-1 by default\n");
+				sched_setaffinity(action->thread->pid, cpumask_of(1));
+			}
+		}
+	}
+#endif
+
+	if (cpu_is_asr1901() || cpu_is_asr1906())
+		usb_phy_set_suspend(dwc->usb2_phy, 0);
+	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->driver.name);
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	dwc->gadget_driver	= driver;
+/*
+	if (!(cpu_is_asr1901() || cpu_is_asr1906()))
+		usb_phy_set_suspend(dwc->usb2_phy, 0);
+	__dwc3_gadget_start(dwc);
+*/
+	spin_unlock_irqrestore(&dwc->lock, flags); 
+	return 0;
+
+err1:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	free_irq(irq, dwc);
+
+err0:
+	return ret;
+}
+#endif
+
+static void __dwc3_gadget_stop(struct dwc3 *dwc)
+{
+	dwc3_gadget_disable_irq(dwc);
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+	__dwc3_gadget_ep_disable(dwc->eps[1]);
+}
+
+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);
+	dwc->gadget_driver	= NULL;
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	free_irq(dwc->irq_gadget, dwc->ev_buf);
+
+	return 0;
+}
+
+static void dwc3_gadget_config_params(struct usb_gadget *g,
+				      struct usb_dcd_config_params *params)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+
+	params->besl_baseline = USB_DEFAULT_BESL_UNSPECIFIED;
+	params->besl_deep = USB_DEFAULT_BESL_UNSPECIFIED;
+
+	/* Recommended BESL */
+	if (!dwc->dis_enblslpm_quirk) {
+		/*
+		 * If the recommended BESL baseline is 0 or if the BESL deep is
+		 * less than 2, Microsoft's Windows 10 host usb stack will issue
+		 * a usb reset immediately after it receives the extended BOS
+		 * descriptor and the enumeration will fail. To maintain
+		 * compatibility with the Windows' usb stack, let's set the
+		 * recommended BESL baseline to 1 and clamp the BESL deep to be
+		 * within 2 to 15.
+		 */
+		params->besl_baseline = 1;
+		if (dwc->is_utmi_l1_suspend)
+			params->besl_deep =
+				clamp_t(u8, dwc->hird_threshold, 2, 15);
+	}
+
+	/* U1 Device exit Latency */
+	if (dwc->dis_u1_entry_quirk)
+		params->bU1devExitLat = 0;
+	else
+		params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT;
+
+	/* U2 Device exit Latency */
+	if (dwc->dis_u2_entry_quirk)
+		params->bU2DevExitLat = 0;
+	else
+		params->bU2DevExitLat =
+				cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT);
+}
+
+static void dwc3_gadget_set_speed_nolock(struct usb_gadget *g,
+				  enum usb_device_speed speed)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	u32			reg;
+
+	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 &&
+	    !dwc->dis_metastability_quirk) {
+		reg |= DWC3_DCFG_SUPERSPEED;
+	} else {
+		switch (speed) {
+		case USB_SPEED_LOW:
+			reg |= DWC3_DCFG_LOWSPEED;
+			break;
+		case USB_SPEED_FULL:
+			reg |= DWC3_DCFG_FULLSPEED;
+			break;
+		case USB_SPEED_HIGH:
+			reg |= DWC3_DCFG_HIGHSPEED;
+			break;
+		case USB_SPEED_SUPER:
+			reg |= DWC3_DCFG_SUPERSPEED;
+			break;
+		case USB_SPEED_SUPER_PLUS:
+			if (dwc3_is_usb31(dwc))
+				reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+			else
+				reg |= DWC3_DCFG_SUPERSPEED;
+			break;
+		default:
+			dev_err(dwc->dev, "invalid speed (%d)\n", speed);
+
+			if (dwc->revision & DWC3_REVISION_IS_DWC31)
+				reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+			else
+				reg |= DWC3_DCFG_SUPERSPEED;
+		}
+	}
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void dwc3_gadget_set_speed(struct usb_gadget *g,
+				  enum usb_device_speed speed)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_gadget_set_speed_nolock(g, speed);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+}
+
+static int asr_usb_vbus_session(struct usb_gadget *gadget, int is_active);
+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,
+	.udc_set_speed		= dwc3_gadget_set_speed,
+	.get_config_params	= dwc3_gadget_config_params,
+	.vbus_session	= asr_usb_vbus_session,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep)
+{
+	struct dwc3 *dwc = dep->dwc;
+
+	usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
+	dep->endpoint.maxburst = 1;
+	dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+	if (!dep->direction)
+		dwc->gadget.ep0 = &dep->endpoint;
+
+	dep->endpoint.caps.type_control = true;
+
+	return 0;
+}
+
+static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep)
+{
+	struct dwc3 *dwc = dep->dwc;
+	int mdwidth;
+	int size;
+
+	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+	/* MDWIDTH is represented in bits, we need it in bytes */
+	mdwidth /= 8;
+
+	size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1));
+	if (dwc3_is_usb31(dwc))
+		size = DWC31_GTXFIFOSIZ_TXFDEF(size);
+	else
+		size = DWC3_GTXFIFOSIZ_TXFDEF(size);
+
+	/* FIFO Depth is in MDWDITH bytes. Multiply */
+	size *= mdwidth;
+
+	/*
+	 * To meet performance requirement, a minimum TxFIFO size of 3x
+	 * MaxPacketSize is recommended for endpoints that support burst and a
+	 * minimum TxFIFO size of 2x MaxPacketSize for endpoints that don't
+	 * support burst. Use those numbers and we can calculate the max packet
+	 * limit as below.
+	 */
+	if (dwc->maximum_speed >= USB_SPEED_SUPER)
+		size /= 3;
+	else
+		size /= 2;
+
+	usb_ep_set_maxpacket_limit(&dep->endpoint, size);
+
+	dep->endpoint.max_streams = 15;
+	dep->endpoint.ops = &dwc3_gadget_ep_ops;
+	list_add_tail(&dep->endpoint.ep_list,
+			&dwc->gadget.ep_list);
+	dep->endpoint.caps.type_iso = true;
+	dep->endpoint.caps.type_bulk = true;
+	dep->endpoint.caps.type_int = true;
+
+	return dwc3_alloc_trb_pool(dep);
+}
+
+static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep)
+{
+	struct dwc3 *dwc = dep->dwc;
+	int mdwidth;
+	int size;
+
+	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+
+	/* MDWIDTH is represented in bits, convert to bytes */
+	mdwidth /= 8;
+
+	/* All OUT endpoints share a single RxFIFO space */
+	size = dwc3_readl(dwc->regs, DWC3_GRXFIFOSIZ(0));
+	if (dwc3_is_usb31(dwc))
+		size = DWC31_GRXFIFOSIZ_RXFDEP(size);
+	else
+		size = DWC3_GRXFIFOSIZ_RXFDEP(size);
+
+	/* FIFO depth is in MDWDITH bytes */
+	size *= mdwidth;
+
+	/*
+	 * To meet performance requirement, a minimum recommended RxFIFO size
+	 * is defined as follow:
+	 * RxFIFO size >= (3 x MaxPacketSize) +
+	 * (3 x 8 bytes setup packets size) + (16 bytes clock crossing margin)
+	 *
+	 * Then calculate the max packet limit as below.
+	 */
+	size -= (3 * 8) + 16;
+	if (size < 0)
+		size = 0;
+	else
+		size /= 3;
+
+	usb_ep_set_maxpacket_limit(&dep->endpoint, size);
+	dep->endpoint.max_streams = 15;
+	dep->endpoint.ops = &dwc3_gadget_ep_ops;
+	list_add_tail(&dep->endpoint.ep_list,
+			&dwc->gadget.ep_list);
+	dep->endpoint.caps.type_iso = true;
+	dep->endpoint.caps.type_bulk = true;
+	dep->endpoint.caps.type_int = true;
+
+	return dwc3_alloc_trb_pool(dep);
+}
+
+static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
+{
+	struct dwc3_ep			*dep;
+	bool				direction = epnum & 1;
+	int				ret;
+	u8				num = epnum >> 1;
+
+	dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+	if (!dep)
+		return -ENOMEM;
+
+	dep->dwc = dwc;
+	dep->number = epnum;
+	dep->direction = direction;
+	dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
+	dwc->eps[epnum] = dep;
+	dep->combo_num = 0;
+	dep->start_cmd_status = 0;
+
+	snprintf(dep->name, sizeof(dep->name), "ep%u%s", num,
+			direction ? "in" : "out");
+
+	dep->endpoint.name = dep->name;
+
+	if (!(dep->number > 1)) {
+		dep->endpoint.desc = &dwc3_gadget_ep0_desc;
+		dep->endpoint.comp_desc = NULL;
+	}
+
+	if (num == 0)
+		ret = dwc3_gadget_init_control_endpoint(dep);
+	else if (direction)
+		ret = dwc3_gadget_init_in_endpoint(dep);
+	else
+		ret = dwc3_gadget_init_out_endpoint(dep);
+
+	if (ret)
+		return ret;
+
+	dep->endpoint.caps.dir_in = direction;
+	dep->endpoint.caps.dir_out = !direction;
+
+	INIT_LIST_HEAD(&dep->pending_list);
+	INIT_LIST_HEAD(&dep->started_list);
+	INIT_LIST_HEAD(&dep->cancelled_list);
+
+	if (dep->number < 16)
+		dwc3_debugfs_create_endpoint_dir(dep);
+
+	return 0;
+}
+
+static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
+{
+	u8				epnum;
+
+	INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+	for (epnum = 0; epnum < total; epnum++) {
+		int			ret;
+
+		ret = dwc3_gadget_init_endpoint(dwc, epnum);
+		if (ret)
+			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);
+		}
+
+		debugfs_remove_recursive(debugfs_lookup(dep->name, dwc->root));
+		kfree(dep);
+	}
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep,
+		struct dwc3_request *req, struct dwc3_trb *trb,
+		const struct dwc3_event_depevt *event, int status, int chain)
+{
+	unsigned int		count;
+
+	dwc3_ep_inc_deq(dep);
+
+	trace_dwc3_complete_trb(dep, trb);
+	req->num_trbs--;
+
+	/*
+	 * If we're in the middle of series of chained TRBs and we
+	 * receive a short transfer along the way, DWC3 will skip
+	 * through all TRBs including the last TRB in the chain (the
+	 * where CHN bit is zero. DWC3 will also avoid clearing HWO
+	 * bit and SW has to do it manually.
+	 *
+	 * We're going to do that here to avoid problems of HW trying
+	 * to use bogus TRBs for transfers.
+	 */
+	if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
+		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+
+	/*
+	 * For isochronous transfers, the first TRB in a service interval must
+	 * have the Isoc-First type. Track and report its interval frame number.
+	 */
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+	    (trb->ctrl & DWC3_TRBCTL_ISOCHRONOUS_FIRST)) {
+		unsigned int frame_number;
+
+		frame_number = DWC3_TRB_CTRL_GET_SID_SOFN(trb->ctrl);
+		frame_number &= ~(dep->interval - 1);
+		req->request.frame_number = frame_number;
+	}
+
+	/*
+	 * If we're dealing with unaligned size OUT transfer, we will be left
+	 * with one TRB pending in the ring. We need to manually clear HWO bit
+	 * from that TRB.
+	 */
+
+	if (req->needs_extra_trb && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) {
+		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+		return 1;
+	}
+
+	count = trb->size & DWC3_TRB_SIZE_MASK;
+	req->remaining += count;
+
+	if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
+		return 1;
+
+	if (event->status & DEPEVT_STATUS_SHORT && !chain)
+		return 1;
+
+	if ((trb->ctrl & DWC3_TRB_CTRL_ISP_IMI) &&
+	    DWC3_TRB_SIZE_TRBSTS(trb->size) == DWC3_TRBSTS_MISSED_ISOC)
+		return 1;
+
+	if ((trb->ctrl & DWC3_TRB_CTRL_IOC) ||
+	    (trb->ctrl & DWC3_TRB_CTRL_LST))
+		return 1;
+
+	return 0;
+}
+
+static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep,
+		struct dwc3_request *req, const struct dwc3_event_depevt *event,
+		int status)
+{
+	struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue];
+	struct scatterlist *sg = req->sg;
+	struct scatterlist *s;
+	unsigned int num_queued = req->num_queued_sgs;
+	unsigned int i;
+	int ret = 0;
+
+	for_each_sg(sg, s, num_queued, i) {
+		trb = &dep->trb_pool[dep->trb_dequeue];
+
+		req->sg = sg_next(s);
+		req->num_queued_sgs--;
+
+		ret = dwc3_gadget_ep_reclaim_completed_trb(dep, req,
+				trb, event, status, true);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep,
+		struct dwc3_request *req, const struct dwc3_event_depevt *event,
+		int status)
+{
+	struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue];
+
+	return dwc3_gadget_ep_reclaim_completed_trb(dep, req, trb,
+			event, status, false);
+}
+
+static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req)
+{
+	return req->num_pending_sgs == 0 && req->num_queued_sgs == 0;
+}
+
+static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event,
+		struct dwc3_request *req, int status)
+{
+	int request_status;
+	int ret;
+
+	if (req->request.num_mapped_sgs)
+		ret = dwc3_gadget_ep_reclaim_trb_sg(dep, req, event,
+				status);
+	else
+		ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
+				status);
+
+	req->request.actual = req->request.length - req->remaining;
+
+	if (!dwc3_gadget_ep_request_completed(req))
+		goto out;
+
+	if (req->needs_extra_trb) {
+		unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
+
+		ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
+				status);
+
+		/* Reclaim MPS padding TRB for ZLP */
+		if (!req->direction && req->request.zero && req->request.length &&
+		    !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+		    (IS_ALIGNED(req->request.length, maxp)))
+			ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status);
+
+		req->needs_extra_trb = false;
+	}
+
+	/*
+	 * The event status only reflects the status of the TRB with IOC set.
+	 * For the requests that don't set interrupt on completion, the driver
+	 * needs to check and return the status of the completed TRBs associated
+	 * with the request. Use the status of the last TRB of the request.
+	 */
+	if (req->request.no_interrupt) {
+		struct dwc3_trb *trb;
+
+		trb = dwc3_ep_prev_trb(dep, dep->trb_dequeue);
+		switch (DWC3_TRB_SIZE_TRBSTS(trb->size)) {
+		case DWC3_TRBSTS_MISSED_ISOC:
+			/* Isoc endpoint only */
+			request_status = -EXDEV;
+			break;
+		case DWC3_TRB_STS_XFER_IN_PROG:
+			/* Applicable when End Transfer with ForceRM=0 */
+		case DWC3_TRBSTS_SETUP_PENDING:
+			/* Control endpoint only */
+		case DWC3_TRBSTS_OK:
+		default:
+			request_status = 0;
+			break;
+		}
+	} else {
+		request_status = status;
+	}
+
+	dwc3_gadget_giveback(dep, req, request_status);
+
+out:
+	return ret;
+}
+
+static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event, int status)
+{
+	struct dwc3_request	*req;
+	struct dwc3_request	*tmp;
+
+	list_for_each_entry_safe(req, tmp, &dep->started_list, list) {
+		int ret;
+
+		ret = dwc3_gadget_ep_cleanup_completed_request(dep, event,
+				req, status);
+		if (ret)
+			break;
+	}
+}
+
+static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep)
+{
+	struct dwc3_request	*req;
+
+#ifdef CONFIG_CPU_ASR18XX
+	if (dep->number == 2)
+		return false;
+
+	if ((dep->number == 3) && (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) && (dwc3_calc_trbs_left(dep) < 16))
+		return false;
+#endif
+
+	if (!list_empty(&dep->pending_list))
+		return true;
+
+	/*
+	 * We only need to check the first entry of the started list. We can
+	 * assume the completed requests are removed from the started list.
+	 */
+	req = next_request(&dep->started_list);
+	if (!req)
+		return false;
+
+	return !dwc3_gadget_ep_request_completed(req);
+}
+
+static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	dep->frame_number = event->parameters;
+}
+
+static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3		*dwc = dep->dwc;
+	unsigned		status = 0;
+	bool			stop = false;
+
+	dwc3_gadget_endpoint_frame_from_event(dep, event);
+
+	if (event->status & DEPEVT_STATUS_BUSERR)
+		status = -ECONNRESET;
+
+	if (event->status & DEPEVT_STATUS_MISSED_ISOC) {
+		status = -EXDEV;
+
+		if (list_empty(&dep->started_list))
+			stop = true;
+	}
+
+	dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
+
+	if (stop)
+		dwc3_stop_active_transfer(dep, true, true);
+	else if (dwc3_gadget_ep_should_continue(dep))
+		__dwc3_gadget_kick_transfer(dep);
+
+	/*
+	 * 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->started_list))
+				return;
+		}
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg |= dwc->u1u2;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+		dwc->u1u2 = 0;
+	}
+}
+
+static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	dwc3_gadget_endpoint_frame_from_event(dep, event);
+	(void) __dwc3_gadget_start_isoc(dep);
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	u8			epnum = event->endpoint_number;
+	u8			cmd;
+
+#ifdef CONFIG_DWC3_HWSULOG
+	if (unlikely(sulog_ep_num && (epnum == (sulog_ep_num * 2 + 1))))
+		BUG();
+#endif
+
+	dep = dwc->eps[epnum];
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
+			return;
+
+		/* Handle only EPCMDCMPLT when EP disabled */
+		if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
+			return;
+	}
+
+	if (epnum == 0 || epnum == 1) {
+		dwc3_ep0_interrupt(dwc, event);
+		return;
+	}
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		dwc3_gadget_endpoint_transfer_in_progress(dep, event);
+		break;
+	case DWC3_DEPEVT_XFERNOTREADY:
+		dwc3_gadget_endpoint_transfer_not_ready(dep, event);
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		cmd = DEPEVT_PARAMETER_CMD(event->parameters);
+
+		if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
+			dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
+			dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+			pr_info("ep%d 0x%x ENDCMD\n", dep->number, dep->flags);
+
+			dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+
+			dep->flags &= ~DWC3_EP_STALL_IN_PROGRESS;
+
+			if (dep->flags & DWC3_EP_PENDING_CLEAR_STALL) {
+				struct dwc3 *dwc = dep->dwc;
+
+				dep->flags &= ~DWC3_EP_PENDING_CLEAR_STALL;
+				if (dwc3_send_clear_stall_ep_cmd(dep)) {
+					struct usb_ep *ep0 = &dwc->eps[0]->endpoint;
+
+					dev_err(dwc->dev, "failed to clear STALL on %s\n",
+						dep->name);
+					if (dwc->delayed_status)
+						__dwc3_gadget_ep0_set_halt(ep0, 1);
+					return;
+				}
+
+				dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
+				if (dwc->delayed_status)
+					dwc3_ep0_send_delayed_status(dwc);
+			}
+
+			if ((dep->flags & DWC3_EP_DELAY_START) &&
+			    !usb_endpoint_xfer_isoc(dep->endpoint.desc))
+				__dwc3_gadget_kick_transfer(dep);
+
+			dep->flags &= ~DWC3_EP_DELAY_START;
+		}
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
+	case DWC3_DEPEVT_XFERCOMPLETE:
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		break;
+	}
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+	if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+		if (irqs_disabled()) {
+			spin_unlock_irq(&dwc->lock);
+			dwc->gadget_driver->disconnect(&dwc->gadget);
+			spin_lock_irq(&dwc->lock);
+		} else {
+			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);
+	}
+	if (dwc->link_state != 0 && dwc->link_state != 1)
+		dev_err(dwc->dev, "%s: st: %d, link_st: %d 0x%x\n",
+		__func__, dwc->gadget.state, dwc->link_state,
+		dwc3_readl(dwc->regs, DWC3_DSTS));
+
+	if (dwc->allow_suspend && dwc->gadget.state >= USB_STATE_CONFIGURED
+		&& dwc->link_state == DWC3_LINK_STATE_U3)
+		dwc3_release_wakeup_event_timeout(DWC3_WAKEUP_TIMEOUT_SEC);
+}
+
+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);
+		spin_lock(&dwc->lock);
+	}
+	dev_err(dwc->dev, "%s: st: %d, link_st: %d 0x%x\n",
+		__func__, dwc->gadget.state, dwc->link_state,
+		dwc3_readl(dwc->regs, DWC3_DSTS));
+
+	if (dwc->allow_suspend)
+		dwc3_acquire_wakeup_event();
+}
+
+#if 0 /* ASR private */
+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);
+	}
+}
+#endif
+
+static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
+	bool interrupt)
+{
+	struct dwc3 *dwc = dep->dwc;
+	struct dwc3_gadget_ep_cmd_params params;
+	u32 cmd;
+	int ret;
+
+	if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) ||
+	    (dep->flags & DWC3_EP_END_TRANSFER_PENDING))
+		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 arbitrary 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
+	 *
+	 * As of IP version 3.10a of the DWC_usb3 IP, the controller
+	 * supports a mode to work around the above limitation. The
+	 * software can poll the CMDACT bit in the DEPCMD register
+	 * after issuing a EndTransfer command. This mode is enabled
+	 * by writing GUCTL2[14]. This polling is already done in the
+	 * dwc3_send_gadget_ep_cmd() function so if the mode is
+	 * enabled, the EndTransfer command will have completed upon
+	 * returning from this function and we don't need to delay for
+	 * 100us.
+	 *
+	 * This mode is NOT available on the DWC_usb31 IP.
+	 */
+
+	cmd = DWC3_DEPCMD_ENDTRANSFER;
+	cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
+	cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0;
+	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
+	memset(&params, 0, sizeof(params));
+	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+	WARN_ON_ONCE(ret);
+	if (ret) {
+		dev_err(dwc->dev, "cmd: 0x%x failed->%d, 0x%x 0x%x 0x%x\n",
+		cmd, ret, dwc3_readl(dwc->regs, DWC3_DCFG),
+		dwc3_readl(dwc->regs, DWC3_DCTL),
+		dwc3_readl(dwc->regs, DWC3_DSTS));
+	}
+	dep->resource_index = 0;
+
+	if (!interrupt)
+		dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+	else
+		dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
+
+	if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
+		udelay(100);
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+		int ret;
+
+		dep = dwc->eps[epnum];
+		if (!dep)
+			continue;
+
+		if (!(dep->flags & DWC3_EP_STALL))
+			continue;
+
+		dep->flags &= ~DWC3_EP_STALL;
+
+		ret = dwc3_send_clear_stall_ep_cmd(dep);
+		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->gadget.speed = USB_SPEED_UNKNOWN;
+	dwc->setup_packet_pending = false;
+	usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
+
+	dwc->connected = false;
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+	u32			reg;
+	u32			vbus = 0;
+	int			ret;
+
+	ret = pxa_usb_extern_call(PXA_USB_DEV_OTG, vbus, get_vbus, &vbus);
+	if (ret) {
+		vbus = usb_phy_get_vbus(dwc->usb2_phy);
+	}
+
+	/*
+	 * Ideally, dwc3_reset_gadget() would trigger the function
+	 * drivers to stop any active transfers through ep disable.
+	 * However, for functions which defer ep disable, such as mass
+	 * storage, we will need to rely on the call to stop active
+	 * transfers here, and avoid allowing of request queuing.
+	 */
+	dwc->connected = false;
+
+	/*
+	 * 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 SETUP_PENDING
+	 * status for EP0 TRBs 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);
+	}
+
+#if 0 /* ASR private */
+	dwc3_reset_gadget(dwc);
+#endif
+	/*
+	 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+	 * Section 4.1.2 Table 4-2, it states that during a USB reset, the SW
+	 * needs to ensure that it sends "a DEPENDXFER command for any active
+	 * transfers."
+	 */
+	dwc3_stop_active_transfers(dwc);
+	dwc->connected = true;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	dwc->test_mode = false;
+	dwc3_clear_stall_all_ep(dwc);
+
+	/* Reset device address to zero */
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	if ((dwc->gadget.state >= USB_STATE_CONFIGURED) && vbus) {
+		dwc->usb_do_restart = 1;
+	} else {
+		printk("st:%d, vbus:%d\n", dwc->gadget.state, vbus);
+	}
+
+	usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
+
+	/* ASR private */
+	/* report disconnect; the driver is already quiesced */
+	if (dwc->gadget_driver && dwc->gadget_driver->disconnect && dwc->gadget.speed != USB_SPEED_UNKNOWN) {
+		if (irqs_disabled()) {
+			spin_unlock_irq(&dwc->lock);
+			dwc->gadget_driver->disconnect(&dwc->gadget);
+			spin_lock_irq(&dwc->lock);
+		} else {
+			spin_unlock(&dwc->lock);
+			dwc->gadget_driver->disconnect(&dwc->gadget);
+			spin_lock(&dwc->lock);
+		}
+	}
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	usb_os_detect_reset_state();
+#endif
+	dwc->bus_reset_received = true;
+	dev_err(dwc->dev, "reset irq\n");
+}
+
+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;
+
+	/*
+	 * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+	 * each time on Connect Done.
+	 *
+	 * Currently we always use the reset value. If any platform
+	 * wants to set this to a different value, we need to add a
+	 * setting and update GCTL.RAMCLKSEL here.
+	 */
+
+	switch (speed) {
+	case DWC3_DSTS_SUPERSPEED_PLUS:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+		dwc->gadget.ep0->maxpacket = 512;
+		dwc->gadget.speed = USB_SPEED_SUPER_PLUS;
+		if (dwc->allow_suspend) {
+			reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+			reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+			dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+		}
+		break;
+	case DWC3_DSTS_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;
+		if (dwc->allow_suspend) {
+			reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+			reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+			dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+		}
+		break;
+	case DWC3_DSTS_HIGHSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case DWC3_DSTS_FULLSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_FULL;
+		break;
+	case DWC3_DSTS_LOWSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+		dwc->gadget.ep0->maxpacket = 8;
+		dwc->gadget.speed = USB_SPEED_LOW;
+		break;
+	}
+
+	dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket;
+
+	/* Enable USB2 LPM Capability */
+
+	if ((dwc->revision > DWC3_REVISION_194A) &&
+	    (speed != DWC3_DSTS_SUPERSPEED) &&
+	    (speed != DWC3_DSTS_SUPERSPEED_PLUS)) {
+		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 |
+					    (dwc->is_utmi_l1_suspend << 4));
+
+		/*
+		 * 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.
+		 */
+		WARN_ONCE(dwc->revision < DWC3_REVISION_240A
+				&& dwc->has_lpm_erratum,
+				"LPM Erratum not available on dwc3 revisions < 2.40a\n");
+
+		if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
+			reg |= DWC3_DCTL_NYET_THRES(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_DEPCFG_ACTION_MODIFY);
+	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_DEPCFG_ACTION_MODIFY);
+	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.
+	 */
+
+	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
+		spin_unlock(&dwc->lock);
+		dwc->gadget_driver->resume(&dwc->gadget);
+		spin_lock(&dwc->lock);
+	}
+	dev_err(dwc->dev, "%s: st: %d, link_st: %d 0x%x\n",
+		__func__, dwc->gadget.state, dwc->link_state,
+		dwc3_readl(dwc->regs, DWC3_DSTS));
+
+	if (dwc->allow_suspend)
+		dwc3_acquire_wakeup_event();
+}
+
+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)) {
+			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;
+	/* in HS means early suspend */
+	case DWC3_LINK_STATE_RX_DET:
+		if ((evtinfo & (0x1 << 4)) == 0)
+			dwc->suspend_received = true;
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	dwc->link_state = next;
+
+	if (dwc->allow_suspend && dwc->link_state != DWC3_LINK_STATE_U3)
+		dwc3_acquire_wakeup_event();
+}
+
+static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
+					  unsigned int evtinfo)
+{
+	enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
+
+	if (dwc->link_state != next && next == DWC3_LINK_STATE_U3)
+		dwc3_suspend_gadget(dwc);
+
+	dev_err(dwc->dev, "%s: st: %d, link_st: %d 0x%x\n",
+		__func__, dwc->gadget.state, dwc->link_state,
+		dwc3_readl(dwc->regs, DWC3_DSTS));
+	dwc->link_state = next;
+	if (dwc->allow_suspend && dwc->gadget.state >= USB_STATE_CONFIGURED
+		&& dwc->link_state == DWC3_LINK_STATE_U3)
+		dwc3_release_wakeup_event_timeout(DWC3_WAKEUP_TIMEOUT_SEC);
+}
+
+static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
+		unsigned int evtinfo)
+{
+	unsigned int is_ss = evtinfo & BIT(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);
+		if (dwc->gadget.state >= USB_STATE_CONFIGURED)
+			asr_udc_notify_resume_event(dwc, 0);
+		break;
+	case DWC3_DEVICE_EVENT_HIBER_REQ:
+		if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
+					"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:
+		dwc->suspend_received = true;
+		/* It changed to be suspend event for version 2.30a and above */
+		if (dwc->revision >= DWC3_REVISION_230A) {
+			/*
+			 * Ignore suspend event until the gadget enters into
+			 * USB_STATE_CONFIGURED state.
+			 */
+			if (dwc->gadget.state >= USB_STATE_CONFIGURED)
+				dwc3_gadget_suspend_interrupt(dwc,
+						event->event_info);
+		}
+		break;
+	case DWC3_DEVICE_EVENT_SOF:
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		break;
+	default:
+		dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+	}
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+		const union dwc3_event *event)
+{
+	trace_dwc3_event(event->raw, dwc);
+
+	if (!event->type.is_devspec) {
+		dwc3_endpoint_interrupt(dwc, &event->depevt);
+	} else if (event->type.type == DWC3_EVENT_TYPE_DEV) {
+#ifdef CONFIG_CPU_ASR1901
+		if (0x110301 != event->raw && 0x120301 != event->raw) {
+			if (0x100301 == event->raw) {
+				dev_err_ratelimited(dwc->dev, "dev event: 0x%x ep0state: %d\n", event->raw, dwc->ep0state);
+				usb_phy_dump_cfg(dwc->usb2_phy);
+			} else {
+				dev_err(dwc->dev, "dev event: 0x%x\n", event->raw);
+			}
+		}
+#else
+		if (0x100301 != event->raw && 0x110301 != event->raw
+			&& 0x120301 != event->raw) {
+			dev_err(dwc->dev, "dev event: 0x%x\n", event->raw);
+		}
+#endif
+		dwc3_gadget_interrupt(dwc, &event->devt);
+	} else {
+		dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+	}
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
+{
+	struct dwc3 *dwc = evt->dwc;
+	irqreturn_t ret = IRQ_NONE;
+	int left;
+	u32 reg;
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	u32 count;
+#endif
+
+	left = evt->count;
+
+	if (!(evt->flags & DWC3_EVENT_PENDING))
+		return IRQ_NONE;
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	if (unlikely(!dwc->active)) {
+		reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		reg &= DWC3_GEVNTCOUNT_MASK;
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
+		/* Unmask interrupt */
+		reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
+		reg &= ~DWC3_GEVNTSIZ_INTMASK;
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
+		evt->lpos = 0;
+		evt->count = 0;
+		evt->flags &= ~DWC3_EVENT_PENDING;
+		return IRQ_HANDLED;
+	}
+#endif
+
+	while (left > 0 && dwc->active) {
+		union dwc3_event event;
+
+		event.raw = *(u32 *) (evt->cache + 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) % evt->length;
+		left -= 4;
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+		if (unlikely(os_detect_is_done())) {
+			dev_info(dwc->dev, "%s: break on os detect done\n", __func__);
+			left = 0;
+			break;
+		}
+#endif
+	}
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	if (unlikely(os_detect_is_done())) {
+		dev_info(dwc->dev, "%s: handle os detect done\n", __func__);
+		count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		count &= DWC3_GEVNTCOUNT_MASK;
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+		dwc3_gadget_run_stop(dwc, 0, false);
+		/* Unmask interrupt */
+		reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
+		reg &= ~DWC3_GEVNTSIZ_INTMASK;
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
+		evt->count = 0;
+		evt->flags &= ~DWC3_EVENT_PENDING;
+		evt->lpos = 0;
+		memset(evt->buf, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+		os_detect_clear_done();
+		return IRQ_HANDLED;
+	}
+#endif
+	if (unlikely(!dwc->active)) {
+		dev_info(dwc->dev, "dwc3 is inactive\n");
+		reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		reg &= DWC3_GEVNTCOUNT_MASK;
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
+		evt->lpos = 0;
+	}
+
+	evt->count = 0;
+	evt->flags &= ~DWC3_EVENT_PENDING;
+	ret = IRQ_HANDLED;
+
+	/* Unmask interrupt */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
+	reg &= ~DWC3_GEVNTSIZ_INTMASK;
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
+
+	if (dwc->imod_interval) {
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
+		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
+	}
+
+	if (dwc->usb_do_restart) {
+		pr_info("!!!!!dwc3 usb restart\n");
+		count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		count &= DWC3_GEVNTCOUNT_MASK;
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+		dwc3_gadget_run_stop(dwc, 0, false);
+
+		if (work_pending(&dwc->usb_restart_work.work))
+			cancel_delayed_work(&dwc->usb_restart_work);
+
+#ifdef CONFIG_DWC3_HWSULOG
+		hwsulog_set_clear_stop_flag(true);
+#endif
+		schedule_delayed_work(&dwc->usb_restart_work, 0);
+	}
+
+	return ret;
+}
+
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt)
+{
+	struct dwc3_event_buffer *evt = _evt;
+	struct dwc3 *dwc = evt->dwc;
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+
+	//ASR private: disable bh enable/disable, ASR has no such issue
+#ifndef CONFIG_ASR_TOE
+	//local_bh_disable();
+#endif
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = dwc3_process_event_buf(evt);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+#ifndef CONFIG_ASR_TOE
+	//local_bh_enable();
+#endif
+
+	return ret;
+}
+
+static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
+{
+	struct dwc3 *dwc = evt->dwc;
+	u32 amount;
+	u32 count;
+	u32 reg;
+
+#if 0 /* ASR private */
+	if (pm_runtime_suspended(dwc->dev)) {
+		dwc->pending_events = true;
+		/*
+		* Trigger runtime resume. The get() function will be balanced
+		* after processing the pending events in dwc3_process_pending
+		* events().
+		*/
+		pm_runtime_get(dwc->dev);
+		disable_irq_nosync(dwc->irq_gadget);
+		return IRQ_HANDLED;
+	}
+#endif
+
+	/*
+	 * With PCIe legacy interrupt, test shows that top-half irq handler can
+	 * be called again after HW interrupt deassertion. Check if bottom-half
+	 * irq event handler completes before caching new event to prevent
+	 * losing events.
+	 */
+	if (evt->flags & DWC3_EVENT_PENDING)
+		return IRQ_HANDLED;
+
+	count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+	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(0));
+	reg |= DWC3_GEVNTSIZ_INTMASK;
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
+
+	amount = min(count, evt->length - evt->lpos);
+	memcpy(evt->cache + evt->lpos, evt->buf + evt->lpos, amount);
+
+	if (amount < count)
+		memcpy(evt->cache, evt->buf, count - amount);
+
+	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_evt)
+{
+	struct dwc3_event_buffer	*evt = _evt;
+
+	return dwc3_check_event_buf(evt);
+}
+
+#ifdef CONFIG_USB_DWC3_ASR_OTG
+static int asr_usb_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct dwc3 *dwc;
+	unsigned long flags;
+	int retval = 0;
+	static unsigned int vbus = 0;
+	static bool first_vbus = true;
+
+	dwc = container_of(gadget, struct dwc3, gadget);
+	dwc->vbus_active = (is_active != 0);
+	dev_info(dwc->dev, "%s: softconnect %d, vbus_active %d, pre_chrgr: %d\n",
+		__func__, dwc->softconnect, dwc->vbus_active, dwc->prev_charger_type);
+
+	if (work_pending(&dwc->usb_restart_work.work)) {
+		dev_info(dwc->dev, "cancel restart work...");
+		cancel_delayed_work_sync(&dwc->usb_restart_work);
+		dev_info(dwc->dev, "done\n");
+	}
+
+	if (!first_vbus) {
+		if (vbus == dwc->vbus_active) {
+			dev_info(dwc->dev, "!!!skip vbus event %d -> %d\n", vbus, dwc->vbus_active);
+			if (vbus)
+				pm_stay_awake(dwc->dev);
+			return 0;
+		}
+	}
+	if (first_vbus)
+		first_vbus = false;
+	vbus = dwc->vbus_active;
+
+	pr_emerg("vbus session otg state: %d - %s\n",
+		dwc->otg_state, usb_otg_state_string(dwc->otg_state));
+
+	if (dwc->otg_state != OTG_STATE_B_IDLE
+		&& dwc->otg_state != OTG_STATE_B_PERIPHERAL) {
+		pr_info("vbus exit for host mode\n");
+		return 0;
+	}
+
+	mutex_lock(&usb_con_mutex);
+	dwc->prev_charger_type = dwc->charger_type;
+	usb_phy_set_suspend(dwc->usb2_phy, 0);
+	if (dwc->vbus_active) {
+		pm_stay_awake(dwc->dev);
+		pm_qos_update_request(&dwc->qos_idle, dwc->lpm_qos);
+		dwc->charger_type = DEFAULT_CHARGER;
+	} else {
+		pm_wakeup_event(dwc->dev, 5000);
+		pm_qos_update_request_timeout(&dwc->qos_idle,
+			PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE, (5000 * 1000));
+		dwc->charger_type = NULL_CHARGER;
+	}
+
+	if (work_pending(&dwc->delayed_charger_work.work))
+		cancel_delayed_work(&dwc->delayed_charger_work);
+
+	if (dwc->charger_type == NULL_CHARGER)
+		schedule_delayed_work(&dwc->delayed_charger_work, 0);
+
+	if (dwc->charger_type == DEFAULT_CHARGER) {
+		int enum_delay  = ENUMERATION_DELAY;
+		dev_info(dwc->dev, "1st stage charger type: %s\n",
+					charger_type(dwc->charger_type));
+		call_charger_notifier(dwc);
+		schedule_delayed_work(&dwc->delayed_charger_work, enum_delay);
+	}
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->gadget_driver && dwc->softconnect && dwc->vbus_active) {
+		if (work_pending(&dwc->usb_restart_work.work))
+			cancel_delayed_work(&dwc->usb_restart_work);
+		__dwc3_gadget_start(dwc);
+		dwc3_gadget_run_stop(dwc, 1, false);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_charger_type_confirm(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+	} else if (dwc->gadget_driver && dwc->softconnect) {
+		if (dwc->prev_charger_type != DCP_CHARGER) {
+			dwc3_stop_active_transfers(dwc);
+			__dwc3_gadget_stop(dwc);
+			dwc3_gadget_run_stop(dwc, 0, false);
+			if (cpu_is_asr1901() || cpu_is_asr1906())
+				spin_unlock_irqrestore(&dwc->lock, flags);
+			dwc3_controller_reset(dwc);
+			if (cpu_is_asr1901() || cpu_is_asr1906())
+				spin_lock_irqsave(&dwc->lock, flags);
+			/* __dwc3_gadget_start(dwc); */
+		}
+#ifdef CONFIG_DWC3_HWSULOG
+		hwsulog_on = false;
+#endif
+		dwc->ev_buf->count = 0;
+		dwc->ev_buf->flags &= ~DWC3_EVENT_PENDING;
+		dwc->ev_buf->lpos = 0;
+		memset(dwc->ev_buf->buf, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+		memset(dwc->ev_buf->cache, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	if ((!dwc->vbus_active) && dwc->gadget_driver && dwc->softconnect
+		&& (dwc->prev_charger_type == SDP_CHARGER
+			|| dwc->prev_charger_type == CDP_CHARGER)) {
+		mutex_unlock(&usb_con_mutex);
+		cancel_reconfigure_work();
+		/* restore os type to default state */
+		android_dev_enable(0);
+		usb_os_restore();
+		android_dev_enable(1);
+		mutex_lock(&usb_con_mutex);
+		dwc->prev_charger_type = NULL_CHARGER;
+	}
+#endif
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!dwc->vbus_active) {
+		dwc->prev_charger_type = NULL_CHARGER;
+		usb_phy_set_suspend(dwc->usb2_phy, 1);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	mutex_unlock(&usb_con_mutex);
+	return retval;
+}
+#else
+static int asr_usb_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct dwc3 *dwc;
+	unsigned long flags;
+	int retval = 0;
+
+	dwc = container_of(gadget, struct dwc3, gadget);
+	dwc->vbus_active = (is_active != 0);
+	dev_info(dwc->dev, "%s: softconnect %d, vbus_active %d, pre_chrgr: %d\n",
+		__func__, dwc->softconnect, dwc->vbus_active, dwc->prev_charger_type);
+
+	if (work_pending(&dwc->usb_restart_work.work)) {
+		dev_info(dwc->dev, "cancel restart work...");
+		cancel_delayed_work_sync(&dwc->usb_restart_work);
+		dev_info(dwc->dev, "done\n");
+	}
+
+	mutex_lock(&usb_con_mutex);
+	dwc->prev_charger_type = dwc->charger_type;
+	usb_phy_set_suspend(dwc->usb2_phy, 0);
+	if (dwc->vbus_active) {
+		pm_stay_awake(dwc->dev);
+		pm_qos_update_request(&dwc->qos_idle, dwc->lpm_qos);
+		dwc->charger_type = DEFAULT_CHARGER;
+	} else {
+		pm_wakeup_event(dwc->dev, 5000);
+		pm_qos_update_request_timeout(&dwc->qos_idle,
+			PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE, (5000 * 1000));
+		dwc->charger_type = NULL_CHARGER;
+	}
+
+	if (work_pending(&dwc->delayed_charger_work.work))
+		cancel_delayed_work(&dwc->delayed_charger_work);
+
+	if (dwc->charger_type == NULL_CHARGER)
+		schedule_delayed_work(&dwc->delayed_charger_work, 0);
+
+	if (dwc->charger_type == DEFAULT_CHARGER) {
+		int enum_delay  = ENUMERATION_DELAY;
+		dev_info(dwc->dev, "1st stage charger type: %s\n",
+					charger_type(dwc->charger_type));
+		call_charger_notifier(dwc);
+		schedule_delayed_work(&dwc->delayed_charger_work, enum_delay);
+	}
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->gadget_driver && dwc->softconnect && dwc->vbus_active) {
+		if (work_pending(&dwc->usb_restart_work.work))
+			cancel_delayed_work(&dwc->usb_restart_work);
+		dwc3_gadget_run_stop(dwc, 1, false);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dwc3_charger_type_confirm(dwc);
+		spin_lock_irqsave(&dwc->lock, flags);
+	} else if (dwc->gadget_driver && dwc->softconnect) {
+		if (dwc->prev_charger_type != DCP_CHARGER) {
+			dwc3_stop_active_transfers(dwc);
+			__dwc3_gadget_stop(dwc);
+			dwc3_gadget_run_stop(dwc, 0, false);
+			if (cpu_is_asr1901() || cpu_is_asr1906())
+				spin_unlock_irqrestore(&dwc->lock, flags);
+			dwc3_controller_reset(dwc);
+			if (cpu_is_asr1901() || cpu_is_asr1906())
+				spin_lock_irqsave(&dwc->lock, flags);
+			__dwc3_gadget_start(dwc);
+		}
+
+#ifdef CONFIG_DWC3_HWSULOG
+		hwsulog_on = false;
+#endif
+		dwc->ev_buf->count = 0;
+		dwc->ev_buf->flags &= ~DWC3_EVENT_PENDING;
+		dwc->ev_buf->lpos = 0;
+		memset(dwc->ev_buf->buf, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+		memset(dwc->ev_buf->cache, 0x0, DWC3_EVENT_BUFFERS_SIZE);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+#if defined(CONFIG_USB_ANDROID_DETECT_HOST_OS)
+	if ((!dwc->vbus_active) && dwc->gadget_driver && dwc->softconnect
+		&& (dwc->prev_charger_type == SDP_CHARGER
+			|| dwc->prev_charger_type == CDP_CHARGER)) {
+		mutex_unlock(&usb_con_mutex);
+		cancel_reconfigure_work();
+		/* restore os type to default state */
+		android_dev_enable(0);
+		usb_os_restore();
+		android_dev_enable(1);
+		mutex_lock(&usb_con_mutex);
+		dwc->prev_charger_type = NULL_CHARGER;
+	}
+#endif
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!dwc->vbus_active) {
+		dwc->prev_charger_type = NULL_CHARGER;
+		usb_phy_set_suspend(dwc->usb2_phy, 1);
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	mutex_unlock(&usb_con_mutex);
+	return retval;
+}
+#endif
+
+static int asr_usb_vbus_notifier_call(struct notifier_block *nb,
+						unsigned long val, void *v)
+{
+	struct dwc3 *dwc = container_of(nb, struct dwc3, notifier);
+	/* polling VBUS and init phy may cause too much time*/
+	if (dwc->qwork && val == EVENT_VBUS)
+		queue_work(dwc->qwork, &dwc->vbus_work);
+
+	return 0;
+}
+
+static void asr_usb_vbus_work(struct work_struct *work)
+{
+	struct dwc3 *dwc;
+	unsigned int vbus = 0;
+	int ret;
+	static bool first_vbus = true;
+
+	dwc = container_of(work, struct dwc3, vbus_work);
+	ret = pxa_usb_extern_call(PXA_USB_DEV_OTG, vbus, get_vbus, &vbus);
+	if (ret) {
+		vbus = usb_phy_get_vbus(dwc->usb2_phy);
+	}
+
+	if (!first_vbus) {
+		if (vbus == dwc->vbus_active) {
+			dev_info(dwc->dev, "!!!skip vbus event %d -> %d\n", vbus, dwc->vbus_active);
+			if (vbus)
+				pm_stay_awake(dwc->dev);
+			return;
+		}
+	}
+
+	if (first_vbus)
+		first_vbus = false;
+	dev_info(dwc->dev, "vbus is %s.\n", vbus ? "on" : "off");
+	asr_usb_vbus_session(&dwc->gadget, vbus);
+}
+static int dwc3_gadget_get_irq(struct dwc3 *dwc)
+{
+	struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
+	int irq;
+
+	irq = platform_get_irq_byname_optional(dwc3_pdev, "peripheral");
+	if (irq > 0)
+		goto out;
+
+	if (irq == -EPROBE_DEFER)
+		goto out;
+
+	irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
+	if (irq > 0)
+		goto out;
+
+	if (irq == -EPROBE_DEFER)
+		goto out;
+
+	irq = platform_get_irq(dwc3_pdev, 0);
+	if (irq > 0)
+		goto out;
+
+	if (!irq)
+		irq = -EINVAL;
+
+out:
+	return irq;
+}
+
+#ifdef CONFIG_USB_DWC3_ASR_OTG
+extern int usb_otg_set_peripheral(struct usb_gadget *gadget);
+extern int usb_otg_set_phy(struct usb_phy *usb2phy, struct usb_phy *usb3phy);
+extern int usb_otg_set_controller(struct dwc3 *dwc);
+#endif
+
+/**
+ * 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;
+	int irq;
+
+	irq = dwc3_gadget_get_irq(dwc);
+	if (irq < 0) {
+		ret = irq;
+		goto err0;
+	}
+
+	dwc->irq_gadget = irq;
+
+	dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev,
+					  sizeof(*dwc->ep0_trb) * 2,
+					  &dwc->ep0_trb_addr, GFP_KERNEL);
+	if (!dwc->ep0_trb) {
+		dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
+	if (!dwc->setup_buf) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
+			&dwc->bounce_addr, GFP_KERNEL);
+	if (!dwc->bounce) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	dwc->ctrl_req = dma_alloc_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
+			&dwc->ctrl_req_addr, GFP_KERNEL);
+	if (!dwc->ctrl_req) {
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	init_completion(&dwc->ep0_in_setup);
+
+	dwc->gadget.ops			= &dwc3_gadget_ops;
+	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
+	dwc->gadget.sg_supported	= true;
+	dwc->gadget.name		= "dwc3-gadget";
+	dwc->gadget.lpm_capable		= true;
+
+	/*
+	 * FIXME We might be setting max_speed to <SUPER, however versions
+	 * <2.20a of dwc3 have an issue with metastability (documented
+	 * elsewhere in this driver) which tells us we can't set max speed to
+	 * anything lower than SUPER.
+	 *
+	 * Because gadget.max_speed is only used by composite.c and function
+	 * drivers (i.e. it won't go into dwc3's registers) we are allowing this
+	 * to happen so we avoid sending SuperSpeed Capability descriptor
+	 * together with our BOS descriptor as that could confuse host into
+	 * thinking we can handle super speed.
+	 *
+	 * Note that, in fact, we won't even support GetBOS requests when speed
+	 * is less than super speed because we don't have means, yet, to tell
+	 * composite.c that we are USB 2.0 + LPM ECN.
+	 */
+	if (dwc->revision < DWC3_REVISION_220A &&
+	    !dwc->dis_metastability_quirk)
+		dev_info(dwc->dev, "changing max_speed on rev %08x\n",
+				dwc->revision);
+
+	if (cpu_is_asr1828() || cpu_is_asr1903())
+		dwc->gadget.max_speed		= USB_SPEED_SUPER;
+	else
+		dwc->gadget.max_speed		= dwc->maximum_speed;
+
+	/*
+	 * 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, dwc->num_eps);
+	if (ret)
+		goto err4;
+
+	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register udc\n");
+		goto err5;
+	}
+
+	dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed);
+	dwc->qwork = create_singlethread_workqueue("asr_vbus_queue");
+	if (!dwc->qwork) {
+		dev_err(dwc->dev, "cannot create workqueue\n");
+		ret = -ENOMEM;
+		goto err5;
+	}
+	INIT_WORK(&dwc->vbus_work, asr_usb_vbus_work);
+	dwc->notifier.notifier_call = asr_usb_vbus_notifier_call;
+	pxa_usb_register_notifier(PXA_USB_DEV_OTG, &dwc->notifier);
+
+	INIT_DELAYED_WORK(&dwc->delayed_charger_work, do_delayed_charger_work);
+	dwc->charger_type = NULL_CHARGER;
+
+	INIT_DELAYED_WORK(&dwc->usb_restart_work, dwc3_restart_work);
+
+	device_init_wakeup(dwc->dev, 1);
+
+#ifdef CONFIG_DWC3_HWSULOG
+	dwc->hwsulog_regs = dwc->regs - DWC3_GLOBALS_REGS_START + SULOG_BASE_OFFSET;
+	if (cpu_is_asr1903() || cpu_is_asr1828() || cpu_is_asr1901() || cpu_is_asr1906())
+		register_hwsulog_udc_func(asr_udc_hwsulog_callback);
+#endif
+
+#ifdef CONFIG_USB_DWC3_ASR_OTG
+	usb_otg_set_peripheral(&dwc->gadget);
+	usb_otg_set_phy(dwc->usb2_phy, dwc->usb3_phy);
+	usb_otg_set_controller(dwc);
+#endif
+	dwc->phys_mem_end = PAGE_SIZE * max_pfn;
+	dev_info(dwc->dev, "phys_mem_end: 0x%lx\n", dwc->phys_mem_end);
+
+	the_controller = dwc;
+
+	return 0;
+
+err5:
+	dwc3_gadget_free_endpoints(dwc);
+
+err4:
+	dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req), dwc->ctrl_req,
+			dwc->ctrl_req_addr);
+
+err3:
+	dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
+			dwc->bounce_addr);
+
+err2:
+	kfree(dwc->setup_buf);
+
+err1:
+	dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
+			dwc->ep0_trb, dwc->ep0_trb_addr);
+
+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->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
+			  dwc->bounce_addr);
+	kfree(dwc->setup_buf);
+	dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
+			  dwc->ep0_trb, dwc->ep0_trb_addr);
+}
+
+int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+	if (!dwc->gadget_driver)
+		return 0;
+
+	dwc3_gadget_run_stop(dwc, false, false);
+	dwc3_disconnect_gadget(dwc);
+	__dwc3_gadget_stop(dwc);
+
+	return 0;
+}
+
+int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+	int			ret;
+
+	if (!dwc->gadget_driver || !dwc->softconnect)
+		return 0;
+
+	ret = __dwc3_gadget_start(dwc);
+	if (ret < 0)
+		goto err0;
+
+	ret = dwc3_gadget_run_stop(dwc, true, false);
+	if (ret < 0)
+		goto err1;
+
+	return 0;
+
+err1:
+	__dwc3_gadget_stop(dwc);
+
+err0:
+	return ret;
+}
diff --git a/marvell/linux/drivers/usb/dwc3/gadget.h b/marvell/linux/drivers/usb/dwc3/gadget.h
new file mode 100644
index 0000000..f207e59
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/gadget.h
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#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) & 0x1f) << 0)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN	BIT(8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN	BIT(9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN	BIT(10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN	BIT(11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN	BIT(13)
+#define DWC3_DEPCFG_BINTERVAL_M1(n)	(((n) & 0xff) << 16)
+#define DWC3_DEPCFG_STREAM_CAPABLE	BIT(24)
+#define DWC3_DEPCFG_EP_NUMBER(n)	(((n) & 0x1f) << 25)
+#define DWC3_DEPCFG_BULK_BASED		BIT(30)
+#define DWC3_DEPCFG_FIFO_BASED		BIT(31)
+
+/* DEPCFG parameter 0 */
+#define DWC3_DEPCFG_EP_TYPE(n)		(((n) & 0x3) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n)	(((n) & 0x7ff) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n)	(((n) & 0x1f) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n)	(((n) & 0xf) << 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		BIT(31)
+/* These apply for core versions 1.94a and later */
+#define DWC3_DEPCFG_ACTION_INIT		(0 << 30)
+#define DWC3_DEPCFG_ACTION_RESTORE	BIT(30)
+#define DWC3_DEPCFG_ACTION_MODIFY	(2 << 30)
+
+/* DEPXFERCFG parameter 0 */
+#define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
+
+/* U1 Device exit Latency */
+#define DWC3_DEFAULT_U1_DEV_EXIT_LAT	0x0A	/* Less then 10 microsec */
+
+/* U2 Device exit Latency */
+#define DWC3_DEFAULT_U2_DEV_EXIT_LAT	0x1FF	/* Less then 511 microsec */
+
+/* -------------------------------------------------------------------------- */
+
+#define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))
+
+/**
+ * next_request - gets the next request on the given list
+ * @list: the request list to operate on
+ *
+ * Caller should take care of locking. This function return %NULL or the first
+ * request available on @list.
+ */
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+	return list_first_entry_or_null(list, struct dwc3_request, list);
+}
+
+/**
+ * dwc3_gadget_move_started_request - move @req to the started_list
+ * @req: the request to be moved
+ *
+ * Caller should take care of locking. This function will move @req from its
+ * current list to the endpoint's started_list.
+ */
+static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
+{
+	struct dwc3_ep		*dep = req->dep;
+
+	req->status = DWC3_REQUEST_STATUS_STARTED;
+	list_move_tail(&req->list, &dep->started_list);
+}
+
+/**
+ * dwc3_gadget_move_cancelled_request - move @req to the cancelled_list
+ * @req: the request to be moved
+ *
+ * Caller should take care of locking. This function will move @req from its
+ * current list to the endpoint's cancelled_list.
+ */
+static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req)
+{
+	struct dwc3_ep		*dep = req->dep;
+
+	req->status = DWC3_REQUEST_STATUS_CANCELLED;
+	list_move_tail(&req->list, &dep->cancelled_list);
+}
+
+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_ep0_send_delayed_status(struct dwc3 *dwc);
+
+/**
+ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+ * @dep: dwc3 endpoint
+ *
+ * Caller should take care of locking. Returns the transfer resource
+ * index for a given endpoint.
+ */
+static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
+{
+	u32			res_id;
+
+	res_id = dwc3_readl(dep->regs, DWC3_DEPCMD);
+	dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */
diff --git a/marvell/linux/drivers/usb/dwc3/host.c b/marvell/linux/drivers/usb/dwc3/host.c
new file mode 100644
index 0000000..ffd1c7c
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/host.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * host.c - DesignWare USB3 DRD Controller Host Glue
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ */
+
+#include <linux/platform_device.h>
+
+#include "core.h"
+
+static int dwc3_host_get_irq(struct dwc3 *dwc)
+{
+	struct platform_device	*dwc3_pdev = to_platform_device(dwc->dev);
+	int irq;
+
+	irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
+	if (irq > 0)
+		goto out;
+
+	if (irq == -EPROBE_DEFER)
+		goto out;
+
+	irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
+	if (irq > 0)
+		goto out;
+
+	if (irq == -EPROBE_DEFER)
+		goto out;
+
+	irq = platform_get_irq(dwc3_pdev, 0);
+	if (irq > 0)
+		goto out;
+
+	if (!irq)
+		irq = -EINVAL;
+
+out:
+	return irq;
+}
+
+int dwc3_host_init(struct dwc3 *dwc)
+{
+	struct property_entry	props[4];
+	struct platform_device	*xhci;
+	int			ret, irq;
+	struct resource		*res;
+	struct platform_device	*dwc3_pdev = to_platform_device(dwc->dev);
+	int			prop_idx = 0;
+
+	irq = dwc3_host_get_irq(dwc);
+	if (irq < 0)
+		return irq;
+	dev_info(dwc->dev, "host irq: %d\n", irq);
+
+	res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host");
+	if (!res)
+		res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
+				"dwc_usb3");
+
+	if (!res)
+		res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0);
+	if (!res)
+		return -ENOMEM;
+
+	dwc->xhci_resources[1].start = irq;
+	dwc->xhci_resources[1].end = irq;
+	dwc->xhci_resources[1].flags = res->flags;
+	dwc->xhci_resources[1].name = res->name;
+
+	xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
+	if (!xhci) {
+		dev_err(dwc->dev, "couldn't allocate xHCI device\n");
+		return -ENOMEM;
+	}
+
+	xhci->dev.parent	= dwc->dev;
+
+	dwc->xhci = xhci;
+
+	ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+						DWC3_XHCI_RESOURCES_NUM);
+	if (ret) {
+		dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
+		goto err;
+	}
+
+	memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
+
+	if (dwc->usb3_lpm_capable)
+		props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable");
+
+	if (dwc->usb2_lpm_disable)
+		props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb2-lpm-disable");
+
+	/**
+	 * WORKAROUND: dwc3 revisions <=3.00a have a limitation
+	 * where Port Disable command doesn't work.
+	 *
+	 * The suggested workaround is that we avoid Port Disable
+	 * completely.
+	 *
+	 * This following flag tells XHCI to do just that.
+	 */
+	if (dwc->revision <= DWC3_REVISION_300A)
+		props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
+
+	if (prop_idx) {
+		ret = platform_device_add_properties(xhci, props);
+		if (ret) {
+			dev_err(dwc->dev, "failed to add properties to xHCI\n");
+			goto err;
+		}
+	}
+
+	ret = platform_device_add(xhci);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register xHCI device\n");
+		goto err;
+	}
+
+	return 0;
+err:
+	platform_device_put(xhci);
+	return ret;
+}
+
+void dwc3_host_exit(struct dwc3 *dwc)
+{
+	platform_device_unregister(dwc->xhci);
+	dwc->xhci = NULL;
+}
diff --git a/marvell/linux/drivers/usb/dwc3/io.h b/marvell/linux/drivers/usb/dwc3/io.h
new file mode 100644
index 0000000..70acdf9
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/io.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <linux/io.h>
+#include "trace.h"
+#include "debug.h"
+#include "core.h"
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+	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 + offset - DWC3_GLOBALS_REGS_START);
+
+	/*
+	 * When tracing we want to make it easy to find the correct address on
+	 * documentation, so we revert it back to the proper addresses, the
+	 * same way they are described on SNPS documentation
+	 */
+	trace_dwc3_readl(base - DWC3_GLOBALS_REGS_START, offset, value);
+
+	return value;
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, 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.
+	 */
+	writel(value, base + offset - DWC3_GLOBALS_REGS_START);
+
+	/*
+	 * When tracing we want to make it easy to find the correct address on
+	 * documentation, so we revert it back to the proper addresses, the
+	 * same way they are described on SNPS documentation
+	 */
+	trace_dwc3_writel(base - DWC3_GLOBALS_REGS_START, offset, value);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/marvell/linux/drivers/usb/dwc3/trace.c b/marvell/linux/drivers/usb/dwc3/trace.c
new file mode 100644
index 0000000..f8886f3
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/trace.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * trace.c - DesignWare USB3 DRD Controller Trace Support
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/marvell/linux/drivers/usb/dwc3/trace.h b/marvell/linux/drivers/usb/dwc3/trace.h
new file mode 100644
index 0000000..9edff17
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/trace.h
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * trace.h - DesignWare USB3 DRD Controller Trace Support
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM dwc3
+
+#if !defined(__DWC3_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __DWC3_TRACE_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <asm/byteorder.h>
+#include "core.h"
+#include "debug.h"
+
+DECLARE_EVENT_CLASS(dwc3_log_io,
+	TP_PROTO(void *base, u32 offset, u32 value),
+	TP_ARGS(base, offset, value),
+	TP_STRUCT__entry(
+		__field(void *, base)
+		__field(u32, offset)
+		__field(u32, value)
+	),
+	TP_fast_assign(
+		__entry->base = base;
+		__entry->offset = offset;
+		__entry->value = value;
+	),
+	TP_printk("addr %p value %08x", __entry->base + __entry->offset,
+			__entry->value)
+);
+
+DEFINE_EVENT(dwc3_log_io, dwc3_readl,
+	TP_PROTO(void __iomem *base, u32 offset, u32 value),
+	TP_ARGS(base, offset, value)
+);
+
+DEFINE_EVENT(dwc3_log_io, dwc3_writel,
+	TP_PROTO(void __iomem *base, u32 offset, u32 value),
+	TP_ARGS(base, offset, value)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_event,
+	TP_PROTO(u32 event, struct dwc3 *dwc),
+	TP_ARGS(event, dwc),
+	TP_STRUCT__entry(
+		__field(u32, event)
+		__field(u32, ep0state)
+		__dynamic_array(char, str, DWC3_MSG_MAX)
+	),
+	TP_fast_assign(
+		__entry->event = event;
+		__entry->ep0state = dwc->ep0state;
+	),
+	TP_printk("event (%08x): %s", __entry->event,
+			dwc3_decode_event(__get_str(str), DWC3_MSG_MAX,
+					__entry->event, __entry->ep0state))
+);
+
+DEFINE_EVENT(dwc3_log_event, dwc3_event,
+	TP_PROTO(u32 event, struct dwc3 *dwc),
+	TP_ARGS(event, dwc)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_ctrl,
+	TP_PROTO(struct usb_ctrlrequest *ctrl),
+	TP_ARGS(ctrl),
+	TP_STRUCT__entry(
+		__field(__u8, bRequestType)
+		__field(__u8, bRequest)
+		__field(__u16, wValue)
+		__field(__u16, wIndex)
+		__field(__u16, wLength)
+		__dynamic_array(char, str, DWC3_MSG_MAX)
+	),
+	TP_fast_assign(
+		__entry->bRequestType = ctrl->bRequestType;
+		__entry->bRequest = ctrl->bRequest;
+		__entry->wValue = le16_to_cpu(ctrl->wValue);
+		__entry->wIndex = le16_to_cpu(ctrl->wIndex);
+		__entry->wLength = le16_to_cpu(ctrl->wLength);
+	),
+	TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX,
+					__entry->bRequestType,
+					__entry->bRequest, __entry->wValue,
+					__entry->wIndex, __entry->wLength)
+	)
+);
+
+DEFINE_EVENT(dwc3_log_ctrl, dwc3_ctrl_req,
+	TP_PROTO(struct usb_ctrlrequest *ctrl),
+	TP_ARGS(ctrl)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_request,
+	TP_PROTO(struct dwc3_request *req),
+	TP_ARGS(req),
+	TP_STRUCT__entry(
+		__string(name, req->dep->name)
+		__field(struct dwc3_request *, req)
+		__field(unsigned, actual)
+		__field(unsigned, length)
+		__field(int, status)
+		__field(int, zero)
+		__field(int, short_not_ok)
+		__field(int, no_interrupt)
+	),
+	TP_fast_assign(
+		__assign_str(name, req->dep->name);
+		__entry->req = req;
+		__entry->actual = req->request.actual;
+		__entry->length = req->request.length;
+		__entry->status = req->request.status;
+		__entry->zero = req->request.zero;
+		__entry->short_not_ok = req->request.short_not_ok;
+		__entry->no_interrupt = req->request.no_interrupt;
+	),
+	TP_printk("%s: req %p length %u/%u %s%s%s ==> %d",
+		__get_str(name), __entry->req, __entry->actual, __entry->length,
+		__entry->zero ? "Z" : "z",
+		__entry->short_not_ok ? "S" : "s",
+		__entry->no_interrupt ? "i" : "I",
+		__entry->status
+	)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_alloc_request,
+	TP_PROTO(struct dwc3_request *req),
+	TP_ARGS(req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_free_request,
+	TP_PROTO(struct dwc3_request *req),
+	TP_ARGS(req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_ep_queue,
+	TP_PROTO(struct dwc3_request *req),
+	TP_ARGS(req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_ep_dequeue,
+	TP_PROTO(struct dwc3_request *req),
+	TP_ARGS(req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_gadget_giveback,
+	TP_PROTO(struct dwc3_request *req),
+	TP_ARGS(req)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
+	TP_PROTO(unsigned int cmd, u32 param, int status),
+	TP_ARGS(cmd, param, status),
+	TP_STRUCT__entry(
+		__field(unsigned int, cmd)
+		__field(u32, param)
+		__field(int, status)
+	),
+	TP_fast_assign(
+		__entry->cmd = cmd;
+		__entry->param = param;
+		__entry->status = status;
+	),
+	TP_printk("cmd '%s' [%x] param %08x --> status: %s",
+		dwc3_gadget_generic_cmd_string(__entry->cmd),
+		__entry->cmd, __entry->param,
+		dwc3_gadget_generic_cmd_status_string(__entry->status)
+	)
+);
+
+DEFINE_EVENT(dwc3_log_generic_cmd, dwc3_gadget_generic_cmd,
+	TP_PROTO(unsigned int cmd, u32 param, int status),
+	TP_ARGS(cmd, param, status)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
+	TP_PROTO(struct dwc3_ep *dep, unsigned int cmd,
+		struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
+	TP_ARGS(dep, cmd, params, cmd_status),
+	TP_STRUCT__entry(
+		__string(name, dep->name)
+		__field(unsigned int, cmd)
+		__field(u32, param0)
+		__field(u32, param1)
+		__field(u32, param2)
+		__field(int, cmd_status)
+	),
+	TP_fast_assign(
+		__assign_str(name, dep->name);
+		__entry->cmd = cmd;
+		__entry->param0 = params->param0;
+		__entry->param1 = params->param1;
+		__entry->param2 = params->param2;
+		__entry->cmd_status = cmd_status;
+	),
+	TP_printk("%s: cmd '%s' [%x] params %08x %08x %08x --> status: %s",
+		__get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
+		__entry->cmd, __entry->param0,
+		__entry->param1, __entry->param2,
+		dwc3_ep_cmd_status_string(__entry->cmd_status)
+	)
+);
+
+DEFINE_EVENT(dwc3_log_gadget_ep_cmd, dwc3_gadget_ep_cmd,
+	TP_PROTO(struct dwc3_ep *dep, unsigned int cmd,
+		struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
+	TP_ARGS(dep, cmd, params, cmd_status)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_trb,
+	TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb),
+	TP_ARGS(dep, trb),
+	TP_STRUCT__entry(
+		__string(name, dep->name)
+		__field(struct dwc3_trb *, trb)
+		__field(u32, allocated)
+		__field(u32, queued)
+		__field(u32, bpl)
+		__field(u32, bph)
+		__field(u32, size)
+		__field(u32, ctrl)
+		__field(u32, type)
+	),
+	TP_fast_assign(
+		__assign_str(name, dep->name);
+		__entry->trb = trb;
+		__entry->bpl = trb->bpl;
+		__entry->bph = trb->bph;
+		__entry->size = trb->size;
+		__entry->ctrl = trb->ctrl;
+		__entry->type = usb_endpoint_type(dep->endpoint.desc);
+	),
+	TP_printk("%s: trb %p buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)",
+		__get_str(name), __entry->trb, __entry->bph, __entry->bpl,
+		({char *s;
+		int pcm = ((__entry->size >> 24) & 3) + 1;
+		switch (__entry->type) {
+		case USB_ENDPOINT_XFER_INT:
+		case USB_ENDPOINT_XFER_ISOC:
+			switch (pcm) {
+			case 1:
+				s = "1x ";
+				break;
+			case 2:
+				s = "2x ";
+				break;
+			case 3:
+			default:
+				s = "3x ";
+				break;
+			}
+			break;
+		default:
+			s = "";
+		} s; }),
+		DWC3_TRB_SIZE_LENGTH(__entry->size), __entry->ctrl,
+		__entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h',
+		__entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l',
+		__entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c',
+		__entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
+		__entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
+		__entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
+		  dwc3_trb_type_string(DWC3_TRBCTL_TYPE(__entry->ctrl))
+	)
+);
+
+DEFINE_EVENT(dwc3_log_trb, dwc3_prepare_trb,
+	TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb),
+	TP_ARGS(dep, trb)
+);
+
+DEFINE_EVENT(dwc3_log_trb, dwc3_complete_trb,
+	TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb),
+	TP_ARGS(dep, trb)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_ep,
+	TP_PROTO(struct dwc3_ep *dep),
+	TP_ARGS(dep),
+	TP_STRUCT__entry(
+		__string(name, dep->name)
+		__field(unsigned, maxpacket)
+		__field(unsigned, maxpacket_limit)
+		__field(unsigned, max_streams)
+		__field(unsigned, maxburst)
+		__field(unsigned, flags)
+		__field(unsigned, direction)
+		__field(u8, trb_enqueue)
+		__field(u8, trb_dequeue)
+	),
+	TP_fast_assign(
+		__assign_str(name, dep->name);
+		__entry->maxpacket = dep->endpoint.maxpacket;
+		__entry->maxpacket_limit = dep->endpoint.maxpacket_limit;
+		__entry->max_streams = dep->endpoint.max_streams;
+		__entry->maxburst = dep->endpoint.maxburst;
+		__entry->flags = dep->flags;
+		__entry->direction = dep->direction;
+		__entry->trb_enqueue = dep->trb_enqueue;
+		__entry->trb_dequeue = dep->trb_dequeue;
+	),
+	TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c",
+		__get_str(name), __entry->maxpacket,
+		__entry->maxpacket_limit, __entry->max_streams,
+		__entry->maxburst, __entry->trb_enqueue,
+		__entry->trb_dequeue,
+		__entry->flags & DWC3_EP_ENABLED ? 'E' : 'e',
+		__entry->flags & DWC3_EP_STALL ? 'S' : 's',
+		__entry->flags & DWC3_EP_WEDGE ? 'W' : 'w',
+		__entry->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b',
+		__entry->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p',
+		__entry->direction ? '<' : '>'
+	)
+);
+
+DEFINE_EVENT(dwc3_log_ep, dwc3_gadget_ep_enable,
+	TP_PROTO(struct dwc3_ep *dep),
+	TP_ARGS(dep)
+);
+
+DEFINE_EVENT(dwc3_log_ep, dwc3_gadget_ep_disable,
+	TP_PROTO(struct dwc3_ep *dep),
+	TP_ARGS(dep)
+);
+
+#endif /* __DWC3_TRACE_H */
+
+/* this part has to be here */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/marvell/linux/drivers/usb/dwc3/ulpi.c b/marvell/linux/drivers/usb/dwc3/ulpi.c
new file mode 100644
index 0000000..ffe3440
--- /dev/null
+++ b/marvell/linux/drivers/usb/dwc3/ulpi.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/time64.h>
+#include <linux/ulpi/regs.h>
+
+#include "core.h"
+#include "io.h"
+
+#define DWC3_ULPI_ADDR(a) \
+		((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
+		DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
+		DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
+
+#define DWC3_ULPI_BASE_DELAY	DIV_ROUND_UP(NSEC_PER_SEC, 60000000L)
+
+static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read)
+{
+	unsigned long ns = 5L * DWC3_ULPI_BASE_DELAY;
+	unsigned int count = 1000;
+	u32 reg;
+
+	if (addr >= ULPI_EXT_VENDOR_SPECIFIC)
+		ns += DWC3_ULPI_BASE_DELAY;
+
+	if (read)
+		ns += DWC3_ULPI_BASE_DELAY;
+
+	while (count--) {
+		ndelay(ns);
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
+		if (reg & DWC3_GUSB2PHYACC_DONE)
+			return 0;
+		cpu_relax();
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int dwc3_ulpi_read(struct device *dev, u8 addr)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	u32 reg;
+	int ret;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	}
+
+	reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
+
+	ret = dwc3_ulpi_busyloop(dwc, addr, true);
+	if (ret)
+		return ret;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
+
+	return DWC3_GUSB2PHYACC_DATA(reg);
+}
+
+static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
+{
+	struct dwc3 *dwc = dev_get_drvdata(dev);
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+	}
+
+	reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
+	reg |= DWC3_GUSB2PHYACC_WRITE | val;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
+
+	return dwc3_ulpi_busyloop(dwc, addr, false);
+}
+
+static const struct ulpi_ops dwc3_ulpi_ops = {
+	.read = dwc3_ulpi_read,
+	.write = dwc3_ulpi_write,
+};
+
+int dwc3_ulpi_init(struct dwc3 *dwc)
+{
+	/* Register the interface */
+	dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
+	if (IS_ERR(dwc->ulpi)) {
+		dev_err(dwc->dev, "failed to register ULPI interface");
+		return PTR_ERR(dwc->ulpi);
+	}
+
+	return 0;
+}
+
+void dwc3_ulpi_exit(struct dwc3 *dwc)
+{
+	if (dwc->ulpi) {
+		ulpi_unregister_interface(dwc->ulpi);
+		dwc->ulpi = NULL;
+	}
+}