Commit bbc6f06c0031249bf1983b875e54cb7549bafe60
Committed by
Marek Vasut
1 parent
74ffc7cbb1
Exists in
smarc_8mq_lf_v2020.04
and in
17 other branches
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
common/usb_hub.c
... | ... | @@ -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 | /* |
include/usb.h
... | ... | @@ -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 |
include/usb_defs.h