Skip to content

Commit 0e357b5

Browse files
bardliaoplbossart
authored andcommitted
ASoC: SOF: ipc4-topology: add SoundWire/ALH aggregation support
Some SoundWire hardware topologies rely on different amplifiers or capture devices connected on different links. These devices need to be 'aggregated', remain synchronized and be handled as a single logical device. In the IPC3 solution, the aggregation for amplifiers was handled by a firmware 'demux' component. In the IPC4 solution, the demux component is not needed, the gateway component can handle multiple ALH/DMA transfers at the same time. This change makes the topology slightly more complicated in that only one ALH DAI will be connected in the topology with the gateway. The other DAIs that are part of the 'aggregated' dailink are not shown in the DAPM graph as connected to the gateway, but they will however be activated thanks to a feature in soc-dapm.c where events are forwarded to all DAIs in the dailink (see soc_dapm_stream_event). The topology also sets the same stream name for all widgets, dais and dailinks, so a search for the stream name helps identify cases where SoundWire/ALH aggregation is needed. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
1 parent 2e09d08 commit 0e357b5

2 files changed

Lines changed: 77 additions & 5 deletions

File tree

sound/soc/sof/ipc4-topology.c

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#define SOF_IPC4_GAIN_PARAM_ID 0
2020
#define SOF_IPC4_TPLG_ABI_SIZE 6
2121

22+
static DEFINE_IDA(alh_group_ida);
23+
2224
static const struct sof_topology_token ipc4_sched_tokens[] = {
2325
{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
2426
offsetof(struct sof_ipc4_pipeline, lp_mode)}
@@ -478,14 +480,27 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
478480
switch (ipc4_copier->dai_type) {
479481
case SOF_DAI_INTEL_ALH:
480482
{
483+
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
481484
struct sof_ipc4_alh_configuration_blob *blob;
485+
struct snd_sof_widget *w;
482486

483487
blob = kzalloc(sizeof(*blob), GFP_KERNEL);
484488
if (!blob) {
485489
ret = -ENOMEM;
486490
goto err;
487491
}
488492

493+
list_for_each_entry(w, &sdev->widget_list, list) {
494+
if (w->widget->sname &&
495+
strcmp(w->widget->sname, swidget->widget->sname))
496+
continue;
497+
498+
blob->alh_cfg.count++;
499+
}
500+
/* Set blob->alh_cfg.count = 0 if the widget is not aggregated */
501+
if (blob->alh_cfg.count == 1)
502+
blob->alh_cfg.count = 0;
503+
489504
ipc4_copier->copier_config = (uint32_t *)blob;
490505
ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
491506
break;
@@ -844,6 +859,17 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
844859
struct snd_sof_dai *dai = swidget->private;
845860

846861
ipc4_copier = dai->private;
862+
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
863+
struct sof_ipc4_alh_configuration_blob *blob;
864+
unsigned int group_id;
865+
866+
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
867+
if (blob->alh_cfg.count > 1) {
868+
group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
869+
ALH_MULTI_GTW_BASE;
870+
ida_free(&alh_group_ida, group_id);
871+
}
872+
}
847873
}
848874

849875
if (ipc4_copier) {
@@ -974,6 +1000,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
9741000
struct sof_ipc4_copier_data *copier_data;
9751001
struct snd_pcm_hw_params *ref_params;
9761002
struct sof_ipc4_copier *ipc4_copier;
1003+
struct snd_sof_dai *dai;
9771004
struct snd_mask *fmt;
9781005
int out_sample_valid_bits;
9791006
size_t ref_audio_fmt_size;
@@ -1023,7 +1050,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
10231050
case snd_soc_dapm_dai_in:
10241051
case snd_soc_dapm_dai_out:
10251052
{
1026-
struct snd_sof_dai *dai = swidget->private;
1053+
dai = swidget->private;
10271054

10281055
ipc4_copier = (struct sof_ipc4_copier *)dai->private;
10291056
copier_data = &ipc4_copier->data;
@@ -1078,22 +1105,56 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
10781105
*/
10791106
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
10801107
struct sof_ipc4_alh_configuration_blob *blob;
1108+
struct sof_ipc4_copier_data *alh_data;
1109+
struct sof_ipc4_copier *alh_copier;
1110+
struct snd_sof_widget *w;
1111+
u32 ch_mask = 0;
10811112
u32 ch_map;
10821113
int i;
10831114

10841115
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1085-
/* TODO: add aggregation mode support */
1086-
blob->alh_cfg.count = 1;
1087-
blob->alh_cfg.mapping[0].alh_id = copier_data->gtw_cfg.node_id;
1116+
10881117
blob->gw_attr.lp_buffer_alloc = 0;
10891118

10901119
/* Get channel_mask from ch_map */
10911120
ch_map = copier_data->base_config.audio_fmt.ch_map;
10921121
for (i = 0; ch_map; i++) {
10931122
if ((ch_map & 0xf) != 0xf)
1094-
blob->alh_cfg.mapping[0].channel_mask |= BIT(i);
1123+
ch_mask |= BIT(i);
10951124
ch_map >>= 4;
10961125
}
1126+
1127+
/*
1128+
* Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
1129+
* for all widgets with the same stream name
1130+
*/
1131+
i = 0;
1132+
list_for_each_entry(w, &sdev->widget_list, list) {
1133+
if (w->widget->sname &&
1134+
strcmp(w->widget->sname, swidget->widget->sname))
1135+
continue;
1136+
1137+
dai = w->private;
1138+
alh_copier = (struct sof_ipc4_copier *)dai->private;
1139+
alh_data = &alh_copier->data;
1140+
blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id;
1141+
blob->alh_cfg.mapping[i].channel_mask = ch_mask;
1142+
i++;
1143+
}
1144+
if (blob->alh_cfg.count > 1) {
1145+
int group_id;
1146+
1147+
group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT,
1148+
GFP_KERNEL);
1149+
1150+
if (group_id < 0)
1151+
return group_id;
1152+
1153+
/* add multi-gateway base */
1154+
group_id += ALH_MULTI_GTW_BASE;
1155+
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1156+
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
1157+
}
10971158
}
10981159
}
10991160
}

sound/soc/sof/ipc4-topology.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@
4242

4343
#define ALH_MAX_NUMBER_OF_GTW 16
4444

45+
/*
46+
* The base of multi-gateways. Multi-gateways addressing starts from
47+
* ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources
48+
* and ALH_MULTI_GTW_COUNT multi-sinks available.
49+
* Addressing is continuous from ALH_MULTI_GTW_BASE to
50+
* ALH_MULTI_GTW_BASE + ALH_MULTI_GTW_COUNT - 1.
51+
*/
52+
#define ALH_MULTI_GTW_BASE 0x50
53+
/* A magic number from FW */
54+
#define ALH_MULTI_GTW_COUNT 8
55+
4556
/**
4657
* struct sof_ipc4_pipeline - pipeline config data
4758
* @priority: Priority of this pipeline

0 commit comments

Comments
 (0)