aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2023-11-13 01:28:27 +0000
committerMark Brown <broonie@kernel.org>2023-11-27 13:44:00 +0000
commit45cc50d13433a62f23b7b4af380497aae5e8ddc7 (patch)
tree848a28bbfd7fe8ef6e1a81f2eca35f62914b90c3 /sound
parentASoC: SOF: ipc4: Add support for control change (diff)
downloadwireguard-linux-45cc50d13433a62f23b7b4af380497aae5e8ddc7.tar.xz
wireguard-linux-45cc50d13433a62f23b7b4af380497aae5e8ddc7.zip
ASoC: makes CPU/Codec channel connection map more generic
Current ASoC CPU:Codec = N:M connection is using connection mapping idea, but it is used for N < M case only. We want to use it for any case. By this patch, not only N:M connection, but all existing connection (1:1, 1:N, N:N) will use same connection mapping. Then, because it will use default mapping, no conversion patch is needed to exising drivers. More over, CPU:Codec = N:M (N > M) also supported in the same time. ch_maps array will has CPU/Codec index by this patch. Image CPU0 <---> Codec0 CPU1 <-+-> Codec1 CPU2 <-/ ch_map ch_map[0].cpu = 0 ch_map[0].codec = 0 ch_map[1].cpu = 1 ch_map[1].codec = 1 ch_map[2].cpu = 2 ch_map[2].codec = 1 Link: https://lore.kernel.org/r/87fs6wuszr.wl-kuninori.morimoto.gx@renesas.com Link: https://lore.kernel.org/r/878r7yqeo4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Tested-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Tested-by: Jerome Brunet <jbrunet@baylibre.com> Link: https://lore.kernel.org/r/87ttpq4f2c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/intel/boards/sof_sdw.c28
-rw-r--r--sound/soc/soc-core.c95
-rw-r--r--sound/soc/soc-dapm.c45
-rw-r--r--sound/soc/soc-pcm.c44
4 files changed, 132 insertions, 80 deletions
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 3312ad8a563b..2faf7372bad0 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -570,16 +570,14 @@ int sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai_link_ch_map *ch_maps;
int ch = params_channels(params);
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
unsigned int ch_mask;
int num_codecs;
int step;
int i;
- int j;
- if (!rtd->dai_link->codec_ch_maps)
+ if (!rtd->dai_link->ch_maps)
return 0;
/* Identical data will be sent to all codecs in playback */
@@ -605,13 +603,9 @@ int sdw_hw_params(struct snd_pcm_substream *substream,
* link has more than one codec DAIs. Set codec channel mask and
* ASoC will set the corresponding channel numbers for each cpu dai.
*/
- for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i)
- continue;
- rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step);
- }
- }
+ for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
+ ch_maps->ch_mask = ch_mask << (i * step);
+
return 0;
}
@@ -1350,15 +1344,17 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
return 0;
}
-static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps,
+static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps,
int codec_num, int cpu_num)
{
int step;
int i;
step = codec_num / cpu_num;
- for (i = 0; i < codec_num; i++)
- sdw_codec_ch_maps[i].connected_cpu_id = i / step;
+ for (i = 0; i < codec_num; i++) {
+ sdw_codec_ch_maps[i].cpu = i / step;
+ sdw_codec_ch_maps[i].codec = i;
+ }
}
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
@@ -1453,7 +1449,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
*ignore_pch_dmic = true;
for_each_pcm_streams(stream) {
- struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps;
+ struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps;
char *name, *cpu_name;
int playback, capture;
static const char * const sdw_stream_name[] = {
@@ -1530,7 +1526,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
dai_links[*link_index].nonatomic = true;
set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
- dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps;
+ dai_links[*link_index].ch_maps = sdw_codec_ch_maps;
ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
playback, group_id, adr_index, dai_index);
if (ret < 0) {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b2bd45e87bc3..4ca3319a8e19 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1015,6 +1015,94 @@ component_dai_empty:
return -EINVAL;
}
+#define MAX_DEFAULT_CH_MAP_SIZE 7
+static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] = {
+ { .cpu = 0, .codec = 0 },
+ { .cpu = 1, .codec = 1 },
+ { .cpu = 2, .codec = 2 },
+ { .cpu = 3, .codec = 3 },
+ { .cpu = 4, .codec = 4 },
+ { .cpu = 5, .codec = 5 },
+ { .cpu = 6, .codec = 6 },
+};
+static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] = {
+ { .cpu = 0, .codec = 0 },
+ { .cpu = 0, .codec = 1 },
+ { .cpu = 0, .codec = 2 },
+ { .cpu = 0, .codec = 3 },
+ { .cpu = 0, .codec = 4 },
+ { .cpu = 0, .codec = 5 },
+ { .cpu = 0, .codec = 6 },
+};
+static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] = {
+ { .cpu = 0, .codec = 0 },
+ { .cpu = 1, .codec = 0 },
+ { .cpu = 2, .codec = 0 },
+ { .cpu = 3, .codec = 0 },
+ { .cpu = 4, .codec = 0 },
+ { .cpu = 5, .codec = 0 },
+ { .cpu = 6, .codec = 0 },
+};
+static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_dai_link_ch_map *ch_maps;
+ int i;
+
+ /*
+ * dai_link->ch_maps indicates how CPU/Codec are connected.
+ * It will be a map seen from a larger number of DAI.
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
+ */
+
+ /* it should have ch_maps if connection was N:M */
+ if (dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
+ dai_link->num_cpus != dai_link->num_codecs && !dai_link->ch_maps) {
+ dev_err(card->dev, "need to have ch_maps when N:M connction (%s)",
+ dai_link->name);
+ return -EINVAL;
+ }
+
+ /* do nothing if it has own maps */
+ if (dai_link->ch_maps)
+ goto sanity_check;
+
+ /* check default map size */
+ if (dai_link->num_cpus > MAX_DEFAULT_CH_MAP_SIZE ||
+ dai_link->num_codecs > MAX_DEFAULT_CH_MAP_SIZE) {
+ dev_err(card->dev, "soc-core.c needs update default_connection_maps");
+ return -EINVAL;
+ }
+
+ /* Compensate missing map for ... */
+ if (dai_link->num_cpus == dai_link->num_codecs)
+ dai_link->ch_maps = default_ch_map_sync; /* for 1:1 or N:N */
+ else if (dai_link->num_cpus < dai_link->num_codecs)
+ dai_link->ch_maps = default_ch_map_1cpu; /* for 1:N */
+ else
+ dai_link->ch_maps = default_ch_map_1codec; /* for N:1 */
+
+sanity_check:
+ dev_dbg(card->dev, "dai_link %s\n", dai_link->stream_name);
+ for_each_link_ch_maps(dai_link, i, ch_maps) {
+ if ((ch_maps->cpu >= dai_link->num_cpus) ||
+ (ch_maps->codec >= dai_link->num_codecs)) {
+ dev_err(card->dev,
+ "unexpected dai_link->ch_maps[%d] index (cpu(%d/%d) codec(%d/%d))",
+ i,
+ ch_maps->cpu, dai_link->num_cpus,
+ ch_maps->codec, dai_link->num_codecs);
+ return -EINVAL;
+ }
+
+ dev_dbg(card->dev, " [%d] cpu%d <-> codec%d\n",
+ i, ch_maps->cpu, ch_maps->codec);
+ }
+
+ return 0;
+}
+
/**
* snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card
* @card: The ASoC card to which the pcm_runtime has
@@ -1121,8 +1209,13 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
int num_dai_link)
{
for (int i = 0; i < num_dai_link; i++) {
- int ret = snd_soc_add_pcm_runtime(card, dai_link + i);
+ int ret;
+
+ ret = snd_soc_compensate_channel_connection_map(card, dai_link + i);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_add_pcm_runtime(card, dai_link + i);
if (ret < 0)
return ret;
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 407a26af3eaf..bffeea80277f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -4436,11 +4436,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
- int i;
/* for each BE DAI link... */
for_each_card_rtds(card, rtd) {
+ struct snd_soc_dai_link_ch_map *ch_maps;
+ int i;
+
/*
* dynamic FE links have no fixed DAI mapping.
* CODEC<->CODEC links have no direct connection.
@@ -4448,39 +4451,15 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
if (rtd->dai_link->dynamic)
continue;
- if (rtd->dai_link->num_cpus == 1) {
- for_each_rtd_codec_dais(rtd, i, codec_dai)
- dapm_connect_dai_pair(card, rtd, codec_dai,
- snd_soc_rtd_to_cpu(rtd, 0));
- } else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) {
- for_each_rtd_codec_dais(rtd, i, codec_dai)
- dapm_connect_dai_pair(card, rtd, codec_dai,
- snd_soc_rtd_to_cpu(rtd, i));
- } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
- int cpu_id;
-
- if (!rtd->dai_link->codec_ch_maps) {
- dev_err(card->dev, "%s: no codec channel mapping table provided\n",
- __func__);
- continue;
- }
+ /*
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
+ */
+ for_each_rtd_ch_maps(rtd, i, ch_maps) {
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu);
+ codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec);
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
- if (cpu_id >= rtd->dai_link->num_cpus) {
- dev_err(card->dev,
- "%s: dai_link %s cpu_id %d too large, num_cpus is %d\n",
- __func__, rtd->dai_link->name, cpu_id,
- rtd->dai_link->num_cpus);
- continue;
- }
- dapm_connect_dai_pair(card, rtd, codec_dai,
- snd_soc_rtd_to_cpu(rtd, cpu_id));
- }
- } else {
- dev_err(card->dev,
- "%s: codec number %d < cpu number %d is not supported\n",
- __func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus);
+ dapm_connect_dai_pair(card, rtd, codec_dai, cpu_dai);
}
}
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 323e4d7b6adf..c20573aeb756 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1050,6 +1050,7 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
}
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+ struct snd_soc_dai_link_ch_map *ch_maps;
unsigned int ch_mask = 0;
int j;
@@ -1063,22 +1064,20 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
/* copy params for each cpu */
tmp_params = *params;
- if (!rtd->dai_link->codec_ch_maps)
- goto hw_params;
/*
* construct cpu channel mask by combining ch_mask of each
* codec which maps to the cpu.
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
*/
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id == i)
- ch_mask |= rtd->dai_link->codec_ch_maps[j].ch_mask;
- }
+ for_each_rtd_ch_maps(rtd, j, ch_maps)
+ if (ch_maps->cpu == i)
+ ch_mask |= ch_maps->ch_mask;
/* fixup cpu channel number */
if (ch_mask)
soc_pcm_codec_params_fixup(&tmp_params, ch_mask);
-hw_params:
ret = snd_soc_dai_hw_params(cpu_dai, substream, &tmp_params);
if (ret < 0)
goto out;
@@ -2826,35 +2825,20 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
}
}
} else {
+ struct snd_soc_dai_link_ch_map *ch_maps;
struct snd_soc_dai *codec_dai;
/* Adapt stream for codec2codec links */
int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE);
int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK);
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- if (dai_link->num_cpus == 1) {
- cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
- } else if (dai_link->num_cpus == dai_link->num_codecs) {
- cpu_dai = snd_soc_rtd_to_cpu(rtd, i);
- } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
- int cpu_id;
-
- if (!rtd->dai_link->codec_ch_maps) {
- dev_err(rtd->card->dev, "%s: no codec channel mapping table provided\n",
- __func__);
- return -EINVAL;
- }
-
- cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
- cpu_dai = snd_soc_rtd_to_cpu(rtd, cpu_id);
- } else {
- dev_err(rtd->card->dev,
- "%s codec number %d < cpu number %d is not supported\n",
- __func__, rtd->dai_link->num_codecs,
- rtd->dai_link->num_cpus);
- return -EINVAL;
- }
+ /*
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
+ */
+ for_each_rtd_ch_maps(rtd, i, ch_maps) {
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu);
+ codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec);
if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
snd_soc_dai_stream_valid(cpu_dai, cpu_playback))