History

ASoC: SOF: ipc4/intel: Add support for chained DMA

Add logic for setting up and tearing down chained DMA connections. Since pipelines are not used, all the logic to set the pipeline states can be bypassed, with only the DMA programming sequences remaining. In addition the same format needs to be used for host- and link-DMA, without the usual fixup to use the S32_LE format on the link. Note however that for convenience and compatibility with existing definitions, the topology relies on the concept of pipelines with a 'USE_CHAIN_DMA' token indicating that all the logic shall be bypassed. Unlike 'normal' ALSA sequences, the chain DMA is not programmed in hw_params/hw_free. The IPC message to set-up and tear-down chained DMA are sent in sof_ipc4_trigger_pipelines(), but the contents prepared earlier. Chained DMA is only supported by the Intel HDA DAI for now, and only S16_LE and S32_LE formats are supported for now.

Jyri Sarha committed 3 years ago

Commit ca5ce0c1 parent cb3cdef5 files · +255 −8Browse files

Unified · Split

5 files
  1. include/uapi/sound/sof/tokens.h +1 −0
  2. sound/soc/sof/intel/hda-dai-ops.c +17 −1
  3. sound/soc/sof/ipc4-pcm.c +118 −4
  4. sound/soc/sof/ipc4-topology.c +117 −3
  5. sound/soc/sof/ipc4-topology.h +2 −0
