aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/pci-quirks.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
-rw-r--r--drivers/usb/host/pci-quirks.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index fd930618c28f..a9d315906e3d 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -35,6 +35,8 @@
35#define OHCI_INTRSTATUS 0x0c 35#define OHCI_INTRSTATUS 0x0c
36#define OHCI_INTRENABLE 0x10 36#define OHCI_INTRENABLE 0x10
37#define OHCI_INTRDISABLE 0x14 37#define OHCI_INTRDISABLE 0x14
38#define OHCI_FMINTERVAL 0x34
39#define OHCI_HCR (1 << 0) /* host controller reset */
38#define OHCI_OCR (1 << 3) /* ownership change request */ 40#define OHCI_OCR (1 << 3) /* ownership change request */
39#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ 41#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
40#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ 42#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
@@ -497,6 +499,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
497 499
498 /* reset controller, preserving RWC (and possibly IR) */ 500 /* reset controller, preserving RWC (and possibly IR) */
499 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); 501 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
502 readl(base + OHCI_CONTROL);
503
504 /* Some NVIDIA controllers stop working if kept in RESET for too long */
505 if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
506 u32 fminterval;
507 int cnt;
508
509 /* drive reset for at least 50 ms (7.1.7.5) */
510 msleep(50);
511
512 /* software reset of the controller, preserving HcFmInterval */
513 fminterval = readl(base + OHCI_FMINTERVAL);
514 writel(OHCI_HCR, base + OHCI_CMDSTATUS);
515
516 /* reset requires max 10 us delay */
517 for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
518 if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
519 break;
520 udelay(1);
521 }
522 writel(fminterval, base + OHCI_FMINTERVAL);
523
524 /* Now we're in the SUSPEND state with all devices reset
525 * and wakeups and interrupts disabled
526 */
527 }
500 528
501 /* 529 /*
502 * disable interrupts 530 * disable interrupts
@@ -507,20 +535,34 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
507 iounmap(base); 535 iounmap(base);
508} 536}
509 537
538static const struct dmi_system_id __initconst ehci_dmi_nohandoff_table[] = {
539 {
540 /* Pegatron Lucid (ExoPC) */
541 .matches = {
542 DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"),
543 DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"),
544 },
545 },
546 {
547 /* Pegatron Lucid (Ordissimo AIRIS) */
548 .matches = {
549 DMI_MATCH(DMI_BOARD_NAME, "M11JB"),
550 DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"),
551 },
552 },
553 { }
554};
555
510static void __devinit ehci_bios_handoff(struct pci_dev *pdev, 556static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
511 void __iomem *op_reg_base, 557 void __iomem *op_reg_base,
512 u32 cap, u8 offset) 558 u32 cap, u8 offset)
513{ 559{
514 int try_handoff = 1, tried_handoff = 0; 560 int try_handoff = 1, tried_handoff = 0;
515 561
516 /* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90 562 /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
517 * seconds trying the handoff on its unused controller. Skip 563 * the handoff on its unused controller. Skip it. */
518 * it. */
519 if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { 564 if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
520 const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME); 565 if (dmi_check_system(ehci_dmi_nohandoff_table))
521 const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION);
522 if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") &&
523 dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133"))
524 try_handoff = 0; 566 try_handoff = 0;
525 } 567 }
526 568