diff mbox

[v4,4/4] OMAP3: DMA: Errata i541: sDMA FIFO draining does not finish

Message ID 1286180294-32618-5-git-send-email-peter.ujfalusi@nokia.com (mailing list archive)
State Superseded, archived
Delegated to: Tony Lindgren
Headers show

Commit Message

Peter Ujfalusi Oct. 4, 2010, 8:18 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c116c41..a102cf5 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -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)
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index 776ba44..cf66f85 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -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