[][kernel][mt7988][usb]Add USB 2.0 Phy preemphasis parameter support]

[Description]
Add USB 2.0 phy preemphasis parameter support

[Release-log]
N/A

Change-Id: I0543ec4c840706bafaf0727f6409f40cff5b8056
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6378563
diff --git a/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h b/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h
index 70db398..a790c62 100644
--- a/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h
+++ b/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h
@@ -13,6 +13,7 @@
  DEVICE_ATTR_DECLARED(RG_USB20_HSTX_SRCTRL);
  DEVICE_ATTR_DECLARED(RG_USB20_DISCTH);
  DEVICE_ATTR_DECLARED(RG_CHGDT_EN);
+ DEVICE_ATTR_DECLARED(RG_USB20_PHY_REV);
  DEVICE_ATTR_DECLARED(reg);
 
  #define HQA_INFORMACTION_COLLECTS() do {\
@@ -22,5 +23,6 @@
 	ECHO_HQA(USB20_PHY_USBPHYACR5, RG_USB20_HSTX_SRCTRL, 3); \
 	ECHO_HQA(USB20_PHY_USBPHYACR6, RG_USB20_DISCTH, 4); \
 	ECHO_HQA(USB20_PHY_U2PHYBC12C, RG_CHGDT_EN, 1); \
+	ECHO_HQA(USB20_PHY_USBPHYACR6, RG_USB20_PHY_REV, 2); \
 	} while (0)
 
diff --git a/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-statement.h b/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-statement.h
index e898a26..80b786a 100644
--- a/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-statement.h
+++ b/target/linux/mediatek/files-5.4/drivers/usb/host/unusual-statement.h
@@ -13,5 +13,6 @@
 UNUSUAL_DEVICE_ATTR(RG_USB20_HSTX_SRCTRL),
 UNUSUAL_DEVICE_ATTR(RG_USB20_DISCTH),
 UNUSUAL_DEVICE_ATTR(RG_CHGDT_EN),
+UNUSUAL_DEVICE_ATTR(RG_USB20_PHY_REV),
 UNUSUAL_DEVICE_ATTR(reg),
 
diff --git a/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-preemphasic.c b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-preemphasic.c
new file mode 100644
index 0000000..5041dbc
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-preemphasic.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for pre-emphasic
+ *
+ * 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"
+
+static ssize_t RG_USB20_PHY_REV_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct device_node  *node = dev->of_node;
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_USB20_PHY_REV usage:\n");
+	cnt += sprintf(buf + cnt,
+                "   echo u2p index 2b00 > RG_USB20_PHY_REV\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt, " e.g.: echo 2 0 2b10 > RG_USB20_PHY_REV\n");
+	cnt += sprintf(buf + cnt,
+		"  port2 binding phy 0, enable 2b'10 as RG_USB20_PHY_REV\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(node,
+					 &index, &io, &length, PHY_TYPE_USB2);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static ssize_t RG_USB20_PHY_REV_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_USB20_PHY_REV(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 2b%2[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length, PHY_TYPE_USB2);
+	if (ret && ret != -EACCES)
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_USBPHYACR6;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width2(addr, SHFT_RG_USB20_PHY_REV, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_USB20_PHY_REV);
diff --git a/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c
index 01029fb..b02720d 100644
--- a/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c
+++ b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c
@@ -35,6 +35,27 @@
 	return val;
 }
 
+u32 binary_write_width2(u32 __iomem *addr, u32 shift, const char *buf)
+{
+	u32 val = 0;
+
+	if (!strncmp(buf, STRNG_0_WIDTH_2, BIT_WIDTH_2))
+		val = 0;
+	else if (!strncmp(buf, STRNG_1_WIDTH_2, BIT_WIDTH_2))
+		val = 1;
+	else if (!strncmp(buf, STRNG_2_WIDTH_2, BIT_WIDTH_2))
+		val = 2;
+	else if (!strncmp(buf, STRNG_3_WIDTH_2, BIT_WIDTH_2))
+		val = 3;
+	else
+		val = 0xFFFFFFFF;
+
+	if (val <= 3)
+		val = usb20hqa_write(addr, shift, MSK_WIDTH_2, val);
+
+	return val;
+}
+
 u32 binary_write_width3(u32 __iomem *addr, u32 shift, const char *buf)
 {
 	u32 val = 0;
diff --git a/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h
index 0bc6dd8..3850ccf 100644
--- a/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h
+++ b/target/linux/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h
@@ -92,6 +92,11 @@
 #define SHFT_RG_CHGDT_EN		0
 #define BV_RG_CHGDT_EN			BIT(0)
 
+#define NAME_RG_USB20_PHY_REV		"RG_USB20_PHY_REV"
+/* #define USB20_PHY_USBPHYACR6		0x18 */
+#define SHFT_RG_USB20_PHY_REV		30
+#define BV_RG_USB20_PHY_REV		GENMASK(31, 30)
+
 #define ECHO_HQA(reg, _bd, _bw)  do {\
 	val = usb20hqa_read(addr + (reg), \
 		 SHFT_##_bd, \
@@ -127,6 +132,8 @@
 
 u32 binary_write_width1(u32 __iomem *addr,
 				u32 shift, const char *buf);
+u32 binary_write_width2(u32 __iomem *addr,
+				u32 shift, const char *buf);
 u32 binary_write_width3(u32 __iomem *addr,
 				u32 shift, const char *buf);
 u32 binary_write_width4(u32 __iomem *addr,
@@ -168,6 +175,11 @@
 {
 	return 0;
 };
+static inline u32 binary_write_width2(u32 __iomem *addr,
+					u32 shift, const char *buf)
+{
+	return 0;
+};
 static inline u32 binary_write_width3(u32 __iomem *addr,
 					u32 shift, const char *buf)
 {