diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/alchemy-common.c | 337 | ||||
-rw-r--r-- | drivers/usb/host/ehci-au1xxx.c | 77 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 22 | ||||
-rw-r--r-- | drivers/usb/host/ehci-xls.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/fsl-mph-dr-of.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/isp1760-if.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ohci-at91.c | 245 | ||||
-rw-r--r-- | drivers/usb/host/ohci-au1xxx.c | 110 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 15 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 26 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 1 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 58 | ||||
-rw-r--r-- | drivers/usb/host/whci/debug.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/whci/hcd.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/whci/qset.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 13 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 39 |
22 files changed, 669 insertions, 292 deletions
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index ed48a5d79e1..7ca290fcb07 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -36,3 +36,4 @@ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o +obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o diff --git a/drivers/usb/host/alchemy-common.c b/drivers/usb/host/alchemy-common.c new file mode 100644 index 00000000000..b4192c964d0 --- /dev/null +++ b/drivers/usb/host/alchemy-common.c @@ -0,0 +1,337 @@ +/* + * USB block power/access management abstraction. + * + * Au1000+: The OHCI block control register is at the far end of the OHCI memory + * area. Au1550 has OHCI on different base address. No need to handle + * UDC here. + * Au1200: one register to control access and clocks to O/EHCI, UDC and OTG + * as well as the PHY for EHCI and UDC. + * + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/syscore_ops.h> +#include <asm/mach-au1x00/au1000.h> + +/* control register offsets */ +#define AU1000_OHCICFG 0x7fffc +#define AU1550_OHCICFG 0x07ffc +#define AU1200_USBCFG 0x04 + +/* Au1000 USB block config bits */ +#define USBHEN_RD (1 << 4) /* OHCI reset-done indicator */ +#define USBHEN_CE (1 << 3) /* OHCI block clock enable */ +#define USBHEN_E (1 << 2) /* OHCI block enable */ +#define USBHEN_C (1 << 1) /* OHCI block coherency bit */ +#define USBHEN_BE (1 << 0) /* OHCI Big-Endian */ + +/* Au1200 USB config bits */ +#define USBCFG_PFEN (1 << 31) /* prefetch enable (undoc) */ +#define USBCFG_RDCOMB (1 << 30) /* read combining (undoc) */ +#define USBCFG_UNKNOWN (5 << 20) /* unknown, leave this way */ +#define USBCFG_SSD (1 << 23) /* serial short detect en */ +#define USBCFG_PPE (1 << 19) /* HS PHY PLL */ +#define USBCFG_UCE (1 << 18) /* UDC clock enable */ +#define USBCFG_ECE (1 << 17) /* EHCI clock enable */ +#define USBCFG_OCE (1 << 16) /* OHCI clock enable */ +#define USBCFG_FLA(x) (((x) & 0x3f) << 8) +#define USBCFG_UCAM (1 << 7) /* coherent access (undoc) */ +#define USBCFG_GME (1 << 6) /* OTG mem access */ +#define USBCFG_DBE (1 << 5) /* UDC busmaster enable */ +#define USBCFG_DME (1 << 4) /* UDC mem enable */ +#define USBCFG_EBE (1 << 3) /* EHCI busmaster enable */ +#define USBCFG_EME (1 << 2) /* EHCI mem enable */ +#define USBCFG_OBE (1 << 1) /* OHCI busmaster enable */ +#define USBCFG_OME (1 << 0) /* OHCI mem enable */ +#define USBCFG_INIT_AU1200 (USBCFG_PFEN | USBCFG_RDCOMB | USBCFG_UNKNOWN |\ + USBCFG_SSD | USBCFG_FLA(0x20) | USBCFG_UCAM | \ + USBCFG_GME | USBCFG_DBE | USBCFG_DME | \ + USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ + USBCFG_OME) + + +static DEFINE_SPINLOCK(alchemy_usb_lock); + + +static inline void __au1200_ohci_control(void __iomem *base, int enable) +{ + unsigned long r = __raw_readl(base + AU1200_USBCFG); + if (enable) { + __raw_writel(r | USBCFG_OCE, base + AU1200_USBCFG); + wmb(); + udelay(2000); + } else { + __raw_writel(r & ~USBCFG_OCE, base + AU1200_USBCFG); + wmb(); + udelay(1000); + } +} + +static inline void __au1200_ehci_control(void __iomem *base, int enable) +{ + unsigned long r = __raw_readl(base + AU1200_USBCFG); + if (enable) { + __raw_writel(r | USBCFG_ECE | USBCFG_PPE, base + AU1200_USBCFG); + wmb(); + udelay(1000); + } else { + if (!(r & USBCFG_UCE)) /* UDC also off? */ + r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ + __raw_writel(r & ~USBCFG_ECE, base + AU1200_USBCFG); + wmb(); + udelay(1000); + } +} + +static inline void __au1200_udc_control(void __iomem *base, int enable) +{ + unsigned long r = __raw_readl(base + AU1200_USBCFG); + if (enable) { + __raw_writel(r | USBCFG_UCE | USBCFG_PPE, base + AU1200_USBCFG); + wmb(); + } else { + if (!(r & USBCFG_ECE)) /* EHCI also off? */ + r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ + __raw_writel(r & ~USBCFG_UCE, base + AU1200_USBCFG); + wmb(); + } +} + +static inline int au1200_coherency_bug(void) +{ +#if defined(CONFIG_DMA_COHERENT) + /* Au1200 AB USB does not support coherent memory */ + if (!(read_c0_prid() & 0xff)) { + printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n"); + printk(KERN_INFO "Au1200 USB: update your board or re-configure" + " the kernel\n"); + return -ENODEV; + } +#endif + return 0; +} + +static inline int au1200_usb_control(int block, int enable) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); + int ret = 0; + + switch (block) { + case ALCHEMY_USB_OHCI0: + ret = au1200_coherency_bug(); + if (ret && enable) + goto out; + __au1200_ohci_control(base, enable); + break; + case ALCHEMY_USB_UDC0: + __au1200_udc_control(base, enable); + break; + case ALCHEMY_USB_EHCI0: + ret = au1200_coherency_bug(); + if (ret && enable) + goto out; + __au1200_ehci_control(base, enable); + break; + default: + ret = -ENODEV; + } +out: + return ret; +} + + +/* initialize USB block(s) to a known working state */ +static inline void au1200_usb_init(void) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); + __raw_writel(USBCFG_INIT_AU1200, base + AU1200_USBCFG); + wmb(); + udelay(1000); +} + +static inline void au1000_usb_init(unsigned long rb, int reg) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg); + unsigned long r = __raw_readl(base); + +#if defined(__BIG_ENDIAN) + r |= USBHEN_BE; +#endif + r |= USBHEN_C; + + __raw_writel(r, base); + wmb(); + udelay(1000); +} + + +static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(rb); + unsigned long r = __raw_readl(base + creg); + + if (enable) { + __raw_writel(r | USBHEN_CE, base + creg); + wmb(); + udelay(1000); + __raw_writel(r | USBHEN_CE | USBHEN_E, base + creg); + wmb(); + udelay(1000); + + /* wait for reset complete (read reg twice: au1500 erratum) */ + while (__raw_readl(base + creg), + !(__raw_readl(base + creg) & USBHEN_RD)) + udelay(1000); + } else { + __raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg); + wmb(); + } +} + +static inline int au1000_usb_control(int block, int enable, unsigned long rb, + int creg) +{ + int ret = 0; + + switch (block) { + case ALCHEMY_USB_OHCI0: + __au1xx0_ohci_control(enable, rb, creg); + break; + default: + ret = -ENODEV; + } + return ret; +} + +/* + * alchemy_usb_control - control Alchemy on-chip USB blocks + * @block: USB block to target + * @enable: set 1 to enable a block, 0 to disable + */ +int alchemy_usb_control(int block, int enable) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&alchemy_usb_lock, flags); + switch (alchemy_get_cputype()) { + case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1100: + ret = au1000_usb_control(block, enable, + AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); + break; + case ALCHEMY_CPU_AU1550: + ret = au1000_usb_control(block, enable, + AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); + break; + case ALCHEMY_CPU_AU1200: + ret = au1200_usb_control(block, enable); + break; + default: + ret = -ENODEV; + } + spin_unlock_irqrestore(&alchemy_usb_lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(alchemy_usb_control); + + +static unsigned long alchemy_usb_pmdata[2]; + +static void au1000_usb_pm(unsigned long br, int creg, int susp) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(br); + + if (susp) { + alchemy_usb_pmdata[0] = __raw_readl(base + creg); + /* There appears to be some undocumented reset register.... */ + __raw_writel(0, base + 0x04); + wmb(); + __raw_writel(0, base + creg); + wmb(); + } else { + __raw_writel(alchemy_usb_pmdata[0], base + creg); + wmb(); + } +} + +static void au1200_usb_pm(int susp) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1200_USB_OTG_PHYS_ADDR); + if (susp) { + /* save OTG_CAP/MUX registers which indicate port routing */ + /* FIXME: write an OTG driver to do that */ + alchemy_usb_pmdata[0] = __raw_readl(base + 0x00); + alchemy_usb_pmdata[1] = __raw_readl(base + 0x04); + } else { + /* restore access to all MMIO areas */ + au1200_usb_init(); + + /* restore OTG_CAP/MUX registers */ + __raw_writel(alchemy_usb_pmdata[0], base + 0x00); + __raw_writel(alchemy_usb_pmdata[1], base + 0x04); + wmb(); + } +} + +static void alchemy_usb_pm(int susp) +{ + switch (alchemy_get_cputype()) { + case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1100: + au1000_usb_pm(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG, susp); + break; + case ALCHEMY_CPU_AU1550: + au1000_usb_pm(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG, susp); + break; + case ALCHEMY_CPU_AU1200: + au1200_usb_pm(susp); + break; + } +} + +static int alchemy_usb_suspend(void) +{ + alchemy_usb_pm(1); + return 0; +} + +static void alchemy_usb_resume(void) +{ + alchemy_usb_pm(0); +} + +static struct syscore_ops alchemy_usb_pm_ops = { + .suspend = alchemy_usb_suspend, + .resume = alchemy_usb_resume, +}; + +static int __init alchemy_usb_init(void) +{ + switch (alchemy_get_cputype()) { + case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1100: + au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); + break; + case ALCHEMY_CPU_AU1550: + au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); + break; + case ALCHEMY_CPU_AU1200: + au1200_usb_init(); + break; + } + + register_syscore_ops(&alchemy_usb_pm_ops); + + return 0; +} +arch_initcall(alchemy_usb_init); diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 65719e8d24e..18bafa99fe5 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -14,61 +14,9 @@ #include <linux/platform_device.h> #include <asm/mach-au1x00/au1000.h> -#define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG) -#define USB_MCFG_PFEN (1<<31) -#define USB_MCFG_RDCOMB (1<<30) -#define USB_MCFG_SSDEN (1<<23) -#define USB_MCFG_PHYPLLEN (1<<19) -#define USB_MCFG_UCECLKEN (1<<18) -#define USB_MCFG_EHCCLKEN (1<<17) -#ifdef CONFIG_DMA_COHERENT -#define USB_MCFG_UCAM (1<<7) -#else -#define USB_MCFG_UCAM (0) -#endif -#define USB_MCFG_EBMEN (1<<3) -#define USB_MCFG_EMEMEN (1<<2) - -#define USBH_ENABLE_CE (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN) -#define USBH_ENABLE_INIT (USB_MCFG_PFEN | USB_MCFG_RDCOMB | \ - USBH_ENABLE_CE | USB_MCFG_SSDEN | \ - USB_MCFG_UCAM | USB_MCFG_EBMEN | \ - USB_MCFG_EMEMEN) - -#define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN) extern int usb_disabled(void); -static void au1xxx_start_ehc(void) -{ - /* enable clock to EHCI block and HS PHY PLL*/ - au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_CE, USB_HOST_CONFIG); - au_sync(); - udelay(1000); - - /* enable EHCI mmio */ - au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG); - au_sync(); - udelay(1000); -} - -static void au1xxx_stop_ehc(void) -{ - unsigned long c; - - /* Disable mem */ - au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_DISABLE, USB_HOST_CONFIG); - au_sync(); - udelay(1000); - - /* Disable EHC clock. If the HS PHY is unused disable it too. */ - c = au_readl(USB_HOST_CONFIG) & ~USB_MCFG_EHCCLKEN; - if (!(c & USB_MCFG_UCECLKEN)) /* UDC disabled? */ - c &= ~USB_MCFG_PHYPLLEN; /* yes: disable HS PHY PLL */ - au_writel(c, USB_HOST_CONFIG); - au_sync(); -} - static int au1xxx_ehci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -136,16 +84,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; -#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT) - /* Au1200 AB USB does not support coherent memory */ - if (!(read_c0_prid() & 0xff)) { - printk(KERN_INFO "%s: this is chip revision AB!\n", pdev->name); - printk(KERN_INFO "%s: update your board or re-configure" - " the kernel\n", pdev->name); - return -ENODEV; - } -#endif - if (pdev->resource[1].flags != IORESOURCE_IRQ) { pr_debug("resource[1] is not IORESOURCE_IRQ"); return -ENOMEM; @@ -171,7 +109,11 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) goto err2; } - au1xxx_start_ehc(); + if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) { + printk(KERN_INFO "%s: controller init failed!\n", pdev->name); + ret = -ENODEV; + goto err3; + } ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; @@ -187,7 +129,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) return ret; } - au1xxx_stop_ehc(); + alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); +err3: iounmap(hcd->regs); err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); @@ -201,10 +144,10 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); + alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - au1xxx_stop_ehc(); platform_set_drvdata(pdev, NULL); return 0; @@ -236,7 +179,7 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) // could save FLADJ in case of Vaux power loss // ... we'd only use it to handle clock skew - au1xxx_stop_ehc(); + alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); return rc; } @@ -246,7 +189,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev) struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - au1xxx_start_ehc(); + alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); // maybe restore FLADJ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 59e81615e09..3ff9f82f726 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1224,7 +1224,7 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_sh_driver #endif -#ifdef CONFIG_SOC_AU1200 +#ifdef CONFIG_MIPS_ALCHEMY #include "ehci-au1xxx.c" #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver #endif diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 2e829fae648..a60679cbbf8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1475,30 +1475,36 @@ iso_stream_schedule ( * jump until after the queue is primed. */ else { + int done = 0; start = SCHEDULE_SLOP + (now & ~0x07); /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - /* find a uframe slot with enough bandwidth */ - next = start + period; - for (; start < next; start++) { - + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; /* check schedule: enough space? */ if (stream->highspeed) { if (itd_slot_ok(ehci, mod, start, stream->usecs, period)) - break; + done = 1; } else { if ((start % 8) >= 6) continue; if (sitd_slot_ok(ehci, mod, stream, start, sched, period)) - break; + done = 1; } - } + } while (start > next && !done); /* no room in the schedule */ - if (start == next) { + if (!done) { ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", urb, now, now + mod); status = -ENOSPC; diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c index fe74bd67601..b4fb511d24b 100644 --- a/drivers/usb/host/ehci-xls.c +++ b/drivers/usb/host/ehci-xls.c @@ -19,7 +19,7 @@ static int ehci_xls_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"); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 79a66d622f9..9037035ad1e 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/of_platform.h> #include <linux/clk.h> +#include <linux/module.h> struct fsl_usb2_dev_data { char *dr_mode; /* controller mode */ diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 2c7fc830c9e..a7dc1e1d45f 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -11,6 +11,7 @@ #include <linux/usb.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/usb/isp1760.h> #include <linux/usb/hcd.h> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 944291e10f9..95a9fec38e8 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -35,8 +35,7 @@ extern int usb_disabled(void); static void at91_start_clock(void) { - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_enable(hclk); + clk_enable(hclk); clk_enable(iclk); clk_enable(fclk); clocked = 1; @@ -46,8 +45,7 @@ static void at91_stop_clock(void) { clk_disable(fclk); clk_disable(iclk); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_disable(hclk); + clk_disable(hclk); clocked = 0; } @@ -142,8 +140,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, iclk = clk_get(&pdev->dev, "ohci_clk"); fclk = clk_get(&pdev->dev, "uhpck"); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - hclk = clk_get(&pdev->dev, "hck0"); + hclk = clk_get(&pdev->dev, "hclk"); at91_start_hc(pdev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -155,8 +152,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, /* Error handling */ at91_stop_hc(pdev); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_put(hclk); + clk_put(hclk); clk_put(fclk); clk_put(iclk); @@ -192,8 +188,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) - clk_put(hclk); + clk_put(hclk); clk_put(fclk); clk_put(iclk); fclk = iclk = hclk = NULL; @@ -223,6 +218,162 @@ ohci_at91_start (struct usb_hcd *hcd) return 0; } +static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) +{ + if (port < 0 || port >= 2) + return; + + if (pdata->vbus_pin[port] <= 0) + return; + + gpio_set_value(pdata->vbus_pin[port], !pdata->vbus_pin_inverted ^ enable); +} + +static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) +{ + if (port < 0 || port >= 2) + return -EINVAL; + + if (pdata->vbus_pin[port] <= 0) + return -EINVAL; + + return gpio_get_value(pdata->vbus_pin[port]) ^ !pdata->vbus_pin_inverted; +} + +/* + * Update the status data from the hub with the over-current indicator change. + */ +static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + int length = ohci_hub_status_data(hcd, buf); + int port; + + for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { + if (pdata->overcurrent_changed[port]) { + if (! length) + length = 1; + buf[0] |= 1 << (port + 1); + } + } + + return length; +} + +/* + * Look at the control requests to the root hub and see if we need to override. + */ +static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + struct usb_hub_descriptor *desc; + int ret = -EINVAL; + u32 *data = (u32 *)buf; + + dev_dbg(hcd->self.controller, + "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", + hcd, typeReq, wValue, wIndex, buf, wLength); + + switch (typeReq) { + case SetPortFeature: + if (wValue == USB_PORT_FEAT_POWER) { + dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); + ohci_at91_usb_set_power(pdata, wIndex - 1, 1); + goto out; + } + break; + + case ClearPortFeature: + switch (wValue) { + case USB_PORT_FEAT_C_OVER_CURRENT: + dev_dbg(hcd->self.controller, + "ClearPortFeature: C_OVER_CURRENT\n"); + + if (wIndex == 1 || wIndex == 2) { + pdata->overcurrent_changed[wIndex-1] = 0; + pdata->overcurrent_status[wIndex-1] = 0; + } + + goto out; + + case USB_PORT_FEAT_OVER_CURRENT: + dev_dbg(hcd->self.controller, + "ClearPortFeature: OVER_CURRENT\n"); + + if (wIndex == 1 || wIndex == 2) { + pdata->overcurrent_status[wIndex-1] = 0; + } + + goto out; + + case USB_PORT_FEAT_POWER: + dev_dbg(hcd->self.controller, + "ClearPortFeature: POWER\n"); + + if (wIndex == 1 || wIndex == 2) { + ohci_at91_usb_set_power(pdata, wIndex - 1, 0); + return 0; + } + } + break; + } + + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + if (ret) + goto out; + + switch (typeReq) { + case GetHubDescriptor: + + /* update the hub's descriptor */ + + desc = (struct usb_hub_descriptor *)buf; + + dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", + desc->wHubCharacteristics); + + /* remove the old configurations for power-switching, and + * over-current protection, and insert our new configuration + */ + + desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); + desc->wHubCharacteristics |= cpu_to_le16(0x0001); + + if (pdata->overcurrent_supported) { + desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); + desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); + } + + dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", + desc->wHubCharacteristics); + + return ret; + + case GetPortStatus: + /* check port status */ + + dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); + + if (wIndex == 1 || wIndex == 2) { + if (! ohci_at91_usb_get_power(pdata, wIndex-1)) { + *data &= ~cpu_to_le32(RH_PS_PPS); + } + + if (pdata->overcurrent_changed[wIndex-1]) { + *data |= cpu_to_le32(RH_PS_OCIC); + } + + if (pdata->overcurrent_status[wIndex-1]) { + *data |= cpu_to_le32(RH_PS_POCI); + } + } + } + + out: + return ret; +} + /*-------------------------------------------------------------------------*/ static const struct hc_driver ohci_at91_hc_driver = { @@ -258,8 +409,8 @@ static const struct hc_driver ohci_at91_hc_driver = { /* * root hub support */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, + .hub_status_data = ohci_at91_hub_status_data, + .hub_control = ohci_at91_hub_control, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -269,22 +420,71 @@ static const struct hc_driver ohci_at91_hc_driver = { /*-------------------------------------------------------------------------*/ +static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) +{ + struct platform_device *pdev = data; + struct at91_usbh_data *pdata = pdev->dev.platform_data; + int val, gpio, port; + + /* From the GPIO notifying the over-current situation, find + * out the corresponding port */ + gpio = irq_to_gpio(irq); + for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { + if (pdata->overcurrent_pin[port] == gpio) + break; + } + + if (port == ARRAY_SIZE(pdata->overcurrent_pin)) { + dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n"); + return IRQ_HANDLED; + } + + val = gpio_get_value(gpio); + + /* When notified of an over-current situation, disable power + on the corresponding port, and mark this port in + over-current. */ + if (! val) { + ohci_at91_usb_set_power(pdata, port, 0); + pdata->overcurrent_status[port] = 1; + pdata->overcurrent_changed[port] = 1; + } + + dev_dbg(& pdev->dev, "overcurrent situation %s\n", + val ? "exited" : "notified"); + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { struct at91_usbh_data *pdata = pdev->dev.platform_data; int i; if (pdata) { - /* REVISIT make the driver support per-port power switching, - * and also overcurrent detection. Here we assume the ports - * are always powered while this driver is active, and use - * active-low power switches. - */ for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (pdata->vbus_pin[i] <= 0) continue; gpio_request(pdata->vbus_pin[i], "ohci_vbus"); - gpio_direction_output(pdata->vbus_pin[i], 0); + ohci_at91_usb_set_power(pdata, i, 1); + } + + for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { + int ret; + + if (pdata->overcurrent_pin[i] <= 0) + continue; + gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent"); + + ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]), + ohci_hcd_at91_overcurrent_irq, + IRQF_SHARED, "ohci_overcurrent", pdev); + if (ret) { + gpio_free(pdata->overcurrent_pin[i]); + dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n"); + } } } @@ -301,9 +501,16 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (pdata->vbus_pin[i] <= 0) continue; - gpio_direction_output(pdata->vbus_pin[i], 1); + ohci_at91_usb_set_power(pdata, i, 0); gpio_free(pdata->vbus_pin[i]); } + + for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { + if (pdata->overcurrent_pin[i] <= 0) + continue; + free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev); + gpio_free(pdata->overcurrent_pin[i]); + } } device_init_wakeup(&pdev->dev, 0); diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 6b7bc50dfea..9b66df8278f 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -23,92 +23,9 @@ #include <asm/mach-au1x00/au1000.h> -#ifndef CONFIG_SOC_AU1200 - -#define USBH_ENABLE_BE (1<<0) -#define USBH_ENABLE_C (1<<1) -#define USBH_ENABLE_E (1<<2) -#define USBH_ENABLE_CE (1<<3) -#define USBH_ENABLE_RD (1<<4) - -#ifdef __LITTLE_ENDIAN -#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C) -#elif defined(__BIG_ENDIAN) -#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \ - USBH_ENABLE_BE) -#else -#error not byte order defined -#endif - -#else /* Au1200 */ - -#define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG) -#define USB_MCFG_PFEN (1<<31) -#define USB_MCFG_RDCOMB (1<<30) -#define USB_MCFG_SSDEN (1<<23) -#define USB_MCFG_OHCCLKEN (1<<16) -#ifdef CONFIG_DMA_COHERENT -#define USB_MCFG_UCAM (1<<7) -#else -#define USB_MCFG_UCAM (0) -#endif -#define USB_MCFG_OBMEN (1<<1) -#define USB_MCFG_OMEMEN (1<<0) - -#define USBH_ENABLE_CE USB_MCFG_OHCCLKEN - -#define USBH_ENABLE_INIT (USB_MCFG_PFEN | USB_MCFG_RDCOMB | \ - USBH_ENABLE_CE | USB_MCFG_SSDEN | \ - USB_MCFG_UCAM | \ - USB_MCFG_OBMEN | USB_MCFG_OMEMEN) - -#define USBH_DISABLE (USB_MCFG_OBMEN | USB_MCFG_OMEMEN) - -#endif /* Au1200 */ extern int usb_disabled(void); -static void au1xxx_start_ohc(void) -{ - /* enable host controller */ -#ifndef CONFIG_SOC_AU1200 - au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG); - au_sync(); - udelay(1000); - - au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG); - au_sync(); - udelay(1000); - - /* wait for reset complete (read register twice; see au1500 errata) */ - while (au_readl(USB_HOST_CONFIG), - !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD)) - udelay(1000); - -#else /* Au1200 */ - au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_CE, USB_HOST_CONFIG); - au_sync(); - udelay(1000); - - au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG); - au_sync(); - udelay(2000); -#endif /* Au1200 */ -} - -static void au1xxx_stop_ohc(void) -{ -#ifdef CONFIG_SOC_AU1200 - /* Disable mem */ - au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_DISABLE, USB_HOST_CONFIG); - au_sync(); - udelay(1000); -#endif - /* Disable clock */ - au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG); - au_sync(); -} - static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); @@ -178,17 +95,6 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; -#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT) - /* Au1200 AB USB does not support coherent memory */ - if (!(read_c0_prid() & 0xff)) { - printk(KERN_INFO "%s: this is chip revision AB !!\n", - pdev->name); - printk(KERN_INFO "%s: update your board or re-configure " - "the kernel\n", pdev->name); - return -ENODEV; - } -#endif - if (pdev->resource[1].flags != IORESOURCE_IRQ) { pr_debug("resource[1] is not IORESOURCE_IRQ\n"); return -ENOMEM; @@ -214,7 +120,12 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) goto err2; } - au1xxx_start_ohc(); + if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) { + printk(KERN_INFO "%s: controller init failed!\n", pdev->name); + ret = -ENODEV; + goto err3; + } + ohci_hcd_init(hcd_to_ohci(hcd)); ret = usb_add_hcd(hcd, pdev->resource[1].start, @@ -224,7 +135,8 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) return ret; } - au1xxx_stop_ohc(); + alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); +err3: iounmap(hcd->regs); err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); @@ -238,7 +150,7 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - au1xxx_stop_ohc(); + alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); @@ -275,7 +187,7 @@ static int ohci_hcd_au1xxx_drv_suspend(struct device *dev) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - au1xxx_stop_ohc(); + alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); bail: spin_unlock_irqrestore(&ohci->lock, flags); @@ -286,7 +198,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - au1xxx_start_ohc(); + alchemy_usb_control(ALCHEMY_USB_OHCI0, 1); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); ohci_finish_controller_resume(hcd); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 34efd479e06..b2639191549 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -389,17 +389,14 @@ ohci_shutdown (struct usb_hcd *hcd) struct ohci_hcd *ohci; ohci = hcd_to_ohci (hcd); - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); - /* If the SHUTDOWN quirk is set, don't put the controller in RESET */ - ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ? - OHCI_CTRL_RWC | OHCI_CTRL_HCFS : - OHCI_CTRL_RWC); - ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); + /* Software reset, after which the controller goes into SUSPEND */ + ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); + ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ + udelay(10); - /* flush the writes */ - (void) ohci_readl (ohci, &ohci->regs->control); + ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); } static int check_ed(struct ohci_hcd *ohci, struct ed *ed) diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ad8166c681e..bc01b064585 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -175,28 +175,6 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) return 0; } -/* nVidia controllers continue to drive Reset signalling on the bus - * even after system shutdown, wasting power. This flag tells the - * shutdown routine to leave the controller OPERATIONAL instead of RESET. - */ -static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) -{ - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - /* Evidently nVidia fixed their later hardware; this is a guess at - * the changeover point. - */ -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d - - if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { - ohci->flags |= OHCI_QUIRK_SHUTDOWN; - ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); - } - - return 0; -} - static void sb800_prefetch(struct ohci_hcd *ohci, int on) { struct pci_dev *pdev; @@ -260,10 +238,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), .driver_data = (unsigned long)ohci_quirk_amd700, }, - { - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), - .driver_data = (unsigned long) ohci_quirk_nvidia_shutdown, - }, /* FIXME for some of the early AMD 760 southbridges, OHCI * won't work at all. blacklist them. diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 35e5fd640ce..0795b934d00 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -403,7 +403,6 @@ struct ohci_hcd { #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ -#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 629a96813fd..caf87428ca4 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -13,6 +13,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/acpi.h> #include <linux/dmi.h> #include "pci-quirks.h" @@ -36,6 +37,7 @@ #define OHCI_INTRENABLE 0x10 #define OHCI_INTRDISABLE 0x14 #define OHCI_FMINTERVAL 0x34 +#define OHCI_HCFS (3 << 6) /* hc functional state */ #define OHCI_HCR (1 << 0) /* host controller reset */ #define OHCI_OCR (1 << 3) /* ownership change request */ #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ @@ -465,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) { void __iomem *base; u32 control; + u32 fminterval; + int cnt; if (!mmio_resource_enabled(pdev, 0)) return; @@ -497,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) } #endif - /* reset controller, preserving RWC (and possibly IR) */ - writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); - readl(base + OHCI_CONTROL); + /* disable interrupts */ + writel((u32) ~0, base + OHCI_INTRDISABLE); - /* Some NVIDIA controllers stop working if kept in RESET for too long */ - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { - u32 fminterval; - int cnt; + /* Reset the USB bus, if the controller isn't already in RESET */ + if (control & OHCI_HCFS) { + /* Go into RESET, preserving RWC (and possibly IR) */ + writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); + readl(base + OHCI_CONTROL); - /* drive reset for at least 50 ms (7.1.7.5) */ + /* drive bus reset for at least 50 ms (7.1.7.5) */ msleep(50); + } - /* software reset of the controller, preserving HcFmInterval */ - fminterval = readl(base + OHCI_FMINTERVAL); - writel(OHCI_HCR, base + OHCI_CMDSTATUS); + /* software reset of the controller, preserving HcFmInterval */ + fminterval = readl(base + OHCI_FMINTERVAL); + writel(OHCI_HCR, base + OHCI_CMDSTATUS); - /* reset requires max 10 us delay */ - for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ - if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) - break; - udelay(1); - } - writel(fminterval, base + OHCI_FMINTERVAL); - - /* Now we're in the SUSPEND state with all devices reset - * and wakeups and interrupts disabled - */ + /* reset requires max 10 us delay */ + for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ + if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) + break; + udelay(1); } + writel(fminterval, base + OHCI_FMINTERVAL); - /* - * disable interrupts - */ - writel(~(u32)0, base + OHCI_INTRDISABLE); - writel(~(u32)0, base + OHCI_INTRSTATUS); - + /* Now the controller is safely in SUSPEND and nothing can wake it up */ iounmap(base); } @@ -626,7 +621,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) void __iomem *base, *op_reg_base; u32 hcc_params, cap, val; u8 offset, cap_length; - int wait_time, delta, count = 256/4; + int wait_time, count = 256/4; if (!mmio_resource_enabled(pdev, 0)) return; @@ -672,11 +667,10 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) writel(val, op_reg_base + EHCI_USBCMD); wait_time = 2000; - delta = 100; do { writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(delta); - wait_time -= delta; + udelay(100); + wait_time -= 100; val = readl(op_reg_base + EHCI_USBSTS); if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { break; diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c index 767af265e00..ba61dae9e4d 100644 --- a/drivers/usb/host/whci/debug.c +++ b/drivers/usb/host/whci/debug.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/export.h> #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 9546f6cd01f..1e141f755b2 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -17,6 +17,7 @@ */ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/uwb/umc.h> #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index d6e17542861..a403b53e86b 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -124,7 +124,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) { qset->td_start = qset->td_end = qset->ntds = 0; - qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); + qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; qset->qh.err_count = 0; qset->qh.scratch[0] = 0; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 431efe72b1f..430e88fd3f6 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,6 +20,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/gfp.h> #include <asm/unaligned.h> #include "xhci.h" diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 42a22b8e692..0e4b25fa3bc 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -982,7 +982,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud struct xhci_virt_device *dev; struct xhci_ep_ctx *ep0_ctx; struct xhci_slot_ctx *slot_ctx; - struct xhci_input_control_ctx *ctrl_ctx; u32 port_num; struct usb_device *top_dev; @@ -994,12 +993,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud return -EINVAL; } ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); - ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); - /* 2) New slot context and endpoint 0 context are valid*/ - ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); - /* 3) Only the control endpoint is valid - one endpoint context */ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route); switch (udev->speed) { diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 9f51f88cc0f..ef98b38626f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -22,6 +22,7 @@ #include <linux/pci.h> #include <linux/slab.h> +#include <linux/module.h> #include "xhci.h" diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 940321b3ec6..9f1d4b15d81 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -816,23 +816,24 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) struct xhci_ring *ring; struct xhci_td *cur_td; int ret, i, j; + unsigned long flags; ep = (struct xhci_virt_ep *) arg; xhci = ep->xhci; - spin_lock(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); ep->stop_cmds_pending--; if (xhci->xhc_state & XHCI_STATE_DYING) { xhci_dbg(xhci, "Stop EP timer ran, but another timer marked " "xHCI as DYING, exiting.\n"); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); return; } if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { xhci_dbg(xhci, "Stop EP timer ran, but no command pending, " "exiting.\n"); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); return; } @@ -844,11 +845,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) xhci->xhc_state |= XHCI_STATE_DYING; /* Disable interrupts from the host controller and start halting it */ xhci_quiesce(xhci); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); ret = xhci_halt(xhci); - spin_lock(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); if (ret < 0) { /* This is bad; the host is not responding to commands and it's * not allowing itself to be halted. At least interrupts are @@ -896,7 +897,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) } } } - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "Calling usb_hc_died()\n"); usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); xhci_dbg(xhci, "xHCI host controller is dead.\n"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1ff95a0df57..a1afb7c39f7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -711,7 +711,10 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) ring = xhci->cmd_ring; seg = ring->deq_seg; do { - memset(seg->trbs, 0, SEGMENT_SIZE); + memset(seg->trbs, 0, + sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); + seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= + cpu_to_le32(~TRB_CYCLE); seg = seg->next; } while (seg != ring->deq_seg); @@ -799,7 +802,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; - int retval; + int retval = 0; /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. @@ -809,6 +812,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci->bus_state[1].next_statechange)) msleep(100); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + spin_lock_irq(&xhci->lock); if (xhci->quirks & XHCI_RESET_ON_RESUME) hibernated = true; @@ -878,20 +884,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) return retval; xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); - if (retval) - goto failed_restart; - - xhci_dbg(xhci, "Start the secondary HCD\n"); - retval = xhci_run(secondary_hcd); if (!retval) { - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, - &xhci->shared_hcd->flags); + xhci_dbg(xhci, "Start the secondary HCD\n"); + retval = xhci_run(secondary_hcd); } -failed_restart: hcd->state = HC_STATE_SUSPENDED; xhci->shared_hcd->state = HC_STATE_SUSPENDED; - return retval; + goto done; } /* step 4: set Run/Stop bit */ @@ -910,11 +909,14 @@ failed_restart: * Running endpoints by ringing their doorbells */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); - spin_unlock_irq(&xhci->lock); - return 0; + + done: + if (retval == 0) { + usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); + } + return retval; } #endif /* CONFIG_PM */ @@ -3504,6 +3506,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* Otherwise, update the control endpoint ring enqueue pointer. */ else xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); + ctrl_ctx->drop_flags = 0; + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); @@ -3585,7 +3591,6 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) + 1; /* Zero the input context control for later use */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx->add_flags = 0; ctrl_ctx->drop_flags = 0; |