Commit bbc6f06c0031249bf1983b875e54cb7549bafe60

Authored by Bin Meng
Committed by Marek Vasut
1 parent 74ffc7cbb1

usb: hub: Support 'set hub depth' request for USB 3.0 hubs

USB 3.0 hub uses a hub depth value multiplied by four as an offset
into the 'route string' to locate the bits it uses to determine the
downstream port number. We shall set the hub depth value of a USB
3.0 hub after it is configured.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>

Showing 3 changed files with 56 additions and 0 deletions Side-by-side Diff

... ... @@ -75,6 +75,16 @@
75 75  
76 76 return false;
77 77 }
  78 +
  79 +static int usb_set_hub_depth(struct usb_device *dev, int depth)
  80 +{
  81 + if (depth < 0 || depth > 4)
  82 + return -EINVAL;
  83 +
  84 + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  85 + USB_REQ_SET_HUB_DEPTH, USB_DIR_OUT | USB_RT_HUB,
  86 + depth, 0, NULL, 0, USB_CNTL_TIMEOUT);
  87 +}
78 88 #endif
79 89  
80 90 static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
... ... @@ -726,6 +736,48 @@
726 736 debug("%sover-current condition exists\n",
727 737 (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
728 738 "" : "no ");
  739 +
  740 +#ifdef CONFIG_DM_USB
  741 + /*
  742 + * A maximum of seven tiers are allowed in a USB topology, and the
  743 + * root hub occupies the first tier. The last tier ends with a normal
  744 + * USB device. USB 3.0 hubs use a 20-bit field called 'route string'
  745 + * to route packets to the designated downstream port. The hub uses a
  746 + * hub depth value multiplied by four as an offset into the 'route
  747 + * string' to locate the bits it uses to determine the downstream
  748 + * port number.
  749 + */
  750 + if (usb_hub_is_root_hub(dev->dev)) {
  751 + hub->hub_depth = -1;
  752 + } else {
  753 + struct udevice *hdev;
  754 + int depth = 0;
  755 +
  756 + hdev = dev->dev->parent;
  757 + while (!usb_hub_is_root_hub(hdev)) {
  758 + depth++;
  759 + hdev = hdev->parent;
  760 + }
  761 +
  762 + hub->hub_depth = depth;
  763 +
  764 + if (usb_hub_is_superspeed(dev)) {
  765 + debug("set hub (%p) depth to %d\n", dev, depth);
  766 + /*
  767 + * This request sets the value that the hub uses to
  768 + * determine the index into the 'route string index'
  769 + * for this hub.
  770 + */
  771 + ret = usb_set_hub_depth(dev, depth);
  772 + if (ret < 0) {
  773 + debug("%s: failed to set hub depth (%lX)\n",
  774 + __func__, dev->status);
  775 + return ret;
  776 + }
  777 + }
  778 + }
  779 +#endif
  780 +
729 781 usb_hub_power_on(hub);
730 782  
731 783 /*
... ... @@ -570,6 +570,7 @@
570 570 ulong connect_timeout; /* Device connection timeout in ms */
571 571 ulong query_delay; /* Device query delay in ms */
572 572 int overcurrent_count[USB_MAXCHILDREN]; /* Over-current counter */
  573 + int hub_depth; /* USB 3.0 hub depth */
573 574 };
574 575  
575 576 #ifdef CONFIG_DM_USB
... ... @@ -306,6 +306,9 @@
306 306 /* Mask for wIndex in get/set port feature */
307 307 #define USB_HUB_PORT_MASK 0xf
308 308  
  309 +/* Hub class request codes */
  310 +#define USB_REQ_SET_HUB_DEPTH 0x0c
  311 +
309 312 /*
310 313 * CBI style
311 314 */