Intel xhci: Support EHCI/xHCI port switching.
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / usb / host / ehci-pci.c
index 07bb982..1102ce6 100644 (file)
@@ -44,42 +44,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
        return 0;
 }
 
-static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci)
-{
-       struct pci_dev *amd_smbus_dev;
-       u8 rev = 0;
-
-       amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
-       if (amd_smbus_dev) {
-               pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
-               if (rev < 0x40) {
-                       pci_dev_put(amd_smbus_dev);
-                       amd_smbus_dev = NULL;
-                       return 0;
-               }
-       } else {
-               amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL);
-               if (!amd_smbus_dev)
-                       return 0;
-               pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
-               if (rev < 0x11 || rev > 0x18) {
-                       pci_dev_put(amd_smbus_dev);
-                       amd_smbus_dev = NULL;
-                       return 0;
-               }
-       }
-
-       if (!amd_nb_dev)
-               amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
-
-       ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n");
-
-       pci_dev_put(amd_smbus_dev);
-       amd_smbus_dev = NULL;
-
-       return 1;
-}
-
 /* called during probe() after chip reset completes */
 static int ehci_pci_setup(struct usb_hcd *hcd)
 {
@@ -106,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");
@@ -138,9 +102,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
-       if (ehci_quirk_amd_hudson(ehci))
-               ehci->amd_l1_fix = 1;
-
        retval = ehci_halt(ehci);
        if (retval)
                return retval;
@@ -191,6 +152,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                }
                break;
        case PCI_VENDOR_ID_AMD:
+               /* AMD PLL quirk */
+               if (usb_amd_find_chipset_info())
+                       ehci->amd_pll_fix = 1;
                /* AMD8111 EHCI doesn't work, according to AMD errata */
                if (pdev->device == 0x7463) {
                        ehci_info(ehci, "ignoring AMD8111 (errata)\n");
@@ -236,6 +200,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                }
                break;
        case PCI_VENDOR_ID_ATI:
+               /* AMD PLL quirk */
+               if (usb_amd_find_chipset_info())
+                       ehci->amd_pll_fix = 1;
                /* SB600 and old version of SB700 have a bug in EHCI controller,
                 * which causes usb devices lose response in some cases.
                 */
@@ -381,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))