xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision 260eb73aa252d0cbdfe11523d5def9d6d00625d4)
1e4e2d2f4SJeeja KP /*
2e4e2d2f4SJeeja KP  *  skl-topology.c - Implements Platform component ALSA controls/widget
3e4e2d2f4SJeeja KP  *  handlers.
4e4e2d2f4SJeeja KP  *
5e4e2d2f4SJeeja KP  *  Copyright (C) 2014-2015 Intel Corp
6e4e2d2f4SJeeja KP  *  Author: Jeeja KP <jeeja.kp@intel.com>
7e4e2d2f4SJeeja KP  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8e4e2d2f4SJeeja KP  *
9e4e2d2f4SJeeja KP  * This program is free software; you can redistribute it and/or modify
10e4e2d2f4SJeeja KP  * it under the terms of the GNU General Public License as version 2, as
11e4e2d2f4SJeeja KP  * published by the Free Software Foundation.
12e4e2d2f4SJeeja KP  *
13e4e2d2f4SJeeja KP  * This program is distributed in the hope that it will be useful, but
14e4e2d2f4SJeeja KP  * WITHOUT ANY WARRANTY; without even the implied warranty of
15e4e2d2f4SJeeja KP  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16e4e2d2f4SJeeja KP  * General Public License for more details.
17e4e2d2f4SJeeja KP  */
18e4e2d2f4SJeeja KP 
19e4e2d2f4SJeeja KP #include <linux/slab.h>
20e4e2d2f4SJeeja KP #include <linux/types.h>
21e4e2d2f4SJeeja KP #include <linux/firmware.h>
22e4e2d2f4SJeeja KP #include <sound/soc.h>
23e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
24e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
25e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
26e4e2d2f4SJeeja KP #include "skl-topology.h"
27e4e2d2f4SJeeja KP #include "skl.h"
28e4e2d2f4SJeeja KP #include "skl-tplg-interface.h"
296c5768b3SDharageswari R #include "../common/sst-dsp.h"
306c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
31e4e2d2f4SJeeja KP 
32f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
33f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
34f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
35f7590d4fSJeeja KP 
36e4e2d2f4SJeeja KP /*
37e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
38e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
39e4e2d2f4SJeeja KP  */
40e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
41e4e2d2f4SJeeja KP {
42e4e2d2f4SJeeja KP 	switch (w->id) {
43e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
44e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
45e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
46e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
47e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
48e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
49e4e2d2f4SJeeja KP 		return false;
50e4e2d2f4SJeeja KP 	default:
51e4e2d2f4SJeeja KP 		return true;
52e4e2d2f4SJeeja KP 	}
53e4e2d2f4SJeeja KP }
54e4e2d2f4SJeeja KP 
55e4e2d2f4SJeeja KP /*
56e4e2d2f4SJeeja KP  * Each pipelines needs memory to be allocated. Check if we have free memory
579ba8ffefSDharageswari.R  * from available pool.
58e4e2d2f4SJeeja KP  */
599ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl,
60e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
61e4e2d2f4SJeeja KP {
62e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
63e4e2d2f4SJeeja KP 
64e4e2d2f4SJeeja KP 	if (skl->resource.mem + mconfig->pipe->memory_pages >
65e4e2d2f4SJeeja KP 				skl->resource.max_mem) {
66e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
67e4e2d2f4SJeeja KP 				"%s: module_id %d instance %d\n", __func__,
68e4e2d2f4SJeeja KP 				mconfig->id.module_id,
69e4e2d2f4SJeeja KP 				mconfig->id.instance_id);
70e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
71e4e2d2f4SJeeja KP 				"exceeds ppl memory available %d mem %d\n",
72e4e2d2f4SJeeja KP 				skl->resource.max_mem, skl->resource.mem);
73e4e2d2f4SJeeja KP 		return false;
749ba8ffefSDharageswari.R 	} else {
759ba8ffefSDharageswari.R 		return true;
769ba8ffefSDharageswari.R 	}
77e4e2d2f4SJeeja KP }
78e4e2d2f4SJeeja KP 
799ba8ffefSDharageswari.R /*
809ba8ffefSDharageswari.R  * Add the mem to the mem pool. This is freed when pipe is deleted.
819ba8ffefSDharageswari.R  * Note: DSP does actual memory management we only keep track for complete
829ba8ffefSDharageswari.R  * pool
839ba8ffefSDharageswari.R  */
849ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl,
859ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
869ba8ffefSDharageswari.R {
87e4e2d2f4SJeeja KP 	skl->resource.mem += mconfig->pipe->memory_pages;
88e4e2d2f4SJeeja KP }
89e4e2d2f4SJeeja KP 
90e4e2d2f4SJeeja KP /*
91e4e2d2f4SJeeja KP  * Pipeline needs needs DSP CPU resources for computation, this is
92e4e2d2f4SJeeja KP  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
93e4e2d2f4SJeeja KP  *
94e4e2d2f4SJeeja KP  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
959ba8ffefSDharageswari.R  * pipe.
96e4e2d2f4SJeeja KP  */
979ba8ffefSDharageswari.R 
989ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl,
99e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
100e4e2d2f4SJeeja KP {
101e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
102e4e2d2f4SJeeja KP 
103e4e2d2f4SJeeja KP 	if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
104e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
105e4e2d2f4SJeeja KP 			"%s: module_id %d instance %d\n", __func__,
106e4e2d2f4SJeeja KP 			mconfig->id.module_id, mconfig->id.instance_id);
107e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
1087ca42f5aSGuneshwor Singh 			"exceeds ppl mcps available %d > mem %d\n",
109e4e2d2f4SJeeja KP 			skl->resource.max_mcps, skl->resource.mcps);
110e4e2d2f4SJeeja KP 		return false;
1119ba8ffefSDharageswari.R 	} else {
1129ba8ffefSDharageswari.R 		return true;
1139ba8ffefSDharageswari.R 	}
114e4e2d2f4SJeeja KP }
115e4e2d2f4SJeeja KP 
1169ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
1179ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1189ba8ffefSDharageswari.R {
119e4e2d2f4SJeeja KP 	skl->resource.mcps += mconfig->mcps;
120e4e2d2f4SJeeja KP }
121e4e2d2f4SJeeja KP 
122e4e2d2f4SJeeja KP /*
123e4e2d2f4SJeeja KP  * Free the mcps when tearing down
124e4e2d2f4SJeeja KP  */
125e4e2d2f4SJeeja KP static void
126e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
127e4e2d2f4SJeeja KP {
128e4e2d2f4SJeeja KP 	skl->resource.mcps -= mconfig->mcps;
129e4e2d2f4SJeeja KP }
130e4e2d2f4SJeeja KP 
131e4e2d2f4SJeeja KP /*
132e4e2d2f4SJeeja KP  * Free the memory when tearing down
133e4e2d2f4SJeeja KP  */
134e4e2d2f4SJeeja KP static void
135e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
136e4e2d2f4SJeeja KP {
137e4e2d2f4SJeeja KP 	skl->resource.mem -= mconfig->pipe->memory_pages;
138e4e2d2f4SJeeja KP }
139e4e2d2f4SJeeja KP 
140f7590d4fSJeeja KP 
141f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx,
142f7590d4fSJeeja KP 					struct skl_module_cfg *mcfg)
143f7590d4fSJeeja KP {
144f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Dumping config\n");
145f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Input Format:\n");
1464cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
1474cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
1484cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
1494cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
150f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Output Format:\n");
1514cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
1524cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
1534cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
1544cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
155f7590d4fSJeeja KP }
156f7590d4fSJeeja KP 
157ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
158ea5a137dSSubhransu S. Prusty {
159ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
160ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
161ea5a137dSSubhransu S. Prusty 	int i;
162ea5a137dSSubhransu S. Prusty 
163ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
164ea5a137dSSubhransu S. Prusty 		/*
165ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
166ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
167ea5a137dSSubhransu S. Prusty 		 */
168ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
169ea5a137dSSubhransu S. Prusty 		start_slot++;
170ea5a137dSSubhransu S. Prusty 	}
171ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
172ea5a137dSSubhransu S. Prusty }
173ea5a137dSSubhransu S. Prusty 
174f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
175f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
176f7590d4fSJeeja KP {
177f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
178f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
179ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
180f7590d4fSJeeja KP 		fmt->channels = params->ch;
181ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
182ea5a137dSSubhransu S. Prusty 	}
18398256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
18498256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
18598256f83SJeeja KP 
18698256f83SJeeja KP 		/*
18798256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
18898256f83SJeeja KP 		 * container so update bit depth accordingly
18998256f83SJeeja KP 		 */
19098256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
19198256f83SJeeja KP 		case SKL_DEPTH_16BIT:
19298256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
19398256f83SJeeja KP 			break;
19498256f83SJeeja KP 
19598256f83SJeeja KP 		default:
19698256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
19798256f83SJeeja KP 			break;
19898256f83SJeeja KP 		}
19998256f83SJeeja KP 	}
20098256f83SJeeja KP 
201f7590d4fSJeeja KP }
202f7590d4fSJeeja KP 
203f7590d4fSJeeja KP /*
204f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
205f7590d4fSJeeja KP  * channel converter, format converter.
206f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
207f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
208f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
209f7590d4fSJeeja KP  *
210f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
211f7590d4fSJeeja KP  * for BE with its hw_params invoked.
212f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
213f7590d4fSJeeja KP  * outfix and then apply that for a module
214f7590d4fSJeeja KP  */
215f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
216f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
217f7590d4fSJeeja KP {
218f7590d4fSJeeja KP 	int in_fixup, out_fixup;
219f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
220f7590d4fSJeeja KP 
2214cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
2224cd9899fSHardik T Shah 	in_fmt = &m_cfg->in_fmt[0];
2234cd9899fSHardik T Shah 	out_fmt = &m_cfg->out_fmt[0];
224f7590d4fSJeeja KP 
225f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
226f7590d4fSJeeja KP 		if (is_fe) {
227f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
228f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
229f7590d4fSJeeja KP 					m_cfg->params_fixup;
230f7590d4fSJeeja KP 		} else {
231f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
232f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
233f7590d4fSJeeja KP 					m_cfg->params_fixup;
234f7590d4fSJeeja KP 		}
235f7590d4fSJeeja KP 	} else {
236f7590d4fSJeeja KP 		if (is_fe) {
237f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
238f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
239f7590d4fSJeeja KP 					m_cfg->params_fixup;
240f7590d4fSJeeja KP 		} else {
241f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
242f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
243f7590d4fSJeeja KP 					m_cfg->params_fixup;
244f7590d4fSJeeja KP 		}
245f7590d4fSJeeja KP 	}
246f7590d4fSJeeja KP 
247f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
248f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
249f7590d4fSJeeja KP }
250f7590d4fSJeeja KP 
251f7590d4fSJeeja KP /*
252f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
253f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
254f7590d4fSJeeja KP  * well.
255f7590d4fSJeeja KP  */
256f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
257f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
258f7590d4fSJeeja KP {
259f7590d4fSJeeja KP 	int multiplier = 1;
2604cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
261f0c8e1d9SSubhransu S. Prusty 	int in_rate, out_rate;
2624cd9899fSHardik T Shah 
2634cd9899fSHardik T Shah 
2644cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
2654cd9899fSHardik T Shah 	 * change for pin 0 only
2664cd9899fSHardik T Shah 	 */
2674cd9899fSHardik T Shah 	in_fmt = &mcfg->in_fmt[0];
2684cd9899fSHardik T Shah 	out_fmt = &mcfg->out_fmt[0];
269f7590d4fSJeeja KP 
270f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
271f7590d4fSJeeja KP 		multiplier = 5;
272f0c8e1d9SSubhransu S. Prusty 
273f0c8e1d9SSubhransu S. Prusty 	if (in_fmt->s_freq % 1000)
274f0c8e1d9SSubhransu S. Prusty 		in_rate = (in_fmt->s_freq / 1000) + 1;
275f0c8e1d9SSubhransu S. Prusty 	else
276f0c8e1d9SSubhransu S. Prusty 		in_rate = (in_fmt->s_freq / 1000);
277f0c8e1d9SSubhransu S. Prusty 
278f0c8e1d9SSubhransu S. Prusty 	mcfg->ibs = in_rate * (mcfg->in_fmt->channels) *
2794cd9899fSHardik T Shah 			(mcfg->in_fmt->bit_depth >> 3) *
280f7590d4fSJeeja KP 			multiplier;
281f7590d4fSJeeja KP 
282f0c8e1d9SSubhransu S. Prusty 	if (mcfg->out_fmt->s_freq % 1000)
283f0c8e1d9SSubhransu S. Prusty 		out_rate = (mcfg->out_fmt->s_freq / 1000) + 1;
284f0c8e1d9SSubhransu S. Prusty 	else
285f0c8e1d9SSubhransu S. Prusty 		out_rate = (mcfg->out_fmt->s_freq / 1000);
286f0c8e1d9SSubhransu S. Prusty 
287f0c8e1d9SSubhransu S. Prusty 	mcfg->obs = out_rate * (mcfg->out_fmt->channels) *
2884cd9899fSHardik T Shah 			(mcfg->out_fmt->bit_depth >> 3) *
289f7590d4fSJeeja KP 			multiplier;
290f7590d4fSJeeja KP }
291f7590d4fSJeeja KP 
2922d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
2932d1419a3SJeeja KP 						struct skl_sst *ctx)
2942d1419a3SJeeja KP {
2952d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
2962d1419a3SJeeja KP 	int link_type, dir;
2972d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
2982d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
2992d1419a3SJeeja KP 	struct skl *skl = get_skl_ctx(ctx->dev);
3002d1419a3SJeeja KP 
3012d1419a3SJeeja KP 	/* check if we already have blob */
3022d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
3032d1419a3SJeeja KP 		return 0;
3042d1419a3SJeeja KP 
305c7c6c736SJeeja KP 	dev_dbg(ctx->dev, "Applying default cfg blob\n");
3062d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
3072d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3082d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
309c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
3102d1419a3SJeeja KP 		s_freq = m_cfg->in_fmt[0].s_freq;
3112d1419a3SJeeja KP 		s_fmt = m_cfg->in_fmt[0].bit_depth;
3122d1419a3SJeeja KP 		ch = m_cfg->in_fmt[0].channels;
3132d1419a3SJeeja KP 		break;
3142d1419a3SJeeja KP 
3152d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
3162d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
3172d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
318c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
3192d1419a3SJeeja KP 			s_freq = m_cfg->out_fmt[0].s_freq;
3202d1419a3SJeeja KP 			s_fmt = m_cfg->out_fmt[0].bit_depth;
3212d1419a3SJeeja KP 			ch = m_cfg->out_fmt[0].channels;
322c7c6c736SJeeja KP 		} else {
323c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
324c7c6c736SJeeja KP 			s_freq = m_cfg->in_fmt[0].s_freq;
325c7c6c736SJeeja KP 			s_fmt = m_cfg->in_fmt[0].bit_depth;
326c7c6c736SJeeja KP 			ch = m_cfg->in_fmt[0].channels;
3272d1419a3SJeeja KP 		}
3282d1419a3SJeeja KP 		break;
3292d1419a3SJeeja KP 
3302d1419a3SJeeja KP 	default:
3312d1419a3SJeeja KP 		return -EINVAL;
3322d1419a3SJeeja KP 	}
3332d1419a3SJeeja KP 
3342d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
3352d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
3362d1419a3SJeeja KP 					s_fmt, ch, s_freq, dir);
3372d1419a3SJeeja KP 	if (cfg) {
3382d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
3392d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
3402d1419a3SJeeja KP 	} else {
3412d1419a3SJeeja KP 		dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n",
3422d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
3432d1419a3SJeeja KP 		dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n",
3442d1419a3SJeeja KP 					ch, s_freq, s_fmt);
3452d1419a3SJeeja KP 		return -EIO;
3462d1419a3SJeeja KP 	}
3472d1419a3SJeeja KP 
3482d1419a3SJeeja KP 	return 0;
3492d1419a3SJeeja KP }
3502d1419a3SJeeja KP 
351f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
352f7590d4fSJeeja KP 							struct skl_sst *ctx)
353f7590d4fSJeeja KP {
354f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
355f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
356f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
357f7590d4fSJeeja KP 	bool is_fe;
358f7590d4fSJeeja KP 
359f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
360f7590d4fSJeeja KP 		return;
361f7590d4fSJeeja KP 
362f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
363f7590d4fSJeeja KP 				w->name);
364f7590d4fSJeeja KP 
365f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
366f7590d4fSJeeja KP 
367f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
368f7590d4fSJeeja KP 		is_fe = true;
369f7590d4fSJeeja KP 	else
370f7590d4fSJeeja KP 		is_fe = false;
371f7590d4fSJeeja KP 
372f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
373f7590d4fSJeeja KP 	skl_tplg_update_buffer_size(ctx, m_cfg);
374f7590d4fSJeeja KP 
375f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
376f7590d4fSJeeja KP 				w->name);
377f7590d4fSJeeja KP 
378f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
379f7590d4fSJeeja KP }
380f7590d4fSJeeja KP 
381e4e2d2f4SJeeja KP /*
382e4e2d2f4SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
383e4e2d2f4SJeeja KP  * well. While managing a pipeline we need to get the list of all the
384e4e2d2f4SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps
385e4e2d2f4SJeeja KP  * to get the SKL type widgets in that pipeline
386e4e2d2f4SJeeja KP  */
387e4e2d2f4SJeeja KP static int skl_tplg_alloc_pipe_widget(struct device *dev,
388e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w, struct skl_pipe *pipe)
389e4e2d2f4SJeeja KP {
390e4e2d2f4SJeeja KP 	struct skl_module_cfg *src_module = NULL;
391e4e2d2f4SJeeja KP 	struct snd_soc_dapm_path *p = NULL;
392e4e2d2f4SJeeja KP 	struct skl_pipe_module *p_module = NULL;
393e4e2d2f4SJeeja KP 
394e4e2d2f4SJeeja KP 	p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL);
395e4e2d2f4SJeeja KP 	if (!p_module)
396e4e2d2f4SJeeja KP 		return -ENOMEM;
397e4e2d2f4SJeeja KP 
398e4e2d2f4SJeeja KP 	p_module->w = w;
399e4e2d2f4SJeeja KP 	list_add_tail(&p_module->node, &pipe->w_list);
400e4e2d2f4SJeeja KP 
401e4e2d2f4SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
402e4e2d2f4SJeeja KP 		if ((p->sink->priv == NULL)
403e4e2d2f4SJeeja KP 				&& (!is_skl_dsp_widget_type(w)))
404e4e2d2f4SJeeja KP 			continue;
405e4e2d2f4SJeeja KP 
406e4e2d2f4SJeeja KP 		if ((p->sink->priv != NULL) && p->connect
407e4e2d2f4SJeeja KP 				&& is_skl_dsp_widget_type(p->sink)) {
408e4e2d2f4SJeeja KP 
409e4e2d2f4SJeeja KP 			src_module = p->sink->priv;
410e4e2d2f4SJeeja KP 			if (pipe->ppl_id == src_module->pipe->ppl_id)
411e4e2d2f4SJeeja KP 				skl_tplg_alloc_pipe_widget(dev,
412e4e2d2f4SJeeja KP 							p->sink, pipe);
413e4e2d2f4SJeeja KP 		}
414e4e2d2f4SJeeja KP 	}
415e4e2d2f4SJeeja KP 	return 0;
416e4e2d2f4SJeeja KP }
417e4e2d2f4SJeeja KP 
418e4e2d2f4SJeeja KP /*
419abb74003SJeeja KP  * some modules can have multiple params set from user control and
420abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
421abb74003SJeeja KP  * set module params will be done after module is initialised.
422abb74003SJeeja KP  */
423abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
424abb74003SJeeja KP 						struct skl_sst *ctx)
425abb74003SJeeja KP {
426abb74003SJeeja KP 	int i, ret;
427abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
428abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
429abb74003SJeeja KP 	struct soc_bytes_ext *sb;
430abb74003SJeeja KP 	struct skl_algo_data *bc;
431abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
432abb74003SJeeja KP 
433abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
4344ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
435abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
436abb74003SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
437abb74003SJeeja KP 					sp_cfg->caps_size,
438abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
439abb74003SJeeja KP 		if (ret < 0)
440abb74003SJeeja KP 			return ret;
441abb74003SJeeja KP 	}
442abb74003SJeeja KP 
443abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
444abb74003SJeeja KP 		k = &w->kcontrol_news[i];
445abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
446abb74003SJeeja KP 			sb = (void *) k->private_value;
447abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
448abb74003SJeeja KP 
4494ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
450abb74003SJeeja KP 				ret = skl_set_module_params(ctx,
451abb74003SJeeja KP 						(u32 *)bc->params, bc->max,
452abb74003SJeeja KP 						bc->param_id, mconfig);
453abb74003SJeeja KP 				if (ret < 0)
454abb74003SJeeja KP 					return ret;
455abb74003SJeeja KP 			}
456abb74003SJeeja KP 		}
457abb74003SJeeja KP 	}
458abb74003SJeeja KP 
459abb74003SJeeja KP 	return 0;
460abb74003SJeeja KP }
461abb74003SJeeja KP 
462abb74003SJeeja KP /*
463abb74003SJeeja KP  * some module param can set from user control and this is required as
464abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
465abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
466abb74003SJeeja KP  * parameter needs to set as part of module init.
467abb74003SJeeja KP  */
468abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
469abb74003SJeeja KP {
470abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
471abb74003SJeeja KP 	struct soc_bytes_ext *sb;
472abb74003SJeeja KP 	struct skl_algo_data *bc;
473abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
474abb74003SJeeja KP 	int i;
475abb74003SJeeja KP 
476abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
477abb74003SJeeja KP 		k = &w->kcontrol_news[i];
478abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
479abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
480abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
481abb74003SJeeja KP 
4824ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
483abb74003SJeeja KP 				continue;
484abb74003SJeeja KP 
485abb74003SJeeja KP 			mconfig->formats_config.caps = (u32 *)&bc->params;
486abb74003SJeeja KP 			mconfig->formats_config.caps_size = bc->max;
487abb74003SJeeja KP 
488abb74003SJeeja KP 			break;
489abb74003SJeeja KP 		}
490abb74003SJeeja KP 	}
491abb74003SJeeja KP 
492abb74003SJeeja KP 	return 0;
493abb74003SJeeja KP }
494abb74003SJeeja KP 
495abb74003SJeeja KP /*
496e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
497e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
498e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
499e4e2d2f4SJeeja KP  */
500e4e2d2f4SJeeja KP static int
501e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
502e4e2d2f4SJeeja KP {
503e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
504e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
505e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
506e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
507e4e2d2f4SJeeja KP 	int ret = 0;
508e4e2d2f4SJeeja KP 
509e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
510e4e2d2f4SJeeja KP 		w = w_module->w;
511e4e2d2f4SJeeja KP 		mconfig = w->priv;
512e4e2d2f4SJeeja KP 
513e4e2d2f4SJeeja KP 		/* check resource available */
5149ba8ffefSDharageswari.R 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
515e4e2d2f4SJeeja KP 			return -ENOMEM;
516e4e2d2f4SJeeja KP 
5176c5768b3SDharageswari R 		if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
5186c5768b3SDharageswari R 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
5196c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
5206c5768b3SDharageswari R 			if (ret < 0)
5216c5768b3SDharageswari R 				return ret;
522d643678bSJeeja KP 
523d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
5246c5768b3SDharageswari R 		}
5256c5768b3SDharageswari R 
5262d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
5272d1419a3SJeeja KP 		skl_tplg_update_be_blob(w, ctx);
5282d1419a3SJeeja KP 
529f7590d4fSJeeja KP 		/*
530f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
531f7590d4fSJeeja KP 		 * FE/BE params
532f7590d4fSJeeja KP 		 */
533f7590d4fSJeeja KP 		skl_tplg_update_module_params(w, ctx);
534abb74003SJeeja KP 
535abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
5369939a9c3SJeeja KP 		ret = skl_init_module(ctx, mconfig);
537e4e2d2f4SJeeja KP 		if (ret < 0)
538e4e2d2f4SJeeja KP 			return ret;
539abb74003SJeeja KP 
540*260eb73aSDharageswari R 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
541abb74003SJeeja KP 		ret = skl_tplg_set_module_params(w, ctx);
542e4e2d2f4SJeeja KP 		if (ret < 0)
543e4e2d2f4SJeeja KP 			return ret;
544e4e2d2f4SJeeja KP 	}
545e4e2d2f4SJeeja KP 
546e4e2d2f4SJeeja KP 	return 0;
547e4e2d2f4SJeeja KP }
548d93f8e55SVinod Koul 
5496c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
5506c5768b3SDharageswari R 	 struct skl_pipe *pipe)
5516c5768b3SDharageswari R {
5526c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
5536c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
5546c5768b3SDharageswari R 
5556c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
5566c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
5576c5768b3SDharageswari R 
558d643678bSJeeja KP 		if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
559d643678bSJeeja KP 			mconfig->m_state > SKL_MODULE_UNINIT)
5606c5768b3SDharageswari R 			return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
5616c5768b3SDharageswari R 						mconfig->id.module_id);
5626c5768b3SDharageswari R 	}
5636c5768b3SDharageswari R 
5646c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
5656c5768b3SDharageswari R 	return 0;
5666c5768b3SDharageswari R }
5676c5768b3SDharageswari R 
568d93f8e55SVinod Koul /*
569d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
570d93f8e55SVinod Koul  * need create the pipeline. So we do following:
571d93f8e55SVinod Koul  *   - check the resources
572d93f8e55SVinod Koul  *   - Create the pipeline
573d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
574d93f8e55SVinod Koul  *   - finally bind all modules together
575d93f8e55SVinod Koul  */
576d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
577d93f8e55SVinod Koul 							struct skl *skl)
578d93f8e55SVinod Koul {
579d93f8e55SVinod Koul 	int ret;
580d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
581d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
582d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
583d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
584d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
585d93f8e55SVinod Koul 
586d93f8e55SVinod Koul 	/* check resource available */
5879ba8ffefSDharageswari.R 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
588d93f8e55SVinod Koul 		return -EBUSY;
589d93f8e55SVinod Koul 
5909ba8ffefSDharageswari.R 	if (!skl_is_pipe_mem_avail(skl, mconfig))
591d93f8e55SVinod Koul 		return -ENOMEM;
592d93f8e55SVinod Koul 
593d93f8e55SVinod Koul 	/*
594d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
595d93f8e55SVinod Koul 	 * This list contains modules from source to sink
596d93f8e55SVinod Koul 	 */
597d93f8e55SVinod Koul 	ret = skl_create_pipeline(ctx, mconfig->pipe);
598d93f8e55SVinod Koul 	if (ret < 0)
599d93f8e55SVinod Koul 		return ret;
600d93f8e55SVinod Koul 
601*260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mem(skl, mconfig);
602*260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mcps(skl, mconfig);
603*260eb73aSDharageswari R 
604d93f8e55SVinod Koul 	/*
605d93f8e55SVinod Koul 	 * we create a w_list of all widgets in that pipe. This list is not
606d93f8e55SVinod Koul 	 * freed on PMD event as widgets within a pipe are static. This
607d93f8e55SVinod Koul 	 * saves us cycles to get widgets in pipe every time.
608d93f8e55SVinod Koul 	 *
609d93f8e55SVinod Koul 	 * So if we have already initialized all the widgets of a pipeline
610d93f8e55SVinod Koul 	 * we skip, so check for list_empty and create the list if empty
611d93f8e55SVinod Koul 	 */
612d93f8e55SVinod Koul 	if (list_empty(&s_pipe->w_list)) {
613d93f8e55SVinod Koul 		ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe);
614d93f8e55SVinod Koul 		if (ret < 0)
615d93f8e55SVinod Koul 			return ret;
616d93f8e55SVinod Koul 	}
617d93f8e55SVinod Koul 
618d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
619d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
620d93f8e55SVinod Koul 	if (ret < 0)
621d93f8e55SVinod Koul 		return ret;
622d93f8e55SVinod Koul 
623d93f8e55SVinod Koul 	/* Bind modules from source to sink */
624d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
625d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
626d93f8e55SVinod Koul 
627d93f8e55SVinod Koul 		if (src_module == NULL) {
628d93f8e55SVinod Koul 			src_module = dst_module;
629d93f8e55SVinod Koul 			continue;
630d93f8e55SVinod Koul 		}
631d93f8e55SVinod Koul 
632d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_module, dst_module);
633d93f8e55SVinod Koul 		if (ret < 0)
634d93f8e55SVinod Koul 			return ret;
635d93f8e55SVinod Koul 
636d93f8e55SVinod Koul 		src_module = dst_module;
637d93f8e55SVinod Koul 	}
638d93f8e55SVinod Koul 
639d93f8e55SVinod Koul 	return 0;
640d93f8e55SVinod Koul }
641d93f8e55SVinod Koul 
642cc6a4044SJeeja KP /*
643cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
644cc6a4044SJeeja KP  * all pins connected.
645cc6a4044SJeeja KP  *
646cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
647cc6a4044SJeeja KP  * send params after binding
648cc6a4044SJeeja KP  */
649cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
650cc6a4044SJeeja KP 			struct skl_module_cfg *mcfg, struct skl_sst *ctx)
651cc6a4044SJeeja KP {
652cc6a4044SJeeja KP 	int i, ret;
653cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
654cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
655cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
656cc6a4044SJeeja KP 	struct skl_algo_data *bc;
657cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
658cc6a4044SJeeja KP 
659cc6a4044SJeeja KP 	/*
660cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
661cc6a4044SJeeja KP 	 * if so set the module param
662cc6a4044SJeeja KP 	 */
663cc6a4044SJeeja KP 	for (i = 0; i < mcfg->max_out_queue; i++) {
664cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
665cc6a4044SJeeja KP 			return 0;
666cc6a4044SJeeja KP 	}
667cc6a4044SJeeja KP 
668cc6a4044SJeeja KP 	for (i = 0; i < mcfg->max_in_queue; i++) {
669cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
670cc6a4044SJeeja KP 			return 0;
671cc6a4044SJeeja KP 	}
672cc6a4044SJeeja KP 
673cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
674cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
675cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
676cc6a4044SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
677cc6a4044SJeeja KP 					sp_cfg->caps_size,
678cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
679cc6a4044SJeeja KP 		if (ret < 0)
680cc6a4044SJeeja KP 			return ret;
681cc6a4044SJeeja KP 	}
682cc6a4044SJeeja KP 
683cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
684cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
685cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
686cc6a4044SJeeja KP 			sb = (void *) k->private_value;
687cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
688cc6a4044SJeeja KP 
689cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
690cc6a4044SJeeja KP 				ret = skl_set_module_params(ctx,
691cc6a4044SJeeja KP 						(u32 *)bc->params, bc->max,
692cc6a4044SJeeja KP 						bc->param_id, mconfig);
693cc6a4044SJeeja KP 				if (ret < 0)
694cc6a4044SJeeja KP 					return ret;
695cc6a4044SJeeja KP 			}
696cc6a4044SJeeja KP 		}
697cc6a4044SJeeja KP 	}
698cc6a4044SJeeja KP 
699cc6a4044SJeeja KP 	return 0;
700cc6a4044SJeeja KP }
701cc6a4044SJeeja KP 
7028724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
7038724ff17SJeeja KP 				struct skl *skl,
7046bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
7058724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
706d93f8e55SVinod Koul {
707d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
7080ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
7098724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
710d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
7118724ff17SJeeja KP 	int ret;
712d93f8e55SVinod Koul 
7138724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
714d93f8e55SVinod Koul 		if (!p->connect)
715d93f8e55SVinod Koul 			continue;
716d93f8e55SVinod Koul 
717d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
718d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
719d93f8e55SVinod Koul 
7200ed95d76SJeeja KP 		next_sink = p->sink;
7216bd4cf85SJeeja KP 
7226bd4cf85SJeeja KP 		if (!is_skl_dsp_widget_type(p->sink))
7236bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
7246bd4cf85SJeeja KP 
725d93f8e55SVinod Koul 		/*
726d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
727d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
728d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
729d93f8e55SVinod Koul 		 */
730d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
731d93f8e55SVinod Koul 					is_skl_dsp_widget_type(p->sink)) {
732d93f8e55SVinod Koul 
733d93f8e55SVinod Koul 			sink = p->sink;
734d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
735d93f8e55SVinod Koul 
736cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
737cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
738cc6a4044SJeeja KP 				continue;
739cc6a4044SJeeja KP 
740d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
741d93f8e55SVinod Koul 			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
742d93f8e55SVinod Koul 			if (ret)
743d93f8e55SVinod Koul 				return ret;
744d93f8e55SVinod Koul 
745cc6a4044SJeeja KP 			/* set module params after bind */
746cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx);
747cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
748cc6a4044SJeeja KP 
749d93f8e55SVinod Koul 			/* Start sinks pipe first */
750d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
751d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
752d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
753d1730c3dSJeeja KP 					ret = skl_run_pipe(ctx,
754d1730c3dSJeeja KP 							sink_mconfig->pipe);
755d93f8e55SVinod Koul 				if (ret)
756d93f8e55SVinod Koul 					return ret;
757d93f8e55SVinod Koul 			}
758d93f8e55SVinod Koul 		}
759d93f8e55SVinod Koul 	}
760d93f8e55SVinod Koul 
7618724ff17SJeeja KP 	if (!sink)
7626bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
7638724ff17SJeeja KP 
7648724ff17SJeeja KP 	return 0;
7658724ff17SJeeja KP }
7668724ff17SJeeja KP 
767d93f8e55SVinod Koul /*
768d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
769d93f8e55SVinod Koul  * we need to do following:
770d93f8e55SVinod Koul  *   - Bind to sink pipeline
771d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
772d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
773d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
774d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
775d93f8e55SVinod Koul  *   - Then run current pipe
776d93f8e55SVinod Koul  */
777d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
778d93f8e55SVinod Koul 								struct skl *skl)
779d93f8e55SVinod Koul {
7808724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
781d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
782d93f8e55SVinod Koul 	int ret = 0;
783d93f8e55SVinod Koul 
7848724ff17SJeeja KP 	src_mconfig = w->priv;
785d93f8e55SVinod Koul 
786d93f8e55SVinod Koul 	/*
787d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
788d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
789d93f8e55SVinod Koul 	 * this pipe
790d93f8e55SVinod Koul 	 */
7916bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
7928724ff17SJeeja KP 	if (ret)
7938724ff17SJeeja KP 		return ret;
7948724ff17SJeeja KP 
795d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
796d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
797d1730c3dSJeeja KP 		return skl_run_pipe(ctx, src_mconfig->pipe);
798d93f8e55SVinod Koul 
799d93f8e55SVinod Koul 	return 0;
800d93f8e55SVinod Koul }
801d93f8e55SVinod Koul 
8028724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
8038724ff17SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl *skl)
8048724ff17SJeeja KP {
8058724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
8068724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
8078724ff17SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
8088724ff17SJeeja KP 
809d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
8108724ff17SJeeja KP 		src_w = p->source;
811d93f8e55SVinod Koul 		if (!p->connect)
812d93f8e55SVinod Koul 			continue;
813d93f8e55SVinod Koul 
8148724ff17SJeeja KP 		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
8158724ff17SJeeja KP 		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
816d93f8e55SVinod Koul 
817d93f8e55SVinod Koul 		/*
8188724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
8198724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
8208724ff17SJeeja KP 		 * ones used for SKL so check that first
821d93f8e55SVinod Koul 		 */
8228724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
8238724ff17SJeeja KP 					is_skl_dsp_widget_type(p->source)) {
8248724ff17SJeeja KP 			return p->source;
825d93f8e55SVinod Koul 		}
826d93f8e55SVinod Koul 	}
827d93f8e55SVinod Koul 
8288724ff17SJeeja KP 	if (src_w != NULL)
8298724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
830d93f8e55SVinod Koul 
8318724ff17SJeeja KP 	return NULL;
832d93f8e55SVinod Koul }
833d93f8e55SVinod Koul 
834d93f8e55SVinod Koul /*
835d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
836d93f8e55SVinod Koul  *   - Check if this pipe is running
837d93f8e55SVinod Koul  *   - if not, then
838d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
839d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
840d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
841d93f8e55SVinod Koul  *	- start this pipeline
842d93f8e55SVinod Koul  */
843d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
844d93f8e55SVinod Koul 							struct skl *skl)
845d93f8e55SVinod Koul {
846d93f8e55SVinod Koul 	int ret = 0;
847d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
848d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
849d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
850d93f8e55SVinod Koul 	int src_pipe_started = 0;
851d93f8e55SVinod Koul 
852d93f8e55SVinod Koul 	sink = w;
853d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
854d93f8e55SVinod Koul 
855d93f8e55SVinod Koul 	/*
856d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
857d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
858d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
859d93f8e55SVinod Koul 	 */
8608724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
8618724ff17SJeeja KP 	if (source != NULL) {
862d93f8e55SVinod Koul 		src_mconfig = source->priv;
863d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
864d93f8e55SVinod Koul 		src_pipe_started = 1;
865d93f8e55SVinod Koul 
866d93f8e55SVinod Koul 		/*
8678724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
8688724ff17SJeeja KP 		 * pipe
869d93f8e55SVinod Koul 		 */
870d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
871d93f8e55SVinod Koul 			src_pipe_started = 0;
872d93f8e55SVinod Koul 	}
873d93f8e55SVinod Koul 
874d93f8e55SVinod Koul 	if (src_pipe_started) {
875d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
876d93f8e55SVinod Koul 		if (ret)
877d93f8e55SVinod Koul 			return ret;
878d93f8e55SVinod Koul 
879cc6a4044SJeeja KP 		/* set module params after bind */
880cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(source, src_mconfig, ctx);
881cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
882cc6a4044SJeeja KP 
883d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
884d93f8e55SVinod Koul 			ret = skl_run_pipe(ctx, sink_mconfig->pipe);
885d93f8e55SVinod Koul 	}
886d93f8e55SVinod Koul 
887d93f8e55SVinod Koul 	return ret;
888d93f8e55SVinod Koul }
889d93f8e55SVinod Koul 
890d93f8e55SVinod Koul /*
891d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
892d93f8e55SVinod Koul  *   - Stop the pipe
893d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
894d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
895d93f8e55SVinod Koul  */
896d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
897d93f8e55SVinod Koul 							struct skl *skl)
898d93f8e55SVinod Koul {
899d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
900ce1b5551SJeeja KP 	int ret = 0, i;
901d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
902d93f8e55SVinod Koul 
903ce1b5551SJeeja KP 	sink_mconfig = w->priv;
904d93f8e55SVinod Koul 
905d93f8e55SVinod Koul 	/* Stop the pipe */
906d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
907d93f8e55SVinod Koul 	if (ret)
908d93f8e55SVinod Koul 		return ret;
909d93f8e55SVinod Koul 
910ce1b5551SJeeja KP 	for (i = 0; i < sink_mconfig->max_in_queue; i++) {
911ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
912ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
913ce1b5551SJeeja KP 			if (!src_mconfig)
914ce1b5551SJeeja KP 				continue;
915d93f8e55SVinod Koul 			/*
916ce1b5551SJeeja KP 			 * If path_found == 1, that means pmd for source
917ce1b5551SJeeja KP 			 * pipe has not occurred, source is connected to
918ce1b5551SJeeja KP 			 * some other sink. so its responsibility of sink
919ce1b5551SJeeja KP 			 * to unbind itself from source.
920d93f8e55SVinod Koul 			 */
921d93f8e55SVinod Koul 			ret = skl_stop_pipe(ctx, src_mconfig->pipe);
922d93f8e55SVinod Koul 			if (ret < 0)
923d93f8e55SVinod Koul 				return ret;
924d93f8e55SVinod Koul 
925ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx,
926ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
927ce1b5551SJeeja KP 		}
928d93f8e55SVinod Koul 	}
929d93f8e55SVinod Koul 
930d93f8e55SVinod Koul 	return ret;
931d93f8e55SVinod Koul }
932d93f8e55SVinod Koul 
933d93f8e55SVinod Koul /*
934d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
935d93f8e55SVinod Koul  *   - Free the mcps used
936d93f8e55SVinod Koul  *   - Free the mem used
937d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
938d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
939d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
940d93f8e55SVinod Koul  */
941d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
942d93f8e55SVinod Koul 							struct skl *skl)
943d93f8e55SVinod Koul {
944d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
945d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
946d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
947d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
948d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
949d93f8e55SVinod Koul 	int ret = 0;
950d93f8e55SVinod Koul 
951*260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
952*260eb73aSDharageswari R 		return -EINVAL;
953*260eb73aSDharageswari R 
954d93f8e55SVinod Koul 	skl_tplg_free_pipe_mcps(skl, mconfig);
95565976878SVinod Koul 	skl_tplg_free_pipe_mem(skl, mconfig);
956d93f8e55SVinod Koul 
957d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
958d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
959d93f8e55SVinod Koul 
960*260eb73aSDharageswari R 		if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
9617ae3cb15SVinod Koul 			skl_tplg_free_pipe_mcps(skl, dst_module);
962d93f8e55SVinod Koul 		if (src_module == NULL) {
963d93f8e55SVinod Koul 			src_module = dst_module;
964d93f8e55SVinod Koul 			continue;
965d93f8e55SVinod Koul 		}
966d93f8e55SVinod Koul 
9677ca42f5aSGuneshwor Singh 		skl_unbind_modules(ctx, src_module, dst_module);
968d93f8e55SVinod Koul 		src_module = dst_module;
969d93f8e55SVinod Koul 	}
970d93f8e55SVinod Koul 
971d93f8e55SVinod Koul 	ret = skl_delete_pipe(ctx, mconfig->pipe);
972d93f8e55SVinod Koul 
9736c5768b3SDharageswari R 	return skl_tplg_unload_pipe_modules(ctx, s_pipe);
974d93f8e55SVinod Koul }
975d93f8e55SVinod Koul 
976d93f8e55SVinod Koul /*
977d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
978d93f8e55SVinod Koul  *   - Free the mcps used
979d93f8e55SVinod Koul  *   - Stop the pipeline
980d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
981d93f8e55SVinod Koul  */
982d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
983d93f8e55SVinod Koul 								struct skl *skl)
984d93f8e55SVinod Koul {
985d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
986ce1b5551SJeeja KP 	int ret = 0, i;
987d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
988d93f8e55SVinod Koul 
989ce1b5551SJeeja KP 	src_mconfig = w->priv;
990d93f8e55SVinod Koul 
991d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
992d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, src_mconfig->pipe);
993d93f8e55SVinod Koul 	if (ret)
994d93f8e55SVinod Koul 		return ret;
995d93f8e55SVinod Koul 
996ce1b5551SJeeja KP 	for (i = 0; i < src_mconfig->max_out_queue; i++) {
997ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
998ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
999ce1b5551SJeeja KP 			if (!sink_mconfig)
1000ce1b5551SJeeja KP 				continue;
1001d93f8e55SVinod Koul 			/*
1002ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1003d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1004d93f8e55SVinod Koul 			 */
1005ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx, src_mconfig,
1006ce1b5551SJeeja KP 							sink_mconfig);
1007ce1b5551SJeeja KP 		}
1008d93f8e55SVinod Koul 	}
1009d93f8e55SVinod Koul 
1010d93f8e55SVinod Koul 	return ret;
1011d93f8e55SVinod Koul }
1012d93f8e55SVinod Koul 
1013d93f8e55SVinod Koul /*
1014d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline.  If
1015d93f8e55SVinod Koul  * mixer is not required then it is treated as static mixer aka vmixer with
1016d93f8e55SVinod Koul  * a hard path to source module
1017d93f8e55SVinod Koul  * So we don't need to check if source is started or not as hard path puts
1018d93f8e55SVinod Koul  * dependency on each other
1019d93f8e55SVinod Koul  */
1020d93f8e55SVinod Koul static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w,
1021d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1022d93f8e55SVinod Koul {
1023d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1024d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1025d93f8e55SVinod Koul 
1026d93f8e55SVinod Koul 	switch (event) {
1027d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1028d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1029d93f8e55SVinod Koul 
1030de1fedf2SJeeja KP 	case SND_SOC_DAPM_POST_PMU:
1031de1fedf2SJeeja KP 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1032de1fedf2SJeeja KP 
1033de1fedf2SJeeja KP 	case SND_SOC_DAPM_PRE_PMD:
1034de1fedf2SJeeja KP 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1035de1fedf2SJeeja KP 
1036d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1037d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1038d93f8e55SVinod Koul 	}
1039d93f8e55SVinod Koul 
1040d93f8e55SVinod Koul 	return 0;
1041d93f8e55SVinod Koul }
1042d93f8e55SVinod Koul 
1043d93f8e55SVinod Koul /*
1044d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1045d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1046d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1047d93f8e55SVinod Koul  * instance
1048d93f8e55SVinod Koul  */
1049d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1050d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1051d93f8e55SVinod Koul {
1052d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1053d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1054d93f8e55SVinod Koul 
1055d93f8e55SVinod Koul 	switch (event) {
1056d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1057d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1058d93f8e55SVinod Koul 
1059d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1060d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1061d93f8e55SVinod Koul 
1062d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1063d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1064d93f8e55SVinod Koul 
1065d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1066d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1067d93f8e55SVinod Koul 	}
1068d93f8e55SVinod Koul 
1069d93f8e55SVinod Koul 	return 0;
1070d93f8e55SVinod Koul }
1071d93f8e55SVinod Koul 
1072d93f8e55SVinod Koul /*
1073d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1074d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1075d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1076d93f8e55SVinod Koul  * scenarios
1077d93f8e55SVinod Koul  */
1078d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1079d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1080d93f8e55SVinod Koul 
1081d93f8e55SVinod Koul {
1082d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1083d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1084d93f8e55SVinod Koul 
1085d93f8e55SVinod Koul 	switch (event) {
1086d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1087d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1088d93f8e55SVinod Koul 
1089d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1090d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1091d93f8e55SVinod Koul 	}
1092d93f8e55SVinod Koul 
1093d93f8e55SVinod Koul 	return 0;
1094d93f8e55SVinod Koul }
1095cfb0a873SVinod Koul 
1096140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1097140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1098140adfbaSJeeja KP {
1099140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1100140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1101140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
11027d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
11037d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
11047d9f2911SOmair M Abdullah 	struct skl *skl = get_skl_ctx(w->dapm->dev);
11057d9f2911SOmair M Abdullah 
11067d9f2911SOmair M Abdullah 	if (w->power)
11077d9f2911SOmair M Abdullah 		skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
11087d9f2911SOmair M Abdullah 				      bc->max, bc->param_id, mconfig);
1109140adfbaSJeeja KP 
111041556f68SVinod Koul 	/* decrement size for TLV header */
111141556f68SVinod Koul 	size -= 2 * sizeof(u32);
111241556f68SVinod Koul 
111341556f68SVinod Koul 	/* check size as we don't want to send kernel data */
111441556f68SVinod Koul 	if (size > bc->max)
111541556f68SVinod Koul 		size = bc->max;
111641556f68SVinod Koul 
1117140adfbaSJeeja KP 	if (bc->params) {
1118140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1119140adfbaSJeeja KP 			return -EFAULT;
1120e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1121140adfbaSJeeja KP 			return -EFAULT;
1122e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1123140adfbaSJeeja KP 			return -EFAULT;
1124140adfbaSJeeja KP 	}
1125140adfbaSJeeja KP 
1126140adfbaSJeeja KP 	return 0;
1127140adfbaSJeeja KP }
1128140adfbaSJeeja KP 
1129140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1130140adfbaSJeeja KP 
1131140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1132140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1133140adfbaSJeeja KP {
1134140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1135140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1136140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1137140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1138140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1139140adfbaSJeeja KP 	struct skl *skl = get_skl_ctx(w->dapm->dev);
1140140adfbaSJeeja KP 
1141140adfbaSJeeja KP 	if (ac->params) {
1142140adfbaSJeeja KP 		/*
1143140adfbaSJeeja KP 		 * if the param_is is of type Vendor, firmware expects actual
1144140adfbaSJeeja KP 		 * parameter id and size from the control.
1145140adfbaSJeeja KP 		 */
1146140adfbaSJeeja KP 		if (ac->param_id == SKL_PARAM_VENDOR_ID) {
1147140adfbaSJeeja KP 			if (copy_from_user(ac->params, data, size))
1148140adfbaSJeeja KP 				return -EFAULT;
1149140adfbaSJeeja KP 		} else {
1150140adfbaSJeeja KP 			if (copy_from_user(ac->params,
115165b4bcb8SAlan 					   data + 2, size))
1152140adfbaSJeeja KP 				return -EFAULT;
1153140adfbaSJeeja KP 		}
1154140adfbaSJeeja KP 
1155140adfbaSJeeja KP 		if (w->power)
1156140adfbaSJeeja KP 			return skl_set_module_params(skl->skl_sst,
1157140adfbaSJeeja KP 						(u32 *)ac->params, ac->max,
1158140adfbaSJeeja KP 						ac->param_id, mconfig);
1159140adfbaSJeeja KP 	}
1160140adfbaSJeeja KP 
1161140adfbaSJeeja KP 	return 0;
1162140adfbaSJeeja KP }
1163140adfbaSJeeja KP 
1164cfb0a873SVinod Koul /*
1165cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1166cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1167cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1168cfb0a873SVinod Koul  * conversion is done here
1169cfb0a873SVinod Koul  */
1170cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1171cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1172cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1173cfb0a873SVinod Koul {
1174cfb0a873SVinod Koul 	struct skl_pipe *pipe = mconfig->pipe;
1175cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1176cfb0a873SVinod Koul 
1177cfb0a873SVinod Koul 	memcpy(pipe->p_params, params, sizeof(*params));
1178cfb0a873SVinod Koul 
1179cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
11804cd9899fSHardik T Shah 		format = &mconfig->in_fmt[0];
1181cfb0a873SVinod Koul 	else
11824cd9899fSHardik T Shah 		format = &mconfig->out_fmt[0];
1183cfb0a873SVinod Koul 
1184cfb0a873SVinod Koul 	/* set the hw_params */
1185cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1186cfb0a873SVinod Koul 	format->channels = params->ch;
1187cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1188cfb0a873SVinod Koul 
1189cfb0a873SVinod Koul 	/*
1190cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1191cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1192cfb0a873SVinod Koul 	 */
1193cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1194cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1195cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1196cfb0a873SVinod Koul 		break;
1197cfb0a873SVinod Koul 
1198cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
11996654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1200cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1201cfb0a873SVinod Koul 		break;
1202cfb0a873SVinod Koul 
1203cfb0a873SVinod Koul 	default:
1204cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1205cfb0a873SVinod Koul 				format->valid_bit_depth);
1206cfb0a873SVinod Koul 		return -EINVAL;
1207cfb0a873SVinod Koul 	}
1208cfb0a873SVinod Koul 
1209cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1210cfb0a873SVinod Koul 		mconfig->ibs = (format->s_freq / 1000) *
1211cfb0a873SVinod Koul 				(format->channels) *
1212cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1213cfb0a873SVinod Koul 	} else {
1214cfb0a873SVinod Koul 		mconfig->obs = (format->s_freq / 1000) *
1215cfb0a873SVinod Koul 				(format->channels) *
1216cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1217cfb0a873SVinod Koul 	}
1218cfb0a873SVinod Koul 
1219cfb0a873SVinod Koul 	return 0;
1220cfb0a873SVinod Koul }
1221cfb0a873SVinod Koul 
1222cfb0a873SVinod Koul /*
1223cfb0a873SVinod Koul  * Query the module config for the FE DAI
1224cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1225cfb0a873SVinod Koul  * pipeline
1226cfb0a873SVinod Koul  */
1227cfb0a873SVinod Koul struct skl_module_cfg *
1228cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1229cfb0a873SVinod Koul {
1230cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1231cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1232cfb0a873SVinod Koul 
1233cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1234cfb0a873SVinod Koul 		w = dai->playback_widget;
1235f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1236cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1237a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->sink))
1238cfb0a873SVinod Koul 				continue;
1239cfb0a873SVinod Koul 
1240cfb0a873SVinod Koul 			if (p->sink->priv) {
1241cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1242cfb0a873SVinod Koul 						p->sink->name);
1243cfb0a873SVinod Koul 				return p->sink->priv;
1244cfb0a873SVinod Koul 			}
1245cfb0a873SVinod Koul 		}
1246cfb0a873SVinod Koul 	} else {
1247cfb0a873SVinod Koul 		w = dai->capture_widget;
1248f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1249cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1250a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->source))
1251cfb0a873SVinod Koul 				continue;
1252cfb0a873SVinod Koul 
1253cfb0a873SVinod Koul 			if (p->source->priv) {
1254cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1255cfb0a873SVinod Koul 						p->source->name);
1256cfb0a873SVinod Koul 				return p->source->priv;
1257cfb0a873SVinod Koul 			}
1258cfb0a873SVinod Koul 		}
1259cfb0a873SVinod Koul 	}
1260cfb0a873SVinod Koul 
1261cfb0a873SVinod Koul 	return NULL;
1262cfb0a873SVinod Koul }
1263cfb0a873SVinod Koul 
1264718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1265718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1266718a42b5SDharageswari.R {
1267718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1268718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1269718a42b5SDharageswari.R 
1270718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1271718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1272718a42b5SDharageswari.R 			if (p->connect &&
1273718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1274718a42b5SDharageswari.R 				    p->source->priv) {
1275718a42b5SDharageswari.R 				mconfig = p->source->priv;
1276718a42b5SDharageswari.R 				return mconfig;
1277718a42b5SDharageswari.R 			}
1278718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1279718a42b5SDharageswari.R 			if (mconfig)
1280718a42b5SDharageswari.R 				return mconfig;
1281718a42b5SDharageswari.R 		}
1282718a42b5SDharageswari.R 	}
1283718a42b5SDharageswari.R 	return mconfig;
1284718a42b5SDharageswari.R }
1285718a42b5SDharageswari.R 
1286718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1287718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1288718a42b5SDharageswari.R {
1289718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1290718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1291718a42b5SDharageswari.R 
1292718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1293718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1294718a42b5SDharageswari.R 			if (p->connect &&
1295718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1296718a42b5SDharageswari.R 				    p->sink->priv) {
1297718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1298718a42b5SDharageswari.R 				return mconfig;
1299718a42b5SDharageswari.R 			}
1300718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1301718a42b5SDharageswari.R 			if (mconfig)
1302718a42b5SDharageswari.R 				return mconfig;
1303718a42b5SDharageswari.R 		}
1304718a42b5SDharageswari.R 	}
1305718a42b5SDharageswari.R 	return mconfig;
1306718a42b5SDharageswari.R }
1307718a42b5SDharageswari.R 
1308718a42b5SDharageswari.R struct skl_module_cfg *
1309718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1310718a42b5SDharageswari.R {
1311718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1312718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1313718a42b5SDharageswari.R 
1314718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1315718a42b5SDharageswari.R 		w = dai->playback_widget;
1316718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1317718a42b5SDharageswari.R 	} else {
1318718a42b5SDharageswari.R 		w = dai->capture_widget;
1319718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1320718a42b5SDharageswari.R 	}
1321718a42b5SDharageswari.R 	return mconfig;
1322718a42b5SDharageswari.R }
1323718a42b5SDharageswari.R 
1324cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1325cfb0a873SVinod Koul {
1326cfb0a873SVinod Koul 	int ret;
1327cfb0a873SVinod Koul 
1328cfb0a873SVinod Koul 	switch (dev_type) {
1329cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1330cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1331cfb0a873SVinod Koul 		break;
1332cfb0a873SVinod Koul 
1333cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1334cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1335cfb0a873SVinod Koul 		break;
1336cfb0a873SVinod Koul 
1337cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1338cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1339cfb0a873SVinod Koul 		break;
1340cfb0a873SVinod Koul 
1341cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1342cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1343cfb0a873SVinod Koul 		break;
1344cfb0a873SVinod Koul 
1345cfb0a873SVinod Koul 	default:
1346cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1347cfb0a873SVinod Koul 		break;
1348cfb0a873SVinod Koul 	}
1349cfb0a873SVinod Koul 
1350cfb0a873SVinod Koul 	return ret;
1351cfb0a873SVinod Koul }
1352cfb0a873SVinod Koul 
1353cfb0a873SVinod Koul /*
1354cfb0a873SVinod Koul  * Fill the BE gateway parameters
1355cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1356cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1357cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1358cfb0a873SVinod Koul  * parameters
1359cfb0a873SVinod Koul  */
1360cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1361cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1362cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1363cfb0a873SVinod Koul {
1364cfb0a873SVinod Koul 	struct skl_pipe *pipe = mconfig->pipe;
1365cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1366cfb0a873SVinod Koul 	struct skl *skl = get_skl_ctx(dai->dev);
1367cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1368cfb0a873SVinod Koul 
1369cfb0a873SVinod Koul 	memcpy(pipe->p_params, params, sizeof(*params));
1370cfb0a873SVinod Koul 
1371b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1372b30c275eSJeeja KP 		return 0;
1373b30c275eSJeeja KP 
1374cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1375cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1376cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1377cfb0a873SVinod Koul 					params->s_freq, params->stream);
1378cfb0a873SVinod Koul 	if (cfg) {
1379cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1380bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1381cfb0a873SVinod Koul 	} else {
1382cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1383cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1384cfb0a873SVinod Koul 					params->stream);
1385cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1386cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1387cfb0a873SVinod Koul 		return -EINVAL;
1388cfb0a873SVinod Koul 	}
1389cfb0a873SVinod Koul 
1390cfb0a873SVinod Koul 	return 0;
1391cfb0a873SVinod Koul }
1392cfb0a873SVinod Koul 
1393cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1394cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1395cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1396cfb0a873SVinod Koul {
1397cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
13984d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1399cfb0a873SVinod Koul 
1400f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1401cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->source) &&
1402cfb0a873SVinod Koul 						p->source->priv) {
1403cfb0a873SVinod Koul 
14049a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
14059a03cb49SJeeja KP 						p->source->priv, params);
14064d8adccbSSubhransu S. Prusty 			if (ret < 0)
14074d8adccbSSubhransu S. Prusty 				return ret;
1408cfb0a873SVinod Koul 		} else {
14099a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
14109a03cb49SJeeja KP 						p->source, params);
14114d8adccbSSubhransu S. Prusty 			if (ret < 0)
14124d8adccbSSubhransu S. Prusty 				return ret;
1413cfb0a873SVinod Koul 		}
1414cfb0a873SVinod Koul 	}
1415cfb0a873SVinod Koul 
14164d8adccbSSubhransu S. Prusty 	return ret;
1417cfb0a873SVinod Koul }
1418cfb0a873SVinod Koul 
1419cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1420cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1421cfb0a873SVinod Koul {
1422cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
14234d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1424cfb0a873SVinod Koul 
1425f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1426cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
1427cfb0a873SVinod Koul 						p->sink->priv) {
1428cfb0a873SVinod Koul 
14299a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
14309a03cb49SJeeja KP 						p->sink->priv, params);
14314d8adccbSSubhransu S. Prusty 			if (ret < 0)
14324d8adccbSSubhransu S. Prusty 				return ret;
14334d8adccbSSubhransu S. Prusty 		} else {
14344d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1435cfb0a873SVinod Koul 						dai, p->sink, params);
14364d8adccbSSubhransu S. Prusty 			if (ret < 0)
14374d8adccbSSubhransu S. Prusty 				return ret;
1438cfb0a873SVinod Koul 		}
1439cfb0a873SVinod Koul 	}
1440cfb0a873SVinod Koul 
14414d8adccbSSubhransu S. Prusty 	return ret;
1442cfb0a873SVinod Koul }
1443cfb0a873SVinod Koul 
1444cfb0a873SVinod Koul /*
1445cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1446cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1447cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1448cfb0a873SVinod Koul  */
1449cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1450cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1451cfb0a873SVinod Koul {
1452cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1453cfb0a873SVinod Koul 
1454cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1455cfb0a873SVinod Koul 		w = dai->playback_widget;
1456cfb0a873SVinod Koul 
1457cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1458cfb0a873SVinod Koul 
1459cfb0a873SVinod Koul 	} else {
1460cfb0a873SVinod Koul 		w = dai->capture_widget;
1461cfb0a873SVinod Koul 
1462cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1463cfb0a873SVinod Koul 	}
1464cfb0a873SVinod Koul 
1465cfb0a873SVinod Koul 	return 0;
1466cfb0a873SVinod Koul }
14673af36706SVinod Koul 
14683af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
14693af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
14703af36706SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_vmixer_event},
14713af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
14723af36706SVinod Koul };
14733af36706SVinod Koul 
1474140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1475140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1476140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1477140adfbaSJeeja KP };
1478140adfbaSJeeja KP 
14793af36706SVinod Koul /*
14803af36706SVinod Koul  * The topology binary passes the pin info for a module so initialize the pin
14813af36706SVinod Koul  * info passed into module instance
14823af36706SVinod Koul  */
14836abca1d7SJeeja KP static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
14843af36706SVinod Koul 						struct skl_module_pin *m_pin,
14856abca1d7SJeeja KP 						bool is_dynamic, int max_pin)
14863af36706SVinod Koul {
14873af36706SVinod Koul 	int i;
14883af36706SVinod Koul 
14893af36706SVinod Koul 	for (i = 0; i < max_pin; i++) {
14906abca1d7SJeeja KP 		m_pin[i].id.module_id = dfw_pin[i].module_id;
14916abca1d7SJeeja KP 		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
14923af36706SVinod Koul 		m_pin[i].in_use = false;
14936abca1d7SJeeja KP 		m_pin[i].is_dynamic = is_dynamic;
14944f745708SJeeja KP 		m_pin[i].pin_state = SKL_PIN_UNBIND;
14953af36706SVinod Koul 	}
14963af36706SVinod Koul }
14973af36706SVinod Koul 
14983af36706SVinod Koul /*
14993af36706SVinod Koul  * Add pipeline from topology binary into driver pipeline list
15003af36706SVinod Koul  *
15013af36706SVinod Koul  * If already added we return that instance
15023af36706SVinod Koul  * Otherwise we create a new instance and add into driver list
15033af36706SVinod Koul  */
15043af36706SVinod Koul static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
15053af36706SVinod Koul 			struct skl *skl, struct skl_dfw_pipe *dfw_pipe)
15063af36706SVinod Koul {
15073af36706SVinod Koul 	struct skl_pipeline *ppl;
15083af36706SVinod Koul 	struct skl_pipe *pipe;
15093af36706SVinod Koul 	struct skl_pipe_params *params;
15103af36706SVinod Koul 
15113af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
15123af36706SVinod Koul 		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id)
15133af36706SVinod Koul 			return ppl->pipe;
15143af36706SVinod Koul 	}
15153af36706SVinod Koul 
15163af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
15173af36706SVinod Koul 	if (!ppl)
15183af36706SVinod Koul 		return NULL;
15193af36706SVinod Koul 
15203af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
15213af36706SVinod Koul 	if (!pipe)
15223af36706SVinod Koul 		return NULL;
15233af36706SVinod Koul 
15243af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
15253af36706SVinod Koul 	if (!params)
15263af36706SVinod Koul 		return NULL;
15273af36706SVinod Koul 
15283af36706SVinod Koul 	pipe->ppl_id = dfw_pipe->pipe_id;
15293af36706SVinod Koul 	pipe->memory_pages = dfw_pipe->memory_pages;
15303af36706SVinod Koul 	pipe->pipe_priority = dfw_pipe->pipe_priority;
15313af36706SVinod Koul 	pipe->conn_type = dfw_pipe->conn_type;
15323af36706SVinod Koul 	pipe->state = SKL_PIPE_INVALID;
15333af36706SVinod Koul 	pipe->p_params = params;
15343af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
15353af36706SVinod Koul 
15363af36706SVinod Koul 	ppl->pipe = pipe;
15373af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
15383af36706SVinod Koul 
15393af36706SVinod Koul 	return ppl->pipe;
15403af36706SVinod Koul }
15413af36706SVinod Koul 
15424cd9899fSHardik T Shah static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
15434cd9899fSHardik T Shah 				struct skl_dfw_module_fmt *src_fmt,
15444cd9899fSHardik T Shah 				int pins)
15454cd9899fSHardik T Shah {
15464cd9899fSHardik T Shah 	int i;
15474cd9899fSHardik T Shah 
15484cd9899fSHardik T Shah 	for (i = 0; i < pins; i++) {
15494cd9899fSHardik T Shah 		dst_fmt[i].channels  = src_fmt[i].channels;
15504cd9899fSHardik T Shah 		dst_fmt[i].s_freq = src_fmt[i].freq;
15514cd9899fSHardik T Shah 		dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
15524cd9899fSHardik T Shah 		dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
15534cd9899fSHardik T Shah 		dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
15544cd9899fSHardik T Shah 		dst_fmt[i].ch_map = src_fmt[i].ch_map;
15554cd9899fSHardik T Shah 		dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
15564cd9899fSHardik T Shah 		dst_fmt[i].sample_type = src_fmt[i].sample_type;
15574cd9899fSHardik T Shah 	}
15584cd9899fSHardik T Shah }
15594cd9899fSHardik T Shah 
15603af36706SVinod Koul /*
15613af36706SVinod Koul  * Topology core widget load callback
15623af36706SVinod Koul  *
15633af36706SVinod Koul  * This is used to save the private data for each widget which gives
15643af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
15653af36706SVinod Koul  * FW expects like ids, resource values, formats etc
15663af36706SVinod Koul  */
15673af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
15683af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
15693af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
15703af36706SVinod Koul {
15713af36706SVinod Koul 	int ret;
15723af36706SVinod Koul 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
15733af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
15743af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
15753af36706SVinod Koul 	struct skl_module_cfg *mconfig;
15763af36706SVinod Koul 	struct skl_pipe *pipe;
1577b663a8c5SJeeja KP 	struct skl_dfw_module *dfw_config =
1578b663a8c5SJeeja KP 				(struct skl_dfw_module *)tplg_w->priv.data;
15793af36706SVinod Koul 
15803af36706SVinod Koul 	if (!tplg_w->priv.size)
15813af36706SVinod Koul 		goto bind_event;
15823af36706SVinod Koul 
15833af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
15843af36706SVinod Koul 
15853af36706SVinod Koul 	if (!mconfig)
15863af36706SVinod Koul 		return -ENOMEM;
15873af36706SVinod Koul 
15883af36706SVinod Koul 	w->priv = mconfig;
158909305da9SShreyas NC 	memcpy(&mconfig->guid, &dfw_config->uuid, 16);
159009305da9SShreyas NC 
1591ea6b3e94SShreyas NC 	ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config);
1592ea6b3e94SShreyas NC 	if (ret < 0)
1593ea6b3e94SShreyas NC 		return ret;
1594ea6b3e94SShreyas NC 
15953af36706SVinod Koul 	mconfig->id.module_id = dfw_config->module_id;
15963af36706SVinod Koul 	mconfig->id.instance_id = dfw_config->instance_id;
15973af36706SVinod Koul 	mconfig->mcps = dfw_config->max_mcps;
15983af36706SVinod Koul 	mconfig->ibs = dfw_config->ibs;
15993af36706SVinod Koul 	mconfig->obs = dfw_config->obs;
16003af36706SVinod Koul 	mconfig->core_id = dfw_config->core_id;
16013af36706SVinod Koul 	mconfig->max_in_queue = dfw_config->max_in_queue;
16023af36706SVinod Koul 	mconfig->max_out_queue = dfw_config->max_out_queue;
16033af36706SVinod Koul 	mconfig->is_loadable = dfw_config->is_loadable;
16044cd9899fSHardik T Shah 	skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
16054cd9899fSHardik T Shah 						MODULE_MAX_IN_PINS);
16064cd9899fSHardik T Shah 	skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
16074cd9899fSHardik T Shah 						MODULE_MAX_OUT_PINS);
16084cd9899fSHardik T Shah 
16093af36706SVinod Koul 	mconfig->params_fixup = dfw_config->params_fixup;
16103af36706SVinod Koul 	mconfig->converter = dfw_config->converter;
16113af36706SVinod Koul 	mconfig->m_type = dfw_config->module_type;
16123af36706SVinod Koul 	mconfig->vbus_id = dfw_config->vbus_id;
1613b18c458dSJeeja KP 	mconfig->mem_pages = dfw_config->mem_pages;
16143af36706SVinod Koul 
16153af36706SVinod Koul 	pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
16163af36706SVinod Koul 	if (pipe)
16173af36706SVinod Koul 		mconfig->pipe = pipe;
16183af36706SVinod Koul 
16193af36706SVinod Koul 	mconfig->dev_type = dfw_config->dev_type;
16203af36706SVinod Koul 	mconfig->hw_conn_type = dfw_config->hw_conn_type;
16213af36706SVinod Koul 	mconfig->time_slot = dfw_config->time_slot;
16223af36706SVinod Koul 	mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
16233af36706SVinod Koul 
16244cd9899fSHardik T Shah 	mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
16253af36706SVinod Koul 						sizeof(*mconfig->m_in_pin),
16263af36706SVinod Koul 						GFP_KERNEL);
16273af36706SVinod Koul 	if (!mconfig->m_in_pin)
16283af36706SVinod Koul 		return -ENOMEM;
16293af36706SVinod Koul 
16306abca1d7SJeeja KP 	mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) *
16313af36706SVinod Koul 						sizeof(*mconfig->m_out_pin),
16323af36706SVinod Koul 						GFP_KERNEL);
16333af36706SVinod Koul 	if (!mconfig->m_out_pin)
16343af36706SVinod Koul 		return -ENOMEM;
16353af36706SVinod Koul 
16366abca1d7SJeeja KP 	skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin,
16376abca1d7SJeeja KP 						dfw_config->is_dynamic_in_pin,
16383af36706SVinod Koul 						mconfig->max_in_queue);
16396abca1d7SJeeja KP 
16406abca1d7SJeeja KP 	skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin,
16416abca1d7SJeeja KP 						 dfw_config->is_dynamic_out_pin,
16423af36706SVinod Koul 							mconfig->max_out_queue);
16433af36706SVinod Koul 
16446abca1d7SJeeja KP 
16453af36706SVinod Koul 	if (mconfig->formats_config.caps_size == 0)
16463af36706SVinod Koul 		goto bind_event;
16473af36706SVinod Koul 
16483af36706SVinod Koul 	mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev,
16493af36706SVinod Koul 			mconfig->formats_config.caps_size, GFP_KERNEL);
16503af36706SVinod Koul 
16513af36706SVinod Koul 	if (mconfig->formats_config.caps == NULL)
16523af36706SVinod Koul 		return -ENOMEM;
16533af36706SVinod Koul 
16543af36706SVinod Koul 	memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
16553af36706SVinod Koul 						 dfw_config->caps.caps_size);
1656abb74003SJeeja KP 	mconfig->formats_config.param_id = dfw_config->caps.param_id;
1657abb74003SJeeja KP 	mconfig->formats_config.set_params = dfw_config->caps.set_params;
16583af36706SVinod Koul 
16593af36706SVinod Koul bind_event:
16603af36706SVinod Koul 	if (tplg_w->event_type == 0) {
16613373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
16623af36706SVinod Koul 		return 0;
16633af36706SVinod Koul 	}
16643af36706SVinod Koul 
16653af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
1666b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
1667b663a8c5SJeeja KP 					tplg_w->event_type);
16683af36706SVinod Koul 
16693af36706SVinod Koul 	if (ret) {
16703af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
16713af36706SVinod Koul 					__func__, tplg_w->event_type);
16723af36706SVinod Koul 		return -EINVAL;
16733af36706SVinod Koul 	}
16743af36706SVinod Koul 
16753af36706SVinod Koul 	return 0;
16763af36706SVinod Koul }
16773af36706SVinod Koul 
1678140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
1679140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
1680140adfbaSJeeja KP {
1681140adfbaSJeeja KP 	struct skl_algo_data *ac;
1682140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
1683140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
1684140adfbaSJeeja KP 
1685140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
1686140adfbaSJeeja KP 	if (!ac)
1687140adfbaSJeeja KP 		return -ENOMEM;
1688140adfbaSJeeja KP 
1689140adfbaSJeeja KP 	/* Fill private data */
1690140adfbaSJeeja KP 	ac->max = dfw_ac->max;
1691140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
1692140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
1693140adfbaSJeeja KP 
1694140adfbaSJeeja KP 	if (ac->max) {
1695140adfbaSJeeja KP 		ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
1696140adfbaSJeeja KP 		if (!ac->params)
1697140adfbaSJeeja KP 			return -ENOMEM;
1698140adfbaSJeeja KP 
1699140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
1700140adfbaSJeeja KP 	}
1701140adfbaSJeeja KP 
1702140adfbaSJeeja KP 	be->dobj.private  = ac;
1703140adfbaSJeeja KP 	return 0;
1704140adfbaSJeeja KP }
1705140adfbaSJeeja KP 
1706140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
1707140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
1708140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
1709140adfbaSJeeja KP {
1710140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
1711140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
1712140adfbaSJeeja KP 	struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
1713140adfbaSJeeja KP 	struct hdac_bus *bus = ebus_to_hbus(ebus);
1714140adfbaSJeeja KP 
1715140adfbaSJeeja KP 	switch (hdr->ops.info) {
1716140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
1717140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
1718140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
1719140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1720140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
1721140adfbaSJeeja KP 			if (tplg_bc->priv.size)
1722140adfbaSJeeja KP 				return skl_init_algo_data(
1723140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
1724140adfbaSJeeja KP 		}
1725140adfbaSJeeja KP 		break;
1726140adfbaSJeeja KP 
1727140adfbaSJeeja KP 	default:
1728140adfbaSJeeja KP 		dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
1729140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
1730140adfbaSJeeja KP 		break;
1731140adfbaSJeeja KP 	}
1732140adfbaSJeeja KP 
1733140adfbaSJeeja KP 	return 0;
1734140adfbaSJeeja KP }
1735140adfbaSJeeja KP 
17363af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
17373af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
1738140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
1739140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
1740140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
17413af36706SVinod Koul };
17423af36706SVinod Koul 
17433af36706SVinod Koul /* This will be read from topology manifest, currently defined here */
17443af36706SVinod Koul #define SKL_MAX_MCPS 30000000
17453af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000
17463af36706SVinod Koul 
17473af36706SVinod Koul /*
17483af36706SVinod Koul  * SKL topology init routine
17493af36706SVinod Koul  */
17503af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
17513af36706SVinod Koul {
17523af36706SVinod Koul 	int ret;
17533af36706SVinod Koul 	const struct firmware *fw;
17543af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
17553af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
17563af36706SVinod Koul 
17574b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
17583af36706SVinod Koul 	if (ret < 0) {
1759b663a8c5SJeeja KP 		dev_err(bus->dev, "tplg fw %s load failed with %d\n",
17604b235c43SVinod Koul 				skl->tplg_name, ret);
17614b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
17624b235c43SVinod Koul 		if (ret < 0) {
17634b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
17643af36706SVinod Koul 					"dfw_sst.bin", ret);
17653af36706SVinod Koul 			return ret;
17663af36706SVinod Koul 		}
17674b235c43SVinod Koul 	}
17683af36706SVinod Koul 
17693af36706SVinod Koul 	/*
17703af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
17713af36706SVinod Koul 	 * any other index
17723af36706SVinod Koul 	 */
1773b663a8c5SJeeja KP 	ret = snd_soc_tplg_component_load(&platform->component,
1774b663a8c5SJeeja KP 					&skl_tplg_ops, fw, 0);
17753af36706SVinod Koul 	if (ret < 0) {
17763af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
1777c14a82c7SSudip Mukherjee 		release_firmware(fw);
17783af36706SVinod Koul 		return -EINVAL;
17793af36706SVinod Koul 	}
17803af36706SVinod Koul 
17813af36706SVinod Koul 	skl->resource.max_mcps = SKL_MAX_MCPS;
17823af36706SVinod Koul 	skl->resource.max_mem = SKL_FW_MAX_MEM;
17833af36706SVinod Koul 
1784d8018361SVinod Koul 	skl->tplg = fw;
1785d8018361SVinod Koul 
17863af36706SVinod Koul 	return 0;
17873af36706SVinod Koul }
1788