Commit 083522d7 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Greg Kroah-Hartman

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: default avatarKou Ishizaki <kou.ishizaki@toshiba.co.jp>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: default avatarGeoff Levand <geoffrey.levand@am.sony.com>
Acked-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 11d1a4aa
...@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED ...@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say N. If unsure, say N.
config USB_EHCI_BIG_ENDIAN_MMIO
bool
depends on USB_EHCI_HCD
default n
config USB_ISP116X_HCD config USB_ISP116X_HCD
tristate "ISP116X HCD support" tristate "ISP116X HCD support"
depends on USB depends on USB
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
*/ */
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
{ {
u32 params = readl (&ehci->caps->hcs_params); u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_dbg (ehci, ehci_dbg (ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n", "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
...@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} ...@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
* */ * */
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
{ {
u32 params = readl (&ehci->caps->hcc_params); u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE (params)) { if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci, ehci_dbg (ehci,
...@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf) ...@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
} }
/* Capability Registers */ /* Capability Registers */
i = HC_VERSION(readl (&ehci->caps->hc_capbase)); i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size, temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n" "bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n" "%s\n"
...@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf) ...@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4; unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
while (offset && count--) { while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap); pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) { switch (cap & 0xff) {
...@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf) ...@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
#endif #endif
// FIXME interpret both types of params // FIXME interpret both types of params
i = readl (&ehci->caps->hcs_params); i = ehci_readl(ehci, &ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i); temp = scnprintf (next, size, "structural params 0x%08x\n", i);
size -= temp; size -= temp;
next += temp; next += temp;
i = readl (&ehci->caps->hcc_params); i = ehci_readl(ehci, &ehci->caps->hcc_params);
temp = scnprintf (next, size, "capability params 0x%08x\n", i); temp = scnprintf (next, size, "capability params 0x%08x\n", i);
size -= temp; size -= temp;
next += temp; next += temp;
/* Operational Registers */ /* Operational Registers */
temp = dbg_status_buf (scratch, sizeof scratch, label, temp = dbg_status_buf (scratch, sizeof scratch, label,
readl (&ehci->regs->status)); ehci_readl(ehci, &ehci->regs->status));
temp = scnprintf (next, size, fmt, temp, scratch); temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp; size -= temp;
next += temp; next += temp;
temp = dbg_command_buf (scratch, sizeof scratch, label, temp = dbg_command_buf (scratch, sizeof scratch, label,
readl (&ehci->regs->command)); ehci_readl(ehci, &ehci->regs->command));
temp = scnprintf (next, size, fmt, temp, scratch); temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp; size -= temp;
next += temp; next += temp;
temp = dbg_intr_buf (scratch, sizeof scratch, label, temp = dbg_intr_buf (scratch, sizeof scratch, label,
readl (&ehci->regs->intr_enable)); ehci_readl(ehci, &ehci->regs->intr_enable));
temp = scnprintf (next, size, fmt, temp, scratch); temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp; size -= temp;
next += temp; next += temp;
temp = scnprintf (next, size, "uframe %04x\n", temp = scnprintf (next, size, "uframe %04x\n",
readl (&ehci->regs->frame_index)); ehci_readl(ehci, &ehci->regs->frame_index));
size -= temp; size -= temp;
next += temp; next += temp;
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) { for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i, temp = dbg_port_buf (scratch, sizeof scratch, label, i,
readl (&ehci->regs->port_status [i - 1])); ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch); temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp; size -= temp;
next += temp; next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) { if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size, temp = scnprintf (next, size,
" debug control %08x\n", " debug control %08x\n",
readl (&ehci->debug->control)); ehci_readl(ehci, &ehci->debug->control));
size -= temp; size -= temp;
next += temp; next += temp;
} }
......
...@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci, ...@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
case FSL_USB2_PHY_NONE: case FSL_USB2_PHY_NONE:
break; break;
} }
writel(portsc, &ehci->regs->port_status[port_offset]); ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
} }
static void mpc83xx_usb_setup(struct usb_hcd *hcd) static void mpc83xx_usb_setup(struct usb_hcd *hcd)
...@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd) ...@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
} }
/* put controller in host mode. */ /* put controller in host mode. */
writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE); ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
...@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) ...@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */ /* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100; ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 + ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(readl(&ehci->caps->hc_capbase)); HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */ /* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci); retval = ehci_halt(ehci);
if (retval) if (retval)
......
...@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); ...@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
* before driver shutdown. But it also seems to be caused by bugs in cardbus * before driver shutdown. But it also seems to be caused by bugs in cardbus
* bridge shutdown: shutting down the bridge before the devices using it. * bridge shutdown: shutting down the bridge before the devices using it.
*/ */
static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
u32 mask, u32 done, int usec)
{ {
u32 result; u32 result;
do { do {
result = readl (ptr); result = ehci_readl(ehci, ptr);
if (result == ~(u32)0) /* card removed */ if (result == ~(u32)0) /* card removed */
return -ENODEV; return -ENODEV;
result &= mask; result &= mask;
...@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) ...@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
/* force HC to halt state from unknown (EHCI spec section 2.3) */ /* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci) static int ehci_halt (struct ehci_hcd *ehci)
{ {
u32 temp = readl (&ehci->regs->status); u32 temp = ehci_readl(ehci, &ehci->regs->status);
/* disable any irqs left enabled by previous code */ /* disable any irqs left enabled by previous code */
writel (0, &ehci->regs->intr_enable); ehci_writel(ehci, 0, &ehci->regs->intr_enable);
if ((temp & STS_HALT) != 0) if ((temp & STS_HALT) != 0)
return 0; return 0;
temp = readl (&ehci->regs->command); temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~CMD_RUN; temp &= ~CMD_RUN;
writel (temp, &ehci->regs->command); ehci_writel(ehci, temp, &ehci->regs->command);
return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); return handshake (ehci, &ehci->regs->status,
STS_HALT, STS_HALT, 16 * 125);
} }
/* put TDI/ARC silicon into EHCI mode */ /* put TDI/ARC silicon into EHCI mode */
...@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci) ...@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 tmp; u32 tmp;
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
tmp = readl (reg_ptr); tmp = ehci_readl(ehci, reg_ptr);
tmp |= 0x3; tmp |= 0x3;
writel (tmp, reg_ptr); ehci_writel(ehci, tmp, reg_ptr);
} }
/* reset a non-running (STS_HALT == 1) controller */ /* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset (struct ehci_hcd *ehci) static int ehci_reset (struct ehci_hcd *ehci)
{ {
int retval; int retval;
u32 command = readl (&ehci->regs->command); u32 command = ehci_readl(ehci, &ehci->regs->command);
command |= CMD_RESET; command |= CMD_RESET;
dbg_cmd (ehci, "reset", command); dbg_cmd (ehci, "reset", command);
writel (command, &ehci->regs->command); ehci_writel(ehci, command, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci_to_hcd(ehci)->state = HC_STATE_HALT;
ehci->next_statechange = jiffies; ehci->next_statechange = jiffies;
retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); retval = handshake (ehci, &ehci->regs->command,
CMD_RESET, 0, 250 * 1000);
if (retval) if (retval)
return retval; return retval;
...@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci) ...@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif #endif
/* wait for any schedule enables/disables to take effect */ /* wait for any schedule enables/disables to take effect */
temp = readl (&ehci->regs->command) << 10; temp = ehci_readl(ehci, &ehci->regs->command) << 10;
temp &= STS_ASS | STS_PSS; temp &= STS_ASS | STS_PSS;
if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) { temp, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return; return;
} }
/* then disable anything that's still active */ /* then disable anything that's still active */
temp = readl (&ehci->regs->command); temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
writel (temp, &ehci->regs->command); ehci_writel(ehci, temp, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */ /* hardware can take 16 microframes to turn off ... */
if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
0, 16 * 125) != 0) { 0, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return; return;
...@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param) ...@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param)
/* lost IAA irqs wedge things badly; seen with a vt8235 */ /* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) { if (ehci->reclaim) {
u32 status = readl (&ehci->regs->status); u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) { if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n"); ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa); COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status); ehci_writel(ehci, STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1; ehci->reclaim_ready = 1;
} }
} }
...@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd) ...@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
(void) ehci_halt (ehci); (void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */ /* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag); ehci_writel(ehci, 0, &ehci->regs->configured_flag);
} }
static void ehci_port_power (struct ehci_hcd *ehci, int is_on) 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,11 +382,11 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_quiesce (ehci); ehci_quiesce (ehci);
ehci_reset (ehci); ehci_reset (ehci);
writel (0, &ehci->regs->intr_enable); ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock); spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */ /* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag); ehci_writel(ehci, 0, &ehci->regs->configured_flag);
remove_debug_files (ehci); remove_debug_files (ehci);
...@@ -402,7 +405,8 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -402,7 +405,8 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci->stats.complete, ehci->stats.unlink); ehci->stats.complete, ehci->stats.unlink);
#endif #endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); dbg_status (ehci, "ehci_stop completed",
ehci_readl(ehci, &ehci->regs->status));
} }
/* one-time init, only for memory state */ /* one-time init, only for memory state */
...@@ -428,7 +432,7 @@ static int ehci_init(struct usb_hcd *hcd) ...@@ -428,7 +432,7 @@ static int ehci_init(struct usb_hcd *hcd)
return retval; return retval;
/* controllers may cache some of the periodic schedule ... */ /* controllers may cache some of the periodic schedule ... */
hcc_params = readl(&ehci->caps->hcc_params); hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8; ehci->i_thresh = 8;
else // N microframes cached else // N microframes cached
...@@ -501,8 +505,8 @@ static int ehci_run (struct usb_hcd *hcd) ...@@ -501,8 +505,8 @@ static int ehci_run (struct usb_hcd *hcd)
ehci_mem_cleanup(ehci); ehci_mem_cleanup(ehci);
return retval; return retval;
} }
writel(ehci->periodic_dma, &ehci->regs->frame_list); ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
writel((u32)ehci->async->qh_dma, &ehci->regs->async_next); ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/* /*
* hcc_params controls whether ehci->regs->segment must (!!!) * hcc_params controls whether ehci->regs->segment must (!!!)
...@@ -516,9 +520,9 @@ static int ehci_run (struct usb_hcd *hcd) ...@@ -516,9 +520,9 @@ static int ehci_run (struct usb_hcd *hcd)
* Scsi_Host.highmem_io, and so forth. It's readonly to all * Scsi_Host.highmem_io, and so forth. It's readonly to all
* host side drivers though. * host side drivers though.
*/ */
hcc_params = readl(&ehci->caps->hcc_params); hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_64BIT_ADDR(hcc_params)) { if (HCC_64BIT_ADDR(hcc_params)) {
writel(0, &ehci->regs->segment); ehci_writel(ehci, 0, &ehci->regs->segment);
#if 0 #if 0
// this is deeply broken on almost all architectures // this is deeply broken on almost all architectures
if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK)) if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
...@@ -531,7 +535,7 @@ static int ehci_run (struct usb_hcd *hcd) ...@@ -531,7 +535,7 @@ static int ehci_run (struct usb_hcd *hcd)
// root hub will detect new devices (why?); NEC doesn't // root hub will detect new devices (why?); NEC doesn't
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN; ehci->command |= CMD_RUN;
writel (ehci->command, &ehci->regs->command); ehci_writel(ehci, ehci->command, &ehci->regs->command);
dbg_cmd (ehci, "init", ehci->command); dbg_cmd (ehci, "init", ehci->command);
/* /*
...@@ -541,17 +545,18 @@ static int ehci_run (struct usb_hcd *hcd) ...@@ -541,17 +545,18 @@ static int ehci_run (struct usb_hcd *hcd)
* and there's no companion controller unless maybe for USB OTG.) * and there's no companion controller unless maybe for USB OTG.)
*/ */
hcd->state = HC_STATE_RUNNING; hcd->state = HC_STATE_RUNNING;
writel (FLAG_CF, &ehci->regs->configured_flag); ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
readl (&ehci->regs->command); /* unblock posted writes */ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci, ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x, driver %s%s\n", "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION, temp >> 8, temp & 0xff, DRIVER_VERSION,
ignore_oc ? ", overcurrent ignored" : ""); ignore_oc ? ", overcurrent ignored" : "");
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ ehci_writel(ehci, INTR_MASK,
&ehci->regs->intr_enable); /* Turn On Interrupts */
/* GRR this is run-once init(), being done every time the HC starts. /* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init() * 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,7 +577,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
spin_lock (&ehci->lock); spin_lock (&ehci->lock);
status = readl (&ehci->regs->status); status = ehci_readl(ehci, &ehci->regs->status);
/* e.g. cardbus physical eject */ /* e.g. cardbus physical eject */
if (status == ~(u32) 0) { if (status == ~(u32) 0) {
...@@ -587,8 +592,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) ...@@ -587,8 +592,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
} }
/* clear (just) interrupts */ /* clear (just) interrupts */
writel (status, &ehci->regs->status); ehci_writel(ehci, status, &ehci->regs->status);
readl (&ehci->regs->command); /* unblock posted write */ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
bh = 0; bh = 0;
#ifdef EHCI_VERBOSE_DEBUG #ifdef EHCI_VERBOSE_DEBUG
...@@ -619,11 +624,12 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) ...@@ -619,11 +624,12 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
unsigned i = HCS_N_PORTS (ehci->hcs_params); unsigned i = HCS_N_PORTS (ehci->hcs_params);
/* resume root hub? */ /* resume root hub? */
if (!(readl(&ehci->regs->command) & CMD_RUN)) if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd);
while (i--) { while (i--) {
int pstatus = readl (&ehci->regs->port_status [i]); int pstatus = ehci_readl(ehci,
&ehci->regs->port_status [i]);
if (pstatus & PORT_OWNER) if (pstatus & PORT_OWNER)
continue; continue;
...@@ -643,14 +649,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) ...@@ -643,14 +649,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */ /* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) { if (unlikely ((status & STS_FATAL) != 0)) {
/* bogus "fatal" IRQs appear on some chips... why? */ /* bogus "fatal" IRQs appear on some chips... why? */
status = readl (&ehci->regs->status); status = ehci_readl(ehci, &ehci->regs->status);
dbg_cmd (ehci, "fatal", readl (&ehci->regs->command)); dbg_cmd (ehci, "fatal", ehci_readl(ehci,
&ehci->regs->command));
dbg_status (ehci, "fatal", status); dbg_status (ehci, "fatal", status);
if (status & STS_HALT) { if (status & STS_HALT) {
ehci_err (ehci, "fatal error\n"); ehci_err (ehci, "fatal error\n");
dead: dead:
ehci_reset (ehci); ehci_reset (ehci);
writel (0, &ehci->regs->configured_flag); ehci_writel(ehci, 0, &ehci->regs->configured_flag);
/* generic layer kills/unlinks all urbs, then /* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest * uses ehci_stop to clean up the rest
*/ */
...@@ -873,7 +880,8 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ...@@ -873,7 +880,8 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
static int ehci_get_frame (struct usb_hcd *hcd) static int ehci_get_frame (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
ehci->periodic_size;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
This diff is collapsed.
...@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) ...@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if ((temp & (3 << 13)) == (1 << 13)) { if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff; temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp; ehci->debug = ehci_to_hcd(ehci)->regs + temp;
temp = readl(&ehci->debug->control); temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n", ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params), HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED) (temp & DBGP_ENABLED)
...@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ...@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
u32 temp; u32 temp;
int retval; int retval;
switch (pdev->vendor) {
case PCI_VENDOR_ID_TOSHIBA_2:
/* celleb's companion chip */
if (pdev->device == 0x01b5) {
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
ehci->big_endian_mmio = 1;
#else
ehci_warn(ehci,
"unsupported big endian Toshiba quirk\n");
#endif
}
break;
}
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); ehci->regs = hcd->regs +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");
...@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ...@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
} }
/* cache this readonly data; minimize chip reads */ /* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci); retval = ehci_halt(ehci);
if (retval) if (retval)
...@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) ...@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
rc = -EINVAL; rc = -EINVAL;
goto bail; goto bail;
} }
writel (0, &ehci->regs->intr_enable); ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)readl(&ehci->regs->intr_enable); (void)ehci_readl(ehci, &ehci->regs->intr_enable);
/* make sure snapshot being resumed re-enumerates everything */ /* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW) { if (message.event == PM_EVENT_PRETHAW) {
...@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd) ...@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* If CF is still set, we maintained PCI Vaux power. /* If CF is still set, we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend(). * Just undo the effect of ehci_pci_suspend().
*/ */
if (readl(&ehci->regs->configured_flag) == FLAG_CF) { if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK; int mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev)) if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD; mask &= ~STS_PCD;
writel(mask, &ehci->regs->intr_enable); ehci_writel(ehci, mask, &ehci->regs->intr_enable);
readl(&ehci->regs->intr_enable); ehci_readl(ehci, &ehci->regs->intr_enable);
return 0; return 0;
} }
...@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd) ...@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* here we "know" root ports should always stay powered */ /* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1); ehci_port_power(ehci, 1);
writel(ehci->command, &ehci->regs->command); ehci_writel(ehci, ehci->command, &ehci->regs->command);
writel(FLAG_CF, &ehci->regs->configured_flag); ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
readl(&ehci->regs->command); /* unblock posted writes */ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
hcd->state = HC_STATE_SUSPENDED; hcd->state = HC_STATE_SUSPENDED;
return 0; return 0;
......
...@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async; head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF); timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) { if (!head->qh_next.qh) {
u32 cmd = readl (&ehci->regs->command); u32 cmd = ehci_readl(ehci, &ehci->regs->command);
if (!(cmd & CMD_ASE)) { if (!(cmd & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */ /* in case a clear of CMD_ASE didn't take yet */
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150); (void)handshake(ehci, &ehci->regs->status,
STS_ASS, 0, 150);
cmd |= CMD_ASE | CMD_RUN; cmd |= CMD_ASE | CMD_RUN;
writel (cmd, &ehci->regs->command); ehci_writel(ehci, cmd, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */ /* posted write need not be known to HC yet ... */
} }
...@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) ...@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
int cmd = readl (&ehci->regs->command); int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev; struct ehci_qh *prev;
#ifdef DEBUG #ifdef DEBUG
...@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
&& !ehci->reclaim) { && !ehci->reclaim) {
/* ... and CMD_IAAD clear */ /* ... and CMD_IAAD clear */
writel (cmd & ~CMD_ASE, &ehci->regs->command); ehci_writel(ehci, cmd & ~CMD_ASE,
&ehci->regs->command);
wmb (); wmb ();
// handshake later, if we need to // handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF); timer_action_done (ehci, TIMER_ASYNC_OFF);
...@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->reclaim_ready = 0; ehci->reclaim_ready = 0;
cmd |= CMD_IAAD; cmd |= CMD_IAAD;
writel (cmd, &ehci->regs->command); ehci_writel(ehci, cmd, &ehci->regs->command);
(void) readl (&ehci->regs->command); (void)ehci_readl(ehci, &ehci->regs->command);
timer_action (ehci, TIMER_IAA_WATCHDOG); timer_action (ehci, TIMER_IAA_WATCHDOG);
} }
......
...@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci) ...@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* did clearing PSE did take effect yet? /* did clearing PSE did take effect yet?
* takes effect only at frame boundaries... * takes effect only at frame boundaries...
*/ */
status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) { if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status; return status;
} }
cmd = readl (&ehci->regs->command) | CMD_PSE; cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
writel (cmd, &ehci->regs->command); ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... PSS happens later */ /* posted write ... PSS happens later */
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* make sure ehci_work scans these */ /* make sure ehci_work scans these */
ehci->next_uframe = readl (&ehci->regs->frame_index) ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
% (ehci->periodic_size << 3); % (ehci->periodic_size << 3);
return 0; return 0;
} }
...@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci) ...@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
/* did setting PSE not take effect yet? /* did setting PSE not take effect yet?
* takes effect only at frame boundaries... * takes effect only at frame boundaries...
*/ */
status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) { if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status; return status;
} }
cmd = readl (&ehci->regs->command) & ~CMD_PSE; cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
writel (cmd, &ehci->regs->command); ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */ /* posted write ... */
ehci->next_uframe = -1; ehci->next_uframe = -1;
...@@ -1336,7 +1336,7 @@ iso_stream_schedule ( ...@@ -1336,7 +1336,7 @@ iso_stream_schedule (
goto fail; goto fail;
} }
now = readl (&ehci->regs->frame_index) % mod; now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */ /* when's the last uframe this urb could start? */
max = now + mod; max = now + mod;
...@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci) ...@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
*/ */
now_uframe = ehci->next_uframe; now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
clock = readl (&ehci->regs->frame_index); clock = ehci_readl(ehci, &ehci->regs->frame_index);
else else
clock = now_uframe + mod - 1; clock = now_uframe + mod - 1;
clock %= mod; clock %= mod;
...@@ -2213,7 +2213,7 @@ scan_periodic (struct ehci_hcd *ehci) ...@@ -2213,7 +2213,7 @@ scan_periodic (struct ehci_hcd *ehci)
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
break; break;
ehci->next_uframe = now_uframe; ehci->next_uframe = now_uframe;
now = readl (&ehci->regs->frame_index) % mod; now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
if (now_uframe == now) if (now_uframe == now)
break; break;
......
...@@ -92,6 +92,7 @@ struct ehci_hcd { /* one per controller */ ...@@ -92,6 +92,7 @@ struct ehci_hcd { /* one per controller */
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
unsigned no_selective_suspend:1; unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */ unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
u8 sbrn; /* packed release number */ u8 sbrn; /* packed release number */
...@@ -651,6 +652,37 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) ...@@ -651,6 +652,37 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_portno_bug(e) (0) #define ehci_has_fsl_portno_bug(e) (0)
#endif #endif
/*
* While most USB host controllers implement their registers in
* little-endian format, a minority (celleb companion chip) implement
* them in big endian format.
*
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
#else
#define ehci_big_endian_mmio(e) 0
#endif
static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
__u32 __iomem * regs)
{
return ehci_big_endian_mmio(ehci) ?
readl_be((__force u32 *)regs) :
readl((__force u32 *)regs);
}
static inline void ehci_writel (const struct ehci_hcd *ehci,
const unsigned int val, __u32 __iomem *regs)
{
ehci_big_endian_mmio(ehci) ?
writel_be(val, (__force u32 *)regs) :
writel(val, (__force u32 *)regs);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment