From 98b235a8328967390580d20f68f3206b72cf13ae Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 9 Sep 2024 13:56:52 +0530 Subject: [PATCH 1/5] ASoC: intel: sof_sdw: rename soundwire endpoint and dailink structures Rename SoundWire endpoint and dai link structures with asoc tag to make it generic. Signed-off-by: Vijendar Mukunda --- sound/soc/intel/boards/sof_sdw.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 7be76841c9d55d..2d4944e41d3591 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -636,7 +636,7 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = asoc_sdw_shutdown, }; -struct sof_sdw_endpoint { +struct asoc_sdw_endpoint { struct list_head list; u32 link_mask; @@ -648,7 +648,7 @@ struct sof_sdw_endpoint { const struct asoc_sdw_dai_info *dai_info; }; -struct sof_sdw_dailink { +struct asoc_sdw_dailink { bool initialised; u8 group_id; @@ -679,8 +679,8 @@ static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *nu return 0; } -static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks, - const struct snd_soc_acpi_endpoint *new) +static struct asoc_sdw_dailink *find_dailink(struct asoc_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new) { while (dailinks->initialised) { if (new->aggregated && dailinks->group_id == new->group_id) @@ -697,8 +697,8 @@ static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks, } static int parse_sdw_endpoints(struct snd_soc_card *card, - struct sof_sdw_dailink *sof_dais, - struct sof_sdw_endpoint *sof_ends, + struct asoc_sdw_dailink *sof_dais, + struct asoc_sdw_endpoint *sof_ends, int *num_devs) { struct device *dev = card->dev; @@ -706,7 +706,7 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link; - struct sof_sdw_endpoint *sof_end = sof_ends; + struct asoc_sdw_endpoint *sof_end = sof_ends; int num_dais = 0; int i, j; int ret; @@ -757,7 +757,7 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, for (j = 0; j < adr_dev->num_endpoints; j++) { const struct snd_soc_acpi_endpoint *adr_end; const struct asoc_sdw_dai_info *dai_info; - struct sof_sdw_dailink *sof_dai; + struct asoc_sdw_dailink *sof_dai; int stream; adr_end = &adr_dev->endpoints[j]; @@ -818,14 +818,14 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, } static int create_sdw_dailink(struct snd_soc_card *card, - struct sof_sdw_dailink *sof_dai, + struct asoc_sdw_dailink *sof_dai, struct snd_soc_dai_link **dai_links, int *be_id, struct snd_soc_codec_conf **codec_conf) { struct device *dev = card->dev; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; - struct sof_sdw_endpoint *sof_end; + struct asoc_sdw_endpoint *sof_end; int stream; int ret; @@ -864,7 +864,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, continue; sof_end = list_first_entry(&sof_dai->endpoints, - struct sof_sdw_endpoint, list); + struct asoc_sdw_endpoint, list); *be_id = sof_end->dai_info->dailink[stream]; if (*be_id < 0) { @@ -955,7 +955,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, static int create_sdw_dailinks(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, int *be_id, - struct sof_sdw_dailink *sof_dais, + struct asoc_sdw_dailink *sof_dais, struct snd_soc_codec_conf **codec_conf) { struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); @@ -1123,8 +1123,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct snd_soc_codec_conf *codec_conf; struct asoc_sdw_codec_info *ssp_info; - struct sof_sdw_endpoint *sof_ends; - struct sof_sdw_dailink *sof_dais; + struct asoc_sdw_endpoint *sof_ends; + struct asoc_sdw_dailink *sof_dais; int num_devs = 0; int num_ends = 0; struct snd_soc_dai_link *dai_links; From a8454e7fac60e6e62fff61a23ac6c04ea9d14a4f Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 9 Sep 2024 14:28:42 +0530 Subject: [PATCH 2/5] ASoC: intel: sof_sdw: rename soundwire parsing helper functions Rename SoundWire parsing helper functions with 'asoc_sdw' tag to make it generic. Signed-off-by: Vijendar Mukunda --- sound/soc/intel/boards/sof_sdw.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 2d4944e41d3591..834a320f35f92c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -659,7 +659,7 @@ struct asoc_sdw_dailink { static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +static int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) { struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); @@ -679,8 +679,8 @@ static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *nu return 0; } -static struct asoc_sdw_dailink *find_dailink(struct asoc_sdw_dailink *dailinks, - const struct snd_soc_acpi_endpoint *new) +static struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new) { while (dailinks->initialised) { if (new->aggregated && dailinks->group_id == new->group_id) @@ -696,10 +696,10 @@ static struct asoc_sdw_dailink *find_dailink(struct asoc_sdw_dailink *dailinks, return dailinks; } -static int parse_sdw_endpoints(struct snd_soc_card *card, - struct asoc_sdw_dailink *sof_dais, - struct asoc_sdw_endpoint *sof_ends, - int *num_devs) +static int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct asoc_sdw_dailink *sof_dais, + struct asoc_sdw_endpoint *sof_ends, + int *num_devs) { struct device *dev = card->dev; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); @@ -762,7 +762,7 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, adr_end = &adr_dev->endpoints[j]; dai_info = &codec_info->dais[adr_end->num]; - sof_dai = find_dailink(sof_dais, adr_end); + sof_dai = asoc_sdw_find_dailink(sof_dais, adr_end); if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk)) continue; @@ -1134,7 +1134,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) unsigned long ssp_mask; int ret; - ret = count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; @@ -1152,7 +1152,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); if (ret < 0) goto err_end; From bfbc3c53329905550ca297e42e82d2a46a08e2ef Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 9 Sep 2024 14:09:27 +0530 Subject: [PATCH 3/5] ASoC: sdw_util/intel: move soundwire endpoint and dai link structures Move Soundwire endpoint and dai link structures from Intel generic machine driver code to common place holder(soc_sdw_utils.h). These structures will be used in other platform SoundWire machine driver code. Signed-off-by: Vijendar Mukunda --- include/sound/soc_sdw_utils.h | 21 +++++++++++++++++++++ sound/soc/intel/boards/sof_sdw.c | 21 --------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index e366b7968c2d02..e3482720a3eb0c 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -93,6 +93,27 @@ struct asoc_sdw_mc_private { int codec_info_list_count; }; +struct asoc_sdw_endpoint { + struct list_head list; + + u32 link_mask; + const char *codec_name; + const char *name_prefix; + bool include_sidecar; + + struct asoc_sdw_codec_info *codec_info; + const struct asoc_sdw_dai_info *dai_info; +}; + +struct asoc_sdw_dailink { + bool initialised; + + u8 group_id; + u32 link_mask[SNDRV_PCM_STREAM_LAST + 1]; + int num_devs[SNDRV_PCM_STREAM_LAST + 1]; + struct list_head endpoints; +}; + extern struct asoc_sdw_codec_info codec_info_list[]; int asoc_sdw_get_codec_info_list_count(void); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 834a320f35f92c..567d6bd13f2895 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -636,27 +636,6 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = asoc_sdw_shutdown, }; -struct asoc_sdw_endpoint { - struct list_head list; - - u32 link_mask; - const char *codec_name; - const char *name_prefix; - bool include_sidecar; - - struct asoc_sdw_codec_info *codec_info; - const struct asoc_sdw_dai_info *dai_info; -}; - -struct asoc_sdw_dailink { - bool initialised; - - u8 group_id; - u32 link_mask[SNDRV_PCM_STREAM_LAST + 1]; - int num_devs[SNDRV_PCM_STREAM_LAST + 1]; - struct list_head endpoints; -}; - static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; static int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) From f85ea151d2f98a6690ce3095bbe10d6d181c80a8 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 9 Sep 2024 14:59:00 +0530 Subject: [PATCH 4/5] ASoC: sdw_utils/intel: move soundwire endpoint parsing helper functions Move SoundWire endpoint parsing helper functions to common place holder. These functions will be used by other platform machine driver code. Signed-off-by: Vijendar Mukunda --- include/sound/soc_sdw_utils.h | 10 ++ sound/soc/intel/boards/sof_sdw.c | 158 --------------------------- sound/soc/sdw_utils/soc_sdw_utils.c | 161 ++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 158 deletions(-) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index e3482720a3eb0c..f68c1f193b3b46 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -161,6 +161,16 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops); +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends); + +struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new); + +int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct asoc_sdw_dailink *soc_dais, + struct asoc_sdw_endpoint *soc_ends, + int *num_devs); + int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd); /* DMIC support */ diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 567d6bd13f2895..dc7d65d8db1e75 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -638,164 +638,6 @@ static const struct snd_soc_ops sdw_ops = { static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -static int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) -{ - struct device *dev = card->dev; - struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); - struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link; - int i; - - for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { - *num_devs += adr_link->num_adr; - - for (i = 0; i < adr_link->num_adr; i++) - *num_ends += adr_link->adr_d[i].num_endpoints; - } - - dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); - - return 0; -} - -static struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, - const struct snd_soc_acpi_endpoint *new) -{ - while (dailinks->initialised) { - if (new->aggregated && dailinks->group_id == new->group_id) - return dailinks; - - dailinks++; - } - - INIT_LIST_HEAD(&dailinks->endpoints); - dailinks->group_id = new->group_id; - dailinks->initialised = true; - - return dailinks; -} - -static int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, - struct asoc_sdw_dailink *sof_dais, - struct asoc_sdw_endpoint *sof_ends, - int *num_devs) -{ - struct device *dev = card->dev; - struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); - struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link; - struct asoc_sdw_endpoint *sof_end = sof_ends; - int num_dais = 0; - int i, j; - int ret; - - for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { - int num_link_dailinks = 0; - - if (!is_power_of_2(adr_link->mask)) { - dev_err(dev, "link with multiple mask bits: 0x%x\n", - adr_link->mask); - return -EINVAL; - } - - for (i = 0; i < adr_link->num_adr; i++) { - const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; - struct asoc_sdw_codec_info *codec_info; - const char *codec_name; - - if (!adr_dev->name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_dev->adr); - return -EINVAL; - } - - codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); - if (!codec_info) - return -EINVAL; - - ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; - - codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); - if (!codec_name) - return -ENOMEM; - - dev_dbg(dev, "Adding prefix %s for %s\n", - adr_dev->name_prefix, codec_name); - - sof_end->name_prefix = adr_dev->name_prefix; - - if (codec_info->count_sidecar && codec_info->add_sidecar) { - ret = codec_info->count_sidecar(card, &num_dais, num_devs); - if (ret) - return ret; - - sof_end->include_sidecar = true; - } - - for (j = 0; j < adr_dev->num_endpoints; j++) { - const struct snd_soc_acpi_endpoint *adr_end; - const struct asoc_sdw_dai_info *dai_info; - struct asoc_sdw_dailink *sof_dai; - int stream; - - adr_end = &adr_dev->endpoints[j]; - dai_info = &codec_info->dais[adr_end->num]; - sof_dai = asoc_sdw_find_dailink(sof_dais, adr_end); - - if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk)) - continue; - - dev_dbg(dev, - "Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n", - ffs(adr_link->mask) - 1, adr_dev->adr, - adr_end->num, type_strings[dai_info->dai_type], - dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', - dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', - adr_end->aggregated ? "group" : "solo", - adr_end->group_id); - - if (adr_end->num >= codec_info->dai_num) { - dev_err(dev, - "%d is too many endpoints for codec: 0x%x\n", - adr_end->num, codec_info->part_id); - return -EINVAL; - } - - for_each_pcm_streams(stream) { - if (dai_info->direction[stream] && - dai_info->dailink[stream] < 0) { - dev_err(dev, - "Invalid dailink id %d for codec: 0x%x\n", - dai_info->dailink[stream], - codec_info->part_id); - return -EINVAL; - } - - if (dai_info->direction[stream]) { - num_dais += !sof_dai->num_devs[stream]; - sof_dai->num_devs[stream]++; - sof_dai->link_mask[stream] |= adr_link->mask; - } - } - - num_link_dailinks += !!list_empty(&sof_dai->endpoints); - list_add_tail(&sof_end->list, &sof_dai->endpoints); - - sof_end->link_mask = adr_link->mask; - sof_end->codec_name = codec_name; - sof_end->codec_info = codec_info; - sof_end->dai_info = dai_info; - sof_end++; - } - } - - ctx->append_dai_type |= (num_link_dailinks > 1); - } - - return num_dais; -} - static int create_sdw_dailink(struct snd_soc_card *card, struct asoc_sdw_dailink *sof_dai, struct snd_soc_dai_link **dai_links, diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index d59ccb56642c79..a6070f822eb9e4 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -1005,5 +1005,166 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d } EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, SND_SOC_SDW_UTILS); +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link; + int i; + + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { + *num_devs += adr_link->num_adr; + + for (i = 0; i < adr_link->num_adr; i++) + *num_ends += adr_link->adr_d[i].num_endpoints; + } + + dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, SND_SOC_SDW_UTILS); + +struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new) +{ + while (dailinks->initialised) { + if (new->aggregated && dailinks->group_id == new->group_id) + return dailinks; + + dailinks++; + } + + INIT_LIST_HEAD(&dailinks->endpoints); + dailinks->group_id = new->group_id; + dailinks->initialised = true; + + return dailinks; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, SND_SOC_SDW_UTILS); + +int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct asoc_sdw_dailink *soc_dais, + struct asoc_sdw_endpoint *soc_ends, + int *num_devs) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link; + struct asoc_sdw_endpoint *soc_end = soc_ends; + int num_dais = 0; + int i, j; + int ret; + + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { + int num_link_dailinks = 0; + + if (!is_power_of_2(adr_link->mask)) { + dev_err(dev, "link with multiple mask bits: 0x%x\n", + adr_link->mask); + return -EINVAL; + } + + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; + struct asoc_sdw_codec_info *codec_info; + const char *codec_name; + + if (!adr_dev->name_prefix) { + dev_err(dev, "codec 0x%llx does not have a name prefix\n", + adr_dev->adr); + return -EINVAL; + } + + codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); + if (!codec_info) + return -EINVAL; + + ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; + + codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); + if (!codec_name) + return -ENOMEM; + + dev_dbg(dev, "Adding prefix %s for %s\n", + adr_dev->name_prefix, codec_name); + + soc_end->name_prefix = adr_dev->name_prefix; + + if (codec_info->count_sidecar && codec_info->add_sidecar) { + ret = codec_info->count_sidecar(card, &num_dais, num_devs); + if (ret) + return ret; + + soc_end->include_sidecar = true; + } + + for (j = 0; j < adr_dev->num_endpoints; j++) { + const struct snd_soc_acpi_endpoint *adr_end; + const struct asoc_sdw_dai_info *dai_info; + struct asoc_sdw_dailink *soc_dai; + int stream; + + adr_end = &adr_dev->endpoints[j]; + dai_info = &codec_info->dais[adr_end->num]; + soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); + + if (dai_info->quirk && !(dai_info->quirk & ctx->mc_quirk)) + continue; + + dev_dbg(dev, + "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n", + ffs(adr_link->mask) - 1, adr_dev->adr, + adr_end->num, dai_info->dai_type, + dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', + dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', + adr_end->aggregated ? "group" : "solo", + adr_end->group_id); + + if (adr_end->num >= codec_info->dai_num) { + dev_err(dev, + "%d is too many endpoints for codec: 0x%x\n", + adr_end->num, codec_info->part_id); + return -EINVAL; + } + + for_each_pcm_streams(stream) { + if (dai_info->direction[stream] && + dai_info->dailink[stream] < 0) { + dev_err(dev, + "Invalid dailink id %d for codec: 0x%x\n", + dai_info->dailink[stream], + codec_info->part_id); + return -EINVAL; + } + + if (dai_info->direction[stream]) { + num_dais += !soc_dai->num_devs[stream]; + soc_dai->num_devs[stream]++; + soc_dai->link_mask[stream] |= adr_link->mask; + } + } + + num_link_dailinks += !!list_empty(&soc_dai->endpoints); + list_add_tail(&soc_end->list, &soc_dai->endpoints); + + soc_end->link_mask = adr_link->mask; + soc_end->codec_name = codec_name; + soc_end->codec_info = codec_info; + soc_end->dai_info = dai_info; + soc_end++; + } + } + + ctx->append_dai_type |= (num_link_dailinks > 1); + } + + return num_dais; +} +EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, SND_SOC_SDW_UTILS); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SoundWire ASoC helpers"); From b01feb38ee768bcd1826a6a6efd06fee68d8f0ab Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 9 Sep 2024 15:27:41 +0530 Subject: [PATCH 5/5] ASoC: amd: acp: refactor SoundWire machine driver code Refactor Soundwire machine driver code by using common SoundWire endpoint parsing helper functions. Signed-off-by: Vijendar Mukunda --- sound/soc/amd/acp/acp-sdw-sof-mach.c | 540 ++++++++------------------- 1 file changed, 154 insertions(+), 386 deletions(-) diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index 08f368b3bbc861..76a79c7ea047d7 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -64,197 +64,6 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = asoc_sdw_shutdown, }; -/* - * get BE dailink number and CPU DAI number based on sdw link adr. - * Since some sdw slaves may be aggregated, the CPU DAI number - * may be larger than the number of BE dailinks. - */ -static int get_dailink_info(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - int *sdw_be_num, int *codecs_num) -{ - bool group_visited[AMD_SDW_MAX_GROUPS]; - int i; - int j; - - *sdw_be_num = 0; - - if (!adr_link) - return -EINVAL; - - for (i = 0; i < AMD_SDW_MAX_GROUPS; i++) - group_visited[i] = false; - - for (; adr_link->num_adr; adr_link++) { - const struct snd_soc_acpi_endpoint *endpoint; - struct asoc_sdw_codec_info *codec_info; - int stream; - u64 adr; - - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; - - for (i = 0; i < adr_link->num_adr; i++) { - adr = adr_link->adr_d[i].adr; - codec_info = asoc_sdw_find_codec_info_part(adr); - if (!codec_info) - return -EINVAL; - - *codecs_num += codec_info->dai_num; - - if (!adr_link->adr_d[i].name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_link->adr_d[i].adr); - return -EINVAL; - } - - endpoint = adr_link->adr_d[i].endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x\n", - adr_link->mask); - return -EINVAL; - } - - for (j = 0; j < codec_info->dai_num; j++) { - /* count DAI number for playback and capture */ - for_each_pcm_streams(stream) { - if (!codec_info->dais[j].direction[stream]) - continue; - - /* count BE for each non-aggregated slave or group */ - if (!endpoint->aggregated || - !group_visited[endpoint->group_id]) - (*sdw_be_num)++; - } - } - - if (endpoint->aggregated) - group_visited[endpoint->group_id] = true; - } - } - return 0; -} - -static int fill_sdw_codec_dlc(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link_component *codec, - int adr_index, int dai_index) -{ - u64 adr = adr_link->adr_d[adr_index].adr; - struct asoc_sdw_codec_info *codec_info; - - codec_info = asoc_sdw_find_codec_info_part(adr); - if (!codec_info) - return -EINVAL; - - codec->name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, adr_index); - if (!codec->name) - return -ENOMEM; - - codec->dai_name = codec_info->dais[dai_index].dai_name; - dev_err(dev, "codec->dai_name:%s\n", codec->dai_name); - return 0; -} - -static int set_codec_init_func(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link *dai_links, - bool playback, int group_id, int adr_index, int dai_index) -{ - int i = adr_index; - - do { - /* - * Initialize the codec. If codec is part of an aggregated - * group (group_id>0), initialize all codecs belonging to - * same group. - * The first link should start with adr_link->adr_d[adr_index] - * because that is the device that we want to initialize and - * we should end immediately if it is not aggregated (group_id=0) - */ - for ( ; i < adr_link->num_adr; i++) { - struct asoc_sdw_codec_info *codec_info; - - codec_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[i].adr); - if (!codec_info) - return -EINVAL; - - /* The group_id is > 0 iff the codec is aggregated */ - if (adr_link->adr_d[i].endpoints->group_id != group_id) - continue; - if (codec_info->dais[dai_index].init) - codec_info->dais[dai_index].init(card, - dai_links, - codec_info, - playback); - - if (!group_id) - return 0; - } - - i = 0; - adr_link++; - } while (adr_link->mask); - - return 0; -} - -/* - * check endpoint status in slaves and gather link ID for all slaves in - * the same group to generate different CPU DAI. Now only support - * one sdw link with all slaves set with only single group id. - * - * one slave on one sdw link with aggregated = 0 - * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI - * - * two or more slaves on one sdw link with aggregated = 1 - * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs - */ -static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, - struct device *dev, int *cpu_dai_id, int *cpu_dai_num, - int *codec_num, unsigned int *group_id, - int adr_index) -{ - int i; - - if (!adr_link->adr_d[adr_index].endpoints->aggregated) { - cpu_dai_id[0] = ffs(adr_link->mask) - 1; - *cpu_dai_num = 1; - *codec_num = 1; - *group_id = 0; - return 0; - } - - *codec_num = 0; - *cpu_dai_num = 0; - *group_id = adr_link->adr_d[adr_index].endpoints->group_id; - - /* Count endpoints with the same group_id in the adr_link */ - for (; adr_link && adr_link->num_adr; adr_link++) { - unsigned int link_codecs = 0; - - for (i = 0; i < adr_link->num_adr; i++) { - if (adr_link->adr_d[i].endpoints->aggregated && - adr_link->adr_d[i].endpoints->group_id == *group_id) - link_codecs++; - } - - if (link_codecs) { - *codec_num += link_codecs; - - if (*cpu_dai_num >= ACP63_SDW_MAX_CPU_DAIS) { - dev_err(dev, "cpu_dai_id array overflowed\n"); - return -EINVAL; - } - - cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; - } - } - - return 0; -} - static int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev) { switch (sdw_link_id) { @@ -306,116 +115,64 @@ static int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, str static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; static int create_sdw_dailink(struct snd_soc_card *card, + struct asoc_sdw_dailink *sof_dai, struct snd_soc_dai_link **dai_links, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_codec_conf **codec_conf, - int *be_id, int adr_index, int dai_index) + int *be_id, struct snd_soc_codec_conf **codec_conf) { + struct device *dev = card->dev; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private; - struct device *dev = card->dev; - const struct snd_soc_acpi_link_adr *adr_link_next; - struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; - struct snd_soc_dai_link_component *codecs; - struct snd_soc_dai_link_component *cpus; - struct asoc_sdw_codec_info *codec_info; - int cpu_dai_id[ACP63_SDW_MAX_CPU_DAIS]; - int cpu_dai_num; - unsigned int group_id; - unsigned int sdw_link_id; - int codec_dlc_index = 0; - int codec_num; + struct asoc_sdw_endpoint *sof_end; + int cpu_pin_id; int stream; - int i = 0; - int j, k; int ret; - int cpu_pin_id; - - ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, adr_index); - if (ret) - return ret; - codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); - if (!codecs) - return -ENOMEM; - sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, - sizeof(*sdw_codec_ch_maps), GFP_KERNEL); - if (!sdw_codec_ch_maps) - return -ENOMEM; - - /* generate codec name on different links in the same group */ - j = adr_index; - for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && - i < cpu_dai_num; adr_link_next++) { - /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) - continue; - - /* j reset after loop, adr_index only applies to first link */ - for (k = 0 ; (j < adr_link_next->num_adr) && (k < codec_num) ; j++, k++) { - const struct snd_soc_acpi_endpoint *endpoints; - - endpoints = adr_link_next->adr_d[j].endpoints; - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; - - /* sanity check */ - if (*codec_conf >= card->codec_conf + card->num_configs) { - dev_err(dev, "codec_conf array overflowed\n"); - return -EINVAL; - } + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->name_prefix) { + (*codec_conf)->dlc.name = sof_end->codec_name; + (*codec_conf)->name_prefix = sof_end->name_prefix; + (*codec_conf)++; + } - ret = fill_sdw_codec_dlc(dev, adr_link_next, - &codecs[codec_dlc_index], - j, dai_index); + if (sof_end->include_sidecar) { + ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); if (ret) return ret; - (*codec_conf)->dlc = codecs[codec_dlc_index]; - (*codec_conf)->name_prefix = adr_link_next->adr_d[j].name_prefix; - - sdw_codec_ch_maps[codec_dlc_index].cpu = i; - sdw_codec_ch_maps[codec_dlc_index].codec = codec_dlc_index; - - codec_dlc_index++; - (*codec_conf)++; } - j = 0; - - /* check next link to create codec dai in the processed group */ - i++; } - /* find codec info to create BE DAI */ - codec_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[adr_index].adr); - if (!codec_info) - return -EINVAL; - - ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; - - sdw_link_id = (adr_link->adr_d[adr_index].adr) >> 48; for_each_pcm_streams(stream) { - char *name, *cpu_name; - int playback, capture; static const char * const sdw_stream_name[] = { "SDW%d-PIN%d-PLAYBACK", "SDW%d-PIN%d-CAPTURE", "SDW%d-PIN%d-PLAYBACK-%s", "SDW%d-PIN%d-CAPTURE-%s", }; + struct snd_soc_dai_link_ch_map *codec_maps; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + int num_cpus = hweight32(sof_dai->link_mask[stream]); + int num_codecs = sof_dai->num_devs[stream]; + int playback, capture; + int i = 0, j = 0; + char *name; - if (!codec_info->dais[dai_index].direction[stream]) + if (!sof_dai->num_devs[stream]) continue; - *be_id = codec_info->dais[dai_index].dailink[stream]; + sof_end = list_first_entry(&sof_dai->endpoints, + struct asoc_sdw_endpoint, list); + + *be_id = sof_end->dai_info->dailink[stream]; if (*be_id < 0) { dev_err(dev, "Invalid dailink id %d\n", *be_id); return -EINVAL; } + switch (amd_ctx->acp_rev) { case ACP63_PCI_REV: - ret = get_acp63_cpu_pin_id(sdw_link_id, *be_id, &cpu_pin_id, dev); + ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask - 1), + *be_id, &cpu_pin_id, dev); if (ret) return ret; break; @@ -425,55 +182,105 @@ static int create_sdw_dailink(struct snd_soc_card *card, /* create stream name according to first link id */ if (ctx->append_dai_type) { name = devm_kasprintf(dev, GFP_KERNEL, - sdw_stream_name[stream + 2], sdw_link_id, cpu_pin_id, - type_strings[codec_info->dais[dai_index].dai_type]); + sdw_stream_name[stream + 2], + ffs(sof_end->link_mask) - 1, + cpu_pin_id, + type_strings[sof_end->dai_info->dai_type]); } else { name = devm_kasprintf(dev, GFP_KERNEL, - sdw_stream_name[stream], sdw_link_id, cpu_pin_id); + sdw_stream_name[stream], + ffs(sof_end->link_mask) - 1, + cpu_pin_id); } if (!name) return -ENOMEM; - cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL); + cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); if (!cpus) return -ENOMEM; - /* - * generate CPU DAI name base on the sdw link ID and - * cpu pin id according to sdw dai driver. - */ - for (k = 0; k < cpu_dai_num; k++) { - cpu_name = devm_kasprintf(dev, GFP_KERNEL, - "SDW%d Pin%d", sdw_link_id, cpu_pin_id); - if (!cpu_name) + + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; + + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); + if (!codec_maps) + return -ENOMEM; + + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (!sof_end->dai_info->direction[stream]) + continue; + + int link_num = ffs(sof_end->link_mask) - 1; + + cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, cpu_pin_id); + dev_dbg(dev, "cpu[%d].dai_name:%s\n", i, cpus[i].dai_name); + if (!cpus[i].dai_name) return -ENOMEM; - cpus[k].dai_name = cpu_name; + codec_maps[j].cpu = i; + codec_maps[j].codec = j; + + codecs[j].name = sof_end->codec_name; + codecs[j].dai_name = sof_end->dai_info->dai_name; + j++; } + WARN_ON(j != num_codecs); + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, - playback, capture, - cpus, cpu_dai_num, - platform_component, ARRAY_SIZE(platform_component), - codecs, codec_num, + + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, platform_component, + ARRAY_SIZE(platform_component), codecs, num_codecs, asoc_sdw_rtd_init, &sdw_ops); + /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations * based on wait_for_completion(), tag them as 'nonatomic'. */ (*dai_links)->nonatomic = true; - (*dai_links)->ch_maps = sdw_codec_ch_maps; + (*dai_links)->ch_maps = codec_maps; - ret = set_codec_init_func(card, adr_link, *dai_links, - playback, group_id, adr_index, dai_index); - if (ret < 0) { - dev_err(dev, "failed to init codec 0x%x\n", codec_info->part_id); - return ret; + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->dai_info->init) + sof_end->dai_info->init(card, *dai_links, + sof_end->codec_info, + playback); } (*dai_links)++; } + + return 0; +} + +static int create_sdw_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_dailink *sof_dais, + struct snd_soc_codec_conf **codec_conf) +{ + int ret; + + /* generate DAI links by each sdw link */ + while (sof_dais->initialised) { + int current_be_id; + + ret = create_sdw_dailink(card, sof_dais, dai_links, + ¤t_be_id, codec_conf); + if (ret) + return ret; + + /* Update the be_id to match the highest ID used for SDW link */ + if (*be_id < current_be_id) + *be_id = current_be_id; + + sof_dais++; + } + return 0; } @@ -504,132 +311,93 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int sdw_be_num = 0, dmic_num = 0; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; struct snd_soc_codec_conf *codec_conf; - int codec_conf_num = 0; - bool group_generated[AMD_SDW_MAX_GROUPS] = { }; + struct asoc_sdw_endpoint *sof_ends; + struct asoc_sdw_dailink *sof_dais; struct snd_soc_dai_link *dai_links; - struct asoc_sdw_codec_info *codec_info; + int num_devs = 0; + int num_ends = 0; int num_links; - int i, j, be_id = 0; + int be_id = 0; int ret; - ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d\n", ret); + dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + /* One per DAI link, worst case is a DAI link for every endpoint */ + sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL); + if (!sof_dais) + return -ENOMEM; + + /* One per endpoint, ie. each DAI on each codec/amp */ + sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); + if (!sof_ends) { + ret = -ENOMEM; + goto err_dai; + } + + ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + if (ret < 0) + goto err_end; + + sdw_be_num = ret; + /* enable dmic */ if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num) dmic_num = 1; dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); + codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + if (!codec_conf) { + ret = -ENOMEM; + goto err_end; + } + /* allocate BE dailinks */ num_links = sdw_be_num + dmic_num; dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); - if (!dai_links) - return -ENOMEM; - - /* allocate codec conf, will be populated when dailinks are created */ - codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), - GFP_KERNEL); - if (!codec_conf) - return -ENOMEM; + if (!dai_links) { + ret = -ENOMEM; + goto err_end; + } + card->codec_conf = codec_conf; + card->num_configs = num_devs; card->dai_link = dai_links; card->num_links = num_links; - card->codec_conf = codec_conf; - card->num_configs = codec_conf_num; /* SDW */ - if (!sdw_be_num) - goto DMIC; - - for (; adr_link->num_adr; adr_link++) { - /* - * If there are two or more different devices on the same sdw link, we have to - * append the codec type to the dai link name to prevent duplicated dai link name. - * The same type devices on the same sdw link will be in the same - * snd_soc_acpi_adr_device array. They won't be described in different adr_links. - */ - for (i = 0; i < adr_link->num_adr; i++) { - /* find codec info to get dai_num */ - codec_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[i].adr); - if (!codec_info) - return -EINVAL; - if (codec_info->dai_num > 1) { - ctx->append_dai_type = true; - goto out; - } - for (j = 0; j < i; j++) { - if ((SDW_PART_ID(adr_link->adr_d[i].adr) != - SDW_PART_ID(adr_link->adr_d[j].adr)) || - (SDW_MFG_ID(adr_link->adr_d[i].adr) != - SDW_MFG_ID(adr_link->adr_d[j].adr))) { - ctx->append_dai_type = true; - goto out; - } - } - } - } -out: - - /* generate DAI links by each sdw link */ - for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) { - for (i = 0; i < adr_link->num_adr; i++) { - const struct snd_soc_acpi_endpoint *endpoint; - - endpoint = adr_link->adr_d[i].endpoints; - - /* this group has been generated */ - if (endpoint->aggregated && - group_generated[endpoint->group_id]) - continue; - - /* find codec info to get dai_num */ - codec_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[i].adr); - if (!codec_info) - return -EINVAL; - - for (j = 0; j < codec_info->dai_num ; j++) { - int current_be_id; - - ret = create_sdw_dailink(card, &dai_links, adr_link, - &codec_conf, ¤t_be_id, - i, j); - if (ret < 0) { - dev_err(dev, - "failed to create dai link %d on 0x%x\n", - j, codec_info->part_id); - return ret; - } - /* Update the be_id to match the highest ID used for SDW link */ - if (be_id < current_be_id) - be_id = current_be_id; - } - - if (endpoint->aggregated) - group_generated[endpoint->group_id] = true; - } + if (sdw_be_num) { + ret = create_sdw_dailinks(card, &dai_links, &be_id, + sof_dais, &codec_conf); + if (ret) + goto err_end; } -DMIC: /* dmic */ if (dmic_num > 0) { if (ctx->ignore_internal_dmic) { dev_warn(dev, "Ignoring ACP DMIC\n"); } else { - be_id = SOC_SDW_DMIC_DAI_ID; ret = create_dmic_dailinks(card, &dai_links, &be_id); if (ret) - return ret; + goto err_end; } } + WARN_ON(codec_conf != card->codec_conf + card->num_configs); WARN_ON(dai_links != card->dai_link + card->num_links); - return 0; + +err_end: + kfree(sof_ends); +err_dai: + kfree(sof_dais); + + return ret; } /* SoC card */