1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * mtu3_debugfs.c - debugfs interface 4 * 5 * Copyright (C) 2019 MediaTek Inc. 6 * 7 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> 8 */ 9 10 #include <linux/uaccess.h> 11 12 #include "mtu3.h" 13 #include "mtu3_dr.h" 14 #include "mtu3_debug.h" 15 16 #define dump_register(nm) \ 17 { \ 18 .name = __stringify(nm), \ 19 .offset = U3D_ ##nm, \ 20 } 21 22 #define dump_prb_reg(nm, os) \ 23 { \ 24 .name = nm, \ 25 .offset = os, \ 26 } 27 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), 41 }; 42 43 static const struct debugfs_reg32 mtu3_dev_regs[] = { 44 dump_register(LV1ISR), 45 dump_register(LV1IER), 46 dump_register(EPISR), 47 dump_register(EPIER), 48 dump_register(EP0CSR), 49 dump_register(RXCOUNT0), 50 dump_register(QISAR0), 51 dump_register(QIER0), 52 dump_register(QISAR1), 53 dump_register(QIER1), 54 dump_register(CAP_EPNTXFFSZ), 55 dump_register(CAP_EPNRXFFSZ), 56 dump_register(CAP_EPINFO), 57 dump_register(MISC_CTRL), 58 }; 59 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), 76 }; 77 78 static int mtu3_link_state_show(struct seq_file *sf, void *unused) 79 { 80 struct mtu3 *mtu = sf->private; 81 void __iomem *mbase = mtu->mac_base; 82 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))); 86 87 return 0; 88 } 89 90 static int mtu3_ep_used_show(struct seq_file *sf, void *unused) 91 { 92 struct mtu3 *mtu = sf->private; 93 struct mtu3_ep *mep; 94 unsigned long flags; 95 int used = 0; 96 int i; 97 98 spin_lock_irqsave(&mtu->lock, flags); 99 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); 104 used++; 105 } 106 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); 110 used++; 111 } 112 } 113 seq_printf(sf, "total used: %d eps\n", used); 114 115 spin_unlock_irqrestore(&mtu->lock, flags); 116 117 return 0; 118 } 119 120 DEFINE_SHOW_ATTRIBUTE(mtu3_link_state); 121 DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used); 122 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) 126 { 127 struct debugfs_regset32 *regset; 128 struct mtu3_regset *mregs; 129 130 mregs = devm_kzalloc(mtu->dev, sizeof(*regset), GFP_KERNEL); 131 if (!mregs) 132 return; 133 134 sprintf(mregs->name, "%s", name); 135 regset = &mregs->regset; 136 regset->regs = regs; 137 regset->nregs = nregs; 138 regset->base = base; 139 140 debugfs_create_regset32(mregs->name, 0444, parent, regset); 141 } 142 143 static void mtu3_debugfs_ep_regset(struct mtu3 *mtu, struct mtu3_ep *mep, 144 struct dentry *parent) 145 { 146 struct debugfs_reg32 *regs; 147 int epnum = mep->epnum; 148 int in = mep->is_in; 149 150 regs = devm_kcalloc(mtu->dev, 7, sizeof(*regs), GFP_KERNEL); 151 if (!regs) 152 return; 153 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); 168 169 mtu3_debugfs_regset(mtu, mtu->mac_base, regs, 7, "ep-regs", parent); 170 } 171 172 static int mtu3_ep_info_show(struct seq_file *sf, void *unused) 173 { 174 struct mtu3_ep *mep = sf->private; 175 struct mtu3 *mtu = mep->mtu; 176 unsigned long flags; 177 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); 182 183 return 0; 184 } 185 186 static int mtu3_fifo_show(struct seq_file *sf, void *unused) 187 { 188 struct mtu3_ep *mep = sf->private; 189 struct mtu3 *mtu = mep->mtu; 190 unsigned long flags; 191 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); 196 197 return 0; 198 } 199 200 static int mtu3_qmu_ring_show(struct seq_file *sf, void *unused) 201 { 202 struct mtu3_ep *mep = sf->private; 203 struct mtu3 *mtu = mep->mtu; 204 struct mtu3_gpd_ring *ring; 205 unsigned long flags; 206 207 ring = &mep->gpd_ring; 208 spin_lock_irqsave(&mtu->lock, flags); 209 seq_printf(sf, 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); 214 215 return 0; 216 } 217 218 static int mtu3_qmu_gpd_show(struct seq_file *sf, void *unused) 219 { 220 struct mtu3_ep *mep = sf->private; 221 struct mtu3 *mtu = mep->mtu; 222 struct mtu3_gpd_ring *ring; 223 struct qmu_gpd *gpd; 224 dma_addr_t dma; 225 unsigned long flags; 226 int i; 227 228 spin_lock_irqsave(&mtu->lock, flags); 229 ring = &mep->gpd_ring; 230 gpd = ring->start; 231 if (!gpd || !(mep->flags & MTU3_EP_ENABLED)) { 232 seq_puts(sf, "empty!\n"); 233 goto out; 234 } 235 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); 241 } 242 243 out: 244 spin_unlock_irqrestore(&mtu->lock, flags); 245 246 return 0; 247 } 248 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, }, 254 }; 255 256 static int mtu3_ep_open(struct inode *inode, struct file *file) 257 { 258 const char *file_name = file_dentry(file)->d_iname; 259 const struct mtu3_file_map *f_map; 260 int i; 261 262 for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { 263 f_map = &mtu3_ep_files[i]; 264 265 if (strcmp(f_map->name, file_name) == 0) 266 break; 267 } 268 269 return single_open(file, f_map->show, inode->i_private); 270 } 271 272 static const struct file_operations mtu3_ep_fops = { 273 .open = mtu3_ep_open, 274 .read = seq_read, 275 .llseek = seq_lseek, 276 .release = single_release, 277 }; 278 279 static const 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), 286 }; 287 288 static int mtu3_probe_show(struct seq_file *sf, void *unused) 289 { 290 const char *file_name = file_dentry(sf->file)->d_iname; 291 struct mtu3 *mtu = sf->private; 292 const struct debugfs_reg32 *regs; 293 int i; 294 295 for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { 296 regs = &mtu3_prb_regs[i]; 297 298 if (strcmp(regs->name, file_name) == 0) 299 break; 300 } 301 302 seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset, 303 mtu3_readl(mtu->ippc_base, (u32)regs->offset)); 304 305 return 0; 306 } 307 308 static int mtu3_probe_open(struct inode *inode, struct file *file) 309 { 310 return single_open(file, mtu3_probe_show, inode->i_private); 311 } 312 313 static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf, 314 size_t count, loff_t *ppos) 315 { 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; 320 char buf[32]; 321 u32 val; 322 int i; 323 324 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 325 return -EFAULT; 326 327 if (kstrtou32(buf, 0, &val)) 328 return -EINVAL; 329 330 for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { 331 regs = &mtu3_prb_regs[i]; 332 333 if (strcmp(regs->name, file_name) == 0) 334 break; 335 } 336 mtu3_writel(mtu->ippc_base, (u32)regs->offset, val); 337 338 return count; 339 } 340 341 static const struct file_operations mtu3_probe_fops = { 342 .open = mtu3_probe_open, 343 .write = mtu3_probe_write, 344 .read = seq_read, 345 .llseek = seq_lseek, 346 .release = single_release, 347 }; 348 349 static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu) 350 { 351 struct ssusb_mtk *ssusb = mtu->ssusb; 352 const struct debugfs_reg32 *regs; 353 struct dentry *dir_prb; 354 int i; 355 356 dir_prb = debugfs_create_dir("probe", ssusb->dbgfs_root); 357 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); 362 } 363 364 mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs, 365 ARRAY_SIZE(mtu3_prb_regs), "regs", dir_prb); 366 } 367 368 static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep, 369 struct dentry *parent) 370 { 371 const struct mtu3_file_map *files; 372 struct dentry *dir_ep; 373 int i; 374 375 dir_ep = debugfs_create_dir(mep->name, parent); 376 mtu3_debugfs_ep_regset(mep->mtu, mep, dir_ep); 377 378 for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { 379 files = &mtu3_ep_files[i]; 380 381 debugfs_create_file(files->name, 0444, dir_ep, 382 mep, &mtu3_ep_fops); 383 } 384 } 385 386 static void mtu3_debugfs_create_ep_dirs(struct mtu3 *mtu) 387 { 388 struct ssusb_mtk *ssusb = mtu->ssusb; 389 struct dentry *dir_eps; 390 int i; 391 392 dir_eps = debugfs_create_dir("eps", ssusb->dbgfs_root); 393 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); 397 } 398 } 399 400 void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb) 401 { 402 struct mtu3 *mtu = ssusb->u3d; 403 struct dentry *dir_regs; 404 405 dir_regs = debugfs_create_dir("regs", ssusb->dbgfs_root); 406 407 mtu3_debugfs_regset(mtu, mtu->ippc_base, 408 mtu3_ippc_regs, ARRAY_SIZE(mtu3_ippc_regs), 409 "reg-ippc", dir_regs); 410 411 mtu3_debugfs_regset(mtu, mtu->mac_base, 412 mtu3_dev_regs, ARRAY_SIZE(mtu3_dev_regs), 413 "reg-dev", dir_regs); 414 415 mtu3_debugfs_regset(mtu, mtu->mac_base, 416 mtu3_csr_regs, ARRAY_SIZE(mtu3_csr_regs), 417 "reg-csr", dir_regs); 418 419 mtu3_debugfs_create_ep_dirs(mtu); 420 421 mtu3_debugfs_create_prb_files(mtu); 422 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); 427 } 428 429 static int ssusb_mode_show(struct seq_file *sf, void *unused) 430 { 431 struct ssusb_mtk *ssusb = sf->private; 432 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"); 436 437 return 0; 438 } 439 440 static int ssusb_mode_open(struct inode *inode, struct file *file) 441 { 442 return single_open(file, ssusb_mode_show, inode->i_private); 443 } 444 445 static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf, 446 size_t count, loff_t *ppos) 447 { 448 struct seq_file *sf = file->private_data; 449 struct ssusb_mtk *ssusb = sf->private; 450 char buf[16]; 451 452 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 453 return -EFAULT; 454 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); 459 } else { 460 dev_err(ssusb->dev, "wrong or duplicated setting\n"); 461 return -EINVAL; 462 } 463 464 return count; 465 } 466 467 static const struct file_operations ssusb_mode_fops = { 468 .open = ssusb_mode_open, 469 .write = ssusb_mode_write, 470 .read = seq_read, 471 .llseek = seq_lseek, 472 .release = single_release, 473 }; 474 475 static int ssusb_vbus_show(struct seq_file *sf, void *unused) 476 { 477 struct ssusb_mtk *ssusb = sf->private; 478 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 479 480 seq_printf(sf, "vbus state: %s\n(echo on/off)\n", 481 regulator_is_enabled(otg_sx->vbus) ? "on" : "off"); 482 483 return 0; 484 } 485 486 static int ssusb_vbus_open(struct inode *inode, struct file *file) 487 { 488 return single_open(file, ssusb_vbus_show, inode->i_private); 489 } 490 491 static ssize_t ssusb_vbus_write(struct file *file, const char __user *ubuf, 492 size_t count, loff_t *ppos) 493 { 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; 497 char buf[16]; 498 bool enable; 499 500 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 501 return -EFAULT; 502 503 if (kstrtobool(buf, &enable)) { 504 dev_err(ssusb->dev, "wrong setting\n"); 505 return -EINVAL; 506 } 507 508 ssusb_set_vbus(otg_sx, enable); 509 510 return count; 511 } 512 513 static const struct file_operations ssusb_vbus_fops = { 514 .open = ssusb_vbus_open, 515 .write = ssusb_vbus_write, 516 .read = seq_read, 517 .llseek = seq_lseek, 518 .release = single_release, 519 }; 520 521 void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb) 522 { 523 struct dentry *root = ssusb->dbgfs_root; 524 525 debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); 526 debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops); 527 } 528 529 void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb) 530 { 531 ssusb->dbgfs_root = 532 debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); 533 } 534 535 void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb) 536 { 537 debugfs_remove_recursive(ssusb->dbgfs_root); 538 ssusb->dbgfs_root = NULL; 539 } 540