All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver
@ 2020-09-18  9:10 Chunfeng Yun
  2020-09-18  9:10 ` [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties Chunfeng Yun
                   ` (10 more replies)
  0 siblings, 11 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

These patches introduce the MediaTek USB3 Dual-Role Controller
driver.
The driver can be configured as Peripheral only and Host only(xHCI)
modes, and it's ported from Linux Kernel 5.8-rc1

v7 changes
    1. use xhci quirk flag XHCI_MTK_HOST

v6 changes
    1. modify commit message of [4/10]

v5 changes:
    1. change condition of readl_poll_timeout() when check clocks
    2. add xhci-mtk.c and myself as maintainer for MTK USB

v4 changes:
    1. [4/10], [9/10] and [10/10] are new patches
    2. add a glue driver
    3. add host driver and rebuild host flow
    4. support force_vbus mode for device
    5. update bindings to support glue driver

v3 changes:
    1. add patch [5/7]
    2. add udc_set_speed()
    3. simplify some code flow

v2 changes:
    1. simplify QMU operations

Chunfeng Yun (10):
  dt-binding: usb: add bindings for some common properties
  dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD
  usb: add USB_SPEED_SUPER_PLUS
  usb: common: add define of usb_speed_string()
  usb: add MediaTek USB3 DRD driver
  usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller
  arm: dts: mt8512: add usb related nodes
  configs: mt8512: enable fastboot
  configs: mt8512: add USB host related configs
  MAINTAINERS: add USB driver to ARM MEDIATEK

 MAINTAINERS                                    |   3 +
 Makefile                                       |   1 +
 arch/arm/dts/mt8512-bm1-emmc.dts               |  34 +
 arch/arm/dts/mt8512.dtsi                       |  49 +-
 configs/mt8512_bm1_emmc_defconfig              |  26 +
 doc/device-tree-bindings/usb/generic.txt       |  31 +
 doc/device-tree-bindings/usb/mediatek,mtu3.txt |  79 +++
 drivers/usb/Kconfig                            |   2 +
 drivers/usb/common/common.c                    |   8 +
 drivers/usb/gadget/gadget_chips.h              |   8 +
 drivers/usb/mtu3/Kconfig                       |  45 ++
 drivers/usb/mtu3/Makefile                      |  11 +
 drivers/usb/mtu3/mtu3.h                        | 423 +++++++++++
 drivers/usb/mtu3/mtu3_core.c                   | 838 ++++++++++++++++++++++
 drivers/usb/mtu3/mtu3_dr.h                     |  52 ++
 drivers/usb/mtu3/mtu3_gadget.c                 | 686 ++++++++++++++++++
 drivers/usb/mtu3/mtu3_gadget_ep0.c             | 933 +++++++++++++++++++++++++
 drivers/usb/mtu3/mtu3_host.c                   | 141 ++++
 drivers/usb/mtu3/mtu3_hw_regs.h                | 515 ++++++++++++++
 drivers/usb/mtu3/mtu3_plat.c                   | 368 ++++++++++
 drivers/usb/mtu3/mtu3_qmu.c                    | 504 +++++++++++++
 drivers/usb/mtu3/mtu3_qmu.h                    |  37 +
 include/linux/usb/ch9.h                        |   5 +-
 23 files changed, 4794 insertions(+), 5 deletions(-)
 create mode 100644 doc/device-tree-bindings/usb/generic.txt
 create mode 100644 doc/device-tree-bindings/usb/mediatek,mtu3.txt
 create mode 100644 drivers/usb/mtu3/Kconfig
 create mode 100644 drivers/usb/mtu3/Makefile
 create mode 100644 drivers/usb/mtu3/mtu3.h
 create mode 100644 drivers/usb/mtu3/mtu3_core.c
 create mode 100644 drivers/usb/mtu3/mtu3_dr.h
 create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
 create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
 create mode 100644 drivers/usb/mtu3/mtu3_host.c
 create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
 create mode 100644 drivers/usb/mtu3/mtu3_plat.c
 create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
 create mode 100644 drivers/usb/mtu3/mtu3_qmu.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:15   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD Chunfeng Yun
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add bindings for common properties, include maximum-speed,
dr_mode and phy_type

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v2~v7: no changes
---
 doc/device-tree-bindings/usb/generic.txt | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 doc/device-tree-bindings/usb/generic.txt

