This is a buildfix for the DaVinci PCM code, resyncing it with
the version in the DaVinci tree.  The notable change is using
current EDMA interfaces, which recently merged to mainline.
(The older interfaces never made it into mainline.)

NOTE:  open issue, the DMA should be to/from SRAM; see chip
errata for more info.  The artifacts are extremely easy to
hear on DM355 hardware (not yet supported in mainline), but
don't seem as audible on DM6446 hardwaare (which does have
mainline support).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
David Brownell 2009-05-14 12:41:22 -07:00 коммит произвёл Mark Brown
Родитель 1ffafeb556
Коммит 82075af6cb
1 изменённых файлов: 41 добавлений и 28 удалений

Просмотреть файл

@ -22,6 +22,7 @@
#include <sound/soc.h>
#include <asm/dma.h>
#include <mach/edma.h>
#include "davinci-pcm.h"
@ -51,7 +52,7 @@ struct davinci_runtime_data {
spinlock_t lock;
int period; /* current DMA period */
int master_lch; /* Master DMA channel */
int slave_lch; /* Slave DMA channel */
int slave_lch; /* linked parameter RAM reload slot */
struct davinci_pcm_dma_params *params; /* DMA params */
};
@ -90,18 +91,18 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
dst_bidx = data_type;
}
davinci_set_dma_src_params(lch, src, INCR, W8BIT);
davinci_set_dma_dest_params(lch, dst, INCR, W8BIT);
davinci_set_dma_src_index(lch, src_bidx, 0);
davinci_set_dma_dest_index(lch, dst_bidx, 0);
davinci_set_dma_transfer_params(lch, data_type, count, 1, 0, ASYNC);
edma_set_src(lch, src, INCR, W8BIT);
edma_set_dest(lch, dst, INCR, W8BIT);
edma_set_src_index(lch, src_bidx, 0);
edma_set_dest_index(lch, dst_bidx, 0);
edma_set_transfer_params(lch, data_type, count, 1, 0, ASYNC);
prtd->period++;
if (unlikely(prtd->period >= runtime->periods))
prtd->period = 0;
}
static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data)
static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data)
{
struct snd_pcm_substream *substream = data;
struct davinci_runtime_data *prtd = substream->runtime->private_data;
@ -125,7 +126,7 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data;
int tcc = TCC_ANY;
struct edmacc_param p_ram;
int ret;
if (!dma_data)
@ -134,22 +135,34 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
prtd->params = dma_data;
/* Request master DMA channel */
ret = davinci_request_dma(prtd->params->channel, prtd->params->name,
ret = edma_alloc_channel(prtd->params->channel,
davinci_pcm_dma_irq, substream,
&prtd->master_lch, &tcc, EVENTQ_0);
if (ret)
EVENTQ_0);
if (ret < 0)
return ret;
prtd->master_lch = ret;
/* Request slave DMA channel */
ret = davinci_request_dma(PARAM_ANY, "Link",
NULL, NULL, &prtd->slave_lch, &tcc, EVENTQ_0);
if (ret) {
davinci_free_dma(prtd->master_lch);
/* Request parameter RAM reload slot */
ret = edma_alloc_slot(EDMA_SLOT_ANY);
if (ret < 0) {
edma_free_channel(prtd->master_lch);
return ret;
}
prtd->slave_lch = ret;
/* Link slave DMA channel in loopback */
davinci_dma_link_lch(prtd->slave_lch, prtd->slave_lch);
/* Issue transfer completion IRQ when the channel completes a
* transfer, then always reload from the same slot (by a kind
* of loopback link). The completion IRQ handler will update
* the reload slot with a new buffer.
*
* REVISIT save p_ram here after setting up everything except
* the buffer and its length (ccnt) ... use it as a template
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
*/
edma_read_slot(prtd->slave_lch, &p_ram);
p_ram.opt |= TCINTEN | EDMA_TCC(prtd->master_lch);
p_ram.link_bcntrld = prtd->slave_lch << 5;
edma_write_slot(prtd->slave_lch, &p_ram);
return 0;
}
@ -165,12 +178,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
davinci_start_dma(prtd->master_lch);
edma_start(prtd->master_lch);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
davinci_stop_dma(prtd->master_lch);
edma_stop(prtd->master_lch);
break;
default:
ret = -EINVAL;
@ -185,14 +198,14 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
{
struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct paramentry_descriptor temp;
struct edmacc_param temp;
prtd->period = 0;
davinci_pcm_enqueue_dma(substream);
/* Get slave channel dma params for master channel startup */
davinci_get_dma_params(prtd->slave_lch, &temp);
davinci_set_dma_params(prtd->master_lch, &temp);
/* Copy self-linked parameter RAM entry into master channel */
edma_read_slot(prtd->slave_lch, &temp);
edma_write_slot(prtd->master_lch, &temp);
return 0;
}
@ -208,7 +221,7 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
spin_lock(&prtd->lock);
davinci_dma_getposition(prtd->master_lch, &src, &dst);
edma_get_position(prtd->master_lch, &src, &dst);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
count = src - runtime->dma_addr;
else
@ -253,10 +266,10 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct davinci_runtime_data *prtd = runtime->private_data;
davinci_dma_unlink_lch(prtd->slave_lch, prtd->slave_lch);
edma_unlink(prtd->slave_lch);
davinci_free_dma(prtd->slave_lch);
davinci_free_dma(prtd->master_lch);
edma_free_slot(prtd->slave_lch);
edma_free_channel(prtd->master_lch);
kfree(prtd);