blob: 1a6d611502fb83a72779a2c953e9fc8b179a218e [file] [log] [blame]
developerba28e032021-12-07 10:40:00 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * xHCI host controller toolkit driver for vrt 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 ssize_t RG_USB20_VRT_VREF_SEL_show(struct device *dev,
19 struct device_attribute *attr, char *buf)
20{
21 struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
22 struct usb_hcd *hcd = mtk->hcd;
23 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
developerabd06d72022-03-03 16:13:41 +080024 struct device_node *node = dev->of_node;
developerba28e032021-12-07 10:40:00 +080025 ssize_t cnt = 0;
26 void __iomem *addr;
27 u32 val;
28 u32 i;
29 int ports;
30 char str[32];
31 int index = 0;
32 u32 io, length;
33 int ret;
34
35 ports = mtk->num_u3_ports + mtk->num_u2_ports;
36 cnt += sprintf(buf + cnt, " RG_USB20_VRT_VREF_SEL usage:\n");
37 cnt += sprintf(buf + cnt,
38 " echo u2p index 3b011 > RG_USB20_VRT_VREF_SEL\n");
39 if (mtk->num_u3_ports + 1 != ports)
40 cnt += sprintf(buf + cnt, " parameter: u2p: %i ~ %i\n",
41 mtk->num_u3_ports + 1, ports);
42 else
43 cnt += sprintf(buf + cnt, " parameter: u2p: %i\n",
44 mtk->num_u3_ports + 1);
45
46 if (mtk->num_u2_ports > 1)
47 cnt += sprintf(buf + cnt, " parameter: index: 0 ~ %i\n",
48 mtk->num_u2_ports);
49 else
50 cnt += sprintf(buf + cnt, " parameter: index: 0\n");
51
52 cnt += sprintf(buf + cnt,
53 " e.g.: echo 2 0 3b101 > RG_USB20_VRT_VREF_SEL\n");
54 cnt += sprintf(buf + cnt,
55 " port2 binding phy 0, tune 3b'010 as VRT_VREF value\n");
56
57 cnt += sprintf(buf + cnt,
58 "\n=========current HQA setting check=========\n");
59 for (i = 1; i <= ports; i++) {
60 addr = &xhci->op_regs->port_status_base +
61 NUM_PORT_REGS * ((i - 1) & 0xff);
62 val = readl(addr);
63 if (i <= mtk->num_u3_ports) {
64 cnt += sprintf(buf + cnt,
65 "USB30 Port%i: 0x%08X\n", i, val);
66 } else {
67 cnt += sprintf(buf + cnt,
68 "USB20 Port%i: 0x%08X\n", i, val);
69
developerabd06d72022-03-03 16:13:41 +080070 ret = query_phy_addr(node,
71 &index, &io, &length, PHY_TYPE_USB2);
developerba28e032021-12-07 10:40:00 +080072 if (ret && ret != -EACCES) {
73 if (ret == -EPERM)
74 cnt += sprintf(buf + cnt,
75 "USB20 Port%i (Phy%i: absent)\n",
76 i, index);
77 else
78 cnt += sprintf(buf + cnt,
79 "USB20 Port%i (Phy%i) failure %i\n",
80 i, index, ret);
81 continue;
82 }
83
84 cnt += sprintf(buf + cnt,
85 "USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
86 i, index, ret ? " dis" : " en", io, length);
87
88 addr = ioremap_nocache(io, length);
89 addr += (length != 0x100) ? 0x300 : 0;
90
91 HQA_INFORMACTION_COLLECTS();
92
93 iounmap(addr);
94 index ++;
95 }
96 }
97
98 if (mtk->hqa_pos) {
developerabd06d72022-03-03 16:13:41 +080099 cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
developerba28e032021-12-07 10:40:00 +0800100 mtk->hqa_pos = 0;
101 }
102
103 return cnt;
104}
105
106
107static ssize_t RG_USB20_VRT_VREF_SEL_store(struct device *dev,
108 struct device_attribute *attr,
109 const char *buf, size_t n)
110{
111 u32 val;
112 u32 io;
113 u32 length;
114 int ports;
115 int words;
116 int port;
117 int index;
118 int ret;
119 char *str = NULL;
120 void __iomem *addr;
121 struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
122 struct device_node *node = dev->of_node;
123
124 ports = mtk->num_u3_ports + mtk->num_u2_ports;
125 mtk->hqa_pos = 0;
126
127 memset(mtk->hqa_buf, 0, mtk->hqa_size);
128
129 str = kzalloc(n, GFP_ATOMIC);
130
131 hqa_info(mtk, "RG_USB20_VRT_VREF_SEL(%lu): %s\n", n, buf);
132
133 words = sscanf(buf, "%i %i 3b%3[0,1]", &port, &index, str);
134 if ((words != 3) ||
135 (port < mtk->num_u3_ports || port > ports)) {
136 hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
137 words, port, index, str);
138
139 ret = -EINVAL;
140 goto error;
141 }
142
143 hqa_info(mtk, " params: %i %i %s\n",
144 port, index, str);
145
developerabd06d72022-03-03 16:13:41 +0800146 ret = query_phy_addr(node, &index, &io, &length, PHY_TYPE_USB2);
147 if (ret && ret != -EACCES)
developerba28e032021-12-07 10:40:00 +0800148 goto error;
149
150 io += (length != 0x100) ? 0x300 : 0;
151 io += USB20_PHY_USBPHYACR1;
152
153 addr = ioremap_nocache(io, 4);
154 val = binary_write_width3(addr, SHFT_RG_USB20_VRT_VREF_SEL, str);
155 hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
156 port, index, io, val, readl(addr));
157
158 iounmap(addr);
159 ret = n;
developerabd06d72022-03-03 16:13:41 +0800160
developerba28e032021-12-07 10:40:00 +0800161error:
162 kfree(str);
163 return ret;
164}
165DEVICE_ATTR_RW(RG_USB20_VRT_VREF_SEL);