| 1 | /* |
| 2 | * ADM5120 HCD (Host Controller Driver) for USB |
| 3 | * |
| 4 | * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> |
| 5 | * |
| 6 | * This file was derived from fragments of the OHCI driver. |
| 7 | * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> |
| 8 | * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net> |
| 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify it |
| 11 | * under the terms of the GNU General Public License version 2 as published |
| 12 | * by the Free Software Foundation. |
| 13 | * |
| 14 | */ |
| 15 | |
| 16 | #define OHCI_SCHED_ENABLES \ |
| 17 | (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) |
| 18 | |
| 19 | #ifdef CONFIG_PM |
| 20 | static int admhc_restart(struct admhcd *ahcd); |
| 21 | |
| 22 | static int admhc_rh_suspend(struct admhcd *ahcd, int autostop) |
| 23 | __releases(ahcd->lock) |
| 24 | __acquires(ahcd->lock) |
| 25 | { |
| 26 | int status = 0; |
| 27 | |
| 28 | ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control); |
| 29 | switch (ahcd->hc_control & OHCI_CTRL_HCFS) { |
| 30 | case OHCI_USB_RESUME: |
| 31 | admhc_dbg(ahcd, "resume/suspend?\n"); |
| 32 | ahcd->hc_control &= ~OHCI_CTRL_HCFS; |
| 33 | ahcd->hc_control |= OHCI_USB_RESET; |
| 34 | admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control); |
| 35 | (void) admhc_readl(ahcd, &ahcd->regs->control); |
| 36 | /* FALL THROUGH */ |
| 37 | case OHCI_USB_RESET: |
| 38 | status = -EBUSY; |
| 39 | admhc_dbg(ahcd, "needs reinit!\n"); |
| 40 | goto done; |
| 41 | case OHCI_USB_SUSPEND: |
| 42 | if (!ahcd->autostop) { |
| 43 | admhc_dbg(ahcd, "already suspended\n"); |
| 44 | goto done; |
| 45 | } |
| 46 | } |
| 47 | admhc_dbg(ahcd, "%s root hub\n", |
| 48 | autostop ? "auto-stop" : "suspend"); |
| 49 | |
| 50 | /* First stop any processing */ |
| 51 | if (!autostop && (ahcd->hc_control & OHCI_SCHED_ENABLES)) { |
| 52 | ahcd->hc_control &= ~OHCI_SCHED_ENABLES; |
| 53 | admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control); |
| 54 | ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control); |
| 55 | admhc_writel(ahcd, OHCI_INTR_SF, &ahcd->regs->intrstatus); |
| 56 | |
| 57 | /* sched disables take effect on the next frame, |
| 58 | * then the last WDH could take 6+ msec |
| 59 | */ |
| 60 | admhc_dbg(ahcd, "stopping schedules ...\n"); |
| 61 | ahcd->autostop = 0; |
| 62 | spin_unlock_irq (&ahcd->lock); |
| 63 | msleep (8); |
| 64 | spin_lock_irq(&ahcd->lock); |
| 65 | } |
| 66 | dl_done_list (ahcd); |
| 67 | finish_unlinks (ahcd, admhc_frame_no(ahcd)); |
| 68 | |
| 69 | /* maybe resume can wake root hub */ |
| 70 | if (device_may_wakeup(&admhcd_to_hcd(ahcd)->self.root_hub->dev) || |
| 71 | autostop) |
| 72 | ahcd->hc_control |= OHCI_CTRL_RWE; |
| 73 | else { |
| 74 | admhc_writel(ahcd, OHCI_INTR_RHSC, &ahcd->regs->intrdisable); |
| 75 | ahcd->hc_control &= ~OHCI_CTRL_RWE; |
| 76 | } |
| 77 | |
| 78 | /* Suspend hub ... this is the "global (to this bus) suspend" mode, |
| 79 | * which doesn't imply ports will first be individually suspended. |
| 80 | */ |
| 81 | ahcd->hc_control &= ~OHCI_CTRL_HCFS; |
| 82 | ahcd->hc_control |= OHCI_USB_SUSPEND; |
| 83 | admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control); |
| 84 | (void) admhc_readl(ahcd, &ahcd->regs->control); |
| 85 | |
| 86 | /* no resumes until devices finish suspending */ |
| 87 | if (!autostop) { |
| 88 | ahcd->next_statechange = jiffies + msecs_to_jiffies (5); |
| 89 | ahcd->autostop = 0; |
| 90 | } |
| 91 | |
| 92 | done: |
| 93 | return status; |
| 94 | } |
| 95 | |
| 96 | static inline struct ed *find_head(struct ed *ed) |
| 97 | { |
| 98 | /* for bulk and control lists */ |
| 99 | while (ed->ed_prev) |
| 100 | ed = ed->ed_prev; |
| 101 | return ed; |
| 102 | } |
| 103 | |
| 104 | /* caller has locked the root hub */ |
| 105 | static int admhc_rh_resume(struct admhcd *ahcd) |
| 106 | __releases(ahcd->lock) |
| 107 | __acquires(ahcd->lock) |
| 108 | { |
| 109 | struct usb_hcd *hcd = admhcd_to_hcd (ahcd); |
| 110 | u32 temp, enables; |
| 111 | int status = -EINPROGRESS; |
| 112 | int autostopped = ahcd->autostop; |
| 113 | |
| 114 | ahcd->autostop = 0; |
| 115 | ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control); |
| 116 | |
| 117 | if (ahcd->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { |
| 118 | /* this can happen after resuming a swsusp snapshot */ |
| 119 | if (hcd->state == HC_STATE_RESUMING) { |
| 120 | admhc_dbg(ahcd, "BIOS/SMM active, control %03x\n", |
| 121 | ahcd->hc_control); |
| 122 | status = -EBUSY; |
| 123 | /* this happens when pmcore resumes HC then root */ |
| 124 | } else { |
| 125 | admhc_dbg(ahcd, "duplicate resume\n"); |
| 126 | status = 0; |
| 127 | } |
| 128 | } else switch (ahcd->hc_control & OHCI_CTRL_HCFS) { |
| 129 | case OHCI_USB_SUSPEND: |
| 130 | ahcd->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); |
| 131 | ahcd->hc_control |= OHCI_USB_RESUME; |
| 132 | admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control); |
| 133 | (void) admhc_readl(ahcd, &ahcd->regs->control); |
| 134 | admhc_dbg(ahcd, "%s root hub\n", |
| 135 | autostopped ? "auto-start" : "resume"); |
| 136 | break; |
| 137 | case OHCI_USB_RESUME: |
| 138 | /* HCFS changes sometime after INTR_RD */ |
| 139 | admhc_dbg(ahcd, "%swakeup root hub\n", |
| 140 | autostopped ? "auto-" : ""); |
| 141 | break; |
| 142 | case OHCI_USB_OPER: |
| 143 | /* this can happen after resuming a swsusp snapshot */ |
| 144 | admhc_dbg(ahcd, "snapshot resume? reinit\n"); |
| 145 | status = -EBUSY; |
| 146 | break; |
| 147 | default: /* RESET, we lost power */ |
| 148 | admhc_dbg(ahcd, "lost power\n"); |
| 149 | status = -EBUSY; |
| 150 | } |
| 151 | if (status == -EBUSY) { |
| 152 | if (!autostopped) { |
| 153 | spin_unlock_irq (&ahcd->lock); |
| 154 | (void) ahcd_init (ahcd); |
| 155 | status = admhc_restart (ahcd); |
| 156 | spin_lock_irq(&ahcd->lock); |
| 157 | } |
| 158 | return status; |
| 159 | } |
| 160 | if (status != -EINPROGRESS) |
| 161 | return status; |
| 162 | if (autostopped) |
| 163 | goto skip_resume; |
| 164 | spin_unlock_irq (&ahcd->lock); |
| 165 | |
| 166 | /* Some controllers (lucent erratum) need extra-long delays */ |
| 167 | msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); |
| 168 | |
| 169 | temp = admhc_readl(ahcd, &ahcd->regs->control); |
| 170 | temp &= OHCI_CTRL_HCFS; |
| 171 | if (temp != OHCI_USB_RESUME) { |
| 172 | admhc_err (ahcd, "controller won't resume\n"); |
| 173 | spin_lock_irq(&ahcd->lock); |
| 174 | return -EBUSY; |
| 175 | } |
| 176 | |
| 177 | /* disable old schedule state, reinit from scratch */ |
| 178 | admhc_writel(ahcd, 0, &ahcd->regs->ed_controlhead); |
| 179 | admhc_writel(ahcd, 0, &ahcd->regs->ed_controlcurrent); |
| 180 | admhc_writel(ahcd, 0, &ahcd->regs->ed_bulkhead); |
| 181 | admhc_writel(ahcd, 0, &ahcd->regs->ed_bulkcurrent); |
| 182 | admhc_writel(ahcd, 0, &ahcd->regs->ed_periodcurrent); |
| 183 | admhc_writel(ahcd, (u32) ahcd->hcca_dma, &ahcd->ahcd->regs->hcca); |
| 184 | |
| 185 | /* Sometimes PCI D3 suspend trashes frame timings ... */ |
| 186 | periodic_reinit(ahcd); |
| 187 | |
| 188 | /* the following code is executed with ahcd->lock held and |
| 189 | * irqs disabled if and only if autostopped is true |
| 190 | */ |
| 191 | |
| 192 | skip_resume: |
| 193 | /* interrupts might have been disabled */ |
| 194 | admhc_writel(ahcd, OHCI_INTR_INIT, &ahcd->regs->int_enable); |
| 195 | if (ahcd->ed_rm_list) |
| 196 | admhc_writel(ahcd, OHCI_INTR_SF, &ahcd->regs->int_enable); |
| 197 | |
| 198 | /* Then re-enable operations */ |
| 199 | admhc_writel(ahcd, OHCI_USB_OPER, &ahcd->regs->control); |
| 200 | (void) admhc_readl(ahcd, &ahcd->regs->control); |
| 201 | if (!autostopped) |
| 202 | msleep (3); |
| 203 | |
| 204 | temp = ahcd->hc_control; |
| 205 | temp &= OHCI_CTRL_RWC; |
| 206 | temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER; |
| 207 | ahcd->hc_control = temp; |
| 208 | admhc_writel(ahcd, temp, &ahcd->regs->control); |
| 209 | (void) admhc_readl(ahcd, &ahcd->regs->control); |
| 210 | |
| 211 | /* TRSMRCY */ |
| 212 | if (!autostopped) { |
| 213 | msleep (10); |
| 214 | spin_lock_irq(&ahcd->lock); |
| 215 | } |
| 216 | /* now ahcd->lock is always held and irqs are always disabled */ |
| 217 | |
| 218 | /* keep it alive for more than ~5x suspend + resume costs */ |
| 219 | ahcd->next_statechange = jiffies + STATECHANGE_DELAY; |
| 220 | |
| 221 | /* maybe turn schedules back on */ |
| 222 | enables = 0; |
| 223 | temp = 0; |
| 224 | if (!ahcd->ed_rm_list) { |
| 225 | if (ahcd->ed_controltail) { |
| 226 | admhc_writel(ahcd, |
| 227 | find_head (ahcd->ed_controltail)->dma, |
| 228 | &ahcd->regs->ed_controlhead); |
| 229 | enables |= OHCI_CTRL_CLE; |
| 230 | temp |= OHCI_CLF; |
| 231 | } |
| 232 | if (ahcd->ed_bulktail) { |
| 233 | admhc_writel(ahcd, find_head (ahcd->ed_bulktail)->dma, |
| 234 | &ahcd->regs->ed_bulkhead); |
| 235 | enables |= OHCI_CTRL_BLE; |
| 236 | temp |= OHCI_BLF; |
| 237 | } |
| 238 | } |
| 239 | if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs) |
| 240 | enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; |
| 241 | if (enables) { |
| 242 | admhc_dbg(ahcd, "restarting schedules ... %08x\n", enables); |
| 243 | ahcd->hc_control |= enables; |
| 244 | admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control); |
| 245 | if (temp) |
| 246 | admhc_writel(ahcd, temp, &ahcd->regs->cmdstatus); |
| 247 | (void) admhc_readl(ahcd, &ahcd->regs->control); |
| 248 | } |
| 249 | |
| 250 | return 0; |
| 251 | } |
| 252 | |
| 253 | static int admhc_bus_suspend(struct usb_hcd *hcd) |
| 254 | { |
| 255 | struct admhcd *ahcd = hcd_to_admhcd(hcd); |
| 256 | int rc; |
| 257 | |
| 258 | spin_lock_irq(&ahcd->lock); |
| 259 | |
| 260 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) |
| 261 | rc = -ESHUTDOWN; |
| 262 | else |
| 263 | rc = admhc_rh_suspend(ahcd, 0); |
| 264 | spin_unlock_irq(&ahcd->lock); |
| 265 | return rc; |
| 266 | } |
| 267 | |
| 268 | static int admhc_bus_resume(struct usb_hcd *hcd) |
| 269 | { |
| 270 | struct admhcd *ahcd = hcd_to_admhcd(hcd); |
| 271 | int rc; |
| 272 | |
| 273 | if (time_before(jiffies, ahcd->next_statechange)) |
| 274 | msleep(5); |
| 275 | |
| 276 | spin_lock_irq(&ahcd->lock); |
| 277 | |
| 278 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) |
| 279 | rc = -ESHUTDOWN; |
| 280 | else |
| 281 | rc = admhc_rh_resume(ahcd); |
| 282 | spin_unlock_irq(&ahcd->lock); |
| 283 | |
| 284 | /* poll until we know a device is connected or we autostop */ |
| 285 | if (rc == 0) |
| 286 | usb_hcd_poll_rh_status(hcd); |
| 287 | return rc; |
| 288 | } |
| 289 | |
| 290 | /* Carry out polling-, autostop-, and autoresume-related state changes */ |
| 291 | static int admhc_root_hub_state_changes(struct admhcd *ahcd, int changed, |
| 292 | int any_connected) |
| 293 | { |
| 294 | int poll_rh = 1; |
| 295 | |
| 296 | switch (ahcd->hc_control & OHCI_CTRL_HCFS) { |
| 297 | |
| 298 | case OHCI_USB_OPER: |
| 299 | /* keep on polling until we know a device is connected |
| 300 | * and RHSC is enabled */ |
| 301 | if (!ahcd->autostop) { |
| 302 | if (any_connected || |
| 303 | !device_may_wakeup(&admhcd_to_hcd(ahcd) |
| 304 | ->self.root_hub->dev)) { |
| 305 | if (admhc_readl(ahcd, &ahcd->regs->int_enable) & |
| 306 | OHCI_INTR_RHSC) |
| 307 | poll_rh = 0; |
| 308 | } else { |
| 309 | ahcd->autostop = 1; |
| 310 | ahcd->next_statechange = jiffies + HZ; |
| 311 | } |
| 312 | |
| 313 | /* if no devices have been attached for one second, autostop */ |
| 314 | } else { |
| 315 | if (changed || any_connected) { |
| 316 | ahcd->autostop = 0; |
| 317 | ahcd->next_statechange = jiffies + |
| 318 | STATECHANGE_DELAY; |
| 319 | } else if (time_after_eq(jiffies, |
| 320 | ahcd->next_statechange) |
| 321 | && !ahcd->ed_rm_list |
| 322 | && !(ahcd->hc_control & |
| 323 | OHCI_SCHED_ENABLES)) { |
| 324 | ahcd_rh_suspend(ahcd, 1); |
| 325 | } |
| 326 | } |
| 327 | break; |
| 328 | |
| 329 | /* if there is a port change, autostart or ask to be resumed */ |
| 330 | case OHCI_USB_SUSPEND: |
| 331 | case OHCI_USB_RESUME: |
| 332 | if (changed) { |
| 333 | if (ahcd->autostop) |
| 334 | admhc_rh_resume(ahcd); |
| 335 | else |
| 336 | usb_hcd_resume_root_hub(admhcd_to_hcd(ahcd)); |
| 337 | } else { |
| 338 | /* everything is idle, no need for polling */ |
| 339 | poll_rh = 0; |
| 340 | } |
| 341 | break; |
| 342 | } |
| 343 | return poll_rh; |
| 344 | } |
| 345 | |
| 346 | /*-------------------------------------------------------------------------*/ |
| 347 | |
| 348 | /* must not be called from interrupt context */ |
| 349 | static int admhc_restart(struct admhcd *ahcd) |
| 350 | { |
| 351 | int temp; |
| 352 | int i; |
| 353 | struct urb_priv *priv; |
| 354 | |
| 355 | /* mark any devices gone, so they do nothing till khubd disconnects. |
| 356 | * recycle any "live" eds/tds (and urbs) right away. |
| 357 | * later, khubd disconnect processing will recycle the other state, |
| 358 | * (either as disconnect/reconnect, or maybe someday as a reset). |
| 359 | */ |
| 360 | spin_lock_irq(&ahcd->lock); |
| 361 | admhc_disable(ahcd); |
| 362 | usb_root_hub_lost_power(admhcd_to_hcd(ahcd)->self.root_hub); |
| 363 | if (!list_empty(&ahcd->pending)) |
| 364 | admhc_dbg(ahcd, "abort schedule...\n"); |
| 365 | list_for_each_entry(priv, &ahcd->pending, pending) { |
| 366 | struct urb *urb = priv->td[0]->urb; |
| 367 | struct ed *ed = priv->ed; |
| 368 | |
| 369 | switch (ed->state) { |
| 370 | case ED_OPER: |
| 371 | ed->state = ED_UNLINK; |
| 372 | ed->hwINFO |= cpu_to_hc32(ahcd, ED_DEQUEUE); |
| 373 | ed_deschedule (ahcd, ed); |
| 374 | |
| 375 | ed->ed_next = ahcd->ed_rm_list; |
| 376 | ed->ed_prev = NULL; |
| 377 | ahcd->ed_rm_list = ed; |
| 378 | /* FALLTHROUGH */ |
| 379 | case ED_UNLINK: |
| 380 | break; |
| 381 | default: |
| 382 | admhc_dbg(ahcd, "bogus ed %p state %d\n", |
| 383 | ed, ed->state); |
| 384 | } |
| 385 | |
| 386 | if (!urb->unlinked) |
| 387 | urb->unlinked = -ESHUTDOWN; |
| 388 | } |
| 389 | finish_unlinks(ahcd, 0); |
| 390 | spin_unlock_irq(&ahcd->lock); |
| 391 | |
| 392 | /* paranoia, in case that didn't work: */ |
| 393 | |
| 394 | /* empty the interrupt branches */ |
| 395 | for (i = 0; i < NUM_INTS; i++) ahcd->load[i] = 0; |
| 396 | for (i = 0; i < NUM_INTS; i++) ahcd->hcca->int_table[i] = 0; |
| 397 | |
| 398 | /* no EDs to remove */ |
| 399 | ahcd->ed_rm_list = NULL; |
| 400 | |
| 401 | /* empty control and bulk lists */ |
| 402 | ahcd->ed_controltail = NULL; |
| 403 | ahcd->ed_bulktail = NULL; |
| 404 | |
| 405 | if ((temp = admhc_run(ahcd)) < 0) { |
| 406 | admhc_err(ahcd, "can't restart, %d\n", temp); |
| 407 | return temp; |
| 408 | } else { |
| 409 | /* here we "know" root ports should always stay powered, |
| 410 | * and that if we try to turn them back on the root hub |
| 411 | * will respond to CSC processing. |
| 412 | */ |
| 413 | i = ahcd->num_ports; |
| 414 | while (i--) |
| 415 | admhc_writel(ahcd, RH_PS_PSS, |
| 416 | &ahcd->regs->portstatus[i]); |
| 417 | admhc_dbg(ahcd, "restart complete\n"); |
| 418 | } |
| 419 | return 0; |
| 420 | } |
| 421 | |
| 422 | #else /* CONFIG_PM */ |
| 423 | |
| 424 | static inline int admhc_rh_resume(struct admhcd *ahcd) |
| 425 | { |
| 426 | return 0; |
| 427 | } |
| 428 | |
| 429 | /* Carry out polling-related state changes. |
| 430 | * autostop isn't used when CONFIG_PM is turned off. |
| 431 | */ |
| 432 | static int admhc_root_hub_state_changes(struct admhcd *ahcd, int changed, |
| 433 | int any_connected) |
| 434 | { |
| 435 | /* If INSM is enabled, don't poll */ |
| 436 | if (admhc_readl(ahcd, &ahcd->regs->int_enable) & ADMHC_INTR_INSM) |
| 437 | return 0; |
| 438 | |
| 439 | /* If no status changes are pending, enable status-change interrupts */ |
| 440 | if (!changed) { |
| 441 | admhc_intr_enable(ahcd, ADMHC_INTR_INSM); |
| 442 | return 0; |
| 443 | } |
| 444 | |
| 445 | return 1; |
| 446 | } |
| 447 | |
| 448 | #endif /* CONFIG_PM */ |
| 449 | |
| 450 | |