diff options
Diffstat (limited to 'sound/soc/sof/ipc4-pcm.c')
-rw-r--r-- | sound/soc/sof/ipc4-pcm.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index d07c1b0620..4594470ed0 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -40,9 +40,12 @@ struct sof_ipc4_timestamp_info { /** * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data * @time_info: pointer to time info struct if it is supported, otherwise NULL + * @chain_dma_allocated: indicates the ChainDMA allocation state */ struct sof_ipc4_pcm_stream_priv { struct sof_ipc4_timestamp_info *time_info; + + bool chain_dma_allocated; }; static inline struct sof_ipc4_timestamp_info * @@ -269,12 +272,17 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, */ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, int direction, struct snd_sof_pcm_stream_pipeline_list *pipeline_list, int state, int cmd) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_ipc4_pcm_stream_priv *stream_priv; bool allocate, enable, set_fifo_size; struct sof_ipc4_msg msg = {{ 0 }}; - int i; + int ret, i; + + stream_priv = spcm->stream[direction].private; switch (state) { case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */ @@ -295,6 +303,11 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, set_fifo_size = false; break; case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */ + + /* ChainDMA can only be reset if it has been allocated */ + if (!stream_priv->chain_dma_allocated) + return 0; + allocate = false; enable = false; set_fifo_size = false; @@ -332,13 +345,32 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, msg.extension |= pipeline->msg.extension; } + if (direction == SNDRV_PCM_STREAM_CAPTURE) { + /* + * For ChainDMA the DMA ids are unique with the following mapping: + * playback: 0 - (num_playback_streams - 1) + * capture: num_playback_streams - (num_playback_streams + + * num_capture_streams - 1) + * + * Add the num_playback_streams offset to the DMA ids stored in + * msg.primary in case capture + */ + msg.primary += SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(ipc4_data->num_playback_streams); + msg.primary += SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(ipc4_data->num_playback_streams); + } + if (allocate) msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK; if (enable) msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK; - return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); + ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); + /* Update the ChainDMA allocation state */ + if (!ret) + stream_priv->chain_dma_allocated = allocate; + + return ret; } static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, @@ -378,7 +410,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, * trigger function that handles the rest for the substream. */ if (pipeline->use_chain_dma) - return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd); + return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, + pipeline_list, state, cmd); /* allocate memory for the pipeline data */ trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids, |