OHCI: add a quirk for ULi M5237 blocking on reset
[pandora-kernel.git] / drivers / usb / host / pci-quirks.c
index caf8742..d5cb148 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/kconfig.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -74,7 +75,9 @@
 #define        NB_PIF0_PWRDOWN_1       0x01100013
 
 #define USB_INTEL_XUSB2PR      0xD0
+#define USB_INTEL_USB2PRM      0xD4
 #define USB_INTEL_USB3_PSSEN   0xD8
+#define USB_INTEL_USB3PRM      0xDC
 
 static struct amd_chipset_info {
        struct pci_dev  *nb_dev;
@@ -467,7 +470,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
 {
        void __iomem *base;
        u32 control;
-       u32 fminterval;
+       u32 fminterval = 0;
+       bool no_fminterval = false;
        int cnt;
 
        if (!mmio_resource_enabled(pdev, 0))
@@ -477,6 +481,13 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
        if (base == NULL)
                return;
 
+       /*
+        * ULi M5237 OHCI controller locks the whole system when accessing
+        * the OHCI_FMINTERVAL offset.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_AL && pdev->device == 0x5237)
+               no_fminterval = true;
+
        control = readl(base + OHCI_CONTROL);
 
 /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
@@ -515,7 +526,9 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
        }
 
        /* software reset of the controller, preserving HcFmInterval */
-       fminterval = readl(base + OHCI_FMINTERVAL);
+       if (!no_fminterval)
+               fminterval = readl(base + OHCI_FMINTERVAL);
+
        writel(OHCI_HCR, base + OHCI_CMDSTATUS);
 
        /* reset requires max 10 us delay */
@@ -524,7 +537,9 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
                        break;
                udelay(1);
        }
-       writel(fminterval, base + OHCI_FMINTERVAL);
+
+       if (!no_fminterval)
+               writel(fminterval, base + OHCI_FMINTERVAL);
 
        /* Now the controller is safely in SUSPEND and nothing can wake it up */
        iounmap(base);
@@ -542,7 +557,22 @@ static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
                /*  Pegatron Lucid (Ordissimo AIRIS) */
                .matches = {
                        DMI_MATCH(DMI_BOARD_NAME, "M11JB"),
-                       DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"),
+               },
+       },
+       {
+               /*  Pegatron Lucid (Ordissimo) */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "Ordissimo"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"),
+               },
+       },
+       {
+               /* HASEE E200 */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "HASEE"),
+                       DMI_MATCH(DMI_BOARD_NAME, "E210"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "6.00"),
                },
        },
        { }
@@ -554,9 +584,14 @@ static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
 {
        int try_handoff = 1, tried_handoff = 0;
 
-       /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
-        * the handoff on its unused controller.  Skip it. */
-       if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
+       /*
+        * The Pegatron Lucid tablet sporadically waits for 98 seconds trying
+        * the handoff on its unused controller.  Skip it.
+        *
+        * The HASEE E200 hangs when the semaphore is set (bugzilla #77021).
+        */
+       if (pdev->vendor == 0x8086 && (pdev->device == 0x283a ||
+                       pdev->device == 0x27cc)) {
                if (dmi_check_system(ehci_dmi_nohandoff_table))
                        try_handoff = 0;
        }
@@ -712,12 +747,30 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
        return -ETIMEDOUT;
 }
 
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI    0x8C31
+#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31
+
+bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
 {
        return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
                pdev->vendor == PCI_VENDOR_ID_INTEL &&
                pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
 }
+
+/* The Intel Lynx Point chipset also has switchable ports. */
+bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
+{
+       return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
+               pdev->vendor == PCI_VENDOR_ID_INTEL &&
+               (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI);
+}
+
+bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+{
+       return usb_is_intel_ppt_switchable_xhci(pdev) ||
+               usb_is_intel_lpt_switchable_xhci(pdev);
+}
 EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
 
 /*
@@ -742,10 +795,32 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
 {
        u32             ports_available;
 
-       ports_available = 0xffffffff;
+       /* Don't switchover the ports if the user hasn't compiled the xHCI
+        * driver.  Otherwise they will see "dead" USB ports that don't power
+        * the devices.
+        */
+       if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
+               dev_warn(&xhci_pdev->dev,
+                               "CONFIG_USB_XHCI_HCD is turned off, "
+                               "defaulting to EHCI.\n");
+               dev_warn(&xhci_pdev->dev,
+                               "USB 3.0 devices will work at USB 2.0 speeds.\n");
+               usb_disable_xhci_ports(xhci_pdev);
+               return;
+       }
+
+       /* Read USB3PRM, the USB 3.0 Port Routing Mask Register
+        * Indicate the ports that can be changed from OS.
+        */
+       pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM,
+                       &ports_available);
+
+       dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n",
+                       ports_available);
+
        /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
