|
@@ -37,6 +37,7 @@
|
|
|
#define OHCI_INTRENABLE 0x10
|
|
|
#define OHCI_INTRDISABLE 0x14
|
|
|
#define OHCI_FMINTERVAL 0x34
|
|
|
+#define OHCI_HCFS (3 << 6) /* hc functional state */
|
|
|
#define OHCI_HCR (1 << 0) /* host controller reset */
|
|
|
#define OHCI_OCR (1 << 3) /* ownership change request */
|
|
|
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
|
|
@@ -466,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
|
|
{
|
|
|
void __iomem *base;
|
|
|
u32 control;
|
|
|
+ u32 fminterval;
|
|
|
+ int cnt;
|
|
|
|
|
|
if (!mmio_resource_enabled(pdev, 0))
|
|
|
return;
|
|
@@ -498,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- /* reset controller, preserving RWC (and possibly IR) */
|
|
|
- writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
|
|
|
- readl(base + OHCI_CONTROL);
|
|
|
+ /* disable interrupts */
|
|
|
+ writel((u32) ~0, base + OHCI_INTRDISABLE);
|
|
|
|
|
|
- /* Some NVIDIA controllers stop working if kept in RESET for too long */
|
|
|
- if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
|
|
|
- u32 fminterval;
|
|
|
- int cnt;
|
|
|
+ /* Reset the USB bus, if the controller isn't already in RESET */
|
|
|
+ if (control & OHCI_HCFS) {
|
|
|
+ /* Go into RESET, preserving RWC (and possibly IR) */
|
|
|
+ writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
|
|
|
+ readl(base + OHCI_CONTROL);
|
|
|
|
|
|
- /* drive reset for at least 50 ms (7.1.7.5) */
|
|
|
+ /* drive bus reset for at least 50 ms (7.1.7.5) */
|
|
|
msleep(50);
|
|
|
+ }
|
|
|
|
|
|
- /* software reset of the controller, preserving HcFmInterval */
|
|
|
- fminterval = readl(base + OHCI_FMINTERVAL);
|
|
|
- writel(OHCI_HCR, base + OHCI_CMDSTATUS);
|
|
|
+ /* software reset of the controller, preserving HcFmInterval */
|
|
|
+ fminterval = readl(base + OHCI_FMINTERVAL);
|
|
|
+ writel(OHCI_HCR, base + OHCI_CMDSTATUS);
|
|
|
|
|
|
- /* reset requires max 10 us delay */
|
|
|
- for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
|
|
|
- if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
|
|
|
- break;
|
|
|
- udelay(1);
|
|
|
- }
|
|
|
- writel(fminterval, base + OHCI_FMINTERVAL);
|
|
|
-
|
|
|
- /* Now we're in the SUSPEND state with all devices reset
|
|
|
- * and wakeups and interrupts disabled
|
|
|
- */
|
|
|
+ /* reset requires max 10 us delay */
|
|
|
+ for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
|
|
|
+ if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
|
|
|
+ break;
|
|
|
+ udelay(1);
|
|
|
}
|
|
|
+ writel(fminterval, base + OHCI_FMINTERVAL);
|
|
|
|
|
|
- /*
|
|
|
- * disable interrupts
|
|
|
- */
|
|
|
- writel(~(u32)0, base + OHCI_INTRDISABLE);
|
|
|
- writel(~(u32)0, base + OHCI_INTRSTATUS);
|
|
|
-
|
|
|
+ /* Now the controller is safely in SUSPEND and nothing can wake it up */
|
|
|
iounmap(base);
|
|
|
}
|
|
|
|