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_IP_PW_STS1
),
34 dump_register(SSUSB_OTG_STS
),
35 dump_register(SSUSB_IP_XHCI_CAP
),
36 dump_register(SSUSB_IP_DEV_CAP
),
37 dump_register(SSUSB_U3_CTRL_0P
),
38 dump_register(SSUSB_U2_CTRL_0P
),
39 dump_register(SSUSB_HW_ID
),
40 dump_register(SSUSB_HW_SUB_ID
),
41 dump_register(SSUSB_IP_SPARE0
),
44 static const struct debugfs_reg32 mtu3_dev_regs
[] = {
45 dump_register(LV1ISR
),
46 dump_register(LV1IER
),
49 dump_register(EP0CSR
),
50 dump_register(RXCOUNT0
),
51 dump_register(QISAR0
),
53 dump_register(QISAR1
),
55 dump_register(CAP_EPNTXFFSZ
),
56 dump_register(CAP_EPNRXFFSZ
),
57 dump_register(CAP_EPINFO
),
58 dump_register(MISC_CTRL
),
61 static const struct debugfs_reg32 mtu3_csr_regs
[] = {
62 dump_register(DEVICE_CONF
),
63 dump_register(DEV_LINK_INTR_ENABLE
),
64 dump_register(DEV_LINK_INTR
),
65 dump_register(LTSSM_CTRL
),
66 dump_register(USB3_CONFIG
),
67 dump_register(LINK_STATE_MACHINE
),
68 dump_register(LTSSM_INTR_ENABLE
),
69 dump_register(LTSSM_INTR
),
70 dump_register(U3U2_SWITCH_CTRL
),
71 dump_register(POWER_MANAGEMENT
),
72 dump_register(DEVICE_CONTROL
),
73 dump_register(COMMON_USB_INTR_ENABLE
),
74 dump_register(COMMON_USB_INTR
),
75 dump_register(USB20_MISC_CONTROL
),
76 dump_register(USB20_OPSTATE
),
79 static int mtu3_link_state_show(struct seq_file
*sf
, void *unused
)
81 struct mtu3
*mtu
= sf
->private;
82 void __iomem
*mbase
= mtu
->mac_base
;
84 seq_printf(sf
, "opstate: %#x, ltssm: %#x\n",
85 mtu3_readl(mbase
, U3D_USB20_OPSTATE
),
86 LTSSM_STATE(mtu3_readl(mbase
, U3D_LINK_STATE_MACHINE
)));
91 static int mtu3_ep_used_show(struct seq_file
*sf
, void *unused
)
93 struct mtu3
*mtu
= sf
->private;
99 spin_lock_irqsave(&mtu
->lock
, flags
);
101 for (i
= 0; i
< mtu
->num_eps
; i
++) {
102 mep
= mtu
->in_eps
+ i
;
103 if (mep
->flags
& MTU3_EP_ENABLED
) {
104 seq_printf(sf
, "%s - type: %s\n", mep
->name
, usb_ep_type_string(mep
->type
));
108 mep
= mtu
->out_eps
+ i
;
109 if (mep
->flags
& MTU3_EP_ENABLED
) {
110 seq_printf(sf
, "%s - type: %s\n", mep
->name
, usb_ep_type_string(mep
->type
));
114 seq_printf(sf
, "total used: %d eps\n", used
);
116 spin_unlock_irqrestore(&mtu
->lock
, flags
);
121 DEFINE_SHOW_ATTRIBUTE(mtu3_link_state
);
122 DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used
);
124 static void mtu3_debugfs_regset(struct mtu3
*mtu
, void __iomem
*base
,
125 const struct debugfs_reg32
*regs
, size_t nregs
,
126 const char *name
, struct dentry
*parent
)
128 struct debugfs_regset32
*regset
;
129 struct mtu3_regset
*mregs
;
131 mregs
= devm_kzalloc(mtu
->dev
, sizeof(*mregs
), GFP_KERNEL
);
135 sprintf(mregs
->name
, "%s", name
);
136 regset
= &mregs
->regset
;
138 regset
->nregs
= nregs
;
141 debugfs_create_regset32(mregs
->name
, 0444, parent
, regset
);
144 static void mtu3_debugfs_ep_regset(struct mtu3
*mtu
, struct mtu3_ep
*mep
,
145 struct dentry
*parent
)
147 struct debugfs_reg32
*regs
;
148 int epnum
= mep
->epnum
;
151 regs
= devm_kcalloc(mtu
->dev
, 7, sizeof(*regs
), GFP_KERNEL
);
155 regs
[0].name
= in
? "TCR0" : "RCR0";
156 regs
[0].offset
= in
? MU3D_EP_TXCR0(epnum
) : MU3D_EP_RXCR0(epnum
);
157 regs
[1].name
= in
? "TCR1" : "RCR1";
158 regs
[1].offset
= in
? MU3D_EP_TXCR1(epnum
) : MU3D_EP_RXCR1(epnum
);
159 regs
[2].name
= in
? "TCR2" : "RCR2";
160 regs
[2].offset
= in
? MU3D_EP_TXCR2(epnum
) : MU3D_EP_RXCR2(epnum
);
161 regs
[3].name
= in
? "TQHIAR" : "RQHIAR";
162 regs
[3].offset
= in
? USB_QMU_TQHIAR(epnum
) : USB_QMU_RQHIAR(epnum
);
163 regs
[4].name
= in
? "TQCSR" : "RQCSR";
164 regs
[4].offset
= in
? USB_QMU_TQCSR(epnum
) : USB_QMU_RQCSR(epnum
);
165 regs
[5].name
= in
? "TQSAR" : "RQSAR";
166 regs
[5].offset
= in
? USB_QMU_TQSAR(epnum
) : USB_QMU_RQSAR(epnum
);
167 regs
[6].name
= in
? "TQCPR" : "RQCPR";
168 regs
[6].offset
= in
? USB_QMU_TQCPR(epnum
) : USB_QMU_RQCPR(epnum
);
170 mtu3_debugfs_regset(mtu
, mtu
->mac_base
, regs
, 7, "ep-regs", parent
);
173 static int mtu3_ep_info_show(struct seq_file
*sf
, void *unused
)
175 struct mtu3_ep
*mep
= sf
->private;
176 struct mtu3
*mtu
= mep
->mtu
;
179 spin_lock_irqsave(&mtu
->lock
, flags
);
180 seq_printf(sf
, "ep - type:%s, maxp:%d, slot:%d, flags:%x\n",
181 usb_ep_type_string(mep
->type
), mep
->maxp
, mep
->slot
, mep
->flags
);
182 spin_unlock_irqrestore(&mtu
->lock
, flags
);
187 static int mtu3_fifo_show(struct seq_file
*sf
, void *unused
)
189 struct mtu3_ep
*mep
= sf
->private;
190 struct mtu3
*mtu
= mep
->mtu
;
193 spin_lock_irqsave(&mtu
->lock
, flags
);
194 seq_printf(sf
, "fifo - seg_size:%d, addr:%d, size:%d\n",
195 mep
->fifo_seg_size
, mep
->fifo_addr
, mep
->fifo_size
);
196 spin_unlock_irqrestore(&mtu
->lock
, flags
);
201 static int mtu3_qmu_ring_show(struct seq_file
*sf
, void *unused
)
203 struct mtu3_ep
*mep
= sf
->private;
204 struct mtu3
*mtu
= mep
->mtu
;
205 struct mtu3_gpd_ring
*ring
;
208 ring
= &mep
->gpd_ring
;
209 spin_lock_irqsave(&mtu
->lock
, flags
);
211 "qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n",
212 &ring
->dma
, ring
->start
, ring
->end
,
213 ring
->enqueue
, ring
->dequeue
);
214 spin_unlock_irqrestore(&mtu
->lock
, flags
);
219 static int mtu3_qmu_gpd_show(struct seq_file
*sf
, void *unused
)
221 struct mtu3_ep
*mep
= sf
->private;
222 struct mtu3
*mtu
= mep
->mtu
;
223 struct mtu3_gpd_ring
*ring
;
229 spin_lock_irqsave(&mtu
->lock
, flags
);
230 ring
= &mep
->gpd_ring
;
232 if (!gpd
|| !(mep
->flags
& MTU3_EP_ENABLED
)) {
233 seq_puts(sf
, "empty!\n");
237 for (i
= 0; i
< MAX_GPD_NUM
; i
++, gpd
++) {
238 dma
= ring
->dma
+ i
* sizeof(*gpd
);
239 seq_printf(sf
, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n",
240 i
, &dma
, gpd
, gpd
->dw0_info
, gpd
->next_gpd
,
241 gpd
->buffer
, gpd
->dw3_info
);
245 spin_unlock_irqrestore(&mtu
->lock
, flags
);
250 static const struct mtu3_file_map mtu3_ep_files
[] = {
251 {"ep-info", mtu3_ep_info_show
, },
252 {"fifo", mtu3_fifo_show
, },
253 {"qmu-ring", mtu3_qmu_ring_show
, },
254 {"qmu-gpd", mtu3_qmu_gpd_show
, },
257 static int mtu3_ep_open(struct inode
*inode
, struct file
*file
)
259 const char *file_name
= file_dentry(file
)->d_iname
;
260 const struct mtu3_file_map
*f_map
;
263 for (i
= 0; i
< ARRAY_SIZE(mtu3_ep_files
); i
++) {
264 f_map
= &mtu3_ep_files
[i
];
266 if (strcmp(f_map
->name
, file_name
) == 0)
270 return single_open(file
, f_map
->show
, inode
->i_private
);
273 static const struct file_operations mtu3_ep_fops
= {
274 .open
= mtu3_ep_open
,
277 .release
= single_release
,
280 static const struct debugfs_reg32 mtu3_prb_regs
[] = {
281 dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0
),
282 dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1
),
283 dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2
),
284 dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3
),
285 dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4
),
286 dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5
),
289 static int mtu3_probe_show(struct seq_file
*sf
, void *unused
)
291 const char *file_name
= file_dentry(sf
->file
)->d_iname
;
292 struct mtu3
*mtu
= sf
->private;
293 const struct debugfs_reg32
*regs
;
296 for (i
= 0; i
< ARRAY_SIZE(mtu3_prb_regs
); i
++) {
297 regs
= &mtu3_prb_regs
[i
];
299 if (strcmp(regs
->name
, file_name
) == 0)
303 seq_printf(sf
, "0x%04x - 0x%08x\n", (u32
)regs
->offset
,
304 mtu3_readl(mtu
->ippc_base
, (u32
)regs
->offset
));
309 static int mtu3_probe_open(struct inode
*inode
, struct file
*file
)
311 return single_open(file
, mtu3_probe_show
, inode
->i_private
);
314 static ssize_t
mtu3_probe_write(struct file
*file
, const char __user
*ubuf
,
315 size_t count
, loff_t
*ppos
)
317 const char *file_name
= file_dentry(file
)->d_iname
;
318 struct seq_file
*sf
= file
->private_data
;
319 struct mtu3
*mtu
= sf
->private;
320 const struct debugfs_reg32
*regs
;
325 if (copy_from_user(&buf
, ubuf
, min_t(size_t, sizeof(buf
) - 1, count
)))
328 if (kstrtou32(buf
, 0, &val
))
331 for (i
= 0; i
< ARRAY_SIZE(mtu3_prb_regs
); i
++) {
332 regs
= &mtu3_prb_regs
[i
];
334 if (strcmp(regs
->name
, file_name
) == 0)
337 mtu3_writel(mtu
->ippc_base
, (u32
)regs
->offset
, val
);
342 static const struct file_operations mtu3_probe_fops
= {
343 .open
= mtu3_probe_open
,
344 .write
= mtu3_probe_write
,
347 .release
= single_release
,
350 static void mtu3_debugfs_create_prb_files(struct mtu3
*mtu
)
352 struct ssusb_mtk
*ssusb
= mtu
->ssusb
;
353 const struct debugfs_reg32
*regs
;
354 struct dentry
*dir_prb
;
357 dir_prb
= debugfs_create_dir("probe", ssusb
->dbgfs_root
);
359 for (i
= 0; i
< ARRAY_SIZE(mtu3_prb_regs
); i
++) {
360 regs
= &mtu3_prb_regs
[i
];
361 debugfs_create_file(regs
->name
, 0644, dir_prb
,
362 mtu
, &mtu3_probe_fops
);
365 mtu3_debugfs_regset(mtu
, mtu
->ippc_base
, mtu3_prb_regs
,
366 ARRAY_SIZE(mtu3_prb_regs
), "regs", dir_prb
);
369 static void mtu3_debugfs_create_ep_dir(struct mtu3_ep
*mep
,
370 struct dentry
*parent
)
372 const struct mtu3_file_map
*files
;
373 struct dentry
*dir_ep
;
376 dir_ep
= debugfs_create_dir(mep
->name
, parent
);
377 mtu3_debugfs_ep_regset(mep
->mtu
, mep
, dir_ep
);
379 for (i
= 0; i
< ARRAY_SIZE(mtu3_ep_files
); i
++) {
380 files
= &mtu3_ep_files
[i
];
382 debugfs_create_file(files
->name
, 0444, dir_ep
,
387 static void mtu3_debugfs_create_ep_dirs(struct mtu3
*mtu
)
389 struct ssusb_mtk
*ssusb
= mtu
->ssusb
;
390 struct dentry
*dir_eps
;
393 dir_eps
= debugfs_create_dir("eps", ssusb
->dbgfs_root
);
395 for (i
= 1; i
< mtu
->num_eps
; i
++) {
396 mtu3_debugfs_create_ep_dir(mtu
->in_eps
+ i
, dir_eps
);
397 mtu3_debugfs_create_ep_dir(mtu
->out_eps
+ i
, dir_eps
);
401 void ssusb_dev_debugfs_init(struct ssusb_mtk
*ssusb
)
403 struct mtu3
*mtu
= ssusb
->u3d
;
404 struct dentry
*dir_regs
;
406 dir_regs
= debugfs_create_dir("regs", ssusb
->dbgfs_root
);
408 mtu3_debugfs_regset(mtu
, mtu
->ippc_base
,
409 mtu3_ippc_regs
, ARRAY_SIZE(mtu3_ippc_regs
),
410 "reg-ippc", dir_regs
);
412 mtu3_debugfs_regset(mtu
, mtu
->mac_base
,
413 mtu3_dev_regs
, ARRAY_SIZE(mtu3_dev_regs
),
414 "reg-dev", dir_regs
);
416 mtu3_debugfs_regset(mtu
, mtu
->mac_base
,
417 mtu3_csr_regs
, ARRAY_SIZE(mtu3_csr_regs
),
418 "reg-csr", dir_regs
);
420 mtu3_debugfs_create_ep_dirs(mtu
);
422 mtu3_debugfs_create_prb_files(mtu
);
424 debugfs_create_file("link-state", 0444, ssusb
->dbgfs_root
,
425 mtu
, &mtu3_link_state_fops
);
426 debugfs_create_file("ep-used", 0444, ssusb
->dbgfs_root
,
427 mtu
, &mtu3_ep_used_fops
);
430 static int ssusb_mode_show(struct seq_file
*sf
, void *unused
)
432 struct ssusb_mtk
*ssusb
= sf
->private;
434 seq_printf(sf
, "current mode: %s(%s drd)\n(echo device/host)\n",
435 ssusb
->is_host
? "host" : "device",
436 ssusb
->otg_switch
.manual_drd_enabled
? "manual" : "auto");
441 static int ssusb_mode_open(struct inode
*inode
, struct file
*file
)
443 return single_open(file
, ssusb_mode_show
, inode
->i_private
);
446 static ssize_t
ssusb_mode_write(struct file
*file
, const char __user
*ubuf
,
447 size_t count
, loff_t
*ppos
)
449 struct seq_file
*sf
= file
->private_data
;
450 struct ssusb_mtk
*ssusb
= sf
->private;
453 if (copy_from_user(&buf
, ubuf
, min_t(size_t, sizeof(buf
) - 1, count
)))
456 if (!strncmp(buf
, "host", 4) && !ssusb
->is_host
) {
457 ssusb_mode_switch(ssusb
, 1);
458 } else if (!strncmp(buf
, "device", 6) && ssusb
->is_host
) {
459 ssusb_mode_switch(ssusb
, 0);
461 dev_err(ssusb
->dev
, "wrong or duplicated setting\n");
468 static const struct file_operations ssusb_mode_fops
= {
469 .open
= ssusb_mode_open
,
470 .write
= ssusb_mode_write
,
473 .release
= single_release
,
476 static int ssusb_vbus_show(struct seq_file
*sf
, void *unused
)
478 struct ssusb_mtk
*ssusb
= sf
->private;
479 struct otg_switch_mtk
*otg_sx
= &ssusb
->otg_switch
;
481 seq_printf(sf
, "vbus state: %s\n(echo on/off)\n",
482 regulator_is_enabled(otg_sx
->vbus
) ? "on" : "off");
487 static int ssusb_vbus_open(struct inode
*inode
, struct file
*file
)
489 return single_open(file
, ssusb_vbus_show
, inode
->i_private
);
492 static ssize_t
ssusb_vbus_write(struct file
*file
, const char __user
*ubuf
,
493 size_t count
, loff_t
*ppos
)
495 struct seq_file
*sf
= file
->private_data
;
496 struct ssusb_mtk
*ssusb
= sf
->private;
497 struct otg_switch_mtk
*otg_sx
= &ssusb
->otg_switch
;
501 if (copy_from_user(&buf
, ubuf
, min_t(size_t, sizeof(buf
) - 1, count
)))
504 if (kstrtobool(buf
, &enable
)) {
505 dev_err(ssusb
->dev
, "wrong setting\n");
509 ssusb_set_vbus(otg_sx
, enable
);
514 static const struct file_operations ssusb_vbus_fops
= {
515 .open
= ssusb_vbus_open
,
516 .write
= ssusb_vbus_write
,
519 .release
= single_release
,
522 void ssusb_dr_debugfs_init(struct ssusb_mtk
*ssusb
)
524 struct dentry
*root
= ssusb
->dbgfs_root
;
526 debugfs_create_file("mode", 0644, root
, ssusb
, &ssusb_mode_fops
);
527 debugfs_create_file("vbus", 0644, root
, ssusb
, &ssusb_vbus_fops
);
530 void ssusb_debugfs_create_root(struct ssusb_mtk
*ssusb
)
533 debugfs_create_dir(dev_name(ssusb
->dev
), usb_debug_root
);
536 void ssusb_debugfs_remove_root(struct ssusb_mtk
*ssusb
)
538 debugfs_remove_recursive(ssusb
->dbgfs_root
);
539 ssusb
->dbgfs_root
= NULL
;