Diff
Modified: trunk/drivers/usb/musb/blackfin.c (9801 => 9802)
--- trunk/drivers/usb/musb/blackfin.c 2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/blackfin.c 2011-03-28 17:00:58 UTC (rev 9802)
@@ -21,6 +21,7 @@
#include <asm/cacheflush.h>
#include "musb_core.h"
+#include "musbhsdma.h"
#include "blackfin.h"
struct bfin_glue {
@@ -332,6 +333,27 @@
return -EIO;
}
+static int bfin_musb_channel_program(struct dma_channel *channel,
+ u16 *packet_sz, u8 *mode,
+ dma_addr_t *dma_addr, u32 *len)
+{
+ struct musb_dma_channel *musb_channel = channel->private_data;
+
+ /*
+ * Anomaly 05000450 might cause data corruption when using DMA
+ * MODE 1 transmits with short packet. So to work around this,
+ * we truncate all MODE 1 transfers down to a multiple of the
+ * max packet size, and then do the last short packet transfer
+ * (if there is any) using MODE 0.
+ */
+ if (ANOMALY_05000450) {
+ if (musb_channel->transmit && *mode == 1)
+ *len = *len - (*len % *packet_sz);
+ }
+
+ return 0;
+}
+
static void bfin_musb_reg_init(struct musb *musb)
{
if (ANOMALY_05000346) {
@@ -430,6 +452,8 @@
.vbus_status = bfin_musb_vbus_status,
.set_vbus = bfin_musb_set_vbus,
+
+ .channel_program = bfin_musb_channel_program,
};
static u64 bfin_dmamask = DMA_BIT_MASK(32);
Modified: trunk/drivers/usb/musb/musb_core.h (9801 => 9802)
--- trunk/drivers/usb/musb/musb_core.h 2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musb_core.h 2011-03-28 17:00:58 UTC (rev 9802)
@@ -261,6 +261,7 @@
* @try_ilde: tries to idle the IP
* @vbus_status: returns vbus status if possible
* @set_vbus: forces vbus status
+ * @channel_program: pre check for standard dma channel_program func
*/
struct musb_platform_ops {
int (*init)(struct musb *musb);
@@ -274,6 +275,10 @@
int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);
+
+ int (*channel_program)(struct dma_channel *channel,
+ u16 *packet_sz, u8 *mode,
+ dma_addr_t *dma_addr, u32 *len);
};
/*
Modified: trunk/drivers/usb/musb/musb_gadget.c (9801 => 9802)
--- trunk/drivers/usb/musb/musb_gadget.c 2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musb_gadget.c 2011-03-28 17:00:58 UTC (rev 9802)
@@ -384,13 +384,7 @@
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
musb_ep->dma->desired_mode,
- request->dma + request->actual,
- (musb_ep->dma->desired_mode == 0)
- ? request_size
- : (request_size -
- (request_size %
- musb_ep->packet_sz)));
-
+ request->dma + request->actual, request_size);
if (use_dma) {
if (musb_ep->dma->desired_mode == 0) {
/*
@@ -757,11 +751,7 @@
channel->desired_mode,
request->dma
+ request->actual,
- (musb_ep->dma->desired_mode == 0)
- ? transfer_size
- : (transfer_size -
- (transfer_size %
- musb_ep->packet_sz)));
+ transfer_size);
}
if (use_dma)
Modified: trunk/drivers/usb/musb/musb_host.c (9801 => 9802)
--- trunk/drivers/usb/musb/musb_host.c 2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musb_host.c 2011-03-28 17:00:58 UTC (rev 9802)
@@ -672,10 +672,7 @@
wmb();
if (!dma->channel_program(channel, pkt_size, mode,
- urb->transfer_dma + offset,
- (channel->desired_mode == 0) ? length :
- length - (length % qh->maxpacket)))
- {
+ urb->transfer_dma + offset, length)) {
dma->channel_release(channel);
hw_ep->tx_channel = NULL;
@@ -1753,10 +1750,7 @@
*/
ret = c->channel_program(
dma, qh->maxpacket,
- dma->desired_mode, buf,
- (dma->desired_mode == 0)
- ? length
- : length - (length % qh->maxpacket));
+ dma->desired_mode, buf, length);
if (!ret) {
c->channel_release(dma);
Modified: trunk/drivers/usb/musb/musbhsdma.c (9801 => 9802)
--- trunk/drivers/usb/musb/musbhsdma.c 2011-03-28 09:49:24 UTC (rev 9801)
+++ trunk/drivers/usb/musb/musbhsdma.c 2011-03-28 17:00:58 UTC (rev 9802)
@@ -169,6 +169,14 @@
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ /* Let targets check/tweak the arguments */
+ if (musb->ops->channel_program) {
+ int ret = musb->ops->channel_program(channel, &packet_sz,
+ &mode, &dma_addr, &len);
+ if (ret)
+ return ret;
+ }
+
/*
* The DMA engine in RTL1.8 and above cannot handle
* DMA addresses that are not aligned to a 4 byte boundary.