1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/kernel.h> 3 #include <linux/device.h> 4 #include <linux/types.h> 5 #include <linux/spinlock.h> 6 #include <linux/debugfs.h> 7 #include <linux/seq_file.h> 8 #include <linux/uaccess.h> 9 #include <linux/usb/ch9.h> 10 #include <linux/usb/gadget.h> 11 #include <linux/usb/phy.h> 12 #include <linux/usb/otg.h> 13 #include <linux/usb/otg-fsm.h> 14 #include <linux/usb/chipidea.h> 15 16 #include "ci.h" 17 #include "udc.h" 18 #include "bits.h" 19 #include "otg.h" 20 21 /** 22 * ci_device_show: prints information about device capabilities and status 23 */ 24 static int ci_device_show(struct seq_file *s, void *data) 25 { 26 struct ci_hdrc *ci = s->private; 27 struct usb_gadget *gadget = &ci->gadget; 28 29 seq_printf(s, "speed = %d\n", gadget->speed); 30 seq_printf(s, "max_speed = %d\n", gadget->max_speed); 31 seq_printf(s, "is_otg = %d\n", gadget->is_otg); 32 seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral); 33 seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable); 34 seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support); 35 seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support); 36 seq_printf(s, "name = %s\n", 37 (gadget->name ? gadget->name : "")); 38 39 if (!ci->driver) 40 return 0; 41 42 seq_printf(s, "gadget function = %s\n", 43 (ci->driver->function ? ci->driver->function : "")); 44 seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed); 45 46 return 0; 47 } 48 DEFINE_SHOW_ATTRIBUTE(ci_device); 49 50 /** 51 * ci_port_test_show: reads port test mode 52 */ 53 static int ci_port_test_show(struct seq_file *s, void *data) 54 { 55 struct ci_hdrc *ci = s->private; 56 unsigned long flags; 57 unsigned mode; 58 59 pm_runtime_get_sync(ci->dev); 60 spin_lock_irqsave(&ci->lock, flags); 61 mode = hw_port_test_get(ci); 62 spin_unlock_irqrestore(&ci->lock, flags); 63 pm_runtime_put_sync(ci->dev); 64 65 seq_printf(s, "mode = %u\n", mode); 66 67 return 0; 68 } 69 70 /** 71 * ci_port_test_write: writes port test mode 72 */ 73 static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf, 74 size_t count, loff_t *ppos) 75 { 76 struct seq_file *s = file->private_data; 77 struct ci_hdrc *ci = s->private; 78 unsigned long flags; 79 unsigned mode; 80 char buf[32]; 81 int ret; 82 83 count = min_t(size_t, sizeof(buf) - 1, count); 84 if (copy_from_user(buf, ubuf, count)) 85 return -EFAULT; 86 87 /* sscanf requires a zero terminated string */ 88 buf[count] = '\0'; 89 90 if (sscanf(buf, "%u", &mode) != 1) 91 return -EINVAL; 92 93 if (mode > 255) 94 return -EBADRQC; 95 96 pm_runtime_get_sync(ci->dev); 97 spin_lock_irqsave(&ci->lock, flags); 98 ret = hw_port_test_set(ci, mode); 99 spin_unlock_irqrestore(&ci->lock, flags); 100 pm_runtime_put_sync(ci->dev); 101 102 return ret ? ret : count; 103 } 104 105 static int ci_port_test_open(struct inode *inode, struct file *file) 106 { 107 return single_open(file, ci_port_test_show, inode->i_private); 108 } 109 110 static const struct file_operations ci_port_test_fops = { 111 .open = ci_port_test_open, 112 .write = ci_port_test_write, 113 .read = seq_read, 114 .llseek = seq_lseek, 115 .release = single_release, 116 }; 117 118 /** 119 * ci_qheads_show: DMA contents of all queue heads 120 */ 121 static int ci_qheads_show(struct seq_file *s, void *data) 122 { 123 struct ci_hdrc *ci = s->private; 124 unsigned long flags; 125 unsigned i, j; 126 127 if (ci->role != CI_ROLE_GADGET) { 128 seq_printf(s, "not in gadget mode\n"); 129 return 0; 130 } 131 132 spin_lock_irqsave(&ci->lock, flags); 133 for (i = 0; i < ci->hw_ep_max/2; i++) { 134 struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i]; 135 struct ci_hw_ep *hweptx = 136 &ci->ci_hw_ep[i + ci->hw_ep_max/2]; 137 seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n", 138 i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma); 139 for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++) 140 seq_printf(s, " %04X: %08X %08X\n", j, 141 *((u32 *)hweprx->qh.ptr + j), 142 *((u32 *)hweptx->qh.ptr + j)); 143 } 144 spin_unlock_irqrestore(&ci->lock, flags); 145 146 return 0; 147 } 148 DEFINE_SHOW_ATTRIBUTE(ci_qheads); 149 150 /** 151 * ci_requests_show: DMA contents of all requests currently queued (all endpts) 152 */ 153 static int ci_requests_show(struct seq_file *s, void *data) 154 { 155 struct ci_hdrc *ci = s->private; 156 unsigned long flags; 157 struct ci_hw_req *req = NULL; 158 struct td_node *node, *tmpnode; 159 unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32); 160 161 if (ci->role != CI_ROLE_GADGET) { 162 seq_printf(s, "not in gadget mode\n"); 163 return 0; 164 } 165 166 spin_lock_irqsave(&ci->lock, flags); 167 for (i = 0; i < ci->hw_ep_max; i++) 168 list_for_each_entry(req, &ci->ci_hw_ep[i].qh.queue, queue) { 169 list_for_each_entry_safe(node, tmpnode, &req->tds, td) { 170 seq_printf(s, "EP=%02i: TD=%08X %s\n", 171 i % (ci->hw_ep_max / 2), 172 (u32)node->dma, 173 ((i < ci->hw_ep_max/2) ? 174 "RX" : "TX")); 175 176 for (j = 0; j < qsize; j++) 177 seq_printf(s, " %04X: %08X\n", j, 178 *((u32 *)node->ptr + j)); 179 } 180 } 181 spin_unlock_irqrestore(&ci->lock, flags); 182 183 return 0; 184 } 185 DEFINE_SHOW_ATTRIBUTE(ci_requests); 186 187 static int ci_otg_show(struct seq_file *s, void *unused) 188 { 189 struct ci_hdrc *ci = s->private; 190 struct otg_fsm *fsm; 191 192 if (!ci || !ci_otg_is_fsm_mode(ci)) 193 return 0; 194 195 fsm = &ci->fsm; 196 197 /* ------ State ----- */ 198 seq_printf(s, "OTG state: %s\n\n", 199 usb_otg_state_string(ci->otg.state)); 200 201 /* ------ State Machine Variables ----- */ 202 seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); 203 204 seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req); 205 206 seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det); 207 208 seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld); 209 210 seq_printf(s, "b_conn: %d\n", fsm->b_conn); 211 212 seq_printf(s, "adp_change: %d\n", fsm->adp_change); 213 214 seq_printf(s, "power_up: %d\n", fsm->power_up); 215 216 seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume); 217 218 seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend); 219 220 seq_printf(s, "a_conn: %d\n", fsm->a_conn); 221 222 seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req); 223 224 seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend); 225 226 seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp); 227 228 seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp); 229 230 seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld); 231 232 seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done); 233 234 seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus); 235 236 seq_printf(s, "loc_conn: %d\n", fsm->loc_conn); 237 238 seq_printf(s, "loc_sof: %d\n", fsm->loc_sof); 239 240 seq_printf(s, "adp_prb: %d\n", fsm->adp_prb); 241 242 seq_printf(s, "id: %d\n", fsm->id); 243 244 seq_printf(s, "protocol: %d\n", fsm->protocol); 245 246 return 0; 247 } 248 DEFINE_SHOW_ATTRIBUTE(ci_otg); 249 250 static int ci_role_show(struct seq_file *s, void *data) 251 { 252 struct ci_hdrc *ci = s->private; 253 254 if (ci->role != CI_ROLE_END) 255 seq_printf(s, "%s\n", ci_role(ci)->name); 256 257 return 0; 258 } 259 260 static ssize_t ci_role_write(struct file *file, const char __user *ubuf, 261 size_t count, loff_t *ppos) 262 { 263 struct seq_file *s = file->private_data; 264 struct ci_hdrc *ci = s->private; 265 enum ci_role role; 266 char buf[8]; 267 int ret; 268 269 if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 270 return -EFAULT; 271 272 for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) 273 if (ci->roles[role] && 274 !strncmp(buf, ci->roles[role]->name, 275 strlen(ci->roles[role]->name))) 276 break; 277 278 if (role == CI_ROLE_END || role == ci->role) 279 return -EINVAL; 280 281 pm_runtime_get_sync(ci->dev); 282 disable_irq(ci->irq); 283 ci_role_stop(ci); 284 ret = ci_role_start(ci, role); 285 enable_irq(ci->irq); 286 pm_runtime_put_sync(ci->dev); 287 288 return ret ? ret : count; 289 } 290 291 static int ci_role_open(struct inode *inode, struct file *file) 292 { 293 return single_open(file, ci_role_show, inode->i_private); 294 } 295 296 static const struct file_operations ci_role_fops = { 297 .open = ci_role_open, 298 .write = ci_role_write, 299 .read = seq_read, 300 .llseek = seq_lseek, 301 .release = single_release, 302 }; 303 304 static int ci_registers_show(struct seq_file *s, void *unused) 305 { 306 struct ci_hdrc *ci = s->private; 307 u32 tmp_reg; 308 309 if (!ci || ci->in_lpm) 310 return -EPERM; 311 312 /* ------ Registers ----- */ 313 tmp_reg = hw_read_intr_enable(ci); 314 seq_printf(s, "USBINTR reg: %08x\n", tmp_reg); 315 316 tmp_reg = hw_read_intr_status(ci); 317 seq_printf(s, "USBSTS reg: %08x\n", tmp_reg); 318 319 tmp_reg = hw_read(ci, OP_USBMODE, ~0); 320 seq_printf(s, "USBMODE reg: %08x\n", tmp_reg); 321 322 tmp_reg = hw_read(ci, OP_USBCMD, ~0); 323 seq_printf(s, "USBCMD reg: %08x\n", tmp_reg); 324 325 tmp_reg = hw_read(ci, OP_PORTSC, ~0); 326 seq_printf(s, "PORTSC reg: %08x\n", tmp_reg); 327 328 if (ci->is_otg) { 329 tmp_reg = hw_read_otgsc(ci, ~0); 330 seq_printf(s, "OTGSC reg: %08x\n", tmp_reg); 331 } 332 333 return 0; 334 } 335 DEFINE_SHOW_ATTRIBUTE(ci_registers); 336 337 /** 338 * dbg_create_files: initializes the attribute interface 339 * @ci: device 340 * 341 * This function returns an error code 342 */ 343 void dbg_create_files(struct ci_hdrc *ci) 344 { 345 ci->debugfs = debugfs_create_dir(dev_name(ci->dev), usb_debug_root); 346 347 debugfs_create_file("device", S_IRUGO, ci->debugfs, ci, 348 &ci_device_fops); 349 debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, ci, 350 &ci_port_test_fops); 351 debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci, 352 &ci_qheads_fops); 353 debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci, 354 &ci_requests_fops); 355 356 if (ci_otg_is_fsm_mode(ci)) { 357 debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci, 358 &ci_otg_fops); 359 } 360 361 debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci, 362 &ci_role_fops); 363 debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci, 364 &ci_registers_fops); 365 } 366 367 /** 368 * dbg_remove_files: destroys the attribute interface 369 * @ci: device 370 */ 371 void dbg_remove_files(struct ci_hdrc *ci) 372 { 373 debugfs_remove_recursive(ci->debugfs); 374 } 375