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 <[EMAIL PROTECTED]>
Signed-off-by: Benjamin Herrenschmidt <[EMAIL PROTECTED]>
Acked-by: David Brownell <[EMAIL PROTECTED]>

Index: linux-test-x86/drivers/usb/host/ehci-dbg.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-dbg.c     2006-12-13 
13:03:44.000000000 +1100
+++ linux-test-x86/drivers/usb/host/ehci-dbg.c  2006-12-13 13:06:02.000000000 
+1100
@@ -43,7 +43,7 @@
  */
 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,
                "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@
  * */
 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)) {
                ehci_dbg (ehci,
@@ -653,7 +653,7 @@
        }
 
        /* Capability Registers */
-       i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+       i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        temp = scnprintf (next, size,
                "bus %s, device %s (driver " DRIVER_VERSION ")\n"
                "%s\n"
@@ -673,7 +673,7 @@
                unsigned        count = 256/4;
 
                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--) {
                        pci_read_config_dword (pdev, offset, &cap);
                        switch (cap & 0xff) {
@@ -704,50 +704,50 @@
 #endif
 
        // 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);
        size -= 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);
        size -= temp;
        next += temp;
 
        /* Operational Registers */
        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);
        size -= temp;
        next += temp;
 
        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);
        size -= temp;
        next += temp;
 
        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);
        size -= temp;
        next += temp;
 
        temp = scnprintf (next, size, "uframe %04x\n",
-                       readl (&ehci->regs->frame_index));
+                       ehci_readl(ehci, &ehci->regs->frame_index));
        size -= temp;
        next += temp;
 
        for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); 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);
                size -= temp;
                next += temp;
                if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
                        temp = scnprintf (next, size,
                                        "    debug control %08x\n",
-                                       readl (&ehci->debug->control));
+                                       ehci_readl(ehci, 
&ehci->debug->control));
                        size -= temp;
                        next += temp;
                }
Index: linux-test-x86/drivers/usb/host/Kconfig
===================================================================
--- linux-test-x86.orig/drivers/usb/host/Kconfig        2006-12-13 
13:05:40.000000000 +1100
+++ linux-test-x86/drivers/usb/host/Kconfig     2006-12-13 13:06:02.000000000 
+1100
@@ -67,6 +67,11 @@
 
          If unsure, say N.
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+       bool
+       depends on USB_EHCI_HCD
+       default n
+
 config USB_ISP116X_HCD
        tristate "ISP116X HCD support"
        depends on USB
Index: linux-test-x86/drivers/usb/host/ehci-fsl.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-fsl.c     2006-09-28 
20:44:49.000000000 +1000
+++ linux-test-x86/drivers/usb/host/ehci-fsl.c  2006-12-13 13:06:02.000000000 
+1100
@@ -177,7 +177,7 @@
        case FSL_USB2_PHY_NONE:
                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)
@@ -214,7 +214,7 @@
        }
 
        /* 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_AGECNTTHRSH, 0x00000040);
        out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@
        /* EHCI registers start at offset 0x100 */
        ehci->caps = 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_hcc_params(ehci, "reset");
 
        /* 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);
        if (retval)
Index: linux-test-x86/drivers/usb/host/ehci-hcd.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-hcd.c     2006-12-13 
13:03:44.000000000 +1100
+++ linux-test-x86/drivers/usb/host/ehci-hcd.c  2006-12-13 13:06:02.000000000 
+1100
@@ -157,12 +157,13 @@
  * 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.
  */
-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;
 
        do {
-               result = readl (ptr);
+               result = ehci_readl(ehci, ptr);
                if (result == ~(u32)0)          /* card removed */
                        return -ENODEV;
                result &= mask;
@@ -177,18 +178,19 @@
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 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 */
-       writel (0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
        if ((temp & STS_HALT) != 0)
                return 0;
 
-       temp = readl (&ehci->regs->command);
+       temp = ehci_readl(ehci, &ehci->regs->command);
        temp &= ~CMD_RUN;
-       writel (temp, &ehci->regs->command);
-       return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+       ehci_writel(ehci, temp, &ehci->regs->command);
+       return handshake (ehci, &ehci->regs->status,
+                         STS_HALT, STS_HALT, 16 * 125);
 }
 
 /* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@
        u32             tmp;
 
        reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
-       tmp = readl (reg_ptr);
+       tmp = ehci_readl(ehci, reg_ptr);
        tmp |= 0x3;
-       writel (tmp, reg_ptr);
+       ehci_writel(ehci, tmp, reg_ptr);
 }
 
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
        int     retval;
-       u32     command = readl (&ehci->regs->command);
+       u32     command = ehci_readl(ehci, &ehci->regs->command);
 
        command |= CMD_RESET;
        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->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)
                return retval;
@@ -236,21 +239,21 @@
 #endif
 
        /* 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;
-       if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+       if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
                                temp, 16 * 125) != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return;
        }
 
        /* 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);
-       writel (temp, &ehci->regs->command);
+       ehci_writel(ehci, temp, &ehci->regs->command);
 
        /* 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) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return;
@@ -277,11 +280,11 @@
 
        /* lost IAA irqs wedge things badly; seen with a vt8235 */
        if (ehci->reclaim) {
-               u32             status = readl (&ehci->regs->status);
+               u32             status = ehci_readl(ehci, &ehci->regs->status);
                if (status & STS_IAA) {
                        ehci_vdbg (ehci, "lost IAA\n");
                        COUNT (ehci->stats.lost_iaa);
-                       writel (STS_IAA, &ehci->regs->status);
+                       ehci_writel(ehci, STS_IAA, &ehci->regs->status);
                        ehci->reclaim_ready = 1;
                }
        }
@@ -309,7 +312,7 @@
        (void) ehci_halt (ehci);
 
        /* 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)
@@ -379,11 +382,11 @@
                ehci_quiesce (ehci);
 
        ehci_reset (ehci);
-       writel (0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        spin_unlock_irq(&ehci->lock);
 
        /* 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);
 
@@ -402,7 +405,8 @@
                ehci->stats.complete, ehci->stats.unlink);
 #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 */
@@ -428,7 +432,7 @@
                return retval;
 
        /* 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
                ehci->i_thresh = 8;
        else                                    // N microframes cached
@@ -501,8 +505,8 @@
                ehci_mem_cleanup(ehci);
                return retval;
        }
-       writel(ehci->periodic_dma, &ehci->regs->frame_list);
-       writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+       ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+       ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
        /*
         * hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +520,9 @@
         * Scsi_Host.highmem_io, and so forth.  It's readonly to all
         * 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)) {
-               writel(0, &ehci->regs->segment);
+               ehci_writel(ehci, 0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
                if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +535,7 @@
        // 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_RUN;
-       writel (ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
        dbg_cmd (ehci, "init", ehci->command);
 
        /*
@@ -541,17 +545,18 @@
         * and there's no companion controller unless maybe for USB OTG.)
         */
        hcd->state = HC_STATE_RUNNING;
-       writel (FLAG_CF, &ehci->regs->configured_flag);
-       readl (&ehci->regs->command);   /* unblock posted writes */
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       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,
                "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
                ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
                temp >> 8, temp & 0xff, DRIVER_VERSION,
                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.
         * So long as they're part of class devices, we can't do it init()
@@ -572,7 +577,7 @@
 
        spin_lock (&ehci->lock);
 
-       status = readl (&ehci->regs->status);
+       status = ehci_readl(ehci, &ehci->regs->status);
 
        /* e.g. cardbus physical eject */
        if (status == ~(u32) 0) {
@@ -587,8 +592,8 @@
        }
 
        /* clear (just) interrupts */
-       writel (status, &ehci->regs->status);
-       readl (&ehci->regs->command);   /* unblock posted write */
+       ehci_writel(ehci, status, &ehci->regs->status);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
        bh = 0;
 
 #ifdef EHCI_VERBOSE_DEBUG
@@ -619,11 +624,12 @@
                unsigned        i = HCS_N_PORTS (ehci->hcs_params);
 
                /* 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);
 
                while (i--) {
-                       int pstatus = readl (&ehci->regs->port_status [i]);
+                       int pstatus = ehci_readl(ehci,
+                                                &ehci->regs->port_status [i]);
 
                        if (pstatus & PORT_OWNER)
                                continue;
@@ -643,14 +649,15 @@
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
                /* bogus "fatal" IRQs appear on some chips... why?  */
-               status = readl (&ehci->regs->status);
-               dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+               status = ehci_readl(ehci, &ehci->regs->status);
+               dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+                                                  &ehci->regs->command));
                dbg_status (ehci, "fatal", status);
                if (status & STS_HALT) {
                        ehci_err (ehci, "fatal error\n");
 dead:
                        ehci_reset (ehci);
-                       writel (0, &ehci->regs->configured_flag);
+                       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
                        /* generic layer kills/unlinks all urbs, then
                         * uses ehci_stop to clean up the rest
                         */
@@ -873,7 +880,8 @@
 static int ehci_get_frame (struct usb_hcd *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;
 }
 
 /*-------------------------------------------------------------------------*/
Index: linux-test-x86/drivers/usb/host/ehci-hub.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-hub.c     2006-12-13 
13:03:44.000000000 +1100
+++ linux-test-x86/drivers/usb/host/ehci-hub.c  2006-12-13 13:06:02.000000000 
+1100
@@ -47,7 +47,7 @@
                ehci_quiesce (ehci);
                hcd->state = HC_STATE_QUIESCING;
        }
-       ehci->command = readl (&ehci->regs->command);
+       ehci->command = ehci_readl(ehci, &ehci->regs->command);
        if (ehci->reclaim)
                ehci->reclaim_ready = 1;
        ehci_work(ehci);
@@ -60,7 +60,7 @@
        ehci->bus_suspended = 0;
        while (port--) {
                u32 __iomem     *reg = &ehci->regs->port_status [port];
-               u32             t1 = readl (reg) & ~PORT_RWC_BITS;
+               u32             t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
                u32             t2 = t1;
 
                /* keep track of which ports we suspend */
@@ -79,7 +79,7 @@
                if (t1 != t2) {
                        ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
                                port + 1, t1, t2);
-                       writel (t2, reg);
+                       ehci_writel(ehci, t2, reg);
                }
        }
 
@@ -92,8 +92,8 @@
        mask = INTR_MASK;
        if (!device_may_wakeup(&hcd->self.root_hub->dev))
                mask &= ~STS_PCD;
-       writel(mask, &ehci->regs->intr_enable);
-       readl(&ehci->regs->intr_enable);
+       ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+       ehci_readl(ehci, &ehci->regs->intr_enable);
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(10);
        spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@
         * the last user of the controller, not reset/pm hardware keeping
         * state we gave to it.
         */
-       temp = readl(&ehci->regs->intr_enable);
+       temp = ehci_readl(ehci, &ehci->regs->intr_enable);
        ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 
        /* at least some APM implementations will try to deliver
         * IRQs right away, so delay them until we're ready.
         */
-       writel(0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
        /* re-init operational registers */
-       writel(0, &ehci->regs->segment);
-       writel(ehci->periodic_dma, &ehci->regs->frame_list);
-       writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+       ehci_writel(ehci, 0, &ehci->regs->segment);
+       ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+       ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
        /* restore CMD_RUN, framelist size, and irq threshold */
-       writel (ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
        /* manually resume the ports we suspended during bus_suspend() */
        i = HCS_N_PORTS (ehci->hcs_params);
        while (i--) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                temp &= ~(PORT_RWC_BITS
                        | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
                if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@
                        ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
                        temp |= PORT_RESUME;
                }
-               writel (temp, &ehci->regs->port_status [i]);
+               ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
        }
        i = HCS_N_PORTS (ehci->hcs_params);
        mdelay (20);
        while (i--) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                if (test_bit(i, &ehci->bus_suspended) &&
                                (temp & PORT_SUSPEND)) {
                        temp &= ~(PORT_RWC_BITS | PORT_RESUME);
-                       writel (temp, &ehci->regs->port_status [i]);
+                       ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
                        ehci_vdbg (ehci, "resumed port %d\n", i + 1);
                }
        }
