2 * Copyright (c) 2001-2002 by David Brownell
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.
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
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.
19 /* this file is part of ehci-hcd.c */
21 /*-------------------------------------------------------------------------*/
24 * EHCI Root Hub ... the nonsharable stuff
26 * Registers don't need cpu_to_le32, that happens transparently
29 /*-------------------------------------------------------------------------*/
33 static int ehci_hub_suspend (struct usb_hcd
*hcd
)
35 struct ehci_hcd
*ehci
= hcd_to_ehci (hcd
);
36 struct usb_device
*root
= hcd_to_bus (&ehci
->hcd
)->root_hub
;
40 if (root
->dev
.power
.power_state
!= 0)
42 if (time_before (jiffies
, ehci
->next_statechange
))
45 port
= HCS_N_PORTS (ehci
->hcs_params
);
46 spin_lock_irq (&ehci
->lock
);
48 /* suspend any active/unsuspended ports, maybe allow wakeup */
50 u32 t1
= readl (&ehci
->regs
->port_status
[port
]);
53 if ((t1
& PORT_PE
) && !(t1
& PORT_OWNER
))
55 if (ehci
->hcd
.remote_wakeup
)
56 t2
|= PORT_WKOC_E
|PORT_WKDISC_E
|PORT_WKCONN_E
;
58 t2
&= ~(PORT_WKOC_E
|PORT_WKDISC_E
|PORT_WKCONN_E
);
61 ehci_vdbg (ehci
, "port %d, %08x -> %08x\n",
63 writel (t2
, &ehci
->regs
->port_status
[port
]);
67 /* stop schedules, then turn off HC and clean any completed work */
68 if (hcd
->state
== USB_STATE_RUNNING
)
70 ehci
->command
= readl (&ehci
->regs
->command
);
71 writel (ehci
->command
& ~CMD_RUN
, &ehci
->regs
->command
);
73 ehci
->reclaim_ready
= 1;
74 ehci_work(ehci
, NULL
);
75 (void) handshake (&ehci
->regs
->status
, STS_HALT
, STS_HALT
, 2000);
77 root
->dev
.power
.power_state
= 3;
78 ehci
->next_statechange
= jiffies
+ msecs_to_jiffies(10);
79 spin_unlock_irq (&ehci
->lock
);
84 /* caller owns root->serialize, and should reset/reinit on error */
85 static int ehci_hub_resume (struct usb_hcd
*hcd
)
87 struct ehci_hcd
*ehci
= hcd_to_ehci (hcd
);
88 struct usb_device
*root
= hcd_to_bus (&ehci
->hcd
)->root_hub
;
92 if (!root
->dev
.power
.power_state
)
94 if (time_before (jiffies
, ehci
->next_statechange
))
97 /* re-init operational registers in case we lost power */
98 if (readl (&ehci
->regs
->intr_enable
) == 0) {
99 writel (INTR_MASK
, &ehci
->regs
->intr_enable
);
100 writel (0, &ehci
->regs
->segment
);
101 writel (ehci
->periodic_dma
, &ehci
->regs
->frame_list
);
102 writel ((u32
)ehci
->async
->qh_dma
, &ehci
->regs
->async_next
);
103 /* FIXME will this work even (pci) vAUX was lost? */
106 /* restore CMD_RUN, framelist size, and irq threshold */
107 writel (ehci
->command
, &ehci
->regs
->command
);
109 /* take ports out of suspend */
110 i
= HCS_N_PORTS (ehci
->hcs_params
);
112 temp
= readl (&ehci
->regs
->port_status
[i
]);
113 temp
&= ~(PORT_WKOC_E
|PORT_WKDISC_E
|PORT_WKCONN_E
);
114 if (temp
& PORT_SUSPEND
) {
115 ehci
->reset_done
[i
] = jiffies
+ msecs_to_jiffies (20);
118 writel (temp
, &ehci
->regs
->port_status
[i
]);
120 i
= HCS_N_PORTS (ehci
->hcs_params
);
123 temp
= readl (&ehci
->regs
->port_status
[i
]);
124 if ((temp
& PORT_SUSPEND
) == 0)
126 temp
&= ~PORT_RESUME
;
127 writel (temp
, &ehci
->regs
->port_status
[i
]);
128 ehci_vdbg (ehci
, "resumed port %d\n", i
+ 1);
130 (void) readl (&ehci
->regs
->command
);
132 /* maybe re-activate the schedule(s) */
134 if (ehci
->async
->qh_next
.qh
)
136 if (ehci
->periodic_sched
)
139 writel (ehci
->command
| temp
, &ehci
->regs
->command
);
141 root
->dev
.power
.power_state
= 0;
142 ehci
->next_statechange
= jiffies
+ msecs_to_jiffies(5);
143 ehci
->hcd
.state
= USB_STATE_RUNNING
;
149 #define ehci_hub_suspend NULL
150 #define ehci_hub_resume NULL
152 #endif /* CONFIG_PM */
154 /*-------------------------------------------------------------------------*/
156 static int check_reset_complete (
157 struct ehci_hcd
*ehci
,
161 if (!(port_status
& PORT_CONNECT
)) {
162 ehci
->reset_done
[index
] = 0;
166 /* if reset finished and it's still not enabled -- handoff */
167 if (!(port_status
& PORT_PE
)) {
169 /* with integrated TT, there's nobody to hand it to! */
170 if (ehci_is_ARC(ehci
)) {
172 "Failed to enable port %d on root hub TT\n",
177 ehci_dbg (ehci
, "port %d full speed --> companion\n",
180 // what happens if HCS_N_CC(params) == 0 ?
181 #ifndef CONFIG_ARCH_MOXACPU // add by Victor Yu. 01-03-2006
182 port_status
|= PORT_OWNER
;
184 writel (port_status
, &ehci
->regs
->port_status
[index
]);
187 ehci_dbg (ehci
, "port %d high speed\n", index
+ 1);
192 /*-------------------------------------------------------------------------*/
195 /* build "status change" packet (one or two bytes) from HC registers */
198 ehci_hub_status_data (struct usb_hcd
*hcd
, char *buf
)
200 struct ehci_hcd
*ehci
= hcd_to_ehci (hcd
);
201 u32 temp
, status
= 0;
202 int ports
, i
, retval
= 1;
205 /* init status to no-changes */
207 ports
= HCS_N_PORTS (ehci
->hcs_params
);
213 /* no hub change reports (bit 0) for now (power, ...) */
215 /* port N changes (bit N)? */
216 spin_lock_irqsave (&ehci
->lock
, flags
);
217 for (i
= 0; i
< ports
; i
++) {
218 temp
= readl (&ehci
->regs
->port_status
[i
]);
219 if (temp
& PORT_OWNER
) {
220 /* don't report this in GetPortStatus */
221 if (temp
& PORT_CSC
) {
223 writel (temp
, &ehci
->regs
->port_status
[i
]);
227 if (!(temp
& PORT_CONNECT
))
228 ehci
->reset_done
[i
] = 0;
229 if ((temp
& (PORT_CSC
| PORT_PEC
| PORT_OCC
)) != 0
230 // PORT_STAT_C_SUSPEND?
231 || ((temp
& PORT_RESUME
) != 0
232 && time_after (jiffies
,
233 ehci
->reset_done
[i
]))) {
235 buf
[0] |= 1 << (i
+ 1);
237 buf
[1] |= 1 << (i
- 7);
241 spin_unlock_irqrestore (&ehci
->lock
, flags
);
242 return status
? retval
: 0;
245 /*-------------------------------------------------------------------------*/
248 ehci_hub_descriptor (
249 struct ehci_hcd
*ehci
,
250 struct usb_hub_descriptor
*desc
252 int ports
= HCS_N_PORTS (ehci
->hcs_params
);
255 desc
->bDescriptorType
= 0x29;
256 desc
->bPwrOn2PwrGood
= 10; /* ehci 1.0, 2.3.9 says 20ms max */
257 desc
->bHubContrCurrent
= 0;
259 desc
->bNbrPorts
= ports
;
260 temp
= 1 + (ports
/ 8);
261 desc
->bDescLength
= 7 + 2 * temp
;
263 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
264 memset (&desc
->bitmap
[0], 0, temp
);
265 memset (&desc
->bitmap
[temp
], 0xff, temp
);
267 temp
= 0x0008; /* per-port overcurrent reporting */
268 if (HCS_PPC (ehci
->hcs_params
))
269 temp
|= 0x0001; /* per-port power control */
270 if (HCS_INDICATOR (ehci
->hcs_params
))
271 temp
|= 0x0080; /* per-port indicators (LEDs) */
272 desc
->wHubCharacteristics
= cpu_to_le16 (temp
);
275 /*-------------------------------------------------------------------------*/
277 #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
279 static int ehci_hub_control (
287 struct ehci_hcd
*ehci
= hcd_to_ehci (hcd
);
288 int ports
= HCS_N_PORTS (ehci
->hcs_params
);
294 * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
295 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
296 * (track current state ourselves) ... blink for diagnostics,
297 * power, "this is the one", etc. EHCI spec supports this.
300 spin_lock_irqsave (&ehci
->lock
, flags
);
302 case ClearHubFeature
:
304 case C_HUB_LOCAL_POWER
:
305 case C_HUB_OVER_CURRENT
:
306 /* no hub-wide feature/status flags */
312 case ClearPortFeature
:
313 if (!wIndex
|| wIndex
> ports
)
316 #ifdef CONFIG_ARCH_MOXACPU // add by Victor Yu. 01-10-2006
317 // because the CPU IP has bug to need to do this
318 if ( wValue
== USB_PORT_FEAT_ENABLE
) {
319 temp
= readl(&ehci
->regs
->command
);
321 writel(temp
, &ehci
->regs
->command
);
326 temp
= readl (&ehci
->regs
->port_status
[wIndex
]);
327 #ifndef CONFIG_ARCH_MOXACPU // add by Victor Yu. 12-30-2005
328 if (temp
& PORT_OWNER
)
333 case USB_PORT_FEAT_ENABLE
:
334 writel (temp
& ~PORT_PE
,
335 &ehci
->regs
->port_status
[wIndex
]);
337 case USB_PORT_FEAT_C_ENABLE
:
338 writel (temp
| PORT_PEC
,
339 &ehci
->regs
->port_status
[wIndex
]);
341 case USB_PORT_FEAT_SUSPEND
:
342 if (temp
& PORT_RESET
)
344 if (temp
& PORT_SUSPEND
) {
345 if ((temp
& PORT_PE
) == 0)
347 /* resume signaling for 20 msec */
348 writel ((temp
& ~PORT_WAKE_BITS
) | PORT_RESUME
,
349 &ehci
->regs
->port_status
[wIndex
]);
350 ehci
->reset_done
[wIndex
] = jiffies
351 + msecs_to_jiffies (20);
354 case USB_PORT_FEAT_C_SUSPEND
:
355 /* we auto-clear this feature */
357 case USB_PORT_FEAT_POWER
:
358 if (HCS_PPC (ehci
->hcs_params
))
359 writel (temp
& ~PORT_POWER
,
360 &ehci
->regs
->port_status
[wIndex
]);
362 case USB_PORT_FEAT_C_CONNECTION
:
363 writel (temp
| PORT_CSC
,
364 &ehci
->regs
->port_status
[wIndex
]);
366 case USB_PORT_FEAT_C_OVER_CURRENT
:
367 writel (temp
| PORT_OCC
,
368 &ehci
->regs
->port_status
[wIndex
]);
370 case USB_PORT_FEAT_C_RESET
:
371 /* GetPortStatus clears reset */
376 readl (&ehci
->regs
->command
); /* unblock posted write */
378 case GetHubDescriptor
:
379 ehci_hub_descriptor (ehci
, (struct usb_hub_descriptor
*)
383 /* no hub-wide feature/status flags */
385 //cpu_to_le32s ((u32 *) buf);
388 if (!wIndex
|| wIndex
> ports
)
392 temp
= readl (&ehci
->regs
->port_status
[wIndex
]);
396 status
|= 1 << USB_PORT_FEAT_C_CONNECTION
;
398 status
|= 1 << USB_PORT_FEAT_C_ENABLE
;
400 status
|= 1 << USB_PORT_FEAT_C_OVER_CURRENT
;
402 /* whoever resumes must GetPortStatus to complete it!! */
403 if ((temp
& PORT_RESUME
)
404 && time_after (jiffies
,
405 ehci
->reset_done
[wIndex
])) {
406 status
|= 1 << USB_PORT_FEAT_C_SUSPEND
;
407 ehci
->reset_done
[wIndex
] = 0;
409 /* stop resume signaling */
410 temp
= readl (&ehci
->regs
->port_status
[wIndex
]);
411 writel (temp
& ~PORT_RESUME
,
412 &ehci
->regs
->port_status
[wIndex
]);
414 &ehci
->regs
->port_status
[wIndex
],
415 PORT_RESUME
, 0, 2000 /* 2msec */);
417 ehci_err (ehci
, "port %d resume error %d\n",
421 temp
&= ~(PORT_SUSPEND
|PORT_RESUME
|(3<<10));
424 /* whoever resets must GetPortStatus to complete it!! */
425 if ((temp
& PORT_RESET
)
426 && time_after (jiffies
,
427 ehci
->reset_done
[wIndex
])) {
428 status
|= 1 << USB_PORT_FEAT_C_RESET
;
429 ehci
->reset_done
[wIndex
] = 0;
431 /* force reset to complete */
432 writel (temp
& ~PORT_RESET
,
433 &ehci
->regs
->port_status
[wIndex
]);
435 &ehci
->regs
->port_status
[wIndex
],
438 ehci_err (ehci
, "port %d reset error %d\n",
443 /* see what we found out */
444 temp
= check_reset_complete (ehci
, wIndex
,
445 readl (&ehci
->regs
->port_status
[wIndex
]));
446 #ifdef CONFIG_ARCH_MOXACPU // add by Victor Yu. 02-10-2006
447 // because the CPU IP has bug to need to do this
448 // Frarady suggests me to modify here
449 writel(readl(&ehci
->regs
->command
)|CMD_RUN
, &ehci
->regs
->command
);
450 //ehci->hcd.state = USB_STATE_RUNNING;
454 // don't show wPortStatus if it's owned by a companion hc
455 if (!(temp
& PORT_OWNER
)) {
456 if (temp
& PORT_CONNECT
) {
457 status
|= 1 << USB_PORT_FEAT_CONNECTION
;
458 // status may be from integrated TT
459 status
|= ehci_port_speed(ehci
, temp
);
462 status
|= 1 << USB_PORT_FEAT_ENABLE
;
463 if (temp
& (PORT_SUSPEND
|PORT_RESUME
))
464 status
|= 1 << USB_PORT_FEAT_SUSPEND
;
466 status
|= 1 << USB_PORT_FEAT_OVER_CURRENT
;
467 if (temp
& PORT_RESET
)
468 status
|= 1 << USB_PORT_FEAT_RESET
;
469 if (temp
& PORT_POWER
)
470 status
|= 1 << USB_PORT_FEAT_POWER
;
473 #ifndef EHCI_VERBOSE_DEBUG
474 if (status
& ~0xffff) /* only if wPortChange is interesting */
476 dbg_port (ehci
, "GetStatus", wIndex
+ 1, temp
);
477 // we "know" this alignment is good, caller used kmalloc()...
478 *((__le32
*) buf
) = cpu_to_le32 (status
);
482 case C_HUB_LOCAL_POWER
:
483 case C_HUB_OVER_CURRENT
:
484 /* no hub-wide feature/status flags */
491 if (!wIndex
|| wIndex
> ports
)
494 temp
= readl (&ehci
->regs
->port_status
[wIndex
]);
495 #ifndef CONFIG_ARCH_MOXACPU // add by Victor Yu. 12-30-2005
496 if (temp
& PORT_OWNER
)
501 case USB_PORT_FEAT_SUSPEND
:
502 if ((temp
& PORT_PE
) == 0
503 || (temp
& PORT_RESET
) != 0)
505 if (ehci
->hcd
.remote_wakeup
)
506 temp
|= PORT_WAKE_BITS
;
507 writel (temp
| PORT_SUSPEND
,
508 &ehci
->regs
->port_status
[wIndex
]);
510 case USB_PORT_FEAT_POWER
:
511 if (HCS_PPC (ehci
->hcs_params
))
512 writel (temp
| PORT_POWER
,
513 &ehci
->regs
->port_status
[wIndex
]);
515 case USB_PORT_FEAT_RESET
:
516 if (temp
& PORT_RESUME
)
518 /* line status bits may report this as low speed,
519 * which can be fine if this root hub has a
520 * transaction translator built in.
522 if ((temp
& (PORT_PE
|PORT_CONNECT
)) == PORT_CONNECT
523 && !ehci_is_ARC(ehci
)
524 && PORT_USB11 (temp
)) {
526 "port %d low speed --> companion\n",
528 #ifndef CONFIG_ARCH_MOXACPU // add by Victor Yu. 01-03-2006
531 //add by Victor Yu.08-21-2007,for reset anyway
534 reset_done
://add by Victor Yu.08-21-2007,for reset anyway
535 ehci_vdbg (ehci
, "port %d reset\n", wIndex
+ 1);
540 * caller must wait, then call GetPortStatus
541 * usb 2.0 spec says 50 ms resets on root
543 ehci
->reset_done
[wIndex
] = jiffies
544 + msecs_to_jiffies (50);
546 writel (temp
, &ehci
->regs
->port_status
[wIndex
]);
551 readl (&ehci
->regs
->command
); /* unblock posted writes */
556 /* "stall" on error */
559 spin_unlock_irqrestore (&ehci
->lock
, flags
);