diff --git a/doc/device-tree-bindings/usb/generic.txt b/doc/device-tree-bindings/usb/generic.txt
new file mode 100644
index 0000000..a02a198
--- /dev/null
+++ b/doc/device-tree-bindings/usb/generic.txt
@@ -0,0 +1,31 @@
+Generic USB Properties
+
+Optional properties:
+ - maximum-speed: tells USB controllers we want to work up to a certain
+			speed. Valid arguments are "super-speed-plus",
+			"super-speed", "high-speed", "full-speed" and
+			"low-speed". In case this isn't passed via DT, USB
+			controllers should default to their maximum HW
+			capability.
+ - dr_mode: tells Dual-Role USB controllers that we want to work on a
+			particular mode. Valid arguments are "host",
+			"peripheral" and "otg". In case this attribute isn't
+			passed via DT, USB DRD controllers should default to
+			OTG.
+ - phy_type: tells USB controllers that we want to configure the core to support
+			a UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is
+			selected. Valid arguments are "utmi" and "utmi_wide".
+			In case this isn't passed via DT, USB controllers should
+			default to HW capability.
+
+This is an attribute to a USB controller such as:
+
+dwc3 at 4a030000 {
+	compatible = "synopsys,dwc3";
+	reg = <0x4a030000 0xcfff>;
+	interrupts = <0 92 4>
+	usb-phy = <&usb2_phy>, <&usb3,phy>;
+	maximum-speed = "super-speed";
+	dr_mode = "otg";
+	phy_type = "utmi_wide";
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
  2020-09-18  9:10 ` [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:18   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS Chunfeng Yun
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add dt-binding for MediaTek USB3 DRD Driver

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v5~v7: no changes

v4:
  Add support host mode, introduce some new properties and subnode

v2~v3: no changes
---
 doc/device-tree-bindings/usb/mediatek,mtu3.txt | 79 ++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 doc/device-tree-bindings/usb/mediatek,mtu3.txt

diff --git a/doc/device-tree-bindings/usb/mediatek,mtu3.txt b/doc/device-tree-bindings/usb/mediatek,mtu3.txt
new file mode 100644
index 0000000..ab877bf
--- /dev/null
+++ b/doc/device-tree-bindings/usb/mediatek,mtu3.txt
@@ -0,0 +1,79 @@
+The device node for Mediatek USB3 DRD controller
+
+Required properties:
+ - compatible : should be "mediatek,<soc-model>-mtu3", "mediatek,mtu3",
+	soc-model is the name of SoC, such as mt8512 etc,
+	when using "mediatek,mtu3" compatible string, you need SoC specific
+	ones in addition, one of:
+	- "mediatek,mt8512-mtu3"
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be
+	- "ippc" : IP Port Control
+ - power-domains : a phandle to USB power domain node to control USB's MTCMOS
+ - clocks : a list of phandle + clock-specifier pairs, one for each
+	entry in clock-names
+ - clock-names : must contain "sys_ck" for clock of controller,
+	the following clocks are optional:
+	"ref_ck", "mcu_ck", "dma_ck" and "xhci_ck";
+ - phys : list of all the USB PHYs on this HCD
+ - #address-cells, #size-cells : used for sub-nodes with 'reg' property
+ - ranges : allows valid 1:1 translation between child's address space and
+	parent's address space
+
+Optional properties:
+ - vusb33-supply : regulator of USB AVDD3.3v
+ - vbus-supply : regulator of VBUS 5v, needed when supports host mode.
+
+Sub-nodes:
+Required properties:
+ - compatible : should be "mediatek,ssusb"
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be
+	- "mac" : SSUSB MAC, include xHCI and device
+ - interrupts : interrupt used by xHCI or device
+ - dr_mode : should be one of "host" or "peripheral",
+	see : usb/generic.txt
+
+Optional properties:
+ - pinctrl-names : a pinctrl state named "default" is optional
+ - pinctrl-0 : pin control group
+	See: pinctrl/pinctrl-bindings.txt
+
+ - device mode:
+   - maximum-speed : valid arguments are "full-speed", "high-speed",
+	"super-speed" and "super-speed-plus",
+	see: usb/generic.txt
+   - mediatek,force-vbus : force vbus as valid by SW
+
+ - host mode (dr_mode is "host"):
+   - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
+	bit1 for u3port1, ... etc;
+
+Example:
+usb3: usb at 11213e00 {
+	compatible = "mediatek,mt8512-mtu3", "mediatek,mtu3";
+	reg = <0x11213e00 0x0100>;
+	reg-names = "ippc";
+	phys = <&u2port0 PHY_TYPE_USB2>, <&u2port1 PHY_TYPE_USB2>;
+	power-domains = <&scpsys MT8512_POWER_DOMAIN_USB>;
+	clocks = <&infracfg CLK_INFRA_USB_SYS>,
+		 <&topckgen CLK_TOP_SSUSB_TOP_CK_EN>,
+		 <&infracfg CLK_INFRA_ICUSB>;
+	clock-names = "sys_ck", "ref_ck", "mcu_ck";
+	vusb33-supply = <reg_3p3v>;
+	vbus-supply = <&usb_p0_vbus>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+	status = "disabled";
+
+	ssusb: usb at 11210000 {
+		compatible = "mediatek,ssusb";
+		reg = <0x11210000 0x3e00>;
+		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_LOW>;
+		reg-names = "mac";
+		dr_mode = "peripheral";
+		maximum-speed = "high-speed";
+		status = "disabled";
+	};
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
  2020-09-18  9:10 ` [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties Chunfeng Yun
  2020-09-18  9:10 ` [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:19   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 04/10] usb: common: add define of usb_speed_string() Chunfeng Yun
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add enum USB_SPEED_SUPER_PLUS for USB3.1

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v5~v7: no changes

v4: also add it into speed_names array

v2~v3: no changes
---
 drivers/usb/common/common.c | 1 +
 include/linux/usb/ch9.h     | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index d4ae186..76f5a9c 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -46,6 +46,7 @@ static const char *const speed_names[] = {
 	[USB_SPEED_HIGH] = "high-speed",
 	[USB_SPEED_WIRELESS] = "wireless",
 	[USB_SPEED_SUPER] = "super-speed",
+	[USB_SPEED_SUPER_PLUS] = "super-speed-plus",
 };
 
 enum usb_device_speed usb_get_maximum_speed(ofnode node)
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 989a5fc..7d225ee 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -956,6 +956,7 @@ enum usb_device_speed {
 	USB_SPEED_HIGH,				/* usb 2.0 */
 	USB_SPEED_WIRELESS,			/* wireless (usb 2.5) */
 	USB_SPEED_SUPER,			/* usb 3.0 */
+	USB_SPEED_SUPER_PLUS,			/* usb 3.1 */
 };
 
 #ifdef __KERNEL__
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 04/10] usb: common: add define of usb_speed_string()
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (2 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:21   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver Chunfeng Yun
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

There is only declaration of usb_speed_string(), but no definition,
so add it to avoid build error when call it.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v7: no changes

v6: modify commit message suggested by Roger

v5: no changes

v4: new patch
---
 drivers/usb/common/common.c | 7 +++++++
 include/linux/usb/ch9.h     | 4 ----
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index 76f5a9c..5e5c3c3 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -49,6 +49,13 @@ static const char *const speed_names[] = {
 	[USB_SPEED_SUPER_PLUS] = "super-speed-plus",
 };
 
+const char *usb_speed_string(enum usb_device_speed speed)
+{
+	if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
+		speed = USB_SPEED_UNKNOWN;
+	return speed_names[speed];
+}
+
 enum usb_device_speed usb_get_maximum_speed(ofnode node)
 {
 	const char *max_speed;
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 7d225ee..a8fa5d7 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -959,8 +959,6 @@ enum usb_device_speed {
 	USB_SPEED_SUPER_PLUS,			/* usb 3.1 */
 };
 
-#ifdef __KERNEL__
-
 /**
  * usb_speed_string() - Returns human readable-name of the speed.
  * @speed: The speed to return human-readable name for.  If it's not
@@ -969,8 +967,6 @@ enum usb_device_speed {
  */
 extern const char *usb_speed_string(enum usb_device_speed speed);
 
-#endif
-
 enum usb_device_state {
 	/* NOTATTACHED isn't in the USB spec, and this state acts
 	 * the same as ATTACHED ... but it's clearer this way.
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (3 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 04/10] usb: common: add define of usb_speed_string() Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:26   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 06/10] usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller Chunfeng Yun
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

This patch adds support for the MediaTek USB3 DRD controller,
its host side is based on xHCI, this driver supports device mode
and host mode.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v7:
    1. use xhci quirk flag XHCI_MTK_HOST

v6: no changes

v5: 
    1. change condition of readl_poll_timeout() when check clocks

v4:
    1. remove unused member @busy and @wedged, use their flags instead
    2. support force_vbus mode
    3. add a glue driver using UCLASS_NOP
    4. add host driver, and rebuild host flow

v3 changes
    1. add ->udc_set_speed()
    2. simplify some code flow

v2: simplify QMU operations
---
 Makefile                           |   1 +
 drivers/usb/Kconfig                |   2 +
 drivers/usb/mtu3/Kconfig           |  45 ++
 drivers/usb/mtu3/Makefile          |  11 +
 drivers/usb/mtu3/mtu3.h            | 423 +++++++++++++++++
 drivers/usb/mtu3/mtu3_core.c       | 838 +++++++++++++++++++++++++++++++++
 drivers/usb/mtu3/mtu3_dr.h         |  52 +++
 drivers/usb/mtu3/mtu3_gadget.c     | 686 +++++++++++++++++++++++++++
 drivers/usb/mtu3/mtu3_gadget_ep0.c | 933 +++++++++++++++++++++++++++++++++++++
 drivers/usb/mtu3/mtu3_host.c       | 141 ++++++
 drivers/usb/mtu3/mtu3_hw_regs.h    | 515 ++++++++++++++++++++
 drivers/usb/mtu3/mtu3_plat.c       | 368 +++++++++++++++
 drivers/usb/mtu3/mtu3_qmu.c        | 504 ++++++++++++++++++++
 drivers/usb/mtu3/mtu3_qmu.h        |  37 ++
 14 files changed, 4556 insertions(+)
 create mode 100644 drivers/usb/mtu3/Kconfig
 create mode 100644 drivers/usb/mtu3/Makefile
 create mode 100644 drivers/usb/mtu3/mtu3.h
 create mode 100644 drivers/usb/mtu3/mtu3_core.c
 create mode 100644 drivers/usb/mtu3/mtu3_dr.h
 create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
 create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
 create mode 100644 drivers/usb/mtu3/mtu3_host.c
 create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
 create mode 100644 drivers/usb/mtu3/mtu3_plat.c
 create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
 create mode 100644 drivers/usb/mtu3/mtu3_qmu.h

diff --git a/Makefile b/Makefile
index 7a05fc7..2dcc41a 100644
--- a/Makefile
+++ b/Makefile
@@ -795,6 +795,7 @@ libs-y += drivers/usb/eth/
 libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/
 libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/udc/
 libs-y += drivers/usb/host/
+libs-y += drivers/usb/mtu3/
 libs-y += drivers/usb/musb/
 libs-y += drivers/usb/musb-new/
 libs-y += drivers/usb/phy/
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 34881a1..fedc013 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -72,6 +72,8 @@ source "drivers/usb/cdns3/Kconfig"
 
 source "drivers/usb/dwc3/Kconfig"
 
+source "drivers/usb/mtu3/Kconfig"
+
 source "drivers/usb/musb/Kconfig"
 
 source "drivers/usb/musb-new/Kconfig"
diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
new file mode 100644
index 0000000..66651ad
--- /dev/null
+++ b/drivers/usb/mtu3/Kconfig
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# For MTK USB3.0 IP
+
+config USB_MTU3
+	bool "MediaTek USB3 Dual Role controller"
+	depends on USB || USB_GADGET
+	depends on ARCH_MEDIATEK
+	help
+	  Say Y here if your system runs on MediaTek SoCs with
+	  Dual Role SuperSpeed USB controller. You can select usb
+	  mode as peripheral role or host role.
+
+	  If you don't know what this is, please say N.
+
+if USB_MTU3
+choice
+	bool "MTU3 Mode Selection"
+	default USB_MTU3_GADGET if USB_GADGET
+	default USB_MTU3_HOST if (USB && !USB_GADGET)
+
+config USB_MTU3_HOST
+	bool "Host only mode"
+	depends on USB=y || USB=USB_MTU3
+	select USB_XHCI_HCD
+	help
+	  Select this when you want to use MTU3 in host mode only,
+	  thereby the gadget feature will be regressed.
+
+config USB_MTU3_GADGET
+	bool "Gadget only mode"
+	depends on USB_GADGET=y || USB_GADGET=USB_MTU3
+	select USB_GADGET_DUALSPEED
+	help
+	  Select this when you want to use MTU3 in gadget mode only,
+	  thereby the host feature will be regressed.
+
+endchoice
+
+config USB_MTU3_DEBUG
+	bool "Enable Debugging Messages"
+	help
+	  Say Y here to enable debugging messages in the MTU3 Driver.
+
+endif
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
new file mode 100644
index 0000000..234f3a3
--- /dev/null
+++ b/drivers/usb/mtu3/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-$(CONFIG_USB_MTU3_DEBUG)	+= -DDEBUG
+
+obj-$(CONFIG_USB_MTU3)	+= mtu3.o
+
+mtu3-y	:= mtu3_plat.o
+
+obj-$(CONFIG_USB_MTU3_GADGET)	+= mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o
+obj-$(CONFIG_USB_MTU3_GADGET)	+= mtu3_qmu.o
+obj-$(CONFIG_USB_MTU3_HOST)	+= mtu3_host.o
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
new file mode 100644
index 0000000..7ff8ea8
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3.h
@@ -0,0 +1,423 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3.h - MediaTek USB3 DRD header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTU3_H__
+#define __MTU3_H__
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <generic-phy.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <power/regulator.h>
+#include <usb/xhci.h>
+
+struct mtu3;
+struct mtu3_ep;
+struct mtu3_request;
+struct mtu3_host;
+
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+#define	MU3D_EP_TXCR0(epnum)	(U3D_TX1CSR0 + (((epnum) - 1) * 0x10))
+#define	MU3D_EP_TXCR1(epnum)	(U3D_TX1CSR1 + (((epnum) - 1) * 0x10))
+#define	MU3D_EP_TXCR2(epnum)	(U3D_TX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define	MU3D_EP_RXCR0(epnum)	(U3D_RX1CSR0 + (((epnum) - 1) * 0x10))
+#define	MU3D_EP_RXCR1(epnum)	(U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
+#define	MU3D_EP_RXCR2(epnum)	(U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_RQCSR(epnum)	(U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQSAR(epnum)	(U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQCPR(epnum)	(U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_TQCSR(epnum)	(U3D_TXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQSAR(epnum)	(U3D_TXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQCPR(epnum)	(U3D_TXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define SSUSB_U3_CTRL(p)	(U3D_SSUSB_U3_CTRL_0P + ((p) * 0x08))
+#define SSUSB_U2_CTRL(p)	(U3D_SSUSB_U2_CTRL_0P + ((p) * 0x08))
+
+#define MTU3_DRIVER_NAME	"mtu3-gadget"
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+#define MTU3_EP_ENABLED		BIT(0)
+#define MTU3_EP_STALL		BIT(1)
+#define MTU3_EP_WEDGE		BIT(2)
+#define MTU3_EP_BUSY		BIT(3)
+
+/* should be set as 1 */
+#define MTU3_U2_IP_SLOT_DEFAULT 1
+#define MTU3_U3_IP_SLOT_DEFAULT (MTU3_U2_IP_SLOT_DEFAULT)
+
+/**
+ * IP TRUNK version
+ * from 0x1003 version, USB3 Gen2 is supported, two changes affect driver:
+ * 1. MAXPKT and MULTI bits layout of TXCSR1 and RXCSR1 are adjusted,
+ *    but not backward compatible
+ * 2. QMU extend buffer length supported
+ */
+#define MTU3_TRUNK_VERS_1003	0x1003
+
+/**
+ * Normally the device works on HS or SS, to simplify fifo management,
+ * devide fifo into some 2*maxp parts, use bitmap to manage it; And
+ * 32 bits size of bitmap is large enough, that means it can manage
+ * up to 32KB/64KB fifo size.
+ * NOTE: MTU3_U2/3IP_EP_FIFO_UNIT should be power of two;
+ *	FIFO size is allocated according to @slot which is 1 by default
+ */
+#define USB_HS_MAXP	512
+#define USB_SS_MAXP	1024
+#define MTU3_U2IP_EP_FIFO_UNIT	\
+	((USB_HS_MAXP) * ((MTU3_U2_IP_SLOT_DEFAULT) + 1))
+#define MTU3_U3IP_EP_FIFO_UNIT	\
+	((USB_SS_MAXP) * ((MTU3_U3_IP_SLOT_DEFAULT) + 1))
+
+#define MTU3_FIFO_BIT_SIZE		32
+#define MTU3_U2_IP_EP0_FIFO_SIZE	64
+
+/**
+ * Maximum size of ep0 response buffer for ch9 requests,
+ * the SET_SEL request uses 6 so far, and GET_STATUS is 2
+ */
+#define EP0_RESPONSE_BUF  6
+
+/* device operated link and speed got from DEVICE_CONF register */
+enum mtu3_speed {
+	MTU3_SPEED_INACTIVE = 0,
+	MTU3_SPEED_FULL = 1,
+	MTU3_SPEED_HIGH = 3,
+	MTU3_SPEED_SUPER = 4,
+	MTU3_SPEED_SUPER_PLUS = 5,
+};
+
+/**
+ * @MU3D_EP0_STATE_SETUP: waits for SETUP or received a SETUP
+ *		without data stage.
+ * @MU3D_EP0_STATE_TX: IN data stage
+ * @MU3D_EP0_STATE_RX: OUT data stage
+ * @MU3D_EP0_STATE_TX_END: the last IN data is transferred, and
+ *		waits for its completion interrupt
+ * @MU3D_EP0_STATE_STALL: ep0 is in stall status, will be auto-cleared
+ *		after receives a SETUP.
+ */
+enum mtu3_g_ep0_state {
+	MU3D_EP0_STATE_SETUP = 1,
+	MU3D_EP0_STATE_TX,
+	MU3D_EP0_STATE_RX,
+	MU3D_EP0_STATE_TX_END,
+	MU3D_EP0_STATE_STALL,
+};
+
+/**
+ * MTU3_DR_FORCE_NONE: automatically switch host and peripheral mode
+ *		by IDPIN signal.
+ * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
+ *		IDPIN signal.
+ * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
+ */
+enum mtu3_dr_force_mode {
+	MTU3_DR_FORCE_NONE = 0,
+	MTU3_DR_FORCE_HOST,
+	MTU3_DR_FORCE_DEVICE,
+};
+
+/**
+ * @mac_base: register base address of MAC, include xHCI and device
+ * @ippc_base: register base address of IP Power and Clock interface (IPPC)
+ * @vusb33_supply: usb3.3V shared by device/host IP
+ * @vbus_supply: vbus 5v of OTG port
+ * @clks: optional clocks, include "sys_ck", "ref_ck", "mcu_ck",
+ *		"dma_ck" and "xhci_ck"
+ * @phys: phys used
+ * @dr_mode: works in which mode:
+ *		host only, device only or dual-role mode
+ */
+struct ssusb_mtk {
+	struct udevice *dev;
+	struct mtu3 *u3d;
+	struct mtu3_host *u3h;
+	void __iomem *mac_base;
+	void __iomem *ippc_base;
+	/* common power & clock */
+	struct udevice *vusb33_supply;
+	struct udevice *vbus_supply;
+	struct clk_bulk clks;
+	struct phy_bulk phys;
+	/* otg */
+	enum usb_dr_mode dr_mode;
+};
+
+/**
+ * @ctrl: xHCI controller, needs to come first in this struct!
+ * @hcd: xHCI's register base address
+ * @u2_ports: number of usb2 host ports
+ * @u3_ports: number of usb3 host ports
+ * @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
+ *		disable u3port0, bit1==1 to disable u3port1,... etc
+ */
+struct mtu3_host {
+	struct xhci_ctrl ctrl;
+	struct xhci_hccr *hcd;
+	void __iomem *ippc_base;
+	struct ssusb_mtk *ssusb;
+	struct udevice *dev;
+	u32 u2_ports;
+	u32 u3_ports;
+	u32 u3p_dis_msk;
+};
+
+/**
+ * @base: the base address of fifo
+ * @limit: the bitmap size in bits
+ * @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
+ */
+struct mtu3_fifo_info {
+	u32 base;
+	u32 limit;
+	DECLARE_BITMAP(bitmap, MTU3_FIFO_BIT_SIZE);
+};
+
+/**
+ * General Purpose Descriptor (GPD):
+ *	The format of TX GPD is a little different from RX one.
+ *	And the size of GPD is 16 bytes.
+ *
+ * @flag:
+ *	bit0: Hardware Own (HWO)
+ *	bit1: Buffer Descriptor Present (BDP), always 0, BD is not supported
+ *	bit2: Bypass (BPS), 1: HW skips this GPD if HWO = 1
+ *	bit7: Interrupt On Completion (IOC)
+ * @chksum: This is used to validate the contents of this GPD;
+ *	If TXQ_CS_EN / RXQ_CS_EN bit is set, an interrupt is issued
+ *	when checksum validation fails;
+ *	Checksum value is calculated over the 16 bytes of the GPD by default;
+ * @data_buf_len (RX ONLY): This value indicates the length of
+ *	the assigned data buffer
+ * @next_gpd: Physical address of the next GPD
+ * @buffer: Physical address of the data buffer
+ * @buf_len:
+ *	(TX): This value indicates the length of the assigned data buffer
+ *	(RX): The total length of data received
+ * @ext_len: reserved
+ * @ext_flag:
+ *	bit5 (TX ONLY): Zero Length Packet (ZLP),
+ */
+struct qmu_gpd {
+	__u8 flag;
+	__u8 chksum;
+	__le16 data_buf_len;
+	__le32 next_gpd;
+	__le32 buffer;
+	__le16 buf_len;
+	__u8 ext_len;
+	__u8 ext_flag;
+} __packed;
+
+/**
+ * dma: physical base address of GPD segment
+ * start: virtual base address of GPD segment
+ * end: the last GPD element
+ * enqueue: the first empty GPD to use
+ * dequeue: the first completed GPD serviced by ISR
+ * NOTE: the size of GPD ring should be >= 2
+ */
+struct mtu3_gpd_ring {
+	dma_addr_t dma;
+	struct qmu_gpd *start;
+	struct qmu_gpd *end;
+	struct qmu_gpd *enqueue;
+	struct qmu_gpd *dequeue;
+};
+
+/**
+ * @fifo_size: it is (@slot + 1) * @fifo_seg_size
+ * @fifo_seg_size: it is roundup_pow_of_two(@maxp)
+ */
+struct mtu3_ep {
+	struct usb_ep ep;
+	char name[12];
+	struct mtu3 *mtu;
+	u8 epnum;
+	u8 type;
+	u8 is_in;
+	u16 maxp;
+	int slot;
+	u32 fifo_size;
+	u32 fifo_addr;
+	u32 fifo_seg_size;
+	struct mtu3_fifo_info *fifo;
+
+	struct list_head req_list;
+	struct mtu3_gpd_ring gpd_ring;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	const struct usb_endpoint_descriptor *desc;
+
+	int flags;
+};
+
+struct mtu3_request {
+	struct usb_request request;
+	struct list_head list;
+	struct mtu3_ep *mep;
+	struct mtu3 *mtu;
+	struct qmu_gpd *gpd;
+	int epnum;
+};
+
+static inline struct ssusb_mtk *dev_to_ssusb(struct udevice *dev)
+{
+	return dev_get_priv(dev);
+}
+
+/**
+ * struct mtu3 - device driver instance data.
+ * @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP only,
+ *		MTU3_U3_IP_SLOT_DEFAULT for U3 IP
+ * @may_wakeup: means device's remote wakeup is enabled
+ * @is_self_powered: is reported in device status and the config descriptor
+ * @delayed_status: true when function drivers ask for delayed status
+ * @gen2cp: compatible with USB3 Gen2 IP
+ * @ep0_req: dummy request used while handling standard USB requests
+ *		for GET_STATUS and SET_SEL
+ * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests
+ */
+struct mtu3 {
+	spinlock_t lock;
+	struct ssusb_mtk *ssusb;
+	struct udevice *dev;
+	void __iomem *mac_base;
+	void __iomem *ippc_base;
+	int irq;
+
+	struct mtu3_fifo_info tx_fifo;
+	struct mtu3_fifo_info rx_fifo;
+
+	struct mtu3_ep *ep_array;
+	struct mtu3_ep *in_eps;
+	struct mtu3_ep *out_eps;
+	struct mtu3_ep *ep0;
+	int num_eps;
+	int slot;
+	int active_ep;
+
+	enum mtu3_g_ep0_state ep0_state;
+	struct usb_gadget g;	/* the gadget */
+	struct usb_gadget_driver *gadget_driver;
+	struct mtu3_request ep0_req;
+	u8 setup_buf[EP0_RESPONSE_BUF];
+	enum usb_device_speed max_speed;
+	enum usb_device_speed speed;
+
+	unsigned is_active:1;
+	unsigned may_wakeup:1;
+	unsigned is_self_powered:1;
+	unsigned test_mode:1;
+	unsigned softconnect:1;
+	unsigned u1_enable:1;
+	unsigned u2_enable:1;
+	unsigned is_u3_ip:1;
+	unsigned delayed_status:1;
+	unsigned gen2cp:1;
+	unsigned force_vbus:1;
+
+	u8 address;
+	u8 test_mode_nr;
+	u32 hw_version;
+};
+
+static inline struct mtu3 *gadget_to_mtu3(struct usb_gadget *g)
+{
+	return container_of(g, struct mtu3, g);
+}
+
+static inline int is_first_entry(const struct list_head *list,
+				 const struct list_head *head)
+{
+	return list_is_last(head, list);
+}
+
+static inline struct mtu3_request *to_mtu3_request(struct usb_request *req)
+{
+	return req ? container_of(req, struct mtu3_request, request) : NULL;
+}
+
+static inline struct mtu3_ep *to_mtu3_ep(struct usb_ep *ep)
+{
+	return ep ? container_of(ep, struct mtu3_ep, ep) : NULL;
+}
+
+static inline struct mtu3_request *next_request(struct mtu3_ep *mep)
+{
+	if (list_empty(&mep->req_list))
+		return NULL;
+
+	return list_first_entry(&mep->req_list, struct mtu3_request, list);
+}
+
+static inline void mtu3_writel(void __iomem *base, u32 offset, u32 data)
+{
+	writel(data, base + offset);
+}
+
+static inline u32 mtu3_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void mtu3_setbits(void __iomem *base, u32 offset, u32 bits)
+{
+	void __iomem *addr = base + offset;
+	u32 tmp = readl(addr);
+
+	writel((tmp | (bits)), addr);
+}
+
+static inline void mtu3_clrbits(void __iomem *base, u32 offset, u32 bits)
+{
+	void __iomem *addr = base + offset;
+	u32 tmp = readl(addr);
+
+	writel((tmp & ~(bits)), addr);
+}
+
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks);
+struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+void mtu3_free_request(struct usb_ep *ep, struct usb_request *req);
+void mtu3_req_complete(struct mtu3_ep *mep,
+		       struct usb_request *req, int status);
+
+int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+		   int interval, int burst, int mult);
+void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep);
+void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set);
+void mtu3_ep0_setup(struct mtu3 *mtu);
+void mtu3_start(struct mtu3 *mtu);
+void mtu3_stop(struct mtu3 *mtu);
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on);
+void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed);
+
+int mtu3_gadget_setup(struct mtu3 *mtu);
+void mtu3_gadget_cleanup(struct mtu3 *mtu);
+void mtu3_gadget_reset(struct mtu3 *mtu);
+void mtu3_gadget_suspend(struct mtu3 *mtu);
+void mtu3_gadget_resume(struct mtu3 *mtu);
+void mtu3_gadget_disconnect(struct mtu3 *mtu);
+
+irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu);
+extern const struct usb_ep_ops mtu3_ep0_ops;
+
+#endif
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
new file mode 100644
index 0000000..28136f8
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -0,0 +1,838 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_core.c - hardware access layer and gadget init/exit of
+ *                     MediaTek usb3 Dual-Role Controller Driver
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/log2.h>
+#include <linux/bitmap.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size)
+{
+	struct mtu3_fifo_info *fifo = mep->fifo;
+	struct mtu3 *mtu = mep->mtu;
+	u32 fz_bit;
+
+	mep->fifo_seg_size = mtu->is_u3_ip ? USB_SS_MAXP : USB_HS_MAXP;
+
+	fz_bit = find_first_zero_bit(fifo->bitmap, fifo->limit);
+	if (fz_bit >= fifo->limit)
+		return -EOVERFLOW;
+
+	mep->fifo_size = mep->fifo_seg_size * (mep->slot + 1);
+	mep->fifo_addr = fifo->base + mep->fifo_size * fz_bit;
+	generic_set_bit(fz_bit, fifo->bitmap);
+
+	dev_dbg(mep->mtu->dev, "%s fifo:%#x/%#x, bit: %d\n",
+		__func__, mep->fifo_seg_size, mep->fifo_size, fz_bit);
+
+	return mep->fifo_addr;
+}
+
+static void ep_fifo_free(struct mtu3_ep *mep)
+{
+	struct mtu3_fifo_info *fifo = mep->fifo;
+	u32 addr = mep->fifo_addr;
+	u32 bit;
+
+	if (unlikely(addr < fifo->base))
+		return;
+
+	bit = (addr - fifo->base) / mep->fifo_size;
+	generic_clear_bit(bit, fifo->bitmap);
+	mep->fifo_size = 0;
+	mep->fifo_seg_size = 0;
+
+	dev_dbg(mep->mtu->dev, "%s size:%#x/%#x, bit: %d\n",
+		__func__, mep->fifo_seg_size, mep->fifo_size, bit);
+}
+
+/* enable/disable U3D SS function */
+static inline void mtu3_ss_func_set(struct mtu3 *mtu, bool enable)
+{
+	/* If usb3_en==0, LTSSM will go to SS.Disable state */
+	if (enable)
+		mtu3_setbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+	else
+		mtu3_clrbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+
+	dev_dbg(mtu->dev, "USB3_EN = %d\n", !!enable);
+}
+
+/* set/clear U3D HS device soft connect */
+static inline void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable)
+{
+	if (enable) {
+		mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
+			     SOFT_CONN | SUSPENDM_ENABLE);
+	} else {
+		mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
+			     SOFT_CONN | SUSPENDM_ENABLE);
+	}
+	dev_dbg(mtu->dev, "SOFTCONN = %d\n", !!enable);
+}
+
+/* only port0 of U2/U3 supports device mode */
+static int mtu3_device_enable(struct mtu3 *mtu)
+{
+	void __iomem *ibase = mtu->ippc_base;
+	u32 check_clk = 0;
+
+	mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+
+	if (mtu->is_u3_ip) {
+		check_clk = SSUSB_U3_MAC_RST_B_STS;
+		mtu3_clrbits(ibase, SSUSB_U3_CTRL(0),
+			     (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN |
+			      SSUSB_U3_PORT_HOST_SEL));
+	}
+	mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
+		     (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
+		      SSUSB_U2_PORT_HOST_SEL));
+
+	return ssusb_check_clocks(mtu->ssusb, check_clk);
+}
+
+static void mtu3_device_disable(struct mtu3 *mtu)
+{
+	void __iomem *ibase = mtu->ippc_base;
+
+	if (mtu->is_u3_ip)
+		mtu3_setbits(ibase, SSUSB_U3_CTRL(0),
+			     (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN));
+
+	mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
+		     SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
+
+	mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+}
+
+/* reset U3D's device module. */
+static void mtu3_device_reset(struct mtu3 *mtu)
+{
+	void __iomem *ibase = mtu->ippc_base;
+
+	mtu3_setbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST);
+	udelay(1);
+	mtu3_clrbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST);
+}
+
+static void mtu3_intr_status_clear(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	/* Clear EP0 and Tx/Rx EPn interrupts status */
+	mtu3_writel(mbase, U3D_EPISR, ~0x0);
+	/* Clear U2 USB common interrupts status */
+	mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);
+	/* Clear U3 LTSSM interrupts status */
+	mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);
+	/* Clear speed change interrupt status */
+	mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
+	/* Clear QMU interrupt status */
+	mtu3_writel(mbase, U3D_QISAR0, ~0x0);
+}
+
+/* disable all interrupts */
+static void mtu3_intr_disable(struct mtu3 *mtu)
+{
+	/* Disable level 1 interrupts */
+	mtu3_writel(mtu->mac_base, U3D_LV1IECR, ~0x0);
+	/* Disable endpoint interrupts */
+	mtu3_writel(mtu->mac_base, U3D_EPIECR, ~0x0);
+	mtu3_intr_status_clear(mtu);
+}
+
+/* enable system global interrupt */
+static void mtu3_intr_enable(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 value;
+
+	/*Enable level 1 interrupts (BMU, QMU, MAC3, DMA, MAC2, EPCTL) */
+	value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR;
+	mtu3_writel(mbase, U3D_LV1IESR, value);
+
+	/* Enable U2 common USB interrupts */
+	value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
+	mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value);
+
+	if (mtu->is_u3_ip) {
+		/* Enable U3 LTSSM interrupts */
+		value = HOT_RST_INTR | WARM_RST_INTR |
+			ENTER_U3_INTR | EXIT_U3_INTR;
+		mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value);
+	}
+
+	/* Enable QMU interrupts. */
+	value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT |
+			RXQ_LENERR_INT | RXQ_ZLPERR_INT;
+	mtu3_writel(mbase, U3D_QIESR1, value);
+
+	/* Enable speed change interrupt */
+	mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR);
+}
+
+void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	if (speed > mtu->max_speed)
+		speed = mtu->max_speed;
+
+	switch (speed) {
+	case USB_SPEED_FULL:
+		/* disable U3 SS function */
+		mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+		/* disable HS function */
+		mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+		break;
+	case USB_SPEED_HIGH:
+		mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+		/* HS/FS detected by HW */
+		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+		break;
+	case USB_SPEED_SUPER:
+		mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+			     SSUSB_U3_PORT_SSP_SPEED);
+		break;
+	case USB_SPEED_SUPER_PLUS:
+		mtu3_setbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+			     SSUSB_U3_PORT_SSP_SPEED);
+		break;
+	default:
+		dev_err(mtu->dev, "invalid speed: %d\n", speed);
+		return;
+	}
+
+	mtu->speed = speed;
+	dev_dbg(mtu->dev, "set speed: %s\n", usb_speed_string(mtu->speed));
+}
+
+/* reset: u2 - data toggle, u3 - SeqN, flow control status etc */
+static void mtu3_ep_reset(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	u32 rst_bit = EP_RST(mep->is_in, mep->epnum);
+
+	mtu3_setbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+	mtu3_clrbits(mtu->mac_base, U3D_EP_RST, rst_bit);
+}
+
+/* set/clear the stall and toggle bits for non-ep0 */
+void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	u8 epnum = mep->epnum;
+	u32 csr;
+
+	if (mep->is_in) {	/* TX */
+		csr = mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)) & TX_W1C_BITS;
+		if (set)
+			csr |= TX_SENDSTALL;
+		else
+			csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL;
+		mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr);
+	} else {	/* RX */
+		csr = mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)) & RX_W1C_BITS;
+		if (set)
+			csr |= RX_SENDSTALL;
+		else
+			csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL;
+		mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr);
+	}
+
+	if (!set) {
+		mtu3_ep_reset(mep);
+		mep->flags &= ~MTU3_EP_STALL;
+	} else {
+		mep->flags |= MTU3_EP_STALL;
+	}
+
+	dev_dbg(mtu->dev, "%s: %s\n", mep->name,
+		set ? "SEND STALL" : "CLEAR STALL, with EP RESET");
+}
+
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
+{
+	if (mtu->is_u3_ip && mtu->speed >= USB_SPEED_SUPER)
+		mtu3_ss_func_set(mtu, is_on);
+	else
+		mtu3_hs_softconn_set(mtu, is_on);
+
+	dev_info(mtu->dev, "gadget (%s) pullup D%s\n",
+		 usb_speed_string(mtu->speed), is_on ? "+" : "-");
+}
+
+void mtu3_start(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	dev_dbg(mtu->dev, "%s devctl 0x%x\n", __func__,
+		mtu3_readl(mbase, U3D_DEVICE_CONTROL));
+
+	/* Initialize the default interrupts */
+	mtu3_intr_enable(mtu);
+	mtu->is_active = 1;
+
+	if (mtu->softconnect)
+		mtu3_dev_on_off(mtu, 1);
+}
+
+void mtu3_stop(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	mtu3_intr_disable(mtu);
+
+	if (mtu->softconnect)
+		mtu3_dev_on_off(mtu, 0);
+
+	mtu->is_active = 0;
+}
+
+/* for non-ep0 */
+int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+		   int interval, int burst, int mult)
+{
+	void __iomem *mbase = mtu->mac_base;
+	bool gen2cp = mtu->gen2cp;
+	int epnum = mep->epnum;
+	u32 csr0, csr1, csr2;
+	int fifo_sgsz, fifo_addr;
+	int num_pkts;
+
+	fifo_addr = ep_fifo_alloc(mep, mep->maxp);
+	if (fifo_addr < 0) {
+		dev_err(mtu->dev, "alloc ep fifo failed(%d)\n", mep->maxp);
+		return -ENOMEM;
+	}
+	fifo_sgsz = ilog2(mep->fifo_seg_size);
+	dev_dbg(mtu->dev, "%s fifosz: %x(%x/%x)\n", __func__, fifo_sgsz,
+		mep->fifo_seg_size, mep->fifo_size);
+
+	if (mep->is_in) {
+		csr0 = TX_TXMAXPKTSZ(mep->maxp);
+		csr0 |= TX_DMAREQEN;
+
+		num_pkts = (burst + 1) * (mult + 1) - 1;
+		csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot);
+		csr1 |= TX_MAX_PKT(gen2cp, num_pkts) | TX_MULT(gen2cp, mult);
+
+		csr2 = TX_FIFOADDR(fifo_addr >> 4);
+		csr2 |= TX_FIFOSEGSIZE(fifo_sgsz);
+
+		switch (mep->type) {
+		case USB_ENDPOINT_XFER_BULK:
+			csr1 |= TX_TYPE(TYPE_BULK);
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			csr1 |= TX_TYPE(TYPE_ISO);
+			csr2 |= TX_BINTERVAL(interval);
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			csr1 |= TX_TYPE(TYPE_INT);
+			csr2 |= TX_BINTERVAL(interval);
+			break;
+		}
+
+		/* Enable QMU Done interrupt */
+		mtu3_setbits(mbase, U3D_QIESR0, QMU_TX_DONE_INT(epnum));
+
+		mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr0);
+		mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), csr1);
+		mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), csr2);
+
+		dev_dbg(mtu->dev, "U3D_TX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n",
+			epnum, mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)),
+			mtu3_readl(mbase, MU3D_EP_TXCR1(epnum)),
+			mtu3_readl(mbase, MU3D_EP_TXCR2(epnum)));
+	} else {
+		csr0 = RX_RXMAXPKTSZ(mep->maxp);
+		csr0 |= RX_DMAREQEN;
+
+		num_pkts = (burst + 1) * (mult + 1) - 1;
+		csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot);
+		csr1 |= RX_MAX_PKT(gen2cp, num_pkts) | RX_MULT(gen2cp, mult);
+
+		csr2 = RX_FIFOADDR(fifo_addr >> 4);
+		csr2 |= RX_FIFOSEGSIZE(fifo_sgsz);
+
+		switch (mep->type) {
+		case USB_ENDPOINT_XFER_BULK:
+			csr1 |= RX_TYPE(TYPE_BULK);
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			csr1 |= RX_TYPE(TYPE_ISO);
+			csr2 |= RX_BINTERVAL(interval);
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			csr1 |= RX_TYPE(TYPE_INT);
+			csr2 |= RX_BINTERVAL(interval);
+			break;
+		}
+
+		/*Enable QMU Done interrupt */
+		mtu3_setbits(mbase, U3D_QIESR0, QMU_RX_DONE_INT(epnum));
+
+		mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr0);
+		mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), csr1);
+		mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), csr2);
+
+		dev_dbg(mtu->dev, "U3D_RX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n",
+			epnum, mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)),
+			mtu3_readl(mbase, MU3D_EP_RXCR1(epnum)),
+			mtu3_readl(mbase, MU3D_EP_RXCR2(epnum)));
+	}
+
+	dev_dbg(mtu->dev, "csr0:%#x, csr1:%#x, csr2:%#x\n", csr0, csr1, csr2);
+	dev_dbg(mtu->dev, "%s: %s, fifo-addr:%#x, fifo-size:%#x(%#x/%#x)\n",
+		__func__, mep->name, mep->fifo_addr, mep->fifo_size,
+		fifo_sgsz, mep->fifo_seg_size);
+
+	return 0;
+}
+
+/* for non-ep0 */
+void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep)
+{
+	void __iomem *mbase = mtu->mac_base;
+	int epnum = mep->epnum;
+
+	if (mep->is_in) {
+		mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), 0);
+		mtu3_setbits(mbase, U3D_QIECR0, QMU_TX_DONE_INT(epnum));
+	} else {
+		mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), 0);
+		mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), 0);
+		mtu3_setbits(mbase, U3D_QIECR0, QMU_RX_DONE_INT(epnum));
+	}
+
+	mtu3_ep_reset(mep);
+	ep_fifo_free(mep);
+
+	dev_dbg(mtu->dev, "%s: %s\n", __func__, mep->name);
+}
+
+/*
+ * Two scenarios:
+ * 1. when device IP supports SS, the fifo of EP0, TX EPs, RX EPs
+ *	are separated;
+ * 2. when supports only HS, the fifo is shared for all EPs, and
+ *	the capability registers of @EPNTXFFSZ or @EPNRXFFSZ indicate
+ *	the total fifo size of non-ep0, and ep0's is fixed to 64B,
+ *	so the total fifo size is 64B + @EPNTXFFSZ;
+ *	Due to the first 64B should be reserved for EP0, non-ep0's fifo
+ *	starts from offset 64 and are divided into two equal parts for
+ *	TX or RX EPs for simplification.
+ */
+static void get_ep_fifo_config(struct mtu3 *mtu)
+{
+	struct mtu3_fifo_info *tx_fifo;
+	struct mtu3_fifo_info *rx_fifo;
+	u32 fifosize;
+
+	if (mtu->is_u3_ip) {
+		fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+		tx_fifo = &mtu->tx_fifo;
+		tx_fifo->base = 0;
+		tx_fifo->limit = fifosize / MTU3_U3IP_EP_FIFO_UNIT;
+		bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+		fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNRXFFSZ);
+		rx_fifo = &mtu->rx_fifo;
+		rx_fifo->base = 0;
+		rx_fifo->limit = fifosize / MTU3_U3IP_EP_FIFO_UNIT;
+		bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+		mtu->slot = MTU3_U3_IP_SLOT_DEFAULT;
+	} else {
+		fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+		tx_fifo = &mtu->tx_fifo;
+		tx_fifo->base = MTU3_U2_IP_EP0_FIFO_SIZE;
+		tx_fifo->limit = (fifosize / MTU3_U2IP_EP_FIFO_UNIT) >> 1;
+		bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+		rx_fifo = &mtu->rx_fifo;
+		rx_fifo->base = tx_fifo->base +
+				tx_fifo->limit * MTU3_U2IP_EP_FIFO_UNIT;
+		rx_fifo->limit = tx_fifo->limit;
+		bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+		mtu->slot = MTU3_U2_IP_SLOT_DEFAULT;
+	}
+
+	dev_dbg(mtu->dev, "%s, TX: base-%d, limit-%d; RX: base-%d, limit-%d\n",
+		__func__, tx_fifo->base, tx_fifo->limit,
+		rx_fifo->base, rx_fifo->limit);
+}
+
+void mtu3_ep0_setup(struct mtu3 *mtu)
+{
+	u32 maxpacket = mtu->g.ep0->maxpacket;
+	u32 csr;
+
+	dev_dbg(mtu->dev, "%s maxpacket: %d\n", __func__, maxpacket);
+
+	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR);
+	csr &= ~EP0_MAXPKTSZ_MSK;
+	csr |= EP0_MAXPKTSZ(maxpacket);
+	csr &= EP0_W1C_BITS;
+	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
+
+	/* Enable EP0 interrupt */
+	mtu3_writel(mtu->mac_base, U3D_EPIESR, EP0ISR | SETUPENDISR);
+}
+
+static int mtu3_mem_alloc(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	struct mtu3_ep *ep_array;
+	int in_ep_num, out_ep_num;
+	u32 cap_epinfo;
+	int i;
+
+	cap_epinfo = mtu3_readl(mbase, U3D_CAP_EPINFO);
+	in_ep_num = CAP_TX_EP_NUM(cap_epinfo);
+	out_ep_num = CAP_RX_EP_NUM(cap_epinfo);
+
+	dev_info(mtu->dev, "fifosz/epnum: Tx=%#x/%d, Rx=%#x/%d\n",
+		 mtu3_readl(mbase, U3D_CAP_EPNTXFFSZ), in_ep_num,
+		 mtu3_readl(mbase, U3D_CAP_EPNRXFFSZ), out_ep_num);
+
+	/* one for ep0, another is reserved */
+	mtu->num_eps = min(in_ep_num, out_ep_num) + 1;
+	ep_array = kcalloc(mtu->num_eps * 2, sizeof(*ep_array), GFP_KERNEL);
+	if (!ep_array)
+		return -ENOMEM;
+
+	mtu->ep_array = ep_array;
+	mtu->in_eps = ep_array;
+	mtu->out_eps = &ep_array[mtu->num_eps];
+	/* ep0 uses in_eps[0], out_eps[0] is reserved */
+	mtu->ep0 = mtu->in_eps;
+	mtu->ep0->mtu = mtu;
+	mtu->ep0->epnum = 0;
+
+	for (i = 1; i < mtu->num_eps; i++) {
+		struct mtu3_ep *mep = mtu->in_eps + i;
+
+		mep->fifo = &mtu->tx_fifo;
+		mep = mtu->out_eps + i;
+		mep->fifo = &mtu->rx_fifo;
+	}
+
+	get_ep_fifo_config(mtu);
+	mtu3_qmu_init(mtu);
+
+	return 0;
+}
+
+static void mtu3_mem_free(struct mtu3 *mtu)
+{
+	mtu3_qmu_exit(mtu);
+	kfree(mtu->ep_array);
+}
+
+static void mtu3_regs_init(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+
+	/* be sure interrupts are disabled before registration of ISR */
+	mtu3_intr_disable(mtu);
+
+	if (mtu->is_u3_ip) {
+		/* disable LGO_U1/U2 by default */
+		mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL,
+			     SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE);
+		/* enable accept LGO_U1/U2 link command from host */
+		mtu3_setbits(mbase, U3D_LINK_POWER_CONTROL,
+			     SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE);
+		/* device responses to u3_exit from host automatically */
+		mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN);
+		/* automatically build U2 link when U3 detect fail */
+		mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH);
+		/* auto clear SOFT_CONN when clear USB3_EN if work as HS */
+		mtu3_setbits(mbase, U3D_U3U2_SWITCH_CTRL, SOFTCON_CLR_AUTO_EN);
+	}
+
+	/* delay about 0.1us from detecting reset to send chirp-K */
+	mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
+	/* U2/U3 detected by HW */
+	mtu3_writel(mbase, U3D_DEVICE_CONF, 0);
+	/* enable automatical HWRW from L1 */
+	mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE);
+
+	mtu3_set_speed(mtu, mtu->max_speed);
+	ssusb_set_force_mode(mtu->ssusb, MTU3_DR_FORCE_DEVICE);
+
+	if (mtu->force_vbus)
+		mtu3_setbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
+	else	/* vbus detected by HW */
+		mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
+}
+
+static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	enum usb_device_speed udev_speed;
+	u32 maxpkt = 64;
+	u32 link;
+	u32 speed;
+
+	link = mtu3_readl(mbase, U3D_DEV_LINK_INTR);
+	link &= mtu3_readl(mbase, U3D_DEV_LINK_INTR_ENABLE);
+	mtu3_writel(mbase, U3D_DEV_LINK_INTR, link); /* W1C */
+	dev_dbg(mtu->dev, "=== LINK[%x] ===\n", link);
+
+	if (!(link & SSUSB_DEV_SPEED_CHG_INTR))
+		return IRQ_NONE;
+
+	speed = SSUSB_DEV_SPEED(mtu3_readl(mbase, U3D_DEVICE_CONF));
+
+	switch (speed) {
+	case MTU3_SPEED_FULL:
+		udev_speed = USB_SPEED_FULL;
+		/*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */
+		mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf)
+			    | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa));
+		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
+			     LPM_BESL_STALL | LPM_BESLD_STALL);
+		break;
+	case MTU3_SPEED_HIGH:
+		udev_speed = USB_SPEED_HIGH;
+		/*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */
+		mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf)
+			    | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa));
+		mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
+			     LPM_BESL_STALL | LPM_BESLD_STALL);
+		break;
+	case MTU3_SPEED_SUPER:
+		udev_speed = USB_SPEED_SUPER;
+		maxpkt = 512;
+		break;
+	case MTU3_SPEED_SUPER_PLUS:
+		udev_speed = USB_SPEED_SUPER_PLUS;
+		maxpkt = 512;
+		break;
+	default:
+		udev_speed = USB_SPEED_UNKNOWN;
+		break;
+	}
+	dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed));
+
+	mtu->g.speed = udev_speed;
+	mtu->g.ep0->maxpacket = maxpkt;
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+	if (udev_speed == USB_SPEED_UNKNOWN)
+		mtu3_gadget_disconnect(mtu);
+	else
+		mtu3_ep0_setup(mtu);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 ltssm;
+
+	ltssm = mtu3_readl(mbase, U3D_LTSSM_INTR);
+	ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE);
+	mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */
+	dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm);
+
+	if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
+		mtu3_gadget_reset(mtu);
+
+	if (ltssm & VBUS_FALL_INTR) {
+		mtu3_ss_func_set(mtu, false);
+		mtu3_gadget_reset(mtu);
+	}
+
+	if (ltssm & VBUS_RISE_INTR)
+		mtu3_ss_func_set(mtu, true);
+
+	if (ltssm & EXIT_U3_INTR)
+		mtu3_gadget_resume(mtu);
+
+	if (ltssm & ENTER_U3_INTR)
+		mtu3_gadget_suspend(mtu);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 u2comm;
+
+	u2comm = mtu3_readl(mbase, U3D_COMMON_USB_INTR);
+	u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE);
+	mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */
+	dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm);
+
+	if (u2comm & SUSPEND_INTR)
+		mtu3_gadget_suspend(mtu);
+
+	if (u2comm & RESUME_INTR)
+		mtu3_gadget_resume(mtu);
+
+	if (u2comm & RESET_INTR)
+		mtu3_gadget_reset(mtu);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t mtu3_irq(int irq, void *data)
+{
+	struct mtu3 *mtu = (struct mtu3 *)data;
+	unsigned long flags;
+	u32 level1;
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	/* U3D_LV1ISR is RU */
+	level1 = mtu3_readl(mtu->mac_base, U3D_LV1ISR);
+	level1 &= mtu3_readl(mtu->mac_base, U3D_LV1IER);
+
+	if (level1 & EP_CTRL_INTR)
+		mtu3_link_isr(mtu);
+
+	if (level1 & MAC2_INTR)
+		mtu3_u2_common_isr(mtu);
+
+	if (level1 & MAC3_INTR)
+		mtu3_u3_ltssm_isr(mtu);
+
+	if (level1 & BMU_INTR)
+		mtu3_ep0_isr(mtu);
+
+	if (level1 & QMU_INTR)
+		mtu3_qmu_isr(mtu);
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void mtu3_check_params(struct mtu3 *mtu)
+{
+	/* check the max_speed parameter */
+	switch (mtu->max_speed) {
+	case USB_SPEED_FULL:
+	case USB_SPEED_HIGH:
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		break;
+	default:
+		dev_err(mtu->dev, "invalid max_speed: %d\n", mtu->max_speed);
+		/* fall through */
+	case USB_SPEED_UNKNOWN:
+		/* default as SS */
+		mtu->max_speed = USB_SPEED_SUPER;
+		break;
+	}
+
+	if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH))
+		mtu->max_speed = USB_SPEED_HIGH;
+
+	mtu->speed = mtu->max_speed;
+
+	dev_info(mtu->dev, "max_speed: %s\n", usb_speed_string(mtu->speed));
+}
+
+static int mtu3_hw_init(struct mtu3 *mtu)
+{
+	u32 value;
+	int ret;
+
+	value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_TRUNK_VERS);
+	mtu->hw_version = IP_TRUNK_VERS(value);
+	mtu->gen2cp = !!(mtu->hw_version >= MTU3_TRUNK_VERS_1003);
+
+	value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
+	mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value);
+
+	dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version,
+		 mtu->is_u3_ip ? "U3" : "U2");
+
+	mtu3_check_params(mtu);
+
+	mtu3_device_reset(mtu);
+
+	ret = mtu3_device_enable(mtu);
+	if (ret) {
+		dev_err(mtu->dev, "device enable failed %d\n", ret);
+		return ret;
+	}
+
+	ret = mtu3_mem_alloc(mtu);
+	if (ret)
+		return ret;
+
+	mtu3_regs_init(mtu);
+
+	return 0;
+}
+
+static void mtu3_hw_exit(struct mtu3 *mtu)
+{
+	mtu3_device_disable(mtu);
+	mtu3_mem_free(mtu);
+}
+
+int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+	struct mtu3 *mtu = ssusb->u3d;
+	struct udevice *dev = mtu->dev;
+	int ret = -ENOMEM;
+
+	spin_lock_init(&mtu->lock);
+	mtu->ippc_base = ssusb->ippc_base;
+	mtu->mac_base = ssusb->mac_base;
+	mtu->ssusb = ssusb;
+	mtu->max_speed = usb_get_maximum_speed(dev->node);
+	mtu->force_vbus = dev_read_bool(dev, "mediatek,force-vbus");
+
+	ret = mtu3_hw_init(mtu);
+	if (ret) {
+		dev_err(dev, "mtu3 hw init failed:%d\n", ret);
+		return ret;
+	}
+
+	ret = mtu3_gadget_setup(mtu);
+	if (ret) {
+		dev_err(dev, "mtu3 gadget init failed:%d\n", ret);
+		goto gadget_err;
+	}
+
+	dev_info(dev, "%s() done...\n", __func__);
+
+	return 0;
+
+gadget_err:
+	mtu3_hw_exit(mtu);
+	ssusb->u3d = NULL;
+	dev_err(dev, "%s() fail...\n", __func__);
+
+	return ret;
+}
+
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{
+	struct mtu3 *mtu = ssusb->u3d;
+
+	mtu3_gadget_cleanup(mtu);
+	mtu3_hw_exit(mtu);
+}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
new file mode 100644
index 0000000..ec0e50c
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_dr.h - dual role switch and host glue layer header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef _MTU3_DR_H_
+#define _MTU3_DR_H_
+
+#if IS_ENABLED(CONFIG_USB_MTU3_HOST)
+
+int ssusb_host_init(struct ssusb_mtk *ssusb);
+void ssusb_host_exit(struct ssusb_mtk *ssusb);
+
+#else
+
+static inline int ssusb_host_init(struct ssusb_mtk *ssusb)
+{
+	return 0;
+}
+
+static inline void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{}
+
+#endif
+
+#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
+int ssusb_gadget_init(struct ssusb_mtk *ssusb);
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
+irqreturn_t mtu3_irq(int irq, void *data);
+#else
+static inline int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+	return 0;
+}
+
+static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{}
+
+static inline irqreturn_t mtu3_irq(int irq, void *data)
+{
+	return IRQ_NONE;
+}
+#endif
+
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+			  enum mtu3_dr_force_mode mode);
+
+#endif		/* _MTU3_DR_H_ */
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
new file mode 100644
index 0000000..027b7e6
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -0,0 +1,686 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_gadget.c - MediaTek usb3 DRD peripheral support
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include "mtu3.h"
+
+void mtu3_req_complete(struct mtu3_ep *mep,
+		       struct usb_request *req, int status)
+__releases(mep->mtu->lock)
+__acquires(mep->mtu->lock)
+{
+	struct mtu3_request *mreq = to_mtu3_request(req);
+	struct mtu3 *mtu = mreq->mtu;
+
+	list_del(&mreq->list);
+	if (req->status == -EINPROGRESS)
+		req->status = status;
+
+	spin_unlock(&mtu->lock);
+
+	/* ep0 makes use of PIO, needn't unmap it */
+	if (mep->epnum)
+		usb_gadget_unmap_request(&mtu->g, req, mep->is_in);
+
+	dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n",
+		mep->name, req, req->status, req->actual, req->length);
+
+	usb_gadget_giveback_request(&mep->ep, req);
+	spin_lock(&mtu->lock);
+}
+
+static void nuke(struct mtu3_ep *mep, const int status)
+{
+	struct mtu3_request *mreq = NULL;
+
+	if (list_empty(&mep->req_list))
+		return;
+
+	dev_dbg(mep->mtu->dev, "abort %s's req: sts %d\n", mep->name, status);
+
+	/* exclude EP0 */
+	if (mep->epnum)
+		mtu3_qmu_flush(mep);
+
+	while (!list_empty(&mep->req_list)) {
+		mreq = list_first_entry(&mep->req_list,
+					struct mtu3_request, list);
+		mtu3_req_complete(mep, &mreq->request, status);
+	}
+}
+
+static int mtu3_ep_enable(struct mtu3_ep *mep)
+{
+	const struct usb_endpoint_descriptor *desc;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
+	struct mtu3 *mtu = mep->mtu;
+	u32 interval = 0;
+	u32 mult = 0;
+	u32 burst = 0;
+	int max_packet;
+	int ret;
+
+	desc = mep->desc;
+	comp_desc = mep->comp_desc;
+	mep->type = usb_endpoint_type(desc);
+	max_packet = usb_endpoint_maxp(desc);
+	mep->maxp = max_packet & GENMASK(10, 0);
+
+	switch (mtu->g.speed) {
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		if (usb_endpoint_xfer_int(desc) ||
+		    usb_endpoint_xfer_isoc(desc)) {
+			interval = desc->bInterval;
+			interval = clamp_val(interval, 1, 16) - 1;
+			if (usb_endpoint_xfer_isoc(desc) && comp_desc)
+				mult = comp_desc->bmAttributes;
+		}
+		if (comp_desc)
+			burst = comp_desc->bMaxBurst;
+
+		break;
+	case USB_SPEED_HIGH:
+		if (usb_endpoint_xfer_isoc(desc) ||
+		    usb_endpoint_xfer_int(desc)) {
+			interval = desc->bInterval;
+			interval = clamp_val(interval, 1, 16) - 1;
+			burst = (max_packet & GENMASK(12, 11)) >> 11;
+		}
+		break;
+	default:
+		break; /*others are ignored */
+	}
+
+	dev_dbg(mtu->dev, "%s maxp:%d, interval:%d, burst:%d, mult:%d\n",
+		__func__, mep->maxp, interval, burst, mult);
+
+	mep->ep.maxpacket = mep->maxp;
+	mep->ep.desc = desc;
+	mep->ep.comp_desc = comp_desc;
+	mep->slot = mtu->slot;
+
+	ret = mtu3_config_ep(mtu, mep, interval, burst, mult);
+	if (ret < 0)
+		return ret;
+
+	ret = mtu3_gpd_ring_alloc(mep);
+	if (ret < 0) {
+		mtu3_deconfig_ep(mtu, mep);
+		return ret;
+	}
+
+	mtu3_qmu_start(mep);
+
+	return 0;
+}
+
+static int mtu3_ep_disable(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+
+	mtu3_qmu_stop(mep);
+
+	/* abort all pending requests */
+	nuke(mep, -ESHUTDOWN);
+	mtu3_deconfig_ep(mtu, mep);
+	mtu3_gpd_ring_free(mep);
+
+	mep->desc = NULL;
+	mep->ep.desc = NULL;
+	mep->comp_desc = NULL;
+	mep->type = 0;
+	mep->flags = 0;
+
+	return 0;
+}
+
+static int mtu3_gadget_ep_enable(struct usb_ep *ep,
+				 const struct usb_endpoint_descriptor *desc)
+{
+	struct mtu3_ep *mep;
+	struct mtu3 *mtu;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+		pr_debug("%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!desc->wMaxPacketSize) {
+		pr_debug("%s missing wMaxPacketSize\n", __func__);
+		return -EINVAL;
+	}
+	mep = to_mtu3_ep(ep);
+	mtu = mep->mtu;
+
+	/* check ep number and direction against endpoint */
+	if (usb_endpoint_num(desc) != mep->epnum)
+		return -EINVAL;
+
+	if (!!usb_endpoint_dir_in(desc) ^ !!mep->is_in)
+		return -EINVAL;
+
+	dev_dbg(mtu->dev, "%s %s\n", __func__, ep->name);
+
+	if (mep->flags & MTU3_EP_ENABLED) {
+		dev_warn(mtu->dev, "%s is already enabled\n", mep->name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	mep->desc = desc;
+	mep->comp_desc = ep->comp_desc;
+
+	ret = mtu3_ep_enable(mep);
+	if (ret)
+		goto error;
+
+	mep->flags = MTU3_EP_ENABLED;
+	mtu->active_ep++;
+
+error:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep);
+
+	return ret;
+}
+
+static int mtu3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3 *mtu = mep->mtu;
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name);
+
+	if (!(mep->flags & MTU3_EP_ENABLED)) {
+		dev_warn(mtu->dev, "%s is already disabled\n", mep->name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	mtu3_ep_disable(mep);
+	mep->flags = 0;
+	mtu->active_ep--;
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	dev_dbg(mtu->dev, "%s active_ep=%d, mtu3 is_active=%d\n",
+		__func__, mtu->active_ep, mtu->is_active);
+
+	return 0;
+}
+
+struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3_request *mreq;
+
+	mreq = kzalloc(sizeof(*mreq), gfp_flags);
+	if (!mreq)
+		return NULL;
+
+	mreq->request.dma = DMA_ADDR_INVALID;
+	mreq->epnum = mep->epnum;
+	mreq->mep = mep;
+
+	return &mreq->request;
+}
+
+void mtu3_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mtu3_request *mreq = to_mtu3_request(req);
+
+	kfree(mreq);
+}
+
+static int mtu3_gadget_queue(struct usb_ep *ep,
+			     struct usb_request *req, gfp_t gfp_flags)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3_request *mreq = to_mtu3_request(req);
+	struct mtu3 *mtu = mep->mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!req->buf)
+		return -ENODATA;
+
+	if (mreq->mep != mep)
+		return -EINVAL;
+
+	dev_dbg(mtu->dev, "%s %s EP%d(%s), req=%p, maxp=%d, len#%d\n",
+		__func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name,
+		mreq, ep->maxpacket, mreq->request.length);
+
+	if (req->length > GPD_BUF_SIZE) {
+		dev_warn(mtu->dev,
+			 "req length > supported MAX:%d requested:%d\n",
+			 GPD_BUF_SIZE, req->length);
+		return -EOPNOTSUPP;
+	}
+
+	/* don't queue if the ep is down */
+	if (!mep->desc) {
+		dev_dbg(mtu->dev, "req=%p queued to %s while it's disabled\n",
+			req, ep->name);
+		return -ESHUTDOWN;
+	}
+
+	mreq->mtu = mtu;
+	mreq->request.actual = 0;
+	mreq->request.status = -EINPROGRESS;
+
+	ret = usb_gadget_map_request(&mtu->g, req, mep->is_in);
+	if (ret) {
+		dev_err(mtu->dev, "dma mapping failed\n");
+		return ret;
+	}
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	if (mtu3_prepare_transfer(mep)) {
+		ret = -EAGAIN;
+		goto error;
+	}
+
+	list_add_tail(&mreq->list, &mep->req_list);
+	mtu3_insert_gpd(mep, mreq);
+	mtu3_qmu_resume(mep);
+
+error:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+
+static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3_request *mreq = to_mtu3_request(req);
+	struct mtu3_request *r;
+	struct mtu3 *mtu = mep->mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (mreq->mep != mep)
+		return -EINVAL;
+
+	dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	list_for_each_entry(r, &mep->req_list, list) {
+		if (r == mreq)
+			break;
+	}
+	if (r != mreq) {
+		dev_dbg(mtu->dev, "req=%p not queued to %s\n", req, ep->name);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mtu3_qmu_flush(mep);  /* REVISIT: set BPS ?? */
+	mtu3_req_complete(mep, req, -ECONNRESET);
+	mtu3_qmu_start(mep);
+
+done:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+
+/*
+ * Set or clear the halt bit of an EP.
+ * A halted EP won't TX/RX any data but will queue requests.
+ */
+static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+	struct mtu3 *mtu = mep->mtu;
+	struct mtu3_request *mreq;
+	unsigned long flags = 0;
+	int ret = 0;
+
+	dev_dbg(mtu->dev, "%s : %s...", __func__, ep->name);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	if (mep->type == USB_ENDPOINT_XFER_ISOC) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mreq = next_request(mep);
+	if (value) {
+		/*
+		 * If there is not request for TX-EP, QMU will not transfer
+		 * data to TX-FIFO, so no need check whether TX-FIFO
+		 * holds bytes or not here
+		 */
+		if (mreq) {
+			dev_dbg(mtu->dev, "req in progress, cannot halt %s\n",
+				ep->name);
+			ret = -EAGAIN;
+			goto done;
+		}
+	} else {
+		mep->flags &= ~MTU3_EP_WEDGE;
+	}
+
+	dev_dbg(mtu->dev, "%s %s stall\n", ep->name, value ? "set" : "clear");
+
+	mtu3_ep_stall_set(mep, value);
+
+done:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+
+/* Sets the halt feature with the clear requests ignored */
+static int mtu3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+	struct mtu3_ep *mep = to_mtu3_ep(ep);
+
+	mep->flags |= MTU3_EP_WEDGE;
+
+	return usb_ep_set_halt(ep);
+}
+
+static const struct usb_ep_ops mtu3_ep_ops = {
+	.enable = mtu3_gadget_ep_enable,
+	.disable = mtu3_gadget_ep_disable,
+	.alloc_request = mtu3_alloc_request,
+	.free_request = mtu3_free_request,
+	.queue = mtu3_gadget_queue,
+	.dequeue = mtu3_gadget_dequeue,
+	.set_halt = mtu3_gadget_ep_set_halt,
+	.set_wedge = mtu3_gadget_ep_set_wedge,
+};
+
+static int mtu3_gadget_get_frame(struct usb_gadget *gadget)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+
+	return (int)mtu3_readl(mtu->mac_base, U3D_USB20_FRAME_NUM);
+}
+
+static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	/* remote wakeup feature is not enabled by host */
+	if (!mtu->may_wakeup)
+		return  -EOPNOTSUPP;
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	if (mtu->g.speed >= USB_SPEED_SUPER) {
+		mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
+	} else {
+		mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+		spin_unlock_irqrestore(&mtu->lock, flags);
+		mdelay(10);
+		spin_lock_irqsave(&mtu->lock, flags);
+		mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+	}
+	spin_unlock_irqrestore(&mtu->lock, flags);
+	return 0;
+}
+
+static int mtu3_gadget_set_self_powered(struct usb_gadget *gadget,
+					int is_selfpowered)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+
+	mtu->is_self_powered = !!is_selfpowered;
+	return 0;
+}
+
+static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s (%s) for %sactive device\n", __func__,
+		is_on ? "on" : "off", mtu->is_active ? "" : "in");
+
+	/* we'd rather not pullup unless the device is active. */
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	is_on = !!is_on;
+	if (!mtu->is_active) {
+		/* save it for mtu3_start() to process the request */
+		mtu->softconnect = is_on;
+	} else if (is_on != mtu->softconnect) {
+		mtu->softconnect = is_on;
+		mtu3_dev_on_off(mtu, is_on);
+	}
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return 0;
+}
+
+static int mtu3_gadget_start(struct usb_gadget *gadget,
+			     struct usb_gadget_driver *driver)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(gadget);
+	unsigned long flags;
+
+	if (mtu->gadget_driver) {
+		dev_err(mtu->dev, "%s is already bound to %s\n",
+			mtu->g.name, mtu->gadget_driver->function);
+		return -EBUSY;
+	}
+
+	dev_dbg(mtu->dev, "bind driver %s\n", driver->function);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	mtu->softconnect = 0;
+	mtu->gadget_driver = driver;
+	mtu3_start(mtu);
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return 0;
+}
+
+static void stop_activity(struct mtu3 *mtu)
+{
+	int i;
+
+	mtu->g.speed = USB_SPEED_UNKNOWN;
+
+	/* deactivate the hardware */
+	if (mtu->softconnect) {
+		mtu->softconnect = 0;
+		mtu3_dev_on_off(mtu, 0);
+	}
+
+	/*
+	 * killing any outstanding requests will quiesce the driver;
+	 * then report disconnect
+	 */
+	nuke(mtu->ep0, -ESHUTDOWN);
+	for (i = 1; i < mtu->num_eps; i++) {
+		nuke(mtu->in_eps + i, -ESHUTDOWN);
+		nuke(mtu->out_eps + i, -ESHUTDOWN);
+	}
+}
+
+static int mtu3_gadget_stop(struct usb_gadget *g)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(g);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	stop_activity(mtu);
+	mtu->gadget_driver = NULL;
+	mtu3_stop(mtu);
+
+	spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return 0;
+}
+
+static void
+mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
+{
+	struct mtu3 *mtu = gadget_to_mtu3(g);
+	unsigned long flags;
+
+	dev_dbg(mtu->dev, "%s %d\n", __func__, speed);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	mtu3_set_speed(mtu, speed);
+	spin_unlock_irqrestore(&mtu->lock, flags);
+}
+
+static const struct usb_gadget_ops mtu3_gadget_ops = {
+	.get_frame = mtu3_gadget_get_frame,
+	.wakeup = mtu3_gadget_wakeup,
+	.set_selfpowered = mtu3_gadget_set_self_powered,
+	.pullup = mtu3_gadget_pullup,
+	.udc_start = mtu3_gadget_start,
+	.udc_stop = mtu3_gadget_stop,
+	.udc_set_speed = mtu3_gadget_set_speed,
+};
+
+static void mtu3_state_reset(struct mtu3 *mtu)
+{
+	mtu->address = 0;
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+	mtu->may_wakeup = 0;
+	mtu->u1_enable = 0;
+	mtu->u2_enable = 0;
+	mtu->delayed_status = false;
+	mtu->test_mode = false;
+}
+
+static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
+		       u32 epnum, u32 is_in)
+{
+	mep->epnum = epnum;
+	mep->mtu = mtu;
+	mep->is_in = is_in;
+
+	INIT_LIST_HEAD(&mep->req_list);
+
+	sprintf(mep->name, "ep%d%s", epnum,
+		!epnum ? "" : (is_in ? "in" : "out"));
+
+	mep->ep.name = mep->name;
+	INIT_LIST_HEAD(&mep->ep.ep_list);
+
+	/* initialize maxpacket as SS */
+	if (!epnum) {
+		usb_ep_set_maxpacket_limit(&mep->ep, USB_HS_MAXP);
+		mep->ep.ops = &mtu3_ep0_ops;
+		mtu->g.ep0 = &mep->ep;
+	} else {
+		usb_ep_set_maxpacket_limit(&mep->ep, USB_SS_MAXP);
+		mep->ep.ops = &mtu3_ep_ops;
+		list_add_tail(&mep->ep.ep_list, &mtu->g.ep_list);
+	}
+
+	dev_dbg(mtu->dev, "%s, name=%s, maxp=%d\n", __func__, mep->ep.name,
+		mep->ep.maxpacket);
+}
+
+static void mtu3_gadget_init_eps(struct mtu3 *mtu)
+{
+	u8 epnum;
+
+	/* initialize endpoint list just once */
+	INIT_LIST_HEAD(&mtu->g.ep_list);
+
+	dev_dbg(mtu->dev, "%s num_eps(1 for a pair of tx&rx ep)=%d\n",
+		__func__, mtu->num_eps);
+
+	init_hw_ep(mtu, mtu->ep0, 0, 0);
+	for (epnum = 1; epnum < mtu->num_eps; epnum++) {
+		init_hw_ep(mtu, mtu->in_eps + epnum, epnum, 1);
+		init_hw_ep(mtu, mtu->out_eps + epnum, epnum, 0);
+	}
+}
+
+int mtu3_gadget_setup(struct mtu3 *mtu)
+{
+	mtu->g.ops = &mtu3_gadget_ops;
+	mtu->g.max_speed = mtu->max_speed;
+	mtu->g.speed = USB_SPEED_UNKNOWN;
+	mtu->g.is_dualspeed = 1;
+	mtu->g.name = MTU3_DRIVER_NAME;
+	mtu->is_active = 0;
+	mtu->delayed_status = false;
+
+	mtu3_gadget_init_eps(mtu);
+
+	return usb_add_gadget_udc((struct device *)mtu->dev, &mtu->g);
+}
+
+void mtu3_gadget_cleanup(struct mtu3 *mtu)
+{
+	usb_del_gadget_udc(&mtu->g);
+}
+
+void mtu3_gadget_resume(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget RESUME\n");
+	if (mtu->gadget_driver && mtu->gadget_driver->resume) {
+		spin_unlock(&mtu->lock);
+		mtu->gadget_driver->resume(&mtu->g);
+		spin_lock(&mtu->lock);
+	}
+}
+
+/* called when SOF packets stop for 3+ msec or enters U3 */
+void mtu3_gadget_suspend(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget SUSPEND\n");
+	if (mtu->gadget_driver && mtu->gadget_driver->suspend) {
+		spin_unlock(&mtu->lock);
+		mtu->gadget_driver->suspend(&mtu->g);
+		spin_lock(&mtu->lock);
+	}
+}
+
+/* called when VBUS drops below session threshold, and in other cases */
+void mtu3_gadget_disconnect(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget DISCONNECT\n");
+	if (mtu->gadget_driver && mtu->gadget_driver->disconnect) {
+		spin_unlock(&mtu->lock);
+		mtu->gadget_driver->disconnect(&mtu->g);
+		spin_lock(&mtu->lock);
+	}
+
+	mtu3_state_reset(mtu);
+	usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED);
+}
+
+void mtu3_gadget_reset(struct mtu3 *mtu)
+{
+	dev_dbg(mtu->dev, "gadget RESET\n");
+
+	/* report disconnect, if we didn't flush EP state */
+	if (mtu->g.speed != USB_SPEED_UNKNOWN)
+		mtu3_gadget_disconnect(mtu);
+	else
+		mtu3_state_reset(mtu);
+}
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
new file mode 100644
index 0000000..4b0bc5f
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -0,0 +1,933 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Author:  Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/iopoll.h>
+#include <linux/usb/composite.h>
+
+#include "mtu3.h"
+
+/* ep0 is always mtu3->in_eps[0] */
+#define	next_ep0_request(mtu)	next_request((mtu)->ep0)
+
+/* for high speed test mode; see USB 2.0 spec 7.1.20 */
+static const u8 mtu3_test_packet[53] = {
+	/* implicit SYNC then DATA0 to start */
+
+	/* JKJKJKJK x9 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* JJKKJJKK x8 */
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	/* JJJJKKKK x8 */
+	0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+	/* JJJJJJJKKKKKKK x8 */
+	0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	/* JJJJJJJK x8 */
+	0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+	/* JKKKKKKK x10, JK */
+	0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e,
+	/* implicit CRC16 then EOP to end */
+};
+
+static char *decode_ep0_state(struct mtu3 *mtu)
+{
+	switch (mtu->ep0_state) {
+	case MU3D_EP0_STATE_SETUP:
+		return "SETUP";
+	case MU3D_EP0_STATE_TX:
+		return "IN";
+	case MU3D_EP0_STATE_RX:
+		return "OUT";
+	case MU3D_EP0_STATE_TX_END:
+		return "TX-END";
+	case MU3D_EP0_STATE_STALL:
+		return "STALL";
+	default:
+		return "??";
+	}
+}
+
+static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req)
+{
+	mtu3_req_complete(mtu->ep0, req, 0);
+}
+
+static int
+forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
+__releases(mtu->lock)
+__acquires(mtu->lock)
+{
+	int ret;
+
+	if (!mtu->gadget_driver)
+		return -EOPNOTSUPP;
+
+	spin_unlock(&mtu->lock);
+	ret = mtu->gadget_driver->setup(&mtu->g, setup);
+	spin_lock(&mtu->lock);
+
+	dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret);
+	return ret;
+}
+
+static inline void writel_rep(volatile void *addr, const void *buffer,
+			      unsigned int count)
+{
+	if (count) {
+		const u32 *buf = buffer;
+
+		do {
+			writel(*buf++, addr);
+		} while (--count);
+	}
+}
+
+static inline void readl_rep(const volatile void *addr, void *buffer,
+			     unsigned int count)
+{
+	if (count) {
+		u32 *buf = buffer;
+
+		do {
+			u32 x = readl(addr);
+			*buf++ = x;
+		} while (--count);
+	}
+}
+
+static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len)
+{
+	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
+	u16 index = 0;
+
+	dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n",
+		__func__, mep->epnum, len, src);
+
+	if (len >= 4) {
+		writel_rep(fifo, src, len >> 2);
+		index = len & ~0x03;
+	}
+	if (len & 0x02) {
+		writew(*(u16 *)&src[index], fifo);
+		index += 2;
+	}
+	if (len & 0x01)
+		writeb(src[index], fifo);
+}
+
+static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len)
+{
+	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
+	u32 value;
+	u16 index = 0;
+
+	dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n",
+		__func__, mep->epnum, len, dst);
+
+	if (len >= 4) {
+		readl_rep(fifo, dst, len >> 2);
+		index = len & ~0x03;
+	}
+	if (len & 0x3) {
+		value = readl(fifo);
+		memcpy(&dst[index], &value, len & 0x3);
+	}
+}
+
+static void ep0_load_test_packet(struct mtu3 *mtu)
+{
+	/*
+	 * because the length of test packet is less than max packet of HS ep0,
+	 * write it into fifo directly.
+	 */
+	ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet));
+}
+
+/*
+ * A. send STALL for setup transfer without data stage:
+ *		set SENDSTALL and SETUPPKTRDY at the same time;
+ * B. send STALL for other cases:
+ *		set SENDSTALL only.
+ */
+static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
+{
+	struct mtu3 *mtu = mep0->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	u32 csr;
+
+	/* EP0_SENTSTALL is W1C */
+	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+	if (set)
+		csr |= EP0_SENDSTALL | pktrdy;
+	else
+		csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
+	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
+
+	mtu->delayed_status = false;
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+	dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n",
+		set ? "SEND" : "CLEAR", decode_ep0_state(mtu));
+}
+
+static void ep0_do_status_stage(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 value;
+
+	value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+	mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
+}
+
+static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq);
+
+static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
+{}
+
+static void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mtu3_request *mreq;
+	struct mtu3 *mtu;
+	struct usb_set_sel_req sel;
+
+	memcpy(&sel, req->buf, sizeof(sel));
+
+	mreq = to_mtu3_request(req);
+	mtu = mreq->mtu;
+	dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n",
+		sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel);
+}
+
+/* queue data stage to handle 6 byte SET_SEL request */
+static int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+	int ret;
+	u16 length = le16_to_cpu(setup->wLength);
+
+	if (unlikely(length != 6)) {
+		dev_err(mtu->dev, "%s wrong wLength:%d\n",
+			__func__, length);
+		return -EINVAL;
+	}
+
+	mtu->ep0_req.mep = mtu->ep0;
+	mtu->ep0_req.request.length = 6;
+	mtu->ep0_req.request.buf = mtu->setup_buf;
+	mtu->ep0_req.request.complete = ep0_set_sel_complete;
+	ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+
+	return ret < 0 ? ret : 1;
+}
+
+static int
+ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
+{
+	struct mtu3_ep *mep = NULL;
+	int handled = 1;
+	u8 result[2] = {0, 0};
+	u8 epnum = 0;
+	int is_in;
+
+	switch (setup->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
+		result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+
+		if (mtu->g.speed >= USB_SPEED_SUPER) {
+			result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
+			result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
+		}
+
+		dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__,
+			result[0], mtu->u1_enable, mtu->u2_enable);
+
+		break;
+	case USB_RECIP_INTERFACE:
+		break;
+	case USB_RECIP_ENDPOINT:
+		epnum = (u8)le16_to_cpu(setup->wIndex);
+		is_in = epnum & USB_DIR_IN;
+		epnum &= USB_ENDPOINT_NUMBER_MASK;
+
+		if (epnum >= mtu->num_eps) {
+			handled = -EINVAL;
+			break;
+		}
+		if (!epnum)
+			break;
+
+		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
+		if (!mep->desc) {
+			handled = -EINVAL;
+			break;
+		}
+		if (mep->flags & MTU3_EP_STALL)
+			result[0] |= 1 << USB_ENDPOINT_HALT;
+
+		break;
+	default:
+		/* class, vendor, etc ... delegate */
+		handled = 0;
+		break;
+	}
+
+	if (handled > 0) {
+		int ret;
+
+		/* prepare a data stage for GET_STATUS */
+		dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result);
+		memcpy(mtu->setup_buf, result, sizeof(result));
+		mtu->ep0_req.mep = mtu->ep0;
+		mtu->ep0_req.request.length = 2;
+		mtu->ep0_req.request.buf = &mtu->setup_buf;
+		mtu->ep0_req.request.complete = ep0_dummy_complete;
+		ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+		if (ret < 0)
+			handled = ret;
+	}
+	return handled;
+}
+
+static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+	void __iomem *mbase = mtu->mac_base;
+	int handled = 1;
+	u32 value = 0;
+
+	switch (le16_to_cpu(setup->wIndex) >> 8) {
+	case TEST_J:
+		dev_dbg(mtu->dev, "TEST_J\n");
+		mtu->test_mode_nr = TEST_J_MODE;
+		break;
+	case TEST_K:
+		dev_dbg(mtu->dev, "TEST_K\n");
+		mtu->test_mode_nr = TEST_K_MODE;
+		break;
+	case TEST_SE0_NAK:
+		dev_dbg(mtu->dev, "TEST_SE0_NAK\n");
+		mtu->test_mode_nr = TEST_SE0_NAK_MODE;
+		break;
+	case TEST_PACKET:
+		dev_dbg(mtu->dev, "TEST_PACKET\n");
+		mtu->test_mode_nr = TEST_PACKET_MODE;
+		break;
+	default:
+		handled = -EINVAL;
+		goto out;
+	}
+
+	mtu->test_mode = true;
+
+	/* no TX completion interrupt, and need restart platform after test */
+	if (mtu->test_mode_nr == TEST_PACKET_MODE)
+		ep0_load_test_packet(mtu);
+
+	/* send status before entering test mode. */
+	ep0_do_status_stage(mtu);
+
+	/* wait for ACK status sent by host */
+	readl_poll_timeout(mbase + U3D_EP0CSR, value,
+			   !(value & EP0_DATAEND), 5000);
+
+	mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr);
+
+	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+out:
+	return handled;
+}
+
+static int ep0_handle_feature_dev(struct mtu3 *mtu,
+				  struct usb_ctrlrequest *setup, bool set)
+{
+	void __iomem *mbase = mtu->mac_base;
+	int handled = -EINVAL;
+	u32 lpc;
+
+	switch (le16_to_cpu(setup->wValue)) {
+	case USB_DEVICE_REMOTE_WAKEUP:
+		mtu->may_wakeup = !!set;
+		handled = 1;
+		break;
+	case USB_DEVICE_TEST_MODE:
+		if (!set || (mtu->g.speed != USB_SPEED_HIGH) ||
+		    (le16_to_cpu(setup->wIndex) & 0xff))
+			break;
+
+		handled = handle_test_mode(mtu, setup);
+		break;
+	case USB_DEVICE_U1_ENABLE:
+		if (mtu->g.speed < USB_SPEED_SUPER ||
+		    mtu->g.state != USB_STATE_CONFIGURED)
+			break;
+
+		lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+		if (set)
+			lpc |= SW_U1_REQUEST_ENABLE;
+		else
+			lpc &= ~SW_U1_REQUEST_ENABLE;
+		mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+		mtu->u1_enable = !!set;
+		handled = 1;
+		break;
+	case USB_DEVICE_U2_ENABLE:
+		if (mtu->g.speed < USB_SPEED_SUPER ||
+		    mtu->g.state != USB_STATE_CONFIGURED)
+			break;
+
+		lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+		if (set)
+			lpc |= SW_U2_REQUEST_ENABLE;
+		else
+			lpc &= ~SW_U2_REQUEST_ENABLE;
+		mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+		mtu->u2_enable = !!set;
+		handled = 1;
+		break;
+	default:
+		handled = -EINVAL;
+		break;
+	}
+	return handled;
+}
+
+static int ep0_handle_feature(struct mtu3 *mtu,
+			      struct usb_ctrlrequest *setup, bool set)
+{
+	struct mtu3_ep *mep;
+	int handled = -EINVAL;
+	int is_in;
+	u16 value;
+	u16 index;
+	u8 epnum;
+
+	value = le16_to_cpu(setup->wValue);
+	index = le16_to_cpu(setup->wIndex);
+
+	switch (setup->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		handled = ep0_handle_feature_dev(mtu, setup, set);
+		break;
+	case USB_RECIP_INTERFACE:
+		/* superspeed only */
+		if (value == USB_INTRF_FUNC_SUSPEND &&
+		    mtu->g.speed >= USB_SPEED_SUPER) {
+			/*
+			 * forward the request because function drivers
+			 * should handle it
+			 */
+			handled = 0;
+		}
+		break;
+	case USB_RECIP_ENDPOINT:
+		epnum = index & USB_ENDPOINT_NUMBER_MASK;
+		if (epnum == 0 || epnum >= mtu->num_eps ||
+		    value != USB_ENDPOINT_HALT)
+			break;
+
+		is_in = index & USB_DIR_IN;
+		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
+		if (!mep->desc)
+			break;
+
+		handled = 1;
+		/* ignore request if endpoint is wedged */
+		if (mep->flags & MTU3_EP_WEDGE)
+			break;
+
+		mtu3_ep_stall_set(mep, set);
+		break;
+	default:
+		/* class, vendor, etc ... delegate */
+		handled = 0;
+		break;
+	}
+	return handled;
+}
+
+/*
+ * handle all control requests can be handled
+ * returns:
+ *	negative errno - error happened
+ *	zero - need delegate SETUP to gadget driver
+ *	positive - already handled
+ */
+static int handle_standard_request(struct mtu3 *mtu,
+				   struct usb_ctrlrequest *setup)
+{
+	void __iomem *mbase = mtu->mac_base;
+	enum usb_device_state state = mtu->g.state;
+	int handled = -EINVAL;
+	u32 dev_conf;
+	u16 value;
+
+	value = le16_to_cpu(setup->wValue);
+
+	/* the gadget driver handles everything except what we must handle */
+	switch (setup->bRequest) {
+	case USB_REQ_SET_ADDRESS:
+		/* change it after the status stage */
+		mtu->address = (u8)(value & 0x7f);
+		dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address);
+
+		dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF);
+		dev_conf &= ~DEV_ADDR_MSK;
+		dev_conf |= DEV_ADDR(mtu->address);
+		mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf);
+
+		if (mtu->address)
+			usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS);
+		else
+			usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT);
+
+		handled = 1;
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		if (state == USB_STATE_ADDRESS) {
+			usb_gadget_set_state(&mtu->g,
+					     USB_STATE_CONFIGURED);
+		} else if (state == USB_STATE_CONFIGURED) {
+			/*
+			 * USB2 spec sec 9.4.7, if wValue is 0 then dev
+			 * is moved to addressed state
+			 */
+			if (!value)
+				usb_gadget_set_state(&mtu->g,
+						     USB_STATE_ADDRESS);
+		}
+		handled = 0;
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		handled = ep0_handle_feature(mtu, setup, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		handled = ep0_handle_feature(mtu, setup, 1);
+		break;
+	case USB_REQ_GET_STATUS:
+		handled = ep0_get_status(mtu, setup);
+		break;
+	case USB_REQ_SET_SEL:
+		handled = ep0_set_sel(mtu, setup);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		handled = 1;
+		break;
+	default:
+		/* delegate SET_CONFIGURATION, etc */
+		handled = 0;
+	}
+
+	return handled;
+}
+
+/* receive an data packet (OUT) */
+static void ep0_rx_state(struct mtu3 *mtu)
+{
+	struct mtu3_request *mreq;
+	struct usb_request *req;
+	void __iomem *mbase = mtu->mac_base;
+	u32 maxp;
+	u32 csr;
+	u16 count = 0;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
+	mreq = next_ep0_request(mtu);
+	req = &mreq->request;
+
+	/* read packet and ack; or stall because of gadget driver bug */
+	if (req) {
+		void *buf = req->buf + req->actual;
+		unsigned int len = req->length - req->actual;
+
+		/* read the buffer */
+		count = mtu3_readl(mbase, U3D_RXCOUNT0);
+		if (count > len) {
+			req->status = -EOVERFLOW;
+			count = len;
+		}
+		ep0_read_fifo(mtu->ep0, buf, count);
+		req->actual += count;
+		csr |= EP0_RXPKTRDY;
+
+		maxp = mtu->g.ep0->maxpacket;
+		if (count < maxp || req->actual == req->length) {
+			mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+			dev_dbg(mtu->dev, "ep0 state: %s\n",
+				decode_ep0_state(mtu));
+
+			csr |= EP0_DATAEND;
+		} else {
+			req = NULL;
+		}
+	} else {
+		csr |= EP0_RXPKTRDY | EP0_SENDSTALL;
+		dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__);
+	}
+
+	mtu3_writel(mbase, U3D_EP0CSR, csr);
+
+	/* give back the request if have received all data */
+	if (req)
+		ep0_req_giveback(mtu, req);
+}
+
+/* transmitting to the host (IN) */
+static void ep0_tx_state(struct mtu3 *mtu)
+{
+	struct mtu3_request *mreq = next_ep0_request(mtu);
+	struct usb_request *req;
+	u32 csr;
+	u8 *src;
+	u32 count;
+	u32 maxp;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	if (!mreq)
+		return;
+
+	maxp = mtu->g.ep0->maxpacket;
+	req = &mreq->request;
+
+	/* load the data */
+	src = (u8 *)req->buf + req->actual;
+	count = min(maxp, req->length - req->actual);
+	if (count)
+		ep0_write_fifo(mtu->ep0, src, count);
+
+	dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n",
+		__func__, req->actual, req->length, count, maxp, req->zero);
+
+	req->actual += count;
+
+	if ((count < maxp) ||
+	    ((req->actual == req->length) && !req->zero))
+		mtu->ep0_state = MU3D_EP0_STATE_TX_END;
+
+	/* send it out, triggering a "txpktrdy cleared" irq */
+	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
+	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY);
+
+	dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__,
+		mtu3_readl(mtu->mac_base, U3D_EP0CSR));
+}
+
+static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+	struct mtu3_request *mreq;
+	u32 count;
+	u32 csr;
+
+	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
+	count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0);
+
+	ep0_read_fifo(mtu->ep0, (u8 *)setup, count);
+
+	dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n",
+		setup->bRequestType, setup->bRequest,
+		le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex),
+		le16_to_cpu(setup->wLength));
+
+	/* clean up any leftover transfers */
+	mreq = next_ep0_request(mtu);
+	if (mreq)
+		ep0_req_giveback(mtu, &mreq->request);
+
+	if (le16_to_cpu(setup->wLength) == 0) {
+		;	/* no data stage, nothing to do */
+	} else if (setup->bRequestType & USB_DIR_IN) {
+		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
+			    csr | EP0_SETUPPKTRDY | EP0_DPHTX);
+		mtu->ep0_state = MU3D_EP0_STATE_TX;
+	} else {
+		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
+			    (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX));
+		mtu->ep0_state = MU3D_EP0_STATE_RX;
+	}
+}
+
+static int ep0_handle_setup(struct mtu3 *mtu)
+__releases(mtu->lock)
+__acquires(mtu->lock)
+{
+	struct usb_ctrlrequest setup;
+	struct mtu3_request *mreq;
+	int handled = 0;
+
+	ep0_read_setup(mtu, &setup);
+
+	if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		handled = handle_standard_request(mtu, &setup);
+
+	dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n",
+		handled, decode_ep0_state(mtu));
+
+	if (handled < 0)
+		goto stall;
+	else if (handled > 0)
+		goto finish;
+
+	handled = forward_to_driver(mtu, &setup);
+	if (handled < 0) {
+stall:
+		dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled);
+
+		ep0_stall_set(mtu->ep0, true,
+			      le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY);
+
+		return 0;
+	}
+
+finish:
+	if (mtu->test_mode) {
+		;	/* nothing to do */
+	} else if (handled == USB_GADGET_DELAYED_STATUS) {
+
+		mreq = next_ep0_request(mtu);
+		if (mreq) {
+			/* already asked us to continue delayed status */
+			ep0_do_status_stage(mtu);
+			ep0_req_giveback(mtu, &mreq->request);
+		} else {
+			/* do delayed STATUS stage till receive ep0_queue */
+			mtu->delayed_status = true;
+		}
+	} else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
+
+		ep0_do_status_stage(mtu);
+		/* complete zlp request directly */
+		mreq = next_ep0_request(mtu);
+		if (mreq && !mreq->request.length)
+			ep0_req_giveback(mtu, &mreq->request);
+	}
+
+	return 0;
+}
+
+irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	struct mtu3_request *mreq;
+	u32 int_status;
+	irqreturn_t ret = IRQ_NONE;
+	u32 csr;
+	u32 len;
+
+	int_status = mtu3_readl(mbase, U3D_EPISR);
+	int_status &= mtu3_readl(mbase, U3D_EPIER);
+	mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */
+
+	/* only handle ep0's */
+	if (!(int_status & (EP0ISR | SETUPENDISR)))
+		return IRQ_NONE;
+
+	/* abort current SETUP, and process new one */
+	if (int_status & SETUPENDISR)
+		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+
+	csr = mtu3_readl(mbase, U3D_EP0CSR);
+
+	dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr);
+
+	/* we sent a stall.. need to clear it now.. */
+	if (csr & EP0_SENTSTALL) {
+		ep0_stall_set(mtu->ep0, false, 0);
+		csr = mtu3_readl(mbase, U3D_EP0CSR);
+		ret = IRQ_HANDLED;
+	}
+	dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+
+	switch (mtu->ep0_state) {
+	case MU3D_EP0_STATE_TX:
+		/* irq on clearing txpktrdy */
+		if ((csr & EP0_FIFOFULL) == 0) {
+			ep0_tx_state(mtu);
+			ret = IRQ_HANDLED;
+		}
+		break;
+	case MU3D_EP0_STATE_RX:
+		/* irq on set rxpktrdy */
+		if (csr & EP0_RXPKTRDY) {
+			ep0_rx_state(mtu);
+			ret = IRQ_HANDLED;
+		}
+		break;
+	case MU3D_EP0_STATE_TX_END:
+		mtu3_writel(mbase, U3D_EP0CSR,
+			    (csr & EP0_W1C_BITS) | EP0_DATAEND);
+
+		mreq = next_ep0_request(mtu);
+		if (mreq)
+			ep0_req_giveback(mtu, &mreq->request);
+
+		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+		ret = IRQ_HANDLED;
+		dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+		break;
+	case MU3D_EP0_STATE_SETUP:
+		if (!(csr & EP0_SETUPPKTRDY))
+			break;
+
+		len = mtu3_readl(mbase, U3D_RXCOUNT0);
+		if (len != 8) {
+			dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len);
+			break;
+		}
+
+		ep0_handle_setup(mtu);
+		ret = IRQ_HANDLED;
+		break;
+	default:
+		/* can't happen */
+		ep0_stall_set(mtu->ep0, true, 0);
+		WARN_ON(1);
+		break;
+	}
+
+	return ret;
+}
+
+static int mtu3_ep0_enable(struct usb_ep *ep,
+			   const struct usb_endpoint_descriptor *desc)
+{
+	/* always enabled */
+	return -EINVAL;
+}
+
+static int mtu3_ep0_disable(struct usb_ep *ep)
+{
+	/* always enabled */
+	return -EINVAL;
+}
+
+static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	struct mtu3 *mtu = mep->mtu;
+
+	mreq->mtu = mtu;
+	mreq->request.actual = 0;
+	mreq->request.status = -EINPROGRESS;
+
+	dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__,
+		mep->name, decode_ep0_state(mtu), mreq->request.length);
+
+	switch (mtu->ep0_state) {
+	case MU3D_EP0_STATE_SETUP:
+	case MU3D_EP0_STATE_RX:	/* control-OUT data */
+	case MU3D_EP0_STATE_TX:	/* control-IN data */
+		break;
+	default:
+		dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__,
+			decode_ep0_state(mtu));
+		return -EINVAL;
+	}
+
+	if (mtu->delayed_status) {
+		mtu->delayed_status = false;
+		ep0_do_status_stage(mtu);
+		/* needn't giveback the request for handling delay STATUS */
+		return 0;
+	}
+
+	if (!list_empty(&mep->req_list))
+		return -EBUSY;
+
+	list_add_tail(&mreq->list, &mep->req_list);
+
+	/* sequence #1, IN ... start writing the data */
+	if (mtu->ep0_state == MU3D_EP0_STATE_TX)
+		ep0_tx_state(mtu);
+
+	return 0;
+}
+
+static int mtu3_ep0_queue(struct usb_ep *ep,
+			  struct usb_request *req, gfp_t gfp)
+{
+	struct mtu3_ep *mep;
+	struct mtu3_request *mreq;
+	struct mtu3 *mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!ep || !req)
+		return -EINVAL;
+
+	mep = to_mtu3_ep(ep);
+	mtu = mep->mtu;
+	mreq = to_mtu3_request(req);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+	ret = ep0_queue(mep, mreq);
+	spin_unlock_irqrestore(&mtu->lock, flags);
+	return ret;
+}
+
+static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	/* we just won't support this */
+	return -EINVAL;
+}
+
+static int mtu3_ep0_halt(struct usb_ep *ep, int value)
+{
+	struct mtu3_ep *mep;
+	struct mtu3 *mtu;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!ep || !value)
+		return -EINVAL;
+
+	mep = to_mtu3_ep(ep);
+	mtu = mep->mtu;
+
+	dev_dbg(mtu->dev, "%s\n", __func__);
+
+	spin_lock_irqsave(&mtu->lock, flags);
+
+	if (!list_empty(&mep->req_list)) {
+		ret = -EBUSY;
+		goto cleanup;
+	}
+
+	switch (mtu->ep0_state) {
+	/*
+	 * stalls are usually issued after parsing SETUP packet, either
+	 * directly in irq context from setup() or else later.
+	 */
+	case MU3D_EP0_STATE_TX:
+	case MU3D_EP0_STATE_TX_END:
+	case MU3D_EP0_STATE_RX:
+	case MU3D_EP0_STATE_SETUP:
+		ep0_stall_set(mtu->ep0, true, 0);
+		break;
+	default:
+		dev_dbg(mtu->dev, "ep0 can't halt in state %s\n",
+			decode_ep0_state(mtu));
+		ret = -EINVAL;
+	}
+
+cleanup:
+	spin_unlock_irqrestore(&mtu->lock, flags);
+	return ret;
+}
+
+const struct usb_ep_ops mtu3_ep0_ops = {
+	.enable = mtu3_ep0_enable,
+	.disable = mtu3_ep0_disable,
+	.alloc_request = mtu3_alloc_request,
+	.free_request = mtu3_free_request,
+	.queue = mtu3_ep0_queue,
+	.dequeue = mtu3_ep0_dequeue,
+	.set_halt = mtu3_ep0_halt,
+};
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
new file mode 100644
index 0000000..8001fc2
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_dr.c - dual role switch and host glue layer
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <dm/lists.h>
+#include <linux/iopoll.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+static void host_ports_num_get(struct mtu3_host *u3h)
+{
+	u32 xhci_cap;
+
+	xhci_cap = mtu3_readl(u3h->ippc_base, U3D_SSUSB_IP_XHCI_CAP);
+	u3h->u2_ports = SSUSB_IP_XHCI_U2_PORT_NUM(xhci_cap);
+	u3h->u3_ports = SSUSB_IP_XHCI_U3_PORT_NUM(xhci_cap);
+
+	dev_dbg(u3h->dev, "host - u2_ports:%d, u3_ports:%d\n",
+		u3h->u2_ports, u3h->u3_ports);
+}
+
+/* only configure ports will be used later */
+static int ssusb_host_enable(struct mtu3_host *u3h)
+{
+	void __iomem *ibase = u3h->ippc_base;
+	int num_u3p = u3h->u3_ports;
+	int num_u2p = u3h->u2_ports;
+	int u3_ports_disabed;
+	u32 check_clk;
+	u32 value;
+	int i;
+
+	/* power on host ip */
+	mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+
+	/* power on and enable u3 ports except skipped ones */
+	u3_ports_disabed = 0;
+	for (i = 0; i < num_u3p; i++) {
+		if ((0x1 << i) & u3h->u3p_dis_msk) {
+			u3_ports_disabed++;
+			continue;
+		}
+
+		value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+		value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
+		value |= SSUSB_U3_PORT_HOST_SEL;
+		mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+	}
+
+	/* power on and enable all u2 ports */
+	for (i = 0; i < num_u2p; i++) {
+		value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+		value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
+		value |= SSUSB_U2_PORT_HOST_SEL;
+		mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+	}
+
+	check_clk = SSUSB_XHCI_RST_B_STS;
+	if (num_u3p > u3_ports_disabed)
+		check_clk = SSUSB_U3_MAC_RST_B_STS;
+
+	return ssusb_check_clocks(u3h->ssusb, check_clk);
+}
+
+static void ssusb_host_disable(struct mtu3_host *u3h)
+{
+	void __iomem *ibase = u3h->ippc_base;
+	int num_u3p = u3h->u3_ports;
+	int num_u2p = u3h->u2_ports;
+	u32 value;
+	int i;
+
+	/* power down and disable u3 ports except skipped ones */
+	for (i = 0; i < num_u3p; i++) {
+		if ((0x1 << i) & u3h->u3p_dis_msk)
+			continue;
+
+		value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+		value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
+		mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+	}
+
+	/* power down and disable all u2 ports */
+	for (i = 0; i < num_u2p; i++) {
+		value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+		value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
+		mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+	}
+
+	/* power down host ip */
+	mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+}
+
+/*
+ * If host supports multiple ports, the VBUSes(5V) of ports except port0
+ * which supports OTG are better to be enabled by default in DTS.
+ * Because the host driver will keep link with devices attached when system
+ * enters suspend mode, so no need to control VBUSes after initialization.
+ */
+int ssusb_host_init(struct ssusb_mtk *ssusb)
+{
+	struct mtu3_host *u3h = ssusb->u3h;
+	struct udevice *dev = u3h->dev;
+	int ret;
+
+	u3h->ssusb = ssusb;
+	u3h->hcd = ssusb->mac_base;
+	u3h->ippc_base = ssusb->ippc_base;
+
+	/* optional property, ignore the error */
+	dev_read_u32(dev, "mediatek,u3p-dis-msk", &u3h->u3p_dis_msk);
+
+	host_ports_num_get(u3h);
+	ret = ssusb_host_enable(u3h);
+	if (ret)
+		return ret;
+
+	ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+
+	ret = regulator_set_enable(ssusb->vbus_supply, true);
+	if (ret < 0 && ret != -ENOSYS) {
+		dev_err(dev, "failed to enable vbus %d!\n", ret);
+		return ret;
+	}
+
+	dev_info(dev, "%s done...\n", __func__);
+
+	return 0;
+}
+
+void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{
+	regulator_set_enable(ssusb->vbus_supply, false);
+	ssusb_host_disable(ssusb->u3h);
+}
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
new file mode 100644
index 0000000..9c2a7e1
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -0,0 +1,515 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef _SSUSB_HW_REGS_H_
+#define _SSUSB_HW_REGS_H_
+
+/* segment offset of MAC register */
+#define SSUSB_XCHI_BASE		0x0000
+#define SSUSB_DEV_BASE		0x1000
+#define SSUSB_EPCTL_CSR_BASE	0x1800
+#define SSUSB_USB3_MAC_CSR_BASE	0x2400
+#define SSUSB_USB3_SYS_CSR_BASE	0x2400
+#define SSUSB_USB2_CSR_BASE	0x3400
+
+/* IPPC register in Infra */
+#define SSUSB_SIFSLV_IPPC_BASE	0x0000
+
+/* --------------- SSUSB_DEV REGISTER DEFINITION --------------- */
+
+#define U3D_LV1ISR		(SSUSB_DEV_BASE + 0x0000)
+#define U3D_LV1IER		(SSUSB_DEV_BASE + 0x0004)
+#define U3D_LV1IESR		(SSUSB_DEV_BASE + 0x0008)
+#define U3D_LV1IECR		(SSUSB_DEV_BASE + 0x000C)
+
+#define U3D_EPISR		(SSUSB_DEV_BASE + 0x0080)
+#define U3D_EPIER		(SSUSB_DEV_BASE + 0x0084)
+#define U3D_EPIESR		(SSUSB_DEV_BASE + 0x0088)
+#define U3D_EPIECR		(SSUSB_DEV_BASE + 0x008C)
+
+#define U3D_EP0CSR		(SSUSB_DEV_BASE + 0x0100)
+#define U3D_RXCOUNT0		(SSUSB_DEV_BASE + 0x0108)
+#define U3D_RESERVED		(SSUSB_DEV_BASE + 0x010C)
+#define U3D_TX1CSR0		(SSUSB_DEV_BASE + 0x0110)
+#define U3D_TX1CSR1		(SSUSB_DEV_BASE + 0x0114)
+#define U3D_TX1CSR2		(SSUSB_DEV_BASE + 0x0118)
+
+#define U3D_RX1CSR0		(SSUSB_DEV_BASE + 0x0210)
+#define U3D_RX1CSR1		(SSUSB_DEV_BASE + 0x0214)
+#define U3D_RX1CSR2		(SSUSB_DEV_BASE + 0x0218)
+
+#define U3D_FIFO0		(SSUSB_DEV_BASE + 0x0300)
+
+#define U3D_QCR0		(SSUSB_DEV_BASE + 0x0400)
+#define U3D_QCR1		(SSUSB_DEV_BASE + 0x0404)
+#define U3D_QCR2		(SSUSB_DEV_BASE + 0x0408)
+#define U3D_QCR3		(SSUSB_DEV_BASE + 0x040C)
+#define U3D_QFCR		(SSUSB_DEV_BASE + 0x0428)
+
+#define U3D_TXQCSR1		(SSUSB_DEV_BASE + 0x0510)
+#define U3D_TXQSAR1		(SSUSB_DEV_BASE + 0x0514)
+#define U3D_TXQCPR1		(SSUSB_DEV_BASE + 0x0518)
+
+#define U3D_RXQCSR1		(SSUSB_DEV_BASE + 0x0610)
+#define U3D_RXQSAR1		(SSUSB_DEV_BASE + 0x0614)
+#define U3D_RXQCPR1		(SSUSB_DEV_BASE + 0x0618)
+#define U3D_RXQLDPR1		(SSUSB_DEV_BASE + 0x061C)
+
+#define U3D_QISAR0		(SSUSB_DEV_BASE + 0x0700)
+#define U3D_QIER0		(SSUSB_DEV_BASE + 0x0704)
+#define U3D_QIESR0		(SSUSB_DEV_BASE + 0x0708)
+#define U3D_QIECR0		(SSUSB_DEV_BASE + 0x070C)
+#define U3D_QISAR1		(SSUSB_DEV_BASE + 0x0710)
+#define U3D_QIER1		(SSUSB_DEV_BASE + 0x0714)
+#define U3D_QIESR1		(SSUSB_DEV_BASE + 0x0718)
+#define U3D_QIECR1		(SSUSB_DEV_BASE + 0x071C)
+
+#define U3D_TQERRIR0		(SSUSB_DEV_BASE + 0x0780)
+#define U3D_TQERRIER0		(SSUSB_DEV_BASE + 0x0784)
+#define U3D_TQERRIESR0		(SSUSB_DEV_BASE + 0x0788)
+#define U3D_TQERRIECR0		(SSUSB_DEV_BASE + 0x078C)
+#define U3D_RQERRIR0		(SSUSB_DEV_BASE + 0x07C0)
+#define U3D_RQERRIER0		(SSUSB_DEV_BASE + 0x07C4)
+#define U3D_RQERRIESR0		(SSUSB_DEV_BASE + 0x07C8)
+#define U3D_RQERRIECR0		(SSUSB_DEV_BASE + 0x07CC)
+#define U3D_RQERRIR1		(SSUSB_DEV_BASE + 0x07D0)
+#define U3D_RQERRIER1		(SSUSB_DEV_BASE + 0x07D4)
+#define U3D_RQERRIESR1		(SSUSB_DEV_BASE + 0x07D8)
+#define U3D_RQERRIECR1		(SSUSB_DEV_BASE + 0x07DC)
+
+#define U3D_CAP_EP0FFSZ		(SSUSB_DEV_BASE + 0x0C04)
+#define U3D_CAP_EPNTXFFSZ	(SSUSB_DEV_BASE + 0x0C08)
+#define U3D_CAP_EPNRXFFSZ	(SSUSB_DEV_BASE + 0x0C0C)
+#define U3D_CAP_EPINFO		(SSUSB_DEV_BASE + 0x0C10)
+#define U3D_MISC_CTRL		(SSUSB_DEV_BASE + 0x0C84)
+
+/*---------------- SSUSB_DEV FIELD DEFINITION ---------------*/
+
+/* U3D_LV1ISR */
+#define EP_CTRL_INTR		BIT(5)
+#define MAC2_INTR		BIT(4)
+#define DMA_INTR		BIT(3)
+#define MAC3_INTR		BIT(2)
+#define QMU_INTR		BIT(1)
+#define BMU_INTR		BIT(0)
+
+/* U3D_LV1IECR */
+#define LV1IECR_MSK		GENMASK(31, 0)
+
+/* U3D_EPISR */
+#define EPRISR(x)		(BIT(16) << (x))
+#define SETUPENDISR		BIT(16)
+#define EPTISR(x)		(BIT(0) << (x))
+#define EP0ISR			BIT(0)
+
+/* U3D_EP0CSR */
+#define EP0_SENDSTALL		BIT(25)
+#define EP0_FIFOFULL		BIT(23)
+#define EP0_SENTSTALL		BIT(22)
+#define EP0_DPHTX		BIT(20)
+#define EP0_DATAEND		BIT(19)
+#define EP0_TXPKTRDY		BIT(18)
+#define EP0_SETUPPKTRDY		BIT(17)
+#define EP0_RXPKTRDY		BIT(16)
+#define EP0_MAXPKTSZ_MSK	GENMASK(9, 0)
+#define EP0_MAXPKTSZ(x)		((x) & EP0_MAXPKTSZ_MSK)
+#define EP0_W1C_BITS	(~(EP0_RXPKTRDY | EP0_SETUPPKTRDY | EP0_SENTSTALL))
+
+/* U3D_TX1CSR0 */
+#define TX_DMAREQEN		BIT(29)
+#define TX_FIFOFULL		BIT(25)
+#define TX_FIFOEMPTY		BIT(24)
+#define TX_SENTSTALL		BIT(22)
+#define TX_SENDSTALL		BIT(21)
+#define TX_TXPKTRDY		BIT(16)
+#define TX_TXMAXPKTSZ_MSK	GENMASK(10, 0)
+#define TX_TXMAXPKTSZ(x)	((x) & TX_TXMAXPKTSZ_MSK)
+#define TX_W1C_BITS		(~(TX_SENTSTALL))
+
+/* U3D_TX1CSR1 */
+#define TX_MAX_PKT_G2(x)	(((x) & 0xff) << 24)
+#define TX_MULT_G2(x)		(((x) & 0x7) << 21)
+#define TX_MULT_OG(x)		(((x) & 0x3) << 22)
+#define TX_MAX_PKT_OG(x)	(((x) & 0x3f) << 16)
+#define TX_SLOT(x)		(((x) & 0x3f) << 8)
+#define TX_TYPE(x)		(((x) & 0x3) << 4)
+#define TX_SS_BURST(x)		(((x) & 0xf) << 0)
+#define TX_MULT(g2c, x)		\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? TX_MULT_G2(x_) : TX_MULT_OG(x_);	\
+})
+#define TX_MAX_PKT(g2c, x)	\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? TX_MAX_PKT_G2(x_) : TX_MAX_PKT_OG(x_);	\
+})
+
+/* for TX_TYPE & RX_TYPE */
+#define TYPE_BULK		(0x0)
+#define TYPE_INT		(0x1)
+#define TYPE_ISO		(0x2)
+#define TYPE_MASK		(0x3)
+
+/* U3D_TX1CSR2 */
+#define TX_BINTERVAL(x)		(((x) & 0xff) << 24)
+#define TX_FIFOSEGSIZE(x)	(((x) & 0xf) << 16)
+#define TX_FIFOADDR(x)		(((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR0 */
+#define RX_DMAREQEN		BIT(29)
+#define RX_SENTSTALL		BIT(22)
+#define RX_SENDSTALL		BIT(21)
+#define RX_RXPKTRDY		BIT(16)
+#define RX_RXMAXPKTSZ_MSK	GENMASK(10, 0)
+#define RX_RXMAXPKTSZ(x)	((x) & RX_RXMAXPKTSZ_MSK)
+#define RX_W1C_BITS		(~(RX_SENTSTALL | RX_RXPKTRDY))
+
+/* U3D_RX1CSR1 */
+#define RX_MAX_PKT_G2(x)	(((x) & 0xff) << 24)
+#define RX_MULT_G2(x)		(((x) & 0x7) << 21)
+#define RX_MULT_OG(x)		(((x) & 0x3) << 22)
+#define RX_MAX_PKT_OG(x)	(((x) & 0x3f) << 16)
+#define RX_SLOT(x)		(((x) & 0x3f) << 8)
+#define RX_TYPE(x)		(((x) & 0x3) << 4)
+#define RX_SS_BURST(x)		(((x) & 0xf) << 0)
+#define RX_MULT(g2c, x)		\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? RX_MULT_G2(x_) : RX_MULT_OG(x_);	\
+})
+#define RX_MAX_PKT(g2c, x)	\
+({				\
+	typeof(x) x_ = (x);	\
+	(g2c) ? RX_MAX_PKT_G2(x_) : RX_MAX_PKT_OG(x_);	\
+})
+
+/* U3D_RX1CSR2 */
+#define RX_BINTERVAL(x)		(((x) & 0xff) << 24)
+#define RX_FIFOSEGSIZE(x)	(((x) & 0xf) << 16)
+#define RX_FIFOADDR(x)		(((x) & 0x1fff) << 0)
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)		(BIT(16) << (x))
+#define QMU_TX_CS_EN(x)		(BIT(0) << (x))
+#define QMU_CS16B_EN		BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)		(BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)		(BIT(16) << (x))
+#define QMU_RX_ZLP(x)		(BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE		BIT(15)
+#define QMU_Q_STOP		BIT(2)
+#define QMU_Q_RESUME		BIT(1)
+#define QMU_Q_START		BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)	(BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)	(BIT(0) << (x))
+
+/* U3D_QISAR1, U3D_QIER1, U3D_QIESR1, U3D_QIECR1 */
+#define RXQ_ZLPERR_INT		BIT(20)
+#define RXQ_LENERR_INT		BIT(18)
+#define RXQ_CSERR_INT		BIT(17)
+#define RXQ_EMPTY_INT		BIT(16)
+#define TXQ_LENERR_INT		BIT(2)
+#define TXQ_CSERR_INT		BIT(1)
+#define TXQ_EMPTY_INT		BIT(0)
+
+/* U3D_TQERRIR0, U3D_TQERRIER0, U3D_TQERRIESR0, U3D_TQERRIECR0 */
+#define QMU_TX_LEN_ERR(x)	(BIT(16) << (x))
+#define QMU_TX_CS_ERR(x)	(BIT(0) << (x))
+
+/* U3D_RQERRIR0, U3D_RQERRIER0, U3D_RQERRIESR0, U3D_RQERRIECR0 */
+#define QMU_RX_LEN_ERR(x)	(BIT(16) << (x))
+#define QMU_RX_CS_ERR(x)	(BIT(0) << (x))
+
+/* U3D_RQERRIR1, U3D_RQERRIER1, U3D_RQERRIESR1, U3D_RQERRIECR1 */
+#define QMU_RX_ZLP_ERR(n)	(BIT(16) << (n))
+
+/* U3D_CAP_EPINFO */
+#define CAP_RX_EP_NUM(x)	(((x) >> 8) & 0x1f)
+#define CAP_TX_EP_NUM(x)	((x) & 0x1f)
+
+/* U3D_MISC_CTRL */
+#define VBUS_ON			BIT(1)
+#define VBUS_FRC_EN		BIT(0)
+
+/*---------------- SSUSB_EPCTL_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_DEVICE_CONF			(SSUSB_EPCTL_CSR_BASE + 0x0000)
+#define U3D_EP_RST			(SSUSB_EPCTL_CSR_BASE + 0x0004)
+
+#define U3D_DEV_LINK_INTR_ENABLE	(SSUSB_EPCTL_CSR_BASE + 0x0050)
+#define U3D_DEV_LINK_INTR		(SSUSB_EPCTL_CSR_BASE + 0x0054)
+
+/*---------------- SSUSB_EPCTL_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_DEVICE_CONF */
+#define DEV_ADDR_MSK		GENMASK(30, 24)
+#define DEV_ADDR(x)		((0x7f & (x)) << 24)
+#define HW_USB2_3_SEL		BIT(18)
+#define SW_USB2_3_SEL_EN	BIT(17)
+#define SW_USB2_3_SEL		BIT(16)
+#define SSUSB_DEV_SPEED(x)	((x) & 0x7)
+
+/* U3D_EP_RST */
+#define EP1_IN_RST		BIT(17)
+#define EP1_OUT_RST		BIT(1)
+#define EP_RST(is_in, epnum)	(((is_in) ? BIT(16) : BIT(0)) << (epnum))
+#define EP0_RST			BIT(0)
+
+/* U3D_DEV_LINK_INTR_ENABLE */
+/* U3D_DEV_LINK_INTR */
+#define SSUSB_DEV_SPEED_CHG_INTR	BIT(0)
+
+/*---------------- SSUSB_USB3_MAC_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_LTSSM_CTRL		(SSUSB_USB3_MAC_CSR_BASE + 0x0010)
+#define U3D_USB3_CONFIG		(SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+
+#define U3D_LINK_STATE_MACHINE	(SSUSB_USB3_MAC_CSR_BASE + 0x0134)
+#define U3D_LTSSM_INTR_ENABLE	(SSUSB_USB3_MAC_CSR_BASE + 0x013C)
+#define U3D_LTSSM_INTR		(SSUSB_USB3_MAC_CSR_BASE + 0x0140)
+
+#define U3D_U3U2_SWITCH_CTRL	(SSUSB_USB3_MAC_CSR_BASE + 0x0170)
+
+/*---------------- SSUSB_USB3_MAC_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_LTSSM_CTRL */
+#define FORCE_POLLING_FAIL	BIT(4)
+#define FORCE_RXDETECT_FAIL	BIT(3)
+#define SOFT_U3_EXIT_EN		BIT(2)
+#define COMPLIANCE_EN		BIT(1)
+#define U1_GO_U2_EN		BIT(0)
+
+/* U3D_USB3_CONFIG */
+#define USB3_EN			BIT(0)
+
+/* U3D_LINK_STATE_MACHINE */
+#define LTSSM_STATE(x)	((x) & 0x1f)
+
+/* U3D_LTSSM_INTR_ENABLE */
+/* U3D_LTSSM_INTR */
+#define U3_RESUME_INTR		BIT(18)
+#define U3_LFPS_TMOUT_INTR	BIT(17)
+#define VBUS_FALL_INTR		BIT(16)
+#define VBUS_RISE_INTR		BIT(15)
+#define RXDET_SUCCESS_INTR	BIT(14)
+#define EXIT_U3_INTR		BIT(13)
+#define EXIT_U2_INTR		BIT(12)
+#define EXIT_U1_INTR		BIT(11)
+#define ENTER_U3_INTR		BIT(10)
+#define ENTER_U2_INTR		BIT(9)
+#define ENTER_U1_INTR		BIT(8)
+#define ENTER_U0_INTR		BIT(7)
+#define RECOVERY_INTR		BIT(6)
+#define WARM_RST_INTR		BIT(5)
+#define HOT_RST_INTR		BIT(4)
+#define LOOPBACK_INTR		BIT(3)
+#define COMPLIANCE_INTR		BIT(2)
+#define SS_DISABLE_INTR		BIT(1)
+#define SS_INACTIVE_INTR	BIT(0)
+
+/* U3D_U3U2_SWITCH_CTRL */
+#define SOFTCON_CLR_AUTO_EN	BIT(0)
+
+/*---------------- SSUSB_USB3_SYS_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_LINK_UX_INACT_TIMER	(SSUSB_USB3_SYS_CSR_BASE + 0x020C)
+#define U3D_LINK_POWER_CONTROL	(SSUSB_USB3_SYS_CSR_BASE + 0x0210)
+#define U3D_LINK_ERR_COUNT	(SSUSB_USB3_SYS_CSR_BASE + 0x0214)
+
+/*---------------- SSUSB_USB3_SYS_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_LINK_UX_INACT_TIMER */
+#define DEV_U2_INACT_TIMEOUT_MSK	GENMASK(23, 16)
+#define DEV_U2_INACT_TIMEOUT_VALUE(x)	(((x) & 0xff) << 16)
+#define U2_INACT_TIMEOUT_MSK		GENMASK(15, 8)
+#define U1_INACT_TIMEOUT_MSK		GENMASK(7, 0)
+#define U1_INACT_TIMEOUT_VALUE(x)	((x) & 0xff)
+
+/* U3D_LINK_POWER_CONTROL */
+#define SW_U2_ACCEPT_ENABLE	BIT(9)
+#define SW_U1_ACCEPT_ENABLE	BIT(8)
+#define UX_EXIT			BIT(5)
+#define LGO_U3			BIT(4)
+#define LGO_U2			BIT(3)
+#define LGO_U1			BIT(2)
+#define SW_U2_REQUEST_ENABLE	BIT(1)
+#define SW_U1_REQUEST_ENABLE	BIT(0)
+
+/* U3D_LINK_ERR_COUNT */
+#define CLR_LINK_ERR_CNT	BIT(16)
+#define LINK_ERROR_COUNT	GENMASK(15, 0)
+
+/*---------------- SSUSB_USB2_CSR REGISTER DEFINITION ----------------*/
+
+#define U3D_POWER_MANAGEMENT		(SSUSB_USB2_CSR_BASE + 0x0004)
+#define U3D_DEVICE_CONTROL		(SSUSB_USB2_CSR_BASE + 0x000C)
+#define U3D_USB2_TEST_MODE		(SSUSB_USB2_CSR_BASE + 0x0014)
+#define U3D_COMMON_USB_INTR_ENABLE	(SSUSB_USB2_CSR_BASE + 0x0018)
+#define U3D_COMMON_USB_INTR		(SSUSB_USB2_CSR_BASE + 0x001C)
+#define U3D_LINK_RESET_INFO		(SSUSB_USB2_CSR_BASE + 0x0024)
+#define U3D_USB20_FRAME_NUM		(SSUSB_USB2_CSR_BASE + 0x003C)
+#define U3D_USB20_LPM_PARAMETER		(SSUSB_USB2_CSR_BASE + 0x0044)
+#define U3D_USB20_MISC_CONTROL		(SSUSB_USB2_CSR_BASE + 0x004C)
+#define U3D_USB20_OPSTATE		(SSUSB_USB2_CSR_BASE + 0x0060)
+
+/*---------------- SSUSB_USB2_CSR FIELD DEFINITION ----------------*/
+
+/* U3D_POWER_MANAGEMENT */
+#define LPM_BESL_STALL		BIT(14)
+#define LPM_BESLD_STALL		BIT(13)
+#define LPM_RWP			BIT(11)
+#define LPM_HRWE		BIT(10)
+#define LPM_MODE(x)		(((x) & 0x3) << 8)
+#define ISO_UPDATE		BIT(7)
+#define SOFT_CONN		BIT(6)
+#define HS_ENABLE		BIT(5)
+#define RESUME			BIT(2)
+#define SUSPENDM_ENABLE		BIT(0)
+
+/* U3D_DEVICE_CONTROL */
+#define DC_HOSTREQ		BIT(1)
+#define DC_SESSION		BIT(0)
+
+/* U3D_USB2_TEST_MODE */
+#define U2U3_AUTO_SWITCH	BIT(10)
+#define LPM_FORCE_STALL		BIT(8)
+#define FIFO_ACCESS		BIT(6)
+#define FORCE_FS		BIT(5)
+#define FORCE_HS		BIT(4)
+#define TEST_PACKET_MODE	BIT(3)
+#define TEST_K_MODE		BIT(2)
+#define TEST_J_MODE		BIT(1)
+#define TEST_SE0_NAK_MODE	BIT(0)
+
+/* U3D_COMMON_USB_INTR_ENABLE */
+/* U3D_COMMON_USB_INTR */
+#define LPM_RESUME_INTR		BIT(9)
+#define LPM_INTR		BIT(8)
+#define DISCONN_INTR		BIT(5)
+#define CONN_INTR		BIT(4)
+#define SOF_INTR		BIT(3)
+#define RESET_INTR		BIT(2)
+#define RESUME_INTR		BIT(1)
+#define SUSPEND_INTR		BIT(0)
+
+/* U3D_LINK_RESET_INFO */
+#define WTCHRP_MSK		GENMASK(19, 16)
+
+/* U3D_USB20_LPM_PARAMETER */
+#define LPM_BESLCK_U3(x)	(((x) & 0xf) << 12)
+#define LPM_BESLCK(x)		(((x) & 0xf) << 8)
+#define LPM_BESLDCK(x)		(((x) & 0xf) << 4)
+#define LPM_BESL		GENMASK(3, 0)
+
+/* U3D_USB20_MISC_CONTROL */
+#define LPM_U3_ACK_EN		BIT(0)
+
+/*---------------- SSUSB_SIFSLV_IPPC REGISTER DEFINITION ----------------*/
+
+#define U3D_SSUSB_IP_PW_CTRL0	(SSUSB_SIFSLV_IPPC_BASE + 0x0000)
+#define U3D_SSUSB_IP_PW_CTRL1	(SSUSB_SIFSLV_IPPC_BASE + 0x0004)
+#define U3D_SSUSB_IP_PW_CTRL2	(SSUSB_SIFSLV_IPPC_BASE + 0x0008)
+#define U3D_SSUSB_IP_PW_CTRL3	(SSUSB_SIFSLV_IPPC_BASE + 0x000C)
+#define U3D_SSUSB_IP_PW_STS1	(SSUSB_SIFSLV_IPPC_BASE + 0x0010)
+#define U3D_SSUSB_IP_PW_STS2	(SSUSB_SIFSLV_IPPC_BASE + 0x0014)
+#define U3D_SSUSB_OTG_STS	(SSUSB_SIFSLV_IPPC_BASE + 0x0018)
+#define U3D_SSUSB_OTG_STS_CLR	(SSUSB_SIFSLV_IPPC_BASE + 0x001C)
+#define U3D_SSUSB_IP_XHCI_CAP	(SSUSB_SIFSLV_IPPC_BASE + 0x0024)
+#define U3D_SSUSB_IP_DEV_CAP	(SSUSB_SIFSLV_IPPC_BASE + 0x0028)
+#define U3D_SSUSB_OTG_INT_EN	(SSUSB_SIFSLV_IPPC_BASE + 0x002C)
+#define U3D_SSUSB_U3_CTRL_0P	(SSUSB_SIFSLV_IPPC_BASE + 0x0030)
+#define U3D_SSUSB_U2_CTRL_0P	(SSUSB_SIFSLV_IPPC_BASE + 0x0050)
+#define U3D_SSUSB_REF_CK_CTRL	(SSUSB_SIFSLV_IPPC_BASE + 0x008C)
+#define U3D_SSUSB_DEV_RST_CTRL	(SSUSB_SIFSLV_IPPC_BASE + 0x0098)
+#define U3D_SSUSB_HW_ID		(SSUSB_SIFSLV_IPPC_BASE + 0x00A0)
+#define U3D_SSUSB_HW_SUB_ID	(SSUSB_SIFSLV_IPPC_BASE + 0x00A4)
+#define U3D_SSUSB_IP_TRUNK_VERS	(U3D_SSUSB_HW_SUB_ID)
+#define U3D_SSUSB_PRB_CTRL0	(SSUSB_SIFSLV_IPPC_BASE + 0x00B0)
+#define U3D_SSUSB_PRB_CTRL1	(SSUSB_SIFSLV_IPPC_BASE + 0x00B4)
+#define U3D_SSUSB_PRB_CTRL2	(SSUSB_SIFSLV_IPPC_BASE + 0x00B8)
+#define U3D_SSUSB_PRB_CTRL3	(SSUSB_SIFSLV_IPPC_BASE + 0x00BC)
+#define U3D_SSUSB_PRB_CTRL4	(SSUSB_SIFSLV_IPPC_BASE + 0x00C0)
+#define U3D_SSUSB_PRB_CTRL5	(SSUSB_SIFSLV_IPPC_BASE + 0x00C4)
+#define U3D_SSUSB_IP_SPARE0	(SSUSB_SIFSLV_IPPC_BASE + 0x00C8)
+
+/*---------------- SSUSB_SIFSLV_IPPC FIELD DEFINITION ----------------*/
+
+/* U3D_SSUSB_IP_PW_CTRL0 */
+#define SSUSB_IP_SW_RST			BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL1 */
+#define SSUSB_IP_HOST_PDN		BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL2 */
+#define SSUSB_IP_DEV_PDN		BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL3 */
+#define SSUSB_IP_PCIE_PDN		BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS1 */
+#define SSUSB_IP_SLEEP_STS		BIT(30)
+#define SSUSB_U3_MAC_RST_B_STS		BIT(16)
+#define SSUSB_XHCI_RST_B_STS		BIT(11)
+#define SSUSB_SYS125_RST_B_STS		BIT(10)
+#define SSUSB_REF_RST_B_STS		BIT(8)
+#define SSUSB_SYSPLL_STABLE		BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS2 */
+#define SSUSB_U2_MAC_SYS_RST_B_STS	BIT(0)
+
+/* U3D_SSUSB_OTG_STS */
+#define SSUSB_VBUS_VALID		BIT(9)
+
+/* U3D_SSUSB_OTG_STS_CLR */
+#define SSUSB_VBUS_INTR_CLR		BIT(6)
+
+/* U3D_SSUSB_IP_XHCI_CAP */
+#define SSUSB_IP_XHCI_U2_PORT_NUM(x)	(((x) >> 8) & 0xff)
+#define SSUSB_IP_XHCI_U3_PORT_NUM(x)	((x) & 0xff)
+
+/* U3D_SSUSB_IP_DEV_CAP */
+#define SSUSB_IP_DEV_U3_PORT_NUM(x)	((x) & 0xff)
+
+/* U3D_SSUSB_OTG_INT_EN */
+#define SSUSB_VBUS_CHG_INT_A_EN		BIT(7)
+#define SSUSB_VBUS_CHG_INT_B_EN		BIT(6)
+
+/* U3D_SSUSB_U3_CTRL_0P */
+#define SSUSB_U3_PORT_SSP_SPEED	BIT(9)
+#define SSUSB_U3_PORT_DUAL_MODE	BIT(7)
+#define SSUSB_U3_PORT_HOST_SEL		BIT(2)
+#define SSUSB_U3_PORT_PDN		BIT(1)
+#define SSUSB_U3_PORT_DIS		BIT(0)
+
+/* U3D_SSUSB_U2_CTRL_0P */
+#define SSUSB_U2_PORT_RG_IDDIG		BIT(12)
+#define SSUSB_U2_PORT_FORCE_IDDIG	BIT(11)
+#define SSUSB_U2_PORT_VBUSVALID	BIT(9)
+#define SSUSB_U2_PORT_OTG_SEL		BIT(7)
+#define SSUSB_U2_PORT_HOST		BIT(2)
+#define SSUSB_U2_PORT_PDN		BIT(1)
+#define SSUSB_U2_PORT_DIS		BIT(0)
+#define SSUSB_U2_PORT_HOST_SEL	(SSUSB_U2_PORT_VBUSVALID | SSUSB_U2_PORT_HOST)
+
+/* U3D_SSUSB_DEV_RST_CTRL */
+#define SSUSB_DEV_SW_RST		BIT(0)
+
+/* U3D_SSUSB_IP_TRUNK_VERS */
+#define IP_TRUNK_VERS(x)		(((x) >> 16) & 0xffff)
+
+#endif	/* _SSUSB_HW_REGS_H_ */
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
new file mode 100644
index 0000000..24ffdb3
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm/lists.h>
+#include <linux/iopoll.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+			  enum mtu3_dr_force_mode mode)
+{
+	u32 value;
+
+	value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
+	switch (mode) {
+	case MTU3_DR_FORCE_DEVICE:
+		value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
+		break;
+	case MTU3_DR_FORCE_HOST:
+		value |= SSUSB_U2_PORT_FORCE_IDDIG;
+		value &= ~SSUSB_U2_PORT_RG_IDDIG;
+		break;
+	case MTU3_DR_FORCE_NONE:
+		value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
+		break;
+	default:
+		return;
+	}
+	mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
+}
+
+/* u2-port0 should be powered on and enabled; */
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks)
+{
+	void __iomem *ibase = ssusb->ippc_base;
+	u32 value, check_val;
+	int ret;
+
+	check_val = ex_clks | SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
+			SSUSB_REF_RST_B_STS;
+
+	ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value,
+				 ((value & check_val) == check_val), 10000);
+	if (ret) {
+		dev_err(ssusb->dev, "clks of sts1 are not stable!\n");
+		return ret;
+	}
+
+	ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS2, value,
+				 (value & SSUSB_U2_MAC_SYS_RST_B_STS), 10000);
+	if (ret) {
+		dev_err(ssusb->dev, "mac2 clock is not stable\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int ssusb_phy_setup(struct ssusb_mtk *ssusb)
+{
+	struct udevice *dev = ssusb->dev;
+	struct phy_bulk *phys = &ssusb->phys;
+	int ret;
+
+	ret = generic_phy_get_bulk(dev, phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_init_bulk(phys);
+	if (ret)
+		return ret;
+
+	ret = generic_phy_power_on_bulk(phys);
+	if (ret)
+		generic_phy_exit_bulk(phys);
+
+	return ret;
+}
+
+void ssusb_phy_shutdown(struct ssusb_mtk *ssusb)
+{
+	generic_phy_power_off_bulk(&ssusb->phys);
+	generic_phy_exit_bulk(&ssusb->phys);
+}
+
+static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
+{
+	int ret = 0;
+
+	ret = regulator_set_enable(ssusb->vusb33_supply, true);
+	if (ret < 0 && ret != -ENOSYS) {
+		dev_err(ssusb->dev, "failed to enable vusb33\n");
+		goto vusb33_err;
+	}
+
+	ret = clk_enable_bulk(&ssusb->clks);
+	if (ret)
+		goto clks_err;
+
+	ret = ssusb_phy_setup(ssusb);
+	if (ret) {
+		dev_err(ssusb->dev, "failed to setup phy\n");
+		goto phy_err;
+	}
+
+	return 0;
+
+phy_err:
+	clk_disable_bulk(&ssusb->clks);
+clks_err:
+	regulator_set_enable(ssusb->vusb33_supply, false);
+vusb33_err:
+	return ret;
+}
+
+static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
+{
+	clk_disable_bulk(&ssusb->clks);
+	regulator_set_enable(ssusb->vusb33_supply, false);
+	ssusb_phy_shutdown(ssusb);
+}
+
+static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
+{
+	/* reset whole ip (xhci & u3d) */
+	mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+	udelay(1);
+	mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+}
+
+static int get_ssusb_rscs(struct udevice *dev, struct ssusb_mtk *ssusb)
+{
+	struct udevice *child;
+	int ret;
+
+	ret = device_get_supply_regulator(dev, "vusb33-supply",
+					  &ssusb->vusb33_supply);
+	if (ret)	/* optional, ignore error */
+		dev_warn(dev, "can't get optional vusb33 %d\n", ret);
+
+	ret = device_get_supply_regulator(dev, "vbus-supply",
+					  &ssusb->vbus_supply);
+	if (ret)	/* optional, ignore error */
+		dev_warn(dev, "can't get optional vbus regulator %d!\n", ret);
+
+	ret = clk_get_bulk(dev, &ssusb->clks);
+	if (ret) {
+		dev_err(dev, "failed to get clocks %d!\n", ret);
+		return ret;
+	}
+
+	ssusb->ippc_base = devfdt_remap_addr_name(dev, "ippc");
+	if (!ssusb->ippc_base) {
+		dev_err(dev, "error mapping memory for ippc\n");
+		return -ENODEV;
+	}
+
+	ret = device_find_first_child(dev, &child);
+	if (ret || !child) {
+		dev_err(dev, "failed to get child %d!\n", ret);
+		return ret;
+	}
+
+	ssusb->mac_base = devfdt_remap_addr_name(child, "mac");
+	if (!ssusb->mac_base) {
+		dev_err(dev, "error mapping memory for mac\n");
+		return -ENODEV;
+	}
+
+	ssusb->dr_mode = usb_get_dr_mode(child->node);
+
+	if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN ||
+		ssusb->dr_mode == USB_DR_MODE_OTG)
+		ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+	if (IS_ENABLED(CONFIG_USB_MTU3_GADGET))
+		ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+	else if (IS_ENABLED(CONFIG_USB_MTU3_HOST))
+		ssusb->dr_mode = USB_DR_MODE_HOST;
+
+	dev_info(dev, "dr_mode: %d, ippc: 0x%p, mac: 0x%p\n",
+		 ssusb->dr_mode, ssusb->ippc_base, ssusb->mac_base);
+
+	return 0;
+}
+
+static int mtu3_probe(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_get_priv(dev);
+	int ret = -ENOMEM;
+
+	ssusb->dev = dev;
+
+	ret = get_ssusb_rscs(dev, ssusb);
+	if (ret)
+		return ret;
+
+	ret = ssusb_rscs_init(ssusb);
+	if (ret)
+		return ret;
+
+	ssusb_ip_sw_reset(ssusb);
+
+	return 0;
+}
+
+static int mtu3_remove(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
+
+	ssusb_rscs_exit(ssusb);
+	return 0;
+}
+
+static const struct udevice_id ssusb_of_match[] = {
+	{.compatible = "mediatek,ssusb",},
+	{},
+};
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct mtu3 *mtu = dev_get_priv(dev);
+
+	mtu3_irq(0, mtu);
+
+	return 0;
+}
+
+static int mtu3_gadget_probe(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
+	struct mtu3 *mtu = dev_get_priv(dev);
+
+	mtu->dev = dev;
+	ssusb->u3d = mtu;
+	return ssusb_gadget_init(ssusb);
+}
+
+static int mtu3_gadget_remove(struct udevice *dev)
+{
+	struct mtu3 *mtu = dev_get_priv(dev);
+
+	ssusb_gadget_exit(mtu->ssusb);
+	return 0;
+}
+
+U_BOOT_DRIVER(mtu3_peripheral) = {
+	.name = "mtu3-peripheral",
+	.id = UCLASS_USB_GADGET_GENERIC,
+	.of_match = ssusb_of_match,
+	.probe = mtu3_gadget_probe,
+	.remove = mtu3_gadget_remove,
+	.priv_auto_alloc_size = sizeof(struct mtu3),
+};
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	(!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+static int mtu3_host_probe(struct udevice *dev)
+{
+	struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent);
+	struct mtu3_host *u3h = dev_get_priv(dev);
+	struct xhci_hcor *hcor;
+	int rc;
+
+	u3h->dev = dev;
+	ssusb->u3h = u3h;
+	rc = ssusb_host_init(ssusb);
+	if (rc)
+		return rc;
+
+	u3h->ctrl.quirks = XHCI_MTK_HOST;
+	hcor = (struct xhci_hcor *)((uintptr_t)u3h->hcd +
+			HC_LENGTH(xhci_readl(&u3h->hcd->cr_capbase)));
+
+	return xhci_register(dev, u3h->hcd, hcor);
+}
+
+static int mtu3_host_remove(struct udevice *dev)
+{
+	struct mtu3_host *u3h = dev_get_priv(dev);
+
+	xhci_deregister(dev);
+	ssusb_host_exit(u3h->ssusb);
+	return 0;
+}
+
+U_BOOT_DRIVER(mtu3_host) = {
+	.name = "mtu3-host",
+	.id = UCLASS_USB,
+	.of_match = ssusb_of_match,
+	.probe = mtu3_host_probe,
+	.remove = mtu3_host_remove,
+	.priv_auto_alloc_size = sizeof(struct mtu3_host),
+	.ops = &xhci_usb_ops,
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
+
+static int mtu3_glue_bind(struct udevice *parent)
+{
+	struct udevice *dev;
+	enum usb_dr_mode dr_mode;
+	const char *driver;
+	const char *name;
+	ofnode node;
+	int ret;
+
+	node = ofnode_by_compatible(parent->node, "mediatek,ssusb");
+	if (!ofnode_valid(node))
+		return -ENODEV;
+
+	name = ofnode_get_name(node);
+	dr_mode = usb_get_dr_mode(node);
+
+	switch (dr_mode) {
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
+		dev_dbg(parent, "%s: dr_mode: peripheral\n", __func__);
+		driver = "mtu3-peripheral";
+		break;
+#endif
+
+#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
+	(!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST))
+	case USB_DR_MODE_HOST:
+		dev_dbg(parent, "%s: dr_mode: host\n", __func__);
+		driver = "mtu3-host";
+		break;
+#endif
+	default:
+		dev_err(parent, "%s: unsupported dr_mode %d\n",
+			__func__, dr_mode);
+		return -ENODEV;
+	};
+
+	dev_dbg(parent, "%s: node name: %s, driver %s, dr_mode %d\n",
+		__func__, name, driver, dr_mode);
+
+	ret = device_bind_driver_to_node(parent, driver, name, node, &dev);
+	if (ret)
+		dev_err("%s: not able to bind usb device mode\n", __func__);
+
+	return ret;
+}
+
+static const struct udevice_id mtu3_of_match[] = {
+	{.compatible = "mediatek,mtu3",},
+	{},
+};
+
+U_BOOT_DRIVER(mtu3) = {
+	.name = "mtu3",
+	.id = UCLASS_NOP,
+	.of_match = mtu3_of_match,
+	.bind = mtu3_glue_bind,
+	.probe = mtu3_probe,
+	.remove = mtu3_remove,
+	.priv_auto_alloc_size = sizeof(struct ssusb_mtk),
+};
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c
new file mode 100644
index 0000000..f602e50
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_qmu.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_qmu.c - Queue Management Unit driver for device controller
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+/*
+ * Queue Management Unit (QMU) is designed to unload SW effort
+ * to serve DMA interrupts.
+ * By preparing General Purpose Descriptor (GPD) and Buffer Descriptor (BD),
+ * SW links data buffers and triggers QMU to send / receive data to
+ * host / from device at a time.
+ * And now only GPD is supported.
+ *
+ * For more detailed information, please refer to QMU Programming Guide
+ */
+
+#include <asm/cache.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+
+#include "mtu3.h"
+
+#define QMU_CHECKSUM_LEN	16
+
+#define GPD_FLAGS_HWO	BIT(0)
+#define GPD_FLAGS_BDP	BIT(1)
+#define GPD_FLAGS_BPS	BIT(2)
+#define GPD_FLAGS_IOC	BIT(7)
+
+#define GPD_EXT_FLAG_ZLP	BIT(5)
+
+#define DCACHELINE_SIZE		CONFIG_SYS_CACHELINE_SIZE
+
+void mtu3_flush_cache(uintptr_t addr, u32 len)
+{
+	WARN_ON(!(void *)addr || len == 0);
+
+	flush_dcache_range(addr & ~(DCACHELINE_SIZE - 1),
+			   ALIGN(addr + len, DCACHELINE_SIZE));
+}
+
+void mtu3_inval_cache(uintptr_t addr, u32 len)
+{
+	WARN_ON(!(void *)addr || len == 0);
+
+	invalidate_dcache_range(addr & ~(DCACHELINE_SIZE - 1),
+				ALIGN(addr + len, DCACHELINE_SIZE));
+}
+
+static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
+				       dma_addr_t dma_addr)
+{
+	dma_addr_t dma_base = ring->dma;
+	struct qmu_gpd *gpd_head = ring->start;
+	u32 offset = (dma_addr - dma_base) / sizeof(*gpd_head);
+
+	if (offset >= MAX_GPD_NUM)
+		return NULL;
+
+	return gpd_head + offset;
+}
+
+static dma_addr_t gpd_virt_to_dma(struct mtu3_gpd_ring *ring,
+				  struct qmu_gpd *gpd)
+{
+	dma_addr_t dma_base = ring->dma;
+	struct qmu_gpd *gpd_head = ring->start;
+	u32 offset;
+
+	offset = gpd - gpd_head;
+	if (offset >= MAX_GPD_NUM)
+		return 0;
+
+	return dma_base + (offset * sizeof(*gpd));
+}
+
+static void gpd_ring_init(struct mtu3_gpd_ring *ring, struct qmu_gpd *gpd)
+{
+	ring->start = gpd;
+	ring->enqueue = gpd;
+	ring->dequeue = gpd;
+	ring->end = gpd + MAX_GPD_NUM - 1;
+}
+
+static void reset_gpd_list(struct mtu3_ep *mep)
+{
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	struct qmu_gpd *gpd = ring->start;
+
+	if (gpd) {
+		gpd->flag &= ~GPD_FLAGS_HWO;
+		gpd_ring_init(ring, gpd);
+		mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+	}
+}
+
+int mtu3_gpd_ring_alloc(struct mtu3_ep *mep)
+{
+	struct qmu_gpd *gpd;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+	/* software own all gpds as default */
+	gpd = memalign(DCACHELINE_SIZE, QMU_GPD_RING_SIZE);
+	if (!gpd)
+		return -ENOMEM;
+
+	memset(gpd, 0, QMU_GPD_RING_SIZE);
+	ring->dma = (dma_addr_t)gpd;
+	gpd_ring_init(ring, gpd);
+
+	return 0;
+}
+
+void mtu3_gpd_ring_free(struct mtu3_ep *mep)
+{
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+	kfree(ring->start);
+	memset(ring, 0, sizeof(*ring));
+}
+
+void mtu3_qmu_resume(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	int epnum = mep->epnum;
+	u32 offset;
+
+	offset = mep->is_in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+	mtu3_writel(mbase, offset, QMU_Q_RESUME);
+	if (!(mtu3_readl(mbase, offset) & QMU_Q_ACTIVE))
+		mtu3_writel(mbase, offset, QMU_Q_RESUME);
+}
+
+static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
+{
+	if (ring->enqueue < ring->end)
+		ring->enqueue++;
+	else
+		ring->enqueue = ring->start;
+
+	return ring->enqueue;
+}
+
+static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
+{
+	if (ring->dequeue < ring->end)
+		ring->dequeue++;
+	else
+		ring->dequeue = ring->start;
+
+	return ring->dequeue;
+}
+
+/* check if a ring is emtpy */
+static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+{
+	struct qmu_gpd *enq = ring->enqueue;
+	struct qmu_gpd *next;
+
+	if (ring->enqueue < ring->end)
+		next = enq + 1;
+	else
+		next = ring->start;
+
+	/* one gpd is reserved to simplify gpd preparation */
+	return next == ring->dequeue;
+}
+
+int mtu3_prepare_transfer(struct mtu3_ep *mep)
+{
+	return gpd_ring_empty(&mep->gpd_ring);
+}
+
+static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	struct qmu_gpd *enq;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	struct qmu_gpd *gpd = ring->enqueue;
+	struct usb_request *req = &mreq->request;
+
+	/* set all fields to zero as default value */
+	memset(gpd, 0, sizeof(*gpd));
+
+	gpd->buffer = cpu_to_le32((u32)req->dma);
+	gpd->buf_len = cpu_to_le16(req->length);
+
+	/* get the next GPD */
+	enq = advance_enq_gpd(ring);
+	dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p\n",
+		mep->epnum, gpd, enq);
+
+	enq->flag &= ~GPD_FLAGS_HWO;
+	gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
+
+	if (req->zero)
+		gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
+
+	gpd->flag |= GPD_FLAGS_IOC | GPD_FLAGS_HWO;
+
+	mreq->gpd = gpd;
+
+	if (req->length)
+		mtu3_flush_cache((uintptr_t)req->buf, req->length);
+
+	mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	return 0;
+}
+
+static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	struct qmu_gpd *enq;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	struct qmu_gpd *gpd = ring->enqueue;
+	struct usb_request *req = &mreq->request;
+
+	/* set all fields to zero as default value */
+	memset(gpd, 0, sizeof(*gpd));
+
+	gpd->buffer = cpu_to_le32((u32)req->dma);
+	gpd->data_buf_len = cpu_to_le16(req->length);
+
+	/* get the next GPD */
+	enq = advance_enq_gpd(ring);
+	dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p\n",
+		mep->epnum, gpd, enq);
+
+	enq->flag &= ~GPD_FLAGS_HWO;
+	gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
+	gpd->flag |= GPD_FLAGS_IOC | GPD_FLAGS_HWO;
+
+	mreq->gpd = gpd;
+
+	mtu3_inval_cache((uintptr_t)req->buf, req->length);
+	mtu3_flush_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	return 0;
+}
+
+void mtu3_insert_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
+{
+	if (mep->is_in)
+		mtu3_prepare_tx_gpd(mep, mreq);
+	else
+		mtu3_prepare_rx_gpd(mep, mreq);
+}
+
+int mtu3_qmu_start(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	u8 epnum = mep->epnum;
+
+	if (mep->is_in) {
+		/* set QMU start address */
+		mtu3_writel(mbase, USB_QMU_TQSAR(epnum), ring->dma);
+		mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN);
+		/* send zero length packet according to ZLP flag in GPD */
+		mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum));
+		mtu3_writel(mbase, U3D_TQERRIESR0,
+			    QMU_TX_LEN_ERR(epnum) | QMU_TX_CS_ERR(epnum));
+
+		if (mtu3_readl(mbase, USB_QMU_TQCSR(epnum)) & QMU_Q_ACTIVE) {
+			dev_warn(mtu->dev, "Tx %d Active Now!\n", epnum);
+			return 0;
+		}
+		mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START);
+
+	} else {
+		mtu3_writel(mbase, USB_QMU_RQSAR(epnum), ring->dma);
+		mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN);
+		/* don't expect ZLP */
+		mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum));
+		/* move to next GPD when receive ZLP */
+		mtu3_setbits(mbase, U3D_QCR3, QMU_RX_COZ(epnum));
+		mtu3_writel(mbase, U3D_RQERRIESR0,
+			    QMU_RX_LEN_ERR(epnum) | QMU_RX_CS_ERR(epnum));
+		mtu3_writel(mbase, U3D_RQERRIESR1, QMU_RX_ZLP_ERR(epnum));
+
+		if (mtu3_readl(mbase, USB_QMU_RQCSR(epnum)) & QMU_Q_ACTIVE) {
+			dev_warn(mtu->dev, "Rx %d Active Now!\n", epnum);
+			return 0;
+		}
+		mtu3_writel(mbase, USB_QMU_RQCSR(epnum), QMU_Q_START);
+	}
+
+	return 0;
+}
+
+/* may called in atomic context */
+void mtu3_qmu_stop(struct mtu3_ep *mep)
+{
+	struct mtu3 *mtu = mep->mtu;
+	void __iomem *mbase = mtu->mac_base;
+	int epnum = mep->epnum;
+	u32 value = 0;
+	u32 qcsr;
+	int ret;
+
+	qcsr = mep->is_in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+	if (!(mtu3_readl(mbase, qcsr) & QMU_Q_ACTIVE)) {
+		dev_dbg(mtu->dev, "%s's qmu is inactive now!\n", mep->name);
+		return;
+	}
+	mtu3_writel(mbase, qcsr, QMU_Q_STOP);
+
+	ret = readl_poll_timeout(mbase + qcsr, value,
+				 !(value & QMU_Q_ACTIVE), 1000);
+	if (ret) {
+		dev_err(mtu->dev, "stop %s's qmu failed\n", mep->name);
+		return;
+	}
+
+	dev_dbg(mtu->dev, "%s's qmu stop now!\n", mep->name);
+}
+
+void mtu3_qmu_flush(struct mtu3_ep *mep)
+{
+	dev_dbg(mep->mtu->dev, "%s flush QMU %s\n", __func__,
+		((mep->is_in) ? "TX" : "RX"));
+
+	/*Stop QMU */
+	mtu3_qmu_stop(mep);
+	reset_gpd_list(mep);
+}
+
+/*
+ * NOTE: request list maybe is already empty as following case:
+ * queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)-->
+ * queue_tx --> process_tasklet(meanwhile, the second one is transferred,
+ * tasklet process both of them)-->qmu_interrupt for second one.
+ * To avoid upper case, put qmu_done_tx in ISR directly to process it.
+ */
+static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
+{
+	struct mtu3_ep *mep = mtu->in_eps + epnum;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	void __iomem *mbase = mtu->mac_base;
+	struct qmu_gpd *gpd = ring->dequeue;
+	struct qmu_gpd *gpd_current = NULL;
+	struct usb_request *req = NULL;
+	struct mtu3_request *mreq;
+	dma_addr_t cur_gpd_dma;
+
+	/*transfer phy address got from QMU register to virtual address */
+	cur_gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
+	gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+	mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
+		__func__, epnum, gpd, gpd_current, ring->enqueue);
+
+	while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+		mreq = next_request(mep);
+
+		if (!mreq || mreq->gpd != gpd) {
+			dev_err(mtu->dev, "no correct TX req is found\n");
+			break;
+		}
+
+		req = &mreq->request;
+		req->actual = le16_to_cpu(gpd->buf_len);
+		mtu3_req_complete(mep, req, 0);
+
+		gpd = advance_deq_gpd(ring);
+		mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+	}
+
+	dev_dbg(mtu->dev, "%s EP%d, deq=%p, enq=%p, complete\n",
+		__func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
+{
+	struct mtu3_ep *mep = mtu->out_eps + epnum;
+	struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+	void __iomem *mbase = mtu->mac_base;
+	struct qmu_gpd *gpd = ring->dequeue;
+	struct qmu_gpd *gpd_current = NULL;
+	struct usb_request *req = NULL;
+	struct mtu3_request *mreq;
+	dma_addr_t cur_gpd_dma;
+
+	cur_gpd_dma = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
+	gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+	mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+
+	dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
+		__func__, epnum, gpd, gpd_current, ring->enqueue);
+
+	while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+		mreq = next_request(mep);
+
+		if (!mreq || mreq->gpd != gpd) {
+			dev_err(mtu->dev, "no correct RX req is found\n");
+			break;
+		}
+		req = &mreq->request;
+
+		req->actual = le16_to_cpu(gpd->buf_len);
+		mtu3_req_complete(mep, req, 0);
+
+		gpd = advance_deq_gpd(ring);
+		mtu3_inval_cache((uintptr_t)gpd, sizeof(*gpd));
+	}
+
+	dev_dbg(mtu->dev, "%s EP%d, deq=%p, enq=%p, complete\n",
+		__func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_isr(struct mtu3 *mtu, u32 done_status)
+{
+	int i;
+
+	for (i = 1; i < mtu->num_eps; i++) {
+		if (done_status & QMU_RX_DONE_INT(i))
+			qmu_done_rx(mtu, i);
+		if (done_status & QMU_TX_DONE_INT(i))
+			qmu_done_tx(mtu, i);
+	}
+}
+
+static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 errval;
+	int i;
+
+	if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
+		errval = mtu3_readl(mbase, U3D_RQERRIR0);
+		for (i = 1; i < mtu->num_eps; i++) {
+			if (errval & QMU_RX_CS_ERR(i))
+				dev_err(mtu->dev, "Rx %d CS error!\n", i);
+
+			if (errval & QMU_RX_LEN_ERR(i))
+				dev_err(mtu->dev, "RX %d Length error\n", i);
+		}
+		mtu3_writel(mbase, U3D_RQERRIR0, errval);
+	}
+
+	if (qmu_status & RXQ_ZLPERR_INT) {
+		errval = mtu3_readl(mbase, U3D_RQERRIR1);
+		for (i = 1; i < mtu->num_eps; i++) {
+			if (errval & QMU_RX_ZLP_ERR(i))
+				dev_dbg(mtu->dev, "RX EP%d Recv ZLP\n", i);
+		}
+		mtu3_writel(mbase, U3D_RQERRIR1, errval);
+	}
+
+	if ((qmu_status & TXQ_CSERR_INT) || (qmu_status & TXQ_LENERR_INT)) {
+		errval = mtu3_readl(mbase, U3D_TQERRIR0);
+		for (i = 1; i < mtu->num_eps; i++) {
+			if (errval & QMU_TX_CS_ERR(i))
+				dev_err(mtu->dev, "Tx %d checksum error!\n", i);
+
+			if (errval & QMU_TX_LEN_ERR(i))
+				dev_err(mtu->dev, "Tx %d zlp error!\n", i);
+		}
+		mtu3_writel(mbase, U3D_TQERRIR0, errval);
+	}
+}
+
+irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu)
+{
+	void __iomem *mbase = mtu->mac_base;
+	u32 qmu_status;
+	u32 qmu_done_status;
+
+	/* U3D_QISAR1 is read update */
+	qmu_status = mtu3_readl(mbase, U3D_QISAR1);
+	qmu_status &= mtu3_readl(mbase, U3D_QIER1);
+
+	qmu_done_status = mtu3_readl(mbase, U3D_QISAR0);
+	qmu_done_status &= mtu3_readl(mbase, U3D_QIER0);
+	mtu3_writel(mbase, U3D_QISAR0, qmu_done_status); /* W1C */
+	dev_dbg(mtu->dev, "=== QMUdone[tx=%x, rx=%x] QMUexp[%x] ===\n",
+		(qmu_done_status & 0xFFFF), qmu_done_status >> 16,
+		qmu_status);
+
+	if (qmu_done_status)
+		qmu_done_isr(mtu, qmu_done_status);
+
+	if (qmu_status)
+		qmu_exception_isr(mtu, qmu_status);
+
+	return IRQ_HANDLED;
+}
+
+void mtu3_qmu_init(struct mtu3 *mtu)
+{
+	compiletime_assert(QMU_GPD_SIZE == 16, "QMU_GPD size SHOULD be 16B");
+}
+
+void mtu3_qmu_exit(struct mtu3 *mtu)
+{
+}
diff --git a/drivers/usb/mtu3/mtu3_qmu.h b/drivers/usb/mtu3/mtu3_qmu.h
new file mode 100644
index 0000000..ba8a3aa
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_qmu.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtu3_qmu.h - Queue Management Unit driver header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTK_QMU_H__
+#define __MTK_QMU_H__
+
+#define MAX_GPD_NUM		16
+#define QMU_GPD_SIZE		(sizeof(struct qmu_gpd))
+#define QMU_GPD_RING_SIZE	(MAX_GPD_NUM * QMU_GPD_SIZE)
+
+#define GPD_BUF_SIZE		65532
+
+void mtu3_flush_cache(uintptr_t addr, u32 len);
+void mtu3_inval_cache(uintptr_t addr, u32 len);
+
+void mtu3_qmu_stop(struct mtu3_ep *mep);
+int mtu3_qmu_start(struct mtu3_ep *mep);
+void mtu3_qmu_resume(struct mtu3_ep *mep);
+void mtu3_qmu_flush(struct mtu3_ep *mep);
+
+void mtu3_insert_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq);
+int mtu3_prepare_transfer(struct mtu3_ep *mep);
+
+int mtu3_gpd_ring_alloc(struct mtu3_ep *mep);
+void mtu3_gpd_ring_free(struct mtu3_ep *mep);
+
+irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu);
+void mtu3_qmu_init(struct mtu3 *mtu);
+void mtu3_qmu_exit(struct mtu3 *mtu);
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 06/10] usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (4 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:28   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 07/10] arm: dts: mt8512: add usb related nodes Chunfeng Yun
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add an entry in usb_gadget_controller_number() for the MTU3
gadget controller. It is used to bind the USB Ethernet driver.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v4~v7: no changes

v3: new patch
---
 drivers/usb/gadget/gadget_chips.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 587204c..0cdf47c 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -161,6 +161,12 @@
 #define gadget_is_max3420(g)        0
 #endif
 
+#ifdef CONFIG_USB_MTU3_GADGET
+#define gadget_is_mtu3(g)        (!strcmp("mtu3-gadget", (g)->name))
+#else
+#define gadget_is_mtu3(g)        0
+#endif
+
 /**
  * usb_gadget_controller_number - support bcdDevice id convention
  * @gadget: the controller being driven
@@ -224,5 +230,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x24;
 	else if (gadget_is_max3420(gadget))
 		return 0x25;
+	else if (gadget_is_mtu3(gadget))
+		return 0x26;
 	return -ENOENT;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 07/10] arm: dts: mt8512: add usb related nodes
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (5 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 06/10] usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:32   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 08/10] configs: mt8512: enable fastboot Chunfeng Yun
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add usb, usb phy, and fixed regulators nodes

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v5~v7: no changes

v4: add host related properties, add subnode.

v3: remove unused property mediatek,discth

v2: no changes
---
 arch/arm/dts/mt8512-bm1-emmc.dts | 34 ++++++++++++++++++++++++++++
 arch/arm/dts/mt8512.dtsi         | 49 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/arch/arm/dts/mt8512-bm1-emmc.dts b/arch/arm/dts/mt8512-bm1-emmc.dts
index 296ed93..12511b5 100644
--- a/arch/arm/dts/mt8512-bm1-emmc.dts
+++ b/arch/arm/dts/mt8512-bm1-emmc.dts
@@ -43,6 +43,25 @@
 		regulator-boot-on;
 		regulator-always-on;
 	};
+
+	usb_p0_vbus: regulator at 0 {
+		compatible = "regulator-fixed";
+		regulator-name = "p0_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio 27 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	usb_p1_vbus: regulator at 1 {
+		compatible = "regulator-fixed";
+		regulator-name = "p1_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio 32 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
 };
 
 &mmc0 {
@@ -95,6 +114,21 @@
 		};
 };
 
+&ssusb {
+	dr_mode = "peripheral";
+	maximum-speed = "high-speed";
+	status = "okay";
+};
+
+&usb3 {
+	vbus-supply = <&usb_p0_vbus>;
+	status = "okay";
+};
+
+&u3phy {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins>;
diff --git a/arch/arm/dts/mt8512.dtsi b/arch/arm/dts/mt8512.dtsi
index 01a02a7..bdb84f8 100644
--- a/arch/arm/dts/mt8512.dtsi
+++ b/arch/arm/dts/mt8512.dtsi
@@ -9,6 +9,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
 
 / {
 	compatible = "mediatek,mt8512";
@@ -100,6 +101,52 @@
 		status = "disabled";
 	};
 
+	usb3: usb at 11213e00 {
+		compatible = "mediatek,mt8512-mtu3", "mediatek,mtu3";
+		reg = <0x11213e00 0x0100>;
+		reg-names = "ippc";
+		phys = <&u2port0 PHY_TYPE_USB2>, <&u2port1 PHY_TYPE_USB2>;
+		clocks = <&infracfg CLK_INFRA_USB_SYS>,
+			 <&topckgen CLK_TOP_SSUSB_TOP_CK_EN>,
+			 <&infracfg CLK_INFRA_ICUSB>;
+		clock-names = "sys_ck", "ref_ck", "mcu_ck";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		status = "disabled";
+
+		ssusb: usb at 11210000 {
+			compatible = "mediatek,ssusb";
+			reg = <0x11210000 0x3e00>;
+			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_LOW>;
+			reg-names = "mac";
+			status = "disabled";
+		};
+	};
+
+	u3phy: usb-phy at 11cc0000 {
+		compatible = "mediatek,mt8512-tphy",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		status = "disabled";
+
+		u2port0: usb-phy at 11cc0000 {
+			reg = <0x11cc0000 0x400>;
+			clocks = <&topckgen CLK_TOP_USB20_48M_EN>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u2port1: usb-phy at 11c40000 {
+			reg = <0x11c40000 0x400>;
+			#phy-cells = <1>;
+			status = "okay";
+		};
+	};
+
 	mmc0: mmc at 11230000 {
 		compatible = "mediatek,mt8512-mmc";
 		reg = <0x11230000 0x1000>,
@@ -112,4 +159,4 @@
 		status = "disabled";
 	};
 
-};
\ No newline at end of file
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 08/10] configs: mt8512: enable fastboot
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (6 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 07/10] arm: dts: mt8512: add usb related nodes Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-09-18  9:10 ` [PATCH next v7 09/10] configs: mt8512: add USB host related configs Chunfeng Yun
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Enable fastboot to support download image from usb, also enable
usb related drivers, such as usb phy etc.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v2~v7: no changes
---
 configs/mt8512_bm1_emmc_defconfig | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/configs/mt8512_bm1_emmc_defconfig b/configs/mt8512_bm1_emmc_defconfig
index 950507f..d41446f 100644
--- a/configs/mt8512_bm1_emmc_defconfig
+++ b/configs/mt8512_bm1_emmc_defconfig
@@ -9,6 +9,7 @@ CONFIG_DM_GPIO=y
 CONFIG_TARGET_MT8512=y
 CONFIG_DEFAULT_DEVICE_TREE="mt8512-bm1-emmc"
 CONFIG_FIT=y
+CONFIG_EFI_PARTITION=y
 CONFIG_FIT_SIGNATURE=y
 CONFIG_DEFAULT_FDT_FILE="mt8512-bm1-emmc.dtb"
 CONFIG_SYS_PROMPT="MT8512> "
@@ -26,6 +27,15 @@ CONFIG_PINCONF=y
 CONFIG_PINCTRL_MT8512=y
 CONFIG_RAM=y
 CONFIG_BAUDRATE=921600
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x56000000
+CONFIG_FASTBOOT_BUF_SIZE=0x1e00000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT=y
+CONFIG_PHY=y
+CONFIG_PHY_MTK_TPHY=y
+CONFIG_DM_REGULATOR=y
 CONFIG_DM_SERIAL=y
 CONFIG_MTK_SERIAL=y
 CONFIG_TIMER=y
@@ -33,3 +43,12 @@ CONFIG_MTK_TIMER=y
 CONFIG_WDT=y
 CONFIG_WDT_MTK=y
 CONFIG_LZO=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_USB_MTU3=y
+CONFIG_USB_MTU3_GADGET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="MediaTek"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d
+CONFIG_USB_GADGET_PRODUCT_NUM=0x201c
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 09/10] configs: mt8512: add USB host related configs
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (7 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 08/10] configs: mt8512: enable fastboot Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:34   ` Bin Meng
  2020-09-18  9:10 ` [PATCH next v7 10/10] MAINTAINERS: add USB driver to ARM MEDIATEK Chunfeng Yun
  2020-09-28  2:01 ` [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add USB, FAT commands, and fixed regulator, mass storage
drivers.
Due to device mode is enabled by default, comment out
the host mode config here.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v5~v7: no changes

v4: new patch
---
 configs/mt8512_bm1_emmc_defconfig | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/configs/mt8512_bm1_emmc_defconfig b/configs/mt8512_bm1_emmc_defconfig
index d41446f..6b5454c 100644
--- a/configs/mt8512_bm1_emmc_defconfig
+++ b/configs/mt8512_bm1_emmc_defconfig
@@ -15,6 +15,10 @@ CONFIG_DEFAULT_FDT_FILE="mt8512-bm1-emmc.dtb"
 CONFIG_SYS_PROMPT="MT8512> "
 CONFIG_CMD_BOOTMENU=y
 CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+# CONFIG_DOS_PARTITION is not set
 CONFIG_ENV_OVERWRITE=y
 CONFIG_REGMAP=y
 CONFIG_SYSCON=y
@@ -36,6 +40,7 @@ CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT=y
 CONFIG_PHY=y
 CONFIG_PHY_MTK_TPHY=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_SERIAL=y
 CONFIG_MTK_SERIAL=y
 CONFIG_TIMER=y
@@ -48,6 +53,8 @@ CONFIG_DM_USB=y
 CONFIG_DM_USB_GADGET=y
 CONFIG_USB_MTU3=y
 CONFIG_USB_MTU3_GADGET=y
+#CONFIG_USB_MTU3_HOST=y
+CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MANUFACTURER="MediaTek"
 CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 10/10] MAINTAINERS: add USB driver to ARM MEDIATEK
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (8 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 09/10] configs: mt8512: add USB host related configs Chunfeng Yun
@ 2020-09-18  9:10 ` Chunfeng Yun
  2020-10-13 14:35   ` Bin Meng
  2020-09-28  2:01 ` [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-18  9:10 UTC (permalink / raw)
  To: u-boot

Add MediaTek USB3 Dual-Role controller driver to ARM MEDIATEK,
and add myself as a maintainer for it.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v6~v7: no changes

v5: add mtu3/, xhci-mtk.c, and myself as maintainer for MTK USB

v4: new patch
---
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7e46470..08724f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -262,6 +262,7 @@ F:	arch/arm/include/asm/arch-pxa/
 ARM MEDIATEK
 M:	Ryder Lee <ryder.lee@mediatek.com>
 M:	Weijie Gao <weijie.gao@mediatek.com>
+M:	Chunfeng Yun <chunfeng.yun@mediatek.com>
 R:	GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com>
 S:	Maintained
 F:	arch/arm/mach-mediatek/
@@ -278,6 +279,8 @@ F:	drivers/power/domain/mtk-power-domain.c
 F:	drivers/ram/mediatek/
 F:	drivers/spi/mtk_snfi_spi.c
 F:	drivers/timer/mtk_timer.c
+F:	drivers/usb/host/xhci-mtk.c
+F:	drivers/usb/mtu3/
 F:	drivers/watchdog/mtk_wdt.c
 F:	drivers/net/mtk_eth.c
 F:	drivers/reset/reset-mediatek.c
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver
  2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
                   ` (9 preceding siblings ...)
  2020-09-18  9:10 ` [PATCH next v7 10/10] MAINTAINERS: add USB driver to ARM MEDIATEK Chunfeng Yun
@ 2020-09-28  2:01 ` Chunfeng Yun
  2020-09-28  2:12   ` Marek Vasut
  10 siblings, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-28  2:01 UTC (permalink / raw)
  To: u-boot

Hi Marek, Lukasz

   Any comments on this patch series?

Thanks a lot


On Fri, 2020-09-18 at 17:10 +0800, Chunfeng Yun wrote:
> These patches introduce the MediaTek USB3 Dual-Role Controller
> driver.
> The driver can be configured as Peripheral only and Host only(xHCI)
> modes, and it's ported from Linux Kernel 5.8-rc1
> 
> v7 changes
>     1. use xhci quirk flag XHCI_MTK_HOST
> 
> v6 changes
>     1. modify commit message of [4/10]
> 
> v5 changes:
>     1. change condition of readl_poll_timeout() when check clocks
>     2. add xhci-mtk.c and myself as maintainer for MTK USB
> 
> v4 changes:
>     1. [4/10], [9/10] and [10/10] are new patches
>     2. add a glue driver
>     3. add host driver and rebuild host flow
>     4. support force_vbus mode for device
>     5. update bindings to support glue driver
> 
> v3 changes:
>     1. add patch [5/7]
>     2. add udc_set_speed()
>     3. simplify some code flow
> 
> v2 changes:
>     1. simplify QMU operations
> 
> Chunfeng Yun (10):
>   dt-binding: usb: add bindings for some common properties
>   dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD
>   usb: add USB_SPEED_SUPER_PLUS
>   usb: common: add define of usb_speed_string()
>   usb: add MediaTek USB3 DRD driver
>   usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller
>   arm: dts: mt8512: add usb related nodes
>   configs: mt8512: enable fastboot
>   configs: mt8512: add USB host related configs
>   MAINTAINERS: add USB driver to ARM MEDIATEK
> 
>  MAINTAINERS                                    |   3 +
>  Makefile                                       |   1 +
>  arch/arm/dts/mt8512-bm1-emmc.dts               |  34 +
>  arch/arm/dts/mt8512.dtsi                       |  49 +-
>  configs/mt8512_bm1_emmc_defconfig              |  26 +
>  doc/device-tree-bindings/usb/generic.txt       |  31 +
>  doc/device-tree-bindings/usb/mediatek,mtu3.txt |  79 +++
>  drivers/usb/Kconfig                            |   2 +
>  drivers/usb/common/common.c                    |   8 +
>  drivers/usb/gadget/gadget_chips.h              |   8 +
>  drivers/usb/mtu3/Kconfig                       |  45 ++
>  drivers/usb/mtu3/Makefile                      |  11 +
>  drivers/usb/mtu3/mtu3.h                        | 423 +++++++++++
>  drivers/usb/mtu3/mtu3_core.c                   | 838 ++++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_dr.h                     |  52 ++
>  drivers/usb/mtu3/mtu3_gadget.c                 | 686 ++++++++++++++++++
>  drivers/usb/mtu3/mtu3_gadget_ep0.c             | 933 +++++++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_host.c                   | 141 ++++
>  drivers/usb/mtu3/mtu3_hw_regs.h                | 515 ++++++++++++++
>  drivers/usb/mtu3/mtu3_plat.c                   | 368 ++++++++++
>  drivers/usb/mtu3/mtu3_qmu.c                    | 504 +++++++++++++
>  drivers/usb/mtu3/mtu3_qmu.h                    |  37 +
>  include/linux/usb/ch9.h                        |   5 +-
>  23 files changed, 4794 insertions(+), 5 deletions(-)
>  create mode 100644 doc/device-tree-bindings/usb/generic.txt
>  create mode 100644 doc/device-tree-bindings/usb/mediatek,mtu3.txt
>  create mode 100644 drivers/usb/mtu3/Kconfig
>  create mode 100644 drivers/usb/mtu3/Makefile
>  create mode 100644 drivers/usb/mtu3/mtu3.h
>  create mode 100644 drivers/usb/mtu3/mtu3_core.c
>  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
>  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
>  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
>  create mode 100644 drivers/usb/mtu3/mtu3_host.c
>  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
>  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver
  2020-09-28  2:01 ` [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
@ 2020-09-28  2:12   ` Marek Vasut
  2020-09-28  2:20     ` Chunfeng Yun
  2020-10-13  7:26     ` Chunfeng Yun
  0 siblings, 2 replies; 29+ messages in thread
From: Marek Vasut @ 2020-09-28  2:12 UTC (permalink / raw)
  To: u-boot

On 9/28/20 4:01 AM, Chunfeng Yun wrote:
[...]
>>  create mode 100644 drivers/usb/mtu3/mtu3_core.c
>>  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
>>  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
>>  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
>>  create mode 100644 drivers/usb/mtu3/mtu3_host.c
>>  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
>>  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
>>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
>>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h

Since this is USB3 driver, you want this reviewed by Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver
  2020-09-28  2:12   ` Marek Vasut
@ 2020-09-28  2:20     ` Chunfeng Yun
  2020-10-13  7:26     ` Chunfeng Yun
  1 sibling, 0 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-09-28  2:20 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On Mon, 2020-09-28 at 04:12 +0200, Marek Vasut wrote:
> On 9/28/20 4:01 AM, Chunfeng Yun wrote:
> [...]
> >>  create mode 100644 drivers/usb/mtu3/mtu3_core.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
> >>  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_host.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
> >>  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
> 
> Since this is USB3 driver, you want this reviewed by Bin
Got it.

Hi Bin,

  Would you please help to review this series?

Thank you Marek and Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver
  2020-09-28  2:12   ` Marek Vasut
  2020-09-28  2:20     ` Chunfeng Yun
@ 2020-10-13  7:26     ` Chunfeng Yun
  2020-10-13 10:27       ` Bin Meng
  1 sibling, 1 reply; 29+ messages in thread
From: Chunfeng Yun @ 2020-10-13  7:26 UTC (permalink / raw)
  To: u-boot

Hi Bin,

Gentle ping...

Could you help to review this series?

Thanks a lot


On Mon, 2020-09-28 at 04:12 +0200, Marek Vasut wrote:
> On 9/28/20 4:01 AM, Chunfeng Yun wrote:
> [...]
> >>  create mode 100644 drivers/usb/mtu3/mtu3_core.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
> >>  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_host.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
> >>  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
> >>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
> 
> Since this is USB3 driver, you want this reviewed by Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver
  2020-10-13  7:26     ` Chunfeng Yun
@ 2020-10-13 10:27       ` Bin Meng
  0 siblings, 0 replies; 29+ messages in thread
From: Bin Meng @ 2020-10-13 10:27 UTC (permalink / raw)
  To: u-boot

Hi Chunfeng,

On Tue, Oct 13, 2020 at 3:26 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Hi Bin,
>
> Gentle ping...
>
> Could you help to review this series?

Will have a look soon.

>
> Thanks a lot
>
>
> On Mon, 2020-09-28 at 04:12 +0200, Marek Vasut wrote:
> > On 9/28/20 4:01 AM, Chunfeng Yun wrote:
> > [...]
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_core.c
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_host.c
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
> > >>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
> >
> > Since this is USB3 driver, you want this reviewed by Bin
>

Regards,
Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties
  2020-09-18  9:10 ` [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties Chunfeng Yun
@ 2020-10-13 14:15   ` Bin Meng
  0 siblings, 0 replies; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:15 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add bindings for common properties, include maximum-speed,
> dr_mode and phy_type
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v2~v7: no changes
> ---
>  doc/device-tree-bindings/usb/generic.txt | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
>  create mode 100644 doc/device-tree-bindings/usb/generic.txt
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD
  2020-09-18  9:10 ` [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD Chunfeng Yun
@ 2020-10-13 14:18   ` Bin Meng
  2020-10-14  2:46     ` Chunfeng Yun
  0 siblings, 1 reply; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:18 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add dt-binding for MediaTek USB3 DRD Driver

There are some differences compared to the one in the Linux kernel:
https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/usb/mediatek%2Cmtu3.txt

Please specify which kernel commit id the device bindings are referenced here.

>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v5~v7: no changes
>
> v4:
>   Add support host mode, introduce some new properties and subnode
>
> v2~v3: no changes
> ---
>  doc/device-tree-bindings/usb/mediatek,mtu3.txt | 79 ++++++++++++++++++++++++++
>  1 file changed, 79 insertions(+)
>  create mode 100644 doc/device-tree-bindings/usb/mediatek,mtu3.txt
>

Regards,
Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS
  2020-09-18  9:10 ` [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS Chunfeng Yun
@ 2020-10-13 14:19   ` Bin Meng
  2020-10-14  2:50     ` Chunfeng Yun
  0 siblings, 1 reply; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:19 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add enum USB_SPEED_SUPER_PLUS for USB3.1
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v5~v7: no changes
>
> v4: also add it into speed_names array
>
> v2~v3: no changes
> ---
>  drivers/usb/common/common.c | 1 +
>  include/linux/usb/ch9.h     | 1 +
>  2 files changed, 2 insertions(+)
>
> diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
> index d4ae186..76f5a9c 100644
> --- a/drivers/usb/common/common.c
> +++ b/drivers/usb/common/common.c
> @@ -46,6 +46,7 @@ static const char *const speed_names[] = {
>         [USB_SPEED_HIGH] = "high-speed",
>         [USB_SPEED_WIRELESS] = "wireless",
>         [USB_SPEED_SUPER] = "super-speed",
> +       [USB_SPEED_SUPER_PLUS] = "super-speed-plus",
>  };
>
>  enum usb_device_speed usb_get_maximum_speed(ofnode node)
> diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
> index 989a5fc..7d225ee 100644
> --- a/include/linux/usb/ch9.h
> +++ b/include/linux/usb/ch9.h
> @@ -956,6 +956,7 @@ enum usb_device_speed {
>         USB_SPEED_HIGH,                         /* usb 2.0 */
>         USB_SPEED_WIRELESS,                     /* wireless (usb 2.5) */
>         USB_SPEED_SUPER,                        /* usb 3.0 */
> +       USB_SPEED_SUPER_PLUS,                   /* usb 3.1 */
>  };
>
>  #ifdef __KERNEL__

Should we add usb 3.2 as well?

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 04/10] usb: common: add define of usb_speed_string()
  2020-09-18  9:10 ` [PATCH next v7 04/10] usb: common: add define of usb_speed_string() Chunfeng Yun
@ 2020-10-13 14:21   ` Bin Meng
  0 siblings, 0 replies; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:21 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> There is only declaration of usb_speed_string(), but no definition,
> so add it to avoid build error when call it.
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v7: no changes
>
> v6: modify commit message suggested by Roger
>
> v5: no changes
>
> v4: new patch
> ---
>  drivers/usb/common/common.c | 7 +++++++
>  include/linux/usb/ch9.h     | 4 ----
>  2 files changed, 7 insertions(+), 4 deletions(-)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver
  2020-09-18  9:10 ` [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver Chunfeng Yun
@ 2020-10-13 14:26   ` Bin Meng
  2020-10-14  3:15     ` Chunfeng Yun
  0 siblings, 1 reply; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:26 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> This patch adds support for the MediaTek USB3 DRD controller,
> its host side is based on xHCI, this driver supports device mode
> and host mode.
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>

I can only comment some generic stuff, since I have no access to the
controller datasheet.

> ---
> v7:
>     1. use xhci quirk flag XHCI_MTK_HOST
>
> v6: no changes
>
> v5:
>     1. change condition of readl_poll_timeout() when check clocks
>
> v4:
>     1. remove unused member @busy and @wedged, use their flags instead
>     2. support force_vbus mode
>     3. add a glue driver using UCLASS_NOP
>     4. add host driver, and rebuild host flow
>
> v3 changes
>     1. add ->udc_set_speed()
>     2. simplify some code flow
>
> v2: simplify QMU operations
> ---
>  Makefile                           |   1 +
>  drivers/usb/Kconfig                |   2 +
>  drivers/usb/mtu3/Kconfig           |  45 ++
>  drivers/usb/mtu3/Makefile          |  11 +
>  drivers/usb/mtu3/mtu3.h            | 423 +++++++++++++++++
>  drivers/usb/mtu3/mtu3_core.c       | 838 +++++++++++++++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_dr.h         |  52 +++
>  drivers/usb/mtu3/mtu3_gadget.c     | 686 +++++++++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_gadget_ep0.c | 933 +++++++++++++++++++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_host.c       | 141 ++++++
>  drivers/usb/mtu3/mtu3_hw_regs.h    | 515 ++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_plat.c       | 368 +++++++++++++++
>  drivers/usb/mtu3/mtu3_qmu.c        | 504 ++++++++++++++++++++
>  drivers/usb/mtu3/mtu3_qmu.h        |  37 ++
>  14 files changed, 4556 insertions(+)
>  create mode 100644 drivers/usb/mtu3/Kconfig
>  create mode 100644 drivers/usb/mtu3/Makefile
>  create mode 100644 drivers/usb/mtu3/mtu3.h
>  create mode 100644 drivers/usb/mtu3/mtu3_core.c
>  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
>  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
>  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
>  create mode 100644 drivers/usb/mtu3/mtu3_host.c
>  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
>  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
>  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
>
> diff --git a/Makefile b/Makefile
> index 7a05fc7..2dcc41a 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -795,6 +795,7 @@ libs-y += drivers/usb/eth/
>  libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/
>  libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/udc/
>  libs-y += drivers/usb/host/
> +libs-y += drivers/usb/mtu3/
>  libs-y += drivers/usb/musb/
>  libs-y += drivers/usb/musb-new/
>  libs-y += drivers/usb/phy/
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index 34881a1..fedc013 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -72,6 +72,8 @@ source "drivers/usb/cdns3/Kconfig"
>
>  source "drivers/usb/dwc3/Kconfig"
>
> +source "drivers/usb/mtu3/Kconfig"
> +
>  source "drivers/usb/musb/Kconfig"
>
>  source "drivers/usb/musb-new/Kconfig"
> diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
> new file mode 100644
> index 0000000..66651ad
> --- /dev/null
> +++ b/drivers/usb/mtu3/Kconfig
> @@ -0,0 +1,45 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# For MTK USB3.0 IP
> +
> +config USB_MTU3
> +       bool "MediaTek USB3 Dual Role controller"
> +       depends on USB || USB_GADGET
> +       depends on ARCH_MEDIATEK
> +       help
> +         Say Y here if your system runs on MediaTek SoCs with
> +         Dual Role SuperSpeed USB controller. You can select usb
> +         mode as peripheral role or host role.
> +
> +         If you don't know what this is, please say N.
> +
> +if USB_MTU3
> +choice
> +       bool "MTU3 Mode Selection"
> +       default USB_MTU3_GADGET if USB_GADGET
> +       default USB_MTU3_HOST if (USB && !USB_GADGET)
> +
> +config USB_MTU3_HOST
> +       bool "Host only mode"
> +       depends on USB=y || USB=USB_MTU3

Is this Kconfig grammer supported by U-Boot?

> +       select USB_XHCI_HCD
> +       help
> +         Select this when you want to use MTU3 in host mode only,
> +         thereby the gadget feature will be regressed.
> +
> +config USB_MTU3_GADGET
> +       bool "Gadget only mode"
> +       depends on USB_GADGET=y || USB_GADGET=USB_MTU3
> +       select USB_GADGET_DUALSPEED
> +       help
> +         Select this when you want to use MTU3 in gadget mode only,
> +         thereby the host feature will be regressed.
> +
> +endchoice
> +
> +config USB_MTU3_DEBUG
> +       bool "Enable Debugging Messages"
> +       help
> +         Say Y here to enable debugging messages in the MTU3 Driver.
> +
> +endif
> diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
> new file mode 100644
> index 0000000..234f3a3
> --- /dev/null
> +++ b/drivers/usb/mtu3/Makefile
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +ccflags-$(CONFIG_USB_MTU3_DEBUG)       += -DDEBUG
> +
> +obj-$(CONFIG_USB_MTU3) += mtu3.o
> +
> +mtu3-y := mtu3_plat.o
> +
> +obj-$(CONFIG_USB_MTU3_GADGET)  += mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o
> +obj-$(CONFIG_USB_MTU3_GADGET)  += mtu3_qmu.o
> +obj-$(CONFIG_USB_MTU3_HOST)    += mtu3_host.o

[snip]

Regards,
Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 06/10] usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller
  2020-09-18  9:10 ` [PATCH next v7 06/10] usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller Chunfeng Yun
@ 2020-10-13 14:28   ` Bin Meng
  0 siblings, 0 replies; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:28 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add an entry in usb_gadget_controller_number() for the MTU3
> gadget controller. It is used to bind the USB Ethernet driver.
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v4~v7: no changes
>
> v3: new patch
> ---
>  drivers/usb/gadget/gadget_chips.h | 8 ++++++++
>  1 file changed, 8 insertions(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 07/10] arm: dts: mt8512: add usb related nodes
  2020-09-18  9:10 ` [PATCH next v7 07/10] arm: dts: mt8512: add usb related nodes Chunfeng Yun
@ 2020-10-13 14:32   ` Bin Meng
  0 siblings, 0 replies; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:32 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add usb, usb phy, and fixed regulators nodes
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v5~v7: no changes
>
> v4: add host related properties, add subnode.
>
> v3: remove unused property mediatek,discth
>
> v2: no changes
> ---
>  arch/arm/dts/mt8512-bm1-emmc.dts | 34 ++++++++++++++++++++++++++++
>  arch/arm/dts/mt8512.dtsi         | 49 +++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 82 insertions(+), 1 deletion(-)
>

LGTM

Acked-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 09/10] configs: mt8512: add USB host related configs
  2020-09-18  9:10 ` [PATCH next v7 09/10] configs: mt8512: add USB host related configs Chunfeng Yun
@ 2020-10-13 14:34   ` Bin Meng
  2020-10-14  3:40     ` Chunfeng Yun
  0 siblings, 1 reply; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:34 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add USB, FAT commands, and fixed regulator, mass storage
> drivers.
> Due to device mode is enabled by default, comment out
> the host mode config here.

This patch should be squashed into patch [08/10]

>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v5~v7: no changes
>
> v4: new patch
> ---
>  configs/mt8512_bm1_emmc_defconfig | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/configs/mt8512_bm1_emmc_defconfig b/configs/mt8512_bm1_emmc_defconfig
> index d41446f..6b5454c 100644
> --- a/configs/mt8512_bm1_emmc_defconfig
> +++ b/configs/mt8512_bm1_emmc_defconfig
> @@ -15,6 +15,10 @@ CONFIG_DEFAULT_FDT_FILE="mt8512-bm1-emmc.dtb"
>  CONFIG_SYS_PROMPT="MT8512> "
>  CONFIG_CMD_BOOTMENU=y
>  CONFIG_CMD_MMC=y
> +CONFIG_CMD_USB=y
> +CONFIG_CMD_FAT=y
> +CONFIG_CMD_FS_GENERIC=y
> +# CONFIG_DOS_PARTITION is not set
>  CONFIG_ENV_OVERWRITE=y
>  CONFIG_REGMAP=y
>  CONFIG_SYSCON=y
> @@ -36,6 +40,7 @@ CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT=y
>  CONFIG_PHY=y
>  CONFIG_PHY_MTK_TPHY=y
>  CONFIG_DM_REGULATOR=y
> +CONFIG_DM_REGULATOR_FIXED=y
>  CONFIG_DM_SERIAL=y
>  CONFIG_MTK_SERIAL=y
>  CONFIG_TIMER=y
> @@ -48,6 +53,8 @@ CONFIG_DM_USB=y
>  CONFIG_DM_USB_GADGET=y
>  CONFIG_USB_MTU3=y
>  CONFIG_USB_MTU3_GADGET=y
> +#CONFIG_USB_MTU3_HOST=y

This should be :

# CONFIG_USB_MTU3_HOST is not set

> +CONFIG_USB_STORAGE=y
>  CONFIG_USB_GADGET=y
>  CONFIG_USB_GADGET_MANUFACTURER="MediaTek"
>  CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d
> --

Regards,
Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 10/10] MAINTAINERS: add USB driver to ARM MEDIATEK
  2020-09-18  9:10 ` [PATCH next v7 10/10] MAINTAINERS: add USB driver to ARM MEDIATEK Chunfeng Yun
@ 2020-10-13 14:35   ` Bin Meng
  0 siblings, 0 replies; 29+ messages in thread
From: Bin Meng @ 2020-10-13 14:35 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> Add MediaTek USB3 Dual-Role controller driver to ARM MEDIATEK,
> and add myself as a maintainer for it.
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v6~v7: no changes
>
> v5: add mtu3/, xhci-mtk.c, and myself as maintainer for MTK USB
>
> v4: new patch
> ---
>  MAINTAINERS | 3 +++
>  1 file changed, 3 insertions(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD
  2020-10-13 14:18   ` Bin Meng
@ 2020-10-14  2:46     ` Chunfeng Yun
  0 siblings, 0 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-10-14  2:46 UTC (permalink / raw)
  To: u-boot

On Tue, 2020-10-13 at 22:18 +0800, Bin Meng wrote:
> On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
> >
> > Add dt-binding for MediaTek USB3 DRD Driver
> 
> There are some differences compared to the one in the Linux kernel:
Some properties are removed due to dual-role switch is not supported in
Uboot.

> https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/usb/mediatek%2Cmtu3.txt
> 
> Please specify which kernel commit id the device bindings are referenced here.
Ok, will add it in next version

Thanks

> 
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > v5~v7: no changes
> >
> > v4:
> >   Add support host mode, introduce some new properties and subnode
> >
> > v2~v3: no changes
> > ---
> >  doc/device-tree-bindings/usb/mediatek,mtu3.txt | 79 ++++++++++++++++++++++++++
> >  1 file changed, 79 insertions(+)
> >  create mode 100644 doc/device-tree-bindings/usb/mediatek,mtu3.txt
> >
> 
> Regards,
> Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS
  2020-10-13 14:19   ` Bin Meng
@ 2020-10-14  2:50     ` Chunfeng Yun
  0 siblings, 0 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-10-14  2:50 UTC (permalink / raw)
  To: u-boot

On Tue, 2020-10-13 at 22:19 +0800, Bin Meng wrote:
> On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
> >
> > Add enum USB_SPEED_SUPER_PLUS for USB3.1
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > v5~v7: no changes
> >
> > v4: also add it into speed_names array
> >
> > v2~v3: no changes
> > ---
> >  drivers/usb/common/common.c | 1 +
> >  include/linux/usb/ch9.h     | 1 +
> >  2 files changed, 2 insertions(+)
> >
> > diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
> > index d4ae186..76f5a9c 100644
> > --- a/drivers/usb/common/common.c
> > +++ b/drivers/usb/common/common.c
> > @@ -46,6 +46,7 @@ static const char *const speed_names[] = {
> >         [USB_SPEED_HIGH] = "high-speed",
> >         [USB_SPEED_WIRELESS] = "wireless",
> >         [USB_SPEED_SUPER] = "super-speed",
> > +       [USB_SPEED_SUPER_PLUS] = "super-speed-plus",
> >  };
> >
> >  enum usb_device_speed usb_get_maximum_speed(ofnode node)
> > diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
> > index 989a5fc..7d225ee 100644
> > --- a/include/linux/usb/ch9.h
> > +++ b/include/linux/usb/ch9.h
> > @@ -956,6 +956,7 @@ enum usb_device_speed {
> >         USB_SPEED_HIGH,                         /* usb 2.0 */
> >         USB_SPEED_WIRELESS,                     /* wireless (usb 2.5) */
> >         USB_SPEED_SUPER,                        /* usb 3.0 */
> > +       USB_SPEED_SUPER_PLUS,                   /* usb 3.1 */
> >  };
> >
> >  #ifdef __KERNEL__
> 
> Should we add usb 3.2 as well?
I found the patches to support USB3.2 are still in public review for
Linux kernel, so no need support it currently

> 
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver
  2020-10-13 14:26   ` Bin Meng
@ 2020-10-14  3:15     ` Chunfeng Yun
  0 siblings, 0 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-10-14  3:15 UTC (permalink / raw)
  To: u-boot

On Tue, 2020-10-13 at 22:26 +0800, Bin Meng wrote:
> On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
> >
> > This patch adds support for the MediaTek USB3 DRD controller,
> > its host side is based on xHCI, this driver supports device mode
> > and host mode.
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> 
> I can only comment some generic stuff, since I have no access to the
> controller datasheet.
It's good enough, I and my workmate will test the function

> 
> > ---
> > v7:
> >     1. use xhci quirk flag XHCI_MTK_HOST
> >
> > v6: no changes
> >
> > v5:
> >     1. change condition of readl_poll_timeout() when check clocks
> >
> > v4:
> >     1. remove unused member @busy and @wedged, use their flags instead
> >     2. support force_vbus mode
> >     3. add a glue driver using UCLASS_NOP
> >     4. add host driver, and rebuild host flow
> >
> > v3 changes
> >     1. add ->udc_set_speed()
> >     2. simplify some code flow
> >
> > v2: simplify QMU operations
> > ---
> >  Makefile                           |   1 +
> >  drivers/usb/Kconfig                |   2 +
> >  drivers/usb/mtu3/Kconfig           |  45 ++
> >  drivers/usb/mtu3/Makefile          |  11 +
> >  drivers/usb/mtu3/mtu3.h            | 423 +++++++++++++++++
> >  drivers/usb/mtu3/mtu3_core.c       | 838 +++++++++++++++++++++++++++++++++
> >  drivers/usb/mtu3/mtu3_dr.h         |  52 +++
> >  drivers/usb/mtu3/mtu3_gadget.c     | 686 +++++++++++++++++++++++++++
> >  drivers/usb/mtu3/mtu3_gadget_ep0.c | 933 +++++++++++++++++++++++++++++++++++++
> >  drivers/usb/mtu3/mtu3_host.c       | 141 ++++++
> >  drivers/usb/mtu3/mtu3_hw_regs.h    | 515 ++++++++++++++++++++
> >  drivers/usb/mtu3/mtu3_plat.c       | 368 +++++++++++++++
> >  drivers/usb/mtu3/mtu3_qmu.c        | 504 ++++++++++++++++++++
> >  drivers/usb/mtu3/mtu3_qmu.h        |  37 ++
> >  14 files changed, 4556 insertions(+)
> >  create mode 100644 drivers/usb/mtu3/Kconfig
> >  create mode 100644 drivers/usb/mtu3/Makefile
> >  create mode 100644 drivers/usb/mtu3/mtu3.h
> >  create mode 100644 drivers/usb/mtu3/mtu3_core.c
> >  create mode 100644 drivers/usb/mtu3/mtu3_dr.h
> >  create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
> >  create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
> >  create mode 100644 drivers/usb/mtu3/mtu3_host.c
> >  create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
> >  create mode 100644 drivers/usb/mtu3/mtu3_plat.c
> >  create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
> >  create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
> >
> > diff --git a/Makefile b/Makefile
> > index 7a05fc7..2dcc41a 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -795,6 +795,7 @@ libs-y += drivers/usb/eth/
> >  libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/
> >  libs-$(CONFIG_USB_GADGET) += drivers/usb/gadget/udc/
> >  libs-y += drivers/usb/host/
> > +libs-y += drivers/usb/mtu3/
> >  libs-y += drivers/usb/musb/
> >  libs-y += drivers/usb/musb-new/
> >  libs-y += drivers/usb/phy/
> > diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> > index 34881a1..fedc013 100644
> > --- a/drivers/usb/Kconfig
> > +++ b/drivers/usb/Kconfig
> > @@ -72,6 +72,8 @@ source "drivers/usb/cdns3/Kconfig"
> >
> >  source "drivers/usb/dwc3/Kconfig"
> >
> > +source "drivers/usb/mtu3/Kconfig"
> > +
> >  source "drivers/usb/musb/Kconfig"
> >
> >  source "drivers/usb/musb-new/Kconfig"
> > diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
> > new file mode 100644
> > index 0000000..66651ad
> > --- /dev/null
> > +++ b/drivers/usb/mtu3/Kconfig
> > @@ -0,0 +1,45 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# For MTK USB3.0 IP
> > +
> > +config USB_MTU3
> > +       bool "MediaTek USB3 Dual Role controller"
> > +       depends on USB || USB_GADGET
> > +       depends on ARCH_MEDIATEK
> > +       help
> > +         Say Y here if your system runs on MediaTek SoCs with
> > +         Dual Role SuperSpeed USB controller. You can select usb
> > +         mode as peripheral role or host role.
> > +
> > +         If you don't know what this is, please say N.
> > +
> > +if USB_MTU3
> > +choice
> > +       bool "MTU3 Mode Selection"
> > +       default USB_MTU3_GADGET if USB_GADGET
> > +       default USB_MTU3_HOST if (USB && !USB_GADGET)
> > +
> > +config USB_MTU3_HOST
> > +       bool "Host only mode"
> > +       depends on USB=y || USB=USB_MTU3
> 
> Is this Kconfig grammer supported by U-Boot?
Yes, no error happens when use menuconfig, but can be simplified,
I modify it.

Thanks a lot

> 
> > +       select USB_XHCI_HCD
> > +       help
> > +         Select this when you want to use MTU3 in host mode only,
> > +         thereby the gadget feature will be regressed.
> > +
> > +config USB_MTU3_GADGET
> > +       bool "Gadget only mode"
> > +       depends on USB_GADGET=y || USB_GADGET=USB_MTU3
> > +       select USB_GADGET_DUALSPEED
> > +       help
> > +         Select this when you want to use MTU3 in gadget mode only,
> > +         thereby the host feature will be regressed.
> > +
> > +endchoice
> > +
> > +config USB_MTU3_DEBUG
> > +       bool "Enable Debugging Messages"
> > +       help
> > +         Say Y here to enable debugging messages in the MTU3 Driver.
> > +
> > +endif
> > diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
> > new file mode 100644
> > index 0000000..234f3a3
> > --- /dev/null
> > +++ b/drivers/usb/mtu3/Makefile
> > @@ -0,0 +1,11 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +ccflags-$(CONFIG_USB_MTU3_DEBUG)       += -DDEBUG
> > +
> > +obj-$(CONFIG_USB_MTU3) += mtu3.o
> > +
> > +mtu3-y := mtu3_plat.o
> > +
> > +obj-$(CONFIG_USB_MTU3_GADGET)  += mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o
> > +obj-$(CONFIG_USB_MTU3_GADGET)  += mtu3_qmu.o
> > +obj-$(CONFIG_USB_MTU3_HOST)    += mtu3_host.o
> 
> [snip]
> 
> Regards,
> Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH next v7 09/10] configs: mt8512: add USB host related configs
  2020-10-13 14:34   ` Bin Meng
@ 2020-10-14  3:40     ` Chunfeng Yun
  0 siblings, 0 replies; 29+ messages in thread
From: Chunfeng Yun @ 2020-10-14  3:40 UTC (permalink / raw)
  To: u-boot

On Tue, 2020-10-13 at 22:34 +0800, Bin Meng wrote:
> On Fri, Sep 18, 2020 at 5:12 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
> >
> > Add USB, FAT commands, and fixed regulator, mass storage
> > drivers.
> > Due to device mode is enabled by default, comment out
> > the host mode config here.
> 
> This patch should be squashed into patch [08/10]
Ok

> 
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > v5~v7: no changes
> >
> > v4: new patch
> > ---
> >  configs/mt8512_bm1_emmc_defconfig | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/configs/mt8512_bm1_emmc_defconfig b/configs/mt8512_bm1_emmc_defconfig
> > index d41446f..6b5454c 100644
> > --- a/configs/mt8512_bm1_emmc_defconfig
> > +++ b/configs/mt8512_bm1_emmc_defconfig
> > @@ -15,6 +15,10 @@ CONFIG_DEFAULT_FDT_FILE="mt8512-bm1-emmc.dtb"
> >  CONFIG_SYS_PROMPT="MT8512> "
> >  CONFIG_CMD_BOOTMENU=y
> >  CONFIG_CMD_MMC=y
> > +CONFIG_CMD_USB=y
> > +CONFIG_CMD_FAT=y
> > +CONFIG_CMD_FS_GENERIC=y
> > +# CONFIG_DOS_PARTITION is not set
> >  CONFIG_ENV_OVERWRITE=y
> >  CONFIG_REGMAP=y
> >  CONFIG_SYSCON=y
> > @@ -36,6 +40,7 @@ CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT=y
> >  CONFIG_PHY=y
> >  CONFIG_PHY_MTK_TPHY=y
> >  CONFIG_DM_REGULATOR=y
> > +CONFIG_DM_REGULATOR_FIXED=y
> >  CONFIG_DM_SERIAL=y
> >  CONFIG_MTK_SERIAL=y
> >  CONFIG_TIMER=y
> > @@ -48,6 +53,8 @@ CONFIG_DM_USB=y
> >  CONFIG_DM_USB_GADGET=y
> >  CONFIG_USB_MTU3=y
> >  CONFIG_USB_MTU3_GADGET=y
> > +#CONFIG_USB_MTU3_HOST=y
> 
> This should be :
> 
> # CONFIG_USB_MTU3_HOST is not set
Will modify it.

Thanks a lot

> 
> > +CONFIG_USB_STORAGE=y
> >  CONFIG_USB_GADGET=y
> >  CONFIG_USB_GADGET_MANUFACTURER="MediaTek"
> >  CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d
> > --
> 
> Regards,
> Bin

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2020-10-14  3:40 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-18  9:10 [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
2020-09-18  9:10 ` [PATCH next v7 01/10] dt-binding: usb: add bindings for some common properties Chunfeng Yun
2020-10-13 14:15   ` Bin Meng
2020-09-18  9:10 ` [PATCH next v7 02/10] dt-bindings: usb: mtu3: add bindings for MediaTek USB3 DRD Chunfeng Yun
2020-10-13 14:18   ` Bin Meng
2020-10-14  2:46     ` Chunfeng Yun
2020-09-18  9:10 ` [PATCH next v7 03/10] usb: add USB_SPEED_SUPER_PLUS Chunfeng Yun
2020-10-13 14:19   ` Bin Meng
2020-10-14  2:50     ` Chunfeng Yun
2020-09-18  9:10 ` [PATCH next v7 04/10] usb: common: add define of usb_speed_string() Chunfeng Yun
2020-10-13 14:21   ` Bin Meng
2020-09-18  9:10 ` [PATCH next v7 05/10] usb: add MediaTek USB3 DRD driver Chunfeng Yun
2020-10-13 14:26   ` Bin Meng
2020-10-14  3:15     ` Chunfeng Yun
2020-09-18  9:10 ` [PATCH next v7 06/10] usb: gadget: Add bcdDevice for the MTU3 USB Gadget Controller Chunfeng Yun
2020-10-13 14:28   ` Bin Meng
2020-09-18  9:10 ` [PATCH next v7 07/10] arm: dts: mt8512: add usb related nodes Chunfeng Yun
2020-10-13 14:32   ` Bin Meng
2020-09-18  9:10 ` [PATCH next v7 08/10] configs: mt8512: enable fastboot Chunfeng Yun
2020-09-18  9:10 ` [PATCH next v7 09/10] configs: mt8512: add USB host related configs Chunfeng Yun
2020-10-13 14:34   ` Bin Meng
2020-10-14  3:40     ` Chunfeng Yun
2020-09-18  9:10 ` [PATCH next v7 10/10] MAINTAINERS: add USB driver to ARM MEDIATEK Chunfeng Yun
2020-10-13 14:35   ` Bin Meng
2020-09-28  2:01 ` [PATCH next v7 00/10] Add support MediaTek USB3 DRD driver Chunfeng Yun
2020-09-28  2:12   ` Marek Vasut
2020-09-28  2:20     ` Chunfeng Yun
2020-10-13  7:26     ` Chunfeng Yun
2020-10-13 10:27       ` Bin Meng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.