diff options
author | Bing Song <bing.song@nxp.com> | 2020-08-12 10:22:04 +0800 |
---|---|---|
committer | Bing Song <bing.song@nxp.com> | 2020-08-14 16:48:50 +0800 |
commit | c731ea37eeb2390ebf91d5185ffb8860c86ffc34 (patch) | |
tree | 8fb6b891b8eb98a312d4fd939b323f345ab563c2 /sound/soc/fsl/fsl_dsp_platform_compress.c | |
parent | 5ae911fd64fb27e97fd95b0e5f4813a4b2546e2f (diff) |
MLK-24501-5 dsp: add lpa pcm support.
Use reserved memory as PCM mode need more memory.
Use ping-pong buffer for PCM LPA playback to avoid underrun.
Signed-off-by: Bing Song <bing.song@nxp.com>
Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Diffstat (limited to 'sound/soc/fsl/fsl_dsp_platform_compress.c')
-rw-r--r-- | sound/soc/fsl/fsl_dsp_platform_compress.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/sound/soc/fsl/fsl_dsp_platform_compress.c b/sound/soc/fsl/fsl_dsp_platform_compress.c index 9402b18f107c..04a33774a5f2 100644 --- a/sound/soc/fsl/fsl_dsp_platform_compress.c +++ b/sound/soc/fsl/fsl_dsp_platform_compress.c @@ -33,6 +33,7 @@ void dsp_platform_process(struct work_struct *w) return; if (rmsg->opcode == XF_EMPTY_THIS_BUFFER) { client->consume_bytes += rmsg->length; + atomic_inc(&client->buffer_cnt); snd_compr_fragment_elapsed(client->cstream); if (rmsg->buffer == NULL && rmsg->length == 0) @@ -139,6 +140,7 @@ static int dsp_platform_compr_set_params(struct snd_compr_stream *cstream, switch (params->codec.id) { case SND_AUDIOCODEC_PCM: drv->codec_type = CODEC_PCM_DEC; + atomic_set(&drv->client->buffer_cnt, 2); break; case SND_AUDIOCODEC_MP3: drv->codec_type = CODEC_MP3_DEC; @@ -212,6 +214,7 @@ static int dsp_platform_compr_set_params(struct snd_compr_stream *cstream, drv->client->input_bytes = 0; drv->client->consume_bytes = 0; drv->client->offset = 0; + drv->client->ping_pong_offset = 0; if (drv->codec_type == CODEC_PCM_DEC) { s_param.id = XA_PCM_CONFIG_PARAM_IN_PCM_WIDTH; @@ -323,6 +326,7 @@ static int dsp_platform_compr_trigger_stop(struct snd_compr_stream *cstream) drv->client->input_bytes = 0; drv->client->consume_bytes = 0; drv->client->offset = 0; + drv->client->ping_pong_offset = 0; if (!dsp_priv->dsp_is_lpa) { ret = xaf_comp_delete(drv->client, &drv->component[0]); @@ -438,7 +442,8 @@ static int dsp_platform_compr_pointer(struct snd_compr_stream *cstream, goto out; } - if (drv->client->input_bytes != drv->client->consume_bytes) + if ((drv->codec_type != CODEC_PCM_DEC && drv->client->input_bytes != drv->client->consume_bytes) + || (drv->codec_type == CODEC_PCM_DEC && atomic_read(&drv->client->buffer_cnt) <= 0)) tstamp->copied_total = drv->client->input_bytes+drv->client->offset-4096; else tstamp->copied_total = drv->client->input_bytes+drv->client->offset; @@ -492,6 +497,74 @@ static int dsp_platform_compr_copy(struct snd_compr_stream *cstream, return copied; } +static int dsp_platform_compr_lpa_pcm_copy(struct snd_compr_stream *cstream, + char __user *buf, + size_t count) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + struct xaf_comp *p_comp = &drv->component[0]; + int copied = 0; + int ret; + + if (atomic_read(&drv->client->buffer_cnt) > 0) { + if (drv->client->offset+count >= (INBUF_SIZE_LPA_PCM>>1)-4096 || !buf) { + /* buf == NULL and count == 1 is for drain and */ + /* suspend as tinycompress drain is blocking call */ + copied = count; + if (!buf) + copied = 0; + if (buf) { + ret = copy_from_user(p_comp->inptr+drv->client->ping_pong_offset+drv->client->offset, buf, copied); + if (ret) { + dev_err(component->dev, "failed to get message from user space\n"); + return -EFAULT; + } + } + + if (cstream->runtime->state == SNDRV_PCM_STATE_RUNNING) { + ret = xaf_comp_process(drv->client, p_comp, + p_comp->inptr+drv->client->ping_pong_offset, drv->client->offset+copied, + XF_EMPTY_THIS_BUFFER); + if (!drv->client->input_bytes) { + ret = xaf_connect(drv->client, + &drv->component[0], + &drv->component[1], + 1, + OUTBUF_SIZE); + if (ret) { + dev_err(component->dev, "Failed to connect component, err = %d\n", ret); + return ret; + } + } + + schedule_work(&drv->client->work); + drv->client->input_bytes += drv->client->offset+copied; + drv->client->offset = 0; + atomic_dec(&drv->client->buffer_cnt); + if (drv->client->ping_pong_offset) + drv->client->ping_pong_offset = 0; + else + drv->client->ping_pong_offset = INBUF_SIZE_LPA_PCM>>1; + } + if (!buf) + copied = count; + } else { + ret = copy_from_user(p_comp->inptr+drv->client->ping_pong_offset+drv->client->offset, buf, count); + if (ret) { + dev_err(component->dev, "failed to get message from user space\n"); + return -EFAULT; + } + copied = count; + drv->client->offset += copied; + } + } + + return copied; +} + static int dsp_platform_compr_lpa_copy(struct snd_compr_stream *cstream, char __user *buf, size_t count) @@ -504,6 +577,9 @@ static int dsp_platform_compr_lpa_copy(struct snd_compr_stream *cstream, int copied = 0; int ret; + if (drv->codec_type == CODEC_PCM_DEC) + return dsp_platform_compr_lpa_pcm_copy(cstream, buf, count); + if (drv->client->input_bytes == drv->client->consume_bytes) { if (drv->client->offset+count >= INBUF_SIZE_LPA-4096 || !buf) { /* buf == NULL and count == 1 is for drain and */ |