Skip to content

Commit ca5ce0c

Browse files
jsarhabroonie
authored andcommitted
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. Signed-off-by: Jyri Sarha <[email protected]> Reviewed-by: Rander Wang <[email protected]> Signed-off-by: Peter Ujfalusi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent cb3cdef commit ca5ce0c

File tree

5 files changed

+255
-8
lines changed

5 files changed

+255
-8
lines changed

include/uapi/sound/sof/tokens.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,15 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
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
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

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,88 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
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,
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,
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,
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,
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:

0 commit comments

Comments
 (0)