-        * Register, to turn on SuperSpeed terminations for all
-        * available ports.
+        * Register, to turn on SuperSpeed terminations for the
+        * switchable ports.
         */
        pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
                        cpu_to_le32(ports_available));
@@ -755,7 +830,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
        dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
                        "under xHCI: 0x%x\n", ports_available);
 
-       ports_available = 0xffffffff;
+       /* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register
+        * Indicate the USB 2.0 ports to be controlled by the xHCI host.
+        */
+
+       pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM,
+                       &ports_available);
+
+       dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n",
+                       ports_available);
+
        /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to
         * switch the USB 2.0 power and data lines over to the xHCI
         * host.
@@ -770,6 +854,13 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
 }
 EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
 
+void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
+{
+       pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, 0x0);
+       pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, 0x0);
+}
+EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
+
 /**
  * PCI Quirks for xHCI.
  *
@@ -785,12 +876,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
        void __iomem *op_reg_base;
        u32 val;
        int timeout;
+       int len = pci_resource_len(pdev, 0);
 
        if (!mmio_resource_enabled(pdev, 0))
                return;
 
-       base = ioremap_nocache(pci_resource_start(pdev, 0),
-                               pci_resource_len(pdev, 0));
+       base = ioremap_nocache(pci_resource_start(pdev, 0), len);
        if (base == NULL)
                return;
 
@@ -800,9 +891,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
         */
        ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
        do {
+               if ((ext_cap_offset + sizeof(val)) > len) {
+                       /* We're reading garbage from the controller */
+                       dev_warn(&pdev->dev,
+                                "xHCI controller failing to respond");
+                       return;
+               }
+
                if (!ext_cap_offset)
                        /* We've reached the end of the extended capabilities */
                        goto hc_init;
+
                val = readl(base + ext_cap_offset);
                if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
                        break;
@@ -825,13 +924,18 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
                }
        }
 
-       /* Disable any BIOS SMIs */
-       writel(XHCI_LEGACY_DISABLE_SMI,
-                       base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
+       val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
+       /* Mask off (turn off) any enabled SMIs */
+       val &= XHCI_LEGACY_DISABLE_SMI;
+       /* Mask all SMI events bits, RW1C */
+       val |= XHCI_LEGACY_SMI_EVENTS;
+       /* Disable any BIOS SMIs and clear all SMI events*/
+       writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
 
+hc_init:
        if (usb_is_intel_switchable_xhci(pdev))
                usb_enable_xhci_ports(pdev);
-hc_init:
+
        op_reg_base = base + XHCI_HC_LENGTH(readl(base));
 
        /* Wait for the host controller to be ready before writing any
@@ -867,6 +971,22 @@ hc_init:
 
 static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
 {
+       /* Skip Netlogic mips SoC's internal PCI USB controller.
+        * This device does not need/support EHCI/OHCI handoff
+        */
+       if (pdev->vendor == 0x184e)     /* vendor Netlogic */
+               return;
+       if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI &&
+                       pdev->class != PCI_CLASS_SERIAL_USB_OHCI &&
+                       pdev->class != PCI_CLASS_SERIAL_USB_EHCI &&
+                       pdev->class != PCI_CLASS_SERIAL_USB_XHCI)
+               return;
+
+       if (pci_enable_device(pdev) < 0) {
+               dev_warn(&pdev->dev, "Can't enable PCI device, "
+                               "BIOS handoff failed.\n");
+               return;
+       }
        if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
                quirk_usb_handoff_uhci(pdev);
        else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
@@ -875,5 +995,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
                quirk_usb_disable_ehci(pdev);
        else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
                quirk_usb_handoff_xhci(pdev);
+       pci_disable_device(pdev);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);