Skip to content

Commit 47469c2

Browse files
ujfalusiranj063
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>
1 parent 3fc50b3 commit 47469c2

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
@@ -434,9 +434,33 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
434434
* If use_chain_dma attribute is set we proceed to chained DMA
435435
* trigger function that handles the rest for the substream.
436436
*/
437-
if (pipeline->use_chain_dma)
438-
return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
439-
pipeline_list, state, cmd);
437+
if (pipeline->use_chain_dma) {
438+
struct sof_ipc4_timestamp_info *time_info;
439+
440+
time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
441+
442+
ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
443+
pipeline_list, state, cmd);
444+
if (ret || !time_info)
445+
return ret;
446+
447+
if (state == SOF_IPC4_PIPE_PAUSED) {
448+
/*
449+
* Record the DAI position for delay reporting
450+
* To handle multiple pause/resume/xrun we need to add
451+
* the positions to simulate how the firmware behaves
452+
*/
453+
u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component,
454+
substream);
455+
456+
time_info->stream_end_offset += pos;
457+
} else if (state == SOF_IPC4_PIPE_RESET) {
458+
/* Reset the end offset as the stream is stopped */
459+
time_info->stream_end_offset = 0;
460+
}
461+
462+
return 0;
463+
}
440464

441465
/* allocate memory for the pipeline data */
442466
trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
@@ -984,8 +1008,24 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
9841008
if (!host_copier || !dai_copier)
9851009
return -EINVAL;
9861010

987-
if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID)
1011+
if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) {
9881012
return -EINVAL;
1013+
} else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
1014+
/*
1015+
* While the firmware does not supports time_info reporting for
1016+
* streams using ChainDMA, it is granted that ChainDMA can only
1017+
* be used on Host+Link pairs where the link position is
1018+
* accessible from the host side.
1019+
*
1020+
* Enable delay calculation in case of ChainDMA via host
1021+
* accessible registers.
1022+
*
1023+
* The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts
1024+
* when 1ms data is available
1025+
*/
1026+
time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC;
1027+
goto out;
1028+
}
9891029

9901030
node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id);
9911031
offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg);
@@ -1003,6 +1043,7 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
10031043
time_info->stream_end_offset = ppl_reg.stream_end_offset;
10041044
do_div(time_info->stream_end_offset, dai_sample_size);
10051045

1046+
out:
10061047
/*
10071048
* Calculate the wrap boundary need to be used for delay calculation
10081049
* 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
@@ -1999,10 +1999,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
19991999
pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
20002000

20012001
/*
2002-
* Chain DMA does not support stream timestamping, set node_id to invalid
2003-
* to skip the code in sof_ipc4_get_stream_start_offset().
2002+
* Chain DMA does not support stream timestamping, but it
2003+
* can use the host side registers for delay calculation.
20042004
*/
2005-
copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
2005+
copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID;
20062006

20072007
return 0;
20082008
}

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)