diff options
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 15 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-pci.c | 26 | ||||
| -rw-r--r-- | drivers/usb/host/ohci.h | 1 | ||||
| -rw-r--r-- | drivers/usb/host/pci-quirks.c | 50 |
4 files changed, 28 insertions, 64 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 34efd479e068..b2639191549e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
| @@ -389,17 +389,14 @@ ohci_shutdown (struct usb_hcd *hcd) | |||
| 389 | struct ohci_hcd *ohci; | 389 | struct ohci_hcd *ohci; |
| 390 | 390 | ||
| 391 | ohci = hcd_to_ohci (hcd); | 391 | ohci = hcd_to_ohci (hcd); |
| 392 | ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); | 392 | ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); |
| 393 | ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); | ||
| 394 | 393 | ||
| 395 | /* If the SHUTDOWN quirk is set, don't put the controller in RESET */ | 394 | /* Software reset, after which the controller goes into SUSPEND */ |
| 396 | ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ? | 395 | ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); |
| 397 | OHCI_CTRL_RWC | OHCI_CTRL_HCFS : | 396 | ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ |
| 398 | OHCI_CTRL_RWC); | 397 | udelay(10); |
| 399 | ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); | ||
| 400 | 398 | ||
| 401 | /* flush the writes */ | 399 | ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); |
| 402 | (void) ohci_readl (ohci, &ohci->regs->control); | ||
| 403 | } | 400 | } |
| 404 | 401 | ||
| 405 | static int check_ed(struct ohci_hcd *ohci, struct ed *ed) | 402 | static int check_ed(struct ohci_hcd *ohci, struct ed *ed) |
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ad8166c681e2..bc01b064585a 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c | |||
| @@ -175,28 +175,6 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) | |||
| 175 | return 0; | 175 | return 0; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | /* nVidia controllers continue to drive Reset signalling on the bus | ||
| 179 | * even after system shutdown, wasting power. This flag tells the | ||
| 180 | * shutdown routine to leave the controller OPERATIONAL instead of RESET. | ||
| 181 | */ | ||
| 182 | static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) | ||
| 183 | { | ||
| 184 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
| 185 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
| 186 | |||
| 187 | /* Evidently nVidia fixed their later hardware; this is a guess at | ||
| 188 | * the changeover point. | ||
| 189 | */ | ||
| 190 | #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d | ||
| 191 | |||
| 192 | if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { | ||
| 193 | ohci->flags |= OHCI_QUIRK_SHUTDOWN; | ||
| 194 | ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); | ||
| 195 | } | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void sb800_prefetch(struct ohci_hcd *ohci, int on) | 178 | static void sb800_prefetch(struct ohci_hcd *ohci, int on) |
| 201 | { | 179 | { |
| 202 | struct pci_dev *pdev; | 180 | struct pci_dev *pdev; |
| @@ -260,10 +238,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { | |||
| 260 | PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), | 238 | PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), |
| 261 | .driver_data = (unsigned long)ohci_quirk_amd700, | 239 | .driver_data = (unsigned long)ohci_quirk_amd700, |
| 262 | }, | 240 | }, |
| 263 | { | ||
| 264 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), | ||
| 265 | .driver_data = (unsigned long) ohci_quirk_nvidia_shutdown, | ||
| 266 | }, | ||
| 267 | 241 | ||
| 268 | /* FIXME for some of the early AMD 760 southbridges, OHCI | 242 | /* FIXME for some of the early AMD 760 southbridges, OHCI |
| 269 | * won't work at all. blacklist them. | 243 | * won't work at all. blacklist them. |
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 35e5fd640ce7..0795b934d00c 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h | |||
| @@ -403,7 +403,6 @@ struct ohci_hcd { | |||
| 403 | #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ | 403 | #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ |
| 404 | #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ | 404 | #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ |
| 405 | #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ | 405 | #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ |
| 406 | #define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ | ||
| 407 | // there are also chip quirks/bugs in init logic | 406 | // there are also chip quirks/bugs in init logic |
| 408 | 407 | ||
| 409 | struct work_struct nec_work; /* Worker for NEC quirk */ | 408 | struct work_struct nec_work; /* Worker for NEC quirk */ |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c7fd6ce11904..caf87428ca43 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #define OHCI_INTRENABLE 0x10 | 37 | #define OHCI_INTRENABLE 0x10 |
| 38 | #define OHCI_INTRDISABLE 0x14 | 38 | #define OHCI_INTRDISABLE 0x14 |
| 39 | #define OHCI_FMINTERVAL 0x34 | 39 | #define OHCI_FMINTERVAL 0x34 |
| 40 | #define OHCI_HCFS (3 << 6) /* hc functional state */ | ||
| 40 | #define OHCI_HCR (1 << 0) /* host controller reset */ | 41 | #define OHCI_HCR (1 << 0) /* host controller reset */ |
| 41 | #define OHCI_OCR (1 << 3) /* ownership change request */ | 42 | #define OHCI_OCR (1 << 3) /* ownership change request */ |
| 42 | #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ | 43 | #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ |
| @@ -466,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
| 466 | { | 467 | { |
| 467 | void __iomem *base; | 468 | void __iomem *base; |
| 468 | u32 control; | 469 | u32 control; |
| 470 | u32 fminterval; | ||
| 471 | int cnt; | ||
| 469 | 472 | ||
| 470 | if (!mmio_resource_enabled(pdev, 0)) | 473 | if (!mmio_resource_enabled(pdev, 0)) |
| 471 | return; | 474 | return; |
| @@ -498,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | |||
| 498 | } | 501 | } |
| 499 | #endif | 502 | #endif |
| 500 | 503 | ||
| 501 | /* reset controller, preserving RWC (and possibly IR) */ | 504 | /* disable interrupts */ |
| 502 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); | 505 | writel((u32) ~0, base + OHCI_INTRDISABLE); |
| 503 | readl(base + OHCI_CONTROL); | ||
| 504 | 506 | ||
| 505 | /* 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 */ |
| 506 | if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { | 508 | if (control & OHCI_HCFS) { |
| 507 | u32 fminterval; | 509 | /* Go into RESET, preserving RWC (and possibly IR) */ |
| 508 | int cnt; | 510 | writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); |
| 511 | readl(base + OHCI_CONTROL); | ||
| 509 | 512 | ||
| 510 | /* drive reset for at least 50 ms (7.1.7.5) */ | 513 | /* drive bus reset for at least 50 ms (7.1.7.5) */ |
| 511 | msleep(50); | 514 | msleep(50); |
| 515 | } | ||
| 512 | 516 | ||
| 513 | /* software reset of the controller, preserving HcFmInterval */ | 517 | /* software reset of the controller, preserving HcFmInterval */ |
| 514 | fminterval = readl(base + OHCI_FMINTERVAL); | 518 | fminterval = readl(base + OHCI_FMINTERVAL); |
| 515 | writel(OHCI_HCR, base + OHCI_CMDSTATUS); | 519 | writel(OHCI_HCR, base + OHCI_CMDSTATUS); |
| 516 | 520 | ||
| 517 | /* reset requires max 10 us delay */ | 521 | /* reset requires max 10 us delay */ |
| 518 | for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ | 522 | for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ |
| 519 | if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) | 523 | if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) |
| 520 | break; | 524 | break; |
| 521 | udelay(1); | 525 | udelay(1); |
| 522 | } | ||
| 523 | writel(fminterval, base + OHCI_FMINTERVAL); | ||
| 524 | |||
| 525 | /* Now we're in the SUSPEND state with all devices reset | ||
| 526 | * and wakeups and interrupts disabled | ||
| 527 | */ | ||
| 528 | } | 526 | } |
| 527 | writel(fminterval, base + OHCI_FMINTERVAL); | ||
| 529 | 528 | ||
| 530 | /* | 529 | /* Now the controller is safely in SUSPEND and nothing can wake it up */ |
| 531 | * disable interrupts | ||
| 532 | */ | ||
| 533 | writel(~(u32)0, base + OHCI_INTRDISABLE); | ||
| 534 | writel(~(u32)0, base + OHCI_INTRSTATUS); | ||
| 535 | |||
| 536 | iounmap(base); | 530 | iounmap(base); |
| 537 | } | 531 | } |
| 538 | 532 | ||