-       (void) readl (&ehci->regs->command);
+       (void) ehci_readl(ehci, &ehci->regs->command);
 
        /* maybe re-activate the schedule(s) */
        temp = 0;
@@ -168,14 +168,14 @@
                temp |= CMD_PSE;
        if (temp) {
                ehci->command |= temp;
-               writel (ehci->command, &ehci->regs->command);
+               ehci_writel(ehci, ehci->command, &ehci->regs->command);
        }
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(5);
        hcd->state = HC_STATE_RUNNING;
 
        /* Now we can safely re-enable irqs */
-       writel(INTR_MASK, &ehci->regs->intr_enable);
+       ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
        spin_unlock_irq (&ehci->lock);
        return 0;
@@ -217,7 +217,8 @@
                // what happens if HCS_N_CC(params) == 0 ?
                port_status |= PORT_OWNER;
                port_status &= ~PORT_RWC_BITS;
-               writel (port_status, &ehci->regs->port_status [index]);
+               ehci_writel(ehci, port_status,
+                           &ehci->regs->port_status [index]);
 
        } else
                ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,13 +269,14 @@
        /* port N changes (bit N)? */
        spin_lock_irqsave (&ehci->lock, flags);
        for (i = 0; i < ports; i++) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                if (temp & PORT_OWNER) {
                        /* don't report this in GetPortStatus */
                        if (temp & PORT_CSC) {
                                temp &= ~PORT_RWC_BITS;
                                temp |= PORT_CSC;
-                               writel (temp, &ehci->regs->port_status [i]);
+                               ehci_writel(ehci, temp,
+                                           &ehci->regs->port_status [i]);
                        }
                        continue;
                }
@@ -373,18 +375,18 @@
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]);
                if (temp & PORT_OWNER)
                        break;
 
                switch (wValue) {
                case USB_PORT_FEAT_ENABLE:
-                       writel (temp & ~PORT_PE,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp & ~PORT_PE,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_ENABLE:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_SUSPEND:
                        if (temp & PORT_RESET)
@@ -396,8 +398,8 @@
                                        goto error;
                                /* resume signaling for 20 msec */
                                temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-                               writel (temp | PORT_RESUME,
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci, temp | PORT_RESUME,
+                                           &ehci->regs->port_status [wIndex]);
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (20);
                        }
@@ -407,16 +409,17 @@
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci,
+                                         temp & ~(PORT_RWC_BITS | PORT_POWER),
+                                         &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_CONNECTION:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_OVER_CURRENT:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_RESET:
                        /* GetPortStatus clears reset */
@@ -424,7 +427,7 @@
                default:
                        goto error;
                }
-               readl (&ehci->regs->command);   /* unblock posted write */
+               ehci_readl(ehci, &ehci->regs->command); /* unblock posted write 
*/
                break;
        case GetHubDescriptor:
                ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +443,7 @@
                        goto error;
                wIndex--;
                status = 0;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]);
 
                // wPortChange bits
                if (temp & PORT_CSC)
@@ -458,12 +461,14 @@
                        ehci->reset_done [wIndex] = 0;
 
                        /* stop resume signaling */
-                       temp = readl (&ehci->regs->port_status [wIndex]);
-                       writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
-                               &ehci->regs->port_status [wIndex]);
-                       retval = handshake (
-                                       &ehci->regs->port_status [wIndex],
-                                       PORT_RESUME, 0, 2000 /* 2msec */);
+                       temp = ehci_readl(ehci,
+                                         &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci,
+                                   temp & ~(PORT_RWC_BITS | PORT_RESUME),
+                                   &ehci->regs->port_status [wIndex]);
+                       retval = handshake(ehci,
+                                          &ehci->regs->port_status [wIndex],
+                                          PORT_RESUME, 0, 2000 /* 2msec */);
                        if (retval != 0) {
                                ehci_err (ehci, "port %d resume error %d\n",
                                        wIndex + 1, retval);
@@ -480,13 +485,13 @@
                        ehci->reset_done [wIndex] = 0;
 
                        /* force reset to complete */
-                       writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
-                                       &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+                                   &ehci->regs->port_status [wIndex]);
                        /* REVISIT:  some hardware needs 550+ usec to clear
                         * this bit; seems too long to spin routinely...
                         */
