diff options
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index b5a7304fcbef..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 |