diff options
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 73 |
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 | ||
532 | static 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 | |||
510 | static void __devinit ehci_bios_handoff(struct pci_dev *pdev, | 550 | static 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, |