[][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);