Skip to content

Commit

Permalink
USB: EHCI: Support controllers with big endian capability regs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jan Andersson authored and Greg Kroah-Hartman committed May 3, 2011
1 parent 2ce2c3a commit c430131
Show file tree
Hide file tree
Showing 27 changed files with 48 additions and 30 deletions.
5 changes: 4 additions & 1 deletion drivers/usb/early/ehci-dbgp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
*/
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions drivers/usb/host/ehci-ath79.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/host/ehci-au1xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-cns3xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-fsl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-ixp4xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-msm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-mxc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-octeon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-omap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-orion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-pmcmsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-ppc-of.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-ps3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/host/ehci-s5p.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-spear.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/host/ehci-vt8500.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-w90x900.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-xilinx-of.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions drivers/usb/host/ehci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

/*
Expand Down
9 changes: 7 additions & 2 deletions include/linux/usb/ehci_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@
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 */
Expand Down

0 comments on commit c430131

Please sign in to comment.