Commit 5f14d70b authored by Charles Keepax's avatar Charles Keepax Committed by Mark Brown

ASoC: Intel: sof_sdw: Move generation of DAI links to new parsing

The only part left using the old parsing code is now the generation of
the actual DAI links. Move this generation over to being based on the
new parsing, which allows the removal of the last of the old parsing
code.

The new DAI link generation is a simple matter of creating a new DAI
link for each sof_sdw_dailink struct, and adding a cpu, a codec, and
a mapping for each sof_sdw_endpoint contained in that sof_sdw_dailink.
Note that the CPUs can be inferred as the endpoint list is iterated,
because the endpoints were added into the list sorted by link.
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://msgid.link/r/20240326160429.13560-23-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 13e698e8
...@@ -1234,129 +1234,6 @@ static const char *get_codec_name(struct device *dev, ...@@ -1234,129 +1234,6 @@ static const char *get_codec_name(struct device *dev,
return NULL; return NULL;
} }
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 sof_sdw_codec_info *codec_info;
codec_info = find_codec_info_part(adr);
if (!codec_info)
return -EINVAL;
codec->name = 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;
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 sof_sdw_codec_info *codec_info;
codec_info = 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,
adr_link,
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 = 0
* one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs
*
* multiple links with multiple slaves with aggregated = 1
* one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N 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 >= 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 sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct sof_sdw_codec_info *codec_info; struct sof_sdw_codec_info *codec_info;
...@@ -1563,135 +1440,102 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, ...@@ -1563,135 +1440,102 @@ static int parse_sdw_endpoints(struct snd_soc_card *card,
} }
static int create_sdw_dailink(struct snd_soc_card *card, static int create_sdw_dailink(struct snd_soc_card *card,
struct sof_sdw_dailink *sof_dai,
struct snd_soc_dai_link **dai_links, struct snd_soc_dai_link **dai_links,
const struct snd_soc_acpi_link_adr *adr_link, int *be_id)
int *be_id, int adr_index, int dai_index)
{ {
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct device *dev = card->dev; struct device *dev = card->dev;
const struct snd_soc_acpi_link_adr *adr_link_next; struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; struct sof_sdw_endpoint *sof_end;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *cpus;
struct sof_sdw_codec_info *codec_info;
int cpu_dai_id[SDW_MAX_CPU_DAIS];
int cpu_dai_num;
unsigned int group_id;
int codec_dlc_index = 0;
int codec_num;
int stream; int stream;
int i = 0;
int j, k;
int ret;
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 (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) {
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;
ret = fill_sdw_codec_dlc(dev, adr_link_next,
&codecs[codec_dlc_index],
j, dai_index);
if (ret)
return ret;
sdw_codec_ch_maps[codec_dlc_index].cpu = i;
sdw_codec_ch_maps[codec_dlc_index].codec = codec_dlc_index;
codec_dlc_index++;
}
j = 0;
/* check next link to create codec dai in the processed group */
i++;
}
/* find codec info to create BE DAI */
codec_info = find_codec_info_part(adr_link->adr_d[adr_index].adr);
if (!codec_info)
return -EINVAL;
for_each_pcm_streams(stream) { for_each_pcm_streams(stream) {
char *name, *cpu_name;
int playback, capture;
static const char * const sdw_stream_name[] = { static const char * const sdw_stream_name[] = {
"SDW%d-Playback", "SDW%d-Playback",
"SDW%d-Capture", "SDW%d-Capture",
"SDW%d-Playback-%s", "SDW%d-Playback-%s",
"SDW%d-Capture-%s", "SDW%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 cur_link = 0;
int i = 0, j = 0;
char *name;
if (!codec_info->dais[dai_index].direction[stream]) if (!sof_dai->num_devs[stream])
continue; continue;
*be_id = codec_info->dais[dai_index].dailink[stream]; sof_end = list_first_entry(&sof_dai->endpoints,
struct sof_sdw_endpoint, list);
*be_id = sof_end->dai_info->dailink[stream];
if (*be_id < 0) { if (*be_id < 0) {
dev_err(dev, "Invalid dailink id %d\n", *be_id); dev_err(dev, "Invalid dailink id %d\n", *be_id);
return -EINVAL; return -EINVAL;
} }
/* create stream name according to first link id */ /* create stream name according to first link id */
if (ctx->append_dai_type) { if (ctx->append_dai_type)
name = devm_kasprintf(dev, GFP_KERNEL, name = devm_kasprintf(dev, GFP_KERNEL,
sdw_stream_name[stream + 2], cpu_dai_id[0], sdw_stream_name[stream + 2],
type_strings[codec_info->dais[dai_index].dai_type]); ffs(sof_end->link_mask) - 1,
} else { type_strings[sof_end->dai_info->dai_type]);
else
name = devm_kasprintf(dev, GFP_KERNEL, name = devm_kasprintf(dev, GFP_KERNEL,
sdw_stream_name[stream], cpu_dai_id[0]); sdw_stream_name[stream],
} ffs(sof_end->link_mask) - 1);
if (!name) if (!name)
return -ENOMEM; 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) if (!cpus)
return -ENOMEM; return -ENOMEM;
/* codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
* generate CPU DAI name base on the sdw link ID and if (!codecs)
* PIN ID with offset of 2 according to sdw dai driver. return -ENOMEM;
*/
for (k = 0; k < cpu_dai_num; k++) { codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
cpu_name = devm_kasprintf(dev, GFP_KERNEL, if (!codec_maps)
"SDW%d Pin%d", cpu_dai_id[k], return -ENOMEM;
ctx->sdw_pin_index[cpu_dai_id[k]]++);
if (!cpu_name) list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
return -ENOMEM; if (!sof_end->dai_info->direction[stream])
continue;
if (cur_link != sof_end->link_mask) {
int link_num = ffs(sof_end->link_mask) - 1;
int pin_num = ctx->sdw_pin_index[link_num]++;
cur_link = sof_end->link_mask;
cpus[k].dai_name = cpu_name; cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SDW%d Pin%d",
link_num, pin_num);
if (!cpus[i].dai_name)
return -ENOMEM;
i++;
}
codec_maps[j].cpu = i - 1;
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(i != num_cpus || j != num_codecs);
playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
capture = (stream == SNDRV_PCM_STREAM_CAPTURE); capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
init_dai_link(dev, *dai_links, be_id, name, playback, capture, init_dai_link(dev, *dai_links, be_id, name, playback, capture,
cpus, cpu_dai_num, codecs, codec_num, cpus, num_cpus, codecs, num_codecs,
sof_sdw_rtd_init, &sdw_ops); sof_sdw_rtd_init, &sdw_ops);
/* /*
...@@ -1699,13 +1543,14 @@ static int create_sdw_dailink(struct snd_soc_card *card, ...@@ -1699,13 +1543,14 @@ static int create_sdw_dailink(struct snd_soc_card *card,
* based on wait_for_completion(), tag them as 'nonatomic'. * based on wait_for_completion(), tag them as 'nonatomic'.
*/ */
(*dai_links)->nonatomic = true; (*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, list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
playback, group_id, adr_index, dai_index); if (sof_end->dai_info->init)
if (ret < 0) { sof_end->dai_info->init(card, sof_end->adr_link,
dev_err(dev, "failed to init codec 0x%x\n", codec_info->part_id); *dai_links,
return ret; sof_end->codec_info,
playback);
} }
(*dai_links)++; (*dai_links)++;
...@@ -1839,18 +1684,15 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) ...@@ -1839,18 +1684,15 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 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; struct snd_soc_codec_conf *codec_conf;
struct sof_sdw_codec_info *codec_info;
struct sof_sdw_codec_info *ssp_info; struct sof_sdw_codec_info *ssp_info;
struct sof_sdw_endpoint *sof_ends; struct sof_sdw_endpoint *sof_ends;
struct sof_sdw_dailink *sof_dais; struct sof_sdw_dailink *sof_dais;
int num_devs = 0; int num_devs = 0;
int num_ends = 0; int num_ends = 0;
bool group_generated[SDW_MAX_GROUPS] = { };
struct snd_soc_dai_link *dai_links; struct snd_soc_dai_link *dai_links;
int num_links; int num_links;
int i, j, be_id = 0; int i, be_id = 0;
int hdmi_num; int hdmi_num;
unsigned long ssp_mask; unsigned long ssp_mask;
int ret; int ret;
...@@ -1939,44 +1781,18 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) ...@@ -1939,44 +1781,18 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
/* generate DAI links by each sdw link */ /* generate DAI links by each sdw link */
for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) { while (sof_dais->initialised) {
for (i = 0; i < adr_link->num_adr; i++) { int current_be_id;
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 = find_codec_info_part(adr_link->adr_d[i].adr);
if (!codec_info) {
ret = -EINVAL;
goto err_end;
}
for (j = 0; j < codec_info->dai_num ; j++) { ret = create_sdw_dailink(card, sof_dais, &dai_links, &current_be_id);
int current_be_id; if (ret)
goto err_end;
ret = create_sdw_dailink(card, &dai_links, adr_link,
&current_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 */ /* Update the be_id to match the highest ID used for SDW link */
if (be_id < current_be_id) if (be_id < current_be_id)
be_id = current_be_id; be_id = current_be_id;
}
if (endpoint->aggregated) sof_dais++;
group_generated[endpoint->group_id] = true;
}
} }
SSP: SSP:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment