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