summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorBin Meng <bmeng.cn@gmail.com>2017-07-19 21:51:15 +0800
committerMarek Vasut <marex@denx.de>2017-07-28 23:34:33 +0200
commit493b8dd070f2412b49190b71b44baddbb2b24e37 (patch)
treecf31154bb950fd15e96c6216da3195562f5bf208 /drivers/usb
parentdaec4691449fa4728f29260554701602e8f91d5c (diff)
usb: xhci: Program 'route string' in the input slot context
xHCI spec says: the values of the 'route string' field shall be initialized by the first 'Address Device' command issued to a device slot, and shall not be modified by any other command. So far U-Boot does not program this field, and it does not prevent SS device directly attached to root port, or HS device behind an HS hub, from working, due to the fact that 'route string' is used by the xHC to target SS packets. But in order to enumerate devices behind an SS hub, this field must be programmed. With this commit and along with previous commits, now SS & HS devices attached to a USB 3.0 hub can be enumerated by U-Boot. As usual, this new feature is only available when DM is on. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-mem.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 9aa309237ee..c02059ee0ab 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -723,6 +723,11 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
u64 trb_64 = 0;
int slot_id = udev->slot_id;
int speed = udev->speed;
+ int route = 0;
+#ifdef CONFIG_DM_USB
+ struct usb_device *dev = udev;
+ struct usb_hub_device *hub;
+#endif
virt_dev = ctrl->devs[slot_id];
@@ -733,7 +738,32 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->in_ctx);
/* Only the control endpoint is valid - one endpoint context */
- slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | 0);
+ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1));
+
+#ifdef CONFIG_DM_USB
+ /* Calculate the route string for this device */
+ port_num = dev->portnr;
+ while (!usb_hub_is_root_hub(dev->dev)) {
+ hub = dev_get_uclass_priv(dev->dev);
+ /*
+ * Each hub in the topology is expected to have no more than
+ * 15 ports in order for the route string of a device to be
+ * unique. SuperSpeed hubs are restricted to only having 15
+ * ports, but FS/LS/HS hubs are not. The xHCI specification
+ * says that if the port number the device is greater than 15,
+ * that portion of the route string shall be set to 15.
+ */
+ if (port_num > 15)
+ port_num = 15;
+ route |= port_num << (hub->hub_depth * 4);
+ dev = dev_get_parent_priv(dev->dev);
+ port_num = dev->portnr;
+ dev = dev_get_parent_priv(dev->dev->parent);
+ }
+
+ debug("route string %x\n", route);
+#endif
+ slot_ctx->dev_info |= route;
switch (speed) {
case USB_SPEED_SUPER: