Commit 19db13b2 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] ohci-hcd init err detect

Here's a followup patch, should apply on top of what I sent
this morning ... please do so!  (Sorry, same name but the
patch is different.)

Along with some cleanups, this actually restores a line that
was dropped somewhere in 2.5 ... basically, at least SiS and
OPTi violate the OHCI spec so they don't init "by the book".
parent fc245714
...@@ -106,7 +106,6 @@ ...@@ -106,7 +106,6 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define OHCI_USE_NPS // force NoPowerSwitching mode
// #define OHCI_VERBOSE_DEBUG /* not always helpful */ // #define OHCI_VERBOSE_DEBUG /* not always helpful */
/* For initializing controller (mask in an HCFS mode too) */ /* For initializing controller (mask in an HCFS mode too) */
...@@ -349,22 +348,23 @@ static int ohci_get_frame (struct usb_hcd *hcd) ...@@ -349,22 +348,23 @@ static int ohci_get_frame (struct usb_hcd *hcd)
static int hc_reset (struct ohci_hcd *ohci) static int hc_reset (struct ohci_hcd *ohci)
{ {
int timeout = 30; u32 temp;
int smm_timeout = 50; /* 0,5 sec */
/* SMM owns the HC? not for long! */
if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
temp = 50; /* arbitrary: half second */
writel (OHCI_INTR_OC, &ohci->regs->intrenable); writel (OHCI_INTR_OC, &ohci->regs->intrenable);
writel (OHCI_OCR, &ohci->regs->cmdstatus); writel (OHCI_OCR, &ohci->regs->cmdstatus);
dbg ("USB HC TakeOver from SMM"); dbg ("USB HC TakeOver from SMM");
while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10); wait_ms (10);
if (--smm_timeout == 0) { if (--temp == 0) {
err ("USB HC TakeOver failed!"); err ("USB HC TakeOver failed!");
return -1; return -1;
} }
} }
} }
/* Disable HC interrupts */ /* Disable HC interrupts */
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
...@@ -372,22 +372,34 @@ static int hc_reset (struct ohci_hcd *ohci) ...@@ -372,22 +372,34 @@ static int hc_reset (struct ohci_hcd *ohci)
ohci->hcd.self.bus_name, ohci->hcd.self.bus_name,
readl (&ohci->regs->control)); readl (&ohci->regs->control));
/* Reset USB (needed by some controllers) */ /* Reset USB (needed by some controllers); RemoteWakeupConnected
writel (0, &ohci->regs->control); * saved if boot firmware (BIOS/SMM/...) told us it's connected
*/
/* HC Reset requires max 10 ms delay */ ohci->hc_control = readl (&ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */
writel (ohci->hc_control, &ohci->regs->control);
wait_ms (50);
/* HC Reset requires max 10 us delay */
writel (OHCI_HCR, &ohci->regs->cmdstatus); writel (OHCI_HCR, &ohci->regs->cmdstatus);
temp = 30; /* ... allow extra time */
while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--timeout == 0) { if (--temp == 0) {
err ("USB HC reset timed out!"); err ("USB HC reset timed out!");
return -1; return -1;
} }
udelay (1); udelay (1);
} }
/* now we're in the SUSPEND state ... must go OPERATIONAL /* now we're in the SUSPEND state ... must go OPERATIONAL
* within 2msec else HC enters RESUME * within 2msec else HC enters RESUME
*
* ... but some hardware won't init fmInterval "by the book"
* (SiS, OPTi ...), so reset again instead. SiS doesn't need
* this if we write fmInterval after we're OPERATIONAL.
*/ */
writel (ohci->hc_control, &ohci->regs->control);
return 0; return 0;
} }
...@@ -434,7 +446,8 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -434,7 +446,8 @@ static int hc_start (struct ohci_hcd *ohci)
} }
/* start controller operations */ /* start controller operations */
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
ohci->disabled = 0; ohci->disabled = 0;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
...@@ -443,13 +456,11 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -443,13 +456,11 @@ static int hc_start (struct ohci_hcd *ohci)
writel (mask, &ohci->regs->intrstatus); writel (mask, &ohci->regs->intrstatus);
writel (mask, &ohci->regs->intrenable); writel (mask, &ohci->regs->intrenable);
#ifdef OHCI_USE_NPS /* hub power always on: required for AMD-756 and some Mac platforms */
/* required for AMD-756 and some Mac platforms */
writel ((roothub_a (ohci) | RH_A_NPS) & ~(RH_A_PSM | RH_A_OCPM), writel ((roothub_a (ohci) | RH_A_NPS) & ~(RH_A_PSM | RH_A_OCPM),
&ohci->regs->roothub.a); &ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status); writel (RH_HS_LPSC, &ohci->regs->roothub.status);
writel (0, &ohci->regs->roothub.b); writel (0, &ohci->regs->roothub.b);
#endif /* OHCI_USE_NPS */
// POTPGT delay is bits 24-31, in 2 ms units. // POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((roothub_a (ohci) >> 23) & 0x1fe); mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
...@@ -458,9 +469,10 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -458,9 +469,10 @@ static int hc_start (struct ohci_hcd *ohci)
ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self); ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self);
ohci->hcd.state = USB_STATE_READY; ohci->hcd.state = USB_STATE_READY;
if (!udev) { if (!udev) {
ohci->disabled = 1; ohci->disabled = 1;
// FIXME cleanup ohci->hc_control &= ~OHCI_CTRL_HCFS;
return -ENOMEM; writel (ohci->hc_control, &ohci->regs->control);
return -ENOMEM;
} }
usb_connect (udev); usb_connect (udev);
...@@ -468,10 +480,11 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -468,10 +480,11 @@ static int hc_start (struct ohci_hcd *ohci)
if (usb_register_root_hub (udev, ohci->parent_dev) != 0) { if (usb_register_root_hub (udev, ohci->parent_dev) != 0) {
usb_free_dev (udev); usb_free_dev (udev);
ohci->disabled = 1; ohci->disabled = 1;
// FIXME cleanup ohci->hc_control &= ~OHCI_CTRL_HCFS;
writel (ohci->hc_control, &ohci->regs->control);
return -ENODEV; return -ENODEV;
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment