diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-12-14 14:54:08 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 18:44:32 -0500 |
commit | 083522d76662cda71328df1f3d75e5a9057c7c9f (patch) | |
tree | eafbb962ec90431d0c1b490b4caea7cf9b54672c /drivers/usb/host/ehci-hcd.c | |
parent | 11d1a4aa8d657478cb2e5d33f203ba8f01b9ac24 (diff) |
USB: Implement support for EHCI with big endian MMIO
This patch implements supports for EHCI controllers whose MMIO
registers are big endian and enables that functionality for
the Toshiba SCC chip. It does _not_ add support for big endian
in-memory data structures as this is not needed for that chip
and I hope it will never be.
The guts of the patch are to convert readl(...) to
ehci_readl(ehci, ...) and similarly for register writes.
Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Geoff Levand <geoffrey.levand@am.sony.com>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 92 |
1 files changed, 50 insertions, 42 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 025d33313681..03d567e4d00a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); | |||
157 | * before driver shutdown. But it also seems to be caused by bugs in cardbus | 157 | * before driver shutdown. But it also seems to be caused by bugs in cardbus |
158 | * bridge shutdown: shutting down the bridge before the devices using it. | 158 | * bridge shutdown: shutting down the bridge before the devices using it. |
159 | */ | 159 | */ |
160 | static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) | 160 | static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, |
161 | u32 mask, u32 done, int usec) | ||
161 | { | 162 | { |
162 | u32 result; | 163 | u32 result; |
163 | 164 | ||
164 | do { | 165 | do { |
165 | result = readl (ptr); | 166 | result = ehci_readl(ehci, ptr); |
166 | if (result == ~(u32)0) /* card removed */ | 167 | if (result == ~(u32)0) /* card removed */ |
167 | return -ENODEV; | 168 | return -ENODEV; |
168 | result &= mask; | 169 | result &= mask; |
@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) | |||
177 | /* force HC to halt state from unknown (EHCI spec section 2.3) */ | 178 | /* force HC to halt state from unknown (EHCI spec section 2.3) */ |
178 | static int ehci_halt (struct ehci_hcd *ehci) | 179 | static int ehci_halt (struct ehci_hcd *ehci) |
179 | { | 180 | { |
180 | u32 temp = readl (&ehci->regs->status); | 181 | u32 temp = ehci_readl(ehci, &ehci->regs->status); |
181 | 182 | ||
182 | /* disable any irqs left enabled by previous code */ | 183 | /* disable any irqs left enabled by previous code */ |
183 | writel (0, &ehci->regs->intr_enable); | 184 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); |
184 | 185 | ||
185 | if ((temp & STS_HALT) != 0) | 186 | if ((temp & STS_HALT) != 0) |
186 | return 0; | 187 | return 0; |
187 | 188 | ||
188 | temp = readl (&ehci->regs->command); | 189 | temp = ehci_readl(ehci, &ehci->regs->command); |
189 | temp &= ~CMD_RUN; | 190 | temp &= ~CMD_RUN; |
190 | writel (temp, &ehci->regs->command); | 191 | ehci_writel(ehci, temp, &ehci->regs->command); |
191 | return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); | 192 | return handshake (ehci, &ehci->regs->status, |
193 | STS_HALT, STS_HALT, 16 * 125); | ||
192 | } | 194 | } |
193 | 195 | ||
194 | /* put TDI/ARC silicon into EHCI mode */ | 196 | /* put TDI/ARC silicon into EHCI mode */ |
@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci) | |||
198 | u32 tmp; | 200 | u32 tmp; |
199 | 201 | ||
200 | reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); | 202 | reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); |
201 | tmp = readl (reg_ptr); | 203 | tmp = ehci_readl(ehci, reg_ptr); |
202 | tmp |= 0x3; | 204 | tmp |= 0x3; |
203 | writel (tmp, reg_ptr); | 205 | ehci_writel(ehci, tmp, reg_ptr); |
204 | } | 206 | } |
205 | 207 | ||
206 | /* reset a non-running (STS_HALT == 1) controller */ | 208 | /* reset a non-running (STS_HALT == 1) controller */ |
207 | static int ehci_reset (struct ehci_hcd *ehci) | 209 | static int ehci_reset (struct ehci_hcd *ehci) |
208 | { | 210 | { |
209 | int retval; | 211 | int retval; |
210 | u32 command = readl (&ehci->regs->command); | 212 | u32 command = ehci_readl(ehci, &ehci->regs->command); |
211 | 213 | ||
212 | command |= CMD_RESET; | 214 | command |= CMD_RESET; |
213 | dbg_cmd (ehci, "reset", command); | 215 | dbg_cmd (ehci, "reset", command); |
214 | writel (command, &ehci->regs->command); | 216 | ehci_writel(ehci, command, &ehci->regs->command); |
215 | ehci_to_hcd(ehci)->state = HC_STATE_HALT; | 217 | ehci_to_hcd(ehci)->state = HC_STATE_HALT; |
216 | ehci->next_statechange = jiffies; | 218 | ehci->next_statechange = jiffies; |
217 | retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); | 219 | retval = handshake (ehci, &ehci->regs->command, |
220 | CMD_RESET, 0, 250 * 1000); | ||
218 | 221 | ||
219 | if (retval) | 222 | if (retval) |
220 | return retval; | 223 | return retval; |
@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci) | |||
236 | #endif | 239 | #endif |
237 | 240 | ||
238 | /* wait for any schedule enables/disables to take effect */ | 241 | /* wait for any schedule enables/disables to take effect */ |
239 | temp = readl (&ehci->regs->command) << 10; | 242 | temp = ehci_readl(ehci, &ehci->regs->command) << 10; |
240 | temp &= STS_ASS | STS_PSS; | 243 | temp &= STS_ASS | STS_PSS; |
241 | if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, | 244 | if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, |
242 | temp, 16 * 125) != 0) { | 245 | temp, 16 * 125) != 0) { |
243 | ehci_to_hcd(ehci)->state = HC_STATE_HALT; | 246 | ehci_to_hcd(ehci)->state = HC_STATE_HALT; |
244 | return; | 247 | return; |
245 | } | 248 | } |
246 | 249 | ||
247 | /* then disable anything that's still active */ | 250 | /* then disable anything that's still active */ |
248 | temp = readl (&ehci->regs->command); | 251 | temp = ehci_readl(ehci, &ehci->regs->command); |
249 | temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); | 252 | temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); |
250 | writel (temp, &ehci->regs->command); | 253 | ehci_writel(ehci, temp, &ehci->regs->command); |
251 | 254 | ||
252 | /* hardware can take 16 microframes to turn off ... */ | 255 | /* hardware can take 16 microframes to turn off ... */ |
253 | if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, | 256 | if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, |
254 | 0, 16 * 125) != 0) { | 257 | 0, 16 * 125) != 0) { |
255 | ehci_to_hcd(ehci)->state = HC_STATE_HALT; | 258 | ehci_to_hcd(ehci)->state = HC_STATE_HALT; |
256 | return; | 259 | return; |
@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param) | |||
277 | 280 | ||
278 | /* lost IAA irqs wedge things badly; seen with a vt8235 */ | 281 | /* lost IAA irqs wedge things badly; seen with a vt8235 */ |
279 | if (ehci->reclaim) { | 282 | if (ehci->reclaim) { |
280 | u32 status = readl (&ehci->regs->status); | 283 | u32 status = ehci_readl(ehci, &ehci->regs->status); |
281 | if (status & STS_IAA) { | 284 | if (status & STS_IAA) { |
282 | ehci_vdbg (ehci, "lost IAA\n"); | 285 | ehci_vdbg (ehci, "lost IAA\n"); |
283 | COUNT (ehci->stats.lost_iaa); | 286 | COUNT (ehci->stats.lost_iaa); |
284 | writel (STS_IAA, &ehci->regs->status); | 287 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); |
285 | ehci->reclaim_ready = 1; | 288 | ehci->reclaim_ready = 1; |
286 | } | 289 | } |
287 | } | 290 | } |
@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd) | |||
309 | (void) ehci_halt (ehci); | 312 | (void) ehci_halt (ehci); |
310 | 313 | ||
311 | /* make BIOS/etc use companion controller during reboot */ | 314 | /* make BIOS/etc use companion controller during reboot */ |
312 | writel (0, &ehci->regs->configured_flag); | 315 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); |
313 | } | 316 | } |
314 | 317 | ||
315 | static void ehci_port_power (struct ehci_hcd *ehci, int is_on) | 318 | static void ehci_port_power (struct ehci_hcd *ehci, int is_on) |
@@ -379,11 +382,11 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
379 | ehci_quiesce (ehci); | 382 | ehci_quiesce (ehci); |
380 | 383 | ||
381 | ehci_reset (ehci); | 384 | ehci_reset (ehci); |
382 | writel (0, &ehci->regs->intr_enable); | 385 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); |
383 | spin_unlock_irq(&ehci->lock); | 386 | spin_unlock_irq(&ehci->lock); |
384 | 387 | ||
385 | /* let companion controllers work when we aren't */ | 388 | /* let companion controllers work when we aren't */ |
386 | writel (0, &ehci->regs->configured_flag); | 389 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); |
387 | 390 | ||
388 | remove_debug_files (ehci); | 391 | remove_debug_files (ehci); |
389 | 392 | ||
@@ -402,7 +405,8 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
402 | ehci->stats.complete, ehci->stats.unlink); | 405 | ehci->stats.complete, ehci->stats.unlink); |
403 | #endif | 406 | #endif |
404 | 407 | ||
405 | dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); | 408 | dbg_status (ehci, "ehci_stop completed", |
409 | ehci_readl(ehci, &ehci->regs->status)); | ||
406 | } | 410 | } |
407 | 411 | ||
408 | /* one-time init, only for memory state */ | 412 | /* one-time init, only for memory state */ |
@@ -428,7 +432,7 @@ static int ehci_init(struct usb_hcd *hcd) | |||
428 | return retval; | 432 | return retval; |
429 | 433 | ||
430 | /* controllers may cache some of the periodic schedule ... */ | 434 | /* controllers may cache some of the periodic schedule ... */ |
431 | hcc_params = readl(&ehci->caps->hcc_params); | 435 | hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); |
432 | if (HCC_ISOC_CACHE(hcc_params)) // full frame cache | 436 | if (HCC_ISOC_CACHE(hcc_params)) // full frame cache |
433 | ehci->i_thresh = 8; | 437 | ehci->i_thresh = 8; |
434 | else // N microframes cached | 438 | else // N microframes cached |
@@ -501,8 +505,8 @@ static int ehci_run (struct usb_hcd *hcd) | |||
501 | ehci_mem_cleanup(ehci); | 505 | ehci_mem_cleanup(ehci); |
502 | return retval; | 506 | return retval; |
503 | } | 507 | } |
504 | writel(ehci->periodic_dma, &ehci->regs->frame_list); | 508 | ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); |
505 | writel((u32)ehci->async->qh_dma, &ehci->regs->async_next); | 509 | ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); |
506 | 510 | ||
507 | /* | 511 | /* |
508 | * hcc_params controls whether ehci->regs->segment must (!!!) | 512 | * hcc_params controls whether ehci->regs->segment must (!!!) |
@@ -516,9 +520,9 @@ static int ehci_run (struct usb_hcd *hcd) | |||
516 | * Scsi_Host.highmem_io, and so forth. It's readonly to all | 520 | * Scsi_Host.highmem_io, and so forth. It's readonly to all |
517 | * host side drivers though. | 521 | * host side drivers though. |
518 | */ | 522 | */ |
519 | hcc_params = readl(&ehci->caps->hcc_params); | 523 | hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); |
520 | if (HCC_64BIT_ADDR(hcc_params)) { | 524 | if (HCC_64BIT_ADDR(hcc_params)) { |
521 | writel(0, &ehci->regs->segment); | 525 | ehci_writel(ehci, 0, &ehci->regs->segment); |
522 | #if 0 | 526 | #if 0 |
523 | // this is deeply broken on almost all architectures | 527 | // this is deeply broken on almost all architectures |
524 | if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK)) | 528 | if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK)) |
@@ -531,7 +535,7 @@ static int ehci_run (struct usb_hcd *hcd) | |||
531 | // root hub will detect new devices (why?); NEC doesn't | 535 | // root hub will detect new devices (why?); NEC doesn't |
532 | ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); | 536 | ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); |
533 | ehci->command |= CMD_RUN; | 537 | ehci->command |= CMD_RUN; |
534 | writel (ehci->command, &ehci->regs->command); | 538 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
535 | dbg_cmd (ehci, "init", ehci->command); | 539 | dbg_cmd (ehci, "init", ehci->command); |
536 | 540 | ||
537 | /* | 541 | /* |
@@ -541,17 +545,18 @@ static int ehci_run (struct usb_hcd *hcd) | |||
541 | * and there's no companion controller unless maybe for USB OTG.) | 545 | * and there's no companion controller unless maybe for USB OTG.) |
542 | */ | 546 | */ |
543 | hcd->state = HC_STATE_RUNNING; | 547 | hcd->state = HC_STATE_RUNNING; |
544 | writel (FLAG_CF, &ehci->regs->configured_flag); | 548 | ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); |
545 | readl (&ehci->regs->command); /* unblock posted writes */ | 549 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ |
546 | 550 | ||
547 | temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); | 551 | temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); |
548 | ehci_info (ehci, | 552 | ehci_info (ehci, |
549 | "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", | 553 | "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", |
550 | ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), | 554 | ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), |
551 | temp >> 8, temp & 0xff, DRIVER_VERSION, | 555 | temp >> 8, temp & 0xff, DRIVER_VERSION, |
552 | ignore_oc ? ", overcurrent ignored" : ""); | 556 | ignore_oc ? ", overcurrent ignored" : ""); |
553 | 557 | ||
554 | writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ | 558 | ehci_writel(ehci, INTR_MASK, |
559 | &ehci->regs->intr_enable); /* Turn On Interrupts */ | ||
555 | 560 | ||
556 | /* GRR this is run-once init(), being done every time the HC starts. | 561 | /* GRR this is run-once init(), being done every time the HC starts. |
557 | * So long as they're part of class devices, we can't do it init() | 562 | * So long as they're part of class devices, we can't do it init() |
@@ -572,7 +577,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
572 | 577 | ||
573 | spin_lock (&ehci->lock); | 578 | spin_lock (&ehci->lock); |
574 | 579 | ||
575 | status = readl (&ehci->regs->status); | 580 | status = ehci_readl(ehci, &ehci->regs->status); |
576 | 581 | ||
577 | /* e.g. cardbus physical eject */ | 582 | /* e.g. cardbus physical eject */ |
578 | if (status == ~(u32) 0) { | 583 | if (status == ~(u32) 0) { |
@@ -587,8 +592,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
587 | } | 592 | } |
588 | 593 | ||
589 | /* clear (just) interrupts */ | 594 | /* clear (just) interrupts */ |
590 | writel (status, &ehci->regs->status); | 595 | ehci_writel(ehci, status, &ehci->regs->status); |
591 | readl (&ehci->regs->command); /* unblock posted write */ | 596 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ |
592 | bh = 0; | 597 | bh = 0; |
593 | 598 | ||
594 | #ifdef EHCI_VERBOSE_DEBUG | 599 | #ifdef EHCI_VERBOSE_DEBUG |
@@ -619,11 +624,12 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
619 | unsigned i = HCS_N_PORTS (ehci->hcs_params); | 624 | unsigned i = HCS_N_PORTS (ehci->hcs_params); |
620 | 625 | ||
621 | /* resume root hub? */ | 626 | /* resume root hub? */ |
622 | if (!(readl(&ehci->regs->command) & CMD_RUN)) | 627 | if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) |
623 | usb_hcd_resume_root_hub(hcd); | 628 | usb_hcd_resume_root_hub(hcd); |
624 | 629 | ||
625 | while (i--) { | 630 | while (i--) { |
626 | int pstatus = readl (&ehci->regs->port_status [i]); | 631 | int pstatus = ehci_readl(ehci, |
632 | &ehci->regs->port_status [i]); | ||
627 | 633 | ||
628 | if (pstatus & PORT_OWNER) | 634 | if (pstatus & PORT_OWNER) |
629 | continue; | 635 | continue; |
@@ -643,14 +649,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
643 | /* PCI errors [4.15.2.4] */ | 649 | /* PCI errors [4.15.2.4] */ |
644 | if (unlikely ((status & STS_FATAL) != 0)) { | 650 | if (unlikely ((status & STS_FATAL) != 0)) { |
645 | /* bogus "fatal" IRQs appear on some chips... why? */ | 651 | /* bogus "fatal" IRQs appear on some chips... why? */ |
646 | status = readl (&ehci->regs->status); | 652 | status = ehci_readl(ehci, &ehci->regs->status); |
647 | dbg_cmd (ehci, "fatal", readl (&ehci->regs->command)); | 653 | dbg_cmd (ehci, "fatal", ehci_readl(ehci, |
654 | &ehci->regs->command)); | ||
648 | dbg_status (ehci, "fatal", status); | 655 | dbg_status (ehci, "fatal", status); |
649 | if (status & STS_HALT) { | 656 | if (status & STS_HALT) { |
650 | ehci_err (ehci, "fatal error\n"); | 657 | ehci_err (ehci, "fatal error\n"); |
651 | dead: | 658 | dead: |
652 | ehci_reset (ehci); | 659 | ehci_reset (ehci); |
653 | writel (0, &ehci->regs->configured_flag); | 660 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); |
654 | /* generic layer kills/unlinks all urbs, then | 661 | /* generic layer kills/unlinks all urbs, then |
655 | * uses ehci_stop to clean up the rest | 662 | * uses ehci_stop to clean up the rest |
656 | */ | 663 | */ |
@@ -873,7 +880,8 @@ done: | |||
873 | static int ehci_get_frame (struct usb_hcd *hcd) | 880 | static int ehci_get_frame (struct usb_hcd *hcd) |
874 | { | 881 | { |
875 | struct ehci_hcd *ehci = hcd_to_ehci (hcd); | 882 | struct ehci_hcd *ehci = hcd_to_ehci (hcd); |
876 | return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; | 883 | return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) % |
884 | ehci->periodic_size; | ||
877 | } | 885 | } |
878 | 886 | ||
879 | /*-------------------------------------------------------------------------*/ | 887 | /*-------------------------------------------------------------------------*/ |