On Tue, Feb 23, 2016 at 10:51:14AM +0000, Liam Girdwood wrote: > On Tue, 2016-02-16 at 21:47 +0530, Jeeja KP wrote: > > We have no mechanism to configure hw_params for DAIs which are hostless. > > Like a loop or DAIs connected to internal sinks/sources. > > > > Fwiw, a few years back Peter, Sebastien and I were considering a similar > mechanism for the ABE on OMAP4. We never got around to implementing or > upstreaming though.... Okay great then :-) > > One comment below. > > > Problem Statement: > > During a BE-BE loop of DSP or a SRC->SINK path, we cannot program > > hw_params. There are no hw_params from user as these are hostless. > > This scenario can happens in below 2 cases: > > > > Case 1: BE-BE loop aka hostless stream through SoC DSP > > Hostless stream can be defined by BE to BE connection and in this case > > the path is enabled or disabled by the state of the DAPM graph. This > > usually means there is a mixer control that can be used to connect or > > disconnect the path between both DAIs. > > Example: > > |--------------/----------------| > > | | > > | | > > codec out modem_in > > | | > > | | > > ssp0_TX ssp1_RX > > | | > > | | > > AIFI_Playback dummy_capture > > > > In the above case (SSP0,codec playback,SSp1 dai needs to be configured > > and turned on with the selected hw_params). > > > > Case 2: SoC Internal Sink or Source > > Example: > > WOV SINK (DAPM Sink) > > | > > | > > | > > Switch > > | > > | > > w1 > > | > > dmic rx (BE dai widget) > > | > > Capture(codec dai widget) > > | > > DMIC AIF > > | > > DMic > > | > > Soc DMic (MIC Widget) (SRC) > > > > In the above case BE (dmic RX) dai hw_params needs to applied. > > > > Approach: > > 1. Allow params to be defined for other BE dai link also. this > > currently applicable only for codec_codec link. > > > > 2. when params is defined for BE dai link, create params kcontrols > > and associate it with the dai widgets. this will allow params to be > > selected via Kcontrol for each dai defined in the dai link. > > > > The only problem we have with using a kcontrol to define params is that > we already have an existing kernel ioctl and public C API to define > SW/HW params. This would add another mechanism, unless each new kcontrol > allows modification of a single param ? Today c-c links specify this the PCM parameters thru these controls so we took the same approach. If we decide that we should have more granular control we can update this part :) Moreover in driver we do sepcify constraints on the user for selecting PCM params. This is our way of specifying constrained values to users :D -- ~Vinod > > 3. Before powering on the dai widget and if the dai is not powered > > with the stream event, then dai_ops(hw_params) for the dai widget will > > be called.This will apply the selected hw_params. > > > > 4. with the above, fix_up can be removed and can use .params to > > select the parameter. > > > > Core Changes: > > 1. params definition needs to changed, currently this is defined to used > > only for codec codec link. define new flag to identifying codec > > codec link. > > > > 2. if params is defined for any BE dai link, then create kcontrol for > > each dai defined in the dai_link and associated the kcontrol to dai > > widget. > > > > 3. In the powering sequence check if the dai widget and if the event is > > not a stream event, SND_SOC_DAPM_STREAM_NOP , then call dai ops with > > the selected params. This will apply the hw_params for dai. > > > > 1. params definition: > > - Add new flag in struct snd_soc_dai_link. > > - Based on this flag create, the codec codec link instead of > > params > > struct snd_soc_dai_link { > > const struct snd_soc_pcm_stream *params; > > unsigned int num_params; > > > > + /* flag to create codec codec based on the flag*/ > > + unsigned int codec_link:1; > > + > > unsigned int dai_fmt; /* format to set on init */ > > > > enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */ > > > > - creation of dai link based on the codec_link flag > > static int soc_probe_link_dais(struct snd_soc_card *card, > > int num, int order) > > } > > } else { > > > > - if (!dai_link->params) { > > + if (!dai_link->codec_link) { > > /* create the pcm */ > > ret = soc_new_pcm(rtd, num); > > if (ret < 0) { > > > > 2. when params is defined for BE dai link, create params kcontrols and > > associate it with the dai widgets. this will allow params to be selected > > via Kcontrol for each dai defined in the dai link. > > a. Move the param control creation from snd_soc_dapm_new_pcm and add new > > API to created kcontrols with the params. > > +snd_soc_dapm_create_param_control(struct snd_soc_card *card, > > + const struct snd_soc_pcm_stream *params, > > + unsigned int num_params) > > { > > /* create kcontrol based on the params */ > > } > > > > - modify the snd_soc_dapm_new_pcm to create the param control > > int snd_soc_dapm_new_pcm(struct snd_soc_card *card, > > const struct snd_soc_pcm_stream *params, > > unsigned int num_params, > > struct snd_soc_dapm_widget *source, > > struct snd_soc_dapm_widget *sink) > > { > > > > template.kcontrol_news = snd_soc_dapm_create_param_control(card, > > params, num_params); > > if (!template.kcontrol_news) { > > dev_err(card->dev, "ASoC: Failed to create control for %s widget\n", > > link_name); > > ret = -ENOMEM; > > - goto outfree_private_value; > > + goto outfree_link_name; > > } > > > > > > b. add new API snd_soc_dapm_new_dai_params() to create kcontrol for dai and associated it to dai. > > +int snd_soc_dapm_new_dai_params(struct snd_soc_card *card, > > + const struct snd_soc_pcm_stream *params, > > + unsigned int num_params, > > + struct snd_soc_dapm_widget *dai_w) > > +{ > > + struct snd_kcontrol_new *kcontrol_news; > > + > > + kcontrol_news = snd_soc_dapm_create_param_control(card, params, > > + num_params); > > + if (!kcontrol_news) { > > + dev_err(card->dev, "ASoC: Failed to create control for %s widget\n", > > + dai_w->name); > > + return -EINVAL; > > + } > > + > > + dai_w->num_kcontrols = 1; > > + dai_w->kcontrol_news = kcontrol_news; > > + > > + dai_w->params = params; > > + dai_w->num_params = num_params; > > + > > + return 0; > > + > > +} > > + > > +++ b/include/sound/soc-dapm.h > > +int snd_soc_dapm_new_dai_params(struct snd_soc_card *card, > > + const struct snd_soc_pcm_stream *params, > > + unsigned int num_params, > > + struct snd_soc_dapm_widget *dai_w); > > > > > > c. if the be dai link has .params defined, call new API snd_soc_dapm_new_dai_params > > > > +static int soc_link_be_params_widget(struct snd_soc_card *card, > > + struct snd_soc_dai *dai, > > + const struct snd_soc_pcm_stream *params, > > + unsigned int num_params) > > +{ > > + int ret; > > + struct snd_soc_dapm_widget *w; > > + > > + if (!strcmp(dai->name, "snd-soc-dummy")) > > + return 0; > > + > > + if (dai->playback_widget) { > > + w = dai->playback_widget; > > + ret = snd_soc_dapm_new_dai_params(card, params, > > + num_params, w); > > + > > + if (ret != 0) { > > + dev_err(card->dev, > > + "ASoC: Can't create params widget=%s %d\n", > > + w->name, ret); > > + return ret; > > + } > > + } > > + > > + if (dai->capture_widget) { > > + w = dai->capture_widget; > > + ret = snd_soc_dapm_new_dai_params(card, params, > > + num_params, w); > > + > > + if (ret != 0) { > > + dev_err(card->dev, > > + "ASoC: Can't create params widget=%s %d\n", > > + w->name, ret); > > + return ret; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int soc_link_be_params_dai_widgets(struct snd_soc_card *card, > > + struct snd_soc_dai_link *dai_link, > > + struct snd_soc_pcm_runtime *rtd) > > +{ > > + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; > > + int ret, i; > > + > > + for (i = 0; i < rtd->num_codecs; i++) { > > + struct snd_soc_dai *codec = rtd->codec_dais[i]; > > + > > + ret = soc_link_be_params_widget(card, codec, > > + dai_link->params, > > + dai_link->num_params); > > + > > + if (!ret) > > + return ret; > > + } > > + > > + return soc_link_be_params_widget(card, cpu_dai, dai_link->params, > > + dai_link->num_params); > > +} > > + > > > > @@ -1651,6 +1714,13 @@ static int soc_probe_link_dais(struct snd_soc_card *card, > > dai_link->stream_name, ret); > > return ret; > > } > > + if (dai_link->params && dai_link->no_pcm) { > > + /* create dai link controls */ > > + ret = soc_link_be_params_dai_widgets(card, > > + dai_link, rtd); > > + if (ret) > > + return ret; > > + } > > } else { > > INIT_DELAYED_WORK(&rtd->delayed_work, > > codec2codec_close_delayed_work); > > > > > > 3. Applying the hw_params for dai widget > > > > --- a/sound/soc/soc-dapm.c > > +++ b/sound/soc/soc-dapm.c > > @@ -1398,9 +1398,64 @@ static void dapm_seq_check_event(struct snd_soc_card * > > card, > > } > > } > > > > +static int snd_soc_dai_params(struct snd_soc_dapm_widget *w, int event) > > +{ > > + struct snd_soc_dai *dai; > > + const struct snd_soc_pcm_stream *config = w->params + w->params_select; > > + struct snd_pcm_substream substream; > > + struct snd_pcm_hw_params *params = NULL; > > + u64 fmt; > > + int ret = 0; > > + > > + if (WARN_ON(!config)) > > + return -EINVAL; > > + > > + dai = w->priv; > > + > > + if (config->formats) { > > + fmt = ffs(config->formats) - 1; > > + } else { > > + dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", > > + config->formats); > > + fmt = 0; > > + } > > + > > + /* Currently very limited parameter selection */ > > + params = kzalloc(sizeof(*params), GFP_KERNEL); > > + if (!params) { > > + ret = -ENOMEM; > > + goto out; > > + } > > + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); > > + > > + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = > > + config->rate_min; > > + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = > > + config->rate_max; > > + > > + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min > > + = config->channels_min; > > + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max > > + = config->channels_max; > > + > > + memset(&substream, 0, sizeof(substream)); > > + if (w->id == snd_soc_dapm_dai_in) > > + substream.stream = SNDRV_PCM_STREAM_CAPTURE; > > + else > > + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; > > + > > + ret = soc_dai_hw_params(&substream, params, dai); > > + if (ret < 0) > > + goto out; > > +out: > > + kfree(params); > > + return ret; > > +} > > + > > /* Apply the coalesced changes from a DAPM sequence */ > > static void dapm_seq_run_coalesced(struct snd_soc_card *card, > > - struct list_head *pending) > > + struct list_head *pending, > > + int event) > > { > > struct snd_soc_dapm_context *dapm; > > struct snd_soc_dapm_widget *w; > > @@ -1413,6 +1468,14 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, > > dapm = w->dapm; > > > > list_for_each_entry(w, pending, power_list) { > > + if ((event == SND_SOC_DAPM_STREAM_NOP) && > > + ((w->id == snd_soc_dapm_dai_out) || > > + (w->id == snd_soc_dapm_dai_in))) { > > + snd_soc_dai_params(w, SND_SOC_DAPM_PRE_PMU); > > + } > > + } > > + > > + list_for_each_entry(w, pending, power_list) { > > WARN_ON(reg != w->reg || dapm != w->dapm); > > w->power = w->new_power; > > > > @@ -1447,6 +1510,13 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, > > dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU); > > dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD); > > } > > + list_for_each_entry(w, pending, power_list) { > > + if ((event == SND_SOC_DAPM_STREAM_NOP) && > > + ((w->id == snd_soc_dapm_dai_out) || > > + (w->id == snd_soc_dapm_dai_in))) { > > + snd_soc_dai_params(w, SND_SOC_DAPM_POST_PMD); > > + } > > + } > > } > > > > /* Apply a DAPM power sequence. > > @@ -1482,7 +1552,7 @@ static void dapm_seq_run(struct snd_soc_card *card, > > if (sort[w->id] != cur_sort || w->reg != cur_reg || > > w->dapm != cur_dapm || w->subseq != cur_subseq) { > > if (!list_empty(&pending)) > > - dapm_seq_run_coalesced(card, &pending); > > + dapm_seq_run_coalesced(card, &pending, event); > > > > if (cur_dapm && cur_dapm->seq_notifier) { > > for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) > > @@ -1545,7 +1615,7 @@ static void dapm_seq_run(struct snd_soc_card *card, > > } > > > > if (!list_empty(&pending)) > > - dapm_seq_run_coalesced(card, &pending); > > + dapm_seq_run_coalesced(card, &pending, event); > > > > if (cur_dapm && cur_dapm->seq_notifier) { > > for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) > > -- > > 1.7.9.5 > > > > Comments welcome, based on discussion we will send patches. > > > > --Jeeja > > -- ~Vinod _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel