diff --git a/configs/uniphier_v7_defconfig b/configs/uniphier_v7_defconfig
index d626968c76d4457e106898bb575946a441396511..03feb04b93785172164dee3da008a8c0a9ec54c7 100644
--- a/configs/uniphier_v7_defconfig
+++ b/configs/uniphier_v7_defconfig
@@ -82,7 +82,6 @@ CONFIG_DM_SPI=y
 CONFIG_UNIPHIER_SPI=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
-CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_GENERIC=y
 CONFIG_USB_DWC3=y
diff --git a/configs/uniphier_v8_defconfig b/configs/uniphier_v8_defconfig
index 6a0e2666cf18d35a2741aafa511a2b0b36bf54b8..ed58b5746e72c9ae2f159e1e39d528063c725d66 100644
--- a/configs/uniphier_v8_defconfig
+++ b/configs/uniphier_v8_defconfig
@@ -71,7 +71,6 @@ CONFIG_SYSRESET=y
 CONFIG_SYSRESET_PSCI=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
-CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_GENERIC=y
 CONFIG_USB_DWC3=y
diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c
index ff5d364f597828dfedb7701116242c711fd66578..3b8595fe610a9fdf4618e9de4afd8a528c5946c8 100644
--- a/drivers/clk/uniphier/clk-uniphier-sys.c
+++ b/drivers/clk/uniphier/clk-uniphier-sys.c
@@ -28,7 +28,10 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = {
 	UNIPHIER_CLK_GATE_SIMPLE(14, 0x2104, 16),	/* usb30 (Pro4, Pro5, PXs2) */
 	UNIPHIER_CLK_GATE_SIMPLE(15, 0x2104, 17),	/* usb31 (Pro4, Pro5, PXs2) */
 	UNIPHIER_CLK_GATE_SIMPLE(16, 0x2104, 19),	/* usb30-phy (PXs2) */
+	UNIPHIER_CLK_RATE(17, 25000000),		/* usb30-phy2 (PXs2) */
+	UNIPHIER_CLK_RATE(18, 25000000),		/* usb30-phy3 (PXs2) */
 	UNIPHIER_CLK_GATE_SIMPLE(20, 0x2104, 20),	/* usb31-phy (PXs2) */
+	UNIPHIER_CLK_RATE(21, 25000000),		/* usb31-phy2 (PXs2) */
 	UNIPHIER_CLK_GATE_SIMPLE(24, 0x2108, 2),	/* pcie (Pro5) */
 	{ /* sentinel */ }
 #endif
@@ -44,6 +47,8 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = {
 	UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14),	/* usb30 (LD20) */
 	UNIPHIER_CLK_GATE_SIMPLE(16, 0x210c, 12),	/* usb30-phy0 (LD20) */
 	UNIPHIER_CLK_GATE_SIMPLE(17, 0x210c, 13),	/* usb30-phy1 (LD20) */
+	UNIPHIER_CLK_RATE(18, 25000000),		/* usb30-phy2 (LD20) */
+	UNIPHIER_CLK_RATE(19, 25000000),		/* usb30-phy3 (LD20) */
 	UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 4),	/* pcie */
 	{ /* sentinel */ }
 #endif
diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig
index bcd579e98ec15668dee7331442b4e2455d2c7381..de87d5b0109bae0cd835d22dc432999b442697a7 100644
--- a/drivers/phy/socionext/Kconfig
+++ b/drivers/phy/socionext/Kconfig
@@ -10,3 +10,11 @@ config PHY_UNIPHIER_PCIE
 	help
 	  Enable this to support PHY implemented in PCIe controller
 	  on UniPhier SoCs.
+
+config PHY_UNIPHIER_USB3
+	bool "UniPhier USB3 PHY driver"
+	depends on PHY && ARCH_UNIPHIER
+	imply REGMAP
+	help
+	  Enable this to support PHY implemented in USB3 controller
+	  on UniPhier SoCs.
diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile
index 5484360b70ff6cb4c5bdbf33630cd6c8b5b7cf71..94d3aa68cfac025e9e8ec3ed44fdb2ddb141647c 100644
--- a/drivers/phy/socionext/Makefile
+++ b/drivers/phy/socionext/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_PHY_UNIPHIER_PCIE)	+= phy-uniphier-pcie.o
+obj-$(CONFIG_PHY_UNIPHIER_USB3)	+= phy-uniphier-usb3.o
diff --git a/drivers/phy/socionext/phy-uniphier-usb3.c b/drivers/phy/socionext/phy-uniphier-usb3.c
new file mode 100644
index 0000000000000000000000000000000000000000..1d65b0b08f760778f7513aaa3588d001c48e3a75
--- /dev/null
+++ b/drivers/phy/socionext/phy-uniphier-usb3.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * phy_uniphier_usb3.c - Socionext UniPhier Usb3 PHY driver
+ * Copyright 2019-2023 Socionext, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+
+#include <clk.h>
+#include <reset.h>
+
+struct uniphier_usb3phy_priv {
+	struct clk *clk_link, *clk_phy, *clk_parent, *clk_phyext;
+	struct reset_ctl *rst_link, *rst_phy, *rst_parent;
+};
+
+static int uniphier_usb3phy_init(struct phy *phy)
+{
+	struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev);
+	int ret;
+
+	ret = clk_enable(priv->clk_phy);
+	if (ret)
+		return ret;
+
+	ret = reset_deassert(priv->rst_phy);
+	if (ret)
+		goto out_clk;
+
+	if (priv->clk_phyext) {
+		ret = clk_enable(priv->clk_phyext);
+		if (ret)
+			goto out_rst;
+	}
+
+	return 0;
+
+out_rst:
+	reset_assert(priv->rst_phy);
+out_clk:
+	clk_disable(priv->clk_phy);
+
+	return ret;
+}
+
+static int uniphier_usb3phy_exit(struct phy *phy)
+{
+	struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev);
+
+	if (priv->clk_phyext)
+		clk_disable(priv->clk_phyext);
+
+	reset_assert(priv->rst_phy);
+	clk_disable(priv->clk_phy);
+
+	return 0;
+}
+
+static int uniphier_usb3phy_probe(struct udevice *dev)
+{
+	struct uniphier_usb3phy_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->clk_link = devm_clk_get(dev, "link");
+	if (IS_ERR(priv->clk_link)) {
+		printf("Failed to get link clock\n");
+		return PTR_ERR(priv->clk_link);
+	}
+
+	priv->clk_phy = devm_clk_get(dev, "phy");
+	if (IS_ERR(priv->clk_link)) {
+		printf("Failed to get phy clock\n");
+		return PTR_ERR(priv->clk_link);
+	}
+
+	priv->clk_parent = devm_clk_get_optional(dev, "gio");
+	if (IS_ERR(priv->clk_parent)) {
+		printf("Failed to get parent clock\n");
+		return PTR_ERR(priv->clk_parent);
+	}
+
+	priv->clk_phyext = devm_clk_get_optional(dev, "phy-ext");
+	if (IS_ERR(priv->clk_phyext)) {
+		printf("Failed to get external phy clock\n");
+		return PTR_ERR(priv->clk_phyext);
+	}
+
+	priv->rst_link = devm_reset_control_get(dev, "link");
+	if (IS_ERR(priv->rst_link)) {
+		printf("Failed to get link reset\n");
+		return PTR_ERR(priv->rst_link);
+	}
+
+	priv->rst_phy = devm_reset_control_get(dev, "phy");
+	if (IS_ERR(priv->rst_phy)) {
+		printf("Failed to get phy reset\n");
+		return PTR_ERR(priv->rst_phy);
+	}
+
+	priv->rst_parent = devm_reset_control_get_optional(dev, "gio");
+	if (IS_ERR(priv->rst_parent)) {
+		printf("Failed to get parent reset\n");
+		return PTR_ERR(priv->rst_parent);
+	}
+
+	if (priv->clk_parent) {
+		ret = clk_enable(priv->clk_parent);
+		if (ret)
+			return ret;
+	}
+	if (priv->rst_parent) {
+		ret = reset_deassert(priv->rst_parent);
+		if (ret)
+			goto out_clk_parent;
+	}
+
+	ret = clk_enable(priv->clk_link);
+	if (ret)
+		goto out_rst_parent;
+
+	ret = reset_deassert(priv->rst_link);
+	if (ret)
+		goto out_clk;
+
+	return 0;
+
+out_clk:
+	clk_disable(priv->clk_link);
+out_rst_parent:
+	if (priv->rst_parent)
+		reset_assert(priv->rst_parent);
+out_clk_parent:
+	if (priv->clk_parent)
+		clk_disable(priv->clk_parent);
+
+	return ret;
+}
+
+static struct phy_ops uniphier_usb3phy_ops = {
+	.init = uniphier_usb3phy_init,
+	.exit = uniphier_usb3phy_exit,
+};
+
+static const struct udevice_id uniphier_usb3phy_ids[] = {
+	{ .compatible = "socionext,uniphier-pro4-usb3-ssphy" },
+	{ .compatible = "socionext,uniphier-pro5-usb3-hsphy" },
+	{ .compatible = "socionext,uniphier-pro5-usb3-ssphy" },
+	{ .compatible = "socionext,uniphier-pxs2-usb3-hsphy" },
+	{ .compatible = "socionext,uniphier-pxs2-usb3-ssphy" },
+	{ .compatible = "socionext,uniphier-ld20-usb3-hsphy" },
+	{ .compatible = "socionext,uniphier-ld20-usb3-ssphy" },
+	{ .compatible = "socionext,uniphier-pxs3-usb3-hsphy" },
+	{ .compatible = "socionext,uniphier-pxs3-usb3-ssphy" },
+	{ .compatible = "socionext,uniphier-nx1-usb3-hsphy" },
+	{ .compatible = "socionext,uniphier-nx1-usb3-ssphy" },
+	{ }
+};
+
+U_BOOT_DRIVER(uniphier_usb3_phy) = {
+	.name		= "uniphier-usb3-phy",
+	.id		= UCLASS_PHY,
+	.of_match	= uniphier_usb3phy_ids,
+	.ops		= &uniphier_usb3phy_ops,
+	.probe		= uniphier_usb3phy_probe,
+	.priv_auto      = sizeof(struct uniphier_usb3phy_priv),
+};
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c
index 7adae51873f356ba0f53852577ce6a41f353a2f0..35e3ccebd72e6271ad49816be975139e86143a25 100644
--- a/drivers/reset/reset-uniphier.c
+++ b/drivers/reset/reset-uniphier.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2016 Socionext Inc.
  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *   Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
  */
 
 #include <common.h>
@@ -9,6 +10,8 @@
 #include <log.h>
 #include <malloc.h>
 #include <reset-uclass.h>
+#include <clk.h>
+#include <reset.h>
 #include <dm/device_compat.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
@@ -178,10 +181,17 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
 	UNIPHIER_RESET_END,
 };
 
+/* Glue reset data */
+static const struct uniphier_reset_data uniphier_pro4_usb3_reset_data[] = {
+	UNIPHIER_RESETX(15, 0, 15)
+};
+
 /* core implementaton */
 struct uniphier_reset_priv {
 	void __iomem *base;
 	const struct uniphier_reset_data *data;
+	struct clk_bulk		clks;
+	struct reset_ctl_bulk	rsts;
 };
 
 static int uniphier_reset_update(struct reset_ctl *reset_ctl, int assert)
@@ -233,10 +243,47 @@ static const struct reset_ops uniphier_reset_ops = {
 	.rst_deassert = uniphier_reset_deassert,
 };
 
+static int uniphier_reset_rst_init(struct udevice *dev)
+{
+	struct uniphier_reset_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = reset_get_bulk(dev, &priv->rsts);
+	if (ret == -ENOSYS || ret == -ENOENT)
+		return 0;
+	else if (ret)
+		return ret;
+
+	ret = reset_deassert_bulk(&priv->rsts);
+	if (ret)
+		reset_release_bulk(&priv->rsts);
+
+	return ret;
+}
+
+static int uniphier_reset_clk_init(struct udevice *dev)
+{
+	struct uniphier_reset_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = clk_get_bulk(dev, &priv->clks);
+	if (ret == -ENOSYS || ret == -ENOENT)
+		return 0;
+	if (ret)
+		return ret;
+
+	ret = clk_enable_bulk(&priv->clks);
+	if (ret)
+		clk_release_bulk(&priv->clks);
+
+	return ret;
+}
+
 static int uniphier_reset_probe(struct udevice *dev)
 {
 	struct uniphier_reset_priv *priv = dev_get_priv(dev);
 	fdt_addr_t addr;
+	int ret;
 
 	addr = dev_read_addr(dev->parent);
 	if (addr == FDT_ADDR_T_NONE)
@@ -248,7 +295,11 @@ static int uniphier_reset_probe(struct udevice *dev)
 
 	priv->data = (void *)dev_get_driver_data(dev);
 
-	return 0;
+	ret = uniphier_reset_clk_init(dev);
+	if (ret)
+		return ret;
+
+	return uniphier_reset_rst_init(dev);
 }
 
 static const struct udevice_id uniphier_reset_match[] = {
@@ -355,6 +406,31 @@ static const struct udevice_id uniphier_reset_match[] = {
 		.compatible = "socionext,uniphier-pxs3-peri-reset",
 		.data = (ulong)uniphier_pro4_peri_reset_data,
 	},
+	/* USB glue reset */
+	{
+		.compatible = "socionext,uniphier-pro4-usb3-reset",
+		.data = (ulong)uniphier_pro4_usb3_reset_data,
+	},
+	{
+		.compatible = "socionext,uniphier-pro5-usb3-reset",
+		.data = (ulong)uniphier_pro4_usb3_reset_data,
+	},
+	{
+		.compatible = "socionext,uniphier-pxs2-usb3-reset",
+		.data = (ulong)uniphier_pro4_usb3_reset_data,
+	},
+	{
+		.compatible = "socionext,uniphier-ld20-usb3-reset",
+		.data = (ulong)uniphier_pro4_usb3_reset_data,
+	},
+	{
+		.compatible = "socionext,uniphier-pxs3-usb3-reset",
+		.data = (ulong)uniphier_pro4_usb3_reset_data,
+	},
+	{
+		.compatible = "socionext,uniphier-nx1-usb3-reset",
+		.data = (ulong)uniphier_pro4_usb3_reset_data,
+	},
 	{ /* sentinel */ }
 };
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index f010291d02230cab34c33d0692267de1e0299971..7ddfa94e518d396dbd7102041ef0d6030627d44a 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -55,7 +55,9 @@ config USB_DWC3_MESON_GXL
 
 config USB_DWC3_UNIPHIER
 	bool "DesignWare USB3 Host Support on UniPhier Platforms"
-	depends on ARCH_UNIPHIER && USB_XHCI_DWC3
+	depends on ARCH_UNIPHIER && USB_DWC3
+	select USB_DWC3_GENERIC
+	select PHY_UNIPHIER_USB3
 	help
 	  Support of USB2/3 functionality in Socionext UniPhier platforms.
 	  Say 'Y' here if you have one such device.
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 78966718d01d1e5053179a8c34dea8c88742ceda..acbf7acb1918d2d1d12b7902bf26d6f32d112022 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -28,11 +28,7 @@
 #include <usb/xhci.h>
 #include <asm/gpio.h>
 
-struct dwc3_glue_data {
-	struct clk_bulk		clks;
-	struct reset_ctl_bulk	resets;
-	fdt_addr_t regs;
-};
+#include "dwc3-generic.h"
 
 struct dwc3_generic_plat {
 	fdt_addr_t base;
@@ -68,10 +64,27 @@ static int dwc3_generic_probe(struct udevice *dev,
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 	dwc3_of_parse(dwc3);
 
+	/*
+	 * There are currently four disparate placement possibilities of DWC3
+	 * reference clock phandle in SoC DTs:
+	 * - in top level glue node, with generic subnode without clock (ZynqMP)
+	 * - in top level generic node, with no subnode (i.MX8MQ)
+	 * - in generic subnode, with other clock in top level node (i.MX8MP)
+	 * - in both top level node and generic subnode (Rockchip)
+	 * Cover all the possibilities here by looking into both nodes, start
+	 * with the top level node as that seems to be used in majority of DTs
+	 * to reference the clock.
+	 */
 	node = dev_ofnode(dev->parent);
 	index = ofnode_stringlist_search(node, "clock-names", "ref");
 	if (index < 0)
 		index = ofnode_stringlist_search(node, "clock-names", "ref_clk");
+	if (index < 0) {
+		node = dev_ofnode(dev);
+		index = ofnode_stringlist_search(node, "clock-names", "ref");
+		if (index < 0)
+			index = ofnode_stringlist_search(node, "clock-names", "ref_clk");
+	}
 	if (index >= 0)
 		dwc3->ref_clk = &glue->clks.clks[index];
 #endif
@@ -258,11 +271,6 @@ U_BOOT_DRIVER(dwc3_generic_host) = {
 };
 #endif
 
-struct dwc3_glue_ops {
-	void (*glue_configure)(struct udevice *dev, int index,
-			       enum usb_dr_mode mode);
-};
-
 void dwc3_imx8mp_glue_configure(struct udevice *dev, int index,
 				enum usb_dr_mode mode)
 {
@@ -398,54 +406,74 @@ struct dwc3_glue_ops ti_ops = {
 	.glue_configure = dwc3_ti_glue_configure,
 };
 
-static int dwc3_glue_bind(struct udevice *parent)
+static int dwc3_glue_bind_common(struct udevice *parent, ofnode node)
 {
-	ofnode node;
-	int ret;
+	const char *name = ofnode_get_name(node);
+	const char *driver = NULL;
 	enum usb_dr_mode dr_mode;
+	struct udevice *dev;
+	int ret;
 
-	dr_mode = usb_get_dr_mode(dev_ofnode(parent));
-
-	ofnode_for_each_subnode(node, dev_ofnode(parent)) {
-		const char *name = ofnode_get_name(node);
-		struct udevice *dev;
-		const char *driver = NULL;
-
-		debug("%s: subnode name: %s\n", __func__, name);
+	debug("%s: subnode name: %s\n", __func__, name);
 
-		/* if the parent node doesn't have a mode check the leaf */
-		if (!dr_mode)
-			dr_mode = usb_get_dr_mode(node);
+	/* if the parent node doesn't have a mode check the leaf */
+	dr_mode = usb_get_dr_mode(dev_ofnode(parent));
+	if (!dr_mode)
+		dr_mode = usb_get_dr_mode(node);
 
-		switch (dr_mode) {
-		case USB_DR_MODE_PERIPHERAL:
-		case USB_DR_MODE_OTG:
+	switch (dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
-			debug("%s: dr_mode: OTG or Peripheral\n", __func__);
-			driver = "dwc3-generic-peripheral";
+		debug("%s: dr_mode: OTG or Peripheral\n", __func__);
+		driver = "dwc3-generic-peripheral";
 #endif
-			break;
+		break;
 #if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
-		case USB_DR_MODE_HOST:
-			debug("%s: dr_mode: HOST\n", __func__);
-			driver = "dwc3-generic-host";
-			break;
+	case USB_DR_MODE_HOST:
+		debug("%s: dr_mode: HOST\n", __func__);
+		driver = "dwc3-generic-host";
+		break;
 #endif
-		default:
-			debug("%s: unsupported dr_mode\n", __func__);
-			return -ENODEV;
-		};
+	default:
+		debug("%s: unsupported dr_mode\n", __func__);
+		return -ENODEV;
+	};
 
-		if (!driver)
-			continue;
+	if (!driver)
+		return -ENXIO;
+
+	ret = device_bind_driver_to_node(parent, driver, name,
+					 node, &dev);
+	if (ret) {
+		debug("%s: not able to bind usb device mode\n",
+		      __func__);
+		return ret;
+	}
+
+	return 0;
+}
 
-		ret = device_bind_driver_to_node(parent, driver, name,
-						 node, &dev);
-		if (ret) {
-			debug("%s: not able to bind usb device mode\n",
-			      __func__);
+int dwc3_glue_bind(struct udevice *parent)
+{
+	struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(parent);
+	ofnode node;
+	int ret;
+
+	if (ops && ops->glue_get_ctrl_dev) {
+		ret = ops->glue_get_ctrl_dev(parent, &node);
+		if (ret)
+			return ret;
+
+		return dwc3_glue_bind_common(parent, node);
+	}
+
+	ofnode_for_each_subnode(node, dev_ofnode(parent)) {
+		ret = dwc3_glue_bind_common(parent, node);
+		if (ret == -ENXIO)
+			continue;
+		if (ret)
 			return ret;
-		}
 	}
 
 	return 0;
@@ -493,7 +521,7 @@ static int dwc3_glue_clk_init(struct udevice *dev,
 	return 0;
 }
 
-static int dwc3_glue_probe(struct udevice *dev)
+int dwc3_glue_probe(struct udevice *dev)
 {
 	struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
 	struct dwc3_glue_data *glue = dev_get_plat(dev);
@@ -514,7 +542,7 @@ static int dwc3_glue_probe(struct udevice *dev)
 		phy.dev = NULL;
 	}
 
-	glue->regs = dev_read_addr(dev);
+	glue->regs = dev_read_addr_size_index(dev, 0, &glue->size);
 
 	ret = dwc3_glue_clk_init(dev, glue);
 	if (ret)
@@ -534,6 +562,12 @@ static int dwc3_glue_probe(struct udevice *dev)
 	if (ret)
 		return ret;
 
+	if (glue->clks.count == 0) {
+		ret = dwc3_glue_clk_init(child, glue);
+		if (ret)
+			return ret;
+	}
+
 	if (glue->resets.count == 0) {
 		ret = dwc3_glue_reset_init(child, glue);
 		if (ret)
@@ -553,7 +587,7 @@ static int dwc3_glue_probe(struct udevice *dev)
 	return 0;
 }
 
-static int dwc3_glue_remove(struct udevice *dev)
+int dwc3_glue_remove(struct udevice *dev)
 {
 	struct dwc3_glue_data *glue = dev_get_plat(dev);
 
diff --git a/drivers/usb/dwc3/dwc3-generic.h b/drivers/usb/dwc3/dwc3-generic.h
new file mode 100644
index 0000000000000000000000000000000000000000..40902c8923f57d05ebd9b0941c24b864eb87b276
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-generic.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * dwc3-generic.h - Generic DWC3 Glue layer header
+ *
+ * Copyright (C) 2016 - 2018 Xilinx, Inc.
+ * Copyright (C) 2023 Socionext Inc.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GENERIC_H
+#define __DRIVERS_USB_DWC3_GENERIC_H
+
+#include <clk.h>
+#include <reset.h>
+#include <dwc3-uboot.h>
+
+struct dwc3_glue_data {
+	struct clk_bulk		clks;
+	struct reset_ctl_bulk	resets;
+	fdt_addr_t regs;
+	fdt_size_t size;
+};
+
+struct dwc3_glue_ops {
+	int (*glue_get_ctrl_dev)(struct udevice *parent, ofnode *node);
+	void (*glue_configure)(struct udevice *dev, int index,
+			       enum usb_dr_mode mode);
+};
+
+int dwc3_glue_bind(struct udevice *parent);
+int dwc3_glue_probe(struct udevice *dev);
+int dwc3_glue_remove(struct udevice *dev);
+
+#endif
diff --git a/drivers/usb/dwc3/dwc3-uniphier.c b/drivers/usb/dwc3/dwc3-uniphier.c
index 54b52dcd66a9f004ca862ca549012796288fc1e2..ab85428a7003b9f1487b00e2881fb20cd7aa198c 100644
--- a/drivers/usb/dwc3/dwc3-uniphier.c
+++ b/drivers/usb/dwc3/dwc3-uniphier.c
@@ -4,14 +4,17 @@
  *
  * Copyright (C) 2016-2017 Socionext Inc.
  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *   Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
  */
 
 #include <dm.h>
-#include <dm/device_compat.h>
+#include <dm/lists.h>
 #include <linux/bitops.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/sizes.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "dwc3-generic.h"
 
 #define UNIPHIER_PRO4_DWC3_RESET	0x40
 #define   UNIPHIER_PRO4_DWC3_RESET_XIOMMU	BIT(5)
@@ -27,8 +30,11 @@
 #define UNIPHIER_PXS2_DWC3_RESET	0x00
 #define   UNIPHIER_PXS2_DWC3_RESET_XLINK	BIT(15)
 
-static int uniphier_pro4_dwc3_init(void __iomem *regs)
+static void uniphier_pro4_dwc3_init(struct udevice *dev, int index,
+				    enum usb_dr_mode mode)
 {
+	struct dwc3_glue_data *glue = dev_get_plat(dev);
+	void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
 	u32 tmp;
 
 	tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET);
@@ -36,11 +42,14 @@ static int uniphier_pro4_dwc3_init(void __iomem *regs)
 	tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK;
 	writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET);
 
-	return 0;
+	unmap_physmem(regs, MAP_NOCACHE);
 }
 
-static int uniphier_pro5_dwc3_init(void __iomem *regs)
+static void uniphier_pro5_dwc3_init(struct udevice *dev, int index,
+				    enum usb_dr_mode mode)
 {
+	struct dwc3_glue_data *glue = dev_get_plat(dev);
+	void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
 	u32 tmp;
 
 	tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET);
@@ -49,72 +58,97 @@ static int uniphier_pro5_dwc3_init(void __iomem *regs)
 	tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU;
 	writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET);
 
-	return 0;
+	unmap_physmem(regs, MAP_NOCACHE);
 }
 
-static int uniphier_pxs2_dwc3_init(void __iomem *regs)
+static void uniphier_pxs2_dwc3_init(struct udevice *dev, int index,
+				    enum usb_dr_mode mode)
 {
+	struct dwc3_glue_data *glue = dev_get_plat(dev);
+	void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
 	u32 tmp;
 
 	tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET);
 	tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK;
 	writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET);
 
-	return 0;
+	unmap_physmem(regs, MAP_NOCACHE);
 }
 
-static int uniphier_dwc3_probe(struct udevice *dev)
+static int dwc3_uniphier_glue_get_ctrl_dev(struct udevice *dev, ofnode *node)
 {
-	fdt_addr_t base;
-	void __iomem *regs;
-	int (*init)(void __iomem *regs);
-	int ret;
+	struct udevice *child;
+	const char *name;
+	ofnode subnode;
+
+	/*
+	 * "controller reset" belongs to glue logic, and it should be
+	 * accessible in .glue_configure() before access to the controller
+	 * begins.
+	 */
+	ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
+		name = ofnode_get_name(subnode);
+		if (!strncmp(name, "reset", 5))
+			device_bind_driver_to_node(dev, "uniphier-reset",
+						   name, subnode, &child);
+	}
+
+	/* Get controller node that is placed separately from the glue node */
+	*node = ofnode_by_compatible(dev_ofnode(dev->parent),
+				     "socionext,uniphier-dwc3");
 
-	base = dev_read_addr(dev);
-	if (base == FDT_ADDR_T_NONE)
-		return -EINVAL;
-
-	regs = ioremap(base, SZ_32K);
-	if (!regs)
-		return -ENOMEM;
+	return 0;
+}
 
-	init = (typeof(init))dev_get_driver_data(dev);
-	ret = init(regs);
-	if (ret)
-		dev_err(dev, "failed to init glue layer\n");
+static const struct dwc3_glue_ops uniphier_pro4_dwc3_ops = {
+	.glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
+	.glue_configure = uniphier_pro4_dwc3_init,
+};
 
