aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/dma.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-10-11 17:18:56 -0400
committerTony Lindgren <tony@atomide.com>2010-10-11 17:18:56 -0400
commit0e4905c0199d683497833be60a428c784d7575b8 (patch)
tree943933b19b9e3f1a0340d044d544c6c3db4c6d67 /arch/arm/plat-omap/dma.c
parent3e57f1626b5febe5cc99aa6870377deef3ae03cc (diff)
OMAP3: DMA: Errata i541: sDMA FIFO draining does not finish
Implement the suggested workaround for OMAP3 regarding to sDMA draining issue, when the channel is disabled on the fly. This errata affects the following configuration: sDMA transfer is source synchronized Buffering is enabled SmartStandby is selected. The issue can be easily reproduced by creating overrun situation while recording audio. Either introduce load to the CPU: nice -19 arecord -D hw:0 -M -B 10000 -F 5000 -f dat > /dev/null & \ dd if=/dev/urandom of=/dev/null or suspending the arecord, and resuming it: arecord -D hw:0 -M -B 10000 -F 5000 -f dat > /dev/null CTRL+Z; fg; CTRL+Z; fg; ... In case of overrun audio stops DMA, and restarts it (without reseting the sDMA channel). When we hit this errata in stop case (sDMA drain did not complete), at the coming start the sDMA will not going to be operational (it is still draining). This leads to DMA stall condition. On OMAP3 we can recover with sDMA channel reset, it has been observed that by introducing unrelated sDMA activity might also help (reading from MMC for example). The same errata exists for OMAP2, where the suggestion is to disable the buffering to avoid this type of error. On OMAP3 the suggestion is to set sDMA to NoStandby before disabling the channel, and wait for the drain to finish, than configure sDMA to SmartStandby again. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Jarkko Nikula <jhnikula@gmail.com> Acked-by : Santosh Shilimkar <santosh.shilimkar@ti.com> Acked-by : Manjunath Kondaiah G <manjugk@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/plat-omap/dma.c')
-rw-r--r--arch/arm/plat-omap/dma.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 420cef370b33..f5c5b8da9a87 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -30,6 +30,7 @@
30#include <linux/irq.h> 30#include <linux/irq.h>
31#include <linux/io.h> 31#include <linux/io.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/delay.h>
33 34
34#include <asm/system.h> 35#include <asm/system.h>
35#include <mach/hardware.h> 36#include <mach/hardware.h>
@@ -1024,8 +1025,39 @@ void omap_stop_dma(int lch)
1024 dma_write(0, CICR(lch)); 1025 dma_write(0, CICR(lch));
1025 1026
1026 l = dma_read(CCR(lch)); 1027 l = dma_read(CCR(lch));
1027 l &= ~OMAP_DMA_CCR_EN; 1028 /* OMAP3 Errata i541: sDMA FIFO draining does not finish */
1028 dma_write(l, CCR(lch)); 1029 if (cpu_is_omap34xx() && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
1030 int i = 0;
1031 u32 sys_cf;
1032
1033 /* Configure No-Standby */
1034 l = dma_read(OCP_SYSCONFIG);
1035 sys_cf = l;
1036 l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
1037 l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
1038 dma_write(l , OCP_SYSCONFIG);
1039
1040 l = dma_read(CCR(lch));
1041 l &= ~OMAP_DMA_CCR_EN;
1042 dma_write(l, CCR(lch));
1043
1044 /* Wait for sDMA FIFO drain */
1045 l = dma_read(CCR(lch));
1046 while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
1047 OMAP_DMA_CCR_WR_ACTIVE))) {
1048 udelay(5);
1049 i++;
1050 l = dma_read(CCR(lch));
1051 }
1052 if (i >= 100)
1053 printk(KERN_ERR "DMA drain did not complete on "
1054 "lch %d\n", lch);
1055 /* Restore OCP_SYSCONFIG */
1056 dma_write(sys_cf, OCP_SYSCONFIG);
1057 } else {
1058 l &= ~OMAP_DMA_CCR_EN;
1059 dma_write(l, CCR(lch));
1060 }
1029 1061
1030 if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { 1062 if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
1031 int next_lch, cur_lch = lch; 1063 int next_lch, cur_lch = lch;