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.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index fd930618c28..23e04fb038b 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -35,6 +35,9 @@
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_HCFS (3 << 6) /* hc functional state */
40#define OHCI_HCR (1 << 0) /* host controller reset */
38#define OHCI_OCR (1 << 3) /* ownership change request */ 41#define OHCI_OCR (1 << 3) /* ownership change request */
39#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ 42#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
40#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ 43#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
@@ -463,6 +466,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
463{ 466{
464 void __iomem *base; 467 void __iomem *base;
465 u32 control; 468 u32 control;
469 u32 fminterval;
470 int cnt;
466 471
467 if (!mmio_resource_enabled(pdev, 0)) 472 if (!mmio_resource_enabled(pdev, 0))
468 return; 473 return;
@@ -495,32 +500,63 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
495 } 500 }
496#endif 501#endif
497 502
498 /* reset controller, preserving RWC (and possibly IR) */ 503 /* disable interrupts */
499 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); 504 writel((u32) ~0, base + OHCI_INTRDISABLE);
500 505
501 /* 506 /* Reset the USB bus, if the controller isn't already in RESET */
502 * disable interrupts 507 if (control & OHCI_HCFS) {
503 */ 508 /* Go into RESET, preserving RWC (and possibly IR) */
504 writel(~(u32)0, base + OHCI_INTRDISABLE); 509 writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
505 writel(~(u32)0, base + OHCI_INTRSTATUS); 510 readl(base + OHCI_CONTROL);
511
512 /* drive bus reset for at least 50 ms (7.1.7.5) */
513 msleep(50);
514 }
515
516 /* software reset of the controller, preserving HcFmInterval */
517 fminterval = readl(base + OHCI_FMINTERVAL);
518 writel(OHCI_HCR, base + OHCI_CMDSTATUS);
506 519
520 /* reset requires max 10 us delay */
521 for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
522 if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
523 break;
524 udelay(1);
525 }
526 writel(fminterval, base + OHCI_FMINTERVAL);
527
528 /* Now the controller is safely in SUSPEND and nothing can wake it up */
507 iounmap(base); 529 iounmap(base);
508} 530}
509 531
532static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
533 {
534 /* Pegatron Lucid (ExoPC) */
535 .matches = {
536 DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"),
537 DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"),
538 },
539 },
540 {
541 /* Pegatron Lucid (Ordissimo AIRIS) */
542 .matches = {
543 DMI_MATCH(DMI_BOARD_NAME, "M11JB"),
544 DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"),
545 },
546 },
547 { }
548};
549
510static void __devinit ehci_bios_handoff(struct pci_dev *pdev, 550static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
511 void __iomem *op_reg_base, 551 void __iomem *op_reg_base,
512 u32 cap, u8 offset) 552 u32 cap, u8 offset)
513{ 553{
514 int try_handoff = 1, tried_handoff = 0; 554 int try_handoff = 1, tried_handoff = 0;
515 555
516 /* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90 556 /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
517 * seconds trying the handoff on its unused controller. Skip 557 * the handoff on its unused controller. Skip it. */
518 * it. */
519 if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { 558 if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
520 const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME); 559 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; 560 try_handoff = 0;
525 } 561 }
526 562
@@ -584,7 +620,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
584 void __iomem *base, *op_reg_base; 620 void __iomem *base, *op_reg_base;
585 u32 hcc_params, cap, val; 621 u32 hcc_params, cap, val;
586 u8 offset, cap_length; 622 u8 offset, cap_length;
587 int wait_time, delta, count = 256/4; 623 int wait_time, count = 256/4;
588 624
589 if (!mmio_resource_enabled(pdev, 0)) 625 if (!mmio_resource_enabled(pdev, 0))
590 return; 626 return;
@@ -630,11 +666,10 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
630 writel(val, op_reg_base + EHCI_USBCMD); 666 writel(val, op_reg_base + EHCI_USBCMD);
631 667
632 wait_time = 2000; 668 wait_time = 2000;
633 delta = 100;
634 do { 669 do {
635 writel(0x3f, op_reg_base + EHCI_USBSTS); 670 writel(0x3f, op_reg_base + EHCI_USBSTS);
636 udelay(delta); 671 udelay(100);
637 wait_time -= delta; 672 wait_time -= 100;
638 val = readl(op_reg_base + EHCI_USBSTS); 673 val = readl(op_reg_base + EHCI_USBSTS);
639 if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { 674 if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
640 break; 675 break;
@@ -775,7 +810,7 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
775 810
776 /* If the BIOS owns the HC, signal that the OS wants it, and wait */ 811 /* If the BIOS owns the HC, signal that the OS wants it, and wait */
777 if (val & XHCI_HC_BIOS_OWNED) { 812 if (val & XHCI_HC_BIOS_OWNED) {
778 writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset); 813 writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
779 814
780 /* Wait for 5 seconds with 10 microsecond polling interval */ 815 /* Wait for 5 seconds with 10 microsecond polling interval */
781 timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED, 816 timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,