diff options
-rw-r--r-- | drivers/usb/musb/blackfin.c | 24 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 5 | ||||
-rw-r--r-- | drivers/usb/musb/musbhsdma.c | 8 |
3 files changed, 37 insertions, 0 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 52312e8af213..8e2a1ff8a35a 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
22 | 22 | ||
23 | #include "musb_core.h" | 23 | #include "musb_core.h" |
24 | #include "musbhsdma.h" | ||
24 | #include "blackfin.h" | 25 | #include "blackfin.h" |
25 | 26 | ||
26 | struct bfin_glue { | 27 | struct bfin_glue { |
@@ -332,6 +333,27 @@ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode) | |||
332 | return -EIO; | 333 | return -EIO; |
333 | } | 334 | } |
334 | 335 | ||
336 | static int bfin_musb_adjust_channel_params(struct dma_channel *channel, | ||
337 | u16 packet_sz, u8 *mode, | ||
338 | dma_addr_t *dma_addr, u32 *len) | ||
339 | { | ||
340 | struct musb_dma_channel *musb_channel = channel->private_data; | ||
341 | |||
342 | /* | ||
343 | * Anomaly 05000450 might cause data corruption when using DMA | ||
344 | * MODE 1 transmits with short packet. So to work around this, | ||
345 | * we truncate all MODE 1 transfers down to a multiple of the | ||
346 | * max packet size, and then do the last short packet transfer | ||
347 | * (if there is any) using MODE 0. | ||
348 | */ | ||
349 | if (ANOMALY_05000450) { | ||
350 | if (musb_channel->transmit && *mode == 1) | ||
351 | *len = *len - (*len % packet_sz); | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
335 | static void bfin_musb_reg_init(struct musb *musb) | 357 | static void bfin_musb_reg_init(struct musb *musb) |
336 | { | 358 | { |
337 | if (ANOMALY_05000346) { | 359 | if (ANOMALY_05000346) { |
@@ -430,6 +452,8 @@ static const struct musb_platform_ops bfin_ops = { | |||
430 | 452 | ||
431 | .vbus_status = bfin_musb_vbus_status, | 453 | .vbus_status = bfin_musb_vbus_status, |
432 | .set_vbus = bfin_musb_set_vbus, | 454 | .set_vbus = bfin_musb_set_vbus, |
455 | |||
456 | .adjust_channel_params = bfin_musb_adjust_channel_params, | ||
433 | }; | 457 | }; |
434 | 458 | ||
435 | static u64 bfin_dmamask = DMA_BIT_MASK(32); | 459 | static u64 bfin_dmamask = DMA_BIT_MASK(32); |
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 4bd9e2145ee4..0e053b587960 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -261,6 +261,7 @@ enum musb_g_ep0_state { | |||
261 | * @try_ilde: tries to idle the IP | 261 | * @try_ilde: tries to idle the IP |
262 | * @vbus_status: returns vbus status if possible | 262 | * @vbus_status: returns vbus status if possible |
263 | * @set_vbus: forces vbus status | 263 | * @set_vbus: forces vbus status |
264 | * @channel_program: pre check for standard dma channel_program func | ||
264 | */ | 265 | */ |
265 | struct musb_platform_ops { | 266 | struct musb_platform_ops { |
266 | int (*init)(struct musb *musb); | 267 | int (*init)(struct musb *musb); |
@@ -274,6 +275,10 @@ struct musb_platform_ops { | |||
274 | 275 | ||
275 | int (*vbus_status)(struct musb *musb); | 276 | int (*vbus_status)(struct musb *musb); |
276 | void (*set_vbus)(struct musb *musb, int on); | 277 | void (*set_vbus)(struct musb *musb, int on); |
278 | |||
279 | int (*adjust_channel_params)(struct dma_channel *channel, | ||
280 | u16 packet_sz, u8 *mode, | ||
281 | dma_addr_t *dma_addr, u32 *len); | ||
277 | }; | 282 | }; |
278 | 283 | ||
279 | /* | 284 | /* |
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 0144a2d481fd..d281792db05c 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c | |||
@@ -169,6 +169,14 @@ static int dma_channel_program(struct dma_channel *channel, | |||
169 | BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || | 169 | BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || |
170 | channel->status == MUSB_DMA_STATUS_BUSY); | 170 | channel->status == MUSB_DMA_STATUS_BUSY); |
171 | 171 | ||
172 | /* Let targets check/tweak the arguments */ | ||
173 | if (musb->ops->adjust_channel_params) { | ||
174 | int ret = musb->ops->adjust_channel_params(channel, | ||
175 | packet_sz, &mode, &dma_addr, &len); | ||
176 | if (ret) | ||
177 | return ret; | ||
178 | } | ||
179 | |||
172 | /* | 180 | /* |
173 | * The DMA engine in RTL1.8 and above cannot handle | 181 | * The DMA engine in RTL1.8 and above cannot handle |
174 | * DMA addresses that are not aligned to a 4 byte boundary. | 182 | * DMA addresses that are not aligned to a 4 byte boundary. |