USB: EHCI: Support controllers with big endian capability regs

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>
This commit is contained in:
Jan Andersson 2011-05-03 20:11:57 +02:00 committed by Greg Kroah-Hartman
parent 2ce2c3ac88
commit c430131a02
27 changed files with 48 additions and 30 deletions

View file

@ -102,6 +102,9 @@ static struct kgdb_io kgdbdbgp_io_ops;
#define dbgp_kgdb_mode (0) #define dbgp_kgdb_mode (0)
#endif #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) * USB Packet IDs (PIDs)
*/ */
@ -892,7 +895,7 @@ int __init early_dbgp_init(char *s)
dbgp_printk("ehci_bar: %p\n", ehci_bar); dbgp_printk("ehci_bar: %p\n", ehci_bar);
ehci_caps = 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_debug = ehci_bar + offset;
ehci_dev.bus = bus; ehci_dev.bus = bus;
ehci_dev.slot = slot; ehci_dev.slot = slot;

View file

@ -44,6 +44,7 @@ static int ehci_ath79_init(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct platform_device *pdev = to_platform_device(hcd->self.controller); struct platform_device *pdev = to_platform_device(hcd->self.controller);
const struct platform_device_id *id; const struct platform_device_id *id;
int hclength;
int ret; int ret;
id = platform_get_device_id(pdev); id = platform_get_device_id(pdev);
@ -52,21 +53,20 @@ static int ehci_ath79_init(struct usb_hcd *hcd)
return -EINVAL; return -EINVAL;
} }
hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
switch (id->driver_data) { switch (id->driver_data) {
case EHCI_ATH79_IP_V1: case EHCI_ATH79_IP_V1:
ehci->has_synopsys_hc_bug = 1; ehci->has_synopsys_hc_bug = 1;
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = hcd->regs + ehci->regs = hcd->regs + hclength;
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
break; break;
case EHCI_ATH79_IP_V2: case EHCI_ATH79_IP_V2:
hcd->has_tt = 1; hcd->has_tt = 1;
ehci->caps = hcd->regs + 0x100; ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 + ehci->regs = hcd->regs + 0x100 + hclength;
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
break; break;
default: default:

View file

@ -56,7 +56,7 @@ static int ehci_atmel_setup(struct usb_hcd *hcd)
/* registers start at offset 0x0 */ /* registers start at offset 0x0 */
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -175,7 +175,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd); ehci = hcd_to_ehci(hcd);
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->caps->hc_capbase));
/* 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 = readl(&ehci->caps->hcs_params);

View file

@ -34,7 +34,7 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 0; hcd->has_tt = 0;

View file

@ -726,7 +726,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
} }
/* Capability Registers */ /* 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, temp = scnprintf (next, size,
"bus %s, device %s\n" "bus %s, device %s\n"
"%s\n" "%s\n"

View file

@ -324,7 +324,7 @@ 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(ehci_readl(ehci, &ehci->caps->hc_capbase)); HC_LENGTH(ehci, 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");

View file

@ -739,7 +739,7 @@ static int ehci_run (struct usb_hcd *hcd)
up_write(&ehci_cf_port_reset_rwsem); up_write(&ehci_cf_port_reset_rwsem);
ehci->last_periodic_enable = ktime_get_real(); 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, ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x%s\n", "USB %x.%x started, EHCI %x.%02x%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),

View file

@ -23,7 +23,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
ehci->caps = hcd->regs + 0x100; ehci->caps = hcd->regs + 0x100;
ehci->regs = 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); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1; hcd->has_tt = 1;

View file

@ -41,7 +41,7 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
ehci->caps = USB_CAPLENGTH; ehci->caps = USB_CAPLENGTH;
ehci->regs = 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_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -208,7 +208,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
/* 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(ehci_readl(ehci, &ehci->caps->hc_capbase)); HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
/* set up the PORTSCx register */ /* set up the PORTSCx register */
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]); ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);

View file

@ -151,7 +151,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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 */ /* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);

View 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 */ /* we know this is the memory we want, no need to ioremap again */
omap_ehci->caps = hcd->regs; omap_ehci->caps = hcd->regs;
omap_ehci->regs = 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_hcs_params(omap_ehci, "reset");
dbg_hcc_params(omap_ehci, "reset"); dbg_hcc_params(omap_ehci, "reset");

View file

@ -251,7 +251,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd); ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs + 0x100; ehci->caps = hcd->regs + 0x100;
ehci->regs = 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); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
hcd->has_tt = 1; hcd->has_tt = 1;
ehci->sbrn = 0x20; ehci->sbrn = 0x20;

View file

@ -70,7 +70,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -83,7 +83,7 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -179,7 +179,7 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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 */ /* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);

View file

@ -29,7 +29,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
ehci->big_endian_mmio = 1; ehci->big_endian_mmio = 1;
ehci->caps = hcd->regs; 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)); &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");

View file

@ -126,7 +126,8 @@ static int s5p_ehci_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd); ehci = hcd_to_ehci(hcd);
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->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -23,7 +23,7 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
int ret; int ret;
ehci->caps = hcd->regs; 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)); &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");

View file

@ -38,7 +38,7 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
/* registers start at offset 0x0 */ /* registers start at offset 0x0 */
ehci->caps = hcd->regs; 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)); &ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */ /* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);

View file

@ -400,7 +400,7 @@ static int tegra_ehci_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->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -121,7 +121,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd); ehci = hcd_to_ehci(hcd);
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->caps->hc_capbase));
dbg_hcs_params(ehci, "reset"); dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset"); dbg_hcc_params(ehci, "reset");

View file

@ -57,7 +57,7 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
ehci = hcd_to_ehci(hcd); ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs; ehci->caps = hcd->regs;
ehci->regs = 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 /* enable PHY 0,1,the regs only apply to w90p910
* 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of * 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of

View file

@ -220,7 +220,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
*/ */
ehci->caps = hcd->regs + 0x100; ehci->caps = hcd->regs + 0x100;
ehci->regs = 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 */ /* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);

View file

@ -128,6 +128,7 @@ struct ehci_hcd { /* one per controller */
unsigned has_fsl_port_bug:1; /* FreeScale */ unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1; unsigned big_endian_mmio:1;
unsigned big_endian_desc:1; unsigned big_endian_desc:1;
unsigned big_endian_capbase:1;
unsigned has_amcc_usb23:1; unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1; unsigned need_io_watchdog:1;
unsigned broken_periodic: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 * This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead * runtime penalty, or both formats with the additional overhead
* of checking a flag bit. * 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 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio) #define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
#else #else
#define ehci_big_endian_mmio(e) 0 #define ehci_big_endian_mmio(e) 0
#define ehci_big_endian_capbase(e) 0
#endif #endif
/* /*

View file

@ -25,10 +25,15 @@
struct ehci_caps { struct ehci_caps {
/* these fields are specified as 8 and 16 bit registers, /* these fields are specified as 8 and 16 bit registers,
* but some hosts can't perform 8 or 16 bit PCI accesses. * 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; u32 hc_capbase;
#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ #define HC_LENGTH(ehci, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ (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 */ u32 hcs_params; /* HCSPARAMS - offset 0x4 */
#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */ #define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ #define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */