diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 57ca5f97a3dc..efbfb79baf44 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -62,6 +62,14 @@ config USB_XHCI_PLATFORM
 
 	  If unsure, say N.
 
+config USB_XHCI_SNPS
+	bool "xHCI fine tune for Synopsys platforms"
+	help
+	  Say 'Y' to enable additional fine tune for Synopsys DWC_usb3x xHCI
+	  controllers.
+
+	  If unsure, say N.
+
 config USB_XHCI_HISTB
 	tristate "xHCI support for HiSilicon STB SoCs"
 	depends on USB_XHCI_PLATFORM && (ARCH_HISI || COMPILE_TEST)
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 2948983618fb..066b78fbc1d1 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -28,6 +28,9 @@ endif
 ifneq ($(CONFIG_USB_XHCI_RCAR), )
 	xhci-plat-hcd-y		+= xhci-rcar.o
 endif
+ifneq ($(CONFIG_USB_XHCI_SNPS), )
+	xhci-plat-hcd-y		+= xhci-snps.o
+endif
 
 ifneq ($(CONFIG_DEBUG_FS),)
 	xhci-hcd-y		+= xhci-debugfs.o
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 044855818cb1..73cc0262cc75 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -24,16 +24,20 @@
 #include "xhci-plat.h"
 #include "xhci-mvebu.h"
 #include "xhci-rcar.h"
+#include "xhci-snps.h"
 
 static struct hc_driver __read_mostly xhci_plat_hc_driver;
 
 static int xhci_plat_setup(struct usb_hcd *hcd);
 static int xhci_plat_start(struct usb_hcd *hcd);
+static int xhci_plat_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+				  struct usb_host_endpoint *ep);
 
 static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
 	.extra_priv_size = sizeof(struct xhci_plat_priv),
 	.reset = xhci_plat_setup,
 	.start = xhci_plat_start,
+	.add_endpoint = xhci_plat_add_endpoint,
 };
 
 static void xhci_priv_plat_start(struct usb_hcd *hcd)
@@ -105,6 +109,20 @@ static int xhci_plat_start(struct usb_hcd *hcd)
 	return xhci_run(hcd);
 }
 
+static int xhci_plat_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+				  struct usb_host_endpoint *ep)
+{
+	struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+	int ret;
+
+	if (priv && priv->add_endpoint_quirk)
+		ret = priv->add_endpoint_quirk(hcd, udev, ep);
+	else
+		ret = xhci_add_endpoint(hcd, udev, ep);
+
+	return ret;
+}
+
 #ifdef CONFIG_OF
 static const struct xhci_plat_priv xhci_plat_marvell_armada = {
 	.init_quirk = xhci_mvebu_mbus_init_quirk,
@@ -173,6 +191,25 @@ static const struct of_device_id usb_xhci_of_match[] = {
 MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
 #endif
 
+static int xhci_plat_setup_snps_quirks(struct usb_hcd *hcd)
+{
+	struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_USB_XHCI_SNPS))
+		return 0;
+
+	ret = xhci_snps_init(hcd);
+	if (ret) {
+		dev_err(hcd->self.controller, "SNPS extension setup fails\n");
+		return ret;
+	}
+
+	priv->init_quirk = &xhci_snps_setup;
+	priv->add_endpoint_quirk = &xhci_snps_add_endpoint;
+	return 0;
+}
+
 static int xhci_plat_probe(struct platform_device *pdev)
 {
 	const struct xhci_plat_priv *priv_match;
@@ -301,6 +338,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
 		if (device_property_read_bool(tmpdev, "quirk-broken-port-ped"))
 			xhci->quirks |= XHCI_BROKEN_PORT_PED;
 
+		if (device_property_read_bool(tmpdev, "xhci-snps-quirks"))
+			xhci_plat_setup_snps_quirks(hcd);
+
 		device_property_read_u32(tmpdev, "imod-interval-ns",
 					 &xhci->imod_interval);
 	}
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index 1fb149d1fbce..7b49aba73833 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -17,6 +17,9 @@ struct xhci_plat_priv {
 	int (*init_quirk)(struct usb_hcd *);
 	int (*suspend_quirk)(struct usb_hcd *);
 	int (*resume_quirk)(struct usb_hcd *);
+	int (*add_endpoint_quirk)(struct usb_hcd *hcd,
+				  struct usb_device *udev,
+				  struct usb_host_endpoint *ep);
 };
 
 #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
diff --git a/drivers/usb/host/xhci-snps.c b/drivers/usb/host/xhci-snps.c
new file mode 100644
index 000000000000..932d914a090a
--- /dev/null
+++ b/drivers/usb/host/xhci-snps.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xhci-snps.c - xHCI glue extension for Synopsys DWC_usb3x IPs.
+ *
+ * Copyright (C) 2022 Synopsys Inc.
+ *
+ * Author: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+ *
+ * Contains some borrowed code from dwc3 driver.
+ */
+
+#include "xhci.h"
+#include "xhci-snps.h"
+
+#define DWC3_GSNPSID			0xc120
+#define DWC3_VER_NUMBER			0xc1a0
+#define DWC3_VER_TYPE			0xc1a4
+
+#define DWC3_GLOBALS_REGS_END		0xc6ff
+
+#define DWC3_GSNPSID_MASK		0xffff0000
+#define DWC3_GSNPS_ID(p)		(((p) & DWC3_GSNPSID_MASK) >> 16)
+
+#define DWC3_IP				0x5533
+#define DWC31_IP			0x3331
+#define DWC32_IP			0x3332
+
+#define DWC3_REVISION_ANY		0x0
+#define DWC3_REVISION_173A		0x5533173a
+#define DWC3_REVISION_175A		0x5533175a
+#define DWC3_REVISION_180A		0x5533180a
+#define DWC3_REVISION_183A		0x5533183a
+#define DWC3_REVISION_185A		0x5533185a
+#define DWC3_REVISION_187A		0x5533187a
+#define DWC3_REVISION_188A		0x5533188a
+#define DWC3_REVISION_190A		0x5533190a
+#define DWC3_REVISION_194A		0x5533194a
+#define DWC3_REVISION_200A		0x5533200a
+#define DWC3_REVISION_202A		0x5533202a
+#define DWC3_REVISION_210A		0x5533210a
+#define DWC3_REVISION_220A		0x5533220a
+#define DWC3_REVISION_230A		0x5533230a
+#define DWC3_REVISION_240A		0x5533240a
+#define DWC3_REVISION_250A		0x5533250a
+#define DWC3_REVISION_260A		0x5533260a
+#define DWC3_REVISION_270A		0x5533270a
+#define DWC3_REVISION_280A		0x5533280a
+#define DWC3_REVISION_290A		0x5533290a
+#define DWC3_REVISION_300A		0x5533300a
+#define DWC3_REVISION_310A		0x5533310a
+#define DWC3_REVISION_330A		0x5533330a
+
+#define DWC31_REVISION_ANY		0x0
+#define DWC31_REVISION_110A		0x3131302a
+#define DWC31_REVISION_120A		0x3132302a
+#define DWC31_REVISION_160A		0x3136302a
+#define DWC31_REVISION_170A		0x3137302a
+#define DWC31_REVISION_180A		0x3138302a
+#define DWC31_REVISION_190A		0x3139302a
+
+#define DWC32_REVISION_ANY		0x0
+#define DWC32_REVISION_100A		0x3130302a
+
+#define DWC31_VERSIONTYPE_ANY		0x0
+#define DWC31_VERSIONTYPE_EA01		0x65613031
+#define DWC31_VERSIONTYPE_EA02		0x65613032
+#define DWC31_VERSIONTYPE_EA03		0x65613033
+#define DWC31_VERSIONTYPE_EA04		0x65613034
+#define DWC31_VERSIONTYPE_EA05		0x65613035
+#define DWC31_VERSIONTYPE_EA06		0x65613036
+
+#define DWC3_IP_IS(_ip)							\
+	(snps->ip == _ip##_IP)
+
+#define DWC3_VER_IS(_ip, _ver)						\
+	(DWC3_IP_IS(_ip) && snps->revision == _ip##_REVISION_##_ver)
+
+#define DWC3_VER_IS_PRIOR(_ip, _ver)					\
+	(DWC3_IP_IS(_ip) && snps->revision < _ip##_REVISION_##_ver)
+
+#define DWC3_VER_IS_WITHIN(_ip, _from, _to)				\
+	(DWC3_IP_IS(_ip) &&						\
+	 snps->revision >= _ip##_REVISION_##_from &&			\
+	 (!(_ip##_REVISION_##_to) ||					\
+	  snps->revision <= _ip##_REVISION_##_to))
+
+#define DWC3_VER_TYPE_IS_WITHIN(_ip, _ver, _from, _to)			\
+	(DWC3_VER_IS(_ip, _ver) &&					\
+	 snps->version_type >= _ip##_VERSIONTYPE_##_from &&		\
+	 (!(_ip##_VERSIONTYPE_##_to) ||					\
+	  snps->version_type <= _ip##_VERSIONTYPE_##_to))
+
+/**
+ * struct xhci_snps - Wrapper for DWC_usb3x host controller
+ * @hcd: the main host device
+ * @ip: controller's ID
+ * @revision: controller's version of an IP
+ * @version_type: VERSIONTYPE register contents, a sub release of a revision
+ */
+struct xhci_snps {
+	struct usb_hcd	*hcd;
+	u32		ip;
+	u32		revision;
+	u32		version_type;
+};
+
+#define dev_to_xhci_snps(p) (container_of((p), struct xhci_snps, dev))
+
+int xhci_snps_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+			   struct usb_host_endpoint *ep)
+{
+	struct xhci_snps *snps = dev_get_drvdata(hcd->self.controller);
+
+	if (DWC3_VER_IS_WITHIN(DWC31, ANY, 190A) &&
+	    usb_endpoint_xfer_int(&ep->desc) &&
+	    udev->speed == USB_SPEED_FULL && ep->desc.bInterval == 6)
+		ep->desc.bInterval = 5;
+
+	return xhci_add_endpoint(hcd, udev, ep);
+}
+
+static bool xhci_is_snps(struct usb_hcd *hcd)
+{
+	u32 id;
+
+	if (hcd->rsrc_len < DWC3_GLOBALS_REGS_END)
+		return false;
+
+	id = DWC3_GSNPS_ID(readl(hcd->regs + DWC3_GSNPSID));
+
+	return (id == DWC3_IP || id == DWC31_IP || id == DWC32_IP);
+}
+
+static int xhci_snps_init_version(struct xhci_snps *snps)
+{
+	void __iomem *regs = snps->hcd->regs;
+	u32 reg;
+
+	reg = readl(regs + DWC3_GSNPSID);
+	snps->ip = DWC3_GSNPS_ID(reg);
+
+	if (DWC3_IP_IS(DWC3)) {
+		snps->revision = reg;
+	} else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) {
+		snps->revision = readl(regs + DWC3_VER_NUMBER);
+		snps->version_type = readl(regs + DWC3_VER_TYPE);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int xhci_snps_setup(struct usb_hcd *hcd)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+	/* These quirks are applicable to all DWC_usb3x IPs and versions */
+	xhci->quirks |= XHCI_SKIP_PHY_INIT | XHCI_SG_TRB_CACHE_SIZE_QUIRK;
+
+	return 0;
+}
+
+int xhci_snps_init(struct usb_hcd *hcd)
+{
+	struct device *dev = hcd->self.controller;
+	struct xhci_snps *snps;
+	int ret;
+
+	if (!xhci_is_snps(hcd))
+		return -EINVAL;
+
+	snps = devm_kzalloc(dev, sizeof(*snps), GFP_KERNEL);
+	if (!snps)
+		return -ENOMEM;
+
+	snps->hcd = hcd;
+
+	ret = xhci_snps_init_version(snps);
+	if (ret)
+		return ret;
+
+	dev_set_drvdata(dev, snps);
+	return 0;
+}
diff --git a/drivers/usb/host/xhci-snps.h b/drivers/usb/host/xhci-snps.h
new file mode 100644
index 000000000000..c35a7ffdeaa3
--- /dev/null
+++ b/drivers/usb/host/xhci-snps.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Synopsys Inc.
+ */
+
+#ifndef _XHCI_SNPS_H
+#define _XHCI_SNPS_H
+
+#if IS_ENABLED(CONFIG_USB_XHCI_SNPS)
+int xhci_snps_init(struct usb_hcd *hcd);
+int xhci_snps_setup(struct usb_hcd *hcd);
+int xhci_snps_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+			   struct usb_host_endpoint *ep);
+#else
+static inline int xhci_snps_init(struct usb_hcd *hcd)
+{
+	return 0;
+}
+
+static inline int xhci_snps_setup(struct usb_hcd *hcd)
+{
+	return 0;
+}
+
+static int xhci_snps_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+				  struct usb_host_endpoint *ep)
+{
+	return 0;
+}
+#endif
+
+#endif /* _XHCI_SNPS_H */
