]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[xhci] Enable USB3 ports on Intel PCH8/PCH9 controllers
authorMichael Brown <mcb30@ipxe.org>
Fri, 6 Mar 2015 11:41:37 +0000 (11:41 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 6 Mar 2015 11:58:14 +0000 (11:58 +0000)
Intel PCH controllers default to routing USB2 ports to EHCI rather
than xHCI, and default to disabling SuperSpeed connections.
Manipulate the PCI configuration space registers as necessary to
reroute ports and enable SuperSpeed.

Originally-fixed-by: Dan Ellis <Dan.Ellis@displaylink.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/usb/xhci.c
src/drivers/usb/xhci.h

index 36dfacc2dd422fe2a957632949faad460238e629..5d4cb15182c7236e6f8cc2fdd36ce2bef89561f4 100644 (file)
@@ -3013,6 +3013,41 @@ static struct usb_host_operations xhci_operations = {
        },
 };
 
+/**
+ * Fix Intel PCH-specific quirks
+ *
+ * @v xhci             xHCI device
+ * @v pci              PCI device
+ */
+static void xhci_pch ( struct xhci_device *xhci, struct pci_device *pci ) {
+       uint32_t xusb2pr;
+       uint32_t xusb2prm;
+       uint32_t usb3pssen;
+       uint32_t usb3prm;
+
+       /* Enable SuperSpeed capability.  Do this before rerouting
+        * USB2 ports, so that USB3 devices connect at SuperSpeed.
+        */
+       pci_read_config_dword ( pci, XHCI_PCH_USB3PSSEN, &usb3pssen );
+       pci_read_config_dword ( pci, XHCI_PCH_USB3PRM, &usb3prm );
+       if ( usb3prm & ~usb3pssen ) {
+               DBGC ( xhci, "XHCI %p enabling SuperSpeed on ports %08x\n",
+                      xhci, ( usb3prm & ~usb3pssen ) );
+       }
+       usb3pssen |= usb3prm;
+       pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, usb3pssen );
+
+       /* Route USB2 ports from EHCI to xHCI */
+       pci_read_config_dword ( pci, XHCI_PCH_XUSB2PR, &xusb2pr );
+       pci_read_config_dword ( pci, XHCI_PCH_XUSB2PRM, &xusb2prm );
+       if ( xusb2prm & ~xusb2pr ) {
+               DBGC ( xhci, "XHCI %p routing ports %08x from EHCI to xHCI\n",
+                      xhci, ( xusb2prm & ~xusb2pr ) );
+       }
+       xusb2pr |= xusb2prm;
+       pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, xusb2pr );
+}
+
 /**
  * Probe PCI device
  *
@@ -3054,6 +3089,10 @@ static int xhci_probe ( struct pci_device *pci ) {
        if ( ( rc = xhci_legacy_claim ( xhci ) ) != 0 )
                goto err_legacy_claim;
 
+       /* Fix Intel PCH-specific quirks, if applicable */
+       if ( pci->id->driver_data & XHCI_PCH )
+               xhci_pch ( xhci, pci );
+
        /* Reset device */
        if ( ( rc = xhci_reset ( xhci ) ) != 0 )
                goto err_reset;
@@ -3115,6 +3154,7 @@ static void xhci_remove ( struct pci_device *pci ) {
 
 /** XHCI PCI device IDs */
 static struct pci_device_id xhci_ids[] = {
+       PCI_ROM ( 0x8086, 0xffff, "xhci-pch", "xHCI (Intel PCH)", XHCI_PCH ),
        PCI_ROM ( 0xffff, 0xffff, "xhci", "xHCI", 0 ),
 };
 
index d0effe43b4eb920662c1e086acfe5c8080ee1b68..d7bfff1690662ffe56775c78f2139302d9cdcabc 100644 (file)
@@ -1103,4 +1103,19 @@ struct xhci_endpoint {
        struct xhci_trb_ring ring;
 };
 
+/** Intel PCH quirk */
+#define XHCI_PCH 0x0001
+
+/** Intel PCH USB2 port routing register */
+#define XHCI_PCH_XUSB2PR 0xd0
+
+/** Intel PCH USB2 port routing mask register */
+#define XHCI_PCH_XUSB2PRM 0xd4
+
+/** Intel PCH USB3 port SuperSpeed enable register */
+#define XHCI_PCH_USB3PSSEN 0xd8
+
+/** Intel PCH USB3 port routing mask register */
+#define XHCI_PCH_USB3PRM 0xdc
+
 #endif /* _IPXE_XHCI_H */