@@ -30,6 +30,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <mach/hardware.h>
@@ -148,6 +149,8 @@ static const u8 omap1_dma_irq[OMAP1_LOGICAL_DMA_CH_COUNT] = {
/* Errata handling */
#define DMA_ERRATA_IFRAME_BUFFERING (1 << 0)
+/* OMAP3 Errata i541: sDMA FIFO draining does not finish */
+#define DMA_ERRATA_i541 (1 << 1)
static u16 dma_errata;
#define IS_DMA_ERRATA(id) (dma_errata & (id))
@@ -1023,8 +1026,40 @@ void omap_stop_dma(int lch)
dma_write(0, CICR(lch));
l = dma_read(CCR(lch));
- l &= ~OMAP_DMA_CCR_EN;
- dma_write(l, CCR(lch));
+ /* OMAP3 Errata i541: sDMA FIFO draining does not finish */
+ if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
+ (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
+ int i = 0;
+ u32 sys_cf;
+
+ /* Configure No-Standby */
+ l = dma_read(OCP_SYSCONFIG);
+ sys_cf = l;
+ l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
+ l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
+ dma_write(l , OCP_SYSCONFIG);
+
+ l = dma_read(CCR(lch));
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+
+ /* Wait for sDMA FIFO drain */
+ l = dma_read(CCR(lch));
+ while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
+ OMAP_DMA_CCR_WR_ACTIVE))) {
+ udelay(5);
+ i++;
+ l = dma_read(CCR(lch));
+ }
+ if (i >= 100)
+ printk(KERN_ERR "DMA drain did not complete on "
+ "lch %d\n", lch);
+ /* Restore OCP_SYSCONFIG */
+ dma_write(sys_cf, OCP_SYSCONFIG);
+ } else {
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+ }
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch = lch;
@@ -2051,6 +2086,9 @@ static void dma_errata_configure(void)
if (cpu_is_omap2420() ||
(cpu_is_omap2430() && (omap_type() == OMAP2430_REV_ES1_0)))
dma_errata |= DMA_ERRATA_IFRAME_BUFFERING;
+
+ if (cpu_is_omap34xx())
+ dma_errata |= DMA_ERRATA_i541;
}
static int __init omap_init_dma(void)
@@ -335,6 +335,9 @@
#define OMAP2_DMA_MISALIGNED_ERR_IRQ (1 << 11)
#define OMAP_DMA_CCR_EN (1 << 7)
+#define OMAP_DMA_CCR_RD_ACTIVE (1 << 9)
+#define OMAP_DMA_CCR_WR_ACTIVE (1 << 10)
+#define OMAP_DMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
#define OMAP_DMA_CCR_BUFFERING_DISABLE (1 << 25)
#define OMAP_DMA_DATA_TYPE_S8 0x00