@@ -193,6 +193,88 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
193
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
+
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
+
196
278
static int sof_ipc4_trigger_pipelines (struct snd_soc_component * component ,
197
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,
201
283
struct snd_sof_pcm_stream_pipeline_list * pipeline_list ;
202
284
struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
203
285
struct ipc4_pipeline_set_state_data * trigger_list ;
286
+ struct snd_sof_widget * pipe_widget ;
287
+ struct sof_ipc4_pipeline * pipeline ;
204
288
struct snd_sof_pipeline * spipe ;
205
289
struct snd_sof_pcm * spcm ;
206
290
int ret ;
@@ -218,6 +302,17 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
218
302
if (!pipeline_list -> pipelines || !pipeline_list -> count )
219
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
316
/* allocate memory for the pipeline data */
222
317
trigger_list = kzalloc (struct_size (trigger_list , pipeline_ids , pipeline_list -> count ),
223
318
GFP_KERNEL );
@@ -422,8 +517,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
422
517
struct snd_soc_component * component = snd_soc_rtdcom_lookup (rtd , SOF_AUDIO_PCM_DRV_NAME );
423
518
struct snd_sof_dai * dai = snd_sof_find_dai (component , rtd -> dai_link -> name );
424
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
521
struct sof_ipc4_copier * ipc4_copier ;
426
- int ret ;
522
+ bool use_chain_dma = false;
523
+ int dir ;
427
524
428
525
if (!dai ) {
429
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,
438
535
return - EINVAL ;
439
536
}
440
537
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
+ }
444
558
445
559
switch (ipc4_copier -> dai_type ) {
446
560
case SOF_DAI_INTEL_SSP :
0 commit comments