root/drivers/usb/mtu3/mtu3_debugfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mtu3_link_state_show
  2. mtu3_ep_used_show
  3. mtu3_debugfs_regset
  4. mtu3_debugfs_ep_regset
  5. mtu3_ep_info_show
  6. mtu3_fifo_show
  7. mtu3_qmu_ring_show
  8. mtu3_qmu_gpd_show
  9. mtu3_ep_open
  10. mtu3_probe_show
  11. mtu3_probe_open
  12. mtu3_probe_write
  13. mtu3_debugfs_create_prb_files
  14. mtu3_debugfs_create_ep_dir
  15. mtu3_debugfs_create_ep_dirs
  16. ssusb_dev_debugfs_init
  17. ssusb_mode_show
  18. ssusb_mode_open
  19. ssusb_mode_write
  20. ssusb_vbus_show
  21. ssusb_vbus_open
  22. ssusb_vbus_write
  23. ssusb_dr_debugfs_init
  24. ssusb_debugfs_create_root
  25. ssusb_debugfs_remove_root

   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 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         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 }

/* [<][>][^][v][top][bottom][index][help] */