Commit b287a6d9 authored by Shengjiu Wang's avatar Shengjiu Wang Committed by Mark Brown

ASoC: fsl_asrc_dma: Fix data copying speed issue with EDMA

With EDMA, there is two dma channels can be used for dev_to_dev,
one is from ASRC, one is from another peripheral (ESAI or SAI).

If we select the dma channel of ASRC, there is an issue for ideal
ratio case, the speed of copy data is faster than sample
frequency, because ASRC output data is very fast in ideal ratio
mode.

So it is reasonable to use the dma channel of Back-End peripheral.
then copying speed of DMA is controlled by data consumption
speed in the peripheral FIFO,
Signed-off-by: default avatarShengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: default avatarNicolin Chen <nicoleotsuka@gmail.com>
Link: https://lore.kernel.org/r/424ed6c249bafcbe30791c9de0352821c5ea67e2.1591947428.git.shengjiu.wang@nxp.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 706e2c88
...@@ -32,6 +32,7 @@ enum asrc_pair_index { ...@@ -32,6 +32,7 @@ enum asrc_pair_index {
* @dma_chan: inputer and output DMA channels * @dma_chan: inputer and output DMA channels
* @dma_data: private dma data * @dma_data: private dma data
* @pos: hardware pointer position * @pos: hardware pointer position
* @req_dma_chan: flag to release dev_to_dev chan
* @private: pair private area * @private: pair private area
*/ */
struct fsl_asrc_pair { struct fsl_asrc_pair {
...@@ -45,6 +46,7 @@ struct fsl_asrc_pair { ...@@ -45,6 +46,7 @@ struct fsl_asrc_pair {
struct dma_chan *dma_chan[2]; struct dma_chan *dma_chan[2];
struct imx_dma_data dma_data; struct imx_dma_data dma_data;
unsigned int pos; unsigned int pos;
bool req_dma_chan;
void *private; void *private;
}; };
......
...@@ -233,11 +233,11 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, ...@@ -233,11 +233,11 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
pair->dma_chan[dir] = pair->dma_chan[dir] =
dma_request_channel(mask, filter, &pair->dma_data); dma_request_channel(mask, filter, &pair->dma_data);
pair->req_dma_chan = true;
} else { } else {
if (!be_chan) pair->dma_chan[dir] = tmp_chan;
dma_release_channel(tmp_chan); /* Do not flag to release if we are reusing the Back-End one */
pair->dma_chan[dir] = pair->req_dma_chan = !be_chan;
asrc->get_dma_channel(pair, dir);
} }
if (!pair->dma_chan[dir]) { if (!pair->dma_chan[dir]) {
...@@ -276,7 +276,8 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, ...@@ -276,7 +276,8 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be); ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be);
if (ret) { if (ret) {
dev_err(dev, "failed to config DMA channel for Back-End\n"); dev_err(dev, "failed to config DMA channel for Back-End\n");
dma_release_channel(pair->dma_chan[dir]); if (pair->req_dma_chan)
dma_release_channel(pair->dma_chan[dir]);
return ret; return ret;
} }
...@@ -288,19 +289,22 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, ...@@ -288,19 +289,22 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
static int fsl_asrc_dma_hw_free(struct snd_soc_component *component, static int fsl_asrc_dma_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data; struct fsl_asrc_pair *pair = runtime->private_data;
u8 dir = tx ? OUT : IN;
snd_pcm_set_runtime_buffer(substream, NULL); snd_pcm_set_runtime_buffer(substream, NULL);
if (pair->dma_chan[IN]) if (pair->dma_chan[!dir])
dma_release_channel(pair->dma_chan[IN]); dma_release_channel(pair->dma_chan[!dir]);
if (pair->dma_chan[OUT]) /* release dev_to_dev chan if we aren't reusing the Back-End one */
dma_release_channel(pair->dma_chan[OUT]); if (pair->dma_chan[dir] && pair->req_dma_chan)
dma_release_channel(pair->dma_chan[dir]);
pair->dma_chan[IN] = NULL; pair->dma_chan[!dir] = NULL;
pair->dma_chan[OUT] = NULL; pair->dma_chan[dir] = NULL;
return 0; return 0;
} }
......
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