blob: 31861be538eba318205c0d8851a335ded27e18ac [file] [log] [blame]
developerba28e032021-12-07 10:40:00 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * xHCI host controller toolkit driver for term vref
4 *
5 * Copyright (C) 2021 MediaTek Inc.
6 *
7 * Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
8 */
9
10#include <linux/platform_device.h>
11#include <linux/module.h>
12#include <linux/slab.h>
13#include <linux/usb.h>
14#include "xhci-mtk.h"
15#include "xhci-mtk-test.h"
16#include "xhci-mtk-unusual.h"
17
18static
19ssize_t RG_USB20_TERM_VREF_SEL_show(struct device *dev,
20 struct device_attribute *attr, char *buf)
21{
22 struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
23 struct usb_hcd *hcd = mtk->hcd;
24 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
developerabd06d72022-03-03 16:13:41 +080025 struct device_node *node = dev->of_node;
developerba28e032021-12-07 10:40:00 +080026 ssize_t cnt = 0;
27 void __iomem *addr;
28 u32 val;
29 u32 i;
30 int ports;
31 char str[32];
32 int index = 0;
33 u32 io, length;
34 int ret;
35
36 ports = mtk->num_u3_ports + mtk->num_u2_ports;
37 cnt += sprintf(buf + cnt, " RG_USB20_TERM_VREF_SEL usage:\n");
38 cnt += sprintf(buf + cnt,
39 " echo u2p index 3b011 > RG_USB20_TERM_VREF_SEL\n");
40 if (mtk->num_u3_ports + 1 != ports)
41 cnt += sprintf(buf + cnt, " parameter: u2p: %i ~ %i\n",
42 mtk->num_u3_ports + 1, ports);
43 else
44 cnt += sprintf(buf + cnt, " parameter: u2p: %i\n",
45 mtk->num_u3_ports + 1);
46
47 if (mtk->num_u2_ports > 1)
48 cnt += sprintf(buf + cnt, " parameter: index: 0 ~ %i\n",
49 mtk->num_u2_ports);
50 else
51 cnt += sprintf(buf + cnt, " parameter: index: 0\n");
52
53 cnt += sprintf(buf + cnt,
54 " e.g.: echo 2 0 3b010 > RG_USB20_TERM_VREF_SEL\n");
55 cnt += sprintf(buf + cnt,
56 " port2 binding phy 0, tune 3b'010 as TERM_VREF value\n");
57
58 cnt += sprintf(buf + cnt,
59 "\n=========current HQA setting check=========\n");
60 for (i = 1; i <= ports; i++) {
61 addr = &xhci->op_regs->port_status_base +
62 NUM_PORT_REGS * ((i - 1) & 0xff);
63 val = readl(addr);
64 if (i <= mtk->num_u3_ports) {
65 cnt += sprintf(buf + cnt,
66 "USB30 Port%i: 0x%08X\n", i, val);
67 } else {
68 cnt += sprintf(buf + cnt,
69 "USB20 Port%i: 0x%08X\n", i, val);
70
developerabd06d72022-03-03 16:13:41 +080071 ret = query_phy_addr(node,
72 &index, &io, &length, PHY_TYPE_USB2);
developerba28e032021-12-07 10:40:00 +080073 if (ret && ret != -EACCES) {
74 if (ret == -EPERM)
75 cnt += sprintf(buf + cnt,
76 "USB20 Port%i (Phy%i: absent)\n",
77 i, index);
78 else
79 cnt += sprintf(buf + cnt,
80 "USB20 Port%i (Phy%i) failure %i\n",
81 i, index, ret);
82 continue;
83 }
84
85 cnt += sprintf(buf + cnt,
86 "USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
87 i, index, ret ? " dis" : " en", io, length);
88
89 addr = ioremap_nocache(io, length);
90 addr += (length != 0x100) ? 0x300 : 0;
91
92 HQA_INFORMACTION_COLLECTS();
93
94 iounmap(addr);
95 index ++;
96 }
97 }
98
99 if (mtk->hqa_pos) {
100 cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
101 mtk->hqa_pos = 0;
102 }
103
104 return cnt;
105}
106
107static
108ssize_t RG_USB20_TERM_VREF_SEL_store(struct device *dev,
109 struct device_attribute *attr,
110 const char *buf, size_t n)
111{
112 u32 val;
113 u32 io;
114 u32 length;
115 int ports;
116 int words;
117 int port;
118 int index;
119 int ret;
120 char *str = NULL;
121 void __iomem *addr;
122 struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
123 struct device_node *node = dev->of_node;
124
125 ports = mtk->num_u3_ports + mtk->num_u2_ports;
126 mtk->hqa_pos = 0;
127
128 memset(mtk->hqa_buf, 0, mtk->hqa_size);
129
130 str = kzalloc(n, GFP_ATOMIC);
131
132 hqa_info(mtk, "RG_USB20_TERM_VREF_SEL(%lu): %s\n", n, buf);
133
134 words = sscanf(buf, "%i %i 3b%3[0,1]", &port, &index, str);
135 if ((words != 3) ||
136 (port < mtk->num_u3_ports || port > ports)) {
137 hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
138 words, port, index, str);
139
140 ret = -EINVAL;
141 goto error;
142 }
143
144 hqa_info(mtk, " params: %i %i %s\n",
145 port, index, str);
146
developerabd06d72022-03-03 16:13:41 +0800147 ret = query_phy_addr(node, &index, &io, &length, PHY_TYPE_USB2);
developerba28e032021-12-07 10:40:00 +0800148 if (ret && ret != -EACCES)
149 goto error;
150
151 io += (length != 0x100) ? 0x300 : 0;
152 io += USB20_PHY_USBPHYACR1;
153
154 addr = ioremap_nocache(io, 4);
155 val = binary_write_width3(addr, SHFT_RG_USB20_TERM_VREF_SEL, str);
156 hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
157 port, index, io, val, readl(addr));
158
159 iounmap(addr);
160 ret = n;
161
162error:
163 kfree(str);
164 return ret;
165}
166DEVICE_ATTR_RW(RG_USB20_TERM_VREF_SEL);
167