include/uapi/sound/sof/tokens.h+1−0
@@ -54,6 +54,7 @@ · 53 unmodified lines
5454 #define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206
5555 #define SOF_TKN_SCHED_LP_MODE 207
5656 #define SOF_TKN_SCHED_MEM_USAGE 208
57+#define SOF_TKN_SCHED_USE_CHAIN_DMA 209
5758
5859 /* volume */
5960 #define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250
sound/soc/sof/intel/hda-dai-ops.c+17−1
@@ -277,6 +277,15 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { · 276 unmodified lines
277277 .post_trigger = hda_ipc4_post_trigger
278278 };
279279
280+static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
281+ .get_hext_stream = hda_get_hext_stream,
282+ .assign_hext_stream = hda_assign_hext_stream,
283+ .release_hext_stream = hda_release_hext_stream,
284+ .setup_hext_stream = hda_setup_hext_stream,
285+ .reset_hext_stream = hda_reset_hext_stream,
286+ .trigger = hda_trigger,
287+};
288+
280289 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
281290 struct snd_pcm_substream *substream, int cmd)
282291 {
@@ -331,8 +340,15 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg · 48 unmodified lines
331340 {
332341 struct sof_ipc4_copier *ipc4_copier = sdai->private;
333342
334− if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA)
343+ if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
344+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
345+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
346+
347+ if (pipeline->use_chain_dma)
348+ return &hda_ipc4_chain_dma_ops;
349+
335350 return &hda_ipc4_dma_ops;
351+ }
336352 break;
337353 }
338354 default:
sound/soc/sof/ipc4-pcm.c+118−4
@@ -193,6 +193,88 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, · 192 unmodified lines
193193 * prepare ioctl before the START trigger.
194194 */
195195
196+/*
197+ * Chained DMA is a special case where there is no processing on
198+ * DSP. The samples are just moved over by host side DMA to a single
199+ * buffer on DSP and directly from there to link DMA. However, the
200+ * model on SOF driver has two notional pipelines, one at host DAI,
201+ * and another at link DAI. They both shall have the use_chain_dma
202+ * attribute.
203+ */
204+
205+static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
206+ struct snd_sof_pcm_stream_pipeline_list *pipeline_list,
207+ int state, int cmd)
208+{
209+ bool allocate, enable, set_fifo_size;
210+ struct sof_ipc4_msg msg = {{ 0 }};
211+ int i;
212+
213+ switch (state) {
214+ case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */
215+ allocate = true;
216+ enable = true;
217+ /*
218+ * SOF assumes creation of a new stream from the presence of fifo_size
219+ * in the message, so we must leave it out in pause release case.
220+ */
221+ if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
222+ set_fifo_size = false;
223+ else
224+ set_fifo_size = true;
225+ break;
226+ case SOF_IPC4_PIPE_PAUSED: /* Disable chained DMA. */
227+ allocate = true;
228+ enable = false;
229+ set_fifo_size = false;
230+ break;
231+ case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */
232+ allocate = false;
233+ enable = false;
234+ set_fifo_size = false;
235+ break;
236+ default:
237+ dev_err(sdev->dev, "Unexpected state %d", state);
238+ return -EINVAL;
239+ }
240+
241+ msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA);
242+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
243+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
244+
245+ /*
246+ * To set-up the DMA chain, the host DMA ID and SCS setting
247+ * are retrieved from the host pipeline configuration. Likewise
248+ * the link DMA ID and fifo_size are retrieved from the link
249+ * pipeline configuration.
250+ */
251+ for (i = 0; i < pipeline_list->count; i++) {
252+ struct snd_sof_pipeline *spipe = pipeline_list->pipelines[i];
253+ struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
254+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
255+
256+ if (!pipeline->use_chain_dma) {
257+ dev_err(sdev->dev,
258+ "All pipelines in chained DMA stream should have use_chain_dma attribute set.");
259+ return -EINVAL;
260+ }
261+
262+ msg.primary |= pipeline->msg.primary;
263+
264+ /* Add fifo_size (actually DMA buffer size) field to the message */
265+ if (set_fifo_size)
266+ msg.extension |= pipeline->msg.extension;
267+ }
268+
269+ if (allocate)
270+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK;
271+
272+ if (enable)
273+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK;
274+
275+ return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
276+}
277+
196278 static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
197279 struct snd_pcm_substream *substream, int state, int cmd)
198280 {
@@ -201,6 +283,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, · 2 unmodified lines
201283 struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
202284 struct sof_ipc4_fw_data *ipc4_data = sdev->private;
203285 struct ipc4_pipeline_set_state_data *trigger_list;
286+ struct snd_sof_widget *pipe_widget;
287+ struct sof_ipc4_pipeline *pipeline;
204288 struct snd_sof_pipeline *spipe;
205289 struct snd_sof_pcm *spcm;
206290 int ret;
@@ -218,6 +302,17 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, · 11 unmodified lines
218302 if (!pipeline_list->pipelines || !pipeline_list->count)
219303 return 0;
220304
305+ spipe = pipeline_list->pipelines[0];
306+ pipe_widget = spipe->pipe_widget;
307+ pipeline = pipe_widget->private;
308+
309+ /*
310+ * If use_chain_dma attribute is set we proceed to chained DMA
311+ * trigger function that handles the rest for the substream.
312+ */
313+ if (pipeline->use_chain_dma)
314+ return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
315+
221316 /* allocate memory for the pipeline data */
222317 trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
223318 GFP_KERNEL);
@@ -422,8 +517,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, · 198 unmodified lines
422517 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
423518 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
424519 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
520+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
425521 struct sof_ipc4_copier *ipc4_copier;
426− int ret;
522+ bool use_chain_dma = false;
523+ int dir;
427524
428525 if (!dai) {
429526 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
@@ -438,9 +535,26 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, · 8 unmodified lines
438535 return -EINVAL;
439536 }
440537
441− ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier);
442− if (ret)
443− return ret;
538+ for_each_pcm_streams(dir) {
539+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, dir);
540+
541+ if (w) {
542+ struct snd_sof_widget *swidget = w->dobj.private;
543+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
544+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
545+
546+ if (pipeline->use_chain_dma)
547+ use_chain_dma = true;
548+ }
549+ }
550+
551+ /* Chain DMA does not use copiers, so no fixup needed */
552+ if (!use_chain_dma) {
553+ int ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier);
554+
555+ if (ret)
556+ return ret;
557+ }
444558
445559 switch (ipc4_copier->dai_type) {
446560 case SOF_DAI_INTEL_SSP:
sound/soc/sof/ipc4-topology.c+117−3
@@ -19,6 +19,7 @@ · 18 unmodified lines
1919
2020 #define SOF_IPC4_GAIN_PARAM_ID 0
2121 #define SOF_IPC4_TPLG_ABI_SIZE 6
22+#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
2223
2324 static DEFINE_IDA(alh_group_ida);
2425 static DEFINE_IDA(pipeline_ida);
@@ -26,6 +27,8 @@ static DEFINE_IDA(pipeline_ida); · 1 unmodified line
2627 static const struct sof_topology_token ipc4_sched_tokens[] = {
2728 {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
2829 offsetof(struct sof_ipc4_pipeline, lp_mode)},
30+ {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
31+ offsetof(struct sof_ipc4_pipeline, use_chain_dma)},
2932 {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
3033 offsetof(struct sof_ipc4_pipeline, core_id)},
3134 };
@@ -475,6 +478,8 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) · 443 unmodified lines
475478 struct snd_soc_component *scomp = swidget->scomp;
476479 struct snd_sof_dai *dai = swidget->private;
477480 struct sof_ipc4_copier *ipc4_copier;
481+ struct snd_sof_widget *pipe_widget;
482+ struct sof_ipc4_pipeline *pipeline;
478483 int node_type = 0;
479484 int ret;
480485
@@ -512,6 +517,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) · 31 unmodified lines
512517
513518 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
514519
520+ pipe_widget = swidget->spipe->pipe_widget;
521+ pipeline = pipe_widget->private;
522+ if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) {
523+ dev_err(scomp->dev,
524+ "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n",
525+ ipc4_copier->dai_type, SOF_DAI_INTEL_HDA);
526+ ret = -ENODEV;
527+ goto free_available_fmt;
528+ }
529+
515530 switch (ipc4_copier->dai_type) {
516531 case SOF_DAI_INTEL_ALH:
517532 {
@@ -643,6 +658,12 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) · 125 unmodified lines
643658
644659 swidget->core = pipeline->core_id;
645660
661+ if (pipeline->use_chain_dma) {
662+ dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
663+ swidget->private = pipeline;
664+ return 0;
665+ }
666+
646667 /* parse one set of pipeline tokens */
647668 ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
648669 swidget->num_tuples, sizeof(*swidget), 1);
@@ -1103,11 +1124,21 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) · 454 unmodified lines
11031124 pipeline->mem_usage = 0;
11041125
11051126 if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
1127+ if (pipeline->use_chain_dma) {
1128+ pipeline->msg.primary = 0;
1129+ pipeline->msg.extension = 0;
1130+ }
11061131 ipc4_copier = swidget->private;
11071132 } else if (WIDGET_IS_DAI(swidget->id)) {
11081133 struct snd_sof_dai *dai = swidget->private;
11091134
11101135 ipc4_copier = dai->private;
1136+
1137+ if (pipeline->use_chain_dma) {
1138+ pipeline->msg.primary = 0;
1139+ pipeline->msg.extension = 0;
1140+ }
1141+
11111142 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
11121143 struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
11131144 struct sof_ipc4_alh_configuration_blob *blob;
@@ -1344,13 +1375,44 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, · 230 unmodified lines
13441375 return ret;
13451376 }
13461377
1347− pipe_widget = swidget->spipe->pipe_widget;
1348− pipeline = pipe_widget->private;
13491378 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
13501379 gtw_attr = ipc4_copier->gtw_attr;
13511380 copier_data = &ipc4_copier->data;
13521381 available_fmt = &ipc4_copier->available_fmt;
13531382
1383+ pipe_widget = swidget->spipe->pipe_widget;
1384+ pipeline = pipe_widget->private;
1385+
1386+ if (pipeline->use_chain_dma) {
1387+ u32 host_dma_id;
1388+ u32 fifo_size;
1389+
1390+ host_dma_id = platform_params->stream_tag - 1;
1391+ pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
1392+
1393+ /* Set SCS bit for S16_LE format only */
1394+ if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE)
1395+ pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
1396+
1397+ /*
1398+ * Despite its name the bitfield 'fifo_size' is used to define DMA buffer
1399+ * size. The expression calculates 2ms buffer size.
1400+ */
1401+ fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS *
1402+ params_rate(fe_params) *
1403+ params_channels(fe_params) *
1404+ params_physical_width(fe_params)), 8000);
1405+ pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
1406+
1407+ /*
1408+ * Chain DMA does not support stream timestamping, set node_id to invalid
1409+ * to skip the code in sof_ipc4_get_stream_start_offset().
1410+ */
1411+ copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
1412+
1413+ return 0;
1414+ }
1415+
13541416 /*
13551417 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
13561418 * for capture.
@@ -1375,6 +1437,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, · 18 unmodified lines
13751437 case snd_soc_dapm_dai_in:
13761438 case snd_soc_dapm_dai_out:
13771439 {
1440+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1441+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1442+
1443+ if (pipeline->use_chain_dma)
1444+ return 0;
1445+
13781446 dai = swidget->private;
13791447
13801448 ipc4_copier = (struct sof_ipc4_copier *)dai->private;
@@ -1921,6 +1989,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 540 unmodified lines
19211989 case snd_soc_dapm_scheduler:
19221990 pipeline = swidget->private;
19231991
1992+ if (pipeline->use_chain_dma)
1993+ return 0;
1994+
19241995 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
19251996 pipeline->mem_usage);
19261997
@@ -1943,6 +2014,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 16 unmodified lines
19432014 {
19442015 struct sof_ipc4_copier *ipc4_copier = swidget->private;
19452016
2017+ pipeline = pipe_widget->private;
2018+ if (pipeline->use_chain_dma)
2019+ return 0;
2020+
19462021 ipc_size = ipc4_copier->ipc_config_size;
19472022 ipc_data = ipc4_copier->ipc_config_data;
19482023
@@ -1955,6 +2030,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 6 unmodified lines
19552030 struct snd_sof_dai *dai = swidget->private;
19562031 struct sof_ipc4_copier *ipc4_copier = dai->private;
19572032
2033+ pipeline = pipe_widget->private;
2034+ if (pipeline->use_chain_dma)
2035+ return 0;
2036+
19582037 ipc_size = ipc4_copier->ipc_config_size;
19592038 ipc_data = ipc4_copier->ipc_config_data;
19602039
@@ -2066,6 +2145,9 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget · 105 unmodified lines
20662145 struct sof_ipc4_msg msg = {{ 0 }};
20672146 u32 header;
20682147
2148+ if (pipeline->use_chain_dma)
2149+ return 0;
2150+
20692151 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
20702152 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
20712153 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
@@ -2082,7 +2164,11 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget · 10 unmodified lines
20822164 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
20832165 ida_free(&pipeline_ida, swidget->instance_id);
20842166 } else {
2085− ida_free(&fw_module->m_ida, swidget->instance_id);
2167+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2168+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
2169+
2170+ if (!pipeline->use_chain_dma)
2171+ ida_free(&fw_module->m_ida, swidget->instance_id);
20862172 }
20872173
20882174 mutex_unlock(&ipc4_data->pipeline_state_mutex);
@@ -2234,12 +2320,27 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * · 145 unmodified lines
22342320 {
22352321 struct snd_sof_widget *src_widget = sroute->src_widget;
22362322 struct snd_sof_widget *sink_widget = sroute->sink_widget;
2323+ struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
2324+ struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
22372325 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
22382326 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
2327+ struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
2328+ struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
22392329 struct sof_ipc4_msg msg = {{ 0 }};
22402330 u32 header, extension;
22412331 int ret;
22422332
2333+ /* no route set up if chain DMA is used */
2334+ if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) {
2335+ if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) {
2336+ dev_err(sdev->dev,
2337+ "use_chain_dma must be set for both src %s and sink %s pipelines\n",
2338+ src_widget->widget->name, sink_widget->widget->name);
2339+ return -EINVAL;
2340+ }
2341+ return 0;
2342+ }
2343+
22432344 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
22442345 SOF_PIN_TYPE_OUTPUT);
22452346 if (sroute->src_queue_id < 0) {
@@ -2310,9 +2411,17 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s · 64 unmodified lines
23102411 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
23112412 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
23122413 struct sof_ipc4_msg msg = {{ 0 }};
2414+ struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
2415+ struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
2416+ struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
2417+ struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
23132418 u32 header, extension;
23142419 int ret = 0;
23152420
2421+ /* no route is set up if chain DMA is used */
2422+ if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma)
2423+ return 0;
2424+
23162425 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
23172426 src_widget->widget->name, sroute->src_queue_id,
23182427 sink_widget->widget->name, sroute->dst_queue_id);
@@ -2374,6 +2483,11 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * · 55 unmodified lines
23742483
23752484 switch (ipc4_copier->dai_type) {
23762485 case SOF_DAI_INTEL_HDA:
2486+ if (pipeline->use_chain_dma) {
2487+ pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
2488+ pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
2489+ break;
2490+ }
23772491 gtw_attr = ipc4_copier->gtw_attr;
23782492 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
23792493 pipeline->skip_during_fe_trigger = true;
sound/soc/sof/ipc4-topology.h+2−0
@@ -126,6 +126,7 @@ struct sof_ipc4_copier_config_set_sink_format { · 125 unmodified lines
126126 * @mem_usage: Memory usage
127127 * @core_id: Target core for the pipeline
128128 * @state: Pipeline state
129+ * @use_chain_dma: flag to indicate if the firmware shall use chained DMA
129130 * @msg: message structure for pipeline
130131 * @skip_during_fe_trigger: skip triggering this pipeline during the FE DAI trigger
131132 */
@@ -135,6 +136,7 @@ struct sof_ipc4_pipeline { · 3 unmodified lines
135136 uint32_t mem_usage;
136137 uint32_t core_id;
137138 int state;
139+ bool use_chain_dma;
138140 struct sof_ipc4_msg msg;
139141 bool skip_during_fe_trigger;
140142 };