aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorHans Petter Selasky <hans.petter.selasky@stericsson.com>2010-06-11 16:26:03 +0200
committerJohn Rigby <john.rigby@linaro.org>2010-09-02 22:45:43 -0600
commit7625ca007e7d22d665d5aa998019cc5627b8dabb (patch)
treedd95ee179f7f85a31c07b6c91906d87c4f4968fa /drivers/usb
parent497591545e0849bdd72f81143215b0982594b776 (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.c8
-rw-r--r--drivers/usb/musb/musb_core.c4
-rw-r--r--drivers/usb/musb/musb_host.c45
-rw-r--r--drivers/usb/musb/stm_musb.c5
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);
}