[PATCH 03/10] usb: dwc3: rtk: Add new realtek soc dwc3 controller glue driver

stanley_chang stanley_chang at realtek.com
Thu Sep 17 04:38:28 EDT 2020


Realtek DHC SoCs embeds a DWC3 USB IP Core. This USB module can be drive
by dwc3-rtk glue driver

Signed-off-by: stanley_chang <stanley_chang at realtek.com>
---
 drivers/usb/dwc3/Kconfig            |  10 +
 drivers/usb/dwc3/Makefile           |   1 +
 drivers/usb/dwc3/dwc3-rtk-debugfs.c | 501 ++++++++++++++++++++++++++++
 drivers/usb/dwc3/dwc3-rtk.c         | 336 +++++++++++++++++++
 drivers/usb/dwc3/dwc3-rtk.h         |  45 +++
 5 files changed, 893 insertions(+)
 create mode 100644 drivers/usb/dwc3/dwc3-rtk-debugfs.c
 create mode 100644 drivers/usb/dwc3/dwc3-rtk.c
 create mode 100644 drivers/usb/dwc3/dwc3-rtk.h

diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 206caa0ea1c6..5353d05d9f6c 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -52,6 +52,16 @@ endchoice
 
 comment "Platform Glue Driver Support"
 
+config USB_DWC3_RTK
+	tristate "Realtek DWC3 Platform Driver"
+	default USB_DWC3
+	select RTK_USB2PHY
+	select RTK_USB3PHY
+	help
+	  RTK SoCs with DesignWare Core USB3 IP inside,
+	  say 'Y' or 'M' if you have such device.
+
+
 config USB_DWC3_OMAP
 	tristate "Texas Instruments OMAP5 and similar Platforms"
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index ae86da0dc5bd..d57cb12d000a 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A)	+= dwc3-meson-g12a.o
 obj-$(CONFIG_USB_DWC3_OF_SIMPLE)	+= dwc3-of-simple.o
 obj-$(CONFIG_USB_DWC3_ST)		+= dwc3-st.o
 obj-$(CONFIG_USB_DWC3_QCOM)		+= dwc3-qcom.o
