Commit 789e3b6c authored by Srinivas Kandagatla's avatar Srinivas Kandagatla Committed by Mark Brown

ASoC: q6asm: make commands specific to streams

Each ASM session can have multiple streams attached to it,
current design was to allow only one static stream id 1 per each session.
However for use-case like gapless, we would need 2 streams to open per session.

This patch converts all the q6asm apis to take stream id as argument
to allow multiple streams to open on a single session, This is useful
for gapless playback cases.

Now the dai driver can specify which stream id for each command.
Signed-off-by: default avatarSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Tested-by: default avatarVinod Koul <vkoul@kernel.org>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarVinod Koul <vkoul@kernel.org>
Link: https://lore.kernel.org/r/20200727093806.17089-3-srinivas.kandagatla@linaro.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 99b7db5f
...@@ -64,6 +64,7 @@ struct q6asm_dai_rtd { ...@@ -64,6 +64,7 @@ struct q6asm_dai_rtd {
uint16_t bits_per_sample; uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */ uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client; struct audio_client *audio_client;
uint32_t stream_id;
uint16_t session_id; uint16_t session_id;
enum stream_state state; enum stream_state state;
}; };
...@@ -181,7 +182,7 @@ static void event_handler(uint32_t opcode, uint32_t token, ...@@ -181,7 +182,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
switch (opcode) { switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE: case ASM_CLIENT_EVENT_CMD_RUN_DONE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
q6asm_write_async(prtd->audio_client, q6asm_write_async(prtd->audio_client, prtd->stream_id,
prtd->pcm_count, 0, 0, NO_TIMESTAMP); prtd->pcm_count, 0, 0, NO_TIMESTAMP);
break; break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE: case ASM_CLIENT_EVENT_CMD_EOS_DONE:
...@@ -191,7 +192,7 @@ static void event_handler(uint32_t opcode, uint32_t token, ...@@ -191,7 +192,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
prtd->pcm_irq_pos += prtd->pcm_count; prtd->pcm_irq_pos += prtd->pcm_count;
snd_pcm_period_elapsed(substream); snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING) if (prtd->state == Q6ASM_STREAM_RUNNING)
q6asm_write_async(prtd->audio_client, q6asm_write_async(prtd->audio_client, prtd->stream_id,
prtd->pcm_count, 0, 0, NO_TIMESTAMP); prtd->pcm_count, 0, 0, NO_TIMESTAMP);
break; break;
...@@ -200,7 +201,7 @@ static void event_handler(uint32_t opcode, uint32_t token, ...@@ -200,7 +201,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
prtd->pcm_irq_pos += prtd->pcm_count; prtd->pcm_irq_pos += prtd->pcm_count;
snd_pcm_period_elapsed(substream); snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING) if (prtd->state == Q6ASM_STREAM_RUNNING)
q6asm_read(prtd->audio_client); q6asm_read(prtd->audio_client, prtd->stream_id);
break; break;
default: default:
...@@ -233,7 +234,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, ...@@ -233,7 +234,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
/* rate and channels are sent to audio driver */ /* rate and channels are sent to audio driver */
if (prtd->state) { if (prtd->state) {
/* clear the previous setup if any */ /* clear the previous setup if any */
q6asm_cmd(prtd->audio_client, CMD_CLOSE); q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
q6asm_unmap_memory_regions(substream->stream, q6asm_unmap_memory_regions(substream->stream,
prtd->audio_client); prtd->audio_client);
q6routing_stream_close(soc_prtd->dai_link->id, q6routing_stream_close(soc_prtd->dai_link->id,
...@@ -252,10 +253,12 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, ...@@ -252,10 +253,12 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
} }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM, ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
FORMAT_LINEAR_PCM,
0, prtd->bits_per_sample); 0, prtd->bits_per_sample);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM, ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
FORMAT_LINEAR_PCM,
prtd->bits_per_sample); prtd->bits_per_sample);
} }
...@@ -276,17 +279,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, ...@@ -276,17 +279,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = q6asm_media_format_block_multi_ch_pcm( ret = q6asm_media_format_block_multi_ch_pcm(
prtd->audio_client, runtime->rate, prtd->audio_client, prtd->stream_id,
runtime->channels, NULL, runtime->rate, runtime->channels, NULL,
prtd->bits_per_sample); prtd->bits_per_sample);
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client, ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
runtime->rate, runtime->channels, prtd->stream_id,
runtime->rate,
runtime->channels,
prtd->bits_per_sample); prtd->bits_per_sample);
/* Queue the buffers */ /* Queue the buffers */
for (i = 0; i < runtime->periods; i++) for (i = 0; i < runtime->periods; i++)
q6asm_read(prtd->audio_client); q6asm_read(prtd->audio_client, prtd->stream_id);
} }
if (ret < 0) if (ret < 0)
...@@ -308,15 +313,18 @@ static int q6asm_dai_trigger(struct snd_soc_component *component, ...@@ -308,15 +313,18 @@ static int q6asm_dai_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0); ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
0, 0, 0);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
prtd->state = Q6ASM_STREAM_STOPPED; prtd->state = Q6ASM_STREAM_STOPPED;
ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
CMD_EOS);
break; break;
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
CMD_PAUSE);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
...@@ -361,6 +369,9 @@ static int q6asm_dai_open(struct snd_soc_component *component, ...@@ -361,6 +369,9 @@ static int q6asm_dai_open(struct snd_soc_component *component,
return ret; return ret;
} }
/* DSP expects stream id from 1 */
prtd->stream_id = 1;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
runtime->hw = q6asm_dai_hardware_playback; runtime->hw = q6asm_dai_hardware_playback;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
...@@ -427,7 +438,8 @@ static int q6asm_dai_close(struct snd_soc_component *component, ...@@ -427,7 +438,8 @@ static int q6asm_dai_close(struct snd_soc_component *component,
if (prtd->audio_client) { if (prtd->audio_client) {
if (prtd->state) if (prtd->state)
q6asm_cmd(prtd->audio_client, CMD_CLOSE); q6asm_cmd(prtd->audio_client, prtd->stream_id,
CMD_CLOSE);
q6asm_unmap_memory_regions(substream->stream, q6asm_unmap_memory_regions(substream->stream,
prtd->audio_client); prtd->audio_client);
...@@ -499,8 +511,8 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, ...@@ -499,8 +511,8 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
case ASM_CLIENT_EVENT_CMD_RUN_DONE: case ASM_CLIENT_EVENT_CMD_RUN_DONE:
spin_lock_irqsave(&prtd->lock, flags); spin_lock_irqsave(&prtd->lock, flags);
if (!prtd->bytes_sent) { if (!prtd->bytes_sent) {
q6asm_write_async(prtd->audio_client, prtd->pcm_count, q6asm_write_async(prtd->audio_client, prtd->stream_id,
0, 0, NO_TIMESTAMP); prtd->pcm_count, 0, 0, NO_TIMESTAMP);
prtd->bytes_sent += prtd->pcm_count; prtd->bytes_sent += prtd->pcm_count;
} }
...@@ -525,7 +537,7 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, ...@@ -525,7 +537,7 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
avail = prtd->bytes_received - prtd->bytes_sent; avail = prtd->bytes_received - prtd->bytes_sent;
if (avail >= prtd->pcm_count) { if (avail >= prtd->pcm_count) {
q6asm_write_async(prtd->audio_client, q6asm_write_async(prtd->audio_client, prtd->stream_id,
prtd->pcm_count, 0, 0, NO_TIMESTAMP); prtd->pcm_count, 0, 0, NO_TIMESTAMP);
prtd->bytes_sent += prtd->pcm_count; prtd->bytes_sent += prtd->pcm_count;
} }
...@@ -560,6 +572,9 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component, ...@@ -560,6 +572,9 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component,
if (!prtd) if (!prtd)
return -ENOMEM; return -ENOMEM;
/* DSP expects stream id from 1 */
prtd->stream_id = 1;
prtd->cstream = stream; prtd->cstream = stream;
prtd->audio_client = q6asm_audio_client_alloc(dev, prtd->audio_client = q6asm_audio_client_alloc(dev,
(q6asm_cb)compress_event_handler, (q6asm_cb)compress_event_handler,
...@@ -607,7 +622,8 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component, ...@@ -607,7 +622,8 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component,
if (prtd->audio_client) { if (prtd->audio_client) {
if (prtd->state) if (prtd->state)
q6asm_cmd(prtd->audio_client, CMD_CLOSE); q6asm_cmd(prtd->audio_client, prtd->stream_id,
CMD_CLOSE);
snd_dma_free_pages(&prtd->dma_buffer); snd_dma_free_pages(&prtd->dma_buffer);
q6asm_unmap_memory_regions(stream->direction, q6asm_unmap_memory_regions(stream->direction,
...@@ -662,8 +678,9 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, ...@@ -662,8 +678,9 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
prtd->pcm_size = runtime->fragments * runtime->fragment_size; prtd->pcm_size = runtime->fragments * runtime->fragment_size;
prtd->bits_per_sample = 16; prtd->bits_per_sample = 16;
if (dir == SND_COMPRESS_PLAYBACK) { if (dir == SND_COMPRESS_PLAYBACK) {
ret = q6asm_open_write(prtd->audio_client, params->codec.id, ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
params->codec.profile, prtd->bits_per_sample); params->codec.id, params->codec.profile,
prtd->bits_per_sample);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "q6asm_open_write failed\n"); dev_err(dev, "q6asm_open_write failed\n");
...@@ -697,6 +714,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, ...@@ -697,6 +714,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
flac_cfg.min_frame_size = flac->min_frame_size; flac_cfg.min_frame_size = flac->min_frame_size;
ret = q6asm_stream_media_format_block_flac(prtd->audio_client, ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
prtd->stream_id,
&flac_cfg); &flac_cfg);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "FLAC CMD Format block failed:%d\n", ret); dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
...@@ -756,10 +774,12 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, ...@@ -756,10 +774,12 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
if (wma_v9) if (wma_v9)
ret = q6asm_stream_media_format_block_wma_v9( ret = q6asm_stream_media_format_block_wma_v9(
prtd->audio_client, &wma_cfg); prtd->audio_client, prtd->stream_id,
&wma_cfg);
else else
ret = q6asm_stream_media_format_block_wma_v10( ret = q6asm_stream_media_format_block_wma_v10(
prtd->audio_client, &wma_cfg); prtd->audio_client, prtd->stream_id,
&wma_cfg);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "WMA9 CMD failed:%d\n", ret); dev_err(dev, "WMA9 CMD failed:%d\n", ret);
return -EIO; return -EIO;
...@@ -792,6 +812,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, ...@@ -792,6 +812,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
break; break;
} }
ret = q6asm_stream_media_format_block_alac(prtd->audio_client, ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
prtd->stream_id,
&alac_cfg); &alac_cfg);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "ALAC CMD Format block failed:%d\n", ret); dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
...@@ -816,6 +837,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, ...@@ -816,6 +837,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
ape_cfg.seek_table_present = ape->seek_table_present; ape_cfg.seek_table_present = ape->seek_table_present;
ret = q6asm_stream_media_format_block_ape(prtd->audio_client, ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
prtd->stream_id,
&ape_cfg); &ape_cfg);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "APE CMD Format block failed:%d\n", ret); dev_err(dev, "APE CMD Format block failed:%d\n", ret);
...@@ -852,15 +874,18 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component, ...@@ -852,15 +874,18 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0); ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
0, 0, 0);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
prtd->state = Q6ASM_STREAM_STOPPED; prtd->state = Q6ASM_STREAM_STOPPED;
ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
CMD_EOS);
break; break;
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
CMD_PAUSE);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
This diff is collapsed.
...@@ -93,37 +93,47 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, ...@@ -93,37 +93,47 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev,
q6asm_cb cb, void *priv, q6asm_cb cb, void *priv,
int session_id, int perf_mode); int session_id, int perf_mode);
void q6asm_audio_client_free(struct audio_client *ac); void q6asm_audio_client_free(struct audio_client *ac);
int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
uint32_t lsw_ts, uint32_t flags); uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags);
int q6asm_open_write(struct audio_client *ac, uint32_t format, int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
u32 codec_profile, uint16_t bits_per_sample); uint32_t format, u32 codec_profile,
int q6asm_open_read(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample); uint16_t bits_per_sample);
int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
uint32_t format, uint16_t bits_per_sample);
int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
uint32_t rate, uint32_t channels, uint16_t bits_per_sample); uint32_t stream_id, uint32_t rate,
int q6asm_read(struct audio_client *ac); uint32_t channels,
uint16_t bits_per_sample);
int q6asm_read(struct audio_client *ac, uint32_t stream_id);
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
uint32_t stream_id,
uint32_t rate, uint32_t channels, uint32_t rate, uint32_t channels,
u8 channel_map[PCM_MAX_NUM_CHANNEL], u8 channel_map[PCM_MAX_NUM_CHANNEL],
uint16_t bits_per_sample); uint16_t bits_per_sample);
int q6asm_stream_media_format_block_flac(struct audio_client *ac, int q6asm_stream_media_format_block_flac(struct audio_client *ac,
uint32_t stream_id,
struct q6asm_flac_cfg *cfg); struct q6asm_flac_cfg *cfg);
int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
uint32_t stream_id,
struct q6asm_wma_cfg *cfg); struct q6asm_wma_cfg *cfg);
int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
uint32_t stream_id,
struct q6asm_wma_cfg *cfg); struct q6asm_wma_cfg *cfg);
int q6asm_stream_media_format_block_alac(struct audio_client *ac, int q6asm_stream_media_format_block_alac(struct audio_client *ac,
uint32_t stream_id,
struct q6asm_alac_cfg *cfg); struct q6asm_alac_cfg *cfg);
int q6asm_stream_media_format_block_ape(struct audio_client *ac, int q6asm_stream_media_format_block_ape(struct audio_client *ac,
uint32_t stream_id,
struct q6asm_ape_cfg *cfg); struct q6asm_ape_cfg *cfg);
int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
uint32_t lsw_ts); uint32_t msw_ts, uint32_t lsw_ts);
int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
uint32_t lsw_ts); uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts);
int q6asm_cmd(struct audio_client *ac, int cmd); int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd);
int q6asm_cmd_nowait(struct audio_client *ac, int cmd); int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd);
int q6asm_get_session_id(struct audio_client *ac); int q6asm_get_session_id(struct audio_client *ac);
int q6asm_map_memory_regions(unsigned int dir, int q6asm_map_memory_regions(unsigned int dir,
struct audio_client *ac, struct audio_client *ac,
......
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