summaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/ipc4-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/ipc4-pcm.c')
-rw-r--r--sound/soc/sof/ipc4-pcm.c39
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,