blob: 366747dc479a514b980b93f1bb7bac7e6c00f99b [file] [log] [blame]
developerabd06d72022-03-03 16:13:41 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * xHCI host controller toolkit driver for intr-en
4 *
5 * Copyright (C) 2021 MediaTek Inc.
6 *
7 * Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
8 */
9
10
11#include <linux/platform_device.h>
12#include <linux/module.h>
13#include <linux/slab.h>
14#include <linux/usb.h>
15#include "xhci-mtk.h"
16#include "xhci-mtk-test.h"
17#include "xhci-mtk-unusual.h"
18
19#define REGS_LIMIT_XHCI 0x1000
20#define REGS_LIMIT_MU3D 0x2e00
21static ssize_t reg_show(struct device *dev,
22 struct device_attribute *attr, char *buf)
23{
24 struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
25 ssize_t cnt = 0;
26
27 cnt += sprintf(buf + cnt,
28 "SSUSB register operation interface help info.\n"
29 " rx - read xhci reg: offset [len]\n"
30 " rm - read mu3d reg: offset [len]\n"
31 " ri - read ippc reg: offset [len]\n"
32 " rp - read phy reg: offset [len]\n"
33 " wx - write xhci reg: offset value\n"
34 " wm - write mu3d reg: offset value\n"
35 " wi - write ippc reg: offset value\n"
36 " wp - write phy reg: offset value\n"
37 " sx - set xhci mac reg bits: offset bit_start mask value\n"
38 " sm - set mu3d mac reg bits: offset bit_start mask value\n"
39 " si - set ippc reg bits: offset bit_start mask value\n"
40 " sp - set phy reg bits: offset bit_start mask value\n"
41 " px - print xhci mac reg bits: offset bit_start mask\n"
42 " pm - print mu3d mac reg bits: offset bit_start mask\n"
43 " pi - print ippc reg bits: offset bit_start mask\n"
44 " pp - print phy reg bits: offset bit_start mask\n"
45 " NOTE: numbers should be HEX, except bit_star(DEC)\n");
46
47 if (mtk->hqa_pos) {
48 cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
49 mtk->hqa_pos = 0;
50 }
51
52 return cnt;
53}
54
55/* base address: return value; limit is put into @limit */
56static void __iomem *get_reg_base_limit(struct xhci_hcd_mtk *mtk,
57 const char *buf, u32 *limit)
58{
59 struct usb_hcd *hcd = mtk->hcd;
60 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
61 struct platform_device *device = to_platform_device(mtk->dev);
62 void __iomem *base = NULL;
63 struct device_node *node = mtk->dev->of_node;
64 u32 io = 0;
65 u32 range = 0;
66 u32 len = 0;
67 int index = 0;
68 int ret = 0;
69
70 switch (buf[1]) {
71 case 'x':
72 ret = query_reg_addr(device, &io, &range, "mac");
73 if (ret) break;
74
75 base = ioremap(io, range);
76
77 xhci_info(xhci, "xhci's reg: [0x%08X ~ 0x%08X]\n",
78 io, io + range);
79 hqa_info (mtk, "xhci's reg: [0x%08X ~ 0x%08X]\n",
80 io, io + range);
81 break;
82 case 'm':
83 if (!mtk->has_ippc)
84 device = to_platform_device(device->dev.parent);
85
86 ret = query_reg_addr(device, &io, &range, "mac");
87 if (ret) break;
88
89 if (mtk->has_ippc) {
90 io += REGS_LIMIT_XHCI;
91 range = REGS_LIMIT_MU3D;
92 }
93
94 base = ioremap(io, range);
95 xhci_info(xhci, "mu3d's reg: [0x%08X ~ 0x%08X]\n",
96 io, io + range);
97 hqa_info (mtk, "mu3d's reg: [0x%08X ~ 0x%08X]\n",
98 io, io + range);
99 break;
100 case 'i':
101 ret = query_reg_addr(device, &io, &range, "ippc");
102 if (ret) break;
103
104 base = ioremap(io, range);
105 xhci_info(xhci, "ippc's reg: [0x%08X ~ 0x%08X]\n",
106 io, io + range);
107 hqa_info (mtk, "ippc's reg: [0x%08X ~ 0x%08X]\n",
108 io, io + range);
109 break;
110 case 'p':
111 ret = query_phy_addr(node, &index, &io, &len, PHY_TYPE_USB3);
112 if (ret && ret != -EACCES) break;
113
114 range = io & 0x0000FFFF;
115 range += len;
116
117 io &= 0xFFFF0000;
118
119 base = ioremap(io, range);
120 xhci_info(xhci, "phy's reg: [0x%08X ~ 0x%08X]\n",
121 io, io + range);
122 hqa_info (mtk, "phy's reg: [0x%08X ~ 0x%08X]\n",
123 io, io + range);
124 break;
125 default:
126 base = NULL;
127 }
128
129 *limit = range;
130
131 return base;
132}
133
134static void ssusb_write_reg(struct xhci_hcd_mtk *mtk, const char *buf)
135{
136 struct usb_hcd *hcd = mtk->hcd;
137 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
138 void __iomem *base;
139 u32 offset = 0;
140 u32 value = 0;
141 u32 old_val = 0;
142 u32 limit = 0;
143 u32 param;
144
145 param = sscanf(buf, "%*s 0x%x 0x%x", &offset, &value);
146 xhci_info(xhci, "params-%d (offset: %#x, value: %#x)\n",
147 param, offset, value);
148 hqa_info (mtk, "params-%d (offset: %#x, value: %#x)\n",
149 param, offset, value);
150
151 base = get_reg_base_limit(mtk, buf, &limit);
152 if (!base || (param != 2)) {
153 xhci_err(xhci, "params are invalid!\n");
154 hqa_info(mtk, "params are invalid since %p, %u!\n",
155 base, param);
156 return;
157 }
158
159 offset &= ~0x3; /* 4-bytes align */
160 if (offset >= limit) {
161 xhci_err(xhci, "reg's offset overrun!\n");
162 hqa_info(mtk, "reg's offset overrun since %u >= %u!\n",
163 offset, limit);
164 return;
165 }
166 old_val = readl(base + offset);
167 writel(value, base + offset);
168 xhci_info(xhci, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,
169 readl(base + offset));
170 hqa_info (mtk, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,
171 readl(base + offset));
172
173 base = (void __iomem *)((unsigned long)base & 0xFFFF0000);
174 iounmap(base);
175}
176
177static void read_single_reg(struct xhci_hcd_mtk *mtk,
178 void __iomem *base, u32 offset, u32 limit)
179{
180 struct usb_hcd *hcd = mtk->hcd;
181 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
182 u32 value;
183
184 offset &= ~0x3; /* 4-bytes align */
185 if (offset >= limit) {
186 xhci_err(xhci, "reg's offset overrun!\n");
187 hqa_info(mtk, "reg's offset overrun since %u >= %u!\n",
188 offset, limit);
189 return;
190 }
191 value = readl(base + offset);
192 xhci_err(xhci, "0x%8.8x : 0x%8.8x\n", offset, value);
193 hqa_info(mtk, "0x%8.8x : 0x%8.8x\n", offset, value);
194}
195
196static void read_multi_regs(struct xhci_hcd_mtk *mtk,
197 void __iomem *base, u32 offset, u32 len, u32 limit)
198{
199 struct usb_hcd *hcd = mtk->hcd;
200 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
201 int i;
202
203 /* at least 4 ints */
204 offset &= ~0xF;
205 len = (len + 0x3) & ~0x3;
206
207 if (offset + len > limit) {
208 xhci_err(xhci, "reg's offset overrun!\n");
209 hqa_info(mtk, "reg's offset overrun since %u > %u!\n",
210 offset + len, limit);
211 return;
212 }
213
214 len >>= 2;
215 xhci_info(xhci, "read regs [%#x, %#x)\n", offset, offset + (len << 4));
216 hqa_info (mtk, "read regs [%#x, %#x)\n", offset, offset + (len << 4));
217 for (i = 0; i < len; i++) {
218 xhci_err(xhci, "0x%8.8x : 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
219 offset, readl(base + offset),
220 readl(base + offset + 0x4),
221 readl(base + offset + 0x8),
222 readl(base + offset + 0xc));
223 hqa_info(mtk, "0x%8.8x : 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
224 offset, readl(base + offset),
225 readl(base + offset + 0x4),
226 readl(base + offset + 0x8),
227 readl(base + offset + 0xc));
228 offset += 0x10;
229 }
230}
231
232static void ssusb_read_regs(struct xhci_hcd_mtk *mtk, const char *buf)
233{
234 struct usb_hcd *hcd = mtk->hcd;
235 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
236 void __iomem *base;
237 u32 offset = 0;
238 u32 len = 0;
239 u32 limit = 0;
240 u32 param;
241
242 param = sscanf(buf, "%*s 0x%x 0x%x", &offset, &len);
243 xhci_info(xhci, "params-%d (offset: %#x, len: %#x)\n",
244 param, offset, len);
245 hqa_info (mtk, "params-%d (offset: %#x, len: %#x)\n",
246 param, offset, len);
247
248 base = get_reg_base_limit(mtk, buf, &limit);
249 if (!base || !param) {
250 xhci_err(xhci, "params are invalid!\n");
251 hqa_info(mtk, "params are invalid since %p, %u!\n",
252 base, param);
253 return;
254 }
255
256 if (param == 1)
257 read_single_reg(mtk, base, offset, limit);
258 else
259 read_multi_regs(mtk, base, offset, len, limit);
260
261 base = (void __iomem *)((unsigned long)base & 0xFFFF0000);
262 iounmap(base);
263}
264
265static void ssusb_set_reg_bits(struct xhci_hcd_mtk *mtk, const char *buf)
266{
267 struct usb_hcd *hcd = mtk->hcd;
268 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
269 void __iomem *base;
270 u32 offset = 0;
271 u32 bit_start = 0;
272 u32 mask = 0;
273 u32 value = 0;
274 u32 old_val = 0;
275 u32 new_val = 0;
276 u32 limit = 0;
277 u32 param;
278
279 param = sscanf(buf, "%*s 0x%x %d 0x%x 0x%x",
280 &offset, &bit_start, &mask, &value);
281 xhci_info(xhci, "params-%d (offset:%#x,bit_start:%d,mask:%#x,value:%#x)\n",
282 param, offset, bit_start, mask, value);
283 hqa_info(mtk, "params-%d (offset:%#x,bit_start:%d,mask:%#x,value:%#x)\n",
284 param, offset, bit_start, mask, value);
285
286 base = get_reg_base_limit(mtk, buf, &limit);
287 if (!base || (param != 4) || (bit_start > 31)) {
288 xhci_err(xhci, "params are invalid!\n");
289 hqa_info(mtk, "params are invalid since %p, %u, %u\n",
290 base, param, bit_start);
291 return;
292 }
293
294 offset &= ~0x3; /* 4-bytes align */
295 if (offset >= limit) {
296 xhci_err(xhci, "reg's offset overrun!\n");
297 hqa_info(mtk, "reg's offset overrun since %u >= %u!\n",
298 offset, limit);
299 return;
300 }
301 old_val = readl(base + offset);
302 new_val = old_val;
303 new_val &= ~(mask << bit_start);
304 new_val |= (value << bit_start);
305 writel(new_val, base + offset);
306 xhci_info(xhci, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,
307 readl(base + offset));
308 hqa_info (mtk, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,
309 readl(base + offset));
310
311 base = (void __iomem *)((unsigned long)base & 0xFFFF0000);
312 iounmap(base);
313}
314
315static void ssusb_print_reg_bits(struct xhci_hcd_mtk *mtk, const char *buf)
316{
317 struct usb_hcd *hcd = mtk->hcd;
318 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
319 void __iomem *base;
320 u32 offset = 0;
321 u32 bit_start = 0;
322 u32 mask = 0;
323 u32 old_val = 0;
324 u32 new_val = 0;
325 u32 limit = 0;
326 u32 param;
327
328 param = sscanf(buf, "%*s 0x%x %d 0x%x", &offset, &bit_start, &mask);
329 xhci_info(xhci, "params-%d (offset: %#x, bit_start: %d, mask: %#x)\n",
330 param, offset, bit_start, mask);
331 hqa_info (mtk, "params-%d (offset: %#x, bit_start: %d, mask: %#x)\n",
332 param, offset, bit_start, mask);
333
334 base = get_reg_base_limit(mtk, buf, &limit);
335 if (!base || (param != 3) || (bit_start > 31)) {
336 xhci_err(xhci, "params are invalid!\n");
337 hqa_info(mtk, "params are invalid since %p, %u, %u\n",
338 base, param, bit_start);
339 return;
340 }
341
342 offset &= ~0x3; /* 4-bytes align */
343 if (offset >= limit) {
344 xhci_err(xhci, "reg's offset overrun!\n");
345 hqa_info(mtk, "reg's offset overrun since %u >= %u!\n",
346 offset, limit);
347 return;
348 }
349
350 old_val = readl(base + offset);
351 new_val = old_val;
352 new_val >>= bit_start;
353 new_val &= mask;
354 xhci_info(xhci, "0x%8.8x : 0x%8.8x (0x%x)\n", offset, old_val, new_val);
355 hqa_info (mtk, "0x%8.8x : 0x%8.8x (0x%x)\n", offset, old_val, new_val);
356
357 base = (void __iomem *)((unsigned long)base & 0xFFFF0000);
358 iounmap(base);
359}
360
361static ssize_t
362reg_store(struct device *dev, struct device_attribute *attr,
363 const char *buf, size_t n)
364{
365 struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
366 struct usb_hcd *hcd = mtk->hcd;
367 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
368
369 xhci_info(xhci, "cmd:%s\n", buf);
370 hqa_info (mtk, "cmd:%s\n", buf);
371
372 switch (buf[0]) {
373 case 'w':
374 ssusb_write_reg(mtk, buf);
375 break;
376 case 'r':
377 ssusb_read_regs(mtk, buf);
378 break;
379 case 's':
380 ssusb_set_reg_bits(mtk, buf);
381 break;
382 case 'p':
383 ssusb_print_reg_bits(mtk, buf);
384 break;
385 default:
386 xhci_err(xhci, "No such cmd\n");
387 hqa_info(mtk, "No such cmd\n");
388 }
389
390 return n;
391}
392DEVICE_ATTR_RW(reg);