Skip to content

Commit b984a62

Browse files
committed
ASoC: SOF: chain-dma: Add support for chained DMA
Add logic for setting up and tearing down chained dma connections. The chained dma means that the samples are not processed by the SOF DSP in any way, they just pass through without any processing. Because of this a lot of code needs to be by passed in chained dma case. Also because of this in chain dma case we have to use the same stream parameters for both back- and front-end dma, including sample format, for both back- and front-end dai, which why we can not set the 32-bit format mask in dai_link_fixup() callback in chained dma case. The IPC message for setting chained dma up and to tear it down are sent in sof_ipc4_trigger_pipelines(), but the contents are partly collected in struct sof_ipc4_pipeline msg data member in sof_ipc4_dai_config() and in sof_ipc4_prepare_copier_module(). Signed-off-by: Jyri Sarha <jyri.sarha@intel.com>
1 parent b6b57a8 commit b984a62

5 files changed

Lines changed: 192 additions & 25 deletions

File tree

include/uapi/sound/sof/tokens.h

Lines changed: 1 addition & 1 deletion
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
@@ -97,7 +98,6 @@
9798
#define SOF_TKN_COMP_SINK_PIN_BINDING_WNAME 413
9899
#define SOF_TKN_COMP_SRC_PIN_BINDING_WNAME 414
99100

100-
101101
/* SSP */
102102
#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
103103
#define SOF_TKN_INTEL_SSP_MCLK_ID 501

sound/soc/sof/intel/hda-dai.c

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -475,36 +475,43 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
475475
case SNDRV_PCM_TRIGGER_START:
476476
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
477477
snd_hdac_ext_stream_start(hext_stream);
478-
if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
478+
if (!pipeline->use_chain_dma) {
479+
if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
480+
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
481+
SOF_IPC4_PIPE_PAUSED);
482+
if (ret < 0)
483+
return ret;
484+
pipeline->state = SOF_IPC4_PIPE_PAUSED;
485+
}
486+
479487
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
480-
SOF_IPC4_PIPE_PAUSED);
488+
SOF_IPC4_PIPE_RUNNING);
481489
if (ret < 0)
482490
return ret;
483-
pipeline->state = SOF_IPC4_PIPE_PAUSED;
484491
}
485492

486-
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
487-
SOF_IPC4_PIPE_RUNNING);
488-
if (ret < 0)
489-
return ret;
490493
pipeline->state = SOF_IPC4_PIPE_RUNNING;
491494
break;
492495
case SNDRV_PCM_TRIGGER_SUSPEND:
493496
case SNDRV_PCM_TRIGGER_STOP:
494497
{
495-
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
496-
SOF_IPC4_PIPE_PAUSED);
497-
if (ret < 0)
498-
return ret;
498+
if (!pipeline->use_chain_dma) {
499+
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
500+
SOF_IPC4_PIPE_PAUSED);
501+
if (ret < 0)
502+
return ret;
503+
}
499504

500505
pipeline->state = SOF_IPC4_PIPE_PAUSED;
501506

502507
snd_hdac_ext_stream_clear(hext_stream);
503508

504-
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
505-
SOF_IPC4_PIPE_RESET);
506-
if (ret < 0)
507-
return ret;
509+
if (!pipeline->use_chain_dma) {
510+
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
511+
SOF_IPC4_PIPE_RESET);
512+
if (ret < 0)
513+
return ret;
514+
}
508515

509516
pipeline->state = SOF_IPC4_PIPE_RESET;
510517

@@ -517,10 +524,12 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
517524
}
518525
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
519526
{
520-
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
521-
SOF_IPC4_PIPE_PAUSED);
522-
if (ret < 0)
523-
return ret;
527+
if (!pipeline->use_chain_dma) {
528+
ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
529+
SOF_IPC4_PIPE_PAUSED);
530+
if (ret < 0)
531+
return ret;
532+
}
524533

525534
pipeline->state = SOF_IPC4_PIPE_PAUSED;
526535

sound/soc/sof/ipc4-pcm.c

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,56 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
5959
}
6060
EXPORT_SYMBOL(sof_ipc4_set_pipeline_state);
6161

62+
static int sof_ipc4_chain_dma_send_msg(struct snd_sof_dev *sdev, struct sof_ipc4_msg *template,
63+
bool allocate, bool enable)
64+
{
65+
/*
66+
* The function expects to have host and link dma IDs, scs bit, and fifo
67+
* size in the message template. The message template bits are set in
68+
* sof_ipc4_prepare_copier_module() and in sof_ipc4_dai_config().
69+
*/
70+
struct sof_ipc4_msg msg = {{ 0 }};
71+
72+
msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA);
73+
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
74+
msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
75+
/* Copy host and link dma IDs from the template. */
76+
msg.primary |= (template->primary & (SOF_IPC4_GLB_CHAIN_DMA_HOST_ID_MASK |
77+
SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK));
78+
/* Copy SCS bit from the template */
79+
msg.primary |= (template->primary & SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK);
80+
81+
if (allocate) {
82+
msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK;
83+
/* Copy fifo_size from the template. It is only need with allocate msg. */
84+
msg.extension = template->extension;
85+
}
86+
87+
if (enable)
88+
msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK;
89+
90+
return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
91+
}
92+
93+
static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, struct sof_ipc4_msg *msg,
94+
int state)
95+
{
96+
switch (state) {
97+
case SOF_IPC4_PIPE_RUNNING:
98+
/* Set allocate and enable bits to configure and enable chain DMA. */
99+
return sof_ipc4_chain_dma_send_msg(sdev, msg, true, true);
100+
case SOF_IPC4_PIPE_PAUSED:
101+
/* Set allocate bit, but not enable bit. */
102+
return sof_ipc4_chain_dma_send_msg(sdev, msg, true, false);
103+
case SOF_IPC4_PIPE_RESET:
104+
/* Set allocat and ennabel bits to zero. */
105+
return sof_ipc4_chain_dma_send_msg(sdev, msg, false, false);
106+
default:
107+
dev_err(sdev->dev, "%s: unexpected state %d", __func__, state);
108+
return -EINVAL;
109+
}
110+
}
111+
62112
static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
63113
struct snd_pcm_substream *substream, int state)
64114
{
@@ -82,6 +132,14 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
82132
if (!pipeline_list->pipe_widgets)
83133
return 0;
84134

135+
/* If this is a chained dma stream, then there is no need to continue further. */
136+
for (i = pipeline_list->count - 1; i >= 0; i--) {
137+
pipe_widget = pipeline_list->pipe_widgets[i];
138+
pipeline = pipe_widget->private;
139+
if (pipeline->use_chain_dma)
140+
return sof_ipc4_chain_dma_trigger(sdev, &pipeline->msg, state);
141+
}
142+
85143
/* allocate memory for the pipeline data */
86144
data = kzalloc(struct_size(data, pipeline_ids, pipeline_list->count), GFP_KERNEL);
87145
if (!data)
@@ -234,24 +292,43 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
234292
struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
235293
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
236294
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
295+
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
237296
struct sof_ipc4_copier *ipc4_copier;
297+
struct snd_soc_dapm_widget *w;
298+
bool use_chain_dma = false;
299+
int dir;
238300

239301
if (!dai) {
240302
dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
241303
rtd->dai_link->name);
242304
return -EINVAL;
243305
}
244306

307+
for_each_pcm_streams(dir) {
308+
w = snd_soc_dai_get_widget(cpu_dai, dir);
309+
if (w) {
310+
struct snd_sof_widget *swidget = w->dobj.private;
311+
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
312+
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
313+
314+
if (pipeline->use_chain_dma)
315+
use_chain_dma = true;
316+
}
317+
}
318+
245319
ipc4_copier = dai->private;
246320
if (!ipc4_copier) {
247321
dev_err(component->dev, "%s: No private data found for DAI %s\n",
248322
__func__, rtd->dai_link->name);
249323
return -EINVAL;
250324
}
251325

252-
/* always set BE format to 32-bits for both playback and capture */
253-
snd_mask_none(fmt);
254-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
326+
/* always set BE format to 32-bits for both playback and capture, except if chain
327+
* dma is in use */
328+
if (!use_chain_dma) {
329+
snd_mask_none(fmt);
330+
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
331+
}
255332

256333
rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency;
257334
rate->max = rate->min;

sound/soc/sof/ipc4-topology.c

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ static DEFINE_IDA(pipeline_ida);
2424

2525
static const struct sof_topology_token ipc4_sched_tokens[] = {
2626
{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
27-
offsetof(struct sof_ipc4_pipeline, lp_mode)}
27+
offsetof(struct sof_ipc4_pipeline, lp_mode)},
28+
{SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
29+
offsetof(struct sof_ipc4_pipeline, use_chain_dma)},
2830
};
2931

3032
static const struct sof_topology_token pipeline_tokens[] = {
@@ -607,6 +609,14 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
607609
goto err;
608610
}
609611

612+
if (pipeline->use_chain_dma) {
613+
dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
614+
615+
swidget->private = pipeline;
616+
617+
return 0;
618+
}
619+
610620
/* parse one set of pipeline tokens */
611621
ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
612622
swidget->num_tuples, sizeof(*swidget), 1);
@@ -1116,6 +1126,30 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
11161126

11171127
pipe_widget = swidget->pipe_widget;
11181128
pipeline = pipe_widget->private;
1129+
1130+
if (pipeline->use_chain_dma) {
1131+
u32 host_dma_id;
1132+
u32 fifo_size;
1133+
1134+
host_dma_id = platform_params->stream_tag - 1;
1135+
pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_HOST_ID_MASK;
1136+
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
1137+
1138+
if (params_width(fe_params) > 16)
1139+
pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
1140+
else
1141+
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
1142+
/*
1143+
* Despite its name the bitfield 'fifo_size' is used to define dma buffer
1144+
* size. The expression calculates 2ms buffer size.
1145+
*/
1146+
fifo_size = 2 * ((params_rate(fe_params) * params_channels(fe_params) *
1147+
params_physical_width(fe_params))/ 8000);
1148+
dev_dbg(sdev->dev, "fifo_size is %d\n", fifo_size);
1149+
pipeline->msg.extension &= ~SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE_MASK;
1150+
pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
1151+
return 0;
1152+
}
11191153
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
11201154
gtw_attr = ipc4_copier->gtw_attr;
11211155
copier_data = &ipc4_copier->data;
@@ -1145,6 +1179,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
11451179
case snd_soc_dapm_dai_in:
11461180
case snd_soc_dapm_dai_out:
11471181
{
1182+
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
1183+
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1184+
1185+
if (pipeline->use_chain_dma)
1186+
return 0;
1187+
11481188
dai = swidget->private;
11491189

11501190
ipc4_copier = (struct sof_ipc4_copier *)dai->private;
@@ -1447,6 +1487,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
14471487
case snd_soc_dapm_scheduler:
14481488
pipeline = swidget->private;
14491489

1490+
if (pipeline->use_chain_dma)
1491+
return 0;
1492+
14501493
dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
14511494
pipeline->mem_usage);
14521495

@@ -1468,6 +1511,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
14681511
{
14691512
struct sof_ipc4_copier *ipc4_copier = swidget->private;
14701513

1514+
pipeline = pipe_widget->private;
1515+
if (pipeline->use_chain_dma)
1516+
return 0;
1517+
14711518
ipc_size = ipc4_copier->ipc_config_size;
14721519
ipc_data = ipc4_copier->ipc_config_data;
14731520

@@ -1480,6 +1527,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
14801527
struct snd_sof_dai *dai = swidget->private;
14811528
struct sof_ipc4_copier *ipc4_copier = dai->private;
14821529

1530+
pipeline = pipe_widget->private;
1531+
if (pipeline->use_chain_dma)
1532+
return 0;
1533+
14831534
ipc_size = ipc4_copier->ipc_config_size;
14841535
ipc_data = ipc4_copier->ipc_config_data;
14851536

@@ -1572,6 +1623,9 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
15721623
struct sof_ipc4_msg msg = {{ 0 }};
15731624
u32 header;
15741625

1626+
if (pipeline->use_chain_dma)
1627+
return 0;
1628+
15751629
header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
15761630
header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
15771631
header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
@@ -1588,7 +1642,11 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
15881642
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
15891643
ida_free(&pipeline_ida, swidget->instance_id);
15901644
} else {
1591-
ida_free(&fw_module->m_ida, swidget->instance_id);
1645+
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
1646+
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1647+
1648+
if (!pipeline->use_chain_dma)
1649+
ida_free(&fw_module->m_ida, swidget->instance_id);
15921650
}
15931651

15941652
return ret;
@@ -1680,12 +1738,20 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
16801738
{
16811739
struct snd_sof_widget *src_widget = sroute->src_widget;
16821740
struct snd_sof_widget *sink_widget = sroute->sink_widget;
1741+
struct snd_sof_widget *src_pipe_widget = src_widget->pipe_widget;
1742+
struct snd_sof_widget *sink_pipe_widget = sink_widget->pipe_widget;
16831743
struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
16841744
struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1745+
struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
1746+
struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
16851747
struct sof_ipc4_msg msg = {{ 0 }};
16861748
u32 header, extension;
16871749
int ret;
16881750

1751+
/* no route set up if chain DMA is used */
1752+
if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma)
1753+
return 0;
1754+
16891755
sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
16901756
SOF_PIN_TYPE_SOURCE);
16911757
if (sroute->src_queue_id < 0) {
@@ -1743,9 +1809,17 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
17431809
struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
17441810
struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
17451811
struct sof_ipc4_msg msg = {{ 0 }};
1812+
struct snd_sof_widget *src_pipe_widget = src_widget->pipe_widget;
1813+
struct snd_sof_widget *sink_pipe_widget = sink_widget->pipe_widget;
1814+
struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
1815+
struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
17461816
u32 header, extension;
17471817
int ret = 0;
17481818

1819+
/* no route is set up if chain DMA is used */
1820+
if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma)
1821+
return 0;
1822+
17491823
dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
17501824
src_widget->widget->name, sroute->src_queue_id,
17511825
sink_widget->widget->name, sroute->dst_queue_id);
@@ -1806,6 +1880,11 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
18061880

18071881
switch (ipc4_copier->dai_type) {
18081882
case SOF_DAI_INTEL_HDA:
1883+
if (pipeline->use_chain_dma) {
1884+
pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
1885+
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
1886+
break;
1887+
}
18091888
gtw_attr = ipc4_copier->gtw_attr;
18101889
gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
18111890
pipeline->skip_during_fe_trigger = true;

0 commit comments

Comments
 (0)