Commit 373a500e authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown

ASoC: omap-mcpdm: Add pm_qos handling to avoid under/overruns with CPU_IDLE

We need to block sleep states which would require longer time to leave than
the time the DMA must react to the DMA request in order to keep the FIFO
serviced without under of overrun.
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Acked-by: default avatarJarkko Nikula <jarkko.nikula@bitmer.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent dd2f52d8
...@@ -54,6 +54,8 @@ struct omap_mcpdm { ...@@ -54,6 +54,8 @@ struct omap_mcpdm {
unsigned long phys_base; unsigned long phys_base;
void __iomem *io_base; void __iomem *io_base;
int irq; int irq;
struct pm_qos_request pm_qos_req;
int latency[2];
struct mutex mutex; struct mutex mutex;
...@@ -277,6 +279,9 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, ...@@ -277,6 +279,9 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
mutex_lock(&mcpdm->mutex); mutex_lock(&mcpdm->mutex);
...@@ -289,6 +294,14 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, ...@@ -289,6 +294,14 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
} }
} }
if (mcpdm->latency[stream2])
pm_qos_update_request(&mcpdm->pm_qos_req,
mcpdm->latency[stream2]);
else if (mcpdm->latency[stream1])
pm_qos_remove_request(&mcpdm->pm_qos_req);
mcpdm->latency[stream1] = 0;
mutex_unlock(&mcpdm->mutex); mutex_unlock(&mcpdm->mutex);
} }
...@@ -300,7 +313,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -300,7 +313,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
int stream = substream->stream; int stream = substream->stream;
struct snd_dmaengine_dai_dma_data *dma_data; struct snd_dmaengine_dai_dma_data *dma_data;
u32 threshold; u32 threshold;
int channels; int channels, latency;
int link_mask = 0; int link_mask = 0;
channels = params_channels(params); channels = params_channels(params);
...@@ -344,14 +357,25 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -344,14 +357,25 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
dma_data->maxburst = dma_data->maxburst =
(MCPDM_DN_THRES_MAX - threshold) * channels; (MCPDM_DN_THRES_MAX - threshold) * channels;
latency = threshold;
} else { } else {
/* If playback is not running assume a stereo stream to come */ /* If playback is not running assume a stereo stream to come */
if (!mcpdm->config[!stream].link_mask) if (!mcpdm->config[!stream].link_mask)
mcpdm->config[!stream].link_mask = (0x3 << 3); mcpdm->config[!stream].link_mask = (0x3 << 3);
dma_data->maxburst = threshold * channels; dma_data->maxburst = threshold * channels;
latency = (MCPDM_DN_THRES_MAX - threshold);
} }
/*
* The DMA must act to a DMA request within latency time (usec) to avoid
* under/overflow
*/
mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params);
if (!mcpdm->latency[stream])
mcpdm->latency[stream] = 10;
/* Check if we need to restart McPDM with this stream */ /* Check if we need to restart McPDM with this stream */
if (mcpdm->config[stream].link_mask && if (mcpdm->config[stream].link_mask &&
mcpdm->config[stream].link_mask != link_mask) mcpdm->config[stream].link_mask != link_mask)
...@@ -366,6 +390,20 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, ...@@ -366,6 +390,20 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req;
int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
int latency = mcpdm->latency[stream2];
/* Prevent omap hardware from hitting off between FIFO fills */
if (!latency || mcpdm->latency[stream1] < latency)
latency = mcpdm->latency[stream1];
if (pm_qos_request_active(pm_qos_req))
pm_qos_update_request(pm_qos_req, latency);
else if (latency)
pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
if (!omap_mcpdm_active(mcpdm)) { if (!omap_mcpdm_active(mcpdm)) {
omap_mcpdm_start(mcpdm); omap_mcpdm_start(mcpdm);
...@@ -427,6 +465,9 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) ...@@ -427,6 +465,9 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
free_irq(mcpdm->irq, (void *)mcpdm); free_irq(mcpdm->irq, (void *)mcpdm);
pm_runtime_disable(mcpdm->dev); pm_runtime_disable(mcpdm->dev);
if (pm_qos_request_active(&mcpdm->pm_qos_req))
pm_qos_remove_request(&mcpdm->pm_qos_req);
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