[][MT79xx add USBIF compliance toolkit]

[Description]
Add USBIF compliance toolkit for MT79xx
hqa
usb3hqa
RG_USB20_INTR_EN
RG_UsB20_VRT_VREF_SEL
RG_USB20_TERM_VREF_SEL
RG_USB20_HSTX_SRCTRL
RG_USB20_DISCTH
RG_CHGDT_EN
reg

fixed Port1 show USB20, it shows USB30

[Release-log]
N/A

Change-Id: Iad411fd7ba992a25fc9a72e62cf6e5b421bf10c4
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5694096
diff --git a/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-reg.c b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-reg.c
new file mode 100644
index 0000000..366747d
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-reg.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0

+/*

+ * xHCI host controller toolkit driver for intr-en

+ *

+ * Copyright (C) 2021  MediaTek Inc.

+ *

+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>

+ */

+

+

+#include <linux/platform_device.h>

+#include <linux/module.h>

+#include <linux/slab.h>

+#include <linux/usb.h>

+#include "xhci-mtk.h"

+#include "xhci-mtk-test.h"

+#include "xhci-mtk-unusual.h"

+

+#define REGS_LIMIT_XHCI 0x1000

+#define REGS_LIMIT_MU3D 0x2e00

+static ssize_t reg_show(struct device *dev,

+			 struct device_attribute *attr, char *buf)

+{

+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);

+	ssize_t cnt = 0;

+

+	cnt += sprintf(buf + cnt,

+		"SSUSB register operation interface help info.\n"

+		"  rx - read xhci  reg: offset [len]\n"

+		"  rm - read mu3d  reg: offset [len]\n"

+		"  ri - read ippc  reg: offset [len]\n"

+		"  rp - read phy   reg: offset [len]\n"

+		"  wx - write xhci reg: offset value\n"

+		"  wm - write mu3d reg: offset value\n"

+		"  wi - write ippc reg: offset value\n"

+		"  wp - write phy  reg: offset value\n"

+		"  sx - set xhci mac reg bits: offset bit_start mask value\n"

+		"  sm - set mu3d mac reg bits: offset bit_start mask value\n"

+		"  si - set ippc     reg bits: offset bit_start mask value\n"

+		"  sp - set phy      reg bits: offset bit_start mask value\n"

+		"  px - print xhci mac reg bits: offset bit_start mask\n"

+		"  pm - print mu3d mac reg bits: offset bit_start mask\n"

+		"  pi - print ippc     reg bits: offset bit_start mask\n"

+		"  pp - print phy      reg bits: offset bit_start mask\n"

+		"  NOTE: numbers should be HEX, except bit_star(DEC)\n");

+

+	if (mtk->hqa_pos) {

+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);

+		mtk->hqa_pos = 0;

+	}

+

+	return cnt;

+}

+

+/* base address: return value; limit is put into @limit */

+static void __iomem *get_reg_base_limit(struct xhci_hcd_mtk *mtk,

+					const char *buf, u32 *limit)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	struct platform_device *device = to_platform_device(mtk->dev);

+	void __iomem *base = NULL;

+	struct device_node  *node = mtk->dev->of_node;

+	u32 io     = 0;

+	u32 range  = 0;

+	u32 len    = 0;

+	int index  = 0;

+	int ret    = 0;

+

+	switch (buf[1]) {

+	case 'x':

+		ret = query_reg_addr(device, &io, &range, "mac");

+		if (ret) break;

+

+		base = ioremap(io, range);

+

+		xhci_info(xhci, "xhci's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+		hqa_info (mtk,  "xhci's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+		break;

+	case 'm':

+		if (!mtk->has_ippc)

+			device = to_platform_device(device->dev.parent);

+

+		ret = query_reg_addr(device, &io, &range, "mac");

+		if (ret) break;

+

+		if (mtk->has_ippc) {

+			io   += REGS_LIMIT_XHCI;

+			range = REGS_LIMIT_MU3D;

+		}

+

+		base = ioremap(io, range);

+                xhci_info(xhci, "mu3d's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+                hqa_info (mtk,  "mu3d's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+		break;

+	case 'i':

+		ret = query_reg_addr(device, &io, &range, "ippc");

+		if (ret) break;

+

+		base = ioremap(io, range);

+		xhci_info(xhci, "ippc's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+		hqa_info (mtk,  "ippc's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+		break;

+	case 'p':

+		ret = query_phy_addr(node, &index, &io, &len, PHY_TYPE_USB3);

+		if (ret && ret != -EACCES) break;

+

+		range  = io & 0x0000FFFF;

+		range += len;

+

+		io &= 0xFFFF0000;

+

+		base = ioremap(io, range);

+		xhci_info(xhci, "phy's reg: [0x%08X ~ 0x%08X]\n",

+			      io, io + range);

+		hqa_info (mtk,  "phy's reg: [0x%08X ~ 0x%08X]\n",

+			  io, io + range);

+		break;

+	default:

+		base = NULL;

+	}

+

+	*limit = range;

+

+	return base;

+}

+

+static void ssusb_write_reg(struct xhci_hcd_mtk *mtk, const char *buf)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	void __iomem *base;

+	u32 offset = 0;

+	u32 value = 0;

+	u32 old_val = 0;

+	u32 limit = 0;

+	u32 param;

+

+	param = sscanf(buf, "%*s 0x%x 0x%x", &offset, &value);

+	xhci_info(xhci, "params-%d (offset: %#x, value: %#x)\n",

+		  param, offset, value);

+	hqa_info (mtk,  "params-%d (offset: %#x, value: %#x)\n",

+		  param, offset, value);

+

+	base = get_reg_base_limit(mtk, buf, &limit);

+	if (!base || (param != 2)) {

+		xhci_err(xhci, "params are invalid!\n");

+		hqa_info(mtk,  "params are invalid since %p, %u!\n",

+			 base, param);

+		return;

+	}

+

+	offset &= ~0x3;  /* 4-bytes align */

+	if (offset >= limit) {

+		xhci_err(xhci, "reg's offset overrun!\n");

+		hqa_info(mtk,  "reg's offset overrun since %u >= %u!\n",

+			 offset, limit);

+		return;

+	}

+	old_val = readl(base + offset);

+	writel(value, base + offset);

+	xhci_info(xhci, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,

+		  readl(base + offset));

+	hqa_info (mtk,  "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,

+		  readl(base + offset));

+

+	base = (void __iomem *)((unsigned long)base & 0xFFFF0000);

+	iounmap(base);

+}

+

+static void read_single_reg(struct xhci_hcd_mtk *mtk,

+			void __iomem *base, u32 offset, u32 limit)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	u32 value;

+

+	offset &= ~0x3;  /* 4-bytes align */

+	if (offset >= limit) {

+		xhci_err(xhci, "reg's offset overrun!\n");

+		hqa_info(mtk,  "reg's offset overrun since %u >= %u!\n",

+			 offset, limit);

+		return;

+	}

+	value = readl(base + offset);

+	xhci_err(xhci, "0x%8.8x : 0x%8.8x\n", offset, value);

+	hqa_info(mtk,  "0x%8.8x : 0x%8.8x\n", offset, value);

+}

+

+static void read_multi_regs(struct xhci_hcd_mtk *mtk,

+			    void __iomem *base, u32 offset, u32 len, u32 limit)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	int i;

+

+	/* at least 4 ints */

+	offset &= ~0xF;

+	len = (len + 0x3) & ~0x3;

+

+	if (offset + len > limit) {

+		xhci_err(xhci, "reg's offset overrun!\n");

+		hqa_info(mtk,  "reg's offset overrun since %u > %u!\n",

+			 offset + len, limit);

+		return;

+	}

+

+	len >>= 2;

+	xhci_info(xhci, "read regs [%#x, %#x)\n", offset, offset + (len << 4));

+	hqa_info (mtk,  "read regs [%#x, %#x)\n", offset, offset + (len << 4));

+	for (i = 0; i < len; i++) {

+		xhci_err(xhci, "0x%8.8x : 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",

+			offset, readl(base + offset),

+			readl(base + offset + 0x4),

+			readl(base + offset + 0x8),

+			readl(base + offset + 0xc));

+		hqa_info(mtk,  "0x%8.8x : 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",

+			 offset, readl(base + offset),

+			 readl(base + offset + 0x4),

+			 readl(base + offset + 0x8),

+			 readl(base + offset + 0xc));

+		offset += 0x10;

+	}

+}

+

+static void ssusb_read_regs(struct xhci_hcd_mtk *mtk, const char *buf)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	void __iomem *base;

+	u32 offset = 0;

+	u32 len = 0;

+	u32 limit = 0;

+	u32 param;

+

+	param = sscanf(buf, "%*s 0x%x 0x%x", &offset, &len);

+	xhci_info(xhci, "params-%d (offset: %#x, len: %#x)\n",

+		  param, offset, len);

+	hqa_info (mtk,  "params-%d (offset: %#x, len: %#x)\n",

+		 param, offset, len);

+

+	base = get_reg_base_limit(mtk, buf, &limit);

+	if (!base || !param) {

+		xhci_err(xhci, "params are invalid!\n");

+		hqa_info(mtk,  "params are invalid since %p, %u!\n",

+			 base, param);

+		return;

+	}

+

+	if (param == 1)

+		read_single_reg(mtk, base, offset, limit);

+	else

+		read_multi_regs(mtk, base, offset, len, limit);

+

+	base = (void __iomem *)((unsigned long)base & 0xFFFF0000);

+	iounmap(base);

