Skip to content

Commit

Permalink
ASoC: Intel: avs: Constrain path based on BE capabilities
Browse files Browse the repository at this point in the history
For i2s and DMIC copiers constraint stream capabilities based on
available NHLT configuration. This allows topology to provide generic
configuration that handles more hardware, while filtering unavailable
ones at runtime.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Link: https://patch.msgid.link/20250407130851.1726800-1-amadeuszx.slawinski@linux.intel.com
Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Amadeusz Sławiński authored and Mark Brown committed Apr 7, 2025
1 parent 95f723c commit f2f8474
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
72 changes: 72 additions & 0 deletions sound/soc/intel/avs/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,78 @@ avs_path_find_variant(struct avs_dev *adev,
return NULL;
}

static struct acpi_nhlt_config *
avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t);

int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template,
struct snd_pcm_hw_constraint_list *rate_list,
struct snd_pcm_hw_constraint_list *channels_list,
struct snd_pcm_hw_constraint_list *sample_bits_list)
{
struct avs_tplg_path *path_template;
unsigned int *rlist, *clist, *slist;
size_t i;

i = 0;
list_for_each_entry(path_template, &template->path_list, node)
i++;

rlist = kcalloc(i, sizeof(rlist), GFP_KERNEL);
clist = kcalloc(i, sizeof(clist), GFP_KERNEL);
slist = kcalloc(i, sizeof(slist), GFP_KERNEL);

i = 0;
list_for_each_entry(path_template, &template->path_list, node) {
struct avs_tplg_pipeline *pipeline_template;

list_for_each_entry(pipeline_template, &path_template->ppl_list, node) {
struct avs_tplg_module *module_template;

list_for_each_entry(module_template, &pipeline_template->mod_list, node) {
const guid_t *type = &module_template->cfg_ext->type;
struct acpi_nhlt_config *blob;

if (!guid_equal(type, &AVS_COPIER_MOD_UUID) &&
!guid_equal(type, &AVS_WOVHOSTM_MOD_UUID))
continue;

switch (module_template->cfg_ext->copier.dma_type) {
case AVS_DMA_DMIC_LINK_INPUT:
case AVS_DMA_I2S_LINK_OUTPUT:
case AVS_DMA_I2S_LINK_INPUT:
break;
default:
continue;
}

blob = avs_nhlt_config_or_default(adev, module_template);
if (IS_ERR(blob))
continue;

rlist[i] = path_template->fe_fmt->sampling_freq;
clist[i] = path_template->fe_fmt->num_channels;
slist[i] = path_template->fe_fmt->bit_depth;
i++;
}
}
}

if (i) {
rate_list->count = i;
rate_list->list = rlist;
channels_list->count = i;
channels_list->list = clist;
sample_bits_list->count = i;
sample_bits_list->list = slist;
} else {
kfree(rlist);
kfree(clist);
kfree(slist);
}

return i;
}

static void avs_init_node_id(union avs_connector_node_id *node_id,
struct avs_tplg_modcfg_ext *te, u32 dma_id)
{
Expand Down
5 changes: 5 additions & 0 deletions sound/soc/intel/avs/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ int avs_path_reset(struct avs_path *path);
int avs_path_pause(struct avs_path *path);
int avs_path_run(struct avs_path *path, int trigger);

int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template,
struct snd_pcm_hw_constraint_list *rate_list,
struct snd_pcm_hw_constraint_list *channels_list,
struct snd_pcm_hw_constraint_list *sample_bits_list);

int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
struct soc_mixer_control *mc, long *input);
int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
Expand Down
49 changes: 48 additions & 1 deletion sound/soc/intel/avs/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ struct avs_dma_data {
struct hdac_ext_stream *host_stream;
};

struct snd_pcm_hw_constraint_list rate_list;
struct snd_pcm_hw_constraint_list channels_list;
struct snd_pcm_hw_constraint_list sample_bits_list;

struct work_struct period_elapsed_work;
struct snd_pcm_substream *substream;
};
Expand Down Expand Up @@ -74,6 +78,45 @@ void avs_period_elapsed(struct snd_pcm_substream *substream)
schedule_work(&data->period_elapsed_work);
}

static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule);
static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hw_constraint_list *r, *c, *s;
struct avs_tplg_path_template *template;
struct avs_dma_data *data;
int ret;

ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
return ret;

data = snd_soc_dai_get_dma_data(dai, substream);
r = &(data->rate_list);
c = &(data->channels_list);
s = &(data->sample_bits_list);

template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream);
ret = avs_path_set_constraint(data->adev, template, r, c, s);
if (ret <= 0)
return ret;

ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, r);
if (ret < 0)
return ret;

ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, c);
if (ret < 0)
return ret;

ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, s);
if (ret < 0)
return ret;

return 0;
}

static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
Expand Down Expand Up @@ -101,7 +144,7 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
if (rtd->dai_link->ignore_suspend)
adev->num_lp_paths++;

return 0;
return avs_hw_constraints_init(substream, dai);
}

static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
Expand All @@ -114,6 +157,10 @@ static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc
if (rtd->dai_link->ignore_suspend)
data->adev->num_lp_paths--;

kfree(data->rate_list.list);
kfree(data->channels_list.list);
kfree(data->sample_bits_list.list);

snd_soc_dai_set_dma_data(dai, substream, NULL);
kfree(data);
}
Expand Down

0 comments on commit f2f8474

Please sign in to comment.