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/string_choices.h> 11 #include <linux/uaccess.h> 12 13 #include "mtu3.h" 14 #include "mtu3_dr.h" 15 #include "mtu3_debug.h" 16 17 #define dump_register(nm) \ 18 { \ 19 .name = __stringify(nm), \ 20 .offset = U3D_ ##nm, \ 21 } 22 23 #define dump_prb_reg(nm, os) \ 24 { \ 25 .name = nm, \ 26 .offset = os, \ 27 } 28 29 static const struct debugfs_reg32 mtu3_ippc_regs[] = { 30 dump_register(SSUSB_IP_PW_CTRL0), 31 dump_register(SSUSB_IP_PW_CTRL1), 32 dump_register(SSUSB_IP_PW_CTRL2), 33 dump_register(SSUSB_IP_PW_CTRL3), 34 dump_register(SSUSB_IP_PW_STS1), 35 dump_register(SSUSB_OTG_STS), 36 dump_register(SSUSB_IP_XHCI_CAP), 37 dump_register(SSUSB_IP_DEV_CAP), 38 dump_register(SSUSB_U3_CTRL_0P), 39 dump_register(SSUSB_U2_CTRL_0P), 40 dump_register(SSUSB_HW_ID), 41 dump_register(SSUSB_HW_SUB_ID), 42 dump_register(SSUSB_IP_SPARE0), 43 }; 44 45 static const struct debugfs_reg32 mtu3_dev_regs[] = { 46 dump_register(LV1ISR), 47 dump_register(LV1IER), 48 dump_register(EPISR), 49 dump_register(EPIER), 50 dump_register(EP0CSR), 51 dump_register(RXCOUNT0), 52 dump_register(QISAR0), 53 dump_register(QIER0), 54 dump_register(QISAR1), 55 dump_register(QIER1), 56 dump_register(CAP_EPNTXFFSZ), 57 dump_register(CAP_EPNRXFFSZ), 58 dump_register(CAP_EPINFO), 59 dump_register(MISC_CTRL), 60 }; 61 62 static const struct debugfs_reg32 mtu3_csr_regs[] = { 63 dump_register(DEVICE_CONF), 64 dump_register(DEV_LINK_INTR_ENABLE), 65 dump_register(DEV_LINK_INTR), 66 dump_register(LTSSM_CTRL), 67 dump_register(USB3_CONFIG), 68 dump_register(LINK_STATE_MACHINE), 69 dump_register(LTSSM_INTR_ENABLE), 70 dump_register(LTSSM_INTR), 71 dump_register(U3U2_SWITCH_CTRL), 72 dump_register(POWER_MANAGEMENT), 73 dump_register(DEVICE_CONTROL), 74 dump_register(COMMON_USB_INTR_ENABLE), 75 dump_register(COMMON_USB_INTR), 76 dump_register(USB20_MISC_CONTROL), 77 dump_register(USB20_OPSTATE), 78 }; 79 80 static int mtu3_link_state_show(struct seq_file *sf, void *unused) 81 { 82 struct mtu3 *mtu = sf->private; 83 void __iomem *mbase = mtu->mac_base; 84 85 seq_printf(sf, "opstate: %#x, ltssm: %#x\n", 86 mtu3_readl(mbase, U3D_USB20_OPSTATE), 87 LTSSM_STATE(mtu3_readl(mbase, U3D_LINK_STATE_MACHINE))); 88 89 return 0; 90 } 91 92 static int mtu3_ep_used_show(struct seq_file *sf, void *unused) 93 { 94 struct mtu3 *mtu = sf->private; 95 struct mtu3_ep *mep; 96 unsigned long flags; 97 int used = 0; 98 int i; 99 100 spin_lock_irqsave(&mtu->lock, flags); 101 102 for (i = 0; i < mtu->num_eps; i++) { 103 mep = mtu->in_eps + i; 104 if (mep->flags & MTU3_EP_ENABLED) { 105 seq_printf(sf, "%s - type: %s\n", mep->name, usb_ep_type_string(mep->type)); 106 used++; 107 } 108 109 mep = mtu->out_eps + i; 110 if (mep->flags & MTU3_EP_ENABLED) { 111 seq_printf(sf, "%s - type: %s\n", mep->name, usb_ep_type_string(mep->type)); 112 used++; 113 } 114 } 115 seq_printf(sf, "total used: %d eps\n", used); 116 117 spin_unlock_irqrestore(&mtu->lock, flags); 118 119 return 0; 120 } 121 122 DEFINE_SHOW_ATTRIBUTE(mtu3_link_state); 123 DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used); 124 125 static void mtu3_debugfs_regset(struct mtu3 *mtu, void __iomem *base, 126 const struct debugfs_reg32 *regs, size_t nregs, 127 const char *name, struct dentry *parent) 128 { 129 struct debugfs_regset32 *regset; 130 struct mtu3_regset *mregs; 131 132 mregs = devm_kzalloc(mtu->dev, sizeof(*mregs), GFP_KERNEL); 133 if (!mregs) 134 return; 135 136 sprintf(mregs->name, "%s", name); 137 regset = &mregs->regset; 138 regset->regs = regs; 139 regset->nregs = nregs; 140 regset->base = base; 141 142 debugfs_create_regset32(mregs->name, 0444, parent, regset); 143 } 144 145 static void mtu3_debugfs_ep_regset(struct mtu3 *mtu, struct mtu3_ep *mep, 146 struct dentry *parent) 147 { 148 struct debugfs_reg32 *regs; 149 int epnum = mep->epnum; 150 int in = mep->is_in; 151 152 regs = devm_kcalloc(mtu->dev, 7, sizeof(*regs), GFP_KERNEL); 153 if (!regs) 154 return; 155 156 regs[0].name = in ? "TCR0" : "RCR0"; 157 regs[0].offset = in ? MU3D_EP_TXCR0(epnum) : MU3D_EP_RXCR0(epnum); 158 regs[1].name = in ? "TCR1" : "RCR1"; 159 regs[1].offset = in ? MU3D_EP_TXCR1(epnum) : MU3D_EP_RXCR1(epnum); 160 regs[2].name = in ? "TCR2" : "RCR2"; 161 regs[2].offset = in ? MU3D_EP_TXCR2(epnum) : MU3D_EP_RXCR2(epnum); 162 regs[3].name = in ? "TQHIAR" : "RQHIAR"; 163 regs[3].offset = in ? USB_QMU_TQHIAR(epnum) : USB_QMU_RQHIAR(epnum); 164 regs[4].name = in ? "TQCSR" : "RQCSR"; 165 regs[4].offset = in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum); 166 regs[5].name = in ? "TQSAR" : "RQSAR"; 167 regs[5].offset = in ? USB_QMU_TQSAR(epnum) : USB_QMU_RQSAR(epnum); 168 regs[6].name = in ? "TQCPR" : "RQCPR"; 169 regs[6].offset = in ? USB_QMU_TQCPR(epnum) : USB_QMU_RQCPR(epnum); 170 171 mtu3_debugfs_regset(mtu, mtu->mac_base, regs, 7, "ep-regs", parent); 172 } 173 174 static int mtu3_ep_info_show(struct seq_file *sf, void *unused) 175 { 176 struct mtu3_ep *mep = sf->private; 177 struct mtu3 *mtu = mep->mtu; 178 unsigned long flags; 179 180 spin_lock_irqsave(&mtu->lock, flags); 181 seq_printf(sf, "ep - type:%s, maxp:%d, slot:%d, flags:%x\n", 182 usb_ep_type_string(mep->type), mep->maxp, mep->slot, mep->flags); 183 spin_unlock_irqrestore(&mtu->lock, flags); 184 185 return 0; 186 } 187 188 static int mtu3_fifo_show(struct seq_file *sf, void *unused) 189 { 190 struct mtu3_ep *mep = sf->private; 191 struct mtu3 *mtu = mep->mtu; 192 unsigned long flags; 193 194 spin_lock_irqsave(&mtu->lock, flags); 195 seq_printf(sf, "fifo - seg_size:%d, addr:%d, size:%d\n", 196 mep->fifo_seg_size, mep->fifo_addr, mep->fifo_size); 197 spin_unlock_irqrestore(&mtu->lock, flags); 198 199 return 0; 200 } 201 202 static int mtu3_qmu_ring_show(struct seq_file *sf, void *unused) 203 { 204 struct mtu3_ep *mep = sf->private; 205 struct mtu3 *mtu = mep->mtu; 206 struct mtu3_gpd_ring *ring; 207 unsigned long flags; 208 209 ring = &mep->gpd_ring; 210 spin_lock_irqsave(&mtu->lock, flags); 211 seq_printf(sf, 212 "qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n", 213 &ring->dma, ring->start, ring->end, 214 ring->enqueue, ring->dequeue); 215 spin_unlock_irqrestore(&mtu->lock, flags); 216 217 return 0; 218 } 219 220 static int mtu3_qmu_gpd_show(struct seq_file *sf, void *unused) 221 { 222 struct mtu3_ep *mep = sf->private; 223 struct mtu3 *mtu = mep->mtu; 224 struct mtu3_gpd_ring *ring; 225 struct qmu_gpd *gpd; 226 dma_addr_t dma; 227 unsigned long flags; 228 int i; 229 230 spin_lock_irqsave(&mtu->lock, flags); 231 ring = &mep->gpd_ring; 232 gpd = ring->start; 233 if (!gpd || !(mep->flags & MTU3_EP_ENABLED)) { 234 seq_puts(sf, "empty!\n"); 235 goto out; 236 } 237 238 for (i = 0; i < MAX_GPD_NUM; i++, gpd++) { 239 dma = ring->dma + i * sizeof(*gpd); 240 seq_printf(sf, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n", 241 i, &dma, gpd, gpd->dw0_info, gpd->next_gpd, 242 gpd->buffer, gpd->dw3_info); 243 } 244 245 out: 246 spin_unlock_irqrestore(&mtu->lock, flags); 247 248 return 0; 249 } 250 251 static const struct mtu3_file_map mtu3_ep_files[] = { 252 {"ep-info", mtu3_ep_info_show, }, 253 {"fifo", mtu3_fifo_show, }, 254 {"qmu-ring", mtu3_qmu_ring_show, }, 255 {"qmu-gpd", mtu3_qmu_gpd_show, }, 256 }; 257 258 static int mtu3_ep_open(struct inode *inode, struct file *file) 259 { 260 const struct mtu3_file_map *f_map = debugfs_get_aux(file); 261 262 return single_open(file, f_map->show, inode->i_private); 263 } 264 265 static const struct file_operations mtu3_ep_fops = { 266 .open = mtu3_ep_open, 267 .read = seq_read, 268 .llseek = seq_lseek, 269 .release = single_release, 270 }; 271 272 static const struct debugfs_reg32 mtu3_prb_regs[] = { 273 dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0), 274 dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1), 275 dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2), 276 dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3), 277 dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4), 278 dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5), 279 }; 280 281 static int mtu3_probe_show(struct seq_file *sf, void *unused) 282 { 283 struct mtu3 *mtu = sf->private; 284 const struct debugfs_reg32 *regs = debugfs_get_aux(sf->file); 285 286 seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset, 287 mtu3_readl(mtu->ippc_base, (u32)regs->offset)); 288 289 return 0; 290 } 291 292 static int mtu3_probe_open(struct inode *inode, struct file *file) 293 { 294 return single_open(file, mtu3_probe_show, inode->i_private); 295 } 296 297 static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf, 298 size_t count, loff_t *ppos) 299 { 300 struct seq_file *sf = file->private_data; 301 struct mtu3 *mtu = sf->private; 302 const struct debugfs_reg32 *regs = debugfs_get_aux(file); 303 char buf[32]; 304 u32 val; 305 306 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 307 return -EFAULT; 308 309 if (kstrtou32(buf, 0, &val)) 310 return -EINVAL; 311 312 mtu3_writel(mtu->ippc_base, (u32)regs->offset, val); 313 314 return count; 315 } 316 317 static const struct file_operations mtu3_probe_fops = { 318 .open = mtu3_probe_open, 319 .write = mtu3_probe_write, 320 .read = seq_read, 321 .llseek = seq_lseek, 322 .release = single_release, 323 }; 324 325 static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu) 326 { 327 struct ssusb_mtk *ssusb = mtu->ssusb; 328 const struct debugfs_reg32 *regs; 329 struct dentry *dir_prb; 330 int i; 331 332 dir_prb = debugfs_create_dir("probe", ssusb->dbgfs_root); 333 334 for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { 335 regs = &mtu3_prb_regs[i]; 336 debugfs_create_file_aux(regs->name, 0644, dir_prb, 337 mtu, regs, &mtu3_probe_fops); 338 } 339 340 mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs, 341 ARRAY_SIZE(mtu3_prb_regs), "regs", dir_prb); 342 } 343 344 static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep, 345 struct dentry *parent) 346 { 347 const struct mtu3_file_map *files; 348 struct dentry *dir_ep; 349 int i; 350 351 dir_ep = debugfs_create_dir(mep->name, parent); 352 mtu3_debugfs_ep_regset(mep->mtu, mep, dir_ep); 353 354 for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { 355 files = &mtu3_ep_files[i]; 356 357 debugfs_create_file_aux(files->name, 0444, dir_ep, 358 mep, files, &mtu3_ep_fops); 359 } 360 } 361 362 static void mtu3_debugfs_create_ep_dirs(struct mtu3 *mtu) 363 { 364 struct ssusb_mtk *ssusb = mtu->ssusb; 365 struct dentry *dir_eps; 366 int i; 367 368 dir_eps = debugfs_create_dir("eps", ssusb->dbgfs_root); 369 370 for (i = 1; i < mtu->num_eps; i++) { 371 mtu3_debugfs_create_ep_dir(mtu->in_eps + i, dir_eps); 372 mtu3_debugfs_create_ep_dir(mtu->out_eps + i, dir_eps); 373 } 374 } 375 376 void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb) 377 { 378 struct mtu3 *mtu = ssusb->u3d; 379 struct dentry *dir_regs; 380 381 dir_regs = debugfs_create_dir("regs", ssusb->dbgfs_root); 382 383 mtu3_debugfs_regset(mtu, mtu->ippc_base, 384 mtu3_ippc_regs, ARRAY_SIZE(mtu3_ippc_regs), 385 "reg-ippc", dir_regs); 386 387 mtu3_debugfs_regset(mtu, mtu->mac_base, 388 mtu3_dev_regs, ARRAY_SIZE(mtu3_dev_regs), 389 "reg-dev", dir_regs); 390 391 mtu3_debugfs_regset(mtu, mtu->mac_base, 392 mtu3_csr_regs, ARRAY_SIZE(mtu3_csr_regs), 393 "reg-csr", dir_regs); 394 395 mtu3_debugfs_create_ep_dirs(mtu); 396 397 mtu3_debugfs_create_prb_files(mtu); 398 399 debugfs_create_file("link-state", 0444, ssusb->dbgfs_root, 400 mtu, &mtu3_link_state_fops); 401 debugfs_create_file("ep-used", 0444, ssusb->dbgfs_root, 402 mtu, &mtu3_ep_used_fops); 403 } 404 405 static int ssusb_mode_show(struct seq_file *sf, void *unused) 406 { 407 struct ssusb_mtk *ssusb = sf->private; 408 409 seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n", 410 ssusb->is_host ? "host" : "device", 411 ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto"); 412 413 return 0; 414 } 415 416 static int ssusb_mode_open(struct inode *inode, struct file *file) 417 { 418 return single_open(file, ssusb_mode_show, inode->i_private); 419 } 420 421 static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf, 422 size_t count, loff_t *ppos) 423 { 424 struct seq_file *sf = file->private_data; 425 struct ssusb_mtk *ssusb = sf->private; 426 char buf[16]; 427 428 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 429 return -EFAULT; 430 431 if (!strncmp(buf, "host", 4) && !ssusb->is_host) { 432 ssusb_mode_switch(ssusb, 1); 433 } else if (!strncmp(buf, "device", 6) && ssusb->is_host) { 434 ssusb_mode_switch(ssusb, 0); 435 } else { 436 dev_err(ssusb->dev, "wrong or duplicated setting\n"); 437 return -EINVAL; 438 } 439 440 return count; 441 } 442 443 static const struct file_operations ssusb_mode_fops = { 444 .open = ssusb_mode_open, 445 .write = ssusb_mode_write, 446 .read = seq_read, 447 .llseek = seq_lseek, 448 .release = single_release, 449 }; 450 451 static int ssusb_vbus_show(struct seq_file *sf, void *unused) 452 { 453 struct ssusb_mtk *ssusb = sf->private; 454 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 455 456 seq_printf(sf, "vbus state: %s\n(echo on/off)\n", 457 str_on_off(regulator_is_enabled(otg_sx->vbus))); 458 459 return 0; 460 } 461 462 static int ssusb_vbus_open(struct inode *inode, struct file *file) 463 { 464 return single_open(file, ssusb_vbus_show, inode->i_private); 465 } 466 467 static ssize_t ssusb_vbus_write(struct file *file, const char __user *ubuf, 468 size_t count, loff_t *ppos) 469 { 470 struct seq_file *sf = file->private_data; 471 struct ssusb_mtk *ssusb = sf->private; 472 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 473 char buf[16]; 474 bool enable; 475 476 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 477 return -EFAULT; 478 479 if (kstrtobool(buf, &enable)) { 480 dev_err(ssusb->dev, "wrong setting\n"); 481 return -EINVAL; 482 } 483 484 ssusb_set_vbus(otg_sx, enable); 485 486 return count; 487 } 488 489 static const struct file_operations ssusb_vbus_fops = { 490 .open = ssusb_vbus_open, 491 .write = ssusb_vbus_write, 492 .read = seq_read, 493 .llseek = seq_lseek, 494 .release = single_release, 495 }; 496 497 void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb) 498 { 499 struct dentry *root = ssusb->dbgfs_root; 500 501 debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); 502 debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops); 503 } 504 505 void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb) 506 { 507 ssusb->dbgfs_root = 508 debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); 509 } 510 511 void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb) 512 { 513 debugfs_remove_recursive(ssusb->dbgfs_root); 514 ssusb->dbgfs_root = NULL; 515 } 516