Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: add N cpus to M codecs dai link support

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

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 series 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.

And add the codec_ch_maps to SOF SoundWire machine driver.

+141 -5
+6
include/sound/soc.h
··· 645 645 const char *dai_name; 646 646 }; 647 647 648 + struct snd_soc_dai_link_codec_ch_map { 649 + unsigned int connected_cpu_id; 650 + unsigned int ch_mask; 651 + }; 652 + 648 653 struct snd_soc_dai_link { 649 654 /* config - must be set by machine driver */ 650 655 const char *name; /* Codec name */ ··· 678 673 struct snd_soc_dai_link_component *codecs; 679 674 unsigned int num_codecs; 680 675 676 + struct snd_soc_dai_link_codec_ch_map *codec_ch_maps; 681 677 /* 682 678 * You MAY specify the link's platform/PCM/DMA driver, either by 683 679 * device name, or by DT/OF node, but not both. Some forms of link
+69
sound/soc/intel/boards/sof_sdw.c
··· 560 560 return ret; 561 561 } 562 562 563 + int sdw_hw_params(struct snd_pcm_substream *substream, 564 + struct snd_pcm_hw_params *params) 565 + { 566 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 567 + int ch = params_channels(params); 568 + struct snd_soc_dai *codec_dai; 569 + struct snd_soc_dai *cpu_dai; 570 + unsigned int ch_mask; 571 + int num_codecs; 572 + int step; 573 + int i; 574 + int j; 575 + 576 + if (!rtd->dai_link->codec_ch_maps) 577 + return 0; 578 + 579 + /* Identical data will be sent to all codecs in playback */ 580 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 581 + ch_mask = GENMASK(ch - 1, 0); 582 + step = 0; 583 + } else { 584 + num_codecs = rtd->dai_link->num_codecs; 585 + 586 + if (ch < num_codecs || ch % num_codecs != 0) { 587 + dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", 588 + ch, num_codecs); 589 + return -EINVAL; 590 + } 591 + 592 + ch_mask = GENMASK(ch / num_codecs - 1, 0); 593 + step = hweight_long(ch_mask); 594 + 595 + } 596 + 597 + /* 598 + * The captured data will be combined from each cpu DAI if the dai 599 + * link has more than one codec DAIs. Set codec channel mask and 600 + * ASoC will set the corresponding channel numbers for each cpu dai. 601 + */ 602 + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { 603 + for_each_rtd_codec_dais(rtd, j, codec_dai) { 604 + if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i) 605 + continue; 606 + rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step); 607 + } 608 + } 609 + return 0; 610 + } 611 + 563 612 int sdw_hw_free(struct snd_pcm_substream *substream) 564 613 { 565 614 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ··· 637 588 .startup = sdw_startup, 638 589 .prepare = sdw_prepare, 639 590 .trigger = sdw_trigger, 591 + .hw_params = sdw_hw_params, 640 592 .hw_free = sdw_hw_free, 641 593 .shutdown = sdw_shutdown, 642 594 }; ··· 1331 1281 return 0; 1332 1282 } 1333 1283 1284 + static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps, 1285 + int codec_num, int cpu_num) 1286 + { 1287 + int step; 1288 + int i; 1289 + 1290 + step = codec_num / cpu_num; 1291 + for (i = 0; i < codec_num; i++) 1292 + sdw_codec_ch_maps[i].connected_cpu_id = i / step; 1293 + } 1294 + 1334 1295 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; 1335 1296 1336 1297 static int create_sdw_dailink(struct snd_soc_card *card, ··· 1418 1357 1419 1358 cpu_dai_index = *cpu_id; 1420 1359 for_each_pcm_streams(stream) { 1360 + struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps; 1421 1361 char *name, *cpu_name; 1422 1362 int playback, capture; 1423 1363 static const char * const sdw_stream_name[] = { ··· 1436 1374 dev_err(dev, "Invalid dailink id %d\n", *link_id); 1437 1375 return -EINVAL; 1438 1376 } 1377 + 1378 + sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, 1379 + sizeof(*sdw_codec_ch_maps), GFP_KERNEL); 1380 + if (!sdw_codec_ch_maps) 1381 + return -ENOMEM; 1439 1382 1440 1383 /* create stream name according to first link id */ 1441 1384 if (append_dai_type) { ··· 1502 1435 */ 1503 1436 dai_links[*link_index].nonatomic = true; 1504 1437 1438 + set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); 1439 + dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; 1505 1440 ret = set_codec_init_func(card, link, dai_links + (*link_index)++, 1506 1441 playback, group_id, adr_index, dai_index); 1507 1442 if (ret < 0) {
+2
sound/soc/intel/boards/sof_sdw_common.h
··· 103 103 int sdw_startup(struct snd_pcm_substream *substream); 104 104 int sdw_prepare(struct snd_pcm_substream *substream); 105 105 int sdw_trigger(struct snd_pcm_substream *substream, int cmd); 106 + int sdw_hw_params(struct snd_pcm_substream *substream, 107 + struct snd_pcm_hw_params *params); 106 108 int sdw_hw_free(struct snd_pcm_substream *substream); 107 109 void sdw_shutdown(struct snd_pcm_substream *substream); 108 110
+1
sound/soc/intel/boards/sof_sdw_maxim.c
··· 123 123 .startup = sdw_startup, 124 124 .prepare = mx8373_sdw_prepare, 125 125 .trigger = sdw_trigger, 126 + .hw_params = sdw_hw_params, 126 127 .hw_free = mx8373_sdw_hw_free, 127 128 .shutdown = sdw_shutdown, 128 129 };
+23 -1
sound/soc/soc-dapm.c
··· 4444 4444 for_each_rtd_codec_dais(rtd, i, codec_dai) 4445 4445 dapm_connect_dai_pair(card, rtd, codec_dai, 4446 4446 asoc_rtd_to_cpu(rtd, i)); 4447 + } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) { 4448 + int cpu_id; 4449 + 4450 + if (!rtd->dai_link->codec_ch_maps) { 4451 + dev_err(card->dev, "%s: no codec channel mapping table provided\n", 4452 + __func__); 4453 + continue; 4454 + } 4455 + 4456 + for_each_rtd_codec_dais(rtd, i, codec_dai) { 4457 + cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id; 4458 + if (cpu_id >= rtd->dai_link->num_cpus) { 4459 + dev_err(card->dev, 4460 + "%s: dai_link %s cpu_id %d too large, num_cpus is %d\n", 4461 + __func__, rtd->dai_link->name, cpu_id, 4462 + rtd->dai_link->num_cpus); 4463 + continue; 4464 + } 4465 + dapm_connect_dai_pair(card, rtd, codec_dai, 4466 + asoc_rtd_to_cpu(rtd, cpu_id)); 4467 + } 4447 4468 } else { 4448 4469 dev_err(card->dev, 4449 - "N cpus to M codecs link is not supported yet\n"); 4470 + "%s: codec number %d < cpu number %d is not supported\n", 4471 + __func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus); 4450 4472 } 4451 4473 } 4452 4474 }
+40 -4
sound/soc/soc-pcm.c
··· 1034 1034 } 1035 1035 1036 1036 for_each_rtd_cpu_dais(rtd, i, cpu_dai) { 1037 + struct snd_pcm_hw_params cpu_params; 1038 + unsigned int ch_mask = 0; 1039 + int j; 1040 + 1037 1041 /* 1038 1042 * Skip CPUs which don't support the current stream 1039 1043 * type. See soc_pcm_init_runtime_hw() for more details ··· 1045 1041 if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) 1046 1042 continue; 1047 1043 1048 - ret = snd_soc_dai_hw_params(cpu_dai, substream, params); 1044 + /* copy params for each cpu */ 1045 + cpu_params = *params; 1046 + 1047 + if (!rtd->dai_link->codec_ch_maps) 1048 + goto hw_params; 1049 + /* 1050 + * construct cpu channel mask by combining ch_mask of each 1051 + * codec which maps to the cpu. 1052 + */ 1053 + for_each_rtd_codec_dais(rtd, j, codec_dai) { 1054 + if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id == i) 1055 + ch_mask |= rtd->dai_link->codec_ch_maps[j].ch_mask; 1056 + } 1057 + 1058 + /* fixup cpu channel number */ 1059 + if (ch_mask) 1060 + soc_pcm_codec_params_fixup(&cpu_params, ch_mask); 1061 + 1062 + hw_params: 1063 + ret = snd_soc_dai_hw_params(cpu_dai, substream, &cpu_params); 1049 1064 if (ret < 0) 1050 1065 goto out; 1051 1066 1052 1067 /* store the parameters for each DAI */ 1053 - soc_pcm_set_dai_params(cpu_dai, params); 1054 - snd_soc_dapm_update_dai(substream, params, cpu_dai); 1068 + soc_pcm_set_dai_params(cpu_dai, &cpu_params); 1069 + snd_soc_dapm_update_dai(substream, &cpu_params, cpu_dai); 1055 1070 } 1056 1071 1057 1072 ret = snd_soc_pcm_component_hw_params(substream, params); ··· 2812 2789 cpu_dai = asoc_rtd_to_cpu(rtd, 0); 2813 2790 } else if (dai_link->num_cpus == dai_link->num_codecs) { 2814 2791 cpu_dai = asoc_rtd_to_cpu(rtd, i); 2792 + } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) { 2793 + int cpu_id; 2794 + 2795 + if (!rtd->dai_link->codec_ch_maps) { 2796 + dev_err(rtd->card->dev, "%s: no codec channel mapping table provided\n", 2797 + __func__); 2798 + return -EINVAL; 2799 + } 2800 + 2801 + cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id; 2802 + cpu_dai = asoc_rtd_to_cpu(rtd, cpu_id); 2815 2803 } else { 2816 2804 dev_err(rtd->card->dev, 2817 - "N cpus to M codecs link is not supported yet\n"); 2805 + "%s codec number %d < cpu number %d is not supported\n", 2806 + __func__, rtd->dai_link->num_codecs, 2807 + rtd->dai_link->num_cpus); 2818 2808 return -EINVAL; 2819 2809 } 2820 2810