Merge "dcache: Skipping dcache flush when no destination pointer"
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index fe1e33c..e7ef65d 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -46,7 +46,6 @@
 		ipq40xx-dk04-c2.dtb \
 		ipq40xx-dk04-c3.dtb \
 		ipq40xx-dk04-c4.dtb \
-		ipq40xx-dk04-c5.dtb \
 		ipq40xx-dk07-c1.dtb \
 		ipq40xx-dk07-c2.dtb \
 		ipq40xx-dk07-c3.dtb \
diff --git a/common/usb_hub.c b/common/usb_hub.c
index 0eb8f15..c9b530b 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -46,9 +46,6 @@
 
 #define USB_BUFSIZ	512
 
-/* TODO(sjg@chromium.org): Remove this when CONFIG_DM_USB is defined */
-static struct usb_hub_device hub_dev[USB_MAX_HUB];
-static int usb_hub_index;
 
 __weak void usb_hub_reset_devices(int port)
 {
@@ -68,6 +65,16 @@
 
 	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)
@@ -105,9 +112,40 @@
 
 int usb_get_port_status(struct usb_device *dev, int port, void *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+	int ret;
+
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 			USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
 			data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+
+#ifdef CONFIG_DM_USB
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Translate the USB 3.0 hub port status field into the old version
+	 * that U-Boot understands. Do this only when the hub is not root hub.
+	 * For root hub, the port status field has already been translated
+	 * in the host controller driver (see xhci_submit_root() in xhci.c).
+	 *
+	 * Note: this only supports driver model.
+	 */
+
+	if (!usb_hub_is_root_hub(dev->dev) && usb_hub_is_superspeed(dev)) {
+		struct usb_port_status *status = (struct usb_port_status *)data;
+		u16 tmp = (status->wPortStatus) & USB_SS_PORT_STAT_MASK;
+
+		if (status->wPortStatus & USB_SS_PORT_STAT_POWER)
+			tmp |= USB_PORT_STAT_POWER;
+		if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) ==
+		    USB_SS_PORT_STAT_SPEED_5GBPS)
+			tmp |= USB_PORT_STAT_SUPER_SPEED;
+
+		status->wPortStatus = tmp;
+	}
+#endif
+
+	return ret;
 }
 
 
@@ -140,6 +178,10 @@
 	mdelay(pgood_delay + 1000);
 }
 
+#ifndef CONFIG_DM_USB
+static struct usb_hub_device hub_dev[USB_MAX_HUB];
+static int usb_hub_index;
+
 void usb_hub_reset(void)
 {
 	usb_hub_index = 0;
@@ -153,6 +195,7 @@
 	printf("ERROR: USB_MAX_HUB (%d) reached\n", USB_MAX_HUB);
 	return NULL;
 }
+#endif
 
 #define MAX_TRIES 5
 
@@ -351,6 +394,20 @@
 }
 
 
+static struct usb_hub_device *usb_get_hub_device(struct usb_device *dev)
+{
+	struct usb_hub_device *hub;
+
+#ifndef CONFIG_DM_USB
+	/* "allocate" Hub device */
+	hub = usb_hub_allocate();
+#else
+	hub = dev_get_uclass_priv(dev->dev);
+#endif
+
+	return hub;
+}
+
 static int usb_hub_configure(struct usb_device *dev)
 {
 	int i, length;
@@ -362,11 +419,11 @@
 	__maybe_unused struct usb_hub_status *hubsts;
 	int ret;
 
-	/* "allocate" Hub device */
-	hub = usb_hub_allocate();
+	hub = usb_get_hub_device(dev);
 	if (hub == NULL)
 		return -ENOMEM;
 	hub->pusb_dev = dev;
+
 	/* Get the the hub descriptor */
 	ret = usb_get_hub_descriptor(dev, buffer, 4);
 	if (ret < 0) {
@@ -476,6 +533,48 @@
 	debug("%sover-current condition exists\n",
 	      (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
 	      "" : "no ");
+
+#ifdef CONFIG_DM_USB
+	/*
+	 * 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);
 
 	/*
@@ -677,6 +776,7 @@
 	.child_pre_probe	= usb_child_pre_probe,
 	.per_child_auto_alloc_size = sizeof(struct usb_device),
 	.per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
+	.per_device_auto_alloc_size = sizeof(struct usb_hub_device),
 };
 
 static const struct usb_device_id hub_id_table[] = {
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index ec8b403..0b268d1 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -174,7 +174,6 @@
 #ifdef CONFIG_USB_STORAGE
 	usb_stor_reset();
 #endif
-	usb_hub_reset();
 	uc_priv->companion_device_count = 0;
 	usb_started = 0;
 
@@ -227,7 +226,6 @@
 	int ret;
 
 	asynch_allowed = 1;
-	usb_hub_reset();
 
 	ret = uclass_get(UCLASS_USB, &uc);
 	if (ret)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 3744452..d6cefc1 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -626,14 +626,21 @@
  * @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];
 
@@ -644,7 +651,32 @@
 	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:
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 3a0c79d..97d64ca 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -415,8 +415,7 @@
 	 * so setting up the slot context.
 	 */
 	debug("Setting up addressable devices %p\n", ctrl->dcbaa);
-	xhci_setup_addressable_virt_dev(ctrl, udev->slot_id, udev->speed,
-					root_portnr);
+	xhci_setup_addressable_virt_dev(ctrl, udev, root_portnr);
 
 	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
 	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index b683850..c081b3c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1244,8 +1244,8 @@
 void xhci_slot_copy(struct xhci_ctrl *ctrl,
 		    struct xhci_container_ctx *in_ctx,
 		    struct xhci_container_ctx *out_ctx);
-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);
 void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr,
 			u32 slot_id, u32 ep_index, trb_type cmd);
 void xhci_acknowledge_event(struct xhci_ctrl *ctrl);
diff --git a/include/usb.h b/include/usb.h
index f2bd76e..fea4cb2 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -566,6 +566,7 @@
 struct usb_hub_device {
 	struct usb_device *pusb_dev;
 	struct usb_hub_descriptor desc;
+	int hub_depth;			/* USB 3.0 hub depth */
 };
 
 #ifdef CONFIG_DM_USB
diff --git a/include/usb_defs.h b/include/usb_defs.h
index 608a0ca..273337f 100644
--- a/include/usb_defs.h
+++ b/include/usb_defs.h
@@ -262,12 +262,17 @@
 
 /*
  * Changes to wPortStatus bit field in USB 3.0
- * See USB 3.0 spec Table 10-11
+ * See USB 3.0 spec Table 10-10
  */
 #define USB_SS_PORT_STAT_LINK_STATE	0x01e0
 #define USB_SS_PORT_STAT_POWER		0x0200
 #define USB_SS_PORT_STAT_SPEED		0x1c00
 #define USB_SS_PORT_STAT_SPEED_5GBPS	0x0000
+/* Bits that are the same from USB 2.0 */
+#define USB_SS_PORT_STAT_MASK		(USB_PORT_STAT_CONNECTION | \
+					 USB_PORT_STAT_ENABLE | \
+					 USB_PORT_STAT_OVERCURRENT | \
+					 USB_PORT_STAT_RESET)
 
 /* wPortChange bits */
 #define USB_PORT_STAT_C_CONNECTION  0x0001
@@ -301,6 +306,9 @@
 /* Mask for wIndex in get/set port feature */
 #define USB_HUB_PORT_MASK	0xf
 
+/* Hub class request codes */
+#define USB_REQ_SET_HUB_DEPTH	0x0c
+
 /*
  * CBI style
  */