Skip to content

Commit

Permalink
USB: musb: workaround Blackfin FIFO anomalies
Browse files Browse the repository at this point in the history
Some of these workarounds are already in place, but labeled as affecting
all BF52x parts.  Since we have official anomaly numbers now, use those
defines.  And since writing to the FIFO has a similar hang issue as reading
from the FIFO, implement the workaround there too when necessary.

Signed-off-by: Bryan Wu <cooloney@kernel.org>
Signed-off-by: Cliff Cai <cliff.cai@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Cc: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Bryan Wu authored and Greg Kroah-Hartman committed Dec 23, 2009
1 parent 0ea52ff commit 1c4bdc0
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 45 deletions.
134 changes: 91 additions & 43 deletions drivers/usb/musb/blackfin.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
{
void __iomem *fifo = hw_ep->fifo;
void __iomem *epio = hw_ep->regs;
u8 epnum = hw_ep->epnum;
u16 dma_reg = 0;

prefetch((u8 *)src);

Expand All @@ -39,67 +41,113 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)

dump_fifo_data(src, len);

if (unlikely((unsigned long)src & 0x01))
outsw_8((unsigned long)fifo, src,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
else
outsw((unsigned long)fifo, src,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
}
if (!ANOMALY_05000380 && epnum != 0) {
flush_dcache_range((unsigned int)src,
(unsigned int)(src + len));

/* Setup DMA address register */
dma_reg = (u16) ((u32) src & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();

dma_reg = (u16) (((u32) src >> 16) & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();

/* Setup DMA count register */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
SSYNC();

/* Enable the DMA */
dma_reg = (epnum << 4) | DMA_ENA | INT_ENA | DIRECTION;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
SSYNC();

/* Wait for compelete */
while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
cpu_relax();

/* acknowledge dma interrupt */
bfin_write_USB_DMA_INTERRUPT(1 << epnum);
SSYNC();

/* Reset DMA */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
SSYNC();
} else {
SSYNC();

if (unlikely((unsigned long)src & 0x01))
outsw_8((unsigned long)fifo, src,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
else
outsw((unsigned long)fifo, src,
len & 0x01 ? (len >> 1) + 1 : len >> 1);

}
}
/*
* Unload an endpoint's FIFO
*/
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
void __iomem *fifo = hw_ep->fifo;

#ifdef CONFIG_BF52x
u8 epnum = hw_ep->epnum;
u16 dma_reg = 0;

invalidate_dcache_range((unsigned int)dst,
(unsigned int)(dst + len));
if (ANOMALY_05000467 && epnum != 0) {

/* Setup DMA address register */
dma_reg = (u16) ((u32) dst & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();
invalidate_dcache_range((unsigned int)dst,
(unsigned int)(dst + len));

dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();
/* Setup DMA address register */
dma_reg = (u16) ((u32) dst & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();

/* Setup DMA count register */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
SSYNC();
dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();

/* Enable the DMA */
dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
SSYNC();
/* Setup DMA count register */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
SSYNC();

/* Wait for compelete */
while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
cpu_relax();
/* Enable the DMA */
dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
SSYNC();

/* acknowledge dma interrupt */
bfin_write_USB_DMA_INTERRUPT(1 << epnum);
SSYNC();
/* Wait for compelete */
while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
cpu_relax();

/* Reset DMA */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
SSYNC();
#else
if (unlikely((unsigned long)dst & 0x01))
insw_8((unsigned long)fifo, dst,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
else
insw((unsigned long)fifo, dst,
len & 0x01 ? (len >> 1) + 1 : len >> 1);
#endif
/* acknowledge dma interrupt */
bfin_write_USB_DMA_INTERRUPT(1 << epnum);
SSYNC();

/* Reset DMA */
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
SSYNC();
} else {
SSYNC();
/* Read the last byte of packet with odd size from address fifo + 4
* to trigger 1 byte access to EP0 FIFO.
*/
if (len == 1)
*dst = (u8)inw((unsigned long)fifo + 4);
else {
if (unlikely((unsigned long)dst & 0x01))
insw_8((unsigned long)fifo, dst, len >> 1);
else
insw((unsigned long)fifo, dst, len >> 1);

if (len & 0x01)
*(dst + len - 1) = (u8)inw((unsigned long)fifo + 4);
}
}
DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
'R', hw_ep->epnum, fifo, len, dst);

Expand Down
2 changes: 0 additions & 2 deletions drivers/usb/musb/blackfin.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ static void dump_fifo_data(u8 *buf, u16 len)
#define dump_fifo_data(buf, len) do {} while (0)
#endif

#ifdef CONFIG_BF52x

#define USB_DMA_BASE USB_DMA_INTERRUPT
#define USB_DMAx_CTRL 0x04
Expand All @@ -79,7 +78,6 @@ static void dump_fifo_data(u8 *buf, u16 len)
#define USB_DMAx_COUNT_HIGH 0x14

#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg)
#endif

/* Almost 1 second */
#define TIMER_DELAY (1 * HZ)
Expand Down

0 comments on commit 1c4bdc0

Please sign in to comment.