-                       retval = handshake (
-                                       &ehci->regs->port_status [wIndex],
+                       retval = handshake(ehci,
+                                          &ehci->regs->port_status [wIndex],
                                        PORT_RESET, 0, 750);
                        if (retval != 0) {
                                ehci_err (ehci, "port %d reset error %d\n",
@@ -496,7 +501,8 @@
 
                        /* see what we found out */
                        temp = check_reset_complete (ehci, wIndex,
-                               readl (&ehci->regs->port_status [wIndex]));
+                               ehci_readl(ehci,
+                                          &ehci->regs->port_status [wIndex]));
                }
 
                // don't show wPortStatus if it's owned by a companion hc
@@ -541,7 +547,7 @@
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [wIndex]);
                if (temp & PORT_OWNER)
                        break;
 
@@ -555,13 +561,13 @@
                                goto error;
                        if (device_may_wakeup(&hcd->self.root_hub->dev))
                                temp |= PORT_WAKE_BITS;
-                       writel (temp | PORT_SUSPEND,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp | PORT_SUSPEND,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp | PORT_POWER,
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci, temp | PORT_POWER,
+                                           &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_RESET:
                        if (temp & PORT_RESUME)
@@ -589,7 +595,8 @@
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (50);
                        }
-                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
 
                /* For downstream facing ports (these):  one hub port is put
@@ -604,13 +611,14 @@
                        ehci_quiesce(ehci);
                        ehci_halt(ehci);
                        temp |= selector << 16;
-                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp,
+                                   &ehci->regs->port_status [wIndex]);
                        break;
 
                default:
                        goto error;
                }
-               readl (&ehci->regs->command);   /* unblock posted writes */
+               ehci_readl(ehci, &ehci->regs->command); /* unblock posted 
writes */
                break;
 
        default:
Index: linux-test-x86/drivers/usb/host/ehci-pci.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-pci.c     2006-12-13 
13:03:44.000000000 +1100
+++ linux-test-x86/drivers/usb/host/ehci-pci.c  2006-12-13 13:06:02.000000000 
+1100
@@ -38,7 +38,7 @@
                if ((temp & (3 << 13)) == (1 << 13)) {
                        temp &= 0x1fff;
                        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",
                                HCS_DEBUG_PORT(ehci->hcs_params),
                                (temp & DBGP_ENABLED)
@@ -72,7 +72,22 @@
        int                     retval;
 
        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));
+       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;
+       }
+
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
@@ -101,7 +116,7 @@
        }
 
        /* 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);
        if (retval)
@@ -235,8 +250,8 @@
                rc = -EINVAL;
                goto bail;
        }
-       writel (0, &ehci->regs->intr_enable);
-       (void)readl(&ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+       (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
        /* make sure snapshot being resumed re-enumerates everything */
        if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +285,13 @@
        /* If CF is still set, we maintained PCI Vaux power.
         * 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;
 
                if (!device_may_wakeup(&hcd->self.root_hub->dev))
                        mask &= ~STS_PCD;
-               writel(mask, &ehci->regs->intr_enable);
-               readl(&ehci->regs->intr_enable);
+               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+               ehci_readl(ehci, &ehci->regs->intr_enable);
                return 0;
        }
 
@@ -300,9 +315,9 @@
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       writel(ehci->command, &ehci->regs->command);
-       writel(FLAG_CF, &ehci->regs->configured_flag);
-       readl(&ehci->regs->command);    /* unblock posted writes */
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
 
        hcd->state = HC_STATE_SUSPENDED;
        return 0;
