X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fusb_hub.c;h=b46dfa16ccf1285d5ff9f2f142461f6146dd06ab;hb=ee3db4fc04714c80196e49f8f3a5f157f20d2862;hp=b0ff15977fee6f1fd7bdb77d7b69c13c0ca97b14;hpb=74ffc7cbb1d2d1f218b1bd67d1bd3cc1cba8aa79;p=u-boot diff --git a/common/usb_hub.c b/common/usb_hub.c index b0ff15977f..b46dfa16cc 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -57,7 +57,7 @@ struct usb_device_scan { static LIST_HEAD(usb_scan_list); -__weak void usb_hub_reset_devices(int port) +__weak void usb_hub_reset_devices(struct usb_hub_device *hub, int port) { return; } @@ -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) @@ -179,7 +189,7 @@ static void usb_hub_power_on(struct usb_hub_device *hub) * but allow this time to be increased via env variable as some * devices break the spec and require longer warm-up times */ - env = getenv("usb_pgood_delay"); + env = env_get("usb_pgood_delay"); if (env) pgood_delay = max(pgood_delay, (unsigned)simple_strtol(env, NULL, 0)); @@ -479,6 +489,17 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) return 0; } + if (portchange & USB_PORT_STAT_C_RESET) { + debug("port %d reset change\n", i + 1); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); + } + + if ((portchange & USB_SS_PORT_STAT_C_BH_RESET) && + usb_hub_is_superspeed(dev)) { + debug("port %d BH reset change\n", i + 1); + usb_clear_port_feature(dev, i + 1, USB_SS_PORT_FEAT_C_BH_RESET); + } + /* A new USB device is ready at this point */ debug("devnum=%d port=%d: USB dev found\n", dev->devnum, i + 1); @@ -533,11 +554,6 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) hub->overcurrent_count[i]); } - if (portchange & USB_PORT_STAT_C_RESET) { - debug("port %d reset change\n", i + 1); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); - } - /* * We're done with this device, so let's remove this device from * scanning list @@ -609,7 +625,7 @@ static int usb_hub_configure(struct usb_device *dev) short hubCharacteristics; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; - __maybe_unused struct usb_hub_status *hubsts; + struct usb_hub_status *hubsts; int ret; hub = usb_get_hub_device(dev); @@ -690,6 +706,56 @@ static int usb_hub_configure(struct usb_device *dev) break; } + switch (dev->descriptor.bDeviceProtocol) { + case USB_HUB_PR_FS: + break; + case USB_HUB_PR_HS_SINGLE_TT: + debug("Single TT\n"); + break; + case USB_HUB_PR_HS_MULTI_TT: + ret = usb_set_interface(dev, 0, 1); + if (ret == 0) { + debug("TT per port\n"); + hub->tt.multi = true; + } else { + debug("Using single TT (err %d)\n", ret); + } + break; + case USB_HUB_PR_SS: + /* USB 3.0 hubs don't have a TT */ + break; + default: + debug("Unrecognized hub protocol %d\n", + dev->descriptor.bDeviceProtocol); + break; + } + + /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ + switch (hubCharacteristics & HUB_CHAR_TTTT) { + case HUB_TTTT_8_BITS: + if (dev->descriptor.bDeviceProtocol != 0) { + hub->tt.think_time = 666; + debug("TT requires at most %d FS bit times (%d ns)\n", + 8, hub->tt.think_time); + } + break; + case HUB_TTTT_16_BITS: + hub->tt.think_time = 666 * 2; + debug("TT requires at most %d FS bit times (%d ns)\n", + 16, hub->tt.think_time); + break; + case HUB_TTTT_24_BITS: + hub->tt.think_time = 666 * 3; + debug("TT requires at most %d FS bit times (%d ns)\n", + 24, hub->tt.think_time); + break; + case HUB_TTTT_32_BITS: + hub->tt.think_time = 666 * 4; + debug("TT requires at most %d FS bit times (%d ns)\n", + 32, hub->tt.think_time); + break; + } + debug("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); debug("hub controller current requirement: %dmA\n", @@ -713,9 +779,7 @@ static int usb_hub_configure(struct usb_device *dev) return ret; } -#ifdef DEBUG hubsts = (struct usb_hub_status *)buffer; -#endif debug("get_hub_status returned status %X, change %X\n", le16_to_cpu(hubsts->wHubStatus), @@ -726,6 +790,59 @@ 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 + /* + * Update USB host controller's internal representation of this hub + * after the hub descriptor is fetched. + */ + ret = usb_update_hub_device(dev); + if (ret < 0 && ret != -ENOSYS) { + debug("%s: failed to update hub device for HCD (%x)\n", + __func__, ret); + return ret; + } + + /* + * 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); /* @@ -734,7 +851,7 @@ static int usb_hub_configure(struct usb_device *dev) * should occur in the board file of the device. */ for (i = 0; i < dev->maxchild; i++) - usb_hub_reset_devices(i + 1); + usb_hub_reset_devices(hub, i + 1); /* * Only add the connected USB devices, including potential hubs,