-	iounmap(regs);
+static const struct dwc3_glue_ops uniphier_pro5_dwc3_ops = {
+	.glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
+	.glue_configure = uniphier_pro5_dwc3_init,
+};
 
-	return ret;
-}
+static const struct dwc3_glue_ops uniphier_pxs2_dwc3_ops = {
+	.glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
+	.glue_configure = uniphier_pxs2_dwc3_init,
+};
 
 static const struct udevice_id uniphier_dwc3_match[] = {
 	{
-		.compatible = "socionext,uniphier-pro4-dwc3",
-		.data = (ulong)uniphier_pro4_dwc3_init,
+		.compatible = "socionext,uniphier-pro4-dwc3-glue",
+		.data = (ulong)&uniphier_pro4_dwc3_ops,
+	},
+	{
+		.compatible = "socionext,uniphier-pro5-dwc3-glue",
+		.data = (ulong)&uniphier_pro5_dwc3_ops,
 	},
 	{
-		.compatible = "socionext,uniphier-pro5-dwc3",
-		.data = (ulong)uniphier_pro5_dwc3_init,
+		.compatible = "socionext,uniphier-pxs2-dwc3-glue",
+		.data = (ulong)&uniphier_pxs2_dwc3_ops,
 	},
 	{
-		.compatible = "socionext,uniphier-pxs2-dwc3",
-		.data = (ulong)uniphier_pxs2_dwc3_init,
+		.compatible = "socionext,uniphier-ld20-dwc3-glue",
+		.data = (ulong)&uniphier_pxs2_dwc3_ops,
 	},
 	{
-		.compatible = "socionext,uniphier-ld20-dwc3",
-		.data = (ulong)uniphier_pxs2_dwc3_init,
+		.compatible = "socionext,uniphier-pxs3-dwc3-glue",
+		.data = (ulong)&uniphier_pxs2_dwc3_ops,
 	},
 	{
-		.compatible = "socionext,uniphier-pxs3-dwc3",
-		.data = (ulong)uniphier_pxs2_dwc3_init,
+		.compatible = "socionext,uniphier-nx1-dwc3-glue",
+		.data = (ulong)&uniphier_pxs2_dwc3_ops,
 	},
 	{ /* sentinel */ }
 };
 
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(dwc3_uniphier_wrapper) = {
 	.name = "uniphier-dwc3",
 	.id = UCLASS_SIMPLE_BUS,
 	.of_match = uniphier_dwc3_match,
-	.probe = uniphier_dwc3_probe,
+	.bind = dwc3_glue_bind,
+	.probe = dwc3_glue_probe,
+	.remove = dwc3_glue_remove,
+	.plat_auto = sizeof(struct dwc3_glue_data),
 };