+}

+

+static void ssusb_set_reg_bits(struct xhci_hcd_mtk *mtk, const char *buf)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	void __iomem *base;

+	u32 offset = 0;

+	u32 bit_start = 0;

+	u32 mask = 0;

+	u32 value = 0;

+	u32 old_val = 0;

+	u32 new_val = 0;

+	u32 limit = 0;

+	u32 param;

+

+	param = sscanf(buf, "%*s 0x%x %d 0x%x 0x%x",

+		       &offset, &bit_start, &mask, &value);

+	xhci_info(xhci, "params-%d (offset:%#x,bit_start:%d,mask:%#x,value:%#x)\n",

+		  param, offset, bit_start, mask, value);

+	hqa_info(mtk,  "params-%d (offset:%#x,bit_start:%d,mask:%#x,value:%#x)\n",

+		 param, offset, bit_start, mask, value);

+

+	base = get_reg_base_limit(mtk, buf, &limit);

+	if (!base || (param != 4) || (bit_start > 31)) {

+		xhci_err(xhci, "params are invalid!\n");

+		hqa_info(mtk,  "params are invalid since %p, %u, %u\n",

+			 base, param, bit_start);

+		return;

+	}

+

+	offset &= ~0x3;  /* 4-bytes align */

+	if (offset >= limit) {

+		xhci_err(xhci, "reg's offset overrun!\n");

+		hqa_info(mtk,  "reg's offset overrun since %u >= %u!\n",

+			 offset, limit);

+		return;

+	}

+	old_val = readl(base + offset);

+	new_val = old_val;

+	new_val &= ~(mask << bit_start);

+	new_val |= (value << bit_start);

+	writel(new_val, base + offset);

+	xhci_info(xhci, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,

+		  readl(base + offset));

+	hqa_info (mtk,  "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,

+		 readl(base + offset));

+

+	base = (void __iomem *)((unsigned long)base & 0xFFFF0000);

+	iounmap(base);

+}

+

+static void ssusb_print_reg_bits(struct xhci_hcd_mtk *mtk, const char *buf)

+{

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+	void __iomem *base;

+	u32 offset = 0;

+	u32 bit_start = 0;

+	u32 mask = 0;

+	u32 old_val = 0;

+	u32 new_val = 0;

+	u32 limit = 0;

+	u32 param;

+

+	param = sscanf(buf, "%*s 0x%x %d 0x%x", &offset, &bit_start, &mask);

+	xhci_info(xhci, "params-%d (offset: %#x, bit_start: %d, mask: %#x)\n",

+		param, offset, bit_start, mask);

+	hqa_info (mtk,  "params-%d (offset: %#x, bit_start: %d, mask: %#x)\n",

+		param, offset, bit_start, mask);

+

+	base = get_reg_base_limit(mtk, buf, &limit);

+	if (!base || (param != 3) || (bit_start > 31)) {

+		xhci_err(xhci, "params are invalid!\n");

+		hqa_info(mtk,  "params are invalid since %p, %u, %u\n",

+			 base, param, bit_start);

+		return;

+	}

+

+	offset &= ~0x3;  /* 4-bytes align */

+	if (offset >= limit) {

+		xhci_err(xhci, "reg's offset overrun!\n");

+		hqa_info(mtk,  "reg's offset overrun since %u >= %u!\n",

+			 offset, limit);

+		return;

+	}

+

+	old_val = readl(base + offset);

+	new_val = old_val;

+	new_val >>= bit_start;

+	new_val &= mask;

+	xhci_info(xhci, "0x%8.8x : 0x%8.8x (0x%x)\n", offset, old_val, new_val);

+	hqa_info (mtk,  "0x%8.8x : 0x%8.8x (0x%x)\n", offset, old_val, new_val);

+

+	base = (void __iomem *)((unsigned long)base & 0xFFFF0000);

+	iounmap(base);

+}

+

+static ssize_t

+reg_store(struct device *dev, struct device_attribute *attr,

+	  const char *buf, size_t n)

+{

+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);

+	struct usb_hcd *hcd = mtk->hcd;

+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

+

+	xhci_info(xhci, "cmd:%s\n", buf);

+	hqa_info (mtk,  "cmd:%s\n", buf);

+

+	switch (buf[0]) {

+	case 'w':

+		ssusb_write_reg(mtk, buf);

+		break;

+	case 'r':

+		ssusb_read_regs(mtk, buf);

+		break;

+	case 's':

+		ssusb_set_reg_bits(mtk, buf);

+		break;

+	case 'p':

+		ssusb_print_reg_bits(mtk, buf);

+		break;

+	default:

+		xhci_err(xhci, "No such cmd\n");

+		hqa_info(mtk,  "No such cmd\n");

+	}

+

+	return n;

+}

+DEVICE_ATTR_RW(reg);