USB: EHCI: Support controllers with big endian capability regs
authorJan Andersson <jan@gaisler.com>
Tue, 3 May 2011 18:11:57 +0000 (20:11 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 3 May 2011 18:43:21 +0000 (11:43 -0700)
The two first HC capability registers (CAPLENGTH and HCIVERSION)
are defined as one 8-bit and one 16-bit register. Most HC
implementations have selected to treat these registers as part
of a 32-bit register, giving the same layout for both big and
small endian systems.

This patch adds a new quirk, big_endian_capbase, to support
controllers with big endian register interfaces that treat
HCIVERSION and CAPLENGTH as individual registers.

Signed-off-by: Jan Andersson <jan@gaisler.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
27 files changed:
drivers/usb/early/ehci-dbgp.c
drivers/usb/host/ehci-ath79.c
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-cns3xxx.c
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-ixp4xx.c
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-octeon.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-pmcmsp.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-spear.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci-vt8500.c
drivers/usb/host/ehci-w90x900.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/ehci.h
include/linux/usb/ehci_def.h

index a6a350f5827bb6a4240fb6b535e15defde84d5fd..1fc8f1249806ab964645b5395e2f2d099a80a757 100644 (file)
@@ -102,6 +102,9 @@ static struct kgdb_io kgdbdbgp_io_ops;
 #define dbgp_kgdb_mode (0)
 #endif
 
+/* Local version of HC_LENGTH macro as ehci struct is not available here */
+#define EARLY_HC_LENGTH(p)     (0x00ff & (p)) /* bits 7 : 0 */
+
 /*
  * USB Packet IDs (PIDs)
  */
@@ -892,7 +895,7 @@ int __init early_dbgp_init(char *s)
        dbgp_printk("ehci_bar: %p\n", ehci_bar);
 
        ehci_caps  = ehci_bar;
-       ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+       ehci_regs  = ehci_bar + EARLY_HC_LENGTH(readl(&ehci_caps->hc_capbase));
        ehci_debug = ehci_bar + offset;
        ehci_dev.bus = bus;
        ehci_dev.slot = slot;
index 7ea23b50f5d8f2a75a06d5bada68baac1449945c..98cc8a13169c9aab288803ecba0d88062a04e727 100644 (file)
@@ -44,6 +44,7 @@ static int ehci_ath79_init(struct usb_hcd *hcd)
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        struct platform_device *pdev = to_platform_device(hcd->self.controller);
        const struct platform_device_id *id;
+       int hclength;
        int ret;
 
        id = platform_get_device_id(pdev);
@@ -52,21 +53,20 @@ static int ehci_ath79_init(struct usb_hcd *hcd)
                return -EINVAL;
        }
 
+       hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        switch (id->driver_data) {
        case EHCI_ATH79_IP_V1:
                ehci->has_synopsys_hc_bug = 1;
 
                ehci->caps = hcd->regs;
-               ehci->regs = hcd->regs +
-                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               ehci->regs = hcd->regs + hclength;
                break;
 
        case EHCI_ATH79_IP_V2:
                hcd->has_tt = 1;
 
                ehci->caps = hcd->regs + 0x100;
-               ehci->regs = hcd->regs + 0x100 +
-                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               ehci->regs = hcd->regs + 0x100 + hclength;
                break;
 
        default:
index b2ed55cb811de995902647eca82406deffbb8314..a5a3ef1f0096a17602f1e802fc72c4ef07fdf737 100644 (file)
@@ -56,7 +56,7 @@ static int ehci_atmel_setup(struct usb_hcd *hcd)
        /* registers start at offset 0x0 */
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
index a869e3c103d348be6e3604e7226b40d96035efb7..40b002869ac2602415682c3b030474069b027ff5 100644 (file)
@@ -175,7 +175,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       ehci->regs = hcd->regs +
+               HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = readl(&ehci->caps->hcs_params);
 
index 708a05b5d25804cc15979cfc07fcb483ced9789b..d41745c6f0c47edbe5632683ccaeaa5bce0aaa05 100644 (file)
@@ -34,7 +34,7 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
 
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs
-               + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        hcd->has_tt = 0;
index 693c29b305218b8fc9b88e39d83f83d6722a41b4..40a844c1dbb4945044a9afe2d94d2097bad29af3 100644 (file)
@@ -726,7 +726,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
        }
 
        /* Capability Registers */
-       i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        temp = scnprintf (next, size,
                "bus %s, device %s\n"
                "%s\n"
index 623732a312dde329598db829a7046b51629a27bd..f380bf97e5af71d614092c300d1e786949da1254 100644 (file)
@@ -324,7 +324,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
        /* EHCI registers start at offset 0x100 */
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-           HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
index 83b7d5f02a15c57b4d4b60ae3c283596797fd931..8164ffafd10a65e3adf9d117d24b956fffa8800c 100644 (file)
@@ -739,7 +739,7 @@ static int ehci_run (struct usb_hcd *hcd)
        up_write(&ehci_cf_port_reset_rwsem);
        ehci->last_periodic_enable = ktime_get_real();
 
-       temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
                "USB %x.%x started, EHCI %x.%02x%s\n",
                ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
index 89b7c70c6ed6f015077a6a0233b78b080f581043..50e600d26e287165e93cfdf205217850e077abd8 100644 (file)
@@ -23,7 +23,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
 
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100
-               + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        hcd->has_tt = 1;
index 9ce1b0bc186d76154a590cb9bceab4bc2e4687c3..b5a0bf649c95e5a9cb5d918ceaba90e18a4e4da9 100644 (file)
@@ -41,7 +41,7 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
 
        ehci->caps = USB_CAPLENGTH;
        ehci->regs = USB_CAPLENGTH +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
index 25c8c10bb6891d1c020a711e2ae6396401680c2e..0c058be35a3887d5a36b9ffa005873f6824e9457 100644 (file)
@@ -208,7 +208,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        /* EHCI registers start at offset 0x100 */
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-           HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 
        /* set up the PORTSCx register */
        ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
index a31a031178a8d52d05f65b613e15d13b6176f583..ff55757ba7d82c01068914620ae54bbcf948627b 100644 (file)
@@ -151,7 +151,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
 
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
index 7e41a95c5ceb6a9aa70ed437b737eabebf379a4a..3c482dc99ece21489a42a12f05cbe0eea6f4191e 100644 (file)
@@ -188,7 +188,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        /* we know this is the memory we want, no need to ioremap again */
        omap_ehci->caps = hcd->regs;
        omap_ehci->regs = hcd->regs
-                       + HC_LENGTH(readl(&omap_ehci->caps->hc_capbase));
+               + HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
 
        dbg_hcs_params(omap_ehci, "reset");
        dbg_hcc_params(omap_ehci, "reset");
index 281e094e1c18b2849a568d5e0466c7c8a53b0d51..395bdb0248d567ec5cffc7724827fd42925fa2f2 100644 (file)
@@ -251,7 +251,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
        hcd->has_tt = 1;
        ehci->sbrn = 0x20;
index d5eaea7caf89ebe8987fb00bff32cce78ede29cc..660b80a75cacc1e8953022e94819dea6eafa2382 100644 (file)
@@ -70,7 +70,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
index a2168642175b4d6c442587efa1f069a6bc416304..cd69099cda1910f9e5aa1f2af67780a872ec28c0 100644 (file)
@@ -83,7 +83,7 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
 
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
index 1f09f253697e9c810bd155cab92d66a7cd6332a2..8552db6c29c9e4cce9c5896bf296cd5a3cb71853 100644 (file)
@@ -179,7 +179,7 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
 
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
index 1dee33b9139e65d1f8714234c7ecde9e7b3d0d24..64626a777d611e59f4b2b02dba0acad950010caf 100644 (file)
@@ -29,7 +29,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
        ehci->big_endian_mmio = 1;
 
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+       ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
                &ehci->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
index 0c18f280bf4c7428bee726899ee65281dd0001d6..321a03301ad2df41538e16befbdc52225f3922b3 100644 (file)
@@ -126,7 +126,8 @@ static int s5p_ehci_probe(struct platform_device *pdev)
 
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       ehci->regs = hcd->regs +
+               HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
index 595f70f42b525a3c04ce226c9e45a5c70ea0338c..86a95bb80a6174701a5190e94d1bf59c8dabfd86 100644 (file)
@@ -23,7 +23,7 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
        int ret;
 
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+       ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
                &ehci->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
index 75c00873443ddf7529e98214152c91d1548c4479..dbf1e4ef3c17ffa626fc1f40fd951f36cbbbd852 100644 (file)
@@ -38,7 +38,7 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
 
        /* registers start at offset 0x0 */
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+       ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
                                &ehci->caps->hc_capbase));
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
index 7359bcbe4176242b3c565b685938f06f7f74acc3..02b2bfd49a10c0bcc0972877fe8527955c6a1344 100644 (file)
@@ -400,7 +400,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
        /* 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->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
index 20168062035a6d872c931d4ff9bc240fb4e9fa51..47d749631bc77ef55fd80b417e1d43bca41687cd 100644 (file)
@@ -121,7 +121,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
 
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       ehci->regs = hcd->regs +
+               HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
 
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
index 6bc35809a5c6b6767c75b1732a4aad9bb4ab831d..52a027aaa37028d464c73236725a74e3c578e7fc 100644 (file)
@@ -57,7 +57,7 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs;
        ehci->regs = hcd->regs +
-                HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 
        /* enable PHY 0,1,the regs only apply to w90p910
        *  0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
index effc58d7af8ba7492ea2490d88b452a21d442732..a64d6d66d7600e8f73e1ae1fba3feafb52f31cfa 100644 (file)
@@ -220,7 +220,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
         */
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
index e9ba8e25248947afc40c96383678a7d1b6aac7ae..d0792f591590ba57b8b02bac43dca3ada52ad6b7 100644 (file)
@@ -128,6 +128,7 @@ struct ehci_hcd {                   /* one per controller */
        unsigned                has_fsl_port_bug:1; /* FreeScale */
        unsigned                big_endian_mmio:1;
        unsigned                big_endian_desc:1;
+       unsigned                big_endian_capbase:1;
        unsigned                has_amcc_usb23:1;
        unsigned                need_io_watchdog:1;
        unsigned                broken_periodic:1;
@@ -605,12 +606,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
  * 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.
+ *
+ * ehci_big_endian_capbase is a special quirk for controllers that
+ * implement the HC capability registers as separate registers and not
+ * as fields of a 32-bit register.
  */
 
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 #define ehci_big_endian_mmio(e)                ((e)->big_endian_mmio)
+#define ehci_big_endian_capbase(e)     ((e)->big_endian_capbase)
 #else
 #define ehci_big_endian_mmio(e)                0
+#define ehci_big_endian_capbase(e)     0
 #endif
 
 /*
index 78799432008e57ac865a5d3fd51612f3db76e2c7..7cc95ee3606bcc415978f316f5c1f0d94c2ca0bb 100644 (file)
 struct ehci_caps {
        /* these fields are specified as 8 and 16 bit registers,
         * but some hosts can't perform 8 or 16 bit PCI accesses.
+        * some hosts treat caplength and hciversion as parts of a 32-bit
+        * register, others treat them as two separate registers, this
+        * affects the memory map for big endian controllers.
         */
        u32             hc_capbase;
-#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
-#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
+#define HC_LENGTH(ehci, p)     (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
+                               (ehci_big_endian_capbase(ehci) ? 24 : 0)))
+#define HC_VERSION(ehci, p)    (0xffff&((p) >> /* bits 31:16 / offset 02h */ \
+                               (ehci_big_endian_capbase(ehci) ? 0 : 16)))
        u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
 #define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
 #define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */