]> git.sur5r.net Git - u-boot/commitdiff
usb: hub: Support 'set hub depth' request for USB 3.0 hubs
authorBin Meng <bmeng.cn@gmail.com>
Wed, 19 Jul 2017 13:51:13 +0000 (21:51 +0800)
committerMarek Vasut <marex@denx.de>
Fri, 28 Jul 2017 21:34:32 +0000 (23:34 +0200)
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>
common/usb_hub.c
include/usb.h
include/usb_defs.h

index b0ff15977fee6f1fd7bdb77d7b69c13c0ca97b14..18c366ab7e0b800850c2efdab1447c2ec7758d7e 100644 (file)
@@ -75,6 +75,16 @@ bool usb_hub_is_root_hub(struct udevice *hub)
 
        return false;
 }
+
+static int usb_set_hub_depth(struct usb_device *dev, int depth)
+{
+       if (depth < 0 || depth > 4)
+               return -EINVAL;
+
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_SET_HUB_DEPTH, USB_DIR_OUT | USB_RT_HUB,
+               depth, 0, NULL, 0, USB_CNTL_TIMEOUT);
+}
 #endif
 
 static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
@@ -726,6 +736,48 @@ static int usb_hub_configure(struct usb_device *dev)
        debug("%sover-current condition exists\n",
              (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
              "" : "no ");
+
+#ifdef CONFIG_DM_USB
+       /*
+        * A maximum of seven tiers are allowed in a USB topology, and the
+        * root hub occupies the first tier. The last tier ends with a normal
+        * USB device. USB 3.0 hubs use a 20-bit field called 'route string'
+        * to route packets to the designated downstream port. The 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.
+        */
+       if (usb_hub_is_root_hub(dev->dev)) {
+               hub->hub_depth = -1;
+       } else {
+               struct udevice *hdev;
+               int depth = 0;
+
+               hdev = dev->dev->parent;
+               while (!usb_hub_is_root_hub(hdev)) {
+                       depth++;
+                       hdev = hdev->parent;
+               }
+
+               hub->hub_depth = depth;
+
+               if (usb_hub_is_superspeed(dev)) {
+                       debug("set hub (%p) depth to %d\n", dev, depth);
+                       /*
+                        * This request sets the value that the hub uses to
+                        * determine the index into the 'route string index'
+                        * for this hub.
+                        */
+                       ret = usb_set_hub_depth(dev, depth);
+                       if (ret < 0) {
+                               debug("%s: failed to set hub depth (%lX)\n",
+                                     __func__, dev->status);
+                               return ret;
+                       }
+               }
+       }
+#endif
+
        usb_hub_power_on(hub);
 
        /*
index 64dfa84a9bef8d726c172e1269a67af1efe0c76f..f71da52b55afa25988270c87436ece4e333f6d5b 100644 (file)
@@ -570,6 +570,7 @@ struct usb_hub_device {
        ulong connect_timeout;          /* Device connection timeout in ms */
        ulong query_delay;              /* Device query delay in ms */
        int overcurrent_count[USB_MAXCHILDREN]; /* Over-current counter */
+       int hub_depth;                  /* USB 3.0 hub depth */
 };
 
 #ifdef CONFIG_DM_USB
index 6b4385a2d8347f0334aa7bcf028137e3d02d6840..273337f46a47d7fb9a7537351fa09a3299546a9c 100644 (file)
 /* Mask for wIndex in get/set port feature */
 #define USB_HUB_PORT_MASK      0xf
 
+/* Hub class request codes */
+#define USB_REQ_SET_HUB_DEPTH  0x0c
+
 /*
  * CBI style
  */