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
54#define SOF_TKN_SCHED_DYNAMIC_PIPELINE 20654#define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206
55#define SOF_TKN_SCHED_LP_MODE 20755#define SOF_TKN_SCHED_LP_MODE 207
56#define SOF_TKN_SCHED_MEM_USAGE 20856#define SOF_TKN_SCHED_MEM_USAGE 208
57#define SOF_TKN_SCHED_USE_CHAIN_DMA 209
57 58
58/* volume */59/* volume */
59#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 25060#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
277 .post_trigger = hda_ipc4_post_trigger277 .post_trigger = hda_ipc4_post_trigger
278};278};
279 279
280static 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
280static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,289static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
281 struct snd_pcm_substream *substream, int cmd)290 struct snd_pcm_substream *substream, int cmd)
282{291{
@@ -331,8 +340,15 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg · 48 unmodified lines
331 {340 {
332 struct sof_ipc4_copier *ipc4_copier = sdai->private;341 struct sof_ipc4_copier *ipc4_copier = sdai->private;
333 342
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
335 return &hda_ipc4_dma_ops;350 return &hda_ipc4_dma_ops;
351 }
336 break;352 break;
337 }353 }
338 default:354 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
193 * prepare ioctl before the START trigger.193 * prepare ioctl before the START trigger.
194 */194 */
195 195
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
205static 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
196static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,278static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
197 struct snd_pcm_substream *substream, int state, int cmd)279 struct snd_pcm_substream *substream, int state, int cmd)
198{280{
@@ -201,6 +283,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, · 2 unmodified lines
201 struct snd_sof_pcm_stream_pipeline_list *pipeline_list;283 struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
202 struct sof_ipc4_fw_data *ipc4_data = sdev->private;284 struct sof_ipc4_fw_data *ipc4_data = sdev->private;
203 struct ipc4_pipeline_set_state_data *trigger_list;285 struct ipc4_pipeline_set_state_data *trigger_list;
286 struct snd_sof_widget *pipe_widget;
287 struct sof_ipc4_pipeline *pipeline;
204 struct snd_sof_pipeline *spipe;288 struct snd_sof_pipeline *spipe;
205 struct snd_sof_pcm *spcm;289 struct snd_sof_pcm *spcm;
206 int ret;290 int ret;
@@ -218,6 +302,17 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, · 11 unmodified lines
218 if (!pipeline_list->pipelines || !pipeline_list->count)302 if (!pipeline_list->pipelines || !pipeline_list->count)
219 return 0;303 return 0;
220 304
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
221 /* allocate memory for the pipeline data */316 /* allocate memory for the pipeline data */
222 trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),317 trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
223 GFP_KERNEL);318 GFP_KERNEL);
@@ -422,8 +517,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, · 198 unmodified lines
422 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);517 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
423 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);518 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
424 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);519 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
520 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
425 struct sof_ipc4_copier *ipc4_copier;521 struct sof_ipc4_copier *ipc4_copier;
426 int ret;522 bool use_chain_dma = false;
523 int dir;
427 524
428 if (!dai) {525 if (!dai) {
429 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,526 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
438 return -EINVAL;535 return -EINVAL;
439 }536 }
440 537
441 ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier);538 for_each_pcm_streams(dir) {
442 if (ret)539 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, dir);
443 return ret;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 }
444 558
445 switch (ipc4_copier->dai_type) {559 switch (ipc4_copier->dai_type) {
446 case SOF_DAI_INTEL_SSP:560 case SOF_DAI_INTEL_SSP:
sound/soc/sof/ipc4-topology.c+117−3
@@ -19,6 +19,7 @@ · 18 unmodified lines
19 19
20#define SOF_IPC4_GAIN_PARAM_ID 020#define SOF_IPC4_GAIN_PARAM_ID 0
21#define SOF_IPC4_TPLG_ABI_SIZE 621#define SOF_IPC4_TPLG_ABI_SIZE 6
22#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
22 23
23static DEFINE_IDA(alh_group_ida);24static DEFINE_IDA(alh_group_ida);
24static DEFINE_IDA(pipeline_ida);25static DEFINE_IDA(pipeline_ida);
@@ -26,6 +27,8 @@ static DEFINE_IDA(pipeline_ida); · 1 unmodified line
26static const struct sof_topology_token ipc4_sched_tokens[] = {27static const struct sof_topology_token ipc4_sched_tokens[] = {
27 {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,28 {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28 offsetof(struct sof_ipc4_pipeline, lp_mode)},29 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)},
29 {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,32 {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
30 offsetof(struct sof_ipc4_pipeline, core_id)},33 offsetof(struct sof_ipc4_pipeline, core_id)},
31};34};
@@ -475,6 +478,8 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) · 443 unmodified lines
475 struct snd_soc_component *scomp = swidget->scomp;478 struct snd_soc_component *scomp = swidget->scomp;
476 struct snd_sof_dai *dai = swidget->private;479 struct snd_sof_dai *dai = swidget->private;
477 struct sof_ipc4_copier *ipc4_copier;480 struct sof_ipc4_copier *ipc4_copier;
481 struct snd_sof_widget *pipe_widget;
482 struct sof_ipc4_pipeline *pipeline;
478 int node_type = 0;483 int node_type = 0;
479 int ret;484 int ret;
480 485
@@ -512,6 +517,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) · 31 unmodified lines
512 517
513 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);518 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
514 519
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
515 switch (ipc4_copier->dai_type) {530 switch (ipc4_copier->dai_type) {
516 case SOF_DAI_INTEL_ALH:531 case SOF_DAI_INTEL_ALH:
517 {532 {
@@ -643,6 +658,12 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) · 125 unmodified lines
643 658
644 swidget->core = pipeline->core_id;659 swidget->core = pipeline->core_id;
645 660
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
646 /* parse one set of pipeline tokens */667 /* parse one set of pipeline tokens */
647 ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,668 ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
648 swidget->num_tuples, sizeof(*swidget), 1);669 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
1103 pipeline->mem_usage = 0;1124 pipeline->mem_usage = 0;
1104 1125
1105 if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {1126 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 }
1106 ipc4_copier = swidget->private;1131 ipc4_copier = swidget->private;
1107 } else if (WIDGET_IS_DAI(swidget->id)) {1132 } else if (WIDGET_IS_DAI(swidget->id)) {
1108 struct snd_sof_dai *dai = swidget->private;1133 struct snd_sof_dai *dai = swidget->private;
1109 1134
1110 ipc4_copier = dai->private;1135 ipc4_copier = dai->private;
1136
1137 if (pipeline->use_chain_dma) {
1138 pipeline->msg.primary = 0;
1139 pipeline->msg.extension = 0;
1140 }
1141
1111 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {1142 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1112 struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;1143 struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
1113 struct sof_ipc4_alh_configuration_blob *blob;1144 struct sof_ipc4_alh_configuration_blob *blob;
@@ -1344,13 +1375,44 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, · 230 unmodified lines
1344 return ret;1375 return ret;
1345 }1376 }
1346 1377
1347 pipe_widget = swidget->spipe->pipe_widget;
1348 pipeline = pipe_widget->private;
1349 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;1378 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1350 gtw_attr = ipc4_copier->gtw_attr;1379 gtw_attr = ipc4_copier->gtw_attr;
1351 copier_data = &ipc4_copier->data;1380 copier_data = &ipc4_copier->data;
1352 available_fmt = &ipc4_copier->available_fmt;1381 available_fmt = &ipc4_copier->available_fmt;
1353 1382
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
1354 /*1416 /*
1355 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts1417 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
1356 * for capture.1418 * for capture.
@@ -1375,6 +1437,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, · 18 unmodified lines
1375 case snd_soc_dapm_dai_in:1437 case snd_soc_dapm_dai_in:
1376 case snd_soc_dapm_dai_out:1438 case snd_soc_dapm_dai_out:
1377 {1439 {
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
1378 dai = swidget->private;1446 dai = swidget->private;
1379 1447
1380 ipc4_copier = (struct sof_ipc4_copier *)dai->private;1448 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
1921 case snd_soc_dapm_scheduler:1989 case snd_soc_dapm_scheduler:
1922 pipeline = swidget->private;1990 pipeline = swidget->private;
1923 1991
1992 if (pipeline->use_chain_dma)
1993 return 0;
1994
1924 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,1995 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
1925 pipeline->mem_usage);1996 pipeline->mem_usage);
1926 1997
@@ -1943,6 +2014,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 16 unmodified lines
1943 {2014 {
1944 struct sof_ipc4_copier *ipc4_copier = swidget->private;2015 struct sof_ipc4_copier *ipc4_copier = swidget->private;
1945 2016
2017 pipeline = pipe_widget->private;
2018 if (pipeline->use_chain_dma)
2019 return 0;
2020
1946 ipc_size = ipc4_copier->ipc_config_size;2021 ipc_size = ipc4_copier->ipc_config_size;
1947 ipc_data = ipc4_copier->ipc_config_data;2022 ipc_data = ipc4_copier->ipc_config_data;
1948 2023
@@ -1955,6 +2030,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 6 unmodified lines
1955 struct snd_sof_dai *dai = swidget->private;2030 struct snd_sof_dai *dai = swidget->private;
1956 struct sof_ipc4_copier *ipc4_copier = dai->private;2031 struct sof_ipc4_copier *ipc4_copier = dai->private;
1957 2032
2033 pipeline = pipe_widget->private;
2034 if (pipeline->use_chain_dma)
2035 return 0;
2036
1958 ipc_size = ipc4_copier->ipc_config_size;2037 ipc_size = ipc4_copier->ipc_config_size;
1959 ipc_data = ipc4_copier->ipc_config_data;2038 ipc_data = ipc4_copier->ipc_config_data;
1960 2039
@@ -2066,6 +2145,9 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget · 105 unmodified lines
2066 struct sof_ipc4_msg msg = {{ 0 }};2145 struct sof_ipc4_msg msg = {{ 0 }};
2067 u32 header;2146 u32 header;
2068 2147
2148 if (pipeline->use_chain_dma)
2149 return 0;
2150
2069 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);2151 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
2070 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);2152 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
2071 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);2153 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
2082 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;2164 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
2083 ida_free(&pipeline_ida, swidget->instance_id);2165 ida_free(&pipeline_ida, swidget->instance_id);
2084 } else {2166 } 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);
2086 }2172 }
2087 2173
2088 mutex_unlock(&ipc4_data->pipeline_state_mutex);2174 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
2234{2320{
2235 struct snd_sof_widget *src_widget = sroute->src_widget;2321 struct snd_sof_widget *src_widget = sroute->src_widget;
2236 struct snd_sof_widget *sink_widget = sroute->sink_widget;2322 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;
2237 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;2325 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
2238 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;2326 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;
2239 struct sof_ipc4_msg msg = {{ 0 }};2329 struct sof_ipc4_msg msg = {{ 0 }};
2240 u32 header, extension;2330 u32 header, extension;
2241 int ret;2331 int ret;
2242 2332
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
2243 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,2344 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
2244 SOF_PIN_TYPE_OUTPUT);2345 SOF_PIN_TYPE_OUTPUT);
2245 if (sroute->src_queue_id < 0) {2346 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
2310 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;2411 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
2311 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;2412 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
2312 struct sof_ipc4_msg msg = {{ 0 }};2413 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;
2313 u32 header, extension;2418 u32 header, extension;
2314 int ret = 0;2419 int ret = 0;
2315 2420
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
2316 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",2425 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
2317 src_widget->widget->name, sroute->src_queue_id,2426 src_widget->widget->name, sroute->src_queue_id,
2318 sink_widget->widget->name, sroute->dst_queue_id);2427 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
2374 2483
2375 switch (ipc4_copier->dai_type) {2484 switch (ipc4_copier->dai_type) {
2376 case SOF_DAI_INTEL_HDA:2485 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 }
2377 gtw_attr = ipc4_copier->gtw_attr;2491 gtw_attr = ipc4_copier->gtw_attr;
2378 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;2492 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
2379 pipeline->skip_during_fe_trigger = true;2493 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
126 * @mem_usage: Memory usage126 * @mem_usage: Memory usage
127 * @core_id: Target core for the pipeline127 * @core_id: Target core for the pipeline
128 * @state: Pipeline state128 * @state: Pipeline state
129 * @use_chain_dma: flag to indicate if the firmware shall use chained DMA
129 * @msg: message structure for pipeline130 * @msg: message structure for pipeline
130 * @skip_during_fe_trigger: skip triggering this pipeline during the FE DAI trigger131 * @skip_during_fe_trigger: skip triggering this pipeline during the FE DAI trigger
131 */132 */
@@ -135,6 +136,7 @@ struct sof_ipc4_pipeline { · 3 unmodified lines
135 uint32_t mem_usage;136 uint32_t mem_usage;
136 uint32_t core_id;137 uint32_t core_id;
137 int state;138 int state;
139 bool use_chain_dma;
138 struct sof_ipc4_msg msg;140 struct sof_ipc4_msg msg;
139 bool skip_during_fe_trigger;141 bool skip_during_fe_trigger;
140};142};