1 // SPDX-License-Identifier: GPL-2.0
3 * mtu3_debugfs.c - debugfs interface
5 * Copyright (C) 2019 MediaTek Inc.
7 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
10 #include <linux/uaccess.h>
14 #include "mtu3_debug.h"
16 #define dump_register(nm) \
18 .name = __stringify(nm), \
19 .offset = U3D_ ##nm, \
22 #define dump_prb_reg(nm, os) \
28 static const struct debugfs_reg32 mtu3_ippc_regs
[] = {
29 dump_register(SSUSB_IP_PW_CTRL0
),
30 dump_register(SSUSB_IP_PW_CTRL1
),
31 dump_register(SSUSB_IP_PW_CTRL2
),
32 dump_register(SSUSB_IP_PW_CTRL3
),
33 dump_register(SSUSB_OTG_STS
),
34 dump_register(SSUSB_IP_XHCI_CAP
),
35 dump_register(SSUSB_IP_DEV_CAP
),
36 dump_register(SSUSB_U3_CTRL_0P
),
37 dump_register(SSUSB_U2_CTRL_0P
),
38 dump_register(SSUSB_HW_ID
),
39 dump_register(SSUSB_HW_SUB_ID
),
40 dump_register(SSUSB_IP_SPARE0
),
43 static const struct debugfs_reg32 mtu3_dev_regs
[] = {
44 dump_register(LV1ISR
),
45 dump_register(LV1IER
),
48 dump_register(EP0CSR
),
49 dump_register(RXCOUNT0
),
50 dump_register(QISAR0
),
52 dump_register(QISAR1
),
54 dump_register(CAP_EPNTXFFSZ
),
55 dump_register(CAP_EPNRXFFSZ
),
56 dump_register(CAP_EPINFO
),
57 dump_register(MISC_CTRL
),
60 static const struct debugfs_reg32 mtu3_csr_regs
[] = {
61 dump_register(DEVICE_CONF
),
62 dump_register(DEV_LINK_INTR_ENABLE
),
63 dump_register(DEV_LINK_INTR
),
64 dump_register(LTSSM_CTRL
),
65 dump_register(USB3_CONFIG
),
66 dump_register(LINK_STATE_MACHINE
),
67 dump_register(LTSSM_INTR_ENABLE
),
68 dump_register(LTSSM_INTR
),
69 dump_register(U3U2_SWITCH_CTRL
),
70 dump_register(POWER_MANAGEMENT
),
71 dump_register(DEVICE_CONTROL
),
72 dump_register(COMMON_USB_INTR_ENABLE
),
73 dump_register(COMMON_USB_INTR
),
74 dump_register(USB20_MISC_CONTROL
),
75 dump_register(USB20_OPSTATE
),
78 static int mtu3_link_state_show(struct seq_file
*sf
, void *unused
)
80 struct mtu3
*mtu
= sf
->private;
81 void __iomem
*mbase
= mtu
->mac_base
;
83 seq_printf(sf
, "opstate: %#x, ltssm: %#x\n",
84 mtu3_readl(mbase
, U3D_USB20_OPSTATE
),
85 LTSSM_STATE(mtu3_readl(mbase
, U3D_LINK_STATE_MACHINE
)));
90 static int mtu3_ep_used_show(struct seq_file
*sf
, void *unused
)
92 struct mtu3
*mtu
= sf
->private;
98 spin_lock_irqsave(&mtu
->lock
, flags
);
100 for (i
= 0; i
< mtu
->num_eps
; i
++) {
101 mep
= mtu
->in_eps
+ i
;
102 if (mep
->flags
& MTU3_EP_ENABLED
) {
103 seq_printf(sf
, "%s - type: %d\n", mep
->name
, mep
->type
);
107 mep
= mtu
->out_eps
+ i
;
108 if (mep
->flags
& MTU3_EP_ENABLED
) {
109 seq_printf(sf
, "%s - type: %d\n", mep
->name
, mep
->type
);
113 seq_printf(sf
, "total used: %d eps\n", used
);
115 spin_unlock_irqrestore(&mtu
->lock
, flags
);
120 DEFINE_SHOW_ATTRIBUTE(mtu3_link_state
);
121 DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used
);
123 static void mtu3_debugfs_regset(struct mtu3
*mtu
, void __iomem
*base
,
124 const struct debugfs_reg32
*regs
, size_t nregs
,
125 const char *name
, struct dentry
*parent
)
127 struct debugfs_regset32
*regset
;
128 struct mtu3_regset
*mregs
;
130 mregs
= devm_kzalloc(mtu
->dev
, sizeof(*regset
), GFP_KERNEL
);
134 sprintf(mregs
->name
, "%s", name
);
135 regset
= &mregs
->regset
;
137 regset
->nregs
= nregs
;
140 debugfs_create_regset32(mregs
->name
, 0444, parent
, regset
);
143 static void mtu3_debugfs_ep_regset(struct mtu3
*mtu
, struct mtu3_ep
*mep
,
144 struct dentry
*parent
)
146 struct debugfs_reg32
*regs
;
147 int epnum
= mep
->epnum
;
150 regs
= devm_kcalloc(mtu
->dev
, 7, sizeof(*regs
), GFP_KERNEL
);
154 regs
[0].name
= in
? "TCR0" : "RCR0";
155 regs
[0].offset
= in
? MU3D_EP_TXCR0(epnum
) : MU3D_EP_RXCR0(epnum
);
156 regs
[1].name
= in
? "TCR1" : "RCR1";
157 regs
[1].offset
= in
? MU3D_EP_TXCR1(epnum
) : MU3D_EP_RXCR1(epnum
);
158 regs
[2].name
= in
? "TCR2" : "RCR2";
159 regs
[2].offset
= in
? MU3D_EP_TXCR2(epnum
) : MU3D_EP_RXCR2(epnum
);
160 regs
[3].name
= in
? "TQHIAR" : "RQHIAR";
161 regs
[3].offset
= in
? USB_QMU_TQHIAR(epnum
) : USB_QMU_RQHIAR(epnum
);
162 regs
[4].name
= in
? "TQCSR" : "RQCSR";
163 regs
[4].offset
= in
? USB_QMU_TQCSR(epnum
) : USB_QMU_RQCSR(epnum
);
164 regs
[5].name
= in
? "TQSAR" : "RQSAR";
165 regs
[5].offset
= in
? USB_QMU_TQSAR(epnum
) : USB_QMU_RQSAR(epnum
);
166 regs
[6].name
= in
? "TQCPR" : "RQCPR";
167 regs
[6].offset
= in
? USB_QMU_TQCPR(epnum
) : USB_QMU_RQCPR(epnum
);
169 mtu3_debugfs_regset(mtu
, mtu
->mac_base
, regs
, 7, "ep-regs", parent
);
172 static int mtu3_ep_info_show(struct seq_file
*sf
, void *unused
)
174 struct mtu3_ep
*mep
= sf
->private;
175 struct mtu3
*mtu
= mep
->mtu
;
178 spin_lock_irqsave(&mtu
->lock
, flags
);
179 seq_printf(sf
, "ep - type:%d, maxp:%d, slot:%d, flags:%x\n",
180 mep
->type
, mep
->maxp
, mep
->slot
, mep
->flags
);
181 spin_unlock_irqrestore(&mtu
->lock
, flags
);
186 static int mtu3_fifo_show(struct seq_file
*sf
, void *unused
)
188 struct mtu3_ep
*mep
= sf
->private;
189 struct mtu3
*mtu
= mep
->mtu
;
192 spin_lock_irqsave(&mtu
->lock
, flags
);
193 seq_printf(sf
, "fifo - seg_size:%d, addr:%d, size:%d\n",
194 mep
->fifo_seg_size
, mep
->fifo_addr
, mep
->fifo_size
);
195 spin_unlock_irqrestore(&mtu
->lock
, flags
);
200 static int mtu3_qmu_ring_show(struct seq_file
*sf
, void *unused
)
202 struct mtu3_ep
*mep
= sf
->private;
203 struct mtu3
*mtu
= mep
->mtu
;
204 struct mtu3_gpd_ring
*ring
;
207 ring
= &mep
->gpd_ring
;
208 spin_lock_irqsave(&mtu
->lock
, flags
);
210 "qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n",
211 &ring
->dma
, ring
->start
, ring
->end
,
212 ring
->enqueue
, ring
->dequeue
);
213 spin_unlock_irqrestore(&mtu
->lock
, flags
);
218 static int mtu3_qmu_gpd_show(struct seq_file
*sf
, void *unused
)
220 struct mtu3_ep
*mep
= sf
->private;
221 struct mtu3
*mtu
= mep
->mtu
;
222 struct mtu3_gpd_ring
*ring
;
228 spin_lock_irqsave(&mtu
->lock
, flags
);
229 ring
= &mep
->gpd_ring
;
231 if (!gpd
|| !(mep
->flags
& MTU3_EP_ENABLED
)) {
232 seq_puts(sf
, "empty!\n");
236 for (i
= 0; i
< MAX_GPD_NUM
; i
++, gpd
++) {
237 dma
= ring
->dma
+ i
* sizeof(*gpd
);
238 seq_printf(sf
, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n",
239 i
, &dma
, gpd
, gpd
->dw0_info
, gpd
->next_gpd
,
240 gpd
->buffer
, gpd
->dw3_info
);
244 spin_unlock_irqrestore(&mtu
->lock
, flags
);
249 static const struct mtu3_file_map mtu3_ep_files
[] = {
250 {"ep-info", mtu3_ep_info_show
, },
251 {"fifo", mtu3_fifo_show
, },
252 {"qmu-ring", mtu3_qmu_ring_show
, },
253 {"qmu-gpd", mtu3_qmu_gpd_show
, },
256 static int mtu3_ep_open(struct inode
*inode
, struct file
*file
)
258 const char *file_name
= file_dentry(file
)->d_iname
;
259 const struct mtu3_file_map
*f_map
;
262 for (i
= 0; i
< ARRAY_SIZE(mtu3_ep_files
); i
++) {
263 f_map
= &mtu3_ep_files
[i
];
265 if (strcmp(f_map
->name
, file_name
) == 0)
269 return single_open(file
, f_map
->show
, inode
->i_private
);
272 static const struct file_operations mtu3_ep_fops
= {
273 .open
= mtu3_ep_open
,
276 .release
= single_release
,
279 static struct debugfs_reg32 mtu3_prb_regs
[] = {
280 dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0
),
281 dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1
),
282 dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2
),
283 dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3
),
284 dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4
),
285 dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5
),
288 static int mtu3_probe_show(struct seq_file
*sf
, void *unused
)
290 const char *file_name
= file_dentry(sf
->file
)->d_iname
;
291 struct mtu3
*mtu
= sf
->private;
292 const struct debugfs_reg32
*regs
;
295 for (i
= 0; i
< ARRAY_SIZE(mtu3_prb_regs
); i
++) {
296 regs
= &mtu3_prb_regs
[i
];
298 if (strcmp(regs
->name
, file_name
) == 0)
302 seq_printf(sf
, "0x%04x - 0x%08x\n", (u32
)regs
->offset
,
303 mtu3_readl(mtu
->ippc_base
, (u32
)regs
->offset
));
308 static int mtu3_probe_open(struct inode
*inode
, struct file
*file
)
310 return single_open(file
, mtu3_probe_show
, inode
->i_private
);
313 static ssize_t
mtu3_probe_write(struct file
*file
, const char __user
*ubuf
,
314 size_t count
, loff_t
*ppos
)
316 const char *file_name
= file_dentry(file
)->d_iname
;
317 struct seq_file
*sf
= file
->private_data
;
318 struct mtu3
*mtu
= sf
->private;
319 const struct debugfs_reg32
*regs
;
324 if (copy_from_user(&buf
, ubuf
, min_t(size_t, sizeof(buf
) - 1, count
)))
327 if (kstrtou32(buf
, 0, &val
))
330 for (i
= 0; i
< ARRAY_SIZE(mtu3_prb_regs
); i
++) {
331 regs
= &mtu3_prb_regs
[i
];
333 if (strcmp(regs
->name
, file_name
) == 0)
336 mtu3_writel(mtu
->ippc_base
, (u32
)regs
->offset
, val
);
341 static const struct file_operations mtu3_probe_fops
= {
342 .open
= mtu3_probe_open
,
343 .write
= mtu3_probe_write
,
346 .release
= single_release
,
349 static void mtu3_debugfs_create_prb_files(struct mtu3
*mtu
)
351 struct ssusb_mtk
*ssusb
= mtu
->ssusb
;
352 struct debugfs_reg32
*regs
;
353 struct dentry
*dir_prb
;
356 dir_prb
= debugfs_create_dir("probe", ssusb
->dbgfs_root
);
358 for (i
= 0; i
< ARRAY_SIZE(mtu3_prb_regs
); i
++) {
359 regs
= &mtu3_prb_regs
[i
];
360 debugfs_create_file(regs
->name
, 0644, dir_prb
,
361 mtu
, &mtu3_probe_fops
);
364 mtu3_debugfs_regset(mtu
, mtu
->ippc_base
, mtu3_prb_regs
,
365 ARRAY_SIZE(mtu3_prb_regs
), "regs", dir_prb
);
368 static void mtu3_debugfs_create_ep_dir(struct mtu3_ep
*mep
,
369 struct dentry
*parent
)
371 const struct mtu3_file_map
*files
;
372 struct dentry
*dir_ep
;
375 dir_ep
= debugfs_create_dir(mep
->name
, parent
);
376 mtu3_debugfs_ep_regset(mep
->mtu
, mep
, dir_ep
);
378 for (i
= 0; i
< ARRAY_SIZE(mtu3_ep_files
); i
++) {
379 files
= &mtu3_ep_files
[i
];
381 debugfs_create_file(files
->name
, 0444, dir_ep
,
386 static void mtu3_debugfs_create_ep_dirs(struct mtu3
*mtu
)
388 struct ssusb_mtk
*ssusb
= mtu
->ssusb
;
389 struct dentry
*dir_eps
;
392 dir_eps
= debugfs_create_dir("eps", ssusb
->dbgfs_root
);
394 for (i
= 1; i
< mtu
->num_eps
; i
++) {
395 mtu3_debugfs_create_ep_dir(mtu
->in_eps
+ i
, dir_eps
);
396 mtu3_debugfs_create_ep_dir(mtu
->out_eps
+ i
, dir_eps
);
400 void ssusb_dev_debugfs_init(struct ssusb_mtk
*ssusb
)
402 struct mtu3
*mtu
= ssusb
->u3d
;
403 struct dentry
*dir_regs
;
405 dir_regs
= debugfs_create_dir("regs", ssusb
->dbgfs_root
);
407 mtu3_debugfs_regset(mtu
, mtu
->ippc_base
,
408 mtu3_ippc_regs
, ARRAY_SIZE(mtu3_ippc_regs
),
409 "reg-ippc", dir_regs
);
411 mtu3_debugfs_regset(mtu
, mtu
->mac_base
,
412 mtu3_dev_regs
, ARRAY_SIZE(mtu3_dev_regs
),
413 "reg-dev", dir_regs
);
415 mtu3_debugfs_regset(mtu
, mtu
->mac_base
,
416 mtu3_csr_regs
, ARRAY_SIZE(mtu3_csr_regs
),
417 "reg-csr", dir_regs
);
419 mtu3_debugfs_create_ep_dirs(mtu
);
421 mtu3_debugfs_create_prb_files(mtu
);
423 debugfs_create_file("link-state", 0444, ssusb
->dbgfs_root
,
424 mtu
, &mtu3_link_state_fops
);
425 debugfs_create_file("ep-used", 0444, ssusb
->dbgfs_root
,
426 mtu
, &mtu3_ep_used_fops
);
429 static int ssusb_mode_show(struct seq_file
*sf
, void *unused
)
431 struct ssusb_mtk
*ssusb
= sf
->private;
433 seq_printf(sf
, "current mode: %s(%s drd)\n(echo device/host)\n",
434 ssusb
->is_host
? "host" : "device",
435 ssusb
->otg_switch
.manual_drd_enabled
? "manual" : "auto");
440 static int ssusb_mode_open(struct inode
*inode
, struct file
*file
)
442 return single_open(file
, ssusb_mode_show
, inode
->i_private
);
445 static ssize_t
ssusb_mode_write(struct file
*file
, const char __user
*ubuf
,
446 size_t count
, loff_t
*ppos
)
448 struct seq_file
*sf
= file
->private_data
;
449 struct ssusb_mtk
*ssusb
= sf
->private;
452 if (copy_from_user(&buf
, ubuf
, min_t(size_t, sizeof(buf
) - 1, count
)))
455 if (!strncmp(buf
, "host", 4) && !ssusb
->is_host
) {
456 ssusb_mode_switch(ssusb
, 1);
457 } else if (!strncmp(buf
, "device", 6) && ssusb
->is_host
) {
458 ssusb_mode_switch(ssusb
, 0);
460 dev_err(ssusb
->dev
, "wrong or duplicated setting\n");
467 static const struct file_operations ssusb_mode_fops
= {
468 .open
= ssusb_mode_open
,
469 .write
= ssusb_mode_write
,
472 .release
= single_release
,
475 static int ssusb_vbus_show(struct seq_file
*sf
, void *unused
)
477 struct ssusb_mtk
*ssusb
= sf
->private;
478 struct otg_switch_mtk
*otg_sx
= &ssusb
->otg_switch
;
480 seq_printf(sf
, "vbus state: %s\n(echo on/off)\n",
481 regulator_is_enabled(otg_sx
->vbus
) ? "on" : "off");
486 static int ssusb_vbus_open(struct inode
*inode
, struct file
*file
)
488 return single_open(file
, ssusb_vbus_show
, inode
->i_private
);
491 static ssize_t
ssusb_vbus_write(struct file
*file
, const char __user
*ubuf
,
492 size_t count
, loff_t
*ppos
)
494 struct seq_file
*sf
= file
->private_data
;
495 struct ssusb_mtk
*ssusb
= sf
->private;
496 struct otg_switch_mtk
*otg_sx
= &ssusb
->otg_switch
;
500 if (copy_from_user(&buf
, ubuf
, min_t(size_t, sizeof(buf
) - 1, count
)))
503 if (kstrtobool(buf
, &enable
)) {
504 dev_err(ssusb
->dev
, "wrong setting\n");
508 ssusb_set_vbus(otg_sx
, enable
);
513 static const struct file_operations ssusb_vbus_fops
= {
514 .open
= ssusb_vbus_open
,
515 .write
= ssusb_vbus_write
,
518 .release
= single_release
,
521 void ssusb_dr_debugfs_init(struct ssusb_mtk
*ssusb
)
523 struct dentry
*root
= ssusb
->dbgfs_root
;
525 debugfs_create_file("mode", 0644, root
, ssusb
, &ssusb_mode_fops
);
526 debugfs_create_file("vbus", 0644, root
, ssusb
, &ssusb_vbus_fops
);
529 void ssusb_debugfs_create_root(struct ssusb_mtk
*ssusb
)
532 debugfs_create_dir(dev_name(ssusb
->dev
), usb_debug_root
);
535 void ssusb_debugfs_remove_root(struct ssusb_mtk
*ssusb
)
537 debugfs_remove_recursive(ssusb
->dbgfs_root
);
538 ssusb
->dbgfs_root
= NULL
;