Index: linux-test-x86/drivers/usb/host/ehci-q.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-q.c       2006-10-18 
09:44:15.000000000 +1000
+++ linux-test-x86/drivers/usb/host/ehci-q.c    2006-12-13 13:06:02.000000000 
+1100
@@ -789,13 +789,14 @@
        head = ehci->async;
        timer_action_done (ehci, TIMER_ASYNC_OFF);
        if (!head->qh_next.qh) {
-               u32     cmd = readl (&ehci->regs->command);
+               u32     cmd = ehci_readl(ehci, &ehci->regs->command);
 
                if (!(cmd & CMD_ASE)) {
                        /* 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;
-                       writel (cmd, &ehci->regs->command);
+                       ehci_writel(ehci, cmd, &ehci->regs->command);
                        ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
                        /* posted write need not be known to HC yet ... */
                }
@@ -1007,7 +1008,7 @@
 
 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;
 
 #ifdef DEBUG
@@ -1025,7 +1026,8 @@
                if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
                                && !ehci->reclaim) {
                        /* ... and CMD_IAAD clear */
-                       writel (cmd & ~CMD_ASE, &ehci->regs->command);
+                       ehci_writel(ehci, cmd & ~CMD_ASE,
+                                   &ehci->regs->command);
                        wmb ();
                        // handshake later, if we need to
                        timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@
 
        ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
-       writel (cmd, &ehci->regs->command);
-       (void) readl (&ehci->regs->command);
+       ehci_writel(ehci, cmd, &ehci->regs->command);
+       (void)ehci_readl(ehci, &ehci->regs->command);
        timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
Index: linux-test-x86/drivers/usb/host/ehci-sched.c
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci-sched.c   2006-10-06 
21:44:38.000000000 +1000
+++ linux-test-x86/drivers/usb/host/ehci-sched.c        2006-12-13 
13:06:02.000000000 +1100
@@ -433,20 +433,20 @@
        /* did clearing PSE did take effect yet?
         * 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) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return status;
        }
 
-       cmd = readl (&ehci->regs->command) | CMD_PSE;
-       writel (cmd, &ehci->regs->command);
+       cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+       ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... PSS happens later */
        ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
        /* make sure ehci_work scans these */
-       ehci->next_uframe = readl (&ehci->regs->frame_index)
-                               % (ehci->periodic_size << 3);
+       ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+               % (ehci->periodic_size << 3);
        return 0;
 }
 
@@ -458,14 +458,14 @@
        /* did setting PSE not take effect yet?
         * 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) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return status;
        }
 
-       cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-       writel (cmd, &ehci->regs->command);
+       cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+       ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... */
 
        ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@
                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? */
        max = now + mod;
@@ -2088,7 +2088,7 @@
         */
        now_uframe = ehci->next_uframe;
        if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-               clock = readl (&ehci->regs->frame_index);
+               clock = ehci_readl(ehci, &ehci->regs->frame_index);
        else
                clock = now_uframe + mod - 1;
        clock %= mod;
@@ -2213,7 +2213,7 @@
                        if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
                                break;
                        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)
                                break;
 
Index: linux-test-x86/drivers/usb/host/ehci.h
===================================================================
--- linux-test-x86.orig/drivers/usb/host/ehci.h 2006-12-13 13:03:44.000000000 
+1100
+++ linux-test-x86/drivers/usb/host/ehci.h      2006-12-13 13:06:02.000000000 
+1100
@@ -92,6 +92,7 @@
        unsigned                is_tdi_rh_tt:1; /* TDI roothub with TT */
        unsigned                no_selective_suspend:1;
        unsigned                has_fsl_port_bug:1; /* FreeScale */
+       unsigned                big_endian_mmio:1;
 
        u8                      sbrn;           /* packed release number */
 
@@ -651,6 +652,37 @@
 #define        ehci_has_fsl_portno_bug(e)              (0)
 #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);
+}
 
 /*-------------------------------------------------------------------------*/
 



-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to