]> git.sur5r.net Git - u-boot/blobdiff - drivers/usb/host/xhci-mem.c
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / drivers / usb / host / xhci-mem.c
index 12e277a26d988b3554cb665452e78039cb58cfac..da5dbd94edd074891419dc5fd9f5b87d4c03fc4d 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * USB HOST XHCI Controller stack
  *
@@ -10,8 +11,6 @@
  * Copyright (C) 2013 Samsung Electronics Co.Ltd
  * Authors: Vivek Gautam <gautam.vivek@samsung.com>
  *         Vikas Sajjan <vikas.sajjan@samsung.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
@@ -713,14 +712,21 @@ void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx,
  * @param udev pointer to the Device Data Structure
  * @return returns negative value on failure else 0 on success
  */
-void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
-                                    int speed, int hop_portnr)
+void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
+                                    struct usb_device *udev, int hop_portnr)
 {
        struct xhci_virt_device *virt_dev;
        struct xhci_ep_ctx *ep0_ctx;
        struct xhci_slot_ctx *slot_ctx;
        u32 port_num = 0;
        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];
 
@@ -731,7 +737,32 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
        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:
@@ -751,6 +782,30 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
                BUG();
        }
 
+#ifdef CONFIG_DM_USB
+       /* Set up TT fields to support FS/LS devices */
+       if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
+               struct udevice *parent = udev->dev;
+
+               dev = udev;
+               do {
+                       port_num = dev->portnr;
+                       dev = dev_get_parent_priv(parent);
+                       if (usb_hub_is_root_hub(dev->dev))
+                               break;
+                       parent = dev->dev->parent;
+               } while (dev->speed != USB_SPEED_HIGH);
+
+               if (!usb_hub_is_root_hub(dev->dev)) {
+                       hub = dev_get_uclass_priv(dev->dev);
+                       if (hub->tt.multi)
+                               slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
+                       slot_ctx->tt_info |= cpu_to_le32(TT_PORT(port_num));
+                       slot_ctx->tt_info |= cpu_to_le32(TT_SLOT(dev->slot_id));
+               }
+       }
+#endif
+
        port_num = hop_portnr;
        debug("port_num = %d\n", port_num);
 
@@ -794,6 +849,12 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
        trb_64 = (uintptr_t)virt_dev->eps[0].ring->first_seg->trbs;
        ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
 
+       /*
+        * xHCI spec 6.2.3:
+        * software shall set 'Average TRB Length' to 8 for control endpoints.
+        */
+       ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8));
+
        /* Steps 7 and 8 were done in xhci_alloc_virt_device() */
 
        xhci_flush_cache((uintptr_t)ep0_ctx, sizeof(struct xhci_ep_ctx));