usb: hub: Parse and save TT details from device descriptor

A high speed hub has a special responsibility to handle full speed/
low speed devices connected on downstream ports. In this case, the
hub must isolate the high speed signaling environment from the full
speed/low speed signaling environment with the help of Transaction
Translator (TT). TT details are provided by hub descriptors and we
parse and save it to hub uclass_priv for later use.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/common/usb_hub.c b/common/usb_hub.c
index 18c366a..bbb1155 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -700,6 +700,56 @@
 		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",
diff --git a/include/usb.h b/include/usb.h
index f71da52..58b4549 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -537,6 +537,21 @@
 	unsigned short wHubChange;
 } __attribute__ ((packed));
 
+/*
+ * Hub Device descriptor
+ * USB Hub class device protocols
+ */
+#define USB_HUB_PR_FS		0 /* Full speed hub */
+#define USB_HUB_PR_HS_NO_TT	0 /* Hi-speed hub without TT */
+#define USB_HUB_PR_HS_SINGLE_TT	1 /* Hi-speed hub with single TT */
+#define USB_HUB_PR_HS_MULTI_TT	2 /* Hi-speed hub with multiple TT */
+#define USB_HUB_PR_SS		3 /* Super speed hub */
+
+/* Transaction Translator Think Times, in bits */
+#define HUB_TTTT_8_BITS		0x00
+#define HUB_TTTT_16_BITS	0x20
+#define HUB_TTTT_24_BITS	0x40
+#define HUB_TTTT_32_BITS	0x60
 
 /* Hub descriptor */
 struct usb_hub_descriptor {
@@ -571,6 +586,7 @@
 	ulong query_delay;		/* Device query delay in ms */
 	int overcurrent_count[USB_MAXCHILDREN];	/* Over-current counter */
 	int hub_depth;			/* USB 3.0 hub depth */
+	struct usb_tt tt;		/* Transaction Translator */
 };
 
 #ifdef CONFIG_DM_USB
diff --git a/include/usb_defs.h b/include/usb_defs.h
index 273337f..b7f2ead 100644
--- a/include/usb_defs.h
+++ b/include/usb_defs.h
@@ -293,6 +293,7 @@
 #define HUB_CHAR_LPSM               0x0003
 #define HUB_CHAR_COMPOUND           0x0004
 #define HUB_CHAR_OCPM               0x0018
+#define HUB_CHAR_TTTT               0x0060 /* TT Think Time mask */
 
 /*
  * Hub Status & Hub Change bit masks
@@ -310,6 +311,17 @@
 #define USB_REQ_SET_HUB_DEPTH	0x0c
 
 /*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ */
+struct usb_tt {
+	bool		multi;		/* true means one TT per port */
+	unsigned	think_time;	/* think time in ns */
+};
+
+/*
  * CBI style
  */