Commit 7d9aa8fd87171164a6f14167a0c9c066f4312b8d

Authored by Julius Werner
Committed by Marek Vasut
1 parent b068deb363

usb: Add new command to set USB 2.0 port test modes

This patch adds a new 'usb test' command, that will set a port to a USB
2.0 test mode (see USB 2.0 spec 7.1.20). It supports all five test modes
on both downstream hub ports and ordinary device's upstream ports. In
addition, it supports EHCI root hub ports.

Signed-off-by: Julius Werner <jwerner@chromium.org>

Showing 3 changed files with 125 additions and 34 deletions Side-by-side Diff

... ... @@ -269,6 +269,22 @@
269 269 printf("\n");
270 270 }
271 271  
  272 +static struct usb_device *usb_find_device(int devnum)
  273 +{
  274 + struct usb_device *dev;
  275 + int d;
  276 +
  277 + for (d = 0; d < USB_MAX_DEVICE; d++) {
  278 + dev = usb_get_dev_index(d);
  279 + if (dev == NULL)
  280 + return NULL;
  281 + if (dev->devnum == devnum)
  282 + return dev;
  283 + }
  284 +
  285 + return NULL;
  286 +}
  287 +
272 288 static inline char *portspeed(int speed)
273 289 {
274 290 if (speed == USB_SPEED_HIGH)
275 291  
... ... @@ -348,7 +364,67 @@
348 364 usb_show_tree_graph(dev, &preamble[0]);
349 365 }
350 366  
  367 +static int usb_test(struct usb_device *dev, int port, char* arg)
  368 +{
  369 + int mode;
351 370  
  371 + if (port > dev->maxchild) {
  372 + printf("Device is no hub or does not have %d ports.\n", port);
  373 + return 1;
  374 + }
  375 +
  376 + switch (arg[0]) {
  377 + case 'J':
  378 + case 'j':
  379 + printf("Setting Test_J mode");
  380 + mode = USB_TEST_MODE_J;
  381 + break;
  382 + case 'K':
  383 + case 'k':
  384 + printf("Setting Test_K mode");
  385 + mode = USB_TEST_MODE_K;
  386 + break;
  387 + case 'S':
  388 + case 's':
  389 + printf("Setting Test_SE0_NAK mode");
  390 + mode = USB_TEST_MODE_SE0_NAK;
  391 + break;
  392 + case 'P':
  393 + case 'p':
  394 + printf("Setting Test_Packet mode");
  395 + mode = USB_TEST_MODE_PACKET;
  396 + break;
  397 + case 'F':
  398 + case 'f':
  399 + printf("Setting Test_Force_Enable mode");
  400 + mode = USB_TEST_MODE_FORCE_ENABLE;
  401 + break;
  402 + default:
  403 + printf("Unrecognized test mode: %s\nAvailable modes: "
  404 + "J, K, S[E0_NAK], P[acket], F[orce_Enable]\n", arg);
  405 + return 1;
  406 + }
  407 +
  408 + if (port)
  409 + printf(" on downstream facing port %d...\n", port);
  410 + else
  411 + printf(" on upstream facing port...\n");
  412 +
  413 + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_FEATURE,
  414 + port ? USB_RT_PORT : USB_RECIP_DEVICE,
  415 + port ? USB_PORT_FEAT_TEST : USB_FEAT_TEST,
  416 + (mode << 8) | port,
  417 + NULL, 0, USB_CNTL_TIMEOUT) == -1) {
  418 + printf("Error during SET_FEATURE.\n");
  419 + return 1;
  420 + } else {
  421 + printf("Test mode successfully set. Use 'usb start' "
  422 + "to return to normal operation.\n");
  423 + return 0;
  424 + }
  425 +}
  426 +
  427 +
352 428 /******************************************************************************
353 429 * usb boot command intepreter. Derived from diskboot
354 430 */
355 431  
... ... @@ -441,17 +517,9 @@
441 517 }
442 518 return 0;
443 519 } else {
444   - int d;
445   -
446   - i = simple_strtoul(argv[2], NULL, 16);
  520 + i = simple_strtoul(argv[2], NULL, 10);
447 521 printf("config for device %d\n", i);
448   - for (d = 0; d < USB_MAX_DEVICE; d++) {
449   - dev = usb_get_dev_index(d);
450   - if (dev == NULL)
451   - break;
452   - if (dev->devnum == i)
453   - break;
454   - }
  522 + dev = usb_find_device(i);
455 523 if (dev == NULL) {
456 524 printf("*** No device available ***\n");
457 525 return 0;
... ... @@ -462,6 +530,18 @@
462 530 }
463 531 return 0;
464 532 }
  533 + if (strncmp(argv[1], "test", 4) == 0) {
  534 + if (argc < 5)
  535 + return CMD_RET_USAGE;
  536 + i = simple_strtoul(argv[2], NULL, 10);
  537 + dev = usb_find_device(i);
  538 + if (dev == NULL) {
  539 + printf("Device %d does not exist.\n", i);
  540 + return 1;
  541 + }
  542 + i = simple_strtoul(argv[3], NULL, 10);
  543 + return usb_test(dev, i, argv[4]);
  544 + }
465 545 #ifdef CONFIG_USB_STORAGE
466 546 if (strncmp(argv[1], "stor", 4) == 0)
467 547 return usb_stor_info();
... ... @@ -571,7 +651,6 @@
571 651 return CMD_RET_USAGE;
572 652 }
573 653  
574   -#ifdef CONFIG_USB_STORAGE
575 654 U_BOOT_CMD(
576 655 usb, 5, 1, do_usb,
577 656 "USB sub-system",
578 657  
579 658  
580 659  
581 660  
... ... @@ -580,31 +659,27 @@
580 659 "usb stop [f] - stop USB [f]=force stop\n"
581 660 "usb tree - show USB device tree\n"
582 661 "usb info [dev] - show available USB devices\n"
  662 + "usb test [dev] [port] [mode] - set USB 2.0 test mode\n"
  663 + " (specify port 0 to indicate the device's upstream port)\n"
  664 + " Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]\n"
  665 +#ifdef CONFIG_USB_STORAGE
583 666 "usb storage - show details of USB storage devices\n"
584 667 "usb dev [dev] - show or set current USB storage device\n"
585 668 "usb part [dev] - print partition table of one or all USB storage"
586   - " devices\n"
  669 + " devices\n"
587 670 "usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
588 671 " to memory address `addr'\n"
589 672 "usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'\n"
590 673 " from memory address `addr'"
  674 +#endif /* CONFIG_USB_STORAGE */
591 675 );
592 676  
593 677  
  678 +#ifdef CONFIG_USB_STORAGE
594 679 U_BOOT_CMD(
595 680 usbboot, 3, 1, do_usbboot,
596 681 "boot from USB device",
597 682 "loadAddr dev:part"
598 683 );
599   -
600   -#else
601   -U_BOOT_CMD(
602   - usb, 5, 1, do_usb,
603   - "USB sub-system",
604   - "start - start (scan) USB controller\n"
605   - "usb reset - reset (rescan) USB controller\n"
606   - "usb tree - show USB device tree\n"
607   - "usb info [dev] - show available USB devices"
608   -);
609   -#endif
  684 +#endif /* CONFIG_USB_STORAGE */
drivers/usb/host/ehci-hcd.c
... ... @@ -623,15 +623,14 @@
623 623 int len, srclen;
624 624 uint32_t reg;
625 625 uint32_t *status_reg;
  626 + int port = le16_to_cpu(req->index) & 0xff;
626 627 struct ehci_ctrl *ctrl = dev->controller;
627 628  
628   - if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
629   - printf("The request port(%d) is not configured\n",
630   - le16_to_cpu(req->index) - 1);
  629 + if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
  630 + printf("The request port(%d) is not configured\n", port - 1);
631 631 return -1;
632 632 }
633   - status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
634   - le16_to_cpu(req->index) - 1];
  633 + status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
635 634 srclen = 0;
636 635  
637 636 debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
... ... @@ -748,7 +747,7 @@
748 747 tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
749 748 if (reg & EHCI_PS_OCC)
750 749 tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
751   - if (ctrl->portreset & (1 << le16_to_cpu(req->index)))
  750 + if (ctrl->portreset & (1 << port))
752 751 tmpbuf[2] |= USB_PORT_STAT_C_RESET;
753 752  
754 753 srcptr = tmpbuf;
... ... @@ -774,7 +773,7 @@
774 773 EHCI_PS_IS_LOWSPEED(reg)) {
775 774 /* Low speed device, give up ownership. */
776 775 debug("port %d low speed --> companion\n",
777   - req->index - 1);
  776 + port - 1);
778 777 reg |= EHCI_PS_PO;
779 778 ehci_writel(status_reg, reg);
780 779 break;
781 780  
782 781  
... ... @@ -800,13 +799,17 @@
800 799 ret = handshake(status_reg, EHCI_PS_PR, 0,
801 800 2 * 1000);
802 801 if (!ret)
803   - ctrl->portreset |=
804   - 1 << le16_to_cpu(req->index);
  802 + ctrl->portreset |= 1 << port;
805 803 else
806 804 printf("port(%d) reset error\n",
807   - le16_to_cpu(req->index) - 1);
  805 + port - 1);
808 806 }
809 807 break;
  808 + case USB_PORT_FEAT_TEST:
  809 + reg &= ~(0xf << 16);
  810 + reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16;
  811 + ehci_writel(status_reg, reg);
  812 + break;
810 813 default:
811 814 debug("unknown feature %x\n", le16_to_cpu(req->value));
812 815 goto unknown;
... ... @@ -833,7 +836,7 @@
833 836 reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
834 837 break;
835 838 case USB_PORT_FEAT_C_RESET:
836   - ctrl->portreset &= ~(1 << le16_to_cpu(req->index));
  839 + ctrl->portreset &= ~(1 << port);
837 840 break;
838 841 default:
839 842 debug("unknown feature %x\n", le16_to_cpu(req->value));
... ... @@ -150,7 +150,19 @@
150 150 #define USB_REQ_SET_IDLE 0x0A
151 151 #define USB_REQ_SET_PROTOCOL 0x0B
152 152  
  153 +/* Device features */
  154 +#define USB_FEAT_HALT 0x00
  155 +#define USB_FEAT_WAKEUP 0x01
  156 +#define USB_FEAT_TEST 0x02
153 157  
  158 +/* Test modes */
  159 +#define USB_TEST_MODE_J 0x01
  160 +#define USB_TEST_MODE_K 0x02
  161 +#define USB_TEST_MODE_SE0_NAK 0x03
  162 +#define USB_TEST_MODE_PACKET 0x04
  163 +#define USB_TEST_MODE_FORCE_ENABLE 0x05
  164 +
  165 +
154 166 /* "pipe" definitions */
155 167  
156 168 #define PIPE_ISOCHRONOUS 0
... ... @@ -208,6 +220,7 @@
208 220 #define USB_PORT_FEAT_C_SUSPEND 18
209 221 #define USB_PORT_FEAT_C_OVER_CURRENT 19
210 222 #define USB_PORT_FEAT_C_RESET 20
  223 +#define USB_PORT_FEAT_TEST 21
211 224  
212 225 /* wPortStatus bits */
213 226 #define USB_PORT_STAT_CONNECTION 0x0001