summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb/xhci.c
diff options
context:
space:
mode:
authorMichael Brown2015-03-06 12:41:37 +0100
committerMichael Brown2015-03-06 12:58:14 +0100
commitff320404d5a7d608a0d5df435f4d930c414e2348 (patch)
treea024158796ece778a31c5208fe885e7e9a778ee5 /src/drivers/usb/xhci.c
parent[legal] Relicense files under GPL2_OR_LATER_OR_UBDL (diff)
downloadipxe-ff320404d5a7d608a0d5df435f4d930c414e2348.tar.gz
ipxe-ff320404d5a7d608a0d5df435f4d930c414e2348.tar.xz
ipxe-ff320404d5a7d608a0d5df435f4d930c414e2348.zip
[xhci] Enable USB3 ports on Intel PCH8/PCH9 controllers
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>
Diffstat (limited to 'src/drivers/usb/xhci.c')
-rw-r--r--src/drivers/usb/xhci.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c
index 36dfacc2..5d4cb151 100644
--- a/src/drivers/usb/xhci.c
+++ b/src/drivers/usb/xhci.c
@@ -3014,6 +3014,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
*
* @v pci 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 ),
};