ehci-hub.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * Copyright (c) 2001-2002 by David Brownell
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation; either version 2 of the License, or (at your
  7. * option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. * for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. /* this file is part of ehci-hcd.c */
  19. /*-------------------------------------------------------------------------*/
  20. /*
  21. * EHCI Root Hub ... the nonsharable stuff
  22. *
  23. * Registers don't need cpu_to_le32, that happens transparently
  24. */
  25. /*-------------------------------------------------------------------------*/
  26. #ifdef CONFIG_PM
  27. static int ehci_hub_suspend (struct usb_hcd *hcd)
  28. {
  29. struct ehci_hcd *ehci = hcd_to_ehci (hcd);
  30. int port;
  31. if (time_before (jiffies, ehci->next_statechange))
  32. msleep(5);
  33. port = HCS_N_PORTS (ehci->hcs_params);
  34. spin_lock_irq (&ehci->lock);
  35. /* stop schedules, clean any completed work */
  36. if (HC_IS_RUNNING(hcd->state)) {
  37. ehci_quiesce (ehci);
  38. hcd->state = HC_STATE_QUIESCING;
  39. }
  40. ehci->command = readl (&ehci->regs->command);
  41. if (ehci->reclaim)
  42. ehci->reclaim_ready = 1;
  43. ehci_work(ehci, NULL);
  44. /* suspend any active/unsuspended ports, maybe allow wakeup */
  45. while (port--) {
  46. u32 __iomem *reg = &ehci->regs->port_status [port];
  47. u32 t1 = readl (reg);
  48. u32 t2 = t1;
  49. if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
  50. t2 |= PORT_SUSPEND;
  51. if (hcd->remote_wakeup)
  52. t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
  53. else
  54. t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
  55. if (t1 != t2) {
  56. ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
  57. port + 1, t1, t2);
  58. writel (t2, reg);
  59. }
  60. }
  61. /* turn off now-idle HC */
  62. ehci_halt (ehci);
  63. hcd->state = HC_STATE_SUSPENDED;
  64. ehci->next_statechange = jiffies + msecs_to_jiffies(10);
  65. spin_unlock_irq (&ehci->lock);
  66. return 0;
  67. }
  68. /* caller has locked the root hub, and should reset/reinit on error */
  69. static int ehci_hub_resume (struct usb_hcd *hcd)
  70. {
  71. struct ehci_hcd *ehci = hcd_to_ehci (hcd);
  72. u32 temp;
  73. int i;
  74. int intr_enable;
  75. if (time_before (jiffies, ehci->next_statechange))
  76. msleep(5);
  77. spin_lock_irq (&ehci->lock);
  78. /* re-init operational registers in case we lost power */
  79. if (readl (&ehci->regs->intr_enable) == 0) {
  80. /* at least some APM implementations will try to deliver
  81. * IRQs right away, so delay them until we're ready.
  82. */
  83. intr_enable = 1;
  84. writel (0, &ehci->regs->segment);
  85. writel (ehci->periodic_dma, &ehci->regs->frame_list);
  86. writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
  87. } else
  88. intr_enable = 0;
  89. ehci_dbg(ehci, "resume root hub%s\n",
  90. intr_enable ? " after power loss" : "");
  91. /* restore CMD_RUN, framelist size, and irq threshold */
  92. writel (ehci->command, &ehci->regs->command);
  93. /* take ports out of suspend */
  94. i = HCS_N_PORTS (ehci->hcs_params);
  95. while (i--) {
  96. temp = readl (&ehci->regs->port_status [i]);
  97. temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
  98. if (temp & PORT_SUSPEND) {
  99. ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
  100. temp |= PORT_RESUME;
  101. }
  102. writel (temp, &ehci->regs->port_status [i]);
  103. }
  104. i = HCS_N_PORTS (ehci->hcs_params);
  105. mdelay (20);
  106. while (i--) {
  107. temp = readl (&ehci->regs->port_status [i]);
  108. if ((temp & PORT_SUSPEND) == 0)
  109. continue;
  110. temp &= ~PORT_RESUME;
  111. writel (temp, &ehci->regs->port_status [i]);
  112. ehci_vdbg (ehci, "resumed port %d\n", i + 1);
  113. }
  114. (void) readl (&ehci->regs->command);
  115. /* maybe re-activate the schedule(s) */
  116. temp = 0;
  117. if (ehci->async->qh_next.qh)
  118. temp |= CMD_ASE;
  119. if (ehci->periodic_sched)
  120. temp |= CMD_PSE;
  121. if (temp) {
  122. ehci->command |= temp;
  123. writel (ehci->command, &ehci->regs->command);
  124. }
  125. ehci->next_statechange = jiffies + msecs_to_jiffies(5);
  126. hcd->state = HC_STATE_RUNNING;
  127. /* Now we can safely re-enable irqs */
  128. if (intr_enable)
  129. writel (INTR_MASK, &ehci->regs->intr_enable);
  130. spin_unlock_irq (&ehci->lock);
  131. return 0;
  132. }
  133. #else
  134. #define ehci_hub_suspend NULL
  135. #define ehci_hub_resume NULL
  136. #endif /* CONFIG_PM */
  137. /*-------------------------------------------------------------------------*/
  138. static int check_reset_complete (
  139. struct ehci_hcd *ehci,
  140. int index,
  141. int port_status
  142. ) {
  143. if (!(port_status & PORT_CONNECT)) {
  144. ehci->reset_done [index] = 0;
  145. return port_status;
  146. }
  147. /* if reset finished and it's still not enabled -- handoff */
  148. if (!(port_status & PORT_PE)) {
  149. /* with integrated TT, there's nobody to hand it to! */
  150. if (ehci_is_TDI(ehci)) {
  151. ehci_dbg (ehci,
  152. "Failed to enable port %d on root hub TT\n",
  153. index+1);
  154. return port_status;
  155. }
  156. ehci_dbg (ehci, "port %d full speed --> companion\n",
  157. index + 1);
  158. // what happens if HCS_N_CC(params) == 0 ?
  159. port_status |= PORT_OWNER;
  160. writel (port_status, &ehci->regs->port_status [index]);
  161. } else
  162. ehci_dbg (ehci, "port %d high speed\n", index + 1);
  163. return port_status;
  164. }
  165. /*-------------------------------------------------------------------------*/
  166. /* build "status change" packet (one or two bytes) from HC registers */
  167. static int
  168. ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
  169. {
  170. struct ehci_hcd *ehci = hcd_to_ehci (hcd);
  171. u32 temp, status = 0;
  172. int ports, i, retval = 1;
  173. unsigned long flags;
  174. /* if !USB_SUSPEND, root hub timers won't get shut down ... */
  175. if (!HC_IS_RUNNING(hcd->state))
  176. return 0;
  177. /* init status to no-changes */
  178. buf [0] = 0;
  179. ports = HCS_N_PORTS (ehci->hcs_params);
  180. if (ports > 7) {
  181. buf [1] = 0;
  182. retval++;
  183. }
  184. /* no hub change reports (bit 0) for now (power, ...) */
  185. /* port N changes (bit N)? */
  186. spin_lock_irqsave (&ehci->lock, flags);
  187. for (i = 0; i < ports; i++) {
  188. temp = readl (&ehci->regs->port_status [i]);
  189. if (temp & PORT_OWNER) {
  190. /* don't report this in GetPortStatus */
  191. if (temp & PORT_CSC) {
  192. temp &= ~PORT_CSC;
  193. writel (temp, &ehci->regs->port_status [i]);
  194. }
  195. continue;
  196. }
  197. if (!(temp & PORT_CONNECT))
  198. ehci->reset_done [i] = 0;
  199. if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0
  200. // PORT_STAT_C_SUSPEND?
  201. || ((temp & PORT_RESUME) != 0
  202. && time_after (jiffies,
  203. ehci->reset_done [i]))) {
  204. if (i < 7)
  205. buf [0] |= 1 << (i + 1);
  206. else
  207. buf [1] |= 1 << (i - 7);
  208. status = STS_PCD;
  209. }
  210. }
  211. /* FIXME autosuspend idle root hubs */
  212. spin_unlock_irqrestore (&ehci->lock, flags);
  213. return status ? retval : 0;
  214. }
  215. /*-------------------------------------------------------------------------*/
  216. static void
  217. ehci_hub_descriptor (
  218. struct ehci_hcd *ehci,
  219. struct usb_hub_descriptor *desc
  220. ) {
  221. int ports = HCS_N_PORTS (ehci->hcs_params);
  222. u16 temp;
  223. desc->bDescriptorType = 0x29;
  224. desc->bPwrOn2PwrGood = 10; /* ehci 1.0, 2.3.9 says 20ms max */
  225. desc->bHubContrCurrent = 0;
  226. desc->bNbrPorts = ports;
  227. temp = 1 + (ports / 8);
  228. desc->bDescLength = 7 + 2 * temp;
  229. /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
  230. memset (&desc->bitmap [0], 0, temp);
  231. memset (&desc->bitmap [temp], 0xff, temp);
  232. temp = 0x0008; /* per-port overcurrent reporting */
  233. if (HCS_PPC (ehci->hcs_params))
  234. temp |= 0x0001; /* per-port power control */
  235. else
  236. temp |= 0x0002; /* no power switching */
  237. #if 0
  238. // re-enable when we support USB_PORT_FEAT_INDICATOR below.
  239. if (HCS_INDICATOR (ehci->hcs_params))
  240. temp |= 0x0080; /* per-port indicators (LEDs) */
  241. #endif
  242. desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp);
  243. }
  244. /*-------------------------------------------------------------------------*/
  245. #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
  246. static int ehci_hub_control (
  247. struct usb_hcd *hcd,
  248. u16 typeReq,
  249. u16 wValue,
  250. u16 wIndex,
  251. char *buf,
  252. u16 wLength
  253. ) {
  254. struct ehci_hcd *ehci = hcd_to_ehci (hcd);
  255. int ports = HCS_N_PORTS (ehci->hcs_params);
  256. u32 temp, status;
  257. unsigned long flags;
  258. int retval = 0;
  259. /*
  260. * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
  261. * HCS_INDICATOR may say we can change LEDs to off/amber/green.
  262. * (track current state ourselves) ... blink for diagnostics,
  263. * power, "this is the one", etc. EHCI spec supports this.
  264. */
  265. spin_lock_irqsave (&ehci->lock, flags);
  266. switch (typeReq) {
  267. case ClearHubFeature:
  268. switch (wValue) {
  269. case C_HUB_LOCAL_POWER:
  270. case C_HUB_OVER_CURRENT:
  271. /* no hub-wide feature/status flags */
  272. break;
  273. default:
  274. goto error;
  275. }
  276. break;
  277. case ClearPortFeature:
  278. if (!wIndex || wIndex > ports)
  279. goto error;
  280. wIndex--;
  281. temp = readl (&ehci->regs->port_status [wIndex]);
  282. if (temp & PORT_OWNER)
  283. break;
  284. switch (wValue) {
  285. case USB_PORT_FEAT_ENABLE:
  286. writel (temp & ~PORT_PE,
  287. &ehci->regs->port_status [wIndex]);
  288. break;
  289. case USB_PORT_FEAT_C_ENABLE:
  290. writel (temp | PORT_PEC,
  291. &ehci->regs->port_status [wIndex]);
  292. break;
  293. case USB_PORT_FEAT_SUSPEND:
  294. if (temp & PORT_RESET)
  295. goto error;
  296. if (temp & PORT_SUSPEND) {
  297. if ((temp & PORT_PE) == 0)
  298. goto error;
  299. /* resume signaling for 20 msec */
  300. writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,
  301. &ehci->regs->port_status [wIndex]);
  302. ehci->reset_done [wIndex] = jiffies
  303. + msecs_to_jiffies (20);
  304. }
  305. break;
  306. case USB_PORT_FEAT_C_SUSPEND:
  307. /* we auto-clear this feature */
  308. break;
  309. case USB_PORT_FEAT_POWER:
  310. if (HCS_PPC (ehci->hcs_params))
  311. writel (temp & ~PORT_POWER,
  312. &ehci->regs->port_status [wIndex]);
  313. break;
  314. case USB_PORT_FEAT_C_CONNECTION:
  315. writel (temp | PORT_CSC,
  316. &ehci->regs->port_status [wIndex]);
  317. break;
  318. case USB_PORT_FEAT_C_OVER_CURRENT:
  319. writel (temp | PORT_OCC,
  320. &ehci->regs->port_status [wIndex]);
  321. break;
  322. case USB_PORT_FEAT_C_RESET:
  323. /* GetPortStatus clears reset */
  324. break;
  325. default:
  326. goto error;
  327. }
  328. readl (&ehci->regs->command); /* unblock posted write */
  329. break;
  330. case GetHubDescriptor:
  331. ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
  332. buf);
  333. break;
  334. case GetHubStatus:
  335. /* no hub-wide feature/status flags */
  336. memset (buf, 0, 4);
  337. //cpu_to_le32s ((u32 *) buf);
  338. break;
  339. case GetPortStatus:
  340. if (!wIndex || wIndex > ports)
  341. goto error;
  342. wIndex--;
  343. status = 0;
  344. temp = readl (&ehci->regs->port_status [wIndex]);
  345. // wPortChange bits
  346. if (temp & PORT_CSC)
  347. status |= 1 << USB_PORT_FEAT_C_CONNECTION;
  348. if (temp & PORT_PEC)
  349. status |= 1 << USB_PORT_FEAT_C_ENABLE;
  350. if (temp & PORT_OCC)
  351. status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
  352. /* whoever resumes must GetPortStatus to complete it!! */
  353. if ((temp & PORT_RESUME)
  354. && time_after (jiffies,
  355. ehci->reset_done [wIndex])) {
  356. status |= 1 << USB_PORT_FEAT_C_SUSPEND;
  357. ehci->reset_done [wIndex] = 0;
  358. /* stop resume signaling */
  359. temp = readl (&ehci->regs->port_status [wIndex]);
  360. writel (temp & ~PORT_RESUME,
  361. &ehci->regs->port_status [wIndex]);
  362. retval = handshake (
  363. &ehci->regs->port_status [wIndex],
  364. PORT_RESUME, 0, 2000 /* 2msec */);
  365. if (retval != 0) {
  366. ehci_err (ehci, "port %d resume error %d\n",
  367. wIndex + 1, retval);
  368. goto error;
  369. }
  370. temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
  371. }
  372. /* whoever resets must GetPortStatus to complete it!! */
  373. if ((temp & PORT_RESET)
  374. && time_after (jiffies,
  375. ehci->reset_done [wIndex])) {
  376. status |= 1 << USB_PORT_FEAT_C_RESET;
  377. ehci->reset_done [wIndex] = 0;
  378. /* force reset to complete */
  379. writel (temp & ~PORT_RESET,
  380. &ehci->regs->port_status [wIndex]);
  381. retval = handshake (
  382. &ehci->regs->port_status [wIndex],
  383. PORT_RESET, 0, 500);
  384. if (retval != 0) {
  385. ehci_err (ehci, "port %d reset error %d\n",
  386. wIndex + 1, retval);
  387. goto error;
  388. }
  389. /* see what we found out */
  390. temp = check_reset_complete (ehci, wIndex,
  391. readl (&ehci->regs->port_status [wIndex]));
  392. }
  393. // don't show wPortStatus if it's owned by a companion hc
  394. if (!(temp & PORT_OWNER)) {
  395. if (temp & PORT_CONNECT) {
  396. status |= 1 << USB_PORT_FEAT_CONNECTION;
  397. // status may be from integrated TT
  398. status |= ehci_port_speed(ehci, temp);
  399. }
  400. if (temp & PORT_PE)
  401. status |= 1 << USB_PORT_FEAT_ENABLE;
  402. if (temp & (PORT_SUSPEND|PORT_RESUME))
  403. status |= 1 << USB_PORT_FEAT_SUSPEND;
  404. if (temp & PORT_OC)
  405. status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
  406. if (temp & PORT_RESET)
  407. status |= 1 << USB_PORT_FEAT_RESET;
  408. if (temp & PORT_POWER)
  409. status |= 1 << USB_PORT_FEAT_POWER;
  410. }
  411. #ifndef EHCI_VERBOSE_DEBUG
  412. if (status & ~0xffff) /* only if wPortChange is interesting */
  413. #endif
  414. dbg_port (ehci, "GetStatus", wIndex + 1, temp);
  415. // we "know" this alignment is good, caller used kmalloc()...
  416. *((__le32 *) buf) = cpu_to_le32 (status);
  417. break;
  418. case SetHubFeature:
  419. switch (wValue) {
  420. case C_HUB_LOCAL_POWER:
  421. case C_HUB_OVER_CURRENT:
  422. /* no hub-wide feature/status flags */
  423. break;
  424. default:
  425. goto error;
  426. }
  427. break;
  428. case SetPortFeature:
  429. if (!wIndex || wIndex > ports)
  430. goto error;
  431. wIndex--;
  432. temp = readl (&ehci->regs->port_status [wIndex]);
  433. if (temp & PORT_OWNER)
  434. break;
  435. switch (wValue) {
  436. case USB_PORT_FEAT_SUSPEND:
  437. if ((temp & PORT_PE) == 0
  438. || (temp & PORT_RESET) != 0)
  439. goto error;
  440. if (hcd->remote_wakeup)
  441. temp |= PORT_WAKE_BITS;
  442. writel (temp | PORT_SUSPEND,
  443. &ehci->regs->port_status [wIndex]);
  444. break;
  445. case USB_PORT_FEAT_POWER:
  446. if (HCS_PPC (ehci->hcs_params))
  447. writel (temp | PORT_POWER,
  448. &ehci->regs->port_status [wIndex]);
  449. break;
  450. case USB_PORT_FEAT_RESET:
  451. if (temp & PORT_RESUME)
  452. goto error;
  453. /* line status bits may report this as low speed,
  454. * which can be fine if this root hub has a
  455. * transaction translator built in.
  456. */
  457. if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
  458. && !ehci_is_TDI(ehci)
  459. && PORT_USB11 (temp)) {
  460. ehci_dbg (ehci,
  461. "port %d low speed --> companion\n",
  462. wIndex + 1);
  463. temp |= PORT_OWNER;
  464. } else {
  465. ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
  466. temp |= PORT_RESET;
  467. temp &= ~PORT_PE;
  468. /*
  469. * caller must wait, then call GetPortStatus
  470. * usb 2.0 spec says 50 ms resets on root
  471. */
  472. ehci->reset_done [wIndex] = jiffies
  473. + msecs_to_jiffies (50);
  474. }
  475. writel (temp, &ehci->regs->port_status [wIndex]);
  476. break;
  477. default:
  478. goto error;
  479. }
  480. readl (&ehci->regs->command); /* unblock posted writes */
  481. break;
  482. default:
  483. error:
  484. /* "stall" on error */
  485. retval = -EPIPE;
  486. }
  487. spin_unlock_irqrestore (&ehci->lock, flags);
  488. return retval;
  489. }