Lines Matching +full:usb +full:- +full:hub

1 // SPDX-License-Identifier: GPL-2.0+
3 * Most of this source has been derived from the Linux USB
6 * (C) Copyright Johannes Erdfelt 1999-2001
9 * (C) Copyright Deti Fliegl 1999 (new USB architecture)
15 * Adapted for U-Boot:
20 * HUB "Driver"
21 * Probes device for being a hub and configurate it
39 #include <usb.h>
49 struct usb_device *dev; /* USB hub device to scan */
50 struct usb_hub_device *hub; /* USB hub struct */ member
51 int port; /* USB port to scan */
57 __weak void usb_hub_reset_devices(struct usb_hub_device *hub, int port) in usb_hub_reset_devices() argument
64 return hdev->descriptor.bDeviceProtocol == 3; in usb_hub_is_superspeed()
68 bool usb_hub_is_root_hub(struct udevice *hub) in usb_hub_is_root_hub() argument
70 if (device_get_uclass_id(hub->parent) != UCLASS_USB_HUB) in usb_hub_is_root_hub()
79 return -EINVAL; in usb_set_hub_depth()
133 * Translate the USB 3.0 hub port status field into the old version in usb_get_port_status()
134 * that U-Boot understands. Do this only when the hub is not root hub. in usb_get_port_status()
135 * For root hub, the port status field has already been translated in usb_get_port_status()
141 if (!usb_hub_is_root_hub(dev->dev) && usb_hub_is_superspeed(dev)) { in usb_get_port_status()
143 u16 tmp = (status->wPortStatus) & USB_SS_PORT_STAT_MASK; in usb_get_port_status()
145 if (status->wPortStatus & USB_SS_PORT_STAT_POWER) in usb_get_port_status()
147 if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) == in usb_get_port_status()
151 status->wPortStatus = tmp; in usb_get_port_status()
159 static void usb_hub_power_on(struct usb_hub_device *hub) in usb_hub_power_on() argument
163 unsigned pgood_delay = hub->desc.bPwrOn2PwrGood * 2; in usb_hub_power_on()
166 dev = hub->pusb_dev; in usb_hub_power_on()
169 for (i = 0; i < dev->maxchild; i++) { in usb_hub_power_on()
171 debug("port %d returns %lX\n", i + 1, dev->status); in usb_hub_power_on()
185 * plus spec-defined max time for device to connect in usb_hub_power_on()
187 * devices break the spec and require longer warm-up times in usb_hub_power_on()
199 hub->query_delay = get_timer(0) + max(100, (int)pgood_delay); in usb_hub_power_on()
202 * Record the power-on timeout here. The max. delay (timeout) in usb_hub_power_on()
203 * will be done based on this value in the USB port loop in in usb_hub_power_on()
206 hub->connect_timeout = hub->query_delay + 1000; in usb_hub_power_on()
208 dev->devnum, max(100, (int)pgood_delay), in usb_hub_power_on()
220 /* Zero out global hub_dev in case its re-used again */ in usb_hub_reset()
259 * usb_hub_port_reset() - reset a port given its usb_device pointer
261 * Reset a hub port and see if a device is present on that port, providing
264 * @dev: USB device to reset
277 debug("%s: resetting '%s' port %d...\n", __func__, dev->dev->name, in usb_hub_port_reset()
291 dev->status); in usb_hub_port_reset()
292 return -1; in usb_hub_port_reset()
294 portstatus = le16_to_cpu(portsts->wPortStatus); in usb_hub_port_reset()
295 portchange = le16_to_cpu(portsts->wPortChange); in usb_hub_port_reset()
308 * - C_CONNECTION hasn't been set. in usb_hub_port_reset()
309 * - CONNECTION is still set. in usb_hub_port_reset()
313 * USB bus reset was going on. in usb_hub_port_reset()
316 * USB 3.0 16GB device fails to reset on (at least) an NVIDIA in usb_hub_port_reset()
333 debug("Maybe the USB cable is bad?\n"); in usb_hub_port_reset()
334 return -1; in usb_hub_port_reset()
355 portstatus = le16_to_cpu(portsts->wPortStatus); in usb_hub_port_connect_change()
358 le16_to_cpu(portsts->wPortChange), in usb_hub_port_connect_change()
368 debug("usb_disconnect(&hub->children[port]);\n"); in usb_hub_port_connect_change()
371 return -ENOTCONN; in usb_hub_port_connect_change()
377 if (ret != -ENXIO) in usb_hub_port_connect_change()
400 ret = usb_scan_device(dev->dev, port + 1, speed, &child); in usb_hub_port_connect_change()
402 struct usb_device *usb; in usb_hub_port_connect_change() local
404 ret = usb_alloc_new_device(dev->controller, &usb); in usb_hub_port_connect_change()
410 dev->children[port] = usb; in usb_hub_port_connect_change()
411 usb->speed = speed; in usb_hub_port_connect_change()
412 usb->parent = dev; in usb_hub_port_connect_change()
413 usb->portnr = port + 1; in usb_hub_port_connect_change()
415 ret = usb_new_device(usb); in usb_hub_port_connect_change()
418 usb_free_device(dev->controller); in usb_hub_port_connect_change()
419 dev->children[port] = NULL; in usb_hub_port_connect_change()
423 debug("hub: disabling port %d\n", port + 1); in usb_hub_port_connect_change()
436 struct usb_hub_device *hub; in usb_scan_port() local
440 dev = usb_scan->dev; in usb_scan_port()
441 hub = usb_scan->hub; in usb_scan_port()
442 i = usb_scan->port; in usb_scan_port()
448 if (get_timer(0) < hub->query_delay) in usb_scan_port()
454 if (get_timer(0) >= hub->connect_timeout) { in usb_scan_port()
456 dev->devnum, i + 1); in usb_scan_port()
458 list_del(&usb_scan->list); in usb_scan_port()
465 portstatus = le16_to_cpu(portsts->wPortStatus); in usb_scan_port()
466 portchange = le16_to_cpu(portsts->wPortChange); in usb_scan_port()
472 * For some situation, the hub reports no connection change but a in usb_scan_port()
474 * in the PORTSC register of a root hub), ignore such case. in usb_scan_port()
478 if (get_timer(0) >= hub->connect_timeout) { in usb_scan_port()
480 dev->devnum, i + 1); in usb_scan_port()
482 list_del(&usb_scan->list); in usb_scan_port()
500 /* A new USB device is ready at this point */ in usb_scan_port()
501 debug("devnum=%d port=%d: USB dev found\n", dev->devnum, i + 1); in usb_scan_port()
514 * EM interference sometimes causes bad shielded USB in usb_scan_port()
515 * devices to be shutdown by the hub, this hack enables in usb_scan_port()
521 debug("already running port %i disabled by hub (EMI?), re-enabling...\n", in usb_scan_port()
534 debug("port %d over-current change\n", i + 1); in usb_scan_port()
537 /* Only power-on this one port */ in usb_scan_port()
539 hub->overcurrent_count[i]++; in usb_scan_port()
542 * If the max-scan-count is not reached, return without removing in usb_scan_port()
543 * the device from scan-list. This will re-issue a new scan. in usb_scan_port()
545 if (hub->overcurrent_count[i] <= in usb_scan_port()
550 printf("Port %d over-current occurred %d times\n", i + 1, in usb_scan_port()
551 hub->overcurrent_count[i]); in usb_scan_port()
558 list_del(&usb_scan->list); in usb_scan_port()
594 * This USB controller has finished scanning all its connected in usb_device_list_scan()
595 * USB devices. Set "running" back to 0, so that other USB controllers in usb_device_list_scan()
605 struct usb_hub_device *hub; in usb_get_hub_device() local
608 /* "allocate" Hub device */ in usb_get_hub_device()
609 hub = usb_hub_allocate(); in usb_get_hub_device()
611 hub = dev_get_uclass_priv(dev->dev); in usb_get_hub_device()
614 return hub; in usb_get_hub_device()
624 struct usb_hub_device *hub; in usb_hub_configure() local
628 hub = usb_get_hub_device(dev); in usb_hub_configure()
629 if (hub == NULL) in usb_hub_configure()
630 return -ENOMEM; in usb_hub_configure()
631 hub->pusb_dev = dev; in usb_hub_configure()
633 /* Get the the hub descriptor */ in usb_hub_configure()
636 debug("usb_hub_configure: failed to get hub " \ in usb_hub_configure()
637 "descriptor, giving up %lX\n", dev->status); in usb_hub_configure()
642 length = min_t(int, descriptor->bLength, in usb_hub_configure()
647 debug("usb_hub_configure: failed to get hub " \ in usb_hub_configure()
648 "descriptor 2nd giving up %lX\n", dev->status); in usb_hub_configure()
651 memcpy((unsigned char *)&hub->desc, buffer, length); in usb_hub_configure()
654 &descriptor->wHubCharacteristics)), in usb_hub_configure()
655 &hub->desc.wHubCharacteristics); in usb_hub_configure()
657 bitmap = (unsigned char *)&hub->desc.u.hs.DeviceRemovable[0]; in usb_hub_configure()
660 bitmap = (unsigned char *)&hub->desc.u.hs.PortPowerCtrlMask[0]; in usb_hub_configure()
663 for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) in usb_hub_configure()
664 hub->desc.u.hs.DeviceRemovable[i] = in usb_hub_configure()
665 descriptor->u.hs.DeviceRemovable[i]; in usb_hub_configure()
667 for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) in usb_hub_configure()
668 hub->desc.u.hs.PortPowerCtrlMask[i] = in usb_hub_configure()
669 descriptor->u.hs.PortPowerCtrlMask[i]; in usb_hub_configure()
671 dev->maxchild = descriptor->bNbrPorts; in usb_hub_configure()
672 debug("%d ports detected\n", dev->maxchild); in usb_hub_configure()
674 hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics); in usb_hub_configure()
691 debug("standalone hub\n"); in usb_hub_configure()
695 debug("global over-current protection\n"); in usb_hub_configure()
698 debug("individual port over-current protection\n"); in usb_hub_configure()
702 debug("no over-current protection\n"); in usb_hub_configure()
706 switch (dev->descriptor.bDeviceProtocol) { in usb_hub_configure()
716 hub->tt.multi = true; in usb_hub_configure()
722 /* USB 3.0 hubs don't have a TT */ in usb_hub_configure()
725 debug("Unrecognized hub protocol %d\n", in usb_hub_configure()
726 dev->descriptor.bDeviceProtocol); in usb_hub_configure()
733 if (dev->descriptor.bDeviceProtocol != 0) { in usb_hub_configure()
734 hub->tt.think_time = 666; in usb_hub_configure()
736 8, hub->tt.think_time); in usb_hub_configure()
740 hub->tt.think_time = 666 * 2; in usb_hub_configure()
742 16, hub->tt.think_time); in usb_hub_configure()
745 hub->tt.think_time = 666 * 3; in usb_hub_configure()
747 24, hub->tt.think_time); in usb_hub_configure()
750 hub->tt.think_time = 666 * 4; in usb_hub_configure()
752 32, hub->tt.think_time); in usb_hub_configure()
757 descriptor->bPwrOn2PwrGood * 2); in usb_hub_configure()
758 debug("hub controller current requirement: %dmA\n", in usb_hub_configure()
759 descriptor->bHubContrCurrent); in usb_hub_configure()
761 for (i = 0; i < dev->maxchild; i++) in usb_hub_configure()
763 hub->desc.u.hs.DeviceRemovable[(i + 1) / 8] & \ in usb_hub_configure()
767 debug("usb_hub_configure: failed to get Status - " \ in usb_hub_configure()
768 "too long: %d\n", descriptor->bLength); in usb_hub_configure()
769 return -EFBIG; in usb_hub_configure()
775 dev->status); in usb_hub_configure()
782 le16_to_cpu(hubsts->wHubStatus), in usb_hub_configure()
783 le16_to_cpu(hubsts->wHubChange)); in usb_hub_configure()
785 (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ in usb_hub_configure()
787 debug("%sover-current condition exists\n", in usb_hub_configure()
788 (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ in usb_hub_configure()
793 * Update USB host controller's internal representation of this hub in usb_hub_configure()
794 * after the hub descriptor is fetched. in usb_hub_configure()
797 if (ret < 0 && ret != -ENOSYS) { in usb_hub_configure()
798 debug("%s: failed to update hub device for HCD (%x)\n", in usb_hub_configure()
804 * A maximum of seven tiers are allowed in a USB topology, and the in usb_hub_configure()
805 * root hub occupies the first tier. The last tier ends with a normal in usb_hub_configure()
806 * USB device. USB 3.0 hubs use a 20-bit field called 'route string' in usb_hub_configure()
807 * to route packets to the designated downstream port. The hub uses a in usb_hub_configure()
808 * hub depth value multiplied by four as an offset into the 'route in usb_hub_configure()
812 if (usb_hub_is_root_hub(dev->dev)) { in usb_hub_configure()
813 hub->hub_depth = -1; in usb_hub_configure()
818 hdev = dev->dev->parent; in usb_hub_configure()
821 hdev = hdev->parent; in usb_hub_configure()
824 hub->hub_depth = depth; in usb_hub_configure()
827 debug("set hub (%p) depth to %d\n", dev, depth); in usb_hub_configure()
829 * This request sets the value that the hub uses to in usb_hub_configure()
831 * for this hub. in usb_hub_configure()
835 debug("%s: failed to set hub depth (%lX)\n", in usb_hub_configure()
836 __func__, dev->status); in usb_hub_configure()
843 usb_hub_power_on(hub); in usb_hub_configure()
850 for (i = 0; i < dev->maxchild; i++) in usb_hub_configure()
851 usb_hub_reset_devices(hub, i + 1); in usb_hub_configure()
854 * Only add the connected USB devices, including potential hubs, in usb_hub_configure()
860 for (i = 0; i < dev->maxchild; i++) { in usb_hub_configure()
865 printf("Can't allocate memory for USB device!\n"); in usb_hub_configure()
866 return -ENOMEM; in usb_hub_configure()
868 usb_scan->dev = dev; in usb_hub_configure()
869 usb_scan->hub = hub; in usb_hub_configure()
870 usb_scan->port = i; in usb_hub_configure()
871 list_add_tail(&usb_scan->list, &usb_scan_list); in usb_hub_configure()
887 iface = &dev->config.if_desc[ifnum]; in usb_hub_check()
888 /* Is it a hub? */ in usb_hub_check()
889 if (iface->desc.bInterfaceClass != USB_CLASS_HUB) in usb_hub_check()
893 if ((iface->desc.bInterfaceSubClass != 0) && in usb_hub_check()
894 (iface->desc.bInterfaceSubClass != 1)) in usb_hub_check()
896 /* Multiple endpoints? What kind of mutant ninja-hub is this? */ in usb_hub_check()
897 if (iface->desc.bNumEndpoints != 1) in usb_hub_check()
899 ep = &iface->ep_desc[0]; in usb_hub_check()
901 if (!(ep->bEndpointAddress & USB_DIR_IN)) in usb_hub_check()
904 if ((ep->bmAttributes & 3) != 3) in usb_hub_check()
906 /* We found a hub */ in usb_hub_check()
907 debug("USB hub found\n"); in usb_hub_check()
911 debug("USB hub not found: bInterfaceClass=%d, bInterfaceSubClass=%d, bNumEndpoints=%d\n", in usb_hub_check()
912 iface->desc.bInterfaceClass, iface->desc.bInterfaceSubClass, in usb_hub_check()
913 iface->desc.bNumEndpoints); in usb_hub_check()
916 ep->bEndpointAddress, ep->bmAttributes); in usb_hub_check()
919 return -ENOENT; in usb_hub_check()
934 int usb_hub_scan(struct udevice *hub) in usb_hub_scan() argument
936 struct usb_device *udev = dev_get_parent_priv(hub); in usb_hub_scan()
948 { .compatible = "usb-hub" },