+obj-$(CONFIG_USB_DWC3_RTK)		+= dwc3-rtk.o dwc3-rtk-debugfs.o
diff --git a/drivers/usb/dwc3/dwc3-rtk-debugfs.c b/drivers/usb/dwc3/dwc3-rtk-debugfs.c
new file mode 100644
index 000000000000..367f194c4e8e
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-rtk-debugfs.c
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-rtk-debugfs.c - Reltek DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2020 Realtek Semiconductor Corporation
+ *
+ */
+
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/of_address.h>
+
+#include "dwc3-rtk.h"
+#include "core.h"
+#include "io.h"
+
+#ifdef CONFIG_DYNAMIC_DEBUG
+
+struct rtk_debugfs_reg32 {
+	char *name;
+	unsigned long offset;
+	int default_val;
+};
+
+#define dump_register(nm)				\
+{							\
+	.name	= __stringify(nm) " [" __stringify(DWC3_ ##nm) "]", \
+	.offset	= DWC3_ ##nm,				\
+}
+
+#define dump_ep_register_set_DEPCMDPAR2(n)	\
+	{					\
+		.name = "DEPCMDPAR2("__stringify(n)") ["	\
+			    __stringify(DWC3_DEP_BASE(n)) " + " \
+			    __stringify(DWC3_DEPCMDPAR2) "]",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMDPAR2,	\
+	},
+#define dump_ep_register_set_DEPCMDPAR1(n)	\
+	{					\
+		.name = "DEPCMDPAR1("__stringify(n)" ["		\
+			    __stringify(DWC3_DEP_BASE(n)) " + " \
+			    __stringify(DWC3_DEPCMDPAR1) "]",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMDPAR1,	\
+	},
+#define dump_ep_register_set_DEPCMDPAR0(n)	\
+	{					\
+		.name = "DEPCMDPAR0("__stringify(n)") ["	\
+			    __stringify(DWC3_DEP_BASE(n)) " + " \
+			    __stringify(DWC3_DEPCMDPAR0) "]",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMDPAR0,	\
+	},
+#define dump_ep_register_set_CMD(n)		\
+	{					\
+		.name = "DEPCMD("__stringify(n)") [" \
+			    __stringify(DWC3_DEP_BASE(n)) " + " \
+			    __stringify(DWC3_DEPCMD) "]",	\
+		.offset = DWC3_DEP_BASE(n) +	\
+			DWC3_DEPCMD,		\
+	}
+
+#define dump_ep_register_set(n)				\
+	dump_ep_register_set_DEPCMDPAR2(n)		\
+	dump_ep_register_set_DEPCMDPAR1(n)		\
+	dump_ep_register_set_DEPCMDPAR0(n)		\
+	dump_ep_register_set_CMD(n)			\
+
+static const struct rtk_debugfs_reg32 dwc3_regs[] = {
+	dump_register(GSBUSCFG0),
+	dump_register(GSBUSCFG1),
+	dump_register(GTXTHRCFG),
+	dump_register(GRXTHRCFG),
+	dump_register(GCTL),
+	dump_register(GEVTEN),
+	dump_register(GSTS),
+	dump_register(GUCTL1),
+	dump_register(GSNPSID),
+	dump_register(GGPIO),
+	dump_register(GUID),
+	dump_register(GUCTL),
+	dump_register(GBUSERRADDR0),
+	dump_register(GBUSERRADDR1),
+	dump_register(GPRTBIMAP0),
+	dump_register(GPRTBIMAP1),
+	dump_register(GHWPARAMS0),
+	dump_register(GHWPARAMS1),
+	dump_register(GHWPARAMS2),
+	dump_register(GHWPARAMS3),
+	dump_register(GHWPARAMS4),
+	dump_register(GHWPARAMS5),
+	dump_register(GHWPARAMS6),
+	dump_register(GHWPARAMS7),
+	dump_register(GDBGFIFOSPACE),
+	dump_register(GDBGLTSSM),
+	dump_register(GPRTBIMAP_HS0),
+	dump_register(GPRTBIMAP_HS1),
+	dump_register(GPRTBIMAP_FS0),
+	dump_register(GPRTBIMAP_FS1),
+
+	dump_register(GUSB2PHYCFG(0)),
+	dump_register(GUSB2PHYCFG(1)),
+	dump_register(GUSB2PHYCFG(2)),
+	dump_register(GUSB2PHYCFG(3)),
+	dump_register(GUSB2PHYCFG(4)),
+	dump_register(GUSB2PHYCFG(5)),
+	dump_register(GUSB2PHYCFG(6)),
+	dump_register(GUSB2PHYCFG(7)),
+	dump_register(GUSB2PHYCFG(8)),
+	dump_register(GUSB2PHYCFG(9)),
+	dump_register(GUSB2PHYCFG(10)),
+	dump_register(GUSB2PHYCFG(11)),
+	dump_register(GUSB2PHYCFG(12)),
+	dump_register(GUSB2PHYCFG(13)),
+	dump_register(GUSB2PHYCFG(14)),
+	dump_register(GUSB2PHYCFG(15)),
+
+	dump_register(GUSB2I2CCTL(0)),
+	dump_register(GUSB2I2CCTL(1)),
+	dump_register(GUSB2I2CCTL(2)),
+	dump_register(GUSB2I2CCTL(3)),
+	dump_register(GUSB2I2CCTL(4)),
+	dump_register(GUSB2I2CCTL(5)),
+	dump_register(GUSB2I2CCTL(6)),
+	dump_register(GUSB2I2CCTL(7)),
+	dump_register(GUSB2I2CCTL(8)),
+	dump_register(GUSB2I2CCTL(9)),
+	dump_register(GUSB2I2CCTL(10)),
+	dump_register(GUSB2I2CCTL(11)),
+	dump_register(GUSB2I2CCTL(12)),
+	dump_register(GUSB2I2CCTL(13)),
+	dump_register(GUSB2I2CCTL(14)),
+	dump_register(GUSB2I2CCTL(15)),
+
+	dump_register(GUSB2PHYACC(0)),
+	dump_register(GUSB2PHYACC(1)),
+	dump_register(GUSB2PHYACC(2)),
+	dump_register(GUSB2PHYACC(3)),
+	dump_register(GUSB2PHYACC(4)),
+	dump_register(GUSB2PHYACC(5)),
+	dump_register(GUSB2PHYACC(6)),
+	dump_register(GUSB2PHYACC(7)),
+	dump_register(GUSB2PHYACC(8)),
+	dump_register(GUSB2PHYACC(9)),
+	dump_register(GUSB2PHYACC(10)),
+	dump_register(GUSB2PHYACC(11)),
+	dump_register(GUSB2PHYACC(12)),
+	dump_register(GUSB2PHYACC(13)),
+	dump_register(GUSB2PHYACC(14)),
+	dump_register(GUSB2PHYACC(15)),
+
+	dump_register(GUSB3PIPECTL(0)),
+	dump_register(GUSB3PIPECTL(1)),
+	dump_register(GUSB3PIPECTL(2)),
+	dump_register(GUSB3PIPECTL(3)),
+	dump_register(GUSB3PIPECTL(4)),
+	dump_register(GUSB3PIPECTL(5)),
+	dump_register(GUSB3PIPECTL(6)),
+	dump_register(GUSB3PIPECTL(7)),
+	dump_register(GUSB3PIPECTL(8)),
+	dump_register(GUSB3PIPECTL(9)),
+	dump_register(GUSB3PIPECTL(10)),
+	dump_register(GUSB3PIPECTL(11)),
+	dump_register(GUSB3PIPECTL(12)),
+	dump_register(GUSB3PIPECTL(13)),
+	dump_register(GUSB3PIPECTL(14)),
+	dump_register(GUSB3PIPECTL(15)),
+
+	dump_register(GTXFIFOSIZ(0)),
+	dump_register(GTXFIFOSIZ(1)),
+	dump_register(GTXFIFOSIZ(2)),
+	dump_register(GTXFIFOSIZ(3)),
+	dump_register(GTXFIFOSIZ(4)),
+	dump_register(GTXFIFOSIZ(5)),
+	dump_register(GTXFIFOSIZ(6)),
+	dump_register(GTXFIFOSIZ(7)),
+	dump_register(GTXFIFOSIZ(8)),
+	dump_register(GTXFIFOSIZ(9)),
+	dump_register(GTXFIFOSIZ(10)),
+	dump_register(GTXFIFOSIZ(11)),
+	dump_register(GTXFIFOSIZ(12)),
+	dump_register(GTXFIFOSIZ(13)),
+	dump_register(GTXFIFOSIZ(14)),
+	dump_register(GTXFIFOSIZ(15)),
+	dump_register(GTXFIFOSIZ(16)),
+	dump_register(GTXFIFOSIZ(17)),
+	dump_register(GTXFIFOSIZ(18)),
+	dump_register(GTXFIFOSIZ(19)),
+	dump_register(GTXFIFOSIZ(20)),
+	dump_register(GTXFIFOSIZ(21)),
+	dump_register(GTXFIFOSIZ(22)),
+	dump_register(GTXFIFOSIZ(23)),
+	dump_register(GTXFIFOSIZ(24)),
+	dump_register(GTXFIFOSIZ(25)),
+	dump_register(GTXFIFOSIZ(26)),
+	dump_register(GTXFIFOSIZ(27)),
+	dump_register(GTXFIFOSIZ(28)),
+	dump_register(GTXFIFOSIZ(29)),
+	dump_register(GTXFIFOSIZ(30)),
+	dump_register(GTXFIFOSIZ(31)),
+
+	dump_register(GRXFIFOSIZ(0)),
+	dump_register(GRXFIFOSIZ(1)),
+	dump_register(GRXFIFOSIZ(2)),
+	dump_register(GRXFIFOSIZ(3)),
+	dump_register(GRXFIFOSIZ(4)),
+	dump_register(GRXFIFOSIZ(5)),
+	dump_register(GRXFIFOSIZ(6)),
+	dump_register(GRXFIFOSIZ(7)),
+	dump_register(GRXFIFOSIZ(8)),
+	dump_register(GRXFIFOSIZ(9)),
+	dump_register(GRXFIFOSIZ(10)),
+	dump_register(GRXFIFOSIZ(11)),
+	dump_register(GRXFIFOSIZ(12)),
+	dump_register(GRXFIFOSIZ(13)),
+	dump_register(GRXFIFOSIZ(14)),
+	dump_register(GRXFIFOSIZ(15)),
+	dump_register(GRXFIFOSIZ(16)),
+	dump_register(GRXFIFOSIZ(17)),
+	dump_register(GRXFIFOSIZ(18)),
+	dump_register(GRXFIFOSIZ(19)),
+	dump_register(GRXFIFOSIZ(20)),
+	dump_register(GRXFIFOSIZ(21)),
+	dump_register(GRXFIFOSIZ(22)),
+	dump_register(GRXFIFOSIZ(23)),
+	dump_register(GRXFIFOSIZ(24)),
+	dump_register(GRXFIFOSIZ(25)),
+	dump_register(GRXFIFOSIZ(26)),
+	dump_register(GRXFIFOSIZ(27)),
+	dump_register(GRXFIFOSIZ(28)),
+	dump_register(GRXFIFOSIZ(29)),
+	dump_register(GRXFIFOSIZ(30)),
+	dump_register(GRXFIFOSIZ(31)),
+
+	dump_register(GEVNTADRLO(0)),
+	dump_register(GEVNTADRHI(0)),
+	dump_register(GEVNTSIZ(0)),
+	dump_register(GEVNTCOUNT(0)),
+
+	dump_register(GHWPARAMS8),
+	dump_register(DCFG),
+	dump_register(DCTL),
+	dump_register(DEVTEN),
+	dump_register(DSTS),
+	dump_register(DGCMDPAR),
+	dump_register(DGCMD),
+	dump_register(DALEPENA),
+
+	dump_ep_register_set(0),
+	dump_ep_register_set(1),
+	dump_ep_register_set(2),
+	dump_ep_register_set(3),
+	dump_ep_register_set(4),
+	dump_ep_register_set(5),
+	dump_ep_register_set(6),
+	dump_ep_register_set(7),
+	dump_ep_register_set(8),
+	dump_ep_register_set(9),
+	dump_ep_register_set(10),
+	dump_ep_register_set(11),
+	dump_ep_register_set(12),
+	dump_ep_register_set(13),
+	dump_ep_register_set(14),
+	dump_ep_register_set(15),
+	dump_ep_register_set(16),
+	dump_ep_register_set(17),
+	dump_ep_register_set(18),
+	dump_ep_register_set(19),
+	dump_ep_register_set(20),
+	dump_ep_register_set(21),
+	dump_ep_register_set(22),
+	dump_ep_register_set(23),
+	dump_ep_register_set(24),
+	dump_ep_register_set(25),
+	dump_ep_register_set(26),
+	dump_ep_register_set(27),
+	dump_ep_register_set(28),
+	dump_ep_register_set(29),
+	dump_ep_register_set(30),
+	dump_ep_register_set(31),
+
+	dump_register(OCFG),
+	dump_register(OCTL),
+	dump_register(OEVT),
+	dump_register(OEVTEN),
+	dump_register(OSTS),
+};
+
+#define dump_wrap_register(nm)				\
+{							\
+	.name	= __stringify(nm) " [" __stringify(WRAP_ ##nm) "]", \
+	.offset	= WRAP_ ##nm,				\
+}
+
+static const struct rtk_debugfs_reg32 wrap_regs[] = {
+	dump_wrap_register(CTR_reg),
+	dump_wrap_register(USB_HMAC_CTR0_reg),
+	dump_wrap_register(USB2_PHY_reg),
+};
+
+static int dwc3_rtk_dwc_regdump_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_rtk		*dwc3_rtk = s->private;
+	struct dwc3		*dwc;
+	unsigned long		flags;
+	struct rtk_debugfs_reg32 *regs = (struct rtk_debugfs_reg32 *)dwc3_regs;
+	u32 nregs = ARRAY_SIZE(dwc3_regs);
+	int i;
+
+	dwc = dwc3_rtk->dwc;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	for (i = 0; i < nregs; i++, regs++) {
+		u32 val = dwc3_readl(dwc->regs, regs->offset);
+
+		seq_printf(s, "%s = 0x%08x -> 0x%08x (diff=0x%08x)\n",
+			    regs->name,
+			    regs->default_val, val, regs->default_val ^ val);
+		if (seq_has_overflowed(s))
+			break;
+	}
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_rtk_dwc_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_rtk_dwc_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_rtk_dwc_regdump_fops = {
+	.open			= dwc3_rtk_dwc_regdump_open,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int dwc3_rtk_wrap_regdump_show(struct seq_file *s, void *unused)
+{
+	struct dwc3_rtk		*dwc3_rtk = s->private;
+	struct rtk_debugfs_reg32 *regs = (struct rtk_debugfs_reg32 *)wrap_regs;
+	u32 nregs = ARRAY_SIZE(wrap_regs);
+	int i;
+
+	for (i = 0; i < nregs; i++, regs++) {
+		u32 val = readl(dwc3_rtk->regs + regs->offset);
+
+		seq_printf(s, "%s = 0x%08x -> 0x%08x (diff=0x%08x)\n",
+			    regs->name,
+			    regs->default_val, val, regs->default_val ^ val);
+		if (seq_has_overflowed(s))
+			break;
+	}
+
+	return 0;
+}
+
+static int dwc3_rtk_wrap_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_rtk_wrap_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_rtk_wrap_regdump_fops = {
+	.open			= dwc3_rtk_wrap_regdump_open,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+void dwc3_rtk_regdump_init(struct dwc3_rtk *dwc3_rtk)
+{
+	struct device		*dev;
+	struct device_node	*node;
+	struct device_node	*dwc3_node;
+
+	if (!dwc3_rtk) {
+		pr_err("%s: No device for dwc3_rtk!\n", __func__);
+		return;
+	}
+
+	dev = dwc3_rtk->dev;
+	if (!dev) {
+		pr_err("%s: No device for dwc3_rtk!\n", __func__);
+		return;
+	}
+
+	node = dev->of_node;
+	if (!node) {
+		pr_err("%s: No device node for dwc3_rtk!\n", __func__);
+		return;
+	}
+
+	dwc3_node = of_get_next_child(node, NULL);
+	if (dwc3_node) {
+		const __be32	*addrp;
+		u64		addr;
+		u64		size;
+		unsigned int	flags;
+		u32		fixed_dwc3_globals_regs_start;
+		struct rtk_debugfs_reg32 *regs;
+		void __iomem *base;
+		int i;
+
+		regs = (struct rtk_debugfs_reg32 *)dwc3_regs;
+
+		addrp = of_get_address(dwc3_node, 0, &size, &flags);
+		if (addrp == NULL) {
+			dev_err(dev, "%s: Error! Can't get dwc3 reg address!\n",
+				    __func__);
+			return;
+		}
+		addr = of_translate_address(dwc3_node, addrp);
+
+		of_property_read_u32(dwc3_node,
+			    "snps,fixed_dwc3_globals_regs_start",
+			    &fixed_dwc3_globals_regs_start);
+		if (fixed_dwc3_globals_regs_start) {
+			addr += fixed_dwc3_globals_regs_start;
+			size -= fixed_dwc3_globals_regs_start;
+		}
+		dev_dbg(dev, "dwc3 register start address to 0x%x (size=%x)\n",
+			    (u32)addr, (u32)size);
+
+		base = ioremap(addr, size);
+		for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++, regs++)
+			regs->default_val = dwc3_readl(base, regs->offset);
+
+		iounmap(base);
+	}
+
+	if (dwc3_rtk) {
+		struct rtk_debugfs_reg32 *regs;
+		int i;
+
+		regs = (struct rtk_debugfs_reg32 *)wrap_regs;
+
+		for (i = 0; i < ARRAY_SIZE(wrap_regs); i++, regs++) {
+			regs->default_val = readl(dwc3_rtk->regs +
+			    regs->offset);
+		}
+	}
+}
+
+void dwc3_rtk_debugfs_init(struct dwc3_rtk *dwc3_rtk)
+{
+	struct dentry		*debug_dir;
+	struct dentry		*file;
+	struct device		*dev;
+
+	if (!dwc3_rtk) {
+		pr_err("%s: No device for dwc3_rtk!\n", __func__);
+		return;
+	}
+
+	dev = dwc3_rtk->dev;
+	if (!dev) {
+		pr_err("%s: No device for dwc3_rtk!\n", __func__);
+		return;
+	}
+
+	dwc3_rtk_regdump_init(dwc3_rtk);
+
+	debug_dir = debugfs_create_dir(dev_name(dev), usb_debug_root);
+	if (!debug_dir) {
+		dev_err(dev, "%s: Can't create debugfs dir\n", __func__);
+		return;
+	}
+	dwc3_rtk->debug_dir = debug_dir;
+
+	file = debugfs_create_file("dwc3_regdump", S_IRUGO,
+		    debug_dir, dwc3_rtk, &dwc3_rtk_dwc_regdump_fops);
+	if (!file)
+		dev_err(dev, "%s: Can't create debugfs regdump\n", __func__);
+
+	file = debugfs_create_file("wrap_regdump", S_IRUGO,
+		    debug_dir, dwc3_rtk, &dwc3_rtk_wrap_regdump_fops);
+	if (!file)
+		dev_err(dev, "%s: Can't create debugfs regdump\n", __func__);
+}
+
+void dwc3_rtk_debugfs_exit(struct dwc3_rtk *dwc3_rtk)
+{
+	debugfs_remove_recursive(dwc3_rtk->debug_dir);
+}
+
+#else
+void dwc3_rtk_debugfs_init(struct dwc3_rtk *dwc3_rtk)
+{
+
+}
+
+void dwc3_rtk_debugfs_exit(struct dwc3_rtk *dwc3_rtk)
+{
+
+}
+#endif /* CONFIG_DYNAMIC_DEBUG */
diff --git a/drivers/usb/dwc3/dwc3-rtk.c b/drivers/usb/dwc3/dwc3-rtk.c
new file mode 100644
index 000000000000..3291ee401a64
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-rtk.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-rtk.c - Realtek DWC3 Specific Glue layer
+ *
+ * Copyright (C) 2017 Realtek Semiconductor Corporation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/suspend.h>
+#include <linux/sys_soc.h>
+
+#include "dwc3-rtk.h"
+#include "core.h"
+#include "io.h"
+
+static const struct soc_device_attribute rtk_soc_kylin_a00[] = {
+	{
+		.family = "Realtek Kylin",
+		.revision = "A00",
+	},
+	{
+		/* empty */
+	}
+};
+
+static const struct soc_device_attribute rtk_soc_hercules[] = {
+	{
+		.family = "Realtek Hercules",
+	},
+	{
+		/* empty */
+	}
+};
+
+static void switch_u2_dr_mode(struct dwc3_rtk *rtk, int dr_mode)
+{
+	switch (dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+		writel(USB2_PHY_SWITCH_DEVICE |
+			    (~USB2_PHY_SWITCH_MASK &
+			      readl(rtk->regs + WRAP_USB2_PHY_reg)),
+			    rtk->regs + WRAP_USB2_PHY_reg);
+		break;
+	case USB_DR_MODE_HOST:
+		writel(USB2_PHY_SWITCH_HOST |
+			    (~USB2_PHY_SWITCH_MASK &
+			      readl(rtk->regs + WRAP_USB2_PHY_reg)),
+			    rtk->regs + WRAP_USB2_PHY_reg);
+		break;
+	case USB_DR_MODE_OTG:
+		//writel(BIT(11) , rtk->regs + WRAP_USB2_PHY_reg);
+		dev_info(rtk->dev, "%s: USB_DR_MODE_OTG\n", __func__);
+		break;
+	}
+}
+
+static int dwc3_rtk_init(struct dwc3_rtk *rtk)
+{
+	struct device		*dev = rtk->dev;
+	void __iomem		*regs = rtk->regs;
+
+	if (soc_device_match(rtk_soc_kylin_a00)) {
+		writel(DISABLE_MULTI_REQ | readl(regs + WRAP_CTR_reg),
+				regs + WRAP_CTR_reg);
+		dev_info(dev, "[bug fixed] 1295/1296 A00: add workaround to disable multiple request for D-Bus");
+	}
+
+	if (soc_device_match(rtk_soc_hercules)) {
+		writel(USB2_PHY_EN_PHY_PLL_PORT1 |
+			    readl(regs + WRAP_USB2_PHY_reg),
+			    regs + WRAP_USB2_PHY_reg);
+		dev_info(dev, "[bug fixed] 1395 add workaround to disable usb2 port 2 suspend!");
+
+	}
+	return 0;
+}
+
+static int dwc3_rtk_probe_dwc3core(struct dwc3_rtk *rtk)
+{
+	struct device		*dev = rtk->dev;
+	struct device_node	*node = dev->of_node;
+	struct device_node	*dwc3_node;
+	int    ret = 0;
+
+	dwc3_rtk_init(rtk);
+
+	if (node) {
+		ret = of_platform_populate(node, NULL, NULL, dev);
+		if (ret) {
+			dev_err(dev, "failed to add dwc3 core\n");
+			return ret;
+		}
+
+		dwc3_node = of_get_next_child(node, NULL);
+		if (dwc3_node != NULL) {
+			struct device *dwc3_dev;
+			struct platform_device *dwc3_pdev;
+			int dr_mode;
+
+			dwc3_pdev = of_find_device_by_node(dwc3_node);
+			dwc3_dev = &dwc3_pdev->dev;
+			rtk->dwc = platform_get_drvdata(dwc3_pdev);
+
+			dr_mode = usb_get_dr_mode(dwc3_dev);
+			rtk->default_dwc3_dr_mode = dr_mode;
+			rtk->cur_dr_mode = dr_mode;
+
+			switch_u2_dr_mode(rtk, dr_mode);
+
+		} else {
+			dev_err(dev, "dwc3 node is NULL\n");
+		}
+	} else {
+		dev_err(dev, "dwc3_rtk node is NULL\n");
+	}
+
+	return ret;
+}
+
+static void dwc3_rtk_probe_work(struct work_struct *work)
+{
+	struct dwc3_rtk *rtk = container_of(work, struct dwc3_rtk, work);
+	struct device		*dev = rtk->dev;
+	int    ret = 0;
+
+	unsigned long probe_time = jiffies;
+
+	dev_info(dev, "%s Start ...\n", __func__);
+
+	ret = dwc3_rtk_probe_dwc3core(rtk);
+
+	if (ret)
+		dev_err(dev, "%s failed to add dwc3 core\n", __func__);
+
+	dev_info(dev, "%s End ... ok! (take %d ms)\n", __func__,
+		    jiffies_to_msecs(jiffies - probe_time));
+}
+
+static int dwc3_rtk_probe(struct platform_device *pdev)
+{
+	struct dwc3_rtk	*rtk;
+	struct device		*dev = &pdev->dev;
+	struct device_node	*node = dev->of_node;
+
+	struct resource         *res;
+	void __iomem            *regs;
+
+	int			ret = -ENOMEM;
+	unsigned long probe_time = jiffies;
+
+	dev_info(&pdev->dev, "Probe Realtek-SoC USB DWC3 Host Controller\n");
+
+	rtk = devm_kzalloc(dev, sizeof(*rtk), GFP_KERNEL);
+	if (!rtk)
+		goto err1;
+
+	/*
+	 * Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we move to full device tree support this will vanish off.
+	 */
+	if (!dev->dma_mask)
+		dev->dma_mask = &dev->coherent_dma_mask;
+	if (!dev->coherent_dma_mask)
+		dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	platform_set_drvdata(pdev, rtk);
+
+	rtk->dev	= dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing memory resource\n");
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs)) {
+		ret = PTR_ERR(regs);
+		goto err1;
+	}
+
+	rtk->regs = regs;
+	rtk->regs_size = resource_size(res);
+
+	dwc3_rtk_debugfs_init(rtk);
+
+	if (node) {
+		if (of_property_read_bool(node, "dis_u3_port")) {
+			void __iomem *usb_hmac_ctr0 = rtk->regs +
+				    WRAP_USB_HMAC_CTR0_reg;
+			int val_u3port_dis = U3PORT_DIS | readl(usb_hmac_ctr0);
+
+			writel(val_u3port_dis, usb_hmac_ctr0);
+
+			dev_info(rtk->dev, "%s: disable usb 3.0 port (usb_hmac_ctr0=0x%x)\n",
+				    __func__, readl(usb_hmac_ctr0));
+		}
+
+	}
+
+	if (node) {
+		if (of_property_read_bool(node, "delay_probe_work")) {
+			INIT_WORK(&rtk->work, dwc3_rtk_probe_work);
+			schedule_work(&rtk->work);
+		} else {
+			ret = dwc3_rtk_probe_dwc3core(rtk);
+			if (ret) {
+				dev_err(dev, "%s failed to add dwc3 core\n",
+					    __func__);
+				goto err1;
+			}
+		}
+	} else {
+		dev_err(dev, "no device node, failed to add dwc3 core\n");
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	dev_info(dev, "%s ok! (take %d ms)\n", __func__,
+		    jiffies_to_msecs(jiffies - probe_time));
+
+	return 0;
+
+err1:
+	return ret;
+}
+
+static int dwc3_rtk_remove(struct platform_device *pdev)
+{
+	struct dwc3_rtk	*rtk = platform_get_drvdata(pdev);
+
+	dwc3_rtk_debugfs_exit(rtk);
+
+	of_platform_depopulate(rtk->dev);
+
+	return 0;
+}
+
+static void dwc3_rtk_shutdown(struct platform_device *pdev)
+{
+	struct dwc3_rtk	*rtk = platform_get_drvdata(pdev);
+	struct device		*dev = &pdev->dev;
+
+	dev_info(dev, "%s start ...\n", __func__);
+
+	of_platform_depopulate(rtk->dev);
+
+	dev_info(dev, "%s ok!\n", __func__);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtk_dwc3_match[] = {
+	{ .compatible = "realtek,dwc3" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtk_dwc3_match);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_rtk_suspend(struct device *dev)
+{
+	struct dwc3_rtk *rtk = dev_get_drvdata(dev);
+
+	dev_info(dev, "[USB] Enter %s\n", __func__);
+
+	if (!rtk) {
+		dev_err(dev, "[USB] %s dwc3_rtk is NULL\n", __func__);
+		goto out;
+	}
+
+out:
+	dev_info(dev, "[USB] Exit %s", __func__);
+	return 0;
+}
+
+static int dwc3_rtk_resume(struct device *dev)
+{
+	struct dwc3_rtk *rtk = dev_get_drvdata(dev);
+	struct dwc3 *dwc = rtk->dwc;
+
+	dev_info(dev, "[USB] Enter %s", __func__);
+
+	if (!rtk) {
+		dev_err(dev, "[USB] %s dwc3_rtk is NULL\n", __func__);
+		goto out;
+	}
+
+	dwc3_rtk_init(rtk);
+
+	switch_u2_dr_mode(rtk, dwc->dr_mode);
+
+	/* runtime set active to reflect active state. */
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+out:
+	dev_info(dev, "[USB] Exit %s\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops dwc3_rtk_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dwc3_rtk_suspend, dwc3_rtk_resume)
+};
+
+#define DEV_PM_OPS	(&dwc3_rtk_dev_pm_ops)
+#else
+#define DEV_PM_OPS	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver dwc3_rtk_driver = {
+	.probe		= dwc3_rtk_probe,
+	.remove		= dwc3_rtk_remove,
+	.driver		= {
+		.name	= "rtk-dwc3",
+		.of_match_table = of_match_ptr(rtk_dwc3_match),
+		.pm	= DEV_PM_OPS,
+	},
+	.shutdown	= dwc3_rtk_shutdown,
+};
+
+module_platform_driver(dwc3_rtk_driver);
+
+MODULE_ALIAS("platform:rtk-dwc3");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/dwc3/dwc3-rtk.h b/drivers/usb/dwc3/dwc3-rtk.h
new file mode 100644
index 000000000000..9b4e7683def7
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-rtk.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/**
+ * dwc3-rtk.h - Realtek DWC3 Specific Glue layer
+ *
+ * Copyright (C) 2020 Realtek Semiconductor Corporation
+ *
+ */
+
+#ifndef __DRIVERS_USB_DWC3_RTK_H
+#define __DRIVERS_USB_DWC3_RTK_H
+
+#define WRAP_CTR_reg  0x0
+#define DISABLE_MULTI_REQ BIT(1)
+
+#define WRAP_USB_HMAC_CTR0_reg 0x60
+#define U3PORT_DIS BIT(8)
+
+#define WRAP_USB2_PHY_reg  0x70
+#define USB2_PHY_EN_PHY_PLL_PORT0 BIT(12)
+#define USB2_PHY_EN_PHY_PLL_PORT1 BIT(13)
+#define USB2_PHY_SWITCH_MASK 0x707
+#define USB2_PHY_SWITCH_DEVICE 0x0
+#define USB2_PHY_SWITCH_HOST 0x606
+
+struct dwc3_rtk {
+	struct device		*dev;
+
+	void __iomem		*regs;
+	size_t		regs_size;
+
+	struct dwc3 *dwc;
+
+	struct work_struct work;
+
+	int default_dwc3_dr_mode; /* define by dwc3 driver, and it is fixed */
+	int cur_dr_mode; /* current dr mode */
+
+	/* For debugfs */
+	struct dentry		*debug_dir;
+};
+
+void dwc3_rtk_debugfs_init(struct dwc3_rtk *dwc3_rtk);
+void dwc3_rtk_debugfs_exit(struct dwc3_rtk *dwc3_rtk);
+
+#endif /* __DRIVERS_USB_DWC3_RTK_H */
-- 
2.28.0




More information about the linux-realtek-soc mailing list