Merge branch 'usb-next' into musb-merge
[firefly-linux-kernel-4.4.55.git] / drivers / usb / host / ehci-pci.c
index a1e8d273103f77b2d237a5f68438b289b51bb92a..76179c39c0e3490b0a5e9240619b9e4ba18affb9 100644 (file)
@@ -22,6 +22,9 @@
 #error "This file is PCI bus glue.  CONFIG_PCI must be defined."
 #endif
 
+/* defined here to avoid adding to pci_ids.h for single instance use */
+#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
+
 /*-------------------------------------------------------------------------*/
 
 /* called after powerup, by probe or system-pm "wakeup" */
@@ -41,6 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
        return 0;
 }
 
+static int ehci_quirk_amd_SB800(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)
+               return 0;
+
+       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;
+       }
+
+       if (!amd_nb_dev)
+               amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
+       if (!amd_nb_dev)
+               ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
+
+       ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\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)
 {
@@ -99,10 +131,26 @@ 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_SB800(ehci))
+               ehci->amd_l1_fix = 1;
+
        retval = ehci_halt(ehci);
        if (retval)
                return retval;
 
+       if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
+           (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
+               /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+                * read/write memory space which does not belong to it when
+                * there is NULL pointer with T-bit set to 1 in the frame list
+                * table. To avoid the issue, the frame list link pointer
+                * should always contain a valid pointer to a inactive qh.
+                */
+               ehci->use_dummy_qh = 1;
+               ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
+                               "dummy qh workaround\n");
+       }
+
        /* data structure init */
        retval = ehci_init(hcd);
        if (retval)
@@ -124,6 +172,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                        ehci_info(ehci, "disable lpm for langwell/penwell\n");
                        ehci->has_lpm = 0;
                }
+               if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
+                       hcd->has_tt = 1;
+                       tdi_reset(ehci);
+               }
                break;
        case PCI_VENDOR_ID_TDI:
                if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
@@ -148,6 +200,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                        if (pdev->revision < 0xa4)
                                ehci->no_selective_suspend = 1;
                        break;
+
+               /* MCP89 chips on the MacBookAir3,1 give EPROTO when
+                * fetching device descriptors unless LPM is disabled.
+                * There are also intermittent problems enumerating
+                * devices with PPCD enabled.
+                */
+               case 0x0d9d:
+                       ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+                       ehci->has_lpm = 0;
+                       ehci->has_ppcd = 0;
+                       ehci->command &= ~CMD_PPCEE;
+                       break;
                }
                break;
        case PCI_VENDOR_ID_VIA: