From: Mathias Nyman <mathias.ny...@linux.intel.com>

xhci 1.1 controllers that support USB 3.1 must provide a protocol speed ID
(PSI) list to inform the driver of the supported speeds.

The PSI list can be read from the xhci supported protocol extended
capabilities.
The PSI values will be used to create a USB 3.1 SuperSpeedPlus capability
descriptor for the xhci USB 3.1 roothub.

Signed-off-by: Mathias Nyman <mathias.ny...@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
(cherry picked from commit 47189098f8bebe4d937945df70d3ca8e6c0b3e4d)
Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com>
---
 drivers/usb/host/xhci-mem.c | 38 +++++++++++++++++++++++++++++++++++++-
 drivers/usb/host/xhci.h     | 24 ++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 5ab70af..40fbb39 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -2078,14 +2078,23 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, 
unsigned int num_ports,
 {
        u32 temp, port_offset, port_count;
        int i;
+       struct xhci_hub *rhub;
 
-       if (major_revision > 0x03) {
+       temp = readl(addr);
+
+       if (XHCI_EXT_PORT_MAJOR(temp) == 0x03) {
+               rhub = &xhci->usb3_rhub;
+       } else if (XHCI_EXT_PORT_MAJOR(temp) <= 0x02) {
+               rhub = &xhci->usb2_rhub;
+       } else {
                xhci_warn(xhci, "Ignoring unknown port speed, "
                                "Ext Cap %p, revision = 0x%x\n",
                                addr, major_revision);
                /* Ignoring port protocol we can't understand. FIXME */
                return;
        }
+       rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp);
+       rhub->min_rev = XHCI_EXT_PORT_MINOR(temp);
 
        /* Port offset and count in the third dword, see section 7.2 */
        temp = readl(addr + 2);
@@ -2100,6 +2109,33 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, 
unsigned int num_ports,
                /* WTF? "Valid values are ‘1’ to MaxPorts" */
                return;
 
+       rhub->psi_count = XHCI_EXT_PORT_PSIC(temp);
+       if (rhub->psi_count) {
+               rhub->psi = kcalloc(rhub->psi_count, sizeof(*rhub->psi),
+                                   GFP_KERNEL);
+               if (!rhub->psi)
+                       rhub->psi_count = 0;
+
+               rhub->psi_uid_count++;
+               for (i = 0; i < rhub->psi_count; i++) {
+                       rhub->psi[i] = readl(addr + 4 + i);
+
+                       /* count unique ID values, two consecutive entries can
+                        * have the same ID if link is assymetric
+                        */
+                       if (i && (XHCI_EXT_PORT_PSIV(rhub->psi[i]) !=
+                                 XHCI_EXT_PORT_PSIV(rhub->psi[i - 1])))
+                               rhub->psi_uid_count++;
+
+                       xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d 
PSIM:%d\n",
+                                 XHCI_EXT_PORT_PSIV(rhub->psi[i]),
+                                 XHCI_EXT_PORT_PSIE(rhub->psi[i]),
+                                 XHCI_EXT_PORT_PLT(rhub->psi[i]),
+                                 XHCI_EXT_PORT_PFD(rhub->psi[i]),
+                                 XHCI_EXT_PORT_LP(rhub->psi[i]),
+                                 XHCI_EXT_PORT_PSIM(rhub->psi[i]));
+               }
+       }
        /* cache usb2 port capabilities */
        if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
                xhci->ext_caps[xhci->num_ext_caps++] = temp;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c5d6963..a652571 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -515,9 +515,23 @@ struct xhci_protocol_caps {
 };
 
 #define        XHCI_EXT_PORT_MAJOR(x)  (((x) >> 24) & 0xff)
+#define        XHCI_EXT_PORT_MINOR(x)  (((x) >> 16) & 0xff)
+#define        XHCI_EXT_PORT_PSIC(x)   (((x) >> 28) & 0x0f)
 #define        XHCI_EXT_PORT_OFF(x)    ((x) & 0xff)
 #define        XHCI_EXT_PORT_COUNT(x)  (((x) >> 8) & 0xff)
 
+#define        XHCI_EXT_PORT_PSIV(x)   (((x) >> 0) & 0x0f)
+#define        XHCI_EXT_PORT_PSIE(x)   (((x) >> 4) & 0x03)
+#define        XHCI_EXT_PORT_PLT(x)    (((x) >> 6) & 0x03)
+#define        XHCI_EXT_PORT_PFD(x)    (((x) >> 8) & 0x01)
+#define        XHCI_EXT_PORT_LP(x)     (((x) >> 14) & 0x03)
+#define        XHCI_EXT_PORT_PSIM(x)   (((x) >> 16) & 0xffff)
+
+#define PLT_MASK        (0x03 << 6)
+#define PLT_SYM         (0x00 << 6)
+#define PLT_ASYM_RX     (0x02 << 6)
+#define PLT_ASYM_TX     (0x03 << 6)
+
 /**
  * struct xhci_container_ctx
  * @type: Type of context.  Used to calculated offsets to contained contexts.
@@ -1443,6 +1457,14 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd)
                return 1;
 }
 
+struct xhci_hub {
+       u8      maj_rev;
+       u8      min_rev;
+       u32     *psi;           /* array of protocol speed ID entries */
+       u8      psi_count;
+       u8      psi_uid_count;
+};
+
 /* There is one xhci_hcd structure per controller */
 struct xhci_hcd {
        struct usb_hcd *main_hcd;
@@ -1584,6 +1606,8 @@ struct xhci_hcd {
        unsigned int            num_usb3_ports;
        /* Array of pointers to USB 2.0 PORTSC registers */
        __le32 __iomem          **usb2_ports;
+       struct xhci_hub         usb2_rhub;
+       struct xhci_hub         usb3_rhub;
        unsigned int            num_usb2_ports;
        /* support xHCI 0.96 spec USB2 software LPM */
        unsigned                sw_lpm_support:1;
-- 
1.9.1

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to