summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_hub.c52
-rw-r--r--include/usb.h1
-rw-r--r--include/usb_defs.h3
3 files changed, 56 insertions, 0 deletions
diff --git a/common/usb_hub.c b/common/usb_hub.c
index b0ff159..18c366a 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -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);
/*
diff --git a/include/usb.h b/include/usb.h
index 64dfa84..f71da52 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -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
diff --git a/include/usb_defs.h b/include/usb_defs.h
index 6b4385a..273337f 100644
--- a/include/usb_defs.h
+++ b/include/usb_defs.h
@@ -306,6 +306,9 @@
/* 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
*/