diff options
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 58 |
1 files changed, 26 insertions, 32 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 629a96813fd..caf87428ca4 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/pci.h> | 13 | #include <linux/pci.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/export.h> | ||
16 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
17 | #include <linux/dmi.h> | 18 | #include <linux/dmi.h> |
18 | #include "pci-quirks.h" | 19 | #include "pci-quirks.h" |
@@ -36,6 +37,7 @@ | |||
36 | #define OHCI_INTRENABLE 0x10 | 37 | #define OHCI_INTRENABLE 0x10 |
37 | #define OHCI_INTRDISABLE 0x14 | 38 | #define OHCI_INTRDISABLE 0x14 |
38 | #define OHCI_FMINTERVAL 0x34 | 39 | #define OHCI_FMINTERVAL 0x34 |
40 | #define OHCI_HCFS (3 << 6) /* hc functional state */ | ||
39 | #define OHCI_HCR (1 << 0) /* host controller reset */ | 41 | #define OHCI_HCR (1 << 0) /* host controller reset */ |
40 | #define OHCI_OCR (1 << 3) /* ownership change request */ | 42 | #define OHCI_OCR (1 << 3) /* ownership change request */ |
41 | #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ | 43 | #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ |
@@ -465,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
465 | { | 467 | { |
466 | void __iomem *base; | 468 | void __iomem *base; |
467 | u32 control; | 469 | u32 control; |
470 | u32 fminterval; | ||
471 | int cnt; | ||
468 | 472 | ||
469 | if (!mmio_resource_enabled(pdev, 0)) | 473 | if (!mmio_resource_enabled(pdev, 0)) |
470 | return; | 474 | return; |
@@ -497,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
497 | } | 501 | } |
498 | #endif | 502 | #endif |
499 | 503 | ||
500 | /* reset controller, preserving RWC (and possibly IR) */ | 504 | /* disable interrupts */ |
501 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); | 505 | writel((u32) ~0, base + OHCI_INTRDISABLE); |
502 | readl(base + OHCI_CONTROL); | ||
503 | 506 | ||
504 | /* Some NVIDIA controllers stop working if kept in RESET for too long */ | 507 | /* Reset the USB bus, if the controller isn't already in RESET */ |
505 | if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { | 508 | if (control & OHCI_HCFS) { |
506 | u32 fminterval; | 509 | /* Go into RESET, preserving RWC (and possibly IR) */ |
507 | int cnt; | 510 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); |
511 | readl(base + OHCI_CONTROL); | ||
508 | 512 | ||
509 | /* drive reset for at least 50 ms (7.1.7.5) */ | 513 | /* drive bus reset for at least 50 ms (7.1.7.5) */ |
510 | msleep(50); | 514 | msleep(50); |
515 | } | ||
511 | 516 | ||
512 | /* software reset of the controller, preserving HcFmInterval */ | 517 | /* software reset of the controller, preserving HcFmInterval */ |
513 | fminterval = readl(base + OHCI_FMINTERVAL); | 518 | fminterval = readl(base + OHCI_FMINTERVAL); |
514 | writel(OHCI_HCR, base + OHCI_CMDSTATUS); | 519 | writel(OHCI_HCR, base + OHCI_CMDSTATUS); |
515 | 520 | ||
516 | /* reset requires max 10 us delay */ | 521 | /* reset requires max 10 us delay */ |
517 | for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ | 522 | for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ |
518 | if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) | 523 | if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) |
519 | break; | 524 | break; |
520 | udelay(1); | 525 | 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 | } | 526 | } |
527 | writel(fminterval, base + OHCI_FMINTERVAL); | ||
528 | 528 | ||
529 | /* | 529 | /* Now the controller is safely in SUSPEND and nothing can wake it up */ |
530 | * disable interrupts | ||
531 | */ | ||
532 | writel(~(u32)0, base + OHCI_INTRDISABLE); | ||
533 | writel(~(u32)0, base + OHCI_INTRSTATUS); | ||
534 | |||
535 | iounmap(base); | 530 | iounmap(base); |
536 | } | 531 | } |
537 | 532 | ||
@@ -626,7 +621,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) | |||
626 | void __iomem *base, *op_reg_base; | 621 | void __iomem *base, *op_reg_base; |
627 | u32 hcc_params, cap, val; | 622 | u32 hcc_params, cap, val; |
628 | u8 offset, cap_length; | 623 | u8 offset, cap_length; |
629 | int wait_time, delta, count = 256/4; | 624 | int wait_time, count = 256/4; |
630 | 625 | ||
631 | if (!mmio_resource_enabled(pdev, 0)) | 626 | if (!mmio_resource_enabled(pdev, 0)) |
632 | return; | 627 | return; |
@@ -672,11 +667,10 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) | |||
672 | writel(val, op_reg_base + EHCI_USBCMD); | 667 | writel(val, op_reg_base + EHCI_USBCMD); |
673 | 668 | ||
674 | wait_time = 2000; | 669 | wait_time = 2000; |
675 | delta = 100; | ||
676 | do { | 670 | do { |
677 | writel(0x3f, op_reg_base + EHCI_USBSTS); | 671 | writel(0x3f, op_reg_base + EHCI_USBSTS); |
678 | udelay(delta); | 672 | udelay(100); |
679 | wait_time -= delta; | 673 | wait_time -= 100; |
680 | val = readl(op_reg_base + EHCI_USBSTS); | 674 | val = readl(op_reg_base + EHCI_USBSTS); |
681 | if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { | 675 | if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { |
682 | break; | 676 | break; |