diff mbox

[4/9] ASoC: Intel: Skylake: Add FE and BE hw_params handling

Message ID 1438976184-6160-5-git-send-email-subhransu.s.prusty@intel.com
State New, archived
Headers show

Commit Message

Subhransu S. Prusty Aug. 7, 2015, 7:36 p.m. UTC
From: Jeeja KP <jeeja.kp@intel.com>

For FE and BE, the PCM parameters come from FE and BE hw_params values
passed. For a FE we convert the FE params to DSP expected module format
and pass to DSP. For a BE we need to find the gateway settings (i2s/PDM)
to be applied. These are queried from NHLT table and applied.

Further for BE based on direction the settings are applied as either source
or destination parameters.

These helpers here allow the format to be calculated and queried as per
firmware format.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
---
 sound/soc/intel/skylake/skl-topology.c | 274 +++++++++++++++++++++++++++++++++
 sound/soc/intel/skylake/skl-topology.h |  11 ++
 2 files changed, 285 insertions(+)

Comments

Mark Brown Aug. 14, 2015, 9:53 p.m. UTC | #1
On Sat, Aug 08, 2015 at 01:06:19AM +0530, Subhransu S. Prusty wrote:

> +	/*
> +	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit container so
> +	 * update bit depth accordingly
> +	 */
> +	if (format->valid_bit_depth == SKL_DEPTH_16BIT)
> +		format->bit_depth = format->valid_bit_depth;
> +	else if (format->valid_bit_depth == SKL_DEPTH_24BIT)
> +		format->bit_depth = SKL_DEPTH_32BIT;
> +

What if the depth is neither 16 bit nor 24 bit?  Shouldn't this just be
a simple override for the 24 bit case?

