Commit e3d80248 authored by Ben Dooks's avatar Ben Dooks

ARM: S3C: Add info for supporting circular DMA buffers

The S3C64XX DMA implementation will work a lot better with the ability
to enqueue circular buffers as the hardware can do it's own linked-list
management.

Add a function s3c_dma_has_circular() to show that the system can do this
and a flag for the channel.

Update the s3c24xx/s3c64xx I2S DMA code to deal with this.
Signed-off-by: default avatarBen Dooks <ben@simtec.co.uk>
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
Acked-by: Mark Brown <broonie@@opensource.wolfsonmicro.com>
parent 964fe080
...@@ -110,6 +110,8 @@ enum s3c2410_dma_loadst { ...@@ -110,6 +110,8 @@ enum s3c2410_dma_loadst {
* waiting for reloads */ * waiting for reloads */
#define S3C2410_DMAF_AUTOSTART (1<<1) /* auto-start if buffer queued */ #define S3C2410_DMAF_AUTOSTART (1<<1) /* auto-start if buffer queued */
#define S3C2410_DMAF_CIRCULAR (1 << 2) /* no circular dma support */
/* dma buffer */ /* dma buffer */
struct s3c2410_dma_buf; struct s3c2410_dma_buf;
...@@ -194,4 +196,9 @@ struct s3c2410_dma_chan { ...@@ -194,4 +196,9 @@ struct s3c2410_dma_chan {
typedef unsigned long dma_device_t; typedef unsigned long dma_device_t;
static inline bool s3c_dma_has_circular(void)
{
return false;
}
#endif /* __ASM_ARCH_DMA_H */ #endif /* __ASM_ARCH_DMA_H */
...@@ -68,6 +68,11 @@ static __inline__ int s3c_dma_has_circular(void) ...@@ -68,6 +68,11 @@ static __inline__ int s3c_dma_has_circular(void)
#define S3C2410_DMAF_CIRCULAR (1 << 0) #define S3C2410_DMAF_CIRCULAR (1 << 0)
static inline bool s3c_dma_has_circular(void)
{
return false;
}
#include <plat/dma.h> #include <plat/dma.h>
#endif /* __ASM_ARCH_IRQ_H */ #endif /* __ASM_ARCH_IRQ_H */
...@@ -75,11 +75,19 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) ...@@ -75,11 +75,19 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
{ {
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos; dma_addr_t pos = prtd->dma_pos;
unsigned int limit;
int ret; int ret;
pr_debug("Entered %s\n", __func__); pr_debug("Entered %s\n", __func__);
while (prtd->dma_loaded < prtd->dma_limit) { if (s3c_dma_has_circular()) {
limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
} else
limit = prtd->dma_limit;
pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit);
while (prtd->dma_loaded < limit) {
unsigned long len = prtd->dma_period; unsigned long len = prtd->dma_period;
pr_debug("dma_loaded: %d\n", prtd->dma_loaded); pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
...@@ -123,7 +131,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, ...@@ -123,7 +131,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
snd_pcm_period_elapsed(substream); snd_pcm_period_elapsed(substream);
spin_lock(&prtd->lock); spin_lock(&prtd->lock);
if (prtd->state & ST_RUNNING) { if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
prtd->dma_loaded--; prtd->dma_loaded--;
s3c24xx_pcm_enqueue(substream); s3c24xx_pcm_enqueue(substream);
} }
...@@ -164,6 +172,11 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -164,6 +172,11 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
printk(KERN_ERR "failed to get dma channel\n"); printk(KERN_ERR "failed to get dma channel\n");
return ret; return ret;
} }
/* use the circular buffering if we have it available. */
if (s3c_dma_has_circular())
s3c2410_dma_setflags(prtd->params->channel,
S3C2410_DMAF_CIRCULAR);
} }
s3c2410_dma_set_buffdone_fn(prtd->params->channel, s3c2410_dma_set_buffdone_fn(prtd->params->channel,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment