diff options
author | Hans Petter Selasky <hans.petter.selasky@stericsson.com> | 2010-06-11 16:26:03 +0200 |
---|---|---|
committer | John Rigby <john.rigby@linaro.org> | 2010-09-02 22:45:43 -0600 |
commit | 7625ca007e7d22d665d5aa998019cc5627b8dabb (patch) | |
tree | dd95ee179f7f85a31c07b6c91906d87c4f4968fa /drivers/usb | |
parent | 497591545e0849bdd72f81143215b0982594b776 (diff) |
USB: Patch to fix critical problems in USB HOST mode in the MUSB chipdriver.
- Workaround for modem TX-FLUSH due to broken USB HW.
- Disable double-buffer due to broken DMA HW.
- Fix NULL pointer dereference.
ST_Ericsson ID: ER263315
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/1369
Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Change-Id: I741bae292b1529f91228e8eae4dd4d3dd8f641de
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2539
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 8 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 4 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 45 | ||||
-rw-r--r-- | drivers/usb/musb/stm_musb.c | 5 |
4 files changed, 42 insertions, 20 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0940ccd6f4f..c2d13b5850e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1498,12 +1498,14 @@ static void choose_address(struct usb_device *udev) * bus->devnum_next. */ devnum = find_next_zero_bit(bus->devmap.devicemap, 128, bus->devnum_next); - if (devnum >= 128) + /* Due to Hardware bugs we need to reserve a device address + * for flushing of endpoints. */ + if (devnum >= 127) devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + bus->devnum_next = ( devnum >= 126 ? 1 : devnum + 1); } - if (devnum < 128) { + if (devnum < 127) { set_bit(devnum, bus->devmap.devicemap); udev->devnum = devnum; } diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index be4e03b681a..28f22024649 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1118,8 +1118,8 @@ static struct fifo_cfg __initdata mode_4_cfg[] = { /* mode 5 - fits in 8KB */ static struct fifo_cfg __initdata mode_5_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE,}, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE,}, +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 877d20b1dff..5490c2bc46a 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -106,24 +106,41 @@ static void musb_ep_program(struct musb *musb, u8 epnum, static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) { void __iomem *epio = ep->regs; + void __iomem *regs = ep->musb->mregs; u16 csr; - u16 lastcsr = 0; - int retries = 1000; + u8 addr; + int retries = 3000; /* 3ms */ + /* + * NOTE: We are using a hack here because the FIFO-FLUSH + * bit is broken in hardware! The hack consists of changing + * the TXFUNCADDR to an unused device address and waiting + * for any pending USB packets to hit the 3-strikes and your + * gone rule. + */ + addr = musb_readb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, MUSB_TXFUNCADDR)); csr = musb_readw(epio, MUSB_TXCSR); while (csr & MUSB_TXCSR_FIFONOTEMPTY) { - if (csr != lastcsr) - DBG(3, "Host TX FIFONOTEMPTY csr: %02x\n", csr); - lastcsr = csr; - csr |= MUSB_TXCSR_FLUSHFIFO; - musb_writew(epio, MUSB_TXCSR, csr); + musb_writeb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, + MUSB_TXFUNCADDR), 127); csr = musb_readw(epio, MUSB_TXCSR); - if (WARN(retries-- < 1, - "Could not flush host TX%d fifo: csr: %04x\n", - ep->epnum, csr)) - return; - mdelay(1); + retries--; + if (retries == 0) { + /* can happen if the USB clocks are OFF */ + DBG(3, "Could not flush host TX%d " + "fifo: csr=0x%04x\n", ep->epnum, csr); + break; + } + udelay(1); } + /* clear any errors */ + csr &= ~(MUSB_TXCSR_H_ERROR + | MUSB_TXCSR_H_RXSTALL + | MUSB_TXCSR_H_NAKTIMEOUT); + musb_writew(epio, MUSB_TXCSR, csr); + + /* restore endpoint address */ + musb_writeb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, MUSB_TXFUNCADDR), addr); } static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) @@ -1141,7 +1158,9 @@ void musb_host_tx(struct musb *musb, u8 epnum) DBG(3, "TX 3strikes on ep=%d\n", epnum); status = -ETIMEDOUT; - + } else if (tx_csr & MUSB_TXCSR_TXPKTRDY) { + /* BUSY - can happen during USB transfer cancel */ + return; } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { DBG(6, "TX end=%d device not responding\n", epnum); diff --git a/drivers/usb/musb/stm_musb.c b/drivers/usb/musb/stm_musb.c index 7d30cae40f4..822209a1886 100644 --- a/drivers/usb/musb/stm_musb.c +++ b/drivers/usb/musb/stm_musb.c @@ -34,13 +34,14 @@ static unsigned musb_power; void musb_set_session(void) { - u8 val = 0; - void __iomem *regs = musb_status->mregs; + u8 val; + void __iomem *regs; if (musb_status == NULL) { printk(KERN_ERR "Error: devctl session cannot be set\n"); return; } + regs = musb_status->mregs; val = musb_readb(regs, MUSB_DEVCTL); musb_writeb(regs, MUSB_DEVCTL, val | MUSB_DEVCTL_SESSION); } |