diff options
author | Stephen Warren <swarren@nvidia.com> | 2011-04-19 14:23:53 -0700 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2011-08-04 22:57:53 -0600 |
commit | 890e3f0efe94eca870c836b2df4f6478a2c40c0b (patch) | |
tree | 687f038735f4db0c998301cf2904e157184dbbea /sound | |
parent | 2e39114fff798e8904f4c51877ff426799bf0101 (diff) |
CHROMIUM: ASoC: Tegra: Double-buffer DMA in HW
Avoid audio FIFO underflow due to DMA ISR latency.
MODE_ONESHOT works like this:
* CPU tells DMA HW to make a transfer .
* DMA HW performs the transfer, fires an interrupt, and goes idle.
* Interrupt latency (including e.g. LP2 exit time) is seen here.
* DMA driver ISR programs the next transfer, from a SW transfer queue.
In that model, the interrupt latency must be hidden by the I2S FIFO, which
is 16 samples IIRC, i.e. a very short time (~0.3mS @ 48KHz).
MODE_CONTINUOUS_SINGLE works like this:
* CPU tells DMA HW to make a transfer .
* CPU tells DMA HW to make a second transfer.
* DMA HW performs the transfer, fires an interrupt, and starts the second
transfer immediately.
* DMA driver ISR programs the next (third) transfer, while the second is
in progress, from a SW transfer queue.
Thus any DMA ISR latency is seen between transfer N completing and transfer
N+2 starting (rather than N+1), since the HW itself already knows how to
perform transfer N+1 before transfer N completes. Hence, the system is
tolerant of much larger latencies.
BUG=chromium-os-partner:3294
TEST=Seaboard clamshell: "aplay sin-500hz-48000-60s.wav" multiple times
while system idle and power LED flickering indicating CPU power saving.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Olof Johansson <olofj@chromium.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 4524b0f88ef8..dde24b42483b 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -161,7 +161,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) prtd->dma_req[1].dev = prtd; prtd->dma_chan = tegra_dma_allocate_channel( - TEGRA_DMA_MODE_ONESHOT, "pcm"); + TEGRA_DMA_MODE_CONTINUOUS_SINGLE, "pcm"); if (prtd->dma_chan == NULL) { ret = -ENOMEM; goto err; |