Hi Bard > Currently, ASoC supports dailinks with the following mappings: > 1 cpu DAI to N codec DAIs > N cpu DAIs to N codec DAIs > But the mapping between N cpu DAIs and M codec DAIs is not supported. > The reason is that we didn't have a mechanism to map cpu and codec DAIs > > This patch suggests a new snd_soc_dai_link_codec_ch_map struct in > struct snd_soc_dai_link{} which provides codec DAI to cpu DAI mapping > information used to implement N cpu DAIs to M codec DAIs > support. > > When a dailink contains two or more cpu DAIs, we should set channel > number of cpus based on its channel mask. The new struct also provides > channel mask information for each codec and we can construct the cpu > channel mask by combining all codec channel masks which map to the cpu. > > The N:M mapping is however restricted to the N <= M case due to physical > restrictions on a time-multiplexed bus such as I2S/TDM, AC97, SoundWire > and HDaudio. I like CPU:Codec = N:M support ! OTOH, I have interesting to ASoC code cleanup too. So this is meddlesome from me. > +struct snd_soc_dai_link_codec_ch_map { > + unsigned int connected_cpu_id; > + unsigned int ch_mask; > +}; If my understanding was correct, this map is used only for N:M mapping, but we want to use it for all cases. In such case, the code can be more flexible and more clean. see below. > @@ -1041,13 +1045,32 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, > if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) > continue; > > - ret = snd_soc_dai_hw_params(cpu_dai, substream, params); > + /* copy params for each cpu */ > + cpu_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. > + */ > + 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; > + } Can we re-use snd_soc_dai_tdm_mask_get() for this purpose instead of .ch_mask ? May be we want to rename it and/or want to have new xxx_mask on dai->stream[]. I'm asking because it is natural to reuse existing data and/or have variable on similar place instead of on new structure. Maybe I'm not 100% well understanding about CPU:Codec = N:M connection, but if we can assume like below, we can use it on all cases not only for N:M case. We can have connection map on dai_link which is for from M side (here N <= M). The image is like this. CPU0 <---> Codec2 CPU1 <-+-> Codec0 \-> Codec1 .num_cpus = 2; .num_codecs = 3; .map = [1, 1, 0]; // From Codec point of view. // sizeof(map) = num_codecs, because 3 > 2; In this rule, we can also handle CPU > Codec case, too. CPU0 <---> Codec1 CPU1 <-+-> Codec0 CPU2 <-/ .num_cpus = 3; .num_codecs = 2; .map = [1, 0, 0]; // From CPU point of view. We can use this idea for existing connection, too. 1:1 case CPU0 <-> Codec0 N:N case CPU0 <---> Codec0 CPU1 <---> Codec1 1:N case CPU0 <-+-> Codec0 \-> Codec1 default_map1 = [0, 1, 2, 3,...]; default_map2 = [0, 0, 0, 0,...]; if (!dai_link->map) { if (dai_link->num_cpus == dai_link->num_codecs) dai_link->map = default_map1; /* for 1:1, N:N */ else dai_link->map = default_map2; /* for 1:N */ } We can handle more flexible N:N connection as Richard said fixup N:N case CPU0 <---> Codec2 CPU1 <---> Codec1 CPU2 <---> Codec0 .num_cpus = 3; .num_codecs = 3; .map = [2, 1, 0]; // From CPU point of view. with is new .map, we can handle existing 1:1, N:N, 1:N, and new N:M (and M:N) connection with same code. This is just meddlesome from me, but I hope you can think about this. Thank you for your help !! Best regards --- Kuninori Morimoto