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 | |
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>
-rw-r--r-- | sound/soc/fsl/fsl_dsp.c | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dsp.h | 5 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dsp_platform_compress.c | 78 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dsp_proxy.c | 5 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dsp_xaf_api.c | 9 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dsp_xaf_api.h | 2 |
6 files changed, 97 insertions, 5 deletions
diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 46c16ebc8c54..352c8dc599de 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -1074,6 +1074,9 @@ static int fsl_dsp_mem_setup_lpa(struct fsl_dsp *dsp_priv) dsp_priv->scratch_buf_virt = dsp_priv->ocram_vir_addr; dsp_priv->scratch_buf_phys = dsp_priv->ocram_phys_addr; dsp_priv->scratch_buf_size = dsp_priv->ocram_reserved_size; + dsp_priv->dram_reserved_vir_addr = dsp_priv->sdram_vir_addr; + dsp_priv->dram_reserved_phys_addr = dsp_priv->sdram_phys_addr; + dsp_priv->dram_reserved_size = dsp_priv->sdram_reserved_size; dsp_priv->sdram_vir_addr = dsp_priv->regs + SYSRAM_OFFSET; dsp_priv->sdram_phys_addr = dsp_priv->paddr + SYSRAM_OFFSET; dsp_priv->sdram_reserved_size = SYSRAM_SIZE; diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index a4e4537bc19e..2e2c71890819 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -58,6 +58,8 @@ struct xf_client { int input_bytes; int consume_bytes; int offset; + atomic_t buffer_cnt; + int ping_pong_offset; }; union xf_client_link { @@ -88,6 +90,9 @@ struct fsl_dsp { void *sdram_vir_addr; unsigned long sdram_phys_addr; int sdram_reserved_size; + void *dram_reserved_vir_addr; + unsigned long dram_reserved_phys_addr; + int dram_reserved_size; void *ocram_vir_addr; unsigned long ocram_phys_addr; int ocram_reserved_size; 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 */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index 84271e0a17a5..73e6e4cb6147 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -288,6 +288,9 @@ u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b) else if ((u32)(b - dsp_priv->scratch_buf_virt) < dsp_priv->scratch_buf_size) return (u32)(b - dsp_priv->scratch_buf_virt); + else if (dsp_priv->dsp_is_lpa && ((u32)(b - dsp_priv->dram_reserved_vir_addr) < + dsp_priv->dram_reserved_size)) + return (u32)(b - dsp_priv->dram_reserved_vir_addr + dsp_priv->scratch_buf_size); else return XF_PROXY_BADADDR; } @@ -300,6 +303,8 @@ void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address) if (address < dsp_priv->scratch_buf_size) return dsp_priv->scratch_buf_virt + address; + else if (dsp_priv->dsp_is_lpa && (address < dsp_priv->scratch_buf_size + dsp_priv->dram_reserved_size)) + return dsp_priv->dram_reserved_vir_addr + address - dsp_priv->scratch_buf_size; else if (address == XF_PROXY_NULL) return NULL; else diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.c b/sound/soc/fsl/fsl_dsp_xaf_api.c index f721854ac67c..f544b6a3adba 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.c +++ b/sound/soc/fsl/fsl_dsp_xaf_api.c @@ -205,13 +205,18 @@ int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, p_comp->codec_lib.lib_type = DSP_CODEC_LIB; } + size = INBUF_SIZE; switch (comp_type) { case CODEC_PCM_DEC: p_comp->dec_id = "audio-decoder/pcm"; + if (dsp_priv->dsp_is_lpa) + size = INBUF_SIZE_LPA_PCM; break; case CODEC_MP3_DEC: p_comp->dec_id = "audio-decoder/mp3"; strcat(lib_path, "lib_dsp_mp3_dec.so"); + if (dsp_priv->dsp_is_lpa) + size = INBUF_SIZE_LPA; break; case CODEC_AAC_DEC: p_comp->dec_id = "audio-decoder/aac"; @@ -258,10 +263,6 @@ int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, if (request_inbuf) { /* ...allocate input buffer */ - if (dsp_priv->dsp_is_lpa) - size = INBUF_SIZE_LPA; - else - size = INBUF_SIZE; ret = xf_pool_alloc(client, proxy, 1, size, XF_POOL_INPUT, &p_comp->inpool); if (ret) { diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.h b/sound/soc/fsl/fsl_dsp_xaf_api.h index 415aafd9fd2f..7b2dfa48977d 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.h +++ b/sound/soc/fsl/fsl_dsp_xaf_api.h @@ -21,6 +21,8 @@ /* ...buffer size of the buffer shared between A core and DSP. Use large */ /* ...to let A core suspend longer time to save power.*/ #define INBUF_SIZE_LPA (128*1024) +/* ...ping-pong buffer locate in DRAM for PCM LPA. */ +#define INBUF_SIZE_LPA_PCM (8*1024*1024) #define OUTBUF_SIZE 16384 struct xaf_pipeline; |