Skip to content

Commit a1d203d

Browse files
ujfalusibroonie
authored andcommitted
ASoC: SOF: ipc4-pcm: Enable delay reporting for ChainDMA streams
All streams (currently) which is configured to use ChainDMA can only work on Link/host DMA pairs where the link side position can be access via host registers (like HDA on CAVS 2.5 platforms). Since the firmware does not provide time_info for ChainDMA, unlike for HDA stream, the kernel should calculate the start and end offsets that is needed for the delay calculation. With this small change we can report accurate delays when the stream is configured to use ChainDMA. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Link: https://patch.msgid.link/20250619102848.12389-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent ce4b269 commit a1d203d

3 files changed

Lines changed: 49 additions & 7 deletions

File tree

sound/soc/sof/ipc4-pcm.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,33 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
409409
* If use_chain_dma attribute is set we proceed to chained DMA
410410
* trigger function that handles the rest for the substream.
411411
*/
412-
if (pipeline->use_chain_dma)
413-
return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
414-
pipeline_list, state, cmd);
412+
if (pipeline->use_chain_dma) {
413+
struct sof_ipc4_timestamp_info *time_info;
414+
415+
time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
416+
417+
ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
418+
pipeline_list, state, cmd);
419+
if (ret || !time_info)
420+
return ret;
421+
422+
if (state == SOF_IPC4_PIPE_PAUSED) {
423+
/*
424+
* Record the DAI position for delay reporting
425+
* To handle multiple pause/resume/xrun we need to add
426+
* the positions to simulate how the firmware behaves
427+
*/
428+
u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component,
429+
substream);
430+
431+
time_info->stream_end_offset += pos;
432+
} else if (state == SOF_IPC4_PIPE_RESET) {
433+
/* Reset the end offset as the stream is stopped */
434+
time_info->stream_end_offset = 0;
435+
}
436+
437+
return 0;
438+
}
415439

416440
/* allocate memory for the pipeline data */
417441
trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
@@ -959,8 +983,24 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
959983
if (!host_copier || !dai_copier)
960984
return -EINVAL;
961985

962-
if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID)
986+
if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) {
963987
return -EINVAL;
988+
} else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
989+
/*
990+
* While the firmware does not supports time_info reporting for
991+
* streams using ChainDMA, it is granted that ChainDMA can only
992+
* be used on Host+Link pairs where the link position is
993+
* accessible from the host side.
994+
*
995+
* Enable delay calculation in case of ChainDMA via host
996+
* accessible registers.
997+
*
998+
* The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts
999+
* when 1ms data is available
1000+
*/
1001+
time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC;
1002+
goto out;
1003+
}
9641004

9651005
node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id);
9661006
offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg);
@@ -978,6 +1018,7 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
9781018
time_info->stream_end_offset = ppl_reg.stream_end_offset;
9791019
do_div(time_info->stream_end_offset, dai_sample_size);
9801020

1021+
out:
9811022
/*
9821023
* Calculate the wrap boundary need to be used for delay calculation
9831024
* The host counter is in bytes, it will wrap earlier than the frames

sound/soc/sof/ipc4-topology.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,10 +1938,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
19381938
pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
19391939

19401940
/*
1941-
* Chain DMA does not support stream timestamping, set node_id to invalid
1942-
* to skip the code in sof_ipc4_get_stream_start_offset().
1941+
* Chain DMA does not support stream timestamping, but it
1942+
* can use the host side registers for delay calculation.
19431943
*/
1944-
copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
1944+
copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID;
19451945

19461946
return 0;
19471947
}

sound/soc/sof/ipc4-topology.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858

5959
#define SOF_IPC4_DMA_DEVICE_MAX_COUNT 16
6060

61+
#define SOF_IPC4_CHAIN_DMA_NODE_ID 0x7fffffff
6162
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff
6263

6364
/* FW requires minimum 2ms DMA buffer size */

0 commit comments

Comments
 (0)