/* caller has locked the root hub */ static int ohci_bus_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; int status = -EINPROGRESS; unsigned long flags; if (time_before (jiffies, ohci->next_statechange)) msleep(5); spin_lock_irqsave (&ohci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { spin_unlock_irqrestore (&ohci->lock, flags); return -ESHUTDOWN; } ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { /* this can happen after resuming a swsusp snapshot */ if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); status = -EBUSY; /* this happens when pmcore resumes HC then root */ } else { ohci_dbg (ohci, "duplicate resume\n"); status = 0; } } else switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_SUSPEND: ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control |= OHCI_USB_RESUME; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); ohci_dbg (ohci, "resume root hub\n"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: /* this can happen after resuming a swsusp snapshot */ ohci_dbg (ohci, "snapshot resume? reinit\n"); status = -EBUSY; break; default: /* RESET, we lost power */ ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } spin_unlock_irqrestore (&ohci->lock, flags); if (status == -EBUSY) { (void) ohci_init (ohci); return ohci_restart (ohci); } if (status != -EINPROGRESS) return status; temp = ohci->num_ports; enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, &ohci->regs->roothub.portstatus [temp]); /* force global, not selective, resume */ if (!(stat & RH_PS_PSS)) continue; ohci_writel (ohci, RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]); } /* Some controllers (lucent erratum) need extra-long delays */ msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); temp = ohci_readl (ohci, &ohci->regs->control); temp &= OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); return -EBUSY; } /* disable old schedule state, reinit from scratch */ ohci_writel (ohci, 0, &ohci->regs->ed_controlhead); ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead); ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent); ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca); /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* Then re-enable operations */ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); msleep (3); temp = ohci->hc_control; temp &= OHCI_CTRL_RWC; temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->hc_control = temp; ohci_writel (ohci, temp, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* TRSMRCY */ msleep (10); /* keep it alive for more than ~5x suspend + resume costs */ ohci->next_statechange = jiffies + STATECHANGE_DELAY; /* maybe turn schedules back on */ enables = 0; temp = 0; if (!ohci->ed_rm_list) { if (ohci->ed_controltail) { ohci_writel (ohci, find_head (ohci->ed_controltail)->dma, &ohci->regs->ed_controlhead); enables |= OHCI_CTRL_CLE; temp |= OHCI_CLF; } if (ohci->ed_bulktail) { ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma, &ohci->regs->ed_bulkhead); enables |= OHCI_CTRL_BLE; temp |= OHCI_BLF; } } if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs) enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; if (enables) { ohci_dbg (ohci, "restarting schedules ... %08x\n", enables); ohci->hc_control |= enables; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); if (temp) ohci_writel (ohci, temp, &ohci->regs->cmdstatus); (void) ohci_readl (ohci, &ohci->regs->control); } return 0; }
/* Start an OHCI controller, set the BUS operational * resets USB and controller * enable interrupts */ static int admhc_run(struct admhcd *ahcd) { u32 temp; int first = ahcd->fminterval == 0; struct usb_hcd *hcd = admhcd_to_hcd(ahcd); admhc_disable(ahcd); /* boot firmware should have set this up (5.1.1.3.1) */ if (first) { temp = admhc_readl(ahcd, &ahcd->regs->fminterval); ahcd->fminterval = temp & ADMHC_SFI_FI_MASK; if (ahcd->fminterval != FI) admhc_dbg(ahcd, "fminterval delta %d\n", ahcd->fminterval - FI); ahcd->fminterval |= (FSLDP(ahcd->fminterval) << ADMHC_SFI_FSLDP_SHIFT); /* also: power/overcurrent flags in rhdesc */ } #if 0 /* TODO: not applicable */ /* Reset USB nearly "by the book". RemoteWakeupConnected was * saved if boot firmware (BIOS/SMM/...) told us it's connected, * or if bus glue did the same (e.g. for PCI add-in cards with * PCI PM support). */ if ((ahcd->hc_control & OHCI_CTRL_RWC) != 0 && !device_may_wakeup(hcd->self.controller)) device_init_wakeup(hcd->self.controller, 1); #endif switch (ahcd->host_control & ADMHC_HC_BUSS) { case ADMHC_BUSS_OPER: temp = 0; break; case ADMHC_BUSS_SUSPEND: /* FALLTHROUGH ? */ case ADMHC_BUSS_RESUME: ahcd->host_control = ADMHC_BUSS_RESUME; temp = 10 /* msec wait */; break; /* case ADMHC_BUSS_RESET: */ default: ahcd->host_control = ADMHC_BUSS_RESET; temp = 50 /* msec wait */; break; } admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control); /* flush the writes */ admhc_writel_flush(ahcd); msleep(temp); temp = admhc_read_rhdesc(ahcd); if (!(temp & ADMHC_RH_NPS)) { /* power down each port */ for (temp = 0; temp < ahcd->num_ports; temp++) admhc_write_portstatus(ahcd, temp, ADMHC_PS_CPP); } /* flush those writes */ admhc_writel_flush(ahcd); /* 2msec timelimit here means no irqs/preempt */ spin_lock_irq(&ahcd->lock); admhc_writel(ahcd, ADMHC_CTRL_SR, &ahcd->regs->gencontrol); temp = 30; /* ... allow extra time */ while ((admhc_readl(ahcd, &ahcd->regs->gencontrol) & ADMHC_CTRL_SR) != 0) { if (--temp == 0) { spin_unlock_irq(&ahcd->lock); admhc_err(ahcd, "USB HC reset timed out!\n"); return -1; } udelay(1); } /* enable HOST mode, before access any host specific register */ admhc_writel(ahcd, ADMHC_CTRL_UHFE, &ahcd->regs->gencontrol); /* Tell the controller where the descriptor list is */ admhc_writel(ahcd, (u32)ahcd->ed_head->dma, &ahcd->regs->hosthead); periodic_reinit(ahcd); /* use rhsc irqs after khubd is fully initialized */ hcd->poll_rh = 1; hcd->uses_new_polling = 1; #if 0 /* wake on ConnectStatusChange, matching external hubs */ admhc_writel(ahcd, RH_HS_DRWE, &ahcd->regs->roothub.status); #else /* FIXME roothub_write_status (ahcd, ADMHC_RH_DRWE); */ #endif /* Choose the interrupts we care about now, others later on demand */ admhc_intr_ack(ahcd, ~0); admhc_intr_enable(ahcd, ADMHC_INTR_INIT); admhc_writel(ahcd, ADMHC_RH_NPS | ADMHC_RH_LPSC, &ahcd->regs->rhdesc); /* flush those writes */ admhc_writel_flush(ahcd); /* start controller operations */ ahcd->host_control = ADMHC_BUSS_OPER; admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control); temp = 20; while ((admhc_readl(ahcd, &ahcd->regs->host_control) & ADMHC_HC_BUSS) != ADMHC_BUSS_OPER) { if (--temp == 0) { spin_unlock_irq(&ahcd->lock); admhc_err(ahcd, "unable to setup operational mode!\n"); return -1; } mdelay(1); } hcd->state = HC_STATE_RUNNING; ahcd->next_statechange = jiffies + STATECHANGE_DELAY; #if 0 /* FIXME: enabling DMA is always failed here for an unknown reason */ admhc_dma_enable(ahcd); temp = 200; while ((admhc_readl(ahcd, &ahcd->regs->host_control) & ADMHC_HC_DMAE) != ADMHC_HC_DMAE) { if (--temp == 0) { spin_unlock_irq(&ahcd->lock); admhc_err(ahcd, "unable to enable DMA!\n"); admhc_dump(ahcd, 1); return -1; } mdelay(1); } #endif spin_unlock_irq(&ahcd->lock); mdelay(ADMHC_POTPGT); return 0; }
/* caller has locked the root hub */ static int ohci_hub_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; int status = -EINPROGRESS; #if defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) //FOR PULLING VENUS_USB_HOST_WRAPPER BIT6 HIGH BEFOR RESUME OHCI PORT outl(inl(VENUS_USB_HOST_WRAPPER)| 1<<6, VENUS_USB_HOST_WRAPPER); (void) ohci_init (ohci); return ohci_restart (ohci); #endif /* defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) */ if (time_before (jiffies, ohci->next_statechange)) msleep(5); spin_lock_irq (&ohci->lock); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { /* this can happen after suspend-to-disk */ if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); status = -EBUSY; /* this happens when pmcore resumes HC then root */ } else { ohci_dbg (ohci, "duplicate resume\n"); status = 0; } } else switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_SUSPEND: #ifdef CONFIG_REALTEK_VENUS_USB //cfyeh+ //for pulling VENUS_USB_HOST_WRAPPER bit6 high befor resume OHCI port outl(inl(VENUS_USB_HOST_WRAPPER)| 1<<6, VENUS_USB_HOST_WRAPPER); #endif /* CONFIG_REALTEK_VENUS_USB */ //cfyeh- ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control |= OHCI_USB_RESUME; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); ohci_dbg (ohci, "resume root hub\n"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: ohci_dbg (ohci, "already resumed\n"); status = 0; break; default: /* RESET, we lost power */ ohci_dbg (ohci, "root hub hardware reset\n"); status = -EBUSY; } spin_unlock_irq (&ohci->lock); if (status == -EBUSY) { (void) ohci_init (ohci); return ohci_restart (ohci); } if (status != -EINPROGRESS) return status; temp = roothub_a (ohci) & RH_A_NDP; enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, &ohci->regs->roothub.portstatus [temp]); /* force global, not selective, resume */ if (!(stat & RH_PS_PSS)) continue; ohci_writel (ohci, RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]); } /* Some controllers (lucent erratum) need extra-long delays */ hcd->state = HC_STATE_RESUMING; mdelay (20 /* usb 11.5.1.10 */ + 15); temp = ohci_readl (ohci, &ohci->regs->control); temp &= OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); return -EBUSY; } /* disable old schedule state, reinit from scratch */ ohci_writel (ohci, 0, &ohci->regs->ed_controlhead); ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead); ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent); ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca); /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* Then re-enable operations */ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); msleep (3); temp = OHCI_CONTROL_INIT | OHCI_USB_OPER; if (hcd->can_wakeup) temp |= OHCI_CTRL_RWC; ohci->hc_control = temp; ohci_writel (ohci, temp, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* TRSMRCY */ msleep (10); /* keep it alive for ~5x suspend + resume costs */ ohci->next_statechange = jiffies + msecs_to_jiffies (250); /* maybe turn schedules back on */ enables = 0; temp = 0; if (!ohci->ed_rm_list) { if (ohci->ed_controltail) { ohci_writel (ohci, find_head (ohci->ed_controltail)->dma, &ohci->regs->ed_controlhead); enables |= OHCI_CTRL_CLE; temp |= OHCI_CLF; } if (ohci->ed_bulktail) { ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma, &ohci->regs->ed_bulkhead); enables |= OHCI_CTRL_BLE; temp |= OHCI_BLF; } } if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs) enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; if (enables) { ohci_dbg (ohci, "restarting schedules ... %08x\n", enables); ohci->hc_control |= enables; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); if (temp) ohci_writel (ohci, temp, &ohci->regs->cmdstatus); (void) ohci_readl (ohci, &ohci->regs->control); } hcd->state = HC_STATE_RUNNING; return 0; }
/* caller owns root->serialize */ static int ohci_hub_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub; u32 temp, enables; int status = -EINPROGRESS; if (!root->dev.power.power_state) return 0; if (time_before (jiffies, ohci->next_statechange)) msleep(5); spin_lock_irq (&ohci->lock); ohci->hc_control = ohci_readl (&ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_SUSPEND: ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control |= OHCI_USB_RESUME; writel (ohci->hc_control, &ohci->regs->control); (void) ohci_readl (&ohci->regs->control); ohci_dbg (ohci, "resume root hub\n"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: ohci_dbg (ohci, "odd resume\n"); root->dev.power.power_state = 0; status = 0; break; default: /* RESET, we lost power */ ohci_dbg (ohci, "root hub hardware reset\n"); status = -EBUSY; } spin_unlock_irq (&ohci->lock); if (status == -EBUSY) return hc_restart (ohci); if (status != -EINPROGRESS) return status; temp = roothub_a (ohci) & RH_A_NDP; enables = 0; while (temp--) { u32 stat = ohci_readl (&ohci->regs->roothub.portstatus [temp]); /* force global, not selective, resume */ if (!(stat & RH_PS_PSS)) continue; writel (RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]); } /* Some controllers (lucent) need extra-long delays */ ohci->hcd.state = USB_STATE_RESUMING; mdelay (20 /* usb 11.5.1.10 */ + 15); temp = ohci_readl (&ohci->regs->control); temp &= OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); return -EBUSY; } /* disable old schedule state, reinit from scratch */ writel (0, &ohci->regs->ed_controlhead); writel (0, &ohci->regs->ed_controlcurrent); writel (0, &ohci->regs->ed_bulkhead); writel (0, &ohci->regs->ed_bulkcurrent); writel (0, &ohci->regs->ed_periodcurrent); writel ((u32) ohci->hcca_dma, &ohci->regs->hcca); periodic_reinit (ohci); /* interrupts might have been disabled */ writel (OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) writel (OHCI_INTR_SF, &ohci->regs->intrenable); writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus); /* Then re-enable operations */ writel (OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (&ohci->regs->control); msleep (3); temp = OHCI_CONTROL_INIT | OHCI_USB_OPER; if (ohci->hcd.can_wakeup) temp |= OHCI_CTRL_RWC; ohci->hc_control = temp; writel (temp, &ohci->regs->control); (void) ohci_readl (&ohci->regs->control); /* TRSMRCY */ msleep (10); root->dev.power.power_state = 0; /* keep it alive for ~5x suspend + resume costs */ ohci->next_statechange = jiffies + msecs_to_jiffies (250); /* maybe turn schedules back on */ enables = 0; temp = 0; if (!ohci->ed_rm_list) { if (ohci->ed_controltail) { writel (find_head (ohci->ed_controltail)->dma, &ohci->regs->ed_controlhead); enables |= OHCI_CTRL_CLE; temp |= OHCI_CLF; } if (ohci->ed_bulktail) { writel (find_head (ohci->ed_bulktail)->dma, &ohci->regs->ed_bulkhead); enables |= OHCI_CTRL_BLE; temp |= OHCI_BLF; } } if (hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs || hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs) enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; if (enables) { ohci_dbg (ohci, "restarting schedules ... %08x\n", enables); ohci->hc_control |= enables; writel (ohci->hc_control, &ohci->regs->control); if (temp) writel (status, &ohci->regs->cmdstatus); (void) ohci_readl (&ohci->regs->control); } ohci->hcd.state = USB_STATE_RUNNING; return 0; }