Message ID | 20250407130851.1726800-1-amadeuszx.slawinski@linux.intel.com (mailing list archive) |
---|---|
State | Accepted |
Commit | f2f847461fb7620e299be873cdd9437ddecd2266 |
Headers | show |
Series | ASoC: Intel: avs: Constrain path based on BE capabilities | expand |
On 2025-04-07 3:08 PM, Amadeusz Sławiński wrote: > 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> A number of iterations reviewed by me in our linux.avs mainline. Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com> > --- > sound/soc/intel/avs/path.c | 72 ++++++++++++++++++++++++++++++++++++++ > sound/soc/intel/avs/path.h | 5 +++ > sound/soc/intel/avs/pcm.c | 49 +++++++++++++++++++++++++- > 3 files changed, 125 insertions(+), 1 deletion(-) > > diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c > index ef0c1d125d66b..cafb8c6198bed 100644 > --- a/sound/soc/intel/avs/path.c > +++ b/sound/soc/intel/avs/path.c > @@ -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) > { > diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h > index 7ed7e94e0a566..c65ed84aa8530 100644 > --- a/sound/soc/intel/avs/path.h > +++ b/sound/soc/intel/avs/path.h > @@ -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, > diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c > index dac463390da13..b57db62d1b364 100644 > --- a/sound/soc/intel/avs/pcm.c > +++ b/sound/soc/intel/avs/pcm.c > @@ -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; > }; > @@ -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); > @@ -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) > @@ -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); > } > > base-commit: 3a0f0a4355df0240485ed62b6bd6afa5b3e689c5
On Mon, 07 Apr 2025 15:08:51 +0200, Amadeusz Sławiński wrote: > 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. > > Applied to https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next Thanks! [1/1] ASoC: Intel: avs: Constrain path based on BE capabilities commit: f2f847461fb7620e299be873cdd9437ddecd2266 All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted. You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed. If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced. Please add any relevant lists and maintainers to the CCs when replying to this mail. Thanks, Mark
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index ef0c1d125d66b..cafb8c6198bed 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -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) { diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h index 7ed7e94e0a566..c65ed84aa8530 100644 --- a/sound/soc/intel/avs/path.h +++ b/sound/soc/intel/avs/path.h @@ -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, diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index dac463390da13..b57db62d1b364 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -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; }; @@ -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); @@ -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) @@ -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); }
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> --- sound/soc/intel/avs/path.c | 72 ++++++++++++++++++++++++++++++++++++++ sound/soc/intel/avs/path.h | 5 +++ sound/soc/intel/avs/pcm.c | 49 +++++++++++++++++++++++++- 3 files changed, 125 insertions(+), 1 deletion(-) base-commit: 3a0f0a4355df0240485ed62b6bd6afa5b3e689c5