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 0
150 #define ehci_hub_resume 0
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 port_status |= PORT_OWNER;
182 writel (port_status, &ehci->regs->port_status [index]);
185 ehci_dbg (ehci, "port %d high speed\n", index + 1);
190 /*-------------------------------------------------------------------------*/
193 /* build "status change" packet (one or two bytes) from HC registers */
196 ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
198 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
199 u32 temp, status = 0;
200 int ports, i, retval = 1;
203 /* init status to no-changes */
205 ports = HCS_N_PORTS (ehci->hcs_params);
211 /* no hub change reports (bit 0) for now (power, ...) */
213 /* port N changes (bit N)? */
214 spin_lock_irqsave (&ehci->lock, flags);
215 for (i = 0; i < ports; i++) {
216 temp = readl (&ehci->regs->port_status [i]);
217 if (temp & PORT_OWNER) {
218 /* don't report this in GetPortStatus */
219 if (temp & PORT_CSC) {
221 writel (temp, &ehci->regs->port_status [i]);
225 if (!(temp & PORT_CONNECT))
226 ehci->reset_done [i] = 0;
227 if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0
228 // PORT_STAT_C_SUSPEND?
229 || ((temp & PORT_RESUME) != 0
230 && time_after (jiffies,
231 ehci->reset_done [i]))) {
233 buf [0] |= 1 << (i + 1);
235 buf [1] |= 1 << (i - 7);
239 spin_unlock_irqrestore (&ehci->lock, flags);
240 return status ? retval : 0;
243 /*-------------------------------------------------------------------------*/
246 ehci_hub_descriptor (
247 struct ehci_hcd *ehci,
248 struct usb_hub_descriptor *desc
250 int ports = HCS_N_PORTS (ehci->hcs_params);
253 desc->bDescriptorType = 0x29;
254 desc->bPwrOn2PwrGood = 10; /* ehci 1.0, 2.3.9 says 20ms max */
255 desc->bHubContrCurrent = 0;
257 desc->bNbrPorts = ports;
258 temp = 1 + (ports / 8);
259 desc->bDescLength = 7 + 2 * temp;
261 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
262 memset (&desc->bitmap [0], 0, temp);
263 memset (&desc->bitmap [temp], 0xff, temp);
265 temp = 0x0008; /* per-port overcurrent reporting */
266 if (HCS_PPC (ehci->hcs_params))
267 temp |= 0x0001; /* per-port power control */
268 if (HCS_INDICATOR (ehci->hcs_params))
269 temp |= 0x0080; /* per-port indicators (LEDs) */
270 desc->wHubCharacteristics = cpu_to_le16 (temp);
273 /*-------------------------------------------------------------------------*/
275 #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
277 static int ehci_hub_control (
285 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
286 int ports = HCS_N_PORTS (ehci->hcs_params);
292 * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
293 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
294 * (track current state ourselves) ... blink for diagnostics,
295 * power, "this is the one", etc. EHCI spec supports this.
298 spin_lock_irqsave (&ehci->lock, flags);
300 case ClearHubFeature:
302 case C_HUB_LOCAL_POWER:
303 case C_HUB_OVER_CURRENT:
304 /* no hub-wide feature/status flags */
310 case ClearPortFeature:
311 if (!wIndex || wIndex > ports)
314 temp = readl (&ehci->regs->port_status [wIndex]);
315 if (temp & PORT_OWNER)
319 case USB_PORT_FEAT_ENABLE:
320 writel (temp & ~PORT_PE,
321 &ehci->regs->port_status [wIndex]);
323 case USB_PORT_FEAT_C_ENABLE:
324 writel (temp | PORT_PEC,
325 &ehci->regs->port_status [wIndex]);
327 case USB_PORT_FEAT_SUSPEND:
328 if (temp & PORT_RESET)
330 if (temp & PORT_SUSPEND) {
331 if ((temp & PORT_PE) == 0)
333 /* resume signaling for 20 msec */
334 writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,
335 &ehci->regs->port_status [wIndex]);
336 ehci->reset_done [wIndex] = jiffies
337 + msecs_to_jiffies (20);
340 case USB_PORT_FEAT_C_SUSPEND:
341 /* we auto-clear this feature */
343 case USB_PORT_FEAT_POWER:
344 if (HCS_PPC (ehci->hcs_params))
345 writel (temp & ~PORT_POWER,
346 &ehci->regs->port_status [wIndex]);
348 case USB_PORT_FEAT_C_CONNECTION:
349 writel (temp | PORT_CSC,
350 &ehci->regs->port_status [wIndex]);
352 case USB_PORT_FEAT_C_OVER_CURRENT:
353 writel (temp | PORT_OCC,
354 &ehci->regs->port_status [wIndex]);
356 case USB_PORT_FEAT_C_RESET:
357 /* GetPortStatus clears reset */
362 readl (&ehci->regs->command); /* unblock posted write */
364 case GetHubDescriptor:
365 ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
369 /* no hub-wide feature/status flags */
371 //cpu_to_le32s ((u32 *) buf);
374 if (!wIndex || wIndex > ports)
378 temp = readl (&ehci->regs->port_status [wIndex]);
382 status |= 1 << USB_PORT_FEAT_C_CONNECTION;
384 status |= 1 << USB_PORT_FEAT_C_ENABLE;
386 status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
388 /* whoever resumes must GetPortStatus to complete it!! */
389 if ((temp & PORT_RESUME)
390 && time_after (jiffies,
391 ehci->reset_done [wIndex])) {
392 status |= 1 << USB_PORT_FEAT_C_SUSPEND;
393 ehci->reset_done [wIndex] = 0;
395 /* stop resume signaling */
396 temp = readl (&ehci->regs->port_status [wIndex]);
397 writel (temp & ~PORT_RESUME,
398 &ehci->regs->port_status [wIndex]);
400 &ehci->regs->port_status [wIndex],
401 PORT_RESUME, 0, 2000 /* 2msec */);
403 ehci_err (ehci, "port %d resume error %d\n",
407 temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
410 /* whoever resets must GetPortStatus to complete it!! */
411 if ((temp & PORT_RESET)
412 && time_after (jiffies,
413 ehci->reset_done [wIndex])) {
414 status |= 1 << USB_PORT_FEAT_C_RESET;
415 ehci->reset_done [wIndex] = 0;
417 /* force reset to complete */
418 writel (temp & ~PORT_RESET,
419 &ehci->regs->port_status [wIndex]);
421 &ehci->regs->port_status [wIndex],
424 ehci_err (ehci, "port %d reset error %d\n",
429 /* see what we found out */
430 temp = check_reset_complete (ehci, wIndex,
431 readl (&ehci->regs->port_status [wIndex]));
434 // don't show wPortStatus if it's owned by a companion hc
435 if (!(temp & PORT_OWNER)) {
436 if (temp & PORT_CONNECT) {
437 status |= 1 << USB_PORT_FEAT_CONNECTION;
438 // status may be from integrated TT
439 status |= ehci_port_speed(ehci, temp);
442 status |= 1 << USB_PORT_FEAT_ENABLE;
443 if (temp & (PORT_SUSPEND|PORT_RESUME))
444 status |= 1 << USB_PORT_FEAT_SUSPEND;
446 status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
447 if (temp & PORT_RESET)
448 status |= 1 << USB_PORT_FEAT_RESET;
449 if (temp & PORT_POWER)
450 status |= 1 << USB_PORT_FEAT_POWER;
453 #ifndef EHCI_VERBOSE_DEBUG
454 if (status & ~0xffff) /* only if wPortChange is interesting */
456 dbg_port (ehci, "GetStatus", wIndex + 1, temp);
457 // we "know" this alignment is good, caller used kmalloc()...
458 *((u32 *) buf) = cpu_to_le32 (status);
462 case C_HUB_LOCAL_POWER:
463 case C_HUB_OVER_CURRENT:
464 /* no hub-wide feature/status flags */
471 if (!wIndex || wIndex > ports)
474 temp = readl (&ehci->regs->port_status [wIndex]);
475 if (temp & PORT_OWNER)
479 case USB_PORT_FEAT_SUSPEND:
480 if ((temp & PORT_PE) == 0
481 || (temp & PORT_RESET) != 0)
483 if (ehci->hcd.remote_wakeup)
484 temp |= PORT_WAKE_BITS;
485 writel (temp | PORT_SUSPEND,
486 &ehci->regs->port_status [wIndex]);
488 case USB_PORT_FEAT_POWER:
489 if (HCS_PPC (ehci->hcs_params))
490 writel (temp | PORT_POWER,
491 &ehci->regs->port_status [wIndex]);
493 case USB_PORT_FEAT_RESET:
494 if (temp & PORT_RESUME)
496 /* line status bits may report this as low speed,
497 * which can be fine if this root hub has a
498 * transaction translator built in.
500 if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
501 && !ehci_is_ARC(ehci)
502 && PORT_USB11 (temp)) {
504 "port %d low speed --> companion\n",
508 ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
513 * caller must wait, then call GetPortStatus
514 * usb 2.0 spec says 50 ms resets on root
516 ehci->reset_done [wIndex] = jiffies
517 + msecs_to_jiffies (50);
519 writel (temp, &ehci->regs->port_status [wIndex]);
524 readl (&ehci->regs->command); /* unblock posted writes */
529 /* "stall" on error */
532 spin_unlock_irqrestore (&ehci->lock, flags);