Intel xhci: Support EHCI/xHCI port switching.
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / usb / host / ehci-pci.c
index d5eaea7..1102ce6 100644 (file)
@@ -70,7 +70,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
@@ -348,11 +348,50 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
        return rc;
 }
 
+static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
+{
+       return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
+               pdev->vendor == PCI_VENDOR_ID_INTEL &&
+               pdev->device == 0x1E26;
+}
+
+static void ehci_enable_xhci_companion(void)
+{
+       struct pci_dev          *companion = NULL;
+
+       /* The xHCI and EHCI controllers are not on the same PCI slot */
+       for_each_pci_dev(companion) {
+               if (!usb_is_intel_switchable_xhci(companion))
+                       continue;
+               usb_enable_xhci_ports(companion);
+               return;
+       }
+}
+
 static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
 
+       /* The BIOS on systems with the Intel Panther Point chipset may or may
+        * not support xHCI natively.  That means that during system resume, it
+        * may switch the ports back to EHCI so that users can use their
+        * keyboard to select a kernel from GRUB after resume from hibernate.
+        *
+        * The BIOS is supposed to remember whether the OS had xHCI ports
+        * enabled before resume, and switch the ports back to xHCI when the
+        * BIOS/OS semaphore is written, but we all know we can't trust BIOS
+        * writers.
+        *
+        * Unconditionally switch the ports back to xHCI after a system resume.
+        * We can't tell whether the EHCI or xHCI controller will be resumed
+        * first, so we have to do the port switchover in both drivers.  Writing
+        * a '1' to the port switchover registers should have no effect if the
+        * port was already switched over.
+        */
+       if (usb_is_intel_switchable_ehci(pdev))
+               ehci_enable_xhci_companion();
+
        // maybe restore FLADJ
 
        if (time_before(jiffies, ehci->next_statechange))