diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index ce5c9e51748..c7f33123d4c 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -65,6 +65,12 @@ /* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ #define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) +/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */ +#define XHCI_L1C (1 << 16) + +/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */ +#define XHCI_HLC (1 << 19) + /* command register values to disable interrupts and halt the HC */ /* start/stop HC execution - do not write unless HC is halted*/ #define XHCI_CMD_RUN (1 << 0) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index bc6ec0cb3c6..9c7ddf0f3a4 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1959,6 +1959,23 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ return; + + /* Check the host's USB2 LPM capability */ + if ((xhci->hci_version == 0x96) && (major_revision != 0x03) && + (temp & XHCI_L1C)) { + xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n"); + xhci->sw_lpm_support = 1; + } + + if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) { + xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n"); + xhci->sw_lpm_support = 1; + if (temp & XHCI_HLC) { + xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n"); + xhci->hw_lpm_support = 1; + } + } + port_offset--; for (i = port_offset; i < (port_offset + port_count); i++) { /* Duplicate entry. Ignore the port if the revisions differ. */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index fa921cbbe87..8673f985046 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1459,6 +1459,10 @@ struct xhci_hcd { /* Array of pointers to USB 2.0 PORTSC registers */ __le32 __iomem **usb2_ports; unsigned int num_usb2_ports; + /* support xHCI 0.96 spec USB2 software LPM */ + unsigned sw_lpm_support:1; + /* support xHCI 1.0 spec USB2 hardware LPM */ + unsigned hw_lpm_support:1; }; /* convert between an HCD pointer and the corresponding EHCI_HCD */