> +/*
> + * Fill the BE gateway parameters
> + * The BE gateway expects a blob of parameters which are kept in the ACPI
> + * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
> + * The port cna have multiple settings so pick based on the PCM
> + * parameters
> + */
> +static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
> +		struct skl_module_cfg *mconfig, struct skl_pipe_params *params)
> +{
> +	struct skl_pipe *pipe = mconfig->pipe;
> +	struct nhlt_specific_cfg *cfg;
> +	struct skl *skl = get_skl_ctx(dai->dev);
> +	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
> +
> +	memcpy(pipe->p_params, params, sizeof(*params));
> +
> +	/* update the blob based on virtual bus_id*/
> +	cfg = (struct nhlt_specific_cfg *) skl_get_ep_blob(skl,
> +			mconfig->vbus_id, link_type, params->s_fmt,
> +			params->ch, params->s_freq, params->stream);

I don't seem to have slk_get_ep_blob() but hopefully it's returning a
void * in which case why do we need to cast it?  In any case it needs to
be defined in mainline before this can be applied :(

> +	if (cfg) {
> +		mconfig->formats_config.caps_size = cfg->size;
> +		memcpy(mconfig->formats_config.caps, &cfg->caps, cfg->size);
> +	} else {
> +		dev_dbg(dai->dev, "Blob is NULL");
> +		return -EINVAL;
> +	}

This seems like a more serious problem than something we just dev_dbg()
about?

> +static int skl_tplg_be_set_params(struct snd_soc_dai *dai,
> +					struct snd_soc_dapm_widget *w,
> +					struct skl_pipe_params *params)
> +{
> +	if (!w->power) {
> +		dev_dbg(dai->dev, "set params for widget=%s\n", w->name);
> +		return skl_tplg_be_fill_pipe_params(dai, w->priv, params);
> +	}
> +
> +	return -EINVAL;

Shouldn't that be -EBUSY?  The normal idiom would be to check to see if
we were busy and error out rather than writing it as only configuing if
not busy (which looks like an error case now).

> +	list_for_each_entry(p, &w->sources, list_sink) {
> +		if (p->connect && is_skl_dsp_widget_type(p->source) &&
> +						 p->source->priv) {
> +			ret = skl_tplg_be_set_params(dai, p->source, params);
> +
> +			if (ret < 0)
> +				return ret;
> +		} else {
> +			ret = skl_tplg_be_set_src_pipe_params(dai, p->source,
> +									 params);
> +		}

These two cases appear to be identical apart from ignoring the error in
the else case...

> +	}
> +
> +	return ret;

...unless it happens to be the last entry in the list in which case we
pay attention.

> +static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
> +	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
> +{
> +	struct snd_soc_dapm_path *p = NULL;
> +	int ret = 0;
> +
> +	dev_dbg(dai->dev, "widget name=%s\n", w->name);
> +
> +	list_for_each_entry(p, &w->sinks, list_source) {
> +		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
> +						p->sink->priv) {
> +			ret = skl_tplg_be_set_params(dai, p->sink, params);
> +
> +			if (ret < 0)
> +				return ret;
> +		} else {
> +			ret = skl_tplg_be_set_sink_pipe_params(dai, p->sink,
> +									 params);
> +		}
> +	}

There's some more common code here and the same patterns as above...  :/

> +	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		w = dai->playback_widget;
> +
> +		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
> +		return skl_tplg_be_set_src_pipe_params(dai, w, params);
> +	}
> +
> +	if (params->stream == SNDRV_PCM_STREAM_CAPTURE) {
> +		w = dai->capture_widget;
> +
> +		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
> +		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
> +	}

Normally that'd be written as an if/else, and the only difference
between the two cases here is which widget we pick...
Vinod Koul Aug. 15, 2015, 2 p.m. UTC | #2
On Fri, Aug 14, 2015 at 10:53:10PM +0100, Mark Brown wrote:
> On Sat, Aug 08, 2015 at 01:06:19AM +0530, Subhransu S. Prusty wrote:
> 
> > +	/*
> > +	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit container so
> > +	 * update bit depth accordingly
> > +	 */
> > +	if (format->valid_bit_depth == SKL_DEPTH_16BIT)
> > +		format->bit_depth = format->valid_bit_depth;
> > +	else if (format->valid_bit_depth == SKL_DEPTH_24BIT)
> > +		format->bit_depth = SKL_DEPTH_32BIT;
> > +
> 
> What if the depth is neither 16 bit nor 24 bit?  Shouldn't this just be
> a simple override for the 24 bit case?

These are the only two DSP supports, so am not sure that overriding will
work with DSP. I think we should add else and error out.

> 
> > +/*
> > + * Fill the BE gateway parameters
> > + * The BE gateway expects a blob of parameters which are kept in the ACPI
> > + * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
> > + * The port cna have multiple settings so pick based on the PCM
> > + * parameters
> > + */
> > +static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
> > +		struct skl_module_cfg *mconfig, struct skl_pipe_params *params)
> > +{
> > +	struct skl_pipe *pipe = mconfig->pipe;
> > +	struct nhlt_specific_cfg *cfg;
> > +	struct skl *skl = get_skl_ctx(dai->dev);
> > +	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
> > +
> > +	memcpy(pipe->p_params, params, sizeof(*params));
> > +
> > +	/* update the blob based on virtual bus_id*/
> > +	cfg = (struct nhlt_specific_cfg *) skl_get_ep_blob(skl,
> > +			mconfig->vbus_id, link_type, params->s_fmt,
> > +			params->ch, params->s_freq, params->stream);
> 
> I don't seem to have slk_get_ep_blob() but hopefully it's returning a
> void * in which case why do we need to cast it?  In any case it needs to
> be defined in mainline before this can be applied :(

It is already merged in your tree and part of NHLT patch. And my bad, it
returns struct nhlt_specific_cfg so the cast is not required and will fix

> 
> > +	if (cfg) {
> > +		mconfig->formats_config.caps_size = cfg->size;
> > +		memcpy(mconfig->formats_config.caps, &cfg->caps, cfg->size);
> > +	} else {
> > +		dev_dbg(dai->dev, "Blob is NULL");
> > +		return -EINVAL;
> > +	}
> 
> This seems like a more serious problem than something we just dev_dbg()
> about?

Yes this should be an error as it will fail and we can't start a stream
without this, will fix. Thanks for pointing.

> 
> > +static int skl_tplg_be_set_params(struct snd_soc_dai *dai,
> > +					struct snd_soc_dapm_widget *w,
> > +					struct skl_pipe_params *params)
> > +{
> > +	if (!w->power) {
> > +		dev_dbg(dai->dev, "set params for widget=%s\n", w->name);
> > +		return skl_tplg_be_fill_pipe_params(dai, w->priv, params);
> > +	}
> > +
> > +	return -EINVAL;
> 
> Shouldn't that be -EBUSY?  The normal idiom would be to check to see if
> we were busy and error out rather than writing it as only configuing if
> not busy (which looks like an error case now).

Not EBUSY. So here we are trying to set params for the pipe. So we would
expect that pipe (widget) should be powered up by DAPM, but if that is not
the case then we are in bad state. I am thinking EIO might suit this one better

> 
> > +	list_for_each_entry(p, &w->sources, list_sink) {
> > +		if (p->connect && is_skl_dsp_widget_type(p->source) &&
> > +						 p->source->priv) {
> > +			ret = skl_tplg_be_set_params(dai, p->source, params);
> > +
> > +			if (ret < 0)
> > +				return ret;
> > +		} else {
> > +			ret = skl_tplg_be_set_src_pipe_params(dai, p->source,
> > +									 params);
> > +		}
> 
> These two cases appear to be identical apart from ignoring the error in
> the else case...

Former is skl_tplg_be_set_params whereas latter is
skl_tplg_be_set_src_pipe_params(). In former case we set the params but in
former we set for source pipe

Agree we should check return here, will add that
> 
> > +	}
> > +
> > +	return ret;
> 
> ...unless it happens to be the last entry in the list in which case we
> pay attention.
> 
> > +static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
> > +	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
> > +{
> > +	struct snd_soc_dapm_path *p = NULL;
> > +	int ret = 0;
> > +
> > +	dev_dbg(dai->dev, "widget name=%s\n", w->name);
> > +
> > +	list_for_each_entry(p, &w->sinks, list_source) {
> > +		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
> > +						p->sink->priv) {
> > +			ret = skl_tplg_be_set_params(dai, p->sink, params);
> > +
> > +			if (ret < 0)
> > +				return ret;
> > +		} else {
> > +			ret = skl_tplg_be_set_sink_pipe_params(dai, p->sink,
> > +									 params);
> > +		}
> > +	}
> 
> There's some more common code here and the same patterns as above...  :/

well the problem here is sink, source. Former was for source pipe using
p->source, here we have sink pipe and using p->sink.
Same here too that we either set params or for sink pipe

Jeeja did try to make this common but it becomes quite hard, if you have
a trick up your sleeve for this, am all ears :)

> 
> > +	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> > +		w = dai->playback_widget;
> > +
> > +		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
> > +		return skl_tplg_be_set_src_pipe_params(dai, w, params);
> > +	}
> > +
> > +	if (params->stream == SNDRV_PCM_STREAM_CAPTURE) {
> > +		w = dai->capture_widget;
> > +
> > +		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
> > +		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
> > +	}
> 
> Normally that'd be written as an if/else, and the only difference
> between the two cases here is which widget we pick...

Yes we can change to else. Btw should we rather do if and if else, and else
for error check, in case the value became bad. I am thinking latter.
Mark Brown Aug. 15, 2015, 2:46 p.m. UTC | #3
On Sat, Aug 15, 2015 at 07:30:14PM +0530, Vinod Koul wrote:
> On Fri, Aug 14, 2015 at 10:53:10PM +0100, Mark Brown wrote:
> > On Sat, Aug 08, 2015 at 01:06:19AM +0530, Subhransu S. Prusty wrote:

> > > +	/*
> > > +	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit container so
> > > +	 * update bit depth accordingly
> > > +	 */
> > > +	if (format->valid_bit_depth == SKL_DEPTH_16BIT)
> > > +		format->bit_depth = format->valid_bit_depth;
> > > +	else if (format->valid_bit_depth == SKL_DEPTH_24BIT)
> > > +		format->bit_depth = SKL_DEPTH_32BIT;
> > > +

> > What if the depth is neither 16 bit nor 24 bit?  Shouldn't this just be
> > a simple override for the 24 bit case?

> These are the only two DSP supports, so am not sure that overriding will
> work with DSP. I think we should add else and error out.

Then write a switch statement.  :/

> > > +static int skl_tplg_be_set_params(struct snd_soc_dai *dai,
> > > +					struct snd_soc_dapm_widget *w,
> > > +					struct skl_pipe_params *params)
> > > +{
> > > +	if (!w->power) {
> > > +		dev_dbg(dai->dev, "set params for widget=%s\n", w->name);
> > > +		return skl_tplg_be_fill_pipe_params(dai, w->priv, params);
> > > +	}
> > > +
> > > +	return -EINVAL;
> > 
> > Shouldn't that be -EBUSY?  The normal idiom would be to check to see if
> > we were busy and error out rather than writing it as only configuing if
> > not busy (which looks like an error case now).
> 
> Not EBUSY. So here we are trying to set params for the pipe. So we would
> expect that pipe (widget) should be powered up by DAPM, but if that is not
> the case then we are in bad state. I am thinking EIO might suit this one better

Right, that's why I'm saying -EBUSY - we can't configure the pipe
because it is current in use.

> > There's some more common code here and the same patterns as above...  :/

> well the problem here is sink, source. Former was for source pipe using
> p->source, here we have sink pipe and using p->sink.
> Same here too that we either set params or for sink pipe

> Jeeja did try to make this common but it becomes quite hard, if you have
> a trick up your sleeve for this, am all ears :)

Well, I don't have the code any more.

> > > +	if (params->stream == SNDRV_PCM_STREAM_CAPTURE) {
> > > +		w = dai->capture_widget;
> > > +
> > > +		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
> > > +		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
> > > +	}

> > Normally that'd be written as an if/else, and the only difference
> > between the two cases here is which widget we pick...

> Yes we can change to else. Btw should we rather do if and if else, and else
> for error check, in case the value became bad. I am thinking latter.

Either works.
Vinod Koul Aug. 15, 2015, 3:13 p.m. UTC | #4
On Sat, Aug 15, 2015 at 07:46:46AM -0700, Mark Brown wrote:
> On Sat, Aug 15, 2015 at 07:30:14PM +0530, Vinod Koul wrote:
> > On Fri, Aug 14, 2015 at 10:53:10PM +0100, Mark Brown wrote:
> > > On Sat, Aug 08, 2015 at 01:06:19AM +0530, Subhransu S. Prusty wrote:
> 
> > > > +	/*
> > > > +	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit container so
> > > > +	 * update bit depth accordingly
> > > > +	 */
> > > > +	if (format->valid_bit_depth == SKL_DEPTH_16BIT)
> > > > +		format->bit_depth = format->valid_bit_depth;
> > > > +	else if (format->valid_bit_depth == SKL_DEPTH_24BIT)
> > > > +		format->bit_depth = SKL_DEPTH_32BIT;
> > > > +
> 
> > > What if the depth is neither 16 bit nor 24 bit?  Shouldn't this just be
> > > a simple override for the 24 bit case?
> 
> > These are the only two DSP supports, so am not sure that overriding will
> > work with DSP. I think we should add else and error out.
> 
> Then write a switch statement.  :/

Ok

> 
> > > > +static int skl_tplg_be_set_params(struct snd_soc_dai *dai,
> > > > +					struct snd_soc_dapm_widget *w,
> > > > +					struct skl_pipe_params *params)
> > > > +{
> > > > +	if (!w->power) {
> > > > +		dev_dbg(dai->dev, "set params for widget=%s\n", w->name);
> > > > +		return skl_tplg_be_fill_pipe_params(dai, w->priv, params);
> > > > +	}
> > > > +
> > > > +	return -EINVAL;
> > > 
> > > Shouldn't that be -EBUSY?  The normal idiom would be to check to see if
> > > we were busy and error out rather than writing it as only configuing if
> > > not busy (which looks like an error case now).
> > 
> > Not EBUSY. So here we are trying to set params for the pipe. So we would
> > expect that pipe (widget) should be powered up by DAPM, but if that is not
> > the case then we are in bad state. I am thinking EIO might suit this one better
> 
> Right, that's why I'm saying -EBUSY - we can't configure the pipe
> because it is current in use.

Ok will update

> > > There's some more common code here and the same patterns as above...  :/
> 
> > well the problem here is sink, source. Former was for source pipe using
> > p->source, here we have sink pipe and using p->sink.
> > Same here too that we either set params or for sink pipe
> 
> > Jeeja did try to make this common but it becomes quite hard, if you have
> > a trick up your sleeve for this, am all ears :)
> 
> Well, I don't have the code any more.
> 
> > > > +	if (params->stream == SNDRV_PCM_STREAM_CAPTURE) {
> > > > +		w = dai->capture_widget;
> > > > +
> > > > +		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
> > > > +		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
> > > > +	}
> 
> > > Normally that'd be written as an if/else, and the only difference
> > > between the two cases here is which widget we pick...
> 
> > Yes we can change to else. Btw should we rather do if and if else, and else
> > for error check, in case the value became bad. I am thinking latter.
> 
> Either works.
Ok will add latter
diff mbox

Patch

diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index deb5c0d..7f3c54a 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -752,3 +752,277 @@  static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
 
 	return 0;
 }
+
+/*
+ * The FE params are passed by hw_params of the DAI.
+ * On hw_params, the params are stored in Gateway module of the FE and we
+ * need to calculate the format in DSP module configuration, that conversion
+ * is done here
+ */
+static void skl_tplg_update_pipe_params(struct device *dev,
+		struct skl_module_cfg *mconfig,
+		struct skl_pipe_params *params)
+{
+	struct skl_pipe *pipe = mconfig->pipe;
+	struct skl_module_fmt *format = NULL;
+
+	memcpy(pipe->p_params, params, sizeof(*params));
+
+	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		format = &mconfig->in_fmt;
+	else
+		format = &mconfig->out_fmt;
+
+	/* set the hw_params */
+	format->s_freq = params->s_freq;
+	format->channels = params->ch;
+	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
+
+	/*
+	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit container so
+	 * update bit depth accordingly
+	 */
+	if (format->valid_bit_depth == SKL_DEPTH_16BIT)
+		format->bit_depth = format->valid_bit_depth;
+	else if (format->valid_bit_depth == SKL_DEPTH_24BIT)
+		format->bit_depth = SKL_DEPTH_32BIT;
+
+	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mconfig->ibs = (format->s_freq / 1000) *
+				(format->channels) *
+				(format->bit_depth >> 3);
+	} else {
+		mconfig->obs = (format->s_freq / 1000) *
+				(format->channels) *
+				(format->bit_depth >> 3);
+	}
+}
+
+/*
+ * Query the module config for the FE DAI
+ * This is used to find the hw_params set for that DAI and apply to FE
+ * pipeline
+ */
+static struct skl_module_cfg *
+skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
+{
+	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_path *p = NULL;
+
+	dev_dbg(dai->dev, "%s: enter, dai-name=%s\n", __func__, dai->name);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		w = dai->playback_widget;
+		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
+		list_for_each_entry(p, &w->sinks, list_source) {
+			if (p->connect && p->sink->power &&
+					is_skl_dsp_widget_type(p->sink))
+				continue;
+
+			if (p->sink->priv) {
+				dev_dbg(dai->dev, "set params for %s\n", p->sink->name);
+				return p->sink->priv;
+			}
+		}
+	} else {
+		w = dai->capture_widget;
+		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
+		list_for_each_entry(p, &w->sources, list_sink) {
+			if (p->connect && p->source->power &&
+					is_skl_dsp_widget_type(p->source))
+				continue;
+
+			if (p->source->priv) {
+				dev_dbg(dai->dev, "set params for %s\n", p->source->name);
+				return p->source->priv;
+			}
+		}
+	}
+	return NULL;
+}
+
+int skl_tplg_fe_update_params(struct snd_soc_dai *dai,
+			struct skl_pipe_params *params)
+{
+	struct skl_module_cfg *m_cfg;
+
+	m_cfg = skl_tplg_fe_get_cpr_module(dai, params->stream);
+
+	if (m_cfg)
+		skl_tplg_update_pipe_params(dai->dev, m_cfg, params);
+
+	return 0;
+}
+
+static u8 skl_tplg_be_link_type(int dev_type)
+{
+	int ret;
+
+	switch (dev_type) {
+	case SKL_DEVICE_BT:
+		ret = NHLT_LINK_SSP;
+		break;
+
+	case SKL_DEVICE_DMIC:
+		ret = NHLT_LINK_DMIC;
+		break;
+
+	case SKL_DEVICE_I2S:
+		ret = NHLT_LINK_SSP;
+		break;
+
+	case SKL_DEVICE_HDALINK:
+		ret = NHLT_LINK_HDA;
+		break;
+
+	default:
+		ret = NHLT_LINK_INVALID;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Fill the BE gateway parameters
+ * The BE gateway expects a blob of parameters which are kept in the ACPI
+ * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
+ * The port cna have multiple settings so pick based on the PCM
+ * parameters
+ */
+static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
+		struct skl_module_cfg *mconfig, struct skl_pipe_params *params)
+{
+	struct skl_pipe *pipe = mconfig->pipe;
+	struct nhlt_specific_cfg *cfg;
+	struct skl *skl = get_skl_ctx(dai->dev);
+	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
+
+	memcpy(pipe->p_params, params, sizeof(*params));
+
+	/* update the blob based on virtual bus_id*/
+	cfg = (struct nhlt_specific_cfg *) skl_get_ep_blob(skl,
+			mconfig->vbus_id, link_type, params->s_fmt,
+			params->ch, params->s_freq, params->stream);
+
+	if (cfg) {
+		mconfig->formats_config.caps_size = cfg->size;
+		memcpy(mconfig->formats_config.caps, &cfg->caps, cfg->size);
+	} else {
+		dev_dbg(dai->dev, "Blob is NULL");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int skl_tplg_be_set_params(struct snd_soc_dai *dai,
+					struct snd_soc_dapm_widget *w,
+					struct skl_pipe_params *params)
+{
+	if (!w->power) {
+		dev_dbg(dai->dev, "set params for widget=%s\n", w->name);
+		return skl_tplg_be_fill_pipe_params(dai, w->priv, params);
+	}
+
+	return -EINVAL;
+}
+
+static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
+						struct snd_soc_dapm_widget *w,
+						struct skl_pipe_params *params)
+{
+	struct snd_soc_dapm_path *p;
+	int ret = 0;
+
+	dev_dbg(dai->dev, "In %swidget name=%s\n", __func__, w->name);
+
+	list_for_each_entry(p, &w->sources, list_sink) {
+		if (p->connect && is_skl_dsp_widget_type(p->source) &&
+						 p->source->priv) {
+			ret = skl_tplg_be_set_params(dai, p->source, params);
+
+			if (ret < 0)
+				return ret;
+		} else {
+			ret = skl_tplg_be_set_src_pipe_params(dai, p->source,
+									 params);
+		}
+	}
+
+	return ret;
+}
+
+static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
+	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
+{
+	struct snd_soc_dapm_path *p = NULL;
+	int ret = 0;
+
+	dev_dbg(dai->dev, "widget name=%s\n", w->name);
+
+	list_for_each_entry(p, &w->sinks, list_source) {
+		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
+						p->sink->priv) {
+			ret = skl_tplg_be_set_params(dai, p->sink, params);
+
+			if (ret < 0)
+				return ret;
+		} else {
+			ret = skl_tplg_be_set_sink_pipe_params(dai, p->sink,
+									 params);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * BE hw_params can be a source parameters (capture) or sink parameters
+ * (playback). Based on sink and source we need to either find the source
+ * list or the sink list and set the pipeline parameters
+ */
+int skl_tplg_be_update_params(struct snd_soc_dai *dai,
+				struct skl_pipe_params *params)
+{
+	struct snd_soc_dapm_widget *w;
+
+	dev_dbg(dai->dev, "In %s dai-name=%s\n", __func__, dai->name);
+
+	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		w = dai->playback_widget;
+
+		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
+		return skl_tplg_be_set_src_pipe_params(dai, w, params);
+	}
+
+	if (params->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		w = dai->capture_widget;
+
+		dev_dbg(dai->dev, "Stream name=%s\n", w->name);
+		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
+	}
+
+	return 0;
+}
+
+/* Run/Stop the FE pipeline */
+int skl_tplg_set_fe_pipeline_state(struct snd_soc_dai *dai, bool start,
+								int stream)
+{
+	struct skl *skl = get_skl_ctx(dai->dev);
+	struct skl_sst *ctx = skl->skl_sst;
+	struct skl_module_cfg *mconfig = NULL;
+
+	dev_dbg(dai->dev, "%s: enter, dai-name=%s dir=%d\n", __func__, dai->name, stream);
+
+	mconfig = skl_tplg_fe_get_cpr_module(dai, stream);
+	if (mconfig != NULL) {
+		if (start)
+			return skl_run_pipe(ctx, mconfig->pipe);
+		else
+			return skl_stop_pipe(ctx, mconfig->pipe);
+	}
+
+	return 0;
+}
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 73d7916..94c721e 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -273,6 +273,17 @@  struct skl_dapm_path_list {
 	struct list_head node;
 };
 
+int skl_tplg_fe_update_params(struct snd_soc_dai *dai,
+	struct skl_pipe_params *params);
+int skl_tplg_be_update_params(struct snd_soc_dai *dai,
+	struct skl_pipe_params *params);
+void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
+	struct skl_pipe_params *params, int stream);
+int skl_tplg_init(struct snd_soc_platform *platform,
+				struct hdac_ext_bus *ebus);
+int skl_tplg_set_fe_pipeline_state(struct snd_soc_dai *dai,
+			bool start, int stream);
+
 int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe);
 
 int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);