[alsa-devel] [PATCH 1/1] ASoC Blackfin: fix bug - Audio Latency on AD1981 with MMAP enabled
From: Cliff Cai cliff.cai@analog.com
With MMAP enabled (DMA mode) on the AD1981, there is +/- 250ms of delay between writing data to alsa and audio starts coming out of the AD1981.
Copy more data to local buffer before starting DMA
Signed-off-by: Cliff Cai cliff.cai@analog.com Signed-off-by: Bryan Wu cooloney@kernel.org --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 46 +++++++++++++++++++++++++++++----- sound/soc/blackfin/bf5xx-ac97.c | 1 - sound/soc/blackfin/bf5xx-sport.h | 2 + 3 files changed, 41 insertions(+), 8 deletions(-)
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 51f4907..d61febe 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -24,6 +24,10 @@ * along with this program; if not, see the file COPYING, or write * to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Revision history + * 6th June 2008 Initial version + * 25th Sep 2008 fix latency when enable mmap */
#include <linux/module.h> @@ -56,6 +60,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, sport->tx_pos += runtime->period_size; if (sport->tx_pos >= runtime->buffer_size) sport->tx_pos %= runtime->buffer_size; + sport->tx_delay_pos = sport->tx_pos; } else { bf5xx_ac97_to_pcm( (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, @@ -72,7 +77,15 @@ static void bf5xx_dma_irq(void *data) struct snd_pcm_substream *pcm = data; #if defined(CONFIG_SND_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = pcm->runtime; + struct sport_device *sport = runtime->private_data; bf5xx_mmap_copy(pcm, runtime->period_size); + if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (sport->once == 0) { + snd_pcm_period_elapsed(pcm); + bf5xx_mmap_copy(pcm, runtime->period_size); + sport->once = 1; + } + } #endif snd_pcm_period_elapsed(pcm); } @@ -114,6 +127,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + memset(runtime->dma_area, 0, runtime->buffer_size); snd_pcm_lib_free_pages(substream); return 0; } @@ -127,16 +144,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) * SPORT working in TMD mode(include AC97). */ #if defined(CONFIG_SND_MMAP_SUPPORT) - size_t size = bf5xx_pcm_hardware.buffer_bytes_max - * sizeof(struct ac97_frame) / 4; - /*clean up intermediate buffer*/ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - memset(sport->tx_dma_buf, 0, size); sport_set_tx_callback(sport, bf5xx_dma_irq, substream); sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, runtime->period_size * sizeof(struct ac97_frame)); } else { - memset(sport->rx_dma_buf, 0, size); sport_set_rx_callback(sport, bf5xx_dma_irq, substream); sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, runtime->period_size * sizeof(struct ac97_frame)); @@ -164,8 +176,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) pr_debug("%s enter\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + bf5xx_mmap_copy(substream, runtime->period_size); + snd_pcm_period_elapsed(substream); + sport->tx_delay_pos = 0; sport_tx_start(sport); + } else sport_rx_start(sport); break; @@ -198,7 +214,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - curr = sport->tx_pos; + curr = sport->tx_delay_pos; else curr = sport->rx_pos; #else @@ -237,6 +253,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) return ret; }
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + + pr_debug("%s enter\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport->once = 0; + memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + } else + memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + + return 0; +} + #ifdef CONFIG_SND_MMAP_SUPPORT static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) @@ -272,6 +303,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .open = bf5xx_pcm_open, + .close = bf5xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = bf5xx_pcm_hw_params, .hw_free = bf5xx_pcm_hw_free, diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index c782e31..5e5aafb 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) struct ac97_frame *nextwrite;
sport_incfrag(sport, &nextfrag, 1); - sport_incfrag(sport, &nextfrag, 1);
nextwrite = (struct ac97_frame *)(sport->tx_buf + \ nextfrag * sport->tx_fragsize); diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index 4c16345..fcadcc0 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -123,6 +123,8 @@ struct sport_device { int rx_pos; unsigned int tx_buffer_size; unsigned int rx_buffer_size; + int tx_delay_pos; + int once; #endif void *private_data; };
On Sat, Sep 27, 2008 at 04:58:09PM +0800, Bryan Wu wrote:
From: Cliff Cai cliff.cai@analog.com
With MMAP enabled (DMA mode) on the AD1981, there is +/- 250ms of delay between writing data to alsa and audio starts coming out of the AD1981.
Copy more data to local buffer before starting DMA
Signed-off-by: Cliff Cai cliff.cai@analog.com Signed-off-by: Bryan Wu cooloney@kernel.org
Acked-by: Mark Brown broonie@opensource.wolfsonmicro.com
but
- Revision history
6th June 2008 Initial version
*/
25th Sep 2008 fix latency when enable mmap
it'd be good to drop the in-code changelogs - we're already tracking the history of the code with git and they're likely to end up providing an inaccurate history due to people not updating them (this applies to most of the Blackfin code). There were in-code changelogs in ASoC in the past from the time it was out of tree but they shouldn't be required now.
On Sat, Sep 27, 2008 at 5:33 PM, Mark Brown broonie@sirena.org.uk wrote:
On Sat, Sep 27, 2008 at 04:58:09PM +0800, Bryan Wu wrote:
From: Cliff Cai cliff.cai@analog.com
With MMAP enabled (DMA mode) on the AD1981, there is +/- 250ms of delay between writing data to alsa and audio starts coming out of the AD1981.
Copy more data to local buffer before starting DMA
Signed-off-by: Cliff Cai cliff.cai@analog.com Signed-off-by: Bryan Wu cooloney@kernel.org
Acked-by: Mark Brown broonie@opensource.wolfsonmicro.com
but
- Revision history
6th June 2008 Initial version
*/
25th Sep 2008 fix latency when enable mmap
it'd be good to drop the in-code changelogs - we're already tracking the history of the code with git and they're likely to end up providing an inaccurate history due to people not updating them (this applies to most of the Blackfin code). There were in-code changelogs in ASoC in the past from the time it was out of tree but they shouldn't be required now.
OK, I will submit a new patch by moving the changelogs to git log.
Thanks -Bryan
participants (2)
-
Bryan Wu
-
Mark Brown